|
|
|
@ -1,10 +1,21 @@ |
|
|
|
|
'use strict' |
|
|
|
|
import { RunBlockResult, RunTxResult } from '@ethereumjs/vm' |
|
|
|
|
import { Transaction, FeeMarketEIP1559Transaction } from '@ethereumjs/tx' |
|
|
|
|
import { Block } from '@ethereumjs/block' |
|
|
|
|
import { BN, bufferToHex, Address } from 'ethereumjs-util' |
|
|
|
|
import type { Account } from '@ethereumjs/util' |
|
|
|
|
import { EventManager } from '../eventManager' |
|
|
|
|
import { LogsManager } from './logsManager' |
|
|
|
|
|
|
|
|
|
export type VMxecutionResult = { |
|
|
|
|
result: RunTxResult, |
|
|
|
|
transactionHash: string |
|
|
|
|
block: Block, |
|
|
|
|
tx: Transaction |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export type VMExecutionCallBack = (error: string | Error, result?: VMxecutionResult) => void |
|
|
|
|
|
|
|
|
|
export class TxRunnerVM { |
|
|
|
|
event |
|
|
|
|
blockNumber |
|
|
|
@ -48,13 +59,13 @@ export class TxRunnerVM { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
this.runInVm(args.from, args.to, data, args.value, args.gasLimit, args.useCall, args.timestamp, callback) |
|
|
|
|
this.runInVm(args.from, args.to, data, args.value, args.gasLimit, args.useCall, callback) |
|
|
|
|
} catch (e) { |
|
|
|
|
callback(e, null) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
runInVm (from, to, data, value, gasLimit, useCall, timestamp, callback) { |
|
|
|
|
runInVm (from: string, to: string, data: string, value: string, gasLimit: number, useCall: boolean, callback: VMExecutionCallBack) { |
|
|
|
|
const self = this |
|
|
|
|
let account |
|
|
|
|
if (!from && useCall && Object.keys(self.vmaccounts).length) { |
|
|
|
@ -65,30 +76,13 @@ export class TxRunnerVM { |
|
|
|
|
if (!account) { |
|
|
|
|
return callback('Invalid account selected') |
|
|
|
|
} |
|
|
|
|
if (Number.isInteger(gasLimit)) { |
|
|
|
|
gasLimit = '0x' + gasLimit.toString(16) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.getVMObject().stateManager.getAccount(Address.fromString(from)).then((res) => { |
|
|
|
|
// See https://github.com/ethereumjs/ethereumjs-tx/blob/master/docs/classes/transaction.md#constructor
|
|
|
|
|
// for initialization fields and their types
|
|
|
|
|
if (!value) value = 0 |
|
|
|
|
if (typeof value === 'string') { |
|
|
|
|
if (value.startsWith('0x')) value = new BN(value.replace('0x', ''), 'hex') |
|
|
|
|
else { |
|
|
|
|
try { |
|
|
|
|
value = new BN(value, 10) |
|
|
|
|
} catch (e) { |
|
|
|
|
return callback('Unable to parse the value ' + e.message) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.getVMObject().stateManager.getAccount(Address.fromString(from)).then((res: Account) => { |
|
|
|
|
const EIP1559 = this.commonContext.hardfork() !== 'berlin' // berlin is the only pre eip1559 fork that we handle.
|
|
|
|
|
let tx |
|
|
|
|
if (!EIP1559) { |
|
|
|
|
tx = Transaction.fromTxData({ |
|
|
|
|
nonce: useCall ? this.nextNonceForCall : new BN(res.nonce), |
|
|
|
|
nonce: useCall ? this.nextNonceForCall : res.nonce, |
|
|
|
|
gasPrice: '0x1', |
|
|
|
|
gasLimit: gasLimit, |
|
|
|
|
to: to, |
|
|
|
@ -97,7 +91,7 @@ export class TxRunnerVM { |
|
|
|
|
}, { common: this.commonContext }).sign(account.privateKey) |
|
|
|
|
} else { |
|
|
|
|
tx = FeeMarketEIP1559Transaction.fromTxData({ |
|
|
|
|
nonce: useCall ? this.nextNonceForCall : new BN(res.nonce), |
|
|
|
|
nonce: useCall ? this.nextNonceForCall : res.nonce, |
|
|
|
|
maxPriorityFeePerGas: '0x01', |
|
|
|
|
maxFeePerGas: '0x1', |
|
|
|
|
gasLimit: gasLimit, |
|
|
|
@ -109,15 +103,15 @@ export class TxRunnerVM { |
|
|
|
|
if (useCall) this.nextNonceForCall++ |
|
|
|
|
|
|
|
|
|
const coinbases = ['0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a', '0x8945a1288dc78a6d8952a92c77aee6730b414778', '0x94d76e24f818426ae84aa404140e8d5f60e10e7e'] |
|
|
|
|
const difficulties = [new BN('69762765929000', 10), new BN('70762765929000', 10), new BN('71762765929000', 10)] |
|
|
|
|
const difficulties = [69762765929000, 70762765929000, 71762765929000] |
|
|
|
|
|
|
|
|
|
const block = Block.fromBlockData({ |
|
|
|
|
header: { |
|
|
|
|
timestamp: timestamp || (new Date().getTime() / 1000 | 0), |
|
|
|
|
timestamp: new Date().getTime() / 1000 | 0, |
|
|
|
|
number: self.blockNumber, |
|
|
|
|
coinbase: coinbases[self.blockNumber % coinbases.length], |
|
|
|
|
difficulty: difficulties[self.blockNumber % difficulties.length], |
|
|
|
|
gasLimit: new BN(gasLimit.replace('0x', ''), 16).imuln(2), |
|
|
|
|
gasLimit, |
|
|
|
|
baseFeePerGas: EIP1559 ? '0x1' : undefined |
|
|
|
|
}, |
|
|
|
|
transactions: [tx] |
|
|
|
@ -141,14 +135,15 @@ export class TxRunnerVM { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
runBlockInVm (tx, block, callback) { |
|
|
|
|
this.getVMObject().vm.runBlock({ block: block, generate: true, skipBlockValidation: true, skipBalance: false, skipNonce: true }).then((results) => { |
|
|
|
|
this.getVMObject().vm.runBlock({ block: block, generate: true, skipBlockValidation: true, skipBalance: false, skipNonce: true }).then((results: RunBlockResult) => { |
|
|
|
|
const result = results.results[0] |
|
|
|
|
if (result) { |
|
|
|
|
/*if (result) { |
|
|
|
|
const status = result.execResult.exceptionError ? 0 : 1 |
|
|
|
|
result.receipt.status |
|
|
|
|
result.status = `0x${status}` |
|
|
|
|
} |
|
|
|
|
}*/ |
|
|
|
|
callback(null, { |
|
|
|
|
result: result, |
|
|
|
|
result, |
|
|
|
|
transactionHash: bufferToHex(Buffer.from(tx.hash())), |
|
|
|
|
block, |
|
|
|
|
tx |
|
|
|
|