/*
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 .
*/
/** @file CanonBlockChain.cpp
* @author Gav Wood
* @date 2014
*/
#include "CanonBlockChain.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "GenesisInfo.h"
#include "State.h"
#include "Defaults.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
namespace js = json_spirit;
unique_ptr CanonBlockChain::s_genesis;
boost::shared_mutex CanonBlockChain::x_genesis;
Nonce CanonBlockChain::s_nonce(u64(42));
string CanonBlockChain::s_genesisStateJSON;
bytes CanonBlockChain::s_genesisExtraData;
u256 CanonBlockChain::s_genesisDifficulty;
u256 CanonBlockChain::s_genesisGasLimit;
CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc):
FullBlockChain(createGenesisBlock(), createGenesisState(), _path)
{
BlockChain::openDatabase(_path, _we, _pc);
}
void CanonBlockChain::reopen(WithExisting _we, ProgressCallback const& _pc)
{
close();
open(createGenesisBlock(), createGenesisState(), m_dbPath);
openDatabase(m_dbPath, _we, _pc);
}
bytes CanonBlockChain::createGenesisBlock()
{
RLPStream block(3);
h256 stateRoot;
{
MemoryDB db;
SecureTrieDB state(&db);
state.init();
dev::eth::commit(createGenesisState(), state);
stateRoot = state.root();
}
js::mValue val;
json_spirit::read_string(s_genesisStateJSON.empty() ? c_network == Network::Frontier ? c_genesisInfoFrontier : c_genesisInfoOlympic : s_genesisStateJSON, val);
js::mObject genesis = val.get_obj();
h256 mixHash(genesis["mixhash"].get_str());
h256 parentHash(genesis["parentHash"].get_str());
h160 beneficiary(genesis["coinbase"].get_str());
u256 difficulty = fromBigEndian(fromHex(genesis["difficulty"].get_str()));
u256 gasLimit = fromBigEndian(fromHex(genesis["gasLimit"].get_str()));
u256 timestamp = fromBigEndian(fromHex(genesis["timestamp"].get_str()));
bytes extraData = fromHex(genesis["extraData"].get_str());
h64 nonce(genesis["nonce"].get_str());
block.appendList(15)
<< parentHash
<< EmptyListSHA3 // sha3(uncles)
<< beneficiary
<< stateRoot
<< EmptyTrie // transactions
<< EmptyTrie // receipts
<< LogBloom()
<< (s_genesisDifficulty ? s_genesisDifficulty : difficulty)
<< 0 // number
<< (s_genesisGasLimit ? s_genesisGasLimit : gasLimit)
<< 0 // gasUsed
<< timestamp
<< (s_genesisExtraData.empty() ? extraData : s_genesisExtraData)
<< mixHash
<< nonce;
block.appendRaw(RLPEmptyList);
block.appendRaw(RLPEmptyList);
return block.out();
}
AccountMap const& CanonBlockChain::createGenesisState()
{
static AccountMap s_ret;
if (s_ret.empty())
s_ret = jsonToAccountMap(s_genesisStateJSON.empty() ? c_network == Network::Frontier ? c_genesisInfoFrontier : c_genesisInfoOlympic : s_genesisStateJSON);
return s_ret;
}
void CanonBlockChain::setGenesis(std::string const& _json)
{
WriteGuard l(x_genesis);
s_genesisStateJSON = _json;
s_genesis.reset();
}
void CanonBlockChain::forceGenesisExtraData(bytes const& _genesisExtraData)
{
WriteGuard l(x_genesis);
s_genesisExtraData = _genesisExtraData;
s_genesis.reset();
}
void CanonBlockChain::forceGenesisDifficulty(u256 const& _genesisDifficulty)
{
WriteGuard l(x_genesis);
s_genesisDifficulty = _genesisDifficulty;
s_genesis.reset();
}
void CanonBlockChain::forceGenesisGasLimit(u256 const& _genesisGasLimit)
{
WriteGuard l(x_genesis);
s_genesisGasLimit = _genesisGasLimit;
s_genesis.reset();
}
Ethash::BlockHeader const& CanonBlockChain::genesis()
{
UpgradableGuard l(x_genesis);
if (!s_genesis)
{
auto gb = createGenesisBlock();
UpgradeGuard ul(l);
s_genesis.reset(new Ethash::BlockHeader);
s_genesis->populate(&gb, CheckEverything);
}
return *s_genesis;
}