Proof of Authority (PoA) Cosmos SDK Module

April 9, 2026 · View on GitHub

Part of Cosmos SDK Enterprise Modules | Enterprise Modules

Full Documentation: docs.cosmos.network/enterprise/components/poa/overview

License Notice: This module uses the Source Available Evaluation License, different from the core SDK's Apache-2.0 license. See the License section for details.

A Cosmos SDK module that implements a Proof of Authority (PoA) consensus mechanism, allowing a designated admin to manage a permissioned validator set and integrate with governance for validator-only participation.

Overview

The PoA module replaces traditional staking-based validator selection with an admin-controlled validator set. This is useful for permissioned networks, consortium chains, and testing environments where validator participation needs to be tightly controlled.

Key Features

  • Admin-Controlled Validator Set: A single admin account manages validator additions, removals, and power adjustments (this admin could be a group, a multisig or the governance module address)
  • Fee Distribution: Validators accumulate transaction fees proportional to their voting power
  • Governance Integration: Restricts proposal submission, deposits, and voting to active PoA validators only
  • Custom Vote Tallying: Governance votes are weighted by validator power instead of staked tokens

Architecture

The PoA module integrates with several core Cosmos SDK modules and CometBFT:

diagram

Module Interactions

ModulePurposeInterface
CometBFTConsensus engineReceives validator updates via ABCI (BeginBlock/EndBlock)
AuthAccount managementGets module accounts and address codec
BankToken transfersSends accumulated fees from PoA module to validators
GovernanceProposals & votingHooks validate only PoA validators can participate; custom vote tallying by validator power

Breaking Changes

Cosmos SDK v0.54.x Integration

