Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions plugins/batch_operator_plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,16 @@ All 21 batch operators run this plugin in perpetuity. The epoch scheduler (`sysi

| Option | Default | Description |
|--------|---------|-------------|
| `--batch-operator-account` | — | WIRE account name for this operator |
| `--batch-epoch-poll-ms` | 5000 | How often to check epoch state (ms) |
| `--batch-outpost-poll-ms` | 3000 | How often to poll outpost for new messages (ms) |
| `--batch-delivery-timeout-ms` | 30000 | Max time to wait for chain delivery confirmation (ms) |
| `--batch-enabled` | false | Enable batch operator functionality |
| `--batch-operator-account` | — | WIRE account name for this operator. Configuring it enables the relay |
| `--batch-epoch-poll-ms` | 15000 | How often to check epoch state (ms) |
| `--batch-delivery-timeout-ms` | 15000 | Max time to wait for chain delivery confirmation (ms) |
| `--batch-sol-client-id` | `sol-default` | Solana outpost client ID (RPC connection) for SVM outpost rows |
| `--batch-outpost` | — | Remote OPP contract binding for one active `sysio.chains` row, repeatable once per chain code. Spec: `CHAIN_CODE,opp_addr[,opp_inbound_addr]` |

There is no separate enable flag: the relay runs when `--batch-operator-account`
is configured, the way `producer_plugin` keys off `--producer-name`. The plugin
must also be listed under `plugin =` (or pulled in as a dependency by
`external_debugging_plugin`), and requires `read-mode = irreversible`.

## Dependencies

Expand Down
15 changes: 10 additions & 5 deletions plugins/batch_operator_plugin/src/batch_operator_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ struct outpost_descriptor {
struct batch_operator_plugin::impl {
// Configuration
chain::name operator_account;
/// Derived from `operator_account` at plugin_initialize: the relay runs iff
/// an account was configured. There is no separate enable flag.
bool enabled = false;
uint32_t epoch_poll_ms = EPOCH_POLL_MS;
uint32_t delivery_timeout_ms = DELIVERY_TIMEOUT_MS;
Expand Down Expand Up @@ -924,8 +926,13 @@ signal<void(const opp::debugging::DebugEnvelopeEvent&)>& batch_operator_plugin::
void batch_operator_plugin::set_program_options(options_description& cli,
options_description& cfg) {
auto opts = cfg.add_options();
// Presence of this option IS the enable switch (mirrors producer_plugin's
// producer-name): the relay runs when an account is configured. Keying off
// the account rather than the plugin being listed matters because
// external_debugging_plugin declares this plugin as a dependency, which
// would otherwise silently promote a debug node to a batch operator.
opts("batch-operator-account", bpo::value<std::string>(),
"WIRE account name for this batch operator");
"WIRE account name for this batch operator. Configuring an account enables the relay.");
opts("batch-epoch-poll-ms", bpo::value<uint32_t>()->default_value(EPOCH_POLL_MS),
"How often to check epoch state (ms)");
// SIZING RULE for batch-delivery-timeout-ms: it bounds the WHOLE outbound
Expand All @@ -946,8 +953,6 @@ void batch_operator_plugin::set_program_options(options_description& cli,
// splits nodeop --help output on that token).
opts("batch-delivery-timeout-ms", bpo::value<uint32_t>()->default_value(DELIVERY_TIMEOUT_MS),
"Max time to wait for chain delivery confirmation (ms)");
opts("batch-enabled", bpo::value<bool>()->default_value(false),
"Enable batch operator functionality");
opts("batch-sol-client-id", bpo::value<std::string>()->default_value("sol-default"),
"Solana outpost client ID (RPC connection) for SVM outpost rows");
// Help text must not contain a " --" sequence (or non-ASCII): the
Expand All @@ -967,7 +972,7 @@ void batch_operator_plugin::plugin_initialize(const variables_map& options) {
_impl->operator_account = chain::name(options["batch-operator-account"].as<std::string>());
_impl->epoch_poll_ms = options["batch-epoch-poll-ms"].as<uint32_t>();
_impl->delivery_timeout_ms = options["batch-delivery-timeout-ms"].as<uint32_t>();
_impl->enabled = options["batch-enabled"].as<bool>();
_impl->enabled = _impl->operator_account.good();
_impl->sol_client_id = options["batch-sol-client-id"].as<std::string>();
if (options.count(batch_operator_detail::BATCH_OUTPOST_OPTION)) {
for (const auto& spec :
Expand Down Expand Up @@ -998,7 +1003,7 @@ void batch_operator_plugin::plugin_initialize(const variables_map& options) {

void batch_operator_plugin::plugin_startup() {
if (!_impl->enabled) {
ilog("batch_operator_plugin: disabled, skipping startup");
ilog("batch_operator_plugin: no batch-operator-account configured, skipping startup");
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,11 @@ BOOST_AUTO_TEST_CASE(plugin_options_are_registered) try {
BOOST_CHECK(option_names.count("batch-operator-account") > 0);
BOOST_CHECK(option_names.count("batch-epoch-poll-ms") > 0);
BOOST_CHECK(option_names.count("batch-delivery-timeout-ms") > 0);
BOOST_CHECK(option_names.count("batch-enabled") > 0);
BOOST_CHECK(option_names.count(sysio::batch_operator_detail::BATCH_OUTPOST_OPTION) > 0);
// Configuring batch-operator-account is what enables the relay. A separate
// enable flag would let an operator set the account and still relay nothing,
// which is indistinguishable from a healthy node until the group misses an epoch.
BOOST_CHECK(option_names.count("batch-enabled") == 0);
} FC_LOG_AND_RETHROW();

BOOST_AUTO_TEST_CASE(default_options_are_correct) try {
Expand All @@ -74,7 +77,8 @@ BOOST_AUTO_TEST_CASE(default_options_are_correct) try {

BOOST_CHECK_EQUAL(vm["batch-epoch-poll-ms"].as<uint32_t>(), 15000u);
BOOST_CHECK_EQUAL(vm["batch-delivery-timeout-ms"].as<uint32_t>(), 15000u);
BOOST_CHECK_EQUAL(vm["batch-enabled"].as<bool>(), false);
// No default account: an unconfigured node leaves the relay off.
BOOST_CHECK_EQUAL(vm.count("batch-operator-account"), 0u);
} FC_LOG_AND_RETHROW();

/// A normal push result invokes its callback and wakes the waiting relay job.
Expand Down
13 changes: 6 additions & 7 deletions plugins/underwriter_plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,9 @@ authenticated depot submitter.

| Option | Default | Description |
|---|---|---|
| `--underwriter-account` | — | WIRE account name for this underwriter |
| `--underwriter-account` | — | WIRE account name for this underwriter. Configuring it enables the scan cycle |
| `--underwriter-scan-interval-ms` | 5000 | How often to scan for pending uwreqs (ms) |
| `--underwriter-action-timeout-ms` | 15000 | Timeout for outpost RPC calls and table reads (ms) |
| `--underwriter-enabled` | false | Enable underwriter functionality |
| `--underwriter-eth-outpost` | — | Per-EVM-chain outpost wiring (repeatable, one per served EVM chain). Format `<chain_code>,<client_id>,<operator_registry_addr>,<source_deposit_contract_addr>` — keyed by exact `chain_code`, so two EVM chains are wired independently |
| `--underwriter-sol-outpost` | — | Per-SVM-chain outpost wiring (repeatable, one per served SVM chain). Format `<chain_code>,<client_id>,<opp_outpost_program_id>` |
| `--underwriter-eth-source-deposit-function` | — | Name of the ETH swap-deposit function; the chain-agnostic 4-byte selector is resolved at preflight from the loaded `--ethereum-abi-file` ABIs (required) |
Expand Down Expand Up @@ -195,10 +194,10 @@ completes they report the startup-gate state instead of the payload
`wiring_failed` / `startup_failed` with `detail`); once the gate opens
they serve the payloads above with `status: "active"`.

The endpoints are registered only when the underwriter is enabled:
with the plugin loaded but `--underwriter-enabled false` (the
default), `plugin_startup` skips endpoint registration and every
listener returns 404 for these routes.
The endpoints are registered only when the underwriter is enabled,
which means only when `--underwriter-account` is configured. With the
plugin loaded but no account, `plugin_startup` skips endpoint
registration and every listener returns 404 for these routes.

### Listener exposure

Expand All @@ -222,7 +221,7 @@ nodeop \
--http-server-address http-category-address \
--http-category-address underwriter,127.0.0.1:8890 \
--plugin sysio::underwriter_plugin \
--underwriter-enabled true \
--underwriter-account myuwriter \
...
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ namespace sysio {
namespace underwriter_defaults {
constexpr uint32_t scan_interval_ms = 5000;
constexpr uint32_t action_timeout_ms = 15000;
constexpr bool enabled = false;
// The sync-recency window moved to `controller::default_sync_recency_ms`
// — the sync predicate is `controller::is_synced()`, shared by every
// operator-daemon plugin.
Expand Down
14 changes: 8 additions & 6 deletions plugins/underwriter_plugin/src/underwriter_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,9 @@ struct outpost_endpoint {
struct underwriter_plugin::impl {
// Configuration
chain::name underwriter_account;
bool enabled = underwriter_defaults::enabled;
/// Derived from `underwriter_account` at plugin_initialize: the scan cycle
/// runs iff an account was configured. There is no separate enable flag.
bool enabled = false;
uint32_t scan_interval_ms = underwriter_defaults::scan_interval_ms;
uint32_t action_timeout_ms = underwriter_defaults::action_timeout_ms;
/// SEC-13/WSA-027: per-chain outpost wiring, keyed by EXACT `chain_code`
Expand Down Expand Up @@ -2796,14 +2798,14 @@ underwriter_plugin::~underwriter_plugin() = default;
void underwriter_plugin::set_program_options(options_description& cli,
options_description& cfg) {
auto opts = cfg.add_options();
// Presence of this option IS the enable switch (mirrors producer_plugin's
// producer-name): the scan cycle runs when an account is configured.
opts("underwriter-account", bpo::value<std::string>(),
"WIRE account name for this underwriter");
"WIRE account name for this underwriter. Configuring an account enables the scan cycle.");
opts("underwriter-scan-interval-ms", bpo::value<uint32_t>()->default_value(underwriter_defaults::scan_interval_ms),
"How often to scan for pending underwrite requests (ms)");
opts("underwriter-action-timeout-ms", bpo::value<uint32_t>()->default_value(underwriter_defaults::action_timeout_ms),
"Timeout for outpost contract calls and table reads (ms)");
opts("underwriter-enabled", bpo::value<bool>()->default_value(underwriter_defaults::enabled),
"Enable underwriter functionality");
opts("underwriter-eth-outpost",
bpo::value<std::vector<std::string>>()->composing(),
"Per-EVM-chain outpost wiring (repeatable, one per EVM chain served). Format: "
Expand Down Expand Up @@ -2842,7 +2844,7 @@ void underwriter_plugin::plugin_initialize(const variables_map& options) {
_impl->underwriter_account = chain::name(options["underwriter-account"].as<std::string>());
_impl->scan_interval_ms = options["underwriter-scan-interval-ms"].as<uint32_t>();
_impl->action_timeout_ms = options["underwriter-action-timeout-ms"].as<uint32_t>();
_impl->enabled = options["underwriter-enabled"].as<bool>();
_impl->enabled = _impl->underwriter_account.good();
// SEC-13/WSA-027: parse the repeatable per-chain outpost wiring into
// `outpost_endpoints`, keyed by EXACT chain_code. Each entry is a
// comma-separated `<chain_code>,<client_id>,<addr...>`.
Expand Down Expand Up @@ -2913,7 +2915,7 @@ void underwriter_plugin::plugin_initialize(const variables_map& options) {

void underwriter_plugin::plugin_startup() {
if (!_impl->enabled) {
ilog("underwriter_plugin: disabled, skipping startup");
ilog("underwriter_plugin: no underwriter-account configured, skipping startup");
return;
}

Expand Down
10 changes: 8 additions & 2 deletions plugins/underwriter_plugin/test/test_underwriter_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ namespace {
/// the option-surface test catch any future non-finality escape hatch.
constexpr std::string_view removed_eth_min_confirmations_option = "underwriter-eth-min-confirmations";

/// Removed enable flag. Configuring underwriter-account is what enables the
/// scan cycle; a separate flag would let an operator set the account and still
/// underwrite nothing, which is indistinguishable from a healthy node.
constexpr std::string_view removed_enabled_option = "underwriter-enabled";

/// Program id used by the scanner tests to model the configured opp-outpost.
const std::string test_sol_program_id = "OppOutpost11111111111111111111111111111111";

Expand Down Expand Up @@ -346,11 +351,11 @@ BOOST_AUTO_TEST_CASE(plugin_options_are_registered) try {
BOOST_CHECK(option_names.count("underwriter-account") > 0);
BOOST_CHECK(option_names.count("underwriter-scan-interval-ms") > 0);
BOOST_CHECK(option_names.count("underwriter-action-timeout-ms") > 0);
BOOST_CHECK(option_names.count("underwriter-enabled") > 0);
BOOST_CHECK(option_names.count("underwriter-eth-outpost") > 0);
BOOST_CHECK(option_names.count("underwriter-sol-outpost") > 0);
BOOST_CHECK(option_names.count(std::string{ETH_SOURCE_DEPOSIT_LOOKBACK_BLOCKS_OPTION}) > 0);
BOOST_CHECK_EQUAL(option_names.count(std::string{removed_eth_min_confirmations_option}), 0);
BOOST_CHECK_EQUAL(option_names.count(std::string{removed_enabled_option}), 0);
} FC_LOG_AND_RETHROW();

BOOST_AUTO_TEST_CASE(default_options_are_correct) try {
Expand All @@ -365,7 +370,8 @@ BOOST_AUTO_TEST_CASE(default_options_are_correct) try {

BOOST_CHECK_EQUAL(vm["underwriter-scan-interval-ms"].as<uint32_t>(), scan_interval_ms);
BOOST_CHECK_EQUAL(vm["underwriter-action-timeout-ms"].as<uint32_t>(), action_timeout_ms);
BOOST_CHECK_EQUAL(vm["underwriter-enabled"].as<bool>(), enabled);
// No default account: an unconfigured node leaves the scan cycle off.
BOOST_CHECK_EQUAL(vm.count("underwriter-account"), 0u);
// SEC-13/WSA-027: the former single --underwriter-{eth,sol}-client-id were
// replaced by repeatable per-chain --underwriter-{eth,sol}-outpost (no scalar
// default to assert; presence is checked in the option-registration case).
Expand Down
Loading