Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor inherents #647

Merged
merged 1 commit into from
Jan 26, 2024
Merged
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
26 changes: 21 additions & 5 deletions packages/chopsticks/src/plugins/dry-run/dry-run-preimage.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { HexString } from '@polkadot/util/types'
import { blake2AsHex } from '@polkadot/util-crypto'
import { hexToU8a } from '@polkadot/util'
import { compactAddLength, hexToU8a } from '@polkadot/util'

import { Block, newHeader, runTask, setStorage, taskHandler } from '@acala-network/chopsticks-core'
import { DryRunSchemaType } from './index.js'
import { defaultLogger } from '../../logger.js'
import { generateHtmlDiffPreviewFile } from '../../utils/generate-html-diff.js'
import { newHeader, runTask, setStorage, taskHandler } from '@acala-network/chopsticks-core'
import { openHtml } from '../../utils/open-html.js'
import { setupContext } from '../../context.js'

Expand All @@ -24,7 +24,7 @@ export const dryRunPreimage = async (argv: DryRunSchemaType) => {

await setStorage(context.chain, {
Preimage: {
PreimageFor: [[[[hash, data.byteLength]], extrinsic]],
PreimageFor: [[[[hash, data.byteLength]], compactAddLength(data)]],
StatusFor: [
[
[hash],
Expand Down Expand Up @@ -60,10 +60,26 @@ export const dryRunPreimage = async (argv: DryRunSchemaType) => {
},
})

const newBlockHash: HexString = `0x${Math.round(Math.random() * 100000000)
.toString(16)
.padEnd(64, '0')}`
const newBlock = new Block(block.chain, block.number + 1, newBlockHash, block, {
header,
extrinsics: [],
storage: block.storage,
})

const calls: [string, HexString[]][] = [['Core_initialize_block', [header.toHex()]]]

for (const inherent of await block.chain.getInherents()) {
calls.push(['BlockBuilder_apply_extrinsic', [inherent]])
for (const inherentProvider of block.chain.getInherents()) {
const extrinsics = await inherentProvider.createInherents(newBlock, {
transactions: [],
downwardMessages: [],
upwardMessages: [],
horizontalMessages: {},
})
if (extrinsics.length === 0) continue
calls.push(['BlockBuilder_apply_extrinsic', extrinsics])
}

calls.push(['BlockBuilder_finalize_block', []])
Expand Down
38 changes: 24 additions & 14 deletions packages/core/src/blockchain/block-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import {
TransactionValidityError,
} from '@polkadot/types/interfaces'
import { Block } from './block.js'
import { BuildBlockParams } from './txpool.js'
import { GenericExtrinsic } from '@polkadot/types'
import { HexString } from '@polkadot/util/types'
import { InherentProvider } from './inherent/index.js'
import { StorageLayer, StorageValueKind } from './storage-layer.js'
import { TaskCallResponse } from '../wasm-executor/index.js'
import { compactAddLength, hexToU8a, stringToHex, u8aConcat } from '@polkadot/util'
Expand Down Expand Up @@ -106,7 +108,8 @@ export const newHeader = async (head: Block, unsafeBlockHeight?: number) => {
const initNewBlock = async (
head: Block,
header: Header,
inherents: HexString[],
inherentProviders: InherentProvider[],
params: BuildBlockParams,
storageLayer?: StorageLayer,
callback?: BuildBlockCallbacks,
) => {
Expand Down Expand Up @@ -136,15 +139,20 @@ const initNewBlock = async (
callback?.onPhaseApplied?.('initialize', resp)
}

const inherents: HexString[] = []
const layers: StorageLayer[] = []
// apply inherents
for (const extrinsic of inherents) {
for (const inherentProvider of inherentProviders) {
try {
const resp = await newBlock.call('BlockBuilder_apply_extrinsic', [extrinsic])
const extrinsics = await inherentProvider.createInherents(newBlock, params)
if (extrinsics.length === 0) {
continue
}
const resp = await newBlock.call('BlockBuilder_apply_extrinsic', extrinsics)
const layer = newBlock.pushStorageLayer()
layer.setAll(resp.storageDiff)
layers.push(layer)

inherents.push(...extrinsics)
callback?.onPhaseApplied?.(layers.length - 1, resp)
} catch (e) {
logger.warn('Failed to apply inherents %o %s', e, e)
Expand All @@ -154,7 +162,8 @@ const initNewBlock = async (

return {
block: newBlock,
layers: layers,
layers,
inherents,
}
}

Expand All @@ -165,12 +174,11 @@ export type BuildBlockCallbacks = {

export const buildBlock = async (
head: Block,
inherents: HexString[],
extrinsics: HexString[],
ump: Record<number, HexString[]>,
inherentProviders: InherentProvider[],
params: BuildBlockParams,
callbacks?: BuildBlockCallbacks,
unsafeBlockHeight?: number,
): Promise<[Block, HexString[]]> => {
const { transactions: extrinsics, upwardMessages: ump, unsafeBlockHeight } = params
const registry = await head.registry
const header = await newHeader(head, unsafeBlockHeight)
const newBlockNumber = header.number.toNumber()
Expand Down Expand Up @@ -263,7 +271,7 @@ export const buildBlock = async (
}
}

const { block: newBlock } = await initNewBlock(head, header, inherents, layer)
const { block: newBlock, inherents } = await initNewBlock(head, header, inherentProviders, params, layer)

const pendingExtrinsics: HexString[] = []
const includedExtrinsic: HexString[] = []
Expand Down Expand Up @@ -333,12 +341,13 @@ export const buildBlock = async (

export const dryRunExtrinsic = async (
head: Block,
inherents: HexString[],
inherentProviders: InherentProvider[],
extrinsic: HexString | { call: HexString; address: string },
params: BuildBlockParams,
): Promise<TaskCallResponse> => {
const registry = await head.registry
const header = await newHeader(head)
const { block: newBlock } = await initNewBlock(head, header, inherents)
const { block: newBlock } = await initNewBlock(head, header, inherentProviders, params)

if (typeof extrinsic !== 'string') {
if (!head.chain.mockSignatureHost) {
Expand Down Expand Up @@ -377,10 +386,11 @@ export const dryRunExtrinsic = async (

export const dryRunInherents = async (
head: Block,
inherents: HexString[],
inherentProviders: InherentProvider[],
params: BuildBlockParams,
): Promise<[HexString, HexString | null][]> => {
const header = await newHeader(head)
const { layers } = await initNewBlock(head, header, inherents)
const { layers } = await initNewBlock(head, header, inherentProviders, params)
const storage = {}
for (const layer of layers) {
await layer.mergeInto(storage)
Expand Down
47 changes: 20 additions & 27 deletions packages/core/src/blockchain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export interface Options {
/** Build block mode. Default to Batch. */
buildBlockMode?: BuildBlockMode
/** Inherent provider, for creating inherents. */
inherentProvider: InherentProvider
inherentProviders: InherentProvider[]
/** Datasource for caching storage and blocks data. */
db?: Database
/** Used to create the initial head. */
Expand Down Expand Up @@ -59,7 +59,7 @@ export interface Options {
* const chain = new Blockchain({
* api,
* buildBlockMode: BuildBlockMode.Manual,
* inherentProvider: inherents,
* inherentProviders,
* header: {
* hash: blockHash,
* number: Number(header.number),
Expand All @@ -86,7 +86,7 @@ export class Blockchain {
readonly registeredTypes: RegisteredTypes

readonly #txpool: TxPool
readonly #inherentProvider: InherentProvider
readonly #inherentProviders: InherentProvider[]

#head: Block
readonly #blocksByNumber: Map<number, Block> = new Map()
Expand Down Expand Up @@ -126,7 +126,7 @@ export class Blockchain {
constructor({
api,
buildBlockMode,
inherentProvider,
inherentProviders,
db,
header,
mockSignatureHost = false,
Expand All @@ -146,8 +146,8 @@ export class Blockchain {
this.#head = new Block(this, header.number, header.hash)
this.#registerBlock(this.#head)

this.#txpool = new TxPool(this, inherentProvider, buildBlockMode)
this.#inherentProvider = inherentProvider
this.#txpool = new TxPool(this, inherentProviders, buildBlockMode)
this.#inherentProviders = inherentProviders

this.headState = new HeadState(this.#head)

Expand Down Expand Up @@ -427,13 +427,13 @@ export class Blockchain {
throw new Error(`Cannot find block ${at}`)
}
const registry = await head.registry
const inherents = await this.#inherentProvider.createInherents(head, {
const params = {
transactions: [],
downwardMessages: [],
upwardMessages: [],
horizontalMessages: {},
})
const { result, storageDiff } = await dryRunExtrinsic(head, inherents, extrinsic)
}
const { result, storageDiff } = await dryRunExtrinsic(head, this.#inherentProviders, extrinsic, params)
const outcome = registry.createType<ApplyExtrinsicResult>('ApplyExtrinsicResult', result)
return { outcome, storageDiff }
}
Expand All @@ -451,13 +451,13 @@ export class Blockchain {
if (!head) {
throw new Error(`Cannot find block ${at}`)
}
const inherents = await this.#inherentProvider.createInherents(head, {
const params = {
transactions: [],
downwardMessages: [],
upwardMessages: [],
horizontalMessages: hrmp,
})
return dryRunInherents(head, inherents)
}
return dryRunInherents(head, this.#inherentProviders, params)
}

/**
Expand All @@ -470,13 +470,13 @@ export class Blockchain {
if (!head) {
throw new Error(`Cannot find block ${at}`)
}
const inherents = await this.#inherentProvider.createInherents(head, {
const params = {
transactions: [],
downwardMessages: dmp,
upwardMessages: [],
horizontalMessages: {},
})
return dryRunInherents(head, inherents)
}
return dryRunInherents(head, this.#inherentProviders, params)
}

/**
Expand Down Expand Up @@ -511,27 +511,20 @@ export class Blockchain {
}

head.pushStorageLayer().setAll(storageValues)
const inherents = await this.#inherentProvider.createInherents(head, {
const params = {
transactions: [],
downwardMessages: [],
upwardMessages: [],
horizontalMessages: {},
})
return dryRunInherents(head, inherents)
}
return dryRunInherents(head, this.#inherentProviders, params)
}

/**
* Get inherents of head.
*/
async getInherents(): Promise<HexString[]> {
await this.api.isReady
const inherents = await this.#inherentProvider.createInherents(this.head, {
transactions: [],
downwardMessages: [],
upwardMessages: [],
horizontalMessages: {},
})
return inherents
getInherents(): InherentProvider[] {
return this.#inherentProviders
}

/**
Expand Down
49 changes: 14 additions & 35 deletions packages/core/src/blockchain/inherent/index.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,20 @@
import { Block } from '../block.js'
import { BuildBlockParams } from '../txpool.js'
import { GenericExtrinsic } from '@polkadot/types'
import { HexString } from '@polkadot/util/types'
import { getCurrentTimestamp, getSlotDuration } from '../../utils/time-travel.js'
import { ParaInherentEnter } from './para-enter.js'
import { SetBabeRandomness } from './parachain/babe-randomness.js'
import { SetNimbusAuthorInherent } from './parachain/nimbus-author-inherent.js'
import { SetTimestamp } from './timestamp.js'
import { SetValidationData } from './parachain/validation-data.js'

export { SetValidationData } from './parachain/validation-data.js'
export { ParaInherentEnter } from './para-enter.js'
export { SetBabeRandomness } from './parachain/babe-randomness.js'
export { SetNimbusAuthorInherent } from './parachain/nimbus-author-inherent.js'

export interface CreateInherents {
createInherents(parent: Block, params: BuildBlockParams): Promise<HexString[]>
}

export type InherentProvider = CreateInherents

export class SetTimestamp implements InherentProvider {
async createInherents(parent: Block): Promise<HexString[]> {
const meta = await parent.meta
const slotDuration = await getSlotDuration(parent.chain)
const currentTimestamp = await getCurrentTimestamp(parent.chain)
return [new GenericExtrinsic(meta.registry, meta.tx.timestamp.set(currentTimestamp + BigInt(slotDuration))).toHex()]
}
export interface InherentProvider {
createInherents(newBlock: Block, params: BuildBlockParams): Promise<HexString[]>
}

export class InherentProviders implements InherentProvider {
readonly #base: InherentProvider
readonly #providers: CreateInherents[]

constructor(base: InherentProvider, providers: CreateInherents[]) {
this.#base = base
this.#providers = providers
}

async createInherents(parent: Block, params: BuildBlockParams): Promise<HexString[]> {
const base = await this.#base.createInherents(parent, params)
const extra = await Promise.all(this.#providers.map((provider) => provider.createInherents(parent, params)))
return [...base, ...extra.flat()]
}
}
export const inherentProviders = [
new SetTimestamp(),
new SetValidationData(),
new ParaInherentEnter(),
new SetNimbusAuthorInherent(),
new SetBabeRandomness(),
]
9 changes: 6 additions & 3 deletions packages/core/src/blockchain/inherent/para-enter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import { HexString } from '@polkadot/util/types'

import { Block } from '../block.js'
import { BuildBlockParams } from '../txpool.js'
import { CreateInherents } from './index.js'
import { InherentProvider } from './index.js'

export class ParaInherentEnter implements InherentProvider {
async createInherents(newBlock: Block, _params: BuildBlockParams): Promise<HexString[]> {
const parent = await newBlock.parentBlock
if (!parent) throw new Error('parent block not found')

export class ParaInherentEnter implements CreateInherents {
async createInherents(parent: Block, _params: BuildBlockParams): Promise<HexString[]> {
const meta = await parent.meta
if (!meta.tx.paraInherent?.enter) {
return []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ import { HexString } from '@polkadot/util/types'

import { Block } from '../../block.js'
import { BuildBlockParams } from '../../txpool.js'
import { CreateInherents } from '../index.js'
import { InherentProvider } from '../index.js'

// Support for Moonbeam pallet-randomness mandatory inherent
export class SetBabeRandomness implements CreateInherents {
async createInherents(parent: Block, _params: BuildBlockParams): Promise<HexString[]> {
export class SetBabeRandomness implements InherentProvider {
async createInherents(newBlock: Block, _params: BuildBlockParams): Promise<HexString[]> {
const parent = await newBlock.parentBlock
if (!parent) throw new Error('parent block not found')

const meta = await parent.meta
if (!meta.tx.randomness?.setBabeRandomnessResults) {
return []
Expand Down
Loading
Loading