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

feat: EIP-3074 Implementation #1

Open
wants to merge 20 commits into
base: reth_freeze
Choose a base branch
from
Open

feat: EIP-3074 Implementation #1

wants to merge 20 commits into from

Conversation

clabby
Copy link
Owner

@clabby clabby commented Dec 2, 2023

Overview

Contains an implementation of the EIP-3074 specification.

Copy link

@anna-carroll anna-carroll left a comment

Choose a reason for hiding this comment

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

only issue with conformance to spec is the source of value!

};

// If the memory region is longer than 65 bytes, pull the commit from the next [1, 32] bytes.
let commit = (mem_slice.len() > 65).then(|| {

Choose a reason for hiding this comment

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

in general, the spec doesn't specify the behavior if the memory region is less than 97 bytes. should we add that to the spec? i wonder what would be the desired behavior there - immediately return 0?

Copy link
Owner Author

Choose a reason for hiding this comment

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

This is mostly to copy the behavior of Go's copy intrinsic, where it can perform partial reads. It would be nice to have some clarity here!

Immediately returning 0 makes sense, assuming the commit must be present (or at the very least, 0'd out explicitly).

crates/interpreter/src/instructions/host.rs Outdated Show resolved Hide resolved
let signature = {
// Place the yParity value, located at the first byte, in the last byte.
let mut sig = [0u8; 65];
sig[0..64].copy_from_slice(&mem_slice[1..65]);

Choose a reason for hiding this comment

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

we don't check that 65 <= mem_slice.len() before doing this, idk if that's necessary or if this will error on its own

Copy link
Owner Author

@clabby clabby Dec 2, 2023

Choose a reason for hiding this comment

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

Yeah this will panic, but we should handle gracefully. The spec doesn't mention what to do if the length passed to AUTH is < 65 unless I missed it. Should we halt here and consume all gas?

The above memory expansion only covers the length passed to the AUTH op, so you could make it panic with this setup.

Copy link
Collaborator

Choose a reason for hiding this comment

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

The way that i would interpret it is that if the length is less than 65 bytes, then there would be 0 bytes in the sig and if it was more than 65 bytes it would truncate. Tradeoffs in upgrade flexibility (not enshrining ecdsa) vs developer footguns

Choose a reason for hiding this comment

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

Yeah it isn't clearly stated, but I believe the general behavior for EVM operations is that unexpanded memory is always considered 0 (but you need to pay for the expansion). So in this case, if the length is less than 65 bytes you would grab as many bytes as allowed, fill in zeros for the rest, then charge for the filled in zeros and consider that region "expanded".

crates/interpreter/src/instructions/host.rs Outdated Show resolved Hide resolved
crates/interpreter/src/interpreter.rs Outdated Show resolved Hide resolved
Copy link

@lightclient lightclient left a comment

Choose a reason for hiding this comment

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

Looks pretty good to me. I think the gas accounting is missing specific rules for AUTHCALL though, but not certain since didn't dig too deeply into call_inner. The EIP is a bit cheeky and removes the call stipend when value is non-zero.

@@ -24,6 +24,7 @@ pub enum InstructionResult {
OpcodeNotFound,
CallNotAllowedInsideStatic,
StateChangeDuringStaticCall,
ActiveAccountUnsetAuthCall,
Copy link

@lightclient lightclient Dec 3, 2023

Choose a reason for hiding this comment

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

Suggested change
ActiveAccountUnsetAuthCall,
UnauthorizedAuthCall,

just a proposal, maybe read a bit easier

let signature = {
// Place the yParity value, located at the first byte, in the last byte.
let mut sig = [0u8; 65];
sig[0..64].copy_from_slice(&mem_slice[1..65]);

Choose a reason for hiding this comment

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

Yeah it isn't clearly stated, but I believe the general behavior for EVM operations is that unexpanded memory is always considered 0 (but you need to pay for the expansion). So in this case, if the length is less than 65 bytes you would grab as many bytes as allowed, fill in zeros for the rest, then charge for the filled in zeros and consider that region "expanded".

@clabby
Copy link
Owner Author

clabby commented Dec 3, 2023

Looks pretty good to me. I think the gas accounting is missing specific rules for AUTHCALL though, but not certain since didn't dig too deeply into call_inner. The EIP is a bit cheeky and removes the call stipend when value is non-zero.

Thanks for review! Yeah, gas accounting is not yet to-spec. @tynes has a PR open for this @ #6

@clabby clabby mentioned this pull request Dec 9, 2023
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants