or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

block-operations.mdconsensus-operations.mdheader-operations.mdindex.mdutility-functions.md
tile.json

consensus-operations.mddocs/

Consensus Operations

Support for Ethereum consensus mechanisms including Ethash Proof-of-Work and Clique Proof-of-Authority.

Capabilities

Clique Proof-of-Authority Functions

Functions for working with Clique PoA consensus mechanism, including signer validation and epoch transitions.

/**
 * Fixed vanity bytes length in Clique extra data (32 bytes)
 */
const CLIQUE_EXTRA_VANITY: number;

/**
 * Fixed seal bytes length in Clique extra data (65 bytes)
 */
const CLIQUE_EXTRA_SEAL: number;

/**
 * Returns PoA clique signature hash without seal
 * Used for signature verification and signing operations
 * @param header - Block header to get signature hash for
 * @returns Signature hash as Uint8Array
 */
function cliqueSigHash(header: BlockHeader): Uint8Array;

/**
 * Checks if header represents an epoch transition block
 * Epoch transitions occur every N blocks and contain signer list updates
 * @param header - Block header to check
 * @returns True if this is an epoch transition header
 */
function cliqueIsEpochTransition(header: BlockHeader): boolean;

/**
 * Returns extra vanity data from Clique header
 * Vanity data is the first 32 bytes of extra data field
 * @param header - Block header with Clique extra data
 * @returns Vanity data as Uint8Array (32 bytes)
 */
function cliqueExtraVanity(header: BlockHeader): Uint8Array;

/**
 * Returns extra seal data from Clique header
 * Seal data is the last 65 bytes of extra data field containing the signature
 * @param header - Block header with Clique extra data
 * @returns Seal data as Uint8Array (65 bytes)
 */
function cliqueExtraSeal(header: BlockHeader): Uint8Array;

/**
 * Returns the list of signers from an epoch transition header
 * Only valid for epoch transition blocks, throws error otherwise
 * @param header - Epoch transition block header
 * @returns Array of signer addresses
 */
function cliqueEpochTransitionSigners(header: BlockHeader): Address[];

/**
 * Returns the signer address from a Clique block header
 * Recovers the address from the signature in the seal data
 * @param header - Block header with Clique signature
 * @returns Address of the block signer
 */
function cliqueSigner(header: BlockHeader): Address;

/**
 * Verifies signature against a list of authorized signers
 * Checks if the block signer is authorized and signature is valid
 * @param header - Block header with Clique signature
 * @param signerList - Array of authorized signer addresses
 * @returns True if signature is valid and signer is authorized
 */
function cliqueVerifySignature(header: BlockHeader, signerList: Address[]): boolean;

Usage Examples:

import { 
  cliqueSigner, 
  cliqueVerifySignature, 
  cliqueIsEpochTransition,
  cliqueEpochTransitionSigners,
  CLIQUE_EXTRA_VANITY,
  CLIQUE_EXTRA_SEAL 
} from "@ethereumjs/block";

// Working with a Clique PoA block header
const cliqueHeader = createBlockHeaderFromRPC(cliqueBlockData);

// Get the signer of the block
const signerAddress = cliqueSigner(cliqueHeader);
console.log("Block signed by:", signerAddress.toString());

// Verify the signature against authorized signers
const authorizedSigners = [
  Address.fromString("0x1234..."),
  Address.fromString("0x5678..."),
  Address.fromString("0x9abc..."),
];

const isValidSignature = cliqueVerifySignature(cliqueHeader, authorizedSigners);
console.log("Signature valid:", isValidSignature);

// Check if this is an epoch transition
const isEpochTransition = cliqueIsEpochTransition(cliqueHeader);
console.log("Is epoch transition:", isEpochTransition);

if (isEpochTransition) {
  // Get new signer list from epoch transition block
  const newSigners = cliqueEpochTransitionSigners(cliqueHeader);
  console.log("New signer list:", newSigners.map(addr => addr.toString()));
}

