Validators on Sigil come in two roles: block producers propose blocks during their slot; block validators vote in the MACA finality rounds. Both roles require a stake bond, an OAS DID, and a registered consensus key. This recipe walks through the on-chain side. For the node-operator playbook (hardware, networking, snapshots, monitoring) see Operate → Run a validator.

When to use this

  • You want to validate on mainnet, the Evolve canary, or a private testnet.
  • You’re running an organisation-internal block producer for a permissioned zone.

Prerequisites

  • A funded controller DID with at least the network’s min_block_validator_self_bond (or min_block_producer_self_bond) in MINT.
  • A registered identity NFT (issued via the Genesis Ceremony or RegisterIdentity + identity collection).
Query the current bonding minimums:
curl -s "$SIGIL_RPC_URL" -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"sigil_getNetworkActivationStatus","params":{}}'

Recipe

1

Generate validator keys

Use the CLI to derive a fresh consensus keypair. The keys are written under --data-dir.
sigil-cli validator generate-keys \
  --did did:oas:sigil:agent:my-validator-1 \
  --data-dir ~/.sigil
Back up ~/.sigil/keys/validator.key — losing it means rebonding from scratch.
2

Bond stake

Use the SDK’s TransactionBuilder::stake to bond. mode is "validator" for a block validator and "producer" for a block producer.
use sigil_sdk::{TransactionBuilder, sign_transaction};

let tx = TransactionBuilder::new(&chain_id, &sender_did)
    .nonce(current_nonce)
    .stake(10_000_000_000, "validator")?;  // 10,000 MINT
let signed = sign_transaction(tx, &signing_key)?;
Or via CLI:
sigil-cli stake deposit 10000000000 --mode validator
3

Register on-chain

validator register submits a ValidatorRegister transaction that ties your stake to the consensus key and the human-root DID for lineage verification.
sigil-cli validator register \
  --did did:oas:sigil:agent:my-validator-1 \
  --stake 10000000000 \
  --mode validator \
  --human-root did:oas:sigil:hmr:my-name
Verify acceptance:
sigil-cli query validator did:oas:sigil:agent:my-validator-1
The response includes the validator’s stake, mode, status (pending until the next epoch boundary, then active), and last-attested slot.
4

Start the node

See Operate → Run a validator for the full launch procedure. Minimum invocation:
sigil-cli node start \
  --config /etc/sigil/config.toml \
  --mode validator \
  --data-dir ~/.sigil \
  --validator-did did:oas:sigil:agent:my-validator-1
Watch sync progress:
sigil-cli node status
5

Claim rewards

Rewards accrue per epoch and are claimable any time once eligible.
let tx = TransactionBuilder::new(&chain_id, &validator_did)
    .nonce(current_nonce)
    .claim_rewards();
let signed = sign_transaction(tx, &signing_key)?;
Or via CLI:
sigil-cli stake rewards          # show outstanding rewards
6

Unbond (when exiting)

Unbonding starts a chain-defined cooldown — typically two epochs. Funds remain illiquid until the cooldown completes.
let tx = TransactionBuilder::new(&chain_id, &validator_did)
    .nonce(current_nonce)
    .unstake(10_000_000_000);
Or via CLI:
sigil-cli stake withdraw 10000000000

Inspecting validator state

# Full validator set
curl -s "$SIGIL_RPC_URL" -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"sigil_getValidatorSet","params":{}}'

# Tower's finality view
curl -s "$SIGIL_RPC_URL" -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tower_getValidator",
       "params":{"did":"did:oas:sigil:agent:my-validator-1"}}'

Common errors

SymptomCauseFix
stake below minimumBonded below min_block_validator_self_bondBond more, or pick --mode producer if its floor is lower
lineage verification failed--human-root not in your DID’s HMR chainRe-export the lineage proof; match the HMR shown in gal_getHmr
consensus key already registeredReused a key across validatorsGenerate a new key with validator generate-keys
validator status pending past one epochThe chain has not crossed an epoch boundary since registrationWait one full epoch; query current_epoch

See also