Merge pull request #3598 from ethereum/fix_save_blocks

Fix save blocks ref
pull/3612/head^2
yann300 2 years ago committed by GitHub
commit b5eeaa10f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      apps/remix-ide-e2e/src/commands/verifyCallReturnValue.ts
  2. 59
      apps/remix-ide-e2e/src/tests/blockchain.test.ts
  3. 3
      apps/remix-ide-e2e/src/types/index.d.ts
  4. 2
      apps/remix-ide/src/app/providers/mainnet-vm-fork-provider.tsx
  5. 4
      apps/remix-ide/src/blockchain/blockchain.tsx
  6. 4
      apps/remix-ide/src/blockchain/execution-context.js
  7. 2
      libs/remix-debug/src/code/codeUtils.ts
  8. 2
      libs/remix-debug/src/trace/traceManager.ts
  9. 4
      libs/remix-lib/src/execution/forkAt.ts
  10. 5
      libs/remix-lib/src/execution/txRunner.ts
  11. 37
      libs/remix-lib/src/execution/txRunnerVM.ts
  12. 25
      libs/remix-simulator/src/genesis.ts
  13. 2
      libs/remix-simulator/src/methods/transactions.ts
  14. 2
      libs/remix-simulator/src/provider.ts
  15. 47
      libs/remix-simulator/src/vm-context.ts
  16. 2
      libs/remix-simulator/test/blocks.ts

