Skip to content

Commit

Permalink
EVM/VM refactor (#1892)
Browse files Browse the repository at this point in the history
* VM -> EVM/VM Refactor: new EVMOpts EVM options dict, move common and supported HFs to EVM

* VM -> EVM/VM Refactor: standalone DEBUG property in EVM and Interpreter

* VM -> EVM/VM Refactor: standalone EVM stateManager option and property

* VM -> EVM/VM Refactor: moved runCall()/runCode() to EVM, deleted dedicated files, top-level EVM instantiation in VM

* VM -> EVM/VM Refactor: made EVM AsyncEventEmitter, moved beforeMessage, afterMessage, newContract, step events to EVM

* VM -> EVM/VM Refactor: moved allowUnlimitedContractSize option to EVM

* VM -> EVM/VM Refactor: moved opcode and gas handler functionality and options to EVM, removed EVM/Precompiles VM dependency

* Client: fix cliqueActiveSigners method assignments

* VM: refactor TxContext to an interface

* VM: improve Message class types and defaults handling

* VM: refactor runCall and executeMessage into unified runCall

* VM: fix gas refund reset to 0 after tx finishes and fix parenthesis in runBlock receipt ternary

* VM: reimplement transient storage clear method

* VM: use VM async create method instead of constructor

* VM: unify interpreter and evm DEBUG property

Co-authored-by: Holger Drewes <Holger.Drewes@gmail.com>
  • Loading branch information
gabrocheleau and holgerd77 authored May 23, 2022
1 parent 44dac5b commit 66f8779
Show file tree
Hide file tree
Showing 63 changed files with 870 additions and 738 deletions.
2 changes: 1 addition & 1 deletion packages/client/lib/rpc/modules/eth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ export class Eth {
value: toType(value, TypeOutput.BigInt),
data: data ? toBuffer(data) : undefined,
}
const { execResult } = await vm.runCall(runCallOpts)
const { execResult } = await vm.evm.runCall(runCallOpts)
return bufferToHex(execResult.returnValue)
} catch (error: any) {
throw {
Expand Down
8 changes: 5 additions & 3 deletions packages/client/test/integration/merge.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import tape from 'tape'
import Blockchain from '@ethereumjs/blockchain'
import Blockchain, { CliqueConsensus } from '@ethereumjs/blockchain'
import Common, {
Chain as ChainCommon,
ConsensusType,
Expand Down Expand Up @@ -78,7 +78,7 @@ tape('[Integration:Merge]', async (t) => {
validateBlocks: false,
validateConsensus: false,
})
blockchain.cliqueActiveSigners = () => [accounts[0][0]] // stub
;(blockchain.consensus as CliqueConsensus).cliqueActiveSigners = () => [accounts[0][0]] // stub
const serviceConfig = new Config({
common,
servers: [server as any],
Expand All @@ -105,7 +105,9 @@ tape('[Integration:Merge]', async (t) => {
height: 0,
common: commonPoA,
})
remoteService.chain.blockchain.cliqueActiveSigners = () => [accounts[0][0]] // stub
;(remoteService.chain.blockchain.consensus as CliqueConsensus).cliqueActiveSigners = () => [
accounts[0][0],
] // stub
await server.discover('remotePeer1', '127.0.0.2')
const targetTTD = BigInt(5)
remoteService.config.events.on(Event.SYNC_SYNCHRONIZED, async () => {
Expand Down
8 changes: 5 additions & 3 deletions packages/client/test/integration/miner.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import tape from 'tape'
import Blockchain from '@ethereumjs/blockchain'
import Blockchain, { CliqueConsensus } from '@ethereumjs/blockchain'
import Common, {
Chain as ChainCommon,
ConsensusType,
Expand Down Expand Up @@ -51,7 +51,7 @@ tape('[Integration:Miner]', async (t) => {
validateBlocks: false,
validateConsensus: false,
})
blockchain.cliqueActiveSigners = () => [accounts[0][0]] // stub
;(blockchain.consensus as CliqueConsensus).cliqueActiveSigners = () => [accounts[0][0]] // stub
const chain = new Chain({ config, blockchain })
const serviceConfig = new Config({
common,
Expand Down Expand Up @@ -82,7 +82,9 @@ tape('[Integration:Miner]', async (t) => {
height: 0,
common,
})
remoteService.chain.blockchain.cliqueActiveSigners = () => [accounts[0][0]] // stub
;(remoteService.chain.blockchain.consensus as CliqueConsensus).cliqueActiveSigners = () => [
accounts[0][0],
] // stub
;(remoteService as FullEthereumService).execution.run = async () => 1 // stub
await server.discover('remotePeer1', '127.0.0.2')
const targetHeight = BigInt(5)
Expand Down
2 changes: 1 addition & 1 deletion packages/client/test/miner/miner.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ tape('[Miner]', async (t) => {
txPool.add(txA01)

// disable consensus to skip PoA block signer validation
;(vm.blockchain as any)._validateConsensus = false
;(vm.blockchain.consensus as CliqueConsensus).cliqueActiveSigners = () => [A.address] // stub

chain.putBlocks = (blocks: Block[]) => {
t.equal(blocks[0].transactions.length, 1, 'new block should include tx')
Expand Down
11 changes: 6 additions & 5 deletions packages/vm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,16 @@ const PUSH1 = '60'
// Note that numbers added are hex values, so '20' would be '32' as decimal e.g.
const code = [PUSH1, '03', PUSH1, '05', ADD, STOP]

vm.on('step', function (data) {
vm.evm.on('step', function (data) {
// Note that data.stack is not immutable, i.e. it is a reference to the vm's internal stack object
console.log(`Opcode: ${data.opcode.name}\tStack: ${data.stack}`)
})

vm.runCode({
code: Buffer.from(code.join(''), 'hex'),
gasLimit: new BN(0xffff),
})
vm.evm
.runCode({
code: Buffer.from(code.join(''), 'hex'),
gasLimit: new BN(0xffff),
})
.then((results) => {
console.log(`Returned: ${results.returnValue.toString('hex')}`)
console.log(`gasUsed : ${results.gasUsed.toString()}`)
Expand Down
2 changes: 1 addition & 1 deletion packages/vm/examples/run-code-browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const run = async () => {
// Note that numbers added are hex values, so '20' would be '32' as decimal e.g.
const code = [PUSH1, '03', PUSH1, '05', ADD, STOP]

vm.on('step', function (data) {
vm.evm.on('step', function (data) {
console.log(`Opcode: ${data.opcode.name}\tStack: ${data.stack}`)
})

Expand Down
2 changes: 1 addition & 1 deletion packages/vm/examples/run-solidity-contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ async function setGreeting(
async function getGreeting(vm: VM, contractAddress: Address, caller: Address) {
const sigHash = new Interface(['function greet()']).getSighash('greet')

const greetResult = await vm.runCall({
const greetResult = await vm.evm.runCall({
to: contractAddress,
caller: caller,
origin: caller, // The tx.origin is also the caller here
Expand Down
44 changes: 21 additions & 23 deletions packages/vm/src/evm/eei.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export default class EEI {
*/
useGas(amount: bigint, context?: string): void {
this._gasLeft -= amount
if (this._evm._vm.DEBUG) {
if (this._evm.DEBUG) {
debugGas(`${context ? context + ': ' : ''}used ${amount} gas (-> ${this._gasLeft})`)
}
if (this._gasLeft < BigInt(0)) {
Expand All @@ -113,7 +113,7 @@ export default class EEI {
* @param context - Usage context for debugging
*/
refundGas(amount: bigint, context?: string): void {
if (this._evm._vm.DEBUG) {
if (this._evm.DEBUG) {
debugGas(`${context ? context + ': ' : ''}refund ${amount} gas (-> ${this._evm._refund})`)
}
this._evm._refund += amount
Expand All @@ -125,7 +125,7 @@ export default class EEI {
* @param context - Usage context for debugging
*/
subRefund(amount: bigint, context?: string): void {
if (this._evm._vm.DEBUG) {
if (this._evm.DEBUG) {
debugGas(`${context ? context + ': ' : ''}sub gas refund ${amount} (-> ${this._evm._refund})`)
}
this._evm._refund -= amount
Expand All @@ -140,7 +140,7 @@ export default class EEI {
* @param amount - Amount to add
*/
addStipend(amount: bigint): void {
if (this._evm._vm.DEBUG) {
if (this._evm.DEBUG) {
debugGas(`add stipend ${amount} (-> ${this._gasLeft})`)
}
this._gasLeft += amount
Expand Down Expand Up @@ -587,7 +587,7 @@ export default class EEI {
return BigInt(0)
}

const results = await this._evm.executeMessage(msg)
const results = await this._evm.runCall({ message: msg })

if (results.execResult.logs) {
this._result.logs = this._result.logs.concat(results.execResult.logs)
Expand Down Expand Up @@ -618,30 +618,18 @@ export default class EEI {
/**
* Creates a new contract with a given value.
*/
async create(
gasLimit: bigint,
value: bigint,
data: Buffer,
salt: Buffer | null = null
): Promise<bigint> {
async create(gasLimit: bigint, value: bigint, data: Buffer, salt?: Buffer): Promise<bigint> {
const selfdestruct = { ...this._result.selfdestruct }
const msg = new Message({
caller: this._env.address,
gasLimit,
value,
data,
salt,
depth: this._env.depth + 1,
selfdestruct,
})
const caller = this._env.address
const depth = this._env.depth + 1

// empty the return data buffer
this._lastReturned = Buffer.alloc(0)

// Check if account has enough ether and max depth not exceeded
if (
this._env.depth >= Number(this._common.param('vm', 'stackLimit')) ||
(msg.delegatecall !== true && this._env.contract.balance < msg.value)
this._env.contract.balance < value
) {
return BigInt(0)
}
Expand All @@ -655,12 +643,22 @@ export default class EEI {
await this._state.putAccount(this._env.address, this._env.contract)

if (this._common.isActivatedEIP(3860)) {
if (msg.data.length > Number(this._common.param('vm', 'maxInitCodeSize'))) {
if (data.length > Number(this._common.param('vm', 'maxInitCodeSize'))) {
return BigInt(0)
}
}

const results = await this._evm.executeMessage(msg)
const message = new Message({
caller,
gasLimit,
value,
data,
salt,
depth,
selfdestruct,
})

const results = await this._evm.runCall({ message })

if (results.execResult.logs) {
this._result.logs = this._result.logs.concat(results.execResult.logs)
Expand Down
Loading

0 comments on commit 66f8779

Please sign in to comment.