Skip to content
This repository has been archived by the owner on Oct 28, 2021. It is now read-only.

EIP96 - blockhash refactoring #4066

Merged
merged 12 commits into from
Jun 3, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions libdevcrypto/Common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ const Address dev::ZeroAddress = Address();

const Address dev::MaxAddress = Address("0xffffffffffffffffffffffffffffffffffffffff");

const Address dev::SystemAddress = Address("0xfffffffffffffffffffffffffffffffffffffffe");

Public dev::toPublic(Secret const& _secret)
{
auto* ctx = getCtx();
Expand Down
3 changes: 3 additions & 0 deletions libdevcrypto/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ extern const Address ZeroAddress;
/// The last address.
extern const Address MaxAddress;

/// The SYSTEM address.
extern const Address SystemAddress;

/// A vector of Ethereum addresses.
using Addresses = h160s;

Expand Down
2 changes: 2 additions & 0 deletions libethashseal/GenesisInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ using namespace dev;
#include "genesis/eip150Test.cpp"
#include "genesis/eip158Test.cpp"
#include "genesis/metropolisTest.cpp"
#include "genesis/metropolisTransitionTest.cpp"
#include "genesis/transitionnetTest.cpp"

std::string const& dev::eth::genesisInfo(Network _n)
Expand All @@ -45,6 +46,7 @@ std::string const& dev::eth::genesisInfo(Network _n)
case Network::EIP150Test: return c_genesisInfoEIP150Test;
case Network::EIP158Test: return c_genesisInfoEIP158Test;
case Network::MetropolisTest: return c_genesisInfoMetropolisTest;
case Network::MetropolisTransitionTest: return c_genesisInfoMetropolisTransitionTest;
default:
throw std::invalid_argument("Invalid network value");
}
Expand Down
1 change: 1 addition & 0 deletions libethashseal/GenesisInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ enum class Network
EIP150Test = 73, ///< Homestead + EIP150 Rules active from block 0 For BlockchainTests
EIP158Test = 74, ///< Homestead + EIP150 + EIP158 Rules active from block 0
MetropolisTest = 75, ///< All fork rules + Metropolis active from block 0
MetropolisTransitionTest = 76, ///< All fork rules + Metropolis active from block 2
Special = 0xff ///< Something else.
};

Expand Down
63 changes: 63 additions & 0 deletions libethashseal/genesis/metropolisTransitionTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
This file is part of cpp-ethereum.

cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../GenesisInfo.h"

static dev::h256 const c_genesisStateRootMetropolisTransitionTest;
static std::string const c_genesisInfoMetropolisTransitionTest = std::string() +
R"E(
{
"sealEngine": "NoProof",
"params": {
"accountStartNonce": "0x00",
"maximumExtraDataSize": "0x20",
"homsteadForkBlock": "0x00",
"daoHardforkBlock": "0xfffffffffffffff",
"EIP150ForkBlock": "0x00",
"EIP158ForkBlock": "0x00",
"metropolisForkBlock": "0x02",
"minGasLimit": "0x1388",
"maxGasLimit": "7fffffffffffffff",
"tieBreakingGas": false,
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
Copy link
Contributor

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?

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'll remove it in a separate PR

"networkID" : "0x1",
"chainID": "0x01",
"allowFutureBlocks" : true
},
"genesis": {
"nonce": "0x0000000000000042",
"difficulty": "0x400000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x1388"
},
"accounts": {
"0000000000000000000000000000000000000001": { "wei": "1", "precompiled": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } },
"0000000000000000000000000000000000000002": { "wei": "1", "precompiled": { "name": "sha256", "linear": { "base": 60, "word": 12 } } },
"0000000000000000000000000000000000000003": { "wei": "1", "precompiled": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } },
"0000000000000000000000000000000000000004": { "wei": "1", "precompiled": { "name": "identity", "linear": { "base": 15, "word": 3 } } },
"0000000000000000000000000000000000000005": { "wei": "1", "precompiled": { "name": "modexp" } }
}
}
)E";
3 changes: 3 additions & 0 deletions libethcore/Common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Copy link
Contributor

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?

Copy link
Contributor

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?

Copy link
Member Author

