Byzantine Fault Tolerant consensus node for the Certen Protocol -- orchestrating multi-layer cryptographic proof generation, cross-chain state anchoring, and validator attestation across 13 blockchain networks.
The Certen Independent Validator is a BFT consensus node that forms the backbone of the Certen Protocol network. It monitors the Accumulate blockchain for transaction intents, generates multi-layer cryptographic proofs binding account state to on-chain anchors, and coordinates with peer validators to produce aggregate attestations. Anchored state roots and proofs are submitted to target chains (EVM, Solana, Aptos, Sui, NEAR, TON, TRON) via chain-specific smart contracts, enabling trustless cross-chain verification.
Core functions:
- Intent Discovery: Polls the Accumulate network for
CERTEN_INTENTtransactions and routes them for proof generation - Multi-Layer Proof Generation: Produces a 9-phase proof cycle covering lite-client proofs (L1-L4), governance proofs (G0-G2), BLS aggregate signatures, and Ethereum anchoring
- BFT Consensus: Runs CometBFT consensus across the validator set, requiring 2/3+ honest participation
- Batch Management: Groups transactions into on-cadence (time-based) or on-demand (immediate) batches with Merkle root computation
- Cross-Chain Anchoring: Submits batch Merkle roots and comprehensive proofs to target chain smart contracts (EVM, Solana, Aptos, Sui, NEAR, TON, TRON)
- Attestation Collection: Broadcasts proof requests to peer validators and collects 2f+1 BLS/Ed25519 signatures
+------------------------------------------------------------------+
| Certen Independent Validator |
+------------------------------------------------------------------+
| |
| +------------------+ +------------------+ +---------------+ |
| | CometBFT | | Proof Cycle | | Attestation | |
| | Consensus | | Orchestrator | | Service | |
| +--------+---------+ +--------+---------+ +-------+-------+ |
| | | | |
| v v v |
| +------------------+ +------------------+ +---------------+ |
| | P2P Network | | Multi-Chain | | Peer | |
| | (26656/26657) | | Anchoring | | Validators | |
| +------------------+ +------------------+ +---------------+ |
| | | | |
| v v v |
| +------------------+ +------------------+ +---------------+ |
| | Intent | | Batch | | PostgreSQL | |
| | Discovery | | Processor | | Database | |
| +------------------+ +------------------+ +---------------+ |
| |
+------------------------------------------------------------------+
|
v
+------------------------------------------------------------------+
| External Services |
+------------------------------------------------------------------+
| - Accumulate Network (v3 API + CometBFT RPC) |
| - EVM Chains (Ethereum, Arbitrum, Optimism, Base, BSC, |
| Polygon, Moonbeam — all testnets) |
| - Non-EVM Chains (Solana, Aptos, Sui, NEAR, TON, TRON) |
| - CertenAnchor + BLSZKVerifier + AccountFactory contracts |
+------------------------------------------------------------------+
- BFT Consensus: CometBFT-based consensus with configurable validator sets (minimum 4, recommended 7+)
- 9-Phase Proof Cycle: Complete cryptographic proof pipeline from account state to Ethereum anchor
- Multi-Chain Anchoring: 13 target chains — EVM (Ethereum, Arbitrum, Optimism, Base, BSC, Polygon, Moonbeam) and non-EVM (Solana, Aptos, Sui, NEAR, TON, TRON)
- BLS Aggregate Signatures: Groth16 ZK-SNARK proofs for on-chain BLS12-381 verification
- Governance Proofs: Three-level governance verification (G0 inclusion, G1 correctness, G2 outcome binding)
- Two Settlement Classes:
on_cadenceamortises one anchor across many intents;on_demandsettles one intent per anchor with no period wait. See Proof Classes - REST API: Proof discovery, batch status, and ledger state endpoints
- Prometheus Metrics: Consensus height, proofs generated, gas usage, batch sizes
- Optional Firestore Sync: Real-time proof status updates for the web application
- Go 1.24+
- PostgreSQL 15+
- Ethereum RPC endpoint (Alchemy, Infura, or self-hosted)
- Accumulate network access (Kermit Testnet or Mainnet)
- Pre-generated BLS ZK keys (via included
bls-zk-setuptool)
# Clone repository
git clone https://github.com/certenIO/independant_validator.git
cd independant_validator
# Copy environment template
cp .env.example .env
# Edit .env with your configuration
# Build the validator binary
go build -o validator .
# Generate BLS ZK proving/verification keys (first time, ~5-10 minutes)
go run ./cmd/bls-zk-setup
# Start the validator
./validator# Install Go dependencies
go mod download
# Build all binaries
go build -o validator .
cd accumulate-lite-client-2/liteclient/proof/consolidated_governance-proof && go build -o govproof .
cd cmd/txhash && go build -o txhash .# Build image (includes BLS key generation)
docker build -t certen/validator .
# Run single validator
docker run -d \
--name certen-validator \
-p 8080:8080 \
-p 26656:26656 \
-p 26657:26657 \
--env-file .env \
certen/validator# Start the full 7-validator network with PostgreSQL
docker compose up -d
# Check logs
docker compose logs -f validator-1
# Stop
docker compose downThe included docker-compose.yml deploys a complete testnet:
| Service | HTTP | P2P | RPC |
|---|---|---|---|
| validator-1 | 8081 | 26656 | 26657 |
| validator-2 | 8082 | 26666 | 26667 |
| validator-3 | 8083 | 26676 | 26677 |
| validator-4 | 8084 | 26686 | 26687 |
| validator-5 | 8095 | 26696 | 26697 |
| validator-6 | 8086 | 26706 | 26707 |
| validator-7 | 8087 | 26716 | 26717 |
| postgres | - | - | 5432 |
| Variable | Required | Default | Description |
|---|---|---|---|
VALIDATOR_ID |
Yes | - | Unique validator identifier |
NETWORK_NAME |
No | testnet | Network name (devnet/kermit/mainnet) |
| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL |
Yes | - | PostgreSQL connection string |
DATABASE_MAX_CONNS |
No | 25 | Maximum connection pool size |
DATABASE_REQUIRED |
No | false | Fail startup if database unavailable |
| Variable | Required | Default | Description |
|---|---|---|---|
ACCUMULATE_URL |
Yes | - | Accumulate v3 API endpoint. Use the hostname over HTTPS — see below |
ACCUMULATE_COMET_DN |
No | - | Directory Network CometBFT RPC |
ACCUMULATE_COMET_BVN |
No | - | Block Validation Network CometBFT RPC |
| Variable | Required | Default | Description |
|---|---|---|---|
ETHEREUM_URL |
Yes | - | Ethereum RPC endpoint |
ETH_CHAIN_ID |
No | 11155111 | Chain ID (11155111 = Sepolia) |
ETH_PRIVATE_KEY |
Yes | - | Validator Ethereum signing key |
CERTEN_CONTRACT_ADDRESS |
Yes | - | Main anchor contract address |
CERTEN_ANCHOR_V3_ADDRESS |
No | - | CertenAnchorV3 contract address |
BLS_ZK_VERIFIER_ADDRESS |
No | - | BLSZKVerifier contract address |
ARBITRUM_SEPOLIA_RPC_URL |
No | - | Arbitrum Sepolia RPC |
OPTIMISM_SEPOLIA_RPC_URL |
No | - | Optimism Sepolia RPC |
BASE_SEPOLIA_RPC_URL |
No | - | Base Sepolia RPC |
| Variable | Required | Default | Description |
|---|---|---|---|
COMETBFT_ENABLED |
No | true | Enable CometBFT consensus |
COMETBFT_MODE |
No | validator | Node mode (validator/full) |
COMETBFT_CHAIN_ID |
No | certen-testnet | CometBFT chain ID |
COMETBFT_P2P_SEEDS |
No | - | Seed nodes (addr@host:port,...) |
COMETBFT_P2P_LADDR |
No | tcp://0.0.0.0:26656 | P2P listen address |
COMETBFT_RPC_LADDR |
No | tcp://0.0.0.0:26657 | RPC listen address |
| Variable | Required | Default | Description |
|---|---|---|---|
SOLANA_DEVNET_RPC_URL |
No | - | Solana Devnet RPC |
SOLANA_ANCHOR_PROGRAM_ID |
No | - | Solana anchor program address |
APTOS_TESTNET_RPC_URL |
No | - | Aptos Testnet RPC |
APTOS_ANCHOR_PACKAGE |
No | - | Aptos anchor package address |
SUI_TESTNET_RPC_URL |
No | - | Sui Testnet RPC |
SUI_ANCHOR_PACKAGE |
No | - | Sui anchor package address |
NEAR_TESTNET_RPC_URL |
No | - | NEAR Testnet RPC |
NEAR_ANCHOR_CONTRACT |
No | - | NEAR anchor contract ID |
TON_TESTNET_API_URL |
No | - | TON Center API endpoint |
TON_ANCHOR_CONTRACT |
No | - | TON anchor contract address |
TON_BLS_VERIFIER_CONTRACT |
No | - | TON BLS ZK verifier address |
TON_ACCOUNT_FACTORY_CONTRACT |
No | - | TON account factory address |
TRON_SHASTA_RPC_URL |
No | - | TRON Shasta JSON-RPC endpoint |
| Variable | Required | Default | Description |
|---|---|---|---|
ATTESTATION_PEERS |
Yes | - | Peer validator HTTP URLs (comma-separated) |
ATTESTATION_REQUIRED_COUNT |
No | 3 | Required attestation count (2f+1) |
See Proof Classes for what these control.
| Variable | Required | Default | Description |
|---|---|---|---|
BATCH_PERIOD_BLOCKS |
No | 100 | on_cadence period width, in Accumulate blocks (~1.43s each) |
BATCH_LEADER_VALIDATORS |
No | validator-1..7 | Roster used to elect the batch leader (comma-separated) |
ON_DEMAND_INTENT_KEYED |
No | false | true enables intent-keyed on_demand settlement. Off = on_demand uses the period path |
BATCH_MEMPOOL_PATH |
No | data/batch_mempool.json | Queue snapshot, so a restart resumes instead of stranding queued intents |
INTENT_REWIND_BLOCKS |
No | 600 | How far discovery rewinds on startup to re-derive in-flight intents |
BATCH_PERIOD_BLOCKSandBATCH_LEADER_VALIDATORSmust be IDENTICAL on every validator. Both feed thebundleId. A node configured differently derives a different batch from identical membership and can neither propose nor attest — it will refuse every peer's batch withconfig_mismatchand its own will be refused in turn.deploy/deploy-validators.shenforces that each appears exactly once in.env.shared.
ON_DEMAND_INTENT_KEYEDshould also be set uniformly, but a mismatch is degrading rather than breaking: a node without it simply never proposes on the on-demand lane. Do not enable it until every validator is running a binary that serves/api/batch/attestation/ondemand— nodes that answer 404 count as unreachable, and with 2/3-by-power required, three lagging nodes will block quorum.
| Variable | Required | Default | Description |
|---|---|---|---|
BLS_ZK_TESTING_MODE |
No | false | Use test mode for BLS ZK proofs |
BLS_ZK_KEYS_DIR |
No | /app/bls_zk_keys | Groth16 keys directory |
GOV_PROOF_CLI_PATH |
No | /app/govproof | Governance proof CLI binary path |
ENABLE_MERKLE_VERIFICATION |
No | true | Enable Merkle proof verification |
ENABLE_GOVERNANCE_VERIFICATION |
No | true | Enable governance proof verification |
ENABLE_BLS_VERIFICATION |
No | true | Enable BLS signature verification |
ENABLE_PARALLEL_VERIFICATION |
No | true | Enable parallel proof verification |
VERIFICATION_TIMEOUT |
No | 30s | Verification timeout duration |
| Variable | Required | Default | Description |
|---|---|---|---|
PROOF_CYCLE_WRITEBACK |
No | false | Write results back to Accumulate |
FIRESTORE_ENABLED |
No | false | Enable Firestore real-time sync |
FIREBASE_PROJECT_ID |
No | - | Firebase project ID |
GOOGLE_APPLICATION_CREDENTIALS |
No | - | Service account JSON path |
| Network | Accumulate v3 | CometBFT DN | CometBFT BVN |
|---|---|---|---|
| Kermit Testnet | https://kermit.accumulatenetwork.io/v3 |
http://162.217.96.196:16592 |
http://162.217.96.196:16692 |
| DevNet | http://localhost:26660/v3 |
http://localhost:16592 |
http://localhost:16692 |
| Mainnet | https://mainnet.accumulatenetwork.io/v3 |
Production endpoints | Production endpoints |
The two columns are addressed differently on purpose — do not "normalise" them.
ACCUMULATE_URLmust be the HOSTNAME over HTTPS. The TLS certificate is issued forkermit.accumulatenetwork.io(SAN also coverstestnet.accumulatenetwork.io), not for the IP, and plain HTTP on port 80 answers 301 → HTTPS. Go's HTTP client will not replay a POST body across a 301, so anhttp://endpoint fails every JSON-RPC call the moment that redirect is in place — while still looking reachable tocurland to a browser. Addressing the IP directly also returns nginx's own 404 (no server block matches a bare-IPHostheader), which reads like an upstream outage and is not one.This cost most of 2026-08-05:
ACCUMULATE_URLpointed athttp://<ip>:8660, that port stopped serving, discovery froze fleet-wide, and the misleading 404/301 responses sent the diagnosis down two wrong paths before the hostname was tried.CometBFT endpoints stay hardcoded IPv4:port. The proof pipeline queries DN and BVN consensus RPC directly for L3/L4 evidence. Those ports are plain HTTP, are not behind the TLS proxy, and are not served by the hostname — a hostname there would not resolve to a listening service.
The validator executes a 9-phase cryptographic proof cycle for each transaction:
| Phase | Layer | Name | Description |
|---|---|---|---|
| L1 | Account | State Proof | Merkle inclusion of account state in Binary Patricia Tree |
| L2 | Block | BPT Commitment | BPT root committed in block hash |
| L3 | Consensus | Validator Signatures | Validator set signatures on block |
| L4 | Genesis | Trust Chain | Validator set traced to genesis (future) |
| G0 | Governance | Inclusion | Transaction included in block |
| G1 | Governance | Correctness | Authority and key page validation |
| G2 | Governance | Outcome Binding | Transaction hash bound to intent |
| BLS | Aggregation | ZK Proof | Groth16 proof of BLS12-381 aggregate signature |
| Anchor | Target Chain | State Anchoring | Merkle root submitted to CertenAnchor contract on target chain |
Intent Discovery (poll Accumulate blocks)
|
v
Lite Client Proof Generation (L1-L4)
|
v
Governance Proof Generation (G0-G2)
|
v
CometBFT Consensus (2/3+ validators sign)
|
v
Route by proof_class ------------------------.
| |
| on_cadence | on_demand
v v
Period mempool Intent-keyed queue
(bucket by Accumulate height) (one intent = one batch)
| |
v v
Wait for period close + settle grace Settle immediately
| |
'---------------> Merkle root <------------'
|
v
createBatchAnchor on target chain
|
v
Attestation Collection (2/3+ by voting power)
|
v
BLS Aggregation + Groth16 ZK Proof
|
v
Per-member settlement (executeGovernanceProofDirect)
|
v
Phase 7-9 replay -> writeback to Accumulate
|
v
Proof Artifacts stored in PostgreSQL -> REST API
Every intent carries a proof class that decides how it is settled. The two classes are never interchangeable: they trade latency against gas, and an intent submitted as one must not be silently settled as the other.
on_demand |
on_cadence |
|
|---|---|---|
| Intent | Urgent, settle now | Routine, settle economically |
| Batch shape | One intent, one anchor | Many intents share one anchor |
| Waits for a period? | No | Yes — BATCH_PERIOD_BLOCKS (~143s at 100) |
| Settle grace | None (readiness retry) | 4 min, or 60s when alone in its period |
| Anchor gas | Paid in full, per intent | Amortised across members |
| Measured end-to-end | ~117s | ~192s |
Both classes use the same batch mechanism and the same contracts. on_demand is not a
separate code path — it is a batch of exactly one, which CertenAnchorV8_1.createBatchAnchor
supports as a first-class case ("N=1 is a legitimate batch: a one-leaf tree whose root equals
the leaf"). This matters because CertenAccountV7._authorizeLeaf computes only the
batch-form leaf, so an intent routed off the batch path entirely could never settle.
Set proof_class in the intent's intentData blob:
{
"kind": "CERTEN_INTENT",
"version": "2.0",
"intent_id": "…",
"proof_class": "on_demand",
"priority": "high"
}Resolution rules (pkg/consensus/intent.go, ExtractAndSetProofClass):
- If
proof_classis present, it is used verbatim. - If it is blank, the class is inferred from
priority:highorurgent→on_demand, anything else →on_cadence. - Any value other than
on_demandoron_cadenceis rejected — the intent is refused rather than defaulted.
Set it explicitly. Relying on the priority fallback means a change to an unrelated field can silently move an intent between settlement mechanisms.
on_cadence — the member is pooled by its Accumulate commit height into a period of
BATCH_PERIOD_BLOCKS. Once the period closes, the elected period leader waits out a settle
grace so peers can finish proving the period's other members, then forms one Merkle tree over
all of them. One createBatchAnchor and one BLS verification are amortised across the whole
batch — measured at 2.0–2.5 members per anchor on Sepolia.
The grace exists because membership is a set: a peer holding some but not all of a period's
members derives a different bundleId and cannot co-sign.
on_demand — the member is keyed by (chainID, operationID) and settled on its own. Its
entire on-chain identity is a pure function of the intent:
leaf = ComputeBatchLeaf(chainID, {ADIURL, ExecutionCommitment, OperationID})
root = leaf // N=1
bundle = keccak("certen:batchbundle:v1" | chainId | root | 1 | batchOpID | commitHeight)
Nothing in that derivation depends on what else a validator holds, so there is no member set to
agree on and no settle grace is needed. The leader attempts quorum immediately; peers that have
not finished processing the round answer member_not_held, and the leader retries on a short
backoff until they converge. Measured live: all seven validators enqueue within ~5 seconds and
answer a quorum request in ~0.5 seconds.
Enabled with ON_DEMAND_INTENT_KEYED=true. With the flag off, on_demand intents settle on
the period path — correct but slow, and the behaviour before this lane existed.
on_demand deliberately pays a whole anchor per intent. createAnchor +
executeComprehensiveProof are ~81% of an intent's gas, so amortising them is where essentially
all of on_cadence's saving lives. Use on_demand when latency is worth that premium, not by
default.
A multi-leg intent is still one member — leg count is orthogonal to proof class, and legs on one chain nest under a single multi-leg commitment. A multi-chain intent becomes one member per chain, each settling independently under its own anchor and its own leader.
| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Service health check with component status |
/health/ready |
GET | Kubernetes readiness probe |
/health/live |
GET | Kubernetes liveness probe |
Health response includes status of consensus, database, Ethereum, Accumulate, batch system, and proof cycle subsystems.
| Endpoint | Method | Description |
|---|---|---|
/api/v1/proofs/tx/{tx_hash} |
GET | Get proof by Accumulate transaction hash |
/api/v1/proofs/{proof_id} |
GET | Get proof by UUID |
/api/v1/proofs/batch/{batch_id} |
GET | Get all proofs in a batch |
| Endpoint | Method | Description |
|---|---|---|
/api/v1/batches |
GET | List all batches |
/api/v1/batches/{batch_id} |
GET | Get batch details with transactions |
Called by a batch leader asking peers to co-sign. Not public API — peers are reached over
the addresses in ATTESTATION_PEERS.
| Endpoint | Method | Description |
|---|---|---|
/api/batch/attestation/request |
POST | Co-sign an on_cadence period batch, keyed by (chain_id, cutoff_height, period_blocks) |
/api/batch/attestation/ondemand |
POST | Co-sign an on_demand one-member batch, keyed by (chain_id, operation_id) |
Both requests deliberately carry no member data — only a key to look one up, plus the
proposer's bundle_id for comparison. The peer rebuilds the batch from its own mempool and
signs only if its own derived bundleId matches. That independent reconstruction is the only
thing preventing a malicious proposer from having honest validators bless a root that drains an
ADI's account.
A refusal returns HTTP 200 with error and a machine-readable code:
| Code | Meaning | Retryable |
|---|---|---|
member_not_held |
Peer has not finished processing the round yet | Yes — the normal answer for the first seconds |
bundle_mismatch |
Peer holds it and derived a different bundleId |
No — a real disagreement |
config_mismatch |
Period width or chain differs between the nodes | No — operator must fix |
not_ready |
Peer's batch stack or attester identity is not up | Yes |
refused |
Anything else | No |
Match on code, never on the prose in error.
| Endpoint | Method | Description |
|---|---|---|
/api/v1/ledger/state |
GET | Current ledger state |
/api/v1/intents/{intent_id} |
GET | Intent details and processing status |
Standard CometBFT endpoints: /status, /net_info, /validators, /consensus_state, /abci_query
| Metric | Description |
|---|---|
validator_consensus_height |
Current consensus block height |
validator_proofs_generated_total |
Total proofs generated |
validator_batch_size_histogram |
Batch size distribution |
validator_ethereum_gas_used_total |
Cumulative gas spent on anchoring |
validator_attestations_collected |
Total attestation signatures |
The validator uses PostgreSQL with auto-applied migrations:
| Table | Description |
|---|---|
batches |
Transaction batches with type, Merkle root, and lifecycle status |
batch_transactions |
Transaction-to-batch mappings with Merkle indices |
proofs |
Generated proof artifacts with JSON proof data |
anchors |
Ethereum anchor records with confirmation tracking |
attestations |
Validator signatures (BLS/Ed25519) on proofs |
consensus_entries |
CometBFT block and commit history |
proof_artifacts |
Complete proof bundles with metadata |
Migrations are located in pkg/database/migrations/:
| Migration | Description |
|---|---|
001_initial_schema.sql |
Core tables |
002_add_intent_tracking.sql |
Intent metadata |
003_unified_multi_chain.sql |
Multi-chain support |
004_add_proof_detail_tables.sql |
Extended proof details |
005_intent_metadata.sql |
Intent tracking |
006_add_merkle_path.sql |
Merkle path storage |
./validator [--validator-id validator-1]Starts the complete validator node with all subsystems.
./govproof --level G0|G1|G2 \
--keypage acc://example.acme/page/1 \
acc://example.acme \
main \
<transaction_hash>Generates governance proofs with cryptographic verification against the Accumulate network.
go run ./cmd/bls-zk-setupGenerates Groth16 proving and verification keys for BLS12-381 signature verification. This is a one-time operation that takes approximately 5-10 minutes.
go run ./cmd/bls-key-info/main.goInspects and displays BLS key properties.
independant_validator/
├── main.go # Entry point and service orchestration
├── go.mod / go.sum # Go module dependencies
├── Dockerfile # Multi-stage production build
├── docker-compose.yml # 7-validator testnet deployment
├── .env.example # Environment variable template
├── accumulate-lite-client-2/ # Embedded Accumulate lite client
│ └── liteclient/
│ ├── proof/
│ │ └── consolidated_governance-proof/ # G0/G1/G2 proof CLI
│ └── api/ # Accumulate API client
├── cmd/
│ ├── bls-zk-setup/ # Groth16 key generation tool
│ ├── bls-key-info/ # BLS key inspection utility
│ └── generate-vk/ # Verification key generation
├── pkg/
│ ├── config/ # Configuration and .env loading
│ ├── database/ # PostgreSQL client, repositories, migrations
│ ├── consensus/ # CometBFT ABCI integration
│ ├── proof/ # Lite client proof generation
│ ├── anchor/ # Ethereum anchor management
│ ├── anchor_proof/ # Anchor proof types and operations
│ ├── batch/ # Transaction batching (collector, processor)
│ ├── execution/ # Proof cycle orchestrator
│ ├── verification/ # Unified proof verification engine
│ ├── attestation/ # Multi-validator attestation service
│ ├── intent/ # Intent discovery and routing
│ ├── accumulate/ # Accumulate network client
│ ├── ethereum/ # Ethereum RPC and contract bindings
│ ├── crypto/ # BLS12-381 and ZK-SNARK operations
│ ├── chain/ # Multi-chain execution strategies
│ │ └── strategy/ # Per-chain strategies (EVM, Solana, Aptos, Sui, NEAR, TON, TRON)
│ ├── merkle/ # Merkle tree construction and receipts
│ ├── ledger/ # Ledger state management
│ ├── metrics/ # Prometheus metrics
│ ├── server/ # HTTP API handlers
│ └── firestore/ # Optional Firestore real-time sync
├── scripts/ # Deployment and setup scripts (Node.js)
│ ├── setup_certen_identity_kermit.js
│ ├── submit_intent_kermit.js
│ └── register_validators.js
└── implementation-planning-doc/ # Architecture documentation
# Build validator
go build -o validator .
# Build all binaries
go build -o validator . && \
cd accumulate-lite-client-2/liteclient/proof/consolidated_governance-proof && \
go build -o govproof .# Unit tests
go test ./...
# With coverage
go test -cover ./...
# Specific package
go test -v ./pkg/batch/...
# Integration tests
go test -tags=integration ./...# Start PostgreSQL
docker run -d \
--name certen-postgres \
-e POSTGRES_USER=certen \
-e POSTGRES_PASSWORD=certen \
-e POSTGRES_DB=certen_validator \
-p 5432:5432 \
postgres:15-alpine
# Configure and run
export DATABASE_URL="postgres://certen:certen@localhost:5432/certen_validator?sslmode=disable"
export BLS_ZK_TESTING_MODE=true
go run .- Generate unique Ed25519 keys per validator
- Fund validator wallets with gas tokens on each target chain (ETH, SOL, APT, SUI, NEAR, TON)
- Pre-generate BLS ZK keys via
bls-zk-setup - Set
BLS_ZK_TESTING_MODE=falsefor production - Configure
ATTESTATION_PEERSwith all peer validator URLs - Use production Ethereum RPC endpoints
- Set strong PostgreSQL credentials
[Unit]
Description=Certen Independent Validator
After=network.target postgresql.service
[Service]
Type=simple
User=certen
WorkingDirectory=/opt/certen-validator
ExecStart=/opt/certen-validator/validator
Restart=always
RestartSec=10
EnvironmentFile=/opt/certen-validator/.env
[Install]
WantedBy=multi-user.target| Validators | Byzantine Tolerance | Consensus Threshold |
|---|---|---|
| 4 | 1 faulty | 3 of 4 |
| 7 | 2 faulty | 5 of 7 |
| 10 | 3 faulty | 7 of 10 |
Each validator requires its own Ethereum wallet, Ed25519 keypair, and BLS12-381 keys.
curl http://localhost:8080/healthReturns component-level status:
{
"status": "ok",
"consensus": "cometbft",
"database": "connected",
"ethereum": "connected",
"accumulate": "connected",
"batch_system": "active",
"proof_cycle": "active",
"uptime_seconds": 3600
}Metrics available at http://localhost:9090/metrics for integration with Grafana or other monitoring systems.
| Asset | Algorithm | Purpose |
|---|---|---|
| Ethereum Private Key | secp256k1 | Signs anchor transactions |
| BLS12-381 Keys | BLS | Signs aggregate proof attestations |
| Ed25519 Keys | Ed25519 | CometBFT consensus signing |
| Groth16 Keys | BN254 | ZK-SNARK proving/verification |
- Store private keys in environment variables, never in source control
- Use
sslmode=requirefor PostgreSQL connections in production - Restrict CometBFT P2P ports to known validator peers
- Monitor attestation counts for early detection of validator failures
- Enable all verification flags in production (
ENABLE_MERKLE_VERIFICATION,ENABLE_GOVERNANCE_VERIFICATION,ENABLE_BLS_VERIFICATION)
| Component | Repository | Description |
|---|---|---|
| Smart Contracts | certen-contracts |
EVM, Solana, Aptos, Sui, NEAR, TON, TRON contract suites |
| Independent Miner | independant_miner |
LXR proof-of-work audit nodes |
| Proofs Service | proofs_service |
Proof storage and retrieval API |
| API Bridge | api-bridge |
Accumulate integration REST API |
| Web App | certen-web-app |
User interface for ADI management |
| Key Vault | key-vault-signer |
Browser extension for transaction signing |
Copyright 2026 Certen Protocol. All rights reserved.