From cd45bb65d01858f919b1c61839c956d073b2c933 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 6 Jan 2014 21:43:32 +0000 Subject: [PATCH] Genesis block stuff. --- libethereum/BlockChain.cpp | 32 ++++++++++++++++++++++++++++++++ libethereum/BlockChain.h | 21 ++++++++++++++++----- libethereum/BlockInfo.cpp | 20 +++++++++++++++++++- libethereum/BlockInfo.h | 8 ++++++++ libethereum/RLP.cpp | 9 +++++++++ libethereum/RLP.h | 4 ++++ libethereum/State.cpp | 12 ++++++++++-- 7 files changed, 98 insertions(+), 8 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index d249f6f88..3ad65a7d9 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -20,12 +20,16 @@ */ #include "Common.h" +#include "BlockInfo.h" #include "BlockChain.h" using namespace std; using namespace eth; BlockChain::BlockChain() { + // Initialise with the genesis as the last block on the longest chain. + m_lastBlockHash = m_genesisHash = BlockInfo::genesis().hash; + m_genesisBlock = BlockInfo::createGenesisBlock(); } BlockChain::~BlockChain() @@ -35,3 +39,31 @@ BlockChain::~BlockChain() void BlockChain::import(bytes const& _block) { } + +bytesConstRef BlockChain::block(u256 _hash) const +{ + auto it = m_cache.find(_hash); + if (it == m_cache.end()) + { + // Load block from disk. + pair> loaded; + it = m_cache.insert(loaded).first; + } + return it->second->data(); +} + +bytesConstRef BlockChain::lastBlock() const +{ + if (m_lastBlockHash == m_genesisHash) + return bytesConstRef((bytes*)&m_genesisBlock); + + return block(m_lastBlockHash); +} + +u256 BlockChain::lastBlockNumber() const +{ + if (m_lastBlockHash == m_genesisHash) + return 0; + + return m_numberAndParent[m_lastBlockHash].first; +} diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index d79b7c0b8..30d7a7ab2 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -40,30 +40,41 @@ private: }; /** - * @brief Models the blockchain database. + * @brief Implements the blockchain database. All data this gives is disk-backed. */ class BlockChain { public: BlockChain(); ~BlockChain(); + + /// (Potentiall) renders invalid existing bytesConstRef returned by lastBlock. + /// To be called from main loop every 100ms or so. + void process(); /// Import block into disk-backed DB void import(bytes const& _block); /// Get the last block of the longest chain. - bytesConstRef lastBlock() const { return bytesConstRef(); } + bytesConstRef lastBlock() const; // TODO: switch to return MappedBlock or add the lock into vector_ref /// Get the number of the last block of the longest chain. - u256 lastBlockNumber() const { return Invalid256; } + u256 lastBlockNumber() const; + + bytesConstRef block(u256 _hash) const; private: - // Get fully populated from disk DB. + /// Get fully populated from disk DB. mutable std::map> m_numberAndParent; mutable std::multimap m_children; - // Gets populated on demand and reduced after a while. + /// Gets populated on demand. Inactive nodes are pruned after a while. mutable std::map> m_cache; + + /// Hash of the last (valid) block on the longest chain. + u256 m_lastBlockHash; + u256 m_genesisHash; + bytes m_genesisBlock; }; } diff --git a/libethereum/BlockInfo.cpp b/libethereum/BlockInfo.cpp index e7fec94c4..06eb638ed 100644 --- a/libethereum/BlockInfo.cpp +++ b/libethereum/BlockInfo.cpp @@ -27,11 +27,29 @@ using namespace std; using namespace eth; +BlockInfo* BlockInfo::s_genesis = nullptr; + BlockInfo::BlockInfo() { number = Invalid256; } +bytes BlockInfo::createGenesisBlock() +{ + RLPStream block(3); + auto sha256EmptyList = sha256(RLPEmptyList); + block.appendList(7) << (uint)0 << sha256EmptyList << (uint)0 << sha256EmptyList << (uint)0 << (uint)0 << (uint)0; + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); +} + +void BlockInfo::populateGenesis() +{ + bytes genesisBlock = createGenesisBlock(); + populate(&genesisBlock, 0); +} + void BlockInfo::populate(bytesConstRef _block, u256 _number) { number = _number; @@ -70,5 +88,5 @@ void BlockInfo::verify(bytesConstRef _block, u256 _number) // TODO: check difficulty against timestamp. // TODO: check proof of work. - // TODO: check each transaction - allow any destination for the miner fees, but everything else must be exactly how we would do it. + // TODO: check each transaction - allow coinbaseAddress for the miner fees, but everything else must be exactly how we would do it. } diff --git a/libethereum/BlockInfo.h b/libethereum/BlockInfo.h index 8455114ea..9d54465fc 100644 --- a/libethereum/BlockInfo.h +++ b/libethereum/BlockInfo.h @@ -45,8 +45,16 @@ public: bool operator==(BlockInfo const& _cmp) const { return hash == _cmp.hash && parentHash == _cmp.parentHash && nonce == _cmp.nonce && number == _cmp.number; } + static BlockInfo const& genesis() { if (!s_genesis) (s_genesis = new BlockInfo)->populateGenesis(); return *s_genesis; } void populate(bytesConstRef _block, u256 _number); void verify(bytesConstRef _block, u256 _number); + + static bytes createGenesisBlock(); + +private: + void populateGenesis(); + + static BlockInfo* s_genesis; }; } diff --git a/libethereum/RLP.cpp b/libethereum/RLP.cpp index 7cf0dd41c..bca4e1e1b 100644 --- a/libethereum/RLP.cpp +++ b/libethereum/RLP.cpp @@ -24,6 +24,7 @@ using namespace std; using namespace eth; bytes eth::RLPNull = rlp(""); +bytes eth::RLPEmptyList = rlpList(); RLP::iterator& RLP::iterator::operator++() { @@ -124,6 +125,14 @@ RLPStream& RLPStream::append(std::string const& _s) return *this; } +RLPStream& RLPStream::appendRaw(bytes const& _s) +{ + uint os = m_out.size(); + m_out.resize(os + _s.size()); + memcpy(m_out.data() + os, _s.data(), _s.size()); + return *this; +} + RLPStream& RLPStream::appendList(uint _count) { if (_count < 0x38) diff --git a/libethereum/RLP.h b/libethereum/RLP.h index 891e767d9..23e93824a 100644 --- a/libethereum/RLP.h +++ b/libethereum/RLP.h @@ -277,6 +277,7 @@ public: RLPStream& append(bigint _s); RLPStream& append(std::string const& _s); RLPStream& appendList(uint _count); + RLPStream& appendRaw(bytes const& _rlp); /// Shift operators for appending data items. RLPStream& operator<<(uint _i) { return append(_i); } @@ -334,6 +335,9 @@ template bytes rlpList(_Ts ... _ts) /// The empty string in RLP format. extern bytes RLPNull; +/// The empty list in RLP format. +extern bytes RLPEmptyList; + } /// Human readable version of RLP. diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 8ac0151dc..b464b3c1a 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -41,7 +41,8 @@ u256 const State::c_txFee = 0; State::State(Address _minerAddress): m_minerAddress(_minerAddress) { secp256k1_start(); - // TODO: Initialise current block/previous block, ready for sync. + m_previousBlock = BlockInfo::genesis(); + m_currentBlock.number = 1; } void State::sync(BlockChain const& _bc, TransactionQueue const& _tq) @@ -156,11 +157,15 @@ bool State::verify(bytes const& _block, uint _number) void State::execute(Transaction const& _t, Address _sender) { // Entry point for a contract-originated transaction. - m_transactions.push_back(_t); + // Ignore invalid transactions. if (_t.nonce != transactionsFrom(_sender)) throw InvalidNonce(); + // Add to the transactions in + m_transactions.push_back(_t); + + // Not considered invalid - just pointless. if (balance(_sender) < _t.value + _t.fee) throw NotEnoughCash(); @@ -198,11 +203,14 @@ void State::execute(Transaction const& _t, Address _sender) void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _txFee, u256s const& _txData, u256* _totalFee) { std::vector stack; + + // Find our memory. auto m = m_current.find(_myAddress); if (m == m_current.end()) throw NoSuchContract(); auto& myMemory = m->second.memory(); + // Set up some local functions. auto require = [&](u256 _n) { if (stack.size() < _n)