Choose a reason for hiding this comment

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

  1. Yeah, blockchain tests check that the contract with correct code exists in the state

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


Address toAddress(std::string const& _s)
{
try
Expand Down
5 changes: 5 additions & 0 deletions libethcore/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ extern const unsigned c_minorProtocolVersion;
/// Current database version.
extern const unsigned c_databaseVersion;

/// Address of the special contract for block hash storage defined in EIP96
extern const Address c_blockhashContractAddress;
/// Code of the special contract for block hash storage defined in EIP96
extern const bytes c_blockhashContractCode;

/// User-friendly string representation of the amount _b in wei.
std::string formatBalance(bigint const& _b);

Expand Down
25 changes: 25 additions & 0 deletions libethereum/Block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ void Block::resetCurrent(u256 const& _timestamp)
m_committedToSeal = false;

performIrregularModifications();
updateBlockhashContract();
}

SealEngineFace* Block::sealEngine() const
Expand Down Expand Up @@ -692,6 +693,30 @@ void Block::performIrregularModifications()
}
}

void Block::updateBlockhashContract()
{
u256 const blockNumber = info().number();

u256 const metropolisForkBlock = m_sealEngine->chainParams().u256Param("metropolisForkBlock");
if (blockNumber == metropolisForkBlock)
{
m_state.createContract(c_blockhashContractAddress);
m_state.setNewCode(c_blockhashContractAddress, bytes(c_blockhashContractCode));
m_state.commit(State::CommitBehaviour::KeepEmptyAccounts);
}

if (blockNumber >= metropolisForkBlock)
{
Executive e(*this);
h256 const parentHash = m_previousBlock.hash();
if (!e.call(c_blockhashContractAddress, SystemAddress, 0, 0, parentHash.ref(), 1000000))
e.go();
e.finalize();

m_state.commit(State::CommitBehaviour::KeepEmptyAccounts);
}
}

void Block::commitToSeal(BlockChain const& _bc, bytes const& _extraData)
{
if (isSealed())
Expand Down
3 changes: 3 additions & 0 deletions libethereum/Block.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,9 @@ class Block
/// Performs irregular modifications right after initialization, e.g. to implement a hard fork.
void performIrregularModifications();

/// Creates and updates the special contract for storing block hashes according to EIP96
void updateBlockhashContract();

/// Provide a standard VM trace for debugging purposes.
std::string vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir);

Expand Down
23 changes: 23 additions & 0 deletions libethereum/ExtVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,26 @@ void ExtVM::suicide(Address _a)
m_s.subBalance(myAddress, m_s.balance(myAddress));
ExtVMFace::suicide(_a);
}

h256 ExtVM::blockHash(u256 _number)
{
u256 const currentNumber = envInfo().number();

if (_number >= currentNumber || _number < (std::max<u256>(256, currentNumber) - 256))
return h256();

if (currentNumber < m_sealEngine.chainParams().u256Param("metropolisForkBlock") + 256)
{
assert(envInfo().lastHashes().size() > (unsigned)(currentNumber - 1 - _number));
Copy link
Member

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.

Copy link
Member Author

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

Copy link
Member Author

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

Copy link
Member

Choose a reason for hiding this comment

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

OK, seems valid.

return envInfo().lastHashes()[(unsigned)(currentNumber - 1 - _number)];
}

u256 const nonce = m_s.getNonce(caller);
u256 const gas = 1000000;
Transaction tx(0, 0, gas, c_blockhashContractAddress, toBigEndian(_number), nonce);
tx.forceSender(caller);

ExecutionResult res;
std::tie(res, std::ignore) = m_s.execute(envInfo(), m_sealEngine, tx, Permanence::Reverted);
return h256(res.output);
}
3 changes: 3 additions & 0 deletions libethereum/ExtVM.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ class ExtVM: public ExtVMFace

State const& state() const { return m_s; }

/// Hash of a block if within the last 256 blocks, or h256() otherwise.
h256 blockHash(u256 _number) override;

private:
State& m_s; ///< A reference to the base state.
SealEngineFace const& m_sealEngine;
Expand Down
2 changes: 1 addition & 1 deletion libevm/ExtVMFace.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ class ExtVMFace
virtual void log(h256s&& _topics, bytesConstRef _data) { sub.logs.push_back(LogEntry(myAddress, std::move(_topics), _data.toBytes())); }

