Skip to main content
The Avail runtime is built using Substrate’s FRAME framework, composing multiple pallets that each handle specific functionality. The runtime is compiled to WebAssembly and executes on-chain, providing deterministic state transitions.

Runtime Composition

The Avail runtime (runtime/src/lib.rs:103-153) consists of 20+ pallets organized into functional categories:

Core Pallets

  • System (index 0): Core blockchain functionality, block management
  • Utility (index 1): Batch transactions and multi-signature operations
  • Timestamp (index 3): Block timestamp management
  • Indices (index 5): Account index lookup system
  • Multisig (index 34): Multi-signature account operations
  • Proxy (index 40): Proxy account delegation
  • Babe (index 2): Block production using BABE (Blind Assignment for Blockchain Extension)
  • Grandpa (index 17): Block finality using GRANDPA consensus
  • Authorship (index 4): Block authorship tracking and uncle rewards
  • ImOnline (index 20): Validator heartbeat mechanism
  • AuthorityDiscovery (index 21): P2P authority node discovery
  • Balances (index 6): Account balances and transfers
  • TransactionPayment (index 7): Transaction fee calculation and payment
  • Staking (index 10): Proof-of-Stake validator economics
  • Session (index 11): Validator session management
  • Treasury (index 18): On-chain treasury for protocol funds
  • NominationPools (index 36): Pooled staking for nominators
  • DataAvailability (da_control) (index 29): Core DA functionality, application keys, data submission
  • Mmr (index 27): Merkle Mountain Range for efficient proofs
  • Preimage (index 33): Storage for large preimages
  • Vector (index 39): Ethereum light client bridge integration
  • Mandate (index 38): Technical committee privileged calls
  • Identity (index 37): On-chain identity management
  • TxPause (index 41): Circuit breaker for pausing transactions

Transaction Flow

Transaction Processing Pipeline

1

Pre-Validation

Transaction is decoded and basic checks are performed (signature, nonce, payment).
// Transaction validation in runtime
fn validate_transaction(
    source: TransactionSource,
    tx: <Block as BlockT>::Extrinsic,
) -> TransactionValidity
2

Application ID Check

The CheckAppId extension (pallets/dactr/src/extensions/check_app_id.rs) validates that the AppId exists if specified.
3

Fee Calculation

TransactionPayment pallet calculates fees based on:
  • Extrinsic weight
  • Data length
  • Dynamic fee multiplier
  • For submit_data: special weight calculation based on matrix space
See da_control::weight_helper::submit_data (pallets/dactr/src/lib.rs:416-463)
4

Execution

The pallet’s dispatchable function executes, modifying runtime state.
5

Event Emission

Events are emitted to the event log for indexing and monitoring.

Data Availability Pallet

The da_control pallet (pallets/dactr/src/lib.rs) is the core of Avail’s data availability functionality.

Key Data Structures

#[derive(Clone, Encode, Decode, TypeInfo, PartialEq, RuntimeDebug)]
pub struct AppKeyInfo<Acc: PartialEq> {
    /// Owner of the key
    pub owner: Acc,
    /// Application ID associated
    pub id: AppId,
}

Dispatchable Functions

Creates a new application key and assigns an AppId.
pallets/dactr/src/lib.rs:158-178
pub fn create_application_key(
    origin: OriginFor<T>,
    key: AppKeyFor<T>,
) -> DispatchResultWithPostInfo
  • Ensures key doesn’t already exist
  • Increments NextAppId
  • Stores key-to-AppId mapping
  • Emits ApplicationKeyCreated event

Weight Calculation for Data Submission

Avail uses a sophisticated weight model for submit_data that accounts for data availability matrix space:
pallets/dactr/src/lib.rs:421-463
pub fn submit_data<T: Config>(data_len: usize) -> Weight {
    // Calculate data size with SCALE encoding prefix
    let encoded_data_len = data_len + compact_len(&data_len);
    
    // Get current matrix dimensions
    let cols = current_block_dimension.cols.0;
    let rows = current_block_dimension.rows.0;
    
    // Calculate max scalars with DA ratio (90%)
    let max_scalar_da_ratio = DA_DISPATCH_RATIO_PERBILL * cols * rows;
    
    // Compute number of 31-byte scalars needed
    let nb_scalar = encoded_data_len / (BLOCK_CHUNK_SIZE - 1);
    
    // Weight proportional to matrix space used
    let data_scalar_ratio = nb_scalar / max_scalar_da_ratio;
    let weight = data_scalar_ratio * max_weight_normal_ratio;
    
    return max(weight, basic_weight);
}
This weight model ensures that transactions consuming more matrix space pay proportionally higher fees, preventing block space spam.

