1 // Aleth: Ethereum C++ client, tools and libraries. 2 // Copyright 2015-2019 Aleth Authors. 3 // Licensed under the GNU General Public License, Version 3. 4 5 #pragma once 6 7 #include <mutex> 8 #include <unordered_map> 9 10 #include <libdevcore/Guards.h> 11 #include <libethcore/Common.h> 12 #include <libethcore/BlockHeader.h> 13 #include <libp2p/Common.h> 14 #include "CommonNet.h" 15 16 namespace dev 17 { 18 19 class RLPStream; 20 21 namespace eth 22 { 23 class EthereumCapability; 24 class BlockQueue; 25 class EthereumPeer; 26 27 /** 28 * @brief Base BlockChain synchronization strategy class. 29 * Syncs to peers and keeps up to date. Base class handles blocks downloading but does not contain any details on state transfer logic. 30 */ 31 class BlockChainSync final: public HasInvariants 32 { 33 public: 34 explicit BlockChainSync(EthereumCapability& _host); 35 ~BlockChainSync(); 36 void abortSync(); ///< Abort all sync activity 37 38 /// @returns true is Sync is in progress 39 bool isSyncing() const; 40 41 /// Restart sync 42 void restartSync(); 43 44 /// Called after all blocks have been downloaded 45 /// Public only for test mode 46 void completeSync(); 47 48 /// Called by peer to report status 49 void onPeerStatus(EthereumPeer const& _peer); 50 51 /// Called by peer once it has new block headers during sync 52 void onPeerBlockHeaders(NodeID const& _peerID, RLP const& _r); 53 54 /// Called by peer once it has new block bodies 55 void onPeerBlockBodies(NodeID const& _peerID, RLP const& _r); 56 57 /// Called by peer once it has new block bodies 58 void onPeerNewBlock(NodeID const& _peerID, RLP const& _r); 59 60 void onPeerNewHashes(NodeID const& _peerID, std::vector<std::pair<h256, u256>> const& _hashes); 61 62 /// Called by peer when it is disconnecting 63 void onPeerAborting(); 64 65 /// Called when a blockchain has imported a new block onto the DB 66 void onBlockImported(BlockHeader const& _info); 67 68 /// @returns Synchonization status 69 SyncStatus status() const; 70 stateName(SyncState _s)71 static char const* stateName(SyncState _s) { return s_stateNames[static_cast<int>(_s)]; } 72 73 private: 74 /// Resume downloading after witing state 75 void continueSync(); 76 77 /// Enter waiting state pauseSync()78 void pauseSync() { m_state = SyncState::Waiting; } isSyncPaused()79 bool isSyncPaused() { return m_state == SyncState::Waiting; } 80 host()81 EthereumCapability& host() { return m_host; } host()82 EthereumCapability const& host() const { return m_host; } 83 84 void resetSync(); 85 void syncPeer(NodeID const& _peerID, bool _force); 86 void requestBlocks(NodeID const& _peerID); 87 void clearPeerDownload(NodeID const& _peerID); 88 void clearPeerDownload(); 89 void collectBlocks(); 90 bool requestDaoForkBlockHeader(NodeID const& _peerID); 91 bool verifyDaoChallengeResponse(RLP const& _r); 92 void logImported(unsigned _success, unsigned _future, unsigned _got, unsigned _unknown); 93 94 private: 95 struct Header 96 { 97 bytes data; ///< Header data 98 h256 hash; ///< Block hash 99 h256 parent; ///< Parent hash 100 }; 101 102 /// Used to identify header by transactions and uncles hashes 103 struct HeaderId 104 { 105 h256 transactionsRoot; 106 h256 uncles; 107 108 bool operator==(HeaderId const& _other) const 109 { 110 return transactionsRoot == _other.transactionsRoot && uncles == _other.uncles; 111 } 112 }; 113 114 struct HeaderIdHash 115 { operatorHeaderIdHash116 std::size_t operator()(const HeaderId& _k) const 117 { 118 size_t seed = 0; 119 h256::hash hasher; 120 boost::hash_combine(seed, hasher(_k.transactionsRoot)); 121 boost::hash_combine(seed, hasher(_k.uncles)); 122 return seed; 123 } 124 }; 125 126 EthereumCapability& m_host; 127 128 // Triggered once blocks have been drained from the block queue, potentially freeing up space 129 // for more blocks. Note that the block queue can still be full after a drain, depending on how 130 // many blocks are in the queue vs how many are being drained. 131 Handler<> m_bqBlocksDrained; 132 133 mutable RecursiveMutex x_sync; 134 /// Peers to which we've sent DAO request 135 std::set<NodeID> m_daoChallengedPeers; 136 std::atomic<SyncState> m_state{SyncState::Idle}; ///< Current sync state 137 h256Hash m_knownNewHashes; ///< New hashes we know about use for logging only 138 unsigned m_chainStartBlock = 0; 139 unsigned m_startingBlock = 0; ///< Last block number for the start of sync 140 unsigned m_highestBlock = 0; ///< Highest block number seen 141 std::unordered_set<unsigned> m_downloadingHeaders; ///< Set of block body numbers being downloaded 142 std::unordered_set<unsigned> m_downloadingBodies; ///< Set of block header numbers being downloaded 143 std::map<unsigned, std::vector<Header>> m_headers; ///< Downloaded headers 144 std::map<unsigned, std::vector<bytes>> m_bodies; ///< Downloaded block bodies 145 /// Peers to m_downloadingHeaders number map 146 std::map<NodeID, std::vector<unsigned>> m_headerSyncPeers; 147 /// Peers to m_downloadingBodies number map 148 std::map<NodeID, std::vector<unsigned>> m_bodySyncPeers; 149 std::unordered_map<HeaderId, unsigned, HeaderIdHash> m_headerIdToNumber; 150 bool m_haveCommonHeader = false; ///< True if common block for our and remote chain has been found 151 unsigned m_lastImportedBlock = 0; ///< Last imported block number 152 h256 m_lastImportedBlockHash; ///< Last imported block hash 153 u256 m_syncingTotalDifficulty; ///< Highest peer difficulty 154 155 Logger m_logger{createLogger(VerbosityDebug, "sync")}; 156 Logger m_loggerInfo{createLogger(VerbosityInfo, "sync")}; 157 Logger m_loggerDetail{createLogger(VerbosityTrace, "sync")}; 158 Logger m_loggerWarning{createLogger(VerbosityWarning, "sync")}; 159 160 private: 161 static char const* const s_stateNames[static_cast<int>(SyncState::Size)]; 162 bool invariants() const override; 163 void logNewBlock(h256 const& _h); 164 }; 165 166 std::ostream& operator<<(std::ostream& _out, SyncStatus const& _sync); 167 168 } 169 } 170