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 EIP-663 variant C #98

Closed
wants to merge 4 commits into from
Closed

Implement EIP-663 variant C #98

wants to merge 4 commits into from

Conversation

chfast
Copy link
Member

@chfast chfast commented Jul 18, 2019

This implement the variant C of the EIP-663 by adding 4 new instructions for EVM stack manipulation: DUPN, SWAPN, DUPSN, SWAPSN.

The function change is only done in the analysis phase when the instruction argument (stack item index) is decode. During execution the same procedure is used as for legacy DUP and SWAP instructions.

Closes #84.

@codecov-io
Copy link

codecov-io commented Jul 18, 2019

Codecov Report

Merging #98 into master will decrease coverage by 3.05%.
The diff coverage is 100%.

@@            Coverage Diff            @@
##           master     #98      +/-   ##
=========================================
- Coverage   93.46%   90.4%   -3.06%     
=========================================
  Files          18      18              
  Lines        1866    1938      +72     
  Branches      197     202       +5     
=========================================
+ Hits         1744    1752       +8     
- Misses         97     161      +64     
  Partials       25      25

@chfast chfast force-pushed the eip-663-c branch 2 times, most recently from babd644 to 689f713 Compare July 18, 2019 11:50

int load_1byte_immediate_value(const uint8_t* code, size_t code_size, size_t& index) noexcept
{
return (index + 1 < code_size) ? code[++index] : 0;
Copy link
Member

Choose a reason for hiding this comment

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

Does this mean that code not having an argument behaves the same as argument 0? And costs the same gas? Is this correct? (how is this with the code not having enough bytes after PUSH?)

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's the same case as implicit zero bytes after any PUSH instructions.

@@ -124,7 +135,41 @@ code_analysis analyze(
instr.arg.p.number = static_cast<int>(i);
else if (c >= OP_LOG0 && c <= OP_LOG4)
instr.arg.p.number = c - OP_LOG0;
else if (is_terminator(c))

if (rev >= EVMC_ISTANBUL)
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 should be better else if, so that it's not even considered if it's some other opcode.

@@ -15,6 +15,18 @@ bool is_terminator(uint8_t c) noexcept
return c == OP_JUMP || c == OP_JUMPI || c == OP_STOP || c == OP_RETURN || c == OP_REVERT ||
c == OP_SELFDESTRUCT;
}

int load_1byte_immediate_value(const uint8_t* code, size_t code_size, size_t& index) noexcept
Copy link
Member

Choose a reason for hiding this comment

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

Minor stylistic suggestion: I would leave updating of index on the calling side, i.e. pass it by value here. Then it would be easier to understand what's happending with it, when you look the calling side

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, but we update the index conditionally. We can rename load_ into consume_ though.

Copy link
Member Author

Choose a reason for hiding this comment

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

Reworked.

EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(1023);

execute(full_stack_code + OP_DUPN + "03fe" + OP_SWAPSN + "00" + OP_RETURN);
Copy link
Member

Choose a reason for hiding this comment

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

why does it not use ret_top() and how does it return anything without storing in memory?

Copy link
Member Author

Choose a reason for hiding this comment

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

The ret_top() requires additional push therefore more stack space. We only check the output size which matches the last duped item.

@gumb0
Copy link
Member

gumb0 commented Jul 18, 2019

Unit test suggestions:

  • check the case with implicit zero bytes (check at least that it completes sucessfully, maybe check that it's the same gas used as with actual zero args)
  • check that it's undefined isntructions before Istanbul
  • Two test cases from the EIP spec

std::pair<int, size_t> load_1byte_immediate_value(
const uint8_t* code, size_t code_size, size_t index) noexcept
{
return {(index + 1 < code_size) ? code[++index] : 0, index};
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 look right, because the order of evaluation of pair constructor arguments is not defined, is 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.

I thought this is now specified in C++17, but it is not. To be fixed.

Copy link
Member

Choose a reason for hiding this comment

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

(re the need to update index conditionally: even if would update it unconditionally on the calling side and go beyond the code size, it will correctly break out of the loop, so updating here doesn't seem necessary to me)

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 though about this, but sounds risky. It would not work if we used != in the loop condition, or used an iterator instead of an index. Quite fragile to have the correctness of the implementation of this helper depend on some other loop implementation outside.

@chfast
Copy link
Member Author

chfast commented Aug 24, 2022

Can I close this?

@chfast chfast closed this Aug 25, 2022
@chfast chfast deleted the eip-663-c branch August 25, 2022 07:32
@rodiazet rodiazet restored the eip-663-c branch November 23, 2022 14:19
rodiazet added a commit that referenced this pull request Nov 23, 2022
@chfast chfast deleted the eip-663-c branch December 13, 2022 12:47
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.

Prototype EIP-663 (unlimited swapdup)
3 participants