hardhat 2.20.1 → 2.21.0-dev.1

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.
Files changed (271) hide show
  1. package/internal/core/jsonrpc/types/input/blockTag.d.ts +3 -3
  2. package/internal/core/jsonrpc/types/input/filterRequest.d.ts +6 -6
  3. package/internal/core/providers/construction.d.ts.map +1 -1
  4. package/internal/core/providers/construction.js +28 -4
  5. package/internal/core/providers/construction.js.map +1 -1
  6. package/internal/core/providers/http.d.ts +2 -0
  7. package/internal/core/providers/http.d.ts.map +1 -1
  8. package/internal/core/providers/http.js +2 -1
  9. package/internal/core/providers/http.js.map +1 -1
  10. package/internal/core/runtime-environment.d.ts.map +1 -1
  11. package/internal/core/runtime-environment.js.map +1 -1
  12. package/internal/hardhat-network/jsonrpc/client.d.ts +0 -2
  13. package/internal/hardhat-network/jsonrpc/client.d.ts.map +1 -1
  14. package/internal/hardhat-network/jsonrpc/client.js +0 -16
  15. package/internal/hardhat-network/jsonrpc/client.js.map +1 -1
  16. package/internal/hardhat-network/jsonrpc/handler.js +9 -1
  17. package/internal/hardhat-network/jsonrpc/handler.js.map +1 -1
  18. package/internal/hardhat-network/provider/BlockchainData.d.ts +5 -5
  19. package/internal/hardhat-network/provider/BlockchainData.d.ts.map +1 -1
  20. package/internal/hardhat-network/provider/BlockchainData.js +10 -10
  21. package/internal/hardhat-network/provider/BlockchainData.js.map +1 -1
  22. package/internal/hardhat-network/provider/HardhatBlockchain.d.ts +0 -7
  23. package/internal/hardhat-network/provider/HardhatBlockchain.d.ts.map +1 -1
  24. package/internal/hardhat-network/provider/HardhatBlockchain.js +2 -14
  25. package/internal/hardhat-network/provider/HardhatBlockchain.js.map +1 -1
  26. package/internal/hardhat-network/provider/TxPool.d.ts +3 -2
  27. package/internal/hardhat-network/provider/TxPool.d.ts.map +1 -1
  28. package/internal/hardhat-network/provider/TxPool.js +16 -16
  29. package/internal/hardhat-network/provider/TxPool.js.map +1 -1
  30. package/internal/hardhat-network/provider/ethereumjs-workarounds.js +1 -1
  31. package/internal/hardhat-network/provider/ethereumjs-workarounds.js.map +1 -1
  32. package/internal/hardhat-network/provider/filter.d.ts +6 -5
  33. package/internal/hardhat-network/provider/filter.d.ts.map +1 -1
  34. package/internal/hardhat-network/provider/filter.js +2 -2
  35. package/internal/hardhat-network/provider/filter.js.map +1 -1
  36. package/internal/hardhat-network/provider/fork/ForkBlockchain.d.ts +0 -7
  37. package/internal/hardhat-network/provider/fork/ForkBlockchain.d.ts.map +1 -1
  38. package/internal/hardhat-network/provider/fork/ForkBlockchain.js +4 -21
  39. package/internal/hardhat-network/provider/fork/ForkBlockchain.js.map +1 -1
  40. package/internal/hardhat-network/provider/fork/ForkStateManager.d.ts +13 -19
  41. package/internal/hardhat-network/provider/fork/ForkStateManager.d.ts.map +1 -1
  42. package/internal/hardhat-network/provider/fork/ForkStateManager.js +61 -59
  43. package/internal/hardhat-network/provider/fork/ForkStateManager.js.map +1 -1
  44. package/internal/hardhat-network/provider/fork/rpcToBlockData.d.ts.map +1 -1
  45. package/internal/hardhat-network/provider/fork/rpcToBlockData.js +0 -3
  46. package/internal/hardhat-network/provider/fork/rpcToBlockData.js.map +1 -1
  47. package/internal/hardhat-network/provider/fork/rpcToTxData.d.ts +2 -2
  48. package/internal/hardhat-network/provider/fork/rpcToTxData.d.ts.map +1 -1
  49. package/internal/hardhat-network/provider/fork/rpcToTxData.js +1 -1
  50. package/internal/hardhat-network/provider/fork/rpcToTxData.js.map +1 -1
  51. package/internal/hardhat-network/provider/modules/base.js +4 -4
  52. package/internal/hardhat-network/provider/modules/base.js.map +1 -1
  53. package/internal/hardhat-network/provider/modules/eth.d.ts.map +1 -1
  54. package/internal/hardhat-network/provider/modules/eth.js +9 -16
  55. package/internal/hardhat-network/provider/modules/eth.js.map +1 -1
  56. package/internal/hardhat-network/provider/modules/logger.d.ts +6 -84
  57. package/internal/hardhat-network/provider/modules/logger.d.ts.map +1 -1
  58. package/internal/hardhat-network/provider/modules/logger.js +3 -530
  59. package/internal/hardhat-network/provider/modules/logger.js.map +1 -1
  60. package/internal/hardhat-network/provider/node-types.d.ts +2 -65
  61. package/internal/hardhat-network/provider/node-types.d.ts.map +1 -1
  62. package/internal/hardhat-network/provider/node-types.js +0 -5
  63. package/internal/hardhat-network/provider/node-types.js.map +1 -1
  64. package/internal/hardhat-network/provider/node.d.ts +2 -6
  65. package/internal/hardhat-network/provider/node.d.ts.map +1 -1
  66. package/internal/hardhat-network/provider/node.js +79 -153
  67. package/internal/hardhat-network/provider/node.js.map +1 -1
  68. package/internal/hardhat-network/provider/output.d.ts +0 -14
  69. package/internal/hardhat-network/provider/output.d.ts.map +1 -1
  70. package/internal/hardhat-network/provider/output.js +0 -264
  71. package/internal/hardhat-network/provider/output.js.map +1 -1
  72. package/internal/hardhat-network/provider/provider.d.ts +28 -25
  73. package/internal/hardhat-network/provider/provider.d.ts.map +1 -1
  74. package/internal/hardhat-network/provider/provider.js +349 -185
  75. package/internal/hardhat-network/provider/provider.js.map +1 -1
  76. package/internal/hardhat-network/provider/transactions/FakeSenderAccessListEIP2930Transaction.d.ts +10 -8
  77. package/internal/hardhat-network/provider/transactions/FakeSenderAccessListEIP2930Transaction.d.ts.map +1 -1
  78. package/internal/hardhat-network/provider/transactions/FakeSenderAccessListEIP2930Transaction.js +9 -9
  79. package/internal/hardhat-network/provider/transactions/FakeSenderAccessListEIP2930Transaction.js.map +1 -1
  80. package/internal/hardhat-network/provider/transactions/FakeSenderEIP1559Transaction.d.ts +10 -8
  81. package/internal/hardhat-network/provider/transactions/FakeSenderEIP1559Transaction.d.ts.map +1 -1
  82. package/internal/hardhat-network/provider/transactions/FakeSenderEIP1559Transaction.js +9 -9
  83. package/internal/hardhat-network/provider/transactions/FakeSenderEIP1559Transaction.js.map +1 -1
  84. package/internal/hardhat-network/provider/transactions/FakeSenderTransaction.d.ts +10 -9
  85. package/internal/hardhat-network/provider/transactions/FakeSenderTransaction.d.ts.map +1 -1
  86. package/internal/hardhat-network/provider/transactions/FakeSenderTransaction.js +7 -6
  87. package/internal/hardhat-network/provider/transactions/FakeSenderTransaction.js.map +1 -1
  88. package/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP1559Transaction.d.ts +6 -5
  89. package/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP1559Transaction.d.ts.map +1 -1
  90. package/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP1559Transaction.js +1 -1
  91. package/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP1559Transaction.js.map +1 -1
  92. package/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP2930Transaction.d.ts +5 -4
  93. package/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP2930Transaction.d.ts.map +1 -1
  94. package/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP2930Transaction.js +1 -1
  95. package/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP2930Transaction.js.map +1 -1
  96. package/internal/hardhat-network/provider/transactions/ReadOnlyValidTransaction.d.ts +8 -7
  97. package/internal/hardhat-network/provider/transactions/ReadOnlyValidTransaction.d.ts.map +1 -1
  98. package/internal/hardhat-network/provider/transactions/ReadOnlyValidTransaction.js +2 -2
  99. package/internal/hardhat-network/provider/transactions/ReadOnlyValidTransaction.js.map +1 -1
  100. package/internal/hardhat-network/provider/transactions/ReadOnlyValidUnknownTypeTransaction.d.ts +8 -7
  101. package/internal/hardhat-network/provider/transactions/ReadOnlyValidUnknownTypeTransaction.d.ts.map +1 -1
  102. package/internal/hardhat-network/provider/transactions/ReadOnlyValidUnknownTypeTransaction.js +2 -2
  103. package/internal/hardhat-network/provider/transactions/ReadOnlyValidUnknownTypeTransaction.js.map +1 -1
  104. package/internal/hardhat-network/provider/types/HardhatBlockchainInterface.d.ts +5 -4
  105. package/internal/hardhat-network/provider/types/HardhatBlockchainInterface.d.ts.map +1 -1
  106. package/internal/hardhat-network/provider/utils/convertToEdr.d.ts +14 -0
  107. package/internal/hardhat-network/provider/utils/convertToEdr.d.ts.map +1 -0
  108. package/internal/hardhat-network/provider/utils/convertToEdr.js +194 -0
  109. package/internal/hardhat-network/provider/utils/convertToEdr.js.map +1 -0
  110. package/internal/hardhat-network/provider/utils/getCurrentTimestamp.d.ts +0 -1
  111. package/internal/hardhat-network/provider/utils/getCurrentTimestamp.d.ts.map +1 -1
  112. package/internal/hardhat-network/provider/utils/getCurrentTimestamp.js +1 -5
  113. package/internal/hardhat-network/provider/utils/getCurrentTimestamp.js.map +1 -1
  114. package/internal/hardhat-network/provider/utils/makeCommon.d.ts +1 -1
  115. package/internal/hardhat-network/provider/utils/makeCommon.d.ts.map +1 -1
  116. package/internal/hardhat-network/provider/utils/makeCommon.js +1 -3
  117. package/internal/hardhat-network/provider/utils/makeCommon.js.map +1 -1
  118. package/internal/hardhat-network/provider/utils/makeFakeSignature.d.ts +2 -2
  119. package/internal/hardhat-network/provider/utils/makeFakeSignature.d.ts.map +1 -1
  120. package/internal/hardhat-network/provider/utils/makeFakeSignature.js +1 -15
  121. package/internal/hardhat-network/provider/utils/makeFakeSignature.js.map +1 -1
  122. package/internal/hardhat-network/provider/utils/makeForkClient.d.ts +10 -1
  123. package/internal/hardhat-network/provider/utils/makeForkClient.d.ts.map +1 -1
  124. package/internal/hardhat-network/provider/utils/makeForkClient.js +38 -18
  125. package/internal/hardhat-network/provider/utils/makeForkClient.js.map +1 -1
  126. package/internal/hardhat-network/provider/utils/makeStateTrie.js +2 -2
  127. package/internal/hardhat-network/provider/utils/makeStateTrie.js.map +1 -1
  128. package/internal/hardhat-network/provider/utils/putGenesisBlock.d.ts +3 -1
  129. package/internal/hardhat-network/provider/utils/putGenesisBlock.d.ts.map +1 -1
  130. package/internal/hardhat-network/provider/utils/putGenesisBlock.js +2 -6
  131. package/internal/hardhat-network/provider/utils/putGenesisBlock.js.map +1 -1
  132. package/internal/hardhat-network/provider/utils/random.d.ts +1 -0
  133. package/internal/hardhat-network/provider/utils/random.d.ts.map +1 -1
  134. package/internal/hardhat-network/provider/utils/random.js +7 -1
  135. package/internal/hardhat-network/provider/utils/random.js.map +1 -1
  136. package/internal/hardhat-network/provider/utils/reorgs-protection.d.ts +1 -1
  137. package/internal/hardhat-network/provider/utils/reorgs-protection.d.ts.map +1 -1
  138. package/internal/hardhat-network/provider/utils/reorgs-protection.js +5 -5
  139. package/internal/hardhat-network/provider/utils/reorgs-protection.js.map +1 -1
  140. package/internal/hardhat-network/provider/vm/exit.d.ts +22 -0
  141. package/internal/hardhat-network/provider/vm/exit.d.ts.map +1 -0
  142. package/internal/hardhat-network/provider/vm/exit.js +93 -0
  143. package/internal/hardhat-network/provider/vm/exit.js.map +1 -0
  144. package/internal/hardhat-network/provider/vm/minimal-vm.d.ts +29 -0
  145. package/internal/hardhat-network/provider/vm/minimal-vm.d.ts.map +1 -0
  146. package/internal/hardhat-network/provider/vm/minimal-vm.js +43 -0
  147. package/internal/hardhat-network/provider/vm/minimal-vm.js.map +1 -0
  148. package/internal/hardhat-network/provider/vm/proxy-vm.d.ts +36 -0
  149. package/internal/hardhat-network/provider/vm/proxy-vm.d.ts.map +1 -0
  150. package/internal/hardhat-network/provider/vm/proxy-vm.js +73 -0
  151. package/internal/hardhat-network/provider/vm/proxy-vm.js.map +1 -0
  152. package/internal/hardhat-network/provider/vm/types.d.ts +28 -0
  153. package/internal/hardhat-network/provider/vm/types.d.ts.map +1 -0
  154. package/internal/hardhat-network/provider/vm/types.js +3 -0
  155. package/internal/hardhat-network/provider/vm/types.js.map +1 -0
  156. package/internal/hardhat-network/stack-traces/consoleLogger.d.ts +6 -0
  157. package/internal/hardhat-network/stack-traces/consoleLogger.d.ts.map +1 -1
  158. package/internal/hardhat-network/stack-traces/consoleLogger.js +33 -16
  159. package/internal/hardhat-network/stack-traces/consoleLogger.js.map +1 -1
  160. package/internal/hardhat-network/stack-traces/contracts-identifier.d.ts +1 -2
  161. package/internal/hardhat-network/stack-traces/contracts-identifier.d.ts.map +1 -1
  162. package/internal/hardhat-network/stack-traces/contracts-identifier.js +6 -7
  163. package/internal/hardhat-network/stack-traces/contracts-identifier.js.map +1 -1
  164. package/internal/hardhat-network/stack-traces/debug.js +6 -6
  165. package/internal/hardhat-network/stack-traces/debug.js.map +1 -1
  166. package/internal/hardhat-network/stack-traces/error-inferrer.d.ts.map +1 -1
  167. package/internal/hardhat-network/stack-traces/error-inferrer.js +13 -7
  168. package/internal/hardhat-network/stack-traces/error-inferrer.js.map +1 -1
  169. package/internal/hardhat-network/stack-traces/message-trace.d.ts +8 -3
  170. package/internal/hardhat-network/stack-traces/message-trace.d.ts.map +1 -1
  171. package/internal/hardhat-network/stack-traces/message-trace.js +22 -1
  172. package/internal/hardhat-network/stack-traces/message-trace.js.map +1 -1
  173. package/internal/hardhat-network/stack-traces/model.d.ts +8 -0
  174. package/internal/hardhat-network/stack-traces/model.d.ts.map +1 -1
  175. package/internal/hardhat-network/stack-traces/model.js +52 -0
  176. package/internal/hardhat-network/stack-traces/model.js.map +1 -1
  177. package/internal/hardhat-network/stack-traces/opcodes.d.ts +1 -0
  178. package/internal/hardhat-network/stack-traces/opcodes.d.ts.map +1 -1
  179. package/internal/hardhat-network/stack-traces/opcodes.js +5 -1
  180. package/internal/hardhat-network/stack-traces/opcodes.js.map +1 -1
  181. package/internal/hardhat-network/stack-traces/solidity-errors.js +2 -2
  182. package/internal/hardhat-network/stack-traces/solidity-errors.js.map +1 -1
  183. package/internal/hardhat-network/stack-traces/solidityTracer.d.ts.map +1 -1
  184. package/internal/hardhat-network/stack-traces/solidityTracer.js +5 -5
  185. package/internal/hardhat-network/stack-traces/solidityTracer.js.map +1 -1
  186. package/internal/hardhat-network/stack-traces/vm-debug-tracer.d.ts.map +1 -1
  187. package/internal/hardhat-network/stack-traces/vm-debug-tracer.js +28 -34
  188. package/internal/hardhat-network/stack-traces/vm-debug-tracer.js.map +1 -1
  189. package/internal/hardhat-network/stack-traces/vm-trace-decoder.d.ts +7 -0
  190. package/internal/hardhat-network/stack-traces/vm-trace-decoder.d.ts.map +1 -1
  191. package/internal/hardhat-network/stack-traces/vm-trace-decoder.js +69 -2
  192. package/internal/hardhat-network/stack-traces/vm-trace-decoder.js.map +1 -1
  193. package/internal/hardhat-network/stack-traces/vm-tracer.d.ts +7 -12
  194. package/internal/hardhat-network/stack-traces/vm-tracer.d.ts.map +1 -1
  195. package/internal/hardhat-network/stack-traces/vm-tracer.js +46 -65
  196. package/internal/hardhat-network/stack-traces/vm-tracer.js.map +1 -1
  197. package/internal/util/date.d.ts +1 -0
  198. package/internal/util/date.d.ts.map +1 -1
  199. package/internal/util/date.js +5 -1
  200. package/internal/util/date.js.map +1 -1
  201. package/internal/util/hardforks.d.ts +2 -0
  202. package/internal/util/hardforks.d.ts.map +1 -1
  203. package/internal/util/hardforks.js +27 -1
  204. package/internal/util/hardforks.js.map +1 -1
  205. package/package.json +16 -14
  206. package/src/internal/core/providers/construction.ts +7 -9
  207. package/src/internal/core/providers/http.ts +3 -1
  208. package/src/internal/core/runtime-environment.ts +2 -1
  209. package/src/internal/hardhat-network/jsonrpc/client.ts +1 -28
  210. package/src/internal/hardhat-network/jsonrpc/handler.ts +9 -1
  211. package/src/internal/hardhat-network/provider/modules/logger.ts +6 -801
  212. package/src/internal/hardhat-network/provider/node-types.ts +2 -89
  213. package/src/internal/hardhat-network/provider/output.ts +0 -352
  214. package/src/internal/hardhat-network/provider/provider.ts +501 -261
  215. package/src/internal/hardhat-network/provider/utils/convertToEdr.ts +232 -0
  216. package/src/internal/hardhat-network/provider/utils/getCurrentTimestamp.ts +0 -4
  217. package/src/internal/hardhat-network/provider/utils/makeCommon.ts +1 -12
  218. package/src/internal/hardhat-network/provider/utils/makeForkClient.ts +63 -24
  219. package/src/internal/hardhat-network/provider/utils/random.ts +8 -1
  220. package/src/internal/hardhat-network/provider/utils/reorgs-protection.ts +5 -5
  221. package/src/internal/hardhat-network/provider/vm/exit.ts +101 -0
  222. package/src/internal/hardhat-network/provider/vm/minimal-vm.ts +98 -0
  223. package/src/internal/hardhat-network/provider/vm/types.ts +32 -0
  224. package/src/internal/hardhat-network/stack-traces/consoleLogger.ts +40 -21
  225. package/src/internal/hardhat-network/stack-traces/contracts-identifier.ts +10 -12
  226. package/src/internal/hardhat-network/stack-traces/debug.ts +6 -6
  227. package/src/internal/hardhat-network/stack-traces/error-inferrer.ts +15 -8
  228. package/src/internal/hardhat-network/stack-traces/message-trace.ts +40 -4
  229. package/src/internal/hardhat-network/stack-traces/model.ts +61 -0
  230. package/src/internal/hardhat-network/stack-traces/opcodes.ts +4 -0
  231. package/src/internal/hardhat-network/stack-traces/solidity-errors.ts +2 -2
  232. package/src/internal/hardhat-network/stack-traces/solidityTracer.ts +6 -5
  233. package/src/internal/hardhat-network/stack-traces/vm-trace-decoder.ts +113 -4
  234. package/src/internal/hardhat-network/stack-traces/vm-tracer.ts +67 -95
  235. package/src/internal/util/date.ts +4 -0
  236. package/src/internal/util/hardforks.ts +52 -0
  237. package/src/internal/hardhat-network/provider/BlockchainBase.ts +0 -185
  238. package/src/internal/hardhat-network/provider/BlockchainData.ts +0 -261
  239. package/src/internal/hardhat-network/provider/HardhatBlockchain.ts +0 -140
  240. package/src/internal/hardhat-network/provider/PoolState.ts +0 -48
  241. package/src/internal/hardhat-network/provider/TransactionQueue.ts +0 -158
  242. package/src/internal/hardhat-network/provider/TxPool.ts +0 -715
  243. package/src/internal/hardhat-network/provider/ethereumjs-workarounds.ts +0 -21
  244. package/src/internal/hardhat-network/provider/filter.ts +0 -142
  245. package/src/internal/hardhat-network/provider/fork/ForkBlockchain.ts +0 -433
  246. package/src/internal/hardhat-network/provider/fork/ForkStateManager.ts +0 -480
  247. package/src/internal/hardhat-network/provider/fork/rpcToBlockData.ts +0 -35
  248. package/src/internal/hardhat-network/provider/fork/rpcToTxData.ts +0 -44
  249. package/src/internal/hardhat-network/provider/modules/base.ts +0 -156
  250. package/src/internal/hardhat-network/provider/modules/debug.ts +0 -104
  251. package/src/internal/hardhat-network/provider/modules/eth.ts +0 -1781
  252. package/src/internal/hardhat-network/provider/modules/evm.ts +0 -249
  253. package/src/internal/hardhat-network/provider/modules/hardhat.ts +0 -481
  254. package/src/internal/hardhat-network/provider/modules/net.ts +0 -60
  255. package/src/internal/hardhat-network/provider/modules/personal.ts +0 -40
  256. package/src/internal/hardhat-network/provider/modules/web3.ts +0 -49
  257. package/src/internal/hardhat-network/provider/node.ts +0 -2999
  258. package/src/internal/hardhat-network/provider/transactions/FakeSenderAccessListEIP2930Transaction.ts +0 -226
  259. package/src/internal/hardhat-network/provider/transactions/FakeSenderEIP1559Transaction.ts +0 -224
  260. package/src/internal/hardhat-network/provider/transactions/FakeSenderTransaction.ts +0 -216
  261. package/src/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP1559Transaction.ts +0 -143
  262. package/src/internal/hardhat-network/provider/transactions/ReadOnlyValidEIP2930Transaction.ts +0 -144
  263. package/src/internal/hardhat-network/provider/transactions/ReadOnlyValidTransaction.ts +0 -171
  264. package/src/internal/hardhat-network/provider/transactions/ReadOnlyValidUnknownTypeTransaction.ts +0 -169
  265. package/src/internal/hardhat-network/provider/types/HardhatBlockchainInterface.ts +0 -25
  266. package/src/internal/hardhat-network/provider/utils/makeFakeSignature.ts +0 -60
  267. package/src/internal/hardhat-network/provider/utils/makeStateTrie.ts +0 -29
  268. package/src/internal/hardhat-network/provider/utils/putGenesisBlock.ts +0 -61
  269. package/src/internal/hardhat-network/provider/utils/reorganizeTransactionsLists.ts +0 -45
  270. package/src/internal/hardhat-network/provider/utils/txMapToArray.ts +0 -7
  271. package/src/internal/hardhat-network/stack-traces/vm-debug-tracer.ts +0 -630
