/*
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;
CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc):
FullBlockChain(createGenesisBlock(), createGenesisState(), _path, _we, _pc)
{
}
void CanonBlockChain::reopen(std::string const& _path, WithExisting _we, ProgressCallback const& _pc)
{
close();
open(createGenesisBlock(), createGenesisState(), _path, _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_genesisInfo : 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()
<< difficulty
<< 0 // number
<< gasLimit
<< 0 // gasUsed
<< timestamp
<< (s_genesisExtraData.empty() ? extraData : s_genesisExtraData)
<< mixHash
<< nonce;
block.appendRaw(RLPEmptyList);
block.appendRaw(RLPEmptyList);
return block.out();
}
unordered_map CanonBlockChain::createGenesisState()
{
static std::unordered_map s_ret;
if (s_ret.empty())
{
js::mValue val;
json_spirit::read_string(s_genesisStateJSON.empty() ? c_genesisInfo : s_genesisStateJSON, val);
for (auto account: val.get_obj()["alloc"].get_obj())
{
u256 balance;
if (account.second.get_obj().count("wei"))
balance = u256(account.second.get_obj()["wei"].get_str());
else if (account.second.get_obj().count("balance"))
balance = u256(account.second.get_obj()["balance"].get_str());
else if (account.second.get_obj().count("finney"))
balance = u256(account.second.get_obj()["finney"].get_str()) * finney;
if (account.second.get_obj().count("code"))
{
s_ret[Address(fromHex(account.first))] = Account(balance, Account::ContractConception);
s_ret[Address(fromHex(account.first))].setCode(fromHex(account.second.get_obj()["code"].get_str()));
}
else
s_ret[Address(fromHex(account.first))] = Account(balance, Account::NormalCreation);
}
}
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();
}
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;
}