diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index db1c9c636..8c0e5518e 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -29,7 +29,7 @@ using namespace eth; //#define ETH_ADDRESS_DEBUG 1 -const unsigned eth::c_protocolVersion = 28; +const unsigned eth::c_protocolVersion = 29; const unsigned eth::c_databaseVersion = 1; static const vector> g_units = diff --git a/libethential/Common.cpp b/libethential/Common.cpp index c64d3cb97..a12dfb903 100644 --- a/libethential/Common.cpp +++ b/libethential/Common.cpp @@ -27,6 +27,6 @@ using namespace eth; namespace eth { -char const* EthVersion = "0.6.6"; +char const* EthVersion = "0.6.7"; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index d345271a9..6a44c8d27 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -165,6 +165,16 @@ bool contains(T const& _t, V const& _v) return false; } +inline string toString(h256s const& _bs) +{ + ostringstream out; + out << "[ "; + for (auto i: _bs) + out << i.abridged() << ", "; + out << "]"; + return out.str(); +} + h256s BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max) { vector blocks; @@ -320,20 +330,18 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db) m_lastBlockHash = newHash; } m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&newHash, 32)); - clog(BlockChainNote) << " Imported and best. Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:"; - for (auto r: ret) - clog(BlockChainNote) << r.abridged(); + clog(BlockChainNote) << " Imported and best" << td << ". Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << toString(ret); } else { - clog(BlockChainNote) << " Imported but not best (oTD:" << details(last).totalDifficulty << ", TD:" << td << ")"; + clog(BlockChainNote) << " Imported but not best (oTD:" << details(last).totalDifficulty << " > TD:" << td << ")"; } return ret; } h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, bool _post) const { - cdebug << "treeRoute" << _from.abridged() << "..." << _to.abridged(); +// cdebug << "treeRoute" << _from.abridged() << "..." << _to.abridged(); if (!_from || !_to) { return h256s(); @@ -342,14 +350,14 @@ h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, boo h256s back; unsigned fn = details(_from).number; unsigned tn = details(_to).number; - cdebug << "treeRoute" << fn << "..." << tn; +// cdebug << "treeRoute" << fn << "..." << tn; while (fn > tn) { if (_pre) ret.push_back(_from); _from = details(_from).parent; fn--; - cdebug << "from:" << fn << _from.abridged(); +// cdebug << "from:" << fn << _from.abridged(); } while (fn < tn) { @@ -357,7 +365,7 @@ h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, boo back.push_back(_to); _to = details(_to).parent; tn--; - cdebug << "to:" << tn << _to.abridged(); +// cdebug << "to:" << tn << _to.abridged(); } while (_from != _to) { @@ -371,7 +379,7 @@ h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, boo back.push_back(_to); fn--; tn--; - cdebug << "from:" << fn << _from.abridged() << "; to:" << tn << _to.abridged(); +// cdebug << "from:" << fn << _from.abridged() << "; to:" << tn << _to.abridged(); } if (o_common) *o_common = _from; diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index beb7a6fbd..5f41e67f2 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -367,22 +367,27 @@ void EthereumHost::connect(bi::tcp::endpoint const& _ep) }); } -h256Set EthereumHost::neededBlocks() +h256Set EthereumHost::neededBlocks(h256Set const& _exclude) { Guard l(x_blocksNeeded); h256Set ret; if (m_blocksNeeded.size()) { - while (ret.size() < c_maxBlocksAsk && m_blocksNeeded.size()) - { - ret.insert(m_blocksNeeded.back()); - m_blocksOnWay.insert(m_blocksNeeded.back()); - m_blocksNeeded.pop_back(); - } + int s = m_blocksNeeded.size() - 1; + for (; ret.size() < c_maxBlocksAsk && s < m_blocksNeeded.size(); --s) + if (!_exclude.count(m_blocksNeeded[s])) + { + auto it = m_blocksNeeded.begin() + s; + ret.insert(*it); + m_blocksOnWay.insert(*it); + m_blocksNeeded.erase(it); + } } else - for (auto i = m_blocksOnWay.begin(); ret.size() < c_maxBlocksAsk && i != m_blocksOnWay.end(); ++i) + for (auto i = m_blocksOnWay.begin(); ret.size() < c_maxBlocksAsk && i != m_blocksOnWay.end() && !_exclude.count(*i); ++i) ret.insert(*i); + + clog(NetMessageSummary) << "Asking for" << ret.size() << "blocks that we don't yet have." << m_blocksNeeded.size() << "blocks still needed," << m_blocksOnWay.size() << "blocks on way."; return ret; } @@ -574,7 +579,7 @@ void EthereumHost::noteHaveChain(std::shared_ptr const& _from) if (_from->m_neededBlocks.empty()) return; - clog(NetNote) << "Hash-chain COMPLETE:" << log2((double)_from->m_totalDifficulty) << "vs" << log2((double)m_chain->details().totalDifficulty) << "," << log2((double)m_totalDifficultyOfNeeded) << ";" << _from->m_neededBlocks.size() << " blocks, ends" << _from->m_neededBlocks.back().abridged(); + clog(NetNote) << "Hash-chain COMPLETE:" << _from->m_totalDifficulty << "vs" << m_chain->details().totalDifficulty << "," << m_totalDifficultyOfNeeded << ";" << _from->m_neededBlocks.size() << " blocks, ends" << _from->m_neededBlocks.back().abridged(); if ((m_totalDifficultyOfNeeded && td < m_totalDifficultyOfNeeded) || td < m_chain->details().totalDifficulty) { @@ -596,7 +601,7 @@ void EthereumHost::noteHaveChain(std::shared_ptr const& _from) Guard l(x_peers); for (auto const& i: m_peers) if (shared_ptr p = i.second.lock()) - p->ensureGettingChain(); + p->restartGettingChain(); } } diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h index bbe0d8b86..9487e40f6 100644 --- a/libethereum/EthereumHost.h +++ b/libethereum/EthereumHost.h @@ -129,7 +129,7 @@ private: /// Get a bunch of needed blocks. /// Removes them from our list of needed blocks. /// @returns empty if there's no more blocks left to fetch, otherwise the blocks to fetch. - h256Set neededBlocks(); + h256Set neededBlocks(h256Set const& _exclude); /// Check to see if the network peer-state initialisation has happened. virtual bool isInitialised() const { return m_latestBlockSent; } diff --git a/libethereum/EthereumSession.cpp b/libethereum/EthereumSession.cpp index fd0002967..db25441e5 100644 --- a/libethereum/EthereumSession.cpp +++ b/libethereum/EthereumSession.cpp @@ -56,7 +56,7 @@ EthereumSession::~EthereumSession() catch (...){} } -string toString(h256s const& _bs) +inline string toString(h256s const& _bs) { ostringstream out; out << "[ "; @@ -75,6 +75,7 @@ void EthereumSession::giveUpOnFetch() m_server->m_blocksNeeded.reserve(m_server->m_blocksNeeded.size() + m_askedBlocks.size()); for (auto i: m_askedBlocks) { + m_failedBlocks.insert(i); m_server->m_blocksOnWay.erase(i); m_server->m_blocksNeeded.push_back(i); } @@ -109,8 +110,9 @@ bool EthereumSession::interpret(RLP const& _r) m_id = _r[6].toHash(); m_totalDifficulty = _r[7].toInt(); m_latestHash = _r[8].toHash(); + auto genesisHash = _r[9].toHash(); - clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "/" << m_networkId << "]" << m_id.abridged() << showbase << hex << m_caps << dec << m_listenPort; + clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "/" << m_networkId << "/" << genesisHash.abridged() << "]" << m_id.abridged() << showbase << hex << m_caps << dec << m_listenPort; if (m_server->havePeer(m_id)) { @@ -120,6 +122,12 @@ bool EthereumSession::interpret(RLP const& _r) return false; } + if (genesisHash != m_server->m_chain->genesisHash()) + { + disconnect(WrongGenesis); + return false; + } + if (m_protocolVersion != EthereumHost::protocolVersion() || m_networkId != m_server->networkId() || !m_id) { disconnect(IncompatibleProtocol); @@ -301,12 +309,12 @@ bool EthereumSession::interpret(RLP const& _r) break; clogS(NetMessageSummary) << "Blocks (" << dec << (_r.itemCount() - 1) << " entries)"; - if (_r.itemCount() == 1) + if (_r.itemCount() == 1 && !m_askedBlocksChanged) { // Couldn't get any from last batch - probably got to this peer's latest block - just give up. giveUpOnFetch(); - break; } + m_askedBlocksChanged = false; unsigned used = 0; for (unsigned i = 1; i < _r.itemCount(); ++i) @@ -339,7 +347,7 @@ bool EthereumSession::interpret(RLP const& _r) } } clogS(NetMessageSummary) << dec << knownParents << " known parents, " << unknownParents << "unknown, " << used << "used."; - ensureGettingChain(); + continueGettingChain(); break; } case GetTransactionsPacket: @@ -355,10 +363,30 @@ bool EthereumSession::interpret(RLP const& _r) return true; } +void EthereumSession::restartGettingChain() +{ + if (m_askedBlocks.size()) + { + m_askedBlocksChanged = true; // So that we continue even if the Ask's reply is empty. + m_askedBlocks.clear(); // So that we restart once we get the Ask's reply. + m_failedBlocks.clear(); + } + else + ensureGettingChain(); +} + void EthereumSession::ensureGettingChain() +{ + if (m_askedBlocks.size()) + return; // Already asked & waiting for some. + + continueGettingChain(); +} + +void EthereumSession::continueGettingChain() { if (!m_askedBlocks.size()) - m_askedBlocks = m_server->neededBlocks(); + m_askedBlocks = m_server->neededBlocks(m_failedBlocks); if (m_askedBlocks.size()) { @@ -370,7 +398,7 @@ void EthereumSession::ensureGettingChain() sealAndSend(s); } else - clogS(NetMessageSummary) << "No blocks left to get."; + clogS(NetMessageSummary) << "No blocks left to get. Peer doesn't seem to have " << m_failedBlocks.size() << "of our needed blocks."; } void EthereumSession::ping() @@ -513,7 +541,7 @@ void EthereumSession::start() { RLPStream s; prep(s); - s.appendList(9) << HelloPacket + s.appendList(10) << HelloPacket << (uint)EthereumHost::protocolVersion() << m_server->networkId() << m_server->m_clientVersion @@ -521,7 +549,8 @@ void EthereumSession::start() << m_server->m_public.port() << m_server->m_key.pub() << m_server->m_chain->details().totalDifficulty - << m_server->m_chain->currentHash(); + << m_server->m_chain->currentHash() + << m_server->m_chain->genesisHash(); sealAndSend(s); ping(); getPeers(); diff --git a/libethereum/EthereumSession.h b/libethereum/EthereumSession.h index ca44179c6..2a7e31155 100644 --- a/libethereum/EthereumSession.h +++ b/libethereum/EthereumSession.h @@ -60,6 +60,10 @@ private: /// Ensure that we are waiting for a bunch of blocks from our peer. void ensureGettingChain(); + /// Ensure that we are waiting for a bunch of blocks from our peer. + void continueGettingChain(); + /// Now getting a different chain so we need to make sure we restart. + void restartGettingChain(); void giveUpOnFetch(); @@ -97,8 +101,10 @@ private: h256 m_latestHash; ///< Peer's latest block's hash. u256 m_totalDifficulty; ///< Peer's latest block's total difficulty. h256s m_neededBlocks; ///< The blocks that we should download from this peer. + h256Set m_failedBlocks; ///< Blocks that the peer doesn't seem to have. h256Set m_askedBlocks; ///< The blocks for which we sent the last GetBlocks for but haven't received a corresponding Blocks. + bool m_askedBlocksChanged = true; std::chrono::steady_clock::time_point m_ping; std::chrono::steady_clock::time_point m_connect; diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 9968683fe..ef89971c5 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -27,7 +27,7 @@ using namespace std; using namespace eth; -#define ETH_ADDRESS_DEBUG 1 +#define ETH_ADDRESS_DEBUG 0 Transaction::Transaction(bytesConstRef _rlpData, bool _checkSender) {