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