From 9d05cd43a1ce84d82d72b8ec52fc026b8341f062 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Sun, 12 Nov 2023 18:25:17 +0100 Subject: [PATCH] registry cache (#540) * registry cache * fix --- packages/core/src/blockchain/block.ts | 32 +++------------- packages/core/src/blockchain/index.ts | 38 +++++++++++++++++-- packages/core/src/utils/time-travel.ts | 2 +- .../core/src/wasm-executor/executor.test.ts | 2 +- packages/core/src/wasm-executor/index.ts | 8 ++-- 5 files changed, 44 insertions(+), 38 deletions(-) diff --git a/packages/core/src/blockchain/block.ts b/packages/core/src/blockchain/block.ts index 8cac7bff..d45915b0 100644 --- a/packages/core/src/blockchain/block.ts +++ b/packages/core/src/blockchain/block.ts @@ -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' @@ -254,29 +252,9 @@ export class Block { */ get registry(): Promise { 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( - {}, - 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 } diff --git a/packages/core/src/blockchain/index.ts b/packages/core/src/blockchain/index.ts index 32939818..6261ac72 100644 --- a/packages/core/src/blockchain/index.ts +++ b/packages/core/src/blockchain/index.ts @@ -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' @@ -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' }) @@ -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 => { + 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({}, getSpecExtensions(registry, chain, version.specName), this.api.signedExtensions), + true, + ) + return registry + }, + ) + /** * @param options - Options for instantiating the blockchain */ @@ -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 diff --git a/packages/core/src/utils/time-travel.ts b/packages/core/src/utils/time-travel.ts index 178dcee8..69a4cea8 100644 --- a/packages/core/src/utils/time-travel.ts +++ b/packages/core/src/utils/time-travel.ts @@ -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 } diff --git a/packages/core/src/wasm-executor/executor.test.ts b/packages/core/src/wasm-executor/executor.test.ts index ff14038b..260e04de 100644 --- a/packages/core/src/wasm-executor/executor.test.ts +++ b/packages/core/src/wasm-executor/executor.test.ts @@ -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) }) }) diff --git a/packages/core/src/wasm-executor/index.ts b/packages/core/src/wasm-executor/index.ts index 5ee95db7..7d8c0ede 100644 --- a/packages/core/src/wasm-executor/index.ts +++ b/packages/core/src/wasm-executor/index.ts @@ -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' @@ -201,7 +200,7 @@ export const emptyTaskHandler = { }, } -export const getAuraSlotDuration = _.memoize(async (wasm: HexString, registry: Registry): Promise => { +export const getAuraSlotDuration = _.memoize(async (wasm: HexString): Promise => { const result = await runTask({ wasm, calls: [['AuraApi_slot_duration', []]], @@ -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 () => {