diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index a5401dbbf..886dbd2aa 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -42,12 +42,16 @@ BlockChain::~BlockChain() { } -u256s BlockChain::blockChain() const +u256s BlockChain::blockChain(u256Set const& _earlyExit) const { // TODO: return the current valid block chain from most recent to genesis. // TODO: arguments for specifying a set of early-ends u256s ret; - + ret.reserve(m_numberAndParent[m_lastBlockHash].first + 1); + auto i = m_lastBlockHash; + for (; i != m_genesisHash && !_earlyExit.count(i); i = m_numberAndParent[i].second) + ret.push_back(i); + ret.push_back(i); return ret; } @@ -73,13 +77,9 @@ void BlockChain::import(bytes const& _block) return; bi.number = it->second.first + 1; - // Check Ancestry: - // Check timestamp is after previous timestamp. - if (bi.timestamp <= BlockInfo(block(bi.parentHash)).timestamp) - throw InvalidTimestamp(); - - // TODO: check difficulty is correct given the two timestamps. -// if (bi.timestamp ) + // Check family: + BlockInfo bip(block(bi.parentHash)); + bi.verifyParent(bip); // TODO: check transactions are valid and that they result in a state equivalent to our state_root. // this saves us from an embarrassing exit later. @@ -95,13 +95,14 @@ void BlockChain::import(bytes const& _block) } // Insert into DB - m_numberAndParent[newHash] = make_pair(bi.number, bi.parentHash); + m_numberAndParent[newHash] = make_pair((uint)bi.number, bi.parentHash); m_children.insert(make_pair(bi.parentHash, newHash)); ldb::WriteOptions o; m_db->Put(o, ldb::Slice(toBigEndianString(newHash)), (ldb::Slice)ref(_block)); // This might be the new last block; count back through ancestors to common shared ancestor and compare to current. // TODO: Use GHOST algorithm. + } catch (...) { diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index f85708a44..a0ebb7946 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -51,7 +51,7 @@ public: bytesConstRef lastBlock() const { return block(m_lastBlockHash); } /// Get the full block chain, according to the GHOST algo and the blocks available in the db. - u256s blockChain() const; + u256s blockChain(u256Set const& _earlyExit) const; /// Get the number of the last block of the longest chain. u256 lastBlockNumber() const; @@ -60,7 +60,7 @@ public: private: /// Get fully populated from disk DB. - mutable std::map> m_numberAndParent; + mutable std::map> m_numberAndParent; mutable std::multimap m_children; ldb::DB* m_db; diff --git a/libethereum/BlockInfo.cpp b/libethereum/BlockInfo.cpp index bb3b162b0..ffaac5e75 100644 --- a/libethereum/BlockInfo.cpp +++ b/libethereum/BlockInfo.cpp @@ -84,7 +84,7 @@ void BlockInfo::populate(bytesConstRef _block, u256 _number) } } -void BlockInfo::verifyInternals(bytesConstRef _block) +void BlockInfo::verifyInternals(bytesConstRef _block) const { RLP root(_block); @@ -99,3 +99,32 @@ void BlockInfo::verifyInternals(bytesConstRef _block) if (d.eval(nonce) >= difficulty) throw InvalidNonce(); } + +u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const +{ + /* + D(genesis_block) = 2^36 + D(block) = + if block.timestamp >= block.parent.timestamp + 42: D(block.parent) - floor(D(block.parent) / 1024) + else: D(block.parent) + floor(D(block.parent) / 1024) + */ + if (number == 0) + return (u256)1 << 36; + else + return timestamp >= _parent.timestamp + 42 ? _parent.difficulty - (_parent.difficulty >> 10) : (_parent.difficulty + (_parent.difficulty >> 10)); +} + +void BlockInfo::verifyParent(BlockInfo const& _parent) const +{ + if (number == 0) + // Genesis block - no parent. + return; + + // Check timestamp is after previous timestamp. + if (_parent.timestamp <= _parent.timestamp) + throw InvalidTimestamp(); + + // Check difficulty is correct given the two timestamps. + if (difficulty != calculateDifficulty(_parent)) + throw InvalidDifficulty(); +} diff --git a/libethereum/BlockInfo.h b/libethereum/BlockInfo.h index 96f72be5e..5163b50f9 100644 --- a/libethereum/BlockInfo.h +++ b/libethereum/BlockInfo.h @@ -49,7 +49,10 @@ public: static BlockInfo const& genesis() { if (!s_genesis) (s_genesis = new BlockInfo)->populateGenesis(); return *s_genesis; } void populate(bytesConstRef _block, u256 _number = 0); - void verifyInternals(bytesConstRef _block); + void verifyInternals(bytesConstRef _block) const; + void verifyParent(BlockInfo const& _parent) const; + + u256 calculateDifficulty(BlockInfo const& _bi) const; /// No-nonce sha3 of the header only. u256 headerHashWithoutNonce() const; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 2be0bb6e7..e7a99635b 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -83,7 +83,7 @@ void State::sync(BlockChain const& _bc, TransactionQueue& _tq) // New blocks available, or we've switched to a different branch. All change. // TODO: Find most recent state dump and replay what's left. // (Most recent state dump might end up being genesis.) - std::vector l = _bc.blockChain(); // TODO: take u256Set "restorePoints" argument so it needs only give us the chain up until some restore point in the past where we stored the state. + std::vector l = _bc.blockChain(u256Set()); // TODO: take u256Set "restorePoints" argument so it needs only give us the chain up until some restore point in the past where we stored the state. if (l.back() == BlockInfo::genesis().hash) { @@ -125,6 +125,8 @@ void State::sync(BlockChain const& _bc, TransactionQueue& _tq) } catch (...) { + // Something else went wrong - drop it. + _tq.drop(i.first); } }