Skip to content

Commit

Permalink
Fix api (#373)
Browse files Browse the repository at this point in the history
* fix api

* test api

* cleanup

* cleanup

* cleanup
  • Loading branch information
ermalkaleci authored Aug 18, 2023
1 parent 005f007 commit bf91870
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 36 deletions.
20 changes: 20 additions & 0 deletions packages/core/src/api.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Api } from './api'
import { WsProvider } from '@polkadot/api'
import { expect, test } from 'vitest'

test('handle invalid block hash', async () => {
const api = new Api(new WsProvider('wss://acala-rpc-0.aca-api.network'))
await api.isReady

await expect(api.getHeader('0x')).rejects.toThrow('invalid length')
expect(await api.getHeader('0xc87ae632b2cc4583a37659785f5098947acfdc6a36dbb07abcfa6ad694f97c5d')).toBeNull()
expect(await api.getBlock('0xc87ae632b2cc4583a37659785f5098947acfdc6a36dbb07abcfa6ad694f97c5d')).toBeNull()
expect(await api.getBlockHash(999999999)).toBeNull()
expect(await api.getBlockHash()).toBeTruthy()
expect(await api.getStorage('0x0001')).toBeNull()
await expect(
api.getKeysPaged('0x', 1, '0x', '0xc87ae632b2cc4583a37659785f5098947acfdc6a36dbb07abcfa6ad694f97c5d'),
).rejects.toThrow('Header was not found')

await api.disconnect()
})
15 changes: 7 additions & 8 deletions packages/core/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,26 +86,25 @@ export class Api {
return this.#provider.send<string>('system_chain', [])
}

async getMetadata(hash?: string) {
return this.#provider.send<string>('state_getMetadata', hash ? [hash] : [])
}

async getBlockHash(blockNumber?: number) {
return this.#provider.send<HexString>('chain_getBlockHash', Number.isInteger(blockNumber) ? [blockNumber] : [])
return this.#provider.send<HexString | null>(
'chain_getBlockHash',
Number.isInteger(blockNumber) ? [blockNumber] : [],
)
}

async getHeader(hash?: string) {
return this.#provider.send<Header>('chain_getHeader', hash ? [hash] : [])
return this.#provider.send<Header | null>('chain_getHeader', hash ? [hash] : [])
}

async getBlock(hash?: string) {
return this.#provider.send<SignedBlock>('chain_getBlock', hash ? [hash] : [])
return this.#provider.send<SignedBlock | null>('chain_getBlock', hash ? [hash] : [])
}

async getStorage(key: string, hash?: string) {
const params = [key]
if (hash) params.push(hash)
return this.#provider.send<string>('state_getStorage', params)
return this.#provider.send<string | null>('state_getStorage', params)
}

async getKeysPaged(prefix: string, pageSize: number, startKey: string, hash?: string) {
Expand Down
7 changes: 6 additions & 1 deletion packages/core/src/blockchain/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,12 @@ export class Block {

get extrinsics(): HexString[] | Promise<HexString[]> {
if (!this.#extrinsics) {
this.#extrinsics = this.#chain.api.getBlock(this.hash).then((b) => b.block.extrinsics)
this.#extrinsics = this.#chain.api.getBlock(this.hash).then((b) => {
if (!b) {
throw new Error(`Block ${this.hash} not found`)
}
return b.block.extrinsics
})
}
return this.#extrinsics
}
Expand Down
9 changes: 8 additions & 1 deletion packages/core/src/blockchain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,9 @@ export class Blockchain {
.getRepository(BlockEntity)
.findOne({ where: { [typeof key === 'number' ? 'number' : 'hash']: key } })
if (blockData) {
const { hash, number, header, extrinsics, parentHash, storageDiff } = blockData
const { hash, number, header, extrinsics, parentHash } = blockData
const parentBlock = parentHash ? this.#blocksByHash[parentHash] : undefined
const storageDiff = blockData.storageDiff ?? undefined
const block = new Block(this, number, hash, parentBlock, { header, extrinsics, storageDiff })
this.#registerBlock(block)
return block
Expand All @@ -163,6 +164,9 @@ export class Blockchain {
return blockFromDB
}
const hash = await this.api.getBlockHash(number)
if (!hash) {
return undefined
}
const block = new Block(this, number, hash)
this.#registerBlock(block)
}
Expand All @@ -184,6 +188,9 @@ export class Blockchain {
const blockFromDB = await this.loadBlockFromDB(hash)
if (!blockFromDB) {
const header = await this.api.getHeader(hash)
if (!header) {
throw new Error(`Block ${hash} not found`)
}
const block = new Block(this, Number(header.number), hash)
this.#registerBlock(block)
}
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/blockchain/storage-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ export class RemoteStorageLayer implements StorageLayerProvider {
if (this.#db) {
const res = await keyValuePair?.findOne({ where: { key, blockHash: this.#at } })
if (res) {
return res.value
return res.value ?? undefined
}
}
logger.trace({ at: this.#at, key }, 'RemoteStorageLayer get')
const data = await this.#api.getStorage(key, this.#at)
keyValuePair?.upsert({ key, blockHash: this.#at, value: data }, ['key', 'blockHash'])
return data
return data ?? undefined
}

async foldInto(_into: StorageLayer): Promise<StorageLayerProvider> {
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/db/entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { HexString } from '@polkadot/util/types'
export const KeyValuePair = new EntitySchema<{
blockHash: string
key: string
value?: string
value: string | null
}>({
name: 'KeyValuePair',
columns: {
Expand All @@ -30,9 +30,9 @@ export const BlockEntity = new EntitySchema<{
hash: HexString
number: number
header: Header
parentHash?: HexString
parentHash: HexString | null
extrinsics: HexString[]
storageDiff?: Record<HexString, HexString | null>
storageDiff: Record<HexString, HexString | null> | null
}>({
name: 'Block',
columns: {
Expand Down
16 changes: 1 addition & 15 deletions packages/core/src/genesis-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ import {
ProviderInterfaceEmitted,
ProviderStats,
} from '@polkadot/rpc-provider/types'
import { stringToHex } from '@polkadot/util'
import axios from 'axios'

import { Genesis, genesisSchema } from './schema'
import { JsCallback, calculateStateRoot, emptyTaskHandler, runTask } from './executor'
import { JsCallback, calculateStateRoot, emptyTaskHandler } from './executor'
import { isUrl } from './utils'

export class GenesisProvider implements ProviderInterface {
Expand Down Expand Up @@ -152,19 +151,6 @@ export class GenesisProvider implements ProviderInterface {
return this.#genesis.id
case 'system_name':
return this.#genesis.name
case 'state_getMetadata': {
const code = this.#genesis.genesis.raw.top[stringToHex(':code')] as HexString
return runTask(
{
wasm: code,
calls: [['Metadata_metadata', []]],
mockSignatureHost: false,
allowUnresolvedImports: true,
runtimeLogLevel: 0,
},
this._jsCallback,
)
}
case 'chain_getHeader':
return this.getHeader()
case 'chain_getBlock':
Expand Down
15 changes: 15 additions & 0 deletions packages/core/src/setup.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { expect, test } from 'vitest'
import { setup } from './setup'

test('handle invalid block ', async () => {
await expect(setup({ endpoint: 'wss://acala-rpc-0.aca-api.network', block: '0x' })).rejects.toThrow('invalid length')
await expect(setup({ endpoint: 'wss://acala-rpc-0.aca-api.network', block: 999999999 })).rejects.toThrow(
'Cannot find block hash for 999999999',
)
await expect(
setup({
endpoint: 'wss://acala-rpc-0.aca-api.network',
block: '0xc87ae632b2cc4583a37659785f5098947acfdc6a36dbb07abcfa6ad694f97c5d',
}),
).rejects.toThrow('Cannot find header for 0xc87ae632b2cc4583a37659785f5098947acfdc6a36dbb07abcfa6ad694f97c5d')
})
21 changes: 16 additions & 5 deletions packages/core/src/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,22 @@ export const setup = async (options: Options) => {

let blockHash: string
if (options.block == null) {
blockHash = await api.getBlockHash()
blockHash = await api.getBlockHash().then((hash) => {
if (!hash) {
// should not happen, but just in case
throw new Error('Cannot find block hash')
}
return hash
})
} else if (typeof options.block === 'string' && options.block.startsWith('0x')) {
blockHash = options.block as string
} else if (Number.isInteger(+options.block)) {
blockHash = await api.getBlockHash(Number(options.block))
if (!blockHash) {
throw new Error(`Cannot find block hash for ${options.block}`)
}
blockHash = await api.getBlockHash(Number(options.block)).then((hash) => {
if (!hash) {
throw new Error(`Cannot find block hash for ${options.block}`)
}
return hash
})
} else {
throw new Error(`Invalid block number or hash: ${options.block}`)
}
Expand All @@ -71,6 +79,9 @@ export const setup = async (options: Options) => {
}

const header = await api.getHeader(blockHash)
if (!header) {
throw new Error(`Cannot find header for ${blockHash}`)
}

const inherents = new InherentProviders(new SetTimestamp(), [
new SetValidationData(),
Expand Down
10 changes: 9 additions & 1 deletion packages/e2e/src/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ export const setupAll = async ({
await api.isReady

const header = await api.getHeader(blockHash)
if (!header) {
throw new Error(`Cannot find header for ${blockHash}`)
}

return {
async setup() {
Expand All @@ -70,12 +73,17 @@ export const setupAll = async ({
new SetBabeRandomness(),
])

blockHash ??= await api.getBlockHash().then((hash) => hash ?? undefined)
if (!blockHash) {
throw new Error('Cannot find block hash')
}

const chain = new Blockchain({
api,
buildBlockMode: BuildBlockMode.Manual,
inherentProvider: inherents,
header: {
hash: blockHash || (await api.getBlockHash()),
hash: blockHash,
number: Number(header.number),
},
mockSignatureHost,
Expand Down

0 comments on commit bf91870

Please sign in to comment.