-
Notifications
You must be signed in to change notification settings - Fork 285
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
EOF execution and validation (EIP-3540) #334
Conversation
114f86f
to
913d23c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good so far.
5de5588
to
c8b0852
Compare
Codecov Report
@@ Coverage Diff @@
## master #334 +/- ##
==========================================
- Coverage 99.60% 99.57% -0.04%
==========================================
Files 33 37 +4
Lines 4057 4477 +420
==========================================
+ Hits 4041 4458 +417
- Misses 16 19 +3
Flags with carried forward coverage won't be shown. Click here to find out more.
|
9233479
to
8f83384
Compare
test/utils/bytecode.hpp
Outdated
@@ -62,6 +62,25 @@ inline bytecode operator*(int n, evmc_opcode op) | |||
return n * bytecode{op}; | |||
} | |||
|
|||
inline bytecode eof_header(uint16_t code_size, uint16_t data_size = 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice how non-complex this is.
lib/evmone/eof.hpp
Outdated
struct EOF1Header | ||
{ | ||
int code_size = 0; | ||
int data_size = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to expose data_size
now? It is not used for anything in the VM. Perhaps just leave a comment that this only cares about code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently it's used (only checking != 0
) to find code section offset (i.e. total header size).
101eaf4
to
052f65e
Compare
@@ -121,6 +121,7 @@ class Memory | |||
|
|||
|
|||
/// Generic execution state for generic instructions implementations. | |||
// NOLINTNEXTLINE(clang-analyzer-optin.performance.Padding) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is expected, because stack space is 32-byte aligned and the struct padding changes depending on what fields you have before the stack space.
@@ -165,7 +172,8 @@ class ExecutionState | |||
msg{&message}, | |||
host{host_interface, host_ctx}, | |||
rev{revision}, | |||
code{_code} | |||
code{_code}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the code section ever needed here? The interpreter runs on the padded code from CodeAnalysis
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It needs at least the size of it, at least to report correct code to tracing...
But also the field itself is set in baseline to refenence the padded code, JUMP
s and PC
use it.
test/utils/bytecode.hpp
Outdated
inline bytecode eof_header(uint8_t version, uint16_t code_size, uint16_t data_size) | ||
{ | ||
bytecode out{"ef00"}; | ||
out += bytes{version}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess .push_back()
should work here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or bytecode out{0xEF, 0x00, version}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This works as bytecode{bytes{0xEF, 0x00, version}}
, because bytecode
doesn't have initializer_list
constructor. And adding such constructor would break bytecode{int_const}
expressions, which currently translates to PUSH.
lib/evmone/eof.hpp
Outdated
|
||
struct EOF1Header | ||
{ | ||
size_t code_size = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure size_t
is good type for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Me neither, is uint16_t
better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think uint16_t
is better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed the fields to uint16_t
(but left code_begin()
to return size_t
)
47fc7d9
to
5e9154c
Compare
const auto code_size_offset = 4; // FORMAT + MAGIC + VERSION + CODE_SECTION_ID | ||
header.code_size = | ||
static_cast<uint16_t>((code[code_size_offset] << 8) | code[code_size_offset + 1]); | ||
if (code[code_size_offset + 2] == 2) // is data section present |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't check for truncated EOF headers, i.e. does this expect validation ensures it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is a function to be used for validated deployed code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add this as a comment on the function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lines 28 to 29 in 52912ab
/// Reads the section sizes assuming that code has valid format. | |
/// (must be true for all EOF contracts on-chain) |
lib/evmone/eof.cpp
Outdated
|
||
auto state = State::section_id; | ||
uint8_t section_id = 0; | ||
size_t section_sizes[3] = {0, 0, 0}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are the 3 sizes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sizes for each possible value of section_id, 0th one is always 0 for terminator.
In later commit this is replaced with std::array<uint16_t, MAX_SECTION + 1>
lib/evmone/eof.cpp
Outdated
size_t section_sizes[3] = {0, 0, 0}; | ||
const auto code_end = code.end(); | ||
auto it = code.begin() + sizeof(MAGIC) + 2; // FORMAT + MAGIC + VERSION | ||
while (it != code_end && state != State::terminated) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you decide to implement the generic loop as opposed the short two checks we have in the EIP? Did we ever measure any speed difference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It became handy at one point when implementing RJUMPTABLE with additional jump table section.
That idea is abandoned now, but it can become handy again when we add type section for EOF Functions.
But I don't mind dropping this commit for now.
I was answering wrong question. To "why loop at all": I just liked that it's generic, it's less repetition in code I guess. No measurements done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lib/evmone/eof.cpp
Outdated
return {{}, EOFValidationErrror::impossible}; | ||
} | ||
|
||
++it; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this may be better moved to the cases, ie. size_hi = *it++
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved.
lib/evmone/eof.cpp
Outdated
return {{}, EOFValidationErrror::section_headers_not_terminated}; | ||
|
||
const auto section_bodies_size = section_sizes[CODE_SECTION] + section_sizes[DATA_SECTION]; | ||
const auto remaining_code_size = static_cast<size_t>(code_end - it); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, shouldn't we call this container?
lib/evmone/eof.cpp
Outdated
constexpr uint8_t CODE_SECTION = 0x01; | ||
constexpr uint8_t DATA_SECTION = 0x02; | ||
|
||
std::pair<EOF1Header, EOFValidationErrror> validate_eof_headers(bytes_view code) noexcept |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, how about calling this container?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed.
lib/evmone/eof.cpp
Outdated
return header; | ||
} | ||
|
||
uint8_t get_eof_version(bytes_view cont) noexcept |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uint8_t get_eof_version(bytes_view cont) noexcept | |
uint8_t get_eof_version(bytes_view container) noexcept |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed. (I originally wanted to avoid line wrapping.)
Co-authored-by: Paweł Bylica <[email protected]>
Co-authored-by: Paweł Bylica <[email protected]>
Make EOF header validation more generic (supporting any sections) commit is an optional refactoring, than will make adding new sections easier in the future.