Validator Registration Flow
How adding a validator to an Avalanche L1 actually works: two L1 transactions, one P-Chain transaction, and two signature aggregations.
Add a validator.
STEP 01 / 06 · EVM TX
Initiate registration on the L1
The operator calls initiateValidatorRegistration on the ValidatorManager with the new node's NodeID, BLS public key, and weight. The contract emits an L1-sourced RegisterL1ValidatorMessage through the Warp precompile.
Run the whole flow in code
The six steps above are one call in the Avalanche TypeScript SDK: registerL1Validator from @avalanche-sdk/interchain orchestrates both L1 transactions, the two BLS signature rounds, and the P-Chain submission end to end. The package is early (0.1.x alpha), so pin your version.
npm install @avalanche-sdk/interchainimport { registerL1Validator } from "@avalanche-sdk/interchain/validator-manager";
const result = await registerL1Validator(walletClient, publicClient, {
validatorManagerAddress,
networkId,
subnetId,
validator, // NodeID, BLS public key, weight
aggregateSignatures, // steps 02 + 05: the BLS signature rounds
getBlsProofOfPossession,
submitPChainRegisterTx, // step 03: RegisterL1ValidatorTx
onProgress,
});The six steps at a glance
The interactive explainer above is the narration; this table is the quick reference.
| # | Step | Who acts | What moves |
|---|---|---|---|
| 01 | Initiate registration on the L1 | Operator, ValidatorManager | EVM tx: initiateValidatorRegistration emits the L1-sourced Warp message |
| 02 | Validators sign the L1 message | Validator set, aggregator | BLS signatures to 67% of total weight |
| 03 | Submit RegisterL1ValidatorTx | Aggregator, P-Chain | P-Chain tx; the P-Chain assigns a validationID |
| 04 | The P-Chain acknowledges | P-Chain | Nothing: the registration becomes a P-Chain fact |
| 05 | Validators sign the P-Chain message | Validator set, aggregator, P-Chain | BLS signatures over the P-Chain-sourced message |
| 06 | Complete registration on the L1 | Aggregator, ValidatorManager, operator | The signed message rides the completion tx's access list |
When registration goes wrong
Every failure below is real: each one has occurred in production support cases.
requirePrimaryNetworkSigners
Some L1s set requirePrimaryNetworkSigners in their Warp configuration, which normally routes message verification to the primary network validator set. P-Chain-sourced messages are exempt in Subnet-EVM v0.8.0 and later, so validator registration completion is verified by the L1's own validator set either way.
Appendix: anatomy of the completion message
The P-Chain-sourced L1ValidatorRegistrationMessage that completes a registration is 95 bytes on the wire:
| Offset | Size | Field | Example value |
|---|---|---|---|
| 0 | 2 | Codec version | 0x0000 |
| 2 | 4 | Network ID | 0x00000001 (Mainnet) |
| 6 | 32 | Source chain ID | 32 zero bytes (the P-Chain) |
| 38 | 4 | Payload length | 0x00000035 (53) |
| 42 | 53 | AddressedCall payload | see below |
The 53-byte AddressedCall wraps the inner message: codec 0x0000, type ID 0x00000001, an empty source address (0x00000000), a payload length of 39, and finally the 39-byte L1ValidatorRegistration itself: codec 0x0000, type ID 0x00000002, the 32-byte validationID, and one registered flag byte (0x01).
Related
Add a validator in the Builder Console
The live tool that performs this whole flow.
Academy: validator manager operations
Course lessons and demos for add, weight change, and removal.
Validator Manager contracts
Contract reference for ACP-99 managers.
Validator Manager SDK (TypeScript)
registerL1Validator and the per-step building blocks in @avalanche-sdk/interchain.
Is this guide helpful?