Skip to content

Commit

Permalink
add tests for chainHead_v1
Browse files Browse the repository at this point in the history
  • Loading branch information
voliva committed Sep 3, 2024
1 parent 0413fa6 commit f249d48
Show file tree
Hide file tree
Showing 5 changed files with 324 additions and 3 deletions.
3 changes: 3 additions & 0 deletions packages/e2e/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
"devDependencies": {
"@acala-network/chopsticks": "workspace:*",
"@acala-network/chopsticks-testing": "workspace:*",
"@polkadot-api/substrate-bindings": "^0.6.3",
"@polkadot-api/substrate-client": "^0.2.1",
"@polkadot-api/ws-provider": "^0.2.0",
"@polkadot/api": "^12.3.1",
"typescript": "^5.5.3",
"vitest": "^1.4.0"
Expand Down
87 changes: 87 additions & 0 deletions packages/e2e/src/__snapshots__/chainHead_v1.test.ts.snap

Large diffs are not rendered by default.

145 changes: 145 additions & 0 deletions packages/e2e/src/chainHead_v1.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { Binary } from '@polkadot-api/substrate-bindings'
import { describe, expect, it, vi } from 'vitest'
import type { FollowEventWithRuntime, StorageItemResponse } from '@polkadot-api/substrate-client'

import { api, asyncSpy, dev, env, setupApi, substrateClient } from './helper.js'

setupApi(env.acala)

describe('chainHead_v1 rpc', () => {
it('reports the chain state', async () => {
const onEvent = asyncSpy<[FollowEventWithRuntime], []>()
const onError = vi.fn()
const follower = substrateClient.chainHead(true, onEvent, onError)

const initialized = await onEvent.nextCall()
expect(initialized).toMatchSnapshot()

const blockHash = await dev.newBlock()

const [[newBlock], [bestBlock], [finalized]] = onEvent.mock.calls.slice(1)

expect(newBlock).toEqual({
type: 'newBlock',
blockHash,
parentBlockHash: {},
newRuntime: null,
})
expect(bestBlock).toEqual({
type: 'bestBlockChanged',
bestBlockHash: blockHash,
})
expect(finalized).toEqual({
type: 'finalized',
finalizedBlockHashes: [blockHash],
prunedBlockHashes: [],
})

expect(onError).not.toHaveBeenCalled()
follower.unfollow()
})

it('resolves storage queries', async () => {
const onEvent = asyncSpy<[FollowEventWithRuntime], []>()
const onError = vi.fn()
const follower = substrateClient.chainHead(true, onEvent, onError)

const initialized = await onEvent.nextCall()
const initializedHash = (initialized.type === 'initialized' && initialized.finalizedBlockHashes[0]) || ''

const key = Binary.fromBytes(
api.query.system.account.creator('5F98oWfz2r5rcRVnP9VCndg33DAAsky3iuoBSpaPUbgN9AJn').slice(2),
).asHex()

// An empty value resolves to null
expect(await follower.storage(initializedHash, 'value', key, null)).toEqual(null)

// With an existing value it returns the SCALE-encoded value.
const hash = '0xfc41b9bd8ef8fe53d58c7ea67c794c7ec9a73daf05e6d54b14ff6342c99ba64c'
expect(await follower.storage(hash, 'value', key, null)).toMatchSnapshot()

expect(onError).not.toHaveBeenCalled()
follower.unfollow()
})

it('resolves partial key storage queries', async () => {
const onEvent = asyncSpy<[FollowEventWithRuntime], []>()
const onError = vi.fn()
const follower = substrateClient.chainHead(true, onEvent, onError)

const initialized = await onEvent.nextCall()
const initializedHash = (initialized.type === 'initialized' && initialized.finalizedBlockHashes[0]) || ''

const key = Binary.fromBytes(api.query.tokens.totalIssuance.creator.iterKey!()).asHex()

// An empty value resolves to null
let receivedItems: StorageItemResponse[] = []
const onDone = asyncSpy()
const onDiscardedItems = vi.fn()
follower.storageSubscription(
initializedHash,
[
{
key,
type: 'descendantsValues',
},
],
null,
(items) => (receivedItems = [...receivedItems, ...items]),
onError,
onDone,
onDiscardedItems,
)
await onDone.nextCall()

expect(onDiscardedItems).toHaveBeenCalledWith(0)
expect(receivedItems.length).toEqual(23)

expect(onError).not.toHaveBeenCalled()
follower.unfollow()
})

it('resolves the header for a specific block', async () => {
const onEvent = asyncSpy<[FollowEventWithRuntime], []>()
const onError = vi.fn()
const follower = substrateClient.chainHead(true, onEvent, onError)

const initialized = await onEvent.nextCall()
const hash = (initialized.type === 'initialized' && initialized.finalizedBlockHashes[0]) || ''

expect(await follower.header(hash)).toMatchSnapshot()

expect(onError).not.toHaveBeenCalled()
follower.unfollow()
})

it('runs runtime calls', async () => {
const onEvent = asyncSpy<[FollowEventWithRuntime], []>()
const onError = vi.fn()
const follower = substrateClient.chainHead(true, onEvent, onError)

const initialized = await onEvent.nextCall()
const hash = (initialized.type === 'initialized' && initialized.finalizedBlockHashes[0]) || ''

expect(await follower.call(hash, 'Core_version', '')).toMatchSnapshot()

await expect(follower.call(hash, 'bruh', '')).rejects.toThrow('Function to start was not found')

expect(onError).not.toHaveBeenCalled()
follower.unfollow()
})

it('retrieves the body for a specific block', async () => {
const onEvent = asyncSpy<[FollowEventWithRuntime], []>()
const onError = vi.fn()
const follower = substrateClient.chainHead(true, onEvent, onError)

const initialized = await onEvent.nextCall()
const hash = (initialized.type === 'initialized' && initialized.finalizedBlockHashes[0]) || ''

expect(await follower.body(hash)).toMatchSnapshot()

expect(onError).not.toHaveBeenCalled()
follower.unfollow()
})
})
24 changes: 23 additions & 1 deletion packages/e2e/src/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import { ApiPromise, HttpProvider, WsProvider } from '@polkadot/api'
import { HexString } from '@polkadot/util/types'
import { ProviderInterface } from '@polkadot/rpc-provider/types'
import { RegisteredTypes } from '@polkadot/types/types'
import { SubstrateClient, createClient } from '@polkadot-api/substrate-client'
import { beforeAll, beforeEach, expect, vi } from 'vitest'
import { getWsProvider } from '@polkadot-api/ws-provider/node'

import { Api } from '@acala-network/chopsticks'
import { Blockchain, BuildBlockMode, StorageValues } from '@acala-network/chopsticks-core'
import { Deferred, defer } from '@acala-network/chopsticks-core/utils/index.js'
import { SqliteDatabase } from '@acala-network/chopsticks-db'
import { createServer } from '@acala-network/chopsticks/server.js'
import { defer } from '@acala-network/chopsticks-core/utils/index.js'
import { genesisFromUrl } from '@acala-network/chopsticks/context.js'
import { handler } from '@acala-network/chopsticks/rpc/index.js'
import { inherentProviders } from '@acala-network/chopsticks-core/blockchain/inherent/index.js'
Expand Down Expand Up @@ -102,13 +104,17 @@ export const setupAll = async ({
noInitWarn: true,
})

const substrateClient = createClient(getWsProvider(`ws://localhost:${port}`))

await apiPromise.isReady

return {
chain,
ws,
api: apiPromise,
substrateClient,
async teardown() {
substrateClient.destroy()
await apiPromise.disconnect()
await delay(100)
await close()
Expand All @@ -125,6 +131,7 @@ export const setupAll = async ({
export let api: ApiPromise
export let chain: Blockchain
export let ws: WsProvider
export let substrateClient: SubstrateClient

export const setupApi = (option: SetupOption) => {
let setup: Awaited<ReturnType<typeof setupAll>>['setup']
Expand All @@ -141,11 +148,26 @@ export const setupApi = (option: SetupOption) => {
api = res.api
chain = res.chain
ws = res.ws
substrateClient = res.substrateClient

return res.teardown
})
}

export const asyncSpy = <TArgs extends unknown[], TReturn>(implementation?: (...args: TArgs) => TReturn) => {
let deferred: Deferred<Flatten<TArgs>> | null = null
const nextCall = () => (deferred ?? (deferred = defer())).promise

const result = vi.fn((...args: TArgs) => {
deferred?.resolve((args.length === 1 ? args[0] : args) as any)
deferred = null
return implementation?.(...args) as TReturn
})

return Object.assign(result, { nextCall })
}
type Flatten<T extends Array<unknown>> = T['length'] extends 1 ? (T extends Array<infer R> ? R : never) : T

export const dev = {
newBlock: (param?: { count?: number; to?: number }): Promise<string> => {
return ws.send('dev_newBlock', [param])
Expand Down
68 changes: 66 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ __metadata:
dependencies:
"@acala-network/chopsticks": "workspace:*"
"@acala-network/chopsticks-testing": "workspace:*"
"@polkadot-api/substrate-bindings": "npm:^0.6.3"
"@polkadot-api/substrate-client": "npm:^0.2.1"
"@polkadot-api/ws-provider": "npm:^0.2.0"
"@polkadot/api": "npm:^12.3.1"
typescript: "npm:^5.5.3"
vitest: "npm:^1.4.0"
Expand Down Expand Up @@ -1261,6 +1264,13 @@ __metadata:
languageName: node
linkType: hard

"@noble/hashes@npm:^1.4.0":
version: 1.5.0
resolution: "@noble/hashes@npm:1.5.0"
checksum: 10c0/1b46539695fbfe4477c0822d90c881a04d4fa2921c08c552375b444a48cac9930cb1ee68de0a3c7859e676554d0f3771999716606dc4d8f826e414c11692cdd9
languageName: node
linkType: hard

"@nodelib/fs.scandir@npm:2.1.5":
version: 2.1.5
resolution: "@nodelib/fs.scandir@npm:2.1.5"
Expand Down Expand Up @@ -1389,13 +1399,27 @@ __metadata:
languageName: node
linkType: hard

"@polkadot-api/json-rpc-provider-proxy@npm:0.2.0":
version: 0.2.0
resolution: "@polkadot-api/json-rpc-provider-proxy@npm:0.2.0"
checksum: 10c0/f8b314e35b14d1b8599ad134246e6c006e5c13aa42d6c2d868c28fa69701becb05f142ce765258061b0320750abbe39654a26ea6b734b5ccb83e0193f59d2697
languageName: node
linkType: hard

"@polkadot-api/json-rpc-provider@npm:0.0.1":
version: 0.0.1
resolution: "@polkadot-api/json-rpc-provider@npm:0.0.1"
checksum: 10c0/90dc86693e7ef742c50484f4374d4b4f0eb7b5f7f618cf96a3dfed866fd18edf19132fc750b2944e8300d83c5601343f3876cbe60cd6bb1086301361d682ebd8
languageName: node
linkType: hard

"@polkadot-api/json-rpc-provider@npm:0.0.3":
version: 0.0.3
resolution: "@polkadot-api/json-rpc-provider@npm:0.0.3"
checksum: 10c0/7c27bf20263fea8d6f0b7c77e2498c535889448c3f65a8100f95f761859db39cd4bfdc6646fa2bda3af345d853a5320695cd3630506792f5a323077964c04399
languageName: node
linkType: hard

"@polkadot-api/metadata-builders@npm:0.0.1":
version: 0.0.1
resolution: "@polkadot-api/metadata-builders@npm:0.0.1"
Expand Down Expand Up @@ -1432,20 +1456,60 @@ __metadata:
languageName: node
linkType: hard

"@polkadot-api/substrate-bindings@npm:^0.6.3":
version: 0.6.3
resolution: "@polkadot-api/substrate-bindings@npm:0.6.3"
dependencies:
"@noble/hashes": "npm:^1.4.0"
"@polkadot-api/utils": "npm:0.1.1"
"@scure/base": "npm:^1.1.7"
scale-ts: "npm:^1.6.0"
checksum: 10c0/5405e536a03033b8b2d122214136166cd1f45502ae7089cd6dc59bdc5b50f07155fa03578da4a05a3b22ad4bd30ea17f3c1476114eae8601297b10dea045880a
languageName: node
linkType: hard

"@polkadot-api/substrate-client@npm:0.0.1":
version: 0.0.1
resolution: "@polkadot-api/substrate-client@npm:0.0.1"
checksum: 10c0/92dbe76ea434c8ee2ac6c42be2003a1823e7b6d25955981a1410e3c9aab700fa7e4f0871c98cd3eea30ed4388b0ecaf4eaedad111240e17373704152c1faca98
languageName: node
linkType: hard

"@polkadot-api/substrate-client@npm:^0.2.1":
version: 0.2.1
resolution: "@polkadot-api/substrate-client@npm:0.2.1"
dependencies:
"@polkadot-api/json-rpc-provider": "npm:0.0.3"
"@polkadot-api/utils": "npm:0.1.1"
checksum: 10c0/c057688c926e0a59009508017ff56708d2f58d4a126bd1ce45c677de7e6c38fa7675ec1634602dce606f97df0f97e6f3d61dec504075f4839381ff2dd14cc116
languageName: node
linkType: hard

"@polkadot-api/utils@npm:0.0.1":
version: 0.0.1
resolution: "@polkadot-api/utils@npm:0.0.1"
checksum: 10c0/531de2bfe0a1a55703bc83abb92e7ecf4862f4840bca64626520eb59a6e49dd136c1ec036cc48fab7be40e00fa84601ba1d84bd746997cb93a1bbce5dcfe7a03
languageName: node
linkType: hard

"@polkadot-api/utils@npm:0.1.1":
version: 0.1.1
resolution: "@polkadot-api/utils@npm:0.1.1"
checksum: 10c0/25e4da0e2defb713d18cd0c0db594a89cc4e23f36b2ebc5bccb1e2a8ba9a9814d09630d577b98ebcfdbbda2861fa8be48e914bf5f461481f3a09f1627ea6e784
languageName: node
linkType: hard

"@polkadot-api/ws-provider@npm:^0.2.0":
version: 0.2.0
resolution: "@polkadot-api/ws-provider@npm:0.2.0"
dependencies:
"@polkadot-api/json-rpc-provider": "npm:0.0.3"
"@polkadot-api/json-rpc-provider-proxy": "npm:0.2.0"
ws: "npm:^8.18.0"
checksum: 10c0/502dab5f7888a895b990d954a6b0327e318d34f07b04b38c04cc4e2db6022f9b46fed546ead6b21b13946e07ce7e833d427e173fcfe3aa7b0be2b189bcb2a693
languageName: node
linkType: hard

"@polkadot/api-augment@npm:12.3.1, @polkadot/api-augment@npm:^12.3.1":
version: 12.3.1
resolution: "@polkadot/api-augment@npm:12.3.1"
Expand Down Expand Up @@ -1991,7 +2055,7 @@ __metadata:
languageName: node
linkType: hard

"@scure/base@npm:^1.1.1, @scure/base@npm:^1.1.5":
"@scure/base@npm:^1.1.1, @scure/base@npm:^1.1.5, @scure/base@npm:^1.1.7":
version: 1.1.7
resolution: "@scure/base@npm:1.1.7"
checksum: 10c0/2d06aaf39e6de4b9640eb40d2e5419176ebfe911597856dcbf3bc6209277ddb83f4b4b02cb1fd1208f819654268ec083da68111d3530bbde07bae913e2fc2e5d
Expand Down Expand Up @@ -10068,7 +10132,7 @@ __metadata:
languageName: node
linkType: hard

"ws@npm:^8.16.0, ws@npm:^8.17.1, ws@npm:^8.8.1":
"ws@npm:^8.16.0, ws@npm:^8.17.1, ws@npm:^8.18.0, ws@npm:^8.8.1":
version: 8.18.0
resolution: "ws@npm:8.18.0"
peerDependencies:
Expand Down

0 comments on commit f249d48

Please sign in to comment.