@ -1,5 +1,6 @@
import { NightwatchBrowser } from 'nightwatch'
import EventEmitter from 'events'
import { callbackCheckVerifyCallReturnValue } from '../types/index'
class VerifyCallReturnValue extends EventEmitter {
command (this: NightwatchBrowser, address: string, checks: string[]): NightwatchBrowser {
@ -13,7 +14,7 @@ class VerifyCallReturnValue extends EventEmitter {
}
}
function verifyCallReturnValue (browser: NightwatchBrowser, address: string, checks: string[], done: VoidFunction) {
function verifyCallReturnValue (browser: NightwatchBrowser, address: string, checks: string[] | callbackCheckVerifyCallReturnValue, done: VoidFunction) {
browser.execute(function (address: string) {
const nodes = document.querySelectorAll('#instance' + address + ' [data-id="udapp_value"]') as NodeListOf<HTMLElement>
const ret = []
@ -23,8 +24,13 @@ function verifyCallReturnValue (browser: NightwatchBrowser, address: string, che
}
return ret
}, [address], function (result) {
for (const k in checks) {
browser.assert.equal(result.value[k].trim(), checks[k].trim())
if (typeof checks === 'function') {
const ret = checks(result.value as string[])
if (!ret.pass) browser.assert.fail(ret.message)
} else {
for (const k in checks) {
browser.assert.equal(result.value[k].trim(), checks[k].trim())
}
}
done()
})

@ -0,0 +1,59 @@
'use strict'
import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
module.exports = {
'@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done)
},
'@sources': function () {
return ''
},
'Execute a call that retrieve previous block hashes #group1': function (browser: NightwatchBrowser) {
const code = `
contract A {
function foo(uint p) public view returns(bytes32) {
return blockhash(p);
}
}`
browser.testContracts('test.sol',{ content: code } , ['A'])
.clickLaunchIcon('udapp')
.selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite
.click('.udapp_contractActionsContainerSingle > button')
.clickInstance(0)
.clickFunction('foo - call', { types: 'uint256 p', values: '0' })
.perform((done) => {
browser.getAddressAtPosition(0, (address) => {
browser
.verifyCallReturnValue(address, (values: string[]) => {
// should be looking like: ['0:bytes32: 0x0391a96b0b74805e5fbb79a18840548c5b6c0f1c5e933fc5e3ee015823856e00']
const value = values[0].replace('0:bytes32: ', '')
let pass = value !== '0x0000000000000000000000000000000000000000000000000000000000000000' && value !== '0x'
return {
pass,
message: pass ? 'pass' : 'a non empty blockhash should be returned'
}
})
.perform(() => done())
})
})
.clickFunction('foo - call', { types: 'uint256 p', values: '1' })
.perform((done) => {
browser.getAddressAtPosition(0, (address) => {
browser
.verifyCallReturnValue(address, (values: string[]) => {
// should be looking like: ['0:bytes32: 0x0391a96b0b74805e5fbb79a18840548c5b6c0f1c5e933fc5e3ee015823856e00']
const value = values[0].replace('0:bytes32: ', '')
let pass = value !== '0x0000000000000000000000000000000000000000000000000000000000000000' && value !== '0x'
return {
pass,
message: pass ? 'pass' : 'a non empty blockhash should be returned'
}
})
.perform(() => done())
})
}).end()
}
}

@ -1,6 +1,7 @@
// Merge custom command types with nightwatch types
/* eslint-disable no-use-before-define */
import { NightwatchBrowser } from 'nightwatch' // eslint-disable-line @typescript-eslint/no-unused-vars
export type callbackCheckVerifyCallReturnValue = (values: string[]) => { message: string, pass: boolean }
declare module 'nightwatch' {
export interface NightwatchCustomCommands {
@ -41,7 +42,7 @@ declare module 'nightwatch' {
testConstantFunction(address: string, fnFullName: string, expectedInput: NightwatchTestConstantFunctionExpectedInput | null, expectedOutput: string): NightwatchBrowser,
getEditorValue(callback: (content: string) => void): NightwatchBrowser,
getInstalledPlugins(cb: (plugins: string[]) => void): NightwatchBrowser,
verifyCallReturnValue(address: string, checks: string[]): NightwatchBrowser,
verifyCallReturnValue(address: string, checks: string[] | callbackCheckVerifyCallReturnValue): NightwatchBrowser,
testEditorValue(testvalue: string): NightwatchBrowser,
removeFile(path: string, workspace: string): NightwatchBrowser,
switchBrowserWindow(url: string, windowName: string, cb: (browser: NightwatchBrowser, window?: NightwatchCallbackResult<Window>) => void): NightwatchBrowser,

@ -14,7 +14,7 @@ export class MainnetForkVMProvider extends BasicVMProvider {
version: packageJson.version
}, blockchain)
this.blockchain = blockchain
this.fork = 'london'
this.fork = 'merge'
this.nodeUrl = 'https://mainnet.infura.io/v3/08b2a484451e4635a28b3d8234f24332'
this.blockNumber = 'latest'
}

@ -82,7 +82,7 @@ export class Blockchain extends Plugin {
return this.getProvider() === 'web3' ? this.config.get('settings/personal-mode') : false
}
}, _ => this.executionContext.web3(), _ => this.executionContext.currentblockGasLimit())
this.txRunner = new TxRunner(web3Runner, { runAsync: true })
this.txRunner = new TxRunner(web3Runner, {})
this.networkcallid = 0
this.networkStatus = { network: { name: ' - ', id: ' - ' } }
@ -598,7 +598,7 @@ export class Blockchain extends Plugin {
}
})
})
this.txRunner = new TxRunner(web3Runner, { runAsync: true })
this.txRunner = new TxRunner(web3Runner, {})
}
/**

@ -24,7 +24,7 @@ export class ExecutionContext {
this.lastBlock = null
this.blockGasLimitDefault = 4300000
this.blockGasLimit = this.blockGasLimitDefault
this.currentFork = 'london'
this.currentFork = 'merge'
this.mainNetGenesisHash = '0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3'
this.customNetWorks = {}
this.blocks = {}
@ -161,7 +161,7 @@ export class ExecutionContext {
try {
this.currentFork = execution.forkAt(await web3.eth.net.getId(), block.number)
} catch (e) {
this.currentFork = 'london'
this.currentFork = 'merge'
console.log(`unable to detect fork, defaulting to ${this.currentFork}..`)
console.error(e)
}

@ -46,7 +46,7 @@ type Opcode = {
* information about the opcode.
*/
export function parseCode (raw) {
const common = new Common({ chain: 'mainnet', hardfork: 'london' })
const common = new Common({ chain: 'mainnet', hardfork: 'merge' })
const opcodes = getOpcodesForHF(common).opcodes
const code = []

@ -40,7 +40,7 @@ export class TraceManager {
const networkId = await this.web3.eth.net.getId()
this.fork = execution.forkAt(networkId, tx.blockNumber)
} catch (e) {
this.fork = 'london'
this.fork = 'merge'
console.log(`unable to detect fork, defaulting to ${this.fork}..`)
console.error(e)
}

@ -58,6 +58,10 @@ const forks = {
{
number: 15050000,
name: 'grayGlacier'
},
{
number: 15537394,
name: 'merge'
}
],
3: [

@ -14,7 +14,6 @@ export type Transaction = {
export class TxRunner {
event
runAsync
pendingTxs
queusTxs
opt
@ -24,8 +23,6 @@ export class TxRunner {
this.internalRunner = internalRunner
this.event = new EventManager()
this.runAsync = this.opt.runAsync || true // We have to run like this cause the VM Event Manager does not support running multiple txs at the same time.
this.pendingTxs = {}
this.queusTxs = []
}
@ -44,7 +41,7 @@ export class TxRunner {
}
function run (self, tx: Transaction, stamp, confirmationCb, gasEstimationForceSend = null, promptCb = null, callback = null) {
if (!self.runAsync && Object.keys(self.pendingTxs).length) {
if (Object.keys(self.pendingTxs).length) {
return self.queusTxs.push({ tx, stamp, callback })
}
self.pendingTxs[stamp] = tx

@ -21,13 +21,13 @@ export type VMExecutionCallBack = (error: string | Error, result?: VMexecutionRe
export class TxRunnerVM {
event
blockNumber
runAsync
pendingTxs
vmaccounts
queusTxs
blocks
logsManager
commonContext
blockParentHash
nextNonceForCall: number
getVMObject: () => any
@ -38,9 +38,6 @@ export class TxRunnerVM {
this.getVMObject = getVMObject
this.commonContext = this.getVMObject().common
this.blockNumber = 0
this.runAsync = true
this.blockNumber = 0 // The VM is running in Homestead mode, which started at this block.
this.runAsync = false // We have to run like this cause the VM Event Manager does not support running multiple txs at the same time.
this.pendingTxs = {}
this.vmaccounts = vmaccounts
this.queusTxs = []
@ -52,6 +49,9 @@ export class TxRunnerVM {
For this to function we also need to skip nonce validation, in the vm: `{ skipNonce: true }`
*/
this.nextNonceForCall = 0
const vm = this.getVMObject().vm
this.blockParentHash = vm.blockchain.genesisBlock.hash()
}
execute (args: InternalTransaction, confirmationCb, gasEstimationForceSend, promptCb, callback: VMExecutionCallBack) {
@ -68,12 +68,11 @@ export class TxRunnerVM {
}
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) {
from = Object.keys(self.vmaccounts)[0]
account = self.vmaccounts[from]
} else account = self.vmaccounts[from]
if (!from && useCall && Object.keys(this.vmaccounts).length) {
from = Object.keys(this.vmaccounts)[0]
account = this.vmaccounts[from]
} else account = this.vmaccounts[from]
if (!account) {
return callback('Invalid account selected')
@ -106,23 +105,29 @@ export class TxRunnerVM {
const coinbases = ['0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a', '0x8945a1288dc78a6d8952a92c77aee6730b414778', '0x94d76e24f818426ae84aa404140e8d5f60e10e7e']
const difficulties = [69762765929000, 70762765929000, 71762765929000]
const difficulty = this.commonContext.consensusType() === ConsensusType.ProofOfStake ? 0 : difficulties[self.blockNumber % difficulties.length]
const difficulty = this.commonContext.consensusType() === ConsensusType.ProofOfStake ? 0 : difficulties[this.blockNumber % difficulties.length]
const blocknumber = this.blockNumber + 1
const block = Block.fromBlockData({
header: {
timestamp: new Date().getTime() / 1000 | 0,
number: self.blockNumber,
coinbase: coinbases[self.blockNumber % coinbases.length],
number: blocknumber,
coinbase: coinbases[blocknumber % coinbases.length],
difficulty,
gasLimit,
baseFeePerGas: EIP1559 ? '0x1' : undefined
baseFeePerGas: EIP1559 ? '0x1' : undefined,
parentHash: this.blockParentHash
},
transactions: [tx]
}, { common: this.commonContext })
}, { common: this.commonContext, hardforkByBlockNumber: false, hardforkByTTD: undefined })
if (!useCall) {
++self.blockNumber
this.runBlockInVm(tx, block, callback)
this.blockNumber = this.blockNumber + 1
this.blockParentHash = block.hash()
this.runBlockInVm(tx, block, (err, result) => {
if (!err) this.getVMObject().vm.blockchain.putBlock(block)
callback(err, result)
})
} else {
this.getVMObject().stateManager.checkpoint().then(() => {
this.runBlockInVm(tx, block, (err, result) => {

@ -1,25 +0,0 @@
import { Block } from '@ethereumjs/block'
import { ConsensusType } from '@ethereumjs/common'
export function generateBlock (vmContext) {
const common = vmContext.vmObject().common
const difficulty = common.consensusType() === ConsensusType.ProofOfStake ? 0 : 69762765929000
return new Promise((resolve, reject) => {
const block: Block = Block.fromBlockData({
header: {
timestamp: (new Date().getTime() / 1000 | 0),
number: 0,
coinbase: '0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a',
difficulty,
gasLimit: 8000000
}
}, { common: vmContext.vmObject().common })
vmContext.vm().runBlock({ block: block, generate: true, skipBlockValidation: true, skipBalance: false }).then(() => {
vmContext.addBlock(block)
resolve({})
}).catch((e) => reject(e))
})
}

@ -56,7 +56,7 @@ export class Transactions {
}
this.txRunnerVMInstance = new TxRunnerVM(accounts, api, _ => this.vmContext.vmObject())
this.txRunnerInstance = new TxRunner(this.txRunnerVMInstance, { runAsync: false })
this.txRunnerInstance = new TxRunner(this.txRunnerVMInstance, {})
this.txRunnerInstance.vmaccounts = accounts
}

@ -9,7 +9,6 @@ import { methods as miscMethods } from './methods/misc'
import { methods as netMethods } from './methods/net'
import { Transactions } from './methods/transactions'
import { Debug } from './methods/debug'
import { generateBlock } from './genesis'
import { VMContext } from './vm-context'
export interface JSONRPCRequestPayload {
@ -59,7 +58,6 @@ export class Provider {
this.initialized = false
this.pendingRequests = []
await this.vmContext.init()
await generateBlock(this.vmContext)
await this.Accounts.resetAccounts()
this.Transactions.init(this.Accounts.accounts)
this.initialized = true

@ -9,7 +9,8 @@ import { execution } from '@remix-project/remix-lib'
const { LogsManager } = execution
import { VmProxy } from './VmProxy'
import { VM } from '@ethereumjs/vm'
import { Common } from '@ethereumjs/common'
import type { BigIntLike } from '@ethereumjs/util'
import { Common, ConsensusType } from '@ethereumjs/common'
import { Trie } from '@ethereumjs/trie'
import { DefaultStateManager, StateManager, EthersStateManager, EthersStateManagerOpts } from '@ethereumjs/statemanager'
import { StorageDump } from '@ethereumjs/statemanager/dist/interface'
@ -130,6 +131,25 @@ export type CurrentVm = {
common: Common
}
export class VMCommon extends Common {
/**
* Override "setHardforkByBlockNumber" to disable updating the original fork state
*
* @param blockNumber
* @param td
* @param timestamp
* @returns The name of the HF set
*/
setHardforkByBlockNumber(
blockNumber: BigIntLike,
td?: BigIntLike,
timestamp?: BigIntLike
): string {
return this.hardfork()
}
}
/*
trigger contextChanged, web3EndpointChanged
*/
@ -151,7 +171,7 @@ export class VMContext {
constructor (fork?: string, nodeUrl?: string, blockNumber?: number | 'latest') {
this.blockGasLimitDefault = 4300000
this.blockGasLimit = this.blockGasLimitDefault
this.currentFork = fork || 'london'
this.currentFork = fork || 'merge'
this.nodeUrl = nodeUrl
this.blockNumber = blockNumber
this.blocks = {}
@ -181,14 +201,28 @@ export class VMContext {
} else
stateManager = new StateManagerCommonStorageDump()
const common = new Common({ chain: 'mainnet', hardfork })
const blockchain = new (Blockchain as any)({ common })
const consensusType = hardfork === 'berlin' || hardfork === 'london' ? ConsensusType.ProofOfWork : ConsensusType.ProofOfStake
const difficulty = consensusType === ConsensusType.ProofOfStake ? 0 : 69762765929000
const common = new VMCommon({ chain: 'mainnet', hardfork })
const genesisBlock: Block = Block.fromBlockData({
header: {
timestamp: (new Date().getTime() / 1000 | 0),
number: 0,
coinbase: '0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a',
difficulty,
gasLimit: 8000000
}
}, { common, hardforkByBlockNumber: false, hardforkByTTD: undefined })
const blockchain = await Blockchain.create({ common, validateBlocks: false, validateConsensus: false, genesisBlock })
const eei = new EEI(stateManager, common, blockchain)
const evm = new EVM({ common, eei, allowUnlimitedContractSize: true })
const vm = await VM.create({
common,
activatePrecompiles: true,
hardforkByBlockNumber: false,
stateManager,
blockchain,
evm
@ -198,6 +232,7 @@ export class VMContext {
// VmProxy is used to track the EVM execution (to listen on opcode execution, in order for instance to generate the VM trace)
const web3vm = new VmProxy(this)
web3vm.setVM(vm)
this.addBlock(genesisBlock, true)
return { vm, web3vm, stateManager, common }
}
@ -217,7 +252,7 @@ export class VMContext {
return this.currentVm
}
addBlock (block: Block) {
addBlock (block: Block, genesis?: boolean) {
let blockNumber = bigIntToHex(block.header.number)
if (blockNumber === '0x') {
blockNumber = '0x0'
@ -227,7 +262,7 @@ export class VMContext {
this.blocks[blockNumber] = block
this.latestBlockNumber = blockNumber
this.logsManager.checkBlock(blockNumber, block, this.web3())
if (!genesis) this.logsManager.checkBlock(blockNumber, block, this.web3())
}
trackTx (txHash, block, tx) {

@ -19,7 +19,7 @@ describe('blocks', () => {
const expectedBlock = {
baseFeePerGas: 1,
difficulty: '69762765929000',
difficulty: 0,
extraData: '0x0',
gasLimit: 8000000,
gasUsed: 0,

Loading…
Cancel
Save