From d9157174143a8ebc47b41d2e778880824a1a3247 Mon Sep 17 00:00:00 2001 From: Ryan Ghods Date: Mon, 4 Apr 2022 21:02:15 -0700 Subject: [PATCH 01/13] move ethash depBrowserWorkaround fix for bigint-crypto-utils to blockchain karma.conf.js (karma has trouble with the default browser esm import without es6 transform, so it is easier to tell it to use umd) --- packages/blockchain/karma.conf.js | 11 ++++++++--- packages/ethash/package.json | 2 -- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/blockchain/karma.conf.js b/packages/blockchain/karma.conf.js index 56de7f3448..521927c6d8 100644 --- a/packages/blockchain/karma.conf.js +++ b/packages/blockchain/karma.conf.js @@ -1,4 +1,4 @@ -module.exports = function(config) { +module.exports = function (config) { config.set({ browserNoActivityTimeout: 60000, frameworks: ['karma-typescript', 'tap'], @@ -11,8 +11,13 @@ module.exports = function(config) { bundlerOptions: { entrypoints: /\.spec\.ts$/, acornOptions: { - ecmaVersion: 11 - } + ecmaVersion: 11, + }, + resolve: { + alias: { + 'bigint-crypto-utils': '../../node_modules/bigint-crypto-utils/dist/bundles/umd.js', + }, + }, }, }, concurrency: 1, diff --git a/packages/ethash/package.json b/packages/ethash/package.json index fb1d4c9f99..bc7cfca16c 100644 --- a/packages/ethash/package.json +++ b/packages/ethash/package.json @@ -18,8 +18,6 @@ "types": "dist/index.d.ts", "browser": "dist.browser/index.js", "scripts": { - "postinstall": "npm run depBrowserWorkaround", - "depBrowserWorkaround": "npx json -I -f ../../node_modules/bigint-crypto-utils/package.json -e \"this.browser='./dist/bundles/umd.js'\"", "build": "npm run build:node && npm run build:browser", "build:node": "../../config/cli/ts-build.sh node", "build:browser": "../../config/cli/ts-build.sh browser", From 8308fca52618d9204a92c57ddb63735a8ee12e43 Mon Sep 17 00:00:00 2001 From: Ryan Ghods Date: Mon, 4 Apr 2022 21:04:54 -0700 Subject: [PATCH 02/13] new DefaultStateManager will init a trie if not supplied, so we don't need to init one here --- packages/vm/src/index.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/vm/src/index.ts b/packages/vm/src/index.ts index 6df31271ba..e050b658d5 100644 --- a/packages/vm/src/index.ts +++ b/packages/vm/src/index.ts @@ -1,4 +1,3 @@ -import { SecureTrie as Trie } from 'merkle-patricia-tree' import { Account, Address, BigIntLike, toType, TypeOutput } from 'ethereumjs-util' import Blockchain from '@ethereumjs/blockchain' import Common, { Chain, Hardfork } from '@ethereumjs/common' @@ -284,9 +283,7 @@ export default class VM extends AsyncEventEmitter { if (opts.stateManager) { this.stateManager = opts.stateManager } else { - const trie = new Trie() this.stateManager = new DefaultStateManager({ - trie, common: this._common, }) } From 587cec86756da23b99694cfff8fb93a4fec90fab Mon Sep 17 00:00:00 2001 From: Ryan Ghods Date: Mon, 4 Apr 2022 21:05:40 -0700 Subject: [PATCH 03/13] remove backwards compatibility note (we will keep this property) --- packages/vm/src/evm/interpreter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vm/src/evm/interpreter.ts b/packages/vm/src/evm/interpreter.ts index 752fd89b11..5f93648625 100644 --- a/packages/vm/src/evm/interpreter.ts +++ b/packages/vm/src/evm/interpreter.ts @@ -243,7 +243,7 @@ export default class Interpreter { address: this._eei._env.address, account: this._eei._env.contract, stateManager: this._runState.stateManager, - memory: this._runState.memory._store, // Return underlying array for backwards-compatibility + memory: this._runState.memory._store, memoryWordCount: this._runState.memoryWordCount, codeAddress: this._eei._env.codeAddress, } From 33fa7f6573be554e848b7b6f1fed644d0d7222fb Mon Sep 17 00:00:00 2001 From: Ryan Ghods Date: Mon, 4 Apr 2022 21:06:50 -0700 Subject: [PATCH 04/13] trie: remove old backwards compat methods --- packages/trie/src/baseTrie.ts | 25 +++--------------------- packages/trie/src/util/walkController.ts | 4 ++-- 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/packages/trie/src/baseTrie.ts b/packages/trie/src/baseTrie.ts index b3c77b31c5..7441ef1b09 100644 --- a/packages/trie/src/baseTrie.ts +++ b/packages/trie/src/baseTrie.ts @@ -104,7 +104,7 @@ export class Trie { */ async checkRoot(root: Buffer): Promise { try { - const value = await this._lookupNode(root) + const value = await this.lookupNode(root) return value !== null } catch (error: any) { if (error.message == 'Missing node in DB') { @@ -244,7 +244,7 @@ export class Trie { } } - // Resolve if _walkTrie finishes without finding any nodes + // Resolve if walkTrie finishes without finding any nodes resolve({ node: null, remaining: [], stack }) }) } @@ -259,16 +259,6 @@ export class Trie { await WalkController.newWalk(onFound, this, root) } - /** - * @hidden - * Backwards compatibility - * @param root - - * @param onFound - - */ - async _walkTrie(root: Buffer, onFound: FoundNodeFunction): Promise { - await this.walkTrie(root, onFound) - } - /** * Creates the initial node from an empty tree. * @private @@ -298,15 +288,6 @@ export class Trie { return foundNode } - /** - * @hidden - * Backwards compatibility - * @param node The node hash to lookup from the DB - */ - async _lookupNode(node: Buffer | Buffer[]): Promise { - return this.lookupNode(node) - } - /** * Updates a node. * @private @@ -517,7 +498,7 @@ export class Trie { const branchNodeKey = branchNodes[0][0] // look up node - const foundNode = await this._lookupNode(branchNode) + const foundNode = await this.lookupNode(branchNode) if (foundNode) { key = processBranchNode( key, diff --git a/packages/trie/src/util/walkController.ts b/packages/trie/src/util/walkController.ts index f96c01972f..3015eae234 100644 --- a/packages/trie/src/util/walkController.ts +++ b/packages/trie/src/util/walkController.ts @@ -51,7 +51,7 @@ export class WalkController { this.reject = reject let node try { - node = await this.trie._lookupNode(root) + node = await this.trie.lookupNode(root) } catch (error: any) { return this.reject(error) } @@ -98,7 +98,7 @@ export class WalkController { async (taskFinishedCallback: Function) => { let childNode try { - childNode = await this.trie._lookupNode(nodeRef) + childNode = await this.trie.lookupNode(nodeRef) } catch (error: any) { return this.reject(error) } From aa772ce05b32be55f55fe42e59530a8a57d07083 Mon Sep 17 00:00:00 2001 From: Ryan Ghods Date: Fri, 25 Mar 2022 13:32:45 -0700 Subject: [PATCH 05/13] client: do undefined check first --- packages/client/lib/service/fullethereumservice.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/lib/service/fullethereumservice.ts b/packages/client/lib/service/fullethereumservice.ts index 1bae15741a..a57e87d1a2 100644 --- a/packages/client/lib/service/fullethereumservice.ts +++ b/packages/client/lib/service/fullethereumservice.ts @@ -189,8 +189,8 @@ export class FullEthereumService extends EthereumService { let receiptsSize = 0 for (const hash of hashes) { const blockReceipts = await receiptsManager.getReceipts(hash, true, true) - blockReceipts.forEach((r) => (r.gasUsed = bigIntToBuffer(r.gasUsed) as any)) if (!blockReceipts) continue + blockReceipts.forEach((r) => (r.gasUsed = bigIntToBuffer(r.gasUsed) as any)) receipts.push(...blockReceipts) receiptsSize += Buffer.byteLength(JSON.stringify(blockReceipts)) // From spec: The recommended soft limit for Receipts responses is 2 MiB. From 1e39f6f7ade5603b04fdd2b0a6a0278ce72d9d6e Mon Sep 17 00:00:00 2001 From: Ryan Ghods Date: Fri, 25 Mar 2022 13:34:40 -0700 Subject: [PATCH 06/13] vm: undo doc change --- packages/vm/src/evm/evm.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vm/src/evm/evm.ts b/packages/vm/src/evm/evm.ts index 0bb2dbac04..2d718af58f 100644 --- a/packages/vm/src/evm/evm.ts +++ b/packages/vm/src/evm/evm.ts @@ -57,7 +57,7 @@ export interface ExecResult { */ gas?: bigint /** - * Amount of gas the transaction used to run + * Amount of gas the code used to run */ gasUsed: bigint /** From 195ed217bf620d8bd7adaea8326e78a6ff7f225b Mon Sep 17 00:00:00 2001 From: Ryan Ghods Date: Fri, 25 Mar 2022 14:07:06 -0700 Subject: [PATCH 07/13] client: improve receipt size calculation --- .../client/lib/service/fullethereumservice.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/client/lib/service/fullethereumservice.ts b/packages/client/lib/service/fullethereumservice.ts index a57e87d1a2..177136c09d 100644 --- a/packages/client/lib/service/fullethereumservice.ts +++ b/packages/client/lib/service/fullethereumservice.ts @@ -1,5 +1,5 @@ import { Hardfork } from '@ethereumjs/common' -import { bigIntToBuffer } from 'ethereumjs-util' +import { bigIntToBuffer, rlp } from 'ethereumjs-util' import { EthereumService, EthereumServiceOptions } from './ethereumservice' import { FullSynchronizer } from '../sync/fullsync' import { EthProtocol } from '../net/protocol/ethprotocol' @@ -10,6 +10,7 @@ import { Miner } from '../miner' import { VMExecution } from '../execution' import { Event } from '../types' import type { Block } from '@ethereumjs/block' +import type { PostByzantiumTxReceipt, PreByzantiumTxReceipt } from '@ethereumjs/vm/dist/types' interface FullEthereumServiceOptions extends EthereumServiceOptions { /* Serve LES requests (default: false) */ @@ -190,9 +191,18 @@ export class FullEthereumService extends EthereumService { for (const hash of hashes) { const blockReceipts = await receiptsManager.getReceipts(hash, true, true) if (!blockReceipts) continue - blockReceipts.forEach((r) => (r.gasUsed = bigIntToBuffer(r.gasUsed) as any)) receipts.push(...blockReceipts) - receiptsSize += Buffer.byteLength(JSON.stringify(blockReceipts)) + const receiptsBuffer = Buffer.concat( + receipts.map((r) => + rlp.encode([ + (r as PreByzantiumTxReceipt).stateRoot ?? (r as PostByzantiumTxReceipt).status, + bigIntToBuffer(r.gasUsed), + r.bitvector, + r.logs, + ]) + ) + ) + receiptsSize += Buffer.byteLength(receiptsBuffer) // From spec: The recommended soft limit for Receipts responses is 2 MiB. if (receiptsSize >= 2097152) { break From 89acc198493c8b89e6fc988000302106a73e85c0 Mon Sep 17 00:00:00 2001 From: Ryan Ghods Date: Fri, 25 Mar 2022 18:28:29 -0700 Subject: [PATCH 08/13] vm: resolve more todos --- packages/vm/src/evm/opcodes/gas.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/vm/src/evm/opcodes/gas.ts b/packages/vm/src/evm/opcodes/gas.ts index c9479cf5b7..5391566d46 100644 --- a/packages/vm/src/evm/opcodes/gas.ts +++ b/packages/vm/src/evm/opcodes/gas.ts @@ -201,7 +201,6 @@ export const dynamicGasHandlers: Map Date: Fri, 25 Mar 2022 20:57:02 -0700 Subject: [PATCH 09/13] vm: more hardfork enum usage --- packages/vm/src/evm/opcodes/codes.ts | 16 ++++++++-------- packages/vm/src/evm/opcodes/gas.ts | 12 ++++++------ packages/vm/src/evm/opcodes/util.ts | 5 ++--- packages/vm/src/evm/precompiles/index.ts | 20 ++++++++++---------- packages/vm/src/runTx.ts | 4 ++-- packages/vm/src/state/baseStateManager.ts | 2 +- 6 files changed, 29 insertions(+), 30 deletions(-) diff --git a/packages/vm/src/evm/opcodes/codes.ts b/packages/vm/src/evm/opcodes/codes.ts index 4841fa9527..05ff2b6e93 100644 --- a/packages/vm/src/evm/opcodes/codes.ts +++ b/packages/vm/src/evm/opcodes/codes.ts @@ -1,4 +1,4 @@ -import Common from '@ethereumjs/common' +import Common, { Hardfork } from '@ethereumjs/common' import { CustomOpcode } from '../types' import { getFullname } from './util' import { AsyncDynamicGasHandler, dynamicGasHandlers, SyncDynamicGasHandler } from './gas' @@ -203,15 +203,15 @@ const opcodes: OpcodeEntry = { // If the base gas cost of any of the operations change, then these should also be added to this list. // If there are context variables changed (such as "warm slot reads") which are not the base gas fees, // Then this does not have to be added. -const hardforkOpcodes: { hardforkName: string; opcodes: OpcodeEntry }[] = [ +const hardforkOpcodes: { hardfork: Hardfork; opcodes: OpcodeEntry }[] = [ { - hardforkName: 'homestead', + hardfork: Hardfork.Homestead, opcodes: { 0xf4: { name: 'DELEGATECALL', isAsync: true, dynamicGas: true }, // EIP 7 }, }, { - hardforkName: 'tangerineWhistle', + hardfork: Hardfork.TangerineWhistle, opcodes: { 0x54: { name: 'SLOAD', isAsync: true, dynamicGas: true }, 0xf1: { name: 'CALL', isAsync: true, dynamicGas: true }, @@ -224,7 +224,7 @@ const hardforkOpcodes: { hardforkName: string; opcodes: OpcodeEntry }[] = [ }, }, { - hardforkName: 'byzantium', + hardfork: Hardfork.Byzantium, opcodes: { 0xfd: { name: 'REVERT', isAsync: false, dynamicGas: true }, // EIP 140 0xfa: { name: 'STATICCALL', isAsync: true, dynamicGas: true }, // EIP 214 @@ -233,7 +233,7 @@ const hardforkOpcodes: { hardforkName: string; opcodes: OpcodeEntry }[] = [ }, }, { - hardforkName: 'constantinople', + hardfork: Hardfork.Constantinople, opcodes: { 0x1b: { name: 'SHL', isAsync: false, dynamicGas: false }, // EIP 145 0x1c: { name: 'SHR', isAsync: false, dynamicGas: false }, // EIP 145 @@ -243,7 +243,7 @@ const hardforkOpcodes: { hardforkName: string; opcodes: OpcodeEntry }[] = [ }, }, { - hardforkName: 'istanbul', + hardfork: Hardfork.Istanbul, opcodes: { 0x46: { name: 'CHAINID', isAsync: false, dynamicGas: false }, // EIP 1344 0x47: { name: 'SELFBALANCE', isAsync: false, dynamicGas: false }, // EIP 1884 @@ -323,7 +323,7 @@ export function getOpcodesForHF(common: Common, customOpcodes?: CustomOpcode[]): const dynamicGasHandlersCopy = new Map(dynamicGasHandlers) for (let fork = 0; fork < hardforkOpcodes.length; fork++) { - if (common.gteHardfork(hardforkOpcodes[fork].hardforkName)) { + if (common.gteHardfork(hardforkOpcodes[fork].hardfork)) { opcodeBuilder = { ...opcodeBuilder, ...hardforkOpcodes[fork].opcodes } } } diff --git a/packages/vm/src/evm/opcodes/gas.ts b/packages/vm/src/evm/opcodes/gas.ts index 5391566d46..ed5fbb53f0 100644 --- a/packages/vm/src/evm/opcodes/gas.ts +++ b/packages/vm/src/evm/opcodes/gas.ts @@ -10,7 +10,7 @@ import { import { Address, bigIntToBuffer, setLengthLeft } from 'ethereumjs-util' import { ERROR } from '../../exceptions' import { RunState } from '../interpreter' -import Common from '@ethereumjs/common' +import Common, { Hardfork } from '@ethereumjs/common' import { updateSstoreGasEIP1283 } from './EIP1283' import { updateSstoreGasEIP2200 } from './EIP2200' import { accessAddressEIP2929, accessStorageEIP2929 } from './EIP2929' @@ -203,7 +203,7 @@ export const dynamicGasHandlers: Map BigInt(0)) { @@ -553,7 +553,7 @@ export const dynamicGasHandlers: Map gasAllowed ? gasAllowed : gasLimit } else { diff --git a/packages/vm/src/evm/precompiles/index.ts b/packages/vm/src/evm/precompiles/index.ts index 434dcf2d7f..baa63546af 100644 --- a/packages/vm/src/evm/precompiles/index.ts +++ b/packages/vm/src/evm/precompiles/index.ts @@ -1,5 +1,5 @@ import { Address } from 'ethereumjs-util' -import Common from '@ethereumjs/common' +import Common, { Hardfork } from '@ethereumjs/common' import { PrecompileInput, PrecompileFunc } from './types' import { default as p1 } from './01-ecrecover' import { default as p2 } from './02-sha256' @@ -72,39 +72,39 @@ const precompiles: Precompiles = { const precompileAvailability: PrecompileAvailability = { '0000000000000000000000000000000000000001': { type: PrecompileAvailabilityCheck.Hardfork, - param: 'chainstart', + param: Hardfork.Chainstart, }, '0000000000000000000000000000000000000002': { type: PrecompileAvailabilityCheck.Hardfork, - param: 'chainstart', + param: Hardfork.Chainstart, }, [ripemdPrecompileAddress]: { type: PrecompileAvailabilityCheck.Hardfork, - param: 'chainstart', + param: Hardfork.Chainstart, }, '0000000000000000000000000000000000000004': { type: PrecompileAvailabilityCheck.Hardfork, - param: 'chainstart', + param: Hardfork.Chainstart, }, '0000000000000000000000000000000000000005': { type: PrecompileAvailabilityCheck.Hardfork, - param: 'byzantium', + param: Hardfork.Byzantium, }, '0000000000000000000000000000000000000006': { type: PrecompileAvailabilityCheck.Hardfork, - param: 'byzantium', + param: Hardfork.Byzantium, }, '0000000000000000000000000000000000000007': { type: PrecompileAvailabilityCheck.Hardfork, - param: 'byzantium', + param: Hardfork.Byzantium, }, '0000000000000000000000000000000000000008': { type: PrecompileAvailabilityCheck.Hardfork, - param: 'byzantium', + param: Hardfork.Byzantium, }, '0000000000000000000000000000000000000009': { type: PrecompileAvailabilityCheck.Hardfork, - param: 'istanbul', + param: Hardfork.Istanbul, }, '000000000000000000000000000000000000000a': { type: PrecompileAvailabilityCheck.EIP, diff --git a/packages/vm/src/runTx.ts b/packages/vm/src/runTx.ts index 7e868a1550..9cbc3751a8 100644 --- a/packages/vm/src/runTx.ts +++ b/packages/vm/src/runTx.ts @@ -1,7 +1,7 @@ import { debug as createDebugLogger } from 'debug' import { Address, KECCAK256_NULL, toBuffer } from 'ethereumjs-util' import { Block } from '@ethereumjs/block' -import { ConsensusType } from '@ethereumjs/common' +import { ConsensusType, Hardfork } from '@ethereumjs/common' import { AccessList, AccessListItem, @@ -580,7 +580,7 @@ export async function generateTxReceipt( if (!tx.supports(Capability.EIP2718TypedTransaction)) { // Legacy transaction - if (this._common.gteHardfork('byzantium')) { + if (this._common.gteHardfork(Hardfork.Byzantium)) { // Post-Byzantium receipt = { status: txResult.execResult.exceptionError ? 0 : 1, // Receipts have a 0 as status on error diff --git a/packages/vm/src/state/baseStateManager.ts b/packages/vm/src/state/baseStateManager.ts index 7d483bebe7..27cf1578c4 100644 --- a/packages/vm/src/state/baseStateManager.ts +++ b/packages/vm/src/state/baseStateManager.ts @@ -370,7 +370,7 @@ export abstract class BaseStateManager { * as defined in EIP-161 (https://eips.ethereum.org/EIPS/eip-161). */ async cleanupTouchedAccounts(): Promise { - if (this._common.gteHardfork('spuriousDragon')) { + if (this._common.gteHardfork(Hardfork.SpuriousDragon)) { const touchedArray = Array.from(this._touched) for (const addressHex of touchedArray) { const address = new Address(Buffer.from(addressHex, 'hex')) From 2168ca89b15718b3f09250e3ff6219b3ec90be62 Mon Sep 17 00:00:00 2001 From: Ryan Ghods Date: Sat, 26 Mar 2022 09:10:10 -0700 Subject: [PATCH 10/13] dedupe receipt rlp encoding --- packages/client/lib/net/protocol/ethprotocol.ts | 16 +++------------- .../client/lib/service/fullethereumservice.ts | 14 ++------------ packages/vm/src/buildBlock.ts | 2 +- packages/vm/src/runBlock.ts | 11 ++++++----- 4 files changed, 12 insertions(+), 31 deletions(-) diff --git a/packages/client/lib/net/protocol/ethprotocol.ts b/packages/client/lib/net/protocol/ethprotocol.ts index acc3ef572d..a970ec8de0 100644 --- a/packages/client/lib/net/protocol/ethprotocol.ts +++ b/packages/client/lib/net/protocol/ethprotocol.ts @@ -6,7 +6,8 @@ import { BlockBodyBuffer, } from '@ethereumjs/block' import { TransactionFactory, TypedTransaction } from '@ethereumjs/tx' -import { bigIntToBuffer, bufferToBigInt, bufferToInt, intToBuffer, rlp } from 'ethereumjs-util' +import { encodeReceipt } from '@ethereumjs/vm/dist/runBlock' +import { bigIntToBuffer, bufferToBigInt, bufferToInt, rlp } from 'ethereumjs-util' import { Chain } from './../../blockchain' import { Message, Protocol, ProtocolOptions } from './protocol' import type { TxReceiptWithType } from '../../execution/receipt' @@ -230,18 +231,7 @@ export class EthProtocol extends Protocol { encode: ({ reqId, receipts }: { reqId: bigint; receipts: TxReceiptWithType[] }) => { const serializedReceipts = [] for (const receipt of receipts) { - let encodedReceipt = rlp.encode([ - (receipt as PreByzantiumTxReceipt).stateRoot ?? - (receipt as PostByzantiumTxReceipt).status, - bigIntToBuffer(receipt.gasUsed), - receipt.bitvector, - receipt.logs, - ]) - if (receipt.txType > 0) { - // Serialize receipt according to EIP-2718: - // `typed-receipt = tx-type || receipt-data` - encodedReceipt = Buffer.concat([intToBuffer(receipt.txType), encodedReceipt]) - } + const encodedReceipt = encodeReceipt(receipt, receipt.txType) serializedReceipts.push(encodedReceipt) } return [bigIntToBuffer(reqId), serializedReceipts] diff --git a/packages/client/lib/service/fullethereumservice.ts b/packages/client/lib/service/fullethereumservice.ts index 177136c09d..5279bd176b 100644 --- a/packages/client/lib/service/fullethereumservice.ts +++ b/packages/client/lib/service/fullethereumservice.ts @@ -1,5 +1,5 @@ import { Hardfork } from '@ethereumjs/common' -import { bigIntToBuffer, rlp } from 'ethereumjs-util' +import { encodeReceipt } from '@ethereumjs/vm/dist/runBlock' import { EthereumService, EthereumServiceOptions } from './ethereumservice' import { FullSynchronizer } from '../sync/fullsync' import { EthProtocol } from '../net/protocol/ethprotocol' @@ -10,7 +10,6 @@ import { Miner } from '../miner' import { VMExecution } from '../execution' import { Event } from '../types' import type { Block } from '@ethereumjs/block' -import type { PostByzantiumTxReceipt, PreByzantiumTxReceipt } from '@ethereumjs/vm/dist/types' interface FullEthereumServiceOptions extends EthereumServiceOptions { /* Serve LES requests (default: false) */ @@ -192,16 +191,7 @@ export class FullEthereumService extends EthereumService { const blockReceipts = await receiptsManager.getReceipts(hash, true, true) if (!blockReceipts) continue receipts.push(...blockReceipts) - const receiptsBuffer = Buffer.concat( - receipts.map((r) => - rlp.encode([ - (r as PreByzantiumTxReceipt).stateRoot ?? (r as PostByzantiumTxReceipt).status, - bigIntToBuffer(r.gasUsed), - r.bitvector, - r.logs, - ]) - ) - ) + const receiptsBuffer = Buffer.concat(receipts.map((r) => encodeReceipt(r, r.txType))) receiptsSize += Buffer.byteLength(receiptsBuffer) // From spec: The recommended soft limit for Receipts responses is 2 MiB. if (receiptsSize >= 2097152) { diff --git a/packages/vm/src/buildBlock.ts b/packages/vm/src/buildBlock.ts index fd2ee1d0a7..ec13a15c43 100644 --- a/packages/vm/src/buildBlock.ts +++ b/packages/vm/src/buildBlock.ts @@ -135,7 +135,7 @@ export class BlockBuilder { const receiptTrie = new Trie() for (const [i, txResult] of this.transactionResults.entries()) { const tx = this.transactions[i] - const encodedReceipt = encodeReceipt(tx, txResult.receipt) + const encodedReceipt = encodeReceipt(txResult.receipt, tx.type) await receiptTrie.put(rlp.encode(i), encodedReceipt) } return receiptTrie.root diff --git a/packages/vm/src/runBlock.ts b/packages/vm/src/runBlock.ts index 576b84dfb4..9ffa0a9e75 100644 --- a/packages/vm/src/runBlock.ts +++ b/packages/vm/src/runBlock.ts @@ -359,7 +359,7 @@ async function applyTransactions(this: VM, block: Block, opts: RunBlockOpts) { // Add receipt to trie to later calculate receipt root receipts.push(txRes.receipt) - const encodedReceipt = encodeReceipt(tx, txRes.receipt) + const encodedReceipt = encodeReceipt(txRes.receipt, tx.type) await receiptTrie.put(rlp.encode(txIdx), encodedReceipt) } @@ -434,7 +434,7 @@ export async function rewardAccount( /** * Returns the encoded tx receipt. */ -export function encodeReceipt(tx: TypedTransaction, receipt: TxReceipt) { +export function encodeReceipt(receipt: TxReceipt, txType: number) { const encoded = rlp.encode([ (receipt as PreByzantiumTxReceipt).stateRoot ?? (receipt as PostByzantiumTxReceipt).status, receipt.gasUsed, @@ -442,12 +442,13 @@ export function encodeReceipt(tx: TypedTransaction, receipt: TxReceipt) { receipt.logs, ]) - if (!tx.supports(Capability.EIP2718TypedTransaction)) { + if (txType === 0) { return encoded } - const type = intToBuffer(tx.type) - return Buffer.concat([type, encoded]) + // Serialize receipt according to EIP-2718: + // `typed-receipt = tx-type || receipt-data` + return Buffer.concat([intToBuffer(txType), encoded]) } /** From 359fc7bdd2cc9b728f90a76587047213fa3b0603 Mon Sep 17 00:00:00 2001 From: Ryan Ghods Date: Mon, 28 Mar 2022 12:59:51 -0700 Subject: [PATCH 11/13] lint --- packages/vm/src/runBlock.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/vm/src/runBlock.ts b/packages/vm/src/runBlock.ts index 9ffa0a9e75..8e8631dcde 100644 --- a/packages/vm/src/runBlock.ts +++ b/packages/vm/src/runBlock.ts @@ -7,7 +7,6 @@ import VM from './index' import Bloom from './bloom' import { StateManager } from './state' import { short } from './evm/opcodes' -import { Capability, TypedTransaction } from '@ethereumjs/tx' import type { RunTxResult } from './runTx' import type { TxReceipt, PreByzantiumTxReceipt, PostByzantiumTxReceipt } from './types' import DAOConfig from './config/dao_fork_accounts_config.json' From 65b6c2112d1fe255e70425db23f87a6736e8e8b5 Mon Sep 17 00:00:00 2001 From: Ryan Ghods Date: Wed, 30 Mar 2022 13:45:37 -0700 Subject: [PATCH 12/13] runCall, runCode: add more param typedocs, simplify --- packages/vm/src/runCall.ts | 52 ++++++++++++++++++++++++++++++---- packages/vm/src/runCode.ts | 57 +++++++++++++++++++++++--------------- 2 files changed, 81 insertions(+), 28 deletions(-) diff --git a/packages/vm/src/runCall.ts b/packages/vm/src/runCall.ts index 1b95546db3..f59a87f801 100644 --- a/packages/vm/src/runCall.ts +++ b/packages/vm/src/runCall.ts @@ -9,23 +9,65 @@ import { default as EVM, EVMResult } from './evm/evm' * Options for running a call (or create) operation */ export interface RunCallOpts { + /** + * The `@ethereumjs/block` the `tx` belongs to. If omitted a default blank block will be used. + */ block?: Block + /** + * The gas price for the call. Defaults to `0` + */ gasPrice?: bigint + /** + * The address where the call originated from. Defaults to the zero address. + */ origin?: Address + /** + * The address that ran this code (`msg.sender`). Defaults to the zero address. + */ caller?: Address + /** + * The gas limit for the call. Defaults to `0xffffff` + */ gasLimit?: bigint + /** + * The to address. Defaults to the zero address. + */ to?: Address + /** + * The value in ether that is being sent to `opts.to`. Defaults to `0` + */ value?: bigint + /** + * The data for the call. + */ data?: Buffer /** * This is for CALLCODE where the code to load is different than the code from the `opts.to` address. */ code?: Buffer + /** + * The call depth. Defaults to `0` + */ depth?: number - compiled?: boolean - static?: boolean + /** + * If the code location is a precompile. + */ + isCompiled?: boolean + /** + * If the call should be executed statically. Defaults to false. + */ + isStatic?: boolean + /** + * An optional salt to pass to CREATE2. + */ salt?: Buffer + /** + * Addresses to selfdestruct. Defaults to none. + */ selfdestruct?: { [k: string]: boolean } + /** + * If the call is a DELEGATECALL. Defaults to false. + */ delegatecall?: boolean } @@ -42,14 +84,14 @@ export default function runCall(this: VM, opts: RunCallOpts): Promise const message = new Message({ caller: opts.caller, - gasLimit: opts.gasLimit ?? 0xffffffn, + gasLimit: opts.gasLimit ?? BigInt(0xffffff), to: opts.to ?? undefined, value: opts.value, data: opts.data, code: opts.code, depth: opts.depth ?? 0, - isCompiled: opts.compiled ?? false, - isStatic: opts.static ?? false, + isCompiled: opts.isCompiled ?? false, + isStatic: opts.isStatic ?? false, salt: opts.salt ?? null, selfdestruct: opts.selfdestruct ?? {}, delegatecall: opts.delegatecall ?? false, diff --git a/packages/vm/src/runCode.ts b/packages/vm/src/runCode.ts index 27e9af4ebf..1325137550 100644 --- a/packages/vm/src/runCode.ts +++ b/packages/vm/src/runCode.ts @@ -26,36 +26,49 @@ export interface RunCodeOpts { * The `@ethereumjs/block` the `tx` belongs to. If omitted a default blank block will be used. */ block?: Block + /** + * Pass a custom {@link EVM} to use. If omitted the default {@link EVM} will be used. + */ evm?: EVM - txContext?: TxContext + /** + * The gas price for the call. Defaults to `0` + */ gasPrice?: bigint /** * The address where the call originated from. Defaults to the zero address. */ origin?: Address - message?: Message /** * The address that ran this code (`msg.sender`). Defaults to the zero address. */ caller?: Address /** - * The EVM code to run + * The EVM code to run. */ code?: Buffer /** - * The input data + * The input data. */ data?: Buffer /** - * Gas limit + * The gas limit for the call. */ gasLimit: bigint /** - * The value in ether that is being sent to `opt.address`. Defaults to `0` + * The value in ether that is being sent to `opts.address`. Defaults to `0` */ value?: bigint + /** + * The call depth. Defaults to `0` + */ depth?: number + /** + * If the call should be executed statically. Defaults to false. + */ isStatic?: boolean + /** + * Addresses to selfdestruct. Defaults to none. + */ selfdestruct?: { [k: string]: boolean } /** * The address of the account that is executing this code (`address(this)`). Defaults to the zero address. @@ -73,24 +86,22 @@ export interface RunCodeOpts { export default function runCode(this: VM, opts: RunCodeOpts): Promise { const block = opts.block ?? Block.fromBlockData({}, { common: this._common }) - // Backwards compatibility - const txContext = - opts.txContext ?? - new TxContext(opts.gasPrice ?? BigInt(0), opts.origin ?? opts.caller ?? Address.zero()) + const txContext = new TxContext( + opts.gasPrice ?? BigInt(0), + opts.origin ?? opts.caller ?? Address.zero() + ) - const message = - opts.message ?? - new Message({ - code: opts.code, - data: opts.data, - gasLimit: opts.gasLimit, - to: opts.address ?? Address.zero(), - caller: opts.caller, - value: opts.value, - depth: opts.depth ?? 0, - selfdestruct: opts.selfdestruct ?? {}, - isStatic: opts.isStatic ?? false, - }) + const message = new Message({ + code: opts.code, + data: opts.data, + gasLimit: opts.gasLimit, + to: opts.address ?? Address.zero(), + caller: opts.caller, + value: opts.value, + depth: opts.depth ?? 0, + selfdestruct: opts.selfdestruct ?? {}, + isStatic: opts.isStatic ?? false, + }) const evm = opts.evm ?? new EVM(this, txContext, block) From 5e9da55e127efca807f95ef1ca5791ab66bdc2e3 Mon Sep 17 00:00:00 2001 From: Ryan Ghods Date: Mon, 4 Apr 2022 23:23:10 -0700 Subject: [PATCH 13/13] also add karma workaround to vm --- packages/vm/karma.conf.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/vm/karma.conf.js b/packages/vm/karma.conf.js index 284832aded..76ea1cdaa9 100644 --- a/packages/vm/karma.conf.js +++ b/packages/vm/karma.conf.js @@ -24,8 +24,13 @@ module.exports = function (config) { bundlerOptions: { entrypoints: /\.spec\.ts$/, acornOptions: { - ecmaVersion: 11 - } + ecmaVersion: 11, + }, + resolve: { + alias: { + 'bigint-crypto-utils': '../../node_modules/bigint-crypto-utils/dist/bundles/umd.js', + }, + }, }, },