From 73d6386979465b2090c7bd68fc27b59921b0eda4 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Wed, 15 Feb 2023 12:30:04 +0100 Subject: [PATCH 1/6] handle apply extrinsic error --- src/blockchain/block-builder.ts | 29 +++++++++++++++++++++++----- src/blockchain/index.ts | 4 ++++ src/blockchain/txpool.ts | 9 +++++++-- src/rpc/shared.ts | 2 +- src/rpc/substrate/author.ts | 23 ++++++++++++++++++---- src/server.ts | 34 ++++++++++++++++++++++----------- 6 files changed, 78 insertions(+), 23 deletions(-) diff --git a/src/blockchain/block-builder.ts b/src/blockchain/block-builder.ts index 5356398e..68ce95f8 100644 --- a/src/blockchain/block-builder.ts +++ b/src/blockchain/block-builder.ts @@ -1,4 +1,11 @@ -import { AccountInfo, Call, Header, RawBabePreDigest } from '@polkadot/types/interfaces' +import { + AccountInfo, + ApplyExtrinsicResult, + Call, + Header, + RawBabePreDigest, + TransactionValidityError, +} from '@polkadot/types/interfaces' import { Block, TaskCallResponse } from './block' import { GenericExtrinsic } from '@polkadot/types' import { HexString } from '@polkadot/util/types' @@ -122,7 +129,8 @@ const initNewBlock = async (head: Block, header: Header, inherents: HexString[]) export const buildBlock = async ( head: Block, inherents: HexString[], - extrinsics: HexString[] + extrinsics: HexString[], + onApplyExtrinsicError: (extrinsic: HexString, error: TransactionValidityError) => void ): Promise<[Block, HexString[]]> => { const registry = await head.registry const header = await newHeader(head) @@ -138,13 +146,24 @@ export const buildBlock = async ( ) const pendingExtrinsics: HexString[] = [] + const includedExtrinsic: HexString[] = [] // apply extrinsics for (const extrinsic of extrinsics) { try { - const { storageDiff } = await newBlock.call('BlockBuilder_apply_extrinsic', [extrinsic]) + const { result, storageDiff } = await newBlock.call('BlockBuilder_apply_extrinsic', [extrinsic]) + const outcome = registry.createType('ApplyExtrinsicResult', result) + if (outcome.isErr) { + if (outcome.asErr.isInvalid && outcome.asErr.asInvalid.isFuture) { + pendingExtrinsics.push(extrinsic) + } else { + onApplyExtrinsicError(extrinsic, outcome.asErr) + } + continue + } newBlock.pushStorageLayer().setAll(storageDiff) logger.trace(truncate(storageDiff), 'Applied extrinsic') + includedExtrinsic.push(extrinsic) } catch (e) { logger.info('Failed to apply extrinsic %o %s', e, e) pendingExtrinsics.push(extrinsic) @@ -161,7 +180,7 @@ export const buildBlock = async ( const blockData = registry.createType('Block', { header, - extrinsics, + extrinsics: includedExtrinsic, }) const storageDiff = await newBlock.storageDiff() @@ -171,7 +190,7 @@ export const buildBlock = async ( ) const finalBlock = new Block(head.chain, newBlock.number, blockData.hash.toHex(), head, { header, - extrinsics: [...inherents, ...extrinsics], + extrinsics: [...inherents, ...includedExtrinsic], storage: head.storage, storageDiff, }) diff --git a/src/blockchain/index.ts b/src/blockchain/index.ts index 25b89025..f1fb9f1b 100644 --- a/src/blockchain/index.ts +++ b/src/blockchain/index.ts @@ -83,6 +83,10 @@ export class Blockchain { return this.#txpool.pendingExtrinsics } + get applyExtrinsicError() { + return this.#txpool.applyExtrinsicError + } + async getBlockAt(number?: number): Promise { if (number === undefined) { return this.head diff --git a/src/blockchain/txpool.ts b/src/blockchain/txpool.ts index b475a9c4..18998af5 100644 --- a/src/blockchain/txpool.ts +++ b/src/blockchain/txpool.ts @@ -1,5 +1,6 @@ -import { BehaviorSubject, firstValueFrom } from 'rxjs' +import { BehaviorSubject, ReplaySubject, firstValueFrom } from 'rxjs' import { HexString } from '@polkadot/util/types' +import { TransactionValidityError } from '@polkadot/types/interfaces' import { skip, take } from 'rxjs/operators' import _ from 'lodash' @@ -37,6 +38,8 @@ export class TxPool { readonly #mode: BuildBlockMode readonly #inherentProvider: InherentProvider + readonly applyExtrinsicError = new ReplaySubject<[HexString, TransactionValidityError]>(1) + #last: BehaviorSubject #lastBuildBlockPromise: Promise = Promise.resolve() @@ -87,7 +90,9 @@ export class TxPool { const head = this.#chain.head const extrinsics = this.#pool.splice(0) const inherents = await this.#inherentProvider.createInherents(head, params?.inherent) - const [newBlock, pendingExtrinsics] = await buildBlock(head, inherents, extrinsics) + const [newBlock, pendingExtrinsics] = await buildBlock(head, inherents, extrinsics, (extrinsic, error) => { + this.applyExtrinsicError.next([extrinsic, error]) + }) this.#pool.push(...pendingExtrinsics) await this.#chain.setHead(newBlock) } diff --git a/src/rpc/shared.ts b/src/rpc/shared.ts index c987e290..6bdc4a12 100644 --- a/src/rpc/shared.ts +++ b/src/rpc/shared.ts @@ -25,7 +25,7 @@ export interface Context { } export interface SubscriptionManager { - subscribe: (method: string, subid: string, onCancel?: () => void) => (data: any) => void + subscribe: (method: string, subid: string, onCancel?: () => void) => (data?: any, error?: ResponseError) => void unsubscribe: (subid: string) => void } diff --git a/src/rpc/substrate/author.ts b/src/rpc/substrate/author.ts index 88191b2d..2c6d5274 100644 --- a/src/rpc/substrate/author.ts +++ b/src/rpc/substrate/author.ts @@ -1,3 +1,5 @@ +import { filter } from 'rxjs/operators' + import { Block } from '../../blockchain/block' import { Handlers, ResponseError } from '../../rpc/shared' import { defaultLogger } from '../../logger' @@ -16,7 +18,20 @@ const handlers: Handlers = { const id = context.chain.headState.subscribeHead((block) => update(block)) const callback = subscribe('author_extrinsicUpdate', id, () => context.chain.headState.unsubscribeHead(id)) + const errorSub = context.chain.applyExtrinsicError.pipe(filter((x) => x === extrinsic)).subscribe(([_, error]) => { + callback(null, new ResponseError(1, error.toString())) + done(id) + }) + + const done = (id: string) => { + errorSub.unsubscribe() + unsubscribe(id) + } + update = async (block) => { + const extrisnics = await block.extrinsics + if (!extrisnics.includes(extrinsic)) return + logger.debug({ block: block.hash }, 'author_extrinsicUpdate') // for now just assume tx is always included on next block callback({ @@ -25,7 +40,7 @@ const handlers: Handlers = { callback({ Finalized: block.hash, }) - unsubscribe(id) + done(id) } context.chain @@ -35,10 +50,10 @@ const handlers: Handlers = { Ready: null, }) }) - .catch((error) => { + .catch((error: Error) => { logger.error({ error }, 'ExtrinsicFailed') - callback({ Invalid: null }) - unsubscribe(id) + callback(null, new ResponseError(1, error.message)) + done(id) }) return id }, diff --git a/src/server.ts b/src/server.ts index d15d77dc..81cee9c7 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,6 +1,6 @@ import WebSocket, { AddressInfo, WebSocketServer } from 'ws' -import { SubscriptionManager } from './rpc/shared' +import { ResponseError, SubscriptionManager } from './rpc/shared' import { defaultLogger, truncate } from './logger' const logger = defaultLogger.child({ name: 'ws' }) @@ -65,17 +65,29 @@ export const createServer = async (handler: Handler, port?: number) => { const subscriptionManager = { subscribe: (method: string, subid: string, onCancel: () => void = () => {}) => { subscriptions[subid] = onCancel - return (data: object) => { + return (data?: object, error?: ResponseError) => { if (subscriptions[subid]) { - logger.trace({ method, subid, data: truncate(data) }, 'Subscription notification') - send({ - jsonrpc: '2.0', - method, - params: { - result: data, - subscription: subid, - }, - }) + if (error) { + logger.trace({ method, subid, error }, 'Subscription notification error') + send({ + jsonrpc: '2.0', + method, + error, + params: { + subscription: subid, + }, + }) + } else { + logger.trace({ method, subid, data: truncate(data) }, 'Subscription notification') + send({ + jsonrpc: '2.0', + method, + params: { + result: data, + subscription: subid, + }, + }) + } } } }, From 97ca52b370e245544bdabf481370b64fa66e4b47 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Wed, 15 Feb 2023 13:17:06 +0100 Subject: [PATCH 2/6] update event --- src/blockchain/block-builder.ts | 13 +++---------- src/blockchain/index.ts | 8 ++------ src/blockchain/txpool.ts | 10 ++++++---- src/rpc/substrate/author.ts | 19 +++++++++++-------- 4 files changed, 22 insertions(+), 28 deletions(-) diff --git a/src/blockchain/block-builder.ts b/src/blockchain/block-builder.ts index 68ce95f8..95aa93ef 100644 --- a/src/blockchain/block-builder.ts +++ b/src/blockchain/block-builder.ts @@ -1,11 +1,4 @@ -import { - AccountInfo, - ApplyExtrinsicResult, - Call, - Header, - RawBabePreDigest, - TransactionValidityError, -} from '@polkadot/types/interfaces' +import { AccountInfo, ApplyExtrinsicResult, Call, Header, RawBabePreDigest } from '@polkadot/types/interfaces' import { Block, TaskCallResponse } from './block' import { GenericExtrinsic } from '@polkadot/types' import { HexString } from '@polkadot/util/types' @@ -130,7 +123,7 @@ export const buildBlock = async ( head: Block, inherents: HexString[], extrinsics: HexString[], - onApplyExtrinsicError: (extrinsic: HexString, error: TransactionValidityError) => void + onApplyExtrinsicError: (extrinsic: HexString, error: Error) => void ): Promise<[Block, HexString[]]> => { const registry = await head.registry const header = await newHeader(head) @@ -157,7 +150,7 @@ export const buildBlock = async ( if (outcome.asErr.isInvalid && outcome.asErr.asInvalid.isFuture) { pendingExtrinsics.push(extrinsic) } else { - onApplyExtrinsicError(extrinsic, outcome.asErr) + onApplyExtrinsicError(extrinsic, new Error(outcome.asErr.toString())) } continue } diff --git a/src/blockchain/index.ts b/src/blockchain/index.ts index f1fb9f1b..0a0875ad 100644 --- a/src/blockchain/index.ts +++ b/src/blockchain/index.ts @@ -79,12 +79,8 @@ export class Blockchain { return this.#head } - get pendingExtrinsics(): HexString[] { - return this.#txpool.pendingExtrinsics - } - - get applyExtrinsicError() { - return this.#txpool.applyExtrinsicError + get txPool() { + return this.#txpool } async getBlockAt(number?: number): Promise { diff --git a/src/blockchain/txpool.ts b/src/blockchain/txpool.ts index 18998af5..7fc25098 100644 --- a/src/blockchain/txpool.ts +++ b/src/blockchain/txpool.ts @@ -1,6 +1,6 @@ -import { BehaviorSubject, ReplaySubject, firstValueFrom } from 'rxjs' +import { BehaviorSubject, firstValueFrom } from 'rxjs' +import { EventEmitter } from 'node:stream' import { HexString } from '@polkadot/util/types' -import { TransactionValidityError } from '@polkadot/types/interfaces' import { skip, take } from 'rxjs/operators' import _ from 'lodash' @@ -9,6 +9,8 @@ import { Blockchain } from '.' import { InherentProvider } from './inherent' import { buildBlock } from './block-builder' +export const APPLY_EXTRINSIC_ERROR = 'TxPool::ApplyExtrinsicError' + export enum BuildBlockMode { Batch, // one block per batch, default Instant, // one block per tx @@ -38,7 +40,7 @@ export class TxPool { readonly #mode: BuildBlockMode readonly #inherentProvider: InherentProvider - readonly applyExtrinsicError = new ReplaySubject<[HexString, TransactionValidityError]>(1) + readonly event = new EventEmitter() #last: BehaviorSubject #lastBuildBlockPromise: Promise = Promise.resolve() @@ -91,7 +93,7 @@ export class TxPool { const extrinsics = this.#pool.splice(0) const inherents = await this.#inherentProvider.createInherents(head, params?.inherent) const [newBlock, pendingExtrinsics] = await buildBlock(head, inherents, extrinsics, (extrinsic, error) => { - this.applyExtrinsicError.next([extrinsic, error]) + this.event.emit(APPLY_EXTRINSIC_ERROR, [extrinsic, error]) }) this.#pool.push(...pendingExtrinsics) await this.#chain.setHead(newBlock) diff --git a/src/rpc/substrate/author.ts b/src/rpc/substrate/author.ts index 2c6d5274..0ac3590f 100644 --- a/src/rpc/substrate/author.ts +++ b/src/rpc/substrate/author.ts @@ -1,5 +1,4 @@ -import { filter } from 'rxjs/operators' - +import { APPLY_EXTRINSIC_ERROR } from '../../blockchain/txpool' import { Block } from '../../blockchain/block' import { Handlers, ResponseError } from '../../rpc/shared' import { defaultLogger } from '../../logger' @@ -18,13 +17,17 @@ const handlers: Handlers = { const id = context.chain.headState.subscribeHead((block) => update(block)) const callback = subscribe('author_extrinsicUpdate', id, () => context.chain.headState.unsubscribeHead(id)) - const errorSub = context.chain.applyExtrinsicError.pipe(filter((x) => x === extrinsic)).subscribe(([_, error]) => { - callback(null, new ResponseError(1, error.toString())) - done(id) - }) + const onExtrinsicFail = ([failedExtrinsic, error]) => { + if (failedExtrinsic === extrinsic) { + callback(null, new ResponseError(1, error.message)) + done(id) + } + } + + context.chain.txPool.event.on(APPLY_EXTRINSIC_ERROR, onExtrinsicFail) const done = (id: string) => { - errorSub.unsubscribe() + context.chain.txPool.event.removeListener(APPLY_EXTRINSIC_ERROR, onExtrinsicFail) unsubscribe(id) } @@ -61,7 +64,7 @@ const handlers: Handlers = { unsubscribe(subid) }, author_pendingExtrinsics: async (context) => { - return context.chain.pendingExtrinsics + return context.chain.txPool.pendingExtrinsics }, } From 919ec7864b4754634f4b5cd9643adcaaab9ac829 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Wed, 15 Feb 2023 14:49:29 +0100 Subject: [PATCH 3/6] fix response --- e2e/author.test.ts | 33 +++++++++++++++++++++++++++----- e2e/helper.ts | 2 +- src/blockchain/block-builder.ts | 13 ++++++++++--- src/blockchain/index.ts | 2 +- src/rpc/substrate/author.ts | 9 +++++---- src/server.ts | 34 +++++++++++---------------------- 6 files changed, 56 insertions(+), 37 deletions(-) diff --git a/e2e/author.test.ts b/e2e/author.test.ts index c9d90124..9586c039 100644 --- a/e2e/author.test.ts +++ b/e2e/author.test.ts @@ -1,13 +1,14 @@ +import { SubmittableResult } from '@polkadot/api' import { describe, expect, it } from 'vitest' -import { api, dev, env, expectJson, mockCallback, setupApi, testingPairs } from './helper' +import { api, defer, dev, env, expectJson, mockCallback, setupApi, testingPairs } from './helper' setupApi(env.mandala) describe('author rpc', () => { - it('works', async () => { - const { alice, bob } = testingPairs() + const { alice, bob } = testingPairs() + it('works', async () => { { const { callback, next } = mockCallback() await api.tx.balances.transfer(bob.address, 100).signAndSend(alice, callback) @@ -55,7 +56,6 @@ describe('author rpc', () => { }) it('reject invalid signature', async () => { - const { alice, bob } = testingPairs() const { nonce } = await api.query.system.account(alice.address) const tx = api.tx.balances.transfer(bob.address, 100) @@ -66,6 +66,29 @@ describe('author rpc', () => { blockHash: api.genesisHash, }) - await expect(tx.send()).rejects.toThrow('Extrinsic is invalid') + await expect(tx.send()).rejects.toThrow('{"invalid":{"badProof":null}}') + }) + + it('failed apply extirinsic', async () => { + const finalized = defer() + const invalid = defer() + + const onStatusUpdate = (result: SubmittableResult) => { + if (result.status.isInvalid) { + invalid.resolve(result.status.toString()) + } + if (result.status.isFinalized) { + finalized.resolve(null) + } + } + + const { nonce } = await api.query.system.account(alice.address) + await api.tx.balances.transfer(bob.address, 100).signAndSend(alice, { nonce }, onStatusUpdate) + await api.tx.balances.transfer(bob.address, 200).signAndSend(alice, { nonce }, onStatusUpdate) + + await dev.newBlock() + + await finalized.promise + expect(await invalid.promise).toBe('Invalid') }) }) diff --git a/e2e/helper.ts b/e2e/helper.ts index 06c7eeb6..1d4955f7 100644 --- a/e2e/helper.ts +++ b/e2e/helper.ts @@ -167,7 +167,7 @@ export const dev = { }, } -function defer() { +export function defer() { const deferred = {} as { resolve: (value: any) => void; reject: (reason: any) => void; promise: Promise } deferred.promise = new Promise((resolve, reject) => { deferred.resolve = resolve diff --git a/src/blockchain/block-builder.ts b/src/blockchain/block-builder.ts index 95aa93ef..68ce95f8 100644 --- a/src/blockchain/block-builder.ts +++ b/src/blockchain/block-builder.ts @@ -1,4 +1,11 @@ -import { AccountInfo, ApplyExtrinsicResult, Call, Header, RawBabePreDigest } from '@polkadot/types/interfaces' +import { + AccountInfo, + ApplyExtrinsicResult, + Call, + Header, + RawBabePreDigest, + TransactionValidityError, +} from '@polkadot/types/interfaces' import { Block, TaskCallResponse } from './block' import { GenericExtrinsic } from '@polkadot/types' import { HexString } from '@polkadot/util/types' @@ -123,7 +130,7 @@ export const buildBlock = async ( head: Block, inherents: HexString[], extrinsics: HexString[], - onApplyExtrinsicError: (extrinsic: HexString, error: Error) => void + onApplyExtrinsicError: (extrinsic: HexString, error: TransactionValidityError) => void ): Promise<[Block, HexString[]]> => { const registry = await head.registry const header = await newHeader(head) @@ -150,7 +157,7 @@ export const buildBlock = async ( if (outcome.asErr.isInvalid && outcome.asErr.asInvalid.isFuture) { pendingExtrinsics.push(extrinsic) } else { - onApplyExtrinsicError(extrinsic, new Error(outcome.asErr.toString())) + onApplyExtrinsicError(extrinsic, outcome.asErr) } continue } diff --git a/src/blockchain/index.ts b/src/blockchain/index.ts index 0a0875ad..061fc006 100644 --- a/src/blockchain/index.ts +++ b/src/blockchain/index.ts @@ -158,7 +158,7 @@ export class Blockchain { this.#txpool.submitExtrinsic(extrinsic) return blake2AsHex(extrinsic, 256) } - throw new Error(`Extrinsic is invalid: ${validity.asErr.toString()}`) + throw validity.asErr } async newBlock(params?: BuildBlockParams): Promise { diff --git a/src/rpc/substrate/author.ts b/src/rpc/substrate/author.ts index 0ac3590f..47d59511 100644 --- a/src/rpc/substrate/author.ts +++ b/src/rpc/substrate/author.ts @@ -1,6 +1,7 @@ import { APPLY_EXTRINSIC_ERROR } from '../../blockchain/txpool' import { Block } from '../../blockchain/block' import { Handlers, ResponseError } from '../../rpc/shared' +import { TransactionValidityError } from '@polkadot/types/interfaces' import { defaultLogger } from '../../logger' const logger = defaultLogger.child({ name: 'rpc-author' }) @@ -17,9 +18,9 @@ const handlers: Handlers = { const id = context.chain.headState.subscribeHead((block) => update(block)) const callback = subscribe('author_extrinsicUpdate', id, () => context.chain.headState.unsubscribeHead(id)) - const onExtrinsicFail = ([failedExtrinsic, error]) => { + const onExtrinsicFail = ([failedExtrinsic, error]: [string, TransactionValidityError]) => { if (failedExtrinsic === extrinsic) { - callback(null, new ResponseError(1, error.message)) + callback(error.toJSON()) done(id) } } @@ -53,9 +54,9 @@ const handlers: Handlers = { Ready: null, }) }) - .catch((error: Error) => { + .catch((error: TransactionValidityError) => { logger.error({ error }, 'ExtrinsicFailed') - callback(null, new ResponseError(1, error.message)) + callback(error.toJSON()) done(id) }) return id diff --git a/src/server.ts b/src/server.ts index 81cee9c7..d15d77dc 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,6 +1,6 @@ import WebSocket, { AddressInfo, WebSocketServer } from 'ws' -import { ResponseError, SubscriptionManager } from './rpc/shared' +import { SubscriptionManager } from './rpc/shared' import { defaultLogger, truncate } from './logger' const logger = defaultLogger.child({ name: 'ws' }) @@ -65,29 +65,17 @@ export const createServer = async (handler: Handler, port?: number) => { const subscriptionManager = { subscribe: (method: string, subid: string, onCancel: () => void = () => {}) => { subscriptions[subid] = onCancel - return (data?: object, error?: ResponseError) => { + return (data: object) => { if (subscriptions[subid]) { - if (error) { - logger.trace({ method, subid, error }, 'Subscription notification error') - send({ - jsonrpc: '2.0', - method, - error, - params: { - subscription: subid, - }, - }) - } else { - logger.trace({ method, subid, data: truncate(data) }, 'Subscription notification') - send({ - jsonrpc: '2.0', - method, - params: { - result: data, - subscription: subid, - }, - }) - } + logger.trace({ method, subid, data: truncate(data) }, 'Subscription notification') + send({ + jsonrpc: '2.0', + method, + params: { + result: data, + subscription: subid, + }, + }) } } }, From e1e48a576d4bf91206bbaaf8f3de963b9c070ea3 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Wed, 15 Feb 2023 14:52:28 +0100 Subject: [PATCH 4/6] update type --- src/rpc/shared.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/shared.ts b/src/rpc/shared.ts index 6bdc4a12..c987e290 100644 --- a/src/rpc/shared.ts +++ b/src/rpc/shared.ts @@ -25,7 +25,7 @@ export interface Context { } export interface SubscriptionManager { - subscribe: (method: string, subid: string, onCancel?: () => void) => (data?: any, error?: ResponseError) => void + subscribe: (method: string, subid: string, onCancel?: () => void) => (data: any) => void unsubscribe: (subid: string) => void } From f088752fa8dc9b8a996633d078fa82d69d8ae9aa Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Wed, 15 Feb 2023 15:05:52 +0100 Subject: [PATCH 5/6] update logging --- src/blockchain/block-builder.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/blockchain/block-builder.ts b/src/blockchain/block-builder.ts index 68ce95f8..9ab1e421 100644 --- a/src/blockchain/block-builder.ts +++ b/src/blockchain/block-builder.ts @@ -10,6 +10,7 @@ import { Block, TaskCallResponse } from './block' import { GenericExtrinsic } from '@polkadot/types' import { HexString } from '@polkadot/util/types' import { StorageValueKind } from './storage-layer' +import { blake2AsHex } from '@polkadot/util-crypto' import { compactAddLength, hexToU8a, stringToHex } from '@polkadot/util' import { compactHex } from '../utils' import { defaultLogger, truncate } from '../logger' @@ -142,7 +143,7 @@ export const buildBlock = async ( extrinsicsCount: extrinsics.length, tempHash: newBlock.hash, }, - `Building block #${newBlock.number.toLocaleString()}` + `Try building block #${newBlock.number.toLocaleString()}` ) const pendingExtrinsics: HexString[] = [] @@ -196,7 +197,12 @@ export const buildBlock = async ( }) logger.info( - { hash: finalBlock.hash, number: newBlock.number }, + { + hash: finalBlock.hash, + extrinsics: includedExtrinsic.map((x) => blake2AsHex(x, 256)), + pendingExtrinsics: pendingExtrinsics.length, + number: newBlock.number, + }, `Block built #${newBlock.number.toLocaleString()} hash ${finalBlock.hash}` ) From 8adb50e0754325c7d61a2fb1a086e2d553aa0b1e Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Wed, 15 Feb 2023 15:24:20 +0100 Subject: [PATCH 6/6] update test --- e2e/author.test.ts | 2 +- e2e/mock-signature.test.ts | 2 +- src/rpc/substrate/author.ts | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/e2e/author.test.ts b/e2e/author.test.ts index 9586c039..b2e58de5 100644 --- a/e2e/author.test.ts +++ b/e2e/author.test.ts @@ -66,7 +66,7 @@ describe('author rpc', () => { blockHash: api.genesisHash, }) - await expect(tx.send()).rejects.toThrow('{"invalid":{"badProof":null}}') + await expect(tx.send()).rejects.toThrow('1010: {"invalid":{"badProof":null}}') }) it('failed apply extirinsic', async () => { diff --git a/e2e/mock-signature.test.ts b/e2e/mock-signature.test.ts index ff1243a8..7f85d13b 100644 --- a/e2e/mock-signature.test.ts +++ b/e2e/mock-signature.test.ts @@ -30,7 +30,7 @@ describe('mock signature', () => { blockHash: api.genesisHash, }) - await expect(tx.send()).rejects.toThrow('Extrinsic is invalid') + await expect(tx.send()).rejects.toThrow('1010: {"invalid":{"badProof":null}}') }) it('accept mock signature', async () => { diff --git a/src/rpc/substrate/author.ts b/src/rpc/substrate/author.ts index 47d59511..c72b95c4 100644 --- a/src/rpc/substrate/author.ts +++ b/src/rpc/substrate/author.ts @@ -8,8 +8,9 @@ const logger = defaultLogger.child({ name: 'rpc-author' }) const handlers: Handlers = { author_submitExtrinsic: async (context, [extrinsic]) => { - return context.chain.submitExtrinsic(extrinsic).catch((error) => { - throw new ResponseError(1, error.toString()) + return context.chain.submitExtrinsic(extrinsic).catch((error: TransactionValidityError) => { + const code = error.isInvalid ? 1010 : 1011 + throw new ResponseError(code, error.toString()) }) }, author_submitAndWatchExtrinsic: async (context, [extrinsic], { subscribe, unsubscribe }) => {