/* 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; }