Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Mega EOF #3440

Merged
merged 106 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
4560b59
common: add EOF EIPs
jochem-brouwer May 13, 2024
231ecb3
evm: implement eip3540
jochem-brouwer May 22, 2024
e451935
evm: eof fixes
jochem-brouwer May 22, 2024
78c7c48
evm: add eip3540 tests
jochem-brouwer May 22, 2024
6e950f2
evm/common: add EOF meta eip
jochem-brouwer May 27, 2024
c0bd77e
evm: setup eof in msg/env
jochem-brouwer May 27, 2024
d671026
evm: add placeholders for eof opcodes
jochem-brouwer May 27, 2024
1063856
evm: add explicit eof flag for authcall
jochem-brouwer May 27, 2024
caacdd3
evm: rename eof msg type
jochem-brouwer May 27, 2024
92c952f
evm: setup to run EOF
jochem-brouwer May 27, 2024
b82e424
evm: add eip4200
jochem-brouwer May 28, 2024
ce98aea
evm: refactor eof
jochem-brouwer May 28, 2024
7d9b781
evm: add stack deltas
jochem-brouwer Jan 2, 2023
4326262
evm: add stackDelta
jochem-brouwer May 28, 2024
3db8b1e
evm: make verify use stackDelta
jochem-brouwer May 28, 2024
b4a88e8
evm: add eoftests
jochem-brouwer May 29, 2024
1d5e202
evm: eip4200 validation
jochem-brouwer May 29, 2024
84fd3c2
evm: add general eof container validation tests
jochem-brouwer May 29, 2024
e2f109a
evm: all header validator tests
jochem-brouwer May 29, 2024
f9531eb
evm: eip5450 tests
jochem-brouwer May 29, 2024
ee54398
evm: add reachable code/opcodes verification eof
jochem-brouwer May 30, 2024
10e2a9c
evm: add dataloadn check eof
jochem-brouwer May 30, 2024
3bdc6de
evm: add error [no ci]
jochem-brouwer May 30, 2024
026a123
evm: add various eof stack checks [no ci]
jochem-brouwer May 30, 2024
e31632f
Merge branch 'master' into MEGA-EOF-V2
jochem-brouwer Jun 13, 2024
5ebfce0
evm: implement callf/retf [no ci]
jochem-brouwer Jun 13, 2024
4af54bd
evm: implement dataload*
jochem-brouwer Jun 17, 2024
e1d3c4c
evm: implement swap/dup/exchange
jochem-brouwer Jun 17, 2024
9088baf
Merge branch 'master' into MEGA-EOF-V2
jochem-brouwer Jun 26, 2024
403e70a
evm: add stack.exchange
jochem-brouwer Jun 26, 2024
232eee3
evm: add extcall*opcodes EOF
jochem-brouwer Jun 26, 2024
fda73f0
common: add eof to prague
jochem-brouwer Jul 1, 2024
908c513
Merge branch 'master' into MEGA-EOF-V2
jochem-brouwer Jul 2, 2024
adf91b8
evm: fix dupn
jochem-brouwer Jul 2, 2024
c0c7229
evm: mark non-async opcodes as non async
jochem-brouwer Jul 2, 2024
2e90e01
evm: fix exchange
jochem-brouwer Jul 2, 2024
3ae3ce0
evm: fix swap
jochem-brouwer Jul 2, 2024
dc79614
evm: fix rjumpv
jochem-brouwer Jul 2, 2024
2f879d9
evm: partially fix callf
jochem-brouwer Jul 2, 2024
e4fa4e7
evm: fix eof opcode error handling
jochem-brouwer Jul 2, 2024
3bf2286
evm: add jumpf [no ci]
jochem-brouwer Jul 2, 2024
184d9a6
evm: implement extcall
jochem-brouwer Jul 2, 2024
2822206
evm: add extdelegatecall / extstaticcall
jochem-brouwer Jul 2, 2024
ac0c565
evm: fix datacopy opcode [no ci]
jochem-brouwer Jul 2, 2024
c06333d
evm: add returndataload
jochem-brouwer Jul 2, 2024
308cf39
evm: add dataload gas
jochem-brouwer Jul 2, 2024
82b5cba
evm: fix returndatacopy for eof contracts [no ci]
jochem-brouwer Jul 2, 2024
e57487e
evm: extdelegatecall cannot call legacy contracts [no ci]
jochem-brouwer Jul 2, 2024
c798298
evm: add eof rules for legacy contracts [no ci]
jochem-brouwer Jul 2, 2024
ca8fca6
evm: clear return data buffer on ext*call data exotic cases
jochem-brouwer Jul 2, 2024
429e649
evm: partial eofcreate implementation
jochem-brouwer Jul 2, 2024
34d2a66
evm: add returncontract [no ci]
jochem-brouwer Jul 2, 2024
348c87b
evm: fix eofcreate with no auxdata [no ci]
jochem-brouwer Jul 3, 2024
bca9f80
evm: first attempt to fix auxdata returncontract [no ci]
jochem-brouwer Jul 3, 2024
3db89e6
evm: fix auxdata length write and return value on error
jochem-brouwer Jul 3, 2024
f37a644
evm: add initcontainer mode to eof container
jochem-brouwer Jul 3, 2024
9afc6b5
evm: fix eofcreate gas calculation [no ci]
jochem-brouwer Jul 3, 2024
28feb48
evm: charge correct ext*call gas
jochem-brouwer Jul 3, 2024
4a622e9
evm: add comment
jochem-brouwer Jul 3, 2024
8c46ade
evm: add container mode
jochem-brouwer Jul 3, 2024
3f19694
evm: add support for txn eof creations
jochem-brouwer Jul 3, 2024
bd81fad
evm: fix return contract tests for EOF
jochem-brouwer Jul 3, 2024
51a9ae0
evm: fix stackDelta RETURNCONTRACT for header validation
jochem-brouwer Jul 3, 2024
647dfc2
eof: fix reachable code validation if rjump at end of code
jochem-brouwer Jul 3, 2024
74d24e7
evm: eof container validation add support eofcreate / returncontract
jochem-brouwer Jul 3, 2024
fd5fe7a
evm: correct eofcreate / returncontract to only have 1 byte immediate…
jochem-brouwer Jul 3, 2024
9c0ec01
evm: more header validation
jochem-brouwer Jul 3, 2024
acb2b51
evm: eof verify dupn exchange
jochem-brouwer Jul 3, 2024
26dad2f
evm: add container size max
jochem-brouwer Jul 3, 2024
bc7676a
evm: verify rjumpv into self
jochem-brouwer Jul 3, 2024
436ef52
evm: update max container sections
jochem-brouwer Jul 3, 2024
201d880
evm: fix max header size constant
jochem-brouwer Jul 4, 2024
77cd579
evm: implement EIP 5450 stack validation algorithm
jochem-brouwer Jul 4, 2024
057272c
evm: fix RETURNCONTRACT stack delta
jochem-brouwer Jul 4, 2024
1e97ba1
evm: updat eeof header validation for "initcode" containers
jochem-brouwer Jul 4, 2024
4802aa7
Merge branch 'master' into MEGA-EOF-V2
jochem-brouwer Jul 4, 2024
5d100fe
evm: fix eof dir
jochem-brouwer Jul 4, 2024
d3a8522
evm: delete old eof container tests
jochem-brouwer Jul 4, 2024
56994f5
evm: remove more old tests
jochem-brouwer Jul 4, 2024
8999f8f
evm: remove old eof test
jochem-brouwer Jul 4, 2024
1792a23
evm: remove old eof test
jochem-brouwer Jul 4, 2024
197c349
evm: fix EXCHANGE
jochem-brouwer Jul 4, 2024
fae74dd
evm: ensure eof put right value on stack on ext*call revert
jochem-brouwer Jul 4, 2024
2ebb211
evm: ensure extcall argument order correct
jochem-brouwer Jul 4, 2024
2e92f8e
evm: EXPERIMENTAL - eof initcode container validation on tx init
jochem-brouwer Jul 4, 2024
86d0161
evm: ensure eof header parsing for init txs also fails
jochem-brouwer Jul 5, 2024
042c1e1
evm: container: allow lower data sizes for deployment containers
jochem-brouwer Jul 5, 2024
ae225ff
evm: fix callf/jumpf stack overflow check
jochem-brouwer Jul 5, 2024
eaee14d
evm: implement swapn stack check for eof validation
jochem-brouwer Jul 5, 2024
8e34a0c
Merge branch 'master' into MEGA-EOF-V2
jochem-brouwer Jul 12, 2024
0d77b7a
evm: create stack delta generator script
jochem-brouwer Jul 12, 2024
6e81d50
vm: remove outdated VM EOF API test
jochem-brouwer Jul 12, 2024
1ba1906
vm: remove other outdated test
jochem-brouwer Jul 12, 2024
6fcb016
evm: move and fix header tester to scripts dir
jochem-brouwer Jul 12, 2024
6be0ce7
fix evm header validation test name
jochem-brouwer Jul 12, 2024
da0fbf5
fix hardfork: change to prague without EOF
jochem-brouwer Jul 12, 2024
25ce620
evm: lint
jochem-brouwer Jul 12, 2024
1a88b4b
Merge branch 'master' into MEGA-EOF-V2
jochem-brouwer Jul 16, 2024
7e8c20b
common: fix build
jochem-brouwer Jul 16, 2024
dda0639
evm/eof: add comments
jochem-brouwer Jul 16, 2024
2704a2a
eof: cleanup errors
jochem-brouwer Jul 16, 2024
da6146e
eof: add comment
jochem-brouwer Jul 16, 2024
e009f88
fix typo
jochem-brouwer Jul 16, 2024
f14d656
update eof-header-validation.ts such that it works
jochem-brouwer Jul 17, 2024
d9af095
Merge branch 'master' into MEGA-EOF-V2
holgerd77 Jul 18, 2024
bb326a0
Fixes
holgerd77 Jul 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
evm: add reachable code/opcodes verification eof
  • Loading branch information
