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

Commit

Permalink
Merge pull request #4066 from ethereum/eip96
Browse files Browse the repository at this point in the history
EIP96 - blockhash refactoring
  • Loading branch information
winsvega authored Jun 3, 2017
2 parents 4b555c7 + 0b2e08e commit 8bd9a8b
Show file tree
Hide file tree
Showing 24 changed files with 340 additions and 14 deletions.
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",
"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"));

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));
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 @@ -304,7 +304,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 @@ -809,6 +809,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;
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

0 comments on commit 8bd9a8b

Please sign in to comment.