From 14d89e59be2625a23b64edb1000c678b8d224193 Mon Sep 17 00:00:00 2001 From: William Cory Date: Sun, 14 Jul 2024 06:43:23 -0700 Subject: [PATCH 1/6] :sparkles: Feat: Add getBlockByTag to Chain package --- packages/blockchain/package.json | 1 + packages/blockchain/src/Chain.ts | 16 ++++++++- .../blockchain/src/actions/getBlockByTag.js | 35 +++++++++++++++++++ packages/blockchain/src/createChain.js | 2 ++ pnpm-lock.yaml | 3 ++ 5 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 packages/blockchain/src/actions/getBlockByTag.js diff --git a/packages/blockchain/package.json b/packages/blockchain/package.json index 5de1440955..f5eee8d170 100644 --- a/packages/blockchain/package.json +++ b/packages/blockchain/package.json @@ -65,6 +65,7 @@ "@ethereumjs/blockchain": "^7.2.0", "@tevm/block": "workspace:^", "@tevm/common": "workspace:^", + "@tevm/errors": "workspace:^", "@tevm/jsonrpc": "workspace:^", "@tevm/logger": "workspace:^", "@tevm/trie": "workspace:^", diff --git a/packages/blockchain/src/Chain.ts b/packages/blockchain/src/Chain.ts index fbf104734c..d6345ada7a 100644 --- a/packages/blockchain/src/Chain.ts +++ b/packages/blockchain/src/Chain.ts @@ -1,6 +1,6 @@ import { type BlockchainEvents, type Consensus, type OnBlock } from '@ethereumjs/blockchain' import type { Block, BlockHeader } from '@tevm/block' -import type { AsyncEventEmitter } from '@tevm/utils' +import type { AsyncEventEmitter, BlockTag, Hex } from '@tevm/utils' import type { BaseChain } from './BaseChain.js' /** @@ -41,6 +41,20 @@ export type Chain = {} & BaseChain & { */ getBlock(blockId: Uint8Array | number | bigint): Promise + /** + * Gets block given one of the following inputs: + * - Hex block hash + * - Hex block number (if length is 32 bytes, it is treated as a hash) + * - Uint8Array block hash + * - Number block number + * - BigInt block number + * - BlockTag block tag + * - Named block tag (e.g. 'latest', 'earliest', 'pending') + * @throws {UnknownBlockError} - If the block is not found + * @throw {InvalidBlockTagError} - If the block tag is invalid} + */ + getBlockByTag(blockTag: Hex | Uint8Array | number | bigint | BlockTag): Promise + /** * Iterates through blocks starting at the specified iterator head and calls * the onBlock function on each block. diff --git a/packages/blockchain/src/actions/getBlockByTag.js b/packages/blockchain/src/actions/getBlockByTag.js new file mode 100644 index 0000000000..bd34ec79a5 --- /dev/null +++ b/packages/blockchain/src/actions/getBlockByTag.js @@ -0,0 +1,35 @@ +import { hexToBytes, hexToNumber, isHex } from '@tevm/utils' +import { getBlock } from './getBlock.js' +import { UnknownBlockError } from '@tevm/errors' +import { getBlockFromRpc } from '../utils/getBlockFromRpc.js' +import { putBlock } from './putBlock.js' + +/** + * @param {import('../BaseChain.js').BaseChain} baseChain + * @returns {import('../Chain.js').Chain['getBlockByTag']} + */ +export const getBlockByTag = (baseChain) => async (blockId) => { + const _getBlock = getBlock(baseChain) + if (isHex(blockId)) { + return blockId.length === 66 ? _getBlock(hexToBytes(blockId)) : _getBlock(hexToNumber(blockId)) + } + if (typeof blockId === 'number' || typeof blockId === 'bigint' || blockId instanceof Uint8Array) { + return _getBlock(blockId) + } + const block = baseChain.blocksByTag.get(blockId) + if (!block && baseChain.options.fork?.transport) { + const block = await getBlockFromRpc( + { + transport: baseChain.options.fork.transport, + blockTag: blockId, + }, + baseChain.common, + ) + await putBlock(baseChain)(block) + return block + } + if (!block) { + throw new UnknownBlockError(blockId) + } + return block +} diff --git a/packages/blockchain/src/createChain.js b/packages/blockchain/src/createChain.js index defcda3919..e85dfa9f8d 100644 --- a/packages/blockchain/src/createChain.js +++ b/packages/blockchain/src/createChain.js @@ -1,6 +1,7 @@ import { deepCopy } from './actions/deepCopy.js' import { delBlock } from './actions/delBlock.js' import { getBlock } from './actions/getBlock.js' +import { getBlockByTag } from './actions/getBlockByTag.js' import { getCanonicalHeadBlock } from './actions/getCanonicalHeadBlock.js' import { getIteratorHead } from './actions/getIteratorHead.js' import { putBlock } from './actions/putBlock.js' @@ -18,6 +19,7 @@ export const createChain = async (options) => { */ const decorate = (baseChain) => { return Object.assign(baseChain, { + getBlockByTag: getBlockByTag(baseChain), deepCopy: async () => decorate(await deepCopy(baseChain)()), shallowCopy: () => decorate(shallowCopy(baseChain)()), getBlock: getBlock(baseChain), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a8e4b8f3cf..2b93cd3bdd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1532,6 +1532,9 @@ importers: '@tevm/common': specifier: workspace:^ version: link:../common + '@tevm/errors': + specifier: workspace:^ + version: link:../errors '@tevm/jsonrpc': specifier: workspace:^ version: link:../jsonrpc From 075970445095d9ec27cae536934b8de1911bee17 Mon Sep 17 00:00:00 2001 From: William Cory Date: Sun, 14 Jul 2024 14:49:55 -0700 Subject: [PATCH 2/6] :white_check_mark: Test: Start adding test --- packages/blockchain/package.json | 167 +++++++++--------- .../src/utils/getBlockFromRpc.spec.ts | 79 +++++++++ pnpm-lock.yaml | 3 + 3 files changed, 166 insertions(+), 83 deletions(-) create mode 100644 packages/blockchain/src/utils/getBlockFromRpc.spec.ts diff --git a/packages/blockchain/package.json b/packages/blockchain/package.json index f5eee8d170..9c4679c3c8 100644 --- a/packages/blockchain/package.json +++ b/packages/blockchain/package.json @@ -1,85 +1,86 @@ { - "name": "@tevm/blockchain", - "version": "1.1.0-next.97", - "private": false, - "description": "A custom implementation of ethereumjs blockchain", - "keywords": [ - "solidity", - "ethereumjs", - "typescript", - "web3", - "blockchain" - ], - "repository": { - "type": "git", - "url": "https://github.com/evmts/tevm-monorepo.git", - "directory": "packages/blockchain" - }, - "license": "MIT", - "contributors": [ - "Will Cory " - ], - "type": "module", - "exports": { - "./package.json": "./package.json", - ".": { - "import": { - "types": "./types/index.d.ts", - "default": "./dist/index.js" - }, - "require": { - "types": "./dist/index.d.cts", - "default": "./dist/index.cjs" - } - } - }, - "main": "dist/index.cjs", - "module": "dist/index.js", - "types": "types/index.d.ts", - "files": [ - "dist", - "types", - "src", - "!src/**/*.spec.ts" - ], - "scripts": { - "all": "pnpm i && bun run build && bun lint && bun format && bun test:run && bun generate:docs", - "build": "nx run-many --targets=build:dist,build:types --projects=@tevm/blockchain", - "build:dist": "tsup", - "build:types": "tsup --dts-only && tsc --emitDeclarationOnly --declaration", - "clean": "rm -rf node_modules && rm -rf artifacts && rm -rf dist && rm -rf cache", - "format": "biome format . --write", - "format:check": "biome format .", - "generate:docs": "typedoc", - "lint": "biome check . --write --unsafe", - "lint:check": "biome check . --verbose", - "lint:deps": "bunx depcheck", - "lint:package": "bunx publint --strict && attw --pack", - "package:up": "pnpm up --latest", - "test": "bun test --watch", - "test:coverage": "bun test --coverage", - "test:run": "bun test", - "typecheck": "tsc --noEmit" - }, - "dependencies": { - "@ethereumjs/blockchain": "^7.2.0", - "@tevm/block": "workspace:^", - "@tevm/common": "workspace:^", - "@tevm/errors": "workspace:^", - "@tevm/jsonrpc": "workspace:^", - "@tevm/logger": "workspace:^", - "@tevm/trie": "workspace:^", - "@tevm/utils": "workspace:^" - }, - "devDependencies": { - "@tevm/tsconfig": "workspace:^", - "@tevm/tsupconfig": "workspace:^" - }, - "peerDependencies": { - "viem": "^2.14.2" - }, - "publishConfig": { - "access": "public" - }, - "sideEffect": false + "name": "@tevm/blockchain", + "version": "1.1.0-next.97", + "private": false, + "description": "A custom implementation of ethereumjs blockchain", + "keywords": [ + "solidity", + "ethereumjs", + "typescript", + "web3", + "blockchain" + ], + "repository": { + "type": "git", + "url": "https://github.com/evmts/tevm-monorepo.git", + "directory": "packages/blockchain" + }, + "license": "MIT", + "contributors": [ + "Will Cory " + ], + "type": "module", + "exports": { + "./package.json": "./package.json", + ".": { + "import": { + "types": "./types/index.d.ts", + "default": "./dist/index.js" + }, + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" + } + } + }, + "main": "dist/index.cjs", + "module": "dist/index.js", + "types": "types/index.d.ts", + "files": [ + "dist", + "types", + "src", + "!src/**/*.spec.ts" + ], + "scripts": { + "all": "pnpm i && bun run build && bun lint && bun format && bun test:run && bun generate:docs", + "build": "nx run-many --targets=build:dist,build:types --projects=@tevm/blockchain", + "build:dist": "tsup", + "build:types": "tsup --dts-only && tsc --emitDeclarationOnly --declaration", + "clean": "rm -rf node_modules && rm -rf artifacts && rm -rf dist && rm -rf cache", + "format": "biome format . --write", + "format:check": "biome format .", + "generate:docs": "typedoc", + "lint": "biome check . --write --unsafe", + "lint:check": "biome check . --verbose", + "lint:deps": "bunx depcheck", + "lint:package": "bunx publint --strict && attw --pack", + "package:up": "pnpm up --latest", + "test": "bun test --watch", + "test:coverage": "bun test --coverage", + "test:run": "bun test", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@ethereumjs/blockchain": "^7.2.0", + "@tevm/block": "workspace:^", + "@tevm/common": "workspace:^", + "@tevm/errors": "workspace:^", + "@tevm/jsonrpc": "workspace:^", + "@tevm/logger": "workspace:^", + "@tevm/trie": "workspace:^", + "@tevm/utils": "workspace:^" + }, + "devDependencies": { + "@tevm/test-utils": "workspace:^", + "@tevm/tsconfig": "workspace:^", + "@tevm/tsupconfig": "workspace:^" + }, + "peerDependencies": { + "viem": "^2.14.2" + }, + "publishConfig": { + "access": "public" + }, + "sideEffect": false } diff --git a/packages/blockchain/src/utils/getBlockFromRpc.spec.ts b/packages/blockchain/src/utils/getBlockFromRpc.spec.ts new file mode 100644 index 0000000000..b83a259472 --- /dev/null +++ b/packages/blockchain/src/utils/getBlockFromRpc.spec.ts @@ -0,0 +1,79 @@ +import { describe, expect, it } from 'bun:test' +import { Block } from '@tevm/block' +import { transports } from '@tevm/test-utils' +import { getBlockFromRpc } from './getBlockFromRpc.js' +import { optimism } from '@tevm/common' + +describe('getBlockFromRpc', () => { + it('should fetch the latest block', async () => { + const transport = transports.optimism + const common = optimism.copy() + + const block = await getBlockFromRpc({ transport, blockTag: 'latest' }, common) + expect(block).toBeInstanceOf(Block) + expect(block.header.number).toBeGreaterThanOrEqual(0n) + }) + + it('should fetch a block by number', async () => { + const transport = transports.optimism + const common = optimism.copy() + const blockNumber = 122606365n + + const block = await getBlockFromRpc({ transport, blockTag: blockNumber }, common) + expect(block).toBeInstanceOf(Block) + expect(block.header.number).toBe(blockNumber) + }) + + it('should fetch a block by hash', async () => { + const transport = transports.optimism + const common = optimism.copy() + const blockHash = '0x6d4f1b3c89f9a26e7b1d8af7b093b8936d4d1af7989d0b1a7b1a2b0b0b6a6a6a' + + const block = await getBlockFromRpc({ transport, blockTag: blockHash }, common) + expect(block).toBeInstanceOf(Block) + expect(block.hash().toString('hex')).toBe(blockHash.slice(2)) + }) + + it('should handle invalid block tag', async () => { + const transport = transports.optimism + const common = optimism.copy() + const invalidBlockTag = 'invalid-tag' + + await expect(getBlockFromRpc({ transport, blockTag: invalidBlockTag as any }, common)).rejects.toThrow( + `Invalid blocktag ${invalidBlockTag}`, + ) + }) + + it('should handle non-existing block number', async () => { + const transport = transports.optimism + const common = optimism.copy() + const nonExistingBlockNumber = 99999999999n + + await expect(getBlockFromRpc({ transport, blockTag: nonExistingBlockNumber }, common)).rejects.toThrow( + 'No block found', + ) + }) + + it('should handle non-existing block hash', async () => { + const transport = transports.optimism + const common = optimism.copy() + const nonExistingBlockHash = '0x' + '0'.repeat(64) + + await expect(getBlockFromRpc({ transport, blockTag: nonExistingBlockHash }, common)).rejects.toThrow( + 'No block found', + ) + }) + + it('should handle Optimism deposit transactions filtering', async () => { + const transport = transports.optimism + const common = optimism.copy() + + const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}) + + const block = await getBlockFromRpc({ transport, blockTag: 'latest' }, common) + expect(block).toBeInstanceOf(Block) + expect(consoleWarnSpy).toHaveBeenCalled() + + consoleWarnSpy.mockRestore() + }) +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2b93cd3bdd..61cc4626e5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1551,6 +1551,9 @@ importers: specifier: ^2.14.2 version: 2.14.2(bufferutil@4.0.8)(typescript@5.5.2)(utf-8-validate@6.0.4)(zod@3.23.8) devDependencies: + '@tevm/test-utils': + specifier: workspace:^ + version: link:../../test/test-utils '@tevm/tsconfig': specifier: workspace:^ version: link:../../configs/tsconfig From 49c164b43195d71a88458d9c3988e978ebd7fdba Mon Sep 17 00:00:00 2001 From: William Cory Date: Sun, 14 Jul 2024 15:31:21 -0700 Subject: [PATCH 3/6] :bookmark: Chore: changeset --- .changeset/tall-phones-appear.md | 5 +++++ packages/blockchain/src/actions/getBlockByTag.js | 4 ++-- packages/blockchain/src/utils/getBlockFromRpc.spec.ts | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 .changeset/tall-phones-appear.md diff --git a/.changeset/tall-phones-appear.md b/.changeset/tall-phones-appear.md new file mode 100644 index 0000000000..c49b8881a9 --- /dev/null +++ b/.changeset/tall-phones-appear.md @@ -0,0 +1,5 @@ +--- +"@tevm/blockchain": minor +--- + +Added new getBlockByTag method to Chain. It gets blocks by hash or number just like getBlock but also accepts a named tag such as 'latest', 'pending', or 'forked' diff --git a/packages/blockchain/src/actions/getBlockByTag.js b/packages/blockchain/src/actions/getBlockByTag.js index bd34ec79a5..066c788f87 100644 --- a/packages/blockchain/src/actions/getBlockByTag.js +++ b/packages/blockchain/src/actions/getBlockByTag.js @@ -1,7 +1,7 @@ -import { hexToBytes, hexToNumber, isHex } from '@tevm/utils' -import { getBlock } from './getBlock.js' import { UnknownBlockError } from '@tevm/errors' +import { hexToBytes, hexToNumber, isHex } from '@tevm/utils' import { getBlockFromRpc } from '../utils/getBlockFromRpc.js' +import { getBlock } from './getBlock.js' import { putBlock } from './putBlock.js' /** diff --git a/packages/blockchain/src/utils/getBlockFromRpc.spec.ts b/packages/blockchain/src/utils/getBlockFromRpc.spec.ts index b83a259472..1ce5cef262 100644 --- a/packages/blockchain/src/utils/getBlockFromRpc.spec.ts +++ b/packages/blockchain/src/utils/getBlockFromRpc.spec.ts @@ -1,8 +1,8 @@ import { describe, expect, it } from 'bun:test' import { Block } from '@tevm/block' +import { optimism } from '@tevm/common' import { transports } from '@tevm/test-utils' import { getBlockFromRpc } from './getBlockFromRpc.js' -import { optimism } from '@tevm/common' describe('getBlockFromRpc', () => { it('should fetch the latest block', async () => { @@ -57,7 +57,7 @@ describe('getBlockFromRpc', () => { it('should handle non-existing block hash', async () => { const transport = transports.optimism const common = optimism.copy() - const nonExistingBlockHash = '0x' + '0'.repeat(64) + const nonExistingBlockHash = `0x${'0'.repeat(64)}` await expect(getBlockFromRpc({ transport, blockTag: nonExistingBlockHash }, common)).rejects.toThrow( 'No block found', From 08c2b431b8ab273937e36150a26d9cd4dc48d471 Mon Sep 17 00:00:00 2001 From: William Cory Date: Sun, 14 Jul 2024 15:42:51 -0700 Subject: [PATCH 4/6] :construction: Compiles but wip --- .../blockchain/docs/functions/createChain.md | 2 +- .../docs/functions/getBlockFromRpc.md | 6 ++- .../blockchain/docs/type-aliases/Chain.md | 27 +++++++++++ packages/blockchain/src/actions/getBlock.js | 1 + .../blockchain/src/actions/getBlockByTag.js | 1 + packages/blockchain/src/createBaseChain.js | 2 +- .../blockchain/src/utils/getBlockFromRpc.js | 22 ++------- .../src/utils/getBlockFromRpc.spec.ts | 46 ++++++++++++------- packages/blockchain/src/utils/warnOnce.js | 20 ++++++++ .../src/utils/blockToJsonRpcBlock.spec.ts | 6 ++- .../src/utils/txToJsonRpcTx.spec.ts | 6 ++- .../blockchain/functions/getBlockFromRpc.md | 4 +- tevm/docs/blockchain/type-aliases/Chain.md | 27 +++++++++++ 13 files changed, 128 insertions(+), 42 deletions(-) create mode 100644 packages/blockchain/src/utils/warnOnce.js diff --git a/packages/blockchain/docs/functions/createChain.md b/packages/blockchain/docs/functions/createChain.md index 05edb34718..0100e2bd0d 100644 --- a/packages/blockchain/docs/functions/createChain.md +++ b/packages/blockchain/docs/functions/createChain.md @@ -18,4 +18,4 @@ ## Defined in -[createChain.js:15](https://github.com/evmts/tevm-monorepo/blob/main/packages/blockchain/src/createChain.js#L15) +[createChain.js:16](https://github.com/evmts/tevm-monorepo/blob/main/packages/blockchain/src/createChain.js#L16) diff --git a/packages/blockchain/docs/functions/getBlockFromRpc.md b/packages/blockchain/docs/functions/getBlockFromRpc.md index 37c6b4edfe..e73d359de5 100644 --- a/packages/blockchain/docs/functions/getBlockFromRpc.md +++ b/packages/blockchain/docs/functions/getBlockFromRpc.md @@ -6,10 +6,12 @@ # Function: getBlockFromRpc() -> **getBlockFromRpc**(`params`, `common`): `Promise`\<`Block`\> +> **getBlockFromRpc**(`baseChain`, `params`, `common`): `Promise`\<`Block`\> ## Parameters +• **baseChain**: `BaseChain` + • **params** • **params.blockTag**: `undefined` \| `bigint` \| `BlockTag` \| \`0x$\{string\}\` = `'latest'` @@ -26,4 +28,4 @@ ## Defined in -[utils/getBlockFromRpc.js:37](https://github.com/evmts/tevm-monorepo/blob/main/packages/blockchain/src/utils/getBlockFromRpc.js#L37) +[utils/getBlockFromRpc.js:23](https://github.com/evmts/tevm-monorepo/blob/main/packages/blockchain/src/utils/getBlockFromRpc.js#L23) diff --git a/packages/blockchain/docs/type-aliases/Chain.md b/packages/blockchain/docs/type-aliases/Chain.md index 3f76b7c52d..a457bba118 100644 --- a/packages/blockchain/docs/type-aliases/Chain.md +++ b/packages/blockchain/docs/type-aliases/Chain.md @@ -67,6 +67,33 @@ Returns a block by its hash or number. `Promise`\<`Block`\> +### getBlockByTag() + +Gets block given one of the following inputs: +- Hex block hash +- Hex block number (if length is 32 bytes, it is treated as a hash) +- Uint8Array block hash +- Number block number +- BigInt block number +- BlockTag block tag +- Named block tag (e.g. 'latest', 'earliest', 'pending') + +#### Parameters + +• **blockTag**: `number` \| `bigint` \| `Uint8Array` \| `BlockTag` \| \`0x$\{string\}\` + +#### Returns + +`Promise`\<`Block`\> + +#### Throws + +- If the block is not found + +#### Throw + +- If the block tag is invalid} + ### getCanonicalHeadBlock() Returns the latest full block in the canonical chain. diff --git a/packages/blockchain/src/actions/getBlock.js b/packages/blockchain/src/actions/getBlock.js index c35f4a8f00..5b73da25bf 100644 --- a/packages/blockchain/src/actions/getBlock.js +++ b/packages/blockchain/src/actions/getBlock.js @@ -38,6 +38,7 @@ export const getBlock = (baseChain) => async (blockId) => { baseChain.logger.debug('Fetching block from remote rpc...') const fetchedBlock = await getBlockFromRpc( + baseChain, { transport: baseChain.options.fork?.transport, blockTag: blockId instanceof Uint8Array ? bytesToHex(blockId) : BigInt(blockId), diff --git a/packages/blockchain/src/actions/getBlockByTag.js b/packages/blockchain/src/actions/getBlockByTag.js index 066c788f87..7b16dca521 100644 --- a/packages/blockchain/src/actions/getBlockByTag.js +++ b/packages/blockchain/src/actions/getBlockByTag.js @@ -19,6 +19,7 @@ export const getBlockByTag = (baseChain) => async (blockId) => { const block = baseChain.blocksByTag.get(blockId) if (!block && baseChain.options.fork?.transport) { const block = await getBlockFromRpc( + baseChain, { transport: baseChain.options.fork.transport, blockTag: blockId, diff --git a/packages/blockchain/src/createBaseChain.js b/packages/blockchain/src/createBaseChain.js index 1b10244dcf..a7b86fefb2 100644 --- a/packages/blockchain/src/createBaseChain.js +++ b/packages/blockchain/src/createBaseChain.js @@ -68,7 +68,7 @@ export const createBaseChain = (options) => { // Add genesis block and forked block to chain const genesisBlockPromise = (async () => { if (options.fork?.transport) { - const block = await getBlockFromRpc(options.fork, options.common) + const block = await getBlockFromRpc(chain, options.fork, options.common) await putBlock(chain)(block) chain.blocksByTag.set('forked', block) } else { diff --git a/packages/blockchain/src/utils/getBlockFromRpc.js b/packages/blockchain/src/utils/getBlockFromRpc.js index f2a02fa4ed..2902d1346b 100644 --- a/packages/blockchain/src/utils/getBlockFromRpc.js +++ b/packages/blockchain/src/utils/getBlockFromRpc.js @@ -2,6 +2,7 @@ import { Block, blockFromRpc } from '@tevm/block' import { createJsonRpcFetcher } from '@tevm/jsonrpc' import { numberToHex } from '@tevm/utils' import { withRetry } from 'viem' +import { warnOnce } from './warnOnce.js' /** * Determines if an unknown type is a valid block tag @@ -12,29 +13,14 @@ const isBlockTag = (blockTag) => { return typeof blockTag === 'string' && ['latest', 'earliest', 'pending', 'safe', 'finalized'].includes(blockTag) } -let i = 0 - -/** - * @param {import('viem').RpcBlock} tx - */ -const warnOnce = (tx) => { - if (i > 0) { - return - } - i++ - console.warn( - `Warning: Optimism deposit transactions (type 0x7e) are currently not supported and will be filtered out of blocks until support is added -filtering out tx ${/** @type {import('viem').RpcBlock}*/ (tx).hash}`, - ) -} - /** + * @param {import('../BaseChain.js').BaseChain} baseChain * @param {object} params * @param {{request: import('viem').EIP1193RequestFn}} params.transport * @param {bigint | import('viem').BlockTag | import('viem').Hex} [params.blockTag] * @param {import('@tevm/common').Common} common */ -export const getBlockFromRpc = async ({ transport, blockTag = 'latest' }, common) => { +export const getBlockFromRpc = async (baseChain, { transport, blockTag = 'latest' }, common) => { const fetcher = createJsonRpcFetcher(transport) /** * @param {import('viem').RpcBlock<'latest', true>} rpcBlock @@ -50,7 +36,7 @@ export const getBlockFromRpc = async ({ transport, blockTag = 'latest' }, common // Optimism type is currently not in viem types // @ts-expect-error if (tx.type === '0x7e') { - warnOnce(tx) + warnOnce(baseChain)(tx) return false } return true diff --git a/packages/blockchain/src/utils/getBlockFromRpc.spec.ts b/packages/blockchain/src/utils/getBlockFromRpc.spec.ts index 1ce5cef262..b19e99a706 100644 --- a/packages/blockchain/src/utils/getBlockFromRpc.spec.ts +++ b/packages/blockchain/src/utils/getBlockFromRpc.spec.ts @@ -1,15 +1,18 @@ -import { describe, expect, it } from 'bun:test' +import { describe, expect, it, jest } from 'bun:test' import { Block } from '@tevm/block' import { optimism } from '@tevm/common' +import { InvalidBlockError, UnknownBlockError } from '@tevm/errors' import { transports } from '@tevm/test-utils' +import { createBaseChain } from '../createBaseChain.js' import { getBlockFromRpc } from './getBlockFromRpc.js' describe('getBlockFromRpc', () => { + const baseChain = createBaseChain({ common: optimism.copy() }) it('should fetch the latest block', async () => { const transport = transports.optimism const common = optimism.copy() - const block = await getBlockFromRpc({ transport, blockTag: 'latest' }, common) + const block = await getBlockFromRpc(baseChain, { transport, blockTag: 'latest' }, common) expect(block).toBeInstanceOf(Block) expect(block.header.number).toBeGreaterThanOrEqual(0n) }) @@ -19,7 +22,7 @@ describe('getBlockFromRpc', () => { const common = optimism.copy() const blockNumber = 122606365n - const block = await getBlockFromRpc({ transport, blockTag: blockNumber }, common) + const block = await getBlockFromRpc(baseChain, { transport, blockTag: blockNumber }, common) expect(block).toBeInstanceOf(Block) expect(block.header.number).toBe(blockNumber) }) @@ -29,9 +32,9 @@ describe('getBlockFromRpc', () => { const common = optimism.copy() const blockHash = '0x6d4f1b3c89f9a26e7b1d8af7b093b8936d4d1af7989d0b1a7b1a2b0b0b6a6a6a' - const block = await getBlockFromRpc({ transport, blockTag: blockHash }, common) + const block = await getBlockFromRpc(baseChain, { transport, blockTag: blockHash }, common) expect(block).toBeInstanceOf(Block) - expect(block.hash().toString('hex')).toBe(blockHash.slice(2)) + expect(block.hash().toString()).toBe(blockHash.slice(2)) }) it('should handle invalid block tag', async () => { @@ -39,9 +42,11 @@ describe('getBlockFromRpc', () => { const common = optimism.copy() const invalidBlockTag = 'invalid-tag' - await expect(getBlockFromRpc({ transport, blockTag: invalidBlockTag as any }, common)).rejects.toThrow( - `Invalid blocktag ${invalidBlockTag}`, + const err = await getBlockFromRpc(baseChain, { transport, blockTag: invalidBlockTag as any }, common).catch( + (e) => e, ) + expect(err).toBeInstanceOf(InvalidBlockError) + expect(err).toMatchSnapshot() }) it('should handle non-existing block number', async () => { @@ -49,31 +54,38 @@ describe('getBlockFromRpc', () => { const common = optimism.copy() const nonExistingBlockNumber = 99999999999n - await expect(getBlockFromRpc({ transport, blockTag: nonExistingBlockNumber }, common)).rejects.toThrow( - 'No block found', + const err = await getBlockFromRpc(baseChain, { transport, blockTag: nonExistingBlockNumber }, common).catch( + (e) => e, ) + + expect(err).toBeInstanceOf(UnknownBlockError) + expect(err).toMatchSnapshot() }) it('should handle non-existing block hash', async () => { const transport = transports.optimism const common = optimism.copy() - const nonExistingBlockHash = `0x${'0'.repeat(64)}` + const nonExistingBlockHash = `0x${'0'.repeat(64)}` as const - await expect(getBlockFromRpc({ transport, blockTag: nonExistingBlockHash }, common)).rejects.toThrow( - 'No block found', - ) + const err = await getBlockFromRpc(baseChain, { transport, blockTag: nonExistingBlockHash }, common).catch((e) => e) + expect(err).toBeInstanceOf(UnknownBlockError) + expect(err).toMatchSnapshot() }) it('should handle Optimism deposit transactions filtering', async () => { const transport = transports.optimism const common = optimism.copy() - const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}) + const baseChain = createBaseChain({ common }) + const consoleWarnSpy = jest.fn() + baseChain.logger.warn = consoleWarnSpy - const block = await getBlockFromRpc({ transport, blockTag: 'latest' }, common) + const block = await getBlockFromRpc(baseChain, { transport, blockTag: 'latest' }, common) + await getBlockFromRpc(baseChain, { transport, blockTag: 'latest' }, common) + await getBlockFromRpc(baseChain, { transport, blockTag: 'latest' }, common) expect(block).toBeInstanceOf(Block) - expect(consoleWarnSpy).toHaveBeenCalled() - + expect(consoleWarnSpy).toHaveBeenCalledTimes(1) + expect(consoleWarnSpy.mock.calls).toMatchSnapshot() consoleWarnSpy.mockRestore() }) }) diff --git a/packages/blockchain/src/utils/warnOnce.js b/packages/blockchain/src/utils/warnOnce.js new file mode 100644 index 0000000000..002485bee6 --- /dev/null +++ b/packages/blockchain/src/utils/warnOnce.js @@ -0,0 +1,20 @@ +let i = 0 +/** + * Creates a function that logs a warning once + * @param {import('../BaseChain.js').BaseChain} baseChain + */ +export const warnOnce = (baseChain) => { + /** + * @param {import('viem').RpcBlock} tx + */ + return (tx) => { + if (i > 0) { + return + } + i++ + baseChain.logger.warn( + `Warning: Optimism deposit transactions (type 0x7e) are currently not supported and will be filtered out of blocks until support is added +filtering out tx ${/** @type {import('viem').RpcBlock}*/ (tx).hash}`, + ) + } +} diff --git a/packages/procedures/src/utils/blockToJsonRpcBlock.spec.ts b/packages/procedures/src/utils/blockToJsonRpcBlock.spec.ts index a28cc4815d..83c1063d06 100644 --- a/packages/procedures/src/utils/blockToJsonRpcBlock.spec.ts +++ b/packages/procedures/src/utils/blockToJsonRpcBlock.spec.ts @@ -8,7 +8,11 @@ import { blockToJsonRpcBlock } from './blockToJsonRpcBlock.js' describe('blockToJsonRpcBlock', async () => { const client = createBaseClient({ common: optimism }) const vm = await client.getVm() - const block = await getBlockFromRpc({ blockTag: 121960766n, transport: transports.optimism }, vm.common) + const block = await getBlockFromRpc( + vm.blockchain, + { blockTag: 121960766n, transport: transports.optimism }, + vm.common, + ) it('should convert block to JSON-RPC block format with transactions', async () => { expect(await blockToJsonRpcBlock(block, true)).toMatchSnapshot() diff --git a/packages/procedures/src/utils/txToJsonRpcTx.spec.ts b/packages/procedures/src/utils/txToJsonRpcTx.spec.ts index 94a06d7b3d..01bd2ca64e 100644 --- a/packages/procedures/src/utils/txToJsonRpcTx.spec.ts +++ b/packages/procedures/src/utils/txToJsonRpcTx.spec.ts @@ -26,7 +26,11 @@ describe(txToJsonRpcTx.name, () => { common: optimism, }) const vm = await client.getVm() - const block = await getBlockFromRpc({ blockTag: 121960766n, transport: transports.optimism }, vm.common) + const block = await getBlockFromRpc( + vm.blockchain, + { blockTag: 121960766n, transport: transports.optimism }, + vm.common, + ) expect(txToJsonRpcTx(tx, block, 0)).toMatchSnapshot() }) }) diff --git a/tevm/docs/blockchain/functions/getBlockFromRpc.md b/tevm/docs/blockchain/functions/getBlockFromRpc.md index 8200de5a21..6c99f0e811 100644 --- a/tevm/docs/blockchain/functions/getBlockFromRpc.md +++ b/tevm/docs/blockchain/functions/getBlockFromRpc.md @@ -6,10 +6,12 @@ # Function: getBlockFromRpc() -> **getBlockFromRpc**(`__namedParameters`, `common`): `Promise`\<[`Block`](../../block/classes/Block.md)\> +> **getBlockFromRpc**(`baseChain`, `__namedParameters`, `common`): `Promise`\<[`Block`](../../block/classes/Block.md)\> ## Parameters +• **baseChain**: `BaseChain` + • **\_\_namedParameters** • **\_\_namedParameters.blockTag?**: `bigint` \| \`0x$\{string\}\` \| [`BlockTag`](../../index/type-aliases/BlockTag.md) diff --git a/tevm/docs/blockchain/type-aliases/Chain.md b/tevm/docs/blockchain/type-aliases/Chain.md index bae6fe0f4e..cc6fb4596f 100644 --- a/tevm/docs/blockchain/type-aliases/Chain.md +++ b/tevm/docs/blockchain/type-aliases/Chain.md @@ -67,6 +67,33 @@ Returns a block by its hash or number. `Promise`\<[`Block`](../../block/classes/Block.md)\> +### getBlockByTag() + +Gets block given one of the following inputs: +- Hex block hash +- Hex block number (if length is 32 bytes, it is treated as a hash) +- Uint8Array block hash +- Number block number +- BigInt block number +- BlockTag block tag +- Named block tag (e.g. 'latest', 'earliest', 'pending') + +#### Parameters + +• **blockTag**: `number` \| `bigint` \| \`0x$\{string\}\` \| [`BlockTag`](../../index/type-aliases/BlockTag.md) \| `Uint8Array` + +#### Returns + +`Promise`\<[`Block`](../../block/classes/Block.md)\> + +#### Throws + +- If the block is not found + +#### Throw + +- If the block tag is invalid} + ### getCanonicalHeadBlock() Returns the latest full block in the canonical chain. From bfc4df2e225ef875c704c6da0cba7e2245c36c6e Mon Sep 17 00:00:00 2001 From: William Cory Date: Mon, 15 Jul 2024 09:45:04 -0700 Subject: [PATCH 5/6] :white_check_mark: Fix: tests --- .../@tevm/blockchain/functions/createChain.md | 2 +- .../blockchain/functions/getBlockFromRpc.md | 6 +- .../@tevm/blockchain/type-aliases/Chain.md | 27 ++++ .../getBlockFromRpc.spec.ts.snap | 42 ++++++ .../blockchain/src/utils/getBlockFromRpc.js | 15 +-- .../src/utils/getBlockFromRpc.spec.ts | 121 ++++++++++++++++-- packages/blockchain/src/utils/warnOnce.js | 6 +- 7 files changed, 195 insertions(+), 24 deletions(-) create mode 100644 packages/blockchain/src/utils/__snapshots__/getBlockFromRpc.spec.ts.snap diff --git a/docs/src/content/docs/reference/@tevm/blockchain/functions/createChain.md b/docs/src/content/docs/reference/@tevm/blockchain/functions/createChain.md index 97dc0cdf75..f3d7d6d393 100644 --- a/docs/src/content/docs/reference/@tevm/blockchain/functions/createChain.md +++ b/docs/src/content/docs/reference/@tevm/blockchain/functions/createChain.md @@ -17,4 +17,4 @@ title: "createChain" ## Defined in -[createChain.js:15](https://github.com/evmts/tevm-monorepo/blob/main/packages/blockchain/src/createChain.js#L15) +[createChain.js:16](https://github.com/evmts/tevm-monorepo/blob/main/packages/blockchain/src/createChain.js#L16) diff --git a/docs/src/content/docs/reference/@tevm/blockchain/functions/getBlockFromRpc.md b/docs/src/content/docs/reference/@tevm/blockchain/functions/getBlockFromRpc.md index 3b1a145a09..efa71b9baf 100644 --- a/docs/src/content/docs/reference/@tevm/blockchain/functions/getBlockFromRpc.md +++ b/docs/src/content/docs/reference/@tevm/blockchain/functions/getBlockFromRpc.md @@ -5,10 +5,12 @@ prev: false title: "getBlockFromRpc" --- -> **getBlockFromRpc**(`params`, `common`): `Promise`\<[`Block`](/reference/tevm/block/classes/block/)\> +> **getBlockFromRpc**(`baseChain`, `params`, `common`): `Promise`\<[`Block`](/reference/tevm/block/classes/block/)\> ## Parameters +• **baseChain**: `BaseChain` + • **params** • **params.blockTag**: `undefined` \| `bigint` \| [`BlockTag`](/reference/tevm/utils/type-aliases/blocktag/) \| \`0x$\{string\}\` = `'latest'` @@ -25,4 +27,4 @@ title: "getBlockFromRpc" ## Defined in -[utils/getBlockFromRpc.js:37](https://github.com/evmts/tevm-monorepo/blob/main/packages/blockchain/src/utils/getBlockFromRpc.js#L37) +[utils/getBlockFromRpc.js:23](https://github.com/evmts/tevm-monorepo/blob/main/packages/blockchain/src/utils/getBlockFromRpc.js#L23) diff --git a/docs/src/content/docs/reference/@tevm/blockchain/type-aliases/Chain.md b/docs/src/content/docs/reference/@tevm/blockchain/type-aliases/Chain.md index 02e71e03c7..e2442512bc 100644 --- a/docs/src/content/docs/reference/@tevm/blockchain/type-aliases/Chain.md +++ b/docs/src/content/docs/reference/@tevm/blockchain/type-aliases/Chain.md @@ -66,6 +66,33 @@ Returns a block by its hash or number. `Promise`\<[`Block`](/reference/tevm/block/classes/block/)\> +### getBlockByTag() + +Gets block given one of the following inputs: +- Hex block hash +- Hex block number (if length is 32 bytes, it is treated as a hash) +- Uint8Array block hash +- Number block number +- BigInt block number +- BlockTag block tag +- Named block tag (e.g. 'latest', 'earliest', 'pending') + +#### Parameters + +• **blockTag**: `number` \| `bigint` \| `Uint8Array` \| [`BlockTag`](/reference/tevm/utils/type-aliases/blocktag/) \| \`0x$\{string\}\` + +#### Returns + +`Promise`\<[`Block`](/reference/tevm/block/classes/block/)\> + +#### Throws + +- If the block is not found + +#### Throw + +- If the block tag is invalid} + ### getCanonicalHeadBlock() Returns the latest full block in the canonical chain. diff --git a/packages/blockchain/src/utils/__snapshots__/getBlockFromRpc.spec.ts.snap b/packages/blockchain/src/utils/__snapshots__/getBlockFromRpc.spec.ts.snap new file mode 100644 index 0000000000..ce62dd87ce --- /dev/null +++ b/packages/blockchain/src/utils/__snapshots__/getBlockFromRpc.spec.ts.snap @@ -0,0 +1,42 @@ +// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[`getBlockFromRpc should handle invalid block tag 1`] = `[UnknownBlockError: No block found + +Docs: https://tevm.sh/reference/tevm/errors/classes/unknownblockerror/ +Version: 1.1.0.next-73]`; + +exports[`getBlockFromRpc should handle non-existing block number 1`] = `[UnknownBlockError: No block found + +Docs: https://tevm.sh/reference/tevm/errors/classes/unknownblockerror/ +Version: 1.1.0.next-73]`; + +exports[`getBlockFromRpc should handle non-existing block hash 1`] = `[UnknownBlockError: No block found + +Docs: https://tevm.sh/reference/tevm/errors/classes/unknownblockerror/ +Version: 1.1.0.next-73]`; + +exports[`getBlockFromRpc should handle Optimism deposit transactions filtering 1`] = ` +[ + [ + +"Warning: Optimism deposit transactions (type 0x7e) are currently not supported and will be filtered out of blocks until support is added +filtering out tx 0x284db6dad8681a502b229691d72e890be7f8533cbf34f9d88fbe84db0ed1ff35. +Note: The block hash will be different because of the execluded txs" +, + ], + [ + +"Warning: Optimism deposit transactions (type 0x7e) are currently not supported and will be filtered out of blocks until support is added +filtering out tx 0x284db6dad8681a502b229691d72e890be7f8533cbf34f9d88fbe84db0ed1ff35. +Note: The block hash will be different because of the execluded txs" +, + ], + [ + +"Warning: Optimism deposit transactions (type 0x7e) are currently not supported and will be filtered out of blocks until support is added +filtering out tx 0x284db6dad8681a502b229691d72e890be7f8533cbf34f9d88fbe84db0ed1ff35. +Note: The block hash will be different because of the execluded txs" +, + ], +] +`; diff --git a/packages/blockchain/src/utils/getBlockFromRpc.js b/packages/blockchain/src/utils/getBlockFromRpc.js index 2902d1346b..775d6a60be 100644 --- a/packages/blockchain/src/utils/getBlockFromRpc.js +++ b/packages/blockchain/src/utils/getBlockFromRpc.js @@ -1,4 +1,5 @@ import { Block, blockFromRpc } from '@tevm/block' +import { InvalidBlockError, UnknownBlockError } from '@tevm/errors' import { createJsonRpcFetcher } from '@tevm/jsonrpc' import { numberToHex } from '@tevm/utils' import { withRetry } from 'viem' @@ -21,6 +22,7 @@ const isBlockTag = (blockTag) => { * @param {import('@tevm/common').Common} common */ export const getBlockFromRpc = async (baseChain, { transport, blockTag = 'latest' }, common) => { + const doWarning = warnOnce(baseChain) const fetcher = createJsonRpcFetcher(transport) /** * @param {import('viem').RpcBlock<'latest', true>} rpcBlock @@ -36,7 +38,7 @@ export const getBlockFromRpc = async (baseChain, { transport, blockTag = 'latest // Optimism type is currently not in viem types // @ts-expect-error if (tx.type === '0x7e') { - warnOnce(baseChain)(tx) + doWarning(tx) return false } return true @@ -63,7 +65,7 @@ export const getBlockFromRpc = async (baseChain, { transport, blockTag = 'latest throw error } if (!result) { - throw new Error('No block found') + throw new UnknownBlockError('No block found') } return asEthjsBlock(result) } @@ -75,12 +77,10 @@ export const getBlockFromRpc = async (baseChain, { transport, blockTag = 'latest params: [blockTag, true], }) if (error) { - console.error(error) throw error } if (!result) { - console.error(error) - throw new Error('No block found') + throw new UnknownBlockError('No block found') } return asEthjsBlock(/** @type {any}*/ (result)) } @@ -93,15 +93,14 @@ export const getBlockFromRpc = async (baseChain, { transport, blockTag = 'latest params: [blockTag, true], }) if (error) { - console.error(error) throw error } if (!result) { - throw new Error('No block found') + throw new UnknownBlockError('No block found') } return asEthjsBlock(/** @type {any}*/ (result)) } - throw new Error(`Invalid blocktag ${blockTag}`) + throw new InvalidBlockError(`Invalid blocktag ${blockTag}`) }, { retryCount: 3, diff --git a/packages/blockchain/src/utils/getBlockFromRpc.spec.ts b/packages/blockchain/src/utils/getBlockFromRpc.spec.ts index b19e99a706..6738f4e8a7 100644 --- a/packages/blockchain/src/utils/getBlockFromRpc.spec.ts +++ b/packages/blockchain/src/utils/getBlockFromRpc.spec.ts @@ -1,8 +1,9 @@ import { describe, expect, it, jest } from 'bun:test' import { Block } from '@tevm/block' import { optimism } from '@tevm/common' -import { InvalidBlockError, UnknownBlockError } from '@tevm/errors' +import { UnknownBlockError } from '@tevm/errors' import { transports } from '@tevm/test-utils' +import { bytesToHex } from 'viem' import { createBaseChain } from '../createBaseChain.js' import { getBlockFromRpc } from './getBlockFromRpc.js' @@ -17,42 +18,51 @@ describe('getBlockFromRpc', () => { expect(block.header.number).toBeGreaterThanOrEqual(0n) }) + const blockNumber = 122699513n + const blockHash = '0x485643430d3c6d32d4391353b2de38d335443d6399eccd7f639cd73027cc3245' + // it is different because we filter out optimism deposit tx + const blockHashAfterForking = '0xcbec656e620f3182a946be85fb7fa34b802b064c4be1bd7ce52df74954d7a49e' + it('should fetch a block by number', async () => { const transport = transports.optimism const common = optimism.copy() - const blockNumber = 122606365n const block = await getBlockFromRpc(baseChain, { transport, blockTag: blockNumber }, common) expect(block).toBeInstanceOf(Block) expect(block.header.number).toBe(blockNumber) + expect(bytesToHex(block.header.hash())).toEqual(blockHashAfterForking) + // this is an ethjs bug that the type doesn't match + expect(block.toJSON()).toEqual(expectedBlock as any) }) it('should fetch a block by hash', async () => { const transport = transports.optimism const common = optimism.copy() - const blockHash = '0x6d4f1b3c89f9a26e7b1d8af7b093b8936d4d1af7989d0b1a7b1a2b0b0b6a6a6a' const block = await getBlockFromRpc(baseChain, { transport, blockTag: blockHash }, common) expect(block).toBeInstanceOf(Block) - expect(block.hash().toString()).toBe(blockHash.slice(2)) + expect(bytesToHex(block.hash())).toBe(blockHashAfterForking) + expect(block.header.number).toBe(blockNumber) + // this is an ethjs bug that the type doesn't match + expect(block.toJSON()).toEqual(expectedBlock as any) }) it('should handle invalid block tag', async () => { const transport = transports.optimism const common = optimism.copy() - const invalidBlockTag = 'invalid-tag' + const invalidBlockTag = '0x420420430d3c6d32d4391353b2de38d335443d6399eccd7f639cd73027420420' const err = await getBlockFromRpc(baseChain, { transport, blockTag: invalidBlockTag as any }, common).catch( (e) => e, ) - expect(err).toBeInstanceOf(InvalidBlockError) + expect(err).toBeInstanceOf(UnknownBlockError) expect(err).toMatchSnapshot() }) it('should handle non-existing block number', async () => { const transport = transports.optimism const common = optimism.copy() - const nonExistingBlockNumber = 99999999999n + const nonExistingBlockNumber = 99999999999999999n const err = await getBlockFromRpc(baseChain, { transport, blockTag: nonExistingBlockNumber }, common).catch( (e) => e, @@ -80,12 +90,101 @@ describe('getBlockFromRpc', () => { const consoleWarnSpy = jest.fn() baseChain.logger.warn = consoleWarnSpy - const block = await getBlockFromRpc(baseChain, { transport, blockTag: 'latest' }, common) - await getBlockFromRpc(baseChain, { transport, blockTag: 'latest' }, common) - await getBlockFromRpc(baseChain, { transport, blockTag: 'latest' }, common) + const block = await getBlockFromRpc(baseChain, { transport, blockTag: blockNumber }, common) + await getBlockFromRpc(baseChain, { transport, blockTag: blockNumber }, common) + await getBlockFromRpc(baseChain, { transport, blockTag: blockNumber }, common) expect(block).toBeInstanceOf(Block) - expect(consoleWarnSpy).toHaveBeenCalledTimes(1) + // only called once per call rather than once per tx + expect(consoleWarnSpy).toHaveBeenCalledTimes(3) expect(consoleWarnSpy.mock.calls).toMatchSnapshot() consoleWarnSpy.mockRestore() }) }) + +const expectedBlock = { + header: { + baseFeePerGas: '0x49c53', + blobGasUsed: '0x0', + coinbase: '0x4200000000000000000000000000000000000011', + difficulty: '0x0', + excessBlobGas: '0x0', + extraData: '0x', + gasLimit: '0x1c9c380', + gasUsed: '0x366775', + logsBloom: + '0x00b020004002000800000000000000000000210800080000000800004400000028000000254102000000000000000000004000040840000000402040000008000000001000000000002000080200000000000480000000000000043000a080000011000002000040000000004000082000000000000000040000005000000001001000210000000000001000000080000040008080000000004004022201087000140001040000000008000800000400a00008200000010200000000000000a04000000200020000400210020002004000000000008000000000000020002000000000280080008020000000000000000000010000000c8000020000000000c0', + mixHash: '0xdc4f0757bd0f7e87f05c37e6bcaf12d12f4509e71ef7bcf9dadc6a916155ce16', + nonce: '0x0000000000000000', + number: '0x7503ef9', + parentBeaconBlockRoot: '0x91cf67004be4a1f9cb638f1999aa9b013d2afebbfa1aa4c06ba82e4d668443aa', + parentHash: '0x3e7b1c676f9450cd921209981847d633028d70c8c0720014e31d524b8cf54c07', + receiptTrie: '0x8fa30f0a51947bff54300fefb7ea95998aaf88acefb018869ef6225136f960d4', + stateRoot: '0xc517c452ae4595b87098d196d5ec2285851d39b2feeeeffd493109d3a093b0e0', + timestamp: '0x669457ab', + transactionsTrie: '0xd470b757c11beea437e14b493489946e4b951c60c5c510348a94f8393468e00d', + uncleHash: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', + withdrawalsRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', + }, + requests: undefined, + transactions: [ + { + data: '0x014e17b000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000030479e800000000000000000000000000000000000000000000000000616352f5b60af0000000000000000000000000000000000000000000000000000470de4df820000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000203434303738373500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c00000000000000000000000000000000000000000000000000000000000027190000000000000000000000000000000000000000000000000000000066946680000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000616352f5b60af0000000000000000000000000000000000000000000000000008d6dffd0723a3c00000000000000000000000000000000000000000000000000000000000000006d02232bd3b64baa3746e97b85ffa8a136500a3167a8c4456787a3adcb968f63106636934809813db15d9fae9337df5a127d7087881281e08f948d4fc26917452b2fb8c7196962e8eb430dc38991796df40aa72943a6aa353b538a3083b467f28ca3c0222e7dd4c6e0ca71926856948902d6666b4dea0581dc30ddcb3ab1a9f2aff695e7479d2fe72e972a86c4f3a65781e377129f0c0fe35ac0dc3a0eca8e6086efe350136ca4f6bf8bb0b33f9f98b0e59c7bfbbd9652190d1f9b4214770d8a600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + gasLimit: '0x175dea', + gasPrice: '0x21064c', + nonce: '0x147', + r: '0xd2319cf97f032213fff650db456510e8a11aa7221f30eb2490589b60bb71e889', + s: '0x4696f3d45d8434199b1fb71fbae547f04ea52bcf06d7f6f7c163990ebf4349db', + to: '0xfb4e4811c7a811e098a556bd79b64c20b479e431', + type: '0x0', + v: '0x38', + value: '0x0', + }, + { + accessList: [], + chainId: '0xa', + data: '0x82ad56cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000320000000000000000000000000ca8290402f3639cebf46649a971d320dfb023d2e0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a761202000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb000000000000000000000000cf344fb33e8d3fa1d790a6d03a382d1087b6f311000000000000000000000000000000000000000000000000b469471f80140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041dc87ae994c7c718c1dc3a713610f5ac9d03cdb9d232b193810ca3f1c07cb263a3a3f3a6b40ea82248fb1341779d87320e7cf19de3f56e2ea0e015c8e2fee7d231b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dcce1199eb728d080b8c4fe77f6fa01445e8502e0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a761202000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb000000000000000000000000635d5bbf389c218b0d07a960c677c9a62f715bc60000000000000000000000000000000000000000000000002bfe1a3461fd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041e76ae9a9fd0402e6d77b0fd5250b81da706a4fc5cd6abefce3c10bc2bc18460b2c20d6d459222377f5cdc86e566fcccd47aefdbb2bc688c5727aa00c387a315e1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + gasLimit: '0x29188', + maxFeePerGas: '0x20db37', + maxPriorityFeePerGas: '0x17a291', + nonce: '0x907ac', + r: '0x95f5df460bc6ab7704ffb8d69289116833ebbbd11561c46fb698f321a97adf14', + s: '0x19a83eab66e5f83e2c7c94431862736346b5b58ea222f4a2c9d369cc03f995a8', + to: '0x087000a300de7200382b55d40045000000e5d60e', + type: '0x2', + v: '0x1', + value: '0x0', + }, + { + accessList: [], + chainId: '0xa', + data: '0x379607f500000000000000000000000000000000000000000000000000000000000014ac', + gasLimit: '0x2447c5', + maxFeePerGas: '0x140627', + maxPriorityFeePerGas: '0xf4240', + nonce: '0x3b', + r: '0x7a71d359aed23c13d5bc9ee98906d83a94e1471e1a1cf5734c417932a24bcfa1', + s: '0x5f1f5975144b69fdcde2fa0bbd637da9b3c7b369f58eec86ae716e31e8ae0b5c', + to: '0x9d4736ec60715e71afe72973f7885dcbc21ea99b', + type: '0x2', + v: '0x0', + value: '0x0', + }, + { + accessList: [], + chainId: '0xa', + data: '0xa9059cbb000000000000000000000000f2287c150d6aad5754e718bbe9d052181343bd3f00000000000000000000000000000000000000000000000000000000017b7c70', + gasLimit: '0x8926', + maxFeePerGas: '0x7c63df4', + maxPriorityFeePerGas: '0x1fd81', + nonce: '0x3223b9', + r: '0x8d808d9fffde2669d3b4e00d1ec594f14c0f348876a2df68962d27555ade6d47', + s: '0x73d743608934c6e571db6ad6214844c466fe71e42b6e3e722bf98af60ce4096e', + to: '0x94b008aa00579c1307b0ef2c499ad98a8ce58e58', + type: '0x2', + v: '0x0', + value: '0x0', + }, + ], + uncleHeaders: [], + withdrawals: [], +} diff --git a/packages/blockchain/src/utils/warnOnce.js b/packages/blockchain/src/utils/warnOnce.js index 002485bee6..3c6f7f4edb 100644 --- a/packages/blockchain/src/utils/warnOnce.js +++ b/packages/blockchain/src/utils/warnOnce.js @@ -1,11 +1,12 @@ -let i = 0 /** * Creates a function that logs a warning once * @param {import('../BaseChain.js').BaseChain} baseChain */ export const warnOnce = (baseChain) => { + let i = 0 /** * @param {import('viem').RpcBlock} tx + * @returns {void}} */ return (tx) => { if (i > 0) { @@ -14,7 +15,8 @@ export const warnOnce = (baseChain) => { i++ baseChain.logger.warn( `Warning: Optimism deposit transactions (type 0x7e) are currently not supported and will be filtered out of blocks until support is added -filtering out tx ${/** @type {import('viem').RpcBlock}*/ (tx).hash}`, +filtering out tx ${/** @type {import('viem').RpcBlock}*/ (tx).hash}. +Note: The block hash will be different because of the execluded txs`, ) } } From 68082c394d78d7fe9c0427ae88f13515100c25ef Mon Sep 17 00:00:00 2001 From: William Cory Date: Mon, 15 Jul 2024 09:55:57 -0700 Subject: [PATCH 6/6] :camera_flash: Fix: broken snap --- .../cloneVmWithBlock.spec.ts.snap | 55 +++---------------- .../docs/functions/getBlockFromRpc.md | 2 +- 2 files changed, 9 insertions(+), 48 deletions(-) diff --git a/packages/actions/src/Call/__snapshots__/cloneVmWithBlock.spec.ts.snap b/packages/actions/src/Call/__snapshots__/cloneVmWithBlock.spec.ts.snap index 51c550f6b9..bab23b8a5d 100644 --- a/packages/actions/src/Call/__snapshots__/cloneVmWithBlock.spec.ts.snap +++ b/packages/actions/src/Call/__snapshots__/cloneVmWithBlock.spec.ts.snap @@ -1,55 +1,16 @@ // Bun Snapshot v1, https://goo.gl/fbAQLP -exports[`cloneVmWithBlockTag should handle errors during VM cloning 1`] = ` -"Invalid blocktag Infinity - -Docs: https://tevm.sh/reference/tevm/errors/classes/internalerror/ -Details: Invalid blocktag Infinity -Version: 1.1.0.next-73" -`; - -exports[`cloneVmWithBlockTag should properly handle a fork client requestiong a block prefork 1`] = ` -Uint8Array [ - 107, - 141, - 207, - 138, - 42, - 50, - 122, - 161, - 178, - 227, - 235, - 237, - 89, - 43, - 27, - 29, - 9, - 190, - 201, - 146, - 105, - 196, - 134, - 37, - 180, - 103, - 155, - 110, - 214, - 164, - 226, - 87, -] -`; - exports[`cloneVmWithBfockTag should handle errors during forking 1`] = `[ForkError: Invalid blocktag Infinity + +Docs: https://tevm.sh/reference/tevm/errors/classes/invalidblockerror/ +Version: 1.1.0.next-73 Invalid blocktag Infinity -Docs: https://tevm.sh/reference/tevm/errors/classes/accountlockederror/ -Details: Invalid blocktag Infinity +Docs: https://tevm.sh/reference/tevm/errors/classes/invalidblockerror/ +Version: 1.1.0.next-73 + +Docs: https://tevm.sh/reference/tevm/errors/classes/invalidblockerror/ +Details: /reference/tevm/errors/classes/invalidblockerror/ Version: 1.1.0.next-73]`; exports[`cloneVmWithBfockTag should handle errors during VM cloning 1`] = `[InternalError: deepCopy error diff --git a/packages/blockchain/docs/functions/getBlockFromRpc.md b/packages/blockchain/docs/functions/getBlockFromRpc.md index e73d359de5..cb06e9dc51 100644 --- a/packages/blockchain/docs/functions/getBlockFromRpc.md +++ b/packages/blockchain/docs/functions/getBlockFromRpc.md @@ -28,4 +28,4 @@ ## Defined in -[utils/getBlockFromRpc.js:23](https://github.com/evmts/tevm-monorepo/blob/main/packages/blockchain/src/utils/getBlockFromRpc.js#L23) +[utils/getBlockFromRpc.js:24](https://github.com/evmts/tevm-monorepo/blob/main/packages/blockchain/src/utils/getBlockFromRpc.js#L24)