hardhat 2.20.0 → 2.21.0-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/internal/core/jsonrpc/types/input/blockTag.d.ts +3 -3
- package/internal/core/jsonrpc/types/input/filterRequest.d.ts +6 -6
- package/internal/core/providers/construction.d.ts.map +1 -1
- package/internal/core/providers/construction.js +28 -4
- package/internal/core/providers/construction.js.map +1 -1
- package/internal/core/providers/http.d.ts +2 -0
- package/internal/core/providers/http.d.ts.map +1 -1
- package/internal/core/providers/http.js +2 -1
- package/internal/core/providers/http.js.map +1 -1
- package/internal/core/runtime-environment.d.ts.map +1 -1
- package/internal/core/runtime-environment.js.map +1 -1
- package/internal/hardhat-network/jsonrpc/client.d.ts +0 -2
- package/internal/hardhat-network/jsonrpc/client.d.ts.map +1 -1
- package/internal/hardhat-network/jsonrpc/client.js +0 -16
- package/internal/hardhat-network/jsonrpc/client.js.map +1 -1
- package/internal/hardhat-network/jsonrpc/handler.js +9 -1
- package/internal/hardhat-network/jsonrpc/handler.js.map +1 -1
- package/internal/hardhat-network/provider/BlockchainData.d.ts +5 -5
- package/internal/hardhat-network/provider/BlockchainData.d.ts.map +1 -1
- package/internal/hardhat-network/provider/BlockchainData.js +10 -10
- package/internal/hardhat-network/provider/BlockchainData.js.map +1 -1
- package/internal/hardhat-network/provider/HardhatBlockchain.d.ts +0 -7
- package/internal/hardhat-network/provider/HardhatBlockchain.d.ts.map +1 -1
- package/internal/hardhat-network/provider/HardhatBlockchain.js +2 -14
- package/internal/hardhat-network/provider/HardhatBlockchain.js.map +1 -1
- package/internal/hardhat-network/provider/TxPool.d.ts +3 -2
- package/internal/hardhat-network/provider/TxPool.d.ts.map +1 -1
- package/internal/hardhat-network/provider/TxPool.js +16 -16
- package/internal/hardhat-network/provider/TxPool.js.map +1 -1
- package/internal/hardhat-network/provider/ethereumjs-workarounds.js +1 -1
- package/internal/hardhat-network/provider/ethereumjs-workarounds.js.map +1 -1
- package/internal/hardhat-network/provider/filter.d.ts +6 -5
- package/internal/hardhat-network/provider/filter.d.ts.map +1 -1
- package/internal/hardhat-network/provider/filter.js +2 -2
- package/internal/hardhat-network/provider/filter.js.map +1 -1
- package/internal/hardhat-network/provider/fork/ForkBlockchain.d.ts +0 -7
- package/internal/hardhat-network/provider/fork/ForkBlockchain.d.ts.map +1 -1
- package/internal/hardhat-network/provider/fork/ForkBlockchain.js +4 -21
- package/internal/hardhat-network/provider/fork/ForkBlockchain.js.map +1 -1
- package/internal/hardhat-network/provider/fork/ForkStateManager.d.ts +13 -19
- package/internal/hardhat-network/provider/fork/ForkStateManager.d.ts.map +1 -1
- package/internal/hardhat-network/provider/fork/ForkStateManager.js +61 -59
- package/internal/hardhat-network/provider/fork/ForkStateManager.js.map +1 -1
- package/internal/hardhat-network/provider/fork/rpcToBlockData.d.ts.map +1 -1
- package/internal/hardhat-network/provider/fork/rpcToBlockData.js +0 -3
- package/internal/hardhat-network/provider/fork/rpcToBlockData.js.map +1 -1
- package/internal/hardhat-network/provider/fork/rpcToTxData.d.ts +2 -2
- package/internal/hardhat-network/provider/fork/rpcToTxData.d.ts.map +1 -1
- package/internal/hardhat-network/provider/fork/rpcToTxData.js +1 -1
- package/internal/hardhat-network/provider/fork/rpcToTxData.js.map +1 -1
- package/internal/hardhat-network/provider/modules/base.js +4 -4
- package/internal/hardhat-network/provider/modules/base.js.map +1 -1
- package/internal/hardhat-network/provider/modules/eth.d.ts.map +1 -1
- package/internal/hardhat-network/provider/modules/eth.js +9 -16
- package/internal/hardhat-network/provider/modules/eth.js.map +1 -1
- package/internal/hardhat-network/provider/modules/logger.d.ts +6 -84
- package/internal/hardhat-network/provider/modules/logger.d.ts.map +1 -1
- package/internal/hardhat-network/provider/modules/logger.js +3 -530
- package/internal/hardhat-network/provider/modules/logger.js.map +1 -1
- package/internal/hardhat-network/provider/node-types.d.ts +2 -65
- package/internal/hardhat-network/provider/node-types.d.ts.map +1 -1
- package/internal/hardhat-network/provider/node-types.js +0 -5
- package/internal/hardhat-network/provider/node-types.js.map +1 -1
- package/internal/hardhat-network/provider/node.d.ts +2 -6
- package/internal/hardhat-network/provider/node.d.ts.map +1 -1
- package/internal/hardhat-network/provider/node.js +79 -148
- package/internal/hardhat-network/provider/node.js.map +1 -1
- package/internal/hardhat-network/provider/output.d.ts +0 -14
- package/internal/hardhat-network/provider/output.d.ts.map +1 -1
- package/internal/hardhat-network/provider/output.js +0 -264
- package/internal/hardhat-network/provider/output.js.map +1 -1
- package/internal/hardhat-network/provider/provider.d.ts +26 -25
- package/internal/hardhat-network/provider/provider.d.ts.map +1 -1
- package/internal/hardhat-network/provider/provider.js +342 -186
- package/internal/hardhat-network/provider/provider.js.map +1 -1
- package/internal/hardhat-network/provider/transactions/FakeSenderAccessListEIP2930Transaction.d.ts +10 -8
- package/internal/hardhat-network/provider/transactions/FakeSenderAccessListEIP2930Transaction.d.ts.map +1 -1
- package/internal/hardhat-network/provider/transactions/FakeSenderAccessListEIP2930Transaction.js +9 -9
- package/internal/hardhat-network/provider/transactions/FakeSenderAccessListEIP2930Transaction.js.map +1 -1
- package/internal/hardhat-network/provider/transactions/FakeSenderEIP1559Transaction.d.ts +10 -8
- package/internal/hardhat-network/provider/transactions/FakeSenderEIP1559Transaction.d.ts.map +1 -1
- package/internal/hardhat-network/provider/transactions/FakeSenderEIP1559Transaction.js +9 -9
- package/internal/hardhat-network/provider/transactions/FakeSenderEIP1559Transaction.js.map +1 -1
- package/internal/hardhat-network/provider/transactions/FakeSenderTransaction.d.ts +10 -9
- package/internal/hardhat-network/provider/transactions/FakeSenderTransaction.d.ts.map +1 -1
- package/internal/hardhat-network/provider/transactions/FakeSenderTransaction.js +7 -6
- package/internal/hardhat-network/provider/transactions/FakeSenderTransaction.js.map +1 -1
- package/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP1559Transaction.d.ts +6 -5
- package/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP1559Transaction.d.ts.map +1 -1
- package/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP1559Transaction.js +1 -1
- package/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP1559Transaction.js.map +1 -1
- package/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP2930Transaction.d.ts +5 -4
- package/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP2930Transaction.d.ts.map +1 -1
- package/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP2930Transaction.js +1 -1
- package/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP2930Transaction.js.map +1 -1
- package/internal/hardhat-network/provider/transactions/ReadOnlyValidTransaction.d.ts +8 -7
- package/internal/hardhat-network/provider/transactions/ReadOnlyValidTransaction.d.ts.map +1 -1
- package/internal/hardhat-network/provider/transactions/ReadOnlyValidTransaction.js +2 -2
- package/internal/hardhat-network/provider/transactions/ReadOnlyValidTransaction.js.map +1 -1
- package/internal/hardhat-network/provider/transactions/ReadOnlyValidUnknownTypeTransaction.d.ts +8 -7
- package/internal/hardhat-network/provider/transactions/ReadOnlyValidUnknownTypeTransaction.d.ts.map +1 -1
- package/internal/hardhat-network/provider/transactions/ReadOnlyValidUnknownTypeTransaction.js +2 -2
- package/internal/hardhat-network/provider/transactions/ReadOnlyValidUnknownTypeTransaction.js.map +1 -1
- package/internal/hardhat-network/provider/types/HardhatBlockchainInterface.d.ts +5 -4
- package/internal/hardhat-network/provider/types/HardhatBlockchainInterface.d.ts.map +1 -1
- package/internal/hardhat-network/provider/utils/convertToEdr.d.ts +14 -0
- package/internal/hardhat-network/provider/utils/convertToEdr.d.ts.map +1 -0
- package/internal/hardhat-network/provider/utils/convertToEdr.js +191 -0
- package/internal/hardhat-network/provider/utils/convertToEdr.js.map +1 -0
- package/internal/hardhat-network/provider/utils/getCurrentTimestamp.d.ts +0 -1
- package/internal/hardhat-network/provider/utils/getCurrentTimestamp.d.ts.map +1 -1
- package/internal/hardhat-network/provider/utils/getCurrentTimestamp.js +1 -5
- package/internal/hardhat-network/provider/utils/getCurrentTimestamp.js.map +1 -1
- package/internal/hardhat-network/provider/utils/makeCommon.d.ts +1 -1
- package/internal/hardhat-network/provider/utils/makeCommon.d.ts.map +1 -1
- package/internal/hardhat-network/provider/utils/makeCommon.js +1 -3
- package/internal/hardhat-network/provider/utils/makeCommon.js.map +1 -1
- package/internal/hardhat-network/provider/utils/makeFakeSignature.d.ts +2 -2
- package/internal/hardhat-network/provider/utils/makeFakeSignature.d.ts.map +1 -1
- package/internal/hardhat-network/provider/utils/makeFakeSignature.js +1 -15
- package/internal/hardhat-network/provider/utils/makeFakeSignature.js.map +1 -1
- package/internal/hardhat-network/provider/utils/makeForkClient.d.ts +10 -1
- package/internal/hardhat-network/provider/utils/makeForkClient.d.ts.map +1 -1
- package/internal/hardhat-network/provider/utils/makeForkClient.js +38 -18
- package/internal/hardhat-network/provider/utils/makeForkClient.js.map +1 -1
- package/internal/hardhat-network/provider/utils/makeStateTrie.js +2 -2
- package/internal/hardhat-network/provider/utils/makeStateTrie.js.map +1 -1
- package/internal/hardhat-network/provider/utils/putGenesisBlock.d.ts +3 -1
- package/internal/hardhat-network/provider/utils/putGenesisBlock.d.ts.map +1 -1
- package/internal/hardhat-network/provider/utils/putGenesisBlock.js +2 -6
- package/internal/hardhat-network/provider/utils/putGenesisBlock.js.map +1 -1
- package/internal/hardhat-network/provider/utils/random.d.ts +1 -0
- package/internal/hardhat-network/provider/utils/random.d.ts.map +1 -1
- package/internal/hardhat-network/provider/utils/random.js +7 -1
- package/internal/hardhat-network/provider/utils/random.js.map +1 -1
- package/internal/hardhat-network/provider/utils/reorgs-protection.d.ts +1 -1
- package/internal/hardhat-network/provider/utils/reorgs-protection.d.ts.map +1 -1
- package/internal/hardhat-network/provider/utils/reorgs-protection.js +5 -5
- package/internal/hardhat-network/provider/utils/reorgs-protection.js.map +1 -1
- package/internal/hardhat-network/provider/vm/exit.d.ts +22 -0
- package/internal/hardhat-network/provider/vm/exit.d.ts.map +1 -0
- package/internal/hardhat-network/provider/vm/exit.js +93 -0
- package/internal/hardhat-network/provider/vm/exit.js.map +1 -0
- package/internal/hardhat-network/provider/vm/minimal-vm.d.ts +29 -0
- package/internal/hardhat-network/provider/vm/minimal-vm.d.ts.map +1 -0
- package/internal/hardhat-network/provider/vm/minimal-vm.js +46 -0
- package/internal/hardhat-network/provider/vm/minimal-vm.js.map +1 -0
- package/internal/hardhat-network/provider/vm/proxy-vm.d.ts +36 -0
- package/internal/hardhat-network/provider/vm/proxy-vm.d.ts.map +1 -0
- package/internal/hardhat-network/provider/vm/proxy-vm.js +73 -0
- package/internal/hardhat-network/provider/vm/proxy-vm.js.map +1 -0
- package/internal/hardhat-network/provider/vm/types.d.ts +27 -0
- package/internal/hardhat-network/provider/vm/types.d.ts.map +1 -0
- package/internal/hardhat-network/provider/vm/types.js +3 -0
- package/internal/hardhat-network/provider/vm/types.js.map +1 -0
- package/internal/hardhat-network/stack-traces/consoleLogger.d.ts +6 -0
- package/internal/hardhat-network/stack-traces/consoleLogger.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/consoleLogger.js +33 -16
- package/internal/hardhat-network/stack-traces/consoleLogger.js.map +1 -1
- package/internal/hardhat-network/stack-traces/contracts-identifier.d.ts +1 -2
- package/internal/hardhat-network/stack-traces/contracts-identifier.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/contracts-identifier.js +6 -7
- package/internal/hardhat-network/stack-traces/contracts-identifier.js.map +1 -1
- package/internal/hardhat-network/stack-traces/debug.js +6 -6
- package/internal/hardhat-network/stack-traces/debug.js.map +1 -1
- package/internal/hardhat-network/stack-traces/error-inferrer.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/error-inferrer.js +13 -7
- package/internal/hardhat-network/stack-traces/error-inferrer.js.map +1 -1
- package/internal/hardhat-network/stack-traces/message-trace.d.ts +8 -3
- package/internal/hardhat-network/stack-traces/message-trace.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/message-trace.js +22 -1
- package/internal/hardhat-network/stack-traces/message-trace.js.map +1 -1
- package/internal/hardhat-network/stack-traces/model.d.ts +8 -0
- package/internal/hardhat-network/stack-traces/model.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/model.js +52 -0
- package/internal/hardhat-network/stack-traces/model.js.map +1 -1
- package/internal/hardhat-network/stack-traces/opcodes.d.ts +1 -0
- package/internal/hardhat-network/stack-traces/opcodes.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/opcodes.js +5 -1
- package/internal/hardhat-network/stack-traces/opcodes.js.map +1 -1
- package/internal/hardhat-network/stack-traces/solidity-errors.js +2 -2
- package/internal/hardhat-network/stack-traces/solidity-errors.js.map +1 -1
- package/internal/hardhat-network/stack-traces/solidityTracer.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/solidityTracer.js +5 -5
- package/internal/hardhat-network/stack-traces/solidityTracer.js.map +1 -1
- package/internal/hardhat-network/stack-traces/vm-debug-tracer.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/vm-debug-tracer.js +28 -34
- package/internal/hardhat-network/stack-traces/vm-debug-tracer.js.map +1 -1
- package/internal/hardhat-network/stack-traces/vm-trace-decoder.d.ts +7 -0
- package/internal/hardhat-network/stack-traces/vm-trace-decoder.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/vm-trace-decoder.js +69 -2
- package/internal/hardhat-network/stack-traces/vm-trace-decoder.js.map +1 -1
- package/internal/hardhat-network/stack-traces/vm-tracer.d.ts +7 -12
- package/internal/hardhat-network/stack-traces/vm-tracer.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/vm-tracer.js +46 -65
- package/internal/hardhat-network/stack-traces/vm-tracer.js.map +1 -1
- package/internal/util/date.d.ts +1 -0
- package/internal/util/date.d.ts.map +1 -1
- package/internal/util/date.js +5 -1
- package/internal/util/date.js.map +1 -1
- package/internal/util/hardforks.d.ts +2 -0
- package/internal/util/hardforks.d.ts.map +1 -1
- package/internal/util/hardforks.js +27 -1
- package/internal/util/hardforks.js.map +1 -1
- package/package.json +18 -16
- package/src/internal/core/providers/construction.ts +7 -9
- package/src/internal/core/providers/http.ts +3 -1
- package/src/internal/core/runtime-environment.ts +2 -1
- package/src/internal/hardhat-network/jsonrpc/client.ts +1 -28
- package/src/internal/hardhat-network/jsonrpc/handler.ts +9 -1
- package/src/internal/hardhat-network/provider/modules/logger.ts +6 -801
- package/src/internal/hardhat-network/provider/node-types.ts +2 -89
- package/src/internal/hardhat-network/provider/output.ts +0 -352
- package/src/internal/hardhat-network/provider/provider.ts +482 -263
- package/src/internal/hardhat-network/provider/utils/convertToEdr.ts +228 -0
- package/src/internal/hardhat-network/provider/utils/getCurrentTimestamp.ts +0 -4
- package/src/internal/hardhat-network/provider/utils/makeCommon.ts +1 -12
- package/src/internal/hardhat-network/provider/utils/makeForkClient.ts +63 -24
- package/src/internal/hardhat-network/provider/utils/random.ts +8 -1
- package/src/internal/hardhat-network/provider/utils/reorgs-protection.ts +5 -5
- package/src/internal/hardhat-network/provider/vm/exit.ts +101 -0
- package/src/internal/hardhat-network/provider/vm/minimal-vm.ts +101 -0
- package/src/internal/hardhat-network/provider/vm/types.ts +31 -0
- package/src/internal/hardhat-network/stack-traces/consoleLogger.ts +40 -21
- package/src/internal/hardhat-network/stack-traces/contracts-identifier.ts +10 -12
- package/src/internal/hardhat-network/stack-traces/debug.ts +6 -6
- package/src/internal/hardhat-network/stack-traces/error-inferrer.ts +15 -8
- package/src/internal/hardhat-network/stack-traces/message-trace.ts +40 -4
- package/src/internal/hardhat-network/stack-traces/model.ts +61 -0
- package/src/internal/hardhat-network/stack-traces/opcodes.ts +4 -0
- package/src/internal/hardhat-network/stack-traces/solidity-errors.ts +2 -2
- package/src/internal/hardhat-network/stack-traces/solidityTracer.ts +6 -5
- package/src/internal/hardhat-network/stack-traces/vm-trace-decoder.ts +113 -4
- package/src/internal/hardhat-network/stack-traces/vm-tracer.ts +67 -95
- package/src/internal/util/date.ts +4 -0
- package/src/internal/util/hardforks.ts +52 -0
- package/src/internal/hardhat-network/provider/BlockchainBase.ts +0 -185
- package/src/internal/hardhat-network/provider/BlockchainData.ts +0 -261
- package/src/internal/hardhat-network/provider/HardhatBlockchain.ts +0 -140
- package/src/internal/hardhat-network/provider/PoolState.ts +0 -48
- package/src/internal/hardhat-network/provider/TransactionQueue.ts +0 -158
- package/src/internal/hardhat-network/provider/TxPool.ts +0 -715
- package/src/internal/hardhat-network/provider/ethereumjs-workarounds.ts +0 -21
- package/src/internal/hardhat-network/provider/filter.ts +0 -142
- package/src/internal/hardhat-network/provider/fork/ForkBlockchain.ts +0 -433
- package/src/internal/hardhat-network/provider/fork/ForkStateManager.ts +0 -480
- package/src/internal/hardhat-network/provider/fork/rpcToBlockData.ts +0 -35
- package/src/internal/hardhat-network/provider/fork/rpcToTxData.ts +0 -44
- package/src/internal/hardhat-network/provider/modules/base.ts +0 -156
- package/src/internal/hardhat-network/provider/modules/debug.ts +0 -104
- package/src/internal/hardhat-network/provider/modules/eth.ts +0 -1781
- package/src/internal/hardhat-network/provider/modules/evm.ts +0 -249
- package/src/internal/hardhat-network/provider/modules/hardhat.ts +0 -481
- package/src/internal/hardhat-network/provider/modules/net.ts +0 -60
- package/src/internal/hardhat-network/provider/modules/personal.ts +0 -40
- package/src/internal/hardhat-network/provider/modules/web3.ts +0 -49
- package/src/internal/hardhat-network/provider/node.ts +0 -2993
- package/src/internal/hardhat-network/provider/transactions/FakeSenderAccessListEIP2930Transaction.ts +0 -226
- package/src/internal/hardhat-network/provider/transactions/FakeSenderEIP1559Transaction.ts +0 -224
- package/src/internal/hardhat-network/provider/transactions/FakeSenderTransaction.ts +0 -216
- package/src/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP1559Transaction.ts +0 -143
- package/src/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP2930Transaction.ts +0 -144
- package/src/internal/hardhat-network/provider/transactions/ReadOnlyValidTransaction.ts +0 -171
- package/src/internal/hardhat-network/provider/transactions/ReadOnlyValidUnknownTypeTransaction.ts +0 -169
- package/src/internal/hardhat-network/provider/types/HardhatBlockchainInterface.ts +0 -25
- package/src/internal/hardhat-network/provider/utils/makeFakeSignature.ts +0 -60
- package/src/internal/hardhat-network/provider/utils/makeStateTrie.ts +0 -29
- package/src/internal/hardhat-network/provider/utils/putGenesisBlock.ts +0 -61
- package/src/internal/hardhat-network/provider/utils/reorganizeTransactionsLists.ts +0 -45
- package/src/internal/hardhat-network/provider/utils/txMapToArray.ts +0 -7
- package/src/internal/hardhat-network/stack-traces/vm-debug-tracer.ts +0 -630
|
@@ -1,2993 +0,0 @@
|
|
|
1
|
-
import { Block, HeaderData } from "@nomicfoundation/ethereumjs-block";
|
|
2
|
-
import {
|
|
3
|
-
Common,
|
|
4
|
-
EVMStateManagerInterface,
|
|
5
|
-
} from "@nomicfoundation/ethereumjs-common";
|
|
6
|
-
import { ERROR } from "@nomicfoundation/ethereumjs-evm/dist/cjs/exceptions";
|
|
7
|
-
import {
|
|
8
|
-
AccessListEIP2930Transaction,
|
|
9
|
-
FeeMarketEIP1559Transaction,
|
|
10
|
-
LegacyTransaction,
|
|
11
|
-
TypedTransaction,
|
|
12
|
-
BlobEIP4844Transaction,
|
|
13
|
-
} from "@nomicfoundation/ethereumjs-tx";
|
|
14
|
-
import {
|
|
15
|
-
Address,
|
|
16
|
-
ECDSASignature,
|
|
17
|
-
bigIntToBytes,
|
|
18
|
-
bytesToHex as bufferToHex,
|
|
19
|
-
ecsign,
|
|
20
|
-
equalsBytes,
|
|
21
|
-
hashPersonalMessage,
|
|
22
|
-
privateToAddress,
|
|
23
|
-
setLengthLeft,
|
|
24
|
-
toBytes,
|
|
25
|
-
bytesToBigInt,
|
|
26
|
-
Account,
|
|
27
|
-
} from "@nomicfoundation/ethereumjs-util";
|
|
28
|
-
import {
|
|
29
|
-
Bloom,
|
|
30
|
-
RunBlockResult,
|
|
31
|
-
RunTxResult,
|
|
32
|
-
VM,
|
|
33
|
-
} from "@nomicfoundation/ethereumjs-vm";
|
|
34
|
-
import { EVM, EVMResult } from "@nomicfoundation/ethereumjs-evm";
|
|
35
|
-
import { DefaultStateManager } from "@nomicfoundation/ethereumjs-statemanager";
|
|
36
|
-
import { SignTypedDataVersion, signTypedData } from "@metamask/eth-sig-util";
|
|
37
|
-
import chalk from "chalk";
|
|
38
|
-
import { randomBytes } from "crypto";
|
|
39
|
-
import debug from "debug";
|
|
40
|
-
import EventEmitter from "events";
|
|
41
|
-
|
|
42
|
-
import * as BigIntUtils from "../../util/bigint";
|
|
43
|
-
import { CompilerInput, CompilerOutput } from "../../../types";
|
|
44
|
-
import { HardforkHistoryConfig } from "../../../types/config";
|
|
45
|
-
import { HARDHAT_NETWORK_SUPPORTED_HARDFORKS } from "../../constants";
|
|
46
|
-
import {
|
|
47
|
-
HARDHAT_NETWORK_DEFAULT_INITIAL_BASE_FEE_PER_GAS,
|
|
48
|
-
HARDHAT_NETWORK_DEFAULT_MAX_PRIORITY_FEE_PER_GAS,
|
|
49
|
-
} from "../../core/config/default-config";
|
|
50
|
-
import { assertHardhatInvariant, HardhatError } from "../../core/errors";
|
|
51
|
-
import { RpcDebugTracingConfig } from "../../core/jsonrpc/types/input/debugTraceTransaction";
|
|
52
|
-
import {
|
|
53
|
-
InternalError,
|
|
54
|
-
InvalidArgumentsError,
|
|
55
|
-
InvalidInputError,
|
|
56
|
-
TransactionExecutionError,
|
|
57
|
-
} from "../../core/providers/errors";
|
|
58
|
-
import { HardhatMetadata } from "../../core/jsonrpc/types/output/metadata";
|
|
59
|
-
import { Reporter } from "../../sentry/reporter";
|
|
60
|
-
import { getDifferenceInSeconds } from "../../util/date";
|
|
61
|
-
import {
|
|
62
|
-
getHardforkName,
|
|
63
|
-
hardforkGte,
|
|
64
|
-
HardforkName,
|
|
65
|
-
} from "../../util/hardforks";
|
|
66
|
-
import { getPackageJson } from "../../util/packageInfo";
|
|
67
|
-
import { createModelsAndDecodeBytecodes } from "../stack-traces/compiler-to-model";
|
|
68
|
-
import { ConsoleLogger } from "../stack-traces/consoleLogger";
|
|
69
|
-
import { ContractsIdentifier } from "../stack-traces/contracts-identifier";
|
|
70
|
-
import {
|
|
71
|
-
isCreateTrace,
|
|
72
|
-
isPrecompileTrace,
|
|
73
|
-
MessageTrace,
|
|
74
|
-
} from "../stack-traces/message-trace";
|
|
75
|
-
import {
|
|
76
|
-
encodeSolidityStackTrace,
|
|
77
|
-
SolidityError,
|
|
78
|
-
} from "../stack-traces/solidity-errors";
|
|
79
|
-
import { SolidityStackTrace } from "../stack-traces/solidity-stack-trace";
|
|
80
|
-
import { SolidityTracer } from "../stack-traces/solidityTracer";
|
|
81
|
-
import { VMDebugTracer } from "../stack-traces/vm-debug-tracer";
|
|
82
|
-
import { VmTraceDecoder } from "../stack-traces/vm-trace-decoder";
|
|
83
|
-
import { VMTracer } from "../stack-traces/vm-tracer";
|
|
84
|
-
|
|
85
|
-
import "./ethereumjs-workarounds";
|
|
86
|
-
import { rpcQuantityToBigInt } from "../../core/jsonrpc/types/base-types";
|
|
87
|
-
import { JsonRpcClient } from "../jsonrpc/client";
|
|
88
|
-
import {
|
|
89
|
-
StateOverrideSet,
|
|
90
|
-
StateProperties,
|
|
91
|
-
} from "../../core/jsonrpc/types/input/callRequest";
|
|
92
|
-
import { bloomFilter, Filter, filterLogs, LATEST_BLOCK, Type } from "./filter";
|
|
93
|
-
import { ForkBlockchain } from "./fork/ForkBlockchain";
|
|
94
|
-
import { ForkStateManager } from "./fork/ForkStateManager";
|
|
95
|
-
import { HardhatBlockchain } from "./HardhatBlockchain";
|
|
96
|
-
import {
|
|
97
|
-
CallParams,
|
|
98
|
-
EstimateGasResult,
|
|
99
|
-
FeeHistory,
|
|
100
|
-
FilterParams,
|
|
101
|
-
GatherTracesResult,
|
|
102
|
-
GenesisAccount,
|
|
103
|
-
isForkedNodeConfig,
|
|
104
|
-
MempoolOrder,
|
|
105
|
-
MineBlockResult,
|
|
106
|
-
NodeConfig,
|
|
107
|
-
RunCallResult,
|
|
108
|
-
SendTransactionResult,
|
|
109
|
-
Snapshot,
|
|
110
|
-
TracingConfig,
|
|
111
|
-
TransactionParams,
|
|
112
|
-
} from "./node-types";
|
|
113
|
-
import {
|
|
114
|
-
getRpcBlock,
|
|
115
|
-
getRpcReceiptOutputsFromLocalBlockExecution,
|
|
116
|
-
RpcLogOutput,
|
|
117
|
-
RpcReceiptOutput,
|
|
118
|
-
shouldShowTransactionTypeForHardfork,
|
|
119
|
-
} from "./output";
|
|
120
|
-
import { ReturnData } from "./return-data";
|
|
121
|
-
import { FakeSenderAccessListEIP2930Transaction } from "./transactions/FakeSenderAccessListEIP2930Transaction";
|
|
122
|
-
import { FakeSenderEIP1559Transaction } from "./transactions/FakeSenderEIP1559Transaction";
|
|
123
|
-
import { FakeSenderTransaction } from "./transactions/FakeSenderTransaction";
|
|
124
|
-
import { TxPool } from "./TxPool";
|
|
125
|
-
import { TransactionQueue } from "./TransactionQueue";
|
|
126
|
-
import { HardhatBlockchainInterface } from "./types/HardhatBlockchainInterface";
|
|
127
|
-
import { getCurrentTimestamp } from "./utils/getCurrentTimestamp";
|
|
128
|
-
import { makeCommon } from "./utils/makeCommon";
|
|
129
|
-
import { makeForkClient } from "./utils/makeForkClient";
|
|
130
|
-
import { makeStateTrie } from "./utils/makeStateTrie";
|
|
131
|
-
import { putGenesisBlock } from "./utils/putGenesisBlock";
|
|
132
|
-
import { txMapToArray } from "./utils/txMapToArray";
|
|
133
|
-
import { RandomBufferGenerator } from "./utils/random";
|
|
134
|
-
|
|
135
|
-
type ExecResult = EVMResult["execResult"];
|
|
136
|
-
|
|
137
|
-
const BEACON_ROOT_ADDRESS = "0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02";
|
|
138
|
-
const BEACON_ROOT_BYTECODE =
|
|
139
|
-
"0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500";
|
|
140
|
-
|
|
141
|
-
const log = debug("hardhat:core:hardhat-network:node");
|
|
142
|
-
|
|
143
|
-
/* eslint-disable @nomicfoundation/hardhat-internal-rules/only-hardhat-error */
|
|
144
|
-
|
|
145
|
-
export class HardhatNode extends EventEmitter {
|
|
146
|
-
public static async create(
|
|
147
|
-
config: NodeConfig
|
|
148
|
-
): Promise<[Common, HardhatNode]> {
|
|
149
|
-
const {
|
|
150
|
-
automine,
|
|
151
|
-
genesisAccounts,
|
|
152
|
-
blockGasLimit,
|
|
153
|
-
tracingConfig,
|
|
154
|
-
minGasPrice,
|
|
155
|
-
mempoolOrder,
|
|
156
|
-
networkId,
|
|
157
|
-
chainId,
|
|
158
|
-
allowBlocksWithSameTimestamp,
|
|
159
|
-
enableTransientStorage,
|
|
160
|
-
} = config;
|
|
161
|
-
|
|
162
|
-
const allowUnlimitedContractSize =
|
|
163
|
-
config.allowUnlimitedContractSize ?? false;
|
|
164
|
-
|
|
165
|
-
let stateManager: EVMStateManagerInterface;
|
|
166
|
-
let blockchain: HardhatBlockchainInterface;
|
|
167
|
-
let initialBlockTimeOffset: bigint | undefined;
|
|
168
|
-
let nextBlockBaseFeePerGas: bigint | undefined;
|
|
169
|
-
let forkNetworkId: number | undefined;
|
|
170
|
-
let forkBlockNum: bigint | undefined;
|
|
171
|
-
let forkBlockHash: string | undefined;
|
|
172
|
-
let hardforkActivations: HardforkHistoryConfig = new Map();
|
|
173
|
-
|
|
174
|
-
const initialBaseFeePerGasConfig =
|
|
175
|
-
config.initialBaseFeePerGas !== undefined
|
|
176
|
-
? BigInt(config.initialBaseFeePerGas)
|
|
177
|
-
: undefined;
|
|
178
|
-
|
|
179
|
-
const hardfork = getHardforkName(config.hardfork);
|
|
180
|
-
const mixHashGenerator = RandomBufferGenerator.create("randomMixHashSeed");
|
|
181
|
-
const parentBeaconBlockRootGenerator = RandomBufferGenerator.create(
|
|
182
|
-
"randomParentBeaconBlockRootSeed"
|
|
183
|
-
);
|
|
184
|
-
|
|
185
|
-
let forkClient: JsonRpcClient | undefined;
|
|
186
|
-
|
|
187
|
-
const common = makeCommon(config);
|
|
188
|
-
|
|
189
|
-
if (isForkedNodeConfig(config)) {
|
|
190
|
-
const {
|
|
191
|
-
forkClient: _forkClient,
|
|
192
|
-
forkBlockNumber,
|
|
193
|
-
forkBlockTimestamp,
|
|
194
|
-
forkBlockHash: _forkBlockHash,
|
|
195
|
-
} = await makeForkClient(config.forkConfig, config.forkCachePath);
|
|
196
|
-
forkClient = _forkClient;
|
|
197
|
-
|
|
198
|
-
forkNetworkId = forkClient.getNetworkId();
|
|
199
|
-
forkBlockNum = forkBlockNumber;
|
|
200
|
-
forkBlockHash = _forkBlockHash;
|
|
201
|
-
|
|
202
|
-
this._validateHardforks(
|
|
203
|
-
config.forkConfig.blockNumber,
|
|
204
|
-
common,
|
|
205
|
-
forkNetworkId
|
|
206
|
-
);
|
|
207
|
-
|
|
208
|
-
const forkStateManager = new ForkStateManager(
|
|
209
|
-
forkClient,
|
|
210
|
-
forkBlockNumber
|
|
211
|
-
);
|
|
212
|
-
await forkStateManager.initializeGenesisAccounts(genesisAccounts);
|
|
213
|
-
|
|
214
|
-
if (hardforkGte(hardfork, HardforkName.CANCUN)) {
|
|
215
|
-
await forkStateManager.putContractCode(
|
|
216
|
-
Address.fromString(BEACON_ROOT_ADDRESS),
|
|
217
|
-
Buffer.from(toBytes(BEACON_ROOT_BYTECODE))
|
|
218
|
-
);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
stateManager = forkStateManager;
|
|
222
|
-
|
|
223
|
-
blockchain = new ForkBlockchain(forkClient, forkBlockNumber, common);
|
|
224
|
-
|
|
225
|
-
initialBlockTimeOffset = BigInt(
|
|
226
|
-
getDifferenceInSeconds(new Date(forkBlockTimestamp), new Date())
|
|
227
|
-
);
|
|
228
|
-
|
|
229
|
-
// If the hardfork is London or later we need a base fee per gas for the
|
|
230
|
-
// first local block. If initialBaseFeePerGas config was provided we use
|
|
231
|
-
// that. Otherwise, what we do depends on the block we forked from. If
|
|
232
|
-
// it's an EIP-1559 block we don't need to do anything here, as we'll
|
|
233
|
-
// end up automatically computing the next base fee per gas based on it.
|
|
234
|
-
if (hardforkGte(hardfork, HardforkName.LONDON)) {
|
|
235
|
-
if (initialBaseFeePerGasConfig !== undefined) {
|
|
236
|
-
nextBlockBaseFeePerGas = initialBaseFeePerGasConfig;
|
|
237
|
-
} else {
|
|
238
|
-
const latestBlock = await blockchain.getLatestBlock();
|
|
239
|
-
if (latestBlock.header.baseFeePerGas === undefined) {
|
|
240
|
-
nextBlockBaseFeePerGas = BigInt(
|
|
241
|
-
HARDHAT_NETWORK_DEFAULT_INITIAL_BASE_FEE_PER_GAS
|
|
242
|
-
);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if (config.chains.has(forkNetworkId)) {
|
|
248
|
-
hardforkActivations = config.chains.get(forkNetworkId)!.hardforkHistory;
|
|
249
|
-
}
|
|
250
|
-
} else {
|
|
251
|
-
const stateTrie = await makeStateTrie(genesisAccounts);
|
|
252
|
-
|
|
253
|
-
stateManager = new DefaultStateManager({
|
|
254
|
-
trie: stateTrie,
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
if (hardforkGte(hardfork, HardforkName.CANCUN)) {
|
|
258
|
-
await stateManager.putContractCode(
|
|
259
|
-
Address.fromString(BEACON_ROOT_ADDRESS),
|
|
260
|
-
Buffer.from(toBytes(BEACON_ROOT_BYTECODE))
|
|
261
|
-
);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
const hardhatBlockchain = new HardhatBlockchain(common);
|
|
265
|
-
|
|
266
|
-
const genesisBlockBaseFeePerGas = hardforkGte(
|
|
267
|
-
hardfork,
|
|
268
|
-
HardforkName.LONDON
|
|
269
|
-
)
|
|
270
|
-
? initialBaseFeePerGasConfig ??
|
|
271
|
-
BigInt(HARDHAT_NETWORK_DEFAULT_INITIAL_BASE_FEE_PER_GAS)
|
|
272
|
-
: undefined;
|
|
273
|
-
|
|
274
|
-
await putGenesisBlock(
|
|
275
|
-
hardhatBlockchain,
|
|
276
|
-
common,
|
|
277
|
-
config,
|
|
278
|
-
await stateManager.getStateRoot(),
|
|
279
|
-
hardfork,
|
|
280
|
-
mixHashGenerator.next(),
|
|
281
|
-
parentBeaconBlockRootGenerator.next(),
|
|
282
|
-
genesisBlockBaseFeePerGas
|
|
283
|
-
);
|
|
284
|
-
|
|
285
|
-
if (config.initialDate !== undefined) {
|
|
286
|
-
initialBlockTimeOffset = BigInt(
|
|
287
|
-
getDifferenceInSeconds(config.initialDate, new Date())
|
|
288
|
-
);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
blockchain = hardhatBlockchain;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
const txPool = new TxPool(stateManager, BigInt(blockGasLimit), common);
|
|
295
|
-
|
|
296
|
-
const evm = new EVM({
|
|
297
|
-
allowUnlimitedContractSize,
|
|
298
|
-
allowUnlimitedInitCodeSize: allowUnlimitedContractSize,
|
|
299
|
-
blockchain,
|
|
300
|
-
common,
|
|
301
|
-
stateManager,
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
const vm = await VM.create({
|
|
305
|
-
evm,
|
|
306
|
-
activatePrecompiles: true,
|
|
307
|
-
common,
|
|
308
|
-
stateManager,
|
|
309
|
-
blockchain,
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
const instanceId = bytesToBigInt(randomBytes(32));
|
|
313
|
-
|
|
314
|
-
const node = new HardhatNode(
|
|
315
|
-
vm,
|
|
316
|
-
instanceId,
|
|
317
|
-
stateManager,
|
|
318
|
-
blockchain,
|
|
319
|
-
txPool,
|
|
320
|
-
automine,
|
|
321
|
-
minGasPrice,
|
|
322
|
-
initialBlockTimeOffset,
|
|
323
|
-
mempoolOrder,
|
|
324
|
-
config.coinbase,
|
|
325
|
-
genesisAccounts,
|
|
326
|
-
networkId,
|
|
327
|
-
chainId,
|
|
328
|
-
hardfork,
|
|
329
|
-
hardforkActivations,
|
|
330
|
-
mixHashGenerator,
|
|
331
|
-
parentBeaconBlockRootGenerator,
|
|
332
|
-
allowUnlimitedContractSize,
|
|
333
|
-
allowBlocksWithSameTimestamp,
|
|
334
|
-
tracingConfig,
|
|
335
|
-
forkNetworkId,
|
|
336
|
-
forkBlockNum,
|
|
337
|
-
forkBlockHash,
|
|
338
|
-
nextBlockBaseFeePerGas,
|
|
339
|
-
forkClient,
|
|
340
|
-
enableTransientStorage
|
|
341
|
-
);
|
|
342
|
-
|
|
343
|
-
return [common, node];
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
private static _validateHardforks(
|
|
347
|
-
forkBlockNumber: number | undefined,
|
|
348
|
-
common: Common,
|
|
349
|
-
remoteChainId: number
|
|
350
|
-
): void {
|
|
351
|
-
if (!common.gteHardfork("spuriousDragon")) {
|
|
352
|
-
throw new InternalError(
|
|
353
|
-
`Invalid hardfork selected in Hardhat Network's config.
|
|
354
|
-
|
|
355
|
-
The hardfork must be at least spuriousDragon, but ${common.hardfork()} was given.`
|
|
356
|
-
);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
if (forkBlockNumber !== undefined) {
|
|
360
|
-
let upstreamCommon: Common;
|
|
361
|
-
try {
|
|
362
|
-
upstreamCommon = new Common({ chain: remoteChainId });
|
|
363
|
-
} catch {
|
|
364
|
-
// If ethereumjs doesn't have a common it will throw and we won't have
|
|
365
|
-
// info about the activation block of each hardfork, so we don't run
|
|
366
|
-
// this validation.
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
upstreamCommon.setHardforkBy({ blockNumber: forkBlockNumber });
|
|
371
|
-
|
|
372
|
-
if (!upstreamCommon.gteHardfork("spuriousDragon")) {
|
|
373
|
-
throw new InternalError(
|
|
374
|
-
`Cannot fork ${upstreamCommon.chainName()} from block ${forkBlockNumber}.
|
|
375
|
-
|
|
376
|
-
Hardhat Network's forking functionality only works with blocks from at least spuriousDragon.`
|
|
377
|
-
);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
private readonly _localAccounts: Map<string, Uint8Array> = new Map(); // address => private key
|
|
383
|
-
private readonly _impersonatedAccounts: Set<string> = new Set(); // address
|
|
384
|
-
|
|
385
|
-
private _nextBlockTimestamp: bigint = 0n;
|
|
386
|
-
private _userProvidedNextBlockBaseFeePerGas?: bigint;
|
|
387
|
-
|
|
388
|
-
private _lastFilterId: bigint = 0n;
|
|
389
|
-
private _filters: Map<string, Filter> = new Map();
|
|
390
|
-
|
|
391
|
-
private _nextSnapshotId = 1; // We start in 1 to mimic Ganache
|
|
392
|
-
private readonly _snapshots: Snapshot[] = [];
|
|
393
|
-
|
|
394
|
-
private readonly _vmTracer: VMTracer;
|
|
395
|
-
private readonly _vmTraceDecoder: VmTraceDecoder;
|
|
396
|
-
private readonly _solidityTracer: SolidityTracer;
|
|
397
|
-
private readonly _consoleLogger: ConsoleLogger = new ConsoleLogger();
|
|
398
|
-
private _failedStackTraces = 0;
|
|
399
|
-
|
|
400
|
-
// blockNumber => state root
|
|
401
|
-
private _irregularStatesByBlockNumber: Map<bigint, Uint8Array> = new Map();
|
|
402
|
-
|
|
403
|
-
private constructor(
|
|
404
|
-
private readonly _vm: VM,
|
|
405
|
-
private readonly _instanceId: bigint,
|
|
406
|
-
private readonly _stateManager: EVMStateManagerInterface,
|
|
407
|
-
private readonly _blockchain: HardhatBlockchainInterface,
|
|
408
|
-
private readonly _txPool: TxPool,
|
|
409
|
-
private _automine: boolean,
|
|
410
|
-
private _minGasPrice: bigint,
|
|
411
|
-
private _blockTimeOffsetSeconds: bigint = 0n,
|
|
412
|
-
private _mempoolOrder: MempoolOrder,
|
|
413
|
-
private _coinbase: string,
|
|
414
|
-
genesisAccounts: GenesisAccount[],
|
|
415
|
-
private readonly _configNetworkId: number,
|
|
416
|
-
private readonly _configChainId: number,
|
|
417
|
-
public readonly hardfork: HardforkName,
|
|
418
|
-
private readonly _hardforkActivations: HardforkHistoryConfig,
|
|
419
|
-
private _mixHashGenerator: RandomBufferGenerator,
|
|
420
|
-
private _parentBeaconBlockRootGenerator: RandomBufferGenerator,
|
|
421
|
-
public readonly allowUnlimitedContractSize: boolean,
|
|
422
|
-
private _allowBlocksWithSameTimestamp: boolean,
|
|
423
|
-
tracingConfig?: TracingConfig,
|
|
424
|
-
private _forkNetworkId?: number,
|
|
425
|
-
private _forkBlockNumber?: bigint,
|
|
426
|
-
private _forkBlockHash?: string,
|
|
427
|
-
nextBlockBaseFee?: bigint,
|
|
428
|
-
private _forkClient?: JsonRpcClient,
|
|
429
|
-
private readonly _enableTransientStorage: boolean = false
|
|
430
|
-
) {
|
|
431
|
-
super();
|
|
432
|
-
|
|
433
|
-
this._initLocalAccounts(genesisAccounts);
|
|
434
|
-
|
|
435
|
-
if (nextBlockBaseFee !== undefined) {
|
|
436
|
-
this.setUserProvidedNextBlockBaseFeePerGas(nextBlockBaseFee);
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
this._vmTracer = new VMTracer(
|
|
440
|
-
this._vm,
|
|
441
|
-
this._stateManager.getContractCode.bind(this._stateManager),
|
|
442
|
-
false
|
|
443
|
-
);
|
|
444
|
-
this._vmTracer.enableTracing();
|
|
445
|
-
|
|
446
|
-
const contractsIdentifier = new ContractsIdentifier();
|
|
447
|
-
this._vmTraceDecoder = new VmTraceDecoder(contractsIdentifier);
|
|
448
|
-
this._solidityTracer = new SolidityTracer();
|
|
449
|
-
|
|
450
|
-
if (tracingConfig === undefined || tracingConfig.buildInfos === undefined) {
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
try {
|
|
455
|
-
for (const buildInfo of tracingConfig.buildInfos) {
|
|
456
|
-
const bytecodes = createModelsAndDecodeBytecodes(
|
|
457
|
-
buildInfo.solcVersion,
|
|
458
|
-
buildInfo.input,
|
|
459
|
-
buildInfo.output
|
|
460
|
-
);
|
|
461
|
-
|
|
462
|
-
for (const bytecode of bytecodes) {
|
|
463
|
-
this._vmTraceDecoder.addBytecode(bytecode);
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
} catch (error) {
|
|
467
|
-
console.warn(
|
|
468
|
-
chalk.yellow(
|
|
469
|
-
"The Hardhat Network tracing engine could not be initialized. Run Hardhat with --verbose to learn more."
|
|
470
|
-
)
|
|
471
|
-
);
|
|
472
|
-
|
|
473
|
-
log(
|
|
474
|
-
"Hardhat Network tracing disabled: ContractsIdentifier failed to be initialized. Please report this to help us improve Hardhat.\n",
|
|
475
|
-
error
|
|
476
|
-
);
|
|
477
|
-
|
|
478
|
-
if (error instanceof Error) {
|
|
479
|
-
Reporter.reportError(error);
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
public async getSignedTransaction(
|
|
485
|
-
txParams: TransactionParams
|
|
486
|
-
): Promise<TypedTransaction> {
|
|
487
|
-
const senderAddress = bufferToHex(txParams.from);
|
|
488
|
-
|
|
489
|
-
const pk = this._localAccounts.get(senderAddress);
|
|
490
|
-
if (pk !== undefined) {
|
|
491
|
-
let tx: TypedTransaction;
|
|
492
|
-
|
|
493
|
-
if ("blobs" in txParams) {
|
|
494
|
-
tx = BlobEIP4844Transaction.fromTxData(txParams, {
|
|
495
|
-
common: this._vm.common,
|
|
496
|
-
allowUnlimitedInitCodeSize: true,
|
|
497
|
-
});
|
|
498
|
-
} else if ("maxFeePerGas" in txParams) {
|
|
499
|
-
tx = FeeMarketEIP1559Transaction.fromTxData(txParams, {
|
|
500
|
-
common: this._vm.common,
|
|
501
|
-
allowUnlimitedInitCodeSize: true,
|
|
502
|
-
});
|
|
503
|
-
} else if ("accessList" in txParams) {
|
|
504
|
-
tx = AccessListEIP2930Transaction.fromTxData(txParams, {
|
|
505
|
-
common: this._vm.common,
|
|
506
|
-
allowUnlimitedInitCodeSize: true,
|
|
507
|
-
});
|
|
508
|
-
} else {
|
|
509
|
-
tx = LegacyTransaction.fromTxData(txParams, {
|
|
510
|
-
common: this._vm.common,
|
|
511
|
-
allowUnlimitedInitCodeSize: true,
|
|
512
|
-
});
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
return tx.sign(pk);
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
if (this._impersonatedAccounts.has(senderAddress)) {
|
|
519
|
-
return this._getFakeTransaction(txParams);
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
throw new InvalidInputError(`unknown account ${senderAddress}`);
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
public async sendTransaction(
|
|
526
|
-
tx: TypedTransaction
|
|
527
|
-
): Promise<SendTransactionResult> {
|
|
528
|
-
if (!this._automine) {
|
|
529
|
-
return this._addPendingTransaction(tx);
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
await this._validateAutominedTx(tx);
|
|
533
|
-
|
|
534
|
-
if (
|
|
535
|
-
this._txPool.hasPendingTransactions() ||
|
|
536
|
-
this._txPool.hasQueuedTransactions()
|
|
537
|
-
) {
|
|
538
|
-
return this._mineTransactionAndPending(tx);
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
return this._mineTransaction(tx);
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
public async mineBlock(timestamp?: bigint): Promise<MineBlockResult> {
|
|
545
|
-
const timestampAndOffset = this._calculateTimestampAndOffset(timestamp);
|
|
546
|
-
let [blockTimestamp] = timestampAndOffset;
|
|
547
|
-
const [, offsetShouldChange, newOffset] = timestampAndOffset;
|
|
548
|
-
|
|
549
|
-
const needsTimestampIncrease =
|
|
550
|
-
!this._allowBlocksWithSameTimestamp &&
|
|
551
|
-
(await this._timestampClashesWithPreviousBlockOne(blockTimestamp));
|
|
552
|
-
if (needsTimestampIncrease) {
|
|
553
|
-
blockTimestamp += 1n;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
let result: MineBlockResult;
|
|
557
|
-
try {
|
|
558
|
-
result = await this._mineBlockWithPendingTxs(blockTimestamp);
|
|
559
|
-
} catch (err) {
|
|
560
|
-
if (err instanceof Error) {
|
|
561
|
-
if (err?.message.includes("sender doesn't have enough funds")) {
|
|
562
|
-
throw new InvalidInputError(err.message, err);
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
// Some network errors are HardhatErrors, and can end up here when forking
|
|
566
|
-
if (HardhatError.isHardhatError(err)) {
|
|
567
|
-
throw err;
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
throw new TransactionExecutionError(err);
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
// eslint-disable-next-line @nomicfoundation/hardhat-internal-rules/only-hardhat-error
|
|
574
|
-
throw err;
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
await this._saveBlockAsSuccessfullyRun(result.block, result.blockResult);
|
|
578
|
-
|
|
579
|
-
if (needsTimestampIncrease) {
|
|
580
|
-
this.increaseTime(1n);
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
if (offsetShouldChange) {
|
|
584
|
-
this.setTimeIncrement(newOffset);
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
this._resetNextBlockTimestamp();
|
|
588
|
-
this._resetUserProvidedNextBlockBaseFeePerGas();
|
|
589
|
-
|
|
590
|
-
return result;
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
/**
|
|
594
|
-
* Mines `count` blocks with a difference of `interval` seconds between their
|
|
595
|
-
* timestamps.
|
|
596
|
-
*
|
|
597
|
-
* Returns an array with the results of the blocks that were really mined (the
|
|
598
|
-
* ones that were reserved are not included).
|
|
599
|
-
*/
|
|
600
|
-
public async mineBlocks(
|
|
601
|
-
count: bigint = 1n,
|
|
602
|
-
interval: bigint = 1n
|
|
603
|
-
): Promise<MineBlockResult[]> {
|
|
604
|
-
if (count === 0n) {
|
|
605
|
-
// nothing to do
|
|
606
|
-
return [];
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
const mineBlockResults: MineBlockResult[] = [];
|
|
610
|
-
|
|
611
|
-
// we always mine the first block, and we don't apply the interval for it
|
|
612
|
-
mineBlockResults.push(await this.mineBlock());
|
|
613
|
-
|
|
614
|
-
// helper function to mine a block with a timstamp that respects the
|
|
615
|
-
// interval
|
|
616
|
-
const mineBlock = async () => {
|
|
617
|
-
const nextTimestamp =
|
|
618
|
-
(await this.getLatestBlock()).header.timestamp + interval;
|
|
619
|
-
mineBlockResults.push(await this.mineBlock(nextTimestamp));
|
|
620
|
-
};
|
|
621
|
-
|
|
622
|
-
// then we mine any pending transactions
|
|
623
|
-
while (
|
|
624
|
-
count > mineBlockResults.length &&
|
|
625
|
-
this._txPool.hasPendingTransactions()
|
|
626
|
-
) {
|
|
627
|
-
await mineBlock();
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
// If there is at least one remaining block, we mine one. This way, we
|
|
631
|
-
// guarantee that there's an empty block immediately before and after the
|
|
632
|
-
// reservation. This makes the logging easier to get right.
|
|
633
|
-
if (count > mineBlockResults.length) {
|
|
634
|
-
await mineBlock();
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
const remainingBlockCount = count - BigInt(mineBlockResults.length);
|
|
638
|
-
|
|
639
|
-
// There should be at least 2 blocks left for the reservation to work,
|
|
640
|
-
// because we always mine a block after it. But here we use a bigger
|
|
641
|
-
// number to err on the safer side.
|
|
642
|
-
if (remainingBlockCount <= 5) {
|
|
643
|
-
// if there are few blocks left to mine, we just mine them
|
|
644
|
-
while (count > mineBlockResults.length) {
|
|
645
|
-
await mineBlock();
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
return mineBlockResults;
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
// otherwise, we reserve a range and mine the last one
|
|
652
|
-
const latestBlock = await this.getLatestBlock();
|
|
653
|
-
this._blockchain.reserveBlocks(
|
|
654
|
-
remainingBlockCount - 1n,
|
|
655
|
-
interval,
|
|
656
|
-
await this._stateManager.getStateRoot(),
|
|
657
|
-
await this.getBlockTotalDifficulty(latestBlock),
|
|
658
|
-
(await this.getLatestBlock()).header.baseFeePerGas
|
|
659
|
-
);
|
|
660
|
-
|
|
661
|
-
await mineBlock();
|
|
662
|
-
|
|
663
|
-
return mineBlockResults;
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
public async runCall(
|
|
667
|
-
call: CallParams,
|
|
668
|
-
blockNumberOrPending: bigint | "pending",
|
|
669
|
-
stateOverrideSet: StateOverrideSet = {}
|
|
670
|
-
): Promise<RunCallResult> {
|
|
671
|
-
let txParams: TransactionParams;
|
|
672
|
-
|
|
673
|
-
const nonce = await this._getNonce(
|
|
674
|
-
new Address(call.from),
|
|
675
|
-
blockNumberOrPending
|
|
676
|
-
);
|
|
677
|
-
|
|
678
|
-
if (
|
|
679
|
-
call.gasPrice !== undefined ||
|
|
680
|
-
!this.isEip1559Active(blockNumberOrPending)
|
|
681
|
-
) {
|
|
682
|
-
txParams = {
|
|
683
|
-
gasPrice: 0n,
|
|
684
|
-
nonce,
|
|
685
|
-
...call,
|
|
686
|
-
};
|
|
687
|
-
} else {
|
|
688
|
-
const maxFeePerGas = call.maxFeePerGas ?? call.maxPriorityFeePerGas ?? 0n;
|
|
689
|
-
const maxPriorityFeePerGas = call.maxPriorityFeePerGas ?? 0n;
|
|
690
|
-
|
|
691
|
-
txParams = {
|
|
692
|
-
...call,
|
|
693
|
-
nonce,
|
|
694
|
-
maxFeePerGas,
|
|
695
|
-
maxPriorityFeePerGas,
|
|
696
|
-
accessList: call.accessList ?? [],
|
|
697
|
-
};
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
const tx = await this._getFakeTransaction(txParams);
|
|
701
|
-
|
|
702
|
-
const result = await this._runInBlockContext(
|
|
703
|
-
blockNumberOrPending,
|
|
704
|
-
async () =>
|
|
705
|
-
this._runTxAndRevertMutations(
|
|
706
|
-
tx,
|
|
707
|
-
blockNumberOrPending,
|
|
708
|
-
true,
|
|
709
|
-
stateOverrideSet
|
|
710
|
-
)
|
|
711
|
-
);
|
|
712
|
-
|
|
713
|
-
const traces = await this._gatherTraces(result.execResult);
|
|
714
|
-
|
|
715
|
-
return {
|
|
716
|
-
...traces,
|
|
717
|
-
result: new ReturnData(result.execResult.returnValue),
|
|
718
|
-
};
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
public async getAccountBalance(
|
|
722
|
-
address: Address,
|
|
723
|
-
blockNumberOrPending?: bigint | "pending"
|
|
724
|
-
): Promise<bigint> {
|
|
725
|
-
if (blockNumberOrPending === undefined) {
|
|
726
|
-
blockNumberOrPending = this.getLatestBlockNumber();
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
const account = await this._runInBlockContext(blockNumberOrPending, () =>
|
|
730
|
-
this._stateManager.getAccount(address)
|
|
731
|
-
);
|
|
732
|
-
|
|
733
|
-
return account?.balance ?? 0n;
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
public async getNextConfirmedNonce(
|
|
737
|
-
address: Address,
|
|
738
|
-
blockNumberOrPending: bigint | "pending"
|
|
739
|
-
): Promise<bigint> {
|
|
740
|
-
const account = await this._runInBlockContext(blockNumberOrPending, () =>
|
|
741
|
-
this._stateManager.getAccount(address)
|
|
742
|
-
);
|
|
743
|
-
|
|
744
|
-
return account?.nonce ?? 0n;
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
public async getAccountNextPendingNonce(address: Address): Promise<bigint> {
|
|
748
|
-
return this._txPool.getNextPendingNonce(address);
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
public async getCodeFromTrace(
|
|
752
|
-
trace: MessageTrace | undefined,
|
|
753
|
-
blockNumberOrPending: bigint | "pending"
|
|
754
|
-
): Promise<Buffer> {
|
|
755
|
-
if (
|
|
756
|
-
trace === undefined ||
|
|
757
|
-
isPrecompileTrace(trace) ||
|
|
758
|
-
isCreateTrace(trace)
|
|
759
|
-
) {
|
|
760
|
-
return Buffer.from("");
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
return this.getCode(new Address(trace.address), blockNumberOrPending);
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
public async getLatestBlock(): Promise<Block> {
|
|
767
|
-
return this._blockchain.getLatestBlock();
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
public getLatestBlockNumber(): bigint {
|
|
771
|
-
return this._blockchain.getLatestBlockNumber();
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
public async getPendingBlockAndTotalDifficulty(): Promise<[Block, bigint]> {
|
|
775
|
-
return this._runInPendingBlockContext(async () => {
|
|
776
|
-
const block = await this._blockchain.getLatestBlock();
|
|
777
|
-
const totalDifficulty = await this._blockchain.getTotalDifficulty(
|
|
778
|
-
block.hash()
|
|
779
|
-
);
|
|
780
|
-
|
|
781
|
-
return [block, totalDifficulty];
|
|
782
|
-
});
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
public async getLocalAccountAddresses(): Promise<string[]> {
|
|
786
|
-
return [...this._localAccounts.keys()];
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
public getBlockGasLimit(): bigint {
|
|
790
|
-
return this._txPool.getBlockGasLimit();
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
public async estimateGas(
|
|
794
|
-
callParams: CallParams,
|
|
795
|
-
blockNumberOrPending: bigint | "pending"
|
|
796
|
-
): Promise<EstimateGasResult> {
|
|
797
|
-
// We get the CallParams and transform it into a TransactionParams to be
|
|
798
|
-
// able to run it.
|
|
799
|
-
const nonce = await this._getNonce(
|
|
800
|
-
new Address(callParams.from),
|
|
801
|
-
blockNumberOrPending
|
|
802
|
-
);
|
|
803
|
-
|
|
804
|
-
// TODO: This is more complex in Geth, we should make sure we aren't missing
|
|
805
|
-
// anything here.
|
|
806
|
-
|
|
807
|
-
const feePriceFields = await this._getEstimateGasFeePriceFields(
|
|
808
|
-
callParams,
|
|
809
|
-
blockNumberOrPending
|
|
810
|
-
);
|
|
811
|
-
|
|
812
|
-
let txParams: TransactionParams;
|
|
813
|
-
|
|
814
|
-
if ("gasPrice" in feePriceFields) {
|
|
815
|
-
if (callParams.accessList === undefined) {
|
|
816
|
-
// Legacy tx
|
|
817
|
-
txParams = {
|
|
818
|
-
...callParams,
|
|
819
|
-
nonce,
|
|
820
|
-
gasPrice: feePriceFields.gasPrice,
|
|
821
|
-
};
|
|
822
|
-
} else {
|
|
823
|
-
// Access list tx
|
|
824
|
-
txParams = {
|
|
825
|
-
...callParams,
|
|
826
|
-
nonce,
|
|
827
|
-
gasPrice: feePriceFields.gasPrice,
|
|
828
|
-
accessList: callParams.accessList ?? [],
|
|
829
|
-
};
|
|
830
|
-
}
|
|
831
|
-
} else {
|
|
832
|
-
// EIP-1559 tx
|
|
833
|
-
txParams = {
|
|
834
|
-
...callParams,
|
|
835
|
-
nonce,
|
|
836
|
-
maxFeePerGas: feePriceFields.maxFeePerGas,
|
|
837
|
-
maxPriorityFeePerGas: feePriceFields.maxPriorityFeePerGas,
|
|
838
|
-
accessList: callParams.accessList ?? [],
|
|
839
|
-
};
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
const tx = await this._getFakeTransaction(txParams);
|
|
843
|
-
|
|
844
|
-
// TODO: This may not work if there are multiple txs in the mempool and
|
|
845
|
-
// the one being estimated won't fit in the first block, or maybe even
|
|
846
|
-
// if the state accessed by the tx changes after it is executed within
|
|
847
|
-
// the first block.
|
|
848
|
-
const result = await this._runInBlockContext(blockNumberOrPending, () =>
|
|
849
|
-
this._runTxAndRevertMutations(tx, blockNumberOrPending)
|
|
850
|
-
);
|
|
851
|
-
|
|
852
|
-
let vmTrace = this._vmTracer.getLastTopLevelMessageTrace();
|
|
853
|
-
const vmTracerError = this._vmTracer.getLastError();
|
|
854
|
-
this._vmTracer.clearLastError();
|
|
855
|
-
|
|
856
|
-
if (vmTrace !== undefined) {
|
|
857
|
-
vmTrace = this._vmTraceDecoder.tryToDecodeMessageTrace(vmTrace);
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
const consoleLogMessages = await this._getConsoleLogMessages(
|
|
861
|
-
vmTrace,
|
|
862
|
-
vmTracerError
|
|
863
|
-
);
|
|
864
|
-
|
|
865
|
-
// This is only considered if the call to _runTxAndRevertMutations doesn't
|
|
866
|
-
// manage errors
|
|
867
|
-
if (result.execResult.exceptionError !== undefined) {
|
|
868
|
-
return {
|
|
869
|
-
estimation: this.getBlockGasLimit(),
|
|
870
|
-
trace: vmTrace,
|
|
871
|
-
error: await this._manageErrors(
|
|
872
|
-
result.execResult,
|
|
873
|
-
vmTrace,
|
|
874
|
-
vmTracerError
|
|
875
|
-
),
|
|
876
|
-
consoleLogMessages,
|
|
877
|
-
};
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
const initialEstimation = result.totalGasSpent;
|
|
881
|
-
|
|
882
|
-
return {
|
|
883
|
-
estimation: await this._correctInitialEstimation(
|
|
884
|
-
blockNumberOrPending,
|
|
885
|
-
txParams,
|
|
886
|
-
initialEstimation
|
|
887
|
-
),
|
|
888
|
-
trace: vmTrace,
|
|
889
|
-
consoleLogMessages,
|
|
890
|
-
};
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
public async getGasPrice(): Promise<bigint> {
|
|
894
|
-
const nextBlockBaseFeePerGas = await this.getNextBlockBaseFeePerGas();
|
|
895
|
-
|
|
896
|
-
if (nextBlockBaseFeePerGas === undefined) {
|
|
897
|
-
// We return a hardcoded value for networks without EIP-1559
|
|
898
|
-
return 8n * 10n ** 9n;
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
const suggestedPriorityFeePerGas = 10n ** 9n;
|
|
902
|
-
return nextBlockBaseFeePerGas + suggestedPriorityFeePerGas;
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
public async getMaxPriorityFeePerGas(): Promise<bigint> {
|
|
906
|
-
return BigInt(HARDHAT_NETWORK_DEFAULT_MAX_PRIORITY_FEE_PER_GAS);
|
|
907
|
-
}
|
|
908
|
-
|
|
909
|
-
public getCoinbaseAddress(): Address {
|
|
910
|
-
return Address.fromString(this._coinbase);
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
public async getStorageAt(
|
|
914
|
-
address: Address,
|
|
915
|
-
positionIndex: bigint,
|
|
916
|
-
blockNumberOrPending: bigint | "pending"
|
|
917
|
-
): Promise<Buffer> {
|
|
918
|
-
const key = setLengthLeft(bigIntToBytes(positionIndex), 32);
|
|
919
|
-
|
|
920
|
-
const data = await this._runInBlockContext(
|
|
921
|
-
blockNumberOrPending,
|
|
922
|
-
async () => {
|
|
923
|
-
const account = await this._stateManager.getAccount(address);
|
|
924
|
-
if (account === undefined) {
|
|
925
|
-
return Uint8Array.from([]);
|
|
926
|
-
}
|
|
927
|
-
return this._stateManager.getContractStorage(address, key);
|
|
928
|
-
}
|
|
929
|
-
);
|
|
930
|
-
|
|
931
|
-
const EXPECTED_DATA_SIZE = 32;
|
|
932
|
-
if (data.length < EXPECTED_DATA_SIZE) {
|
|
933
|
-
return Buffer.concat(
|
|
934
|
-
[Buffer.alloc(EXPECTED_DATA_SIZE - data.length, 0), data],
|
|
935
|
-
EXPECTED_DATA_SIZE
|
|
936
|
-
);
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
return Buffer.from(data);
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
public async getBlockByNumber(pending: "pending"): Promise<Block>;
|
|
943
|
-
public async getBlockByNumber(
|
|
944
|
-
blockNumberOrPending: bigint | "pending"
|
|
945
|
-
): Promise<Block | undefined>;
|
|
946
|
-
|
|
947
|
-
public async getBlockByNumber(
|
|
948
|
-
blockNumberOrPending: bigint | "pending"
|
|
949
|
-
): Promise<Block | undefined> {
|
|
950
|
-
if (blockNumberOrPending === "pending") {
|
|
951
|
-
return this._runInPendingBlockContext(() =>
|
|
952
|
-
this._blockchain.getLatestBlock()
|
|
953
|
-
);
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
try {
|
|
957
|
-
const block = await this._blockchain.getBlock(blockNumberOrPending);
|
|
958
|
-
return block;
|
|
959
|
-
} catch {
|
|
960
|
-
return undefined;
|
|
961
|
-
}
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
public async getBlockByHash(blockHash: Buffer): Promise<Block | undefined> {
|
|
965
|
-
try {
|
|
966
|
-
const block = await this._blockchain.getBlock(blockHash);
|
|
967
|
-
return block;
|
|
968
|
-
} catch {
|
|
969
|
-
return undefined;
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
public async getBlockByTransactionHash(
|
|
974
|
-
hash: Buffer
|
|
975
|
-
): Promise<Block | undefined> {
|
|
976
|
-
const block = await this._blockchain.getBlockByTransactionHash(hash);
|
|
977
|
-
return block ?? undefined;
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
public async getBlockTotalDifficulty(block: Block): Promise<bigint> {
|
|
981
|
-
return this._blockchain.getTotalDifficulty(block.hash());
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
public async getCode(
|
|
985
|
-
address: Address,
|
|
986
|
-
blockNumberOrPending: bigint | "pending"
|
|
987
|
-
): Promise<Buffer> {
|
|
988
|
-
return this._runInBlockContext(blockNumberOrPending, () =>
|
|
989
|
-
this._stateManager.getContractCode(address).then(Buffer.from)
|
|
990
|
-
);
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
public getNextBlockTimestamp(): bigint {
|
|
994
|
-
return this._nextBlockTimestamp;
|
|
995
|
-
}
|
|
996
|
-
|
|
997
|
-
public setNextBlockTimestamp(timestamp: bigint) {
|
|
998
|
-
this._nextBlockTimestamp = timestamp;
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
public getTimeIncrement(): bigint {
|
|
1002
|
-
return this._blockTimeOffsetSeconds;
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
|
-
public setTimeIncrement(timeIncrement: bigint) {
|
|
1006
|
-
this._blockTimeOffsetSeconds = timeIncrement;
|
|
1007
|
-
}
|
|
1008
|
-
|
|
1009
|
-
public increaseTime(increment: bigint) {
|
|
1010
|
-
this._blockTimeOffsetSeconds += increment;
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
public setUserProvidedNextBlockBaseFeePerGas(baseFeePerGas: bigint) {
|
|
1014
|
-
this._userProvidedNextBlockBaseFeePerGas = baseFeePerGas;
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
public getUserProvidedNextBlockBaseFeePerGas(): bigint | undefined {
|
|
1018
|
-
return this._userProvidedNextBlockBaseFeePerGas;
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
private _resetUserProvidedNextBlockBaseFeePerGas() {
|
|
1022
|
-
this._userProvidedNextBlockBaseFeePerGas = undefined;
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
public async getNextBlockBaseFeePerGas(): Promise<bigint | undefined> {
|
|
1026
|
-
if (!this.isEip1559Active()) {
|
|
1027
|
-
return undefined;
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
const userDefined = this.getUserProvidedNextBlockBaseFeePerGas();
|
|
1031
|
-
if (userDefined !== undefined) {
|
|
1032
|
-
return userDefined;
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1035
|
-
const latestBlock = await this.getLatestBlock();
|
|
1036
|
-
return latestBlock.header.calcNextBaseFee();
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
public async getPendingTransaction(
|
|
1040
|
-
hash: Buffer
|
|
1041
|
-
): Promise<TypedTransaction | undefined> {
|
|
1042
|
-
return this._txPool.getTransactionByHash(hash)?.data;
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
public async getTransactionReceipt(
|
|
1046
|
-
hash: Uint8Array | string
|
|
1047
|
-
): Promise<RpcReceiptOutput | undefined> {
|
|
1048
|
-
const hashBuffer = hash instanceof Buffer ? hash : toBytes(hash);
|
|
1049
|
-
const receipt = await this._blockchain.getTransactionReceipt(hashBuffer);
|
|
1050
|
-
return receipt ?? undefined;
|
|
1051
|
-
}
|
|
1052
|
-
|
|
1053
|
-
public async getPendingTransactions(): Promise<TypedTransaction[]> {
|
|
1054
|
-
const txPoolPending = txMapToArray(this._txPool.getPendingTransactions());
|
|
1055
|
-
const txPoolQueued = txMapToArray(this._txPool.getQueuedTransactions());
|
|
1056
|
-
return txPoolPending.concat(txPoolQueued);
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
public async signPersonalMessage(
|
|
1060
|
-
address: Address,
|
|
1061
|
-
data: Buffer
|
|
1062
|
-
): Promise<ECDSASignature> {
|
|
1063
|
-
const messageHash = hashPersonalMessage(data);
|
|
1064
|
-
const privateKey = this._getLocalAccountPrivateKey(address);
|
|
1065
|
-
|
|
1066
|
-
return ecsign(messageHash, privateKey);
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
|
-
public async signTypedDataV4(
|
|
1070
|
-
address: Address,
|
|
1071
|
-
typedData: any
|
|
1072
|
-
): Promise<string> {
|
|
1073
|
-
const privateKey = this._getLocalAccountPrivateKey(address);
|
|
1074
|
-
|
|
1075
|
-
return signTypedData({
|
|
1076
|
-
privateKey: Buffer.from(privateKey),
|
|
1077
|
-
version: SignTypedDataVersion.V4,
|
|
1078
|
-
data: typedData,
|
|
1079
|
-
});
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
|
-
public getStackTraceFailuresCount(): number {
|
|
1083
|
-
return this._failedStackTraces;
|
|
1084
|
-
}
|
|
1085
|
-
|
|
1086
|
-
public async takeSnapshot(): Promise<number> {
|
|
1087
|
-
const id = this._nextSnapshotId;
|
|
1088
|
-
|
|
1089
|
-
const snapshot: Snapshot = {
|
|
1090
|
-
id,
|
|
1091
|
-
date: new Date(),
|
|
1092
|
-
latestBlock: await this.getLatestBlock(),
|
|
1093
|
-
stateRoot: await this._stateManager.getStateRoot(),
|
|
1094
|
-
txPoolSnapshotId: this._txPool.snapshot(),
|
|
1095
|
-
blockTimeOffsetSeconds: this.getTimeIncrement(),
|
|
1096
|
-
nextBlockTimestamp: this.getNextBlockTimestamp(),
|
|
1097
|
-
irregularStatesByBlockNumber: this._irregularStatesByBlockNumber,
|
|
1098
|
-
userProvidedNextBlockBaseFeePerGas:
|
|
1099
|
-
this.getUserProvidedNextBlockBaseFeePerGas(),
|
|
1100
|
-
coinbase: this.getCoinbaseAddress().toString(),
|
|
1101
|
-
mixHashGenerator: this._mixHashGenerator.clone(),
|
|
1102
|
-
parentBeaconBlockRootGenerator:
|
|
1103
|
-
this._parentBeaconBlockRootGenerator.clone(),
|
|
1104
|
-
};
|
|
1105
|
-
|
|
1106
|
-
this._irregularStatesByBlockNumber = new Map(
|
|
1107
|
-
this._irregularStatesByBlockNumber
|
|
1108
|
-
);
|
|
1109
|
-
|
|
1110
|
-
this._snapshots.push(snapshot);
|
|
1111
|
-
this._nextSnapshotId += 1;
|
|
1112
|
-
|
|
1113
|
-
return id;
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
public async revertToSnapshot(id: number): Promise<boolean> {
|
|
1117
|
-
const snapshotIndex = this._getSnapshotIndex(id);
|
|
1118
|
-
if (snapshotIndex === undefined) {
|
|
1119
|
-
return false;
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
const snapshot = this._snapshots[snapshotIndex];
|
|
1123
|
-
|
|
1124
|
-
// We compute a new offset such that
|
|
1125
|
-
// now + new_offset === snapshot_date + old_offset
|
|
1126
|
-
const now = new Date();
|
|
1127
|
-
const offsetToSnapshotInMillis = snapshot.date.valueOf() - now.valueOf();
|
|
1128
|
-
const offsetToSnapshotInSecs = Math.ceil(offsetToSnapshotInMillis / 1000);
|
|
1129
|
-
const newOffset =
|
|
1130
|
-
snapshot.blockTimeOffsetSeconds + BigInt(offsetToSnapshotInSecs);
|
|
1131
|
-
|
|
1132
|
-
// We delete all following blocks, changes the state root, and all the
|
|
1133
|
-
// relevant Node fields.
|
|
1134
|
-
//
|
|
1135
|
-
// Note: There's no need to copy the maps here, as snapshots can only be
|
|
1136
|
-
// used once
|
|
1137
|
-
this._blockchain.deleteLaterBlocks(snapshot.latestBlock);
|
|
1138
|
-
this._irregularStatesByBlockNumber = snapshot.irregularStatesByBlockNumber;
|
|
1139
|
-
const irregularStateOrUndefined = this._irregularStatesByBlockNumber.get(
|
|
1140
|
-
(await this.getLatestBlock()).header.number
|
|
1141
|
-
);
|
|
1142
|
-
await this._stateManager.setStateRoot(
|
|
1143
|
-
irregularStateOrUndefined ?? snapshot.stateRoot
|
|
1144
|
-
);
|
|
1145
|
-
this.setTimeIncrement(newOffset);
|
|
1146
|
-
this.setNextBlockTimestamp(snapshot.nextBlockTimestamp);
|
|
1147
|
-
this._txPool.revert(snapshot.txPoolSnapshotId);
|
|
1148
|
-
|
|
1149
|
-
if (snapshot.userProvidedNextBlockBaseFeePerGas !== undefined) {
|
|
1150
|
-
this.setUserProvidedNextBlockBaseFeePerGas(
|
|
1151
|
-
snapshot.userProvidedNextBlockBaseFeePerGas
|
|
1152
|
-
);
|
|
1153
|
-
} else {
|
|
1154
|
-
this._resetUserProvidedNextBlockBaseFeePerGas();
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1157
|
-
this._coinbase = snapshot.coinbase;
|
|
1158
|
-
|
|
1159
|
-
this._mixHashGenerator = snapshot.mixHashGenerator;
|
|
1160
|
-
this._parentBeaconBlockRootGenerator =
|
|
1161
|
-
snapshot.parentBeaconBlockRootGenerator;
|
|
1162
|
-
|
|
1163
|
-
// We delete this and the following snapshots, as they can only be used
|
|
1164
|
-
// once in Ganache
|
|
1165
|
-
this._snapshots.splice(snapshotIndex);
|
|
1166
|
-
|
|
1167
|
-
return true;
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
|
-
public async newFilter(
|
|
1171
|
-
filterParams: FilterParams,
|
|
1172
|
-
isSubscription: boolean
|
|
1173
|
-
): Promise<bigint> {
|
|
1174
|
-
filterParams = await this._computeFilterParams(filterParams, true);
|
|
1175
|
-
|
|
1176
|
-
const filterId = this._getNextFilterId();
|
|
1177
|
-
this._filters.set(this._filterIdToFiltersKey(filterId), {
|
|
1178
|
-
id: filterId,
|
|
1179
|
-
type: Type.LOGS_SUBSCRIPTION,
|
|
1180
|
-
criteria: {
|
|
1181
|
-
fromBlock: filterParams.fromBlock,
|
|
1182
|
-
toBlock: filterParams.toBlock,
|
|
1183
|
-
addresses: filterParams.addresses,
|
|
1184
|
-
normalizedTopics: filterParams.normalizedTopics,
|
|
1185
|
-
},
|
|
1186
|
-
deadline: this._newDeadline(),
|
|
1187
|
-
hashes: [],
|
|
1188
|
-
logs: await this.getLogs(filterParams),
|
|
1189
|
-
subscription: isSubscription,
|
|
1190
|
-
});
|
|
1191
|
-
|
|
1192
|
-
return filterId;
|
|
1193
|
-
}
|
|
1194
|
-
|
|
1195
|
-
public async newBlockFilter(isSubscription: boolean): Promise<bigint> {
|
|
1196
|
-
const block = await this.getLatestBlock();
|
|
1197
|
-
|
|
1198
|
-
const filterId = this._getNextFilterId();
|
|
1199
|
-
this._filters.set(this._filterIdToFiltersKey(filterId), {
|
|
1200
|
-
id: filterId,
|
|
1201
|
-
type: Type.BLOCK_SUBSCRIPTION,
|
|
1202
|
-
deadline: this._newDeadline(),
|
|
1203
|
-
hashes: [bufferToHex(block.header.hash())],
|
|
1204
|
-
logs: [],
|
|
1205
|
-
subscription: isSubscription,
|
|
1206
|
-
});
|
|
1207
|
-
|
|
1208
|
-
return filterId;
|
|
1209
|
-
}
|
|
1210
|
-
|
|
1211
|
-
public async newPendingTransactionFilter(
|
|
1212
|
-
isSubscription: boolean
|
|
1213
|
-
): Promise<bigint> {
|
|
1214
|
-
const filterId = this._getNextFilterId();
|
|
1215
|
-
|
|
1216
|
-
this._filters.set(this._filterIdToFiltersKey(filterId), {
|
|
1217
|
-
id: filterId,
|
|
1218
|
-
type: Type.PENDING_TRANSACTION_SUBSCRIPTION,
|
|
1219
|
-
deadline: this._newDeadline(),
|
|
1220
|
-
hashes: [],
|
|
1221
|
-
logs: [],
|
|
1222
|
-
subscription: isSubscription,
|
|
1223
|
-
});
|
|
1224
|
-
|
|
1225
|
-
return filterId;
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1228
|
-
public async uninstallFilter(
|
|
1229
|
-
filterId: bigint,
|
|
1230
|
-
subscription: boolean
|
|
1231
|
-
): Promise<boolean> {
|
|
1232
|
-
const key = this._filterIdToFiltersKey(filterId);
|
|
1233
|
-
const filter = this._filters.get(key);
|
|
1234
|
-
|
|
1235
|
-
if (filter === undefined) {
|
|
1236
|
-
return false;
|
|
1237
|
-
}
|
|
1238
|
-
|
|
1239
|
-
if (
|
|
1240
|
-
(filter.subscription && !subscription) ||
|
|
1241
|
-
(!filter.subscription && subscription)
|
|
1242
|
-
) {
|
|
1243
|
-
return false;
|
|
1244
|
-
}
|
|
1245
|
-
|
|
1246
|
-
this._filters.delete(key);
|
|
1247
|
-
return true;
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
|
-
public async getFilterChanges(
|
|
1251
|
-
filterId: bigint
|
|
1252
|
-
): Promise<string[] | RpcLogOutput[] | undefined> {
|
|
1253
|
-
const key = this._filterIdToFiltersKey(filterId);
|
|
1254
|
-
const filter = this._filters.get(key);
|
|
1255
|
-
if (filter === undefined) {
|
|
1256
|
-
return undefined;
|
|
1257
|
-
}
|
|
1258
|
-
|
|
1259
|
-
filter.deadline = this._newDeadline();
|
|
1260
|
-
switch (filter.type) {
|
|
1261
|
-
case Type.BLOCK_SUBSCRIPTION:
|
|
1262
|
-
case Type.PENDING_TRANSACTION_SUBSCRIPTION:
|
|
1263
|
-
const hashes = filter.hashes;
|
|
1264
|
-
filter.hashes = [];
|
|
1265
|
-
return hashes;
|
|
1266
|
-
case Type.LOGS_SUBSCRIPTION:
|
|
1267
|
-
const logs = filter.logs;
|
|
1268
|
-
filter.logs = [];
|
|
1269
|
-
return logs;
|
|
1270
|
-
}
|
|
1271
|
-
|
|
1272
|
-
return undefined;
|
|
1273
|
-
}
|
|
1274
|
-
|
|
1275
|
-
public async getFilterLogs(
|
|
1276
|
-
filterId: bigint
|
|
1277
|
-
): Promise<RpcLogOutput[] | undefined> {
|
|
1278
|
-
const key = this._filterIdToFiltersKey(filterId);
|
|
1279
|
-
const filter = this._filters.get(key);
|
|
1280
|
-
if (filter === undefined) {
|
|
1281
|
-
return undefined;
|
|
1282
|
-
}
|
|
1283
|
-
|
|
1284
|
-
const logs = filter.logs;
|
|
1285
|
-
filter.logs = [];
|
|
1286
|
-
filter.deadline = this._newDeadline();
|
|
1287
|
-
return logs;
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
public async getLogs(filterParams: FilterParams): Promise<RpcLogOutput[]> {
|
|
1291
|
-
filterParams = await this._computeFilterParams(filterParams, false);
|
|
1292
|
-
return this._blockchain.getLogs(filterParams);
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
|
-
public async addCompilationResult(
|
|
1296
|
-
solcVersion: string,
|
|
1297
|
-
compilerInput: CompilerInput,
|
|
1298
|
-
compilerOutput: CompilerOutput
|
|
1299
|
-
): Promise<boolean> {
|
|
1300
|
-
let bytecodes;
|
|
1301
|
-
try {
|
|
1302
|
-
bytecodes = createModelsAndDecodeBytecodes(
|
|
1303
|
-
solcVersion,
|
|
1304
|
-
compilerInput,
|
|
1305
|
-
compilerOutput
|
|
1306
|
-
);
|
|
1307
|
-
} catch (error) {
|
|
1308
|
-
console.warn(
|
|
1309
|
-
chalk.yellow(
|
|
1310
|
-
"The Hardhat Network tracing engine could not be updated. Run Hardhat with --verbose to learn more."
|
|
1311
|
-
)
|
|
1312
|
-
);
|
|
1313
|
-
|
|
1314
|
-
log(
|
|
1315
|
-
"ContractsIdentifier failed to be updated. Please report this to help us improve Hardhat.\n",
|
|
1316
|
-
error
|
|
1317
|
-
);
|
|
1318
|
-
|
|
1319
|
-
return false;
|
|
1320
|
-
}
|
|
1321
|
-
|
|
1322
|
-
for (const bytecode of bytecodes) {
|
|
1323
|
-
this._vmTraceDecoder.addBytecode(bytecode);
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
return true;
|
|
1327
|
-
}
|
|
1328
|
-
|
|
1329
|
-
public addImpersonatedAccount(address: Buffer): true {
|
|
1330
|
-
this._impersonatedAccounts.add(bufferToHex(address));
|
|
1331
|
-
return true;
|
|
1332
|
-
}
|
|
1333
|
-
|
|
1334
|
-
public removeImpersonatedAccount(address: Buffer): boolean {
|
|
1335
|
-
return this._impersonatedAccounts.delete(bufferToHex(address));
|
|
1336
|
-
}
|
|
1337
|
-
|
|
1338
|
-
public setAutomine(automine: boolean) {
|
|
1339
|
-
this._automine = automine;
|
|
1340
|
-
}
|
|
1341
|
-
|
|
1342
|
-
public getAutomine() {
|
|
1343
|
-
return this._automine;
|
|
1344
|
-
}
|
|
1345
|
-
|
|
1346
|
-
public async setBlockGasLimit(gasLimit: bigint | number) {
|
|
1347
|
-
this._txPool.setBlockGasLimit(gasLimit);
|
|
1348
|
-
await this._txPool.updatePendingAndQueued();
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1351
|
-
public async setMinGasPrice(minGasPrice: bigint) {
|
|
1352
|
-
this._minGasPrice = minGasPrice;
|
|
1353
|
-
}
|
|
1354
|
-
|
|
1355
|
-
public async dropTransaction(hash: Buffer): Promise<boolean> {
|
|
1356
|
-
const removed = this._txPool.removeTransaction(hash);
|
|
1357
|
-
|
|
1358
|
-
if (removed) {
|
|
1359
|
-
return true;
|
|
1360
|
-
}
|
|
1361
|
-
|
|
1362
|
-
const isTransactionMined = await this._isTransactionMined(hash);
|
|
1363
|
-
if (isTransactionMined) {
|
|
1364
|
-
throw new InvalidArgumentsError(
|
|
1365
|
-
`Transaction ${bufferToHex(
|
|
1366
|
-
hash
|
|
1367
|
-
)} cannot be dropped because it's already mined`
|
|
1368
|
-
);
|
|
1369
|
-
}
|
|
1370
|
-
|
|
1371
|
-
return false;
|
|
1372
|
-
}
|
|
1373
|
-
|
|
1374
|
-
public async setAccountBalance(
|
|
1375
|
-
address: Address,
|
|
1376
|
-
newBalance: bigint
|
|
1377
|
-
): Promise<void> {
|
|
1378
|
-
const account = await this._stateManager.getAccount(address);
|
|
1379
|
-
|
|
1380
|
-
await this._stateManager.putAccount(
|
|
1381
|
-
address,
|
|
1382
|
-
Account.fromAccountData({
|
|
1383
|
-
nonce: account?.nonce,
|
|
1384
|
-
balance: newBalance,
|
|
1385
|
-
storageRoot: account?.storageRoot,
|
|
1386
|
-
codeHash: account?.codeHash,
|
|
1387
|
-
})
|
|
1388
|
-
);
|
|
1389
|
-
await this._persistIrregularWorldState();
|
|
1390
|
-
}
|
|
1391
|
-
|
|
1392
|
-
public async setAccountCode(
|
|
1393
|
-
address: Address,
|
|
1394
|
-
newCode: Buffer
|
|
1395
|
-
): Promise<void> {
|
|
1396
|
-
await this._stateManager.putContractCode(address, newCode);
|
|
1397
|
-
await this._persistIrregularWorldState();
|
|
1398
|
-
}
|
|
1399
|
-
|
|
1400
|
-
public async setNextConfirmedNonce(
|
|
1401
|
-
address: Address,
|
|
1402
|
-
newNonce: bigint
|
|
1403
|
-
): Promise<void> {
|
|
1404
|
-
if (!this._txPool.isEmpty()) {
|
|
1405
|
-
throw new InternalError(
|
|
1406
|
-
"Cannot set account nonce when the transaction pool is not empty"
|
|
1407
|
-
);
|
|
1408
|
-
}
|
|
1409
|
-
const account = await this._stateManager.getAccount(address);
|
|
1410
|
-
const accountNonce = account?.nonce ?? 0n;
|
|
1411
|
-
if (newNonce < accountNonce) {
|
|
1412
|
-
throw new InvalidInputError(
|
|
1413
|
-
`New nonce (${newNonce.toString()}) must not be smaller than the existing nonce (${accountNonce.toString()})`
|
|
1414
|
-
);
|
|
1415
|
-
}
|
|
1416
|
-
await this._stateManager.putAccount(
|
|
1417
|
-
address,
|
|
1418
|
-
Account.fromAccountData({
|
|
1419
|
-
nonce: newNonce,
|
|
1420
|
-
balance: account?.balance,
|
|
1421
|
-
storageRoot: account?.storageRoot,
|
|
1422
|
-
codeHash: account?.codeHash,
|
|
1423
|
-
})
|
|
1424
|
-
);
|
|
1425
|
-
await this._persistIrregularWorldState();
|
|
1426
|
-
}
|
|
1427
|
-
|
|
1428
|
-
public async setStorageAt(
|
|
1429
|
-
address: Address,
|
|
1430
|
-
positionIndex: bigint,
|
|
1431
|
-
value: Buffer
|
|
1432
|
-
) {
|
|
1433
|
-
await this._stateManager.putContractStorage(
|
|
1434
|
-
address,
|
|
1435
|
-
setLengthLeft(bigIntToBytes(positionIndex), 32),
|
|
1436
|
-
value
|
|
1437
|
-
);
|
|
1438
|
-
await this._persistIrregularWorldState();
|
|
1439
|
-
}
|
|
1440
|
-
|
|
1441
|
-
public async traceCall(
|
|
1442
|
-
callParams: CallParams,
|
|
1443
|
-
block: bigint | "pending",
|
|
1444
|
-
traceConfig: RpcDebugTracingConfig
|
|
1445
|
-
) {
|
|
1446
|
-
const vmDebugTracer = new VMDebugTracer(this._vm);
|
|
1447
|
-
|
|
1448
|
-
return vmDebugTracer.trace(async () => {
|
|
1449
|
-
await this.runCall(callParams, block);
|
|
1450
|
-
}, traceConfig);
|
|
1451
|
-
}
|
|
1452
|
-
|
|
1453
|
-
public async traceTransaction(hash: Buffer, config: RpcDebugTracingConfig) {
|
|
1454
|
-
const block = await this.getBlockByTransactionHash(hash);
|
|
1455
|
-
if (block === undefined) {
|
|
1456
|
-
throw new InvalidInputError(
|
|
1457
|
-
`Unable to find a block containing transaction ${bufferToHex(hash)}`
|
|
1458
|
-
);
|
|
1459
|
-
}
|
|
1460
|
-
|
|
1461
|
-
return this._runInBlockContext(block.header.number - 1n, async () => {
|
|
1462
|
-
const blockNumber = block.header.number;
|
|
1463
|
-
const blockchain = this._blockchain;
|
|
1464
|
-
let vm = this._vm;
|
|
1465
|
-
if (
|
|
1466
|
-
blockchain instanceof ForkBlockchain &&
|
|
1467
|
-
blockNumber <= blockchain.getForkBlockNumber()
|
|
1468
|
-
) {
|
|
1469
|
-
assertHardhatInvariant(
|
|
1470
|
-
this._forkNetworkId !== undefined,
|
|
1471
|
-
"this._forkNetworkId should exist if the blockchain is an instance of ForkBlockchain"
|
|
1472
|
-
);
|
|
1473
|
-
|
|
1474
|
-
const common = this._getCommonForTracing(
|
|
1475
|
-
this._forkNetworkId,
|
|
1476
|
-
blockNumber
|
|
1477
|
-
);
|
|
1478
|
-
|
|
1479
|
-
vm = await VM.create({
|
|
1480
|
-
common,
|
|
1481
|
-
activatePrecompiles: true,
|
|
1482
|
-
stateManager: this._vm.stateManager,
|
|
1483
|
-
blockchain: this._vm.blockchain,
|
|
1484
|
-
});
|
|
1485
|
-
}
|
|
1486
|
-
|
|
1487
|
-
// We don't support tracing transactions before the spuriousDragon fork
|
|
1488
|
-
// to avoid having to distinguish between empty and non-existing accounts.
|
|
1489
|
-
// We *could* do it during the non-forked mode, but for simplicity we just
|
|
1490
|
-
// don't support it at all.
|
|
1491
|
-
const isPreSpuriousDragon = !vm.common.gteHardfork("spuriousDragon");
|
|
1492
|
-
if (isPreSpuriousDragon) {
|
|
1493
|
-
throw new InvalidInputError(
|
|
1494
|
-
"Tracing is not supported for transactions using hardforks older than Spurious Dragon. "
|
|
1495
|
-
);
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
|
-
for (const tx of block.transactions) {
|
|
1499
|
-
let txWithCommon: TypedTransaction;
|
|
1500
|
-
const sender = tx.getSenderAddress();
|
|
1501
|
-
if (tx.type === 0) {
|
|
1502
|
-
txWithCommon = new FakeSenderTransaction(sender, tx, {
|
|
1503
|
-
common: vm.common,
|
|
1504
|
-
});
|
|
1505
|
-
} else if (tx.type === 1) {
|
|
1506
|
-
txWithCommon = new FakeSenderAccessListEIP2930Transaction(
|
|
1507
|
-
sender,
|
|
1508
|
-
tx,
|
|
1509
|
-
{ common: vm.common }
|
|
1510
|
-
);
|
|
1511
|
-
} else if (tx.type === 2) {
|
|
1512
|
-
txWithCommon = new FakeSenderEIP1559Transaction(
|
|
1513
|
-
sender,
|
|
1514
|
-
{ ...tx, gasPrice: undefined },
|
|
1515
|
-
{ common: vm.common }
|
|
1516
|
-
);
|
|
1517
|
-
} else {
|
|
1518
|
-
throw new InternalError(
|
|
1519
|
-
"Only legacy, EIP2930, and EIP1559 txs are supported"
|
|
1520
|
-
);
|
|
1521
|
-
}
|
|
1522
|
-
|
|
1523
|
-
const txHash = txWithCommon.hash();
|
|
1524
|
-
if (equalsBytes(txHash, hash)) {
|
|
1525
|
-
const vmDebugTracer = new VMDebugTracer(vm);
|
|
1526
|
-
return vmDebugTracer.trace(async () => {
|
|
1527
|
-
await vm.runTx({
|
|
1528
|
-
tx: txWithCommon,
|
|
1529
|
-
block,
|
|
1530
|
-
skipHardForkValidation: true,
|
|
1531
|
-
});
|
|
1532
|
-
}, config);
|
|
1533
|
-
}
|
|
1534
|
-
await vm.runTx({
|
|
1535
|
-
tx: txWithCommon,
|
|
1536
|
-
block,
|
|
1537
|
-
skipHardForkValidation: true,
|
|
1538
|
-
});
|
|
1539
|
-
}
|
|
1540
|
-
throw new TransactionExecutionError(
|
|
1541
|
-
`Unable to find a transaction in a block that contains that transaction, this should never happen`
|
|
1542
|
-
);
|
|
1543
|
-
});
|
|
1544
|
-
}
|
|
1545
|
-
|
|
1546
|
-
public async getFeeHistory(
|
|
1547
|
-
blockCount: bigint,
|
|
1548
|
-
newestBlock: bigint | "pending",
|
|
1549
|
-
rewardPercentiles: number[]
|
|
1550
|
-
): Promise<FeeHistory> {
|
|
1551
|
-
const latestBlock = this.getLatestBlockNumber();
|
|
1552
|
-
const pendingBlockNumber = latestBlock + 1n;
|
|
1553
|
-
|
|
1554
|
-
const resolvedNewestBlock =
|
|
1555
|
-
newestBlock === "pending" ? pendingBlockNumber : newestBlock;
|
|
1556
|
-
|
|
1557
|
-
const oldestBlock = BigIntUtils.max(
|
|
1558
|
-
resolvedNewestBlock - blockCount + 1n,
|
|
1559
|
-
0n
|
|
1560
|
-
);
|
|
1561
|
-
|
|
1562
|
-
// This is part of a temporary fix to https://github.com/NomicFoundation/hardhat/issues/2380
|
|
1563
|
-
const rangeIncludesRemoteBlocks =
|
|
1564
|
-
this._forkBlockNumber !== undefined &&
|
|
1565
|
-
oldestBlock <= this._forkBlockNumber;
|
|
1566
|
-
|
|
1567
|
-
const baseFeePerGas: bigint[] = [];
|
|
1568
|
-
const gasUsedRatio: number[] = [];
|
|
1569
|
-
const reward: bigint[][] = [];
|
|
1570
|
-
|
|
1571
|
-
const lastBlock = resolvedNewestBlock + 1n;
|
|
1572
|
-
|
|
1573
|
-
// This is part of a temporary fix to https://github.com/NomicFoundation/hardhat/issues/2380
|
|
1574
|
-
if (rangeIncludesRemoteBlocks) {
|
|
1575
|
-
try {
|
|
1576
|
-
const lastRemoteBlock = BigIntUtils.min(
|
|
1577
|
-
BigInt(this._forkBlockNumber!),
|
|
1578
|
-
lastBlock
|
|
1579
|
-
);
|
|
1580
|
-
|
|
1581
|
-
const remoteBlockCount = lastRemoteBlock - oldestBlock + 1n;
|
|
1582
|
-
|
|
1583
|
-
const remoteValues = await this._forkClient!.getFeeHistory(
|
|
1584
|
-
remoteBlockCount,
|
|
1585
|
-
lastRemoteBlock,
|
|
1586
|
-
rewardPercentiles
|
|
1587
|
-
);
|
|
1588
|
-
|
|
1589
|
-
baseFeePerGas.push(...remoteValues.baseFeePerGas);
|
|
1590
|
-
gasUsedRatio.push(...remoteValues.gasUsedRatio);
|
|
1591
|
-
if (remoteValues.reward !== undefined) {
|
|
1592
|
-
reward.push(...remoteValues.reward);
|
|
1593
|
-
}
|
|
1594
|
-
} catch (e) {
|
|
1595
|
-
// TODO: we can return less blocks here still be compliant with the spec
|
|
1596
|
-
throw new InternalError(
|
|
1597
|
-
"Remote node did not answer to eth_feeHistory correctly",
|
|
1598
|
-
e instanceof Error ? e : undefined
|
|
1599
|
-
);
|
|
1600
|
-
}
|
|
1601
|
-
}
|
|
1602
|
-
|
|
1603
|
-
// We get the pending block here, and only if necessary, as it's something
|
|
1604
|
-
// costly to do.
|
|
1605
|
-
let pendingBlock: Block | undefined;
|
|
1606
|
-
if (lastBlock >= pendingBlockNumber) {
|
|
1607
|
-
pendingBlock = await this.getBlockByNumber("pending");
|
|
1608
|
-
}
|
|
1609
|
-
|
|
1610
|
-
// This is part of a temporary fix to https://github.com/NomicFoundation/hardhat/issues/2380
|
|
1611
|
-
const firstLocalBlock = !rangeIncludesRemoteBlocks
|
|
1612
|
-
? oldestBlock
|
|
1613
|
-
: BigIntUtils.min(BigInt(this._forkBlockNumber!), lastBlock) + 1n;
|
|
1614
|
-
|
|
1615
|
-
for (
|
|
1616
|
-
let blockNumber = firstLocalBlock; // This is part of a temporary fix to https://github.com/NomicFoundation/hardhat/issues/2380
|
|
1617
|
-
blockNumber <= lastBlock;
|
|
1618
|
-
blockNumber++
|
|
1619
|
-
) {
|
|
1620
|
-
if (blockNumber < pendingBlockNumber) {
|
|
1621
|
-
// We know the block exists
|
|
1622
|
-
const block = (await this.getBlockByNumber(blockNumber))!;
|
|
1623
|
-
baseFeePerGas.push(block.header.baseFeePerGas ?? 0n);
|
|
1624
|
-
|
|
1625
|
-
if (blockNumber < lastBlock) {
|
|
1626
|
-
gasUsedRatio.push(this._getGasUsedRatio(block));
|
|
1627
|
-
|
|
1628
|
-
if (rewardPercentiles.length > 0) {
|
|
1629
|
-
reward.push(await this._getRewards(block, rewardPercentiles));
|
|
1630
|
-
}
|
|
1631
|
-
}
|
|
1632
|
-
} else if (blockNumber === pendingBlockNumber) {
|
|
1633
|
-
// This can only be run with EIP-1559, so this exists
|
|
1634
|
-
baseFeePerGas.push((await this.getNextBlockBaseFeePerGas())!);
|
|
1635
|
-
|
|
1636
|
-
if (blockNumber < lastBlock) {
|
|
1637
|
-
gasUsedRatio.push(this._getGasUsedRatio(pendingBlock!));
|
|
1638
|
-
|
|
1639
|
-
if (rewardPercentiles.length > 0) {
|
|
1640
|
-
// We don't compute this for the pending block, as there's no
|
|
1641
|
-
// effective miner fee yet.
|
|
1642
|
-
reward.push(rewardPercentiles.map((_) => 0n));
|
|
1643
|
-
}
|
|
1644
|
-
}
|
|
1645
|
-
} else if (blockNumber === pendingBlockNumber + 1n) {
|
|
1646
|
-
baseFeePerGas.push(pendingBlock!.header.calcNextBaseFee());
|
|
1647
|
-
} else {
|
|
1648
|
-
assertHardhatInvariant(false, "This should never happen");
|
|
1649
|
-
}
|
|
1650
|
-
}
|
|
1651
|
-
|
|
1652
|
-
return {
|
|
1653
|
-
oldestBlock,
|
|
1654
|
-
baseFeePerGas,
|
|
1655
|
-
gasUsedRatio,
|
|
1656
|
-
reward: rewardPercentiles.length > 0 ? reward : undefined,
|
|
1657
|
-
};
|
|
1658
|
-
}
|
|
1659
|
-
|
|
1660
|
-
public async setCoinbase(coinbase: Address) {
|
|
1661
|
-
this._coinbase = coinbase.toString();
|
|
1662
|
-
}
|
|
1663
|
-
|
|
1664
|
-
private _getGasUsedRatio(block: Block): number {
|
|
1665
|
-
const FLOATS_PRECISION = 100_000;
|
|
1666
|
-
|
|
1667
|
-
return (
|
|
1668
|
-
Number(
|
|
1669
|
-
(block.header.gasUsed * BigInt(FLOATS_PRECISION)) /
|
|
1670
|
-
block.header.gasLimit
|
|
1671
|
-
) / FLOATS_PRECISION
|
|
1672
|
-
);
|
|
1673
|
-
}
|
|
1674
|
-
|
|
1675
|
-
private async _getRewards(
|
|
1676
|
-
block: Block,
|
|
1677
|
-
rewardPercentiles: number[]
|
|
1678
|
-
): Promise<bigint[]> {
|
|
1679
|
-
const FLOATS_PRECISION = 100_000;
|
|
1680
|
-
|
|
1681
|
-
if (block.transactions.length === 0) {
|
|
1682
|
-
return rewardPercentiles.map((_) => 0n);
|
|
1683
|
-
}
|
|
1684
|
-
|
|
1685
|
-
const receipts = await Promise.all(
|
|
1686
|
-
block.transactions
|
|
1687
|
-
.map((tx) => tx.hash())
|
|
1688
|
-
.map((hash) => this.getTransactionReceipt(hash))
|
|
1689
|
-
);
|
|
1690
|
-
|
|
1691
|
-
const effectiveGasRewardAndGas = receipts
|
|
1692
|
-
.map((r, i) => {
|
|
1693
|
-
const tx = block.transactions[i];
|
|
1694
|
-
const baseFeePerGas = block.header.baseFeePerGas ?? 0n;
|
|
1695
|
-
|
|
1696
|
-
// reward = min(maxPriorityFeePerGas, maxFeePerGas - baseFeePerGas)
|
|
1697
|
-
let effectiveGasReward: bigint;
|
|
1698
|
-
if ("maxPriorityFeePerGas" in tx) {
|
|
1699
|
-
effectiveGasReward = tx.maxFeePerGas - baseFeePerGas;
|
|
1700
|
-
if (tx.maxPriorityFeePerGas < effectiveGasReward) {
|
|
1701
|
-
effectiveGasReward = tx.maxPriorityFeePerGas;
|
|
1702
|
-
}
|
|
1703
|
-
} else {
|
|
1704
|
-
effectiveGasReward = tx.gasPrice - baseFeePerGas;
|
|
1705
|
-
}
|
|
1706
|
-
|
|
1707
|
-
return {
|
|
1708
|
-
effectiveGasReward,
|
|
1709
|
-
gasUsed: rpcQuantityToBigInt(r?.gasUsed!),
|
|
1710
|
-
};
|
|
1711
|
-
})
|
|
1712
|
-
.sort((a, b) =>
|
|
1713
|
-
BigIntUtils.cmp(a.effectiveGasReward, b.effectiveGasReward)
|
|
1714
|
-
);
|
|
1715
|
-
|
|
1716
|
-
return rewardPercentiles.map((p) => {
|
|
1717
|
-
let gasUsed = 0n;
|
|
1718
|
-
const targetGas =
|
|
1719
|
-
(block.header.gasLimit * BigInt(Math.ceil(p * FLOATS_PRECISION))) /
|
|
1720
|
-
BigInt(100 * FLOATS_PRECISION);
|
|
1721
|
-
|
|
1722
|
-
for (const values of effectiveGasRewardAndGas) {
|
|
1723
|
-
gasUsed += values.gasUsed;
|
|
1724
|
-
|
|
1725
|
-
if (targetGas <= gasUsed) {
|
|
1726
|
-
return values.effectiveGasReward;
|
|
1727
|
-
}
|
|
1728
|
-
}
|
|
1729
|
-
|
|
1730
|
-
return effectiveGasRewardAndGas[effectiveGasRewardAndGas.length - 1]
|
|
1731
|
-
.effectiveGasReward;
|
|
1732
|
-
});
|
|
1733
|
-
}
|
|
1734
|
-
|
|
1735
|
-
private async _addPendingTransaction(tx: TypedTransaction): Promise<string> {
|
|
1736
|
-
await this._txPool.addTransaction(tx);
|
|
1737
|
-
await this._notifyPendingTransaction(tx);
|
|
1738
|
-
return bufferToHex(tx.hash());
|
|
1739
|
-
}
|
|
1740
|
-
|
|
1741
|
-
private async _mineTransaction(
|
|
1742
|
-
tx: TypedTransaction
|
|
1743
|
-
): Promise<MineBlockResult> {
|
|
1744
|
-
await this._addPendingTransaction(tx);
|
|
1745
|
-
return this.mineBlock();
|
|
1746
|
-
}
|
|
1747
|
-
|
|
1748
|
-
private async _mineTransactionAndPending(
|
|
1749
|
-
tx: TypedTransaction
|
|
1750
|
-
): Promise<MineBlockResult[]> {
|
|
1751
|
-
const snapshotId = await this.takeSnapshot();
|
|
1752
|
-
|
|
1753
|
-
let result;
|
|
1754
|
-
try {
|
|
1755
|
-
const txHash = await this._addPendingTransaction(tx);
|
|
1756
|
-
result = await this._mineBlocksUntilTransactionIsIncluded(txHash);
|
|
1757
|
-
} catch (err) {
|
|
1758
|
-
await this.revertToSnapshot(snapshotId);
|
|
1759
|
-
throw err;
|
|
1760
|
-
}
|
|
1761
|
-
|
|
1762
|
-
this._removeSnapshot(snapshotId);
|
|
1763
|
-
return result;
|
|
1764
|
-
}
|
|
1765
|
-
|
|
1766
|
-
private async _mineBlocksUntilTransactionIsIncluded(
|
|
1767
|
-
txHash: string
|
|
1768
|
-
): Promise<MineBlockResult[]> {
|
|
1769
|
-
const results = [];
|
|
1770
|
-
let txReceipt;
|
|
1771
|
-
do {
|
|
1772
|
-
if (!this._txPool.hasPendingTransactions()) {
|
|
1773
|
-
throw new TransactionExecutionError(
|
|
1774
|
-
"Failed to mine transaction for unknown reason, this should never happen"
|
|
1775
|
-
);
|
|
1776
|
-
}
|
|
1777
|
-
results.push(await this.mineBlock());
|
|
1778
|
-
txReceipt = await this.getTransactionReceipt(txHash);
|
|
1779
|
-
} while (txReceipt === undefined);
|
|
1780
|
-
|
|
1781
|
-
while (this._txPool.hasPendingTransactions()) {
|
|
1782
|
-
results.push(await this.mineBlock());
|
|
1783
|
-
}
|
|
1784
|
-
|
|
1785
|
-
return results;
|
|
1786
|
-
}
|
|
1787
|
-
|
|
1788
|
-
private async _gatherTraces(result: ExecResult): Promise<GatherTracesResult> {
|
|
1789
|
-
let vmTrace = this._vmTracer.getLastTopLevelMessageTrace();
|
|
1790
|
-
const vmTracerError = this._vmTracer.getLastError();
|
|
1791
|
-
this._vmTracer.clearLastError();
|
|
1792
|
-
|
|
1793
|
-
if (vmTrace !== undefined) {
|
|
1794
|
-
vmTrace = this._vmTraceDecoder.tryToDecodeMessageTrace(vmTrace);
|
|
1795
|
-
}
|
|
1796
|
-
|
|
1797
|
-
const consoleLogMessages = await this._getConsoleLogMessages(
|
|
1798
|
-
vmTrace,
|
|
1799
|
-
vmTracerError
|
|
1800
|
-
);
|
|
1801
|
-
|
|
1802
|
-
const error = await this._manageErrors(result, vmTrace, vmTracerError);
|
|
1803
|
-
|
|
1804
|
-
return {
|
|
1805
|
-
trace: vmTrace,
|
|
1806
|
-
consoleLogMessages,
|
|
1807
|
-
error,
|
|
1808
|
-
};
|
|
1809
|
-
}
|
|
1810
|
-
|
|
1811
|
-
private async _validateAutominedTx(tx: TypedTransaction) {
|
|
1812
|
-
let sender: Address;
|
|
1813
|
-
try {
|
|
1814
|
-
sender = tx.getSenderAddress(); // verifies signature as a side effect
|
|
1815
|
-
} catch (e) {
|
|
1816
|
-
if (e instanceof Error) {
|
|
1817
|
-
throw new InvalidInputError(e.message);
|
|
1818
|
-
}
|
|
1819
|
-
|
|
1820
|
-
// eslint-disable-next-line @nomicfoundation/hardhat-internal-rules/only-hardhat-error
|
|
1821
|
-
throw e;
|
|
1822
|
-
}
|
|
1823
|
-
|
|
1824
|
-
// validate nonce
|
|
1825
|
-
const nextPendingNonce = await this._txPool.getNextPendingNonce(sender);
|
|
1826
|
-
const txNonce = tx.nonce;
|
|
1827
|
-
|
|
1828
|
-
const expectedNonceMsg = `Expected nonce to be ${nextPendingNonce.toString()} but got ${txNonce.toString()}.`;
|
|
1829
|
-
if (txNonce > nextPendingNonce) {
|
|
1830
|
-
throw new InvalidInputError(
|
|
1831
|
-
`Nonce too high. ${expectedNonceMsg} Note that transactions can't be queued when automining.`
|
|
1832
|
-
);
|
|
1833
|
-
}
|
|
1834
|
-
if (txNonce < nextPendingNonce) {
|
|
1835
|
-
throw new InvalidInputError(`Nonce too low. ${expectedNonceMsg}`);
|
|
1836
|
-
}
|
|
1837
|
-
|
|
1838
|
-
// validate gas price
|
|
1839
|
-
const txPriorityFee =
|
|
1840
|
-
"gasPrice" in tx ? tx.gasPrice : tx.maxPriorityFeePerGas;
|
|
1841
|
-
if (txPriorityFee < this._minGasPrice) {
|
|
1842
|
-
throw new InvalidInputError(
|
|
1843
|
-
`Transaction gas price is ${txPriorityFee.toString()}, which is below the minimum of ${this._minGasPrice.toString()}`
|
|
1844
|
-
);
|
|
1845
|
-
}
|
|
1846
|
-
|
|
1847
|
-
// Validate that maxFeePerGas >= next block's baseFee
|
|
1848
|
-
const nextBlockGasFee = await this.getNextBlockBaseFeePerGas();
|
|
1849
|
-
if (nextBlockGasFee !== undefined) {
|
|
1850
|
-
if ("maxFeePerGas" in tx) {
|
|
1851
|
-
if (nextBlockGasFee > tx.maxFeePerGas) {
|
|
1852
|
-
throw new InvalidInputError(
|
|
1853
|
-
`Transaction maxFeePerGas (${tx.maxFeePerGas.toString()}) is too low for the next block, which has a baseFeePerGas of ${nextBlockGasFee.toString()}`
|
|
1854
|
-
);
|
|
1855
|
-
}
|
|
1856
|
-
} else {
|
|
1857
|
-
if (nextBlockGasFee > tx.gasPrice) {
|
|
1858
|
-
throw new InvalidInputError(
|
|
1859
|
-
`Transaction gasPrice (${tx.gasPrice.toString()}) is too low for the next block, which has a baseFeePerGas of ${nextBlockGasFee.toString()}`
|
|
1860
|
-
);
|
|
1861
|
-
}
|
|
1862
|
-
}
|
|
1863
|
-
}
|
|
1864
|
-
}
|
|
1865
|
-
|
|
1866
|
-
/**
|
|
1867
|
-
* Mines a new block with as many pending txs as possible, adding it to
|
|
1868
|
-
* the VM's blockchain.
|
|
1869
|
-
*
|
|
1870
|
-
* This method reverts any modification to the state manager if it throws.
|
|
1871
|
-
*/
|
|
1872
|
-
private async _mineBlockWithPendingTxs(
|
|
1873
|
-
blockTimestamp: bigint
|
|
1874
|
-
): Promise<MineBlockResult> {
|
|
1875
|
-
const parentBlock = await this.getLatestBlock();
|
|
1876
|
-
|
|
1877
|
-
const headerData: HeaderData = {
|
|
1878
|
-
gasLimit: this.getBlockGasLimit(),
|
|
1879
|
-
coinbase: this.getCoinbaseAddress(),
|
|
1880
|
-
nonce: this.isPostMergeHardfork()
|
|
1881
|
-
? "0x0000000000000000"
|
|
1882
|
-
: "0x0000000000000042",
|
|
1883
|
-
timestamp: blockTimestamp,
|
|
1884
|
-
};
|
|
1885
|
-
|
|
1886
|
-
if (this.isPostMergeHardfork()) {
|
|
1887
|
-
headerData.mixHash = this._getNextMixHash();
|
|
1888
|
-
}
|
|
1889
|
-
|
|
1890
|
-
if (this.isPostCancunHardfork()) {
|
|
1891
|
-
headerData.parentBeaconBlockRoot = this._getNextParentBeaconBlockRoot();
|
|
1892
|
-
}
|
|
1893
|
-
|
|
1894
|
-
headerData.baseFeePerGas = await this.getNextBlockBaseFeePerGas();
|
|
1895
|
-
|
|
1896
|
-
const blockBuilder = await this._vm.buildBlock({
|
|
1897
|
-
parentBlock,
|
|
1898
|
-
headerData,
|
|
1899
|
-
blockOpts: { calcDifficultyFromHeader: parentBlock.header },
|
|
1900
|
-
});
|
|
1901
|
-
|
|
1902
|
-
try {
|
|
1903
|
-
const traces: GatherTracesResult[] = [];
|
|
1904
|
-
|
|
1905
|
-
const blockGasLimit = this.getBlockGasLimit();
|
|
1906
|
-
const minTxFee = this._getMinimalTransactionFee();
|
|
1907
|
-
const pendingTxs = this._txPool.getPendingTransactions();
|
|
1908
|
-
const transactionQueue = new TransactionQueue(
|
|
1909
|
-
pendingTxs,
|
|
1910
|
-
this._mempoolOrder,
|
|
1911
|
-
headerData.baseFeePerGas
|
|
1912
|
-
);
|
|
1913
|
-
|
|
1914
|
-
let tx = transactionQueue.getNextTransaction();
|
|
1915
|
-
|
|
1916
|
-
const results = [];
|
|
1917
|
-
const receipts = [];
|
|
1918
|
-
|
|
1919
|
-
while (
|
|
1920
|
-
blockGasLimit - blockBuilder.gasUsed >= minTxFee &&
|
|
1921
|
-
tx !== undefined
|
|
1922
|
-
) {
|
|
1923
|
-
if (
|
|
1924
|
-
!this._isTxMinable(tx, headerData.baseFeePerGas) ||
|
|
1925
|
-
tx.gasLimit > blockGasLimit - blockBuilder.gasUsed
|
|
1926
|
-
) {
|
|
1927
|
-
transactionQueue.removeLastSenderTransactions();
|
|
1928
|
-
} else {
|
|
1929
|
-
const txResult = await blockBuilder.addTransaction(tx);
|
|
1930
|
-
|
|
1931
|
-
traces.push(await this._gatherTraces(txResult.execResult));
|
|
1932
|
-
results.push(txResult);
|
|
1933
|
-
receipts.push(txResult.receipt);
|
|
1934
|
-
}
|
|
1935
|
-
|
|
1936
|
-
tx = transactionQueue.getNextTransaction();
|
|
1937
|
-
}
|
|
1938
|
-
|
|
1939
|
-
const block = await blockBuilder.build();
|
|
1940
|
-
|
|
1941
|
-
await this._txPool.updatePendingAndQueued();
|
|
1942
|
-
|
|
1943
|
-
return {
|
|
1944
|
-
block,
|
|
1945
|
-
blockResult: {
|
|
1946
|
-
results,
|
|
1947
|
-
receipts,
|
|
1948
|
-
stateRoot: block.header.stateRoot,
|
|
1949
|
-
logsBloom: block.header.logsBloom,
|
|
1950
|
-
receiptsRoot: block.header.receiptTrie,
|
|
1951
|
-
gasUsed: block.header.gasUsed,
|
|
1952
|
-
},
|
|
1953
|
-
traces,
|
|
1954
|
-
};
|
|
1955
|
-
} catch (err) {
|
|
1956
|
-
await blockBuilder.revert();
|
|
1957
|
-
throw err;
|
|
1958
|
-
}
|
|
1959
|
-
}
|
|
1960
|
-
|
|
1961
|
-
private _getMinimalTransactionFee(): bigint {
|
|
1962
|
-
// Typically 21_000 gas
|
|
1963
|
-
return this._vm.common.param("gasPrices", "tx");
|
|
1964
|
-
}
|
|
1965
|
-
|
|
1966
|
-
private async _getFakeTransaction(
|
|
1967
|
-
txParams: TransactionParams
|
|
1968
|
-
): Promise<
|
|
1969
|
-
| FakeSenderTransaction
|
|
1970
|
-
| FakeSenderAccessListEIP2930Transaction
|
|
1971
|
-
| FakeSenderEIP1559Transaction
|
|
1972
|
-
> {
|
|
1973
|
-
const sender = new Address(txParams.from);
|
|
1974
|
-
|
|
1975
|
-
if ("maxFeePerGas" in txParams && txParams.maxFeePerGas !== undefined) {
|
|
1976
|
-
return new FakeSenderEIP1559Transaction(sender, txParams, {
|
|
1977
|
-
common: this._vm.common,
|
|
1978
|
-
});
|
|
1979
|
-
}
|
|
1980
|
-
|
|
1981
|
-
if ("accessList" in txParams && txParams.accessList !== undefined) {
|
|
1982
|
-
return new FakeSenderAccessListEIP2930Transaction(sender, txParams, {
|
|
1983
|
-
common: this._vm.common,
|
|
1984
|
-
});
|
|
1985
|
-
}
|
|
1986
|
-
|
|
1987
|
-
return new FakeSenderTransaction(sender, txParams, {
|
|
1988
|
-
common: this._vm.common,
|
|
1989
|
-
});
|
|
1990
|
-
}
|
|
1991
|
-
|
|
1992
|
-
private _getSnapshotIndex(id: number): number | undefined {
|
|
1993
|
-
for (const [i, snapshot] of this._snapshots.entries()) {
|
|
1994
|
-
if (snapshot.id === id) {
|
|
1995
|
-
return i;
|
|
1996
|
-
}
|
|
1997
|
-
|
|
1998
|
-
// We already removed the snapshot we are looking for
|
|
1999
|
-
if (snapshot.id > id) {
|
|
2000
|
-
return undefined;
|
|
2001
|
-
}
|
|
2002
|
-
}
|
|
2003
|
-
|
|
2004
|
-
return undefined;
|
|
2005
|
-
}
|
|
2006
|
-
|
|
2007
|
-
private _removeSnapshot(id: number) {
|
|
2008
|
-
const snapshotIndex = this._getSnapshotIndex(id);
|
|
2009
|
-
if (snapshotIndex === undefined) {
|
|
2010
|
-
return;
|
|
2011
|
-
}
|
|
2012
|
-
this._snapshots.splice(snapshotIndex);
|
|
2013
|
-
}
|
|
2014
|
-
|
|
2015
|
-
private _initLocalAccounts(genesisAccounts: GenesisAccount[]) {
|
|
2016
|
-
const privateKeys = genesisAccounts.map((acc) => toBytes(acc.privateKey));
|
|
2017
|
-
for (const pk of privateKeys) {
|
|
2018
|
-
this._localAccounts.set(bufferToHex(privateToAddress(pk)), pk);
|
|
2019
|
-
}
|
|
2020
|
-
}
|
|
2021
|
-
|
|
2022
|
-
private async _getConsoleLogMessages(
|
|
2023
|
-
vmTrace: MessageTrace | undefined,
|
|
2024
|
-
vmTracerError: Error | undefined
|
|
2025
|
-
): Promise<string[]> {
|
|
2026
|
-
if (vmTrace === undefined || vmTracerError !== undefined) {
|
|
2027
|
-
log(
|
|
2028
|
-
"Could not print console log. Please report this to help us improve Hardhat.\n",
|
|
2029
|
-
vmTracerError
|
|
2030
|
-
);
|
|
2031
|
-
|
|
2032
|
-
return [];
|
|
2033
|
-
}
|
|
2034
|
-
|
|
2035
|
-
return this._consoleLogger.getLogMessages(vmTrace);
|
|
2036
|
-
}
|
|
2037
|
-
|
|
2038
|
-
private async _manageErrors(
|
|
2039
|
-
vmResult: ExecResult,
|
|
2040
|
-
vmTrace: MessageTrace | undefined,
|
|
2041
|
-
vmTracerError: Error | undefined
|
|
2042
|
-
): Promise<SolidityError | TransactionExecutionError | undefined> {
|
|
2043
|
-
if (vmResult.exceptionError === undefined) {
|
|
2044
|
-
return undefined;
|
|
2045
|
-
}
|
|
2046
|
-
|
|
2047
|
-
let stackTrace: SolidityStackTrace | undefined;
|
|
2048
|
-
|
|
2049
|
-
try {
|
|
2050
|
-
if (vmTrace === undefined || vmTracerError !== undefined) {
|
|
2051
|
-
throw vmTracerError;
|
|
2052
|
-
}
|
|
2053
|
-
|
|
2054
|
-
stackTrace = this._solidityTracer.getStackTrace(vmTrace);
|
|
2055
|
-
} catch (err) {
|
|
2056
|
-
this._failedStackTraces += 1;
|
|
2057
|
-
log(
|
|
2058
|
-
"Could not generate stack trace. Please report this to help us improve Hardhat.\n",
|
|
2059
|
-
err
|
|
2060
|
-
);
|
|
2061
|
-
}
|
|
2062
|
-
|
|
2063
|
-
const error = vmResult.exceptionError;
|
|
2064
|
-
|
|
2065
|
-
// we don't use `instanceof` in case someone uses a different VM dependency
|
|
2066
|
-
// see https://github.com/nomiclabs/hardhat/issues/1317
|
|
2067
|
-
const isVmError = "error" in error && typeof error.error === "string";
|
|
2068
|
-
|
|
2069
|
-
// If this is not a VM error, or if it's an internal VM error, we just
|
|
2070
|
-
// rethrow. An example of a non-VmError being thrown here is an HTTP error
|
|
2071
|
-
// coming from the ForkedStateManager.
|
|
2072
|
-
if (!isVmError || error.error === ERROR.INTERNAL_ERROR) {
|
|
2073
|
-
throw error;
|
|
2074
|
-
}
|
|
2075
|
-
|
|
2076
|
-
if (error.error === ERROR.CODESIZE_EXCEEDS_MAXIMUM) {
|
|
2077
|
-
if (stackTrace !== undefined) {
|
|
2078
|
-
return encodeSolidityStackTrace(
|
|
2079
|
-
"Transaction ran out of gas",
|
|
2080
|
-
stackTrace
|
|
2081
|
-
);
|
|
2082
|
-
}
|
|
2083
|
-
|
|
2084
|
-
return new TransactionExecutionError("Transaction ran out of gas");
|
|
2085
|
-
}
|
|
2086
|
-
|
|
2087
|
-
if (error.error === ERROR.OUT_OF_GAS) {
|
|
2088
|
-
// if the error is an out of gas, we ignore the inferred error in the
|
|
2089
|
-
// trace
|
|
2090
|
-
return new TransactionExecutionError("Transaction ran out of gas");
|
|
2091
|
-
}
|
|
2092
|
-
|
|
2093
|
-
const returnData = new ReturnData(vmResult.returnValue);
|
|
2094
|
-
|
|
2095
|
-
let returnDataExplanation;
|
|
2096
|
-
if (returnData.isEmpty()) {
|
|
2097
|
-
returnDataExplanation = "without reason string";
|
|
2098
|
-
} else if (returnData.isErrorReturnData()) {
|
|
2099
|
-
returnDataExplanation = `with reason "${returnData.decodeError()}"`;
|
|
2100
|
-
} else if (returnData.isPanicReturnData()) {
|
|
2101
|
-
const panicCode = returnData.decodePanic().toString(16);
|
|
2102
|
-
returnDataExplanation = `with panic code "0x${panicCode}"`;
|
|
2103
|
-
} else {
|
|
2104
|
-
returnDataExplanation = "with unrecognized return data or custom error";
|
|
2105
|
-
}
|
|
2106
|
-
|
|
2107
|
-
if (error.error === ERROR.REVERT) {
|
|
2108
|
-
const fallbackMessage = `VM Exception while processing transaction: revert ${returnDataExplanation}`;
|
|
2109
|
-
|
|
2110
|
-
if (stackTrace !== undefined) {
|
|
2111
|
-
return encodeSolidityStackTrace(fallbackMessage, stackTrace);
|
|
2112
|
-
}
|
|
2113
|
-
|
|
2114
|
-
return new TransactionExecutionError(fallbackMessage);
|
|
2115
|
-
}
|
|
2116
|
-
|
|
2117
|
-
if (stackTrace !== undefined) {
|
|
2118
|
-
return encodeSolidityStackTrace(
|
|
2119
|
-
`Transaction failed: revert ${returnDataExplanation}`,
|
|
2120
|
-
stackTrace
|
|
2121
|
-
);
|
|
2122
|
-
}
|
|
2123
|
-
|
|
2124
|
-
return new TransactionExecutionError(
|
|
2125
|
-
`Transaction reverted ${returnDataExplanation}`
|
|
2126
|
-
);
|
|
2127
|
-
}
|
|
2128
|
-
|
|
2129
|
-
private _calculateTimestampAndOffset(
|
|
2130
|
-
timestamp?: bigint
|
|
2131
|
-
): [bigint, boolean, bigint] {
|
|
2132
|
-
let blockTimestamp: bigint;
|
|
2133
|
-
let offsetShouldChange: boolean;
|
|
2134
|
-
let newOffset: bigint = 0n;
|
|
2135
|
-
const currentTimestamp = BigInt(getCurrentTimestamp());
|
|
2136
|
-
|
|
2137
|
-
// if timestamp is not provided, we check nextBlockTimestamp, if it is
|
|
2138
|
-
// set, we use it as the timestamp instead. If it is not set, we use
|
|
2139
|
-
// time offset + real time as the timestamp.
|
|
2140
|
-
if (timestamp === undefined || timestamp === 0n) {
|
|
2141
|
-
if (this.getNextBlockTimestamp() === 0n) {
|
|
2142
|
-
blockTimestamp = currentTimestamp + this.getTimeIncrement();
|
|
2143
|
-
offsetShouldChange = false;
|
|
2144
|
-
} else {
|
|
2145
|
-
blockTimestamp = this.getNextBlockTimestamp();
|
|
2146
|
-
offsetShouldChange = true;
|
|
2147
|
-
}
|
|
2148
|
-
} else {
|
|
2149
|
-
offsetShouldChange = true;
|
|
2150
|
-
blockTimestamp = timestamp;
|
|
2151
|
-
}
|
|
2152
|
-
|
|
2153
|
-
if (offsetShouldChange) {
|
|
2154
|
-
newOffset = blockTimestamp - currentTimestamp;
|
|
2155
|
-
}
|
|
2156
|
-
|
|
2157
|
-
return [blockTimestamp, offsetShouldChange, newOffset];
|
|
2158
|
-
}
|
|
2159
|
-
|
|
2160
|
-
private _resetNextBlockTimestamp() {
|
|
2161
|
-
this.setNextBlockTimestamp(0n);
|
|
2162
|
-
}
|
|
2163
|
-
|
|
2164
|
-
private async _notifyPendingTransaction(tx: TypedTransaction) {
|
|
2165
|
-
this._filters.forEach((filter) => {
|
|
2166
|
-
if (filter.type === Type.PENDING_TRANSACTION_SUBSCRIPTION) {
|
|
2167
|
-
const hash = bufferToHex(tx.hash());
|
|
2168
|
-
if (filter.subscription) {
|
|
2169
|
-
this._emitEthEvent(filter.id, hash);
|
|
2170
|
-
return;
|
|
2171
|
-
}
|
|
2172
|
-
|
|
2173
|
-
filter.hashes.push(hash);
|
|
2174
|
-
}
|
|
2175
|
-
});
|
|
2176
|
-
}
|
|
2177
|
-
|
|
2178
|
-
private _getLocalAccountPrivateKey(sender: Address): Uint8Array {
|
|
2179
|
-
const senderAddress = sender.toString();
|
|
2180
|
-
if (!this._localAccounts.has(senderAddress)) {
|
|
2181
|
-
throw new InvalidInputError(`unknown account ${senderAddress}`);
|
|
2182
|
-
}
|
|
2183
|
-
|
|
2184
|
-
return this._localAccounts.get(senderAddress)!;
|
|
2185
|
-
}
|
|
2186
|
-
|
|
2187
|
-
/**
|
|
2188
|
-
* Saves a block as successfully run. This method requires that the block
|
|
2189
|
-
* was added to the blockchain.
|
|
2190
|
-
*/
|
|
2191
|
-
private async _saveBlockAsSuccessfullyRun(
|
|
2192
|
-
block: Block,
|
|
2193
|
-
runBlockResult: RunBlockResult
|
|
2194
|
-
) {
|
|
2195
|
-
const receipts = getRpcReceiptOutputsFromLocalBlockExecution(
|
|
2196
|
-
block,
|
|
2197
|
-
runBlockResult,
|
|
2198
|
-
shouldShowTransactionTypeForHardfork(this._vm.common)
|
|
2199
|
-
);
|
|
2200
|
-
|
|
2201
|
-
this._blockchain.addTransactionReceipts(receipts);
|
|
2202
|
-
|
|
2203
|
-
const td = await this.getBlockTotalDifficulty(block);
|
|
2204
|
-
const rpcLogs: RpcLogOutput[] = [];
|
|
2205
|
-
for (const receipt of receipts) {
|
|
2206
|
-
rpcLogs.push(...receipt.logs);
|
|
2207
|
-
}
|
|
2208
|
-
|
|
2209
|
-
this._filters.forEach((filter, key) => {
|
|
2210
|
-
if (filter.deadline.valueOf() < new Date().valueOf()) {
|
|
2211
|
-
this._filters.delete(key);
|
|
2212
|
-
}
|
|
2213
|
-
|
|
2214
|
-
switch (filter.type) {
|
|
2215
|
-
case Type.BLOCK_SUBSCRIPTION:
|
|
2216
|
-
const hash = block.hash();
|
|
2217
|
-
if (filter.subscription) {
|
|
2218
|
-
this._emitEthEvent(
|
|
2219
|
-
filter.id,
|
|
2220
|
-
getRpcBlock(
|
|
2221
|
-
block,
|
|
2222
|
-
td,
|
|
2223
|
-
shouldShowTransactionTypeForHardfork(this._vm.common),
|
|
2224
|
-
false
|
|
2225
|
-
)
|
|
2226
|
-
);
|
|
2227
|
-
return;
|
|
2228
|
-
}
|
|
2229
|
-
|
|
2230
|
-
filter.hashes.push(bufferToHex(hash));
|
|
2231
|
-
break;
|
|
2232
|
-
case Type.LOGS_SUBSCRIPTION:
|
|
2233
|
-
if (
|
|
2234
|
-
bloomFilter(
|
|
2235
|
-
new Bloom(block.header.logsBloom),
|
|
2236
|
-
filter.criteria!.addresses,
|
|
2237
|
-
filter.criteria!.normalizedTopics
|
|
2238
|
-
)
|
|
2239
|
-
) {
|
|
2240
|
-
const logs = filterLogs(rpcLogs, filter.criteria!);
|
|
2241
|
-
if (logs.length === 0) {
|
|
2242
|
-
return;
|
|
2243
|
-
}
|
|
2244
|
-
|
|
2245
|
-
if (filter.subscription) {
|
|
2246
|
-
logs.forEach((rpcLog) => {
|
|
2247
|
-
this._emitEthEvent(filter.id, rpcLog);
|
|
2248
|
-
});
|
|
2249
|
-
return;
|
|
2250
|
-
}
|
|
2251
|
-
|
|
2252
|
-
filter.logs.push(...logs);
|
|
2253
|
-
}
|
|
2254
|
-
break;
|
|
2255
|
-
}
|
|
2256
|
-
});
|
|
2257
|
-
}
|
|
2258
|
-
|
|
2259
|
-
private async _timestampClashesWithPreviousBlockOne(
|
|
2260
|
-
blockTimestamp: bigint
|
|
2261
|
-
): Promise<boolean> {
|
|
2262
|
-
const latestBlock = await this.getLatestBlock();
|
|
2263
|
-
const latestBlockTimestamp = latestBlock.header.timestamp;
|
|
2264
|
-
|
|
2265
|
-
return latestBlockTimestamp === blockTimestamp;
|
|
2266
|
-
}
|
|
2267
|
-
|
|
2268
|
-
private async _runInBlockContext<T>(
|
|
2269
|
-
blockNumberOrPending: bigint | "pending",
|
|
2270
|
-
action: () => Promise<T>
|
|
2271
|
-
): Promise<T> {
|
|
2272
|
-
if (blockNumberOrPending === "pending") {
|
|
2273
|
-
return this._runInPendingBlockContext(action);
|
|
2274
|
-
}
|
|
2275
|
-
|
|
2276
|
-
if (blockNumberOrPending === this.getLatestBlockNumber()) {
|
|
2277
|
-
return action();
|
|
2278
|
-
}
|
|
2279
|
-
|
|
2280
|
-
const block = await this.getBlockByNumber(blockNumberOrPending);
|
|
2281
|
-
if (block === undefined) {
|
|
2282
|
-
// TODO handle this better
|
|
2283
|
-
throw new Error(
|
|
2284
|
-
`Block with number ${blockNumberOrPending.toString()} doesn't exist. This should never happen.`
|
|
2285
|
-
);
|
|
2286
|
-
}
|
|
2287
|
-
|
|
2288
|
-
const currentStateRoot = await this._stateManager.getStateRoot();
|
|
2289
|
-
await this._setBlockContext(block);
|
|
2290
|
-
try {
|
|
2291
|
-
return await action();
|
|
2292
|
-
} finally {
|
|
2293
|
-
await this._restoreBlockContext(currentStateRoot);
|
|
2294
|
-
}
|
|
2295
|
-
}
|
|
2296
|
-
|
|
2297
|
-
private async _runInPendingBlockContext<T>(action: () => Promise<T>) {
|
|
2298
|
-
const snapshotId = await this.takeSnapshot();
|
|
2299
|
-
try {
|
|
2300
|
-
await this.mineBlock();
|
|
2301
|
-
return await action();
|
|
2302
|
-
} finally {
|
|
2303
|
-
await this.revertToSnapshot(snapshotId);
|
|
2304
|
-
}
|
|
2305
|
-
}
|
|
2306
|
-
|
|
2307
|
-
private async _setBlockContext(block: Block): Promise<void> {
|
|
2308
|
-
const irregularStateOrUndefined = this._irregularStatesByBlockNumber.get(
|
|
2309
|
-
block.header.number
|
|
2310
|
-
);
|
|
2311
|
-
|
|
2312
|
-
if (this._stateManager instanceof ForkStateManager) {
|
|
2313
|
-
return this._stateManager.setBlockContext(
|
|
2314
|
-
block.header.stateRoot,
|
|
2315
|
-
block.header.number,
|
|
2316
|
-
irregularStateOrUndefined
|
|
2317
|
-
);
|
|
2318
|
-
}
|
|
2319
|
-
|
|
2320
|
-
return this._stateManager.setStateRoot(
|
|
2321
|
-
irregularStateOrUndefined ?? block.header.stateRoot
|
|
2322
|
-
);
|
|
2323
|
-
}
|
|
2324
|
-
|
|
2325
|
-
private async _restoreBlockContext(stateRoot: Uint8Array) {
|
|
2326
|
-
if (this._stateManager instanceof ForkStateManager) {
|
|
2327
|
-
return this._stateManager.restoreForkBlockContext(stateRoot);
|
|
2328
|
-
}
|
|
2329
|
-
return this._stateManager.setStateRoot(stateRoot);
|
|
2330
|
-
}
|
|
2331
|
-
|
|
2332
|
-
private async _correctInitialEstimation(
|
|
2333
|
-
blockNumberOrPending: bigint | "pending",
|
|
2334
|
-
txParams: TransactionParams,
|
|
2335
|
-
initialEstimation: bigint
|
|
2336
|
-
): Promise<bigint> {
|
|
2337
|
-
let tx = await this._getFakeTransaction({
|
|
2338
|
-
...txParams,
|
|
2339
|
-
gasLimit: initialEstimation,
|
|
2340
|
-
});
|
|
2341
|
-
|
|
2342
|
-
if (tx.getBaseFee() >= initialEstimation) {
|
|
2343
|
-
initialEstimation = tx.getBaseFee() + 1n;
|
|
2344
|
-
|
|
2345
|
-
tx = await this._getFakeTransaction({
|
|
2346
|
-
...txParams,
|
|
2347
|
-
gasLimit: initialEstimation,
|
|
2348
|
-
});
|
|
2349
|
-
}
|
|
2350
|
-
|
|
2351
|
-
const result = await this._runInBlockContext(blockNumberOrPending, () =>
|
|
2352
|
-
this._runTxAndRevertMutations(tx, blockNumberOrPending)
|
|
2353
|
-
);
|
|
2354
|
-
|
|
2355
|
-
if (result.execResult.exceptionError === undefined) {
|
|
2356
|
-
return initialEstimation;
|
|
2357
|
-
}
|
|
2358
|
-
|
|
2359
|
-
return this._binarySearchEstimation(
|
|
2360
|
-
blockNumberOrPending,
|
|
2361
|
-
txParams,
|
|
2362
|
-
initialEstimation,
|
|
2363
|
-
this.getBlockGasLimit()
|
|
2364
|
-
);
|
|
2365
|
-
}
|
|
2366
|
-
|
|
2367
|
-
private async _binarySearchEstimation(
|
|
2368
|
-
blockNumberOrPending: bigint | "pending",
|
|
2369
|
-
txParams: TransactionParams,
|
|
2370
|
-
highestFailingEstimation: bigint,
|
|
2371
|
-
lowestSuccessfulEstimation: bigint,
|
|
2372
|
-
roundNumber = 0
|
|
2373
|
-
): Promise<bigint> {
|
|
2374
|
-
if (lowestSuccessfulEstimation <= highestFailingEstimation) {
|
|
2375
|
-
// This shouldn't happen, but we don't want to go into an infinite loop
|
|
2376
|
-
// if it ever happens
|
|
2377
|
-
return lowestSuccessfulEstimation;
|
|
2378
|
-
}
|
|
2379
|
-
|
|
2380
|
-
const MAX_GAS_ESTIMATION_IMPROVEMENT_ROUNDS = 20;
|
|
2381
|
-
|
|
2382
|
-
const diff = lowestSuccessfulEstimation - highestFailingEstimation;
|
|
2383
|
-
|
|
2384
|
-
const minDiff =
|
|
2385
|
-
highestFailingEstimation >= 4_000_000n
|
|
2386
|
-
? 50_000
|
|
2387
|
-
: highestFailingEstimation >= 1_000_000n
|
|
2388
|
-
? 10_000
|
|
2389
|
-
: highestFailingEstimation >= 100_000n
|
|
2390
|
-
? 1_000
|
|
2391
|
-
: highestFailingEstimation >= 50_000n
|
|
2392
|
-
? 500
|
|
2393
|
-
: highestFailingEstimation >= 30_000n
|
|
2394
|
-
? 300
|
|
2395
|
-
: 200;
|
|
2396
|
-
|
|
2397
|
-
if (diff <= minDiff) {
|
|
2398
|
-
return lowestSuccessfulEstimation;
|
|
2399
|
-
}
|
|
2400
|
-
|
|
2401
|
-
if (roundNumber > MAX_GAS_ESTIMATION_IMPROVEMENT_ROUNDS) {
|
|
2402
|
-
return lowestSuccessfulEstimation;
|
|
2403
|
-
}
|
|
2404
|
-
|
|
2405
|
-
const binSearchNewEstimation = highestFailingEstimation + diff / 2n;
|
|
2406
|
-
|
|
2407
|
-
const optimizedEstimation =
|
|
2408
|
-
roundNumber === 0
|
|
2409
|
-
? 3n * highestFailingEstimation
|
|
2410
|
-
: binSearchNewEstimation;
|
|
2411
|
-
|
|
2412
|
-
const newEstimation =
|
|
2413
|
-
optimizedEstimation > binSearchNewEstimation
|
|
2414
|
-
? binSearchNewEstimation
|
|
2415
|
-
: optimizedEstimation;
|
|
2416
|
-
|
|
2417
|
-
// Let other things execute
|
|
2418
|
-
await new Promise((resolve) => setImmediate(resolve));
|
|
2419
|
-
|
|
2420
|
-
const tx = await this._getFakeTransaction({
|
|
2421
|
-
...txParams,
|
|
2422
|
-
gasLimit: newEstimation,
|
|
2423
|
-
});
|
|
2424
|
-
|
|
2425
|
-
const result = await this._runInBlockContext(blockNumberOrPending, () =>
|
|
2426
|
-
this._runTxAndRevertMutations(tx, blockNumberOrPending)
|
|
2427
|
-
);
|
|
2428
|
-
|
|
2429
|
-
if (result.execResult.exceptionError === undefined) {
|
|
2430
|
-
return this._binarySearchEstimation(
|
|
2431
|
-
blockNumberOrPending,
|
|
2432
|
-
txParams,
|
|
2433
|
-
highestFailingEstimation,
|
|
2434
|
-
newEstimation,
|
|
2435
|
-
roundNumber + 1
|
|
2436
|
-
);
|
|
2437
|
-
}
|
|
2438
|
-
|
|
2439
|
-
return this._binarySearchEstimation(
|
|
2440
|
-
blockNumberOrPending,
|
|
2441
|
-
txParams,
|
|
2442
|
-
newEstimation,
|
|
2443
|
-
lowestSuccessfulEstimation,
|
|
2444
|
-
roundNumber + 1
|
|
2445
|
-
);
|
|
2446
|
-
}
|
|
2447
|
-
|
|
2448
|
-
private async _applyStateOverrideSet(stateOverrideSet: StateOverrideSet) {
|
|
2449
|
-
// Multiple state override set can be configured for different addresses, hence the loop
|
|
2450
|
-
for (const [addrToOverride, stateOverrideOptions] of Object.entries(
|
|
2451
|
-
stateOverrideSet
|
|
2452
|
-
)) {
|
|
2453
|
-
const address = new Address(toBytes(addrToOverride));
|
|
2454
|
-
|
|
2455
|
-
const { balance, nonce, code, state, stateDiff } = stateOverrideOptions;
|
|
2456
|
-
|
|
2457
|
-
await this._overrideBalanceAndNonce(address, balance, nonce);
|
|
2458
|
-
await this._overrideCode(address, code);
|
|
2459
|
-
await this._overrideStateAndStateDiff(address, state, stateDiff);
|
|
2460
|
-
}
|
|
2461
|
-
}
|
|
2462
|
-
|
|
2463
|
-
private async _overrideBalanceAndNonce(
|
|
2464
|
-
address: Address,
|
|
2465
|
-
balance: bigint | undefined,
|
|
2466
|
-
nonce: bigint | undefined
|
|
2467
|
-
) {
|
|
2468
|
-
const MAX_NONCE = 2n ** 64n - 1n;
|
|
2469
|
-
const MAX_BALANCE = 2n ** 256n - 1n;
|
|
2470
|
-
|
|
2471
|
-
if (nonce !== undefined && nonce > MAX_NONCE) {
|
|
2472
|
-
throw new InvalidInputError(
|
|
2473
|
-
`The 'nonce' property should occupy a maximum of 8 bytes (nonce=${nonce}).`
|
|
2474
|
-
);
|
|
2475
|
-
}
|
|
2476
|
-
|
|
2477
|
-
if (balance !== undefined && balance > MAX_BALANCE) {
|
|
2478
|
-
throw new InvalidInputError(
|
|
2479
|
-
`The 'balance' property should occupy a maximum of 32 bytes (balance=${balance}).`
|
|
2480
|
-
);
|
|
2481
|
-
}
|
|
2482
|
-
|
|
2483
|
-
await this._stateManager.modifyAccountFields(address, {
|
|
2484
|
-
balance,
|
|
2485
|
-
nonce,
|
|
2486
|
-
});
|
|
2487
|
-
}
|
|
2488
|
-
|
|
2489
|
-
private async _overrideCode(address: Address, code: Buffer | undefined) {
|
|
2490
|
-
if (code === undefined) return;
|
|
2491
|
-
|
|
2492
|
-
await this._stateManager.putContractCode(address, code);
|
|
2493
|
-
}
|
|
2494
|
-
|
|
2495
|
-
private async _overrideStateAndStateDiff(
|
|
2496
|
-
address: Address,
|
|
2497
|
-
state: StateProperties | undefined,
|
|
2498
|
-
stateDiff: StateProperties | undefined
|
|
2499
|
-
) {
|
|
2500
|
-
let newState;
|
|
2501
|
-
|
|
2502
|
-
if (state !== undefined && stateDiff === undefined) {
|
|
2503
|
-
await this._stateManager.clearContractStorage(address);
|
|
2504
|
-
newState = state;
|
|
2505
|
-
} else if (state === undefined && stateDiff !== undefined) {
|
|
2506
|
-
newState = stateDiff;
|
|
2507
|
-
} else if (state === undefined && stateDiff === undefined) {
|
|
2508
|
-
// nothing to do
|
|
2509
|
-
return;
|
|
2510
|
-
} else {
|
|
2511
|
-
throw new InvalidInputError(
|
|
2512
|
-
"The properties 'state' and 'stateDiff' cannot be used simultaneously when configuring the state override set passed to the eth_call method."
|
|
2513
|
-
);
|
|
2514
|
-
}
|
|
2515
|
-
|
|
2516
|
-
for (const [storageKey, value] of Object.entries(newState)) {
|
|
2517
|
-
await this._stateManager.putContractStorage(
|
|
2518
|
-
address,
|
|
2519
|
-
toBytes(storageKey),
|
|
2520
|
-
setLengthLeft(bigIntToBytes(value), 32)
|
|
2521
|
-
);
|
|
2522
|
-
}
|
|
2523
|
-
}
|
|
2524
|
-
|
|
2525
|
-
/**
|
|
2526
|
-
* This function runs a transaction and reverts all the modifications that it
|
|
2527
|
-
* makes.
|
|
2528
|
-
*/
|
|
2529
|
-
private async _runTxAndRevertMutations(
|
|
2530
|
-
tx: TypedTransaction,
|
|
2531
|
-
blockNumberOrPending: bigint | "pending",
|
|
2532
|
-
forceBaseFeeZero = false,
|
|
2533
|
-
stateOverrideSet: StateOverrideSet = {}
|
|
2534
|
-
): Promise<RunTxResult> {
|
|
2535
|
-
const initialStateRoot = await this._stateManager.getStateRoot();
|
|
2536
|
-
|
|
2537
|
-
await this._applyStateOverrideSet(stateOverrideSet);
|
|
2538
|
-
|
|
2539
|
-
let blockContext: Block | undefined;
|
|
2540
|
-
let originalCommon: Common | undefined;
|
|
2541
|
-
|
|
2542
|
-
try {
|
|
2543
|
-
if (blockNumberOrPending === "pending") {
|
|
2544
|
-
// the new block has already been mined by _runInBlockContext hence we take latest here
|
|
2545
|
-
blockContext = await this.getLatestBlock();
|
|
2546
|
-
} else {
|
|
2547
|
-
// We know that this block number exists, because otherwise
|
|
2548
|
-
// there would be an error in the RPC layer.
|
|
2549
|
-
const block = await this.getBlockByNumber(blockNumberOrPending);
|
|
2550
|
-
assertHardhatInvariant(
|
|
2551
|
-
block !== undefined,
|
|
2552
|
-
"Tried to run a tx in the context of a non-existent block"
|
|
2553
|
-
);
|
|
2554
|
-
|
|
2555
|
-
blockContext = block;
|
|
2556
|
-
|
|
2557
|
-
// we don't need to add the tx to the block because runTx doesn't
|
|
2558
|
-
// know anything about the txs in the current block
|
|
2559
|
-
}
|
|
2560
|
-
|
|
2561
|
-
originalCommon = (this._vm as any).common;
|
|
2562
|
-
|
|
2563
|
-
assertTransientStorageCompatibility(
|
|
2564
|
-
this._enableTransientStorage,
|
|
2565
|
-
this._vm.common.hardfork() as HardforkName
|
|
2566
|
-
);
|
|
2567
|
-
|
|
2568
|
-
(this._vm as any).common = Common.custom(
|
|
2569
|
-
{
|
|
2570
|
-
chainId:
|
|
2571
|
-
this._forkBlockNumber === undefined ||
|
|
2572
|
-
blockContext.header.number >= this._forkBlockNumber
|
|
2573
|
-
? this._configChainId
|
|
2574
|
-
: this._forkNetworkId,
|
|
2575
|
-
networkId: this._forkNetworkId ?? this._configNetworkId,
|
|
2576
|
-
},
|
|
2577
|
-
{
|
|
2578
|
-
hardfork: this._selectHardfork(blockContext.header.number),
|
|
2579
|
-
}
|
|
2580
|
-
);
|
|
2581
|
-
|
|
2582
|
-
// If this VM is running without EIP4895, but the block has withdrawals,
|
|
2583
|
-
// we remove them and the withdrawal root from the block
|
|
2584
|
-
if (
|
|
2585
|
-
!this.isEip4895Active(blockNumberOrPending) &&
|
|
2586
|
-
blockContext.withdrawals !== undefined
|
|
2587
|
-
) {
|
|
2588
|
-
blockContext = Block.fromBlockData(
|
|
2589
|
-
{
|
|
2590
|
-
...blockContext,
|
|
2591
|
-
withdrawals: undefined,
|
|
2592
|
-
header: {
|
|
2593
|
-
...blockContext.header,
|
|
2594
|
-
withdrawalsRoot: undefined,
|
|
2595
|
-
},
|
|
2596
|
-
},
|
|
2597
|
-
{
|
|
2598
|
-
freeze: false,
|
|
2599
|
-
common: this._vm.common,
|
|
2600
|
-
|
|
2601
|
-
skipConsensusFormatValidation: true,
|
|
2602
|
-
}
|
|
2603
|
-
);
|
|
2604
|
-
}
|
|
2605
|
-
|
|
2606
|
-
// If this VM is running without cancun, but the block has cancun fields,
|
|
2607
|
-
// we remove them from the block
|
|
2608
|
-
if (
|
|
2609
|
-
!this.isCancunBlock(blockNumberOrPending) &&
|
|
2610
|
-
blockContext.header.blobGasUsed !== undefined
|
|
2611
|
-
) {
|
|
2612
|
-
blockContext = Block.fromBlockData(
|
|
2613
|
-
{
|
|
2614
|
-
...blockContext,
|
|
2615
|
-
header: {
|
|
2616
|
-
...blockContext.header,
|
|
2617
|
-
blobGasUsed: undefined,
|
|
2618
|
-
excessBlobGas: undefined,
|
|
2619
|
-
parentBeaconBlockRoot: undefined,
|
|
2620
|
-
},
|
|
2621
|
-
},
|
|
2622
|
-
{
|
|
2623
|
-
freeze: false,
|
|
2624
|
-
common: this._vm.common,
|
|
2625
|
-
|
|
2626
|
-
skipConsensusFormatValidation: true,
|
|
2627
|
-
}
|
|
2628
|
-
);
|
|
2629
|
-
}
|
|
2630
|
-
|
|
2631
|
-
// NOTE: This is a workaround of both an @nomicfoundation/ethereumjs-vm limitation, and
|
|
2632
|
-
// a bug in Hardhat Network.
|
|
2633
|
-
//
|
|
2634
|
-
// See: https://github.com/nomiclabs/hardhat/issues/1666
|
|
2635
|
-
//
|
|
2636
|
-
// If this VM is running with EIP1559 activated, and the block is not
|
|
2637
|
-
// an EIP1559 one, this will crash, so we create a new one that has
|
|
2638
|
-
// baseFeePerGas = 0.
|
|
2639
|
-
//
|
|
2640
|
-
// We also have an option to force the base fee to be zero,
|
|
2641
|
-
// we don't want to debit any balance nor fail any tx when running an
|
|
2642
|
-
// eth_call. This will make the BASEFEE option also return 0, which
|
|
2643
|
-
// shouldn't. See: https://github.com/nomiclabs/hardhat/issues/1688
|
|
2644
|
-
if (
|
|
2645
|
-
this.isEip1559Active(blockNumberOrPending) &&
|
|
2646
|
-
(blockContext.header.baseFeePerGas === undefined || forceBaseFeeZero)
|
|
2647
|
-
) {
|
|
2648
|
-
blockContext = Block.fromBlockData(blockContext, {
|
|
2649
|
-
freeze: false,
|
|
2650
|
-
common: this._vm.common,
|
|
2651
|
-
|
|
2652
|
-
skipConsensusFormatValidation: true,
|
|
2653
|
-
});
|
|
2654
|
-
|
|
2655
|
-
(blockContext.header as any).baseFeePerGas = 0n;
|
|
2656
|
-
}
|
|
2657
|
-
|
|
2658
|
-
return await this._vm.runTx({
|
|
2659
|
-
block: blockContext,
|
|
2660
|
-
tx,
|
|
2661
|
-
skipNonce: true,
|
|
2662
|
-
skipBalance: true,
|
|
2663
|
-
skipBlockGasLimitValidation: true,
|
|
2664
|
-
skipHardForkValidation: true,
|
|
2665
|
-
});
|
|
2666
|
-
} finally {
|
|
2667
|
-
if (originalCommon !== undefined) {
|
|
2668
|
-
(this._vm as any).common = originalCommon;
|
|
2669
|
-
}
|
|
2670
|
-
await this._stateManager.setStateRoot(initialStateRoot);
|
|
2671
|
-
}
|
|
2672
|
-
}
|
|
2673
|
-
|
|
2674
|
-
private async _computeFilterParams(
|
|
2675
|
-
filterParams: FilterParams,
|
|
2676
|
-
isFilter: boolean
|
|
2677
|
-
): Promise<FilterParams> {
|
|
2678
|
-
const latestBlockNumber = this.getLatestBlockNumber();
|
|
2679
|
-
const newFilterParams = { ...filterParams };
|
|
2680
|
-
|
|
2681
|
-
if (newFilterParams.fromBlock === LATEST_BLOCK) {
|
|
2682
|
-
newFilterParams.fromBlock = latestBlockNumber;
|
|
2683
|
-
}
|
|
2684
|
-
|
|
2685
|
-
if (!isFilter && newFilterParams.toBlock === LATEST_BLOCK) {
|
|
2686
|
-
newFilterParams.toBlock = latestBlockNumber;
|
|
2687
|
-
}
|
|
2688
|
-
|
|
2689
|
-
if (newFilterParams.toBlock > latestBlockNumber) {
|
|
2690
|
-
newFilterParams.toBlock = latestBlockNumber;
|
|
2691
|
-
}
|
|
2692
|
-
if (newFilterParams.fromBlock > latestBlockNumber) {
|
|
2693
|
-
newFilterParams.fromBlock = latestBlockNumber;
|
|
2694
|
-
}
|
|
2695
|
-
|
|
2696
|
-
return newFilterParams;
|
|
2697
|
-
}
|
|
2698
|
-
|
|
2699
|
-
private _newDeadline(): Date {
|
|
2700
|
-
const dt = new Date();
|
|
2701
|
-
dt.setMinutes(dt.getMinutes() + 5); // This will not overflow
|
|
2702
|
-
return dt;
|
|
2703
|
-
}
|
|
2704
|
-
|
|
2705
|
-
private _getNextFilterId(): bigint {
|
|
2706
|
-
this._lastFilterId++;
|
|
2707
|
-
|
|
2708
|
-
return this._lastFilterId;
|
|
2709
|
-
}
|
|
2710
|
-
|
|
2711
|
-
private _filterIdToFiltersKey(filterId: bigint): string {
|
|
2712
|
-
return filterId.toString();
|
|
2713
|
-
}
|
|
2714
|
-
|
|
2715
|
-
private _emitEthEvent(filterId: bigint, result: any) {
|
|
2716
|
-
this.emit("ethEvent", {
|
|
2717
|
-
result,
|
|
2718
|
-
filterId,
|
|
2719
|
-
});
|
|
2720
|
-
}
|
|
2721
|
-
|
|
2722
|
-
private async _getNonce(
|
|
2723
|
-
address: Address,
|
|
2724
|
-
blockNumberOrPending: bigint | "pending"
|
|
2725
|
-
): Promise<bigint> {
|
|
2726
|
-
if (blockNumberOrPending === "pending") {
|
|
2727
|
-
return this.getAccountNextPendingNonce(address);
|
|
2728
|
-
}
|
|
2729
|
-
|
|
2730
|
-
return this._runInBlockContext(blockNumberOrPending, async () => {
|
|
2731
|
-
const account = await this._stateManager.getAccount(address);
|
|
2732
|
-
|
|
2733
|
-
return account?.nonce ?? 0n;
|
|
2734
|
-
});
|
|
2735
|
-
}
|
|
2736
|
-
|
|
2737
|
-
private async _isTransactionMined(hash: Buffer): Promise<boolean> {
|
|
2738
|
-
const txReceipt = await this.getTransactionReceipt(hash);
|
|
2739
|
-
return txReceipt !== undefined;
|
|
2740
|
-
}
|
|
2741
|
-
|
|
2742
|
-
private _isTxMinable(
|
|
2743
|
-
tx: TypedTransaction,
|
|
2744
|
-
nextBlockBaseFeePerGas?: bigint
|
|
2745
|
-
): boolean {
|
|
2746
|
-
const txMaxFee = "gasPrice" in tx ? tx.gasPrice : tx.maxFeePerGas;
|
|
2747
|
-
|
|
2748
|
-
const canPayBaseFee =
|
|
2749
|
-
nextBlockBaseFeePerGas !== undefined
|
|
2750
|
-
? txMaxFee >= nextBlockBaseFeePerGas
|
|
2751
|
-
: true;
|
|
2752
|
-
|
|
2753
|
-
const atLeastMinGasPrice = txMaxFee >= this._minGasPrice;
|
|
2754
|
-
|
|
2755
|
-
return canPayBaseFee && atLeastMinGasPrice;
|
|
2756
|
-
}
|
|
2757
|
-
|
|
2758
|
-
private async _persistIrregularWorldState(): Promise<void> {
|
|
2759
|
-
this._irregularStatesByBlockNumber.set(
|
|
2760
|
-
this.getLatestBlockNumber(),
|
|
2761
|
-
await this._stateManager.getStateRoot()
|
|
2762
|
-
);
|
|
2763
|
-
}
|
|
2764
|
-
|
|
2765
|
-
public isEip1559Active(blockNumberOrPending?: bigint | "pending"): boolean {
|
|
2766
|
-
if (
|
|
2767
|
-
blockNumberOrPending !== undefined &&
|
|
2768
|
-
blockNumberOrPending !== "pending"
|
|
2769
|
-
) {
|
|
2770
|
-
return this._vm.common.hardforkGteHardfork(
|
|
2771
|
-
this._selectHardfork(blockNumberOrPending),
|
|
2772
|
-
"london"
|
|
2773
|
-
);
|
|
2774
|
-
}
|
|
2775
|
-
return this._vm.common.gteHardfork("london");
|
|
2776
|
-
}
|
|
2777
|
-
|
|
2778
|
-
public isEip4895Active(blockNumberOrPending?: bigint | "pending"): boolean {
|
|
2779
|
-
if (
|
|
2780
|
-
blockNumberOrPending !== undefined &&
|
|
2781
|
-
blockNumberOrPending !== "pending"
|
|
2782
|
-
) {
|
|
2783
|
-
return this._vm.common.hardforkGteHardfork(
|
|
2784
|
-
this._selectHardfork(blockNumberOrPending),
|
|
2785
|
-
"shanghai"
|
|
2786
|
-
);
|
|
2787
|
-
}
|
|
2788
|
-
return this._vm.common.gteHardfork("shanghai");
|
|
2789
|
-
}
|
|
2790
|
-
|
|
2791
|
-
public isCancunBlock(blockNumberOrPending?: bigint | "pending"): boolean {
|
|
2792
|
-
if (
|
|
2793
|
-
blockNumberOrPending !== undefined &&
|
|
2794
|
-
blockNumberOrPending !== "pending"
|
|
2795
|
-
) {
|
|
2796
|
-
return this._vm.common.hardforkGteHardfork(
|
|
2797
|
-
this._selectHardfork(blockNumberOrPending),
|
|
2798
|
-
"cancun"
|
|
2799
|
-
);
|
|
2800
|
-
}
|
|
2801
|
-
return this._vm.common.gteHardfork("cancun");
|
|
2802
|
-
}
|
|
2803
|
-
|
|
2804
|
-
public isPostMergeHardfork(): boolean {
|
|
2805
|
-
return hardforkGte(this.hardfork, HardforkName.MERGE);
|
|
2806
|
-
}
|
|
2807
|
-
|
|
2808
|
-
public isPostCancunHardfork(): boolean {
|
|
2809
|
-
return hardforkGte(this.hardfork, HardforkName.CANCUN);
|
|
2810
|
-
}
|
|
2811
|
-
|
|
2812
|
-
public setPrevRandao(prevRandao: Buffer): void {
|
|
2813
|
-
this._mixHashGenerator.setNext(prevRandao);
|
|
2814
|
-
}
|
|
2815
|
-
|
|
2816
|
-
public async getClientVersion(): Promise<string> {
|
|
2817
|
-
const hardhatPackage = await getPackageJson();
|
|
2818
|
-
const ethereumjsVMPackage = require("@nomicfoundation/ethereumjs-vm/package.json");
|
|
2819
|
-
return `HardhatNetwork/${hardhatPackage.version}/@nomicfoundation/ethereumjs-vm/${ethereumjsVMPackage.version}`;
|
|
2820
|
-
}
|
|
2821
|
-
|
|
2822
|
-
public async getMetadata(): Promise<HardhatMetadata> {
|
|
2823
|
-
const clientVersion = await this.getClientVersion();
|
|
2824
|
-
|
|
2825
|
-
const instanceIdHex = BigIntUtils.toEvmWord(this._instanceId);
|
|
2826
|
-
const instanceId = `0x${instanceIdHex}`;
|
|
2827
|
-
|
|
2828
|
-
const latestBlock = await this.getLatestBlock();
|
|
2829
|
-
|
|
2830
|
-
const latestBlockHashHex = Buffer.from(latestBlock.header.hash()).toString(
|
|
2831
|
-
"hex"
|
|
2832
|
-
);
|
|
2833
|
-
const latestBlockHash = `0x${latestBlockHashHex}`;
|
|
2834
|
-
|
|
2835
|
-
const metadata: HardhatMetadata = {
|
|
2836
|
-
clientVersion,
|
|
2837
|
-
chainId: this._configChainId,
|
|
2838
|
-
instanceId,
|
|
2839
|
-
latestBlockNumber: Number(latestBlock.header.number),
|
|
2840
|
-
latestBlockHash,
|
|
2841
|
-
};
|
|
2842
|
-
|
|
2843
|
-
if (this._forkBlockNumber !== undefined) {
|
|
2844
|
-
assertHardhatInvariant(
|
|
2845
|
-
this._forkNetworkId !== undefined,
|
|
2846
|
-
"this._forkNetworkId should be defined if this._forkBlockNumber is defined"
|
|
2847
|
-
);
|
|
2848
|
-
assertHardhatInvariant(
|
|
2849
|
-
this._forkBlockHash !== undefined,
|
|
2850
|
-
"this._forkBlockhash should be defined if this._forkBlockNumber is defined"
|
|
2851
|
-
);
|
|
2852
|
-
|
|
2853
|
-
metadata.forkedNetwork = {
|
|
2854
|
-
chainId: this._forkNetworkId,
|
|
2855
|
-
forkBlockNumber: Number(this._forkBlockNumber),
|
|
2856
|
-
forkBlockHash: this._forkBlockHash,
|
|
2857
|
-
};
|
|
2858
|
-
}
|
|
2859
|
-
|
|
2860
|
-
return metadata;
|
|
2861
|
-
}
|
|
2862
|
-
|
|
2863
|
-
private _getNextMixHash(): Uint8Array {
|
|
2864
|
-
return this._mixHashGenerator.next();
|
|
2865
|
-
}
|
|
2866
|
-
|
|
2867
|
-
private _getNextParentBeaconBlockRoot(): Uint8Array {
|
|
2868
|
-
return this._parentBeaconBlockRootGenerator.next();
|
|
2869
|
-
}
|
|
2870
|
-
|
|
2871
|
-
private async _getEstimateGasFeePriceFields(
|
|
2872
|
-
callParams: CallParams,
|
|
2873
|
-
blockNumberOrPending: bigint | "pending"
|
|
2874
|
-
): Promise<
|
|
2875
|
-
| { gasPrice: bigint }
|
|
2876
|
-
| { maxFeePerGas: bigint; maxPriorityFeePerGas: bigint }
|
|
2877
|
-
> {
|
|
2878
|
-
if (
|
|
2879
|
-
!this.isEip1559Active(blockNumberOrPending) ||
|
|
2880
|
-
callParams.gasPrice !== undefined
|
|
2881
|
-
) {
|
|
2882
|
-
return { gasPrice: callParams.gasPrice ?? (await this.getGasPrice()) };
|
|
2883
|
-
}
|
|
2884
|
-
|
|
2885
|
-
let maxFeePerGas = callParams.maxFeePerGas;
|
|
2886
|
-
let maxPriorityFeePerGas = callParams.maxPriorityFeePerGas;
|
|
2887
|
-
|
|
2888
|
-
if (maxPriorityFeePerGas === undefined) {
|
|
2889
|
-
maxPriorityFeePerGas = await this.getMaxPriorityFeePerGas();
|
|
2890
|
-
|
|
2891
|
-
if (maxFeePerGas !== undefined && maxFeePerGas < maxPriorityFeePerGas) {
|
|
2892
|
-
maxPriorityFeePerGas = maxFeePerGas;
|
|
2893
|
-
}
|
|
2894
|
-
}
|
|
2895
|
-
|
|
2896
|
-
if (maxFeePerGas === undefined) {
|
|
2897
|
-
if (blockNumberOrPending === "pending") {
|
|
2898
|
-
const baseFeePerGas = await this.getNextBlockBaseFeePerGas();
|
|
2899
|
-
maxFeePerGas = 2n * baseFeePerGas! + maxPriorityFeePerGas;
|
|
2900
|
-
} else {
|
|
2901
|
-
const block = await this.getBlockByNumber(blockNumberOrPending);
|
|
2902
|
-
|
|
2903
|
-
maxFeePerGas =
|
|
2904
|
-
maxPriorityFeePerGas + (block!.header.baseFeePerGas ?? 0n);
|
|
2905
|
-
}
|
|
2906
|
-
}
|
|
2907
|
-
|
|
2908
|
-
return { maxFeePerGas, maxPriorityFeePerGas };
|
|
2909
|
-
}
|
|
2910
|
-
|
|
2911
|
-
private _selectHardfork(blockNumber: bigint): string {
|
|
2912
|
-
if (
|
|
2913
|
-
this._forkBlockNumber === undefined ||
|
|
2914
|
-
blockNumber >= this._forkBlockNumber
|
|
2915
|
-
) {
|
|
2916
|
-
return this._vm.common.hardfork() as HardforkName;
|
|
2917
|
-
}
|
|
2918
|
-
|
|
2919
|
-
if (this._hardforkActivations.size === 0) {
|
|
2920
|
-
throw new InternalError(
|
|
2921
|
-
`No known hardfork for execution on historical block ${blockNumber.toString()} (relative to fork block number ${
|
|
2922
|
-
this._forkBlockNumber
|
|
2923
|
-
}). The node was not configured with a hardfork activation history. See http://hardhat.org/custom-hardfork-history`
|
|
2924
|
-
);
|
|
2925
|
-
}
|
|
2926
|
-
|
|
2927
|
-
/** search this._hardforkActivations for the highest block number that
|
|
2928
|
-
* isn't higher than blockNumber, and then return that found block number's
|
|
2929
|
-
* associated hardfork name. */
|
|
2930
|
-
const hardforkHistory: Array<[name: string, block: number]> = Array.from(
|
|
2931
|
-
this._hardforkActivations.entries()
|
|
2932
|
-
);
|
|
2933
|
-
const [hardfork, activationBlock] = hardforkHistory.reduce(
|
|
2934
|
-
([highestHardfork, highestBlock], [thisHardfork, thisBlock]) =>
|
|
2935
|
-
thisBlock > highestBlock && thisBlock <= blockNumber
|
|
2936
|
-
? [thisHardfork, thisBlock]
|
|
2937
|
-
: [highestHardfork, highestBlock]
|
|
2938
|
-
);
|
|
2939
|
-
if (hardfork === undefined || blockNumber < activationBlock) {
|
|
2940
|
-
throw new InternalError(
|
|
2941
|
-
`Could not find a hardfork to run for block ${blockNumber.toString()}, after having looked for one in the HardhatNode's hardfork activation history, which was: ${JSON.stringify(
|
|
2942
|
-
hardforkHistory
|
|
2943
|
-
)}. For more information, see https://hardhat.org/hardhat-network/reference/#config`
|
|
2944
|
-
);
|
|
2945
|
-
}
|
|
2946
|
-
|
|
2947
|
-
if (!HARDHAT_NETWORK_SUPPORTED_HARDFORKS.includes(hardfork)) {
|
|
2948
|
-
throw new InternalError(
|
|
2949
|
-
`Tried to run a call or transaction in the context of a block whose hardfork is "${hardfork}", but Hardhat Network only supports the following hardforks: ${HARDHAT_NETWORK_SUPPORTED_HARDFORKS.join(
|
|
2950
|
-
", "
|
|
2951
|
-
)}`
|
|
2952
|
-
);
|
|
2953
|
-
}
|
|
2954
|
-
|
|
2955
|
-
return hardfork === "merge" ? "mergeForkIdTransition" : hardfork;
|
|
2956
|
-
}
|
|
2957
|
-
|
|
2958
|
-
private _getCommonForTracing(networkId: number, blockNumber: bigint): Common {
|
|
2959
|
-
assertTransientStorageCompatibility(
|
|
2960
|
-
this._enableTransientStorage,
|
|
2961
|
-
this._vm.common.hardfork() as HardforkName
|
|
2962
|
-
);
|
|
2963
|
-
|
|
2964
|
-
try {
|
|
2965
|
-
const common = Common.custom(
|
|
2966
|
-
{
|
|
2967
|
-
chainId: networkId,
|
|
2968
|
-
networkId,
|
|
2969
|
-
},
|
|
2970
|
-
{
|
|
2971
|
-
hardfork: this._selectHardfork(BigInt(blockNumber)),
|
|
2972
|
-
}
|
|
2973
|
-
);
|
|
2974
|
-
|
|
2975
|
-
return common;
|
|
2976
|
-
} catch {
|
|
2977
|
-
throw new InternalError(
|
|
2978
|
-
`Network id ${networkId} does not correspond to a network that Hardhat can trace`
|
|
2979
|
-
);
|
|
2980
|
-
}
|
|
2981
|
-
}
|
|
2982
|
-
}
|
|
2983
|
-
|
|
2984
|
-
export function assertTransientStorageCompatibility(
|
|
2985
|
-
enableTransientStorage: boolean,
|
|
2986
|
-
hardfork: HardforkName
|
|
2987
|
-
) {
|
|
2988
|
-
if (enableTransientStorage && !hardforkGte(hardfork, HardforkName.CANCUN)) {
|
|
2989
|
-
throw new InternalError(
|
|
2990
|
-
`Transient storage is not compatible with hardfork "${hardfork}". To use transient storage, set the hardfork to "cancun" or later.`
|
|
2991
|
-
);
|
|
2992
|
-
}
|
|
2993
|
-
}
|