This document covers the code organization, build system, testing strategy, and common development tasks for the Independent Validator.
independant_validator/
├── main.go # Entry point, ABCI app bootstrap
├── go.mod / go.sum # Go module dependencies
├── .env.example # Configuration template
├── docker-compose.yml # 7-validator testnet setup
├── Dockerfile # Production container image
├── Makefile # Build, test, lint targets
├── scripts/
│ ├── init-testnet.sh # Generate testnet configuration
│ └── migrate.sh # Database migration helper
├── cmd/
│ └── migrate/ # Migration CLI tool
│ └── main.go
├── pkg/
│ ├── config/ # Environment-based configuration
│ │ └── config.go
│ ├── database/
│ │ ├── database.go # Connection pool, factory
│ │ ├── migrations/ # SQL migration files (001-007)
│ │ ├── batch_repo.go # Batch CRUD operations
│ │ ├── proof_repo.go # Proof CRUD operations
│ │ ├── anchor_repo.go # Anchor record CRUD
│ │ ├── attestation_repo.go # Attestation CRUD
│ │ └── intent_repo.go # Intent tracking CRUD
│ ├── consensus/
│ │ ├── app.go # ABCI Application implementation
│ │ ├── prepare.go # PrepareProposal handler
│ │ ├── process.go # ProcessProposal handler
│ │ └── finalize.go # FinalizeBlock handler
│ ├── proof/
│ │ ├── engine.go # Proof cycle orchestrator
│ │ ├── phases.go # L1-L4 Merkle proof phases
│ │ ├── governance.go # G0-G2 governance phases
│ │ └── bls.go # BLS aggregation + ZK proof
│ ├── anchor/
│ │ ├── manager.go # Anchor submission orchestrator
│ │ └── tracker.go # Confirmation tracking
│ ├── batch/
│ │ ├── scheduler.go # Batch scheduling logic
│ │ └── manager.go # Batch lifecycle management
│ ├── execution/
│ │ ├── scanner.go # Intent detection on Accumulate
│ │ └── executor.go # Intent validation and queueing
│ ├── verification/
│ │ └── verifier.go # Proof verification logic
│ ├── attestation/
│ │ └── handler.go # Attestation collection
│ ├── intent/
│ │ ├── parser.go # 4-blob intent parsing
│ │ └── validator.go # Intent format validation
│ ├── crypto/
│ │ ├── bls.go # BLS12-381 operations
│ │ ├── ed25519.go # Ed25519 signing
│ │ ├── circuit.go # gnark Groth16 circuit
│ │ └── keys.go # Key loading, generation
│ ├── chain/
│ │ ├── strategy.go # ChainStrategy interface
│ │ ├── registry.go # Chain registration
│ │ └── strategy/
│ │ ├── evm_base.go # Shared EVM logic
│ │ ├── ethereum.go # Ethereum-specific
│ │ ├── arbitrum.go
│ │ ├── optimism.go
│ │ ├── base.go
│ │ ├── polygon.go
│ │ ├── avalanche.go
│ │ ├── bsc.go
│ │ ├── solana.go
│ │ ├── cosmos.go
│ │ ├── aptos.go
│ │ ├── sui.go
│ │ ├── near.go
│ │ └── tron.go
│ ├── merkle/
│ │ ├── tree.go # Merkle tree construction
│ │ └── proof.go # Inclusion proof generation
│ ├── server/
│ │ ├── server.go # HTTP server setup
│ │ ├── health.go # Health endpoint
│ │ └── metrics.go # Prometheus metrics
│ └── firestore/
│ └── client.go # Firestore sync client
└── test/
├── integration/ # Integration tests
└── fixtures/ # Test data files
# Build
go build -o bin/validator ./main.go
# or
make build
# Run tests
go test ./...
# or
make test
# Run tests with coverage
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
# Lint
golangci-lint run
# or
make lint
# Format
gofumpt -w .
# or
make fmt
# Run all checks (format, lint, test)
make checkIf the proof cycle needs an additional phase (e.g., a new governance layer):
- Define the phase type and output structure in
pkg/proof/:
// pkg/proof/phases.go
type NewPhaseProof struct {
Data []byte
ProofPath [][]byte
Root []byte
}- Implement the phase execution in the proof engine:
// pkg/proof/engine.go
func (e *ProofEngine) executeNewPhase(ctx context.Context, batch *Batch) (*NewPhaseProof, error) {
// Query Accumulate for required data
// Construct Merkle proof
// Return proof structure
}- Add the phase to the proof cycle sequence in
engine.go - Update the proof bundle format in
pkg/proof/to include the new phase - Add database storage for the new proof type (new migration + repository method)
- Update verification logic in
pkg/verification/verifier.go - Add tests for the new phase
- Create a new strategy file in
pkg/chain/strategy/:
// pkg/chain/strategy/newchain.go
type NewChainStrategy struct {
rpcClient *rpc.Client
config ChainConfig
}
func NewNewChainStrategy(cfg ChainConfig) (*NewChainStrategy, error) {
// Initialize RPC client
}
func (s *NewChainStrategy) Name() string { return "newchain" }
func (s *NewChainStrategy) ChainID() uint64 { return 12345 }
func (s *NewChainStrategy) SubmitAnchor(ctx context.Context, data AnchorData) (TxHash, error) {
// Construct chain-specific anchor transaction
// Submit via RPC
// Return transaction hash
}
func (s *NewChainStrategy) DeployAccount(ctx context.Context, adi string, salt []byte) (Address, error) {
// Deploy ADI-linked account on the new chain
}
func (s *NewChainStrategy) VerifyProof(ctx context.Context, root, proof, leaf []byte) (bool, error) {
// Call on-chain verification contract
}
func (s *NewChainStrategy) GetBalance(ctx context.Context, address string) (*big.Int, error) {
// Query native token balance
}- Register the strategy in
pkg/chain/registry.go:
if cfg.EnableNewChain {
strategy, err := NewNewChainStrategy(cfg.NewChainConfig)
registry.Register("newchain", strategy)
}-
Add configuration variables to
pkg/config/config.go:NEWCHAIN_RPC: RPC endpointANCHOR_CONTRACT_NEWCHAIN: Contract addressENABLE_NEWCHAIN: Feature flag
-
Deploy the
CertenAnchorcontract on the new chain (if EVM-compatible, reuse existing Solidity; otherwise implement equivalent in the chain's native language) -
Add tests: unit tests for the strategy, integration test with a local chain node
# Create a new migration
# Manually create pkg/database/migrations/008_description.up.sql
# and pkg/database/migrations/008_description.down.sql
# Apply the migration
go run ./cmd/migrate up
# Verify
go run ./cmd/migrate status
# Rollback if needed
go run ./cmd/migrate downMigration files should be idempotent where possible (use IF NOT EXISTS, IF EXISTS).
Each package has _test.go files alongside the source. Use interfaces and mocks for external dependencies:
# Run a specific package's tests
go test ./pkg/proof/...
# Run with verbose output
go test -v ./pkg/consensus/...
# Run a specific test
go test -run TestProofEngineL1 ./pkg/proof/...Located in test/integration/. Require running PostgreSQL and optionally CometBFT:
# Run integration tests (requires DATABASE_URL)
go test -tags=integration ./test/integration/...Test the full consensus flow with multiple validator instances:
# Start a 4-validator testnet
./scripts/init-testnet.sh 4
docker-compose up -d
# Run consensus simulation tests
go test -tags=consensus ./test/integration/consensus_test.go| Package | Target | Rationale |
|---|---|---|
pkg/proof/ |
>90% | Critical proof generation logic |
pkg/consensus/ |
>85% | ABCI state machine correctness |
pkg/crypto/ |
>95% | Cryptographic operations must be correct |
pkg/chain/strategy/ |
>80% | Chain interaction reliability |
pkg/database/ |
>80% | Data integrity |
pkg/intent/ |
>90% | Intent parsing correctness |
- Go version: 1.24+ required
- Formatter:
gofumpt(stricter thangofmt) - Linter:
golangci-lintwith the project's.golangci.ymlconfiguration - Error handling: Always wrap errors with context:
fmt.Errorf("phase L1 failed: %w", err) - Context: Pass
context.Contextas the first parameter to all functions that do I/O - Logging: Use structured logging with
slogpackage