// Examine extra data structure
console.log("Vanity length:", CLIQUE_EXTRA_VANITY); // 32
console.log("Seal length:", CLIQUE_EXTRA_SEAL); // 65
console.log("Total extra data length:", cliqueHeader.extraData.length);

Clique Block Creation

Functions for creating sealed Clique blocks with proper signatures.

/**
 * Creates a sealed Clique PoA block with signature
 * @param blockData - Block data object
 * @param cliqueSigner - Signer private key (32 bytes)
 * @param opts - Block options
 * @returns Sealed Block instance with Clique signature
 */
function createSealedCliqueBlock(
  blockData?: BlockData,
  cliqueSigner: Uint8Array,
  opts?: BlockOptions
): Block;

/**
 * Creates a sealed Clique PoA block header with signature
 * @param headerData - Header data object  
 * @param cliqueSigner - Signer private key (32 bytes)
 * @param opts - Block options
 * @returns Sealed BlockHeader instance with Clique signature
 */
function createSealedCliqueBlockHeader(
  headerData?: HeaderData,
  cliqueSigner: Uint8Array,
  opts?: BlockOptions
): BlockHeader;

Usage Examples:

import { createSealedCliqueBlock, createSealedCliqueBlockHeader } from "@ethereumjs/block";

// Private key for signing (32 bytes)
const signerPrivateKey = new Uint8Array([
  // ... 32 bytes of private key
]);

// Create sealed Clique block
const sealedBlock = createSealedCliqueBlock({
  header: {
    number: 100n,
    gasLimit: 8000000n,
    timestamp: Math.floor(Date.now() / 1000),
    extraData: new Uint8Array(32 + 65), // Vanity + seal space
  },
  transactions: [],
}, signerPrivateKey);

// Create sealed Clique header only
const sealedHeader = createSealedCliqueBlockHeader({
  number: 100n,
  gasLimit: 8000000n,
  timestamp: Math.floor(Date.now() / 1000),
  extraData: new Uint8Array(32 + 65), // Vanity + seal space
}, signerPrivateKey);

// Verify the sealed block
const signerAddress = cliqueSigner(sealedBlock.header);
console.log("Block sealed by:", signerAddress.toString());

// The signature should be valid
const isValid = cliqueVerifySignature(sealedBlock.header, [signerAddress]);
console.log("Signature valid:", isValid);

Ethash Proof-of-Work Functions

Functions for working with Ethash PoW consensus mechanism and difficulty calculations.

/**
 * Calculates canonical difficulty for Ethash PoW consensus
 * Uses the difficulty adjustment algorithm based on block time and parent difficulty
 * Includes difficulty bomb adjustments for specific hard forks
 * @param block - Current block
 * @param parentBlock - Parent block for difficulty calculation
 * @returns Canonical difficulty value for the block
 */
function ethashCanonicalDifficulty(block: Block, parentBlock: Block): bigint;

Usage Examples:

import { ethashCanonicalDifficulty, createBlock } from "@ethereumjs/block";

// Create parent block (PoW era)
const parentBlock = createBlock({
  header: {
    number: 1000000n,
    difficulty: 17179869184n, // ~17 billion
    timestamp: 1609459200n, // Jan 1, 2021
  },
});

// Create child block
const childBlock = createBlock({
  header: {
    number: 1000001n,
    timestamp: 1609459215n, // 15 seconds later (target is ~13-15s)
  },
});

// Calculate what the difficulty should be
const canonicalDifficulty = ethashCanonicalDifficulty(childBlock, parentBlock);
console.log("Parent difficulty:", parentBlock.header.difficulty);
console.log("Canonical difficulty:", canonicalDifficulty);

// The difficulty should be similar since block time is close to target
const difficultyChange = canonicalDifficulty - parentBlock.header.difficulty;
console.log("Difficulty change:", difficultyChange);
console.log("Percentage change:", Number(difficultyChange * 100n / parentBlock.header.difficulty));

Difficulty Calculations

The difficulty adjustment algorithm varies by consensus mechanism and network upgrade.

