Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions packages/core/src/blockchain/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export class Block {
#metadata?: Promise<HexString>
#registry?: Promise<TypeRegistry>
#meta?: Promise<DecoratedMeta>
#extrinsicMeta?: Promise<DecoratedMeta>

#baseStorage: StorageLayerProvider
#storages: StorageLayer[]
Expand Down Expand Up @@ -77,6 +78,7 @@ export class Block {
this.#metadata = parentBlock?.metadata
this.#registry = parentBlock?.registry
this.#meta = parentBlock?.meta
this.#extrinsicMeta = parentBlock?.meta

const storageDiff = block?.storageDiff

Expand All @@ -88,6 +90,9 @@ export class Block {
this.#metadata = undefined
this.#registry = undefined
this.#meta = undefined
// #extrinsicMeta intentionally NOT reset: the block's extrinsics were
// encoded with the pre-upgrade runtime (parent's metadata), so we
// preserve it for correct extrinsic decoding after a runtime upgrade.
}

this.pushStorageLayer().setAll(storageDiff)
Expand Down Expand Up @@ -295,6 +300,24 @@ export class Block {
return this.#meta
}

/**
* Get the metadata used to encode this block's extrinsics.
*
* A block's extrinsics are encoded with the runtime that was active *before*
* the block executed (i.e. the parent block's post-execution metadata).
* After a runtime upgrade, this differs from {@link meta} which reflects the
* new runtime. For blocks without an upgrade the two are identical.
*/
get extrinsicMeta(): Promise<DecoratedMeta> {
if (!this.#extrinsicMeta) {
this.#extrinsicMeta = (async () => {
const parent = await this.parentBlock
return parent ? parent.meta : this.meta
})()
}
return this.#extrinsicMeta
}

/**
* Call a runtime method.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ export type ValidationData = {
}

const getValidationData = async (parent: Block, fallback = true): Promise<ValidationData> => {
const meta = await parent.meta
if (parent.number === 0) {
const { trieRootHash, nodes } = await createProof(MOCK_VALIDATION_DATA.relayChainState.trieNodes, [])
return {
Expand All @@ -79,6 +78,9 @@ const getValidationData = async (parent: Block, fallback = true): Promise<Valida
}
try {
const extrinsics = await parent.extrinsics
// Use extrinsicMeta because the block's extrinsics were encoded with the
// pre-execution runtime, which may differ from parent.meta after a runtime upgrade.
const meta = await parent.extrinsicMeta
const validationDataExtrinsic = extrinsics.find((extrinsic) => {
const firstArg = meta.registry.createType<GenericExtrinsic>('GenericExtrinsic', extrinsic)?.args?.[0]
return firstArg && 'validationData' in firstArg
Expand Down