Skip to content

Commit

Permalink
add feature to dry-run preimage (#179)
Browse files Browse the repository at this point in the history
  • Loading branch information
ermalkaleci authored Jan 30, 2023
1 parent daed180 commit 3b20760
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 5 deletions.
2 changes: 1 addition & 1 deletion src/blockchain/block-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const getNewSlot = (digest: RawBabePreDigest, slotNumber: number) => {
return digest.toJSON()
}

const newHeader = async (head: Block) => {
export const newHeader = async (head: Block) => {
const meta = await head.meta
const parentHeader = await head.header

Expand Down
6 changes: 6 additions & 0 deletions src/blockchain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,4 +192,10 @@ export class Blockchain {
const inherents = await this.#inherentProvider.createInherents(head, { horizontalMessages: hrmp })
return dryRunInherents(head, inherents)
}

async getInherents(): Promise<HexString[]> {
await this.api.isReady
const inherents = await this.#inherentProvider.createInherents(this.head)
return inherents
}
}
13 changes: 11 additions & 2 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Blockchain, BuildBlockMode, connectParachains, connectVertical, setup,
import { configSchema } from './schema'
import { decodeKey } from './utils/decoder'
import { dryRun } from './dry-run'
import { dryRunPreimage } from './dry-run-preimage'
import { isUrl } from './utils'
import { runBlock } from './run-block'

Expand Down Expand Up @@ -88,12 +89,15 @@ yargs(hideBin(process.argv))
extrinsic: {
desc: 'Extrinsic or call to dry run. If you pass call here then address is required to fake signature',
string: true,
required: true,
},
address: {
desc: 'Address to fake sign extrinsic',
string: true,
},
preimage: {
desc: 'Preimage to dry run',
string: true,
},
at: {
desc: 'Block hash to dry run',
string: true,
Expand All @@ -110,7 +114,12 @@ yargs(hideBin(process.argv))
},
}),
async (argv) => {
await dryRun(await processArgv(argv))
const config = await processArgv(argv)
if (config.preimage) {
await dryRunPreimage(config)
} else {
await dryRun(config)
}
}
)
.command(
Expand Down
120 changes: 120 additions & 0 deletions src/dry-run-preimage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { HexString } from '@polkadot/util/types'
import { blake2AsHex } from '@polkadot/util-crypto'
import { hexToU8a } from '@polkadot/util'

import { Config } from './schema'
import { defaultLogger } from './logger'
import { generateHtmlDiffPreviewFile } from './utils/generate-html-diff'
import { newHeader } from './blockchain/block-builder'
import { openHtml } from './utils/open-html'
import { runTask, taskHandler } from './executor'
import { setStorage } from './utils/set-storage'
import { setup } from './setup'

export const dryRunPreimage = async (argv: Config) => {
const context = await setup(argv)

const extrinsic = argv['preimage']

const block = context.chain.head
const registry = await block.registry

const header = await newHeader(block)

const data = hexToU8a(extrinsic)
const hash = blake2AsHex(data, 256)

await setStorage(context.chain, {
Preimage: {
PreimageFor: [[[[hash, data.byteLength]], extrinsic]],
StatusFor: [
[
[hash],
{
Requested: {
count: 1,
len: data.byteLength,
},
},
],
],
},
Scheduler: {
Agenda: [
[
[block.number + 1],
[
{
maybeId: '0x64656d6f637261633a0000000000000000000000000000000000000000000000',
priority: 63,
call: {
Lookup: {
hash: hash,
len: data.byteLength,
},
},
origin: { system: { Root: null } },
},
],
],
],
Lookup: [[['0x64656d6f637261633a0000000000000000000000000000000000000000000000'], [block.number + 1, 0]]],
},
})

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

for (const inherent of await block.chain.getInherents()) {
calls.push(['BlockBuilder_apply_extrinsic', [inherent]])
}

calls.push(['BlockBuilder_finalize_block', []])

defaultLogger.info({ preimage: registry.createType('Call', data).toHuman() }, 'Dry run preimage')

const result = await runTask(
{
wasm: await block.wasm,
calls,
storage: [],
mockSignatureHost: false,
allowUnresolvedImports: false,
},
taskHandler(block)
)

if (result.Error) {
throw new Error(result.Error)
}

const filePath = await generateHtmlDiffPreviewFile(block, result.Call.storageDiff, hash)
console.log(`Generated preview ${filePath}`)
if (argv['open']) {
openHtml(filePath)
}

// if dry-run preimage has extrinsic arguments then dry-run extrinsic
// this is usefull to test something after preimage is applied
if (argv['extrinsic']) {
await context.chain.newBlock()
const input = argv['address'] ? { call: argv['extrinsic'], address: argv['address'] } : argv['extrinsic']
const { outcome, storageDiff } = await context.chain.dryRunExtrinsic(input)
if (outcome.isErr) {
throw new Error(outcome.asErr.toString())
} else {
defaultLogger.info(outcome.toHuman(), 'dry_run_outcome')
}

const filePath = await generateHtmlDiffPreviewFile(
context.chain.head,
storageDiff,
blake2AsHex(argv['extrinsic'], 256)
)
console.log(`Generated preview ${filePath}`)
if (argv['open']) {
openHtml(filePath)
}
}

process.exit(0)
}
6 changes: 4 additions & 2 deletions src/utils/set-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,13 @@ function objectToStorageItems(meta: DecoratedMeta, storage: StorageConfig): RawS

if (storageEntry.meta.type.isPlain) {
const key = new StorageKey(meta.registry, [storageEntry])
storageItems.push([key.toHex(), storage ? meta.registry.createType(key.outputType, storage).toHex(true) : null])
const type = storageEntry.meta.modifier.isOptional ? `Option<${key.outputType}>` : key.outputType
storageItems.push([key.toHex(), storage ? meta.registry.createType(type, storage).toHex() : null])
} else {
for (const [keys, value] of storage) {
const key = new StorageKey(meta.registry, [storageEntry, keys])
storageItems.push([key.toHex(), value ? meta.registry.createType(key.outputType, value).toHex(true) : null])
const type = storageEntry.meta.modifier.isOptional ? `Option<${key.outputType}>` : key.outputType
storageItems.push([key.toHex(), value ? meta.registry.createType(type, value).toHex() : null])
}
}
}
Expand Down

0 comments on commit 3b20760

Please sign in to comment.