Skip to content

Commit

Permalink
registry cache (#540)
Browse files Browse the repository at this point in the history
* registry cache

* fix
  • Loading branch information
ermalkaleci authored Nov 12, 2023
1 parent b00c113 commit 9d05cd4
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 38 deletions.
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

0 comments on commit 9d05cd4

Please sign in to comment.