This program serves as a template for building decentralized consensus networks where multiple operators can collectively agree on shared state through:
- BLS signature aggregation: Efficient cryptographic proof of consensus
- Economic incentives: Fee distribution and slashing mechanisms
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Jito Restaking Infrastructure β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β NCN Program (Core Consensus Logic) β
β βββ Config Management β
β βββ Registry Management (Vaults & Operators) β
β βββ Epoch State Management β
β βββ Snapshot System β
β βββ BLS Voting System β
β βββ Account Lifecycle Management β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Client Libraries β
β βββ Rust Client (Auto-generated) β
β βββ JavaScript Client (Auto-generated) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β CLI Tools β
β βββ NCN Program CLI β
β βββ Keepr β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Testing & Integration β
β βββ Unit Tests β
β βββ Integration Tests β
β βββ Simulation Tests β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ncn-program-template-bls/
βββ π Program Core
β βββ program/ # Main Solana program entry point
β β βββ src/lib.rs # 21 instruction handlers (initializeβvoteβclose)
β β βββ src/*.rs # Individual instruction implementations
β βββ core/ # Shared core functionality
β βββ src/lib.rs # 24 core modules (crypto, accounts, utils)
β βββ schemes/ # BLS signature schemes (SHA256, normalized)
β βββ g1_point.rs # G1 elliptic curve operations
β βββ g2_point.rs # G2 elliptic curve operations
β βββ error.rs # 64 custom error types
β
βββ π§ Client SDKs
β βββ clients/rust/ # Auto-generated Rust client
β β βββ ncn_program/src/ # Generated account/instruction types
β βββ clients/js/ # Auto-generated JavaScript client
β βββ ncn_program/ # TypeScript definitions & helpers
β
βββ π οΈ CLI Tools
β βββ cli/ # Comprehensive CLI tooling
β βββ src/instructions.rs # CLI instruction wrappers
β βββ getting_started.md # CLI usage documentation
β βββ api-docs.md # Complete API reference
β
βββ π§ͺ Testing Infrastructure
β βββ integration_tests/
β βββ tests/fixtures/ # Test fixtures and programs
β βββ tests/ncn_program/ # 15+ comprehensive test modules
β βββ src/main.rs # Test harness entry point
β
βββ βοΈ Configuration & Scripts
β βββ .cargo/config.toml # Program ID environment variables
β βββ scripts/generate-clients.js # Client generation automation
β βββ format.sh # Code formatting and testing pipeline
β βββ generate_client.sh # Quick client regeneration
β βββ idl/ncn_program.json # Interface definition (2307 lines)
β
βββ π Documentation
βββ README.md # This comprehensive guide
βββ cli/getting_started.md # CLI quick start guide
βββ cli/api-docs.md # Complete API documentation
InitializeConfig
: Creates program configuration with consensus parametersInitializeVaultRegistry
: Sets up vault tracking systemRegisterVault
: Adds vaults to the registry (permissionless after handshake)InitializeOperatorRegistry
: Creates operator tracking systemRegisterOperator
: Adds operators with BLS public keysUpdateOperatorBN128Keys
: Updates operator cryptographic keysReallocOperatorRegistry
: Expands operator storage capacityInitializeEpochSnapshot
: Creates immutable epoch state snapshotReallocEpochSnapshot
: Expands snapshot storageInitializeOperatorSnapshot
: Captures individual operator state
InitializeEpochState
: Creates new epoch with voting parametersInitializeWeightTable
: Sets up stake weight calculationsSetEpochWeights
: Finalizes voting weights for the epochSnapshotVaultOperatorDelegation
: Records delegation relationships
CastVote
: Submits BLS aggregated signatures for consensus
AdminSetParameters
: Updates consensus parametersAdminSetNewAdmin
: Changes administrative rolesAdminSetWeight
: Manually adjusts stake weightsAdminRegisterStMint
: Adds supported stake token mintsAdminSetStMint
: Updates stake token configurations
CloseEpochAccount
: Reclaims rent from finalized accounts
pub struct Config {
ncn: Pubkey, // NCN identifier
tie_breaker_admin: Pubkey, // Admin for tie-breaking votes
valid_slots_after_consensus: PodU64, // Voting window after consensus
epochs_before_stall: PodU64, // Epochs before system stalls
epochs_after_consensus_before_close: PodU64, // Cleanup timing
starting_valid_epoch: PodU64, // First valid epoch
fee_config: FeeConfig, // Fee distribution settings
minimum_stake_weight: StakeWeights, // Minimum participation threshold
}
pub struct EpochState {
ncn: Pubkey, // NCN reference
epoch: PodU64, // Epoch number
vault_count: PodU64, // Number of participating vaults
account_status: EpochAccountStatus, // State machine status
set_weight_progress: Progress, // Weight setting progress
operator_snapshot_progress: [Progress; 256], // Per-operator progress
is_closing: PodBool, // Cleanup flag
}
pub struct EpochSnapshot {
ncn: Pubkey, // NCN reference
epoch: PodU64, // Epoch number
operator_count: PodU64, // Total operators
operators_registered: PodU64, // Active operators
operators_can_vote_count: PodU64, // Eligible voters
total_agg_g1_pubkey: [u8; 32], // Aggregated public key
operator_snapshots: [OperatorSnapshot; 256], // Operator states
minimum_stake_weight: StakeWeights, // Participation threshold
}
pub struct OperatorRegistry {
ncn: Pubkey, // NCN reference
operator_list: [OperatorEntry; 256], // Operator data array
}
pub struct OperatorEntry {
operator_pubkey: Pubkey, // Operator identifier
g1_pubkey: [u8; 32], // BLS G1 public key
g2_pubkey: [u8; 64], // BLS G2 public key
operator_index: PodU64, // Registry index
slot_registered: PodU64, // Registration timestamp
}
pub struct VaultRegistry {
ncn: Pubkey, // NCN reference
st_mint_list: [StMintEntry; 1], // Supported stake tokens
vault_list: [VaultEntry; 1], // Registered vaults
}
pub struct WeightTable {
ncn: Pubkey, // NCN reference
epoch: PodU64, // Target epoch
vault_count: PodU64, // Number of vaults
table: [WeightEntry; 1], // Weight entries per vault
}
The system uses the BN254 (alt_bn128) elliptic curve for BLS signatures:
- G1 Points: 32-byte compressed format for signatures
- G2 Points: 64-byte compressed format for public keys
- Pairing Operations: Verification through bilinear pairings
Located in core/src/schemes/
:
Sha256Normalized
: Standard SHA-256 based message hashingtraits.rs
: Generic signing/verification interfaces
- Private keys: 32-byte scalars for signature generation
- G1 Public keys: For signature aggregation
- G2 Public keys: For verification operations
- Signature verification: Uses Solana's alt_bn128 precompiles
1. Admin creates Config with consensus parameters
2. Initialize VaultRegistry for supported tokens
3. Initialize OperatorRegistry for participant tracking
4. Register supported stake token mints with weights
5. Register vaults (permissionless after NCN approval)
6. Register operators with BLS keypairs
7. Create EpochSnapshot: mutable state checkpoint
8. Initialize operator snapshots for each participant
1. Create EpochState for new consensus round
2. Initialize WeightTable with current vault count
3. SetEpochWeights: Calculate voting power per vault
4. Snapshot vault-operator delegations
1. Operators generate BLS signatures on consensus data
2. Signatures are aggregated off-chain
3. CastVote instruction submits aggregated signature
4. Program verifies signature against operator set
6. Consensus reached at 66% threshold
1. Wait for epochs_after_consensus_before_close epochs
2. CloseEpochAccount reclaims rent from old accounts
3. Fee distribution to stakeholders
4. Prepare for next epoch cycle
-
Admin Commands: Configuration management
admin-create-config
: Initialize program parametersadmin-register-st-mint
: Add supported tokensadmin-set-parameters
: Update consensus settings
-
Crank Functions: State maintenance
crank-register-vaults
: Register pending vaultscrank-close-epoch-accounts
: Cleanup finalized epochs
-
Instructions: Core program interactions
create-epoch-state
: Start new epochcast-vote
: Submit consensus votessnapshot-vault-operator-delegation
: Capture delegations
-
Getters: State queries
- Query any on-chain account state
- Inspect epoch progress and voting status
The keeper automates epoch management through state transitions:
- SetWeight: Establish stake weights for epoch
- Snapshot: Capture operator and vault states
- Vote: Monitor and process consensus votes
- PostVoteCooldown: Wait period after consensus
- Distribute: Reward distribution to stakeholders
- Close: Account cleanup and rent reclamation
- Loop timeout: 10 minutes (configurable)
- Error timeout: 10 seconds
- Automatic state progression
- Error recovery and retry logic
Manages operator-specific functionality:
- BLS key generation and management
- Vote preparation and submission
- Delegation monitoring
- Reward claiming
simulation_test.rs
: Complete end-to-end consensus workflowinitialize_config.rs
: Configuration testingregister_operator.rs
: Operator registration flowscast_vote.rs
: Voting mechanism testingepoch_state.rs
: Epoch lifecycle management
The test_builder.rs
provides a comprehensive testing framework:
let mut fixture = TestBuilder::new().await;
fixture.initialize_restaking_and_vault_programs().await?;
fixture.create_test_ncn().await?;
fixture.add_vaults_to_test_ncn(&mut test_ncn, 1, Some(mint_keypair)).await?;
The main simulation test demonstrates:
- Setting up 13 test operators with BLS keypairs
- Creating vault-operator delegations
- Running complete epoch consensus cycle
- BLS signature aggregation and verification
- Consensus achievement and cleanup
- Pre-built program binaries in
integration_tests/tests/fixtures/
- Mock restaking and vault programs
- Pre-generated keypairs and test data
- Configurable test scenarios
The local-test-validator/
submodule provides a complete testing environment that automatically sets up the Jito Restaking Protocol with all dependencies. This is the fastest way to get a working development environment.
# Navigate to the local test validator directory
cd local-test-validator
# Make scripts executable
chmod +x *.sh
# Run the complete setup (one command does everything)
./run.sh
This single command will:
- Start Solana test validator with pre-loaded programs
- Initialize the complete restaking network
- Set up 3 operators with proper handshakes
- Create a vault and delegate tokens
- Advance validator by epochs for connection warm-up
The local test validator provides:
- Pre-built Programs: Jito restaking, vault, and SPL programs
- Automated Setup: Complete network initialization script
- Test Operators: 3 pre-configured operators with BLS keypairs
- Time Simulation: Scripts to advance validator time for epoch testing
- Clean State: Fresh ledger on each run with
--reset
run.sh
: Main orchestration script that sets up everythingvalidator.sh
: Starts Solana test validator with required programssetup-testing-env.sh
: Initializes the complete restaking networkrerun-validator.sh
: Advances validator time for epoch testing
After setup, you'll have:
- Keypairs: NCN admin, vault admin, operator admins in
./keys/
- Addresses: All important addresses saved in
setup_summary.txt
For detailed setup instructions and troubleshooting, see the local-test-validator README.
# Build all workspace components
cargo build --release
# Build Solana program
cargo build-sbf --manifest-path program/Cargo.toml
# Install CLI tools
cargo install --path ./cli --bin ncn-program-bls-cli --locked
# 1. Build shank CLI for IDL generation
cargo b && ./target/debug/ncn-program-shank-cli
# 2. Install Node.js dependencies
yarn install
# 3. Generate Rust and JavaScript clients
yarn generate-clients
# 4. Rebuild with new clients
cargo b
Set up environment variables in .env
or shell:
export RPC_URL=http://127.0.0.1:8899
export COMMITMENT="confirmed"
export NCN_PROGRAM_ID="3fKQSi6VzzDUJSmeksS8qK6RB3Gs3UoZWtsQD3xagy45"
export RESTAKING_PROGRAM_ID="RestkWeAVL8fRGgzhfeoqFhsqKRchg6aa1XrcH96z4Q"
export VAULT_PROGRAM_ID="Vau1t6sLNxnzB7ZDsef8TLbPLfyZMYXH8WTNqUdm9g8"
export KEYPAIR_PATH="~/.config/solana/id.json"
# Create buffer account
solana-keygen new -o target/tmp/buffer.json
# Deploy program
solana program deploy --use-rpc --buffer target/tmp/buffer.json \
--with-compute-unit-price 10000 --max-sign-attempts 10000 \
target/deploy/ncn_program.so
# Upgrade existing program
solana program write-buffer --use-rpc --buffer target/tmp/buffer.json \
--with-compute-unit-price 10000 --max-sign-attempts 10000 \
target/deploy/ncn_program.so
solana program upgrade $(solana address --keypair target/tmp/buffer.json) \
$(solana address --keypair target/deploy/ncn_program-keypair.json)
# Clean up buffers
solana program close --buffers
- BLS Signature Verification: Cryptographic proof of operator consensus
- Minimum Stake-weighted Voting: Economic security through skin-in-the-game
- Time-locked Operations: Prevents hasty state changes
- Role-based Access Control: Admin separation and permissions
- Account Rent Protection: Economic incentives for proper cleanup
- Key Management: BLS private keys must be securely stored
- Maximum Operators: 256 operators per NCN
- Maximum Vaults: Currently limited to 1 vault per registry
- Signature Verification: On-chain BLS verification costs
- Storage Costs: Large account sizes for snapshots
- Compute Units: Complex cryptographic operations
- Split Operator_Registry into multiple accounts, one PDA per operator to be able to add as much metadata as needed.
- You should only init the epoch_snapshot account once, but to do that the first time you will need to init the epoch_state and the weight_table first, So consider uncoupling the epoch_snapshot account from the epoch_state account and the weight_table account.
- instead of having two Instuctions (
ResgiterOperator
andInitOperatorSnapshot
) they could be only one - registering an operators now is being done using two pairing equations, it could all be done by only one by merging the two equations.
- Remove weight table since it is only one vault, no need to init and set weights every epoch.
- since it is only one vault, the vault registry is not needed, consider removing it.
- you can't update the operator snapshots when a new epoch comes before creating the epoch state account first, consider removing it or merging it with the epoch_snapshot account.
- CLI: run-keeper command is not going to work well, it need to change a bit, it will try to init an epoch_snapshot every epoch, but it should not, epoch_snapshot account init should happen only once at the start of the NCN
- CLI: Vote command need to be re-written in a way that supports multi-sig aggregation.
- CLI: registering and operator now will give random G1, G2 pubkeys and a random BN128 privkey, it will log these keys to a file, but you might want to consider giving the operator the options to pass them as params
- CLI: crank-update-all-vaults are updating
- Build the program and the cli:
cargo build-sbf
- Deploy the program:
solana program deploy --program-id ./ncn_program-keypair.json target/deploy/ncn_program.so
-
build and Configure the CLI: refer to the cli/getting_started.md file for more details
-
Configure the NCN program:
# Fund the payer account with 20 SOL for transaction fees
./target/debug/ncn-program-bls-cli admin-fund-account-payer --amount-in-sol 20
sleep 2
# Create and initialize the NCN program configuration with fee wallet, fee bps, consensus slots, and minimum stake weight
./target/debug/ncn-program-bls-cli admin-create-config --ncn-fee-wallet 3ogGQ7nFX6nCa9bkkZ6hwud6VaEQCekCCmNj6ZoWh8MF --ncn-fee-bps 100 --valid-slots-after-consensus 10000 --minimum-stake-weight 100
sleep 2
# Create the vault registry to track supported stake vaults
./target/debug/ncn-program-bls-cli create-vault-registry
sleep 2
# Register vaults that are pending approval and add them to the registry
./target/debug/ncn-program-bls-cli crank-register-vaults
sleep 2
# Register a supported stake token mint and set its weight
./target/debug/ncn-program-bls-cli admin-register-st-mint --weight 10
sleep 2
# Create the operator registry to track BLS operators
./target/debug/ncn-program-bls-cli create-operator-registry
- Register all the Operators: Repeat the command for all operators
./target/debug/ncn-program-bls-cli register-operator --operator <Operator Pubkey> --keypair-path <operator-admin-keypair>
sleep 2
- init the epoch_snapshot account: Notice that for now you will need to init the epoch_state and the weight table before initing the epoch_snapshot, but this should change later
./target/debug/ncn-program-bls-cli create-epoch-state
sleep 2
./target/debug/ncn-program-bls-cli create-weight-table
sleep 2
./target/debug/ncn-program-bls-cli set-epoch-weights
sleep 2
./target/debug/ncn-program-bls-cli create-epoch-snapshot
- init the operator_snapshot for each operator:
./target/debug/ncn-program-bls-cli create-operator-snapshot --operator <Operator Pubkey>
- Snapshot the vault-operator delegations: and to do so, you will need to make sure that the vault are up to date first:
./target/debug/ncn-program-bls-cli full-update-vault
sleep 2
./target/debug/ncn-program-bls-cli snapshot-vault-operator-delegation --operator <Operator Pubkey>