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

registry cache #540

Merged
merged 2 commits into from
Nov 12, 2023
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
32 changes: 5 additions & 27 deletions packages/core/src/blockchain/block.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { ChainProperties, Header } from '@polkadot/types/interfaces'
import { DecoratedMeta } from '@polkadot/types/metadata/decorate/types'
import { Header } from '@polkadot/types/interfaces'
import { Metadata, TypeRegistry } from '@polkadot/types'
import { StorageEntry } from '@polkadot/types/primitive/types'
import { expandMetadata } from '@polkadot/types/metadata'
import { getSpecExtensions, getSpecHasher, getSpecTypes } from '@polkadot/types-known/util'
import { hexToU8a, objectSpread, stringToHex } from '@polkadot/util'
import type { ExtDef } from '@polkadot/types/extrinsic/signedExtensions/types'
import { hexToU8a, stringToHex } from '@polkadot/util'
import type { HexString } from '@polkadot/util/types'

import { Blockchain } from './index.js'
Expand Down Expand Up @@ -254,29 +252,9 @@ export class Block {
*/
get registry(): Promise<TypeRegistry> {
if (!this.#registry) {
this.#registry = Promise.all([
this.metadata,
this.#chain.api.chainProperties,
this.#chain.api.chain,
this.runtimeVersion,
]).then(([data, properties, chain, version]) => {
const registry = new TypeRegistry(this.hash)
registry.setKnownTypes(this.chain.registeredTypes)
registry.setChainProperties(registry.createType('ChainProperties', properties) as ChainProperties)
registry.register(getSpecTypes(registry, chain, version.specName, version.specVersion))
registry.setHasher(getSpecHasher(registry, chain, version.specName))
registry.setMetadata(
new Metadata(registry, data),
undefined,
objectSpread<ExtDef>(
{},
getSpecExtensions(registry, chain, version.specName),
this.#chain.api.signedExtensions,
),
true,
)
return registry
})
this.#registry = Promise.all([this.metadata, this.runtimeVersion]).then(([data, version]) =>
this.#chain.buildRegistry(data, version),
)
}
return this.#registry
}
Expand Down
38 changes: 34 additions & 4 deletions packages/core/src/blockchain/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { ApplyExtrinsicResult, Header } from '@polkadot/types/interfaces'
import { ApplyExtrinsicResult, ChainProperties, Header } from '@polkadot/types/interfaces'
import { HexString } from '@polkadot/util/types'
import { Metadata, TypeRegistry } from '@polkadot/types'
import { RegisteredTypes } from '@polkadot/types/types'
import { blake2AsHex } from '@polkadot/util-crypto'
import { u8aConcat, u8aToHex } from '@polkadot/util'
import { blake2AsHex, xxhashAsHex } from '@polkadot/util-crypto'
import { getSpecExtensions, getSpecHasher, getSpecTypes } from '@polkadot/types-known/util'
import { objectSpread, u8aConcat, u8aToHex } from '@polkadot/util'
import _ from 'lodash'
import type { ExtDef } from '@polkadot/types/extrinsic/signedExtensions/types'
import type { TransactionValidity } from '@polkadot/types/interfaces/txqueue'

import { Api } from '../api.js'
Expand All @@ -12,11 +16,11 @@ import { Database } from '../database.js'
import { HeadState } from './head-state.js'
import { InherentProvider } from './inherent/index.js'
import { OffchainWorker } from '../offchain.js'
import { RuntimeVersion, releaseWorker } from '../wasm-executor/index.js'
import { StorageValue } from './storage-layer.js'
import { compactHex } from '../utils/index.js'
import { defaultLogger } from '../logger.js'
import { dryRunExtrinsic, dryRunInherents } from './block-builder.js'
import { releaseWorker } from '../wasm-executor/index.js'

const logger = defaultLogger.child({ name: 'blockchain' })

Expand Down Expand Up @@ -96,6 +100,27 @@ export class Blockchain {
readonly offchainWorker: OffchainWorker | undefined
readonly #maxMemoryBlockCount: number

// first arg is used as cache key
readonly #registryBuilder = _.memoize(
async (_cacheKey: string, metadata: HexString, version: RuntimeVersion): Promise<TypeRegistry> => {
const chain = await this.api.chain
const properties = await this.api.chainProperties

const registry = new TypeRegistry()
registry.setKnownTypes(this.registeredTypes)
registry.setChainProperties(registry.createType('ChainProperties', properties) as ChainProperties)
registry.register(getSpecTypes(registry, chain, version.specName, version.specVersion))
registry.setHasher(getSpecHasher(registry, chain, version.specName))
registry.setMetadata(
new Metadata(registry, metadata),
undefined,
objectSpread<ExtDef>({}, getSpecExtensions(registry, chain, version.specName), this.api.signedExtensions),
true,
)
return registry
},
)

/**
* @param options - Options for instantiating the blockchain
*/
Expand Down Expand Up @@ -162,6 +187,11 @@ export class Blockchain {
logger.debug(`Runtime log level set to ${logger.level}`)
}

async buildRegistry(metadata: HexString, version: RuntimeVersion) {
const cacheKey = `${xxhashAsHex(metadata, 256)}-${version.specVersion}`
return this.#registryBuilder(cacheKey, metadata, version)
}

async saveBlockToDB(block: Block) {
if (this.db) {
const { hash, number, header, extrinsics } = block
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/utils/time-travel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const getSlotDuration = async (chain: Blockchain) => {
return meta.consts.babe
? (meta.consts.babe.expectedBlockTime as any as BN).toNumber()
: meta.query.aura
? getAuraSlotDuration(await chain.head.wasm, meta.registry)
? getAuraSlotDuration(await chain.head.wasm)
: 12_000
}

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/wasm-executor/executor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ describe('wasm', () => {
})

it('get aura slot duration', async () => {
const slotDuration = await getAuraSlotDuration(getCode(), new TypeRegistry())
const slotDuration = await getAuraSlotDuration(getCode())
expect(slotDuration).eq(12000)
})
})
8 changes: 3 additions & 5 deletions packages/core/src/wasm-executor/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as Comlink from 'comlink'
import { HexString } from '@polkadot/util/types'
import { Registry } from '@polkadot/types-codec/types'
import { hexToString, hexToU8a } from '@polkadot/util'
import { hexToString, hexToU8a, u8aToBn } from '@polkadot/util'
import { randomAsHex } from '@polkadot/util-crypto'
import _ from 'lodash'

Expand Down Expand Up @@ -201,7 +200,7 @@ export const emptyTaskHandler = {
},
}

export const getAuraSlotDuration = _.memoize(async (wasm: HexString, registry: Registry): Promise<number> => {
export const getAuraSlotDuration = _.memoize(async (wasm: HexString): Promise<number> => {
const result = await runTask({
wasm,
calls: [['AuraApi_slot_duration', []]],
Expand All @@ -211,8 +210,7 @@ export const getAuraSlotDuration = _.memoize(async (wasm: HexString, registry: R
})

if ('Error' in result) throw new Error(result.Error)
const slotDuration = registry.createType('u64', hexToU8a(result.Call.result)).toNumber()
return slotDuration
return u8aToBn(hexToU8a(result.Call.result).subarray(0, 8 /* u64: 8 bytes */)).toNumber()
})

export const releaseWorker = async () => {
Expand Down