Vector Pallet (Ethereum Bridge)

The Vector pallet (pallets/vector/src/lib.rs) implements an Ethereum light client bridge using zero-knowledge proofs.

Key Features

  • Light Client Verification: Verifies Ethereum consensus using SP1 Groth16 proofs
  • Message Passing: Enables cross-chain messaging between Avail and Ethereum
  • Sync Committee Tracking: Maintains Ethereum beacon chain sync committee state
pallets/vector/src/lib.rs:35-48
sol! {
    struct ProofOutputs {
        bytes32 executionStateRoot;
        bytes32 newHeader;
        bytes32 nextSyncCommitteeHash;
        uint256 newHead;
        bytes32 prevHeader;
        uint256 prevHead;
        bytes32 syncCommitteeHash;
        bytes32 startSyncCommitteeHash;
    }
}

Mandate Pallet

The Mandate pallet (pallets/mandate/src/lib.rs) provides a governance mechanism for the Technical Committee to execute privileged operations.
pallets/mandate/src/lib.rs:55-68
pub fn mandate(
    origin: OriginFor<T>,
    call: Box<<T as Config>::RuntimeCall>,
) -> DispatchResultWithPostInfo {
    T::ApprovedOrigin::ensure_origin(origin)?;
    
    // Execute call with Root origin
    let res = call.dispatch_bypass_filter(frame_system::RawOrigin::Root.into());
    
    Self::deposit_event(Event::RootOp {
        result: res.map(|_| ()).map_err(|e| e.error),
    });
    
    Ok(Pays::No.into())  // No fee for mandate calls
}

Runtime APIs

The runtime exposes several custom APIs for client-side operations (runtime/src/apis.rs:43-74):

DataAvailApi

fn block_length() -> BlockLength;
Returns current block matrix dimensions.

ExtensionBuilder

fn build_extension(...) -> HeaderExtension;
fn build_data_root(...) -> H256;
fn check_if_extrinsic_is_post_inherent(...) -> bool;
Builds Kate commitments and validates block structure.

KateApi

fn data_proof(...) -> Option<ProofResponse>;
fn rows(...) -> Result<Vec<GRow>, Error>;
fn proof(...) -> Result<Vec<GDataProof>, Error>;
fn multiproof(...) -> Result<Vec<(GMultiProof, GCellBlock)>, Error>;
Generates data availability proofs.

VectorApi

fn sync_committee_poseidons(slot: u64) -> U256;
fn head() -> u64;
fn headers(slot: u64) -> H256;
Queries Ethereum light client state.

Configuration Parameters

Key runtime parameters defined in runtime/src/constants.rs and runtime/src/impls.rs:
// Block time
pub const SLOT_DURATION: u64 = 20_000; // 20 seconds
pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 4 * HOURS;

// Data Availability
pub const MinBlockRows: BlockLengthRows = BlockLengthRows(32);
pub const MaxBlockRows: BlockLengthRows = BlockLengthRows(1024);
pub const MinBlockCols: BlockLengthColumns = BlockLengthColumns(32);
pub const MaxBlockCols: BlockLengthColumns = BlockLengthColumns(1024);
pub const MaxAppDataLength: u32 = 1_048_576; // 1 MB

// Dispatch ratios
pub const DA_DISPATCH_RATIO: u8 = 90; // 90% for DA
pub const NORMAL_DISPATCH_RATIO: u8 = 100; // 100% for normal txs

Call Size Constraints

The runtime enforces strict size limits on calls to prevent DoS (runtime/src/lib.rs:326-343):
const RUNTIME_CALL_SIZE: usize = 208;
const DA_CALL_SIZE: usize = 64;
const SYSTEM_CALL_SIZE: usize = 40;
Large arguments should use Box<T> to keep enum variants small.
If adding new dispatchable functions with large parameters, use Box<T> to avoid increasing the overall RuntimeCall size beyond 208 bytes.

Next Steps

Consensus

Learn how BABE and GRANDPA work together

Data Availability

Deep dive into Kate commitments

Build docs developers (and LLMs) love