From 209718ea00762076ed14338417738d369fa703c5 Mon Sep 17 00:00:00 2001 From: Luis Mastrangelo Date: Sun, 24 Dec 2023 02:32:21 -0300 Subject: [PATCH] Support for fork definitions --- src/step.ts | 69 ++++++++++++++++++++++++++++++++++------ test/evm/special.test.ts | 7 ++-- test/step.test.ts | 26 ++++++++++++++- 3 files changed, 89 insertions(+), 13 deletions(-) diff --git a/src/step.ts b/src/step.ts index 7a9748c5..84a5cf42 100644 --- a/src/step.ts +++ b/src/step.ts @@ -126,15 +126,64 @@ function Step< } /** - * This module is used to `decode` bytecode into `Opcode`. - * - * https://ethereum.github.io/execution-specs/diffs/paris_shanghai.html - * https://eips.ethereum.org/EIPS/eip-3855 + * Latest fork definition. + */ +export const STEP = Shanghai; + +/** + * Defines the `Shanghai` hardfork. + * It includes the `PUSH0` instruction. * - * https://ethereum.github.io/execution-specs/diffs/gray_glacier_paris.html - * https://eips.ethereum.org/EIPS/eip-4399 + * Solidity `0.8.20` uses `push0` for placing `0` on the Stack. + * This decreases the deployment and runtime costs. + * + * @see https://ethereum.github.io/execution-specs/diffs/paris_shanghai.html + * @see https://eips.ethereum.org/EIPS/eip-3855 + * @see https://soliditylang.org/blog/2023/05/10/solidity-0.8.20-release-announcement/ */ -export function STEP( +export function Shanghai( + events: IEvents = {}, + variables: IStore['variables'] = {}, + mappings: IStore['mappings'] = {}, + functionBranches: ISelectorBranches = new Map(), +) { + return Object.assign( + Paris(events, variables, mappings, functionBranches), + Step({ + PUSH0: [0x5f, ({ stack }: Operand) => stack.push(new Val(0n, true))] + }) + ); +} + +/** + * Defines the `Paris` hardfork. + * It includes the `PREVRANDAO` instruction. + * + * Solidity `0.8.18` includes _Support for Paris Hardfork_, + * which introduces the global `block.prevrandao` built-in in Solidity and `prevrandao()` + * instruction in inline assembly for EVM versions >= Paris. + * + * @see https://ethereum.github.io/execution-specs/diffs/gray_glacier_paris.html + * @see https://eips.ethereum.org/EIPS/eip-4399 + * @see https://soliditylang.org/blog/2023/02/01/solidity-0.8.18-release-announcement + */ +export function Paris( + events: IEvents = {}, + variables: IStore['variables'] = {}, + mappings: IStore['mappings'] = {}, + functionBranches: ISelectorBranches = new Map(), +) { + return Object.assign( + London(events, variables, mappings, functionBranches), + Step({ + PREVRANDAO: [0x44, function prevrandao({ stack }: Operand) { + stack.push(Props['block.prevrandao']); + }], + }) + ); +} + +export function London( events: IEvents = {}, variables: IStore['variables'] = {}, mappings: IStore['mappings'] = {}, @@ -156,9 +205,6 @@ export function STEP( LOGS(events), STORAGE({ variables, mappings }), FLOW(functionBranches), - Step({ - PUSH0: [0x5f, ({ stack }) => stack.push(new Val(0n))] - }) ); } @@ -167,6 +213,9 @@ export function STEP( */ export type Mnemonic = { [k in keyof T]: T[k] extends StepFn ? (k & string) : never }[keyof T]; +/** + * This module is used to `decode` bytecode into `Opcode`. + */ class Undef { /** diff --git a/test/evm/special.test.ts b/test/evm/special.test.ts index c8cd08a6..d838502d 100644 --- a/test/evm/special.test.ts +++ b/test/evm/special.test.ts @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { EVM, State, reduce } from 'sevm'; +import { EVM, London, Shanghai, State, reduce } from 'sevm'; import type { Expr, Inst, Log } from 'sevm/ast'; import { Props } from 'sevm/ast'; @@ -23,7 +23,9 @@ describe('evm::special', function () { fallback() external payable { emit Deposit(${prop.symbol}); } }`; - const evm = new EVM(compile(src, '0.8.16', this).bytecode); + const evm = name === 'block.difficulty' + ? new EVM(compile(src, '0.8.16', this).bytecode, London()) + : new EVM(compile(src, '0.8.21', this).bytecode, Shanghai()); let state = new State(); evm.run(0, state); @@ -32,6 +34,7 @@ describe('evm::special', function () { } const stmts = reduce(state.stmts); + console.log(stmts); const stmt = stmts[0]; expect(stmt.name).to.be.equal('Log'); expect((stmt).args![0].eval()).to.be.deep.equal(prop); diff --git a/test/step.test.ts b/test/step.test.ts index a055bed4..e68e1d59 100644 --- a/test/step.test.ts +++ b/test/step.test.ts @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { Opcode, type Operand, sol, Stack, State, STEP } from 'sevm'; +import { Opcode, type Operand, sol, Stack, State, STEP, London, Paris } from 'sevm'; import { Val, type Expr, Local, Locali, type Inst, Invalid, MStore, Jump, Branch, Jumpi, Log, type IEvents, Props } from 'sevm/ast'; import { Add, Create, MLoad, Return, SelfDestruct, Sha3, Stop } from 'sevm/ast'; import { $exprs } from './$exprs'; @@ -491,4 +491,28 @@ describe('::step', function () { }); }); + describe('London -> Paris upgrade', function () { + it('should decode `0x44` -> `DIFFICULTY` with London', function () { + const step = London(); + + const [, , mnemonic] = step[0x44] as [unknown, unknown, 'DIFFICULTY']; + expect(mnemonic).to.be.deep.equal('DIFFICULTY'); + + const stack = new Stack(); + step[mnemonic]({ stack }); + expect(stack.top).to.be.equal(Props['block.difficulty']); + }); + + it('should decode `0x44` -> `PREVRANDAO` with Paris', function () { + const step = Paris(); + + const [, , mnemonic] = step[0x44] as [unknown, unknown, 'PREVRANDAO']; + expect(mnemonic).to.be.deep.equal('PREVRANDAO'); + + const stack = new Stack(); + step[mnemonic]({ stack }); + expect(stack.top).to.be.equal(Props['block.prevrandao']); + }); + + }); });