/// Hash of a block if within the last 256 blocks, or h256() otherwise.
h256 blockHash(u256 _number) { return _number < envInfo().number() && _number >= (std::max<u256>(256, envInfo().number()) - 256) ? envInfo().lastHashes()[(unsigned)(envInfo().number() - 1 - _number)] : h256(); }
virtual h256 blockHash(u256 _number) = 0;

/// Get the execution environment information.
EnvInfo const& envInfo() const { return m_envInfo; }
Expand Down
1 change: 1 addition & 0 deletions libevm/VM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,7 @@ void VM::interpretCases()

CASE(BLOCKHASH)
{
m_runGas = toInt63(m_schedule->blockhashGas);
ON_OP();
updateIOGas();

Expand Down
2 changes: 2 additions & 0 deletions libevmcore/EVMSchedule.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ struct EVMSchedule
unsigned extcodecopyGas = 20;
unsigned balanceGas = 20;
unsigned suicideGas = 0;
unsigned blockhashGas = 20;
unsigned maxCodeSize = unsigned(-1);

bool staticCallDepthLimit() const { return !eip150Mode; }
Expand Down Expand Up @@ -110,6 +111,7 @@ static const EVMSchedule EIP158Schedule = []
static const EVMSchedule MetropolisSchedule = []
{
EVMSchedule schedule = EIP158Schedule;
schedule.blockhashGas = 800;
Copy link
Member

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:/ethereum/EIPs/pull/210/files#r117211219

Copy link
Member

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)

Copy link
Member

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?

Copy link
Member

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.

schedule.haveRevert = true;
schedule.haveReturnData = true;
schedule.haveStaticCall = true;
Expand Down
2 changes: 1 addition & 1 deletion libevmcore/Instruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::EXTCODECOPY, { "EXTCODECOPY", 0, 4, 0, true, Tier::Special } },
{ Instruction::RETURNDATASIZE,{"RETURNDATASIZE", 0, 0, 1, false, Tier::Base } },
{ Instruction::RETURNDATACOPY,{"RETURNDATACOPY", 0, 3, 0, true, Tier::VeryLow } },
{ Instruction::BLOCKHASH, { "BLOCKHASH", 0, 1, 1, false, Tier::Ext } },
{ Instruction::BLOCKHASH, { "BLOCKHASH", 0, 1, 1, false, Tier::Special } },
{ Instruction::COINBASE, { "COINBASE", 0, 0, 1, false, Tier::Base } },
{ Instruction::TIMESTAMP, { "TIMESTAMP", 0, 0, 1, false, Tier::Base } },
{ Instruction::NUMBER, { "NUMBER", 0, 0, 1, false, Tier::Base } },
Expand Down
2 changes: 1 addition & 1 deletion test/jsontests
Submodule jsontests updated 1783 files
10 changes: 9 additions & 1 deletion test/tools/jsontests/vm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ std::pair<bool, eth::owning_bytes_ref> FakeExtVM::call(CallParameters& _p)
return {true, eth::owning_bytes_ref{}}; // Return empty output.
}

h256 FakeExtVM::blockHash(u256 _number)
{
cnote << "Warning: using fake blockhash code!\n";
if (_number < envInfo().number() && _number >= (std::max<u256>(256, envInfo().number()) - 256))
return sha3(toString(_number));

return h256();
}

void FakeExtVM::set(Address _a, u256 _myBalance, u256 _myNonce, map<u256, u256> const& _storage, bytes const& _code)
{
get<0>(addresses[_a]) = _myBalance;
Expand Down Expand Up @@ -96,7 +105,6 @@ EnvInfo FakeExtVM::importEnv(mObject& _o)
info.setTimestamp(toInt(_o["currentTimestamp"]));
info.setAuthor(Address(_o["currentCoinbase"].get_str()));
info.setNumber(toInt(_o["currentNumber"]));
info.setLastHashes( lastHashes( info.number() ) );
return info;
}

