hardhat 2.20.0 → 2.21.0-dev.0

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