-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Implement bitwise shifting (EIP145) #4054
Conversation
Codecov Report
@@ Coverage Diff @@
## develop #4054 +/- ##
===========================================
- Coverage 60.36% 60.28% -0.09%
===========================================
Files 352 352
Lines 27891 27912 +21
Branches 2884 2894 +10
===========================================
- Hits 16836 16826 -10
- Misses 10060 10089 +29
- Partials 995 997 +2 |
libevm/VM.cpp
Outdated
ON_OP(); | ||
updateIOGas(); | ||
|
||
/// TODO: confirm shift >= 256 results in 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.
We should add unit tests for edge cases in boost::multiprecision.
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.
That is done in #4064. So we should add appropriate boundary checks here (and masking).
9d11d0f
to
d5f342e
Compare
libevm/VM.cpp
Outdated
updateIOGas(); | ||
|
||
/// This workarounds a bug in Boost, ... | ||
u256 mask = (u256(1) << (256 - m_SP[1])) - 1; |
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 don't know what happens when m_SP[1]
is more than 256.
- Is the underflown subtraction defined?
- Isn't the shift very slow when
256 - m_SP[1]
is a big number?
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.
The EIP says If the shift amount (`arg2`) is greater or equal 256 the result is 0.
so the above code should be updated accordingly.
Need to swap operands as per latest changes. |
@axic @chfast There is substantial overlap with my #4569. This one is the one that should be pulled. However, you will want libevm/Instruction.h and Instruction.cpp from #4569. Also the convention I am using for an experimental feature like this is to place
in libevm/VMConfig.h and wall off the code for the feature with |
@axic @chfast Inspecting our code there are many differences. For starters. I am taking the item on the top of the stack
You are shifting by Otherwise our code is just different.
So perhaps my code is wrong, but please look. |
libevm/VM.cpp
Outdated
{ | ||
uint64_t amount = uint64_t(m_SP[0]); | ||
m_SPP[0] = shiftee >> amount; | ||
m_SPP[0] |= allbits << (256 - amount); |
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 you have to check shiftee & hibit
here as well.
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.
Done.
afafed4
to
7e4fbf5
Compare
libevm/VM.cpp
Outdated
if (m_SP[0] >= 256) | ||
m_SPP[0] = 0; | ||
else | ||
m_SPP[0] = m_SP[1] << uint64_t(m_SP[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.
Could also just use unsigned
and not the specific uint64_t
since it always fits into 8 bits.
libevm/VM.cpp
Outdated
ON_OP(); | ||
updateIOGas(); | ||
|
||
static u256 const hibit = u256(1) << 255; |
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 I'd prefer a slower, but definitely correct implementation for this case to ensure everything is working properly. Once multiple clients agree on tests, it can be optimised for speed.
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 you think the code I have now is mathematically incorrect? Or are you worried about bugs in boost's library?
libevm/VM.cpp
Outdated
m_SPP[0] = s2u(-1); | ||
} | ||
else | ||
m_SPP[0] = s2u(divWorkaround(value, exp256(2, shift))); |
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 was broken due to EVM DIV not rounding the same way.
I wonder if it is possible to do the RC5 changes in a separate pull request as it doesn't seem related to this PR? |
libevm/VMConfig.h
Outdated
@@ -25,9 +25,13 @@ namespace eth | |||
// | |||
// interpreter configuration macros for development, optimizations and tracing | |||
// | |||
// EIP_145 - bitwise shifting |
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.
Out of curiosity, why is EIP_145
better/more expressive than EVM_USE_BITSHIFT
?
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 tells the reader where to find the spec for the feature. And it's consistent with the others.
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 prefer using a meaning names, because I'm usually confused by numbers.
As a compromise, can it be EIP145_BITSHIFT
or EVM_EIP145_BITSHIFT
?
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 much prefer the compromise.
I chose to use the EIP numbers for a reason--if you are going into the code looking for all configuration macros specific to an EIP all you need to know is the number. Conversely, when you come upon an unnumbered macro in the code you might know EIP it relates to.
If we must remove the numbers from the configuration macros, please add comments at the point of definition as to what EIP they configure.
Where are the unit tests being run? What did change in |
The relationship is the change to use the solidity shift operators rather than exponentiation. The shifts in rc5 are data-dependent, and will be a good stress test. |
If you mean libevm/tests/unittests/performance the tests there are run manually with tests.mk - testing performance on virtualized machines is useless. shift-tests.asm doesn't really belong there so far as being a performance test, but I don't know where else to put it. |
As far as I know nothing changed in jsontests; I just did |
@axic It appears my attempt to remove jsontests from the PR failed, although it did allow for an automatic merge again. I will refrain from further attempts to back this out and, with apologies, leave it to you. |
Please rebase. |
It should be possible, you'd need to add |
How about adding support for the constantinople schedule in this PR then? Shouldn't take too long. |
Or could merge this and help @tcsiwula finish #4838 |
Merged this as every test succeeded except the code coverage :) |
@gcolvin @tcsiwula thank you for your help finishing this! |
@axic Sorry to be late to the game. I believe the runtime tests in VM.cpp can more efficiently be handled in VM::optimize by conditionally replacing the unimplemented instructions with Instruction::INVALID. |
@gcolvin it seems that the |
@axic Unless jump destinations are no longer verified the loop I pointed at is needed, and conditionally invalid opcodes can be tested for there, whether or not my work on bytecode optimization is being abandoned. Once replaced with INVALID these opcodes will be detected by the opcode dispatch without incurring extra overhead on every opcode execution. It would be small change to this PR, or a small new PR, but I haven't time to make it right now. |
... aka it doesn't even replace Byzantium opcodes with |
Also Known As what? I'm not understanding you, sorry. |
The code you have linked to does not replace any Byzantium opcode with the invalid opcode. Not sure how can I write this sentence differently. |
Something like this, and remove the tests in VM.cpp
|
I understand how it can be added, all I am saying that it is not present for As a result, this isn't something which was missed in this PR, rather than it is a new improvement, which can be done separately. |
Aha. I didn't understand what you didn't understand ;) I agree it can be done separately. I just wanted to make note of it. I haven't had much time for this code, but try to notice when changes go in. |
Implements ethereum/EIPs#215