/**
 * Difficulty calculation interface
 */
interface DifficultyCalculation {
  /**
   * Calculates canonical difficulty using Ethash algorithm
   * Factors include:
   * - Parent difficulty
   * - Block time vs target time
   * - Difficulty bomb adjustments
   * - Uncle count (pre-Byzantium)
   */
  ethashCanonicalDifficulty(block: Block, parentBlock: Block): bigint;

  /**
   * Header-level difficulty calculation
   * Available as method on BlockHeader class
   */
  ethashCanonicalDifficulty(parentBlockHeader: BlockHeader): bigint;
}

Usage Examples:

import { createBlockHeader } from "@ethereumjs/block";

// Example of difficulty calculation with different block times
const parentHeader = createBlockHeader({
  number: 5000000n,
  difficulty: 1000000000000000n, // 1 petahash
  timestamp: 1609459200n,
});

// Fast block (10 seconds) - difficulty should increase
const fastChildHeader = createBlockHeader({
  number: 5000001n,
  timestamp: 1609459210n, // 10 seconds later
});

// Slow block (30 seconds) - difficulty should decrease  
const slowChildHeader = createBlockHeader({
  number: 5000001n,
  timestamp: 1609459230n, // 30 seconds later
});

const fastDifficulty = fastChildHeader.ethashCanonicalDifficulty(parentHeader);
const slowDifficulty = slowChildHeader.ethashCanonicalDifficulty(parentHeader);

console.log("Parent difficulty:", parentHeader.difficulty);
console.log("Fast block difficulty:", fastDifficulty);
console.log("Slow block difficulty:", slowDifficulty);

// Fast blocks get higher difficulty, slow blocks get lower difficulty
console.log("Fast block increase:", fastDifficulty > parentHeader.difficulty);
console.log("Slow block decrease:", slowDifficulty < parentHeader.difficulty);

Consensus Network Configuration

Different networks use different consensus mechanisms and require appropriate configuration.

/**
 * Network-specific consensus configuration
 */
interface ConsensusConfiguration {
  /**
   * Ethash PoW networks: mainnet, ropsten (historical)
   * Use ethashCanonicalDifficulty for difficulty calculations
   */
  ethash: {
    networks: string[];
    methods: ["ethashCanonicalDifficulty"];
  };

  /**
   * Clique PoA networks: goerli, rinkeby (historical)
   * Use clique* functions for signer validation
   */
  clique: {
    networks: string[];
    methods: [
      "cliqueSigner",
      "cliqueVerifySignature", 
      "cliqueIsEpochTransition",
      "cliqueEpochTransitionSigners"
    ];
  };

  /**
   * Proof-of-Stake networks: mainnet (post-merge), sepolia
   * No consensus-specific functions needed at block level
   */
  pos: {
    networks: string[];
    methods: [];
  };
}

Usage Examples:

import { Common } from "@ethereumjs/common";
import { createBlock, cliqueSigner } from "@ethereumjs/block";

// Configure for different networks
const mainnetCommon = new Common({ chain: 'mainnet', hardfork: 'london' }); // PoW era
const goerliCommon = new Common({ chain: 'goerli' }); // Clique PoA
const sepoliaCommon = new Common({ chain: 'sepolia' }); // PoS

// Create blocks for different networks
const mainnetBlock = createBlock(blockData, { common: mainnetCommon });
const goerliBlock = createBlock(blockData, { common: goerliCommon });
const sepoliaBlock = createBlock(blockData, { common: sepoliaCommon });

// Use appropriate consensus functions
if (goerliCommon.consensusType() === 'poa') {
  const signer = cliqueSigner(goerliBlock.header);
  console.log("Goerli block signer:", signer.toString());
}

if (mainnetCommon.consensusType() === 'pow') {
  // Would use ethashCanonicalDifficulty for PoW validation
  console.log("Mainnet PoW block difficulty:", mainnetBlock.header.difficulty);
}

console.log("Sepolia consensus:", sepoliaCommon.consensusType()); // 'pos'