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