-
Notifications
You must be signed in to change notification settings - Fork 2.2k
EIP96 - blockhash refactoring #4066
Conversation
e44f355
to
f5f802a
Compare
libdevcrypto/Common.cpp
Outdated
@@ -67,6 +67,8 @@ const Address dev::ZeroAddress = Address(); | |||
|
|||
const Address dev::MaxAddress = Address("0xffffffffffffffffffffffffffffffffffffffff"); | |||
|
|||
const Address dev::SuperuserAddress = Address("0xfffffffffffffffffffffffffffffffffffffffe"); |
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 has been renamed to system
.
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.
Thanks, I'll rename it
libethereum/ExtVM.cpp
Outdated
|
||
h256 ExtVM::blockHash(u256 _number) | ||
{ | ||
if (envInfo().number() < m_sealEngine.chainParams().u256Param("metropolisForkBlock") + 256) |
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 it was agreed last time that the opcode remains limited to the last 256 blocks.
Also the comment in ExtVM.h
should be kept up to date with the final decision:
- /// Hash of a block if within the last 256 blocks, or h256() otherwise.
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.
So where the code or comment disagrees with this?
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.
Right now the comment disagrees with the code. If you update the code to match the current EIP (limited to 256) then the comment is fine again :)
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 see the disagreement.
This line in particular just checks whether the current block (not the block requested) is before or after Metro+256 (according to this spec https://github.com/ethereum/EIPs/pull/210/files#diff-e02a92c2fb96c1a1bfb05e4c6e2ef5daR34 )
If we are before Metro+256, we return, as comment says, "hash of a block if within the last 256 blocks, or h256() otherwise."
Otherwise we do the same but through the call.
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 do not see that it is limited to the last 256 blocks through the call below after Metropolis?
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.
Oh, I see, I was assuming that the contract itself (the new version of it) will return 0 if requested block is out of bounds.
Yeah, anyway it will makes sense to avoid making a call in this case, I'll change it.
Thanks for noticing this!
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 contract has no easy way knowing where the call came from and its code may be different too in the future. Additionally the spec will/should say that the opcode itself filters for <=256.
aeec7b8
to
c4dd751
Compare
Current status:
This should better go into separate PR, because looks like some non-trivial refactoring is needed there Otherwise I think it's ready for review. |
@@ -108,6 +109,7 @@ static const EVMSchedule EIP158Schedule = [] | |||
static const EVMSchedule MetropolisSchedule = [] | |||
{ | |||
EVMSchedule schedule = EIP158Schedule; | |||
schedule.blockhashGas = 800; |
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's uncertain to me if 800
should be applied from the beginning of Metropolis
from 256 blocks into Metropolis
. I asked a question https://github.com/ethereum/EIPs/pull/210/files#r117211219
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.
And I will ask in the allcoredev meeting ethereum/pm#14 (comment)
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 seem to be strange. Shouldn't we just charge for the contract execution?
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 can stay as it is. In this previous allcoredev meeting, it was agreed that the gas schedule changes at the Metropolis block (inclusive), not later.
libethereum/Block.cpp
Outdated
Transaction tx(0, 0, gas, c_blockhashContractAddress, m_previousBlock.hash().asBytes(), nonce); | ||
tx.forceSender(SystemAddress); | ||
// passing empty lastHashes - assuming the contract doesn't use BLOCKHASH | ||
m_state.execute(EnvInfo(info(), {}, 0), *m_sealEngine, tx, Permanence::Committed); |
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 this doesn't increment the nonce.
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.
Hm, I think it does. Shouldn't 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 don't know if it should or not. So I need to ask.
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.
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.
Performing the call to update the blockhash contract should be similar to CALL from EVM, not to external transaction and should not increment SYSTEM_ADDRESS's nonce.
So the fix is needed here.
|
||
if (currentNumber < m_sealEngine.chainParams().u256Param("metropolisForkBlock") + 256) | ||
{ | ||
assert(envInfo().lastHashes().size() > (unsigned)(currentNumber - 1 - _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 assertion seems to fail if currentNumber == 0
and _number
== 0xff..ff
(which is 0 - 1
). I think lastHashes().size()
should be zero in that case, and the right hand side evaluates to zero.
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 won't get here because of the check at line 142, requested _number
is always less than currentNumber
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.
Also currentNumber
is never 0 here, because you can't execute anything in the genesis block
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.
OK, seems valid.
Rebased and comments addressed. |
"difficultyBoundDivisor": "0x0800", | ||
"durationLimit": "0x0d", | ||
"blockReward": "0x4563918244F40000", | ||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", |
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 we remove this from the codebase?
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'll remove it in a separate PR
@@ -53,6 +53,9 @@ const unsigned c_databaseVersionModifier = 0; | |||
|
|||
const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (23 << 9); | |||
|
|||
const Address c_blockhashContractAddress(0xf0); | |||
const bytes c_blockhashContractCode(fromHex("0x73fffffffffffffffffffffffffffffffffffffffe33141561006a5760014303600035610100820755610100810715156100455760003561010061010083050761010001555b6201000081071515610064576000356101006201000083050761020001555b5061013e565b4360003512151561008457600060405260206040f361013d565b61010060003543031315156100a857610100600035075460605260206060f361013c565b6101006000350715156100c55762010000600035430313156100c8565b60005b156100ea576101006101006000350507610100015460805260206080f361013b565b620100006000350715156101095763010000006000354303131561010c565b60005b1561012f57610100620100006000350507610200015460a052602060a0f361013a565b600060c052602060c0f35b5b5b5b5b")); |
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 we use an assert to check the hash of this code against other implementations? Or will the code hash be part of the block tests anyway?
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.
Might there be any global variable initialization race condition problems 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.
-
Yeah, blockchain tests check that the contract with correct code exists in the state
-
There shouldn't be as long as we don't use these constants for other static variable initialization in another module. Which we shouldn't do.
…f executing fake Transaction. Thus SystemAddresss's nonce won't be incremented as EIP96 requires.
# Conflicts: # test/tools/libtesteth/TestHelper.h
The Travis test failure looks related to the blockhash https://travis-ci.org/ethereum/cpp-ethereum/jobs/237208475#L1908 |
…ary stack object.
test/tools/jsontests/StateTests.cpp
Outdated
@@ -115,25 +116,49 @@ class generaltestfixture | |||
|
|||
void fillAllFilesInFolder(string _folder) | |||
{ | |||
std::string fillersPath = dev::test::getTestPath() + "/src/GeneralStateTestsFiller/" + _folder; | |||
std::string fillersPath = getTestPath() + "/src/GeneralStateTestsFiller/" + _folder; | |||
using dirIt = boost::filesystem::directory_iterator; |
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.
@winsvega Begin type alias with uppercase latter
test/tools/jsontests/StateTests.cpp
Outdated
|
||
boost::filesystem::directory_iterator iterator_tmp(fillersPath); | ||
dirIt iterator_tmp(fillersPath); |
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.
@winsvega use camelCase instead of snake_case
test/tools/jsontests/StateTests.cpp
Outdated
//Skip filling this tests as state tests | ||
if (Options::get().filltests && !Options::get().fillchain) | ||
{ | ||
TestOutputHelper::incTestCount(2); |
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.
@winsvega What does this do?
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.
as state test was not designed to run as a blockchain test. I have to overrun the test counter with this to get 100% tests executed output.
test/tools/jsontests/StateTests.cpp
Outdated
if (boost::filesystem::is_regular_file(iterator->path()) && iterator->path().extension() == ".json") | ||
{ | ||
string fileboost = iterator->path().filename().string(); | ||
dev::test::executeTests(fileboost, "/GeneralStateTests/"+_folder, "/GeneralStateTestsFiller/"+_folder, dev::test::doStateTests); | ||
if (fileboost.rfind("BCFiller.json") != std::string::npos) |
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.
@winsvega could you explain what happens here and why do you need to hardcode json file name?
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.
so not to convert 100 of tests into blockchain we decided to add a marker to such tests to be run as blockchain but being state tests.
I had an option in mind - to read file contents and then look for an option to run this test as blockchain.
then I realized that to do that I will have to parse whole json file and that would add to execution time.
there for we have this hardcoded thing.
the mere fact that state tests are being run as blockchain is a workaround. it was not designed to be run as blockchain tests.
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.
@winsvega can you keep a list of these names in a file in the tests
repository?
if (!Options::get().fillchain) //fill blockchain through state tests | ||
bool isRunFromStateTests = true; | ||
string suitename = boost::unit_test::framework::get<boost::unit_test::test_suite>(boost::unit_test::framework::current_test_case().p_parent_id).p_name; | ||
if (suitename.find("StateTests") == string::npos) |
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.
@winsvega Is there any way to pass the flag/enum to this function telling that we're in a special case of StateTests instead of querying suite name from boost? Why is doBlockchainTests
called from StateTests suite anyway?
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.
read above
After discussion with @winsvega he agreed to try a different approach with fixing tests for this - rolling back current workaround changes in testeth code and just convert affected json files |
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 need more time to review test changes.
Codecov Report
@@ Coverage Diff @@
## develop #4066 +/- ##
==========================================
+ Coverage 65.41% 65.71% +0.3%
==========================================
Files 301 303 +2
Lines 22882 22998 +116
==========================================
+ Hits 14968 15114 +146
+ Misses 7914 7884 -30
|
test/tools/jsontests/vm.cpp
Outdated
{ | ||
if (_number < envInfo().number() && _number >= (std::max<u256>(256, envInfo().number()) - 256)) | ||
return sha3(toString(_number)); | ||
else |
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.
There should be no else
.
#3612
ethereum/EIPs#210