jochem-brouwer committed May 30, 2024
commit ee5439815cab2b5f987834bf6e93f463f3589ba8
2 changes: 2 additions & 0 deletions packages/evm/src/eof/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ export enum EOFError {
InvalidJUMPF = 'invalid jumpf target (output count)',
InvalidReturningSection = 'invalid returning code section: section is not returning',
RJUMPVTableSize0 = 'invalid RJUMPV: table size 0',
UnreachableCodeSections = 'unreachable code sections',
UnreachableCode = 'unreachable code (by forward jumps)',
}

export enum SimpleErrors {
Expand Down
15 changes: 8 additions & 7 deletions packages/evm/src/eof/stackDelta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ export const stackDelta: {
outputs: number
name: string
intermediates: number
terminating?: boolean
}
} = {
0x00: { inputs: 0, outputs: 0, name: 'STOP', intermediates: 0 },
0x00: { inputs: 0, outputs: 0, name: 'STOP', intermediates: 0, terminating: true },
0x01: { inputs: 2, outputs: 1, name: 'ADD', intermediates: 0 },
0x02: { inputs: 2, outputs: 1, name: 'MUL', intermediates: 0 },
0x03: { inputs: 2, outputs: 1, name: 'SUB', intermediates: 0 },
Expand Down Expand Up @@ -144,20 +145,20 @@ export const stackDelta: {
0xe1: { inputs: 1, outputs: 0, name: 'RJUMPI', intermediates: 2 },
0xe2: { inputs: 1, outputs: 0, name: 'RJUMPV', intermediates: 1 },
0xe3: { inputs: 0, outputs: 0, name: 'CALLF', intermediates: 2 },
0xe4: { inputs: 0, outputs: 0, name: 'RETF', intermediates: 0 },
0xe5: { inputs: 0, outputs: 0, name: 'JUMPF', intermediates: 2 },
0xe4: { inputs: 0, outputs: 0, name: 'RETF', intermediates: 0, terminating: true },
0xe5: { inputs: 0, outputs: 0, name: 'JUMPF', intermediates: 2, terminating: true },
0xe6: { inputs: 0, outputs: 1, name: 'DUPN', intermediates: 1 },
0xe7: { inputs: 0, outputs: 0, name: 'SWAPN', intermediates: 1 },
0xe8: { inputs: 0, outputs: 0, name: 'EXCHANGE', intermediates: 1 },
0xec: { inputs: 4, outputs: 1, name: 'EOFCREATE', intermediates: 1 },
0xee: { inputs: 2, outputs: 1, name: 'RETURNCONTRACT', intermediates: 1 },
0xf3: { inputs: 2, outputs: 0, name: 'RETURN', intermediates: 0 },
0xee: { inputs: 2, outputs: 1, name: 'RETURNCONTRACT', intermediates: 1, terminating: true },
0xf3: { inputs: 2, outputs: 0, name: 'RETURN', intermediates: 0, terminating: true },
0xf7: { inputs: 1, outputs: 1, name: 'RETURNDATALOAD', intermediates: 0 },
0xf8: { inputs: 4, outputs: 1, name: 'EXTCALL', intermediates: 0 },
0xf9: { inputs: 3, outputs: 1, name: 'EXTDELEGATECALL', intermediates: 0 },
0xfb: { inputs: 3, outputs: 1, name: 'EXTSTATICCALL', intermediates: 0 },
0xfd: { inputs: 2, outputs: 0, name: 'REVERT', intermediates: 0 },
0xfe: { inputs: 0, outputs: 0, name: 'INVALID', intermediates: 0 },
0xfd: { inputs: 2, outputs: 0, name: 'REVERT', intermediates: 0, terminating: true },
0xfe: { inputs: 0, outputs: 0, name: 'INVALID', intermediates: 0, terminating: true },
}

/*
Expand Down
50 changes: 50 additions & 0 deletions packages/evm/src/eof/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,16 +102,29 @@ function validateOpcodes(container: EOFContainer, evm: EVM) {

const validJumps = new Set<number>()

// Add all reachable code sections to
const reachableSections: { [key: number]: Set<number> } = {}

let codeSection = -1
for (const code of container.body.codeSections) {
codeSection++

reachableSections[codeSection] = new Set()

const returningFunction = container.body.typeSections[codeSection].outputs === 0x80
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The naming of this variable is opposite of what is actually contained. Only non-returning functions have an outputs section of 0x80

Suggested change
const returningFunction = container.body.typeSections[codeSection].outputs === 0x80
// 0x80 indicates that this code section is a function that does not return a value
const nonReturningFunction = container.body.typeSections[codeSection].outputs === 0x80


// Tracking set of reachable opcodes
const reachableOpcodes = new Set<number>()
reachableOpcodes.add(0)

// Validate that each opcode is defined
let ptr = 0
let lastOpcode: number = 0 // Note: code sections cannot be empty, so this number will always be set

while (ptr < code.length) {
if (!reachableOpcodes.has(ptr)) {
validationError(EOFError.UnreachableCode)
}
validJumps.add(ptr)
const opcode = code[ptr]

Expand All @@ -131,6 +144,16 @@ function validateOpcodes(container: EOFContainer, evm: EVM) {
validationError(EOFError.InvalidRJUMP)
}
addJump(target)
reachableOpcodes.add(target)

if (opcode === 0xe0) {
// For RJUMP check that the instruction after RJUMP is reachable
// If this is not the case, then it is not yet targeted by a forward jump
// And hence violates the spec
if (!reachableOpcodes.has(ptr + 3)) {
validationError(EOFError.UnreachableCode)
}
}
} else if (opcode === 0xe2) {
// RJUMPV
const tableSize = code[ptr + 1] + 1
Expand Down Expand Up @@ -158,13 +181,15 @@ function validateOpcodes(container: EOFContainer, evm: EVM) {
validationError(EOFError.OpcodeIntermediatesOOB)
}
addJump(target)
reachableOpcodes.add(target)
}

// Special case for RJUMPV: move ptr over the table (the immediate starting byte will be added later)
ptr += 2 * tableSize
} else if (opcode === 0xe3 || opcode === 0xe5) {
// CALLF / JUMPF
const target = readUint16(code, ptr + 1)
reachableSections[codeSection].add(target)
if (target >= container.header.codeSizes.length) {
validationError(EOFError.InvalidCallTarget)
}
Expand Down Expand Up @@ -207,13 +232,38 @@ function validateOpcodes(container: EOFContainer, evm: EVM) {
validationError(EOFError.OpcodeIntermediatesOOB)
}
ptr++ // Move to next opcode
if (stackDelta[opcode].terminating === undefined) {
// If the opcode is not terminating we can add the next opcode to the reachable opcodes
// It can be reached by sequential instruction flow
reachableOpcodes.add(ptr)
}
}

// Validate that the final opcode terminates
if (!terminatingOpcodes.has(lastOpcode)) {
validationError(EOFError.InvalidTerminator)
}
}

// Verify that each code section can be reached from code section 0
const sectionAccumulator = new Set<number>()
sectionAccumulator.add(0) // 0 is always reachable
const toCheck = [0]

while (toCheck.length > 0) {
const checkArray = reachableSections[toCheck.pop()!]
for (const checkSection of checkArray) {
if (!sectionAccumulator.has(checkSection)) {
// Only check the reachable section if
sectionAccumulator.add(checkSection)
toCheck.push(checkSection)
}
}
}

if (sectionAccumulator.size !== container.header.codeSizes.length) {
validationError(EOFError.UnreachableCodeSections)
}
}

function validateStack(_container: EOFContainer, _evm: EVM) {
Expand Down