Skip to content

fix(chain-id): correct mainnet safety gates that missed Movement - #391

Open
apenzk wants to merge 7 commits into
m1from
test/network-detection-mainnet-gates
Open

fix(chain-id): correct mainnet safety gates that missed Movement#391
apenzk wants to merge 7 commits into
m1from
test/network-detection-mainnet-gates

Conversation

@apenzk

@apenzk apenzk commented Jul 6, 2026

Copy link
Copy Markdown

Description

Movement mainnet is configured like a devnet/localnet in some specific locations. ChainId::is_mainnet() / is_testnet() matched only the Aptos chain IDs (1 / 2). Network gates are written like this:

if chain_id.is_mainnet() {
    // strict: require auth, enforce verifiers, reject unstable bytecode, ...
} else {
    // relaxed: permitted (intended for devnet/localnet)
    // Movement mainnet currently falls in here !!!
}

On Movement's chains (mainnet 126 / testnet 250) is_mainnet() returned false, so every such gate took the else — the relaxed, dev-grade path — instead of the strict mainnet path.

The result: a set of production safety/hardening gates that were entirely inactive on Movement mainnet — it ran with dev-grade config leniency instead of mainnet hardening.

This PR makes is_mainnet() / is_testnet() (and the ChainId::mainnet() / testnet() helpers) resolve to Movement's chain IDs, so those gates fire on the correct chains.

Safety gates that are inactive on Movement mainnet but should be active

Gate Site What running on the relaxed branch means on Movement mainnet
Unstable bytecode publishable aptos_vm REJECT_UNSTABLE_BYTECODE (flag 58) is enabled on-chain but unenforced (gated on is_mainnet()), so unaudited, experimental VM/compiler features run on mainnet — a VM-soundness attack surface. This enforces the already-enabled flag.
Unauthenticated AdminService admin_service_config The node's admin/debug control service is auto-enabled and accepts requests with no authentication, so anyone able to reach the port can drive it. On mainnet it must be off or require auth.
In-memory validator keys / test safety-rules safety_rules_config A validator is allowed to keep its consensus signing key in memory (rather than a secure backend) and to run the test safety-rules service — both are meant to be rejected on mainnet.
Paranoid VM verifiers not enforced execution_config The extra runtime VM safety checks (paranoid_type_verification / paranoid_hot_potato_verification) are not required to be enabled, whereas mainnet mandates them.
Inspection endpoints exposed inspection_service_config The node serves its full configuration, peer topology, and system information over the inspection endpoints (info disclosure). Mainnet validators must not expose configuration.
Failpoints permitted api_config Failpoints are a testing hook that injects artificial faults (forced errors, panics, delays) at instrumented points in the running node. The sanitizer normally refuses to let a mainnet node enable them, since they could be used to crash or destabilize it. (Only reachable if the binary was built with the failpoints feature.)
consensus-only-perf-test permitted consensus_config A benchmarking-only consensus mode that bypasses normal consensus may be enabled. Mainnet forbids it.
Netbench permitted netbench_config The network benchmarking application (generates synthetic traffic) may be enabled. Mainnet/testnet forbid it.
Test keyless JWK in genesis vm-genesis (Low — genesis-time only.) When building a genesis, a test keyless issuer (with a publicly known test key) is added to the JWK set. Affects only how a new genesis is constructed, not live chain state — so this change fixes future genesis builds but does not alter Movement mainnet's existing state. Whether the current genesis was affected needs a separate check.
Confidential-asset allow list off confidential_asset (Move framework.) The allow list restricting which tokens are usable for confidential transfers was gated on chain_id == 1, so it never engaged on Movement mainnet (126). Fixed by pointing the constant at 126.

Replaced: hardcoded Aptos config values with Movement's

The node config optimizer injects hardcoded genesis-waypoints and seed peers into a node's config on mainnet/testnet. Those values were Aptos-specific and invalid for Movement, and — now that the predicates resolve to Movement chains — they would actively fire on Movement and inject wrong values. This PR keeps the injection paths (and their constants/helpers/tests) but replaces the values with Movement's seed peers and genesis waypoints (both at version 0), sourced from the movement-networks repo.

Removed: Aptos NamedChain::MAINNET / TESTNET

