Skip to content

Incorrect block author extraction on parachains with multiple PreRuntime digest logs (e.g., Asset Hub) #1901

@TarikGul

Description

@TarikGul

Description

On parachains like Asset Hub, the block author is incorrectly determined because extractAuthor only checks the first PreRuntime digest log, which may not be the Aura digest containing the slot number.

Root Cause

In packages/api-derive/src/type/util.ts, the extractAuthor function uses:

const [pitem] = digest.logs.filter((e) => e.isPreRuntime);

This destructuring takes only the first PreRuntime log. On Asset Hub (and likely other Cumulus-based parachains), the digest contains multiple PreRuntime logs:

  1. PreRuntime CMLS (Cumulus parachain data) ← this is checked
  2. PreRuntime aura (actual slot number) ← this is skipped!

Since CMLS is not recognized as an Aura engine (isAura = false), the code falls through to check the Seal log, which contains the Aura signature (64 bytes). The first 8 bytes of this signature are then incorrectly interpreted as a
slot number.

Example: Asset Hub Polkadot Block 12273189

Digest logs:

log[0] PreRuntime: engine=CMLS data=0x01010114
log[1] PreRuntime: engine=aura data=0x0b67cc0800000000  ← actual slot
log[2] Consensus:  engine=RPSR data=0x1817f286...
log[3] Seal:       engine=aura data=0x1091091abd0bb9f6...  ← signature

Current (incorrect) behavior:

  • Checks log[0] PreRuntime CMLS → isAura = false, no author
  • Skips log[1] PreRuntime aura (never checked!)
  • Checks log[2] Consensus RPSR → isAura = false, no author
  • Checks log[3] Seal aura → interprets signature bytes as slot
  • Slot from signature: 17778253910835302672 (first 8 bytes of signature as u64 LE)
  • Index: 17778253910835302672 % 18 = 14
  • Returns: 12owmS8Sobqxfx6KK9vk9e67FqnGpZdmxCFCRFptzZdsoujC

Correct behavior:

  • Should check log[1] PreRuntime aura
  • Actual slot: 147613451 (0x0b67cc0800000000 as u64 LE)
  • Index: 147613451 % 18 = 5
  • Should return: 14wQoaBqk718MgNxp3qdpqHnEgmTTmTkcVnYuxMWWvYr3DXb

Substrate SDK Reference

From substrate/client/consensus/aura/src/standalone.rs:

/// Get the slot author for given block along with authorities.
pub fn slot_author<P: Pair>(slot: Slot, authorities: &[AuthorityId<P>]) -> Option<&AuthorityId<P>> {
    let idx = *slot % (authorities.len() as u64);
    // ...
    Some(current_author)
}

From substrate/primitives/consensus/aura/src/digests.rs:

  • The PreRuntime digest contains the slot number
  • The Seal digest contains the signature

Suggested Fix

Instead of taking only the first PreRuntime log, check all PreRuntime logs for a supported consensus engine:

// Current (buggy):
const [pitem] = digest.logs.filter((e) => e.isPreRuntime);

// Suggested fix - find a PreRuntime with a supported engine:
const pitem = digest.logs.find((e) => {
  if (!e.isPreRuntime) return false;
  const [engine] = e.asPreRuntime;
  return engine.isAura || engine.isBabe;
});

Or alternatively, iterate through all PreRuntime logs in the extraction logic rather than just the first one.

Impact

  • Affects all Cumulus-based parachains that have multiple PreRuntime digest logs
  • The authorId field in block responses contains an incorrect validator address
  • While this doesn't affect transaction processing, it provides incorrect information to API consumers

Environment

  • Observed on: Asset Hub Polkadot (statemint)
  • polkadot-js/api version: (affects current versions)
  • Also affects substrate-api-sidecar which uses polkadot-js for author extraction

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions