Merge pull request #1122 from ethereum/berlinFork

Use last ethereumjs-vm for berlin fork ("@ethereumjs/vm": "^5.3.2")
pull/988/head^2
yann300 4 years ago committed by GitHub
commit 5884325cb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      apps/remix-ide-e2e/src/tests/ballot.test.ts
  2. 2
      apps/remix-ide-e2e/src/tests/debugger.spec.ts
  3. 4
      apps/remix-ide/src/app/panels/file-panel.js
  4. 1
      apps/remix-ide/src/app/tabs/compileTab/compilerContainer.js
  5. 2
      apps/remix-ide/src/app/tabs/runTab/model/recorder.js
  6. 4
      apps/remix-ide/src/blockchain/blockchain.js
  7. 3
      apps/remix-ide/src/blockchain/providers/injected.js
  8. 3
      apps/remix-ide/src/blockchain/providers/node.js
  9. 3
      apps/remix-ide/src/blockchain/providers/vm.js
  10. 6
      libs/remix-analyzer/package.json
  11. 6
      libs/remix-astwalker/package.json
  12. 8
      libs/remix-debug/package.json
  13. 3
      libs/remix-debug/src/code/disassembler.ts
  14. 6
      libs/remix-debug/src/solidity-decoder/types/Mapping.ts
  15. 4
      libs/remix-debug/src/solidity-decoder/types/util.ts
  16. 2
      libs/remix-debug/src/trace/traceCache.ts
  17. 24
      libs/remix-debug/test/debugger.ts
  18. 4
      libs/remix-debug/test/decoder/localDecoder.ts
  19. 4
      libs/remix-debug/test/decoder/stateTests/mapping.ts
  20. 60
      libs/remix-debug/test/decoder/vmCall.ts
  21. 37
      libs/remix-debug/test/vmCall.ts
  22. 8
      libs/remix-lib/package.json
  23. 99
      libs/remix-lib/src/execution/execution-context.ts
  24. 2
      libs/remix-lib/src/execution/txFormat.ts
  25. 43
      libs/remix-lib/src/execution/txRunner.ts
  26. 23
      libs/remix-lib/src/universalDapp.ts
  27. 34
      libs/remix-lib/src/util.ts
  28. 70
      libs/remix-lib/src/web3Provider/web3VmProvider.ts
  29. 8
      libs/remix-simulator/package.json
  30. 15
      libs/remix-simulator/src/genesis.ts
  31. 34
      libs/remix-simulator/src/methods/accounts.ts
  32. 4
      libs/remix-simulator/src/methods/blocks.ts
  33. 9
      libs/remix-simulator/src/methods/transactions.ts
  34. 4
      libs/remix-simulator/src/provider.ts
  35. 3
      libs/remix-simulator/test/accounts.ts
  36. 5
      libs/remix-simulator/test/blocks.ts
  37. 3
      libs/remix-simulator/test/misc.ts
  38. 6
      libs/remix-solidity/package.json
  39. 2
      libs/remix-solidity/src/compiler/types.ts
  40. 6
      libs/remix-tests/package.json
  41. 1510
      package-lock.json
  42. 9
      package.json

@ -42,6 +42,7 @@ module.exports = {
.pause(2000) .pause(2000)
.waitForElementVisible('#stepdetail') .waitForElementVisible('#stepdetail')
.goToVMTraceStep(144) .goToVMTraceStep(144)
.pause(2000)
.checkVariableDebug('soliditystate', stateCheck) .checkVariableDebug('soliditystate', stateCheck)
.checkVariableDebug('soliditylocals', localsCheck) .checkVariableDebug('soliditylocals', localsCheck)
}, },

@ -187,7 +187,7 @@ module.exports = {
browser browser
.addFile('test_jsGetTrace.js', { content: jsGetTrace }) .addFile('test_jsGetTrace.js', { content: jsGetTrace })
.executeScript('remix.exeCurrent()') .executeScript('remix.exeCurrent()')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'result { "gas": "0x5863", "return": "0x0000000000000000000000000000000000000000000000000000000000000000", "structLogs":', 60000) .waitForElementContainsText('*[data-id="terminalJournal"]', 'result { "gas": "0x575f", "return": "0x0000000000000000000000000000000000000000000000000000000000000000", "structLogs":', 60000)
}, },
'Should call the debugger api: debug': function (browser: NightwatchBrowser) { 'Should call the debugger api: debug': function (browser: NightwatchBrowser) {

@ -4,7 +4,7 @@ import * as packageJson from '../../../../../package.json'
import React from 'react' // eslint-disable-line import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import { Workspace } from '@remix-ui/workspace' // eslint-disable-line import { Workspace } from '@remix-ui/workspace' // eslint-disable-line
import * as ethutil from 'ethereumjs-util' import { bufferToHex, keccakFromString } from 'ethereumjs-util'
import { checkSpecialChars, checkSlash } from '../../lib/helper' import { checkSpecialChars, checkSlash } from '../../lib/helper'
var EventManager = require('../../lib/events') var EventManager = require('../../lib/events')
var { RemixdHandle } = require('../files/remixd-handle.js') var { RemixdHandle } = require('../files/remixd-handle.js')
@ -154,7 +154,7 @@ module.exports = class Filepanel extends ViewPlugin {
try { try {
await this.processCreateWorkspace('code-sample') await this.processCreateWorkspace('code-sample')
this._deps.fileProviders.workspace.setWorkspace('code-sample') this._deps.fileProviders.workspace.setWorkspace('code-sample')
var hash = ethutil.bufferToHex(ethutil.keccak(params.code)) var hash = bufferToHex(keccakFromString(params.code))
const fileName = 'contract-' + hash.replace('0x', '').substring(0, 10) + '.sol' const fileName = 'contract-' + hash.replace('0x', '').substring(0, 10) + '.sol'
const path = fileName const path = fileName
await this._deps.fileProviders.workspace.set(path, atob(params.code)) await this._deps.fileProviders.workspace.set(path, atob(params.code))

@ -225,6 +225,7 @@ class CompilerContainer {
this._view.evmVersionSelector = yo` this._view.evmVersionSelector = yo`
<select onchange="${() => this.onchangeEvmVersion()}" class="custom-select" id="evmVersionSelector"> <select onchange="${() => this.onchangeEvmVersion()}" class="custom-select" id="evmVersionSelector">
<option value="default" selected="selected">compiler default</option> <option value="default" selected="selected">compiler default</option>
<option>berlin</option>
<option>muirGlacier</option> <option>muirGlacier</option>
<option>istanbul</option> <option>istanbul</option>
<option>petersburg</option> <option>petersburg</option>

@ -25,7 +25,7 @@ class Recorder {
var record = { value, parameters: payLoad.funArgs } var record = { value, parameters: payLoad.funArgs }
if (!to) { if (!to) {
var abi = payLoad.contractABI var abi = payLoad.contractABI
var keccak = ethutil.bufferToHex(ethutil.keccak(JSON.stringify(abi))) var keccak = ethutil.bufferToHex(ethutil.keccakFromString(JSON.stringify(abi)))
record.abi = keccak record.abi = keccak
record.contractName = payLoad.contractName record.contractName = payLoad.contractName
record.bytecode = payLoad.contractBytecode record.bytecode = payLoad.contractBytecode

@ -439,7 +439,7 @@ class Blockchain {
function (error, result) { function (error, result) {
if (error) return next(error) if (error) return next(error)
const rawAddress = self.executionContext.isVM() ? result.result.createdAddress : result.result.contractAddress const rawAddress = self.executionContext.isVM() ? (result.result.createdAddress && result.result.createdAddress.toBuffer()) : result.result.contractAddress
const eventName = (tx.useCall ? 'callExecuted' : 'transactionExecuted') const eventName = (tx.useCall ? 'callExecuted' : 'transactionExecuted')
self.event.trigger(eventName, [error, tx.from, tx.to, tx.data, tx.useCall, result, timestamp, payLoad, rawAddress]) self.event.trigger(eventName, [error, tx.from, tx.to, tx.data, tx.useCall, result, timestamp, payLoad, rawAddress])
@ -470,7 +470,7 @@ class Blockchain {
let address = null let address = null
let returnValue = null let returnValue = null
if (txResult && txResult.result) { if (txResult && txResult.result) {
address = isVM ? txResult.result.createdAddress : txResult.result.contractAddress address = isVM ? (txResult.result.createdAddress && txResult.result.createdAddress.toBuffer()) : txResult.result.contractAddress
// if it's not the VM, we don't have return value. We only have the transaction, and it does not contain the return value. // if it's not the VM, we don't have return value. We only have the transaction, and it does not contain the return value.
returnValue = (txResult.result.execResult && isVM) ? txResult.result.execResult.returnValue : txResult.result returnValue = (txResult.result.execResult && isVM) ? txResult.result.execResult.returnValue : txResult.result
} }

@ -1,5 +1,5 @@
const Web3 = require('web3') const Web3 = require('web3')
const { stripHexPrefix, hashPersonalMessage } = require('ethereumjs-util') const { hashPersonalMessage } = require('ethereumjs-util')
class InjectedProvider { class InjectedProvider {
constructor (executionContext) { constructor (executionContext) {
@ -20,7 +20,6 @@ class InjectedProvider {
} }
getBalanceInEther (address, cb) { getBalanceInEther (address, cb) {
address = stripHexPrefix(address)
this.executionContext.web3().eth.getBalance(address, (err, res) => { this.executionContext.web3().eth.getBalance(address, (err, res) => {
if (err) { if (err) {
return cb(err) return cb(err)

@ -1,5 +1,5 @@
const Web3 = require('web3') const Web3 = require('web3')
const { stripHexPrefix, hashPersonalMessage } = require('ethereumjs-util') const { hashPersonalMessage } = require('ethereumjs-util')
const Personal = require('web3-eth-personal') const Personal = require('web3-eth-personal')
class NodeProvider { class NodeProvider {
@ -28,7 +28,6 @@ class NodeProvider {
} }
getBalanceInEther (address, cb) { getBalanceInEther (address, cb) {
address = stripHexPrefix(address)
this.executionContext.web3().eth.getBalance(address, (err, res) => { this.executionContext.web3().eth.getBalance(address, (err, res) => {
if (err) { if (err) {
return cb(err) return cb(err)

@ -1,5 +1,5 @@
const Web3 = require('web3') const Web3 = require('web3')
const { BN, privateToAddress, stripHexPrefix, hashPersonalMessage } = require('ethereumjs-util') const { BN, privateToAddress, hashPersonalMessage } = require('ethereumjs-util')
const RemixSimulator = require('@remix-project/remix-simulator') const RemixSimulator = require('@remix-project/remix-simulator')
class VMProvider { class VMProvider {
@ -39,7 +39,6 @@ class VMProvider {
} }
getBalanceInEther (address, cb) { getBalanceInEther (address, cb) {
address = stripHexPrefix(address)
this.web3.eth.getBalance(address, (err, res) => { this.web3.eth.getBalance(address, (err, res) => {
if (err) { if (err) {
return cb(err) return cb(err)

@ -21,9 +21,9 @@
"dependencies": { "dependencies": {
"@remix-project/remix-astwalker": "^0.0.26", "@remix-project/remix-astwalker": "^0.0.26",
"@remix-project/remix-lib": "^0.4.34", "@remix-project/remix-lib": "^0.4.34",
"ethereumjs-block": "^2.2.2", "@ethereumjs/vm": "^5.3.2",
"ethereumjs-tx": "^2.1.2", "@ethereumjs/block": "^3.2.1",
"ethereumjs-vm": "4.1.3" "@ethereumjs/tx": "^3.1.3"
}, },
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"

@ -36,9 +36,9 @@
"dependencies": { "dependencies": {
"@remix-project/remix-lib": "^0.4.34", "@remix-project/remix-lib": "^0.4.34",
"@types/tape": "^4.2.33", "@types/tape": "^4.2.33",
"ethereumjs-block": "^2.2.2", "@ethereumjs/vm": "^5.3.2",
"ethereumjs-tx": "^2.1.2", "@ethereumjs/block": "^3.2.1",
"ethereumjs-vm": "4.1.3", "@ethereumjs/tx": "^3.1.3",
"nyc": "^13.3.0", "nyc": "^13.3.0",
"tape": "^4.10.1", "tape": "^4.10.1",
"ts-node": "^8.0.3", "ts-node": "^8.0.3",

@ -21,10 +21,10 @@
"@remix-project/remix-astwalker": "^0.0.26", "@remix-project/remix-astwalker": "^0.0.26",
"@remix-project/remix-lib": "^0.4.34", "@remix-project/remix-lib": "^0.4.34",
"commander": "^2.19.0", "commander": "^2.19.0",
"ethereumjs-block": "^2.2.2", "@ethereumjs/vm": "^5.3.2",
"ethereumjs-tx": "^2.1.2", "@ethereumjs/block": "^3.2.1",
"ethereumjs-util": "^6.2.0", "@ethereumjs/tx": "^3.1.3",
"ethereumjs-vm": "4.1.3", "ethereumjs-util": "^7.0.10",
"web3": "^1.2.4" "web3": "^1.2.4"
}, },
"devDependencies": { "devDependencies": {

@ -2,6 +2,7 @@
import { parseCode } from './codeUtils' import { parseCode } from './codeUtils'
import { util } from '@remix-project/remix-lib' import { util } from '@remix-project/remix-lib'
import { bufferToHex } from 'ethereumjs-util'
function createExpressions (instructions) { function createExpressions (instructions) {
const expressions = [] const expressions = []
@ -36,7 +37,7 @@ function createExpressions (instructions) {
function toString (expr) { function toString (expr) {
if (expr.name.slice(0, 4) === 'PUSH') { if (expr.name.slice(0, 4) === 'PUSH') {
return util.hexConvert(expr.pushData) return bufferToHex(expr.pushData)
} else if (expr.name === 'JUMPDEST') { } else if (expr.name === 'JUMPDEST') {
return expr.label + ':' return expr.label + ':'
} else if (expr.args) { } else if (expr.args) {

@ -2,7 +2,6 @@
import { RefType } from './RefType' import { RefType } from './RefType'
import { normalizeHex } from './util' import { normalizeHex } from './util'
import { toBuffer, setLengthLeft, keccak, BN, bufferToHex } from 'ethereumjs-util' import { toBuffer, setLengthLeft, keccak, BN, bufferToHex } from 'ethereumjs-util'
import { intToBuffer } from 'ethjs-util'
export class Mapping extends RefType { export class Mapping extends RefType {
keyType keyType
@ -66,11 +65,10 @@ function getMappingLocation (key, position) {
// key should be a hex string, and position an int // key should be a hex string, and position an int
const mappingK = toBuffer('0x' + key) const mappingK = toBuffer('0x' + key)
let mappingP = intToBuffer(position) let mappingP = toBuffer(position)
mappingP = setLengthLeft(mappingP, 32) mappingP = setLengthLeft(mappingP, 32)
const mappingKeyBuf = concatTypedArrays(mappingK, mappingP) const mappingKeyBuf = concatTypedArrays(mappingK, mappingP)
const mappingKeyPreimage: string = '0x' + mappingKeyBuf.toString('hex') const mappingStorageLocation: Buffer = keccak(mappingKeyBuf)
const mappingStorageLocation: Buffer = keccak(mappingKeyPreimage)
const mappingStorageLocationinBn: BN = new BN(mappingStorageLocation, 16) const mappingStorageLocationinBn: BN = new BN(mappingStorageLocation, 16)
return mappingStorageLocationinBn return mappingStorageLocationinBn
} }

@ -1,5 +1,5 @@
'use strict' 'use strict'
import { BN, bufferToHex, unpad } from 'ethereumjs-util' import { BN, bufferToHex, unpadHexString } from 'ethereumjs-util'
export function decodeIntFromHex (value, byteLength, signed) { export function decodeIntFromHex (value, byteLength, signed) {
let bigNumber = new BN(value, 16) let bigNumber = new BN(value, 16)
@ -57,7 +57,7 @@ export function toBN (value) {
if (value instanceof BN) { if (value instanceof BN) {
return value return value
} else if (value.match && value.match(/^(0x)?([a-f0-9]*)$/)) { } else if (value.match && value.match(/^(0x)?([a-f0-9]*)$/)) {
value = unpad(value.replace(/^(0x)/, '')) value = unpadHexString(value)
value = new BN(value === '' ? '0' : value, 16) value = new BN(value === '' ? '0' : value, 16)
} else if (!isNaN(value)) { } else if (!isNaN(value)) {
value = new BN(value) value = new BN(value)

@ -104,7 +104,7 @@ export class TraceCache {
address: address, address: address,
key: key, key: key,
value: value, value: value,
hashedKey: sha3_256(key) hashedKey: key && sha3_256(key)
} }
this.storageChanges.push(index) this.storageChanges.push(index)
} }

@ -148,16 +148,17 @@ contract Ballot {
winnerName_ = proposals[winningProposal()].name; winnerName_ = proposals[winningProposal()].name;
} }
} }
` `;
var privateKey = Buffer.from('dae9801649ba2d95a21e688b56f77905e5667c44ce868ec83f82e838712a2c7a', 'hex') (async () => {
var vm = vmCall.initVM(privateKey) var privateKey = Buffer.from('dae9801649ba2d95a21e688b56f77905e5667c44ce868ec83f82e838712a2c7a', 'hex')
var output = compiler.compile(compilerInput(ballot)) var vm = await vmCall.initVM(privateKey)
output = JSON.parse(output) var output = compiler.compile(compilerInput(ballot))
var web3VM = new remixLib.vm.Web3VMProvider() output = JSON.parse(output)
web3VM.setVM(vm) var web3VM = new remixLib.vm.Web3VMProvider()
const param = '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000148656c6c6f20576f726c64210000000000000000000000000000000000000000' web3VM.setVM(vm)
vmCall.sendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, output.contracts['test.sol']['Ballot'].evm.bytecode.object + param, (error, txHash) => { const param = '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000148656c6c6f20576f726c64210000000000000000000000000000000000000000'
vmCall.sendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, output.contracts['test.sol']['Ballot'].evm.bytecode.object + param, (error, txHash) => {
console.log(error, txHash) console.log(error, txHash)
if (error) { if (error) {
throw error throw error
@ -189,7 +190,8 @@ vmCall.sendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, output.contracts[
} }
}) })
} }
}) })
})()
function testDebugging (debugManager) { function testDebugging (debugManager) {
// stack // stack

@ -12,9 +12,9 @@ var structArrayLocalTest = require('./localsTests/structArray')
var compilerInput = require('../helpers/compilerHelper').compilerInput var compilerInput = require('../helpers/compilerHelper').compilerInput
tape('solidity', function (t) { tape('solidity', function (t) {
t.test('local decoder', function (st) { t.test('local decoder', async function (st) {
var privateKey = Buffer.from('dae9801649ba2d95a21e688b56f77905e5667c44ce868ec83f82e838712a2c7a', 'hex') var privateKey = Buffer.from('dae9801649ba2d95a21e688b56f77905e5667c44ce868ec83f82e838712a2c7a', 'hex')
var vm = vmCall.initVM(st, privateKey) var vm = await vmCall.initVM(st, privateKey)
test(st, vm, privateKey) test(st, vm, privateKey)
}) })
}) })

@ -6,10 +6,10 @@ import { sendTx, initVM } from '../vmCall'
import { StorageResolver } from '../../../src/storage/storageResolver' import { StorageResolver } from '../../../src/storage/storageResolver'
import { StorageViewer } from '../../../src/storage/storageViewer' import { StorageViewer } from '../../../src/storage/storageViewer'
module.exports = function testMappingStorage (st, cb) { module.exports = async function testMappingStorage (st, cb) {
var mappingStorage = require('../contracts/mappingStorage') var mappingStorage = require('../contracts/mappingStorage')
var privateKey = Buffer.from('dae9801649ba2d95a21e688b56f77905e5667c44ce868ec83f82e838712a2c7a', 'hex') var privateKey = Buffer.from('dae9801649ba2d95a21e688b56f77905e5667c44ce868ec83f82e838712a2c7a', 'hex')
var vm = initVM(st, privateKey) var vm = await initVM(st, privateKey)
var output = compile(compilerInput(mappingStorage.contract)) var output = compile(compilerInput(mappingStorage.contract))
output = JSON.parse(output) output = JSON.parse(output)
sendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, output.contracts['test.sol']['SimpleMappingState'].evm.bytecode.object, function (error, txHash) { sendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, output.contracts['test.sol']['SimpleMappingState'].evm.bytecode.object, function (error, txHash) {

@ -1,10 +1,10 @@
'use strict' 'use strict'
var utileth = require('ethereumjs-util') import { Transaction as Tx } from '@ethereumjs/tx'
var Tx = require('ethereumjs-tx').Transaction import { Block } from '@ethereumjs/block'
var Block = require('ethereumjs-block') import { BN, bufferToHex, Address } from 'ethereumjs-util'
var BN = require('ethereumjs-util').BN import { vm as remixlibVM } from '@remix-project/remix-lib'
var remixLib = require('@remix-project/remix-lib') import VM from '@ethereumjs/vm'
var EthJSVM = require('ethereumjs-vm').default import Common from '@ethereumjs/common'
export function sendTx (vm, from, to, value, data, cb) { export function sendTx (vm, from, to, value, data, cb) {
var tx = new Tx({ var tx = new Tx({
@ -15,19 +15,19 @@ export function sendTx (vm, from, to, value, data, cb) {
value: new BN(value, 10), value: new BN(value, 10),
data: Buffer.from(data, 'hex') data: Buffer.from(data, 'hex')
}) })
tx.sign(from.privateKey) tx = tx.sign(from.privateKey)
var block = new Block({
var block = Block.fromBlockData({
header: { header: {
timestamp: new Date().getTime() / 1000 | 0, timestamp: new Date().getTime() / 1000 | 0,
number: 0 number: 0
}, }
transactions: [], }) // still using default common
uncleHeaders: []
})
try { try {
vm.runTx({block: block, tx: tx, skipBalance: true, skipNonce: true}).then(function (result) { vm.runTx({block: block, tx: tx, skipBalance: true, skipNonce: true}).then(function (result) {
setTimeout(() => { setTimeout(() => {
cb(null, utileth.bufferToHex(tx.hash())) cb(null, bufferToHex(tx.hash()))
}, 500) }, 500)
}).catch((error) => { }).catch((error) => {
console.error(error) console.error(error)
@ -38,35 +38,31 @@ export function sendTx (vm, from, to, value, data, cb) {
} }
} }
function createVm (hardfork) { async function createVm (hardfork) {
// const stateManager = new StateManagerCommonStorageDump({}) const common = new Common({ chain: 'mainnet', hardfork })
// stateManager.checkpoint(() => {}) const vm = new VM({ common })
const vm = new EthJSVM({ await vm.init()
activatePrecompiles: true,
hardfork
})
vm.blockchain.validate = false
return { vm, stateManager: vm.stateManager } return { vm, stateManager: vm.stateManager }
} }
/* /*
Init VM / Send Transaction Init VM / Send Transaction
*/ */
export function initVM (st, privateKey) { export async function initVM (st, privateKey) {
var VM = createVm('muirGlacier') var VM = await createVm('berlin')
const vm = VM.vm const vm = VM.vm
var address = utileth.privateToAddress(privateKey) var address = Address.fromPrivateKey(privateKey)
vm.stateManager.getAccount(address, (error, account) => { try {
if (error) return console.log(error) let account = await vm.stateManager.getAccount(address)
account.balance = '0xf00000000000000001' account.balance = new BN('f00000000000000001', 16)
vm.stateManager.putAccount(address, account, function cb (error) { await vm.stateManager.putAccount(address, account)
if (error) console.log(error) } catch (error) {
}) console.log(error)
}) }
var web3Provider = new remixLib.vm.Web3VMProvider() var web3Provider = new remixlibVM.Web3VMProvider()
web3Provider.setVM(vm) web3Provider.setVM(vm)
vm.web3 = web3Provider vm.web3 = web3Provider
return vm return vm

@ -1,7 +1,8 @@
'use strict' 'use strict'
import { Block } from '@ethereumjs/block'
import VM from '@ethereumjs/vm'
var utileth = require('ethereumjs-util') var utileth = require('ethereumjs-util')
var Tx = require('ethereumjs-tx').Transaction var Tx = require('@ethereumjs/tx').Transaction
var Block = require('ethereumjs-block')
var BN = require('ethereumjs-util').BN var BN = require('ethereumjs-util').BN
var remixLib = require('@remix-project/remix-lib') var remixLib = require('@remix-project/remix-lib')
@ -14,15 +15,14 @@ function sendTx (vm, from, to, value, data, cb) {
value: new BN(value, 10), value: new BN(value, 10),
data: Buffer.from(data, 'hex') data: Buffer.from(data, 'hex')
}) })
tx.sign(from.privateKey) tx = tx.sign(from.privateKey)
var block = new Block({
var block = Block.fromBlockData({
header: { header: {
timestamp: new Date().getTime() / 1000 | 0, timestamp: new Date().getTime() / 1000 | 0,
number: 0 number: 0
}, }
transactions: [], }) // still using default common
uncleHeaders: []
})
vm.runTx({block: block, tx: tx, skipBalance: true, skipNonce: true}).then(function (result) { vm.runTx({block: block, tx: tx, skipBalance: true, skipNonce: true}).then(function (result) {
setTimeout(() => { setTimeout(() => {
cb(null, utileth.bufferToHex(tx.hash())) cb(null, utileth.bufferToHex(tx.hash()))
@ -36,21 +36,20 @@ function sendTx (vm, from, to, value, data, cb) {
/* /*
Init VM / Send Transaction Init VM / Send Transaction
*/ */
function initVM (privateKey) { async function initVM (privateKey) {
var VM = require('ethereumjs-vm').default var address = utileth.Address.fromPrivateKey(privateKey)
var address = utileth.privateToAddress(privateKey)
var vm = new VM({ var vm = new VM({
enableHomestead: true,
activatePrecompiles: true activatePrecompiles: true
}) })
await vm.init()
vm.stateManager.getAccount(address, (error, account) => { try {
if (error) return console.log(error) let account = await vm.stateManager.getAccount(address)
account.balance = '0xf00000000000000001' account.balance = new BN('f00000000000000001', 16)
vm.stateManager.putAccount(address, account, function cb (error) { await vm.stateManager.putAccount(address, account)
if (error) console.log(error) } catch (error) {
}) console.log(error)
}) }
var web3Provider = new remixLib.vm.Web3VMProvider() var web3Provider = new remixLib.vm.Web3VMProvider()
web3Provider.setVM(vm) web3Provider.setVM(vm)

@ -15,10 +15,10 @@
"main": "src/index.js", "main": "src/index.js",
"dependencies": { "dependencies": {
"async": "^2.1.2", "async": "^2.1.2",
"ethereumjs-block": "^2.2.2", "@ethereumjs/block": "^3.2.1",
"ethereumjs-tx": "^2.1.2", "@ethereumjs/tx": "^3.1.3",
"ethereumjs-util": "^6.2.0", "@ethereumjs/vm": "^5.3.2",
"ethereumjs-vm": "4.1.3", "ethereumjs-util": "^7.0.10",
"ethers": "^4.0.40", "ethers": "^4.0.40",
"events": "^3.0.0", "events": "^3.0.0",
"solc": "^0.7.4", "solc": "^0.7.4",

@ -5,8 +5,10 @@ import { EventManager } from '../eventManager'
import { rlp, keccak, bufferToHex } from 'ethereumjs-util' import { rlp, keccak, bufferToHex } from 'ethereumjs-util'
import { Web3VmProvider } from '../web3Provider/web3VmProvider' import { Web3VmProvider } from '../web3Provider/web3VmProvider'
import { LogsManager } from './logsManager' import { LogsManager } from './logsManager'
const EthJSVM = require('ethereumjs-vm').default import VM from '@ethereumjs/vm'
const StateManager = require('ethereumjs-vm/dist/state/stateManager').default import Common from '@ethereumjs/common'
import StateManager from '@ethereumjs/vm/dist/state/stateManager'
import { StorageDump } from '@ethereumjs/vm/dist/state/interface'
declare let ethereum: any declare let ethereum: any
let web3 let web3
@ -23,21 +25,30 @@ if (typeof window !== 'undefined' && typeof window['ethereum'] !== 'undefined')
*/ */
class StateManagerCommonStorageDump extends StateManager { class StateManagerCommonStorageDump extends StateManager {
constructor (arg) { /*
super(arg) * dictionary containing keccak(b) as key and b as value. used to get the initial value from its hash
*/
keyHashes: { [key: string]: string }
constructor () {
super()
this.keyHashes = {} this.keyHashes = {}
} }
putContractStorage (address, key, value, cb) { putContractStorage (address, key, value) {
this.keyHashes[keccak(key).toString('hex')] = bufferToHex(key) this.keyHashes[keccak(key).toString('hex')] = bufferToHex(key)
super.putContractStorage(address, key, value, cb) return super.putContractStorage(address, key, value)
} }
dumpStorage (address, cb) { async dumpStorage (address) {
this._getStorageTrie(address, (err, trie) => { let trie
if (err) { try {
return cb(err) trie = await this._getStorageTrie(address)
} catch (e) {
console.log(e)
throw e
} }
return new Promise<StorageDump>((resolve, reject) => {
try {
const storage = {} const storage = {}
const stream = trie.createReadStream() const stream = trie.createReadStream()
stream.on('data', (val) => { stream.on('data', (val) => {
@ -48,27 +59,39 @@ class StateManagerCommonStorageDump extends StateManager {
} }
}) })
stream.on('end', function () { stream.on('end', function () {
cb(storage) resolve(storage)
}) })
} catch (e) {
reject(e)
}
}) })
} }
getStateRoot (cb) { async getStateRoot (force: boolean = false): Promise<Buffer> {
const checkpoint = this._checkpointCount await this._cache.flush()
this._checkpointCount = 0
super.getStateRoot((err, stateRoot) => { const stateRoot = this._trie.root
this._checkpointCount = checkpoint return stateRoot
cb(err, stateRoot)
})
} }
setStateRoot (stateRoot, cb) { async setStateRoot (stateRoot: Buffer): Promise<void> {
const checkpoint = this._checkpointCount await this._cache.flush()
this._checkpointCount = 0
super.setStateRoot(stateRoot, (err) => { if (stateRoot === this._trie.EMPTY_TRIE_ROOT) {
this._checkpointCount = checkpoint this._trie.root = stateRoot
cb(err) this._cache.clear()
}) this._storageTries = {}
return
}
const hasRoot = await this._trie.checkRoot(stateRoot)
if (!hasRoot) {
throw new Error('State trie does not contain state root')
}
this._trie.root = stateRoot
this._cache.clear()
this._storageTries = {}
} }
} }
@ -96,7 +119,7 @@ export class ExecutionContext {
this.executionContext = null this.executionContext = null
this.blockGasLimitDefault = 4300000 this.blockGasLimitDefault = 4300000
this.blockGasLimit = this.blockGasLimitDefault this.blockGasLimit = this.blockGasLimitDefault
this.currentFork = 'muirGlacier' this.currentFork = 'berlin'
this.vms = { this.vms = {
/* /*
byzantium: createVm('byzantium'), byzantium: createVm('byzantium'),
@ -104,7 +127,7 @@ export class ExecutionContext {
petersburg: createVm('petersburg'), petersburg: createVm('petersburg'),
istanbul: createVm('istanbul'), istanbul: createVm('istanbul'),
*/ */
muirGlacier: this.createVm('muirGlacier') berlin: this.createVm('berlin')
} }
this.mainNetGenesisHash = '0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3' this.mainNetGenesisHash = '0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3'
this.customNetWorks = {} this.customNetWorks = {}
@ -123,18 +146,17 @@ export class ExecutionContext {
} }
createVm (hardfork) { createVm (hardfork) {
const stateManager = new StateManagerCommonStorageDump({}) const stateManager = new StateManagerCommonStorageDump()
stateManager.checkpoint(() => {}) const common = new Common({ chain: 'mainnet', hardfork })
const vm = new EthJSVM({ const vm = new VM({
common,
activatePrecompiles: true, activatePrecompiles: true,
blockchain: stateManager.blockchain, stateManager: stateManager
stateManager: stateManager,
hardfork: hardfork
}) })
vm.blockchain.validate = false
const web3vm = new Web3VmProvider() const web3vm = new Web3VmProvider()
web3vm.setVM(vm) web3vm.setVM(vm)
return { vm, web3vm, stateManager } return { vm, web3vm, stateManager, common }
} }
askPermission () { askPermission () {
@ -210,6 +232,10 @@ export class ExecutionContext {
return this.vms[this.currentFork].vm return this.vms[this.currentFork].vm
} }
vmObject () {
return this.vms[this.currentFork]
}
setContext (context, endPointUrl, confirmCb, infoCb) { setContext (context, endPointUrl, confirmCb, infoCb) {
this.executionContext = context this.executionContext = context
this.executionContextChange(context, endPointUrl, confirmCb, infoCb, null) this.executionContextChange(context, endPointUrl, confirmCb, infoCb, null)
@ -221,9 +247,6 @@ export class ExecutionContext {
if (!infoCb) infoCb = () => {} if (!infoCb) infoCb = () => {}
if (context === 'vm') { if (context === 'vm') {
this.executionContext = context this.executionContext = context
this.vms[this.currentFork].stateManager.revert(() => {
this.vms[this.currentFork].stateManager.checkpoint(() => {})
})
this.event.trigger('contextChanged', ['vm']) this.event.trigger('contextChanged', ['vm'])
return cb() return cb()
} }

@ -309,7 +309,7 @@ export function deployLibrary (libraryName, libraryShortName, library, contracts
}, callbackStep, callbackDeployLibrary) }, callbackStep, callbackDeployLibrary)
} else { } else {
callbackStep(`creation of library ${libraryName} pending...`) callbackStep(`creation of library ${libraryName} pending...`)
const data = { dataHex: bytecode, funAbi: { type: 'constructor' }, funArgs: [], contractBytecode: bytecode, contractName: libraryShortName } const data = { dataHex: bytecode, funAbi: { type: 'constructor' }, funArgs: [], contractBytecode: bytecode, contractName: libraryShortName, contractABI: library.abi }
callbackDeployLibrary({ data: data, useCall: false }, (err, txResult) => { callbackDeployLibrary({ data: data, useCall: false }, (err, txResult) => {
if (err) { if (err) {
return callback(err) return callback(err)

@ -1,7 +1,7 @@
'use strict' 'use strict'
import { Transaction } from 'ethereumjs-tx' import { Transaction } from '@ethereumjs/tx'
import Block from 'ethereumjs-block' import { Block } from '@ethereumjs/block'
import { BN, bufferToHex } from 'ethereumjs-util' import { BN, bufferToHex, Address } from 'ethereumjs-util'
import { ExecutionContext } from './execution-context' import { ExecutionContext } from './execution-context'
import { EventManager } from '../eventManager' import { EventManager } from '../eventManager'
@ -15,11 +15,13 @@ export class TxRunner {
vmaccounts vmaccounts
queusTxs queusTxs
blocks blocks
commonContext
constructor (vmaccounts, api, executionContext) { constructor (vmaccounts, api, executionContext) {
this.event = new EventManager() this.event = new EventManager()
// has a default for now for backwards compatability // has a default for now for backwards compatability
this.executionContext = executionContext || new ExecutionContext() this.executionContext = executionContext || new ExecutionContext()
this.commonContext = this.executionContext.vmObject().common
this._api = api this._api = api
this.blockNumber = 0 this.blockNumber = 0
this.runAsync = true this.runAsync = true
@ -109,48 +111,51 @@ export class TxRunner {
return callback('Invalid account selected') return callback('Invalid account selected')
} }
this.executionContext.vm().stateManager.getAccount(Buffer.from(from.replace('0x', ''), 'hex'), (err, res) => { if (Number.isInteger(gasLimit)) {
if (err) { gasLimit = '0x' + gasLimit.toString(16)
callback('Account not found') }
} else {
this.executionContext.vm().stateManager.getAccount(Address.fromString(from)).then((res) => {
// See https://github.com/ethereumjs/ethereumjs-tx/blob/master/docs/classes/transaction.md#constructor // See https://github.com/ethereumjs/ethereumjs-tx/blob/master/docs/classes/transaction.md#constructor
// for initialization fields and their types // for initialization fields and their types
value = value ? parseInt(value) : 0 value = value ? parseInt(value) : 0
const tx = new Transaction({ const tx = Transaction.fromTxData({
nonce: new BN(res.nonce), nonce: new BN(res.nonce),
gasPrice: '0x1', gasPrice: '0x1',
gasLimit: gasLimit, gasLimit: gasLimit,
to: to, to: to,
value: value, value: value,
data: Buffer.from(data.slice(2), 'hex') data: Buffer.from(data.slice(2), 'hex')
}) }, { common: this.commonContext }).sign(account.privateKey)
tx.sign(account.privateKey)
const coinbases = ['0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a', '0x8945a1288dc78a6d8952a92c77aee6730b414778', '0x94d76e24f818426ae84aa404140e8d5f60e10e7e'] const coinbases = ['0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a', '0x8945a1288dc78a6d8952a92c77aee6730b414778', '0x94d76e24f818426ae84aa404140e8d5f60e10e7e']
const difficulties = [new BN('69762765929000', 10), new BN('70762765929000', 10), new BN('71762765929000', 10)] const difficulties = [new BN('69762765929000', 10), new BN('70762765929000', 10), new BN('71762765929000', 10)]
const block = new Block({
var block = Block.fromBlockData({
header: { header: {
timestamp: timestamp || (new Date().getTime() / 1000 | 0), timestamp: timestamp || (new Date().getTime() / 1000 | 0),
number: self.blockNumber, number: self.blockNumber,
coinbase: coinbases[self.blockNumber % coinbases.length], coinbase: coinbases[self.blockNumber % coinbases.length],
difficulty: difficulties[self.blockNumber % difficulties.length], difficulty: difficulties[self.blockNumber % difficulties.length],
gasLimit: new BN(gasLimit, 10).imuln(2) gasLimit: new BN(gasLimit.replace('0x', ''), 16).imuln(2)
}, },
transactions: [tx], transactions: [tx]
uncleHeaders: [] }, { common: this.commonContext })
})
if (!useCall) { if (!useCall) {
++self.blockNumber ++self.blockNumber
this.runBlockInVm(tx, block, callback) this.runBlockInVm(tx, block, callback)
} else { } else {
this.executionContext.vm().stateManager.checkpoint(() => { this.executionContext.vm().stateManager.checkpoint().then(() => {
this.runBlockInVm(tx, block, (err, result) => { this.runBlockInVm(tx, block, (err, result) => {
this.executionContext.vm().stateManager.revert(() => { this.executionContext.vm().stateManager.revert().then(() => {
callback(err, result) callback(err, result)
}) })
}) })
}) })
} }
} }).catch((e) => {
callback(e)
}) })
} }
@ -167,7 +172,7 @@ export class TxRunner {
result: result, result: result,
transactionHash: bufferToHex(Buffer.from(tx.hash())) transactionHash: bufferToHex(Buffer.from(tx.hash()))
}) })
}).catch(function (err) { }).catch((err) => {
callback(err) callback(err)
}) })
} }

@ -1,6 +1,5 @@
import { waterfall } from 'async' import { waterfall } from 'async'
import { BN, privateToAddress, isValidPrivate, toChecksumAddress } from 'ethereumjs-util' import { BN, privateToAddress, isValidPrivate, toChecksumAddress, Address } from 'ethereumjs-util'
import { stripHexPrefix } from 'ethjs-util'
import { randomBytes } from 'crypto' import { randomBytes } from 'crypto'
import { EventEmitter } from 'events' import { EventEmitter } from 'events'
import { TxRunner } from './execution/txRunner' import { TxRunner } from './execution/txRunner'
@ -124,12 +123,13 @@ export class UniversalDApp {
// FIXME: we don't care about the callback, but we should still make this proper // FIXME: we don't care about the callback, but we should still make this proper
const stateManager = this.executionContext.vm().stateManager const stateManager = this.executionContext.vm().stateManager
stateManager.getAccount(address, (error, account) => { stateManager.getAccount(address).then((account) => {
if (error) return console.log(error) account.balance = new BN(balance.replace('0x', '') || 'f00000000000000001', 16)
account.balance = balance || '0xf00000000000000001' stateManager.putAccount(address, account).catch((error) => {
stateManager.putAccount(address, account, function cb (error) { console.log(error)
if (error) console.log(error)
}) })
}).catch((error) => {
console.log(error)
}) })
this.accounts[toChecksumAddress('0x' + address.toString('hex'))] = { privateKey, nonce: 0 } this.accounts[toChecksumAddress('0x' + address.toString('hex'))] = { privateKey, nonce: 0 }
@ -177,8 +177,6 @@ export class UniversalDApp {
/** Get the balance of an address */ /** Get the balance of an address */
getBalance (address, cb) { getBalance (address, cb) {
address = stripHexPrefix(address)
if (!this.executionContext.isVM()) { if (!this.executionContext.isVM()) {
return this.executionContext.web3().eth.getBalance(address, (err, res) => { return this.executionContext.web3().eth.getBalance(address, (err, res) => {
if (err) { if (err) {
@ -191,11 +189,10 @@ export class UniversalDApp {
return cb('No accounts?') return cb('No accounts?')
} }
this.executionContext.vm().stateManager.getAccount(Buffer.from(address, 'hex'), (err, res) => { this.executionContext.vm().stateManager.getAccount(Address.fromString(address)).then((res) => {
if (err) {
return cb('Account not found')
}
cb(null, new BN(res.balance).toString(10)) cb(null, new BN(res.balance).toString(10))
}).catch(() => {
cb('Account not found')
}) })
} }

@ -1,5 +1,5 @@
'use strict' 'use strict'
import { BN, bufferToHex, keccak, setLengthLeft } from 'ethereumjs-util' import { BN, bufferToHex, keccak, setLengthLeft, toBuffer } from 'ethereumjs-util'
/* /*
contains misc util: @TODO should be splitted contains misc util: @TODO should be splitted
@ -13,18 +13,6 @@ import { BN, bufferToHex, keccak, setLengthLeft } from 'ethereumjs-util'
/* /*
ints: IntArray ints: IntArray
*/ */
export function hexConvert (ints) {
let ret = '0x'
for (let i = 0; i < ints.length; i++) {
const h = ints[i]
if (h) {
ret += (h <= 0xf ? '0' : '') + h.toString(16)
} else {
ret += '00'
}
}
return ret
}
/** /**
* Converts a hex string to an array of integers. * Converts a hex string to an array of integers.
@ -56,22 +44,11 @@ export function hexListFromBNs (bnList) {
return ret return ret
} }
/*
ints: list of IntArrays
*/
export function hexListConvert (intsList) {
const ret = []
for (const k in intsList) {
ret.push(this.hexConvert(intsList[k]))
}
return ret
}
/* /*
ints: ints: IntArray ints: ints: IntArray
*/ */
export function formatMemory (mem) { export function formatMemory (mem) {
const hexMem = this.hexConvert(mem).substr(2) const hexMem = bufferToHex(mem).substr(2)
const ret = [] const ret = []
for (let k = 0; k < hexMem.length; k += 32) { for (let k = 0; k < hexMem.length; k += 32) {
const row = hexMem.substr(k, 32) const row = hexMem.substr(k, 32)
@ -165,11 +142,8 @@ export function buildCallPath (index, rootCall) {
*/ */
// eslint-disable-next-line camelcase // eslint-disable-next-line camelcase
export function sha3_256 (value) { export function sha3_256 (value) {
if (typeof value === 'string' && value.indexOf('0x') !== 0) { value = toBuffer(value)
value = '0x' + value const retInBuffer: Buffer = keccak(setLengthLeft(value, 32))
}
const ret: string = bufferToHex(setLengthLeft(value, 32))
const retInBuffer: Buffer = keccak(ret)
return bufferToHex(retInBuffer) return bufferToHex(retInBuffer)
} }

@ -1,6 +1,6 @@
import { hexConvert, hexListFromBNs, formatMemory } from '../util' import { hexListFromBNs, formatMemory } from '../util'
import { normalizeHexAddress } from '../helpers/uiHelper' import { normalizeHexAddress } from '../helpers/uiHelper'
import { toChecksumAddress, BN, toBuffer } from 'ethereumjs-util' import { toChecksumAddress, BN, bufferToHex, Address } from 'ethereumjs-util'
import Web3 from 'web3' import Web3 from 'web3'
export class Web3VmProvider { export class Web3VmProvider {
@ -74,14 +74,17 @@ export class Web3VmProvider {
setVM (vm) { setVM (vm) {
if (this.vm === vm) return if (this.vm === vm) return
this.vm = vm this.vm = vm
this.vm.on('step', (data) => { this.vm.on('step', async (data, next) => {
this.pushTrace(data) await this.pushTrace(data)
next()
}) })
this.vm.on('afterTx', (data) => { this.vm.on('afterTx', async (data, next) => {
this.txProcessed(data) await this.txProcessed(data)
next()
}) })
this.vm.on('beforeTx', (data) => { this.vm.on('beforeTx', async (data, next) => {
this.txWillProcess(data) await this.txWillProcess(data)
next()
}) })
} }
@ -91,9 +94,9 @@ export class Web3VmProvider {
return ret return ret
} }
txWillProcess (data) { async txWillProcess (data) {
this.incr++ this.incr++
this.processingHash = hexConvert(data.hash()) this.processingHash = bufferToHex(data.hash())
this.vmTraces[this.processingHash] = { this.vmTraces[this.processingHash] = {
gas: '0x0', gas: '0x0',
return: '0x0', return: '0x0',
@ -101,31 +104,32 @@ export class Web3VmProvider {
} }
const tx = {} const tx = {}
tx['hash'] = this.processingHash tx['hash'] = this.processingHash
tx['from'] = toChecksumAddress(hexConvert(data.getSenderAddress())) tx['from'] = toChecksumAddress(data.getSenderAddress().toString())
if (data.to && data.to.length) { if (data.to) {
tx['to'] = toChecksumAddress(hexConvert(data.to)) tx['to'] = toChecksumAddress(data.to.toString())
} }
this.processingAddress = tx['to'] this.processingAddress = tx['to']
tx['data'] = hexConvert(data.data) tx['input'] = bufferToHex(data.data)
tx['input'] = hexConvert(data.input) tx['gas'] = data.gasLimit.toString(10)
tx['gas'] = (new BN(hexConvert(data.gas).replace('0x', ''), 16)).toString(10)
if (data.value) { if (data.value) {
tx['value'] = hexConvert(data.value) tx['value'] = data.value.toString(10)
} }
this.txs[this.processingHash] = tx this.txs[this.processingHash] = tx
this.txsReceipt[this.processingHash] = tx this.txsReceipt[this.processingHash] = tx
this.storageCache[this.processingHash] = {} this.storageCache[this.processingHash] = {}
if (tx['to']) { if (data.to) {
const account = toBuffer(tx['to']) try {
this.vm.stateManager.dumpStorage(account, (storage) => { const storage = await this.vm.stateManager.dumpStorage(data.to)
this.storageCache[this.processingHash][tx['to']] = storage this.storageCache[this.processingHash][tx['to']] = storage
this.lastProcessedStorageTxHash[tx['to']] = this.processingHash this.lastProcessedStorageTxHash[tx['to']] = this.processingHash
}) } catch (e) {
console.log(e)
}
} }
this.processingIndex = 0 this.processingIndex = 0
} }
txProcessed (data) { async txProcessed (data) {
const lastOp = this.vmTraces[this.processingHash].structLogs[this.processingIndex - 1] const lastOp = this.vmTraces[this.processingHash].structLogs[this.processingIndex - 1]
if (lastOp) { if (lastOp) {
lastOp.error = lastOp.op !== 'RETURN' && lastOp.op !== 'STOP' && lastOp.op !== 'thisDESTRUCT' lastOp.error = lastOp.op !== 'RETURN' && lastOp.op !== 'STOP' && lastOp.op !== 'thisDESTRUCT'
@ -156,11 +160,11 @@ export class Web3VmProvider {
this.txsReceipt[this.processingHash].status = `0x${status}` this.txsReceipt[this.processingHash].status = `0x${status}`
if (data.createdAddress) { if (data.createdAddress) {
const address = hexConvert(data.createdAddress) const address = data.createdAddress.toString()
this.vmTraces[this.processingHash].return = toChecksumAddress(address) this.vmTraces[this.processingHash].return = toChecksumAddress(address)
this.txsReceipt[this.processingHash].contractAddress = toChecksumAddress(address) this.txsReceipt[this.processingHash].contractAddress = toChecksumAddress(address)
} else if (data.execResult.returnValue) { } else if (data.execResult.returnValue) {
this.vmTraces[this.processingHash].return = hexConvert(data.execResult.returnValue) this.vmTraces[this.processingHash].return = bufferToHex(data.execResult.returnValue)
} else { } else {
this.vmTraces[this.processingHash].return = '0x' this.vmTraces[this.processingHash].return = '0x'
} }
@ -169,7 +173,7 @@ export class Web3VmProvider {
this.previousDepth = 0 this.previousDepth = 0
} }
pushTrace (data) { async pushTrace (data) {
const depth = data.depth + 1 // geth starts the depth from 1 const depth = data.depth + 1 // geth starts the depth from 1
if (!this.processingHash) { if (!this.processingHash) {
console.log('no tx processing') console.log('no tx processing')
@ -205,11 +209,14 @@ export class Web3VmProvider {
this.processingAddress = normalizeHexAddress(step.stack[step.stack.length - 2]) this.processingAddress = normalizeHexAddress(step.stack[step.stack.length - 2])
this.processingAddress = toChecksumAddress(this.processingAddress) this.processingAddress = toChecksumAddress(this.processingAddress)
if (!this.storageCache[this.processingHash][this.processingAddress]) { if (!this.storageCache[this.processingHash][this.processingAddress]) {
const account = toBuffer(this.processingAddress) const account = Address.fromString(this.processingAddress)
this.vm.stateManager.dumpStorage(account, (storage) => { try {
const storage = await this.vm.stateManager.dumpStorage(account)
this.storageCache[this.processingHash][this.processingAddress] = storage this.storageCache[this.processingHash][this.processingAddress] = storage
this.lastProcessedStorageTxHash[this.processingAddress] = this.processingHash this.lastProcessedStorageTxHash[this.processingAddress] = this.processingHash
}) } catch (e) {
console.log(e)
}
} }
} }
} }
@ -227,9 +234,10 @@ export class Web3VmProvider {
getCode (address, cb) { getCode (address, cb) {
address = toChecksumAddress(address) address = toChecksumAddress(address)
const account = toBuffer(address) this.vm.stateManager.getContractCode(Address.fromString(address)).then((result) => {
this.vm.stateManager.getContractCode(account, (error, result) => { cb(null, bufferToHex(result))
cb(error, hexConvert(result)) }).catch((error) => {
cb(error)
}) })
} }

@ -21,10 +21,10 @@
"color-support": "^1.1.3", "color-support": "^1.1.3",
"commander": "^2.19.0", "commander": "^2.19.0",
"cors": "^2.8.5", "cors": "^2.8.5",
"ethereumjs-block": "^2.2.2", "@ethereumjs/vm": "^5.3.2",
"ethereumjs-tx": "^2.1.2", "@ethereumjs/block": "^3.2.1",
"ethereumjs-util": "^6.2.0", "@ethereumjs/tx": "^3.1.3",
"ethereumjs-vm": "4.1.3", "ethereumjs-util": "^7.0.10",
"express": "^4.16.3", "express": "^4.16.3",
"express-ws": "^4.0.0", "express-ws": "^4.0.0",
"merge": "^1.2.0", "merge": "^1.2.0",

@ -1,20 +1,21 @@
import EthJSBlock from 'ethereumjs-block' import { Block } from '@ethereumjs/block'
import { BN } from 'ethereumjs-util' import { BN } from 'ethereumjs-util'
export function generateBlock (executionContext) { export function generateBlock (executionContext) {
const block: EthJSBlock = new EthJSBlock({ return new Promise((resolve, reject) => {
const block: Block = Block.fromBlockData({
header: { header: {
timestamp: (new Date().getTime() / 1000 | 0), timestamp: (new Date().getTime() / 1000 | 0),
number: 0, number: 0,
coinbase: '0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a', coinbase: '0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a',
difficulty: (new BN('69762765929000', 10)), difficulty: new BN('69762765929000', 10),
gasLimit: new BN('8000000').imuln(1) gasLimit: new BN('8000000').imuln(1)
}, }
transactions: [], }, { common: executionContext.vmObject().common })
uncleHeaders: []
})
executionContext.vm().runBlock({ block: block, generate: true, skipBlockValidation: true, skipBalance: false }).then(() => { executionContext.vm().runBlock({ block: block, generate: true, skipBlockValidation: true, skipBalance: false }).then(() => {
executionContext.addBlock(block) executionContext.addBlock(block)
resolve({})
}).catch((e) => reject(e))
}) })
} }

@ -1,5 +1,4 @@
import { BN, privateToAddress, toChecksumAddress, isValidPrivate } from 'ethereumjs-util' import { BN, privateToAddress, toChecksumAddress, isValidPrivate, Address } from 'ethereumjs-util'
import { stripHexPrefix } from 'ethjs-util'
import Web3 from 'web3' import Web3 from 'web3'
import * as crypto from 'crypto' import * as crypto from 'crypto'
@ -44,19 +43,20 @@ export class Accounts {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
privateKey = Buffer.from(privateKey, 'hex') privateKey = Buffer.from(privateKey, 'hex')
const address: Buffer = privateToAddress(privateKey) const address: Buffer = privateToAddress(privateKey)
const addressStr = toChecksumAddress('0x' + address.toString('hex'))
this.accounts[toChecksumAddress('0x' + address.toString('hex'))] = { privateKey, nonce: 0 } this.accounts[addressStr] = { privateKey, nonce: 0 }
this.accountsKeys[toChecksumAddress('0x' + address.toString('hex'))] = '0x' + privateKey.toString('hex') this.accountsKeys[addressStr] = '0x' + privateKey.toString('hex')
const stateManager = this.executionContext.vm().stateManager const stateManager = this.executionContext.vm().stateManager
stateManager.getAccount(address, (error, account) => { stateManager.getAccount(Address.fromString(addressStr)).then((account) => {
if (error) { account.balance = new BN(balance.replace('0x', '') || 'f00000000000000001', 16)
console.log(error) stateManager.putAccount(Address.fromString(addressStr), account).catch((error) => {
reject(error)
}).then(() => {
resolve({})
})
}).catch((error) => {
reject(error) reject(error)
return
}
account.balance = balance || '0xf00000000000000001'
resolve()
}) })
}) })
} }
@ -83,14 +83,12 @@ export class Accounts {
} }
eth_getBalance (payload, cb) { eth_getBalance (payload, cb) {
let address = payload.params[0] const address = payload.params[0]
address = stripHexPrefix(address)
this.executionContext.vm().stateManager.getAccount(Buffer.from(address, 'hex'), (err, account) => { this.executionContext.vm().stateManager.getAccount(Address.fromString(address)).then((account) => {
if (err) {
return cb(err)
}
cb(null, new BN(account.balance).toString(10)) cb(null, new BN(account.balance).toString(10))
}).catch((error) => {
cb(error)
}) })
} }

@ -31,6 +31,9 @@ export class Blocks {
blockIndex = this.executionContext.latestBlockNumber blockIndex = this.executionContext.latestBlockNumber
} }
if (Number.isInteger(blockIndex)) {
blockIndex = '0x' + blockIndex.toString(16)
}
const block = this.executionContext.blocks[blockIndex] const block = this.executionContext.blocks[blockIndex]
if (!block) { if (!block) {
@ -57,7 +60,6 @@ export class Blocks {
transactions: block.transactions.map((t) => '0x' + t.hash().toString('hex')), transactions: block.transactions.map((t) => '0x' + t.hash().toString('hex')),
uncles: [] uncles: []
} }
cb(null, b) cb(null, b)
} }

@ -1,5 +1,5 @@
import Web3 from 'web3' import Web3 from 'web3'
import { toChecksumAddress, BN } from 'ethereumjs-util' import { toChecksumAddress, BN, Address } from 'ethereumjs-util'
import { processTx } from './txProcess' import { processTx } from './txProcess'
export class Transactions { export class Transactions {
@ -98,12 +98,11 @@ export class Transactions {
eth_getTransactionCount (payload, cb) { eth_getTransactionCount (payload, cb) {
const address = payload.params[0] const address = payload.params[0]
this.executionContext.vm().stateManager.getAccount(address, (err, account) => { this.executionContext.vm().stateManager.getAccount(Address.fromString(address)).then((account) => {
if (err) {
return cb(err)
}
const nonce = new BN(account.nonce).toString(10) const nonce = new BN(account.nonce).toString(10)
cb(null, nonce) cb(null, nonce)
}).catch((error) => {
cb(error)
}) })
} }

@ -39,12 +39,10 @@ export class Provider {
this.methods = merge(this.methods, netMethods()) this.methods = merge(this.methods, netMethods())
this.methods = merge(this.methods, this.Transactions.methods()) this.methods = merge(this.methods, this.Transactions.methods())
this.methods = merge(this.methods, (new Debug(this.executionContext)).methods()) this.methods = merge(this.methods, (new Debug(this.executionContext)).methods())
generateBlock(this.executionContext)
this.init()
} }
async init () { async init () {
await generateBlock(this.executionContext)
await this.Accounts.resetAccounts() await this.Accounts.resetAccounts()
this.Transactions.init(this.Accounts.accounts) this.Transactions.init(this.Accounts.accounts)
} }

@ -5,8 +5,9 @@ const web3 = new Web3()
import * as assert from 'assert' import * as assert from 'assert'
describe('Accounts', () => { describe('Accounts', () => {
before(function () { before(async function () {
const provider = new Provider() const provider = new Provider()
await provider.init()
web3.setProvider(provider) web3.setProvider(provider)
}) })

@ -5,10 +5,11 @@ const web3 = new Web3()
import * as assert from 'assert' import * as assert from 'assert'
describe('blocks', () => { describe('blocks', () => {
before(() => { before(async () => {
const provider = new Provider('vm', { const provider = new Provider('vm', {
coinbase: '0x0000000000000000000000000000000000000001' coinbase: '0x0000000000000000000000000000000000000001'
}) })
await provider.init()
web3.setProvider(provider) web3.setProvider(provider)
}) })
@ -29,7 +30,7 @@ describe('blocks', () => {
parentHash: '0x0000000000000000000000000000000000000000000000000000000000000000', parentHash: '0x0000000000000000000000000000000000000000000000000000000000000000',
sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
size: 163591, size: 163591,
stateRoot: '0x63e1738ea12d4e7d12b71f0f4604706417921eb6a62c407ca5f1d66b9e67f579', stateRoot: '0x0000000000000000000000000000000000000000000000000000000000000000',
timestamp: block.timestamp, timestamp: block.timestamp,
totalDifficulty: '0', totalDifficulty: '0',
transactions: [], transactions: [],

@ -5,8 +5,9 @@ const web3 = new Web3()
import * as assert from 'assert' import * as assert from 'assert'
describe('Misc', () => { describe('Misc', () => {
before(() => { before(async () => {
const provider = new Provider() const provider = new Provider()
await provider.init()
web3.setProvider(provider) web3.setProvider(provider)
}) })

@ -17,9 +17,9 @@
"dependencies": { "dependencies": {
"@remix-project/remix-lib": "^0.4.34", "@remix-project/remix-lib": "^0.4.34",
"eslint-scope": "^5.0.0", "eslint-scope": "^5.0.0",
"ethereumjs-block": "^2.2.2", "@ethereumjs/vm": "^5.3.2",
"ethereumjs-tx": "^2.1.2", "@ethereumjs/block": "^3.2.1",
"ethereumjs-vm": "4.1.3", "@ethereumjs/tx": "^3.1.3",
"solc": "^0.7.4", "solc": "^0.7.4",
"webworkify-webpack": "^2.1.5" "webworkify-webpack": "^2.1.5"
}, },

@ -150,7 +150,7 @@ export interface CompilerInputOptions {
language?: Language language?: Language
} }
export type EVMVersion = 'homestead' | 'tangerineWhistle' | 'spuriousDragon' | 'byzantium' | 'constantinople' | 'petersburg' | 'istanbul' | 'muirGlacier' | null export type EVMVersion = 'homestead' | 'tangerineWhistle' | 'spuriousDragon' | 'byzantium' | 'constantinople' | 'petersburg' | 'istanbul' | 'muirGlacier' | 'berlin' | null
export type Language = 'Solidity' | 'Yul' export type Language = 'Solidity' | 'Yul'

@ -45,9 +45,9 @@
"color-support": "^1.1.3", "color-support": "^1.1.3",
"colors": "^1.1.2", "colors": "^1.1.2",
"commander": "^2.13.0", "commander": "^2.13.0",
"ethereumjs-block": "^2.2.2", "@ethereumjs/vm": "^5.3.2",
"ethereumjs-tx": "^2.1.2", "@ethereumjs/block": "^3.2.1",
"ethereumjs-vm": "4.1.3", "@ethereumjs/tx": "^3.1.3",
"express-ws": "^4.0.0", "express-ws": "^4.0.0",
"merge": "^1.2.0", "merge": "^1.2.0",
"signale": "^1.4.0", "signale": "^1.4.0",

1510
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -130,6 +130,10 @@
}, },
"dependencies": { "dependencies": {
"@erebos/bzz-node": "^0.13.0", "@erebos/bzz-node": "^0.13.0",
"@ethereumjs/block": "^3.2.1",
"@ethereumjs/common": "^2.2.0",
"@ethereumjs/tx": "^3.1.3",
"@ethereumjs/vm": "^5.3.2",
"@remixproject/engine": "^0.3.11", "@remixproject/engine": "^0.3.11",
"@remixproject/engine-web": "^0.3.11", "@remixproject/engine-web": "^0.3.11",
"@remixproject/plugin": "^0.3.11", "@remixproject/plugin": "^0.3.11",
@ -147,10 +151,7 @@
"commander": "^2.20.3", "commander": "^2.20.3",
"deep-equal": "^1.0.1", "deep-equal": "^1.0.1",
"document-register-element": "1.13.1", "document-register-element": "1.13.1",
"ethereumjs-block": "^2.2.2", "ethereumjs-util": "^7.0.10",
"ethereumjs-tx": "^2.1.2",
"ethereumjs-util": "^6.2.0",
"ethereumjs-vm": "4.1.3",
"ethers": "^5.1.4", "ethers": "^5.1.4",
"express-ws": "^4.0.0", "express-ws": "^4.0.0",
"fs-extra": "^3.0.1", "fs-extra": "^3.0.1",

Loading…
Cancel
Save