Expand Down
1 change: 1 addition & 0 deletions test/tools/jsontests/vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class FakeExtVM: public eth::ExtVMFace
virtual size_t codeSizeAt(Address _a) override { return std::get<3>(addresses[_a]).size(); }
virtual std::pair<h160, eth::owning_bytes_ref> create(u256 _endowment, u256& io_gas, bytesConstRef _init, eth::OnOpFunc const&) override;
virtual std::pair<bool, eth::owning_bytes_ref> call(eth::CallParameters&) override;
virtual h256 blockHash(u256 _number) override;
void setTransaction(Address _caller, u256 _value, u256 _gasPrice, bytes const& _data);
void setContract(Address _myAddress, u256 _myBalance, u256 _myNonce, std::map<u256, u256> const& _storage, bytes const& _code);
void set(Address _a, u256 _myBalance, u256 _myNonce, std::map<u256, u256> const& _storage, bytes const& _code);
Expand Down
7 changes: 7 additions & 0 deletions test/tools/libtesteth/BlockChainHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,11 @@ class TestBlockChain
std::unique_ptr<TransientDirectory> m_tempDirBlockchain;
};

class NetworkSelector
{
public:
explicit NetworkSelector(Network _network) { TestBlockChain::s_sealEngineNetwork = _network; }
~NetworkSelector() { TestBlockChain::s_sealEngineNetwork = Network::FrontierTest; } // reset to default
};

}}
14 changes: 13 additions & 1 deletion test/tools/libtesteth/ImportTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ using namespace dev;
using namespace dev::test;
using namespace std;

namespace
{
LastHashes lastHashes(u256 _currentBlockNumber)
{
LastHashes ret;
for (u256 i = 1; i <= 256 && i <= _currentBlockNumber; ++i)
ret.push_back(sha3(toString(_currentBlockNumber - i)));
return ret;
}
}

ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller, testType testTemplate):
m_statePre(0, OverlayDB(), eth::BaseState::Empty),
m_statePost(0, OverlayDB(), eth::BaseState::Empty),
Expand Down Expand Up @@ -135,7 +146,7 @@ bytes ImportTest::executeTest()
json_spirit::mObject obj = fillJsonWithState(search2->second.first, search2->second.second);
for (auto& adr: obj)
{
if (adr.first == toString(m_envInfo.author()))
if (adr.first == "0x" + toString(m_envInfo.author()))
{
if (adr.second.get_obj().count("balance"))
{
Expand Down Expand Up @@ -279,6 +290,7 @@ void ImportTest::importEnv(json_spirit::mObject& _o)
m_envInfo.setNumber(toInt(_o["currentNumber"]));
m_envInfo.setTimestamp(toInt(_o["currentTimestamp"]));
m_envInfo.setAuthor(Address(_o["currentCoinbase"].get_str()));

m_envInfo.setLastHashes( lastHashes( m_envInfo.number() ) );
}

Expand Down
8 changes: 0 additions & 8 deletions test/tools/libtesteth/TestHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -494,14 +494,6 @@ RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject const& _tObj
}


LastHashes lastHashes(u256 _currentBlockNumber)
{
LastHashes ret;
for (u256 i = 1; i <= 256 && i <= _currentBlockNumber; ++i)
ret.push_back(sha3(toString(_currentBlockNumber - i)));
return ret;
}

dev::eth::BlockHeader constructHeader(
h256 const& _parentHash,
h256 const& _sha3Uncles,
Expand Down
1 change: 0 additions & 1 deletion test/tools/libtesteth/TestHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ void updateEthashSeal(dev::eth::BlockHeader& _header, h256 const& _mixHash, dev:
void executeTests(const std::string& _name, const std::string& _testPathAppendix, const std::string& _fillerPathAppendix, std::function<void(json_spirit::mValue&, bool)> doTests, bool _addFillerSuffix = true);
void userDefinedTest(std::function<void(json_spirit::mValue&, bool)> doTests);
RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject const& _tObj);
eth::LastHashes lastHashes(u256 _currentBlockNumber);
json_spirit::mObject fillJsonWithStateChange(eth::State const& _stateOrig, eth::State const& _statePost, eth::ChangeLog const& _changeLog);
json_spirit::mObject fillJsonWithState(eth::State const& _state);
json_spirit::mObject fillJsonWithState(eth::State const& _state, eth::AccountMaskMap const& _map);
Expand Down
Loading