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

core/vm: implement EIP-3540: EVM Object Format (EOF) v1 #22958

Closed
wants to merge 10 commits into from

Conversation

gumb0
Copy link
Member

@gumb0 gumb0 commented May 27, 2021

This is PoC for EIP-3540 implementation.

Some consensus tests are at ethereum/tests#847

@gumb0 gumb0 changed the title Eip 3540 Implement EIP-3540: EVM Object Format (EOF) v1 May 27, 2021
@gumb0 gumb0 changed the title Implement EIP-3540: EVM Object Format (EOF) v1 core/vm: implement EIP-3540: EVM Object Format (EOF) v1 May 27, 2021
@gumb0 gumb0 force-pushed the eip-3540 branch 2 times, most recently from 036cbe7 to 0695098 Compare May 27, 2021 17:02
@gumb0 gumb0 force-pushed the eip-3540 branch 2 times, most recently from b7a2fad to 679ba38 Compare August 18, 2021 17:00
@gumb0 gumb0 force-pushed the eip-3540 branch 2 times, most recently from 69b1645 to 5e765d7 Compare September 28, 2021 18:29
@gumb0 gumb0 force-pushed the eip-3540 branch 2 times, most recently from eff336d to 10d7532 Compare October 14, 2021 14:21
core/vm/eof.go Outdated Show resolved Hide resolved
core/vm/evm.go Outdated Show resolved Hide resolved
core/vm/evm.go Outdated Show resolved Hide resolved
@gumb0 gumb0 force-pushed the eip-3540 branch 4 times, most recently from 77fa3e7 to 35e7209 Compare November 24, 2021 12:14
return 0
}
// For EOF contracts running out of code section means abort execution with failure
return 0xfe
Copy link
Member

Choose a reason for hiding this comment

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

Nice trick.

Copy link
Member

@axic axic Nov 25, 2021

Choose a reason for hiding this comment

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

However isn't there an enum for opcodes? If so, it would make sense using it for both 0 and 0xfe so it is more apparent to the reader.

Hm, the current 0 returned is more in line with the concept of over-reading just returns zeroes (in case of codecopy/calldatacopy), and on that vein 0xfe is indeed a "hack".

Copy link
Member Author

Choose a reason for hiding this comment

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

However isn't there an enum for opcodes? If so, it would make sense using it for both 0 and 0xfe so it is more apparent to the reader.

No enum for 0xfe yet 😃 Also this function returns byte that's why it used 0 I think.
However it doesn't make sense to return byte because it's always casted to OpCode in GetOp above.
I guess I'll submit a separate small cleanup PR for this.

Copy link
Member

Choose a reason for hiding this comment

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

For anyone interested, see #23974 and #24017.

return OpCode(c.Code[n])
}

return STOP
// For legacy contracts running out of code section means STOP
if c.header.codeSize == 0 {
Copy link
Member

@axic axic Nov 29, 2021

Choose a reason for hiding this comment

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

I'd say a helper for this would be nice, otherwise just leave a comment stating that based EIP-3540 codeSize == 0 is invalid, i.e. it must be legacy.

Update: a helper would definitely be nice since this check is used in several places.

op := OpCode(code[pc])
func codeBitmapInternal(c *Contract, bits bitvec) bitvec {
for pc := uint64(0); pc < c.CodeSize(); {
op := OpCode(c.Code[c.CodeBeginOffset()+pc])
Copy link
Contributor

Choose a reason for hiding this comment

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

We def want to be sure that c.CodeBeginOffset() is not actually called every iteration, but only once. Perhaps better to move that out of the loop, to be sure in the future too?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

@gumb0 gumb0 force-pushed the eip-3540 branch 2 times, most recently from 71fb6e7 to b5013e1 Compare September 29, 2022 10:24
return c.header.CodeEndOffset()
}

func (c *Contract) CodeSize() uint64 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Docstring. This is actually not just a nit-pick, one pretty important thing to mention here is whether CodeSize returns the size of header+code, the entire container, or something else

Copy link
Member

Choose a reason for hiding this comment

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

Fixed.

return false
}
// Only JUMPDESTs allowed for destinations
if OpCode(c.Code[udest]) != JUMPDEST {
if OpCode(c.Code[c.CodeBeginOffset()+udest]) != JUMPDEST {
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe something like this, and internalize the call to CodeBeginOffset?

Suggested change
if OpCode(c.Code[c.CodeBeginOffset()+udest]) != JUMPDEST {
if c.OpCodeAt(udest) != JUMPDEST {

Copy link
Member Author

Choose a reason for hiding this comment

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

I went with @axic's suggestion below and used existing GetOp for this.

code := evm.StateDB.GetCode(addrCopy)

var header EOF1Header
if hasEIP3540(&evm.Config) && hasEOFMagic(code) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks a bit odd to me. Shouldn't you instead do something like

if evm.chainRules.IsEip3540 && hasEOFMagic(code) { 

?

Copy link
Member Author

Choose a reason for hiding this comment

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

This was implemented to make EIP-3540 (and EIP-3670) only activatable as an "extra" EIP (list of these is in evm.Config.ExtraEips)

If you think it's okay now to make it part of Shanghai implementation, I'll be happy to change it to evm.chainRules.IsShanghai, this would actually simplify some things I believe.

@@ -184,7 +184,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
}
// Get the operation from the jump table and validate the stack to ensure there are
// enough stack items available to perform the operation.
op = contract.GetOp(pc)
op = contract.GetOp(contract.CodeBeginOffset() + pc)
Copy link
Contributor

Choose a reason for hiding this comment

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

Could also use that contract.OpCodeAt(udest) I suggested above

Copy link
Member

Choose a reason for hiding this comment

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

Could also just change GetOp to the new semantics, couldn't it? It seems to be the only place it is being used at (and has internal length checks).

@gumb0
Copy link
Member Author

gumb0 commented Nov 8, 2022

d5cf7a2 is a refactoring to save code section bounds instead of EOF1Header in Contract to have fewer calculations and branching on the hot paths in interpreter loop.

@gumb0
Copy link
Member Author

gumb0 commented Nov 8, 2022

Renamed Contract.Code to Contract.Container to use terminology from the EIP and disambiguate from mentions of code section.

jumpdests map[common.Hash]bitvec // Aggregated result of JUMPDEST analysis.
analysis bitvec // Locally cached result of JUMPDEST analysis

Code []byte
CodeHash common.Hash
CodeAddr *common.Address
Copy link
Member Author

@gumb0 gumb0 Nov 8, 2022

Choose a reason for hiding this comment

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

CodeAddr was not used.

@gumb0 gumb0 force-pushed the eip-3540 branch 3 times, most recently from 1770a8e to 55cbab6 Compare November 8, 2022 19:05
@gumb0
Copy link
Member Author

gumb0 commented Dec 29, 2022

Outdated and superseded by #26133

@gumb0 gumb0 closed this Dec 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants