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

EOF execution and validation (EIP-3540) #334

Merged
merged 8 commits into from
Apr 1, 2022
Merged

EOF execution and validation (EIP-3540) #334

merged 8 commits into from
Apr 1, 2022

Conversation

gumb0
Copy link
Member

@gumb0 gumb0 commented May 28, 2021

Make EOF header validation more generic (supporting any sections) commit is an optional refactoring, than will make adding new sections easier in the future.

lib/evmone/eof.cpp Outdated Show resolved Hide resolved
@gumb0 gumb0 force-pushed the eof-execution branch 2 times, most recently from 114f86f to 913d23c Compare May 31, 2021 11:18
Copy link
Member

@chfast chfast left a 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.

@gumb0 gumb0 force-pushed the eof-execution branch 2 times, most recently from 5de5588 to c8b0852 Compare May 31, 2021 12:51
@gumb0 gumb0 changed the title WIP EOF exection EOF execution May 31, 2021
@codecov
Copy link

codecov bot commented May 31, 2021

Codecov Report

Merging #334 (a57245a) into master (0c052a2) will decrease coverage by 0.03%.
The diff coverage is 99.29%.

@@            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     
Flag Coverage Δ
consensus 80.06% <19.54%> (-6.51%) ⬇️
unittests 99.61% <99.29%> (-0.04%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
test/utils/bytecode.hpp 97.63% <94.11%> (-0.40%) ⬇️
lib/evmone/eof.cpp 97.70% <97.70%> (ø)
lib/evmone/advanced_execution.cpp 100.00% <100.00%> (ø)
lib/evmone/baseline.cpp 100.00% <100.00%> (ø)
lib/evmone/execution_state.hpp 94.64% <100.00%> (+0.19%) ⬆️
lib/evmone/instructions.hpp 99.80% <100.00%> (ø)
test/unittests/analysis_test.cpp 100.00% <100.00%> (ø)
test/unittests/eof_test.cpp 100.00% <100.00%> (ø)
test/unittests/eof_validation_test.cpp 100.00% <100.00%> (ø)
test/unittests/evm_eof_test.cpp 100.00% <100.00%> (ø)

@gumb0 gumb0 force-pushed the eof-execution branch 11 times, most recently from 9233479 to 8f83384 Compare June 1, 2021 16:30
@@ -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)
Copy link
Member

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.

struct EOF1Header
{
int code_size = 0;
int data_size = 0;
Copy link
Member

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?

Copy link
Member Author

@gumb0 gumb0 Jun 2, 2021

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).

@gumb0 gumb0 force-pushed the eof-execution branch 5 times, most recently from 101eaf4 to 052f65e Compare June 22, 2021 18:28
lib/evmone/baseline.cpp Outdated Show resolved Hide resolved
lib/evmone/baseline.cpp Outdated Show resolved Hide resolved
@gumb0
Copy link
Member Author

gumb0 commented Mar 18, 2022

Rebased, please review @chfast @axic

@@ -121,6 +121,7 @@ class Memory


/// Generic execution state for generic instructions implementations.
// NOLINTNEXTLINE(clang-analyzer-optin.performance.Padding)
Copy link
Member

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},
Copy link
Member

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.

Copy link
Member Author

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, JUMPs and PC use it.

inline bytecode eof_header(uint8_t version, uint16_t code_size, uint16_t data_size)
{
bytecode out{"ef00"};
out += bytes{version};
Copy link
Member

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.

Copy link
Member

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}

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 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.

test/utils/bytecode.hpp Show resolved Hide resolved
test/utils/bytecode.hpp Outdated Show resolved Hide resolved

struct EOF1Header
{
size_t code_size = 0;
Copy link
Member

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.

Copy link
Member Author

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?

Copy link
Member

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.

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 changed the fields to uint16_t (but left code_begin() to return size_t)

@gumb0 gumb0 force-pushed the eof-execution branch 2 times, most recently from 47fc7d9 to 5e9154c Compare March 22, 2022 18:47
lib/evmone/eof.cpp Outdated Show resolved Hide resolved
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
Copy link
Member

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?

Copy link
Member Author

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.

Copy link
Member

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?

Copy link
Member Author

Choose a reason for hiding this comment

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

/// Reads the section sizes assuming that code has valid format.
/// (must be true for all EOF contracts on-chain)


auto state = State::section_id;
uint8_t section_id = 0;
size_t section_sizes[3] = {0, 0, 0};
Copy link
Member

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?

Copy link
Member Author

@gumb0 gumb0 Mar 30, 2022

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 Show resolved Hide resolved
lib/evmone/eof.cpp Outdated Show resolved Hide resolved
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)
Copy link
Member

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?

Copy link
Member Author

@gumb0 gumb0 Mar 23, 2022

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.

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually it was written originaly by @chfast in #303, I decided not to write another one.

return {{}, EOFValidationErrror::impossible};
}

++it;
Copy link
Member

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++ ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Moved.

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);
Copy link
Member

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?

constexpr uint8_t CODE_SECTION = 0x01;
constexpr uint8_t DATA_SECTION = 0x02;

std::pair<EOF1Header, EOFValidationErrror> validate_eof_headers(bytes_view code) noexcept
Copy link
Member

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?

Copy link
Member Author

Choose a reason for hiding this comment

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

Renamed.

return header;
}

uint8_t get_eof_version(bytes_view cont) noexcept
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
uint8_t get_eof_version(bytes_view cont) noexcept
uint8_t get_eof_version(bytes_view container) noexcept

Copy link
Member Author

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.)

@gumb0 gumb0 merged commit 3a2c27c into master Apr 1, 2022
@gumb0 gumb0 deleted the eof-execution branch April 1, 2022 14:13
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.

3 participants