# Proof of Authority (PoA) Consensus Mechanism in Fuel Core: Architecture and Implementation

> Learn how Fuel Core implements Proof of Authority consensus. Discover how signed block headers and authority validation ensure secure and authorized blockchain operations.

- Repository: [Fuel Labs/fuel-core](https://github.com/FuelLabs/fuel-core)
- Tags: architecture
- Published: 2026-03-06

---

**Fuel Core's Proof of Authority (PoA) consensus uses a pre-configured authority key to cryptographically sign block headers, where the PoA Service orchestrates production triggers and the PoAVerifier validates signatures against the known authority address to ensure only authorized entities generate the chain.**

The Fuel Labs `fuel-core` repository implements a lightweight, permissioned Proof of Authority (PoA) consensus mechanism as an efficient alternative to Proof-of-Stake. This system relies on designated authority keys to secure the blockchain, making it ideal for testnets, private networks, and controlled environments where deterministic block production is required.

## How PoA Consensus Works in Fuel Core

### Authority Keys and Block Production

At the heart of the PoA consensus mechanism lies the **authority key**, a cryptographic key pair pre-configured in the node's consensus configuration. The node holding this key runs the **PoA Service**, which handles three critical operations:

- **Triggering block production** based on the configured `Trigger` policy (instant, interval, never, or open)
- **Signing the block header** with the authority's private key, producing a `PoAConsensus.signature`
- **Publishing the sealed block** to the network for import, gossip, and finalization

### Block Validation and Signature Verification

When other nodes receive a block, they validate it using the **PoAVerifier**. The verification process, implemented in [`crates/services/consensus_module/poa/src/verifier.rs`](https://github.com/FuelLabs/fuel-core/blob/main/crates/services/consensus_module/poa/src/verifier.rs), checks that the signature in the block header matches the known authority address defined in the `ConsensusConfig`.

The core verification logic handles both PoA V1 (single key) and PoA V2 (rotating keys):

```rust
match consensus_config {
    ConsensusConfig::PoA { signing_key } => {
        let msg = header.id().as_message();
        consensus.signature.recover(msg)
            .is_ok_and(|k| Input::owner(&k) == *signing_key)
    }
    ConsensusConfig::PoAV2(poa) => {
        let msg = header.id().as_message();
        let signing_key = poa.address_for_height(*header.height());
        consensus.signature.recover(msg)
            .is_ok_and(|k| Input::owner(&k) == signing_key)
    }
}

```

## Core Architectural Components

The PoA consensus mechanism in Fuel Core is modularized across several key components:

| Component | Role | Source Location |
|-----------|------|-----------------|
| **PoAConsensus** | Struct holding the block-header signature (`fuel_crypto::Signature`) | [`crates/types/src/blockchain/consensus/poa.rs`](https://github.com/FuelLabs/fuel-core/blob/main/crates/types/src/blockchain/consensus/poa.rs) |
| **PoAAdapter** | Entry point for the consensus module; provides `manually_produce_blocks` and implements `ConsensusModulePort` | [`crates/fuel-core/src/service/adapters/consensus_module/poa.rs`](https://github.com/FuelLabs/fuel-core/blob/main/crates/fuel-core/src/service/adapters/consensus_module/poa.rs) |
| **PoAVerifier** | Validates signatures and block fields during import | [`crates/services/consensus_module/poa/src/verifier.rs`](https://github.com/FuelLabs/fuel-core/blob/main/crates/services/consensus_module/poa/src/verifier.rs) |
| **RedisLeaderLeaseAdapter** | Optional leader-lock for multi-node setups using Redis | [`crates/fuel-core/src/service/adapters/consensus_module/poa.rs`](https://github.com/FuelLabs/fuel-core/blob/main/crates/fuel-core/src/service/adapters/consensus_module/poa.rs) |
| **Config & Trigger** | Defines production policies (instant, interval, never, open) | [`crates/services/consensus_module/poa/src/config.rs`](https://github.com/FuelLabs/fuel-core/blob/main/crates/services/consensus_module/poa/src/config.rs) |

## Block Production Flow

The block production process follows a deterministic sequence orchestrated by the PoA Service. According to the flow documentation in [`docs/poa/flows.md`](https://github.com/FuelLabs/fuel-core/blob/main/docs/poa/flows.md), the sequence involves:

1. **Trigger**: The PoA Service initiates production based on the configured trigger policy
2. **Transaction Selection**: The Block Producer queries the transaction pool for pending transactions
3. **Execution**: The block is executed and the header is finalized
4. **Signing**: The PoA Service signs the block header with the authority key
5. **Commit**: The sealed block is committed to the database via the Block Importer
6. **Broadcast**: The signed header is gossiped to the network via P2P

## Implementing PoA Operations

### Constructing a PoA Consensus Object

To create a `PoAConsensus` instance programmatically, typically used during testing or custom block construction:

```rust
use fuel_core_types::blockchain::consensus::poa::PoAConsensus;
use fuel_core_fuel_crypto::Signature;

// Create a placeholder signature (in production, sign with authority key)
let dummy_sig = Signature::default();
let poa_consensus = PoAConsensus::new(dummy_sig);

```

*Reference*: [`PoAConsensus::new`](https://github.com/FuelLabs/fuel-core/blob/master/crates/types/src/blockchain/consensus/poa.rs#L15-L18)

### Manually Triggering Block Production

For testing or operational purposes, you can manually trigger block production using the `PoAAdapter`:

```rust
use fuel_core_fuel_core::service::adapters::consensus_module::poa::PoAAdapter;
use fuel_core_poa::service::{Mode, SharedState};
use fuel_core_tai64::Tai64;

// Obtain shared state from the running service
let shared: Option<SharedState> = /* obtained from core service */;
let poa_adapter = PoAAdapter::new(shared);

// Produce a single block immediately
poa_adapter
    .manually_produce_blocks(Some(Tai64::now()), Mode::Blocks { number_of_blocks: 1 })
    .await
    .expect("block production failed");

```

*Implemented in*: `PoAAdapter::manually_produce_blocks` ([source](https://github.com/FuelLabs/fuel-core/blob/master/crates/fuel-core/src/service/adapters/consensus_module/poa.rs#L5-L15))

### Verifying PoA Signatures During Block Import

When implementing custom block import logic, use the verifier to validate PoA signatures:

```rust
use fuel_core_chain_config::ConsensusConfig;
use fuel_core_types::blockchain::{
    block::Block,
    header::BlockHeader,
    consensus::poa::PoAConsensus,
};
use fuel_core_services::consensus_module::poa::verify_consensus;

// Validate block against consensus configuration
let valid = verify_consensus(&config, &header, &PoAConsensus { signature });
assert!(valid, "Invalid PoA block signature");

```

*Verification logic*: [`verify_consensus`](https://github.com/FuelLabs/fuel-core/blob/master/crates/services/consensus_module/poa/src/verifier.rs#L22-L40)

## Leader Election for Multi-Node Deployments

When running multiple nodes with the same authority key, Fuel Core provides the **RedisLeaderLeaseAdapter** to prevent split-brain scenarios. This optional component, located in [`crates/fuel-core/src/service/adapters/consensus_module/poa.rs`](https://github.com/FuelLabs/fuel-core/blob/main/crates/fuel-core/src/service/adapters/consensus_module/poa.rs), implements a distributed leader lock using Redis.

The adapter checks lease ownership before allowing block production:

```rust
async fn can_produce_block(&self, _height: BlockHeight) -> anyhow::Result<bool> {
    if self.renew_lease_if_owner().await? {
        return Ok(true);
    }
    self.acquire_lease_if_free().await
}

```

This ensures that even in clustered deployments, only one node produces blocks at any given time, maintaining the singleton authority property required by the PoA consensus mechanism.

## Summary

- **Proof of Authority (PoA)** in Fuel Core uses a pre-configured authority key to sign block headers, providing a lightweight alternative to Proof-of-Stake for permissioned networks.
- The **PoA Service** orchestrates block production through configurable triggers (instant, interval, never) and seals blocks with cryptographic signatures stored in `PoAConsensus`.
- **PoAVerifier** validates incoming blocks by recovering the public key from the signature and comparing it against the configured authority address, supporting both static and rotating key configurations.
- The **PoAAdapter** bridges the core service graph with the consensus module, enabling manual block production via `manually_produce_blocks` for testing and operational control.
- For high-availability deployments, the **RedisLeaderLeaseAdapter** implements distributed leader election to ensure only one node produces blocks at a time, preventing consensus forks.

## Frequently Asked Questions

### What is the difference between PoA and PoA V2 in Fuel Core?

PoA V1 utilizes a single static authority key defined in the genesis configuration, requiring all blocks to be signed by that specific key. PoA V2 introduces key rotation capabilities, allowing multiple authority addresses that change based on block height. The verifier handles both modes: V1 checks against a fixed `signing_key`, whereas V2 calls `poa.address_for_height(*header.height())` to dynamically determine the valid signer for that specific block.

### How does Fuel Core prevent multiple nodes from producing blocks simultaneously?

In single-node deployments, the authority key configuration naturally prevents conflicts since only one node possesses the key. For multi-node setups sharing the same authority key, Fuel Core provides the `RedisLeaderLeaseAdapter`. This component acquires a distributed lease in Redis before allowing block production, ensuring only one node holds the production lock at any time. If the lease expires or the node fails, another node can acquire the lease and seamlessly take over production responsibilities.

### Can block production be triggered manually in a PoA network?

Yes. The `PoAAdapter` exposes the `manually_produce_blocks` method, which allows operators or automated test suites to trigger immediate block production outside the normal trigger schedule. This functionality requires access to the `SharedState` from the running PoA service and accepts parameters specifying the production mode, such as the number of blocks to produce and the target timestamp.

### Where is the PoA signature stored in the block structure?

The PoA signature is stored within the `PoAConsensus` struct, which serves as the consensus data container for the block header. Defined in [`crates/types/src/blockchain/consensus/poa.rs`](https://github.com/FuelLabs/fuel-core/blob/main/crates/types/src/blockchain/consensus/poa.rs), this struct contains a single field of type `fuel_crypto::Signature`. During the block import process, the `PoAVerifier` extracts this signature from the `PoAConsensus` instance and validates it against the expected authority address recovered from the signed message.