From 1078681ccb2ad7ed39e7e2c8ecff772c6ec58749 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 24 Aug 2014 16:30:24 +0200 Subject: [PATCH] Better uncle building. Repotting. --- libethcore/BlockInfo.cpp | 5 +++ libethcore/BlockInfo.h | 3 ++ libethereum/AccountDiff.cpp | 77 ++++++++++++++++++++++++++++++++++ libethereum/AccountDiff.h | 73 ++++++++++++++++++++++++++++++++ libethereum/State.cpp | 83 ++++++++----------------------------- libethereum/State.h | 41 +----------------- 6 files changed, 177 insertions(+), 105 deletions(-) create mode 100644 libethereum/AccountDiff.cpp create mode 100644 libethereum/AccountDiff.h diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 4c71353d6..0b56c6c85 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -64,6 +64,11 @@ void BlockInfo::fillStream(RLPStream& _s, bool _nonce) const _s << nonce; } +h256 BlockInfo::headerHash(bytesConstRef _block) +{ + return sha3(RLP(_block)[0].data()); +} + void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce) { int field = 0; diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index ecec391c1..cf9735c7d 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -73,6 +73,9 @@ public: explicit BlockInfo(bytes const& _block): BlockInfo(&_block) {} explicit BlockInfo(bytesConstRef _block); + static h256 headerHash(bytes const& _block) { return headerHash(&_block); } + static h256 headerHash(bytesConstRef _block); + static BlockInfo fromHeader(bytesConstRef _block); explicit operator bool() const { return timestamp != Invalid256; } diff --git a/libethereum/AccountDiff.cpp b/libethereum/AccountDiff.cpp new file mode 100644 index 000000000..5b469508f --- /dev/null +++ b/libethereum/AccountDiff.cpp @@ -0,0 +1,77 @@ +/* + 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 AccountDiff.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "AccountDiff.h" + +#include +using namespace std; +using namespace eth; + +AccountChange AccountDiff::changeType() const +{ + bool bn = (balance || nonce); + bool sc = (!storage.empty() || code); + return exist ? exist.from() ? AccountChange::Deletion : AccountChange::Creation : (bn && sc) ? AccountChange::All : bn ? AccountChange::Intrinsic: sc ? AccountChange::CodeStorage : AccountChange::None; +} + +char const* AccountDiff::lead() const +{ + bool bn = (balance || nonce); + bool sc = (!storage.empty() || code); + return exist ? exist.from() ? "XXX" : "+++" : (bn && sc) ? "***" : bn ? " * " : sc ? "* *" : " "; +} + +std::ostream& eth::operator<<(std::ostream& _out, AccountDiff const& _s) +{ + if (!_s.exist.to()) + return _out; + + if (_s.nonce) + { + _out << std::dec << "#" << _s.nonce.to() << " "; + if (_s.nonce.from()) + _out << "(" << std::showpos << (((bigint)_s.nonce.to()) - ((bigint)_s.nonce.from())) << std::noshowpos << ") "; + } + if (_s.balance) + { + _out << std::dec << _s.balance.to() << " "; + if (_s.balance.from()) + _out << "(" << std::showpos << (((bigint)_s.balance.to()) - ((bigint)_s.balance.from())) << std::noshowpos << ") "; + } + if (_s.code) + _out << "$" << std::hex << nouppercase << _s.code.to() << " (" << _s.code.from() << ") "; + for (pair> const& i: _s.storage) + if (!i.second.from()) + _out << endl << " + " << (h256)i.first << ": " << std::hex << nouppercase << i.second.to(); + else if (!i.second.to()) + _out << endl << "XXX " << (h256)i.first << " (" << std::hex << nouppercase << i.second.from() << ")"; + else + _out << endl << " * " << (h256)i.first << ": " << std::hex << nouppercase << i.second.to() << " (" << i.second.from() << ")"; + return _out; +} + +std::ostream& eth::operator<<(std::ostream& _out, StateDiff const& _s) +{ + _out << _s.accounts.size() << " accounts changed:" << endl; + for (auto const& i: _s.accounts) + _out << i.second.lead() << " " << i.first << ": " << i.second << endl; + return _out; +} diff --git a/libethereum/AccountDiff.h b/libethereum/AccountDiff.h new file mode 100644 index 000000000..a4a074e04 --- /dev/null +++ b/libethereum/AccountDiff.h @@ -0,0 +1,73 @@ +/* + 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 AccountDiff.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include + +namespace eth +{ + +enum class ExistDiff { Same, New, Dead }; +template +class Diff +{ +public: + Diff() {} + Diff(T _from, T _to): m_from(_from), m_to(_to) {} + + T const& from() const { return m_from; } + T const& to() const { return m_to; } + + explicit operator bool() const { return m_from != m_to; } + +private: + T m_from; + T m_to; +}; + +enum class AccountChange { None, Creation, Deletion, Intrinsic, CodeStorage, All }; + +struct AccountDiff +{ + inline bool changed() const { return storage.size() || code || nonce || balance || exist; } + char const* lead() const; + AccountChange changeType() const; + + Diff exist; + Diff balance; + Diff nonce; + std::map> storage; + Diff code; +}; + +struct StateDiff +{ + std::map accounts; +}; + +std::ostream& operator<<(std::ostream& _out, StateDiff const& _s); +std::ostream& operator<<(std::ostream& _out, AccountDiff const& _s); + +} + + diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 7b46228b4..6393e2103 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -567,9 +567,9 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce) if (_bc) { BlockInfo uncleParent(_bc->block(uncle.parentHash)); - if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 6) // TODO: check 6. might be 7 or something... + if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 6) throw UncleTooOld(); - if (knownUncles.count(uncle.hash)) + if (knownUncles.count(sha3(i.data()))) throw UncleInChain(); uncle.verifyParent(uncleParent); } @@ -699,19 +699,23 @@ void State::commitToMine(BlockChain const& _bc) if (m_previousBlock != BlockChain::genesis()) { - // TODO: find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. - // Find uncles if we're not a direct child of the genesis. + // Find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. // cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl; - auto us = _bc.details(m_previousBlock.parentHash).children; - assert(us.size() >= 1); // must be at least 1 child of our grandparent - it's our own parent! - uncles.appendList(us.size() - 1); // one fewer - uncles precludes our parent from the list of grandparent's children. - for (auto const& u: us) - if (u != m_previousBlock.hash) // ignore our own parent - it's not an uncle. - { - BlockInfo ubi(_bc.block(u)); - ubi.fillStream(uncles, true); - uncleAddresses.push_back(ubi.coinbaseAddress); - } + set knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash); + auto p = m_previousBlock.parentHash; + for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash(); ++gen, p = _bc.details(p).parent) + { + auto us = _bc.details(p).children; + assert(us.size() >= 1); // must be at least 1 child of our grandparent - it's our own parent! + uncles.appendList(us.size() - 1); // one fewer - uncles precludes our parent from the list of grandparent's children. + for (auto const& u: us) + if (!knownUncles.count(BlockInfo::headerHash(_bc.block(u)))) // ignore any uncles/mainline blocks that we know about. We use header-hash for this. + { + BlockInfo ubi(_bc.block(u)); + ubi.fillStream(uncles, true); + uncleAddresses.push_back(ubi.coinbaseAddress); + } + } } else uncles.appendList(0); @@ -1268,54 +1272,3 @@ std::ostream& eth::operator<<(std::ostream& _out, State const& _s) } return _out; } - -AccountChange AccountDiff::changeType() const -{ - bool bn = (balance || nonce); - bool sc = (!storage.empty() || code); - return exist ? exist.from() ? AccountChange::Deletion : AccountChange::Creation : (bn && sc) ? AccountChange::All : bn ? AccountChange::Intrinsic: sc ? AccountChange::CodeStorage : AccountChange::None; -} - -char const* AccountDiff::lead() const -{ - bool bn = (balance || nonce); - bool sc = (!storage.empty() || code); - return exist ? exist.from() ? "XXX" : "+++" : (bn && sc) ? "***" : bn ? " * " : sc ? "* *" : " "; -} - -std::ostream& eth::operator<<(std::ostream& _out, AccountDiff const& _s) -{ - if (!_s.exist.to()) - return _out; - - if (_s.nonce) - { - _out << std::dec << "#" << _s.nonce.to() << " "; - if (_s.nonce.from()) - _out << "(" << std::showpos << (((bigint)_s.nonce.to()) - ((bigint)_s.nonce.from())) << std::noshowpos << ") "; - } - if (_s.balance) - { - _out << std::dec << _s.balance.to() << " "; - if (_s.balance.from()) - _out << "(" << std::showpos << (((bigint)_s.balance.to()) - ((bigint)_s.balance.from())) << std::noshowpos << ") "; - } - if (_s.code) - _out << "$" << std::hex << nouppercase << _s.code.to() << " (" << _s.code.from() << ") "; - for (pair> const& i: _s.storage) - if (!i.second.from()) - _out << endl << " + " << (h256)i.first << ": " << std::hex << nouppercase << i.second.to(); - else if (!i.second.to()) - _out << endl << "XXX " << (h256)i.first << " (" << std::hex << nouppercase << i.second.from() << ")"; - else - _out << endl << " * " << (h256)i.first << ": " << std::hex << nouppercase << i.second.to() << " (" << i.second.from() << ")"; - return _out; -} - -std::ostream& eth::operator<<(std::ostream& _out, StateDiff const& _s) -{ - _out << _s.accounts.size() << " accounts changed:" << endl; - for (auto const& i: _s.accounts) - _out << i.second.lead() << " " << i.first << ": " << i.second << endl; - return _out; -} diff --git a/libethereum/State.h b/libethereum/State.h index c605ce42e..879e5e741 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -36,6 +36,7 @@ #include "AddressState.h" #include "Transaction.h" #include "Executive.h" +#include "AccountDiff.h" namespace eth { @@ -64,44 +65,6 @@ struct TransactionReceipt Manifest changes; }; -enum class ExistDiff { Same, New, Dead }; -template -class Diff -{ -public: - Diff() {} - Diff(T _from, T _to): m_from(_from), m_to(_to) {} - - T const& from() const { return m_from; } - T const& to() const { return m_to; } - - explicit operator bool() const { return m_from != m_to; } - -private: - T m_from; - T m_to; -}; - -enum class AccountChange { None, Creation, Deletion, Intrinsic, CodeStorage, All }; - -struct AccountDiff -{ - inline bool changed() const { return storage.size() || code || nonce || balance || exist; } - char const* lead() const; - AccountChange changeType() const; - - Diff exist; - Diff balance; - Diff nonce; - std::map> storage; - Diff code; -}; - -struct StateDiff -{ - std::map accounts; -}; - /** * @brief Model of the current state of the ledger. * Maintains current ledger (m_current) as a fast hash-map. This is hashed only when required (i.e. to create or verify a block). @@ -355,8 +318,6 @@ private: }; std::ostream& operator<<(std::ostream& _out, State const& _s); -std::ostream& operator<<(std::ostream& _out, StateDiff const& _s); -std::ostream& operator<<(std::ostream& _out, AccountDiff const& _s); template void commit(std::map const& _cache, DB& _db, TrieDB& _state)