When integrating with SDK v0.54.x+ (see upgrade guide here), note these breaking changes:

  • x/gov Keeper Initialization (#25615): keeper.NewKeeper now requires a CalculateVoteResultsAndVotingPowerFn parameter instead of StakingKeeper. Use keeper.NewDefaultCalculateVoteResultsAndVotingPower(stakingKeeper) to wrap your staking keeper.

  • x/gov GovHooks Interface (#25617): AfterProposalSubmission hook now includes proposerAddr sdk.AccAddress as an additional parameter.

  • x/gov Distribution Keeper (#25616): DistrKeeper is now optional, but must be non-nil if used as a cancellation fee destination.

See the full Cosmos SDK v0.54.x Changelog for details.

Migration from POS

For chains transitioning from Proof-of-Stake to Proof-of-Authority, see the POS-to-POA Migration Example. It includes a transitional simapp, sample upgrade handlers, and an end-to-end system test.

Quick Start

Prerequisites

  • Go 1.25+
  • Docker (for localnet)

Local Development Network

Start a local test network with the PoA module:

# Start localnet (rebuilds chain, resets genesis, starts nodes)
make localnet

# Access node1 shell for testing
make localnet-shell

# Clean up localnet
make localnet-clean

Usage

All commands below should be run inside make localnet-shell or with appropriate node configuration.

Query Commands

Get PoA parameters (including admin address):

simd q poa params

List all validators and their power:

simd q poa validators

Get specific validator by consensus address:

simd q poa validator <consensus-address>

Transaction Commands

Update PoA parameters (admin only):

simd tx poa update-params \
    --admin cosmos1x0mm8rws8lm46xay3zyyznzr6lvu5um3kht0x7 \
    --from admin \
    --keyring-backend test

Update validators (admin only):

Add or modify validators by specifying their public key and power:

simd tx poa update-validators validators.json \
    --from admin \
    --keyring-backend test

Withdraw validator fees:

simd tx poa withdraw-fees \
    --from account \
    --keyring-backend test

Creating and Adding a New Validator

  1. Generate validator operator key and fund the account:
# Add a new key for your validator operator (this is for signing transactions, not consensus)
simd keys add myvalidator --keyring-backend test

export OPERATOR_ADDR="$(simd keys show myvalidator --keyring-backend=test --address)"

# Fund the account from an existing account
simd tx bank send account $OPERATOR_ADDR 100000token \
  --from account \
  --keyring-backend test \
  --chain-id poa-localnet-1 \
  --fees=100token \
  -y
  1. Get the validator consensus public key (ed25519):

Important: The account key from simd keys add (secp256k1) is for signing transactions, not for validator consensus. You need a separate ed25519 consensus public key.

# Option A: If you have a running validator node, get its consensus pubkey:
simd tendermint show-validator

export CONS_PUBKEY="$(simd comet show-validator | jq -r '.key')"

# Option B: For testing, you can use an arbitrary ed25519 key like 13iyxnnVneLg0AxHeUD7dRAegA8W3gB1mT4p7sPGjyY=
  1. Create the validator (admin-gated):
# Admin creates validator with initial positive power.
# operator-address is the validator operator account, while --from is the admin signer.
simd tx poa create-validator \
    "My Validator" \
    $CONS_PUBKEY \
    "ed25519" \
    --description "My validator description" \
    --operator-address $OPERATOR_ADDR \
    --power 1 \
    --from account \
    --keyring-backend test \
    --fees 1token
  1. Admin activates the validator by setting power:

Create a validators.json file:

[
  {
    "pub_key": {
      "@type": "/cosmos.crypto.ed25519.PubKey",
      "key": "<base64-encoded-ed25519-pubkey>"
    },
    "power": 10000,
    "metadata": {
      "moniker": "My Validator",
      "description": "My validator description",
      "operator_address": "cosmos1..."
    }
  }
]

Then update validators:

simd tx poa update-validators validators.json \
    --from account \
    --keyring-backend test

Notes:

  • Setting power to 0 removes a validator from the active set
  • The operator_address is the address that can withdraw fees

Testing & Development

Network Testing

Check node status:

simd status

Get current block height:

simd q block | jq '.block.header.height'

View recent blocks:

simd q block <height>

Governance Testing

Test governance (validators only):

# Submit a proposal (must be from a validator account)
simd tx gov submit-proposal proposal.json \
    --from account \
    --keyring-backend test

# Vote on proposal (only authorized validators can vote)
simd tx gov vote 1 yes \
    --from account \
    --keyring-backend test

# Check proposal status
simd q gov proposal 1

Integration Testing

Run unit tests:

go test ./x/poa/...

Run keeper tests:

go test ./x/poa/keeper/...

Run all tests with coverage:

go test -coverprofile=coverage.out ./x/poa/...
go tool cover -html=coverage.out

Configuration

Genesis Configuration

The PoA module requires the following genesis configuration:

{
  "poa": {
    "params": {
      "admin": "cosmos1..."
    },
    "validators": [
      {
        "pub_key": {
          "@type": "/cosmos.crypto.ed25519.PubKey",
          "key": "base64-encoded-pubkey"
        },
        "power": 10000000,
        "metadata": {
          "operator_address": "cosmos1...",
          "moniker": "validator1"
        }
      }
    ]
  }
}

Module Parameters

ParameterTypeDescription
adminstringBech32 address of the admin account that can update validators and params

Features In Detail

Validator Management

  • Admin-Only Control: Only the designated admin account can add, remove, or modify validators
  • Power-Based Ordering: Validators are indexed by power for efficient iteration
  • Consensus & Operator Addresses: Each validator has both a consensus address (for block signing) and an operator address (for transactions)

Fee Distribution

  • Validators automatically accumulate transaction fees proportional to their voting power
  • Fees are stored as DecCoins to handle fractional amounts precisely
  • Validators withdraw fees to their operator address via withdraw-fees transaction

Governance Integration

  • Restricted Participation: Only active PoA validators with power > 0 can submit proposals, deposit, and vote
  • Power-Based Voting: Votes are tallied using validator power instead of token stakes
  • Governance Hooks: Validates voter authorization at proposal submission, deposit, and vote time

Development

Project Structure

x/poa/
├── keeper/          # Core business logic
│   ├── keeper.go       # Keeper initialization
│   ├── validator.go    # Validator management
│   ├── distribution.go # Fee distribution
│   ├── governance.go   # Governance integration
│   ├── hooks.go        # Module hooks
│   └── abci.go         # BeginBlock/EndBlock
├── types/           # Type definitions
│   ├── poa.proto       # Protobuf definitions
│   ├── expected_keepers.go # Keeper interfaces
│   └── keys.go         # Storage keys
└── client/cli/      # CLI commands

Adding New Features

  1. Define protobuf messages in proto/
  2. Generate code: make proto-gen
  3. Implement keeper methods in keeper/
  4. Add CLI commands in client/cli/
  5. Write tests in keeper/*_test.go

License

IMPORTANT: This module uses a different license than the core Cosmos SDK.

This module is licensed under the Source Available Evaluation License for non-commercial evaluation, testing, and educational purposes only. Commercial use requires a separate license.