@@ -1,2999 +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
- // create the account if it doesn't exist
1434
- const account = await this._stateManager.getAccount(address);
1435
- if (account === undefined) {
1436
- await this._stateManager.putAccount(address, new Account());
1437
- }
1438
-
1439
- await this._stateManager.putContractStorage(
1440
- address,
1441
- setLengthLeft(bigIntToBytes(positionIndex), 32),
1442
- value
1443
- );
1444
- await this._persistIrregularWorldState();
1445
- }
1446
-
1447
- public async traceCall(
1448
- callParams: CallParams,
1449
- block: bigint | "pending",
1450
- traceConfig: RpcDebugTracingConfig
1451
- ) {
1452
- const vmDebugTracer = new VMDebugTracer(this._vm);
1453
-
1454
- return vmDebugTracer.trace(async () => {
1455
- await this.runCall(callParams, block);
1456
- }, traceConfig);
1457
- }
1458
-
1459
- public async traceTransaction(hash: Buffer, config: RpcDebugTracingConfig) {
1460
- const block = await this.getBlockByTransactionHash(hash);
1461
- if (block === undefined) {
1462
- throw new InvalidInputError(
1463
- `Unable to find a block containing transaction ${bufferToHex(hash)}`
1464
- );
1465
- }
1466
-
1467
- return this._runInBlockContext(block.header.number - 1n, async () => {
1468
- const blockNumber = block.header.number;
1469
- const blockchain = this._blockchain;
1470
- let vm = this._vm;
1471
- if (
1472
- blockchain instanceof ForkBlockchain &&
1473
- blockNumber <= blockchain.getForkBlockNumber()
1474
- ) {
1475
- assertHardhatInvariant(
1476
- this._forkNetworkId !== undefined,
1477
- "this._forkNetworkId should exist if the blockchain is an instance of ForkBlockchain"
1478
- );
1479
-
1480
- const common = this._getCommonForTracing(
1481
- this._forkNetworkId,
1482
- blockNumber
1483
- );
1484
-
1485
- vm = await VM.create({
1486
- common,
1487
- activatePrecompiles: true,
1488
- stateManager: this._vm.stateManager,
1489
- blockchain: this._vm.blockchain,
1490
- });
1491
- }
1492
-
1493
- // We don't support tracing transactions before the spuriousDragon fork
1494
- // to avoid having to distinguish between empty and non-existing accounts.
1495
- // We *could* do it during the non-forked mode, but for simplicity we just
1496
- // don't support it at all.
1497
- const isPreSpuriousDragon = !vm.common.gteHardfork("spuriousDragon");
1498
- if (isPreSpuriousDragon) {
1499
- throw new InvalidInputError(
1500
- "Tracing is not supported for transactions using hardforks older than Spurious Dragon. "
1501
- );
1502
- }
1503
-
1504
- for (const tx of block.transactions) {
1505
- let txWithCommon: TypedTransaction;
1506
- const sender = tx.getSenderAddress();
1507
- if (tx.type === 0) {
1508
- txWithCommon = new FakeSenderTransaction(sender, tx, {
1509
- common: vm.common,
1510
- });
1511
- } else if (tx.type === 1) {
1512
- txWithCommon = new FakeSenderAccessListEIP2930Transaction(
1513
- sender,
1514
- tx,
1515
- { common: vm.common }
1516
- );
1517
- } else if (tx.type === 2) {
1518
- txWithCommon = new FakeSenderEIP1559Transaction(
1519
- sender,
1520
- { ...tx, gasPrice: undefined },
1521
- { common: vm.common }
1522
- );
1523
- } else {
1524
- throw new InternalError(
1525
- "Only legacy, EIP2930, and EIP1559 txs are supported"
1526
- );
1527
- }
1528
-
1529
- const txHash = txWithCommon.hash();
1530
- if (equalsBytes(txHash, hash)) {
1531
- const vmDebugTracer = new VMDebugTracer(vm);
1532
- return vmDebugTracer.trace(async () => {
1533
- await vm.runTx({
1534
- tx: txWithCommon,
1535
- block,
1536
- skipHardForkValidation: true,
1537
- });
1538
- }, config);
1539
- }
1540
- await vm.runTx({
1541
- tx: txWithCommon,
1542
- block,
1543
- skipHardForkValidation: true,
1544
- });
1545
- }
1546
- throw new TransactionExecutionError(
1547
- `Unable to find a transaction in a block that contains that transaction, this should never happen`
1548
- );
1549
- });
1550
- }
1551
-
1552
- public async getFeeHistory(
1553
- blockCount: bigint,
1554
- newestBlock: bigint | "pending",
1555
- rewardPercentiles: number[]
1556
- ): Promise<FeeHistory> {
1557
- const latestBlock = this.getLatestBlockNumber();
1558
- const pendingBlockNumber = latestBlock + 1n;
1559
-
1560
- const resolvedNewestBlock =
1561
- newestBlock === "pending" ? pendingBlockNumber : newestBlock;
1562
-
1563
- const oldestBlock = BigIntUtils.max(
1564
- resolvedNewestBlock - blockCount + 1n,
1565
- 0n
1566
- );
1567
-
1568
- // This is part of a temporary fix to https://github.com/NomicFoundation/hardhat/issues/2380
1569
- const rangeIncludesRemoteBlocks =
1570
- this._forkBlockNumber !== undefined &&
1571
- oldestBlock <= this._forkBlockNumber;
1572
-
1573
- const baseFeePerGas: bigint[] = [];
1574
- const gasUsedRatio: number[] = [];
1575
- const reward: bigint[][] = [];
1576
-
1577
- const lastBlock = resolvedNewestBlock + 1n;
1578
-
1579
- // This is part of a temporary fix to https://github.com/NomicFoundation/hardhat/issues/2380
1580
- if (rangeIncludesRemoteBlocks) {
1581
- try {
1582
- const lastRemoteBlock = BigIntUtils.min(
1583
- BigInt(this._forkBlockNumber!),
1584
- lastBlock
1585
- );
1586
-
1587
- const remoteBlockCount = lastRemoteBlock - oldestBlock + 1n;
1588
-
1589
- const remoteValues = await this._forkClient!.getFeeHistory(
1590
- remoteBlockCount,
1591
- lastRemoteBlock,
1592
- rewardPercentiles
1593
- );
1594
-
1595
- baseFeePerGas.push(...remoteValues.baseFeePerGas);
1596
- gasUsedRatio.push(...remoteValues.gasUsedRatio);
1597
- if (remoteValues.reward !== undefined) {
1598
- reward.push(...remoteValues.reward);
1599
- }
1600
- } catch (e) {
1601
- // TODO: we can return less blocks here still be compliant with the spec
1602
- throw new InternalError(
1603
- "Remote node did not answer to eth_feeHistory correctly",
1604
- e instanceof Error ? e : undefined
1605
- );
1606
- }
1607
- }
1608
-
1609
- // We get the pending block here, and only if necessary, as it's something
1610
- // costly to do.
1611
- let pendingBlock: Block | undefined;
1612
- if (lastBlock >= pendingBlockNumber) {
1613
- pendingBlock = await this.getBlockByNumber("pending");
1614
- }
1615
-
1616
- // This is part of a temporary fix to https://github.com/NomicFoundation/hardhat/issues/2380
1617
- const firstLocalBlock = !rangeIncludesRemoteBlocks
1618
- ? oldestBlock
1619
- : BigIntUtils.min(BigInt(this._forkBlockNumber!), lastBlock) + 1n;
1620
-
1621
- for (
1622
- let blockNumber = firstLocalBlock; // This is part of a temporary fix to https://github.com/NomicFoundation/hardhat/issues/2380
1623
- blockNumber <= lastBlock;
1624
- blockNumber++
1625
- ) {
1626
- if (blockNumber < pendingBlockNumber) {
1627
- // We know the block exists
1628
- const block = (await this.getBlockByNumber(blockNumber))!;
1629
- baseFeePerGas.push(block.header.baseFeePerGas ?? 0n);
1630
-
1631
- if (blockNumber < lastBlock) {
1632
- gasUsedRatio.push(this._getGasUsedRatio(block));
1633
-
1634
- if (rewardPercentiles.length > 0) {
1635
- reward.push(await this._getRewards(block, rewardPercentiles));
1636
- }
1637
- }
1638
- } else if (blockNumber === pendingBlockNumber) {
1639
- // This can only be run with EIP-1559, so this exists
1640
- baseFeePerGas.push((await this.getNextBlockBaseFeePerGas())!);
1641
-
1642
- if (blockNumber < lastBlock) {
1643
- gasUsedRatio.push(this._getGasUsedRatio(pendingBlock!));
1644
-
1645
- if (rewardPercentiles.length > 0) {
1646
- // We don't compute this for the pending block, as there's no
1647
- // effective miner fee yet.
1648
- reward.push(rewardPercentiles.map((_) => 0n));
1649
- }
1650
- }
1651
- } else if (blockNumber === pendingBlockNumber + 1n) {
1652
- baseFeePerGas.push(pendingBlock!.header.calcNextBaseFee());
1653
- } else {
1654
- assertHardhatInvariant(false, "This should never happen");
1655
- }
1656
- }
1657
-
1658
- return {
1659
- oldestBlock,
1660
- baseFeePerGas,
1661
- gasUsedRatio,
1662
- reward: rewardPercentiles.length > 0 ? reward : undefined,
1663
- };
1664
- }
1665
-
1666
- public async setCoinbase(coinbase: Address) {
1667
- this._coinbase = coinbase.toString();
1668
- }
1669
-
1670
- private _getGasUsedRatio(block: Block): number {
1671
- const FLOATS_PRECISION = 100_000;
1672
-
1673
- return (
1674
- Number(
1675
- (block.header.gasUsed * BigInt(FLOATS_PRECISION)) /
1676
- block.header.gasLimit
1677
- ) / FLOATS_PRECISION
1678
- );
1679
- }
1680
-
1681
- private async _getRewards(
1682
- block: Block,
1683
- rewardPercentiles: number[]
1684
- ): Promise<bigint[]> {
1685
- const FLOATS_PRECISION = 100_000;
1686
-
1687
- if (block.transactions.length === 0) {
1688
- return rewardPercentiles.map((_) => 0n);
1689
- }
1690
-
1691
- const receipts = await Promise.all(
1692
- block.transactions
1693
- .map((tx) => tx.hash())
1694
- .map((hash) => this.getTransactionReceipt(hash))
1695
- );
1696
-
1697
- const effectiveGasRewardAndGas = receipts
1698
- .map((r, i) => {
1699
- const tx = block.transactions[i];
1700
- const baseFeePerGas = block.header.baseFeePerGas ?? 0n;
1701
-
1702
- // reward = min(maxPriorityFeePerGas, maxFeePerGas - baseFeePerGas)
1703
- let effectiveGasReward: bigint;
1704
- if ("maxPriorityFeePerGas" in tx) {
1705
- effectiveGasReward = tx.maxFeePerGas - baseFeePerGas;
1706
- if (tx.maxPriorityFeePerGas < effectiveGasReward) {
1707
- effectiveGasReward = tx.maxPriorityFeePerGas;
1708
- }
1709
- } else {
1710
- effectiveGasReward = tx.gasPrice - baseFeePerGas;
1711
- }
1712
-
1713
- return {
1714
- effectiveGasReward,
1715
- gasUsed: rpcQuantityToBigInt(r?.gasUsed!),
1716
- };
1717
- })
1718
- .sort((a, b) =>
1719
- BigIntUtils.cmp(a.effectiveGasReward, b.effectiveGasReward)
1720
- );
1721
-
1722
- return rewardPercentiles.map((p) => {
1723
- let gasUsed = 0n;
1724
- const targetGas =
1725
- (block.header.gasLimit * BigInt(Math.ceil(p * FLOATS_PRECISION))) /
1726
- BigInt(100 * FLOATS_PRECISION);
1727
-
1728
- for (const values of effectiveGasRewardAndGas) {
1729
- gasUsed += values.gasUsed;
1730
-
1731
- if (targetGas <= gasUsed) {
1732
- return values.effectiveGasReward;
1733
- }
1734
- }
1735
-
1736
- return effectiveGasRewardAndGas[effectiveGasRewardAndGas.length - 1]
1737
- .effectiveGasReward;
1738
- });
1739
- }
1740
-
1741
- private async _addPendingTransaction(tx: TypedTransaction): Promise<string> {
1742
- await this._txPool.addTransaction(tx);
1743
- await this._notifyPendingTransaction(tx);
1744
- return bufferToHex(tx.hash());
1745
- }
1746
-
1747
- private async _mineTransaction(
1748
- tx: TypedTransaction
1749
- ): Promise<MineBlockResult> {
1750
- await this._addPendingTransaction(tx);
1751
- return this.mineBlock();
1752
- }
1753
-
1754
- private async _mineTransactionAndPending(
1755
- tx: TypedTransaction
1756
- ): Promise<MineBlockResult[]> {
1757
- const snapshotId = await this.takeSnapshot();
1758
-
1759
- let result;
1760
- try {
1761
- const txHash = await this._addPendingTransaction(tx);
1762
- result = await this._mineBlocksUntilTransactionIsIncluded(txHash);
1763
- } catch (err) {
1764
- await this.revertToSnapshot(snapshotId);
1765
- throw err;
1766
- }
1767
-
1768
- this._removeSnapshot(snapshotId);
1769
- return result;
1770
- }
1771
-
1772
- private async _mineBlocksUntilTransactionIsIncluded(
1773
- txHash: string
1774
- ): Promise<MineBlockResult[]> {
1775
- const results = [];
1776
- let txReceipt;
1777
- do {
1778
- if (!this._txPool.hasPendingTransactions()) {
1779
- throw new TransactionExecutionError(
1780
- "Failed to mine transaction for unknown reason, this should never happen"
1781
- );
1782
- }
1783
- results.push(await this.mineBlock());
1784
- txReceipt = await this.getTransactionReceipt(txHash);
1785
- } while (txReceipt === undefined);
1786
-
1787
- while (this._txPool.hasPendingTransactions()) {
1788
- results.push(await this.mineBlock());
1789
- }
1790
-
1791
- return results;
1792
- }
1793
-
1794
- private async _gatherTraces(result: ExecResult): Promise<GatherTracesResult> {
1795
- let vmTrace = this._vmTracer.getLastTopLevelMessageTrace();
1796
- const vmTracerError = this._vmTracer.getLastError();
1797
- this._vmTracer.clearLastError();
1798
-
1799
- if (vmTrace !== undefined) {
1800
- vmTrace = this._vmTraceDecoder.tryToDecodeMessageTrace(vmTrace);
1801
- }
1802
-
1803
- const consoleLogMessages = await this._getConsoleLogMessages(
1804
- vmTrace,
1805
- vmTracerError
1806
- );
1807
-
1808
- const error = await this._manageErrors(result, vmTrace, vmTracerError);
1809
-
1810
- return {
1811
- trace: vmTrace,
1812
- consoleLogMessages,
1813
- error,
1814
- };
1815
- }
1816
-
1817
- private async _validateAutominedTx(tx: TypedTransaction) {
1818
- let sender: Address;
1819
- try {
1820
- sender = tx.getSenderAddress(); // verifies signature as a side effect
1821
- } catch (e) {
1822
- if (e instanceof Error) {
1823
- throw new InvalidInputError(e.message);
1824
- }
1825
-
1826
- // eslint-disable-next-line @nomicfoundation/hardhat-internal-rules/only-hardhat-error
1827
- throw e;
1828
- }
1829
-
1830
- // validate nonce
1831
- const nextPendingNonce = await this._txPool.getNextPendingNonce(sender);
1832
- const txNonce = tx.nonce;
1833
-
1834
- const expectedNonceMsg = `Expected nonce to be ${nextPendingNonce.toString()} but got ${txNonce.toString()}.`;
1835
- if (txNonce > nextPendingNonce) {
1836
- throw new InvalidInputError(
1837
- `Nonce too high. ${expectedNonceMsg} Note that transactions can't be queued when automining.`
1838
- );
1839
- }
1840
- if (txNonce < nextPendingNonce) {
1841
- throw new InvalidInputError(`Nonce too low. ${expectedNonceMsg}`);
1842
- }
1843
-
1844
- // validate gas price
1845
- const txPriorityFee =
1846
- "gasPrice" in tx ? tx.gasPrice : tx.maxPriorityFeePerGas;
1847
- if (txPriorityFee < this._minGasPrice) {
1848
- throw new InvalidInputError(
1849
- `Transaction gas price is ${txPriorityFee.toString()}, which is below the minimum of ${this._minGasPrice.toString()}`
1850
- );
1851
- }
1852
-
1853
- // Validate that maxFeePerGas >= next block's baseFee
1854
- const nextBlockGasFee = await this.getNextBlockBaseFeePerGas();
1855
- if (nextBlockGasFee !== undefined) {
1856
- if ("maxFeePerGas" in tx) {
1857
- if (nextBlockGasFee > tx.maxFeePerGas) {
1858
- throw new InvalidInputError(
1859
- `Transaction maxFeePerGas (${tx.maxFeePerGas.toString()}) is too low for the next block, which has a baseFeePerGas of ${nextBlockGasFee.toString()}`
1860
- );
1861
- }
1862
- } else {
1863
- if (nextBlockGasFee > tx.gasPrice) {
1864
- throw new InvalidInputError(
1865
- `Transaction gasPrice (${tx.gasPrice.toString()}) is too low for the next block, which has a baseFeePerGas of ${nextBlockGasFee.toString()}`
1866
- );
1867
- }
1868
- }
1869
- }
1870
- }
1871
-
1872
- /**
1873
- * Mines a new block with as many pending txs as possible, adding it to
1874
- * the VM's blockchain.
1875
- *
1876
- * This method reverts any modification to the state manager if it throws.
1877
- */
1878
- private async _mineBlockWithPendingTxs(
1879
- blockTimestamp: bigint
1880
- ): Promise<MineBlockResult> {
1881
- const parentBlock = await this.getLatestBlock();
1882
-
1883
- const headerData: HeaderData = {
1884
- gasLimit: this.getBlockGasLimit(),
1885
- coinbase: this.getCoinbaseAddress(),
1886
- nonce: this.isPostMergeHardfork()
1887
- ? "0x0000000000000000"
1888
- : "0x0000000000000042",
1889
- timestamp: blockTimestamp,
1890
- };
1891
-
1892
- if (this.isPostMergeHardfork()) {
1893
- headerData.mixHash = this._getNextMixHash();
1894
- }
1895
-
1896
- if (this.isPostCancunHardfork()) {
1897
- headerData.parentBeaconBlockRoot = this._getNextParentBeaconBlockRoot();
1898
- }
1899
-
1900
- headerData.baseFeePerGas = await this.getNextBlockBaseFeePerGas();
1901
-
1902
- const blockBuilder = await this._vm.buildBlock({
1903
- parentBlock,
1904
- headerData,
1905
- blockOpts: { calcDifficultyFromHeader: parentBlock.header },
1906
- });
1907
-
1908
- try {
1909
- const traces: GatherTracesResult[] = [];
1910
-
1911
- const blockGasLimit = this.getBlockGasLimit();
1912
- const minTxFee = this._getMinimalTransactionFee();
1913
- const pendingTxs = this._txPool.getPendingTransactions();
1914
- const transactionQueue = new TransactionQueue(
1915
- pendingTxs,
1916
- this._mempoolOrder,
1917
- headerData.baseFeePerGas
1918
- );
1919
-
1920
- let tx = transactionQueue.getNextTransaction();
1921
-
1922
- const results = [];
1923
- const receipts = [];
1924
-
1925
- while (
1926
- blockGasLimit - blockBuilder.gasUsed >= minTxFee &&
1927
- tx !== undefined
1928
- ) {
1929
- if (
1930
- !this._isTxMinable(tx, headerData.baseFeePerGas) ||
1931
- tx.gasLimit > blockGasLimit - blockBuilder.gasUsed
1932
- ) {
1933
- transactionQueue.removeLastSenderTransactions();
1934
- } else {
1935
- const txResult = await blockBuilder.addTransaction(tx);
1936
-
1937
- traces.push(await this._gatherTraces(txResult.execResult));
1938
- results.push(txResult);
1939
- receipts.push(txResult.receipt);
1940
- }
1941
-
1942
- tx = transactionQueue.getNextTransaction();
1943
- }
1944
-
1945
- const block = await blockBuilder.build();
1946
-
1947
- await this._txPool.updatePendingAndQueued();
1948
-
1949
- return {
1950
- block,
1951
- blockResult: {
1952
- results,
1953
- receipts,
1954
- stateRoot: block.header.stateRoot,
1955
- logsBloom: block.header.logsBloom,
1956
- receiptsRoot: block.header.receiptTrie,
1957
- gasUsed: block.header.gasUsed,
1958
- },
1959
- traces,
1960
- };
1961
- } catch (err) {
1962
- await blockBuilder.revert();
1963
- throw err;
1964
- }
1965
- }
1966
-
1967
- private _getMinimalTransactionFee(): bigint {
1968
- // Typically 21_000 gas
1969
- return this._vm.common.param("gasPrices", "tx");
1970
- }
1971
-
1972
- private async _getFakeTransaction(
1973
- txParams: TransactionParams
1974
- ): Promise<
1975
- | FakeSenderTransaction
1976
- | FakeSenderAccessListEIP2930Transaction
1977
- | FakeSenderEIP1559Transaction
1978
- > {
1979
- const sender = new Address(txParams.from);
1980
-
1981
- if ("maxFeePerGas" in txParams && txParams.maxFeePerGas !== undefined) {
1982
- return new FakeSenderEIP1559Transaction(sender, txParams, {
1983
- common: this._vm.common,
1984
- });
1985
- }
1986
-
1987
- if ("accessList" in txParams && txParams.accessList !== undefined) {
1988
- return new FakeSenderAccessListEIP2930Transaction(sender, txParams, {
1989
- common: this._vm.common,
1990
- });
1991
- }
1992
-
1993
- return new FakeSenderTransaction(sender, txParams, {
1994
- common: this._vm.common,
1995
- });
1996
- }
1997
-
1998
- private _getSnapshotIndex(id: number): number | undefined {
1999
- for (const [i, snapshot] of this._snapshots.entries()) {
2000
- if (snapshot.id === id) {
2001
- return i;
2002
- }
2003
-
2004
- // We already removed the snapshot we are looking for
2005
- if (snapshot.id > id) {
2006
- return undefined;
2007
- }
2008
- }
2009
-
2010
- return undefined;
2011
- }
2012
-
2013
- private _removeSnapshot(id: number) {
2014
- const snapshotIndex = this._getSnapshotIndex(id);
2015
- if (snapshotIndex === undefined) {
2016
- return;
2017
- }
2018
- this._snapshots.splice(snapshotIndex);
2019
- }
2020
-
2021
- private _initLocalAccounts(genesisAccounts: GenesisAccount[]) {
2022
- const privateKeys = genesisAccounts.map((acc) => toBytes(acc.privateKey));
2023
- for (const pk of privateKeys) {
2024
- this._localAccounts.set(bufferToHex(privateToAddress(pk)), pk);
2025
- }
2026
- }
2027
-
2028
- private async _getConsoleLogMessages(
2029
- vmTrace: MessageTrace | undefined,
2030
- vmTracerError: Error | undefined
2031
- ): Promise<string[]> {
2032
- if (vmTrace === undefined || vmTracerError !== undefined) {
2033
- log(
2034
- "Could not print console log. Please report this to help us improve Hardhat.\n",
2035
- vmTracerError
2036
- );
2037
-
2038
- return [];
2039
- }
2040
-
2041
- return this._consoleLogger.getLogMessages(vmTrace);
2042
- }
2043
-
2044
- private async _manageErrors(
2045
- vmResult: ExecResult,
2046
- vmTrace: MessageTrace | undefined,
2047
- vmTracerError: Error | undefined
2048
- ): Promise<SolidityError | TransactionExecutionError | undefined> {
2049
- if (vmResult.exceptionError === undefined) {
2050
- return undefined;
2051
- }
2052
-
2053
- let stackTrace: SolidityStackTrace | undefined;
2054
-
2055
- try {
2056
- if (vmTrace === undefined || vmTracerError !== undefined) {
2057
- throw vmTracerError;
2058
- }
2059
-
2060
- stackTrace = this._solidityTracer.getStackTrace(vmTrace);
2061
- } catch (err) {
2062
- this._failedStackTraces += 1;
2063
- log(
2064
- "Could not generate stack trace. Please report this to help us improve Hardhat.\n",
2065
- err
2066
- );
2067
- }
2068
-
2069
- const error = vmResult.exceptionError;
2070
-
2071
- // we don't use `instanceof` in case someone uses a different VM dependency
2072
- // see https://github.com/nomiclabs/hardhat/issues/1317
2073
- const isVmError = "error" in error && typeof error.error === "string";
2074
-
2075
- // If this is not a VM error, or if it's an internal VM error, we just
2076
- // rethrow. An example of a non-VmError being thrown here is an HTTP error
2077
- // coming from the ForkedStateManager.
2078
- if (!isVmError || error.error === ERROR.INTERNAL_ERROR) {
2079
- throw error;
2080
- }
2081
-
2082
- if (error.error === ERROR.CODESIZE_EXCEEDS_MAXIMUM) {
2083
- if (stackTrace !== undefined) {
2084
- return encodeSolidityStackTrace(
2085
- "Transaction ran out of gas",
2086
- stackTrace
2087
- );
2088
- }
2089
-
2090
- return new TransactionExecutionError("Transaction ran out of gas");
2091
- }
2092
-
2093
- if (error.error === ERROR.OUT_OF_GAS) {
2094
- // if the error is an out of gas, we ignore the inferred error in the
2095
- // trace
2096
- return new TransactionExecutionError("Transaction ran out of gas");
2097
- }
2098
-
2099
- const returnData = new ReturnData(vmResult.returnValue);
2100
-
2101
- let returnDataExplanation;
2102
- if (returnData.isEmpty()) {
2103
- returnDataExplanation = "without reason string";
2104
- } else if (returnData.isErrorReturnData()) {
2105
- returnDataExplanation = `with reason "${returnData.decodeError()}"`;
2106
- } else if (returnData.isPanicReturnData()) {
2107
- const panicCode = returnData.decodePanic().toString(16);
2108
- returnDataExplanation = `with panic code "0x${panicCode}"`;
2109
- } else {
2110
- returnDataExplanation = "with unrecognized return data or custom error";
2111
- }
2112
-
2113
- if (error.error === ERROR.REVERT) {
2114
- const fallbackMessage = `VM Exception while processing transaction: revert ${returnDataExplanation}`;
2115
-
2116
- if (stackTrace !== undefined) {
2117
- return encodeSolidityStackTrace(fallbackMessage, stackTrace);
2118
- }
2119
-
2120
- return new TransactionExecutionError(fallbackMessage);
2121
- }
2122
-
2123
- if (stackTrace !== undefined) {
2124
- return encodeSolidityStackTrace(
2125
- `Transaction failed: revert ${returnDataExplanation}`,
2126
- stackTrace
2127
- );
2128
- }
2129
-
2130
- return new TransactionExecutionError(
2131
- `Transaction reverted ${returnDataExplanation}`
2132
- );
2133
- }
2134
-
2135
- private _calculateTimestampAndOffset(
2136
- timestamp?: bigint
2137
- ): [bigint, boolean, bigint] {
2138
- let blockTimestamp: bigint;
2139
- let offsetShouldChange: boolean;
2140
- let newOffset: bigint = 0n;
2141
- const currentTimestamp = BigInt(getCurrentTimestamp());
2142
-
2143
- // if timestamp is not provided, we check nextBlockTimestamp, if it is
2144
- // set, we use it as the timestamp instead. If it is not set, we use
2145
- // time offset + real time as the timestamp.
2146
- if (timestamp === undefined || timestamp === 0n) {
2147
- if (this.getNextBlockTimestamp() === 0n) {
2148
- blockTimestamp = currentTimestamp + this.getTimeIncrement();
2149
- offsetShouldChange = false;
2150
- } else {
2151
- blockTimestamp = this.getNextBlockTimestamp();
2152
- offsetShouldChange = true;
2153
- }
2154
- } else {
2155
- offsetShouldChange = true;
2156
- blockTimestamp = timestamp;
2157
- }
2158
-
2159
- if (offsetShouldChange) {
2160
- newOffset = blockTimestamp - currentTimestamp;
2161
- }
2162
-
2163
- return [blockTimestamp, offsetShouldChange, newOffset];
2164
- }
2165
-
2166
- private _resetNextBlockTimestamp() {
2167
- this.setNextBlockTimestamp(0n);
2168
- }
2169
-
2170
- private async _notifyPendingTransaction(tx: TypedTransaction) {
2171
- this._filters.forEach((filter) => {
2172
- if (filter.type === Type.PENDING_TRANSACTION_SUBSCRIPTION) {
2173
- const hash = bufferToHex(tx.hash());
2174
- if (filter.subscription) {
2175
- this._emitEthEvent(filter.id, hash);
2176
- return;
2177
- }
2178
-
2179
- filter.hashes.push(hash);
2180
- }
2181
- });
2182
- }
2183
-
2184
- private _getLocalAccountPrivateKey(sender: Address): Uint8Array {
2185
- const senderAddress = sender.toString();
2186
- if (!this._localAccounts.has(senderAddress)) {
2187
- throw new InvalidInputError(`unknown account ${senderAddress}`);
2188
- }
2189
-
2190
- return this._localAccounts.get(senderAddress)!;
2191
- }
2192
-
2193
- /**
2194
- * Saves a block as successfully run. This method requires that the block
2195
- * was added to the blockchain.
2196
- */
2197
- private async _saveBlockAsSuccessfullyRun(
2198
- block: Block,
2199
- runBlockResult: RunBlockResult
2200
- ) {
2201
- const receipts = getRpcReceiptOutputsFromLocalBlockExecution(
2202
- block,
2203
- runBlockResult,
2204
- shouldShowTransactionTypeForHardfork(this._vm.common)
2205
- );
2206
-
2207
- this._blockchain.addTransactionReceipts(receipts);
2208
-
2209
- const td = await this.getBlockTotalDifficulty(block);
2210
- const rpcLogs: RpcLogOutput[] = [];
2211
- for (const receipt of receipts) {
2212
- rpcLogs.push(...receipt.logs);
2213
- }
2214
-
2215
- this._filters.forEach((filter, key) => {
2216
- if (filter.deadline.valueOf() < new Date().valueOf()) {
2217
- this._filters.delete(key);
2218
- }
2219
-
2220
- switch (filter.type) {
2221
- case Type.BLOCK_SUBSCRIPTION:
2222
- const hash = block.hash();
2223
- if (filter.subscription) {
2224
- this._emitEthEvent(
2225
- filter.id,
2226
- getRpcBlock(
2227
- block,
2228
- td,
2229
- shouldShowTransactionTypeForHardfork(this._vm.common),
2230
- false
2231
- )
2232
- );
2233
- return;
2234
- }
2235
-
2236
- filter.hashes.push(bufferToHex(hash));
2237
- break;
2238
- case Type.LOGS_SUBSCRIPTION:
2239
- if (
2240
- bloomFilter(
2241
- new Bloom(block.header.logsBloom),
2242
- filter.criteria!.addresses,
2243
- filter.criteria!.normalizedTopics
2244
- )
2245
- ) {
2246
- const logs = filterLogs(rpcLogs, filter.criteria!);
2247
- if (logs.length === 0) {
2248
- return;
2249
- }
2250
-
2251
- if (filter.subscription) {
2252
- logs.forEach((rpcLog) => {
2253
- this._emitEthEvent(filter.id, rpcLog);
2254
- });
2255
- return;
2256
- }
2257
-
2258
- filter.logs.push(...logs);
2259
- }
2260
- break;
2261
- }
2262
- });
2263
- }
2264
-
2265
- private async _timestampClashesWithPreviousBlockOne(
2266
- blockTimestamp: bigint
2267
- ): Promise<boolean> {
2268
- const latestBlock = await this.getLatestBlock();
2269
- const latestBlockTimestamp = latestBlock.header.timestamp;
2270
-
2271
- return latestBlockTimestamp === blockTimestamp;
2272
- }
2273
-
2274
- private async _runInBlockContext<T>(
2275
- blockNumberOrPending: bigint | "pending",
2276
- action: () => Promise<T>
2277
- ): Promise<T> {
2278
- if (blockNumberOrPending === "pending") {
2279
- return this._runInPendingBlockContext(action);
2280
- }
2281
-
2282
- if (blockNumberOrPending === this.getLatestBlockNumber()) {
2283
- return action();
2284
- }
2285
-
2286
- const block = await this.getBlockByNumber(blockNumberOrPending);
2287
- if (block === undefined) {
2288
- // TODO handle this better
2289
- throw new Error(
2290
- `Block with number ${blockNumberOrPending.toString()} doesn't exist. This should never happen.`
2291
- );
2292
- }
2293
-
2294
- const currentStateRoot = await this._stateManager.getStateRoot();
2295
- await this._setBlockContext(block);
2296
- try {
2297
- return await action();
2298
- } finally {
2299
- await this._restoreBlockContext(currentStateRoot);
2300
- }
2301
- }
2302
-
2303
- private async _runInPendingBlockContext<T>(action: () => Promise<T>) {
2304
- const snapshotId = await this.takeSnapshot();
2305
- try {
2306
- await this.mineBlock();
2307
- return await action();
2308
- } finally {
2309
- await this.revertToSnapshot(snapshotId);
2310
- }
2311
- }
2312
-
2313
- private async _setBlockContext(block: Block): Promise<void> {
2314
- const irregularStateOrUndefined = this._irregularStatesByBlockNumber.get(
2315
- block.header.number
2316
- );
2317
-
2318
- if (this._stateManager instanceof ForkStateManager) {
2319
- return this._stateManager.setBlockContext(
2320
- block.header.stateRoot,
2321
- block.header.number,
2322
- irregularStateOrUndefined
2323
- );
2324
- }
2325
-
2326
- return this._stateManager.setStateRoot(
2327
- irregularStateOrUndefined ?? block.header.stateRoot
2328
- );
2329
- }
2330
-
2331
- private async _restoreBlockContext(stateRoot: Uint8Array) {
2332
- if (this._stateManager instanceof ForkStateManager) {
2333
- return this._stateManager.restoreForkBlockContext(stateRoot);
2334
- }
2335
- return this._stateManager.setStateRoot(stateRoot);
2336
- }
2337
-
2338
- private async _correctInitialEstimation(
2339
- blockNumberOrPending: bigint | "pending",
2340
- txParams: TransactionParams,
2341
- initialEstimation: bigint
2342
- ): Promise<bigint> {
2343
- let tx = await this._getFakeTransaction({
2344
- ...txParams,
2345
- gasLimit: initialEstimation,
2346
- });
2347
-
2348
- if (tx.getBaseFee() >= initialEstimation) {
2349
- initialEstimation = tx.getBaseFee() + 1n;
2350
-
2351
- tx = await this._getFakeTransaction({
2352
- ...txParams,
2353
- gasLimit: initialEstimation,
2354
- });
2355
- }
2356
-
2357
- const result = await this._runInBlockContext(blockNumberOrPending, () =>
2358
- this._runTxAndRevertMutations(tx, blockNumberOrPending)
2359
- );
2360
-
2361
- if (result.execResult.exceptionError === undefined) {
2362
- return initialEstimation;
2363
- }
2364
-
2365
- return this._binarySearchEstimation(
2366
- blockNumberOrPending,
2367
- txParams,
2368
- initialEstimation,
2369
- this.getBlockGasLimit()
2370
- );
2371
- }
2372
-
2373
- private async _binarySearchEstimation(
2374
- blockNumberOrPending: bigint | "pending",
2375
- txParams: TransactionParams,
2376
- highestFailingEstimation: bigint,
2377
- lowestSuccessfulEstimation: bigint,
2378
- roundNumber = 0
2379
- ): Promise<bigint> {
2380
- if (lowestSuccessfulEstimation <= highestFailingEstimation) {
2381
- // This shouldn't happen, but we don't want to go into an infinite loop
2382
- // if it ever happens
2383
- return lowestSuccessfulEstimation;
2384
- }
2385
-
2386
- const MAX_GAS_ESTIMATION_IMPROVEMENT_ROUNDS = 20;
2387
-
2388
- const diff = lowestSuccessfulEstimation - highestFailingEstimation;
2389
-
2390
- const minDiff =
2391
- highestFailingEstimation >= 4_000_000n
2392
- ? 50_000
2393
- : highestFailingEstimation >= 1_000_000n
2394
- ? 10_000
2395
- : highestFailingEstimation >= 100_000n
2396
- ? 1_000
2397
- : highestFailingEstimation >= 50_000n
2398
- ? 500
2399
- : highestFailingEstimation >= 30_000n
2400
- ? 300
2401
- : 200;
2402
-
2403
- if (diff <= minDiff) {
2404
- return lowestSuccessfulEstimation;
2405
- }
2406
-
2407
- if (roundNumber > MAX_GAS_ESTIMATION_IMPROVEMENT_ROUNDS) {
2408
- return lowestSuccessfulEstimation;
2409
- }
2410
-
2411
- const binSearchNewEstimation = highestFailingEstimation + diff / 2n;
2412
-
2413
- const optimizedEstimation =
2414
- roundNumber === 0
2415
- ? 3n * highestFailingEstimation
2416
- : binSearchNewEstimation;
2417
-
2418
- const newEstimation =
2419
- optimizedEstimation > binSearchNewEstimation
2420
- ? binSearchNewEstimation
2421
- : optimizedEstimation;
2422
-
2423
- // Let other things execute
2424
- await new Promise((resolve) => setImmediate(resolve));
2425
-
2426
- const tx = await this._getFakeTransaction({
2427
- ...txParams,
2428
- gasLimit: newEstimation,
2429
- });
2430
-
2431
- const result = await this._runInBlockContext(blockNumberOrPending, () =>
2432
- this._runTxAndRevertMutations(tx, blockNumberOrPending)
2433
- );
2434
-
2435
- if (result.execResult.exceptionError === undefined) {
2436
- return this._binarySearchEstimation(
2437
- blockNumberOrPending,
2438
- txParams,
2439
- highestFailingEstimation,
2440
- newEstimation,
2441
- roundNumber + 1
2442
- );
2443
- }
2444
-
2445
- return this._binarySearchEstimation(
2446
- blockNumberOrPending,
2447
- txParams,
2448
- newEstimation,
2449
- lowestSuccessfulEstimation,
2450
- roundNumber + 1
2451
- );
2452
- }
2453
-
2454
- private async _applyStateOverrideSet(stateOverrideSet: StateOverrideSet) {
2455
- // Multiple state override set can be configured for different addresses, hence the loop
2456
- for (const [addrToOverride, stateOverrideOptions] of Object.entries(
2457
- stateOverrideSet
2458
- )) {
2459
- const address = new Address(toBytes(addrToOverride));
2460
-
2461
- const { balance, nonce, code, state, stateDiff } = stateOverrideOptions;
2462
-
2463
- await this._overrideBalanceAndNonce(address, balance, nonce);
2464
- await this._overrideCode(address, code);
2465
- await this._overrideStateAndStateDiff(address, state, stateDiff);
2466
- }
2467
- }
2468
-
2469
- private async _overrideBalanceAndNonce(
2470
- address: Address,
2471
- balance: bigint | undefined,
2472
- nonce: bigint | undefined
2473
- ) {
2474
- const MAX_NONCE = 2n ** 64n - 1n;
2475
- const MAX_BALANCE = 2n ** 256n - 1n;
2476
-
2477
- if (nonce !== undefined && nonce > MAX_NONCE) {
2478
- throw new InvalidInputError(
2479
- `The 'nonce' property should occupy a maximum of 8 bytes (nonce=${nonce}).`
2480
- );
2481
- }
2482
-
2483
- if (balance !== undefined && balance > MAX_BALANCE) {
2484
- throw new InvalidInputError(
2485
- `The 'balance' property should occupy a maximum of 32 bytes (balance=${balance}).`
2486
- );
2487
- }
2488
-
2489
- await this._stateManager.modifyAccountFields(address, {
2490
- balance,
2491
- nonce,
2492
- });
2493
- }
2494
-
2495
- private async _overrideCode(address: Address, code: Buffer | undefined) {
2496
- if (code === undefined) return;
2497
-
2498
- await this._stateManager.putContractCode(address, code);
2499
- }
2500
-
2501
- private async _overrideStateAndStateDiff(
2502
- address: Address,
2503
- state: StateProperties | undefined,
2504
- stateDiff: StateProperties | undefined
2505
- ) {
2506
- let newState;
2507
-
2508
- if (state !== undefined && stateDiff === undefined) {
2509
- await this._stateManager.clearContractStorage(address);
2510
- newState = state;
2511
- } else if (state === undefined && stateDiff !== undefined) {
2512
- newState = stateDiff;
2513
- } else if (state === undefined && stateDiff === undefined) {
2514
- // nothing to do
2515
- return;
2516
- } else {
2517
- throw new InvalidInputError(
2518
- "The properties 'state' and 'stateDiff' cannot be used simultaneously when configuring the state override set passed to the eth_call method."
2519
- );
2520
- }
2521
-
2522
- for (const [storageKey, value] of Object.entries(newState)) {
2523
- await this._stateManager.putContractStorage(
2524
- address,
2525
- toBytes(storageKey),
2526
- setLengthLeft(bigIntToBytes(value), 32)
2527
- );
2528
- }
2529
- }
2530
-
2531
- /**
2532
- * This function runs a transaction and reverts all the modifications that it
2533
- * makes.
2534
- */
2535
- private async _runTxAndRevertMutations(
2536
- tx: TypedTransaction,
2537
- blockNumberOrPending: bigint | "pending",
2538
- forceBaseFeeZero = false,
2539
- stateOverrideSet: StateOverrideSet = {}
2540
- ): Promise<RunTxResult> {
2541
- const initialStateRoot = await this._stateManager.getStateRoot();
2542
-
2543
- await this._applyStateOverrideSet(stateOverrideSet);
2544
-
2545
- let blockContext: Block | undefined;
2546
- let originalCommon: Common | undefined;
2547
-
2548
- try {
2549
- if (blockNumberOrPending === "pending") {
2550
- // the new block has already been mined by _runInBlockContext hence we take latest here
2551
- blockContext = await this.getLatestBlock();
2552
- } else {
2553
- // We know that this block number exists, because otherwise
2554
- // there would be an error in the RPC layer.
2555
- const block = await this.getBlockByNumber(blockNumberOrPending);
2556
- assertHardhatInvariant(
2557
- block !== undefined,
2558
- "Tried to run a tx in the context of a non-existent block"
2559
- );
2560
-
2561
- blockContext = block;
2562
-
2563
- // we don't need to add the tx to the block because runTx doesn't
2564
- // know anything about the txs in the current block
2565
- }
2566
-
2567
- originalCommon = (this._vm as any).common;
2568
-
2569
- assertTransientStorageCompatibility(
2570
- this._enableTransientStorage,
2571
- this._vm.common.hardfork() as HardforkName
2572
- );
2573
-
2574
- (this._vm as any).common = Common.custom(
2575
- {
2576
- chainId:
2577
- this._forkBlockNumber === undefined ||
2578
- blockContext.header.number >= this._forkBlockNumber
2579
- ? this._configChainId
2580
- : this._forkNetworkId,
2581
- networkId: this._forkNetworkId ?? this._configNetworkId,
2582
- },
2583
- {
2584
- hardfork: this._selectHardfork(blockContext.header.number),
2585
- }
2586
- );
2587
-
2588
- // If this VM is running without EIP4895, but the block has withdrawals,
2589
- // we remove them and the withdrawal root from the block
2590
- if (
2591
- !this.isEip4895Active(blockNumberOrPending) &&
2592
- blockContext.withdrawals !== undefined
2593
- ) {
2594
- blockContext = Block.fromBlockData(
2595
- {
2596
- ...blockContext,
2597
- withdrawals: undefined,
2598
- header: {
2599
- ...blockContext.header,
2600
- withdrawalsRoot: undefined,
2601
- },
2602
- },
2603
- {
2604
- freeze: false,
2605
- common: this._vm.common,
2606
-
2607
- skipConsensusFormatValidation: true,
2608
- }
2609
- );
2610
- }
2611
-
2612
- // If this VM is running without cancun, but the block has cancun fields,
2613
- // we remove them from the block
2614
- if (
2615
- !this.isCancunBlock(blockNumberOrPending) &&
2616
- blockContext.header.blobGasUsed !== undefined
2617
- ) {
2618
- blockContext = Block.fromBlockData(
2619
- {
2620
- ...blockContext,
2621
- header: {
2622
- ...blockContext.header,
2623
- blobGasUsed: undefined,
2624
- excessBlobGas: undefined,
2625
- parentBeaconBlockRoot: undefined,
2626
- },
2627
- },
2628
- {
2629
- freeze: false,
2630
- common: this._vm.common,
2631
-
2632
- skipConsensusFormatValidation: true,
2633
- }
2634
- );
2635
- }
2636
-
2637
- // NOTE: This is a workaround of both an @nomicfoundation/ethereumjs-vm limitation, and
2638
- // a bug in Hardhat Network.
2639
- //
2640
- // See: https://github.com/nomiclabs/hardhat/issues/1666
2641
- //
2642
- // If this VM is running with EIP1559 activated, and the block is not
2643
- // an EIP1559 one, this will crash, so we create a new one that has
2644
- // baseFeePerGas = 0.
2645
- //
2646
- // We also have an option to force the base fee to be zero,
2647
- // we don't want to debit any balance nor fail any tx when running an
2648
- // eth_call. This will make the BASEFEE option also return 0, which
2649
- // shouldn't. See: https://github.com/nomiclabs/hardhat/issues/1688
2650
- if (
2651
- this.isEip1559Active(blockNumberOrPending) &&
2652
- (blockContext.header.baseFeePerGas === undefined || forceBaseFeeZero)
2653
- ) {
2654
- blockContext = Block.fromBlockData(blockContext, {
2655
- freeze: false,
2656
- common: this._vm.common,
2657
-
2658
- skipConsensusFormatValidation: true,
2659
- });
2660
-
2661
- (blockContext.header as any).baseFeePerGas = 0n;
2662
- }
2663
-
2664
- return await this._vm.runTx({
2665
- block: blockContext,
2666
- tx,
2667
- skipNonce: true,
2668
- skipBalance: true,
2669
- skipBlockGasLimitValidation: true,
2670
- skipHardForkValidation: true,
2671
- });
2672
- } finally {
2673
- if (originalCommon !== undefined) {
2674
- (this._vm as any).common = originalCommon;
2675
- }
2676
- await this._stateManager.setStateRoot(initialStateRoot);
2677
- }
2678
- }
2679
-
2680
- private async _computeFilterParams(
2681
- filterParams: FilterParams,
2682
- isFilter: boolean
2683
- ): Promise<FilterParams> {
2684
- const latestBlockNumber = this.getLatestBlockNumber();
2685
- const newFilterParams = { ...filterParams };
2686
-
2687
- if (newFilterParams.fromBlock === LATEST_BLOCK) {
2688
- newFilterParams.fromBlock = latestBlockNumber;
2689
- }
2690
-
2691
- if (!isFilter && newFilterParams.toBlock === LATEST_BLOCK) {
2692
- newFilterParams.toBlock = latestBlockNumber;
2693
- }
2694
-
2695
- if (newFilterParams.toBlock > latestBlockNumber) {
2696
- newFilterParams.toBlock = latestBlockNumber;
2697
- }
2698
- if (newFilterParams.fromBlock > latestBlockNumber) {
2699
- newFilterParams.fromBlock = latestBlockNumber;
2700
- }
2701
-
2702
- return newFilterParams;
2703
- }
2704
-
2705
- private _newDeadline(): Date {
2706
- const dt = new Date();
2707
- dt.setMinutes(dt.getMinutes() + 5); // This will not overflow
2708
- return dt;
2709
- }
2710
-
2711
- private _getNextFilterId(): bigint {
2712
- this._lastFilterId++;
2713
-
2714
- return this._lastFilterId;
2715
- }
2716
-
2717
- private _filterIdToFiltersKey(filterId: bigint): string {
2718
- return filterId.toString();
2719
- }
2720
-
2721
- private _emitEthEvent(filterId: bigint, result: any) {
2722
- this.emit("ethEvent", {
2723
- result,
2724
- filterId,
2725
- });
2726
- }
2727
-
2728
- private async _getNonce(
2729
- address: Address,
2730
- blockNumberOrPending: bigint | "pending"
2731
- ): Promise<bigint> {
2732
- if (blockNumberOrPending === "pending") {
2733
- return this.getAccountNextPendingNonce(address);
2734
- }
2735
-
2736
- return this._runInBlockContext(blockNumberOrPending, async () => {
2737
- const account = await this._stateManager.getAccount(address);
2738
-
2739
- return account?.nonce ?? 0n;
2740
- });
2741
- }
2742
-
2743
- private async _isTransactionMined(hash: Buffer): Promise<boolean> {
2744
- const txReceipt = await this.getTransactionReceipt(hash);
2745
- return txReceipt !== undefined;
2746
- }
2747
-
2748
- private _isTxMinable(
2749
- tx: TypedTransaction,
2750
- nextBlockBaseFeePerGas?: bigint
2751
- ): boolean {
2752
- const txMaxFee = "gasPrice" in tx ? tx.gasPrice : tx.maxFeePerGas;
2753
-
2754
- const canPayBaseFee =
2755
- nextBlockBaseFeePerGas !== undefined
2756
- ? txMaxFee >= nextBlockBaseFeePerGas
2757
- : true;
2758
-
2759
- const atLeastMinGasPrice = txMaxFee >= this._minGasPrice;
2760
-
2761
- return canPayBaseFee && atLeastMinGasPrice;
2762
- }
2763
-
2764
- private async _persistIrregularWorldState(): Promise<void> {
2765
- this._irregularStatesByBlockNumber.set(
2766
- this.getLatestBlockNumber(),
2767
- await this._stateManager.getStateRoot()
2768
- );
2769
- }
2770
-
2771
- public isEip1559Active(blockNumberOrPending?: bigint | "pending"): boolean {
2772
- if (
2773
- blockNumberOrPending !== undefined &&
2774
- blockNumberOrPending !== "pending"
2775
- ) {
2776
- return this._vm.common.hardforkGteHardfork(
2777
- this._selectHardfork(blockNumberOrPending),
2778
- "london"
2779
- );
2780
- }
2781
- return this._vm.common.gteHardfork("london");
2782
- }
2783
-
2784
- public isEip4895Active(blockNumberOrPending?: bigint | "pending"): boolean {
2785
- if (
2786
- blockNumberOrPending !== undefined &&
2787
- blockNumberOrPending !== "pending"
2788
- ) {
2789
- return this._vm.common.hardforkGteHardfork(
2790
- this._selectHardfork(blockNumberOrPending),
2791
- "shanghai"
2792
- );
2793
- }
2794
- return this._vm.common.gteHardfork("shanghai");
2795
- }
2796
-
2797
- public isCancunBlock(blockNumberOrPending?: bigint | "pending"): boolean {
2798
- if (
2799
- blockNumberOrPending !== undefined &&
2800
- blockNumberOrPending !== "pending"
2801
- ) {
2802
- return this._vm.common.hardforkGteHardfork(
2803
- this._selectHardfork(blockNumberOrPending),
2804
- "cancun"
2805
- );
2806
- }
2807
- return this._vm.common.gteHardfork("cancun");
2808
- }
2809
-
2810
- public isPostMergeHardfork(): boolean {
2811
- return hardforkGte(this.hardfork, HardforkName.MERGE);
2812
- }
2813
-
2814
- public isPostCancunHardfork(): boolean {
2815
- return hardforkGte(this.hardfork, HardforkName.CANCUN);
2816
- }
2817
-
2818
- public setPrevRandao(prevRandao: Buffer): void {
2819
- this._mixHashGenerator.setNext(prevRandao);
2820
- }
2821
-
2822
- public async getClientVersion(): Promise<string> {
2823
- const hardhatPackage = await getPackageJson();
2824
- const ethereumjsVMPackage = require("@nomicfoundation/ethereumjs-vm/package.json");
2825
- return `HardhatNetwork/${hardhatPackage.version}/@nomicfoundation/ethereumjs-vm/${ethereumjsVMPackage.version}`;
2826
- }
2827
-
2828
- public async getMetadata(): Promise<HardhatMetadata> {
2829
- const clientVersion = await this.getClientVersion();
2830
-
2831
- const instanceIdHex = BigIntUtils.toEvmWord(this._instanceId);
2832
- const instanceId = `0x${instanceIdHex}`;
2833
-
2834
- const latestBlock = await this.getLatestBlock();
2835
-
2836
- const latestBlockHashHex = Buffer.from(latestBlock.header.hash()).toString(
2837
- "hex"
2838
- );
2839
- const latestBlockHash = `0x${latestBlockHashHex}`;
2840
-
2841
- const metadata: HardhatMetadata = {
2842
- clientVersion,
2843
- chainId: this._configChainId,
2844
- instanceId,
2845
- latestBlockNumber: Number(latestBlock.header.number),
2846
- latestBlockHash,
2847
- };
2848
-
2849
- if (this._forkBlockNumber !== undefined) {
2850
- assertHardhatInvariant(
2851
- this._forkNetworkId !== undefined,
2852
- "this._forkNetworkId should be defined if this._forkBlockNumber is defined"
2853
- );
2854
- assertHardhatInvariant(
2855
- this._forkBlockHash !== undefined,
2856
- "this._forkBlockhash should be defined if this._forkBlockNumber is defined"
2857
- );
2858
-
2859
- metadata.forkedNetwork = {
2860
- chainId: this._forkNetworkId,
2861
- forkBlockNumber: Number(this._forkBlockNumber),
2862
- forkBlockHash: this._forkBlockHash,
2863
- };
2864
- }
2865
-
2866
- return metadata;
2867
- }
2868
-
2869
- private _getNextMixHash(): Uint8Array {
2870
- return this._mixHashGenerator.next();
2871
- }
2872
-
2873
- private _getNextParentBeaconBlockRoot(): Uint8Array {
2874
- return this._parentBeaconBlockRootGenerator.next();
2875
- }
2876
-
2877
- private async _getEstimateGasFeePriceFields(
2878
- callParams: CallParams,
2879
- blockNumberOrPending: bigint | "pending"
2880
- ): Promise<
2881
- | { gasPrice: bigint }
2882
- | { maxFeePerGas: bigint; maxPriorityFeePerGas: bigint }
2883
- > {
2884
- if (
2885
- !this.isEip1559Active(blockNumberOrPending) ||
2886
- callParams.gasPrice !== undefined
2887
- ) {
2888
- return { gasPrice: callParams.gasPrice ?? (await this.getGasPrice()) };
2889
- }
2890
-
2891
- let maxFeePerGas = callParams.maxFeePerGas;
2892
- let maxPriorityFeePerGas = callParams.maxPriorityFeePerGas;
2893
-
2894
- if (maxPriorityFeePerGas === undefined) {
2895
- maxPriorityFeePerGas = await this.getMaxPriorityFeePerGas();
2896
-
2897
- if (maxFeePerGas !== undefined && maxFeePerGas < maxPriorityFeePerGas) {
2898
- maxPriorityFeePerGas = maxFeePerGas;
2899
- }
2900
- }
2901
-
2902
- if (maxFeePerGas === undefined) {
2903
- if (blockNumberOrPending === "pending") {
2904
- const baseFeePerGas = await this.getNextBlockBaseFeePerGas();
2905
- maxFeePerGas = 2n * baseFeePerGas! + maxPriorityFeePerGas;
2906
- } else {
2907
- const block = await this.getBlockByNumber(blockNumberOrPending);
2908
-
2909
- maxFeePerGas =
2910
- maxPriorityFeePerGas + (block!.header.baseFeePerGas ?? 0n);
2911
- }
2912
- }
2913
-
2914
- return { maxFeePerGas, maxPriorityFeePerGas };
2915
- }
2916
-
2917
- private _selectHardfork(blockNumber: bigint): string {
2918
- if (
2919
- this._forkBlockNumber === undefined ||
2920
- blockNumber >= this._forkBlockNumber
2921
- ) {
2922
- return this._vm.common.hardfork() as HardforkName;
2923
- }
2924
-
2925
- if (this._hardforkActivations.size === 0) {
2926
- throw new InternalError(
2927
- `No known hardfork for execution on historical block ${blockNumber.toString()} (relative to fork block number ${
2928
- this._forkBlockNumber
2929
- }). The node was not configured with a hardfork activation history. See http://hardhat.org/custom-hardfork-history`
2930
- );
2931
- }
2932
-
2933
- /** search this._hardforkActivations for the highest block number that
2934
- * isn't higher than blockNumber, and then return that found block number's
2935
- * associated hardfork name. */
2936
- const hardforkHistory: Array<[name: string, block: number]> = Array.from(
2937
- this._hardforkActivations.entries()
2938
- );
2939
- const [hardfork, activationBlock] = hardforkHistory.reduce(
2940
- ([highestHardfork, highestBlock], [thisHardfork, thisBlock]) =>
2941
- thisBlock > highestBlock && thisBlock <= blockNumber
2942
- ? [thisHardfork, thisBlock]
2943
- : [highestHardfork, highestBlock]
2944
- );
2945
- if (hardfork === undefined || blockNumber < activationBlock) {
2946
- throw new InternalError(
2947
- `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(
2948
- hardforkHistory
2949
- )}. For more information, see https://hardhat.org/hardhat-network/reference/#config`
2950
- );
2951
- }
2952
-
2953
- if (!HARDHAT_NETWORK_SUPPORTED_HARDFORKS.includes(hardfork)) {
2954
- throw new InternalError(
2955
- `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(
2956
- ", "
2957
- )}`
2958
- );
2959
- }
2960
-
2961
- return hardfork === "merge" ? "mergeForkIdTransition" : hardfork;
2962
- }
2963
-
2964
- private _getCommonForTracing(networkId: number, blockNumber: bigint): Common {
2965
- assertTransientStorageCompatibility(
2966
- this._enableTransientStorage,
2967
- this._vm.common.hardfork() as HardforkName
2968
- );
2969
-
2970
- try {
2971
- const common = Common.custom(
2972
- {
2973
- chainId: networkId,
2974
- networkId,
2975
- },
2976
- {
2977
- hardfork: this._selectHardfork(BigInt(blockNumber)),
2978
- }
2979
- );
2980
-
2981
- return common;
2982
- } catch {
2983
- throw new InternalError(
2984
- `Network id ${networkId} does not correspond to a network that Hardhat can trace`
2985
- );
2986
- }
2987
- }
2988
- }
2989
-
2990
- export function assertTransientStorageCompatibility(
2991
- enableTransientStorage: boolean,
2992
- hardfork: HardforkName
2993
- ) {
2994
- if (enableTransientStorage && !hardforkGte(hardfork, HardforkName.CANCUN)) {
2995
- throw new InternalError(
2996
- `Transient storage is not compatible with hardfork "${hardfork}". To use transient storage, set the hardfork to "cancun" or later.`
2997
- );
2998
- }
2999
- }