@feelyourprotocol/vm 8141.0.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 (115) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +583 -0
  3. package/dist/cjs/bloom/index.d.ts +29 -0
  4. package/dist/cjs/bloom/index.d.ts.map +1 -0
  5. package/dist/cjs/bloom/index.js +76 -0
  6. package/dist/cjs/bloom/index.js.map +1 -0
  7. package/dist/cjs/buildBlock.d.ts +118 -0
  8. package/dist/cjs/buildBlock.d.ts.map +1 -0
  9. package/dist/cjs/buildBlock.js +363 -0
  10. package/dist/cjs/buildBlock.js.map +1 -0
  11. package/dist/cjs/constructors.d.ts +9 -0
  12. package/dist/cjs/constructors.d.ts.map +1 -0
  13. package/dist/cjs/constructors.js +75 -0
  14. package/dist/cjs/constructors.js.map +1 -0
  15. package/dist/cjs/emitEVMProfile.d.ts +9 -0
  16. package/dist/cjs/emitEVMProfile.d.ts.map +1 -0
  17. package/dist/cjs/emitEVMProfile.js +130 -0
  18. package/dist/cjs/emitEVMProfile.js.map +1 -0
  19. package/dist/cjs/index.d.ts +11 -0
  20. package/dist/cjs/index.d.ts.map +1 -0
  21. package/dist/cjs/index.js +36 -0
  22. package/dist/cjs/index.js.map +1 -0
  23. package/dist/cjs/package.json +3 -0
  24. package/dist/cjs/params.d.ts +3 -0
  25. package/dist/cjs/params.d.ts.map +1 -0
  26. package/dist/cjs/params.js +105 -0
  27. package/dist/cjs/params.js.map +1 -0
  28. package/dist/cjs/requests.d.ts +11 -0
  29. package/dist/cjs/requests.d.ts.map +1 -0
  30. package/dist/cjs/requests.js +208 -0
  31. package/dist/cjs/requests.js.map +1 -0
  32. package/dist/cjs/runBlock.d.ts +35 -0
  33. package/dist/cjs/runBlock.d.ts.map +1 -0
  34. package/dist/cjs/runBlock.js +797 -0
  35. package/dist/cjs/runBlock.js.map +1 -0
  36. package/dist/cjs/runFrameTx.d.ts +18 -0
  37. package/dist/cjs/runFrameTx.d.ts.map +1 -0
  38. package/dist/cjs/runFrameTx.js +313 -0
  39. package/dist/cjs/runFrameTx.js.map +1 -0
  40. package/dist/cjs/runTx.d.ts +18 -0
  41. package/dist/cjs/runTx.d.ts.map +1 -0
  42. package/dist/cjs/runTx.js +900 -0
  43. package/dist/cjs/runTx.js.map +1 -0
  44. package/dist/cjs/types.d.ts +452 -0
  45. package/dist/cjs/types.d.ts.map +1 -0
  46. package/dist/cjs/types.js +3 -0
  47. package/dist/cjs/types.js.map +1 -0
  48. package/dist/cjs/vm.d.ts +75 -0
  49. package/dist/cjs/vm.d.ts.map +1 -0
  50. package/dist/cjs/vm.js +111 -0
  51. package/dist/cjs/vm.js.map +1 -0
  52. package/dist/esm/bloom/index.d.ts +29 -0
  53. package/dist/esm/bloom/index.d.ts.map +1 -0
  54. package/dist/esm/bloom/index.js +72 -0
  55. package/dist/esm/bloom/index.js.map +1 -0
  56. package/dist/esm/buildBlock.d.ts +118 -0
  57. package/dist/esm/buildBlock.d.ts.map +1 -0
  58. package/dist/esm/buildBlock.js +358 -0
  59. package/dist/esm/buildBlock.js.map +1 -0
  60. package/dist/esm/constructors.d.ts +9 -0
  61. package/dist/esm/constructors.d.ts.map +1 -0
  62. package/dist/esm/constructors.js +72 -0
  63. package/dist/esm/constructors.js.map +1 -0
  64. package/dist/esm/emitEVMProfile.d.ts +9 -0
  65. package/dist/esm/emitEVMProfile.d.ts.map +1 -0
  66. package/dist/esm/emitEVMProfile.js +127 -0
  67. package/dist/esm/emitEVMProfile.js.map +1 -0
  68. package/dist/esm/index.d.ts +11 -0
  69. package/dist/esm/index.d.ts.map +1 -0
  70. package/dist/esm/index.js +11 -0
  71. package/dist/esm/index.js.map +1 -0
  72. package/dist/esm/package.json +3 -0
  73. package/dist/esm/params.d.ts +3 -0
  74. package/dist/esm/params.d.ts.map +1 -0
  75. package/dist/esm/params.js +102 -0
  76. package/dist/esm/params.js.map +1 -0
  77. package/dist/esm/requests.d.ts +11 -0
  78. package/dist/esm/requests.d.ts.map +1 -0
  79. package/dist/esm/requests.js +204 -0
  80. package/dist/esm/requests.js.map +1 -0
  81. package/dist/esm/runBlock.d.ts +35 -0
  82. package/dist/esm/runBlock.d.ts.map +1 -0
  83. package/dist/esm/runBlock.js +790 -0
  84. package/dist/esm/runBlock.js.map +1 -0
  85. package/dist/esm/runFrameTx.d.ts +18 -0
  86. package/dist/esm/runFrameTx.d.ts.map +1 -0
  87. package/dist/esm/runFrameTx.js +310 -0
  88. package/dist/esm/runFrameTx.js.map +1 -0
  89. package/dist/esm/runTx.d.ts +18 -0
  90. package/dist/esm/runTx.d.ts.map +1 -0
  91. package/dist/esm/runTx.js +896 -0
  92. package/dist/esm/runTx.js.map +1 -0
  93. package/dist/esm/types.d.ts +452 -0
  94. package/dist/esm/types.d.ts.map +1 -0
  95. package/dist/esm/types.js +2 -0
  96. package/dist/esm/types.js.map +1 -0
  97. package/dist/esm/vm.d.ts +75 -0
  98. package/dist/esm/vm.d.ts.map +1 -0
  99. package/dist/esm/vm.js +107 -0
  100. package/dist/esm/vm.js.map +1 -0
  101. package/dist/tsconfig.prod.cjs.tsbuildinfo +1 -0
  102. package/dist/tsconfig.prod.esm.tsbuildinfo +1 -0
  103. package/package.json +117 -0
  104. package/src/bloom/index.ts +83 -0
  105. package/src/buildBlock.ts +470 -0
  106. package/src/constructors.ts +91 -0
  107. package/src/emitEVMProfile.ts +151 -0
  108. package/src/index.ts +10 -0
  109. package/src/params.ts +104 -0
  110. package/src/requests.ts +293 -0
  111. package/src/runBlock.ts +1022 -0
  112. package/src/runFrameTx.ts +411 -0
  113. package/src/runTx.ts +1203 -0
  114. package/src/types.ts +511 -0
  115. package/src/vm.ts +147 -0
@@ -0,0 +1,1022 @@
1
+ import { createBlock, genRequestsRoot } from '@feelyourprotocol/block'
2
+ import { ConsensusType, Hardfork } from '@feelyourprotocol/common'
3
+ import { type EVM, type EVMInterface } from '@feelyourprotocol/evm'
4
+ import { MerklePatriciaTrie } from '@feelyourprotocol/mpt'
5
+ import { RLP } from '@feelyourprotocol/rlp'
6
+ import { TransactionType } from '@feelyourprotocol/tx'
7
+ import {
8
+ Account,
9
+ Address,
10
+ BIGINT_0,
11
+ BIGINT_1,
12
+ BIGINT_8,
13
+ EthereumJSErrorWithoutCode,
14
+ GWEI_TO_WEI,
15
+ KECCAK256_RLP,
16
+ bigIntToAddressBytes,
17
+ bigIntToBytes,
18
+ bytesToHex,
19
+ concatBytes,
20
+ createAddressFromString,
21
+ createBlockLevelAccessList,
22
+ equalsBytes,
23
+ hexToBytes,
24
+ intToBytes,
25
+ setLengthLeft,
26
+ short,
27
+ unprefixedHexToBytes,
28
+ } from '@feelyourprotocol/util'
29
+ import { sha256 } from '@noble/hashes/sha2.js'
30
+ import debugDefault from 'debug'
31
+
32
+ import { Bloom } from './bloom/index.ts'
33
+ import { emitEVMProfile } from './emitEVMProfile.ts'
34
+ import { runTx } from './index.ts'
35
+ import { accumulateRequests } from './requests.ts'
36
+
37
+ import type { Block } from '@feelyourprotocol/block'
38
+ import type { Common } from '@feelyourprotocol/common'
39
+ import type { CLRequest, CLRequestType, PrefixedHexString } from '@feelyourprotocol/util'
40
+ import type {
41
+ AfterBlockEvent,
42
+ ApplyBlockResult,
43
+ PostByzantiumTxReceipt,
44
+ PreByzantiumTxReceipt,
45
+ RunBlockOpts,
46
+ RunBlockResult,
47
+ RunTxResult,
48
+ TxReceipt,
49
+ } from './types.ts'
50
+ import type { VM } from './vm.ts'
51
+
52
+ const debug = debugDefault('vm:block')
53
+
54
+ const parentBeaconBlockRootAddress = createAddressFromString(
55
+ '0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02',
56
+ )
57
+
58
+ let enableProfiler = false
59
+ const stateRootCPLabel = 'New state root, DAO HF, checkpoints, block validation'
60
+ const processTxsLabel = 'Tx processing [ use per-tx profiler for more details ]'
61
+ const withdrawalsRewardsCommitLabel = 'Withdrawals, Rewards, EVM journal commit'
62
+ const entireBlockLabel = 'Entire block'
63
+
64
+ /**
65
+ * Processes the `block` running all of the transactions it contains and updating the miner's account
66
+ *
67
+ * vm method modifies the state if successfully executed and header fields are valid.
68
+ * state modifications will be reverted if an exception is raised during execution or validation.
69
+ *
70
+ * @param {VM} vm
71
+ * @param {RunBlockOpts} opts - Default values for options:
72
+ * - `generate`: false
73
+ */
74
+ export async function runBlock(vm: VM, opts: RunBlockOpts): Promise<RunBlockResult> {
75
+ if (vm['_opts'].profilerOpts?.reportAfterBlock === true) {
76
+ enableProfiler = true
77
+ // eslint-disable-next-line no-console
78
+ console.time(entireBlockLabel)
79
+ }
80
+ const stateManager = vm.stateManager
81
+
82
+ const { root } = opts
83
+ const clearCache = opts.clearCache ?? true
84
+ let { block } = opts
85
+ const generateFields = opts.generate === true
86
+
87
+ if (enableProfiler) {
88
+ const title = `Profiler run - Block ${block.header.number} (${bytesToHex(block.hash())} with ${
89
+ block.transactions.length
90
+ } txs`
91
+ // eslint-disable-next-line no-console
92
+ console.log(title)
93
+ // eslint-disable-next-line no-console
94
+ console.time(stateRootCPLabel)
95
+ }
96
+
97
+ /**
98
+ * The `beforeBlock` event.
99
+ *
100
+ * @event Event: beforeBlock
101
+ * @type {Object}
102
+ * @property {Block} block emits the block that is about to be processed
103
+ */
104
+ await vm._emit('beforeBlock', block)
105
+
106
+ const setHardforkUsed = opts.setHardfork ?? vm['_setHardfork']
107
+ if (setHardforkUsed === true) {
108
+ vm.common.setHardforkBy({
109
+ blockNumber: block.header.number,
110
+ timestamp: block.header.timestamp,
111
+ })
112
+ }
113
+
114
+ if (vm.common.isActivatedEIP(7928)) {
115
+ vm.evm.blockLevelAccessList = createBlockLevelAccessList()
116
+ }
117
+
118
+ if (vm.DEBUG) {
119
+ debug('-'.repeat(100))
120
+ debug(
121
+ `Running block hash=${bytesToHex(block.hash())} number=${
122
+ block.header.number
123
+ } hardfork=${vm.common.hardfork()}`,
124
+ )
125
+ }
126
+
127
+ // Set state root if provided
128
+ if (root) {
129
+ if (vm.DEBUG) {
130
+ debug(`Set provided state root ${bytesToHex(root)} clearCache=${clearCache}`)
131
+ }
132
+ await stateManager.setStateRoot(root, clearCache)
133
+ }
134
+
135
+ if (vm.common.isActivatedEIP(7864)) {
136
+ // Initialize the access witness
137
+
138
+ if (vm.DEBUG) {
139
+ debug(`Initializing executionWitness`)
140
+ }
141
+ if (clearCache) {
142
+ stateManager.clearCaches()
143
+ }
144
+ }
145
+
146
+ // check for DAO support and if we should apply the DAO fork
147
+ if (
148
+ vm.common.hardforkIsActiveOnBlock(Hardfork.Dao, block.header.number) &&
149
+ block.header.number === vm.common.hardforkBlock(Hardfork.Dao)!
150
+ ) {
151
+ if (vm.DEBUG) {
152
+ debug(`Apply DAO hardfork`)
153
+ }
154
+
155
+ await vm.evm.journal.checkpoint()
156
+ await _applyDAOHardfork(vm.evm)
157
+ await vm.evm.journal.commit()
158
+ }
159
+
160
+ // Checkpoint state
161
+ await vm.evm.journal.checkpoint()
162
+ if (vm.DEBUG) {
163
+ debug(`block checkpoint`)
164
+ }
165
+
166
+ let result: ApplyBlockResult
167
+
168
+ try {
169
+ result = await applyBlock(vm, block, opts)
170
+ if (vm.DEBUG) {
171
+ debug(
172
+ `Received block results gasUsed=${result.gasUsed} bloom=${short(result.bloom.bitvector)} (${
173
+ result.bloom.bitvector.length
174
+ } bytes) receiptsRoot=${bytesToHex(result.receiptsRoot)} receipts=${
175
+ result.receipts.length
176
+ } txResults=${result.results.length}`,
177
+ )
178
+ }
179
+ } catch (err: any) {
180
+ await vm.evm.journal.revert()
181
+ if (vm.DEBUG) {
182
+ debug(`block checkpoint reverted`)
183
+ }
184
+ if (enableProfiler) {
185
+ // eslint-disable-next-line no-console
186
+ console.timeEnd(withdrawalsRewardsCommitLabel)
187
+ }
188
+ throw err
189
+ }
190
+ let requestsHash: Uint8Array | undefined
191
+ let requests: CLRequest<CLRequestType>[] | undefined
192
+ if (block.common.isActivatedEIP(7685)) {
193
+ const sha256Function = vm.common.customCrypto.sha256 ?? sha256
194
+ requests = await accumulateRequests(vm, result.results)
195
+ requestsHash = genRequestsRoot(requests, sha256Function)
196
+ }
197
+
198
+ const stateRoot = await stateManager.getStateRoot()
199
+
200
+ // Given the generate option, either set resulting header
201
+ // values to the current block, or validate the resulting
202
+ // header values against the current block.
203
+ if (generateFields) {
204
+ const logsBloom = result.bloom.bitvector
205
+ const gasUsed = result.gasUsed
206
+ const receiptTrie = result.receiptsRoot
207
+ const transactionsTrie = await _genTxTrie(block)
208
+ const generatedFields = {
209
+ stateRoot,
210
+ logsBloom,
211
+ gasUsed,
212
+ receiptTrie,
213
+ transactionsTrie,
214
+ requestsHash,
215
+ }
216
+ const blockData = {
217
+ ...block,
218
+ header: { ...block.header, ...generatedFields },
219
+ }
220
+ block = createBlock(blockData, { common: vm.common })
221
+ } else {
222
+ try {
223
+ if (vm.common.isActivatedEIP(7685)) {
224
+ if (!equalsBytes(block.header.requestsHash!, requestsHash!)) {
225
+ if (vm.DEBUG)
226
+ debug(
227
+ `Invalid requestsHash received=${bytesToHex(
228
+ block.header.requestsHash!,
229
+ )} expected=${bytesToHex(requestsHash!)}`,
230
+ )
231
+ const msg = _errorMsg('invalid requestsHash', vm, block)
232
+ throw EthereumJSErrorWithoutCode(msg)
233
+ }
234
+ }
235
+
236
+ // Only validate the following headers if Stateless isn't activated
237
+ if (equalsBytes(result.receiptsRoot, block.header.receiptTrie) === false) {
238
+ if (vm.DEBUG) {
239
+ debug(
240
+ `Invalid receiptTrie received=${bytesToHex(result.receiptsRoot)} expected=${bytesToHex(
241
+ block.header.receiptTrie,
242
+ )}`,
243
+ )
244
+ }
245
+ const msg = _errorMsg('invalid receiptTrie', vm, block)
246
+ throw EthereumJSErrorWithoutCode(msg)
247
+ }
248
+ if (!(equalsBytes(result.bloom.bitvector, block.header.logsBloom) === true)) {
249
+ if (vm.DEBUG) {
250
+ debug(
251
+ `Invalid bloom received=${bytesToHex(result.bloom.bitvector)} expected=${bytesToHex(
252
+ block.header.logsBloom,
253
+ )}`,
254
+ )
255
+ }
256
+ const msg = _errorMsg('invalid bloom', vm, block)
257
+ throw EthereumJSErrorWithoutCode(msg)
258
+ }
259
+ if (result.gasUsed !== block.header.gasUsed) {
260
+ if (vm.DEBUG) {
261
+ debug(`Invalid gasUsed received=${result.gasUsed} expected=${block.header.gasUsed}`)
262
+ }
263
+ const msg = _errorMsg('invalid gasUsed', vm, block)
264
+ throw EthereumJSErrorWithoutCode(msg)
265
+ }
266
+ if (!(equalsBytes(stateRoot, block.header.stateRoot) === true)) {
267
+ if (vm.DEBUG) {
268
+ debug(
269
+ `Invalid stateRoot received=${bytesToHex(stateRoot)} expected=${bytesToHex(
270
+ block.header.stateRoot,
271
+ )}`,
272
+ )
273
+ }
274
+ const msg = _errorMsg(
275
+ `invalid block stateRoot, got: ${bytesToHex(stateRoot)}, want: ${bytesToHex(
276
+ block.header.stateRoot,
277
+ )}`,
278
+ vm,
279
+ block,
280
+ )
281
+ throw EthereumJSErrorWithoutCode(msg)
282
+ }
283
+
284
+ if (vm.common.isActivatedEIP(7864)) {
285
+ if (vm.evm.binaryTreeAccessWitness === undefined) {
286
+ throw Error(`binaryTreeAccessWitness required if binary tree (EIP-7864) is activated`)
287
+ }
288
+ // If binary tree is activated and executing statelessly, only validate the post-state
289
+ if (
290
+ (await vm['_opts'].stateManager!.verifyBinaryTreePostState!(
291
+ vm.evm.binaryTreeAccessWitness,
292
+ )) === false
293
+ ) {
294
+ throw EthereumJSErrorWithoutCode(
295
+ `Binary tree post state verification failed on block ${block.header.number}`,
296
+ )
297
+ }
298
+ debug(`Binary tree post state verification succeeded`)
299
+ }
300
+ } catch (err) {
301
+ await vm.evm.journal.revert()
302
+ if (vm.DEBUG) {
303
+ debug(`block checkpoint reverted`)
304
+ }
305
+ throw err
306
+ }
307
+ }
308
+
309
+ // Persist state
310
+ await vm.evm.journal.commit()
311
+ if (vm.DEBUG) {
312
+ debug(`block checkpoint committed`)
313
+ }
314
+
315
+ if (enableProfiler) {
316
+ // eslint-disable-next-line no-console
317
+ console.timeEnd(withdrawalsRewardsCommitLabel)
318
+ }
319
+
320
+ const results: RunBlockResult = {
321
+ receipts: result.receipts,
322
+ logsBloom: result.bloom.bitvector,
323
+ results: result.results,
324
+ stateRoot,
325
+ gasUsed: result.gasUsed,
326
+ receiptsRoot: result.receiptsRoot,
327
+ preimages: result.preimages,
328
+ requestsHash,
329
+ requests,
330
+ blockLevelAccessList: vm.evm.blockLevelAccessList,
331
+ }
332
+
333
+ const afterBlockEvent: AfterBlockEvent = { ...results, block }
334
+
335
+ /**
336
+ * The `afterBlock` event
337
+ *
338
+ * @event Event: afterBlock
339
+ * @type {AfterBlockEvent}
340
+ * @property {AfterBlockEvent} result emits the results of processing a block
341
+ */
342
+ await vm._emit('afterBlock', afterBlockEvent)
343
+ if (vm.DEBUG) {
344
+ debug(
345
+ `Running block finished hash=${bytesToHex(block.hash())} number=${
346
+ block.header.number
347
+ } hardfork=${vm.common.hardfork()}`,
348
+ )
349
+ }
350
+
351
+ if (enableProfiler) {
352
+ // eslint-disable-next-line no-console
353
+ console.timeEnd(entireBlockLabel)
354
+ const logs = (vm.evm as EVM).getPerformanceLogs()
355
+ if (logs.precompiles.length === 0 && logs.opcodes.length === 0) {
356
+ // eslint-disable-next-line no-console
357
+ console.log('No block txs with precompile or opcode execution.')
358
+ }
359
+
360
+ emitEVMProfile(logs.precompiles, 'Precompile performance')
361
+ emitEVMProfile(logs.opcodes, 'Opcodes performance')
362
+ ;(vm.evm as EVM).clearPerformanceLogs()
363
+ }
364
+
365
+ return results
366
+ }
367
+
368
+ /**
369
+ * Validates and applies a block, computing the results of
370
+ * applying its transactions. vm method doesn't modify the
371
+ * block itself. It computes the block rewards and puts
372
+ * them on state (but doesn't persist the changes).
373
+ * @param {Block} block
374
+ * @param {RunBlockOpts} opts
375
+ */
376
+ async function applyBlock(vm: VM, block: Block, opts: RunBlockOpts): Promise<ApplyBlockResult> {
377
+ // Validate block
378
+ if (opts.skipBlockValidation !== true) {
379
+ if (block.header.gasLimit >= BigInt('0x8000000000000000')) {
380
+ const msg = _errorMsg('Invalid block with gas limit greater than (2^63 - 1)', vm, block)
381
+ throw EthereumJSErrorWithoutCode(msg)
382
+ } else {
383
+ if (vm.DEBUG) {
384
+ debug(`Validate block`)
385
+ }
386
+ // TODO: decide what block validation method is appropriate here
387
+ if (opts.skipHeaderValidation !== true) {
388
+ if (typeof (vm.blockchain as any).validateHeader === 'function') {
389
+ await (vm.blockchain as any).validateHeader(block.header)
390
+ } else {
391
+ throw EthereumJSErrorWithoutCode(
392
+ 'cannot validate header: blockchain has no `validateHeader` method',
393
+ )
394
+ }
395
+ }
396
+ await block.validateData(false, true, opts.validateBlockSize ?? false)
397
+ }
398
+ }
399
+ if (vm.common.isActivatedEIP(4788)) {
400
+ if (vm.DEBUG) {
401
+ debug(`accumulate parentBeaconBlockRoot`)
402
+ }
403
+ await accumulateParentBeaconBlockRoot(
404
+ vm,
405
+ block.header.parentBeaconBlockRoot!,
406
+ block.header.timestamp,
407
+ )
408
+ }
409
+ if (vm.common.isActivatedEIP(2935)) {
410
+ if (vm.DEBUG) {
411
+ debug(`accumulate parentBlockHash `)
412
+ }
413
+
414
+ await accumulateParentBlockHash(vm, block.header.number, block.header.parentHash)
415
+ }
416
+
417
+ if (enableProfiler) {
418
+ // eslint-disable-next-line no-console
419
+ console.timeEnd(stateRootCPLabel)
420
+ }
421
+
422
+ // Apply transactions
423
+ if (vm.DEBUG) {
424
+ debug(`Apply transactions`)
425
+ }
426
+
427
+ const blockResults = await applyTransactions(vm, block, opts)
428
+
429
+ if (enableProfiler) {
430
+ // eslint-disable-next-line no-console
431
+ console.time(withdrawalsRewardsCommitLabel)
432
+ }
433
+
434
+ // Add txResult preimages to the blockResults preimages
435
+ // Also add the coinbase preimage
436
+
437
+ if (opts.reportPreimages === true) {
438
+ if (vm.evm.stateManager.getAppliedKey === undefined) {
439
+ throw EthereumJSErrorWithoutCode(
440
+ 'applyBlock: evm.stateManager.getAppliedKey can not be undefined if reportPreimages is true',
441
+ )
442
+ }
443
+ blockResults.preimages.set(
444
+ bytesToHex(vm.evm.stateManager.getAppliedKey(block.header.coinbase.toBytes())),
445
+ block.header.coinbase.toBytes(),
446
+ )
447
+ for (const txResult of blockResults.results) {
448
+ if (txResult.preimages !== undefined) {
449
+ for (const [key, preimage] of txResult.preimages) {
450
+ blockResults.preimages.set(key, preimage)
451
+ }
452
+ }
453
+ }
454
+ }
455
+
456
+ if (vm.common.isActivatedEIP(4895)) {
457
+ if (opts.reportPreimages === true) vm.evm.journal.startReportingPreimages!()
458
+ await assignWithdrawals(vm, block)
459
+ if (opts.reportPreimages === true && vm.evm.journal.preimages !== undefined) {
460
+ for (const [key, preimage] of vm.evm.journal.preimages) {
461
+ blockResults.preimages.set(key, preimage)
462
+ }
463
+ }
464
+ await vm.evm.journal.cleanup()
465
+ }
466
+ // Pay ommers and miners
467
+ if (block.common.consensusType() === ConsensusType.ProofOfWork) {
468
+ await assignBlockRewards(vm, block)
469
+ }
470
+
471
+ if (vm.common.isActivatedEIP(7864) && vm.evm.systemBinaryTreeAccessWitness !== undefined) {
472
+ vm.evm.systemBinaryTreeAccessWitness?.commit()
473
+ if (vm.DEBUG) {
474
+ debug('Binary tree access witness aggregate costs:')
475
+ vm.evm.binaryTreeAccessWitness?.debugWitnessCost()
476
+ debug('System binary tree access witness aggregate costs:')
477
+ vm.evm.systemBinaryTreeAccessWitness?.debugWitnessCost()
478
+ }
479
+ vm.evm.binaryTreeAccessWitness?.merge(vm.evm.systemBinaryTreeAccessWitness)
480
+ }
481
+
482
+ return blockResults
483
+ }
484
+
485
+ /**
486
+ * vm method runs the logic of EIP 2935 (save blockhashes to state)
487
+ * It will put the `parentHash` of the block to the storage slot of `block.number - 1` of the history storage contract.
488
+ * vm contract is used to retrieve BLOCKHASHes in EVM if EIP 2935 is activated.
489
+ * In case that the previous block of `block` is pre-EIP-2935 (so we are on the EIP 2935 fork block), additionally
490
+ * also add the currently available past blockhashes which are available by BLOCKHASH (so, the past 256 block hashes)
491
+ * @param vm The VM to run on
492
+ * @param block The current block to save the parent block hash of
493
+ */
494
+ export async function accumulateParentBlockHash(
495
+ vm: VM,
496
+ currentBlockNumber: bigint,
497
+ parentHash: Uint8Array,
498
+ ) {
499
+ if (!vm.common.isActivatedEIP(2935)) {
500
+ throw EthereumJSErrorWithoutCode(
501
+ 'Cannot call `accumulateParentBlockHash`: EIP 2935 is not active',
502
+ )
503
+ }
504
+ const historyAddress = new Address(bigIntToAddressBytes(vm.common.param('historyStorageAddress')))
505
+ const historyServeWindow = vm.common.param('historyServeWindow')
506
+
507
+ // getAccount with historyAddress will throw error as witnesses are not bundled
508
+ // but we need to put account so as to query later for slot
509
+ const code = await vm.stateManager.getCode(historyAddress)
510
+
511
+ if (code.length === 0) {
512
+ // Exit early, system contract has no code so no storage is written
513
+ return
514
+ }
515
+
516
+ async function putBlockHash(vm: VM, hash: Uint8Array, number: bigint) {
517
+ // ringKey is the key the hash is actually put in (it is a ring buffer)
518
+ const ringKey = number % historyServeWindow
519
+
520
+ if (vm.common.isActivatedEIP(7864)) {
521
+ if (vm.evm.systemBinaryTreeAccessWitness === undefined) {
522
+ throw Error(`systemBinaryTreeAccessWitness required if binary tree (EIP-7864) is activated`)
523
+ }
524
+ // Add to system binary tree access witness so that it doesn't warm up tx accesses
525
+ vm.evm.systemBinaryTreeAccessWitness.writeAccountStorage(historyAddress, ringKey)
526
+ }
527
+ const key = setLengthLeft(bigIntToBytes(ringKey), 32)
528
+ if (vm.common.isActivatedEIP(7928)) {
529
+ vm.evm.blockLevelAccessList!.addStorageWrite(
530
+ historyAddress.toString(),
531
+ key,
532
+ hash,
533
+ vm.evm.blockLevelAccessList!.blockAccessIndex,
534
+ )
535
+ }
536
+ await vm.stateManager.putStorage(historyAddress, key, hash)
537
+ }
538
+ await putBlockHash(vm, parentHash, currentBlockNumber - BIGINT_1)
539
+
540
+ // do cleanup if the code was not deployed
541
+ await vm.evm.journal.cleanup()
542
+ }
543
+
544
+ export async function accumulateParentBeaconBlockRoot(vm: VM, root: Uint8Array, timestamp: bigint) {
545
+ if (!vm.common.isActivatedEIP(4788)) {
546
+ throw EthereumJSErrorWithoutCode(
547
+ 'Cannot call `accumulateParentBeaconBlockRoot`: EIP 4788 is not active',
548
+ )
549
+ }
550
+ // Save the parentBeaconBlockRoot to the beaconroot stateful precompile ring buffers
551
+ const historicalRootsLength = BigInt(vm.common.param('historicalRootsLength'))
552
+ const timestampIndex = timestamp % historicalRootsLength
553
+ const timestampExtended = timestampIndex + historicalRootsLength
554
+
555
+ /**
556
+ * Note: (by Gabriel)
557
+ * Get account will throw an error in stateless execution b/c witnesses are not bundled
558
+ * But we do need an account so we are able to put the storage
559
+ */
560
+ const code = await vm.stateManager.getCode(parentBeaconBlockRootAddress)
561
+
562
+ if (code.length === 0) {
563
+ // Exit early, system contract has no code so no storage is written
564
+ // TODO: verify with Gabriel that this is fine regarding binary trees (should we put an empty account?)
565
+ return
566
+ }
567
+ if (vm.common.isActivatedEIP(7928)) {
568
+ vm.evm.blockLevelAccessList!.addStorageWrite(
569
+ parentBeaconBlockRootAddress.toString(),
570
+ setLengthLeft(bigIntToBytes(timestampIndex), 32),
571
+ bigIntToBytes(timestamp),
572
+ vm.evm.blockLevelAccessList!.blockAccessIndex,
573
+ )
574
+ }
575
+ await vm.stateManager.putStorage(
576
+ parentBeaconBlockRootAddress,
577
+ setLengthLeft(bigIntToBytes(timestampIndex), 32),
578
+ bigIntToBytes(timestamp),
579
+ )
580
+ if (vm.common.isActivatedEIP(7928)) {
581
+ vm.evm.blockLevelAccessList!.addStorageWrite(
582
+ parentBeaconBlockRootAddress.toString(),
583
+ setLengthLeft(bigIntToBytes(timestampExtended), 32),
584
+ root,
585
+ vm.evm.blockLevelAccessList!.blockAccessIndex,
586
+ )
587
+ }
588
+ await vm.stateManager.putStorage(
589
+ parentBeaconBlockRootAddress,
590
+ setLengthLeft(bigIntToBytes(timestampExtended), 32),
591
+ root,
592
+ )
593
+
594
+ // do cleanup if the code was not deployed
595
+ await vm.evm.journal.cleanup()
596
+ }
597
+
598
+ /**
599
+ * Applies the transactions in a block, computing the receipts
600
+ * as well as gas usage and some relevant data. vm method is
601
+ * side-effect free (it doesn't modify the block nor the state).
602
+ * @param {Block} block
603
+ * @param {RunBlockOpts} opts
604
+ */
605
+ async function applyTransactions(vm: VM, block: Block, opts: RunBlockOpts) {
606
+ if (enableProfiler) {
607
+ // eslint-disable-next-line no-console
608
+ console.time(processTxsLabel)
609
+ }
610
+
611
+ const bloom = new Bloom(undefined, vm.common)
612
+ // Block header gas accounting (EIP-7778: no refund subtraction)
613
+ let gasUsed = BIGINT_0
614
+ // Receipt cumulative gas accounting (keeps tx refund subtraction semantics)
615
+ let receiptGasUsed = BIGINT_0
616
+
617
+ let receiptTrie: MerklePatriciaTrie | undefined = undefined
618
+ if (block.transactions.length !== 0) {
619
+ receiptTrie = new MerklePatriciaTrie({ common: vm.common })
620
+ }
621
+
622
+ const receipts: TxReceipt[] = []
623
+ const txResults: RunTxResult[] = []
624
+
625
+ /*
626
+ * Process transactions
627
+ */
628
+ for (let txIdx = 0; txIdx < block.transactions.length; txIdx++) {
629
+ if (vm.common.isActivatedEIP(7928)) {
630
+ vm.evm.blockLevelAccessList!.blockAccessIndex = txIdx + 1
631
+ }
632
+ const tx = block.transactions[txIdx]
633
+
634
+ if (vm.DEBUG) {
635
+ debug(
636
+ `Run tx ${txIdx + 1}/${block.transactions.length} gasLimit=${tx.gasLimit} type=${tx.type} (block gas used so far: ${gasUsed}/${block.header.gasLimit})`,
637
+ )
638
+ }
639
+
640
+ const gasLimitIsHigherThanBlock = block.header.gasLimit < tx.gasLimit + gasUsed
641
+ if (gasLimitIsHigherThanBlock) {
642
+ const msg = _errorMsg('tx has a higher gas limit than the block', vm, block)
643
+ throw EthereumJSErrorWithoutCode(msg)
644
+ }
645
+
646
+ // Run the tx through the VM
647
+ const { skipBalance, skipNonce, skipHardForkValidation, reportPreimages } = opts
648
+
649
+ const txRes = await runTx(vm, {
650
+ tx,
651
+ block,
652
+ skipBalance,
653
+ skipNonce,
654
+ skipHardForkValidation,
655
+ blockGasUsed: receiptGasUsed,
656
+ reportPreimages,
657
+ })
658
+ txResults.push(txRes)
659
+ if (vm.DEBUG) {
660
+ debug('-'.repeat(100))
661
+ }
662
+
663
+ // Add to total block gas usage
664
+ gasUsed += txRes.blockGasSpent
665
+ receiptGasUsed += txRes.totalGasSpent
666
+ if (vm.DEBUG) {
667
+ debug(`Add tx gas used (${txRes.blockGasSpent}) to total block gas usage (-> ${gasUsed})`)
668
+ }
669
+
670
+ // Combine blooms via bitwise OR
671
+ bloom.or(txRes.bloom)
672
+
673
+ // Add receipt to trie to later calculate receipt root
674
+ receipts.push(txRes.receipt)
675
+ const encodedReceipt = encodeReceipt(txRes.receipt, tx.type)
676
+ await receiptTrie!.put(RLP.encode(txIdx), encodedReceipt)
677
+ }
678
+
679
+ if (enableProfiler) {
680
+ // eslint-disable-next-line no-console
681
+ console.timeEnd(processTxsLabel)
682
+ }
683
+
684
+ const receiptsRoot = receiptTrie !== undefined ? receiptTrie.root() : KECCAK256_RLP
685
+
686
+ return {
687
+ bloom,
688
+ gasUsed,
689
+ preimages: new Map<PrefixedHexString, Uint8Array>(),
690
+ receiptsRoot,
691
+ receipts,
692
+ results: txResults,
693
+ }
694
+ }
695
+
696
+ async function assignWithdrawals(vm: VM, block: Block): Promise<void> {
697
+ if (vm.common.isActivatedEIP(7928)) {
698
+ vm.evm.blockLevelAccessList!.blockAccessIndex = block.transactions.length + 1
699
+ }
700
+ const withdrawals = block.withdrawals!
701
+ for (const withdrawal of withdrawals) {
702
+ const { address, amount } = withdrawal
703
+ // Withdrawal amount is represented in Gwei so needs to be
704
+ // converted to wei
705
+ // Note: event if amount is 0, still reward the account
706
+ // such that the account is touched and marked for cleanup if it is empty
707
+ await rewardAccount(vm.evm, address, amount * GWEI_TO_WEI, vm.common)
708
+ }
709
+ }
710
+
711
+ /**
712
+ * Calculates block rewards for miner and ommers and puts
713
+ * the updated balances of their accounts to state.
714
+ */
715
+ async function assignBlockRewards(vm: VM, block: Block): Promise<void> {
716
+ if (vm.DEBUG) {
717
+ debug(`Assign block rewards`)
718
+ }
719
+ const minerReward = vm.common.param('minerReward')
720
+ const ommers = block.uncleHeaders
721
+ // Reward ommers
722
+ for (const ommer of ommers) {
723
+ const reward = calculateOmmerReward(ommer.number, block.header.number, minerReward)
724
+ const account = await rewardAccount(vm.evm, ommer.coinbase, reward, vm.common)
725
+ if (vm.DEBUG) {
726
+ debug(`Add uncle reward ${reward} to account ${ommer.coinbase} (-> ${account.balance})`)
727
+ }
728
+ }
729
+ // Reward miner
730
+ const reward = calculateMinerReward(minerReward, ommers.length)
731
+ const account = await rewardAccount(vm.evm, block.header.coinbase, reward, vm.common)
732
+ if (vm.DEBUG) {
733
+ debug(`Add miner reward ${reward} to account ${block.header.coinbase} (-> ${account.balance})`)
734
+ }
735
+ }
736
+
737
+ function calculateOmmerReward(
738
+ ommerBlockNumber: bigint,
739
+ blockNumber: bigint,
740
+ minerReward: bigint,
741
+ ): bigint {
742
+ const heightDiff = blockNumber - ommerBlockNumber
743
+ let reward = ((BIGINT_8 - heightDiff) * minerReward) / BIGINT_8
744
+ if (reward < BIGINT_0) {
745
+ reward = BIGINT_0
746
+ }
747
+ return reward
748
+ }
749
+
750
+ export function calculateMinerReward(minerReward: bigint, ommersNum: number): bigint {
751
+ // calculate nibling reward
752
+ const niblingReward = minerReward / BigInt(32)
753
+ const totalNiblingReward = niblingReward * BigInt(ommersNum)
754
+ const reward = minerReward + totalNiblingReward
755
+ return reward
756
+ }
757
+
758
+ export async function rewardAccount(
759
+ evm: EVMInterface,
760
+ address: Address,
761
+ reward: bigint,
762
+ common: Common,
763
+ ): Promise<Account> {
764
+ let account = await evm.stateManager.getAccount(address)
765
+ if (account === undefined) {
766
+ if (common.isActivatedEIP(7864) === true && reward !== BIGINT_0) {
767
+ if (evm.systemBinaryTreeAccessWitness === undefined) {
768
+ throw Error(`systemBinaryTreeAccessWitness required if binary tree (EIP-7864) is activated`)
769
+ }
770
+ evm.systemBinaryTreeAccessWitness.writeAccountHeader(address)
771
+ }
772
+ account = new Account()
773
+ }
774
+ const originalBalance = account.balance
775
+ account.balance += reward
776
+ if (common.isActivatedEIP(7928)) {
777
+ if (reward === BIGINT_0) {
778
+ evm.blockLevelAccessList?.addAddress(address.toString())
779
+ } else {
780
+ evm.blockLevelAccessList!.addBalanceChange(
781
+ address.toString(),
782
+ account.balance,
783
+ evm.blockLevelAccessList!.blockAccessIndex,
784
+ originalBalance,
785
+ )
786
+ }
787
+ }
788
+ await evm.journal.putAccount(address, account)
789
+
790
+ if (common.isActivatedEIP(7864) === true && reward !== BIGINT_0) {
791
+ if (evm.systemBinaryTreeAccessWitness === undefined) {
792
+ throw Error(`systemBinaryTreeAccessWitness required if binary tree (EIP-7864) is activated`)
793
+ }
794
+ evm.systemBinaryTreeAccessWitness.writeAccountBasicData(address)
795
+ evm.systemBinaryTreeAccessWitness.readAccountCodeHash(address)
796
+ }
797
+ return account
798
+ }
799
+
800
+ /**
801
+ * Returns the encoded tx receipt.
802
+ */
803
+ export function encodeReceipt(
804
+ receipt: TxReceipt,
805
+ txType: (typeof TransactionType)[keyof typeof TransactionType],
806
+ ) {
807
+ const encoded = RLP.encode([
808
+ (receipt as PreByzantiumTxReceipt).stateRoot ??
809
+ ((receipt as PostByzantiumTxReceipt).status === 0 ? Uint8Array.from([]) : hexToBytes('0x01')),
810
+ bigIntToBytes(receipt.cumulativeBlockGasUsed),
811
+ receipt.bitvector,
812
+ receipt.logs,
813
+ ])
814
+
815
+ if (txType === TransactionType.Legacy) {
816
+ return encoded
817
+ }
818
+
819
+ // Serialize receipt according to EIP-2718:
820
+ // `typed-receipt = tx-type || receipt-data`
821
+ return concatBytes(intToBytes(txType), encoded)
822
+ }
823
+
824
+ /**
825
+ * Apply the DAO fork changes to the VM
826
+ */
827
+ async function _applyDAOHardfork(evm: EVMInterface) {
828
+ const state = evm.stateManager
829
+
830
+ /* DAO account list */
831
+ const DAOAccountList = DAOConfig.DAOAccounts
832
+ const DAORefundContract = DAOConfig.DAORefundContract
833
+
834
+ const DAORefundContractAddress = new Address(unprefixedHexToBytes(DAORefundContract))
835
+ if ((await state.getAccount(DAORefundContractAddress)) === undefined) {
836
+ await evm.journal.putAccount(DAORefundContractAddress, new Account())
837
+ }
838
+ let DAORefundAccount = await state.getAccount(DAORefundContractAddress)
839
+ if (DAORefundAccount === undefined) {
840
+ DAORefundAccount = new Account()
841
+ }
842
+
843
+ const originalDAORefundAccountBalance = DAORefundAccount.balance
844
+ for (const addr of DAOAccountList) {
845
+ // retrieve the account and add it to the DAO's Refund accounts' balance.
846
+ const address = new Address(unprefixedHexToBytes(addr))
847
+ let account = await state.getAccount(address)
848
+ if (account === undefined) {
849
+ account = new Account()
850
+ }
851
+ DAORefundAccount.balance += account.balance
852
+ // clear the accounts' balance
853
+ const originalBalance = account.balance
854
+ account.balance = BIGINT_0
855
+ await evm.journal.putAccount(address, account)
856
+ if (evm.common.isActivatedEIP(7928)) {
857
+ evm.blockLevelAccessList!.addBalanceChange(
858
+ address.toString(),
859
+ account.balance,
860
+ evm.blockLevelAccessList!.blockAccessIndex,
861
+ originalBalance,
862
+ )
863
+ }
864
+ }
865
+
866
+ // finally, put the Refund Account
867
+ await evm.journal.putAccount(DAORefundContractAddress, DAORefundAccount)
868
+ if (evm.common.isActivatedEIP(7928)) {
869
+ evm.blockLevelAccessList!.addBalanceChange(
870
+ DAORefundContractAddress.toString(),
871
+ DAORefundAccount.balance,
872
+ evm.blockLevelAccessList!.blockAccessIndex,
873
+ originalDAORefundAccountBalance,
874
+ )
875
+ }
876
+ }
877
+
878
+ async function _genTxTrie(block: Block) {
879
+ if (block.transactions.length === 0) {
880
+ return KECCAK256_RLP
881
+ }
882
+ const trie = new MerklePatriciaTrie({ common: block.common })
883
+ for (const [i, tx] of block.transactions.entries()) {
884
+ await trie.put(RLP.encode(i), tx.serialize())
885
+ }
886
+ return trie.root()
887
+ }
888
+
889
+ /**
890
+ * Internal helper function to create an annotated error message
891
+ *
892
+ * @param msg Base error message
893
+ * @hidden
894
+ */
895
+ function _errorMsg(msg: string, vm: VM, block: Block) {
896
+ const blockErrorStr = 'errorStr' in block ? block.errorStr() : 'block'
897
+
898
+ const errorMsg = `${msg} (${vm.errorStr()} -> ${blockErrorStr})`
899
+ return errorMsg
900
+ }
901
+
902
+ const DAOConfig = {
903
+ DAOAccounts: [
904
+ 'd4fe7bc31cedb7bfb8a345f31e668033056b2728',
905
+ 'b3fb0e5aba0e20e5c49d252dfd30e102b171a425',
906
+ '2c19c7f9ae8b751e37aeb2d93a699722395ae18f',
907
+ 'ecd135fa4f61a655311e86238c92adcd779555d2',
908
+ '1975bd06d486162d5dc297798dfc41edd5d160a7',
909
+ 'a3acf3a1e16b1d7c315e23510fdd7847b48234f6',
910
+ '319f70bab6845585f412ec7724b744fec6095c85',
911
+ '06706dd3f2c9abf0a21ddcc6941d9b86f0596936',
912
+ '5c8536898fbb74fc7445814902fd08422eac56d0',
913
+ '6966ab0d485353095148a2155858910e0965b6f9',
914
+ '779543a0491a837ca36ce8c635d6154e3c4911a6',
915
+ '2a5ed960395e2a49b1c758cef4aa15213cfd874c',
916
+ '5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5',
917
+ '9c50426be05db97f5d64fc54bf89eff947f0a321',
918
+ '200450f06520bdd6c527622a273333384d870efb',
919
+ 'be8539bfe837b67d1282b2b1d61c3f723966f049',
920
+ '6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb',
921
+ 'f1385fb24aad0cd7432824085e42aff90886fef5',
922
+ 'd1ac8b1ef1b69ff51d1d401a476e7e612414f091',
923
+ '8163e7fb499e90f8544ea62bbf80d21cd26d9efd',
924
+ '51e0ddd9998364a2eb38588679f0d2c42653e4a6',
925
+ '627a0a960c079c21c34f7612d5d230e01b4ad4c7',
926
+ 'f0b1aa0eb660754448a7937c022e30aa692fe0c5',
927
+ '24c4d950dfd4dd1902bbed3508144a54542bba94',
928
+ '9f27daea7aca0aa0446220b98d028715e3bc803d',
929
+ 'a5dc5acd6a7968a4554d89d65e59b7fd3bff0f90',
930
+ 'd9aef3a1e38a39c16b31d1ace71bca8ef58d315b',
931
+ '63ed5a272de2f6d968408b4acb9024f4cc208ebf',
932
+ '6f6704e5a10332af6672e50b3d9754dc460dfa4d',
933
+ '77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6',
934
+ '492ea3bb0f3315521c31f273e565b868fc090f17',
935
+ '0ff30d6de14a8224aa97b78aea5388d1c51c1f00',
936
+ '9ea779f907f0b315b364b0cfc39a0fde5b02a416',
937
+ 'ceaeb481747ca6c540a000c1f3641f8cef161fa7',
938
+ 'cc34673c6c40e791051898567a1222daf90be287',
939
+ '579a80d909f346fbfb1189493f521d7f48d52238',
940
+ 'e308bd1ac5fda103967359b2712dd89deffb7973',
941
+ '4cb31628079fb14e4bc3cd5e30c2f7489b00960c',
942
+ 'ac1ecab32727358dba8962a0f3b261731aad9723',
943
+ '4fd6ace747f06ece9c49699c7cabc62d02211f75',
944
+ '440c59b325d2997a134c2c7c60a8c61611212bad',
945
+ '4486a3d68fac6967006d7a517b889fd3f98c102b',
946
+ '9c15b54878ba618f494b38f0ae7443db6af648ba',
947
+ '27b137a85656544b1ccb5a0f2e561a5703c6a68f',
948
+ '21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241',
949
+ '23b75c2f6791eef49c69684db4c6c1f93bf49a50',
950
+ '1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b',
951
+ 'b9637156d330c0d605a791f1c31ba5890582fe1c',
952
+ '6131c42fa982e56929107413a9d526fd99405560',
953
+ '1591fc0f688c81fbeb17f5426a162a7024d430c2',
954
+ '542a9515200d14b68e934e9830d91645a980dd7a',
955
+ 'c4bbd073882dd2add2424cf47d35213405b01324',
956
+ '782495b7b3355efb2833d56ecb34dc22ad7dfcc4',
957
+ '58b95c9a9d5d26825e70a82b6adb139d3fd829eb',
958
+ '3ba4d81db016dc2890c81f3acec2454bff5aada5',
959
+ 'b52042c8ca3f8aa246fa79c3feaa3d959347c0ab',
960
+ 'e4ae1efdfc53b73893af49113d8694a057b9c0d1',
961
+ '3c02a7bc0391e86d91b7d144e61c2c01a25a79c5',
962
+ '0737a6b837f97f46ebade41b9bc3e1c509c85c53',
963
+ '97f43a37f595ab5dd318fb46e7a155eae057317a',
964
+ '52c5317c848ba20c7504cb2c8052abd1fde29d03',
965
+ '4863226780fe7c0356454236d3b1c8792785748d',
966
+ '5d2b2e6fcbe3b11d26b525e085ff818dae332479',
967
+ '5f9f3392e9f62f63b8eac0beb55541fc8627f42c',
968
+ '057b56736d32b86616a10f619859c6cd6f59092a',
969
+ '9aa008f65de0b923a2a4f02012ad034a5e2e2192',
970
+ '304a554a310c7e546dfe434669c62820b7d83490',
971
+ '914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79',
972
+ '4deb0033bb26bc534b197e61d19e0733e5679784',
973
+ '07f5c1e1bc2c93e0402f23341973a0e043f7bf8a',
974
+ '35a051a0010aba705c9008d7a7eff6fb88f6ea7b',
975
+ '4fa802324e929786dbda3b8820dc7834e9134a2a',
976
+ '9da397b9e80755301a3b32173283a91c0ef6c87e',
977
+ '8d9edb3054ce5c5774a420ac37ebae0ac02343c6',
978
+ '0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9',
979
+ '5dc28b15dffed94048d73806ce4b7a4612a1d48f',
980
+ 'bcf899e6c7d9d5a215ab1e3444c86806fa854c76',
981
+ '12e626b0eebfe86a56d633b9864e389b45dcb260',
982
+ 'a2f1ccba9395d7fcb155bba8bc92db9bafaeade7',
983
+ 'ec8e57756626fdc07c63ad2eafbd28d08e7b0ca5',
984
+ 'd164b088bd9108b60d0ca3751da4bceb207b0782',
985
+ '6231b6d0d5e77fe001c2a460bd9584fee60d409b',
986
+ '1cba23d343a983e9b5cfd19496b9a9701ada385f',
987
+ 'a82f360a8d3455c5c41366975bde739c37bfeb8a',
988
+ '9fcd2deaff372a39cc679d5c5e4de7bafb0b1339',
989
+ '005f5cee7a43331d5a3d3eec71305925a62f34b6',
990
+ '0e0da70933f4c7849fc0d203f5d1d43b9ae4532d',
991
+ 'd131637d5275fd1a68a3200f4ad25c71a2a9522e',
992
+ 'bc07118b9ac290e4622f5e77a0853539789effbe',
993
+ '47e7aa56d6bdf3f36be34619660de61275420af8',
994
+ 'acd87e28b0c9d1254e868b81cba4cc20d9a32225',
995
+ 'adf80daec7ba8dcf15392f1ac611fff65d94f880',
996
+ '5524c55fb03cf21f549444ccbecb664d0acad706',
997
+ '40b803a9abce16f50f36a77ba41180eb90023925',
998
+ 'fe24cdd8648121a43a7c86d289be4dd2951ed49f',
999
+ '17802f43a0137c506ba92291391a8a8f207f487d',
1000
+ '253488078a4edf4d6f42f113d1e62836a942cf1a',
1001
+ '86af3e9626fce1957c82e88cbf04ddf3a2ed7915',
1002
+ 'b136707642a4ea12fb4bae820f03d2562ebff487',
1003
+ 'dbe9b615a3ae8709af8b93336ce9b477e4ac0940',
1004
+ 'f14c14075d6c4ed84b86798af0956deef67365b5',
1005
+ 'ca544e5c4687d109611d0f8f928b53a25af72448',
1006
+ 'aeeb8ff27288bdabc0fa5ebb731b6f409507516c',
1007
+ 'cbb9d3703e651b0d496cdefb8b92c25aeb2171f7',
1008
+ '6d87578288b6cb5549d5076a207456a1f6a63dc0',
1009
+ 'b2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e',
1010
+ 'accc230e8a6e5be9160b8cdf2864dd2a001c28b6',
1011
+ '2b3455ec7fedf16e646268bf88846bd7a2319bb2',
1012
+ '4613f3bca5c44ea06337a9e439fbc6d42e501d0a',
1013
+ 'd343b217de44030afaa275f54d31a9317c7f441e',
1014
+ '84ef4b2357079cd7a7c69fd7a37cd0609a679106',
1015
+ 'da2fef9e4a3230988ff17df2165440f37e8b1708',
1016
+ 'f4c64518ea10f995918a454158c6b61407ea345c',
1017
+ '7602b46df5390e432ef1c307d4f2c9ff6d65cc97',
1018
+ 'bb9bc244d798123fde783fcc1c72d3bb8c189413',
1019
+ '807640a13483f8ac783c557fcdf27be11ea4ac7a',
1020
+ ],
1021
+ DAORefundContract: 'bf4ed7b27f1d666546e30d74d50d173d20bca754',
1022
+ }