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