Following review, the NamedChain::MAINNET (1) and TESTNET (2) variants are dropped — chain IDs 1 / 2 stay valid as plain numeric IDs but no longer resolve to a named chain. from_str now accepts the movement_mainnet / movement_testnet strings that Display emits, so ChainId round-trips. This also fixes a faucet startup failure: default_value_t = ChainId::testnet() rendered as movement_testnet, which the parser could not read back (release builds errored when --chain-id was omitted; debug builds panicked on clap's default-value assertion).

Type of Change

  • Bug fix
  • Refactoring
  • Tests

Testing

Two gates get dedicated tests — the AdminService auth gate and the inspection-exposure gate. Each has three tests, one per case:

You can walk the chain-126 case through the commit history:

Step 1: prove the bug — the first commit adds the tests but not the fix:

git checkout c6cc85b2df
cargo test -p aptos-config

Two tests fail (admin_service_requires_auth_on_movement_mainnet, inspection_rejects_config_exposure_on_movement_mainnet) — the gates do not fire on Movement mainnet.

Step 2: the fix — check out the branch tip and rerun:

git checkout test/network-detection-mainnet-gates
cargo test -p aptos-config

Both now pass.

Related

apenzk added 3 commits July 3, 2026 13:57
- admin_service and inspection_service reject insecure config on mainnet;
  the Movement (126) cases fail today since is_mainnet() matches only
  Aptos chain id 1
- is_mainnet()/is_testnet() and ChainId::mainnet()/testnet() now resolve to
  Movement chain IDs (126/250); NamedChain discriminants unchanged
- remove unused is_movement_mainnet()/is_movement_testnet() (zero call sites;
  their only caller was refactored out previously)
- drop hardcoded Aptos genesis-waypoint and seed-peer injection from node
  config optimization
- update timed-features test to exercise Movement chains
- assert the mainnet hardening gate does NOT fire on chain 1 (accept
  instead of reject), since is_mainnet() no longer matches chain 1
- rename to *_treats_aptos_mainnet_as_non_production
@apenzk
apenzk requested review from areshand, rubujubi and seanyoung and removed request for Primata July 6, 2026 11:22
ganymedio added a commit that referenced this pull request Jul 6, 2026
#391 removes is_movement_mainnet()/is_movement_testnet() and repoints
is_mainnet()/is_testnet() at Movement's chain IDs, so the plain
predicates now select the Movement large_packages address.

@ganymedio ganymedio left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did a review for side effects of this change; could you check into this finding?

crates/aptos-faucet/core/src/funder/common.rs:82 — Faucet funder now fails at argument parsing.
default_value_t = ChainId::testnet() renders via Display as "movement_testnet", which ChainId::from_str can't parse back.
Verified with a runtime repro on the pinned clap 4.3.9: release builds error whenever --chain-id is omitted; debug builds panic at startup even when the flag is passed (clap's debug assertions validate the default unconditionally).
Root fix belongs in chain_id.rs: teach NamedChain::from_str the movement_mainnet/movement_testnet strings that Display emits.

@fEst1ck

fEst1ck commented Jul 6, 2026

Copy link
Copy Markdown

Can we get rid of the NamedChain::MAINNET and NamedChain::TESTNET altogether?


// Mainnet seed peers. Each seed peer entry is a tuple
// of (account address, public key, network address).
const MAINNET_SEED_PEERS: [(&str, &str, &str); 1] = [(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replace with the movement seed peers?

@apenzk apenzk Jul 13, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — swapped in the Movement mainnet/testnet seed peers (consensus.{mainnet,testnet}.movementnetwork.xyz).

const GENESIS_BLOB_FILENAME: &str = "genesis.blob";
const GENESIS_VERSION: u64 = 0;
const MAINNET_GENESIS_WAYPOINT: &str =
"0:6072b68a942aace147e0655c5704beaa255c84a7829baa4e72a500f1516584c4";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replace with movement values

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

- remove NamedChain::MAINNET (1) and TESTNET (2); IDs 1/2 stay valid numerically but the "mainnet"/"testnet" name strings no longer parse
- accept "movement_mainnet"/"movement_testnet" in from_str so parsing round-trips with Display
- drop the Aptos-specific timed-feature schedules keyed on the removed variants
- point confidential_asset MAINNET_CHAIN_ID at Movement mainnet (126) so the allow-list gate engages
@apenzk

apenzk commented Jul 13, 2026

Copy link
Copy Markdown
Author

Can we get rid of the NamedChain::MAINNET and NamedChain::TESTNET altogether?

@fEst1ck done in cd108b0 — removed both variants and updated/removed where they were used.

apenzk added 3 commits July 13, 2026 15:41
- restore the public-network seed injection and point MAINNET/TESTNET_SEED_PEERS at Movement's mainnet/testnet consensus fullnodes
- seeds are only added when the operator has not set any and the chain is Movement mainnet (126) or testnet (250)
- restore the genesis-waypoint injection and point MAINNET/TESTNET_GENESIS_WAYPOINT at Movement's mainnet (126) and testnet (250) values, both at genesis version 0
- cite the movement-networks repo as the source for the genesis waypoints and the seed peers
@apenzk
apenzk requested a review from areshand July 13, 2026 14:58
@apenzk

apenzk commented Jul 13, 2026

Copy link
Copy Markdown
Author

I did a review for side effects of this change; could you check into this finding?

crates/aptos-faucet/core/src/funder/common.rs:82 — Faucet funder now fails at argument parsing.
default_value_t = ChainId::testnet() renders via Display as "movement_testnet", which ChainId::from_str can't parse back.
Verified with a runtime repro on the pinned clap 4.3.9: release builds error whenever --chain-id is omitted; debug builds panic at startup even when the flag is passed (clap's debug assertions validate the default unconditionally).
Root fix belongs in chain_id.rs: teach NamedChain::from_str the movement_mainnet/movement_testnet strings that Display emits.

Thx @ganymedio — this is fixed in cd108b0: NamedChain::from_str now parses the movement_mainnet/movement_testnet strings that Display emits, so ChainId::testnet() round-trips.

Confirmed the debug-build repro is gone: aptos-faucet-cli --help builds cleanly and clap's default-value assertion passes.

@apenzk
apenzk requested a review from ganymedio July 13, 2026 15:05
@areshand

Copy link
Copy Markdown
Collaborator

this is too risky to rollout now until we have some mainnet testiing env.

@areshand

Copy link
Copy Markdown
Collaborator

approve it to proceed to testing phase

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants