]>
Commit | Line | Data |
---|---|---|
0a61b0df | 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
f914f1a7 | 2 | // Copyright (c) 2009-2014 The Bitcoin Core developers |
c5b390b6 | 3 | // Distributed under the MIT software license, see the accompanying |
3a25a2b9 F |
4 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
5 | ||
51ed9ec9 | 6 | #include "main.h" |
319b1160 | 7 | |
320f2cc7 SB |
8 | #include "sodium.h" |
9 | ||
51ed9ec9 | 10 | #include "addrman.h" |
f35c6c4f | 11 | #include "alert.h" |
26c16d9d | 12 | #include "arith_uint256.h" |
319b1160 | 13 | #include "chainparams.h" |
eb5fff9e | 14 | #include "checkpoints.h" |
319b1160 | 15 | #include "checkqueue.h" |
9e851450 | 16 | #include "consensus/upgrades.h" |
da29ecbc | 17 | #include "consensus/validation.h" |
5b3bc971 | 18 | #include "deprecation.h" |
edd309e5 | 19 | #include "init.h" |
afd4b94b | 20 | #include "merkleblock.h" |
a6df7ab5 | 21 | #include "metrics.h" |
319b1160 | 22 | #include "net.h" |
df852d2b | 23 | #include "pow.h" |
319b1160 GA |
24 | #include "txdb.h" |
25 | #include "txmempool.h" | |
ed6d0b5f | 26 | #include "ui_interface.h" |
937ba572 | 27 | #include "undo.h" |
51ed9ec9 | 28 | #include "util.h" |
217a5c92 | 29 | #include "utilmoneystr.h" |
26c16d9d | 30 | #include "validationinterface.h" |
9ddb6ad0 | 31 | #include "wallet/asyncrpcoperation_sendmany.h" |
06c19063 | 32 | #include "wallet/asyncrpcoperation_shieldcoinbase.h" |
51ed9ec9 | 33 | |
358ce266 | 34 | #include <sstream> |
51ed9ec9 BD |
35 | |
36 | #include <boost/algorithm/string/replace.hpp> | |
37 | #include <boost/filesystem.hpp> | |
38 | #include <boost/filesystem/fstream.hpp> | |
36cba8f1 | 39 | #include <boost/math/distributions/poisson.hpp> |
ad49c256 | 40 | #include <boost/thread.hpp> |
7c68cc07 | 41 | #include <boost/static_assert.hpp> |
0a61b0df | 42 | |
4dc5eb05 | 43 | using namespace std; |
0a61b0df | 44 | |
9b59e3bd | 45 | #if defined(NDEBUG) |
7662d72b | 46 | # error "Zcash cannot be compiled without assertions." |
9b59e3bd GM |
47 | #endif |
48 | ||
d27afb07 | 49 | |
c5b390b6 MF |
50 | /** |
51 | * Global state | |
52 | */ | |
0a61b0df | 53 | |
54 | CCriticalSection cs_main; | |
8dcf7f94 | 55 | extern uint8_t NOTARY_PUBKEY33[33]; |
6477ad07 | 56 | extern int32_t KOMODO_LOADINGBLOCKS,KOMODO_LONGESTCHAIN; |
03e2210d | 57 | int32_t KOMODO_NEWBLOCKS; |
9464ac21 | 58 | int32_t komodo_block2pubkey33(uint8_t *pubkey33,CBlock *block); |
0a61b0df | 59 | |
145d5be8 | 60 | BlockMap mapBlockIndex; |
4c6d41b8 | 61 | CChain chainActive; |
ad6e6017 | 62 | CBlockIndex *pindexBestHeader = NULL; |
51ed9ec9 | 63 | int64_t nTimeBestReceived = 0; |
ff6a7af1 LD |
64 | CWaitableCriticalSection csBestBlock; |
65 | CConditionVariable cvBlockChange; | |
f9cae832 | 66 | int nScriptCheckThreads = 0; |
1f015f6a | 67 | bool fExperimentalMode = false; |
66b02c93 | 68 | bool fImporting = false; |
7fea4846 | 69 | bool fReindex = false; |
2d1fa42e | 70 | bool fTxIndex = false; |
8b78a819 T |
71 | bool fAddressIndex = false; |
72 | bool fTimestampIndex = false; | |
73 | bool fSpentIndex = false; | |
f9ec3f0f | 74 | bool fHavePruned = false; |
75 | bool fPruneMode = false; | |
3da434a2 | 76 | bool fIsBareMultisigStd = true; |
3fcfbc8a | 77 | bool fCheckBlockIndex = false; |
a8cdaf5c | 78 | bool fCheckpointsEnabled = true; |
d212ba32 | 79 | bool fCoinbaseEnforcedProtectionEnabled = true; |
fc684ad8 | 80 | size_t nCoinCacheUsage = 5000 * 300; |
f9ec3f0f | 81 | uint64_t nPruneTarget = 0; |
4d9c7fe6 | 82 | bool fAlerts = DEFAULT_ALERTS; |
0a61b0df | 83 | |
9bb37bf0 JG |
84 | unsigned int expiryDelta = DEFAULT_TX_EXPIRY_DELTA; |
85 | ||
037b4f14 | 86 | /** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */ |
ba0625f2 | 87 | CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); |
13fc83c7 GA |
88 | |
89 | CTxMemPool mempool(::minRelayTxFee); | |
000dc551 | 90 | |
c74332c6 GA |
91 | struct COrphanTx { |
92 | CTransaction tx; | |
93 | NodeId fromPeer; | |
94 | }; | |
72b25b0f CF |
95 | map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(cs_main);; |
96 | map<uint256, set<uint256> > mapOrphanTransactionsByPrev GUARDED_BY(cs_main);; | |
97 | void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |
0a61b0df | 98 | |
9dcd524f PW |
99 | /** |
100 | * Returns true if there are nRequired or more blocks of minVersion or above | |
51aa2492 | 101 | * in the last Consensus::Params::nMajorityWindow blocks, starting at pstart and going backwards. |
9dcd524f | 102 | */ |
51aa2492 | 103 | static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams); |
3fcfbc8a | 104 | static void CheckBlockIndex(); |
9dcd524f | 105 | |
c5b390b6 | 106 | /** Constant stuff for coinbase transactions we create: */ |
7bf8b7c2 | 107 | CScript COINBASE_FLAGS; |
0a61b0df | 108 | |
1a321777 | 109 | const string strMessageMagic = "Komodo Signed Message:\n"; |
2bc4fd60 | 110 | |
caca6aa4 PW |
111 | // Internal stuff |
112 | namespace { | |
8d655683 | 113 | |
6b29ccc9 B |
114 | struct CBlockIndexWorkComparator |
115 | { | |
3fcfbc8a | 116 | bool operator()(CBlockIndex *pa, CBlockIndex *pb) const { |
6b29ccc9 B |
117 | // First sort by most total work, ... |
118 | if (pa->nChainWork > pb->nChainWork) return false; | |
119 | if (pa->nChainWork < pb->nChainWork) return true; | |
8d655683 | 120 | |
6b29ccc9 B |
121 | // ... then by earliest time received, ... |
122 | if (pa->nSequenceId < pb->nSequenceId) return false; | |
123 | if (pa->nSequenceId > pb->nSequenceId) return true; | |
8d655683 | 124 | |
6b29ccc9 B |
125 | // Use pointer address as tie breaker (should only happen with blocks |
126 | // loaded from disk, as those all have id 0). | |
127 | if (pa < pb) return false; | |
128 | if (pa > pb) return true; | |
8d655683 | 129 | |
6b29ccc9 B |
130 | // Identical blocks. |
131 | return false; | |
132 | } | |
133 | }; | |
8d655683 | 134 | |
6b29ccc9 | 135 | CBlockIndex *pindexBestInvalid; |
8d655683 | 136 | |
c5b390b6 | 137 | /** |
3fcfbc8a | 138 | * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and |
f9ec3f0f | 139 | * as good as our current tip or better. Entries may be failed, though, and pruning nodes may be |
140 | * missing the data for the block. | |
c5b390b6 | 141 | */ |
e17bd583 | 142 | set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates; |
c5b390b6 | 143 | /** Number of nodes with fSyncStarted. */ |
341735eb | 144 | int nSyncStarted = 0; |
f9ec3f0f | 145 | /** All pairs A->B, where A (or one if its ancestors) misses transactions, but B has transactions. |
8d655683 | 146 | * Pruned nodes may have entries where B is missing data. |
147 | */ | |
341735eb | 148 | multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked; |
8d655683 | 149 | |
6b29ccc9 | 150 | CCriticalSection cs_LastBlockFile; |
ed6d1a2c | 151 | std::vector<CBlockFileInfo> vinfoBlockFile; |
6b29ccc9 | 152 | int nLastBlockFile = 0; |
f9ec3f0f | 153 | /** Global flag to indicate we should check to see if there are |
154 | * block/undo files that should be deleted. Set on startup | |
155 | * or if we allocate more file space when we're in prune mode | |
156 | */ | |
157 | bool fCheckForPruning = false; | |
8d655683 | 158 | |
c5b390b6 MF |
159 | /** |
160 | * Every received block is assigned a unique and increasing identifier, so we | |
161 | * know which one to give priority in case of a fork. | |
162 | */ | |
6b29ccc9 | 163 | CCriticalSection cs_nBlockSequenceId; |
c5b390b6 | 164 | /** Blocks loaded from disk are assigned id 0, so start the counter at 1. */ |
6b29ccc9 | 165 | uint32_t nBlockSequenceId = 1; |
8d655683 | 166 | |
c5b390b6 | 167 | /** |
b05a89b2 LD |
168 | * Sources of received blocks, saved to be able to send them reject |
169 | * messages or ban them when processing happens afterwards. Protected by | |
170 | * cs_main. | |
c5b390b6 | 171 | */ |
6b29ccc9 | 172 | map<uint256, NodeId> mapBlockSource; |
8d655683 | 173 | |
ec9b6c33 PT |
174 | /** |
175 | * Filter for transactions that were recently rejected by | |
176 | * AcceptToMemoryPool. These are not rerequested until the chain tip | |
177 | * changes, at which point the entire filter is reset. Protected by | |
178 | * cs_main. | |
179 | * | |
180 | * Without this filter we'd be re-requesting txs from each of our peers, | |
181 | * increasing bandwidth consumption considerably. For instance, with 100 | |
182 | * peers, half of which relay a tx we don't accept, that might be a 50x | |
183 | * bandwidth increase. A flooding attacker attempting to roll-over the | |
184 | * filter using minimum-sized, 60byte, transactions might manage to send | |
185 | * 1000/sec if we have fast peers, so we pick 120,000 to give our peers a | |
186 | * two minute window to send invs to us. | |
187 | * | |
188 | * Decreasing the false positive rate is fairly cheap, so we pick one in a | |
189 | * million to make it highly unlikely for users to have issues with this | |
190 | * filter. | |
191 | * | |
192 | * Memory used: 1.7MB | |
193 | */ | |
194 | boost::scoped_ptr<CRollingBloomFilter> recentRejects; | |
195 | uint256 hashRecentRejectsChainTip; | |
8d655683 | 196 | |
c5b390b6 | 197 | /** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */ |
6b29ccc9 B |
198 | struct QueuedBlock { |
199 | uint256 hash; | |
c5b390b6 MF |
200 | CBlockIndex *pindex; //! Optional. |
201 | int64_t nTime; //! Time of "getdata" request in microseconds. | |
91613034 | 202 | bool fValidatedHeaders; //! Whether this block has validated headers at the time of request. |
8ba7f842 | 203 | int64_t nTimeDisconnect; //! The timeout for this block request (for disconnecting a slow peer) |
6b29ccc9 B |
204 | }; |
205 | map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight; | |
8d655683 | 206 | |
91613034 PW |
207 | /** Number of blocks in flight with validated headers. */ |
208 | int nQueuedValidatedHeaders = 0; | |
8d655683 | 209 | |
c5b390b6 | 210 | /** Number of preferable block download peers. */ |
b4ee0bdd | 211 | int nPreferredDownload = 0; |
8d655683 | 212 | |
c5b390b6 | 213 | /** Dirty block index entries. */ |
51ce901a | 214 | set<CBlockIndex*> setDirtyBlockIndex; |
8d655683 | 215 | |
c5b390b6 | 216 | /** Dirty block file entries. */ |
51ce901a | 217 | set<int> setDirtyFileInfo; |
e10dcf27 | 218 | } // anon namespace |
0a61b0df | 219 | |
501da250 EL |
220 | ////////////////////////////////////////////////////////////////////////////// |
221 | // | |
222 | // Registration of network node signals. | |
223 | // | |
224 | ||
b2864d2f | 225 | namespace { |
8d655683 | 226 | |
227 | struct CBlockReject { | |
228 | unsigned char chRejectCode; | |
229 | string strRejectReason; | |
230 | uint256 hashBlock; | |
231 | }; | |
232 | ||
233 | /** | |
234 | * Maintain validation-specific state about nodes, protected by cs_main, instead | |
235 | * by CNode's own locks. This simplifies asynchronous operation, where | |
236 | * processing of incoming data is done after the ProcessMessage call returns, | |
237 | * and we're no longer holding the node's locks. | |
238 | */ | |
239 | struct CNodeState { | |
240 | //! The peer's address | |
241 | CService address; | |
242 | //! Whether we have a fully established connection. | |
243 | bool fCurrentlyConnected; | |
244 | //! Accumulated misbehaviour score for this peer. | |
245 | int nMisbehavior; | |
246 | //! Whether this peer should be disconnected and banned (unless whitelisted). | |
247 | bool fShouldBan; | |
248 | //! String name of this peer (debugging/logging purposes). | |
249 | std::string name; | |
250 | //! List of asynchronously-determined block rejections to notify this peer about. | |
251 | std::vector<CBlockReject> rejects; | |
252 | //! The best known block we know this peer has announced. | |
253 | CBlockIndex *pindexBestKnownBlock; | |
254 | //! The hash of the last unknown block this peer has announced. | |
255 | uint256 hashLastUnknownBlock; | |
256 | //! The last full block we both have. | |
257 | CBlockIndex *pindexLastCommonBlock; | |
258 | //! Whether we've started headers synchronization with this peer. | |
259 | bool fSyncStarted; | |
260 | //! Since when we're stalling block download progress (in microseconds), or 0. | |
261 | int64_t nStallingSince; | |
262 | list<QueuedBlock> vBlocksInFlight; | |
263 | int nBlocksInFlight; | |
264 | int nBlocksInFlightValidHeaders; | |
265 | //! Whether we consider this a preferred download peer. | |
266 | bool fPreferredDownload; | |
267 | ||
268 | CNodeState() { | |
269 | fCurrentlyConnected = false; | |
270 | nMisbehavior = 0; | |
271 | fShouldBan = false; | |
272 | pindexBestKnownBlock = NULL; | |
273 | hashLastUnknownBlock.SetNull(); | |
274 | pindexLastCommonBlock = NULL; | |
275 | fSyncStarted = false; | |
276 | nStallingSince = 0; | |
277 | nBlocksInFlight = 0; | |
278 | nBlocksInFlightValidHeaders = 0; | |
279 | fPreferredDownload = false; | |
280 | } | |
281 | }; | |
282 | ||
283 | /** Map maintaining per-node state. Requires cs_main. */ | |
284 | map<NodeId, CNodeState> mapNodeState; | |
285 | ||
286 | // Requires cs_main. | |
287 | CNodeState *State(NodeId pnode) { | |
288 | map<NodeId, CNodeState>::iterator it = mapNodeState.find(pnode); | |
289 | if (it == mapNodeState.end()) | |
290 | return NULL; | |
291 | return &it->second; | |
b2864d2f | 292 | } |
8d655683 | 293 | |
294 | int GetHeight() | |
295 | { | |
296 | LOCK(cs_main); | |
297 | return chainActive.Height(); | |
9c273790 | 298 | } |
14aa6cc0 | 299 | |
8d655683 | 300 | void UpdatePreferredDownload(CNode* node, CNodeState* state) |
301 | { | |
302 | nPreferredDownload -= state->fPreferredDownload; | |
303 | ||
304 | // Whether this node should be marked as a preferred download node. | |
305 | state->fPreferredDownload = (!node->fInbound || node->fWhitelisted) && !node->fOneShot && !node->fClient; | |
306 | ||
307 | nPreferredDownload += state->fPreferredDownload; | |
308 | } | |
14aa6cc0 | 309 | |
8d655683 | 310 | // Returns time at which to timeout block request (nTime in microseconds) |
311 | int64_t GetBlockTimeout(int64_t nTime, int nValidatedQueuedBefore, const Consensus::Params &consensusParams) | |
312 | { | |
313 | return nTime + 500000 * consensusParams.nPowTargetSpacing * (4 + nValidatedQueuedBefore); | |
f59d8f0b | 314 | } |
8d655683 | 315 | |
316 | void InitializeNode(NodeId nodeid, const CNode *pnode) { | |
317 | LOCK(cs_main); | |
318 | CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second; | |
319 | state.name = pnode->addrName; | |
320 | state.address = pnode->addr; | |
321 | } | |
322 | ||
323 | void FinalizeNode(NodeId nodeid) { | |
324 | LOCK(cs_main); | |
325 | CNodeState *state = State(nodeid); | |
326 | ||
327 | if (state->fSyncStarted) | |
328 | nSyncStarted--; | |
329 | ||
330 | if (state->nMisbehavior == 0 && state->fCurrentlyConnected) { | |
331 | AddressCurrentlyConnected(state->address); | |
aa815647 | 332 | } |
8d655683 | 333 | |
334 | BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight) | |
335 | mapBlocksInFlight.erase(entry.hash); | |
336 | EraseOrphansFor(nodeid); | |
337 | nPreferredDownload -= state->fPreferredDownload; | |
338 | ||
339 | mapNodeState.erase(nodeid); | |
aa815647 | 340 | } |
8d655683 | 341 | |
342 | void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age) | |
0a0ec219 | 343 | { |
8d655683 | 344 | /* int expired = pool.Expire(GetTime() - age); |
345 | if (expired != 0) | |
346 | LogPrint("mempool", "Expired %i transactions from the memory pool\n", expired); | |
347 | ||
348 | std::vector<uint256> vNoSpendsRemaining; | |
349 | pool.TrimToSize(limit, &vNoSpendsRemaining); | |
350 | BOOST_FOREACH(const uint256& removed, vNoSpendsRemaining) | |
351 | pcoinsTip->Uncache(removed);*/ | |
aa815647 | 352 | } |
8d655683 | 353 | |
354 | // Requires cs_main. | |
355 | // Returns a bool indicating whether we requested this block. | |
356 | bool MarkBlockAsReceived(const uint256& hash) { | |
357 | map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash); | |
358 | if (itInFlight != mapBlocksInFlight.end()) { | |
359 | CNodeState *state = State(itInFlight->second.first); | |
360 | nQueuedValidatedHeaders -= itInFlight->second.second->fValidatedHeaders; | |
361 | state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders; | |
362 | state->vBlocksInFlight.erase(itInFlight->second.second); | |
363 | state->nBlocksInFlight--; | |
364 | state->nStallingSince = 0; | |
365 | mapBlocksInFlight.erase(itInFlight); | |
366 | return true; | |
367 | } | |
368 | return false; | |
341735eb | 369 | } |
8d655683 | 370 | |
371 | // Requires cs_main. | |
372 | void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Params& consensusParams, CBlockIndex *pindex = NULL) { | |
373 | CNodeState *state = State(nodeid); | |
374 | assert(state != NULL); | |
375 | ||
376 | // Make sure it's not listed somewhere already. | |
377 | MarkBlockAsReceived(hash); | |
378 | ||
379 | int64_t nNow = GetTimeMicros(); | |
380 | QueuedBlock newentry = {hash, pindex, nNow, pindex != NULL, GetBlockTimeout(nNow, nQueuedValidatedHeaders, consensusParams)}; | |
381 | nQueuedValidatedHeaders += newentry.fValidatedHeaders; | |
382 | list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry); | |
383 | state->nBlocksInFlight++; | |
384 | state->nBlocksInFlightValidHeaders += newentry.fValidatedHeaders; | |
385 | mapBlocksInFlight[hash] = std::make_pair(nodeid, it); | |
341735eb | 386 | } |
8d655683 | 387 | |
388 | /** Check whether the last unknown block a peer advertized is not yet known. */ | |
389 | void ProcessBlockAvailability(NodeId nodeid) { | |
390 | CNodeState *state = State(nodeid); | |
391 | assert(state != NULL); | |
392 | ||
393 | if (!state->hashLastUnknownBlock.IsNull()) { | |
394 | BlockMap::iterator itOld = mapBlockIndex.find(state->hashLastUnknownBlock); | |
395 | if (itOld != mapBlockIndex.end() && itOld->second->nChainWork > 0) | |
396 | { | |
397 | if (state->pindexBestKnownBlock == NULL || itOld->second->nChainWork >= state->pindexBestKnownBlock->nChainWork) | |
398 | state->pindexBestKnownBlock = itOld->second; | |
399 | state->hashLastUnknownBlock.SetNull(); | |
400 | } | |
401 | } | |
341735eb | 402 | } |
8d655683 | 403 | |
404 | /** Update tracking information about which blocks a peer is assumed to have. */ | |
405 | void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) { | |
406 | CNodeState *state = State(nodeid); | |
407 | assert(state != NULL); | |
408 | ||
409 | /*ProcessBlockAvailability(nodeid); | |
410 | ||
411 | BlockMap::iterator it = mapBlockIndex.find(hash); | |
412 | if (it != mapBlockIndex.end() && it->second->nChainWork > 0) { | |
413 | // An actually better block was announced. | |
414 | if (state->pindexBestKnownBlock == NULL || it->second->nChainWork >= state->pindexBestKnownBlock->nChainWork) | |
415 | state->pindexBestKnownBlock = it->second; | |
416 | } else*/ | |
417 | { | |
418 | // An unknown block was announced; just assume that the latest one is the best one. | |
419 | state->hashLastUnknownBlock = hash; | |
420 | } | |
341735eb | 421 | } |
8d655683 | 422 | |
423 | /** Find the last common ancestor two blocks have. | |
424 | * Both pa and pb must be non-NULL. */ | |
425 | CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) { | |
426 | if (pa->nHeight > pb->nHeight) { | |
427 | pa = pa->GetAncestor(pb->nHeight); | |
428 | } else if (pb->nHeight > pa->nHeight) { | |
429 | pb = pb->GetAncestor(pa->nHeight); | |
430 | } | |
431 | ||
432 | while (pa != pb && pa && pb) { | |
433 | pa = pa->pprev; | |
434 | pb = pb->pprev; | |
435 | } | |
436 | ||
437 | // Eventually all chain branches meet at the genesis block. | |
438 | assert(pa == pb); | |
439 | return pa; | |
440 | } | |
441 | ||
442 | /** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has | |
443 | * at most count entries. */ | |
444 | void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBlockIndex*>& vBlocks, NodeId& nodeStaller) { | |
445 | if (count == 0) | |
446 | return; | |
447 | ||
448 | vBlocks.reserve(vBlocks.size() + count); | |
449 | CNodeState *state = State(nodeid); | |
450 | assert(state != NULL); | |
451 | ||
452 | // Make sure pindexBestKnownBlock is up to date, we'll need it. | |
453 | ProcessBlockAvailability(nodeid); | |
454 | ||
455 | if (state->pindexBestKnownBlock == NULL || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork) { | |
456 | // This peer has nothing interesting. | |
457 | return; | |
458 | } | |
459 | ||
460 | if (state->pindexLastCommonBlock == NULL) { | |
461 | // Bootstrap quickly by guessing a parent of our best tip is the forking point. | |
462 | // Guessing wrong in either direction is not a problem. | |
463 | state->pindexLastCommonBlock = chainActive[std::min(state->pindexBestKnownBlock->nHeight, chainActive.Height())]; | |
464 | } | |
465 | ||
466 | // If the peer reorganized, our previous pindexLastCommonBlock may not be an ancestor | |
467 | // of its current tip anymore. Go back enough to fix that. | |
468 | state->pindexLastCommonBlock = LastCommonAncestor(state->pindexLastCommonBlock, state->pindexBestKnownBlock); | |
469 | if (state->pindexLastCommonBlock == state->pindexBestKnownBlock) | |
470 | return; | |
471 | ||
472 | std::vector<CBlockIndex*> vToFetch; | |
473 | CBlockIndex *pindexWalk = state->pindexLastCommonBlock; | |
474 | // Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last | |
475 | // linked block we have in common with this peer. The +1 is so we can detect stalling, namely if we would be able to | |
476 | // download that next block if the window were 1 larger. | |
477 | int nWindowEnd = state->pindexLastCommonBlock->nHeight + BLOCK_DOWNLOAD_WINDOW; | |
478 | int nMaxHeight = std::min<int>(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1); | |
479 | NodeId waitingfor = -1; | |
480 | while (pindexWalk->nHeight < nMaxHeight) { | |
481 | // Read up to 128 (or more, if more blocks than that are needed) successors of pindexWalk (towards | |
482 | // pindexBestKnownBlock) into vToFetch. We fetch 128, because CBlockIndex::GetAncestor may be as expensive | |
483 | // as iterating over ~100 CBlockIndex* entries anyway. | |
484 | int nToFetch = std::min(nMaxHeight - pindexWalk->nHeight, std::max<int>(count - vBlocks.size(), 128)); | |
485 | vToFetch.resize(nToFetch); | |
486 | pindexWalk = state->pindexBestKnownBlock->GetAncestor(pindexWalk->nHeight + nToFetch); | |
487 | vToFetch[nToFetch - 1] = pindexWalk; | |
488 | for (unsigned int i = nToFetch - 1; i > 0; i--) { | |
489 | vToFetch[i - 1] = vToFetch[i]->pprev; | |
34970223 | 490 | } |
8d655683 | 491 | |
492 | // Iterate over those blocks in vToFetch (in forward direction), adding the ones that | |
493 | // are not yet downloaded and not in flight to vBlocks. In the meantime, update | |
494 | // pindexLastCommonBlock as long as all ancestors are already downloaded, or if it's | |
495 | // already part of our chain (and therefore don't need it even if pruned). | |
496 | BOOST_FOREACH(CBlockIndex* pindex, vToFetch) { | |
497 | if (!pindex->IsValid(BLOCK_VALID_TREE)) { | |
498 | // We consider the chain that this peer is on invalid. | |
341735eb PW |
499 | return; |
500 | } | |
8d655683 | 501 | if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) { |
502 | if (pindex->nChainTx) | |
503 | state->pindexLastCommonBlock = pindex; | |
504 | } else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) { | |
505 | // The block is not already downloaded, and not yet in flight. | |
506 | if (pindex->nHeight > nWindowEnd) { | |
507 | // We reached the end of the window. | |
508 | if (vBlocks.size() == 0 && waitingfor != nodeid) { | |
509 | // We aren't able to fetch anything, but we would be if the download window was one larger. | |
510 | nodeStaller = waitingfor; | |
511 | } | |
512 | return; | |
513 | } | |
514 | vBlocks.push_back(pindex); | |
515 | if (vBlocks.size() == count) { | |
516 | return; | |
517 | } | |
518 | } else if (waitingfor == -1) { | |
519 | // This is the first already-in-flight block. | |
520 | waitingfor = mapBlocksInFlight[pindex->GetBlockHash()].first; | |
341735eb | 521 | } |
341735eb PW |
522 | } |
523 | } | |
524 | } | |
8d655683 | 525 | |
e10dcf27 | 526 | } // anon namespace |
b2864d2f PW |
527 | |
528 | bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) { | |
529 | LOCK(cs_main); | |
530 | CNodeState *state = State(nodeid); | |
531 | if (state == NULL) | |
532 | return false; | |
533 | stats.nMisbehavior = state->nMisbehavior; | |
aa815647 | 534 | stats.nSyncHeight = state->pindexBestKnownBlock ? state->pindexBestKnownBlock->nHeight : -1; |
ad6e6017 PW |
535 | stats.nCommonHeight = state->pindexLastCommonBlock ? state->pindexLastCommonBlock->nHeight : -1; |
536 | BOOST_FOREACH(const QueuedBlock& queue, state->vBlocksInFlight) { | |
537 | if (queue.pindex) | |
538 | stats.vHeightInFlight.push_back(queue.pindex->nHeight); | |
539 | } | |
b2864d2f PW |
540 | return true; |
541 | } | |
542 | ||
501da250 EL |
543 | void RegisterNodeSignals(CNodeSignals& nodeSignals) |
544 | { | |
4c6d41b8 | 545 | nodeSignals.GetHeight.connect(&GetHeight); |
501da250 EL |
546 | nodeSignals.ProcessMessages.connect(&ProcessMessages); |
547 | nodeSignals.SendMessages.connect(&SendMessages); | |
b2864d2f PW |
548 | nodeSignals.InitializeNode.connect(&InitializeNode); |
549 | nodeSignals.FinalizeNode.connect(&FinalizeNode); | |
501da250 | 550 | } |
64c7ee7e | 551 | |
501da250 EL |
552 | void UnregisterNodeSignals(CNodeSignals& nodeSignals) |
553 | { | |
4c6d41b8 | 554 | nodeSignals.GetHeight.disconnect(&GetHeight); |
501da250 EL |
555 | nodeSignals.ProcessMessages.disconnect(&ProcessMessages); |
556 | nodeSignals.SendMessages.disconnect(&SendMessages); | |
b2864d2f PW |
557 | nodeSignals.InitializeNode.disconnect(&InitializeNode); |
558 | nodeSignals.FinalizeNode.disconnect(&FinalizeNode); | |
501da250 | 559 | } |
64c7ee7e | 560 | |
6db83db3 | 561 | CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) |
562 | { | |
70e7fba0 | 563 | // Find the first block the caller has in the main chain |
e4daecda | 564 | BOOST_FOREACH(const uint256& hash, locator.vHave) { |
145d5be8 | 565 | BlockMap::iterator mi = mapBlockIndex.find(hash); |
e4d89f43 | 566 | if (mi != mapBlockIndex.end()) |
70e7fba0 MH |
567 | { |
568 | CBlockIndex* pindex = (*mi).second; | |
43450135 | 569 | if (pindex != 0 && chain.Contains(pindex)) |
70e7fba0 | 570 | return pindex; |
409c28a2 | 571 | if (pindex != 0 && pindex->GetAncestor(chain.Height()) == chain.Tip()) { |
89f20450 PW |
572 | return chain.Tip(); |
573 | } | |
70e7fba0 MH |
574 | } |
575 | } | |
6db83db3 | 576 | return chain.Genesis(); |
77339e5a PW |
577 | } |
578 | ||
ae8bfd12 | 579 | CCoinsViewCache *pcoinsTip = NULL; |
d979e6e3 | 580 | CBlockTreeDB *pblocktree = NULL; |
b62d7030 | 581 | |
582 | // Komodo globals | |
b62d7030 | 583 | |
7637aa7f | 584 | #define KOMODO_ZCASH |
eab0d89c | 585 | #include "komodo.h" |
450cbb09 | 586 | |
0a61b0df | 587 | ////////////////////////////////////////////////////////////////////////////// |
588 | // | |
589 | // mapOrphanTransactions | |
590 | // | |
591 | ||
72b25b0f | 592 | bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main) |
0a61b0df | 593 | { |
805344dc | 594 | uint256 hash = tx.GetHash(); |
0a61b0df | 595 | if (mapOrphanTransactions.count(hash)) |
77b99cf7 | 596 | return false; |
8d655683 | 597 | |
77b99cf7 GA |
598 | // Ignore big transactions, to avoid a |
599 | // send-big-orphans memory exhaustion attack. If a peer has a legitimate | |
600 | // large transaction with a missing parent then we assume | |
601 | // it will rebroadcast it later, after the parent transaction(s) | |
602 | // have been mined or received. | |
603 | // 10,000 orphans, each of which is at most 5,000 bytes big is | |
604 | // at most 500 megabytes of orphans: | |
e923e3ae | 605 | unsigned int sz = tx.GetSerializeSize(SER_NETWORK, tx.nVersion); |
159bc481 | 606 | if (sz > 5000) |
77b99cf7 | 607 | { |
7d9d134b | 608 | LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString()); |
77b99cf7 GA |
609 | return false; |
610 | } | |
8d655683 | 611 | |
c74332c6 GA |
612 | mapOrphanTransactions[hash].tx = tx; |
613 | mapOrphanTransactions[hash].fromPeer = peer; | |
223b6f1b | 614 | BOOST_FOREACH(const CTxIn& txin, tx.vin) |
8d655683 | 615 | mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash); |
616 | ||
c74332c6 GA |
617 | LogPrint("mempool", "stored orphan tx %s (mapsz %u prevsz %u)\n", hash.ToString(), |
618 | mapOrphanTransactions.size(), mapOrphanTransactionsByPrev.size()); | |
77b99cf7 | 619 | return true; |
0a61b0df | 620 | } |
621 | ||
72b25b0f | 622 | void static EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) |
0a61b0df | 623 | { |
c74332c6 | 624 | map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash); |
89d91f6a | 625 | if (it == mapOrphanTransactions.end()) |
0a61b0df | 626 | return; |
c74332c6 | 627 | BOOST_FOREACH(const CTxIn& txin, it->second.tx.vin) |
0a61b0df | 628 | { |
89d91f6a | 629 | map<uint256, set<uint256> >::iterator itPrev = mapOrphanTransactionsByPrev.find(txin.prevout.hash); |
def2fdb4 GA |
630 | if (itPrev == mapOrphanTransactionsByPrev.end()) |
631 | continue; | |
89d91f6a WL |
632 | itPrev->second.erase(hash); |
633 | if (itPrev->second.empty()) | |
634 | mapOrphanTransactionsByPrev.erase(itPrev); | |
0a61b0df | 635 | } |
89d91f6a | 636 | mapOrphanTransactions.erase(it); |
0a61b0df | 637 | } |
638 | ||
c74332c6 GA |
639 | void EraseOrphansFor(NodeId peer) |
640 | { | |
641 | int nErased = 0; | |
642 | map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin(); | |
643 | while (iter != mapOrphanTransactions.end()) | |
644 | { | |
645 | map<uint256, COrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid | |
646 | if (maybeErase->second.fromPeer == peer) | |
647 | { | |
805344dc | 648 | EraseOrphanTx(maybeErase->second.tx.GetHash()); |
c74332c6 GA |
649 | ++nErased; |
650 | } | |
651 | } | |
652 | if (nErased > 0) LogPrint("mempool", "Erased %d orphan tx from peer %d\n", nErased, peer); | |
653 | } | |
654 | ||
655 | ||
72b25b0f | 656 | unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRED(cs_main) |
142e6041 | 657 | { |
7bd9c3a3 | 658 | unsigned int nEvicted = 0; |
142e6041 GA |
659 | while (mapOrphanTransactions.size() > nMaxOrphans) |
660 | { | |
661 | // Evict a random orphan: | |
f718aedd | 662 | uint256 randomhash = GetRandHash(); |
c74332c6 | 663 | map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.lower_bound(randomhash); |
142e6041 GA |
664 | if (it == mapOrphanTransactions.end()) |
665 | it = mapOrphanTransactions.begin(); | |
8d655683 | 666 | EraseOrphanTx(it->first); |
667 | ++nEvicted; | |
142e6041 GA |
668 | } |
669 | return nEvicted; | |
670 | } | |
0a61b0df | 671 | |
672 | ||
072099d7 | 673 | bool IsStandardTx(const CTransaction& tx, string& reason, const int nHeight) |
000dc551 | 674 | { |
072099d7 | 675 | bool isOverwinter = NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER); |
8d655683 | 676 | |
072099d7 S |
677 | if (isOverwinter) { |
678 | // Overwinter standard rules apply | |
679 | if (tx.nVersion > CTransaction::OVERWINTER_MAX_CURRENT_VERSION || tx.nVersion < CTransaction::OVERWINTER_MIN_CURRENT_VERSION) { | |
680 | reason = "overwinter-version"; | |
681 | return false; | |
682 | } | |
683 | } else { | |
684 | // Sprout standard rules apply | |
685 | if (tx.nVersion > CTransaction::SPROUT_MAX_CURRENT_VERSION || tx.nVersion < CTransaction::SPROUT_MIN_CURRENT_VERSION) { | |
686 | reason = "version"; | |
687 | return false; | |
688 | } | |
980bfe6e | 689 | } |
8d655683 | 690 | |
05df3fc6 | 691 | BOOST_FOREACH(const CTxIn& txin, tx.vin) |
e679ec96 | 692 | { |
4d79098a PT |
693 | // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed |
694 | // keys. (remember the 520 byte limit on redeemScript size) That works | |
675bcd58 | 695 | // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627 |
4d79098a PT |
696 | // bytes of scriptSig, which we round off to 1650 bytes for some minor |
697 | // future-proofing. That's also enough to spend a 20-of-20 | |
698 | // CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not | |
699 | // considered standard) | |
700 | if (txin.scriptSig.size() > 1650) { | |
980bfe6e | 701 | reason = "scriptsig-size"; |
922e8e29 | 702 | return false; |
980bfe6e JG |
703 | } |
704 | if (!txin.scriptSig.IsPushOnly()) { | |
705 | reason = "scriptsig-not-pushonly"; | |
922e8e29 | 706 | return false; |
87fe71e1 | 707 | } |
e679ec96 | 708 | } |
8d655683 | 709 | |
9632af31 | 710 | unsigned int v=0,nDataOut = 0; |
a7934247 | 711 | txnouttype whichType; |
9632af31 | 712 | BOOST_FOREACH(const CTxOut& txout, tx.vout) |
713 | { | |
cc0f93da | 714 | if (!::IsStandard(txout.scriptPubKey, whichType)) |
715 | { | |
7a82f2fc | 716 | reason = "scriptpubkey"; |
cc0f93da | 717 | fprintf(stderr,">>>>>>>>>>>>>>> vout.%d nDataout.%d\n",v,nDataOut); |
922e8e29 | 718 | return false; |
980bfe6e | 719 | } |
9632af31 | 720 | |
a7934247 | 721 | if (whichType == TX_NULL_DATA) |
cc0f93da | 722 | { |
a7934247 | 723 | nDataOut++; |
7a82f2fc | 724 | //fprintf(stderr,"is OP_RETURN\n"); |
cc0f93da | 725 | } |
3da434a2 JG |
726 | else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) { |
727 | reason = "bare-multisig"; | |
728 | return false; | |
729 | } else if (txout.IsDust(::minRelayTxFee)) { | |
980bfe6e | 730 | reason = "dust"; |
65ce2156 | 731 | return false; |
980bfe6e | 732 | } |
9632af31 | 733 | v++; |
65ce2156 | 734 | } |
8d655683 | 735 | |
a7934247 JG |
736 | // only one OP_RETURN txout is permitted |
737 | if (nDataOut > 1) { | |
b34e88a8 | 738 | reason = "multi-op-return"; |
a7934247 JG |
739 | return false; |
740 | } | |
8d655683 | 741 | |
e679ec96 GA |
742 | return true; |
743 | } | |
744 | ||
14aa6cc0 | 745 | bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime) |
912af0a6 | 746 | { |
b5284a65 | 747 | int32_t i; |
05df3fc6 EL |
748 | if (tx.nLockTime == 0) |
749 | return true; | |
fb50dd55 | 750 | if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime)) |
751 | return true; | |
05df3fc6 | 752 | BOOST_FOREACH(const CTxIn& txin, tx.vin) |
69988609 | 753 | { |
420b712a | 754 | if ( txin.nSequence == 0xfffffffe && (((int64_t)tx.nLockTime >= LOCKTIME_THRESHOLD && (int64_t)tx.nLockTime > nBlockTime) || ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD && (int64_t)tx.nLockTime > nBlockHeight)) ) |
69988609 | 755 | { |
756 | ||
757 | } | |
758 | else if (!txin.IsFinal()) | |
14512c96 | 759 | { |
60aee10d | 760 | //printf("non-final txin seq.%x locktime.%u vs nTime.%u\n",txin.nSequence,(uint32_t)tx.nLockTime,(uint32_t)nBlockTime); |
05df3fc6 | 761 | return false; |
14512c96 | 762 | } |
69988609 | 763 | } |
05df3fc6 EL |
764 | return true; |
765 | } | |
766 | ||
9bb37bf0 JG |
767 | bool IsExpiredTx(const CTransaction &tx, int nBlockHeight) |
768 | { | |
769 | if (tx.nExpiryHeight == 0 || tx.IsCoinBase()) { | |
770 | return false; | |
771 | } | |
772 | return static_cast<uint32_t>(nBlockHeight) > tx.nExpiryHeight; | |
773 | } | |
774 | ||
a1d3c6fb | 775 | bool CheckFinalTx(const CTransaction &tx, int flags) |
75a4d512 PT |
776 | { |
777 | AssertLockHeld(cs_main); | |
8d655683 | 778 | |
a1d3c6fb MF |
779 | // By convention a negative value for flags indicates that the |
780 | // current network-enforced consensus rules should be used. In | |
781 | // a future soft-fork scenario that would mean checking which | |
782 | // rules would be enforced for the next block and setting the | |
783 | // appropriate flags. At the present time no soft-forks are | |
784 | // scheduled, so no flags are set. | |
785 | flags = std::max(flags, 0); | |
8d655683 | 786 | |
a1d3c6fb MF |
787 | // CheckFinalTx() uses chainActive.Height()+1 to evaluate |
788 | // nLockTime because when IsFinalTx() is called within | |
789 | // CBlock::AcceptBlock(), the height of the block *being* | |
790 | // evaluated is what is used. Thus if we want to know if a | |
791 | // transaction can be part of the *next* block, we need to call | |
792 | // IsFinalTx() with one more than chainActive.Height(). | |
793 | const int nBlockHeight = chainActive.Height() + 1; | |
8d655683 | 794 | |
a1d3c6fb MF |
795 | // Timestamps on the other hand don't get any special treatment, |
796 | // because we can't know what timestamp the next block will have, | |
797 | // and there aren't timestamp applications where it matters. | |
798 | // However this changes once median past time-locks are enforced: | |
799 | const int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST) | |
8d655683 | 800 | ? chainActive.Tip()->GetMedianTimePast() |
801 | : GetAdjustedTime(); | |
802 | ||
14aa6cc0 | 803 | return IsFinalTx(tx, nBlockHeight, nBlockTime); |
75a4d512 PT |
804 | } |
805 | ||
c5b390b6 MF |
806 | /** |
807 | * Check transaction inputs to mitigate two | |
808 | * potential denial-of-service attacks: | |
db954a65 | 809 | * |
c5b390b6 MF |
810 | * 1. scriptSigs with extra data stuffed into them, |
811 | * not consumed by scriptPubKey (or P2SH script) | |
812 | * 2. P2SH scripts with a crazy number of expensive | |
813 | * CHECKSIG/CHECKMULTISIG operations | |
814 | */ | |
be126699 | 815 | bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, uint32_t consensusBranchId) |
e679ec96 | 816 | { |
05df3fc6 | 817 | if (tx.IsCoinBase()) |
575bdcde | 818 | return true; // Coinbases don't use vin normally |
8d655683 | 819 | |
05df3fc6 | 820 | for (unsigned int i = 0; i < tx.vin.size(); i++) |
e679ec96 | 821 | { |
05df3fc6 | 822 | const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]); |
8d655683 | 823 | |
e679ec96 | 824 | vector<vector<unsigned char> > vSolutions; |
2a45a494 GA |
825 | txnouttype whichType; |
826 | // get the scriptPubKey corresponding to this input: | |
8d7849b6 | 827 | const CScript& prevScript = prev.scriptPubKey; |
2a45a494 | 828 | if (!Solver(prevScript, whichType, vSolutions)) |
922e8e29 | 829 | return false; |
39f0d968 | 830 | int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions); |
c0a0a93d JG |
831 | if (nArgsExpected < 0) |
832 | return false; | |
8d655683 | 833 | |
39f0d968 GA |
834 | // Transactions with extra stuff in their scriptSigs are |
835 | // non-standard. Note that this EvalScript() call will | |
836 | // be quick, because if there are any operations | |
7f3b4e95 | 837 | // beside "push data" in the scriptSig |
bd2b73bb | 838 | // IsStandardTx() will have already returned false |
7f3b4e95 | 839 | // and this method isn't called. |
39f0d968 | 840 | vector<vector<unsigned char> > stack; |
be126699 | 841 | if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), consensusBranchId)) |
39f0d968 | 842 | return false; |
8d655683 | 843 | |
e679ec96 GA |
844 | if (whichType == TX_SCRIPTHASH) |
845 | { | |
922e8e29 | 846 | if (stack.empty()) |
e679ec96 | 847 | return false; |
2a45a494 | 848 | CScript subscript(stack.back().begin(), stack.back().end()); |
39f0d968 GA |
849 | vector<vector<unsigned char> > vSolutions2; |
850 | txnouttype whichType2; | |
7f3b4e95 GA |
851 | if (Solver(subscript, whichType2, vSolutions2)) |
852 | { | |
853 | int tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2); | |
854 | if (tmpExpected < 0) | |
855 | return false; | |
856 | nArgsExpected += tmpExpected; | |
857 | } | |
858 | else | |
859 | { | |
860 | // Any other Script with less than 15 sigops OK: | |
861 | unsigned int sigops = subscript.GetSigOpCount(true); | |
862 | // ... extra data left on the stack after execution is OK, too: | |
863 | return (sigops <= MAX_P2SH_SIGOPS); | |
864 | } | |
e679ec96 | 865 | } |
8d655683 | 866 | |
c0a0a93d | 867 | if (stack.size() != (unsigned int)nArgsExpected) |
39f0d968 | 868 | return false; |
e679ec96 | 869 | } |
8d655683 | 870 | |
e679ec96 GA |
871 | return true; |
872 | } | |
873 | ||
05df3fc6 | 874 | unsigned int GetLegacySigOpCount(const CTransaction& tx) |
922e8e29 | 875 | { |
7bd9c3a3 | 876 | unsigned int nSigOps = 0; |
05df3fc6 | 877 | BOOST_FOREACH(const CTxIn& txin, tx.vin) |
922e8e29 GA |
878 | { |
879 | nSigOps += txin.scriptSig.GetSigOpCount(false); | |
880 | } | |
05df3fc6 | 881 | BOOST_FOREACH(const CTxOut& txout, tx.vout) |
922e8e29 GA |
882 | { |
883 | nSigOps += txout.scriptPubKey.GetSigOpCount(false); | |
884 | } | |
885 | return nSigOps; | |
886 | } | |
0a61b0df | 887 | |
d0867acb | 888 | unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs) |
05df3fc6 EL |
889 | { |
890 | if (tx.IsCoinBase()) | |
891 | return 0; | |
8d655683 | 892 | |
05df3fc6 EL |
893 | unsigned int nSigOps = 0; |
894 | for (unsigned int i = 0; i < tx.vin.size(); i++) | |
895 | { | |
896 | const CTxOut &prevout = inputs.GetOutputFor(tx.vin[i]); | |
897 | if (prevout.scriptPubKey.IsPayToScriptHash()) | |
898 | nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig); | |
899 | } | |
900 | return nSigOps; | |
901 | } | |
0a61b0df | 902 | |
072099d7 S |
903 | /** |
904 | * Check a transaction contextually against a set of consensus rules valid at a given block height. | |
8d655683 | 905 | * |
072099d7 S |
906 | * Notes: |
907 | * 1. AcceptToMemoryPool calls CheckTransaction and this function. | |
908 | * 2. ProcessNewBlock calls AcceptBlock, which calls CheckBlock (which calls CheckTransaction) | |
909 | * and ContextualCheckBlock (which calls this function). | |
910 | */ | |
911 | bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, const int nHeight, const int dosLevel) | |
912 | { | |
913 | bool isOverwinter = NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER); | |
914 | bool isSprout = !isOverwinter; | |
8d655683 | 915 | |
072099d7 S |
916 | // If Sprout rules apply, reject transactions which are intended for Overwinter and beyond |
917 | if (isSprout && tx.fOverwintered) { | |
918 | return state.DoS(dosLevel, error("ContextualCheckTransaction(): overwinter is not active yet"), | |
919 | REJECT_INVALID, "tx-overwinter-not-active"); | |
920 | } | |
8d655683 | 921 | |
072099d7 S |
922 | // If Overwinter rules apply: |
923 | if (isOverwinter) { | |
924 | // Reject transactions with valid version but missing overwinter flag | |
925 | if (tx.nVersion >= OVERWINTER_MIN_TX_VERSION && !tx.fOverwintered) { | |
926 | return state.DoS(dosLevel, error("ContextualCheckTransaction(): overwinter flag must be set"), | |
8d655683 | 927 | REJECT_INVALID, "tx-overwinter-flag-not-set"); |
072099d7 | 928 | } |
8d655683 | 929 | |
072099d7 S |
930 | // Reject transactions with invalid version |
931 | if (tx.fOverwintered && tx.nVersion > OVERWINTER_MAX_TX_VERSION ) { | |
932 | return state.DoS(100, error("CheckTransaction(): overwinter version too high"), | |
8d655683 | 933 | REJECT_INVALID, "bad-tx-overwinter-version-too-high"); |
072099d7 | 934 | } |
8d655683 | 935 | |
072099d7 S |
936 | // Reject transactions intended for Sprout |
937 | if (!tx.fOverwintered) { | |
938 | return state.DoS(dosLevel, error("ContextualCheckTransaction: overwinter is active"), | |
8d655683 | 939 | REJECT_INVALID, "tx-overwinter-active"); |
072099d7 | 940 | } |
8d655683 | 941 | |
9bb37bf0 JG |
942 | // Check that all transactions are unexpired |
943 | if (IsExpiredTx(tx, nHeight)) { | |
944 | return state.DoS(dosLevel, error("ContextualCheckTransaction(): transaction is expired"), REJECT_INVALID, "tx-overwinter-expired"); | |
945 | } | |
072099d7 | 946 | } |
8d655683 | 947 | |
be126699 JG |
948 | if (!(tx.IsCoinBase() || tx.vjoinsplit.empty())) { |
949 | auto consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus()); | |
950 | // Empty output script. | |
951 | CScript scriptCode; | |
952 | uint256 dataToBeSigned; | |
953 | try { | |
954 | dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); | |
955 | } catch (std::logic_error ex) { | |
956 | return state.DoS(100, error("CheckTransaction(): error computing signature hash"), | |
8d655683 | 957 | REJECT_INVALID, "error-computing-signature-hash"); |
be126699 | 958 | } |
8d655683 | 959 | |
be126699 | 960 | BOOST_STATIC_ASSERT(crypto_sign_PUBLICKEYBYTES == 32); |
8d655683 | 961 | |
be126699 JG |
962 | // We rely on libsodium to check that the signature is canonical. |
963 | // https://github.com/jedisct1/libsodium/commit/62911edb7ff2275cccd74bf1c8aefcc4d76924e0 | |
964 | if (crypto_sign_verify_detached(&tx.joinSplitSig[0], | |
965 | dataToBeSigned.begin(), 32, | |
966 | tx.joinSplitPubKey.begin() | |
967 | ) != 0) { | |
968 | return state.DoS(100, error("CheckTransaction(): invalid joinsplit signature"), | |
8d655683 | 969 | REJECT_INVALID, "bad-txns-invalid-joinsplit-signature"); |
be126699 JG |
970 | } |
971 | } | |
072099d7 S |
972 | return true; |
973 | } | |
974 | ||
6fb8d0c2 JG |
975 | bool CheckTransaction(const CTransaction& tx, CValidationState &state, |
976 | libzcash::ProofVerifier& verifier) | |
948d4e6c | 977 | { |
c2123afe | 978 | static uint256 array[64]; static int32_t numbanned,indallvouts; int32_t j,k,n; |
782e1a56 | 979 | if ( *(int32_t *)&array[0] == 0 ) |
c2123afe | 980 | numbanned = komodo_bannedset(&indallvouts,array,(int32_t)(sizeof(array)/sizeof(*array))); |
6d1d0330 | 981 | n = tx.vin.size(); |
782e1a56 | 982 | for (j=0; j<n; j++) |
983 | { | |
c2123afe | 984 | for (k=0; k<numbanned; k++) |
782e1a56 | 985 | { |
464fe491 | 986 | if ( tx.vin[j].prevout.hash == array[k] && (tx.vin[j].prevout.n == 1 || k >= indallvouts) ) |
782e1a56 | 987 | { |
c40ec31d | 988 | static uint32_t counter; |
989 | if ( counter++ < 100 ) | |
c2123afe | 990 | printf("MEMPOOL: banned tx.%d being used at ht.%d vout.%d\n",k,(int32_t)chainActive.Tip()->nHeight,j); |
782e1a56 | 991 | return(false); |
992 | } | |
993 | } | |
994 | } | |
8d655683 | 995 | // Don't count coinbase transactions because mining skews the count |
a6df7ab5 JG |
996 | if (!tx.IsCoinBase()) { |
997 | transactionsValidated.increment(); | |
998 | } | |
8d655683 | 999 | |
948d4e6c TH |
1000 | if (!CheckTransactionWithoutProofVerification(tx, state)) { |
1001 | return false; | |
1002 | } else { | |
1003 | // Ensure that zk-SNARKs verify | |
b7e4abd6 | 1004 | BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { |
bc59f537 | 1005 | if (!joinsplit.Verify(*pzcashParams, verifier, tx.joinSplitPubKey)) { |
b7e4abd6 | 1006 | return state.DoS(100, error("CheckTransaction(): joinsplit does not verify"), |
8d655683 | 1007 | REJECT_INVALID, "bad-txns-joinsplit-verification-failed"); |
948d4e6c TH |
1008 | } |
1009 | } | |
1010 | return true; | |
1011 | } | |
1012 | } | |
1013 | ||
1014 | bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidationState &state) | |
a790fa46 | 1015 | { |
1016 | // Basic checks that don't depend on any context | |
8d655683 | 1017 | |
072099d7 S |
1018 | /** |
1019 | * Previously: | |
1020 | * 1. The consensus rule below was: | |
1021 | * if (tx.nVersion < SPROUT_MIN_TX_VERSION) { ... } | |
1022 | * which checked if tx.nVersion fell within the range: | |
1023 | * INT32_MIN <= tx.nVersion < SPROUT_MIN_TX_VERSION | |
1024 | * 2. The parser allowed tx.nVersion to be negative | |
1025 | * | |
1026 | * Now: | |
1027 | * 1. The consensus rule checks to see if tx.Version falls within the range: | |
1028 | * 0 <= tx.nVersion < SPROUT_MIN_TX_VERSION | |
1029 | * 2. The previous consensus rule checked for negative values within the range: | |
1030 | * INT32_MIN <= tx.nVersion < 0 | |
1031 | * This is unnecessary for Overwinter transactions since the parser now | |
1032 | * interprets the sign bit as fOverwintered, so tx.nVersion is always >=0, | |
1033 | * and when Overwinter is not active ContextualCheckTransaction rejects | |
1034 | * transactions with fOverwintered set. When fOverwintered is set, | |
1035 | * this function and ContextualCheckTransaction will together check to | |
1036 | * ensure tx.nVersion avoids the following ranges: | |
1037 | * 0 <= tx.nVersion < OVERWINTER_MIN_TX_VERSION | |
1038 | * OVERWINTER_MAX_TX_VERSION < tx.nVersion <= INT32_MAX | |
1039 | */ | |
1040 | if (!tx.fOverwintered && tx.nVersion < SPROUT_MIN_TX_VERSION) { | |
7ac924cd | 1041 | return state.DoS(100, error("CheckTransaction(): version too low"), |
cb124619 | 1042 | REJECT_INVALID, "bad-txns-version-too-low"); |
7ac924cd | 1043 | } |
072099d7 S |
1044 | else if (tx.fOverwintered) { |
1045 | if (tx.nVersion < OVERWINTER_MIN_TX_VERSION) { | |
1046 | return state.DoS(100, error("CheckTransaction(): overwinter version too low"), | |
8d655683 | 1047 | REJECT_INVALID, "bad-tx-overwinter-version-too-low"); |
072099d7 S |
1048 | } |
1049 | if (tx.nVersionGroupId != OVERWINTER_VERSION_GROUP_ID) { | |
1050 | return state.DoS(100, error("CheckTransaction(): unknown tx version group id"), | |
8d655683 | 1051 | REJECT_INVALID, "bad-tx-version-group-id"); |
072099d7 S |
1052 | } |
1053 | if (tx.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD) { | |
1054 | return state.DoS(100, error("CheckTransaction(): expiry height is too high"), | |
8d655683 | 1055 | REJECT_INVALID, "bad-tx-expiry-height-too-high"); |
072099d7 S |
1056 | } |
1057 | } | |
8d655683 | 1058 | |
69761d82 | 1059 | // Transactions can contain empty `vin` and `vout` so long as |
8675d94b SB |
1060 | // `vjoinsplit` is non-empty. |
1061 | if (tx.vin.empty() && tx.vjoinsplit.empty()) | |
5262fde0 | 1062 | return state.DoS(10, error("CheckTransaction(): vin empty"), |
14e7ffcc | 1063 | REJECT_INVALID, "bad-txns-vin-empty"); |
8675d94b | 1064 | if (tx.vout.empty() && tx.vjoinsplit.empty()) |
5262fde0 | 1065 | return state.DoS(10, error("CheckTransaction(): vout empty"), |
14e7ffcc | 1066 | REJECT_INVALID, "bad-txns-vout-empty"); |
8d655683 | 1067 | |
a790fa46 | 1068 | // Size limits |
74f15a73 SB |
1069 | BOOST_STATIC_ASSERT(MAX_BLOCK_SIZE > MAX_TX_SIZE); // sanity |
1070 | if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_TX_SIZE) | |
5262fde0 | 1071 | return state.DoS(100, error("CheckTransaction(): size limits failed"), |
14e7ffcc | 1072 | REJECT_INVALID, "bad-txns-oversize"); |
8d655683 | 1073 | |
a790fa46 | 1074 | // Check for negative or overflow output values |
a372168e | 1075 | CAmount nValueOut = 0; |
05df3fc6 | 1076 | BOOST_FOREACH(const CTxOut& txout, tx.vout) |
a790fa46 | 1077 | { |
1078 | if (txout.nValue < 0) | |
5262fde0 | 1079 | return state.DoS(100, error("CheckTransaction(): txout.nValue negative"), |
14e7ffcc | 1080 | REJECT_INVALID, "bad-txns-vout-negative"); |
a790fa46 | 1081 | if (txout.nValue > MAX_MONEY) |
4e038ef5 | 1082 | { |
1083 | fprintf(stderr,"%.8f > max %.8f\n",(double)txout.nValue/COIN,(double)MAX_MONEY/COIN); | |
1084 | return state.DoS(100, error("CheckTransaction(): txout.nValue too high"),REJECT_INVALID, "bad-txns-vout-toolarge"); | |
1085 | } | |
a790fa46 | 1086 | nValueOut += txout.nValue; |
1087 | if (!MoneyRange(nValueOut)) | |
5262fde0 | 1088 | return state.DoS(100, error("CheckTransaction(): txout total out of range"), |
14e7ffcc | 1089 | REJECT_INVALID, "bad-txns-txouttotal-toolarge"); |
a790fa46 | 1090 | } |
8d655683 | 1091 | |
b7e4abd6 SB |
1092 | // Ensure that joinsplit values are well-formed |
1093 | BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit) | |
69761d82 | 1094 | { |
b7e4abd6 SB |
1095 | if (joinsplit.vpub_old < 0) { |
1096 | return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_old negative"), | |
69761d82 | 1097 | REJECT_INVALID, "bad-txns-vpub_old-negative"); |
6ad4db22 | 1098 | } |
8d655683 | 1099 | |
b7e4abd6 SB |
1100 | if (joinsplit.vpub_new < 0) { |
1101 | return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_new negative"), | |
69761d82 | 1102 | REJECT_INVALID, "bad-txns-vpub_new-negative"); |
6ad4db22 | 1103 | } |
8d655683 | 1104 | |
b7e4abd6 SB |
1105 | if (joinsplit.vpub_old > MAX_MONEY) { |
1106 | return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_old too high"), | |
69761d82 | 1107 | REJECT_INVALID, "bad-txns-vpub_old-toolarge"); |
6ad4db22 | 1108 | } |
8d655683 | 1109 | |
b7e4abd6 SB |
1110 | if (joinsplit.vpub_new > MAX_MONEY) { |
1111 | return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_new too high"), | |
69761d82 | 1112 | REJECT_INVALID, "bad-txns-vpub_new-toolarge"); |
6ad4db22 | 1113 | } |
8d655683 | 1114 | |
b7e4abd6 SB |
1115 | if (joinsplit.vpub_new != 0 && joinsplit.vpub_old != 0) { |
1116 | return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_new and joinsplit.vpub_old both nonzero"), | |
6ad4db22 TH |
1117 | REJECT_INVALID, "bad-txns-vpubs-both-nonzero"); |
1118 | } | |
8d655683 | 1119 | |
d7eeb745 | 1120 | nValueOut += joinsplit.vpub_old; |
6ad4db22 | 1121 | if (!MoneyRange(nValueOut)) { |
69761d82 SB |
1122 | return state.DoS(100, error("CheckTransaction(): txout total out of range"), |
1123 | REJECT_INVALID, "bad-txns-txouttotal-toolarge"); | |
6ad4db22 | 1124 | } |
69761d82 | 1125 | } |
8d655683 | 1126 | |
d7eeb745 SB |
1127 | // Ensure input values do not exceed MAX_MONEY |
1128 | // We have not resolved the txin values at this stage, | |
1129 | // but we do know what the joinsplits claim to add | |
1130 | // to the value pool. | |
1131 | { | |
1132 | CAmount nValueIn = 0; | |
1133 | for (std::vector<JSDescription>::const_iterator it(tx.vjoinsplit.begin()); it != tx.vjoinsplit.end(); ++it) | |
1134 | { | |
1135 | nValueIn += it->vpub_new; | |
8d655683 | 1136 | |
d7eeb745 SB |
1137 | if (!MoneyRange(it->vpub_new) || !MoneyRange(nValueIn)) { |
1138 | return state.DoS(100, error("CheckTransaction(): txin total out of range"), | |
1139 | REJECT_INVALID, "bad-txns-txintotal-toolarge"); | |
1140 | } | |
1141 | } | |
1142 | } | |
8d655683 | 1143 | |
1144 | ||
33208fb5 MC |
1145 | // Check for duplicate inputs |
1146 | set<COutPoint> vInOutPoints; | |
05df3fc6 | 1147 | BOOST_FOREACH(const CTxIn& txin, tx.vin) |
33208fb5 MC |
1148 | { |
1149 | if (vInOutPoints.count(txin.prevout)) | |
5262fde0 | 1150 | return state.DoS(100, error("CheckTransaction(): duplicate inputs"), |
14e7ffcc | 1151 | REJECT_INVALID, "bad-txns-inputs-duplicate"); |
33208fb5 MC |
1152 | vInOutPoints.insert(txin.prevout); |
1153 | } | |
8d655683 | 1154 | |
b7e4abd6 | 1155 | // Check for duplicate joinsplit nullifiers in this transaction |
bfeaf004 | 1156 | set<uint256> vJoinSplitNullifiers; |
b7e4abd6 | 1157 | BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit) |
69761d82 | 1158 | { |
cc01120a | 1159 | BOOST_FOREACH(const uint256& nf, joinsplit.nullifiers) |
69761d82 | 1160 | { |
cc01120a | 1161 | if (vJoinSplitNullifiers.count(nf)) |
bfeaf004 | 1162 | return state.DoS(100, error("CheckTransaction(): duplicate nullifiers"), |
8d655683 | 1163 | REJECT_INVALID, "bad-joinsplits-nullifiers-duplicate"); |
1164 | ||
cc01120a | 1165 | vJoinSplitNullifiers.insert(nf); |
69761d82 SB |
1166 | } |
1167 | } | |
8d655683 | 1168 | |
05df3fc6 | 1169 | if (tx.IsCoinBase()) |
a790fa46 | 1170 | { |
b7e4abd6 | 1171 | // There should be no joinsplits in a coinbase transaction |
8675d94b | 1172 | if (tx.vjoinsplit.size() > 0) |
b7e4abd6 SB |
1173 | return state.DoS(100, error("CheckTransaction(): coinbase has joinsplits"), |
1174 | REJECT_INVALID, "bad-cb-has-joinsplits"); | |
8d655683 | 1175 | |
05df3fc6 | 1176 | if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100) |
5262fde0 | 1177 | return state.DoS(100, error("CheckTransaction(): coinbase script size"), |
14e7ffcc | 1178 | REJECT_INVALID, "bad-cb-length"); |
a790fa46 | 1179 | } |
1180 | else | |
1181 | { | |
05df3fc6 | 1182 | BOOST_FOREACH(const CTxIn& txin, tx.vin) |
8d655683 | 1183 | if (txin.prevout.IsNull()) |
1184 | return state.DoS(10, error("CheckTransaction(): prevout is null"), | |
1185 | REJECT_INVALID, "bad-txns-prevout-null"); | |
a790fa46 | 1186 | } |
8d655683 | 1187 | |
a790fa46 | 1188 | return true; |
1189 | } | |
1190 | ||
a372168e | 1191 | CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree) |
76970091 | 1192 | { |
f24b36ca | 1193 | extern int32_t KOMODO_ON_DEMAND; |
2a72d459 LD |
1194 | { |
1195 | LOCK(mempool.cs); | |
805344dc | 1196 | uint256 hash = tx.GetHash(); |
2a72d459 | 1197 | double dPriorityDelta = 0; |
a372168e | 1198 | CAmount nFeeDelta = 0; |
2a72d459 LD |
1199 | mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta); |
1200 | if (dPriorityDelta > 0 || nFeeDelta > 0) | |
1201 | return 0; | |
1202 | } | |
8d655683 | 1203 | |
a372168e | 1204 | CAmount nMinFee = ::minRelayTxFee.GetFee(nBytes); |
8d655683 | 1205 | |
76970091 JG |
1206 | if (fAllowFree) |
1207 | { | |
87cce04c MC |
1208 | // There is a free transaction area in blocks created by most miners, |
1209 | // * If we are relaying we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 1000 | |
16b3ff66 GA |
1210 | // to be considered to fall into this category. We don't want to encourage sending |
1211 | // multiple transactions instead of one big transaction to avoid fees. | |
b33d1f5e | 1212 | if (nBytes < (DEFAULT_BLOCK_PRIORITY_SIZE - 1000)) |
87cce04c | 1213 | nMinFee = 0; |
76970091 | 1214 | } |
8d655683 | 1215 | |
76970091 JG |
1216 | if (!MoneyRange(nMinFee)) |
1217 | nMinFee = MAX_MONEY; | |
1218 | return nMinFee; | |
1219 | } | |
1220 | ||
450cbb09 | 1221 | |
3fef7c32 | 1222 | bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,bool* pfMissingInputs, bool fRejectAbsurdFee) |
0a61b0df | 1223 | { |
e07c943c | 1224 | AssertLockHeld(cs_main); |
0a61b0df | 1225 | if (pfMissingInputs) |
1226 | *pfMissingInputs = false; | |
9000990c | 1227 | |
be126699 JG |
1228 | int nextBlockHeight = chainActive.Height() + 1; |
1229 | auto consensusBranchId = CurrentEpochBranchId(nextBlockHeight, Params().GetConsensus()); | |
9000990c | 1230 | |
da6d9391 S |
1231 | // Node operator can choose to reject tx by number of transparent inputs |
1232 | static_assert(std::numeric_limits<size_t>::max() >= std::numeric_limits<int64_t>::max(), "size_t too small"); | |
1233 | size_t limit = (size_t) GetArg("-mempooltxinputlimit", 0); | |
1234 | if (limit > 0) { | |
1235 | size_t n = tx.vin.size(); | |
1236 | if (n > limit) { | |
1237 | LogPrint("mempool", "Dropping txid %s : too many transparent inputs %zu > limit %zu\n", tx.GetHash().ToString(), n, limit ); | |
1238 | return false; | |
1239 | } | |
1240 | } | |
9000990c | 1241 | |
6fb8d0c2 | 1242 | auto verifier = libzcash::ProofVerifier::Strict(); |
3d02f57b | 1243 | if ( komodo_validate_interest(tx,chainActive.Tip()->nHeight+1,chainActive.Tip()->GetMedianTimePast() + 777,0) < 0 ) |
e7fa1876 | 1244 | { |
66294e69 | 1245 | //fprintf(stderr,"AcceptToMemoryPool komodo_validate_interest failure\n"); |
e7fa1876 | 1246 | return error("AcceptToMemoryPool: komodo_validate_interest failed"); |
14aa6cc0 | 1247 | } |
6fb8d0c2 | 1248 | if (!CheckTransaction(tx, state, verifier)) |
c7a1d234 | 1249 | { |
1250 | ||
4f1ee565 | 1251 | return error("AcceptToMemoryPool: CheckTransaction failed"); |
c7a1d234 | 1252 | } |
072099d7 S |
1253 | // DoS level set to 10 to be more forgiving. |
1254 | // Check transaction contextually against the set of consensus rules which apply in the next block to be mined. | |
c7a1d234 | 1255 | if (!ContextualCheckTransaction(tx, state, nextBlockHeight, 10)) |
1256 | { | |
072099d7 | 1257 | return error("AcceptToMemoryPool: ContextualCheckTransaction failed"); |
68c266b2 | 1258 | } |
9000990c | 1259 | |
0a61b0df | 1260 | // Coinbase is only valid in a block, not as a loose transaction |
d01903e7 | 1261 | if (tx.IsCoinBase()) |
9eb44c75 | 1262 | { |
1263 | fprintf(stderr,"AcceptToMemoryPool coinbase as individual tx\n"); | |
1264 | return state.DoS(100, error("AcceptToMemoryPool: coinbase as individual tx"),REJECT_INVALID, "coinbase"); | |
1265 | } | |
d9ace8ab | 1266 | // Rather not work on nonstandard transactions (unless -testnet/-regtest) |
980bfe6e | 1267 | string reason; |
072099d7 | 1268 | if (Params().RequireStandard() && !IsStandardTx(tx, reason, nextBlockHeight)) |
9eb44c75 | 1269 | { |
9000990c | 1270 | fprintf(stderr,"AcceptToMemoryPool reject nonstandard transaction: %s\n",reason.c_str()); |
9eb44c75 | 1271 | return state.DoS(0,error("AcceptToMemoryPool: nonstandard transaction: %s", reason),REJECT_NONSTANDARD, reason); |
1272 | } | |
0ea28bae PT |
1273 | // Only accept nLockTime-using transactions that can be mined in the next |
1274 | // block; we don't want our mempool filled up with transactions that can't | |
1275 | // be mined yet. | |
a1d3c6fb | 1276 | if (!CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS)) |
9eb44c75 | 1277 | { |
9e8b81f6 | 1278 | //fprintf(stderr,"AcceptToMemoryPool reject non-final\n"); |
a1d3c6fb | 1279 | return state.DoS(0, false, REJECT_NONSTANDARD, "non-final"); |
9eb44c75 | 1280 | } |
450cbb09 | 1281 | // is it already in the memory pool? |
805344dc | 1282 | uint256 hash = tx.GetHash(); |
319b1160 | 1283 | if (pool.exists(hash)) |
ff2d88cc | 1284 | { |
1285 | fprintf(stderr,"already in mempool\n"); | |
319b1160 | 1286 | return false; |
ff2d88cc | 1287 | } |
9000990c | 1288 | |
0a61b0df | 1289 | // Check for conflicts with in-memory transactions |
319b1160 | 1290 | { |
9000990c | 1291 | LOCK(pool.cs); // protect pool.mapNextTx |
1292 | for (unsigned int i = 0; i < tx.vin.size(); i++) | |
0a61b0df | 1293 | { |
9000990c | 1294 | COutPoint outpoint = tx.vin[i].prevout; |
1295 | if (pool.mapNextTx.count(outpoint)) | |
d66877af | 1296 | { |
d6eb511b | 1297 | //static uint32_t counter; |
9000990c | 1298 | // Disable replacement feature for now |
1299 | //if ( counter++ < 100 ) | |
d6eb511b | 1300 | //fprintf(stderr,"Disable replacement feature for now\n"); |
d66877af SB |
1301 | return false; |
1302 | } | |
0a61b0df | 1303 | } |
9000990c | 1304 | BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) |
1305 | { | |
1306 | BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) | |
d66877af | 1307 | { |
9000990c | 1308 | if (pool.mapNullifiers.count(nf)) |
1309 | { | |
1310 | fprintf(stderr,"pool.mapNullifiers.count\n"); | |
1311 | return false; | |
1312 | } | |
d66877af SB |
1313 | } |
1314 | } | |
1315 | } | |
8d655683 | 1316 | |
0a61b0df | 1317 | { |
4afc0b54 | 1318 | CCoinsView dummy; |
7c70438d | 1319 | CCoinsViewCache view(&dummy); |
355ca565 | 1320 | int64_t interest; |
a372168e | 1321 | CAmount nValueIn = 0; |
4afc0b54 | 1322 | { |
9000990c | 1323 | LOCK(pool.cs); |
1324 | CCoinsViewMemPool viewMemPool(pcoinsTip, pool); | |
1325 | view.SetBackend(viewMemPool); | |
1326 | ||
1327 | // do we already have it? | |
1328 | if (view.HaveCoins(hash)) | |
1329 | { | |
1330 | fprintf(stderr,"view.HaveCoins(hash) error\n"); | |
450cbb09 PW |
1331 | return false; |
1332 | } | |
9000990c | 1333 | |
1334 | // do all inputs exist? | |
1335 | // Note that this does not check for the presence of actual outputs (see the next check for that), | |
1336 | // and only helps with filling in pfMissingInputs (to determine missing vs spent). | |
1337 | BOOST_FOREACH(const CTxIn txin, tx.vin) | |
1338 | { | |
1339 | if (!view.HaveCoins(txin.prevout.hash)) | |
1340 | { | |
1341 | if (pfMissingInputs) | |
1342 | *pfMissingInputs = true; | |
1343 | //fprintf(stderr,"missing inputs\n"); | |
1344 | return false; | |
1345 | } | |
1346 | } | |
1347 | ||
1348 | // are the actual inputs available? | |
1349 | if (!view.HaveInputs(tx)) | |
1350 | { | |
1351 | //fprintf(stderr,"accept failure.1\n"); | |
1352 | return state.Invalid(error("AcceptToMemoryPool: inputs already spent"),REJECT_DUPLICATE, "bad-txns-inputs-spent"); | |
1353 | } | |
1354 | // are the joinsplit's requirements met? | |
1355 | if (!view.HaveJoinSplitRequirements(tx)) | |
1356 | { | |
60aee10d | 1357 | //fprintf(stderr,"accept failure.2\n"); |
9000990c | 1358 | return state.Invalid(error("AcceptToMemoryPool: joinsplit requirements not met"),REJECT_DUPLICATE, "bad-txns-joinsplit-requirements-not-met"); |
1359 | } | |
1360 | ||
1361 | // Bring the best block into scope | |
1362 | view.GetBestBlock(); | |
1363 | ||
1364 | nValueIn = view.GetValueIn(chainActive.Tip()->nHeight,&interest,tx,chainActive.Tip()->nTime); | |
f595c2e0 | 1365 | if ( 0 && interest != 0 ) |
4a4e912b | 1366 | fprintf(stderr,"add interest %.8f\n",(double)interest/COIN); |
9000990c | 1367 | // we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool |
1368 | view.SetBackend(dummy); | |
4afc0b54 | 1369 | } |
9000990c | 1370 | |
922e8e29 | 1371 | // Check for non-standard pay-to-script-hash in inputs |
be126699 | 1372 | if (Params().RequireStandard() && !AreInputsStandard(tx, view, consensusBranchId)) |
9000990c | 1373 | return error("AcceptToMemoryPool: reject nonstandard transaction input"); |
1374 | ||
9ee09dc6 PT |
1375 | // Check that the transaction doesn't have an excessive number of |
1376 | // sigops, making it impossible to mine. Since the coinbase transaction | |
23f34359 | 1377 | // itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than |
9ee09dc6 PT |
1378 | // MAX_BLOCK_SIGOPS; we still consider this an invalid rather than |
1379 | // merely non-standard transaction. | |
1380 | unsigned int nSigOps = GetLegacySigOpCount(tx); | |
1381 | nSigOps += GetP2SHSigOpCount(tx, view); | |
23f34359 | 1382 | if (nSigOps > MAX_STANDARD_TX_SIGOPS) |
68c266b2 | 1383 | { |
1384 | fprintf(stderr,"accept failure.4\n"); | |
1385 | return state.DoS(0, error("AcceptToMemoryPool: too many sigops %s, %d > %d", hash.ToString(), nSigOps, MAX_STANDARD_TX_SIGOPS),REJECT_NONSTANDARD, "bad-txns-too-many-sigops"); | |
1386 | } | |
8d655683 | 1387 | |
a372168e MF |
1388 | CAmount nValueOut = tx.GetValueOut(); |
1389 | CAmount nFees = nValueIn-nValueOut; | |
4d707d51 | 1390 | double dPriority = view.GetPriority(tx, chainActive.Height()); |
9000990c | 1391 | |
a4b25180 SD |
1392 | // Keep track of transactions that spend a coinbase, which we re-scan |
1393 | // during reorgs to ensure COINBASE_MATURITY is still met. | |
1394 | bool fSpendsCoinbase = false; | |
1395 | BOOST_FOREACH(const CTxIn &txin, tx.vin) { | |
1396 | const CCoins *coins = view.AccessCoins(txin.prevout.hash); | |
1397 | if (coins->IsCoinBase()) { | |
1398 | fSpendsCoinbase = true; | |
1399 | break; | |
1400 | } | |
1401 | } | |
9000990c | 1402 | |
34a64fe0 JG |
1403 | // Grab the branch ID we expect this transaction to commit to. We don't |
1404 | // yet know if it does, but if the entry gets added to the mempool, then | |
1405 | // it has passed ContextualCheckInputs and therefore this is correct. | |
1406 | auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); | |
9000990c | 1407 | |
34a64fe0 | 1408 | CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), mempool.HasNoInputsOf(tx), fSpendsCoinbase, consensusBranchId); |
4d707d51 | 1409 | unsigned int nSize = entry.GetTxSize(); |
9000990c | 1410 | |
9ddb6ad0 S |
1411 | // Accept a tx if it contains joinsplits and has at least the default fee specified by z_sendmany. |
1412 | if (tx.vjoinsplit.size() > 0 && nFees >= ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE) { | |
1413 | // In future we will we have more accurate and dynamic computation of fees for tx with joinsplits. | |
1414 | } else { | |
1415 | // Don't accept it if it can't get into a block | |
1416 | CAmount txMinFee = GetMinRelayFee(tx, nSize, true); | |
1417 | if (fLimitFree && nFees < txMinFee) | |
68c266b2 | 1418 | { |
ad4ca5c5 | 1419 | //fprintf(stderr,"accept failure.5\n"); |
68c266b2 | 1420 | return state.DoS(0, error("AcceptToMemoryPool: not enough fees %s, %d < %d",hash.ToString(), nFees, txMinFee),REJECT_INSUFFICIENTFEE, "insufficient fee"); |
1421 | } | |
9ddb6ad0 | 1422 | } |
9000990c | 1423 | |
1c52aad5 | 1424 | // Require that free transactions have sufficient priority to be mined in the next block. |
a5150a15 | 1425 | if (GetBoolArg("-relaypriority", false) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) { |
68c266b2 | 1426 | fprintf(stderr,"accept failure.6\n"); |
1c52aad5 PW |
1427 | return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority"); |
1428 | } | |
9000990c | 1429 | |
bf7835c2 | 1430 | // Continuously rate-limit free (really, very-low-fee) transactions |
88abf703 | 1431 | // This mitigates 'penny-flooding' -- sending thousands of free transactions just to |
b49f1398 | 1432 | // be annoying or make others' transactions take longer to confirm. |
13fc83c7 | 1433 | if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize)) |
97ee01ad | 1434 | { |
98e84aae | 1435 | static CCriticalSection csFreeLimiter; |
5de8b54c | 1436 | static double dFreeCount; |
98e84aae WL |
1437 | static int64_t nLastTime; |
1438 | int64_t nNow = GetTime(); | |
9000990c | 1439 | |
98e84aae | 1440 | LOCK(csFreeLimiter); |
9000990c | 1441 | |
98e84aae WL |
1442 | // Use an exponentially decaying ~10-minute window: |
1443 | dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime)); | |
1444 | nLastTime = nNow; | |
1445 | // -limitfreerelay unit is thousand-bytes-per-minute | |
1446 | // At default rate it would take over a month to fill 1GB | |
1447 | if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000) | |
68c266b2 | 1448 | { |
1449 | fprintf(stderr,"accept failure.7\n"); | |
3fef7c32 | 1450 | return state.DoS(0, error("AcceptToMemoryPool: free transaction rejected by rate limiter"), REJECT_INSUFFICIENTFEE, "rate limited free transaction"); |
68c266b2 | 1451 | } |
319b1160 | 1452 | LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize); |
98e84aae | 1453 | dFreeCount += nSize; |
97ee01ad | 1454 | } |
9000990c | 1455 | |
b310d585 | 1456 | if (fRejectAbsurdFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000 && nFees > nValueOut/19 ) |
68c266b2 | 1457 | { |
1458 | fprintf(stderr,"accept failure.8\n"); | |
1459 | return error("AcceptToMemoryPool: absurdly high fees %s, %d > %d",hash.ToString(), nFees, ::minRelayTxFee.GetFee(nSize) * 10000); | |
1460 | } | |
9000990c | 1461 | |
8d7849b6 GA |
1462 | // Check against previous transactions |
1463 | // This is done last to help prevent CPU exhaustion denial-of-service attacks. | |
6514771a | 1464 | PrecomputedTransactionData txdata(tx); |
be126699 | 1465 | if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId)) |
8d7849b6 | 1466 | { |
60aee10d | 1467 | //fprintf(stderr,"accept failure.9\n"); |
bf7835c2 | 1468 | return error("AcceptToMemoryPool: ConnectInputs failed %s", hash.ToString()); |
8d7849b6 | 1469 | } |
9000990c | 1470 | |
7c041b3b PT |
1471 | // Check again against just the consensus-critical mandatory script |
1472 | // verification flags, in case of bugs in the standard flags that cause | |
1473 | // transactions to pass as valid when they're actually invalid. For | |
1474 | // instance the STRICTENC flag was incorrectly allowing certain | |
1475 | // CHECKSIG NOT scripts to pass, even though they were invalid. | |
1476 | // | |
1477 | // There is a similar check in CreateNewBlock() to prevent creating | |
1478 | // invalid blocks, however allowing such transactions into the mempool | |
1479 | // can be exploited as a DoS attack. | |
be126699 | 1480 | if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId)) |
7c041b3b | 1481 | { |
68c266b2 | 1482 | fprintf(stderr,"accept failure.10\n"); |
4f1ee565 | 1483 | return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString()); |
7c041b3b | 1484 | } |
9000990c | 1485 | |
cd057bfd | 1486 | // Store transaction in memory |
f24b36ca | 1487 | if ( komodo_is_notarytx(tx) == 0 ) |
1488 | KOMODO_ON_DEMAND++; | |
b649e039 | 1489 | pool.addUnchecked(hash, entry, !IsInitialBlockDownload()); |
8b78a819 T |
1490 | |
1491 | // Add memory address index | |
1492 | if (fAddressIndex) { | |
1493 | pool.addAddressIndex(entry, view); | |
1494 | } | |
1495 | ||
1496 | // Add memory spent index | |
1497 | if (fSpentIndex) { | |
1498 | pool.addSpentIndex(entry, view); | |
1499 | } | |
d640a3ce | 1500 | } |
9000990c | 1501 | |
0d27dad8 | 1502 | SyncWithWallets(tx, NULL); |
9000990c | 1503 | |
cd057bfd | 1504 | return true; |
d640a3ce TH |
1505 | } |
1506 | ||
8b78a819 T |
1507 | bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, const bool fActiveOnly, std::vector<std::pair<uint256, unsigned int> > &hashes) |
1508 | { | |
1509 | if (!fTimestampIndex) | |
1510 | return error("Timestamp index not enabled"); | |
1511 | ||
1512 | if (!pblocktree->ReadTimestampIndex(high, low, fActiveOnly, hashes)) | |
1513 | return error("Unable to get hashes for timestamps"); | |
1514 | ||
1515 | return true; | |
1516 | } | |
1517 | ||
1518 | bool GetSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value) | |
1519 | { | |
1520 | if (!fSpentIndex) | |
1521 | return false; | |
1522 | ||
1523 | if (mempool.getSpentIndex(key, value)) | |
1524 | return true; | |
1525 | ||
1526 | if (!pblocktree->ReadSpentIndex(key, value)) | |
1527 | return false; | |
1528 | ||
1529 | return true; | |
1530 | } | |
1531 | ||
1532 | bool GetAddressIndex(uint160 addressHash, int type, | |
1533 | std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex, int start, int end) | |
1534 | { | |
1535 | if (!fAddressIndex) | |
1536 | return error("address index not enabled"); | |
1537 | ||
1538 | if (!pblocktree->ReadAddressIndex(addressHash, type, addressIndex, start, end)) | |
1539 | return error("unable to get txids for address"); | |
1540 | ||
1541 | return true; | |
1542 | } | |
1543 | ||
1544 | bool GetAddressUnspent(uint160 addressHash, int type, | |
1545 | std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs) | |
1546 | { | |
1547 | if (!fAddressIndex) | |
1548 | return error("address index not enabled"); | |
1549 | ||
1550 | if (!pblocktree->ReadAddressUnspentIndex(addressHash, type, unspentOutputs)) | |
1551 | return error("unable to get txids for address"); | |
1552 | ||
1553 | return true; | |
1554 | } | |
1555 | ||
c5b390b6 | 1556 | /** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */ |
450cbb09 | 1557 | bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow) |
c73ba23e | 1558 | { |
450cbb09 | 1559 | CBlockIndex *pindexSlow = NULL; |
8d655683 | 1560 | |
01878c9c | 1561 | LOCK(cs_main); |
8d655683 | 1562 | |
01878c9c | 1563 | if (mempool.lookup(hash, txOut)) |
c73ba23e | 1564 | { |
01878c9c AM |
1565 | return true; |
1566 | } | |
8d655683 | 1567 | |
01878c9c AM |
1568 | if (fTxIndex) { |
1569 | CDiskTxPos postx; | |
1570 | if (pblocktree->ReadTxIndex(hash, postx)) { | |
1571 | CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION); | |
1572 | if (file.IsNull()) | |
1573 | return error("%s: OpenBlockFile failed", __func__); | |
1574 | CBlockHeader header; | |
1575 | try { | |
1576 | file >> header; | |
1577 | fseek(file.Get(), postx.nTxOffset, SEEK_CUR); | |
1578 | file >> txOut; | |
1579 | } catch (const std::exception& e) { | |
1580 | return error("%s: Deserialize or I/O error - %s", __func__, e.what()); | |
2d1fa42e | 1581 | } |
01878c9c | 1582 | hashBlock = header.GetHash(); |
805344dc | 1583 | if (txOut.GetHash() != hash) |
01878c9c AM |
1584 | return error("%s: txid mismatch", __func__); |
1585 | return true; | |
2d1fa42e | 1586 | } |
01878c9c | 1587 | } |
8d655683 | 1588 | |
01878c9c AM |
1589 | if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it |
1590 | int nHeight = -1; | |
1591 | { | |
1592 | CCoinsViewCache &view = *pcoinsTip; | |
1593 | const CCoins* coins = view.AccessCoins(hash); | |
1594 | if (coins) | |
1595 | nHeight = coins->nHeight; | |
c73ba23e | 1596 | } |
01878c9c AM |
1597 | if (nHeight > 0) |
1598 | pindexSlow = chainActive[nHeight]; | |
c73ba23e | 1599 | } |
8d655683 | 1600 | |
450cbb09 PW |
1601 | if (pindexSlow) { |
1602 | CBlock block; | |
b8add6a4 | 1603 | if (ReadBlockFromDisk(block, pindexSlow,1)) { |
450cbb09 | 1604 | BOOST_FOREACH(const CTransaction &tx, block.vtx) { |
805344dc | 1605 | if (tx.GetHash() == hash) { |
450cbb09 PW |
1606 | txOut = tx; |
1607 | hashBlock = pindexSlow->GetBlockHash(); | |
1608 | return true; | |
1609 | } | |
1610 | } | |
1611 | } | |
1612 | } | |
8d655683 | 1613 | |
450cbb09 PW |
1614 | return false; |
1615 | } | |
0a61b0df | 1616 | |
352f8081 | 1617 | /*char *komodo_getspendscript(uint256 hash,int32_t n) |
8d655683 | 1618 | { |
1619 | CTransaction tx; uint256 hashBlock; | |
1620 | if ( !GetTransaction(hash,tx,hashBlock,true) ) | |
1621 | { | |
1622 | printf("null GetTransaction\n"); | |
1623 | return(0); | |
1624 | } | |
1625 | if ( n >= 0 && n < tx.vout.size() ) | |
1626 | return((char *)tx.vout[n].scriptPubKey.ToString().c_str()); | |
1627 | else printf("getspendscript illegal n.%d\n",n); | |
1628 | return(0); | |
1629 | }*/ | |
0a61b0df | 1630 | |
1631 | ||
1632 | ////////////////////////////////////////////////////////////////////////////// | |
1633 | // | |
1634 | // CBlock and CBlockIndex | |
1635 | // | |
1636 | ||
e6973430 | 1637 | bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart) |
226f8219 EL |
1638 | { |
1639 | // Open history file to append | |
eee030f6 | 1640 | CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); |
fef24cab | 1641 | if (fileout.IsNull()) |
5262fde0 | 1642 | return error("WriteBlockToDisk: OpenBlockFile failed"); |
8d655683 | 1643 | |
226f8219 EL |
1644 | // Write index header |
1645 | unsigned int nSize = fileout.GetSerializeSize(block); | |
e6973430 | 1646 | fileout << FLATDATA(messageStart) << nSize; |
8d655683 | 1647 | |
226f8219 | 1648 | // Write block |
a8738238 | 1649 | long fileOutPos = ftell(fileout.Get()); |
226f8219 | 1650 | if (fileOutPos < 0) |
5262fde0 | 1651 | return error("WriteBlockToDisk: ftell failed"); |
226f8219 EL |
1652 | pos.nPos = (unsigned int)fileOutPos; |
1653 | fileout << block; | |
8d655683 | 1654 | |
226f8219 EL |
1655 | return true; |
1656 | } | |
1657 | ||
b8add6a4 | 1658 | bool ReadBlockFromDisk(int32_t height,CBlock& block, const CDiskBlockPos& pos,bool checkPOW) |
80313994 | 1659 | { |
f2dd868d | 1660 | uint8_t pubkey33[33]; |
80313994 | 1661 | block.SetNull(); |
8d655683 | 1662 | |
80313994 | 1663 | // Open history file to read |
eee030f6 | 1664 | CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); |
fef24cab | 1665 | if (filein.IsNull()) |
81a77e92 | 1666 | { |
681589a5 | 1667 | //fprintf(stderr,"readblockfromdisk err A\n"); |
7e28b66b | 1668 | return false;//error("ReadBlockFromDisk: OpenBlockFile failed for %s", pos.ToString()); |
81a77e92 | 1669 | } |
8d655683 | 1670 | |
80313994 EL |
1671 | // Read block |
1672 | try { | |
1673 | filein >> block; | |
1674 | } | |
27df4123 | 1675 | catch (const std::exception& e) { |
81a77e92 | 1676 | fprintf(stderr,"readblockfromdisk err B\n"); |
f5791c6a | 1677 | return error("%s: Deserialize or I/O error - %s at %s", __func__, e.what(), pos.ToString()); |
80313994 | 1678 | } |
80313994 | 1679 | // Check the header |
02290a3f | 1680 | if ( 0 && checkPOW != 0 ) |
e4b3ad62 | 1681 | { |
b8add6a4 | 1682 | komodo_block2pubkey33(pubkey33,(CBlock *)&block); |
1683 | if (!(CheckEquihashSolution(&block, Params()) && CheckProofOfWork(height,pubkey33,block.GetHash(), block.nBits, Params().GetConsensus(),block.nTime))) | |
1684 | { | |
1685 | int32_t i; for (i=0; i<33; i++) | |
1686 | fprintf(stderr,"%02x",pubkey33[i]); | |
1687 | fprintf(stderr," warning unexpected diff at ht.%d\n",height); | |
1688 | ||
1689 | return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); | |
1690 | } | |
e4b3ad62 | 1691 | } |
80313994 EL |
1692 | return true; |
1693 | } | |
1694 | ||
b8add6a4 | 1695 | bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex,bool checkPOW) |
0a61b0df | 1696 | { |
446ad3a7 | 1697 | if ( pindex == 0 ) |
1698 | return false; | |
b8add6a4 | 1699 | if (!ReadBlockFromDisk(pindex->nHeight,block, pindex->GetBlockPos(),checkPOW)) |
0a61b0df | 1700 | return false; |
7db120d5 | 1701 | if (block.GetHash() != pindex->GetBlockHash()) |
f5791c6a | 1702 | return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s", |
8d655683 | 1703 | pindex->ToString(), pindex->GetBlockPos().ToString()); |
0a61b0df | 1704 | return true; |
1705 | } | |
1706 | ||
314350e6 | 1707 | //uint64_t komodo_moneysupply(int32_t height); |
7c130297 | 1708 | extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; |
7a4c01c9 | 1709 | extern uint32_t ASSETCHAINS_MAGIC; |
9339a0cb | 1710 | extern uint64_t ASSETCHAINS_STAKED,ASSETCHAINS_ENDSUBSIDY,ASSETCHAINS_REWARD,ASSETCHAINS_HALVING,ASSETCHAINS_LINEAR,ASSETCHAINS_COMMISSION,ASSETCHAINS_SUPPLY; |
5203fc4b | 1711 | |
935bd0a4 | 1712 | CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) |
0a61b0df | 1713 | { |
6e94384f | 1714 | static uint64_t cached_subsidy; static int32_t cached_numhalvings; |
53a94b28 | 1715 | int32_t numhalvings,i; uint64_t numerator; CAmount nSubsidy = 3 * COIN; |
9a2f3a40 | 1716 | if ( ASSETCHAINS_SYMBOL[0] == 0 ) |
7a4c01c9 | 1717 | { |
9a2f3a40 | 1718 | if ( nHeight == 1 ) |
7a4c01c9 | 1719 | return(100000000 * COIN); // ICO allocation |
314350e6 | 1720 | else if ( nHeight < KOMODO_ENDOFERA ) //komodo_moneysupply(nHeight) < MAX_MONEY ) |
9a2f3a40 | 1721 | return(3 * COIN); |
1722 | else return(0); | |
1723 | } | |
1724 | else | |
1725 | { | |
1726 | if ( nHeight == 1 ) | |
7a4c01c9 | 1727 | return(ASSETCHAINS_SUPPLY * COIN + (ASSETCHAINS_MAGIC & 0xffffff)); |
8683bd8d | 1728 | else if ( ASSETCHAINS_ENDSUBSIDY == 0 || nHeight < ASSETCHAINS_ENDSUBSIDY ) |
1729 | { | |
1730 | if ( ASSETCHAINS_REWARD == 0 ) | |
1731 | return(10000); | |
9757c8f9 | 1732 | else if ( ASSETCHAINS_ENDSUBSIDY != 0 && nHeight >= ASSETCHAINS_ENDSUBSIDY ) |
8683bd8d | 1733 | return(0); |
1734 | else | |
1735 | { | |
1736 | nSubsidy = ASSETCHAINS_REWARD; | |
1737 | if ( ASSETCHAINS_HALVING != 0 ) | |
1738 | { | |
1739 | if ( (numhalvings= (nHeight / ASSETCHAINS_HALVING)) > 0 ) | |
1740 | { | |
1741 | if ( numhalvings >= 64 && ASSETCHAINS_DECAY == 0 ) | |
1742 | return(0); | |
1743 | if ( ASSETCHAINS_DECAY == 0 ) | |
1744 | nSubsidy >>= numhalvings; | |
9757c8f9 | 1745 | else if ( ASSETCHAINS_DECAY == 100000000 && ASSETCHAINS_ENDSUBSIDY != 0 ) |
8683bd8d | 1746 | { |
9757c8f9 | 1747 | numerator = (ASSETCHAINS_ENDSUBSIDY - nHeight); |
53a94b28 | 1748 | nSubsidy = (nSubsidy * numerator) / ASSETCHAINS_ENDSUBSIDY; |
8683bd8d | 1749 | } |
1750 | else | |
1751 | { | |
6e94384f | 1752 | if ( cached_subsidy > 0 && cached_numhalvings == numhalvings ) |
1753 | nSubsidy = cached_subsidy; | |
1754 | else | |
1755 | { | |
1756 | for (i=0; i<numhalvings&&nSubsidy!=0; i++) | |
1757 | nSubsidy = (nSubsidy * ASSETCHAINS_DECAY) / 100000000; | |
1758 | cached_subsidy = nSubsidy; | |
1759 | cached_numhalvings = numhalvings; | |
1760 | } | |
8683bd8d | 1761 | } |
1762 | } | |
1763 | } | |
1764 | } | |
1765 | return(nSubsidy); | |
1766 | } else return(0); | |
7a4c01c9 | 1767 | } |
8d655683 | 1768 | /* |
1769 | // Mining slow start | |
1770 | // The subsidy is ramped up linearly, skipping the middle payout of | |
1771 | // MAX_SUBSIDY/2 to keep the monetary curve consistent with no slow start. | |
1772 | if (nHeight < consensusParams.nSubsidySlowStartInterval / 2) { | |
1773 | nSubsidy /= consensusParams.nSubsidySlowStartInterval; | |
1774 | nSubsidy *= nHeight; | |
1775 | return nSubsidy; | |
1776 | } else if (nHeight < consensusParams.nSubsidySlowStartInterval) { | |
1777 | nSubsidy /= consensusParams.nSubsidySlowStartInterval; | |
1778 | nSubsidy *= (nHeight+1); | |
1779 | return nSubsidy; | |
1780 | } | |
1781 | ||
1782 | assert(nHeight > consensusParams.SubsidySlowStartShift()); | |
1783 | int halvings = (nHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nSubsidyHalvingInterval;*/ | |
c5a9d2ca | 1784 | // Force block reward to zero when right shift is undefined. |
5203fc4b | 1785 | //int halvings = nHeight / consensusParams.nSubsidyHalvingInterval; |
1786 | //if (halvings >= 64) | |
1787 | // return 0; | |
8d655683 | 1788 | |
45e3deea | 1789 | // Subsidy is cut in half every 840,000 blocks which will occur approximately every 4 years. |
5203fc4b | 1790 | //nSubsidy >>= halvings; |
935bd0a4 | 1791 | return nSubsidy; |
0a61b0df | 1792 | } |
1793 | ||
0a61b0df | 1794 | bool IsInitialBlockDownload() |
1795 | { | |
e1e3f309 | 1796 | const CChainParams& chainParams = Params(); |
55a1db4f | 1797 | LOCK(cs_main); |
a8cdaf5c | 1798 | if (fImporting || fReindex) |
8e157f52 | 1799 | { |
03491950 | 1800 | //fprintf(stderr,"IsInitialBlockDownload: fImporting %d || %d fReindex\n",(int32_t)fImporting,(int32_t)fReindex); |
a8cdaf5c | 1801 | return true; |
8e157f52 | 1802 | } |
a8cdaf5c | 1803 | if (fCheckpointsEnabled && chainActive.Height() < Checkpoints::GetTotalBlocksEstimate(chainParams.Checkpoints())) |
8e157f52 | 1804 | { |
03491950 | 1805 | //fprintf(stderr,"IsInitialBlockDownload: checkpoint -> initialdownload\n"); |
0a61b0df | 1806 | return true; |
8e157f52 | 1807 | } |
9ec75c5e RDP |
1808 | static bool lockIBDState = false; |
1809 | if (lockIBDState) | |
cb237ef8 | 1810 | { |
03491950 | 1811 | //fprintf(stderr,"lockIBDState true %d < %d\n",chainActive.Height(),pindexBestHeader->nHeight - 10); |
9ec75c5e | 1812 | return false; |
cb237ef8 | 1813 | } |
03491950 | 1814 | bool state; CBlockIndex *ptr = chainActive.Tip(); |
1815 | if ( ptr == 0 ) | |
1816 | ptr = pindexBestHeader; | |
1dcfdab7 | 1817 | else if ( pindexBestHeader != 0 && pindexBestHeader->nHeight > ptr->nHeight ) |
1818 | ptr = pindexBestHeader; | |
1931844a | 1819 | //if ( ASSETCHAINS_SYMBOL[0] == 0 ) |
8d655683 | 1820 | state = ((chainActive.Height() < ptr->nHeight - 24*60) || |
1821 | ptr->GetBlockTime() < (GetTime() - chainParams.MaxTipAge())); | |
1931844a | 1822 | //else state = (chainActive.Height() < ptr->nHeight - 24*60); |
b11963b5 | 1823 | //fprintf(stderr,"state.%d ht.%d vs %d, t.%u %u\n",state,(int32_t)chainActive.Height(),(uint32_t)ptr->nHeight,(int32_t)ptr->GetBlockTime(),(uint32_t)(GetTime() - chainParams.MaxTipAge())); |
9ec75c5e | 1824 | if (!state) |
8e157f52 | 1825 | { |
9ec75c5e | 1826 | lockIBDState = true; |
8e157f52 | 1827 | } |
9ec75c5e | 1828 | return state; |
0a61b0df | 1829 | } |
1830 | ||
b8585384 | 1831 | bool fLargeWorkForkFound = false; |
f65e7092 | 1832 | bool fLargeWorkInvalidChainFound = false; |
b8585384 MC |
1833 | CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL; |
1834 | ||
1835 | void CheckForkWarningConditions() | |
1836 | { | |
e07c943c | 1837 | AssertLockHeld(cs_main); |
55ed3f14 MC |
1838 | // Before we get past initial download, we cannot reliably alert about forks |
1839 | // (we assume we don't get stuck on a fork before the last checkpoint) | |
1840 | if (IsInitialBlockDownload()) | |
1841 | return; | |
8d655683 | 1842 | |
d4388ed5 | 1843 | // If our best fork is no longer within 288 blocks (+/- 12 hours if no one mines it) |
b8585384 | 1844 | // of our head, drop it |
d4388ed5 | 1845 | if (pindexBestForkTip && chainActive.Height() - pindexBestForkTip->nHeight >= 288) |
b8585384 | 1846 | pindexBestForkTip = NULL; |
8d655683 | 1847 | |
092b58d1 | 1848 | if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (GetBlockProof(*chainActive.Tip()) * 6))) |
b8585384 | 1849 | { |
730b1ed1 | 1850 | if (!fLargeWorkForkFound && pindexBestForkBase) |
f89faa25 | 1851 | { |
e01a7939 | 1852 | std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") + |
8d655683 | 1853 | pindexBestForkBase->phashBlock->ToString() + std::string("'"); |
e01a7939 | 1854 | CAlert::Notify(warning, true); |
f89faa25 | 1855 | } |
730b1ed1 | 1856 | if (pindexBestForkTip && pindexBestForkBase) |
f65e7092 | 1857 | { |
30c1db1c | 1858 | LogPrintf("%s: Warning: Large valid fork found\n forking the chain at height %d (%s)\n lasting to height %d (%s).\nChain state database corruption likely.\n", __func__, |
8d655683 | 1859 | pindexBestForkBase->nHeight, pindexBestForkBase->phashBlock->ToString(), |
1860 | pindexBestForkTip->nHeight, pindexBestForkTip->phashBlock->ToString()); | |
f65e7092 MC |
1861 | fLargeWorkForkFound = true; |
1862 | } | |
1863 | else | |
1864 | { | |
57c074e1 TH |
1865 | std::string warning = std::string("Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely."); |
1866 | LogPrintf("%s: %s\n", warning.c_str(), __func__); | |
1867 | CAlert::Notify(warning, true); | |
f65e7092 MC |
1868 | fLargeWorkInvalidChainFound = true; |
1869 | } | |
1870 | } | |
1871 | else | |
1872 | { | |
b8585384 | 1873 | fLargeWorkForkFound = false; |
f65e7092 MC |
1874 | fLargeWorkInvalidChainFound = false; |
1875 | } | |
b8585384 MC |
1876 | } |
1877 | ||
1878 | void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) | |
1879 | { | |
e07c943c | 1880 | AssertLockHeld(cs_main); |
b8585384 MC |
1881 | // If we are on a fork that is sufficiently large, set a warning flag |
1882 | CBlockIndex* pfork = pindexNewForkTip; | |
4c6d41b8 | 1883 | CBlockIndex* plonger = chainActive.Tip(); |
b8585384 MC |
1884 | while (pfork && pfork != plonger) |
1885 | { | |
1886 | while (plonger && plonger->nHeight > pfork->nHeight) | |
1887 | plonger = plonger->pprev; | |
1888 | if (pfork == plonger) | |
1889 | break; | |
1890 | pfork = pfork->pprev; | |
1891 | } | |
8d655683 | 1892 | |
7e6d23b1 | 1893 | // We define a condition where we should warn the user about as a fork of at least 7 blocks |
4e3ac9b0 | 1894 | // with a tip within 72 blocks (+/- 3 hours if no one mines it) of ours |
b8585384 MC |
1895 | // We use 7 blocks rather arbitrarily as it represents just under 10% of sustained network |
1896 | // hash rate operating on the fork. | |
1897 | // or a chain that is entirely longer than ours and invalid (note that this should be detected by both) | |
1898 | // We define it this way because it allows us to only store the highest fork tip (+ base) which meets | |
1899 | // the 7-block condition and from this always have the most-likely-to-cause-warning fork | |
1900 | if (pfork && (!pindexBestForkTip || (pindexBestForkTip && pindexNewForkTip->nHeight > pindexBestForkTip->nHeight)) && | |
8d655683 | 1901 | pindexNewForkTip->nChainWork - pfork->nChainWork > (GetBlockProof(*pfork) * 7) && |
1902 | chainActive.Height() - pindexNewForkTip->nHeight < 72) | |
b8585384 MC |
1903 | { |
1904 | pindexBestForkTip = pindexNewForkTip; | |
1905 | pindexBestForkBase = pfork; | |
1906 | } | |
8d655683 | 1907 | |
b8585384 MC |
1908 | CheckForkWarningConditions(); |
1909 | } | |
1910 | ||
f59d8f0b | 1911 | // Requires cs_main. |
75f51f2a PW |
1912 | void Misbehaving(NodeId pnode, int howmuch) |
1913 | { | |
1914 | if (howmuch == 0) | |
1915 | return; | |
8d655683 | 1916 | |
75f51f2a PW |
1917 | CNodeState *state = State(pnode); |
1918 | if (state == NULL) | |
1919 | return; | |
8d655683 | 1920 | |
75f51f2a | 1921 | state->nMisbehavior += howmuch; |
42bdb117 | 1922 | int banscore = GetArg("-banscore", 101); |
dc942e6f | 1923 | if (state->nMisbehavior >= banscore && state->nMisbehavior - howmuch < banscore) |
75f51f2a | 1924 | { |
30c1db1c | 1925 | LogPrintf("%s: %s (%d -> %d) BAN THRESHOLD EXCEEDED\n", __func__, state->name, state->nMisbehavior-howmuch, state->nMisbehavior); |
75f51f2a PW |
1926 | state->fShouldBan = true; |
1927 | } else | |
30c1db1c | 1928 | LogPrintf("%s: %s (%d -> %d)\n", __func__, state->name, state->nMisbehavior-howmuch, state->nMisbehavior); |
75f51f2a PW |
1929 | } |
1930 | ||
64c7ee7e | 1931 | void static InvalidChainFound(CBlockIndex* pindexNew) |
0a61b0df | 1932 | { |
85eb2cef | 1933 | if (!pindexBestInvalid || pindexNew->nChainWork > pindexBestInvalid->nChainWork) |
85eb2cef | 1934 | pindexBestInvalid = pindexNew; |
8d655683 | 1935 | |
30c1db1c | 1936 | LogPrintf("%s: invalid block=%s height=%d log2_work=%.8g date=%s\n", __func__, |
8d655683 | 1937 | pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, |
1938 | log(pindexNew->nChainWork.getdouble())/log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", | |
1939 | pindexNew->GetBlockTime())); | |
4a374102 RN |
1940 | CBlockIndex *tip = chainActive.Tip(); |
1941 | assert (tip); | |
30c1db1c | 1942 | LogPrintf("%s: current best=%s height=%d log2_work=%.8g date=%s\n", __func__, |
8d655683 | 1943 | tip->GetBlockHash().ToString(), chainActive.Height(), log(tip->nChainWork.getdouble())/log(2.0), |
1944 | DateTimeStrFormat("%Y-%m-%d %H:%M:%S", tip->GetBlockTime())); | |
b8585384 | 1945 | CheckForkWarningConditions(); |
0a61b0df | 1946 | } |
1947 | ||
75f51f2a PW |
1948 | void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) { |
1949 | int nDoS = 0; | |
1950 | if (state.IsInvalid(nDoS)) { | |
1951 | std::map<uint256, NodeId>::iterator it = mapBlockSource.find(pindex->GetBlockHash()); | |
1952 | if (it != mapBlockSource.end() && State(it->second)) { | |
307f7d48 | 1953 | CBlockReject reject = {state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), pindex->GetBlockHash()}; |
75f51f2a PW |
1954 | State(it->second)->rejects.push_back(reject); |
1955 | if (nDoS > 0) | |
1956 | Misbehaving(it->second, nDoS); | |
857c61df | 1957 | } |
75f51f2a PW |
1958 | } |
1959 | if (!state.CorruptionPossible()) { | |
1960 | pindex->nStatus |= BLOCK_FAILED_VALID; | |
51ce901a | 1961 | setDirtyBlockIndex.insert(pindex); |
e17bd583 | 1962 | setBlockIndexCandidates.erase(pindex); |
75f51f2a PW |
1963 | InvalidChainFound(pindex); |
1964 | } | |
857c61df PW |
1965 | } |
1966 | ||
8cb98d91 | 1967 | void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight) |
450cbb09 | 1968 | { |
021f8bc6 | 1969 | if (!tx.IsCoinBase()) // mark inputs spent |
1970 | { | |
ab15b2ec | 1971 | txundo.vprevout.reserve(tx.vin.size()); |
f28aec01 | 1972 | BOOST_FOREACH(const CTxIn &txin, tx.vin) { |
c444c620 | 1973 | CCoinsModifier coins = inputs.ModifyCoins(txin.prevout.hash); |
1974 | unsigned nPos = txin.prevout.n; | |
8d655683 | 1975 | |
c444c620 | 1976 | if (nPos >= coins->vout.size() || coins->vout[nPos].IsNull()) |
1977 | assert(false); | |
1978 | // mark an outpoint spent, and construct undo information | |
1979 | txundo.vprevout.push_back(CTxInUndo(coins->vout[nPos])); | |
1980 | coins->Spend(nPos); | |
1981 | if (coins->vout.size() == 0) { | |
1982 | CTxInUndo& undo = txundo.vprevout.back(); | |
1983 | undo.nHeight = coins->nHeight; | |
1984 | undo.fCoinBase = coins->fCoinBase; | |
1985 | undo.nVersion = coins->nVersion; | |
1986 | } | |
450cbb09 PW |
1987 | } |
1988 | } | |
021f8bc6 | 1989 | BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { // spend nullifiers |
cc01120a SB |
1990 | BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) { |
1991 | inputs.SetNullifier(nf, true); | |
d66877af SB |
1992 | } |
1993 | } | |
021f8bc6 | 1994 | inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight); // add outputs |
450cbb09 PW |
1995 | } |
1996 | ||
8cb98d91 | 1997 | void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight) |
d7621ccf | 1998 | { |
1999 | CTxUndo txundo; | |
8cb98d91 | 2000 | UpdateCoins(tx, inputs, txundo, nHeight); |
d7621ccf | 2001 | } |
2002 | ||
307f7d48 | 2003 | bool CScriptCheck::operator()() { |
2800ce73 | 2004 | const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; |
2c8d8268 | 2005 | if (!VerifyScript(scriptSig, scriptPubKey, nFlags, ServerTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), consensusBranchId, &error)) { |
805344dc | 2006 | return ::error("CScriptCheck(): %s:%d VerifySignature failed: %s", ptxTo->GetHash().ToString(), nIn, ScriptErrorString(error)); |
307f7d48 | 2007 | } |
2800ce73 PW |
2008 | return true; |
2009 | } | |
2010 | ||
e079f010 | 2011 | int GetSpendHeight(const CCoinsViewCache& inputs) |
0a61b0df | 2012 | { |
e079f010 JT |
2013 | LOCK(cs_main); |
2014 | CBlockIndex* pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second; | |
2015 | return pindexPrev->nHeight + 1; | |
2016 | } | |
f9cae832 | 2017 | |
e079f010 | 2018 | namespace Consensus { |
8d655683 | 2019 | bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, const Consensus::Params& consensusParams) |
2020 | { | |
13c51f20 PW |
2021 | // This doesn't trigger the DoS code on purpose; if it did, it would make it easier |
2022 | // for an attacker to attempt to split the network. | |
05df3fc6 | 2023 | if (!inputs.HaveInputs(tx)) |
805344dc | 2024 | return state.Invalid(error("CheckInputs(): %s inputs unavailable", tx.GetHash().ToString())); |
8d655683 | 2025 | |
b7e4abd6 | 2026 | // are the JoinSplit's requirements met? |
ee964faf | 2027 | if (!inputs.HaveJoinSplitRequirements(tx)) |
805344dc | 2028 | return state.Invalid(error("CheckInputs(): %s JoinSplit requirements not met", tx.GetHash().ToString())); |
8d655683 | 2029 | |
a372168e MF |
2030 | CAmount nValueIn = 0; |
2031 | CAmount nFees = 0; | |
05df3fc6 | 2032 | for (unsigned int i = 0; i < tx.vin.size(); i++) |
0a61b0df | 2033 | { |
05df3fc6 | 2034 | const COutPoint &prevout = tx.vin[i].prevout; |
629d75fa PW |
2035 | const CCoins *coins = inputs.AccessCoins(prevout.hash); |
2036 | assert(coins); | |
8d655683 | 2037 | |
629d75fa | 2038 | if (coins->IsCoinBase()) { |
e079f010 JT |
2039 | // Ensure that coinbases are matured |
2040 | if (nSpendHeight - coins->nHeight < COINBASE_MATURITY) { | |
2041 | return state.Invalid( | |
8d655683 | 2042 | error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight), |
2043 | REJECT_INVALID, "bad-txns-premature-spend-of-coinbase"); | |
e079f010 | 2044 | } |
8d655683 | 2045 | |
1d38795f | 2046 | // Ensure that coinbases cannot be spent to transparent outputs |
c0dde76d | 2047 | // Disabled on regtest |
d212ba32 SB |
2048 | if (fCoinbaseEnforcedProtectionEnabled && |
2049 | consensusParams.fCoinbaseMustBeProtected && | |
2050 | !tx.vout.empty()) { | |
358ce266 | 2051 | return state.Invalid( |
8d655683 | 2052 | error("CheckInputs(): tried to spend coinbase with transparent outputs"), |
2053 | REJECT_INVALID, "bad-txns-coinbase-spend-has-transparent-outputs"); | |
1d38795f | 2054 | } |
450cbb09 | 2055 | } |
8d655683 | 2056 | |
4add41a2 | 2057 | // Check for negative or overflow input values |
629d75fa | 2058 | nValueIn += coins->vout[prevout.n].nValue; |
782120ca | 2059 | #ifdef KOMODO_ENABLE_INTEREST |
c60397dd | 2060 | if ( ASSETCHAINS_SYMBOL[0] == 0 && nSpendHeight > 60000 )//chainActive.Tip() != 0 && chainActive.Tip()->nHeight >= 60000 ) |
782120ca | 2061 | { |
98f68225 | 2062 | if ( coins->vout[prevout.n].nValue >= 10*COIN ) |
782120ca | 2063 | { |
2064 | int64_t interest; int32_t txheight; uint32_t locktime; | |
c60397dd | 2065 | if ( (interest= komodo_accrued_interest(&txheight,&locktime,prevout.hash,prevout.n,0,coins->vout[prevout.n].nValue,(int32_t)nSpendHeight-1)) != 0 ) |
407de87c | 2066 | { |
8d655683 | 2067 | //fprintf(stderr,"checkResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nValueIn/COIN,(double)coins->vout[prevout.n].nValue/COIN,(double)interest/COIN,txheight,locktime,chainActive.Tip()->nTime); |
407de87c | 2068 | nValueIn += interest; |
2069 | } | |
782120ca | 2070 | } |
2071 | } | |
2072 | #endif | |
629d75fa | 2073 | if (!MoneyRange(coins->vout[prevout.n].nValue) || !MoneyRange(nValueIn)) |
5262fde0 | 2074 | return state.DoS(100, error("CheckInputs(): txin values out of range"), |
14e7ffcc | 2075 | REJECT_INVALID, "bad-txns-inputvalues-outofrange"); |
8d655683 | 2076 | |
4add41a2 | 2077 | } |
8d655683 | 2078 | |
942bc467 | 2079 | nValueIn += tx.GetJoinSplitValueIn(); |
f512cf7c SB |
2080 | if (!MoneyRange(nValueIn)) |
2081 | return state.DoS(100, error("CheckInputs(): vpub_old values out of range"), | |
2082 | REJECT_INVALID, "bad-txns-inputvalues-outofrange"); | |
8d655683 | 2083 | |
0733c1bd | 2084 | if (nValueIn < tx.GetValueOut()) |
60aee10d | 2085 | { |
2da1debd | 2086 | fprintf(stderr,"spentheight.%d valuein %s vs %s error\n",nSpendHeight,FormatMoney(nValueIn).c_str(), FormatMoney(tx.GetValueOut()).c_str()); |
2c0218f0 | 2087 | return state.DoS(100, error("CheckInputs(): %s value in (%s) < value out (%s) diff %.8f", |
407de87c | 2088 | tx.GetHash().ToString(), FormatMoney(nValueIn), FormatMoney(tx.GetValueOut()),((double)nValueIn - tx.GetValueOut())/COIN),REJECT_INVALID, "bad-txns-in-belowout"); |
60aee10d | 2089 | } |
450cbb09 | 2090 | // Tally transaction fees |
a372168e | 2091 | CAmount nTxFee = nValueIn - tx.GetValueOut(); |
2c0218f0 | 2092 | if (nTxFee < 0) |
805344dc | 2093 | return state.DoS(100, error("CheckInputs(): %s nTxFee < 0", tx.GetHash().ToString()), |
14e7ffcc | 2094 | REJECT_INVALID, "bad-txns-fee-negative"); |
450cbb09 | 2095 | nFees += nTxFee; |
2c0218f0 | 2096 | if (!MoneyRange(nFees)) |
5262fde0 | 2097 | return state.DoS(100, error("CheckInputs(): nFees out of range"), |
14e7ffcc | 2098 | REJECT_INVALID, "bad-txns-fee-outofrange"); |
8d655683 | 2099 | return true; |
2100 | } | |
e079f010 JT |
2101 | }// namespace Consensus |
2102 | ||
d55e5e77 | 2103 | bool ContextualCheckInputs( |
8d655683 | 2104 | const CTransaction& tx, |
2105 | CValidationState &state, | |
2106 | const CCoinsViewCache &inputs, | |
2107 | bool fScriptChecks, | |
2108 | unsigned int flags, | |
2109 | bool cacheStore, | |
2110 | PrecomputedTransactionData& txdata, | |
2111 | const Consensus::Params& consensusParams, | |
2112 | uint32_t consensusBranchId, | |
2113 | std::vector<CScriptCheck> *pvChecks) | |
e079f010 | 2114 | { |
e079f010 JT |
2115 | if (!tx.IsCoinBase()) |
2116 | { | |
30006a2e JG |
2117 | if (!Consensus::CheckTxInputs(tx, state, inputs, GetSpendHeight(inputs), consensusParams)) { |
2118 | return false; | |
2119 | } | |
8d655683 | 2120 | |
e079f010 JT |
2121 | if (pvChecks) |
2122 | pvChecks->reserve(tx.vin.size()); | |
8d655683 | 2123 | |
4add41a2 GA |
2124 | // The first loop above does all the inexpensive checks. |
2125 | // Only if ALL inputs pass do we perform expensive ECDSA signature checks. | |
2126 | // Helps prevent CPU exhaustion attacks. | |
8d655683 | 2127 | |
450cbb09 | 2128 | // Skip ECDSA signature verification when connecting blocks |
729b1806 | 2129 | // before the last block chain checkpoint. This is safe because block merkle hashes are |
450cbb09 | 2130 | // still computed and checked, and any change will be caught at the next checkpoint. |
1d70f4bd | 2131 | if (fScriptChecks) { |
05df3fc6 EL |
2132 | for (unsigned int i = 0; i < tx.vin.size(); i++) { |
2133 | const COutPoint &prevout = tx.vin[i].prevout; | |
629d75fa PW |
2134 | const CCoins* coins = inputs.AccessCoins(prevout.hash); |
2135 | assert(coins); | |
8d655683 | 2136 | |
b14bd4df | 2137 | // Verify signature |
be126699 | 2138 | CScriptCheck check(*coins, tx, i, flags, cacheStore, consensusBranchId, &txdata); |
f9cae832 PW |
2139 | if (pvChecks) { |
2140 | pvChecks->push_back(CScriptCheck()); | |
2141 | check.swap(pvChecks->back()); | |
97e7901a | 2142 | } else if (!check()) { |
f80cffa2 PT |
2143 | if (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS) { |
2144 | // Check whether the failure was caused by a | |
2145 | // non-mandatory script verification check, such as | |
2146 | // non-standard DER encodings or non-null dummy | |
2147 | // arguments; if so, don't trigger DoS protection to | |
2148 | // avoid splitting the network between upgraded and | |
2149 | // non-upgraded nodes. | |
838e7a29 | 2150 | CScriptCheck check2(*coins, tx, i, |
8d655683 | 2151 | flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, consensusBranchId, &txdata); |
838e7a29 | 2152 | if (check2()) |
307f7d48 | 2153 | return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); |
97e7901a | 2154 | } |
f80cffa2 PT |
2155 | // Failures of other flags indicate a transaction that is |
2156 | // invalid in new blocks, e.g. a invalid P2SH. We DoS ban | |
2157 | // such nodes as they are not following the protocol. That | |
2158 | // said during an upgrade careful thought should be taken | |
2159 | // as to the correct behavior - we may want to continue | |
2160 | // peering with non-upgraded nodes even after a soft-fork | |
2161 | // super-majority vote has passed. | |
307f7d48 | 2162 | return state.DoS(100,false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError()))); |
97e7901a | 2163 | } |
2a45a494 | 2164 | } |
0a61b0df | 2165 | } |
0a61b0df | 2166 | } |
8d655683 | 2167 | |
0a61b0df | 2168 | return true; |
2169 | } | |
2170 | ||
945f015d | 2171 | |
2172 | /*bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector<CScriptCheck> *pvChecks) | |
8d655683 | 2173 | { |
2174 | if (!NonContextualCheckInputs(tx, state, inputs, fScriptChecks, flags, cacheStore, consensusParams, pvChecks)) { | |
2175 | fprintf(stderr,"ContextualCheckInputs failure.0\n"); | |
2176 | return false; | |
2177 | } | |
2178 | ||
2179 | if (!tx.IsCoinBase()) | |
2180 | { | |
2181 | // While checking, GetBestBlock() refers to the parent block. | |
2182 | // This is also true for mempool checks. | |
2183 | CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second; | |
2184 | int nSpendHeight = pindexPrev->nHeight + 1; | |
2185 | for (unsigned int i = 0; i < tx.vin.size(); i++) | |
2186 | { | |
2187 | const COutPoint &prevout = tx.vin[i].prevout; | |
2188 | const CCoins *coins = inputs.AccessCoins(prevout.hash); | |
2189 | // Assertion is okay because NonContextualCheckInputs ensures the inputs | |
2190 | // are available. | |
2191 | assert(coins); | |
2192 | ||
2193 | // If prev is coinbase, check that it's matured | |
2194 | if (coins->IsCoinBase()) { | |
2195 | if ( ASSETCHAINS_SYMBOL[0] == 0 ) | |
2196 | COINBASE_MATURITY = _COINBASE_MATURITY; | |
2197 | if (nSpendHeight - coins->nHeight < COINBASE_MATURITY) { | |
2198 | fprintf(stderr,"ContextualCheckInputs failure.1 i.%d of %d\n",i,(int32_t)tx.vin.size()); | |
2199 | ||
2200 | return state.Invalid( | |
2201 | error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight),REJECT_INVALID, "bad-txns-premature-spend-of-coinbase"); | |
2202 | } | |
2203 | } | |
2204 | } | |
2205 | } | |
2206 | ||
2207 | return true; | |
2208 | }*/ | |
89f3cd11 | 2209 | |
8d655683 | 2210 | namespace { |
2211 | ||
2212 | bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart) | |
2c901fd8 | 2213 | { |
8d655683 | 2214 | // Open history file to append |
2215 | CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); | |
2216 | if (fileout.IsNull()) | |
2217 | return error("%s: OpenUndoFile failed", __func__); | |
2218 | ||
2219 | // Write index header | |
2220 | unsigned int nSize = fileout.GetSerializeSize(blockundo); | |
2221 | fileout << FLATDATA(messageStart) << nSize; | |
2222 | ||
2223 | // Write undo data | |
2224 | long fileOutPos = ftell(fileout.Get()); | |
2225 | if (fileOutPos < 0) | |
2226 | return error("%s: ftell failed", __func__); | |
2227 | pos.nPos = (unsigned int)fileOutPos; | |
2228 | fileout << blockundo; | |
2229 | ||
2230 | // calculate & write checksum | |
2231 | CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); | |
2232 | hasher << hashBlock; | |
2233 | hasher << blockundo; | |
2234 | fileout << hasher.GetHash(); | |
2235 | ||
2236 | return true; | |
2c901fd8 | 2237 | } |
8d655683 | 2238 | |
2239 | bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uint256& hashBlock) | |
2240 | { | |
2241 | // Open history file to read | |
2242 | CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); | |
2243 | if (filein.IsNull()) | |
2244 | return error("%s: OpenBlockFile failed", __func__); | |
2245 | ||
2246 | // Read block | |
2247 | uint256 hashChecksum; | |
2248 | try { | |
2249 | filein >> blockundo; | |
2250 | filein >> hashChecksum; | |
2251 | } | |
2252 | catch (const std::exception& e) { | |
2253 | return error("%s: Deserialize or I/O error - %s", __func__, e.what()); | |
2254 | } | |
8d655683 | 2255 | // Verify checksum |
2256 | CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); | |
2257 | hasher << hashBlock; | |
2258 | hasher << blockundo; | |
2259 | if (hashChecksum != hasher.GetHash()) | |
2260 | return error("%s: Checksum mismatch", __func__); | |
2261 | ||
2262 | return true; | |
87fb3108 | 2263 | } |
8d655683 | 2264 | |
2265 | /** Abort with a message */ | |
2266 | bool AbortNode(const std::string& strMessage, const std::string& userMessage="") | |
2267 | { | |
2268 | strMiscWarning = strMessage; | |
2269 | LogPrintf("*** %s\n", strMessage); | |
2270 | uiInterface.ThreadSafeMessageBox( | |
2271 | userMessage.empty() ? _("Error: A fatal internal error occurred, see debug.log for details") : userMessage, | |
2272 | "", CClientUIInterface::MSG_ERROR); | |
2273 | StartShutdown(); | |
2274 | return false; | |
87fb3108 | 2275 | } |
8d655683 | 2276 | |
2277 | bool AbortNode(CValidationState& state, const std::string& strMessage, const std::string& userMessage="") | |
2278 | { | |
2279 | AbortNode(strMessage, userMessage); | |
2280 | return state.Error(strMessage); | |
2281 | } | |
2282 | ||
87fb3108 | 2283 | } // anon namespace |
0a61b0df | 2284 | |
eb1c2cd3 DK |
2285 | /** |
2286 | * Apply the undo operation of a CTxInUndo to the given chain state. | |
2287 | * @param undo The undo object. | |
2288 | * @param view The coins view to which to apply the changes. | |
2289 | * @param out The out point that corresponds to the tx input. | |
2290 | * @return True on success. | |
2291 | */ | |
2292 | static bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint& out) | |
2293 | { | |
2294 | bool fClean = true; | |
8d655683 | 2295 | |
eb1c2cd3 DK |
2296 | CCoinsModifier coins = view.ModifyCoins(out.hash); |
2297 | if (undo.nHeight != 0) { | |
2298 | // undo data contains height: this is the last output of the prevout tx being spent | |
2299 | if (!coins->IsPruned()) | |
2300 | fClean = fClean && error("%s: undo data overwriting existing transaction", __func__); | |
2301 | coins->Clear(); | |
2302 | coins->fCoinBase = undo.fCoinBase; | |
2303 | coins->nHeight = undo.nHeight; | |
2304 | coins->nVersion = undo.nVersion; | |
2305 | } else { | |
2306 | if (coins->IsPruned()) | |
2307 | fClean = fClean && error("%s: undo data adding output to missing transaction", __func__); | |
2308 | } | |
2309 | if (coins->IsAvailable(out.n)) | |
2310 | fClean = fClean && error("%s: undo data overwriting existing output", __func__); | |
2311 | if (coins->vout.size() < out.n+1) | |
2312 | coins->vout.resize(out.n+1); | |
2313 | coins->vout[out.n] = undo.txout; | |
8d655683 | 2314 | |
eb1c2cd3 DK |
2315 | return fClean; |
2316 | } | |
2317 | ||
5c363ed6 | 2318 | bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean) |
0a61b0df | 2319 | { |
84674082 | 2320 | assert(pindex->GetBlockHash() == view.GetBestBlock()); |
8d655683 | 2321 | |
2cbd71da PW |
2322 | if (pfClean) |
2323 | *pfClean = false; | |
8d655683 | 2324 | |
2cbd71da | 2325 | bool fClean = true; |
4355e769 | 2326 | komodo_disconnect(pindex,block); |
450cbb09 | 2327 | CBlockUndo blockUndo; |
8539361e PW |
2328 | CDiskBlockPos pos = pindex->GetUndoPos(); |
2329 | if (pos.IsNull()) | |
5262fde0 | 2330 | return error("DisconnectBlock(): no undo data available"); |
e035c6a7 | 2331 | if (!UndoReadFromDisk(blockUndo, pos, pindex->pprev->GetBlockHash())) |
5262fde0 | 2332 | return error("DisconnectBlock(): failure reading undo data"); |
8d655683 | 2333 | |
5c363ed6 | 2334 | if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) |
5262fde0 | 2335 | return error("DisconnectBlock(): block and undo data inconsistent"); |
8b78a819 T |
2336 | std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; |
2337 | std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > addressUnspentIndex; | |
2338 | std::vector<std::pair<CSpentIndexKey, CSpentIndexValue> > spentIndex; | |
2339 | ||
450cbb09 | 2340 | // undo transactions in reverse order |
5c363ed6 EL |
2341 | for (int i = block.vtx.size() - 1; i >= 0; i--) { |
2342 | const CTransaction &tx = block.vtx[i]; | |
805344dc | 2343 | uint256 hash = tx.GetHash(); |
8b78a819 T |
2344 | if (fAddressIndex) { |
2345 | ||
2346 | for (unsigned int k = tx.vout.size(); k-- > 0;) { | |
2347 | const CTxOut &out = tx.vout[k]; | |
2348 | ||
2349 | if (out.scriptPubKey.IsPayToScriptHash()) { | |
2350 | vector<unsigned char> hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22); | |
2351 | ||
2352 | // undo receiving activity | |
2353 | addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, hash, k, false), out.nValue)); | |
2354 | ||
2355 | // undo unspent index | |
2356 | addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(2, uint160(hashBytes), hash, k), CAddressUnspentValue())); | |
2357 | ||
2358 | } else if (out.scriptPubKey.IsPayToPublicKeyHash()) { | |
2359 | vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23); | |
2360 | ||
2361 | // undo receiving activity | |
2362 | addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, hash, k, false), out.nValue)); | |
2363 | ||
2364 | // undo unspent index | |
2365 | addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), hash, k), CAddressUnspentValue())); | |
2366 | ||
2367 | } else { | |
2368 | continue; | |
2369 | } | |
2370 | ||
2371 | } | |
2372 | ||
2373 | } | |
2374 | ||
170e02de | 2375 | // Check that all outputs are available and match the outputs in the block itself |
eb1c2cd3 | 2376 | // exactly. |
f28aec01 | 2377 | { |
8d655683 | 2378 | CCoinsModifier outs = view.ModifyCoins(hash); |
2379 | outs->ClearUnspendable(); | |
2380 | ||
2381 | CCoins outsBlock(tx, pindex->nHeight); | |
2382 | // The CCoins serialization does not serialize negative numbers. | |
2383 | // No network rules currently depend on the version here, so an inconsistency is harmless | |
2384 | // but it must be corrected before txout nversion ever influences a network rule. | |
2385 | if (outsBlock.nVersion < 0) | |
2386 | outs->nVersion = outsBlock.nVersion; | |
2387 | if (*outs != outsBlock) | |
2388 | fClean = fClean && error("DisconnectBlock(): added transaction mismatch? database corrupted"); | |
2389 | ||
2390 | // remove outputs | |
2391 | outs->Clear(); | |
f28aec01 | 2392 | } |
8d655683 | 2393 | |
bfeaf004 | 2394 | // unspend nullifiers |
b7e4abd6 | 2395 | BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { |
cc01120a SB |
2396 | BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) { |
2397 | view.SetNullifier(nf, false); | |
d66877af SB |
2398 | } |
2399 | } | |
8d655683 | 2400 | |
450cbb09 PW |
2401 | // restore inputs |
2402 | if (i > 0) { // not coinbases | |
2403 | const CTxUndo &txundo = blockUndo.vtxundo[i-1]; | |
2cbd71da | 2404 | if (txundo.vprevout.size() != tx.vin.size()) |
5262fde0 | 2405 | return error("DisconnectBlock(): transaction and undo data inconsistent"); |
450cbb09 PW |
2406 | for (unsigned int j = tx.vin.size(); j-- > 0;) { |
2407 | const COutPoint &out = tx.vin[j].prevout; | |
2408 | const CTxInUndo &undo = txundo.vprevout[j]; | |
eb1c2cd3 DK |
2409 | if (!ApplyTxInUndo(undo, view, out)) |
2410 | fClean = false; | |
8b78a819 T |
2411 | |
2412 | const CTxIn input = tx.vin[j]; | |
2413 | ||
2414 | if (fSpentIndex) { | |
2415 | // undo and delete the spent index | |
2416 | spentIndex.push_back(make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue())); | |
2417 | } | |
2418 | ||
2419 | if (fAddressIndex) { | |
2420 | const CTxOut &prevout = view.GetOutputFor(tx.vin[j]); | |
2421 | if (prevout.scriptPubKey.IsPayToScriptHash()) { | |
2422 | vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22); | |
2423 | ||
2424 | // undo spending activity | |
2425 | addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, hash, j, true), prevout.nValue * -1)); | |
2426 | ||
2427 | // restore unspent index | |
2428 | addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(2, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight))); | |
2429 | ||
2430 | ||
2431 | } else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) { | |
2432 | vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23); | |
2433 | ||
2434 | // undo spending activity | |
2435 | addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, hash, j, true), prevout.nValue * -1)); | |
2436 | ||
2437 | // restore unspent index | |
2438 | addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight))); | |
2439 | ||
2440 | } else { | |
2441 | continue; | |
2442 | } | |
2443 | } | |
450cbb09 PW |
2444 | } |
2445 | } | |
2446 | } | |
8d655683 | 2447 | |
a8ac403d SB |
2448 | // set the old best anchor back |
2449 | view.PopAnchor(blockUndo.old_tree_root); | |
8d655683 | 2450 | |
450cbb09 | 2451 | // move best block pointer to prevout block |
84674082 | 2452 | view.SetBestBlock(pindex->pprev->GetBlockHash()); |
8d655683 | 2453 | |
2cbd71da PW |
2454 | if (pfClean) { |
2455 | *pfClean = fClean; | |
2456 | return true; | |
2cbd71da | 2457 | } |
eb1c2cd3 | 2458 | |
8b78a819 T |
2459 | if (fAddressIndex) { |
2460 | if (!pblocktree->EraseAddressIndex(addressIndex)) { | |
2461 | return AbortNode(state, "Failed to delete address index"); | |
2462 | } | |
2463 | if (!pblocktree->UpdateAddressUnspentIndex(addressUnspentIndex)) { | |
2464 | return AbortNode(state, "Failed to write address unspent index"); | |
2465 | } | |
2466 | } | |
eb1c2cd3 | 2467 | return fClean; |
0a61b0df | 2468 | } |
2469 | ||
1eb57879 | 2470 | void static FlushBlockFile(bool fFinalize = false) |
44d40f26 PW |
2471 | { |
2472 | LOCK(cs_LastBlockFile); | |
8d655683 | 2473 | |
a8a4b967 | 2474 | CDiskBlockPos posOld(nLastBlockFile, 0); |
8d655683 | 2475 | |
44d40f26 | 2476 | FILE *fileOld = OpenBlockFile(posOld); |
b19388dd | 2477 | if (fileOld) { |
1eb57879 | 2478 | if (fFinalize) |
ed6d1a2c | 2479 | TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nSize); |
b19388dd PK |
2480 | FileCommit(fileOld); |
2481 | fclose(fileOld); | |
2482 | } | |
8d655683 | 2483 | |
44d40f26 | 2484 | fileOld = OpenUndoFile(posOld); |
b19388dd | 2485 | if (fileOld) { |
1eb57879 | 2486 | if (fFinalize) |
ed6d1a2c | 2487 | TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nUndoSize); |
b19388dd PK |
2488 | FileCommit(fileOld); |
2489 | fclose(fileOld); | |
2490 | } | |
44d40f26 PW |
2491 | } |
2492 | ||
ef3988ca | 2493 | bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize); |
5382bcf8 | 2494 | |
f9cae832 PW |
2495 | static CCheckQueue<CScriptCheck> scriptcheckqueue(128); |
2496 | ||
21eb5ada | 2497 | void ThreadScriptCheck() { |
7662d72b | 2498 | RenameThread("zcash-scriptch"); |
f9cae832 | 2499 | scriptcheckqueue.Thread(); |
f9cae832 PW |
2500 | } |
2501 | ||
36cba8f1 GA |
2502 | // |
2503 | // Called periodically asynchronously; alerts if it smells like | |
2504 | // we're being fed a bad chain (blocks being generated much | |
2505 | // too slowly or too quickly). | |
2506 | // | |
fce474c9 GA |
2507 | void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader, |
2508 | int64_t nPowTargetSpacing) | |
36cba8f1 | 2509 | { |
fce474c9 | 2510 | if (bestHeader == NULL || initialDownloadCheck()) return; |
8d655683 | 2511 | |
36cba8f1 GA |
2512 | static int64_t lastAlertTime = 0; |
2513 | int64_t now = GetAdjustedTime(); | |
2514 | if (lastAlertTime > now-60*60*24) return; // Alert at most once per day | |
8d655683 | 2515 | |
36cba8f1 GA |
2516 | const int SPAN_HOURS=4; |
2517 | const int SPAN_SECONDS=SPAN_HOURS*60*60; | |
2518 | int BLOCKS_EXPECTED = SPAN_SECONDS / nPowTargetSpacing; | |
8d655683 | 2519 | |
36cba8f1 | 2520 | boost::math::poisson_distribution<double> poisson(BLOCKS_EXPECTED); |
8d655683 | 2521 | |
36cba8f1 GA |
2522 | std::string strWarning; |
2523 | int64_t startTime = GetAdjustedTime()-SPAN_SECONDS; | |
8d655683 | 2524 | |
36cba8f1 | 2525 | LOCK(cs); |
fce474c9 GA |
2526 | const CBlockIndex* i = bestHeader; |
2527 | int nBlocks = 0; | |
2528 | while (i->GetBlockTime() >= startTime) { | |
2529 | ++nBlocks; | |
2530 | i = i->pprev; | |
c938fb1f | 2531 | if (i == NULL) return; // Ran out of chain, we must not be fully synced |
fce474c9 | 2532 | } |
8d655683 | 2533 | |
36cba8f1 GA |
2534 | // How likely is it to find that many by chance? |
2535 | double p = boost::math::pdf(poisson, nBlocks); | |
8d655683 | 2536 | |
36cba8f1 GA |
2537 | LogPrint("partitioncheck", "%s : Found %d blocks in the last %d hours\n", __func__, nBlocks, SPAN_HOURS); |
2538 | LogPrint("partitioncheck", "%s : likelihood: %g\n", __func__, p); | |
8d655683 | 2539 | |
36cba8f1 GA |
2540 | // Aim for one false-positive about every fifty years of normal running: |
2541 | const int FIFTY_YEARS = 50*365*24*60*60; | |
2542 | double alertThreshold = 1.0 / (FIFTY_YEARS / SPAN_SECONDS); | |
8d655683 | 2543 | |
36cba8f1 GA |
2544 | if (p <= alertThreshold && nBlocks < BLOCKS_EXPECTED) |
2545 | { | |
2546 | // Many fewer blocks than expected: alert! | |
2547 | strWarning = strprintf(_("WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)"), | |
2548 | nBlocks, SPAN_HOURS, BLOCKS_EXPECTED); | |
2549 | } | |
2550 | else if (p <= alertThreshold && nBlocks > BLOCKS_EXPECTED) | |
2551 | { | |
2552 | // Many more blocks than expected: alert! | |
2553 | strWarning = strprintf(_("WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)"), | |
2554 | nBlocks, SPAN_HOURS, BLOCKS_EXPECTED); | |
2555 | } | |
2556 | if (!strWarning.empty()) | |
2557 | { | |
2558 | strMiscWarning = strWarning; | |
2559 | CAlert::Notify(strWarning, true); | |
2560 | lastAlertTime = now; | |
2561 | } | |
2562 | } | |
2563 | ||
d70bc52e PW |
2564 | static int64_t nTimeVerify = 0; |
2565 | static int64_t nTimeConnect = 0; | |
2566 | static int64_t nTimeIndex = 0; | |
2567 | static int64_t nTimeCallbacks = 0; | |
2568 | static int64_t nTimeTotal = 0; | |
2569 | ||
96f9009e | 2570 | bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck,bool fCheckPOW) |
0a61b0df | 2571 | { |
4e382177 | 2572 | const CChainParams& chainparams = Params(); |
8d655683 | 2573 | |
e0440cc3 | 2574 | //fprintf(stderr,"connectblock ht.%d\n",(int32_t)pindex->nHeight); |
b39a07dc | 2575 | AssertLockHeld(cs_main); |
bfa832c7 PW |
2576 | bool fExpensiveChecks = true; |
2577 | if (fCheckpointsEnabled) { | |
2578 | CBlockIndex *pindexLastCheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints()); | |
2579 | if (pindexLastCheckpoint && pindexLastCheckpoint->GetAncestor(pindex->nHeight) == pindex) { | |
2580 | // This block is an ancestor of a checkpoint: disable script checks | |
2581 | fExpensiveChecks = false; | |
2582 | } | |
2583 | } | |
6fb8d0c2 JG |
2584 | auto verifier = libzcash::ProofVerifier::Strict(); |
2585 | auto disabledVerifier = libzcash::ProofVerifier::Disabled(); | |
9f6cb8f0 | 2586 | int32_t futureblock; |
6fb8d0c2 | 2587 | // Check it again to verify JoinSplit proofs, and in case a previous version let a bad block in |
9f6cb8f0 | 2588 | if (!CheckBlock(&futureblock,pindex->nHeight,pindex,block, state, fExpensiveChecks ? verifier : disabledVerifier, fCheckPOW, !fJustCheck)) |
cdb2a22f | 2589 | { |
2590 | fprintf(stderr,"checkblock failure in connectblock\n"); | |
0a61b0df | 2591 | return false; |
cdb2a22f | 2592 | } |
8d655683 | 2593 | |
450cbb09 | 2594 | // verify that the view's current state corresponds to the previous block |
4f152496 | 2595 | uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash(); |
e3b04fea | 2596 | if ( hashPrevBlock != view.GetBestBlock() ) |
2597 | { | |
2598 | fprintf(stderr,"ConnectBlock(): hashPrevBlock != view.GetBestBlock()\n"); | |
2599 | return state.DoS(1, error("ConnectBlock(): hashPrevBlock != view.GetBestBlock()"), | |
2600 | REJECT_INVALID, "hashPrevBlock-not-bestblock"); | |
2601 | } | |
84674082 | 2602 | assert(hashPrevBlock == view.GetBestBlock()); |
8d655683 | 2603 | |
8301ff50 PW |
2604 | // Special case for the genesis block, skipping connection of its transactions |
2605 | // (its coinbase is unspendable) | |
4e382177 | 2606 | if (block.GetHash() == chainparams.GetConsensus().hashGenesisBlock) { |
6a7acc29 | 2607 | if (!fJustCheck) { |
1b178a7f | 2608 | view.SetBestBlock(pindex->GetBlockHash()); |
6a7acc29 JG |
2609 | // Before the genesis block, there was an empty tree |
2610 | ZCIncrementalMerkleTree tree; | |
2611 | pindex->hashAnchor = tree.root(); | |
0bc1e2c4 JG |
2612 | // The genesis block contained no JoinSplits |
2613 | pindex->hashAnchorEnd = pindex->hashAnchor; | |
6a7acc29 | 2614 | } |
8301ff50 PW |
2615 | return true; |
2616 | } | |
8d655683 | 2617 | |
a8cdaf5c | 2618 | bool fScriptChecks = (!fCheckpointsEnabled || pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints())); |
f8b5c164 | 2619 | //if ( KOMODO_TESTNET_EXPIRATION != 0 && pindex->nHeight > KOMODO_TESTNET_EXPIRATION ) // "testnet" |
2620 | // return(false); | |
a206b0ea PW |
2621 | // Do not allow blocks that contain transactions which 'overwrite' older transactions, |
2622 | // unless those are already completely spent. | |
b3be1ef5 | 2623 | BOOST_FOREACH(const CTransaction& tx, block.vtx) { |
805344dc | 2624 | const CCoins* coins = view.AccessCoins(tx.GetHash()); |
b3be1ef5 SB |
2625 | if (coins && !coins->IsPruned()) |
2626 | return state.DoS(100, error("ConnectBlock(): tried to overwrite transaction"), | |
2627 | REJECT_INVALID, "bad-txns-BIP30"); | |
450cbb09 | 2628 | } |
8d655683 | 2629 | |
de609b8c | 2630 | unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; |
8d655683 | 2631 | |
de609b8c | 2632 | // DERSIG (BIP66) is also always enforced, but does not have a flag. |
8d655683 | 2633 | |
8adf48dc | 2634 | CBlockUndo blockundo; |
8d655683 | 2635 | |
6fb8d0c2 | 2636 | CCheckQueueControl<CScriptCheck> control(fExpensiveChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL); |
8d655683 | 2637 | |
d70bc52e | 2638 | int64_t nTimeStart = GetTimeMicros(); |
a372168e | 2639 | CAmount nFees = 0; |
8a28bb6d | 2640 | int nInputs = 0; |
355ca565 | 2641 | int64_t interest,sum = 0; |
7bd9c3a3 | 2642 | unsigned int nSigOps = 0; |
f3ae51dc | 2643 | CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); |
2d1fa42e | 2644 | std::vector<std::pair<uint256, CDiskTxPos> > vPos; |
f3ae51dc | 2645 | vPos.reserve(block.vtx.size()); |
ab15b2ec | 2646 | blockundo.vtxundo.reserve(block.vtx.size() - 1); |
8b78a819 T |
2647 | std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; |
2648 | std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > addressUnspentIndex; | |
2649 | std::vector<std::pair<CSpentIndexKey, CSpentIndexValue> > spentIndex; | |
a8ac403d SB |
2650 | // Construct the incremental merkle tree at the current |
2651 | // block position, | |
2652 | auto old_tree_root = view.GetBestAnchor(); | |
b6961fc1 | 2653 | // saving the top anchor in the block index as we go. |
6a7acc29 JG |
2654 | if (!fJustCheck) { |
2655 | pindex->hashAnchor = old_tree_root; | |
2656 | } | |
434f3284 | 2657 | ZCIncrementalMerkleTree tree; |
a8ac403d SB |
2658 | // This should never fail: we should always be able to get the root |
2659 | // that is on the tip of our chain | |
2660 | assert(view.GetAnchorAt(old_tree_root, tree)); | |
8d655683 | 2661 | |
a8ac403d SB |
2662 | { |
2663 | // Consistency check: the root of the tree we're given should | |
2664 | // match what we asked for. | |
434f3284 | 2665 | assert(tree.root() == old_tree_root); |
a8ac403d | 2666 | } |
8d655683 | 2667 | |
be126699 JG |
2668 | // Grab the consensus branch ID for the block's height |
2669 | auto consensusBranchId = CurrentEpochBranchId(pindex->nHeight, Params().GetConsensus()); | |
8d655683 | 2670 | |
6514771a PW |
2671 | std::vector<PrecomputedTransactionData> txdata; |
2672 | txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated | |
f3ae51dc | 2673 | for (unsigned int i = 0; i < block.vtx.size(); i++) |
0a61b0df | 2674 | { |
f3ae51dc | 2675 | const CTransaction &tx = block.vtx[i]; |
8b78a819 | 2676 | const uint256 txhash = tx.GetHash(); |
8a28bb6d | 2677 | nInputs += tx.vin.size(); |
05df3fc6 | 2678 | nSigOps += GetLegacySigOpCount(tx); |
137d0685 | 2679 | if (nSigOps > MAX_BLOCK_SIGOPS) |
5262fde0 | 2680 | return state.DoS(100, error("ConnectBlock(): too many sigops"), |
14e7ffcc | 2681 | REJECT_INVALID, "bad-blk-sigops"); |
8d655683 | 2682 | //fprintf(stderr,"ht.%d vout0 t%u\n",pindex->nHeight,tx.nLockTime); |
8d7849b6 GA |
2683 | if (!tx.IsCoinBase()) |
2684 | { | |
05df3fc6 | 2685 | if (!view.HaveInputs(tx)) |
5262fde0 | 2686 | return state.DoS(100, error("ConnectBlock(): inputs missing/spent"), |
14e7ffcc | 2687 | REJECT_INVALID, "bad-txns-inputs-missingorspent"); |
8d655683 | 2688 | |
b7e4abd6 | 2689 | // are the JoinSplit's requirements met? |
ee964faf | 2690 | if (!view.HaveJoinSplitRequirements(tx)) |
b7e4abd6 SB |
2691 | return state.DoS(100, error("ConnectBlock(): JoinSplit requirements not met"), |
2692 | REJECT_INVALID, "bad-txns-joinsplit-requirements-not-met"); | |
8b78a819 T |
2693 | if (fAddressIndex || fSpentIndex) |
2694 | { | |
2695 | for (size_t j = 0; j < tx.vin.size(); j++) { | |
2696 | ||
2697 | const CTxIn input = tx.vin[j]; | |
2698 | const CTxOut &prevout = view.GetOutputFor(tx.vin[j]); | |
2699 | uint160 hashBytes; | |
2700 | int addressType; | |
2701 | ||
2702 | if (prevout.scriptPubKey.IsPayToScriptHash()) { | |
2703 | hashBytes = uint160(vector <unsigned char>(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22)); | |
2704 | addressType = 2; | |
2705 | } else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) { | |
2706 | hashBytes = uint160(vector <unsigned char>(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23)); | |
2707 | addressType = 1; | |
2708 | } else { | |
2709 | hashBytes.SetNull(); | |
2710 | addressType = 0; | |
2711 | } | |
2712 | ||
2713 | if (fAddressIndex && addressType > 0) { | |
2714 | // record spending activity | |
2715 | addressIndex.push_back(make_pair(CAddressIndexKey(addressType, hashBytes, pindex->nHeight, i, txhash, j, true), prevout.nValue * -1)); | |
2716 | ||
2717 | // remove address from unspent index | |
2718 | addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(addressType, hashBytes, input.prevout.hash, input.prevout.n), CAddressUnspentValue())); | |
2719 | } | |
2720 | ||
2721 | if (fSpentIndex) { | |
2722 | // add the spent index to determine the txid and input that spent an output | |
2723 | // and to find the amount and address from an input | |
2724 | spentIndex.push_back(make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue(txhash, j, pindex->nHeight, prevout.nValue, addressType, hashBytes))); | |
2725 | } | |
2726 | } | |
2727 | ||
2728 | } | |
b3be1ef5 SB |
2729 | // Add in sigops done by pay-to-script-hash inputs; |
2730 | // this is to prevent a "rogue miner" from creating | |
2731 | // an incredibly-expensive-to-validate block. | |
2732 | nSigOps += GetP2SHSigOpCount(tx, view); | |
2733 | if (nSigOps > MAX_BLOCK_SIGOPS) | |
2734 | return state.DoS(100, error("ConnectBlock(): too many sigops"), | |
2735 | REJECT_INVALID, "bad-blk-sigops"); | |
f762d449 | 2736 | } |
8d655683 | 2737 | |
6514771a | 2738 | txdata.emplace_back(tx); |
8d655683 | 2739 | |
f762d449 PW |
2740 | if (!tx.IsCoinBase()) |
2741 | { | |
17878015 | 2742 | nFees += view.GetValueIn(chainActive.Tip()->nHeight,&interest,tx,chainActive.Tip()->nTime) - tx.GetValueOut(); |
355ca565 | 2743 | sum += interest; |
8d655683 | 2744 | |
f9cae832 | 2745 | std::vector<CScriptCheck> vChecks; |
be126699 | 2746 | if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, txdata[i], chainparams.GetConsensus(), consensusBranchId, nScriptCheckThreads ? &vChecks : NULL)) |
40634605 | 2747 | return false; |
f9cae832 | 2748 | control.Add(vChecks); |
8d7849b6 | 2749 | } |
8b78a819 T |
2750 | |
2751 | if (fAddressIndex) { | |
2752 | for (unsigned int k = 0; k < tx.vout.size(); k++) { | |
2753 | const CTxOut &out = tx.vout[k]; | |
2754 | ||
2755 | if (out.scriptPubKey.IsPayToScriptHash()) { | |
2756 | vector<unsigned char> hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22); | |
2757 | ||
2758 | // record receiving activity | |
2759 | addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, txhash, k, false), out.nValue)); | |
2760 | ||
2761 | // record unspent output | |
2762 | addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(2, uint160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight))); | |
2763 | ||
2764 | } else if (out.scriptPubKey.IsPayToPublicKeyHash()) { | |
2765 | vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23); | |
2766 | ||
2767 | // record receiving activity | |
2768 | addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, txhash, k, false), out.nValue)); | |
2769 | ||
2770 | // record unspent output | |
2771 | addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight))); | |
2772 | ||
2773 | } else { | |
2774 | continue; | |
2775 | } | |
2776 | ||
2777 | } | |
2778 | } | |
2779 | ||
314350e6 | 2780 | //if ( ASSETCHAINS_SYMBOL[0] == 0 ) |
2781 | // komodo_earned_interest(pindex->nHeight,sum); | |
ab15b2ec PW |
2782 | CTxUndo undoDummy; |
2783 | if (i > 0) { | |
2784 | blockundo.vtxundo.push_back(CTxUndo()); | |
2785 | } | |
8cb98d91 | 2786 | UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight); |
8d655683 | 2787 | |
b7e4abd6 | 2788 | BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { |
4bc00dc1 DH |
2789 | BOOST_FOREACH(const uint256 ¬e_commitment, joinsplit.commitments) { |
2790 | // Insert the note commitments into our temporary tree. | |
8d655683 | 2791 | |
4bc00dc1 | 2792 | tree.append(note_commitment); |
a8ac403d SB |
2793 | } |
2794 | } | |
8d655683 | 2795 | |
805344dc | 2796 | vPos.push_back(std::make_pair(tx.GetHash(), pos)); |
2d1fa42e | 2797 | pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); |
0a61b0df | 2798 | } |
8d655683 | 2799 | |
a8ac403d | 2800 | view.PushAnchor(tree); |
0bc1e2c4 JG |
2801 | if (!fJustCheck) { |
2802 | pindex->hashAnchorEnd = tree.root(); | |
2803 | } | |
a8ac403d | 2804 | blockundo.old_tree_root = old_tree_root; |
8d655683 | 2805 | |
d70bc52e PW |
2806 | int64_t nTime1 = GetTimeMicros(); nTimeConnect += nTime1 - nTimeStart; |
2807 | LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001); | |
8d655683 | 2808 | |
6b30b27c | 2809 | CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()) + sum; |
18443f69 | 2810 | if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 ) |
de4a435c | 2811 | { |
2812 | uint64_t checktoshis; | |
18443f69 | 2813 | if ( (checktoshis= komodo_commission((CBlock *)&block)) != 0 ) |
de4a435c | 2814 | { |
2815 | if ( block.vtx[0].vout.size() == 2 && block.vtx[0].vout[1].nValue == checktoshis ) | |
b7dc5699 | 2816 | blockReward += checktoshis; |
2808b68f | 2817 | else fprintf(stderr,"checktoshis %.8f numvouts %d\n",dstr(checktoshis),(int32_t)block.vtx[0].vout.size()); |
de4a435c | 2818 | } |
2819 | } | |
cf7f4402 | 2820 | if ( block.vtx[0].GetValueOut() > blockReward+1 ) |
0b652b66 | 2821 | { |
ea124428 | 2822 | if ( ASSETCHAINS_SYMBOL[0] != 0 || pindex->nHeight >= KOMODO_NOTARIES_HEIGHT1 || block.vtx[0].vout[0].nValue > blockReward ) |
0b652b66 | 2823 | { |
2824 | return state.DoS(100, | |
8d655683 | 2825 | error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)", |
2826 | block.vtx[0].GetValueOut(), blockReward), | |
2827 | REJECT_INVALID, "bad-cb-amount"); | |
ea124428 | 2828 | } else if ( NOTARY_PUBKEY33[0] != 0 ) |
cf7f4402 | 2829 | fprintf(stderr,"allow nHeight.%d coinbase %.8f vs %.8f interest %.8f\n",(int32_t)pindex->nHeight,dstr(block.vtx[0].GetValueOut()),dstr(blockReward),dstr(sum)); |
0b652b66 | 2830 | } |
f9cae832 | 2831 | if (!control.Wait()) |
ef3988ca | 2832 | return state.DoS(100, false); |
d70bc52e PW |
2833 | int64_t nTime2 = GetTimeMicros(); nTimeVerify += nTime2 - nTimeStart; |
2834 | LogPrint("bench", " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs]\n", nInputs - 1, 0.001 * (nTime2 - nTimeStart), nInputs <= 1 ? 0 : 0.001 * (nTime2 - nTimeStart) / (nInputs-1), nTimeVerify * 0.000001); | |
8d655683 | 2835 | |
3cd01fdf LD |
2836 | if (fJustCheck) |
2837 | return true; | |
8d655683 | 2838 | |
5382bcf8 | 2839 | // Write undo information to disk |
942b33a1 | 2840 | if (pindex->GetUndoPos().IsNull() || !pindex->IsValid(BLOCK_VALID_SCRIPTS)) |
5382bcf8 | 2841 | { |
857c61df PW |
2842 | if (pindex->GetUndoPos().IsNull()) { |
2843 | CDiskBlockPos pos; | |
ef3988ca | 2844 | if (!FindUndoPos(state, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40)) |
5262fde0 | 2845 | return error("ConnectBlock(): FindUndoPos failed"); |
e6973430 | 2846 | if (!UndoWriteToDisk(blockundo, pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart())) |
27afcd89 | 2847 | return AbortNode(state, "Failed to write undo data"); |
8d655683 | 2848 | |
857c61df PW |
2849 | // update nUndoPos in block index |
2850 | pindex->nUndoPos = pos.nPos; | |
2851 | pindex->nStatus |= BLOCK_HAVE_UNDO; | |
2852 | } | |
8d655683 | 2853 | |
828940b1 | 2854 | // Now that all consensus rules have been validated, set nCachedBranchId. |
9e851450 JG |
2855 | // Move this if BLOCK_VALID_CONSENSUS is ever altered. |
2856 | static_assert(BLOCK_VALID_CONSENSUS == BLOCK_VALID_SCRIPTS, | |
8d655683 | 2857 | "nCachedBranchId must be set after all consensus rules have been validated."); |
9e851450 JG |
2858 | if (IsActivationHeightForAnyUpgrade(pindex->nHeight, Params().GetConsensus())) { |
2859 | pindex->nStatus |= BLOCK_ACTIVATES_UPGRADE; | |
828940b1 | 2860 | pindex->nCachedBranchId = CurrentEpochBranchId(pindex->nHeight, chainparams.GetConsensus()); |
9e851450 | 2861 | } else if (pindex->pprev) { |
828940b1 | 2862 | pindex->nCachedBranchId = pindex->pprev->nCachedBranchId; |
9e851450 | 2863 | } |
8d655683 | 2864 | |
942b33a1 | 2865 | pindex->RaiseValidity(BLOCK_VALID_SCRIPTS); |
51ce901a | 2866 | setDirtyBlockIndex.insert(pindex); |
0a61b0df | 2867 | } |
8d655683 | 2868 | |
2d1fa42e | 2869 | if (fTxIndex) |
ef3988ca | 2870 | if (!pblocktree->WriteTxIndex(vPos)) |
27afcd89 | 2871 | return AbortNode(state, "Failed to write transaction index"); |
8b78a819 T |
2872 | if (fAddressIndex) { |
2873 | if (!pblocktree->WriteAddressIndex(addressIndex)) { | |
2874 | return AbortNode(state, "Failed to write address index"); | |
2875 | } | |
2876 | ||
2877 | if (!pblocktree->UpdateAddressUnspentIndex(addressUnspentIndex)) { | |
2878 | return AbortNode(state, "Failed to write address unspent index"); | |
2879 | } | |
2880 | } | |
2881 | ||
2882 | if (fSpentIndex) | |
2883 | if (!pblocktree->UpdateSpentIndex(spentIndex)) | |
2884 | return AbortNode(state, "Failed to write transaction index"); | |
2885 | ||
2886 | if (fTimestampIndex) { | |
2887 | unsigned int logicalTS = pindex->nTime; | |
2888 | unsigned int prevLogicalTS = 0; | |
2889 | ||
2890 | // retrieve logical timestamp of the previous block | |
2891 | if (pindex->pprev) | |
2892 | if (!pblocktree->ReadTimestampBlockIndex(pindex->pprev->GetBlockHash(), prevLogicalTS)) | |
2893 | LogPrintf("%s: Failed to read previous block's logical timestamp\n", __func__); | |
2894 | ||
2895 | if (logicalTS <= prevLogicalTS) { | |
2896 | logicalTS = prevLogicalTS + 1; | |
2897 | LogPrintf("%s: Previous logical timestamp is newer Actual[%d] prevLogical[%d] Logical[%d]\n", __func__, pindex->nTime, prevLogicalTS, logicalTS); | |
2898 | } | |
2899 | ||
2900 | if (!pblocktree->WriteTimestampIndex(CTimestampIndexKey(logicalTS, pindex->GetBlockHash()))) | |
2901 | return AbortNode(state, "Failed to write timestamp index"); | |
2902 | ||
2903 | if (!pblocktree->WriteTimestampBlockIndex(CTimestampBlockIndexKey(pindex->GetBlockHash()), CTimestampBlockIndexValue(logicalTS))) | |
2904 | return AbortNode(state, "Failed to write blockhash index"); | |
2905 | } | |
2906 | ||
729b1806 | 2907 | // add this block to the view's block chain |
c9d1a81c | 2908 | view.SetBestBlock(pindex->GetBlockHash()); |
8d655683 | 2909 | |
d70bc52e PW |
2910 | int64_t nTime3 = GetTimeMicros(); nTimeIndex += nTime3 - nTime2; |
2911 | LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeIndex * 0.000001); | |
8d655683 | 2912 | |
202e0194 PW |
2913 | // Watch for changes to the previous coinbase transaction. |
2914 | static uint256 hashPrevBestCoinBase; | |
26c16d9d | 2915 | GetMainSignals().UpdatedTransaction(hashPrevBestCoinBase); |
805344dc | 2916 | hashPrevBestCoinBase = block.vtx[0].GetHash(); |
8d655683 | 2917 | |
d70bc52e PW |
2918 | int64_t nTime4 = GetTimeMicros(); nTimeCallbacks += nTime4 - nTime3; |
2919 | LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeCallbacks * 0.000001); | |
a0344f90 | 2920 | |
0f42af4c | 2921 | //FlushStateToDisk(); |
651989c7 | 2922 | komodo_connectblock(pindex,*(CBlock *)&block); |
0a61b0df | 2923 | return true; |
2924 | } | |
2925 | ||
a2069500 | 2926 | enum FlushStateMode { |
f9ec3f0f | 2927 | FLUSH_STATE_NONE, |
a2069500 PW |
2928 | FLUSH_STATE_IF_NEEDED, |
2929 | FLUSH_STATE_PERIODIC, | |
2930 | FLUSH_STATE_ALWAYS | |
2931 | }; | |
2932 | ||
51ce901a PW |
2933 | /** |
2934 | * Update the on-disk chain state. | |
f9ec3f0f | 2935 | * The caches and indexes are flushed depending on the mode we're called with |
2936 | * if they're too large, if it's been a while since the last write, | |
2937 | * or always and in all cases if we're in prune mode and are deleting files. | |
51ce901a | 2938 | */ |
a2069500 | 2939 | bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) { |
f9ec3f0f | 2940 | LOCK2(cs_main, cs_LastBlockFile); |
75f51f2a | 2941 | static int64_t nLastWrite = 0; |
67708acf PW |
2942 | static int64_t nLastFlush = 0; |
2943 | static int64_t nLastSetChain = 0; | |
f9ec3f0f | 2944 | std::set<int> setFilesToPrune; |
2945 | bool fFlushForPrune = false; | |
e4134579 | 2946 | try { |
8d655683 | 2947 | if (fPruneMode && fCheckForPruning && !fReindex) { |
2948 | FindFilesToPrune(setFilesToPrune); | |
2949 | fCheckForPruning = false; | |
2950 | if (!setFilesToPrune.empty()) { | |
2951 | fFlushForPrune = true; | |
2952 | if (!fHavePruned) { | |
2953 | pblocktree->WriteFlag("prunedblockfiles", true); | |
2954 | fHavePruned = true; | |
2955 | } | |
f9ec3f0f | 2956 | } |
2957 | } | |
8d655683 | 2958 | int64_t nNow = GetTimeMicros(); |
2959 | // Avoid writing/flushing immediately after startup. | |
2960 | if (nLastWrite == 0) { | |
2961 | nLastWrite = nNow; | |
2962 | } | |
2963 | if (nLastFlush == 0) { | |
2964 | nLastFlush = nNow; | |
2965 | } | |
2966 | if (nLastSetChain == 0) { | |
2967 | nLastSetChain = nNow; | |
2968 | } | |
2969 | size_t cacheSize = pcoinsTip->DynamicMemoryUsage(); | |
2970 | // The cache is large and close to the limit, but we have time now (not in the middle of a block processing). | |
2971 | bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize * (10.0/9) > nCoinCacheUsage; | |
2972 | // The cache is over the limit, we have to write now. | |
2973 | bool fCacheCritical = mode == FLUSH_STATE_IF_NEEDED && cacheSize > nCoinCacheUsage; | |
2974 | // It's been a while since we wrote the block index to disk. Do this frequently, so we don't need to redownload after a crash. | |
2975 | bool fPeriodicWrite = mode == FLUSH_STATE_PERIODIC && nNow > nLastWrite + (int64_t)DATABASE_WRITE_INTERVAL * 1000000; | |
2976 | // It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage. | |
2977 | bool fPeriodicFlush = mode == FLUSH_STATE_PERIODIC && nNow > nLastFlush + (int64_t)DATABASE_FLUSH_INTERVAL * 1000000; | |
2978 | // Combine all conditions that result in a full cache flush. | |
2979 | bool fDoFullFlush = (mode == FLUSH_STATE_ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune; | |
2980 | // Write blocks and block index to disk. | |
2981 | if (fDoFullFlush || fPeriodicWrite) { | |
2982 | // Depend on nMinDiskSpace to ensure we can write block index | |
2983 | if (!CheckDiskSpace(0)) | |
2984 | return state.Error("out of disk space"); | |
2985 | // First make sure all block and undo data is flushed to disk. | |
2986 | FlushBlockFile(); | |
2987 | // Then update all block file information (which may refer to block and undo files). | |
2988 | { | |
2989 | std::vector<std::pair<int, const CBlockFileInfo*> > vFiles; | |
2990 | vFiles.reserve(setDirtyFileInfo.size()); | |
2991 | for (set<int>::iterator it = setDirtyFileInfo.begin(); it != setDirtyFileInfo.end(); ) { | |
2992 | vFiles.push_back(make_pair(*it, &vinfoBlockFile[*it])); | |
2993 | setDirtyFileInfo.erase(it++); | |
2994 | } | |
2995 | std::vector<const CBlockIndex*> vBlocks; | |
2996 | vBlocks.reserve(setDirtyBlockIndex.size()); | |
2997 | for (set<CBlockIndex*>::iterator it = setDirtyBlockIndex.begin(); it != setDirtyBlockIndex.end(); ) { | |
2998 | vBlocks.push_back(*it); | |
2999 | setDirtyBlockIndex.erase(it++); | |
3000 | } | |
3001 | if (!pblocktree->WriteBatchSync(vFiles, nLastBlockFile, vBlocks)) { | |
3002 | return AbortNode(state, "Files to write to block index database"); | |
3003 | } | |
51ce901a | 3004 | } |
8d655683 | 3005 | // Finally remove any pruned files |
3006 | if (fFlushForPrune) | |
3007 | UnlinkPrunedFiles(setFilesToPrune); | |
3008 | nLastWrite = nNow; | |
3009 | } | |
3010 | // Flush best chain related state. This can only be done if the blocks / block index write was also done. | |
3011 | if (fDoFullFlush) { | |
3012 | // Typical CCoins structures on disk are around 128 bytes in size. | |
3013 | // Pushing a new one to the database can cause it to be written | |
3014 | // twice (once in the log, and once in the tables). This is already | |
3015 | // an overestimation, as most will delete an existing entry or | |
3016 | // overwrite one. Still, use a conservative safety factor of 2. | |
3017 | if (!CheckDiskSpace(128 * 2 * 2 * pcoinsTip->GetCacheSize())) | |
3018 | return state.Error("out of disk space"); | |
3019 | // Flush the chainstate (which may refer to block index entries). | |
3020 | if (!pcoinsTip->Flush()) | |
3021 | return AbortNode(state, "Failed to write to coin database"); | |
3022 | nLastFlush = nNow; | |
3023 | } | |
3024 | if ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000) { | |
3025 | // Update best block in wallet (so we can detect restored wallets). | |
3026 | GetMainSignals().SetBestChain(chainActive.GetLocator()); | |
3027 | nLastSetChain = nNow; | |
51ce901a | 3028 | } |
e4134579 | 3029 | } catch (const std::runtime_error& e) { |
27afcd89 | 3030 | return AbortNode(state, std::string("System error while flushing: ") + e.what()); |
e4134579 | 3031 | } |
0ec16f35 PW |
3032 | return true; |
3033 | } | |
450cbb09 | 3034 | |
51ce901a PW |
3035 | void FlushStateToDisk() { |
3036 | CValidationState state; | |
a2069500 | 3037 | FlushStateToDisk(state, FLUSH_STATE_ALWAYS); |
51ce901a PW |
3038 | } |
3039 | ||
f9ec3f0f | 3040 | void PruneAndFlush() { |
3041 | CValidationState state; | |
3042 | fCheckForPruning = true; | |
3043 | FlushStateToDisk(state, FLUSH_STATE_NONE); | |
3044 | } | |
3045 | ||
c5b390b6 | 3046 | /** Update chainActive and related internal data structures. */ |
0ec16f35 | 3047 | void static UpdateTip(CBlockIndex *pindexNew) { |
11982d36 | 3048 | const CChainParams& chainParams = Params(); |
4c6d41b8 | 3049 | chainActive.SetTip(pindexNew); |
8d655683 | 3050 | |
0a61b0df | 3051 | // New best block |
0a61b0df | 3052 | nTimeBestReceived = GetTime(); |
319b1160 | 3053 | mempool.AddTransactionsUpdated(1); |
03e2210d | 3054 | KOMODO_NEWBLOCKS++; |
b0ae7941 | 3055 | LogPrintf("%s: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%.1fMiB(%utx)\n", __func__, |
8d655683 | 3056 | chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx, |
3057 | DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), | |
3058 | Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize()); | |
3059 | ||
ff6a7af1 | 3060 | cvBlockChange.notify_all(); |
8d655683 | 3061 | |
2a919e39 | 3062 | // Check the version of the last 100 blocks to see if we need to upgrade: |
dbca89b7 GA |
3063 | static bool fWarned = false; |
3064 | if (!IsInitialBlockDownload() && !fWarned) | |
2a919e39 GA |
3065 | { |
3066 | int nUpgraded = 0; | |
4c6d41b8 | 3067 | const CBlockIndex* pindex = chainActive.Tip(); |
2a919e39 GA |
3068 | for (int i = 0; i < 100 && pindex != NULL; i++) |
3069 | { | |
3070 | if (pindex->nVersion > CBlock::CURRENT_VERSION) | |
3071 | ++nUpgraded; | |
3072 | pindex = pindex->pprev; | |
3073 | } | |
3074 | if (nUpgraded > 0) | |
30c1db1c | 3075 | LogPrintf("%s: %d of last 100 blocks above version %d\n", __func__, nUpgraded, (int)CBlock::CURRENT_VERSION); |
2a919e39 | 3076 | if (nUpgraded > 100/2) |
dbca89b7 | 3077 | { |
07cf4264 | 3078 | // strMiscWarning is read by GetWarnings(), called by the JSON-RPC code to warn the user: |
7e6d23b1 | 3079 | strMiscWarning = _("Warning: This version is obsolete; upgrade required!"); |
dbca89b7 GA |
3080 | CAlert::Notify(strMiscWarning, true); |
3081 | fWarned = true; | |
3082 | } | |
2a919e39 | 3083 | } |
75f51f2a | 3084 | } |
2a919e39 | 3085 | |
34a64fe0 JG |
3086 | /** |
3087 | * Disconnect chainActive's tip. You probably want to call mempool.removeForReorg and | |
3088 | * mempool.removeWithoutBranchId after this, with cs_main held. | |
3089 | */ | |
89f20450 | 3090 | bool static DisconnectTip(CValidationState &state, bool fBare = false) { |
75f51f2a PW |
3091 | CBlockIndex *pindexDelete = chainActive.Tip(); |
3092 | assert(pindexDelete); | |
75f51f2a PW |
3093 | // Read block from disk. |
3094 | CBlock block; | |
b8add6a4 | 3095 | if (!ReadBlockFromDisk(block, pindexDelete,1)) |
27afcd89 | 3096 | return AbortNode(state, "Failed to read block"); |
75f51f2a | 3097 | // Apply the block atomically to the chain state. |
a8ac403d | 3098 | uint256 anchorBeforeDisconnect = pcoinsTip->GetBestAnchor(); |
75f51f2a | 3099 | int64_t nStart = GetTimeMicros(); |
d237f62c | 3100 | { |
7c70438d | 3101 | CCoinsViewCache view(pcoinsTip); |
75f51f2a | 3102 | if (!DisconnectBlock(block, state, pindexDelete, view)) |
5262fde0 | 3103 | return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString()); |
75f51f2a | 3104 | assert(view.Flush()); |
d237f62c | 3105 | } |
d70bc52e | 3106 | LogPrint("bench", "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); |
a8ac403d | 3107 | uint256 anchorAfterDisconnect = pcoinsTip->GetBestAnchor(); |
75f51f2a | 3108 | // Write the chain state to disk, if necessary. |
a2069500 | 3109 | if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED)) |
75f51f2a | 3110 | return false; |
8d655683 | 3111 | |
89f20450 PW |
3112 | if (!fBare) { |
3113 | // Resurrect mempool transactions from the disconnected block. | |
3114 | BOOST_FOREACH(const CTransaction &tx, block.vtx) { | |
3115 | // ignore validation errors in resurrected transactions | |
3116 | list<CTransaction> removed; | |
3117 | CValidationState stateDummy; | |
3118 | if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL)) | |
3119 | mempool.remove(tx, removed, true); | |
3120 | } | |
3121 | if (anchorBeforeDisconnect != anchorAfterDisconnect) { | |
3122 | // The anchor may not change between block disconnects, | |
3123 | // in which case we don't want to evict from the mempool yet! | |
3124 | mempool.removeWithAnchor(anchorBeforeDisconnect); | |
3125 | } | |
89f20450 | 3126 | } |
8d655683 | 3127 | |
75f51f2a PW |
3128 | // Update chainActive and related variables. |
3129 | UpdateTip(pindexDelete->pprev); | |
de42390f JG |
3130 | // Get the current commitment tree |
3131 | ZCIncrementalMerkleTree newTree; | |
3132 | assert(pcoinsTip->GetAnchorAt(pcoinsTip->GetBestAnchor(), newTree)); | |
93a18a36 GA |
3133 | // Let wallets know transactions went from 1-confirmed to |
3134 | // 0-confirmed or conflicted: | |
3135 | BOOST_FOREACH(const CTransaction &tx, block.vtx) { | |
d38da59b | 3136 | SyncWithWallets(tx, NULL); |
93a18a36 | 3137 | } |
769e031c | 3138 | // Update cached incremental witnesses |
e0440cc3 | 3139 | //fprintf(stderr,"chaintip false\n"); |
de42390f | 3140 | GetMainSignals().ChainTip(pindexDelete, &block, newTree, false); |
75f51f2a | 3141 | return true; |
0ec16f35 | 3142 | } |
d237f62c | 3143 | |
d70bc52e PW |
3144 | static int64_t nTimeReadFromDisk = 0; |
3145 | static int64_t nTimeConnectTotal = 0; | |
3146 | static int64_t nTimeFlush = 0; | |
3147 | static int64_t nTimeChainState = 0; | |
3148 | static int64_t nTimePostConnect = 0; | |
3149 | ||
db954a65 | 3150 | /** |
c5b390b6 MF |
3151 | * Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock |
3152 | * corresponding to pindexNew, to bypass loading it again from disk. | |
34a64fe0 | 3153 | * You probably want to call mempool.removeWithoutBranchId after this, with cs_main held. |
c5b390b6 | 3154 | */ |
92bb6f2f | 3155 | bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *pblock) { |
76374710 | 3156 | |
75f51f2a | 3157 | assert(pindexNew->pprev == chainActive.Tip()); |
75f51f2a | 3158 | // Read block from disk. |
d70bc52e | 3159 | int64_t nTime1 = GetTimeMicros(); |
75f51f2a | 3160 | CBlock block; |
92bb6f2f | 3161 | if (!pblock) { |
b8add6a4 | 3162 | if (!ReadBlockFromDisk(block, pindexNew,1)) |
27afcd89 | 3163 | return AbortNode(state, "Failed to read block"); |
92bb6f2f PW |
3164 | pblock = █ |
3165 | } | |
de42390f JG |
3166 | // Get the current commitment tree |
3167 | ZCIncrementalMerkleTree oldTree; | |
3168 | assert(pcoinsTip->GetAnchorAt(pcoinsTip->GetBestAnchor(), oldTree)); | |
75f51f2a | 3169 | // Apply the block atomically to the chain state. |
d70bc52e PW |
3170 | int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1; |
3171 | int64_t nTime3; | |
3172 | LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001); | |
0a61b0df | 3173 | { |
7c70438d | 3174 | CCoinsViewCache view(pcoinsTip); |
96f9009e | 3175 | bool rv = ConnectBlock(*pblock, state, pindexNew, view, false, true); |
26c16d9d | 3176 | GetMainSignals().BlockChecked(*pblock, state); |
24e88964 | 3177 | if (!rv) { |
75f51f2a PW |
3178 | if (state.IsInvalid()) |
3179 | InvalidBlockFound(pindexNew, state); | |
5262fde0 | 3180 | return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); |
7851033d | 3181 | } |
2af5a650 | 3182 | mapBlockSource.erase(pindexNew->GetBlockHash()); |
d70bc52e PW |
3183 | nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2; |
3184 | LogPrint("bench", " - Connect total: %.2fms [%.2fs]\n", (nTime3 - nTime2) * 0.001, nTimeConnectTotal * 0.000001); | |
75f51f2a | 3185 | assert(view.Flush()); |
0a61b0df | 3186 | } |
d70bc52e PW |
3187 | int64_t nTime4 = GetTimeMicros(); nTimeFlush += nTime4 - nTime3; |
3188 | LogPrint("bench", " - Flush: %.2fms [%.2fs]\n", (nTime4 - nTime3) * 0.001, nTimeFlush * 0.000001); | |
75f51f2a | 3189 | // Write the chain state to disk, if necessary. |
a2069500 | 3190 | if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED)) |
75f51f2a | 3191 | return false; |
d70bc52e PW |
3192 | int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4; |
3193 | LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001); | |
75f51f2a | 3194 | // Remove conflicting transactions from the mempool. |
93a18a36 | 3195 | list<CTransaction> txConflicted; |
b649e039 | 3196 | mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted, !IsInitialBlockDownload()); |
8d655683 | 3197 | |
9bb37bf0 JG |
3198 | // Remove transactions that expire at new block height from mempool |
3199 | mempool.removeExpired(pindexNew->nHeight); | |
8d655683 | 3200 | |
75f51f2a | 3201 | // Update chainActive & related variables. |
880b2931 | 3202 | UpdateTip(pindexNew); |
93a18a36 GA |
3203 | // Tell wallet about transactions that went from mempool |
3204 | // to conflicted: | |
3205 | BOOST_FOREACH(const CTransaction &tx, txConflicted) { | |
d38da59b | 3206 | SyncWithWallets(tx, NULL); |
93a18a36 GA |
3207 | } |
3208 | // ... and about transactions that got confirmed: | |
92bb6f2f PW |
3209 | BOOST_FOREACH(const CTransaction &tx, pblock->vtx) { |
3210 | SyncWithWallets(tx, pblock); | |
93a18a36 | 3211 | } |
769e031c | 3212 | // Update cached incremental witnesses |
e0440cc3 | 3213 | //fprintf(stderr,"chaintip true\n"); |
de42390f | 3214 | GetMainSignals().ChainTip(pindexNew, pblock, oldTree, true); |
8d655683 | 3215 | |
5b3bc971 | 3216 | EnforceNodeDeprecation(pindexNew->nHeight); |
8d655683 | 3217 | |
d70bc52e PW |
3218 | int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; |
3219 | LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001); | |
3220 | LogPrint("bench", "- Connect block: %.2fms [%.2fs]\n", (nTime6 - nTime1) * 0.001, nTimeTotal * 0.000001); | |
0a61b0df | 3221 | return true; |
3222 | } | |
3223 | ||
c5b390b6 MF |
3224 | /** |
3225 | * Return the tip of the chain with the most work in it, that isn't | |
3226 | * known to be invalid (it's however far from certain to be valid). | |
3227 | */ | |
77339e5a | 3228 | static CBlockIndex* FindMostWorkChain() { |
75f51f2a | 3229 | do { |
77339e5a | 3230 | CBlockIndex *pindexNew = NULL; |
8d655683 | 3231 | |
75f51f2a PW |
3232 | // Find the best candidate header. |
3233 | { | |
e17bd583 PW |
3234 | std::set<CBlockIndex*, CBlockIndexWorkComparator>::reverse_iterator it = setBlockIndexCandidates.rbegin(); |
3235 | if (it == setBlockIndexCandidates.rend()) | |
77339e5a | 3236 | return NULL; |
75f51f2a PW |
3237 | pindexNew = *it; |
3238 | } | |
8d655683 | 3239 | |
75f51f2a PW |
3240 | // Check whether all blocks on the path between the currently active chain and the candidate are valid. |
3241 | // Just going until the active chain is an optimization, as we know all blocks in it are valid already. | |
3242 | CBlockIndex *pindexTest = pindexNew; | |
3243 | bool fInvalidAncestor = false; | |
3244 | while (pindexTest && !chainActive.Contains(pindexTest)) { | |
341735eb | 3245 | assert(pindexTest->nChainTx || pindexTest->nHeight == 0); |
8d655683 | 3246 | |
f9ec3f0f | 3247 | // Pruned nodes may have entries in setBlockIndexCandidates for |
3248 | // which block files have been deleted. Remove those as candidates | |
3249 | // for the most work chain if we come across them; we can't switch | |
3250 | // to a chain unless we have all the non-active-chain parent blocks. | |
3251 | bool fFailedChain = pindexTest->nStatus & BLOCK_FAILED_MASK; | |
3252 | bool fMissingData = !(pindexTest->nStatus & BLOCK_HAVE_DATA); | |
3253 | if (fFailedChain || fMissingData) { | |
3254 | // Candidate chain is not usable (either invalid or missing data) | |
3255 | if (fFailedChain && (pindexBestInvalid == NULL || pindexNew->nChainWork > pindexBestInvalid->nChainWork)) | |
942b33a1 PW |
3256 | pindexBestInvalid = pindexNew; |
3257 | CBlockIndex *pindexFailed = pindexNew; | |
f9ec3f0f | 3258 | // Remove the entire chain from the set. |
75f51f2a | 3259 | while (pindexTest != pindexFailed) { |
f9ec3f0f | 3260 | if (fFailedChain) { |
3261 | pindexFailed->nStatus |= BLOCK_FAILED_CHILD; | |
3262 | } else if (fMissingData) { | |
3263 | // If we're missing data, then add back to mapBlocksUnlinked, | |
3264 | // so that if the block arrives in the future we can try adding | |
3265 | // to setBlockIndexCandidates again. | |
3266 | mapBlocksUnlinked.insert(std::make_pair(pindexFailed->pprev, pindexFailed)); | |
3267 | } | |
e17bd583 | 3268 | setBlockIndexCandidates.erase(pindexFailed); |
75f51f2a PW |
3269 | pindexFailed = pindexFailed->pprev; |
3270 | } | |
e17bd583 | 3271 | setBlockIndexCandidates.erase(pindexTest); |
75f51f2a PW |
3272 | fInvalidAncestor = true; |
3273 | break; | |
ef3988ca | 3274 | } |
75f51f2a | 3275 | pindexTest = pindexTest->pprev; |
0a61b0df | 3276 | } |
77339e5a PW |
3277 | if (!fInvalidAncestor) |
3278 | return pindexNew; | |
75f51f2a | 3279 | } while(true); |
75f51f2a | 3280 | } |
0a61b0df | 3281 | |
c5b390b6 | 3282 | /** Delete all entries in setBlockIndexCandidates that are worse than the current tip. */ |
cca48f69 | 3283 | static void PruneBlockIndexCandidates() { |
3284 | // Note that we can't delete the current block itself, as we may need to return to it later in case a | |
3285 | // reorganization to a better block fails. | |
3286 | std::set<CBlockIndex*, CBlockIndexWorkComparator>::iterator it = setBlockIndexCandidates.begin(); | |
34559c7c | 3287 | while (it != setBlockIndexCandidates.end() && setBlockIndexCandidates.value_comp()(*it, chainActive.Tip())) { |
cca48f69 | 3288 | setBlockIndexCandidates.erase(it++); |
3289 | } | |
34559c7c PW |
3290 | // Either the current tip or a successor of it we're working towards is left in setBlockIndexCandidates. |
3291 | assert(!setBlockIndexCandidates.empty()); | |
cca48f69 | 3292 | } |
3293 | ||
c5b390b6 MF |
3294 | /** |
3295 | * Try to make some progress towards making pindexMostWork the active block. | |
3296 | * pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork. | |
3297 | */ | |
92bb6f2f | 3298 | static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork, CBlock *pblock) { |
4e0eed88 | 3299 | AssertLockHeld(cs_main); |
202e0194 | 3300 | bool fInvalidFound = false; |
b33bd7a3 DK |
3301 | const CBlockIndex *pindexOldTip = chainActive.Tip(); |
3302 | const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork); | |
8d655683 | 3303 | |
57e6ecda JG |
3304 | // - On ChainDB initialization, pindexOldTip will be null, so there are no removable blocks. |
3305 | // - If pindexMostWork is in a chain that doesn't have the same genesis block as our chain, | |
3306 | // then pindexFork will be null, and we would need to remove the entire chain including | |
3307 | // our genesis block. In practice this (probably) won't happen because of checks elsewhere. | |
3308 | auto reorgLength = pindexOldTip ? pindexOldTip->nHeight - (pindexFork ? pindexFork->nHeight : -1) : 0; | |
3309 | static_assert(MAX_REORG_LENGTH > 0, "We must be able to reorg some distance"); | |
3310 | if (reorgLength > MAX_REORG_LENGTH) { | |
3311 | auto msg = strprintf(_( | |
8d655683 | 3312 | "A block chain reorganization has been detected that would roll back %d blocks! " |
3313 | "This is larger than the maximum of %d blocks, and so the node is shutting down for your safety." | |
3314 | ), reorgLength, MAX_REORG_LENGTH) + "\n\n" + | |
3315 | _("Reorganization details") + ":\n" + | |
3316 | "- " + strprintf(_("Current tip: %s, height %d, work %s"), | |
3317 | pindexOldTip->phashBlock->GetHex(), pindexOldTip->nHeight, pindexOldTip->nChainWork.GetHex()) + "\n" + | |
3318 | "- " + strprintf(_("New tip: %s, height %d, work %s"), | |
3319 | pindexMostWork->phashBlock->GetHex(), pindexMostWork->nHeight, pindexMostWork->nChainWork.GetHex()) + "\n" + | |
3320 | "- " + strprintf(_("Fork point: %s, height %d"), | |
3321 | pindexFork->phashBlock->GetHex(), pindexFork->nHeight) + "\n\n" + | |
3322 | _("Please help, human!"); | |
57e6ecda JG |
3323 | LogPrintf("*** %s\n", msg); |
3324 | uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR); | |
3325 | StartShutdown(); | |
3326 | return false; | |
3327 | } | |
8d655683 | 3328 | |
4e0eed88 | 3329 | // Disconnect active blocks which are no longer in the best chain. |
fe5cef05 | 3330 | bool fBlocksDisconnected = false; |
4e0eed88 PW |
3331 | while (chainActive.Tip() && chainActive.Tip() != pindexFork) { |
3332 | if (!DisconnectTip(state)) | |
3333 | return false; | |
fe5cef05 | 3334 | fBlocksDisconnected = true; |
4e0eed88 | 3335 | } |
8abcd819 | 3336 | if ( KOMODO_REWIND != 0 ) |
8985164d | 3337 | { |
2ca62c87 | 3338 | CBlockIndex *tipindex; |
91165f19 | 3339 | fprintf(stderr,">>>>>>>>>>> rewind start ht.%d -> KOMODO_REWIND.%d\n",chainActive.Tip()->nHeight,KOMODO_REWIND); |
2ca62c87 | 3340 | while ( KOMODO_REWIND > 0 && (tipindex= chainActive.Tip()) != 0 && tipindex->nHeight > KOMODO_REWIND ) |
297a4978 | 3341 | { |
cef5ad03 | 3342 | fBlocksDisconnected = true; |
2ca62c87 | 3343 | fprintf(stderr,"%d ",(int32_t)tipindex->nHeight); |
3344 | InvalidateBlock(state,tipindex); | |
310bb0a1 | 3345 | if ( !DisconnectTip(state) ) |
45142781 | 3346 | break; |
67d2b8b9 | 3347 | } |
fd836de7 | 3348 | fprintf(stderr,"reached rewind.%d, best to do: ./komodo-cli -ac_name=%s stop\n",KOMODO_REWIND,ASSETCHAINS_SYMBOL); |
5c888905 | 3349 | sleep(20); |
91165f19 | 3350 | fprintf(stderr,"resuming normal operations\n"); |
d8be8b2e | 3351 | KOMODO_REWIND = 0; |
cef5ad03 | 3352 | //return(true); |
d8be8b2e | 3353 | } |
4e0eed88 PW |
3354 | // Build list of new blocks to connect. |
3355 | std::vector<CBlockIndex*> vpindexToConnect; | |
afc32c5e PW |
3356 | bool fContinue = true; |
3357 | int nHeight = pindexFork ? pindexFork->nHeight : -1; | |
3358 | while (fContinue && nHeight != pindexMostWork->nHeight) { | |
5aa165d5 MC |
3359 | // Don't iterate the entire list of potential improvements toward the best tip, as we likely only need |
3360 | // a few blocks along the way. | |
3361 | int nTargetHeight = std::min(nHeight + 32, pindexMostWork->nHeight); | |
3362 | vpindexToConnect.clear(); | |
3363 | vpindexToConnect.reserve(nTargetHeight - nHeight); | |
3364 | CBlockIndex *pindexIter = pindexMostWork->GetAncestor(nTargetHeight); | |
3365 | while (pindexIter && pindexIter->nHeight != nHeight) { | |
3366 | vpindexToConnect.push_back(pindexIter); | |
3367 | pindexIter = pindexIter->pprev; | |
3368 | } | |
3369 | nHeight = nTargetHeight; | |
8d655683 | 3370 | |
5aa165d5 MC |
3371 | // Connect new blocks. |
3372 | BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) { | |
3373 | if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) { | |
3374 | if (state.IsInvalid()) { | |
3375 | // The block violates a consensus rule. | |
3376 | if (!state.CorruptionPossible()) | |
3377 | InvalidChainFound(vpindexToConnect.back()); | |
3378 | state = CValidationState(); | |
3379 | fInvalidFound = true; | |
3380 | fContinue = false; | |
3381 | break; | |
3382 | } else { | |
3383 | // A system error occurred (disk space, database error, ...). | |
3384 | return false; | |
3385 | } | |
4e0eed88 | 3386 | } else { |
5aa165d5 MC |
3387 | PruneBlockIndexCandidates(); |
3388 | if (!pindexOldTip || chainActive.Tip()->nChainWork > pindexOldTip->nChainWork) { | |
3389 | // We're in a better position than we were. Return temporarily to release the lock. | |
3390 | fContinue = false; | |
3391 | break; | |
3392 | } | |
75f51f2a PW |
3393 | } |
3394 | } | |
231b3999 | 3395 | } |
8d655683 | 3396 | |
fe5cef05 | 3397 | if (fBlocksDisconnected) { |
233c9eb6 | 3398 | mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); |
afc32c5e | 3399 | } |
34a64fe0 | 3400 | mempool.removeWithoutBranchId( |
8d655683 | 3401 | CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, Params().GetConsensus())); |
fe5cef05 | 3402 | mempool.check(pcoinsTip); |
8d655683 | 3403 | |
202e0194 PW |
3404 | // Callbacks/notifications for a new best chain. |
3405 | if (fInvalidFound) | |
3406 | CheckForkWarningConditionsOnNewFork(vpindexToConnect.back()); | |
3407 | else | |
3408 | CheckForkWarningConditions(); | |
8d655683 | 3409 | |
0a61b0df | 3410 | return true; |
3411 | } | |
0a61b0df | 3412 | |
c5b390b6 MF |
3413 | /** |
3414 | * Make the best chain active, in multiple steps. The result is either failure | |
3415 | * or an activated best chain. pblock is either NULL or a pointer to a block | |
3416 | * that is already loaded (to avoid loading it again from disk). | |
3417 | */ | |
92bb6f2f | 3418 | bool ActivateBestChain(CValidationState &state, CBlock *pblock) { |
202e0194 PW |
3419 | CBlockIndex *pindexNewTip = NULL; |
3420 | CBlockIndex *pindexMostWork = NULL; | |
11982d36 | 3421 | const CChainParams& chainParams = Params(); |
4e0eed88 PW |
3422 | do { |
3423 | boost::this_thread::interruption_point(); | |
8d655683 | 3424 | |
202e0194 PW |
3425 | bool fInitialDownload; |
3426 | { | |
3427 | LOCK(cs_main); | |
3428 | pindexMostWork = FindMostWorkChain(); | |
8d655683 | 3429 | |
202e0194 PW |
3430 | // Whether we have anything to do at all. |
3431 | if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip()) | |
3432 | return true; | |
8d655683 | 3433 | |
92bb6f2f | 3434 | if (!ActivateBestChainStep(state, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL)) |
9083591a | 3435 | return false; |
202e0194 PW |
3436 | pindexNewTip = chainActive.Tip(); |
3437 | fInitialDownload = IsInitialBlockDownload(); | |
3438 | } | |
3439 | // When we reach this point, we switched to a new tip (stored in pindexNewTip). | |
8d655683 | 3440 | |
202e0194 PW |
3441 | // Notifications/callbacks that can run without cs_main |
3442 | if (!fInitialDownload) { | |
3443 | uint256 hashNewTip = pindexNewTip->GetBlockHash(); | |
3444 | // Relay inventory, but don't relay old inventory during initial block download. | |
a8cdaf5c CF |
3445 | int nBlockEstimate = 0; |
3446 | if (fCheckpointsEnabled) | |
3447 | nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainParams.Checkpoints()); | |
f9ec3f0f | 3448 | // Don't relay blocks if pruning -- could cause a peer to try to download, resulting |
3449 | // in a stalled download if the block file is pruned before the request. | |
3450 | if (nLocalServices & NODE_NETWORK) { | |
4dc5eb05 PK |
3451 | LOCK(cs_vNodes); |
3452 | BOOST_FOREACH(CNode* pnode, vNodes) | |
8d655683 | 3453 | if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) |
3454 | pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip)); | |
202e0194 | 3455 | } |
51ce901a | 3456 | // Notify external listeners about the new tip. |
6a793d9c | 3457 | GetMainSignals().UpdatedBlockTip(pindexNewTip); |
c7b6117d | 3458 | uiInterface.NotifyBlockTip(hashNewTip); |
b11963b5 | 3459 | } //else fprintf(stderr,"initial download skips propagation\n"); |
202e0194 | 3460 | } while(pindexMostWork != chainActive.Tip()); |
3fcfbc8a | 3461 | CheckBlockIndex(); |
8d655683 | 3462 | |
51ce901a | 3463 | // Write changes periodically to disk, after relay. |
a2069500 | 3464 | if (!FlushStateToDisk(state, FLUSH_STATE_PERIODIC)) { |
51ce901a PW |
3465 | return false; |
3466 | } | |
8d655683 | 3467 | |
4e0eed88 PW |
3468 | return true; |
3469 | } | |
942b33a1 | 3470 | |
9b0a8d31 PW |
3471 | bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) { |
3472 | AssertLockHeld(cs_main); | |
8d655683 | 3473 | |
9b0a8d31 PW |
3474 | // Mark the block itself as invalid. |
3475 | pindex->nStatus |= BLOCK_FAILED_VALID; | |
0dd06b25 | 3476 | setDirtyBlockIndex.insert(pindex); |
9b0a8d31 | 3477 | setBlockIndexCandidates.erase(pindex); |
8d655683 | 3478 | |
9b0a8d31 PW |
3479 | while (chainActive.Contains(pindex)) { |
3480 | CBlockIndex *pindexWalk = chainActive.Tip(); | |
3481 | pindexWalk->nStatus |= BLOCK_FAILED_CHILD; | |
0dd06b25 | 3482 | setDirtyBlockIndex.insert(pindexWalk); |
9b0a8d31 PW |
3483 | setBlockIndexCandidates.erase(pindexWalk); |
3484 | // ActivateBestChain considers blocks already in chainActive | |
3485 | // unconditionally valid already, so force disconnect away from it. | |
3486 | if (!DisconnectTip(state)) { | |
233c9eb6 | 3487 | mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); |
34a64fe0 | 3488 | mempool.removeWithoutBranchId( |
8d655683 | 3489 | CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, Params().GetConsensus())); |
9b0a8d31 PW |
3490 | return false; |
3491 | } | |
3492 | } | |
ea5f02cb | 3493 | //LimitMempoolSize(mempool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60); |
8d655683 | 3494 | |
9b0a8d31 | 3495 | // The resulting new best tip may not be in setBlockIndexCandidates anymore, so |
b05a89b2 | 3496 | // add it again. |
9b0a8d31 | 3497 | BlockMap::iterator it = mapBlockIndex.begin(); |
e6528c64 | 3498 | while (it != mapBlockIndex.end() && it->second != 0 ) { |
cd3d67cf | 3499 | if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && !setBlockIndexCandidates.value_comp()(it->second, chainActive.Tip())) { |
a9af4158 | 3500 | setBlockIndexCandidates.insert(it->second); |
9b0a8d31 PW |
3501 | } |
3502 | it++; | |
3503 | } | |
8d655683 | 3504 | |
9b0a8d31 | 3505 | InvalidChainFound(pindex); |
233c9eb6 | 3506 | mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); |
34a64fe0 | 3507 | mempool.removeWithoutBranchId( |
8d655683 | 3508 | CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, Params().GetConsensus())); |
9b0a8d31 PW |
3509 | return true; |
3510 | } | |
3511 | ||
3512 | bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex) { | |
3513 | AssertLockHeld(cs_main); | |
8d655683 | 3514 | |
9b0a8d31 | 3515 | int nHeight = pindex->nHeight; |
8d655683 | 3516 | |
9b0a8d31 PW |
3517 | // Remove the invalidity flag from this block and all its descendants. |
3518 | BlockMap::iterator it = mapBlockIndex.begin(); | |
3519 | while (it != mapBlockIndex.end()) { | |
3520 | if (!it->second->IsValid() && it->second->GetAncestor(nHeight) == pindex) { | |
3521 | it->second->nStatus &= ~BLOCK_FAILED_MASK; | |
0dd06b25 | 3522 | setDirtyBlockIndex.insert(it->second); |
9b0a8d31 PW |
3523 | if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && setBlockIndexCandidates.value_comp()(chainActive.Tip(), it->second)) { |
3524 | setBlockIndexCandidates.insert(it->second); | |
3525 | } | |
3526 | if (it->second == pindexBestInvalid) { | |
3527 | // Reset invalid block marker if it was pointing to one of those. | |
3528 | pindexBestInvalid = NULL; | |
3529 | } | |
3530 | } | |
3531 | it++; | |
3532 | } | |
8d655683 | 3533 | |
9b0a8d31 PW |
3534 | // Remove the invalidity flag from all ancestors too. |
3535 | while (pindex != NULL) { | |
0dd06b25 PW |
3536 | if (pindex->nStatus & BLOCK_FAILED_MASK) { |
3537 | pindex->nStatus &= ~BLOCK_FAILED_MASK; | |
3538 | setDirtyBlockIndex.insert(pindex); | |
9b0a8d31 PW |
3539 | } |
3540 | pindex = pindex->pprev; | |
3541 | } | |
3542 | return true; | |
3543 | } | |
3544 | ||
341735eb | 3545 | CBlockIndex* AddToBlockIndex(const CBlockHeader& block) |
0a61b0df | 3546 | { |
3547 | // Check for duplicate | |
1959997a | 3548 | uint256 hash = block.GetHash(); |
145d5be8 | 3549 | BlockMap::iterator it = mapBlockIndex.find(hash); |
b8513092 | 3550 | BlockMap::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock); |
942b33a1 | 3551 | if (it != mapBlockIndex.end()) |
fd835d94 | 3552 | { |
64b45b71 | 3553 | if ( it->second != 0 ) // vNodes.size() >= KOMODO_LIMITED_NETWORKSIZE, change behavior to allow komodo_ensure to work |
66dd02d2 | 3554 | { |
3555 | // this is the strange case where somehow the hash is in the mapBlockIndex via as yet undetermined process, but the pindex for the hash is not there. Theoretically it is due to processing the block headers, but I have seen it get this case without having received it from the block headers or anywhere else... jl777 | |
3556 | //fprintf(stderr,"addtoblockindex already there %p\n",it->second); | |
7732dbc2 | 3557 | return it->second; |
66dd02d2 | 3558 | } |
b8513092 | 3559 | if ( miPrev != mapBlockIndex.end() && (*miPrev).second == 0 ) |
3560 | { | |
e3e263b5 | 3561 | //fprintf(stderr,"edge case of both block and prevblock in the strange state\n"); |
b8513092 | 3562 | return(0); // return here to avoid the state of pindex->nHeight not set and pprev NULL |
3563 | } | |
fd835d94 | 3564 | } |
0a61b0df | 3565 | // Construct new block index object |
1959997a | 3566 | CBlockIndex* pindexNew = new CBlockIndex(block); |
94c8bfb2 | 3567 | assert(pindexNew); |
341735eb PW |
3568 | // We assign the sequence id to blocks only when the full data is available, |
3569 | // to avoid miners withholding blocks but broadcasting headers, to get a | |
3570 | // competitive advantage. | |
3571 | pindexNew->nSequenceId = 0; | |
145d5be8 | 3572 | BlockMap::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; |
0a61b0df | 3573 | pindexNew->phashBlock = &((*mi).first); |
0a61b0df | 3574 | if (miPrev != mapBlockIndex.end()) |
3575 | { | |
b92dfb1e | 3576 | if ( (pindexNew->pprev= (*miPrev).second) != 0 ) |
3577 | pindexNew->nHeight = pindexNew->pprev->nHeight + 1; | |
8dcf7f3f | 3578 | else fprintf(stderr,"unexpected null pprev %s\n",hash.ToString().c_str()); |
c9a09183 | 3579 | pindexNew->BuildSkip(); |
0a61b0df | 3580 | } |
092b58d1 | 3581 | pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew); |
942b33a1 | 3582 | pindexNew->RaiseValidity(BLOCK_VALID_TREE); |
341735eb PW |
3583 | if (pindexBestHeader == NULL || pindexBestHeader->nChainWork < pindexNew->nChainWork) |
3584 | pindexBestHeader = pindexNew; | |
8d655683 | 3585 | |
51ce901a | 3586 | setDirtyBlockIndex.insert(pindexNew); |
66dd02d2 | 3587 | //fprintf(stderr,"added to block index %s %p\n",hash.ToString().c_str(),pindexNew); |
942b33a1 PW |
3588 | return pindexNew; |
3589 | } | |
3590 | ||
c5b390b6 | 3591 | /** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */ |
942b33a1 PW |
3592 | bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos) |
3593 | { | |
3594 | pindexNew->nTx = block.vtx.size(); | |
341735eb | 3595 | pindexNew->nChainTx = 0; |
ad6a36ad JG |
3596 | CAmount sproutValue = 0; |
3597 | for (auto tx : block.vtx) { | |
3598 | for (auto js : tx.vjoinsplit) { | |
3599 | sproutValue += js.vpub_old; | |
3600 | sproutValue -= js.vpub_new; | |
3601 | } | |
3602 | } | |
3603 | pindexNew->nSproutValue = sproutValue; | |
3604 | pindexNew->nChainSproutValue = boost::none; | |
857c61df PW |
3605 | pindexNew->nFile = pos.nFile; |
3606 | pindexNew->nDataPos = pos.nPos; | |
5382bcf8 | 3607 | pindexNew->nUndoPos = 0; |
942b33a1 | 3608 | pindexNew->nStatus |= BLOCK_HAVE_DATA; |
341735eb | 3609 | pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS); |
51ce901a | 3610 | setDirtyBlockIndex.insert(pindexNew); |
8d655683 | 3611 | |
341735eb PW |
3612 | if (pindexNew->pprev == NULL || pindexNew->pprev->nChainTx) { |
3613 | // If pindexNew is the genesis block or all parents are BLOCK_VALID_TRANSACTIONS. | |
3614 | deque<CBlockIndex*> queue; | |
3615 | queue.push_back(pindexNew); | |
8d655683 | 3616 | |
341735eb PW |
3617 | // Recursively process any descendant blocks that now may be eligible to be connected. |
3618 | while (!queue.empty()) { | |
3619 | CBlockIndex *pindex = queue.front(); | |
3620 | queue.pop_front(); | |
3621 | pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx; | |
ad6a36ad JG |
3622 | if (pindex->pprev) { |
3623 | if (pindex->pprev->nChainSproutValue && pindex->nSproutValue) { | |
3624 | pindex->nChainSproutValue = *pindex->pprev->nChainSproutValue + *pindex->nSproutValue; | |
3625 | } else { | |
3626 | pindex->nChainSproutValue = boost::none; | |
3627 | } | |
3628 | } else { | |
3629 | pindex->nChainSproutValue = pindex->nSproutValue; | |
3630 | } | |
c1ecee8f SD |
3631 | { |
3632 | LOCK(cs_nBlockSequenceId); | |
3633 | pindex->nSequenceId = nBlockSequenceId++; | |
3634 | } | |
3fcfbc8a PW |
3635 | if (chainActive.Tip() == NULL || !setBlockIndexCandidates.value_comp()(pindex, chainActive.Tip())) { |
3636 | setBlockIndexCandidates.insert(pindex); | |
3637 | } | |
341735eb PW |
3638 | std::pair<std::multimap<CBlockIndex*, CBlockIndex*>::iterator, std::multimap<CBlockIndex*, CBlockIndex*>::iterator> range = mapBlocksUnlinked.equal_range(pindex); |
3639 | while (range.first != range.second) { | |
3640 | std::multimap<CBlockIndex*, CBlockIndex*>::iterator it = range.first; | |
3641 | queue.push_back(it->second); | |
3642 | range.first++; | |
3643 | mapBlocksUnlinked.erase(it); | |
3644 | } | |
341735eb PW |
3645 | } |
3646 | } else { | |
3647 | if (pindexNew->pprev && pindexNew->pprev->IsValid(BLOCK_VALID_TREE)) { | |
3648 | mapBlocksUnlinked.insert(std::make_pair(pindexNew->pprev, pindexNew)); | |
3649 | } | |
341735eb | 3650 | } |
8d655683 | 3651 | |
18e72167 | 3652 | return true; |
0a61b0df | 3653 | } |
3654 | ||
51ed9ec9 | 3655 | bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false) |
5382bcf8 | 3656 | { |
5382bcf8 | 3657 | LOCK(cs_LastBlockFile); |
8d655683 | 3658 | |
ed6d1a2c PW |
3659 | unsigned int nFile = fKnown ? pos.nFile : nLastBlockFile; |
3660 | if (vinfoBlockFile.size() <= nFile) { | |
3661 | vinfoBlockFile.resize(nFile + 1); | |
3662 | } | |
8d655683 | 3663 | |
ed6d1a2c PW |
3664 | if (!fKnown) { |
3665 | while (vinfoBlockFile[nFile].nSize + nAddSize >= MAX_BLOCKFILE_SIZE) { | |
ed6d1a2c PW |
3666 | nFile++; |
3667 | if (vinfoBlockFile.size() <= nFile) { | |
3668 | vinfoBlockFile.resize(nFile + 1); | |
3669 | } | |
7fea4846 | 3670 | } |
ed6d1a2c PW |
3671 | pos.nFile = nFile; |
3672 | pos.nPos = vinfoBlockFile[nFile].nSize; | |
5382bcf8 | 3673 | } |
8d655683 | 3674 | |
4e895b08 PW |
3675 | if (nFile != nLastBlockFile) { |
3676 | if (!fKnown) { | |
3677 | LogPrintf("Leaving block file %i: %s\n", nFile, vinfoBlockFile[nFile].ToString()); | |
3678 | } | |
3679 | FlushBlockFile(!fKnown); | |
3680 | nLastBlockFile = nFile; | |
3681 | } | |
8d655683 | 3682 | |
ed6d1a2c | 3683 | vinfoBlockFile[nFile].AddBlock(nHeight, nTime); |
bb6acff0 CF |
3684 | if (fKnown) |
3685 | vinfoBlockFile[nFile].nSize = std::max(pos.nPos + nAddSize, vinfoBlockFile[nFile].nSize); | |
3686 | else | |
3687 | vinfoBlockFile[nFile].nSize += nAddSize; | |
8d655683 | 3688 | |
7fea4846 PW |
3689 | if (!fKnown) { |
3690 | unsigned int nOldChunks = (pos.nPos + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; | |
ed6d1a2c | 3691 | unsigned int nNewChunks = (vinfoBlockFile[nFile].nSize + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; |
7fea4846 | 3692 | if (nNewChunks > nOldChunks) { |
f9ec3f0f | 3693 | if (fPruneMode) |
3694 | fCheckForPruning = true; | |
fa45c26a PK |
3695 | if (CheckDiskSpace(nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos)) { |
3696 | FILE *file = OpenBlockFile(pos); | |
3697 | if (file) { | |
881a85a2 | 3698 | LogPrintf("Pre-allocating up to position 0x%x in blk%05u.dat\n", nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile); |
fa45c26a PK |
3699 | AllocateFileRange(file, pos.nPos, nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos); |
3700 | fclose(file); | |
3701 | } | |
7fea4846 | 3702 | } |
fa45c26a | 3703 | else |
c117d9e9 | 3704 | return state.Error("out of disk space"); |
bba89aa8 | 3705 | } |
bba89aa8 | 3706 | } |
8d655683 | 3707 | |
51ce901a | 3708 | setDirtyFileInfo.insert(nFile); |
5382bcf8 PW |
3709 | return true; |
3710 | } | |
3711 | ||
ef3988ca | 3712 | bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize) |
5382bcf8 PW |
3713 | { |
3714 | pos.nFile = nFile; | |
8d655683 | 3715 | |
5382bcf8 | 3716 | LOCK(cs_LastBlockFile); |
8d655683 | 3717 | |
bba89aa8 | 3718 | unsigned int nNewSize; |
ed6d1a2c PW |
3719 | pos.nPos = vinfoBlockFile[nFile].nUndoSize; |
3720 | nNewSize = vinfoBlockFile[nFile].nUndoSize += nAddSize; | |
51ce901a | 3721 | setDirtyFileInfo.insert(nFile); |
8d655683 | 3722 | |
bba89aa8 PW |
3723 | unsigned int nOldChunks = (pos.nPos + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; |
3724 | unsigned int nNewChunks = (nNewSize + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; | |
3725 | if (nNewChunks > nOldChunks) { | |
f9ec3f0f | 3726 | if (fPruneMode) |
3727 | fCheckForPruning = true; | |
fa45c26a PK |
3728 | if (CheckDiskSpace(nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos)) { |
3729 | FILE *file = OpenUndoFile(pos); | |
3730 | if (file) { | |
881a85a2 | 3731 | LogPrintf("Pre-allocating up to position 0x%x in rev%05u.dat\n", nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile); |
fa45c26a PK |
3732 | AllocateFileRange(file, pos.nPos, nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos); |
3733 | fclose(file); | |
3734 | } | |
bba89aa8 | 3735 | } |
fa45c26a | 3736 | else |
c117d9e9 | 3737 | return state.Error("out of disk space"); |
5382bcf8 | 3738 | } |
8d655683 | 3739 | |
5382bcf8 PW |
3740 | return true; |
3741 | } | |
3742 | ||
9f6cb8f0 | 3743 | bool CheckBlockHeader(int32_t *futureblockp,int32_t height,CBlockIndex *pindex, const CBlockHeader& blockhdr, CValidationState& state, bool fCheckPOW) |
0a61b0df | 3744 | { |
d7426190 | 3745 | // Check timestamp |
e40b78e9 | 3746 | if ( 0 ) |
c0dbb034 | 3747 | { |
3748 | uint256 hash; int32_t i; | |
3749 | hash = blockhdr.GetHash(); | |
92266e99 | 3750 | for (i=31; i>=0; i--) |
c0dbb034 | 3751 | fprintf(stderr,"%02x",((uint8_t *)&hash)[i]); |
3752 | fprintf(stderr," <- CheckBlockHeader\n"); | |
807949f4 | 3753 | if ( chainActive.Tip() != 0 ) |
3754 | { | |
3755 | hash = chainActive.Tip()->GetBlockHash(); | |
3756 | for (i=31; i>=0; i--) | |
3757 | fprintf(stderr,"%02x",((uint8_t *)&hash)[i]); | |
3758 | fprintf(stderr," <- chainTip\n"); | |
3759 | } | |
c0dbb034 | 3760 | } |
9f6cb8f0 | 3761 | *futureblockp = 0; |
5dde7075 | 3762 | if (blockhdr.GetBlockTime() > GetAdjustedTime() + 60) |
8999ab66 | 3763 | { |
82b4714b | 3764 | CBlockIndex *tipindex; |
531b9293 | 3765 | fprintf(stderr,"ht.%d future block %u vs time.%u + 60\n",height,(uint32_t)blockhdr.GetBlockTime(),(uint32_t)GetAdjustedTime()); |
d1cd2af5 | 3766 | if ( (tipindex= chainActive.Tip()) != 0 && tipindex->GetBlockHash() == blockhdr.hashPrevBlock && blockhdr.GetBlockTime() < GetAdjustedTime() + 60*2 ) |
5d9f1119 | 3767 | { |
2fea1c97 | 3768 | //fprintf(stderr,"it is the next block, let's wait for %d seconds\n",GetAdjustedTime() + 60 - blockhdr.GetBlockTime()); |
5d9f1119 | 3769 | while ( blockhdr.GetBlockTime() > GetAdjustedTime() + 60 ) |
3770 | sleep(1); | |
2fea1c97 | 3771 | //fprintf(stderr,"now its valid\n"); |
5d9f1119 | 3772 | } |
3773 | else | |
3774 | { | |
9f6cb8f0 | 3775 | if (blockhdr.GetBlockTime() < GetAdjustedTime() + 600) |
3776 | *futureblockp = 1; | |
5d9f1119 | 3777 | return false; //state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),REJECT_INVALID, "time-too-new"); |
3778 | } | |
8999ab66 | 3779 | } |
5d9f1119 | 3780 | if ( ASSETCHAINS_STAKED != 0 && pindex != 0 && pindex->pprev != 0 && pindex->nTime <= pindex->pprev->nTime ) |
935fee29 | 3781 | { |
c38ad724 | 3782 | fprintf(stderr,"ht.%d %u vs ht.%d %u, is not monotonic\n",pindex->nHeight,pindex->nTime,pindex->pprev->nHeight,pindex->pprev->nTime); |
9339a0cb | 3783 | return state.Invalid(error("CheckBlockHeader(): block timestamp needs to always increase"),REJECT_INVALID, "time-too-new"); |
935fee29 | 3784 | } |
80f4cdcf | 3785 | // Check block version |
5d173d2a | 3786 | if (height > 0 && blockhdr.nVersion < MIN_BLOCK_VERSION) |
edddf5f0 | 3787 | return state.DoS(100, error("CheckBlockHeader(): block version too low"),REJECT_INVALID, "version-too-low"); |
8d655683 | 3788 | |
f2dd868d | 3789 | // Check Equihash solution is valid |
dc4124de | 3790 | if ( fCheckPOW ) |
3791 | { | |
3792 | if ( !CheckEquihashSolution(&blockhdr, Params()) ) | |
3793 | return state.DoS(100, error("CheckBlockHeader(): Equihash solution invalid"),REJECT_INVALID, "invalid-solution"); | |
b8add6a4 | 3794 | } |
f2dd868d | 3795 | // Check proof of work matches claimed amount |
ec06a2e3 | 3796 | /*komodo_index2pubkey33(pubkey33,pindex,height); |
3ad8d247 | 3797 | if ( fCheckPOW && !CheckProofOfWork(height,pubkey33,blockhdr.GetHash(), blockhdr.nBits, Params().GetConsensus(),blockhdr.nTime) ) |
8d655683 | 3798 | return state.DoS(50, error("CheckBlockHeader(): proof of work failed"),REJECT_INVALID, "high-hash");*/ |
f4573470 PW |
3799 | return true; |
3800 | } | |
3801 | ||
ce5dd547 | 3802 | int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtime); |
18443f69 | 3803 | int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height); |
b8add6a4 | 3804 | |
9f6cb8f0 | 3805 | bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const CBlock& block, CValidationState& state, |
6fb8d0c2 JG |
3806 | libzcash::ProofVerifier& verifier, |
3807 | bool fCheckPOW, bool fCheckMerkleRoot) | |
0a61b0df | 3808 | { |
e5d9a702 | 3809 | uint8_t pubkey33[33]; uint256 hash; |
8d655683 | 3810 | // These are checks that are independent of context. |
18dd6a3b | 3811 | hash = block.GetHash(); |
18dd6a3b | 3812 | |
57425a24 DK |
3813 | // Check that the header is valid (particularly PoW). This is mostly |
3814 | // redundant with the call in AcceptBlockHeader. | |
9f6cb8f0 | 3815 | if (!CheckBlockHeader(futureblockp,height,pindex,block,state,fCheckPOW)) |
3283cb53 | 3816 | { |
41427baa | 3817 | //fprintf(stderr,"checkblockheader error PoW.%d\n",fCheckPOW); |
f4573470 | 3818 | return false; |
3283cb53 | 3819 | } |
18443f69 | 3820 | if ( fCheckPOW ) |
3821 | { | |
e5d9a702 | 3822 | //if ( !CheckEquihashSolution(&block, Params()) ) |
18443f69 | 3823 | // return state.DoS(100, error("CheckBlock: Equihash solution invalid"),REJECT_INVALID, "invalid-solution"); |
3824 | komodo_block2pubkey33(pubkey33,(CBlock *)&block); | |
e5d9a702 | 3825 | if ( !CheckProofOfWork(height,pubkey33,hash,block.nBits,Params().GetConsensus(),block.nTime) ) |
d3358987 | 3826 | { |
560da193 | 3827 | int32_t z; for (z=31; z>=0; z--) |
e5d9a702 | 3828 | fprintf(stderr,"%02x",((uint8_t *)&hash)[z]); |
80afe35b | 3829 | fprintf(stderr," failed hash ht.%d\n",height); |
8fbee929 | 3830 | return state.DoS(50, error("CheckBlock: proof of work failed"),REJECT_INVALID, "high-hash"); |
d3358987 | 3831 | } |
3acce042 | 3832 | if ( komodo_checkPOW(1,(CBlock *)&block,height) < 0 ) // checks Equihash |
18443f69 | 3833 | return state.DoS(100, error("CheckBlock: failed slow_checkPOW"),REJECT_INVALID, "failed-slow_checkPOW"); |
3834 | } | |
341735eb PW |
3835 | // Check the merkle root. |
3836 | if (fCheckMerkleRoot) { | |
3837 | bool mutated; | |
3838 | uint256 hashMerkleRoot2 = block.BuildMerkleTree(&mutated); | |
3839 | if (block.hashMerkleRoot != hashMerkleRoot2) | |
b8add6a4 | 3840 | return state.DoS(100, error("CheckBlock: hashMerkleRoot mismatch"), |
341735eb | 3841 | REJECT_INVALID, "bad-txnmrklroot", true); |
8d655683 | 3842 | |
341735eb PW |
3843 | // Check for merkle tree malleability (CVE-2012-2459): repeating sequences |
3844 | // of transactions in a block without affecting the merkle root of a block, | |
3845 | // while still invalidating it. | |
3846 | if (mutated) | |
b8add6a4 | 3847 | return state.DoS(100, error("CheckBlock: duplicate transaction"), |
341735eb PW |
3848 | REJECT_INVALID, "bad-txns-duplicate", true); |
3849 | } | |
8d655683 | 3850 | |
341735eb PW |
3851 | // All potential-corruption validation must be done before we do any |
3852 | // transaction validation, as otherwise we may mark the header as invalid | |
3853 | // because we receive the wrong transactions for it. | |
8d655683 | 3854 | |
0a61b0df | 3855 | // Size limits |
38991ffa | 3856 | if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) |
b8add6a4 | 3857 | return state.DoS(100, error("CheckBlock: size limits failed"), |
14e7ffcc | 3858 | REJECT_INVALID, "bad-blk-length"); |
8d655683 | 3859 | |
0a61b0df | 3860 | // First transaction must be coinbase, the rest must not be |
38991ffa | 3861 | if (block.vtx.empty() || !block.vtx[0].IsCoinBase()) |
b8add6a4 | 3862 | return state.DoS(100, error("CheckBlock: first tx is not coinbase"), |
14e7ffcc | 3863 | REJECT_INVALID, "bad-cb-missing"); |
38991ffa EL |
3864 | for (unsigned int i = 1; i < block.vtx.size(); i++) |
3865 | if (block.vtx[i].IsCoinBase()) | |
b8add6a4 | 3866 | return state.DoS(100, error("CheckBlock: more than one coinbase"), |
14e7ffcc | 3867 | REJECT_INVALID, "bad-cb-multiple"); |
8d655683 | 3868 | |
0a61b0df | 3869 | // Check transactions |
38991ffa | 3870 | BOOST_FOREACH(const CTransaction& tx, block.vtx) |
837b94ee | 3871 | { |
f8a07170 | 3872 | if ( komodo_validate_interest(tx,height == 0 ? komodo_block2height((CBlock *)&block) : height,block.nTime,0) < 0 ) |
8d655683 | 3873 | return error("CheckBlock: komodo_validate_interest failed"); |
6fb8d0c2 | 3874 | if (!CheckTransaction(tx, state, verifier)) |
b8add6a4 | 3875 | return error("CheckBlock: CheckTransaction failed"); |
837b94ee | 3876 | } |
7bd9c3a3 | 3877 | unsigned int nSigOps = 0; |
38991ffa | 3878 | BOOST_FOREACH(const CTransaction& tx, block.vtx) |
e679ec96 | 3879 | { |
05df3fc6 | 3880 | nSigOps += GetLegacySigOpCount(tx); |
e679ec96 GA |
3881 | } |
3882 | if (nSigOps > MAX_BLOCK_SIGOPS) | |
b8add6a4 | 3883 | return state.DoS(100, error("CheckBlock: out-of-bounds SigOpCount"), |
14e7ffcc | 3884 | REJECT_INVALID, "bad-blk-sigops", true); |
b1e74295 | 3885 | if ( komodo_check_deposit(height,block,(pindex==0||pindex->pprev==0)?0:pindex->pprev->nTime) < 0 ) |
e699e13d | 3886 | { |
1a26c3fa | 3887 | //static uint32_t counter; |
3888 | //if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 ) | |
41427baa | 3889 | // fprintf(stderr,"check deposit rejection\n"); |
59642d51 | 3890 | return(false); |
e699e13d | 3891 | } |
0a61b0df | 3892 | return true; |
3893 | } | |
3894 | ||
a48f2d6d LD |
3895 | bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev) |
3896 | { | |
11982d36 CF |
3897 | const CChainParams& chainParams = Params(); |
3898 | const Consensus::Params& consensusParams = chainParams.GetConsensus(); | |
a48f2d6d | 3899 | uint256 hash = block.GetHash(); |
4e382177 | 3900 | if (hash == consensusParams.hashGenesisBlock) |
a48f2d6d | 3901 | return true; |
8d655683 | 3902 | |
a48f2d6d | 3903 | assert(pindexPrev); |
8d655683 | 3904 | |
a48f2d6d | 3905 | int nHeight = pindexPrev->nHeight+1; |
8d655683 | 3906 | |
a48f2d6d | 3907 | // Check proof of work |
36f1b84b | 3908 | if ( (nHeight < 235300 || nHeight > 236000) && block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) |
5645d111 | 3909 | { |
c939721c | 3910 | cout << block.nBits << " block.nBits vs. calc " << GetNextWorkRequired(pindexPrev, &block, consensusParams) << endl; |
5262fde0 | 3911 | return state.DoS(100, error("%s: incorrect proof of work", __func__), |
a48f2d6d | 3912 | REJECT_INVALID, "bad-diffbits"); |
5645d111 | 3913 | } |
8d655683 | 3914 | |
a48f2d6d LD |
3915 | // Check timestamp against prev |
3916 | if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) | |
5262fde0 | 3917 | return state.Invalid(error("%s: block's timestamp is too early", __func__), |
a48f2d6d | 3918 | REJECT_INVALID, "time-too-old"); |
8d655683 | 3919 | |
bfa832c7 | 3920 | if (fCheckpointsEnabled) |
a8cdaf5c CF |
3921 | { |
3922 | // Check that the block chain matches the known block chain up to a checkpoint | |
3923 | if (!Checkpoints::CheckBlock(chainParams.Checkpoints(), nHeight, hash)) | |
8d787d25 | 3924 | { |
49601901 | 3925 | /*CBlockIndex *heightblock = chainActive[nHeight]; |
8d787d25 | 3926 | if ( heightblock != 0 && heightblock->GetBlockHash() == hash ) |
3927 | { | |
3928 | //fprintf(stderr,"got a pre notarization block that matches height.%d\n",(int32_t)nHeight); | |
3929 | return true; | |
49601901 | 3930 | }*/ |
3931 | return state.DoS(100, error("%s: rejected by checkpoint lock-in at %d", __func__, nHeight),REJECT_CHECKPOINT, "checkpoint mismatch"); | |
8d787d25 | 3932 | } |
a8cdaf5c CF |
3933 | // Don't accept any forks from the main chain prior to last checkpoint |
3934 | CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainParams.Checkpoints()); | |
b62d7030 | 3935 | int32_t notarized_height; |
4786d20c | 3936 | if (pcheckpoint && nHeight > 1 && nHeight < pcheckpoint->nHeight ) |
176eeb77 | 3937 | return state.DoS(1, error("%s: forked chain older than last checkpoint (height %d) vs %d", __func__, nHeight,pcheckpoint->nHeight)); |
b62d7030 | 3938 | else if ( komodo_checkpoint(¬arized_height,nHeight,hash) < 0 ) |
e2c2f297 | 3939 | { |
3940 | CBlockIndex *heightblock = chainActive[nHeight]; | |
cc07ad72 | 3941 | if ( heightblock != 0 && heightblock->GetBlockHash() == hash ) |
e2c2f297 | 3942 | { |
2c5af2cd | 3943 | //fprintf(stderr,"got a pre notarization block that matches height.%d\n",(int32_t)nHeight); |
e2c2f297 | 3944 | return true; |
176eeb77 | 3945 | } else return state.DoS(1, error("%s: forked chain %d older than last notarized (height %d) vs %d", __func__,nHeight, notarized_height)); |
e2c2f297 | 3946 | } |
a8cdaf5c | 3947 | } |
542da618 SB |
3948 | // Reject block.nVersion < 4 blocks |
3949 | if (block.nVersion < 4) | |
3950 | return state.Invalid(error("%s : rejected nVersion<4 block", __func__), | |
5e82e1c8 | 3951 | REJECT_OBSOLETE, "bad-version"); |
8d655683 | 3952 | |
a48f2d6d LD |
3953 | return true; |
3954 | } | |
3955 | ||
3956 | bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex * const pindexPrev) | |
3957 | { | |
3958 | const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1; | |
51aa2492 | 3959 | const Consensus::Params& consensusParams = Params().GetConsensus(); |
8d655683 | 3960 | |
a48f2d6d | 3961 | // Check that all transactions are finalized |
a1d3c6fb | 3962 | BOOST_FOREACH(const CTransaction& tx, block.vtx) { |
8d655683 | 3963 | |
072099d7 S |
3964 | // Check transaction contextually against consensus rules at block height |
3965 | if (!ContextualCheckTransaction(tx, state, nHeight, 100)) { | |
3966 | return false; // Failure reason has been set in validation state object | |
3967 | } | |
8d655683 | 3968 | |
a1d3c6fb MF |
3969 | int nLockTimeFlags = 0; |
3970 | int64_t nLockTimeCutoff = (nLockTimeFlags & LOCKTIME_MEDIAN_TIME_PAST) | |
8d655683 | 3971 | ? pindexPrev->GetMedianTimePast() |
3972 | : block.GetBlockTime(); | |
14aa6cc0 | 3973 | if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) { |
5262fde0 | 3974 | return state.DoS(10, error("%s: contains a non-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal"); |
a48f2d6d | 3975 | } |
a1d3c6fb | 3976 | } |
8d655683 | 3977 | |
c2a722d3 DH |
3978 | // Enforce BIP 34 rule that the coinbase starts with serialized block height. |
3979 | // In Zcash this has been enforced since launch, except that the genesis | |
3980 | // block didn't include the height in the coinbase (see Zcash protocol spec | |
3981 | // section '6.8 Bitcoin Improvement Proposals'). | |
548bbd95 | 3982 | if (nHeight > 0) |
a48f2d6d LD |
3983 | { |
3984 | CScript expect = CScript() << nHeight; | |
3985 | if (block.vtx[0].vin[0].scriptSig.size() < expect.size() || | |
3986 | !std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) { | |
16cd9f2d | 3987 | return state.DoS(100, error("%s: block height mismatch in coinbase", __func__), REJECT_INVALID, "bad-cb-height"); |
a48f2d6d LD |
3988 | } |
3989 | } | |
8d655683 | 3990 | |
a48f2d6d LD |
3991 | return true; |
3992 | } | |
3993 | ||
8d725ab4 | 3994 | //static uint256 komodo_requestedhash; |
3995 | //static int32_t komodo_requestedcount; | |
161f617d | 3996 | |
531b9293 | 3997 | bool AcceptBlockHeader(int32_t *futureblockp,const CBlockHeader& block, CValidationState& state, CBlockIndex** ppindex) |
0a61b0df | 3998 | { |
161f617d | 3999 | static uint256 zero; |
4e382177 | 4000 | const CChainParams& chainparams = Params(); |
e07c943c | 4001 | AssertLockHeld(cs_main); |
531b9293 | 4002 | |
0a61b0df | 4003 | // Check for duplicate |
2a4d3464 | 4004 | uint256 hash = block.GetHash(); |
145d5be8 | 4005 | BlockMap::iterator miSelf = mapBlockIndex.find(hash); |
6d3df1e6 | 4006 | CBlockIndex *pindex = NULL; |
5215d24e | 4007 | if (miSelf != mapBlockIndex.end()) |
4008 | { | |
341735eb | 4009 | // Block header is already known. |
942b33a1 | 4010 | pindex = miSelf->second; |
341735eb PW |
4011 | if (ppindex) |
4012 | *ppindex = pindex; | |
6477ad07 | 4013 | if ( pindex != 0 && pindex->nStatus & BLOCK_FAILED_MASK ) |
dc4124de | 4014 | return state.Invalid(error("%s: block is marked invalid", __func__), 0, "duplicate"); |
8d725ab4 | 4015 | /*if ( pindex != 0 && hash == komodo_requestedhash ) |
b80fef6f | 4016 | { |
4017 | fprintf(stderr,"AddToBlockIndex A komodo_requestedhash %s\n",komodo_requestedhash.ToString().c_str()); | |
4018 | memset(&komodo_requestedhash,0,sizeof(komodo_requestedhash)); | |
bddeaf5e | 4019 | komodo_requestedcount = 0; |
8d725ab4 | 4020 | }*/ |
b92dfb1e | 4021 | //if ( pindex == 0 ) |
4022 | // fprintf(stderr,"accepthdr %s already known but no pindex\n",hash.ToString().c_str()); | |
dc4124de | 4023 | return true; |
942b33a1 | 4024 | } |
531b9293 | 4025 | if (!CheckBlockHeader(futureblockp,*ppindex!=0?(*ppindex)->nHeight:0,*ppindex, block, state,0)) |
44c0859f | 4026 | { |
2fea1c97 | 4027 | //fprintf(stderr,"AcceptBlockHeader: CheckBlockHeader failed\n"); |
5f197aee | 4028 | return false; |
44c0859f | 4029 | } |
0a61b0df | 4030 | // Get prev block index |
7fea4846 | 4031 | CBlockIndex* pindexPrev = NULL; |
e6c99a7a | 4032 | if (hash != chainparams.GetConsensus().hashGenesisBlock) |
4033 | { | |
145d5be8 | 4034 | BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); |
b56585d0 | 4035 | if (mi == mapBlockIndex.end()) |
beb911ec | 4036 | { |
e5301556 | 4037 | //fprintf(stderr,"AcceptBlockHeader hashPrevBlock %s not found\n",block.hashPrevBlock.ToString().c_str()); |
8d725ab4 | 4038 | /*if ( komodo_requestedhash == zero ) |
bddeaf5e | 4039 | { |
161f617d | 4040 | komodo_requestedhash = block.hashPrevBlock; |
bddeaf5e | 4041 | komodo_requestedcount = 0; |
8d725ab4 | 4042 | }*/ |
f3071571 | 4043 | return(false); |
4044 | //return state.DoS(10, error("%s: prev block not found", __func__), 0, "bad-prevblk"); | |
beb911ec | 4045 | } |
b56585d0 | 4046 | pindexPrev = (*mi).second; |
e6c99a7a | 4047 | if (pindexPrev == 0 ) |
f65a34b9 | 4048 | { |
531b9293 | 4049 | /*fprintf(stderr,"AcceptBlockHeader failed no pindexPrev %s\n",block.hashPrevBlock.ToString().c_str()); |
4050 | if ( komodo_requestedhash == zero ) | |
f65a34b9 | 4051 | { |
4052 | komodo_requestedhash = block.hashPrevBlock; | |
4053 | komodo_requestedcount = 0; | |
8d725ab4 | 4054 | }*/ |
e6c99a7a | 4055 | return(false); |
f65a34b9 | 4056 | } |
e6c99a7a | 4057 | if ( (pindexPrev->nStatus & BLOCK_FAILED_MASK) ) |
5262fde0 | 4058 | return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); |
942b33a1 | 4059 | } |
a48f2d6d | 4060 | if (!ContextualCheckBlockHeader(block, state, pindexPrev)) |
44c0859f | 4061 | { |
2fea1c97 | 4062 | //fprintf(stderr,"AcceptBlockHeader ContextualCheckBlockHeader failed\n"); |
a48f2d6d | 4063 | return false; |
44c0859f | 4064 | } |
942b33a1 | 4065 | if (pindex == NULL) |
7466a330 | 4066 | { |
4067 | if ( (pindex= AddToBlockIndex(block)) == 0 ) | |
f7ce3004 | 4068 | { |
f65a34b9 | 4069 | fprintf(stderr,"AcceptBlockHeader couldnt add to block index\n"); |
f7ce3004 | 4070 | } |
7466a330 | 4071 | } |
942b33a1 PW |
4072 | if (ppindex) |
4073 | *ppindex = pindex; | |
8d725ab4 | 4074 | /*if ( pindex != 0 && hash == komodo_requestedhash ) |
161f617d | 4075 | { |
4076 | fprintf(stderr,"AddToBlockIndex komodo_requestedhash %s\n",komodo_requestedhash.ToString().c_str()); | |
4077 | memset(&komodo_requestedhash,0,sizeof(komodo_requestedhash)); | |
bddeaf5e | 4078 | komodo_requestedcount = 0; |
8d725ab4 | 4079 | }*/ |
942b33a1 PW |
4080 | return true; |
4081 | } | |
4082 | ||
531b9293 | 4083 | bool AcceptBlock(int32_t *futureblockp,CBlock& block, CValidationState& state, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp) |
942b33a1 | 4084 | { |
e6973430 | 4085 | const CChainParams& chainparams = Params(); |
942b33a1 | 4086 | AssertLockHeld(cs_main); |
8d655683 | 4087 | |
942b33a1 | 4088 | CBlockIndex *&pindex = *ppindex; |
531b9293 | 4089 | if (!AcceptBlockHeader(futureblockp,block, state, &pindex)) |
bd8997bf | 4090 | { |
b92dfb1e | 4091 | //fprintf(stderr,"AcceptBlockHeader rejected\n"); |
942b33a1 | 4092 | return false; |
bd8997bf | 4093 | } |
1e9dc6a8 | 4094 | if ( pindex == 0 ) |
4095 | { | |
e3e263b5 | 4096 | //fprintf(stderr,"AcceptBlock error null pindex\n"); |
1e9dc6a8 | 4097 | return false; |
4098 | } | |
da4020cb | 4099 | //fprintf(stderr,"acceptblockheader passed\n"); |
304892fc SD |
4100 | // Try to process all requested blocks that we don't have, but only |
4101 | // process an unrequested block if it's new and has enough work to | |
93b606ae | 4102 | // advance our tip, and isn't too many blocks ahead. |
304892fc SD |
4103 | bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA; |
4104 | bool fHasMoreWork = (chainActive.Tip() ? pindex->nChainWork > chainActive.Tip()->nChainWork : true); | |
93b606ae SD |
4105 | // Blocks that are too out-of-order needlessly limit the effectiveness of |
4106 | // pruning, because pruning will not delete block files that contain any | |
4107 | // blocks which are too close in height to the tip. Apply this test | |
4108 | // regardless of whether pruning is enabled; it should generally be safe to | |
4109 | // not process unrequested blocks. | |
71f2c696 | 4110 | bool fTooFarAhead = (pindex->nHeight > int(chainActive.Height() + MIN_BLOCKS_TO_KEEP)); |
8d655683 | 4111 | |
304892fc SD |
4112 | // TODO: deal better with return value and error conditions for duplicate |
4113 | // and unrequested blocks. | |
b92dfb1e | 4114 | //fprintf(stderr,"Accept %s flags already.%d requested.%d morework.%d farahead.%d\n",pindex->GetBlockHash().ToString().c_str(),fAlreadyHave,fRequested,fHasMoreWork,fTooFarAhead); |
304892fc SD |
4115 | if (fAlreadyHave) return true; |
4116 | if (!fRequested) { // If we didn't ask for it: | |
4117 | if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned | |
4118 | if (!fHasMoreWork) return true; // Don't process less-work chains | |
93b606ae | 4119 | if (fTooFarAhead) return true; // Block height is too high |
341735eb | 4120 | } |
8d655683 | 4121 | |
6fb8d0c2 JG |
4122 | // See method docstring for why this is always disabled |
4123 | auto verifier = libzcash::ProofVerifier::Disabled(); | |
531b9293 | 4124 | if ((!CheckBlock(futureblockp,pindex->nHeight,pindex,block, state, verifier,0)) || !ContextualCheckBlock(block, state, pindex->pprev)) |
07359935 | 4125 | { |
9f6cb8f0 | 4126 | if (futureblock == 0 && state.IsInvalid() && !state.CorruptionPossible()) { |
942b33a1 | 4127 | pindex->nStatus |= BLOCK_FAILED_VALID; |
51ce901a | 4128 | setDirtyBlockIndex.insert(pindex); |
942b33a1 | 4129 | } |
b92dfb1e | 4130 | //fprintf(stderr,"CheckBlock or ContextualCheckBlock failed\n"); |
942b33a1 PW |
4131 | return false; |
4132 | } | |
8d655683 | 4133 | |
942b33a1 | 4134 | int nHeight = pindex->nHeight; |
8d655683 | 4135 | |
0a61b0df | 4136 | // Write block to history file |
421218d3 | 4137 | try { |
2a4d3464 | 4138 | unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); |
421218d3 PW |
4139 | CDiskBlockPos blockPos; |
4140 | if (dbp != NULL) | |
4141 | blockPos = *dbp; | |
209377a7 | 4142 | if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.GetBlockTime(), dbp != NULL)) |
5262fde0 | 4143 | return error("AcceptBlock(): FindBlockPos failed"); |
421218d3 | 4144 | if (dbp == NULL) |
e6973430 | 4145 | if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) |
27afcd89 | 4146 | AbortNode(state, "Failed to write block"); |
942b33a1 | 4147 | if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) |
5262fde0 | 4148 | return error("AcceptBlock(): ReceivedBlockTransactions failed"); |
27df4123 | 4149 | } catch (const std::runtime_error& e) { |
27afcd89 | 4150 | return AbortNode(state, std::string("System error: ") + e.what()); |
421218d3 | 4151 | } |
8d655683 | 4152 | |
f9ec3f0f | 4153 | if (fCheckForPruning) |
4154 | FlushStateToDisk(state, FLUSH_STATE_NONE); // we just allocated more disk space for block files | |
8d655683 | 4155 | |
0a61b0df | 4156 | return true; |
4157 | } | |
4158 | ||
51aa2492 | 4159 | static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams) |
de237cbf GA |
4160 | { |
4161 | unsigned int nFound = 0; | |
51aa2492 | 4162 | for (int i = 0; i < consensusParams.nMajorityWindow && nFound < nRequired && pstart != NULL; i++) |
de237cbf GA |
4163 | { |
4164 | if (pstart->nVersion >= minVersion) | |
4165 | ++nFound; | |
4166 | pstart = pstart->pprev; | |
4167 | } | |
4168 | return (nFound >= nRequired); | |
4169 | } | |
4170 | ||
c75c18fc | 4171 | void komodo_currentheight_set(int32_t height); |
c9a09183 | 4172 | |
b5d0fe2e | 4173 | CBlockIndex *komodo_ensure(CBlock *pblock,uint256 hash) |
4174 | { | |
4175 | CBlockIndex *pindex; | |
4176 | BlockMap::iterator miSelf = mapBlockIndex.find(hash); | |
4177 | if ( miSelf != mapBlockIndex.end() ) | |
4178 | { | |
4179 | if ( (pindex= miSelf->second) == 0 ) // create pindex so first Accept block doesnt fail | |
4180 | { | |
519578c9 | 4181 | miSelf->second = AddToBlockIndex(*pblock); |
b0bf5d02 | 4182 | //fprintf(stderr,"Block header %s is already known, but without pindex -> ensured %p\n",hash.ToString().c_str(),miSelf->second); |
b5d0fe2e | 4183 | } |
882c4cfe | 4184 | /*if ( hash != chainparams.GetConsensus().hashGenesisBlock ) |
f8a07170 | 4185 | { |
4186 | miSelf = mapBlockIndex.find(pblock->hashPrevBlock); | |
4187 | if ( miSelf == mapBlockIndex.end() ) | |
4188 | { | |
4189 | miSelf->second = InsertBlockIndex(pblock->hashPrevBlock); | |
4190 | fprintf(stderr,"autocreate previndex %s\n",pblock->hashPrevBlock.ToString().c_str()); | |
4191 | } | |
882c4cfe | 4192 | }*/ |
b5d0fe2e | 4193 | } |
4194 | } | |
4195 | ||
7bb789bb | 4196 | bool ProcessNewBlock(bool from_miner,int32_t height,CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp) |
0a61b0df | 4197 | { |
0a61b0df | 4198 | // Preliminary checks |
531b9293 | 4199 | bool checked; uint256 hash; int32_t futureblock=0; |
6fb8d0c2 | 4200 | auto verifier = libzcash::ProofVerifier::Disabled(); |
bc2bcf85 | 4201 | hash = pblock->GetHash(); |
bddeaf5e | 4202 | //fprintf(stderr,"process newblock %s\n",hash.ToString().c_str()); |
6ae728c7 | 4203 | if ( chainActive.Tip() != 0 ) |
c75c18fc | 4204 | komodo_currentheight_set(chainActive.Tip()->nHeight); |
9f6cb8f0 | 4205 | checked = CheckBlock(&futureblock,height!=0?height:komodo_block2height(pblock),0,*pblock, state, verifier,0); |
0a61b0df | 4206 | { |
341735eb | 4207 | LOCK(cs_main); |
bc2bcf85 | 4208 | bool fRequested = MarkBlockAsReceived(hash); |
304892fc | 4209 | fRequested |= fForceProcessing; |
bd87f0c0 | 4210 | if ( checked != 0 && komodo_checkPOW(from_miner && ASSETCHAINS_STAKED == 0,pblock,height) < 0 ) |
13b8b2ed | 4211 | { |
b8add6a4 | 4212 | checked = 0; |
ebb59e60 | 4213 | fprintf(stderr,"passed checkblock but failed checkPOW.%d\n",from_miner && ASSETCHAINS_STAKED == 0); |
13b8b2ed | 4214 | } |
9f6cb8f0 | 4215 | if (!checked && futureblock == 0) |
c7a1d234 | 4216 | { |
50c490cb | 4217 | if ( pfrom != 0 ) |
c7a1d234 | 4218 | { |
04a1f0bb | 4219 | Misbehaving(pfrom->GetId(), 1); |
c7a1d234 | 4220 | } |
872cf91b | 4221 | return error("%s: CheckBlock FAILED", __func__); |
5c88e3c1 | 4222 | } |
341735eb PW |
4223 | // Store to disk |
4224 | CBlockIndex *pindex = NULL; | |
17522a55 | 4225 | { |
66dd02d2 | 4226 | // without the komodo_ensure call, it is quite possible to get a non-error but null pindex returned from AcceptBlockHeader. In a 2 node network, it will be a long time before that block is reprocessed. Even though restarting makes it rescan, it seems much better to keep the nodes in sync |
b92dfb1e | 4227 | komodo_ensure(pblock,hash); |
0f102ea7 | 4228 | } |
531b9293 | 4229 | bool ret = AcceptBlock(&futureblock,*pblock, state, &pindex, fRequested, dbp); |
341735eb PW |
4230 | if (pindex && pfrom) { |
4231 | mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId(); | |
0a61b0df | 4232 | } |
3fcfbc8a | 4233 | CheckBlockIndex(); |
531b9293 | 4234 | if (!ret && futureblock == 0) |
5262fde0 | 4235 | return error("%s: AcceptBlock FAILED", __func__); |
bddeaf5e | 4236 | //else fprintf(stderr,"added block %s %p\n",pindex->GetBlockHash().ToString().c_str(),pindex->pprev); |
18e72167 | 4237 | } |
8d655683 | 4238 | |
531b9293 | 4239 | if (futureblock == 0 && !ActivateBestChain(state, pblock)) |
5262fde0 | 4240 | return error("%s: ActivateBestChain failed", __func__); |
8d655683 | 4241 | |
0a61b0df | 4242 | return true; |
4243 | } | |
4244 | ||
df08a626 LD |
4245 | bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex * const pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot) |
4246 | { | |
4247 | AssertLockHeld(cs_main); | |
4248 | assert(pindexPrev == chainActive.Tip()); | |
8d655683 | 4249 | |
df08a626 LD |
4250 | CCoinsViewCache viewNew(pcoinsTip); |
4251 | CBlockIndex indexDummy(block); | |
4252 | indexDummy.pprev = pindexPrev; | |
4253 | indexDummy.nHeight = pindexPrev->nHeight + 1; | |
6fb8d0c2 JG |
4254 | // JoinSplit proofs are verified in ConnectBlock |
4255 | auto verifier = libzcash::ProofVerifier::Disabled(); | |
df08a626 LD |
4256 | // NOTE: CheckBlockHeader is called by CheckBlock |
4257 | if (!ContextualCheckBlockHeader(block, state, pindexPrev)) | |
d4190a2a | 4258 | { |
b92dfb1e | 4259 | //fprintf(stderr,"TestBlockValidity failure A checkPOW.%d\n",fCheckPOW); |
df08a626 | 4260 | return false; |
d4190a2a | 4261 | } |
9f6cb8f0 | 4262 | int32_t futureblock; |
4263 | if (!CheckBlock(&futureblock,indexDummy.nHeight,0,block, state, verifier, fCheckPOW, fCheckMerkleRoot)) | |
d4190a2a | 4264 | { |
b92dfb1e | 4265 | //fprintf(stderr,"TestBlockValidity failure B checkPOW.%d\n",fCheckPOW); |
df08a626 | 4266 | return false; |
d4190a2a | 4267 | } |
df08a626 | 4268 | if (!ContextualCheckBlock(block, state, pindexPrev)) |
d4190a2a | 4269 | { |
b92dfb1e | 4270 | //fprintf(stderr,"TestBlockValidity failure C checkPOW.%d\n",fCheckPOW); |
df08a626 | 4271 | return false; |
d4190a2a | 4272 | } |
455ba304 | 4273 | if (!ConnectBlock(block, state, &indexDummy, viewNew, true,fCheckPOW)) |
d4190a2a | 4274 | { |
b92dfb1e | 4275 | //fprintf(stderr,"TestBlockValidity failure D checkPOW.%d\n",fCheckPOW); |
df08a626 | 4276 | return false; |
d4190a2a | 4277 | } |
df08a626 | 4278 | assert(state.IsValid()); |
8d655683 | 4279 | |
df08a626 LD |
4280 | return true; |
4281 | } | |
4282 | ||
f9ec3f0f | 4283 | /** |
4284 | * BLOCK PRUNING CODE | |
4285 | */ | |
4286 | ||
4287 | /* Calculate the amount of disk space the block & undo files currently use */ | |
4288 | uint64_t CalculateCurrentUsage() | |
4289 | { | |
4290 | uint64_t retval = 0; | |
4291 | BOOST_FOREACH(const CBlockFileInfo &file, vinfoBlockFile) { | |
4292 | retval += file.nSize + file.nUndoSize; | |
4293 | } | |
4294 | return retval; | |
4295 | } | |
4296 | ||
4297 | /* Prune a block file (modify associated database entries)*/ | |
4298 | void PruneOneBlockFile(const int fileNumber) | |
4299 | { | |
4300 | for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); ++it) { | |
4301 | CBlockIndex* pindex = it->second; | |
4302 | if (pindex->nFile == fileNumber) { | |
4303 | pindex->nStatus &= ~BLOCK_HAVE_DATA; | |
4304 | pindex->nStatus &= ~BLOCK_HAVE_UNDO; | |
4305 | pindex->nFile = 0; | |
4306 | pindex->nDataPos = 0; | |
4307 | pindex->nUndoPos = 0; | |
4308 | setDirtyBlockIndex.insert(pindex); | |
8d655683 | 4309 | |
f9ec3f0f | 4310 | // Prune from mapBlocksUnlinked -- any block we prune would have |
4311 | // to be downloaded again in order to consider its chain, at which | |
4312 | // point it would be considered as a candidate for | |
4313 | // mapBlocksUnlinked or setBlockIndexCandidates. | |
4314 | std::pair<std::multimap<CBlockIndex*, CBlockIndex*>::iterator, std::multimap<CBlockIndex*, CBlockIndex*>::iterator> range = mapBlocksUnlinked.equal_range(pindex->pprev); | |
4315 | while (range.first != range.second) { | |
4316 | std::multimap<CBlockIndex *, CBlockIndex *>::iterator it = range.first; | |
4317 | range.first++; | |
4318 | if (it->second == pindex) { | |
4319 | mapBlocksUnlinked.erase(it); | |
4320 | } | |
4321 | } | |
4322 | } | |
4323 | } | |
8d655683 | 4324 | |
f9ec3f0f | 4325 | vinfoBlockFile[fileNumber].SetNull(); |
4326 | setDirtyFileInfo.insert(fileNumber); | |
4327 | } | |
4328 | ||
4329 | ||
4330 | void UnlinkPrunedFiles(std::set<int>& setFilesToPrune) | |
4331 | { | |
4332 | for (set<int>::iterator it = setFilesToPrune.begin(); it != setFilesToPrune.end(); ++it) { | |
4333 | CDiskBlockPos pos(*it, 0); | |
4334 | boost::filesystem::remove(GetBlockPosFilename(pos, "blk")); | |
4335 | boost::filesystem::remove(GetBlockPosFilename(pos, "rev")); | |
4336 | LogPrintf("Prune: %s deleted blk/rev (%05u)\n", __func__, *it); | |
4337 | } | |
4338 | } | |
4339 | ||
4340 | /* Calculate the block/rev files that should be deleted to remain under target*/ | |
4341 | void FindFilesToPrune(std::set<int>& setFilesToPrune) | |
4342 | { | |
4343 | LOCK2(cs_main, cs_LastBlockFile); | |
4344 | if (chainActive.Tip() == NULL || nPruneTarget == 0) { | |
4345 | return; | |
4346 | } | |
4347 | if (chainActive.Tip()->nHeight <= Params().PruneAfterHeight()) { | |
4348 | return; | |
4349 | } | |
b89f3077 | 4350 | unsigned int nLastBlockWeCanPrune = chainActive.Tip()->nHeight - MIN_BLOCKS_TO_KEEP; |
f9ec3f0f | 4351 | uint64_t nCurrentUsage = CalculateCurrentUsage(); |
4352 | // We don't check to prune until after we've allocated new space for files | |
4353 | // So we should leave a buffer under our target to account for another allocation | |
4354 | // before the next pruning. | |
4355 | uint64_t nBuffer = BLOCKFILE_CHUNK_SIZE + UNDOFILE_CHUNK_SIZE; | |
4356 | uint64_t nBytesToPrune; | |
4357 | int count=0; | |
8d655683 | 4358 | |
f9ec3f0f | 4359 | if (nCurrentUsage + nBuffer >= nPruneTarget) { |
4360 | for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) { | |
4361 | nBytesToPrune = vinfoBlockFile[fileNumber].nSize + vinfoBlockFile[fileNumber].nUndoSize; | |
8d655683 | 4362 | |
f9ec3f0f | 4363 | if (vinfoBlockFile[fileNumber].nSize == 0) |
4364 | continue; | |
8d655683 | 4365 | |
f9ec3f0f | 4366 | if (nCurrentUsage + nBuffer < nPruneTarget) // are we below our target? |
4367 | break; | |
8d655683 | 4368 | |
6cb70ca4 | 4369 | // don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning |
b89f3077 | 4370 | if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) |
6cb70ca4 | 4371 | continue; |
8d655683 | 4372 | |
f9ec3f0f | 4373 | PruneOneBlockFile(fileNumber); |
4374 | // Queue up the files for removal | |
4375 | setFilesToPrune.insert(fileNumber); | |
4376 | nCurrentUsage -= nBytesToPrune; | |
4377 | count++; | |
4378 | } | |
4379 | } | |
8d655683 | 4380 | |
b89f3077 | 4381 | LogPrint("prune", "Prune: target=%dMiB actual=%dMiB diff=%dMiB max_prune_height=%d removed %d blk/rev pairs\n", |
8d655683 | 4382 | nPruneTarget/1024/1024, nCurrentUsage/1024/1024, |
4383 | ((int64_t)nPruneTarget - (int64_t)nCurrentUsage)/1024/1024, | |
4384 | nLastBlockWeCanPrune, count); | |
f9ec3f0f | 4385 | } |
4386 | ||
51ed9ec9 | 4387 | bool CheckDiskSpace(uint64_t nAdditionalBytes) |
0a61b0df | 4388 | { |
a3241998 | 4389 | uint64_t nFreeBytesAvailable = boost::filesystem::space(GetDataDir()).available; |
8d655683 | 4390 | |
966ae00f PK |
4391 | // Check for nMinDiskSpace bytes (currently 50MB) |
4392 | if (nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes) | |
b9b2e3fa | 4393 | return AbortNode("Disk space is low!", _("Error: Disk space is low!")); |
8d655683 | 4394 | |
0a61b0df | 4395 | return true; |
4396 | } | |
4397 | ||
5382bcf8 | 4398 | FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly) |
42613c97 | 4399 | { |
cf53fd7c | 4400 | static int32_t didinit[64]; |
450cbb09 | 4401 | if (pos.IsNull()) |
0a61b0df | 4402 | return NULL; |
ec7eb0fa | 4403 | boost::filesystem::path path = GetBlockPosFilename(pos, prefix); |
5382bcf8 PW |
4404 | boost::filesystem::create_directories(path.parent_path()); |
4405 | FILE* file = fopen(path.string().c_str(), "rb+"); | |
4406 | if (!file && !fReadOnly) | |
4407 | file = fopen(path.string().c_str(), "wb+"); | |
450cbb09 | 4408 | if (!file) { |
7d9d134b | 4409 | LogPrintf("Unable to open file %s\n", path.string()); |
0a61b0df | 4410 | return NULL; |
450cbb09 | 4411 | } |
1a608050 | 4412 | if ( pos.nFile < sizeof(didinit)/sizeof(*didinit) && didinit[pos.nFile] == 0 && strcmp(prefix,(char *)"blk") == 0 ) |
f527fcdb | 4413 | { |
cf53fd7c | 4414 | komodo_prefetch(file); |
1a608050 | 4415 | didinit[pos.nFile] = 1; |
f527fcdb | 4416 | } |
5382bcf8 PW |
4417 | if (pos.nPos) { |
4418 | if (fseek(file, pos.nPos, SEEK_SET)) { | |
7d9d134b | 4419 | LogPrintf("Unable to seek to position %u of %s\n", pos.nPos, path.string()); |
5382bcf8 PW |
4420 | fclose(file); |
4421 | return NULL; | |
4422 | } | |
4423 | } | |
0a61b0df | 4424 | return file; |
4425 | } | |
4426 | ||
5382bcf8 PW |
4427 | FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly) { |
4428 | return OpenDiskFile(pos, "blk", fReadOnly); | |
4429 | } | |
4430 | ||
69e07747 | 4431 | FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly) { |
5382bcf8 PW |
4432 | return OpenDiskFile(pos, "rev", fReadOnly); |
4433 | } | |
4434 | ||
ec7eb0fa SD |
4435 | boost::filesystem::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix) |
4436 | { | |
f7e36370 | 4437 | return GetDataDir() / "blocks" / strprintf("%s%05u.dat", prefix, pos.nFile); |
ec7eb0fa SD |
4438 | } |
4439 | ||
2d8a4829 PW |
4440 | CBlockIndex * InsertBlockIndex(uint256 hash) |
4441 | { | |
4f152496 | 4442 | if (hash.IsNull()) |
2d8a4829 | 4443 | return NULL; |
8d655683 | 4444 | |
2d8a4829 | 4445 | // Return existing |
145d5be8 | 4446 | BlockMap::iterator mi = mapBlockIndex.find(hash); |
2d8a4829 PW |
4447 | if (mi != mapBlockIndex.end()) |
4448 | return (*mi).second; | |
8d655683 | 4449 | |
2d8a4829 PW |
4450 | // Create new |
4451 | CBlockIndex* pindexNew = new CBlockIndex(); | |
4452 | if (!pindexNew) | |
5262fde0 | 4453 | throw runtime_error("LoadBlockIndex(): new CBlockIndex failed"); |
2d8a4829 PW |
4454 | mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; |
4455 | pindexNew->phashBlock = &((*mi).first); | |
66dd02d2 | 4456 | //fprintf(stderr,"inserted to block index %s\n",hash.ToString().c_str()); |
e1407365 | 4457 | |
2d8a4829 PW |
4458 | return pindexNew; |
4459 | } | |
4460 | ||
102cc989 | 4461 | //void komodo_pindex_init(CBlockIndex *pindex,int32_t height); |
141950a4 | 4462 | |
2d8a4829 PW |
4463 | bool static LoadBlockIndexDB() |
4464 | { | |
11982d36 | 4465 | const CChainParams& chainparams = Params(); |
6a0c9826 | 4466 | LogPrintf("%s: start loading guts\n", __func__); |
2d8a4829 PW |
4467 | if (!pblocktree->LoadBlockIndexGuts()) |
4468 | return false; | |
6a0c9826 | 4469 | LogPrintf("%s: loaded guts\n", __func__); |
b31499ec | 4470 | boost::this_thread::interruption_point(); |
8d655683 | 4471 | |
1657c4bc | 4472 | // Calculate nChainWork |
2d8a4829 PW |
4473 | vector<pair<int, CBlockIndex*> > vSortedByHeight; |
4474 | vSortedByHeight.reserve(mapBlockIndex.size()); | |
4475 | BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) | |
4476 | { | |
4477 | CBlockIndex* pindex = item.second; | |
4478 | vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex)); | |
102cc989 | 4479 | //komodo_pindex_init(pindex,(int32_t)pindex->nHeight); |
2d8a4829 | 4480 | } |
e1a6427c | 4481 | //fprintf(stderr,"load blockindexDB paired %u\n",(uint32_t)time(NULL)); |
2d8a4829 | 4482 | sort(vSortedByHeight.begin(), vSortedByHeight.end()); |
e1a6427c | 4483 | //fprintf(stderr,"load blockindexDB sorted %u\n",(uint32_t)time(NULL)); |
2d8a4829 PW |
4484 | BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight) |
4485 | { | |
4486 | CBlockIndex* pindex = item.second; | |
092b58d1 | 4487 | pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex); |
f9ec3f0f | 4488 | // We can link the chain of blocks for which we've received transactions at some point. |
4489 | // Pruned nodes may have deleted the block. | |
4490 | if (pindex->nTx > 0) { | |
341735eb PW |
4491 | if (pindex->pprev) { |
4492 | if (pindex->pprev->nChainTx) { | |
4493 | pindex->nChainTx = pindex->pprev->nChainTx + pindex->nTx; | |
ad6a36ad JG |
4494 | if (pindex->pprev->nChainSproutValue && pindex->nSproutValue) { |
4495 | pindex->nChainSproutValue = *pindex->pprev->nChainSproutValue + *pindex->nSproutValue; | |
4496 | } else { | |
4497 | pindex->nChainSproutValue = boost::none; | |
4498 | } | |
341735eb PW |
4499 | } else { |
4500 | pindex->nChainTx = 0; | |
ad6a36ad | 4501 | pindex->nChainSproutValue = boost::none; |
341735eb PW |
4502 | mapBlocksUnlinked.insert(std::make_pair(pindex->pprev, pindex)); |
4503 | } | |
4504 | } else { | |
4505 | pindex->nChainTx = pindex->nTx; | |
ad6a36ad | 4506 | pindex->nChainSproutValue = pindex->nSproutValue; |
341735eb PW |
4507 | } |
4508 | } | |
9e851450 JG |
4509 | // Construct in-memory chain of branch IDs. |
4510 | // Relies on invariant: a block that does not activate a network upgrade | |
4511 | // will always be valid under the same consensus rules as its parent. | |
828940b1 JG |
4512 | // Genesis block has a branch ID of zero by definition, but has no |
4513 | // validity status because it is side-loaded into a fresh chain. | |
4514 | // Activation blocks will have branch IDs set (read from disk). | |
4515 | if (pindex->pprev) { | |
4516 | if (pindex->IsValid(BLOCK_VALID_CONSENSUS) && !pindex->nCachedBranchId) { | |
4517 | pindex->nCachedBranchId = pindex->pprev->nCachedBranchId; | |
4518 | } | |
4519 | } else { | |
be126699 | 4520 | pindex->nCachedBranchId = SPROUT_BRANCH_ID; |
9e851450 | 4521 | } |
341735eb | 4522 | if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == NULL)) |
e17bd583 | 4523 | setBlockIndexCandidates.insert(pindex); |
85eb2cef PW |
4524 | if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork)) |
4525 | pindexBestInvalid = pindex; | |
c9a09183 PW |
4526 | if (pindex->pprev) |
4527 | pindex->BuildSkip(); | |
341735eb PW |
4528 | if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == NULL || CBlockIndexWorkComparator()(pindexBestHeader, pindex))) |
4529 | pindexBestHeader = pindex; | |
102cc989 | 4530 | //komodo_pindex_init(pindex,(int32_t)pindex->nHeight); |
2d8a4829 | 4531 | } |
e1a6427c | 4532 | //fprintf(stderr,"load blockindexDB chained %u\n",(uint32_t)time(NULL)); |
d00db115 | 4533 | |
2d8a4829 PW |
4534 | // Load block file info |
4535 | pblocktree->ReadLastBlockFile(nLastBlockFile); | |
ed6d1a2c | 4536 | vinfoBlockFile.resize(nLastBlockFile + 1); |
7b2bb962 | 4537 | LogPrintf("%s: last block file = %i\n", __func__, nLastBlockFile); |
ed6d1a2c PW |
4538 | for (int nFile = 0; nFile <= nLastBlockFile; nFile++) { |
4539 | pblocktree->ReadBlockFileInfo(nFile, vinfoBlockFile[nFile]); | |
4540 | } | |
7b2bb962 | 4541 | LogPrintf("%s: last block file info: %s\n", __func__, vinfoBlockFile[nLastBlockFile].ToString()); |
ed6d1a2c PW |
4542 | for (int nFile = nLastBlockFile + 1; true; nFile++) { |
4543 | CBlockFileInfo info; | |
4544 | if (pblocktree->ReadBlockFileInfo(nFile, info)) { | |
4545 | vinfoBlockFile.push_back(info); | |
4546 | } else { | |
4547 | break; | |
4548 | } | |
4549 | } | |
8d655683 | 4550 | |
8c93bf4c AH |
4551 | // Check presence of blk files |
4552 | LogPrintf("Checking all blk files are present...\n"); | |
4553 | set<int> setBlkDataFiles; | |
4554 | BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) | |
4555 | { | |
4556 | CBlockIndex* pindex = item.second; | |
4557 | if (pindex->nStatus & BLOCK_HAVE_DATA) { | |
4558 | setBlkDataFiles.insert(pindex->nFile); | |
4559 | } | |
102cc989 | 4560 | //komodo_pindex_init(pindex,(int32_t)pindex->nHeight); |
8c93bf4c | 4561 | } |
e1a6427c | 4562 | //fprintf(stderr,"load blockindexDB %u\n",(uint32_t)time(NULL)); |
8c93bf4c AH |
4563 | for (std::set<int>::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++) |
4564 | { | |
4565 | CDiskBlockPos pos(*it, 0); | |
a8738238 | 4566 | if (CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION).IsNull()) { |
8c93bf4c AH |
4567 | return false; |
4568 | } | |
4569 | } | |
8d655683 | 4570 | |
f9ec3f0f | 4571 | // Check whether we have ever pruned block & undo files |
4572 | pblocktree->ReadFlag("prunedblockfiles", fHavePruned); | |
4573 | if (fHavePruned) | |
4574 | LogPrintf("LoadBlockIndexDB(): Block files have previously been pruned\n"); | |
8d655683 | 4575 | |
89b7019b PW |
4576 | // Check whether we need to continue reindexing |
4577 | bool fReindexing = false; | |
4578 | pblocktree->ReadReindexing(fReindexing); | |
4579 | fReindex |= fReindexing; | |
8d655683 | 4580 | |
2d1fa42e PW |
4581 | // Check whether we have a transaction index |
4582 | pblocktree->ReadFlag("txindex", fTxIndex); | |
52070c87 | 4583 | LogPrintf("%s: transaction index %s\n", __func__, fTxIndex ? "enabled" : "disabled"); |
8b78a819 T |
4584 | // Check whether we have an address index |
4585 | pblocktree->ReadFlag("addressindex", fAddressIndex); | |
4586 | LogPrintf("%s: address index %s\n", __func__, fAddressIndex ? "enabled" : "disabled"); | |
4587 | ||
4588 | // Check whether we have a timestamp index | |
4589 | pblocktree->ReadFlag("timestampindex", fTimestampIndex); | |
4590 | LogPrintf("%s: timestamp index %s\n", __func__, fTimestampIndex ? "enabled" : "disabled"); | |
4591 | ||
4592 | // Check whether we have a spent index | |
4593 | pblocktree->ReadFlag("spentindex", fSpentIndex); | |
4594 | LogPrintf("%s: spent index %s\n", __func__, fSpentIndex ? "enabled" : "disabled"); | |
4595 | ||
0bc1e2c4 JG |
4596 | // Fill in-memory data |
4597 | BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) | |
4598 | { | |
4599 | CBlockIndex* pindex = item.second; | |
4600 | // - This relationship will always be true even if pprev has multiple | |
4601 | // children, because hashAnchor is technically a property of pprev, | |
4602 | // not its children. | |
4603 | // - This will miss chain tips; we handle the best tip below, and other | |
4604 | // tips will be handled by ConnectTip during a re-org. | |
4605 | if (pindex->pprev) { | |
4606 | pindex->pprev->hashAnchorEnd = pindex->hashAnchor; | |
4607 | } | |
102cc989 | 4608 | //komodo_pindex_init(pindex,(int32_t)pindex->nHeight); |
0bc1e2c4 | 4609 | } |
8d655683 | 4610 | |
85eb2cef | 4611 | // Load pointer to end of best chain |
145d5be8 | 4612 | BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); |
84674082 | 4613 | if (it == mapBlockIndex.end()) |
89b7019b | 4614 | return true; |
84674082 | 4615 | chainActive.SetTip(it->second); |
0bc1e2c4 JG |
4616 | // Set hashAnchorEnd for the end of best chain |
4617 | it->second->hashAnchorEnd = pcoinsTip->GetBestAnchor(); | |
8d655683 | 4618 | |
cca48f69 | 4619 | PruneBlockIndexCandidates(); |
8d655683 | 4620 | |
52070c87 | 4621 | LogPrintf("%s: hashBestChain=%s height=%d date=%s progress=%f\n", __func__, |
8d655683 | 4622 | chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), |
4623 | DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), | |
4624 | Checkpoints::GuessVerificationProgress(chainparams.Checkpoints(), chainActive.Tip())); | |
4625 | ||
5b3bc971 | 4626 | EnforceNodeDeprecation(chainActive.Height(), true); |
8d655683 | 4627 | |
1f355b66 PW |
4628 | return true; |
4629 | } | |
4630 | ||
06a91d96 CL |
4631 | CVerifyDB::CVerifyDB() |
4632 | { | |
4633 | uiInterface.ShowProgress(_("Verifying blocks..."), 0); | |
4634 | } | |
4635 | ||
4636 | CVerifyDB::~CVerifyDB() | |
4637 | { | |
4638 | uiInterface.ShowProgress("", 100); | |
4639 | } | |
4640 | ||
2e280311 | 4641 | bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth) |
168ba993 | 4642 | { |
a475285a | 4643 | LOCK(cs_main); |
4c6d41b8 | 4644 | if (chainActive.Tip() == NULL || chainActive.Tip()->pprev == NULL) |
1f355b66 | 4645 | return true; |
8d655683 | 4646 | |
2d8a4829 | 4647 | // Verify blocks in the best chain |
f5906533 | 4648 | if (nCheckDepth <= 0) |
2d8a4829 | 4649 | nCheckDepth = 1000000000; // suffices until the year 19000 |
4c6d41b8 PW |
4650 | if (nCheckDepth > chainActive.Height()) |
4651 | nCheckDepth = chainActive.Height(); | |
1f355b66 | 4652 | nCheckLevel = std::max(0, std::min(4, nCheckLevel)); |
881a85a2 | 4653 | LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); |
7c70438d | 4654 | CCoinsViewCache coins(coinsview); |
4c6d41b8 | 4655 | CBlockIndex* pindexState = chainActive.Tip(); |
1f355b66 PW |
4656 | CBlockIndex* pindexFailure = NULL; |
4657 | int nGoodTransactions = 0; | |
ef3988ca | 4658 | CValidationState state; |
6fb8d0c2 JG |
4659 | // No need to verify JoinSplits twice |
4660 | auto verifier = libzcash::ProofVerifier::Disabled(); | |
d00db115 | 4661 | //fprintf(stderr,"start VerifyDB %u\n",(uint32_t)time(NULL)); |
4c6d41b8 | 4662 | for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) |
2d8a4829 | 4663 | { |
b31499ec | 4664 | boost::this_thread::interruption_point(); |
06a91d96 | 4665 | uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))))); |
4c6d41b8 | 4666 | if (pindex->nHeight < chainActive.Height()-nCheckDepth) |
2d8a4829 PW |
4667 | break; |
4668 | CBlock block; | |
1f355b66 | 4669 | // check level 0: read from disk |
b8add6a4 | 4670 | if (!ReadBlockFromDisk(block, pindex,0)) |
5262fde0 | 4671 | return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); |
2d8a4829 | 4672 | // check level 1: verify block validity |
9f6cb8f0 | 4673 | int32_t futureblock; |
4674 | if (nCheckLevel >= 1 && !CheckBlock(&futureblock,pindex->nHeight,pindex,block, state, verifier,0)) | |
5262fde0 | 4675 | return error("VerifyDB(): *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); |
1f355b66 PW |
4676 | // check level 2: verify undo validity |
4677 | if (nCheckLevel >= 2 && pindex) { | |
4678 | CBlockUndo undo; | |
4679 | CDiskBlockPos pos = pindex->GetUndoPos(); | |
4680 | if (!pos.IsNull()) { | |
e035c6a7 | 4681 | if (!UndoReadFromDisk(undo, pos, pindex->pprev->GetBlockHash())) |
5262fde0 | 4682 | return error("VerifyDB(): *** found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); |
1f355b66 PW |
4683 | } |
4684 | } | |
4685 | // check level 3: check for inconsistencies during memory-only disconnect of tip blocks | |
fc684ad8 | 4686 | if (nCheckLevel >= 3 && pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) { |
1f355b66 | 4687 | bool fClean = true; |
5c363ed6 | 4688 | if (!DisconnectBlock(block, state, pindex, coins, &fClean)) |
5262fde0 | 4689 | return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); |
1f355b66 PW |
4690 | pindexState = pindex->pprev; |
4691 | if (!fClean) { | |
4692 | nGoodTransactions = 0; | |
4693 | pindexFailure = pindex; | |
4694 | } else | |
4695 | nGoodTransactions += block.vtx.size(); | |
2d8a4829 | 4696 | } |
70477a0b TZ |
4697 | if (ShutdownRequested()) |
4698 | return true; | |
2d8a4829 | 4699 | } |
d00db115 | 4700 | //fprintf(stderr,"end VerifyDB %u\n",(uint32_t)time(NULL)); |
1f355b66 | 4701 | if (pindexFailure) |
5262fde0 | 4702 | return error("VerifyDB(): *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainActive.Height() - pindexFailure->nHeight + 1, nGoodTransactions); |
8d655683 | 4703 | |
1f355b66 PW |
4704 | // check level 4: try reconnecting blocks |
4705 | if (nCheckLevel >= 4) { | |
4706 | CBlockIndex *pindex = pindexState; | |
4c6d41b8 | 4707 | while (pindex != chainActive.Tip()) { |
b31499ec | 4708 | boost::this_thread::interruption_point(); |
06a91d96 | 4709 | uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50)))); |
4c6d41b8 | 4710 | pindex = chainActive.Next(pindex); |
b001c871 | 4711 | CBlock block; |
b8add6a4 | 4712 | if (!ReadBlockFromDisk(block, pindex,0)) |
5262fde0 | 4713 | return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); |
96f9009e | 4714 | if (!ConnectBlock(block, state, pindex, coins,false, true)) |
5262fde0 | 4715 | return error("VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); |
1f355b66 | 4716 | } |
2d8a4829 | 4717 | } |
8d655683 | 4718 | |
4c6d41b8 | 4719 | LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", chainActive.Height() - pindexState->nHeight, nGoodTransactions); |
8d655683 | 4720 | |
2d8a4829 PW |
4721 | return true; |
4722 | } | |
4723 | ||
89f20450 PW |
4724 | bool RewindBlockIndex(const CChainParams& params) |
4725 | { | |
4726 | LOCK(cs_main); | |
8d655683 | 4727 | |
9e851450 | 4728 | // RewindBlockIndex is called after LoadBlockIndex, so at this point every block |
828940b1 JG |
4729 | // index will have nCachedBranchId set based on the values previously persisted |
4730 | // to disk. By definition, a set nCachedBranchId means that the block was | |
9e851450 JG |
4731 | // fully-validated under the corresponding consensus rules. Thus we can quickly |
4732 | // identify whether the current active chain matches our expected sequence of | |
4733 | // consensus rule changes, with two checks: | |
4734 | // | |
4735 | // - BLOCK_ACTIVATES_UPGRADE is set only on blocks that activate upgrades. | |
828940b1 | 4736 | // - nCachedBranchId for each block matches what we expect. |
9e851450 JG |
4737 | auto sufficientlyValidated = [¶ms](const CBlockIndex* pindex) { |
4738 | auto consensus = params.GetConsensus(); | |
4739 | bool fFlagSet = pindex->nStatus & BLOCK_ACTIVATES_UPGRADE; | |
4740 | bool fFlagExpected = IsActivationHeightForAnyUpgrade(pindex->nHeight, consensus); | |
828940b1 | 4741 | return fFlagSet == fFlagExpected && |
8d655683 | 4742 | pindex->nCachedBranchId && |
4743 | *pindex->nCachedBranchId == CurrentEpochBranchId(pindex->nHeight, consensus); | |
9e851450 | 4744 | }; |
8d655683 | 4745 | |
89f20450 PW |
4746 | int nHeight = 1; |
4747 | while (nHeight <= chainActive.Height()) { | |
9e851450 | 4748 | if (!sufficientlyValidated(chainActive[nHeight])) { |
89f20450 PW |
4749 | break; |
4750 | } | |
4751 | nHeight++; | |
4752 | } | |
8d655683 | 4753 | |
89f20450 | 4754 | // nHeight is now the height of the first insufficiently-validated block, or tipheight + 1 |
cb580c72 JG |
4755 | auto rewindLength = chainActive.Height() - nHeight; |
4756 | if (rewindLength > 0 && rewindLength > MAX_REORG_LENGTH) { | |
4757 | auto pindexOldTip = chainActive.Tip(); | |
4758 | auto pindexRewind = chainActive[nHeight - 1]; | |
4759 | auto msg = strprintf(_( | |
8d655683 | 4760 | "A block chain rewind has been detected that would roll back %d blocks! " |
4761 | "This is larger than the maximum of %d blocks, and so the node is shutting down for your safety." | |
4762 | ), rewindLength, MAX_REORG_LENGTH) + "\n\n" + | |
4763 | _("Rewind details") + ":\n" + | |
4764 | "- " + strprintf(_("Current tip: %s, height %d"), | |
4765 | pindexOldTip->phashBlock->GetHex(), pindexOldTip->nHeight) + "\n" + | |
4766 | "- " + strprintf(_("Rewinding to: %s, height %d"), | |
4767 | pindexRewind->phashBlock->GetHex(), pindexRewind->nHeight) + "\n\n" + | |
4768 | _("Please help, human!"); | |
cb580c72 JG |
4769 | LogPrintf("*** %s\n", msg); |
4770 | uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR); | |
4771 | StartShutdown(); | |
4772 | return false; | |
4773 | } | |
8d655683 | 4774 | |
89f20450 PW |
4775 | CValidationState state; |
4776 | CBlockIndex* pindex = chainActive.Tip(); | |
4777 | while (chainActive.Height() >= nHeight) { | |
4778 | if (fPruneMode && !(chainActive.Tip()->nStatus & BLOCK_HAVE_DATA)) { | |
4779 | // If pruning, don't try rewinding past the HAVE_DATA point; | |
4780 | // since older blocks can't be served anyway, there's | |
4781 | // no need to walk further, and trying to DisconnectTip() | |
4782 | // will fail (and require a needless reindex/redownload | |
4783 | // of the blockchain). | |
4784 | break; | |
4785 | } | |
4786 | if (!DisconnectTip(state, true)) { | |
4787 | return error("RewindBlockIndex: unable to disconnect block at height %i", pindex->nHeight); | |
4788 | } | |
4789 | // Occasionally flush state to disk. | |
4790 | if (!FlushStateToDisk(state, FLUSH_STATE_PERIODIC)) | |
4791 | return false; | |
4792 | } | |
8d655683 | 4793 | |
89f20450 PW |
4794 | // Reduce validity flag and have-data flags. |
4795 | // We do this after actual disconnecting, otherwise we'll end up writing the lack of data | |
4796 | // to disk before writing the chainstate, resulting in a failure to continue if interrupted. | |
4797 | for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) { | |
4798 | CBlockIndex* pindexIter = it->second; | |
8d655683 | 4799 | |
89f20450 PW |
4800 | // Note: If we encounter an insufficiently validated block that |
4801 | // is on chainActive, it must be because we are a pruning node, and | |
4802 | // this block or some successor doesn't HAVE_DATA, so we were unable to | |
4803 | // rewind all the way. Blocks remaining on chainActive at this point | |
4804 | // must not have their validity reduced. | |
9e851450 | 4805 | if (!sufficientlyValidated(pindexIter) && !chainActive.Contains(pindexIter)) { |
89f20450 | 4806 | // Reduce validity |
9e851450 | 4807 | pindexIter->nStatus = |
8d655683 | 4808 | std::min<unsigned int>(pindexIter->nStatus & BLOCK_VALID_MASK, BLOCK_VALID_TREE) | |
4809 | (pindexIter->nStatus & ~BLOCK_VALID_MASK); | |
9e851450 | 4810 | // Remove have-data flags |
89f20450 | 4811 | pindexIter->nStatus &= ~(BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO); |
9e851450 JG |
4812 | // Remove branch ID |
4813 | pindexIter->nStatus &= ~BLOCK_ACTIVATES_UPGRADE; | |
828940b1 | 4814 | pindexIter->nCachedBranchId = boost::none; |
9e851450 | 4815 | // Remove storage location |
89f20450 PW |
4816 | pindexIter->nFile = 0; |
4817 | pindexIter->nDataPos = 0; | |
4818 | pindexIter->nUndoPos = 0; | |
4819 | // Remove various other things | |
4820 | pindexIter->nTx = 0; | |
4821 | pindexIter->nChainTx = 0; | |
9e851450 JG |
4822 | pindexIter->nSproutValue = boost::none; |
4823 | pindexIter->nChainSproutValue = boost::none; | |
89f20450 | 4824 | pindexIter->nSequenceId = 0; |
9e851450 | 4825 | // Make sure it gets written |
89f20450 | 4826 | setDirtyBlockIndex.insert(pindexIter); |
cef5ad03 | 4827 | if (pindexIter == pindexBestInvalid) |
4828 | { | |
3d3f275f | 4829 | //fprintf(stderr,"Reset invalid block marker if it was pointing to this block\n"); |
cef5ad03 | 4830 | pindexBestInvalid = NULL; |
4831 | } | |
4832 | ||
9e851450 | 4833 | // Update indices |
89f20450 | 4834 | setBlockIndexCandidates.erase(pindexIter); |
9e851450 | 4835 | auto ret = mapBlocksUnlinked.equal_range(pindexIter->pprev); |
89f20450 PW |
4836 | while (ret.first != ret.second) { |
4837 | if (ret.first->second == pindexIter) { | |
4838 | mapBlocksUnlinked.erase(ret.first++); | |
4839 | } else { | |
4840 | ++ret.first; | |
4841 | } | |
4842 | } | |
4843 | } else if (pindexIter->IsValid(BLOCK_VALID_TRANSACTIONS) && pindexIter->nChainTx) { | |
4844 | setBlockIndexCandidates.insert(pindexIter); | |
4845 | } | |
4846 | } | |
8d655683 | 4847 | |
89f20450 | 4848 | PruneBlockIndexCandidates(); |
8d655683 | 4849 | |
89f20450 | 4850 | CheckBlockIndex(); |
8d655683 | 4851 | |
89f20450 PW |
4852 | if (!FlushStateToDisk(state, FLUSH_STATE_ALWAYS)) { |
4853 | return false; | |
4854 | } | |
8d655683 | 4855 | |
89f20450 PW |
4856 | return true; |
4857 | } | |
4858 | ||
f7f3a96b PW |
4859 | void UnloadBlockIndex() |
4860 | { | |
51598b26 | 4861 | LOCK(cs_main); |
e17bd583 | 4862 | setBlockIndexCandidates.clear(); |
4c6d41b8 | 4863 | chainActive.SetTip(NULL); |
85eb2cef | 4864 | pindexBestInvalid = NULL; |
51598b26 PW |
4865 | pindexBestHeader = NULL; |
4866 | mempool.clear(); | |
4867 | mapOrphanTransactions.clear(); | |
4868 | mapOrphanTransactionsByPrev.clear(); | |
4869 | nSyncStarted = 0; | |
4870 | mapBlocksUnlinked.clear(); | |
4871 | vinfoBlockFile.clear(); | |
4872 | nLastBlockFile = 0; | |
4873 | nBlockSequenceId = 1; | |
4874 | mapBlockSource.clear(); | |
4875 | mapBlocksInFlight.clear(); | |
4876 | nQueuedValidatedHeaders = 0; | |
4877 | nPreferredDownload = 0; | |
4878 | setDirtyBlockIndex.clear(); | |
4879 | setDirtyFileInfo.clear(); | |
4880 | mapNodeState.clear(); | |
ec9b6c33 | 4881 | recentRejects.reset(NULL); |
8d655683 | 4882 | |
51598b26 PW |
4883 | BOOST_FOREACH(BlockMap::value_type& entry, mapBlockIndex) { |
4884 | delete entry.second; | |
4885 | } | |
4886 | mapBlockIndex.clear(); | |
f9ec3f0f | 4887 | fHavePruned = false; |
f7f3a96b PW |
4888 | } |
4889 | ||
7fea4846 | 4890 | bool LoadBlockIndex() |
0a61b0df | 4891 | { |
d979e6e3 | 4892 | // Load block index from databases |
d042777b | 4893 | KOMODO_LOADINGBLOCKS = 1; |
2d1fa42e | 4894 | if (!fReindex && !LoadBlockIndexDB()) |
d042777b | 4895 | { |
4896 | KOMODO_LOADINGBLOCKS = 0; | |
0a61b0df | 4897 | return false; |
d042777b | 4898 | } |
25f7ef8c | 4899 | fprintf(stderr,"finished loading blocks %s\n",ASSETCHAINS_SYMBOL); |
38603761 PW |
4900 | return true; |
4901 | } | |
2d1fa42e | 4902 | |
2d1fa42e | 4903 | |
38603761 | 4904 | bool InitBlockIndex() { |
e6973430 | 4905 | const CChainParams& chainparams = Params(); |
55a1db4f | 4906 | LOCK(cs_main); |
8d655683 | 4907 | |
5094a81d WL |
4908 | // Initialize global variables that cannot be constructed at startup. |
4909 | recentRejects.reset(new CRollingBloomFilter(120000, 0.000001)); | |
8d655683 | 4910 | |
38603761 | 4911 | // Check whether we're already initialized |
4c6d41b8 | 4912 | if (chainActive.Genesis() != NULL) |
38603761 | 4913 | return true; |
8d655683 | 4914 | |
38603761 | 4915 | // Use the provided setting for -txindex in the new database |
b2c00e54 | 4916 | fTxIndex = GetBoolArg("-txindex", true); |
38603761 | 4917 | pblocktree->WriteFlag("txindex", fTxIndex); |
8b78a819 T |
4918 | // Use the provided setting for -addressindex in the new database |
4919 | fAddressIndex = GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX); | |
4920 | pblocktree->WriteFlag("addressindex", fAddressIndex); | |
4921 | ||
4922 | // Use the provided setting for -timestampindex in the new database | |
4923 | fTimestampIndex = GetBoolArg("-timestampindex", DEFAULT_TIMESTAMPINDEX); | |
4924 | pblocktree->WriteFlag("timestampindex", fTimestampIndex); | |
4925 | ||
4926 | fSpentIndex = GetBoolArg("-spentindex", DEFAULT_SPENTINDEX); | |
4927 | pblocktree->WriteFlag("spentindex", fSpentIndex); | |
881a85a2 | 4928 | LogPrintf("Initializing databases...\n"); |
8d655683 | 4929 | |
38603761 PW |
4930 | // Only add the genesis block if not reindexing (in which case we reuse the one already on disk) |
4931 | if (!fReindex) { | |
38603761 | 4932 | try { |
0e4b3175 MH |
4933 | CBlock &block = const_cast<CBlock&>(Params().GenesisBlock()); |
4934 | // Start new block file | |
38603761 PW |
4935 | unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); |
4936 | CDiskBlockPos blockPos; | |
4937 | CValidationState state; | |
209377a7 | 4938 | if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.GetBlockTime())) |
5262fde0 | 4939 | return error("LoadBlockIndex(): FindBlockPos failed"); |
e6973430 | 4940 | if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) |
5262fde0 | 4941 | return error("LoadBlockIndex(): writing genesis block to disk failed"); |
942b33a1 | 4942 | CBlockIndex *pindex = AddToBlockIndex(block); |
294925c7 | 4943 | if ( pindex == 0 ) |
4944 | return error("LoadBlockIndex(): couldnt add to block index"); | |
942b33a1 | 4945 | if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) |
5262fde0 | 4946 | return error("LoadBlockIndex(): genesis block not accepted"); |
92bb6f2f | 4947 | if (!ActivateBestChain(state, &block)) |
5262fde0 | 4948 | return error("LoadBlockIndex(): genesis block cannot be activated"); |
bf7835c2 | 4949 | // Force a chainstate write so that when we VerifyDB in a moment, it doesn't check stale data |
a2069500 | 4950 | return FlushStateToDisk(state, FLUSH_STATE_ALWAYS); |
27df4123 | 4951 | } catch (const std::runtime_error& e) { |
5262fde0 | 4952 | return error("LoadBlockIndex(): failed to initialize block database: %s", e.what()); |
38603761 | 4953 | } |
0a61b0df | 4954 | } |
8d655683 | 4955 | |
0a61b0df | 4956 | return true; |
4957 | } | |
4958 | ||
4959 | ||
4960 | ||
7fea4846 | 4961 | bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) |
1d740055 | 4962 | { |
4e382177 | 4963 | const CChainParams& chainparams = Params(); |
ad96e7cc WL |
4964 | // Map of disk positions for blocks with unknown parent (only used for reindex) |
4965 | static std::multimap<uint256, CDiskBlockPos> mapBlocksUnknownParent; | |
51ed9ec9 | 4966 | int64_t nStart = GetTimeMillis(); |
8d655683 | 4967 | |
1d740055 | 4968 | int nLoaded = 0; |
421218d3 | 4969 | try { |
c9fb27da | 4970 | // This takes over fileIn and calls fclose() on it in the CBufferedFile destructor |
b8add6a4 | 4971 | //CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION); |
0e32bd33 | 4972 | CBufferedFile blkdat(fileIn, 32*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION); |
51ed9ec9 | 4973 | uint64_t nRewind = blkdat.GetPos(); |
eb0b56b1 | 4974 | while (!blkdat.eof()) { |
21eb5ada | 4975 | boost::this_thread::interruption_point(); |
8d655683 | 4976 | |
05d97268 PW |
4977 | blkdat.SetPos(nRewind); |
4978 | nRewind++; // start one byte further next time, in case of failure | |
4979 | blkdat.SetLimit(); // remove former limit | |
7fea4846 | 4980 | unsigned int nSize = 0; |
05d97268 PW |
4981 | try { |
4982 | // locate a header | |
0caf2b18 | 4983 | unsigned char buf[MESSAGE_START_SIZE]; |
0e4b3175 | 4984 | blkdat.FindByte(Params().MessageStart()[0]); |
05d97268 PW |
4985 | nRewind = blkdat.GetPos()+1; |
4986 | blkdat >> FLATDATA(buf); | |
0caf2b18 | 4987 | if (memcmp(buf, Params().MessageStart(), MESSAGE_START_SIZE)) |
05d97268 PW |
4988 | continue; |
4989 | // read size | |
1d740055 | 4990 | blkdat >> nSize; |
05d97268 PW |
4991 | if (nSize < 80 || nSize > MAX_BLOCK_SIZE) |
4992 | continue; | |
27df4123 | 4993 | } catch (const std::exception&) { |
7fea4846 PW |
4994 | // no valid block header found; don't complain |
4995 | break; | |
4996 | } | |
4997 | try { | |
05d97268 | 4998 | // read block |
51ed9ec9 | 4999 | uint64_t nBlockPos = blkdat.GetPos(); |
ad96e7cc WL |
5000 | if (dbp) |
5001 | dbp->nPos = nBlockPos; | |
7fea4846 | 5002 | blkdat.SetLimit(nBlockPos + nSize); |
16d51941 PW |
5003 | blkdat.SetPos(nBlockPos); |
5004 | CBlock block; | |
5005 | blkdat >> block; | |
ad96e7cc | 5006 | nRewind = blkdat.GetPos(); |
8d655683 | 5007 | |
16d51941 PW |
5008 | // detect out of order blocks, and store them for later |
5009 | uint256 hash = block.GetHash(); | |
4e382177 | 5010 | if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex.find(block.hashPrevBlock) == mapBlockIndex.end()) { |
ad96e7cc | 5011 | LogPrint("reindex", "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(), |
8d655683 | 5012 | block.hashPrevBlock.ToString()); |
ad96e7cc | 5013 | if (dbp) |
16d51941 | 5014 | mapBlocksUnknownParent.insert(std::make_pair(block.hashPrevBlock, *dbp)); |
ad96e7cc WL |
5015 | continue; |
5016 | } | |
8d655683 | 5017 | |
16d51941 | 5018 | // process in case the block isn't known yet |
8375e221 | 5019 | if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) { |
16d51941 | 5020 | CValidationState state; |
7bb789bb | 5021 | if (ProcessNewBlock(0,0,state, NULL, &block, true, dbp)) |
16d51941 PW |
5022 | nLoaded++; |
5023 | if (state.IsError()) | |
5024 | break; | |
4e382177 | 5025 | } else if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->nHeight % 1000 == 0) { |
50b43fda | 5026 | LogPrintf("Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight); |
16d51941 | 5027 | } |
8d655683 | 5028 | |
ad96e7cc WL |
5029 | // Recursively process earlier encountered successors of this block |
5030 | deque<uint256> queue; | |
5031 | queue.push_back(hash); | |
5032 | while (!queue.empty()) { | |
5033 | uint256 head = queue.front(); | |
5034 | queue.pop_front(); | |
5035 | std::pair<std::multimap<uint256, CDiskBlockPos>::iterator, std::multimap<uint256, CDiskBlockPos>::iterator> range = mapBlocksUnknownParent.equal_range(head); | |
5036 | while (range.first != range.second) { | |
5037 | std::multimap<uint256, CDiskBlockPos>::iterator it = range.first; | |
b8add6a4 | 5038 | if (ReadBlockFromDisk(mapBlockIndex[hash]!=0?mapBlockIndex[hash]->nHeight:0,block, it->second,1)) |
ad96e7cc WL |
5039 | { |
5040 | LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(), | |
8d655683 | 5041 | head.ToString()); |
ad96e7cc | 5042 | CValidationState dummy; |
7bb789bb | 5043 | if (ProcessNewBlock(0,0,dummy, NULL, &block, true, &it->second)) |
ad96e7cc WL |
5044 | { |
5045 | nLoaded++; | |
5046 | queue.push_back(block.GetHash()); | |
5047 | } | |
5048 | } | |
5049 | range.first++; | |
5050 | mapBlocksUnknownParent.erase(it); | |
5051 | } | |
1d740055 | 5052 | } |
27df4123 | 5053 | } catch (const std::exception& e) { |
7ff9d122 | 5054 | LogPrintf("%s: Deserialize or I/O error - %s\n", __func__, e.what()); |
1d740055 PW |
5055 | } |
5056 | } | |
27df4123 | 5057 | } catch (const std::runtime_error& e) { |
b9b2e3fa | 5058 | AbortNode(std::string("System error: ") + e.what()); |
1d740055 | 5059 | } |
7fea4846 | 5060 | if (nLoaded > 0) |
f48742c2 | 5061 | LogPrintf("Loaded %i blocks from external file in %dms\n", nLoaded, GetTimeMillis() - nStart); |
1d740055 PW |
5062 | return nLoaded > 0; |
5063 | } | |
0a61b0df | 5064 | |
3fcfbc8a PW |
5065 | void static CheckBlockIndex() |
5066 | { | |
4e382177 | 5067 | const Consensus::Params& consensusParams = Params().GetConsensus(); |
3fcfbc8a PW |
5068 | if (!fCheckBlockIndex) { |
5069 | return; | |
5070 | } | |
8d655683 | 5071 | |
3fcfbc8a | 5072 | LOCK(cs_main); |
8d655683 | 5073 | |
0421c18f | 5074 | // During a reindex, we read the genesis block and call CheckBlockIndex before ActivateBestChain, |
5075 | // so we have the genesis block in mapBlockIndex but no active chain. (A few of the tests when | |
5076 | // iterating the block tree require that chainActive has been initialized.) | |
5077 | if (chainActive.Height() < 0) { | |
5078 | assert(mapBlockIndex.size() <= 1); | |
5079 | return; | |
5080 | } | |
8d655683 | 5081 | |
3fcfbc8a PW |
5082 | // Build forward-pointing map of the entire block tree. |
5083 | std::multimap<CBlockIndex*,CBlockIndex*> forward; | |
5084 | for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) { | |
8d655683 | 5085 | forward.insert(std::make_pair(it->second->pprev, it->second)); |
3fcfbc8a | 5086 | } |
8d655683 | 5087 | |
3fcfbc8a | 5088 | assert(forward.size() == mapBlockIndex.size()); |
8d655683 | 5089 | |
3fcfbc8a PW |
5090 | std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> rangeGenesis = forward.equal_range(NULL); |
5091 | CBlockIndex *pindex = rangeGenesis.first->second; | |
5092 | rangeGenesis.first++; | |
5093 | assert(rangeGenesis.first == rangeGenesis.second); // There is only one index entry with parent NULL. | |
8d655683 | 5094 | |
3fcfbc8a PW |
5095 | // Iterate over the entire block tree, using depth-first search. |
5096 | // Along the way, remember whether there are blocks on the path from genesis | |
5097 | // block being explored which are the first to have certain properties. | |
5098 | size_t nNodes = 0; | |
5099 | int nHeight = 0; | |
5100 | CBlockIndex* pindexFirstInvalid = NULL; // Oldest ancestor of pindex which is invalid. | |
5101 | CBlockIndex* pindexFirstMissing = NULL; // Oldest ancestor of pindex which does not have BLOCK_HAVE_DATA. | |
f9ec3f0f | 5102 | CBlockIndex* pindexFirstNeverProcessed = NULL; // Oldest ancestor of pindex for which nTx == 0. |
3fcfbc8a | 5103 | CBlockIndex* pindexFirstNotTreeValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_TREE (regardless of being valid or not). |
ede379f7 | 5104 | CBlockIndex* pindexFirstNotTransactionsValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_TRANSACTIONS (regardless of being valid or not). |
3fcfbc8a PW |
5105 | CBlockIndex* pindexFirstNotChainValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_CHAIN (regardless of being valid or not). |
5106 | CBlockIndex* pindexFirstNotScriptsValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_SCRIPTS (regardless of being valid or not). | |
5107 | while (pindex != NULL) { | |
5108 | nNodes++; | |
5109 | if (pindexFirstInvalid == NULL && pindex->nStatus & BLOCK_FAILED_VALID) pindexFirstInvalid = pindex; | |
5110 | if (pindexFirstMissing == NULL && !(pindex->nStatus & BLOCK_HAVE_DATA)) pindexFirstMissing = pindex; | |
f9ec3f0f | 5111 | if (pindexFirstNeverProcessed == NULL && pindex->nTx == 0) pindexFirstNeverProcessed = pindex; |
3fcfbc8a | 5112 | if (pindex->pprev != NULL && pindexFirstNotTreeValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TREE) pindexFirstNotTreeValid = pindex; |
ede379f7 | 5113 | if (pindex->pprev != NULL && pindexFirstNotTransactionsValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TRANSACTIONS) pindexFirstNotTransactionsValid = pindex; |
3fcfbc8a PW |
5114 | if (pindex->pprev != NULL && pindexFirstNotChainValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_CHAIN) pindexFirstNotChainValid = pindex; |
5115 | if (pindex->pprev != NULL && pindexFirstNotScriptsValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_SCRIPTS) pindexFirstNotScriptsValid = pindex; | |
8d655683 | 5116 | |
3fcfbc8a PW |
5117 | // Begin: actual consistency checks. |
5118 | if (pindex->pprev == NULL) { | |
5119 | // Genesis block checks. | |
4e382177 | 5120 | assert(pindex->GetBlockHash() == consensusParams.hashGenesisBlock); // Genesis block's hash must match. |
3fcfbc8a PW |
5121 | assert(pindex == chainActive.Genesis()); // The current active chain's genesis block must be this block. |
5122 | } | |
c1ecee8f | 5123 | if (pindex->nChainTx == 0) assert(pindex->nSequenceId == 0); // nSequenceId can't be set for blocks that aren't linked |
f9ec3f0f | 5124 | // VALID_TRANSACTIONS is equivalent to nTx > 0 for all nodes (whether or not pruning has occurred). |
5125 | // HAVE_DATA is only equivalent to nTx > 0 (or VALID_TRANSACTIONS) if no pruning has occurred. | |
5126 | if (!fHavePruned) { | |
5127 | // If we've never pruned, then HAVE_DATA should be equivalent to nTx > 0 | |
5128 | assert(!(pindex->nStatus & BLOCK_HAVE_DATA) == (pindex->nTx == 0)); | |
5129 | assert(pindexFirstMissing == pindexFirstNeverProcessed); | |
5130 | } else { | |
5131 | // If we have pruned, then we can only say that HAVE_DATA implies nTx > 0 | |
5132 | if (pindex->nStatus & BLOCK_HAVE_DATA) assert(pindex->nTx > 0); | |
5133 | } | |
5134 | if (pindex->nStatus & BLOCK_HAVE_UNDO) assert(pindex->nStatus & BLOCK_HAVE_DATA); | |
5135 | assert(((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS) == (pindex->nTx > 0)); // This is pruning-independent. | |
5136 | // All parents having had data (at some point) is equivalent to all parents being VALID_TRANSACTIONS, which is equivalent to nChainTx being set. | |
5137 | assert((pindexFirstNeverProcessed != NULL) == (pindex->nChainTx == 0)); // nChainTx != 0 is used to signal that all parent blocks have been processed (but may have been pruned). | |
ede379f7 | 5138 | assert((pindexFirstNotTransactionsValid != NULL) == (pindex->nChainTx == 0)); |
3fcfbc8a PW |
5139 | assert(pindex->nHeight == nHeight); // nHeight must be consistent. |
5140 | assert(pindex->pprev == NULL || pindex->nChainWork >= pindex->pprev->nChainWork); // For every block except the genesis block, the chainwork must be larger than the parent's. | |
5141 | assert(nHeight < 2 || (pindex->pskip && (pindex->pskip->nHeight < nHeight))); // The pskip pointer must point back for all but the first 2 blocks. | |
5142 | assert(pindexFirstNotTreeValid == NULL); // All mapBlockIndex entries must at least be TREE valid | |
5143 | if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TREE) assert(pindexFirstNotTreeValid == NULL); // TREE valid implies all parents are TREE valid | |
5144 | if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_CHAIN) assert(pindexFirstNotChainValid == NULL); // CHAIN valid implies all parents are CHAIN valid | |
5145 | if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_SCRIPTS) assert(pindexFirstNotScriptsValid == NULL); // SCRIPTS valid implies all parents are SCRIPTS valid | |
5146 | if (pindexFirstInvalid == NULL) { | |
5147 | // Checks for not-invalid blocks. | |
5148 | assert((pindex->nStatus & BLOCK_FAILED_MASK) == 0); // The failed mask cannot be set for blocks without invalid parents. | |
5149 | } | |
f9ec3f0f | 5150 | if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) && pindexFirstNeverProcessed == NULL) { |
5151 | if (pindexFirstInvalid == NULL) { | |
5152 | // If this block sorts at least as good as the current tip and | |
5153 | // is valid and we have all data for its parents, it must be in | |
5154 | // setBlockIndexCandidates. chainActive.Tip() must also be there | |
5155 | // even if some data has been pruned. | |
5156 | if (pindexFirstMissing == NULL || pindex == chainActive.Tip()) { | |
5157 | assert(setBlockIndexCandidates.count(pindex)); | |
5158 | } | |
5159 | // If some parent is missing, then it could be that this block was in | |
5160 | // setBlockIndexCandidates but had to be removed because of the missing data. | |
5161 | // In this case it must be in mapBlocksUnlinked -- see test below. | |
3fcfbc8a | 5162 | } |
f9ec3f0f | 5163 | } else { // If this block sorts worse than the current tip or some ancestor's block has never been seen, it cannot be in setBlockIndexCandidates. |
3fcfbc8a PW |
5164 | assert(setBlockIndexCandidates.count(pindex) == 0); |
5165 | } | |
5166 | // Check whether this block is in mapBlocksUnlinked. | |
5167 | std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> rangeUnlinked = mapBlocksUnlinked.equal_range(pindex->pprev); | |
5168 | bool foundInUnlinked = false; | |
5169 | while (rangeUnlinked.first != rangeUnlinked.second) { | |
5170 | assert(rangeUnlinked.first->first == pindex->pprev); | |
5171 | if (rangeUnlinked.first->second == pindex) { | |
5172 | foundInUnlinked = true; | |
5173 | break; | |
5174 | } | |
5175 | rangeUnlinked.first++; | |
5176 | } | |
f9ec3f0f | 5177 | if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed != NULL && pindexFirstInvalid == NULL) { |
5178 | // If this block has block data available, some parent was never received, and has no invalid parents, it must be in mapBlocksUnlinked. | |
5179 | assert(foundInUnlinked); | |
5180 | } | |
5181 | if (!(pindex->nStatus & BLOCK_HAVE_DATA)) assert(!foundInUnlinked); // Can't be in mapBlocksUnlinked if we don't HAVE_DATA | |
5182 | if (pindexFirstMissing == NULL) assert(!foundInUnlinked); // We aren't missing data for any parent -- cannot be in mapBlocksUnlinked. | |
5183 | if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed == NULL && pindexFirstMissing != NULL) { | |
5184 | // We HAVE_DATA for this block, have received data for all parents at some point, but we're currently missing data for some parent. | |
5185 | assert(fHavePruned); // We must have pruned. | |
5186 | // This block may have entered mapBlocksUnlinked if: | |
5187 | // - it has a descendant that at some point had more work than the | |
5188 | // tip, and | |
5189 | // - we tried switching to that descendant but were missing | |
5190 | // data for some intermediate block between chainActive and the | |
5191 | // tip. | |
5192 | // So if this block is itself better than chainActive.Tip() and it wasn't in | |
5193 | // setBlockIndexCandidates, then it must be in mapBlocksUnlinked. | |
5194 | if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) && setBlockIndexCandidates.count(pindex) == 0) { | |
5195 | if (pindexFirstInvalid == NULL) { | |
5196 | assert(foundInUnlinked); | |
5197 | } | |
3fcfbc8a | 5198 | } |
3fcfbc8a PW |
5199 | } |
5200 | // assert(pindex->GetBlockHash() == pindex->GetBlockHeader().GetHash()); // Perhaps too slow | |
5201 | // End: actual consistency checks. | |
8d655683 | 5202 | |
3fcfbc8a PW |
5203 | // Try descending into the first subnode. |
5204 | std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> range = forward.equal_range(pindex); | |
5205 | if (range.first != range.second) { | |
5206 | // A subnode was found. | |
5207 | pindex = range.first->second; | |
5208 | nHeight++; | |
5209 | continue; | |
5210 | } | |
5211 | // This is a leaf node. | |
5212 | // Move upwards until we reach a node of which we have not yet visited the last child. | |
5213 | while (pindex) { | |
5214 | // We are going to either move to a parent or a sibling of pindex. | |
5215 | // If pindex was the first with a certain property, unset the corresponding variable. | |
5216 | if (pindex == pindexFirstInvalid) pindexFirstInvalid = NULL; | |
5217 | if (pindex == pindexFirstMissing) pindexFirstMissing = NULL; | |
f9ec3f0f | 5218 | if (pindex == pindexFirstNeverProcessed) pindexFirstNeverProcessed = NULL; |
3fcfbc8a | 5219 | if (pindex == pindexFirstNotTreeValid) pindexFirstNotTreeValid = NULL; |
ede379f7 | 5220 | if (pindex == pindexFirstNotTransactionsValid) pindexFirstNotTransactionsValid = NULL; |
3fcfbc8a PW |
5221 | if (pindex == pindexFirstNotChainValid) pindexFirstNotChainValid = NULL; |
5222 | if (pindex == pindexFirstNotScriptsValid) pindexFirstNotScriptsValid = NULL; | |
5223 | // Find our parent. | |
5224 | CBlockIndex* pindexPar = pindex->pprev; | |
5225 | // Find which child we just visited. | |
5226 | std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> rangePar = forward.equal_range(pindexPar); | |
5227 | while (rangePar.first->second != pindex) { | |
5228 | assert(rangePar.first != rangePar.second); // Our parent must have at least the node we're coming from as child. | |
5229 | rangePar.first++; | |
5230 | } | |
5231 | // Proceed to the next one. | |
5232 | rangePar.first++; | |
5233 | if (rangePar.first != rangePar.second) { | |
5234 | // Move to the sibling. | |
5235 | pindex = rangePar.first->second; | |
5236 | break; | |
5237 | } else { | |
5238 | // Move up further. | |
5239 | pindex = pindexPar; | |
5240 | nHeight--; | |
5241 | continue; | |
5242 | } | |
5243 | } | |
5244 | } | |
8d655683 | 5245 | |
3fcfbc8a PW |
5246 | // Check that we actually traversed the entire map. |
5247 | assert(nNodes == forward.size()); | |
5248 | } | |
5249 | ||
0a61b0df | 5250 | ////////////////////////////////////////////////////////////////////////////// |
5251 | // | |
5252 | // CAlert | |
5253 | // | |
5254 | ||
db954a65 | 5255 | std::string GetWarnings(const std::string& strFor) |
0a61b0df | 5256 | { |
5257 | int nPriority = 0; | |
5258 | string strStatusBar; | |
5259 | string strRPC; | |
8d655683 | 5260 | |
62e21fb5 WL |
5261 | if (!CLIENT_VERSION_IS_RELEASE) |
5262 | strStatusBar = _("This is a pre-release test build - use at your own risk - do not use for mining or merchant applications"); | |
8d655683 | 5263 | |
73578933 | 5264 | if (GetBoolArg("-testsafemode", false)) |
5265 | strStatusBar = strRPC = "testsafemode enabled"; | |
8d655683 | 5266 | |
0a61b0df | 5267 | // Misc warnings like out of disk space and clock is wrong |
5268 | if (strMiscWarning != "") | |
5269 | { | |
5270 | nPriority = 1000; | |
5271 | strStatusBar = strMiscWarning; | |
5272 | } | |
8d655683 | 5273 | |
b8585384 | 5274 | if (fLargeWorkForkFound) |
0a61b0df | 5275 | { |
5276 | nPriority = 2000; | |
f65e7092 MC |
5277 | strStatusBar = strRPC = _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."); |
5278 | } | |
5279 | else if (fLargeWorkInvalidChainFound) | |
0a61b0df | 5280 | { |
5281 | nPriority = 2000; | |
f65e7092 | 5282 | strStatusBar = strRPC = _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."); |
0a61b0df | 5283 | } |
8d655683 | 5284 | |
0a61b0df | 5285 | // Alerts |
0a61b0df | 5286 | { |
f8dcd5ca | 5287 | LOCK(cs_mapAlerts); |
223b6f1b | 5288 | BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) |
0a61b0df | 5289 | { |
5290 | const CAlert& alert = item.second; | |
5291 | if (alert.AppliesToMe() && alert.nPriority > nPriority) | |
5292 | { | |
5293 | nPriority = alert.nPriority; | |
5294 | strStatusBar = alert.strStatusBar; | |
a40034f7 JG |
5295 | if (alert.nPriority >= ALERT_PRIORITY_SAFE_MODE) { |
5296 | strRPC = alert.strRPCError; | |
5297 | } | |
0a61b0df | 5298 | } |
5299 | } | |
5300 | } | |
8d655683 | 5301 | |
0a61b0df | 5302 | if (strFor == "statusbar") |
5303 | return strStatusBar; | |
5304 | else if (strFor == "rpc") | |
5305 | return strRPC; | |
5262fde0 | 5306 | assert(!"GetWarnings(): invalid parameter"); |
0a61b0df | 5307 | return "error"; |
5308 | } | |
5309 | ||
0a61b0df | 5310 | |
5311 | ||
5312 | ||
5313 | ||
5314 | ||
5315 | ||
5316 | ||
5317 | ////////////////////////////////////////////////////////////////////////////// | |
5318 | // | |
5319 | // Messages | |
5320 | // | |
5321 | ||
5322 | ||
72b25b0f | 5323 | bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) |
0a61b0df | 5324 | { |
5325 | switch (inv.type) | |
5326 | { | |
8d655683 | 5327 | case MSG_TX: |
8deb9822 | 5328 | { |
5094a81d | 5329 | assert(recentRejects); |
ec9b6c33 PT |
5330 | if (chainActive.Tip()->GetBlockHash() != hashRecentRejectsChainTip) |
5331 | { | |
5332 | // If the chain tip has changed previously rejected transactions | |
5333 | // might be now valid, e.g. due to a nLockTime'd tx becoming valid, | |
5334 | // or a double-spend. Reset the rejects filter and give those | |
5335 | // txs a second chance. | |
5336 | hashRecentRejectsChainTip = chainActive.Tip()->GetBlockHash(); | |
5337 | recentRejects->reset(); | |
5338 | } | |
8d655683 | 5339 | |
ec9b6c33 | 5340 | return recentRejects->contains(inv.hash) || |
8d655683 | 5341 | mempool.exists(inv.hash) || |
5342 | mapOrphanTransactions.count(inv.hash) || | |
5343 | pcoinsTip->HaveCoins(inv.hash); | |
8deb9822 | 5344 | } |
8d655683 | 5345 | case MSG_BLOCK: |
5346 | return mapBlockIndex.count(inv.hash); | |
0a61b0df | 5347 | } |
5348 | // Don't know what it is, just say we already got one | |
5349 | return true; | |
5350 | } | |
5351 | ||
c7f039b6 PW |
5352 | void static ProcessGetData(CNode* pfrom) |
5353 | { | |
5354 | std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin(); | |
8d655683 | 5355 | |
c7f039b6 | 5356 | vector<CInv> vNotFound; |
8d655683 | 5357 | |
7d38af3c | 5358 | LOCK(cs_main); |
8d655683 | 5359 | |
c7f039b6 PW |
5360 | while (it != pfrom->vRecvGetData.end()) { |
5361 | // Don't bother if send buffer is too full to respond anyway | |
5362 | if (pfrom->nSendSize >= SendBufferSize()) | |
5363 | break; | |
8d655683 | 5364 | |
c7f039b6 PW |
5365 | const CInv &inv = *it; |
5366 | { | |
b31499ec | 5367 | boost::this_thread::interruption_point(); |
c7f039b6 | 5368 | it++; |
8d655683 | 5369 | |
c7f039b6 PW |
5370 | if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK) |
5371 | { | |
d8b4b496 | 5372 | bool send = false; |
145d5be8 | 5373 | BlockMap::iterator mi = mapBlockIndex.find(inv.hash); |
c7f039b6 PW |
5374 | if (mi != mapBlockIndex.end()) |
5375 | { | |
85da07a5 | 5376 | if (chainActive.Contains(mi->second)) { |
2b45345a | 5377 | send = true; |
85da07a5 | 5378 | } else { |
f7303f97 | 5379 | static const int nOneMonth = 30 * 24 * 60 * 60; |
85da07a5 | 5380 | // To prevent fingerprinting attacks, only send blocks outside of the active |
f7303f97 PW |
5381 | // chain if they are valid, and no more than a month older (both in time, and in |
5382 | // best equivalent proof of work) than the best header chain we know about. | |
85da07a5 | 5383 | send = mi->second->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != NULL) && |
8d655683 | 5384 | (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() < nOneMonth) && |
5385 | (GetBlockProofEquivalentTime(*pindexBestHeader, *mi->second, *pindexBestHeader, Params().GetConsensus()) < nOneMonth); | |
85da07a5 | 5386 | if (!send) { |
30c1db1c | 5387 | LogPrintf("%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId()); |
85da07a5 | 5388 | } |
d8b4b496 AH |
5389 | } |
5390 | } | |
f9ec3f0f | 5391 | // Pruned nodes may have deleted the block, so check whether |
5392 | // it's available before trying to send. | |
5393 | if (send && (mi->second->nStatus & BLOCK_HAVE_DATA)) | |
d8b4b496 AH |
5394 | { |
5395 | // Send block from disk | |
c7f039b6 | 5396 | CBlock block; |
b8add6a4 | 5397 | if (!ReadBlockFromDisk(block, (*mi).second,1)) |
13931733 | 5398 | { |
b34b7b31 | 5399 | assert(!"cannot load block from disk"); |
13931733 | 5400 | } |
5401 | else | |
c7f039b6 | 5402 | { |
13931733 | 5403 | if (inv.type == MSG_BLOCK) |
c2b0ec2e | 5404 | { |
37782e4e | 5405 | //uint256 hash; int32_t z; |
5406 | //hash = block.GetHash(); | |
5407 | //for (z=31; z>=0; z--) | |
5408 | // fprintf(stderr,"%02x",((uint8_t *)&hash)[z]); | |
5409 | //fprintf(stderr," send block %d\n",komodo_block2height(&block)); | |
13931733 | 5410 | pfrom->PushMessage("block", block); |
c2b0ec2e | 5411 | } |
13931733 | 5412 | else // MSG_FILTERED_BLOCK) |
c7f039b6 | 5413 | { |
13931733 | 5414 | LOCK(pfrom->cs_filter); |
5415 | if (pfrom->pfilter) | |
5416 | { | |
5417 | CMerkleBlock merkleBlock(block, *pfrom->pfilter); | |
5418 | pfrom->PushMessage("merkleblock", merkleBlock); | |
5419 | // CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see | |
5420 | // This avoids hurting performance by pointlessly requiring a round-trip | |
5421 | // Note that there is currently no way for a node to request any single transactions we didn't send here - | |
5422 | // they must either disconnect and retry or request the full block. | |
5423 | // Thus, the protocol spec specified allows for us to provide duplicate txn here, | |
5424 | // however we MUST always provide at least what the remote peer needs | |
5425 | typedef std::pair<unsigned int, uint256> PairType; | |
5426 | BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn) | |
c7f039b6 PW |
5427 | if (!pfrom->setInventoryKnown.count(CInv(MSG_TX, pair.second))) |
5428 | pfrom->PushMessage("tx", block.vtx[pair.first]); | |
13931733 | 5429 | } |
5430 | // else | |
c7f039b6 | 5431 | // no response |
13931733 | 5432 | } |
c7f039b6 | 5433 | } |
b05a89b2 | 5434 | // Trigger the peer node to send a getblocks request for the next batch of inventory |
c7f039b6 PW |
5435 | if (inv.hash == pfrom->hashContinue) |
5436 | { | |
5437 | // Bypass PushInventory, this must send even if redundant, | |
5438 | // and we want it right after the last block so they don't | |
5439 | // wait for other stuff first. | |
5440 | vector<CInv> vInv; | |
4c6d41b8 | 5441 | vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash())); |
c7f039b6 | 5442 | pfrom->PushMessage("inv", vInv); |
4f152496 | 5443 | pfrom->hashContinue.SetNull(); |
c7f039b6 PW |
5444 | } |
5445 | } | |
5446 | } | |
5447 | else if (inv.IsKnownType()) | |
5448 | { | |
5449 | // Send stream from relay memory | |
5450 | bool pushed = false; | |
5451 | { | |
5452 | LOCK(cs_mapRelay); | |
5453 | map<CInv, CDataStream>::iterator mi = mapRelay.find(inv); | |
5454 | if (mi != mapRelay.end()) { | |
5455 | pfrom->PushMessage(inv.GetCommand(), (*mi).second); | |
5456 | pushed = true; | |
5457 | } | |
5458 | } | |
5459 | if (!pushed && inv.type == MSG_TX) { | |
319b1160 GA |
5460 | CTransaction tx; |
5461 | if (mempool.lookup(inv.hash, tx)) { | |
c7f039b6 PW |
5462 | CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); |
5463 | ss.reserve(1000); | |
5464 | ss << tx; | |
5465 | pfrom->PushMessage("tx", ss); | |
5466 | pushed = true; | |
5467 | } | |
5468 | } | |
5469 | if (!pushed) { | |
5470 | vNotFound.push_back(inv); | |
5471 | } | |
5472 | } | |
8d655683 | 5473 | |
c7f039b6 | 5474 | // Track requests for our stuff. |
26c16d9d | 5475 | GetMainSignals().Inventory(inv.hash); |
8d655683 | 5476 | |
75ef87dd PS |
5477 | if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK) |
5478 | break; | |
c7f039b6 PW |
5479 | } |
5480 | } | |
8d655683 | 5481 | |
c7f039b6 | 5482 | pfrom->vRecvGetData.erase(pfrom->vRecvGetData.begin(), it); |
8d655683 | 5483 | |
c7f039b6 PW |
5484 | if (!vNotFound.empty()) { |
5485 | // Let the peer know that we didn't find what it asked for, so it doesn't | |
5486 | // have to wait around forever. Currently only SPV clients actually care | |
5487 | // about this message: it's needed when they are recursively walking the | |
5488 | // dependencies of relevant unconfirmed transactions. SPV clients want to | |
5489 | // do that because they want to know about (and store and rebroadcast and | |
5490 | // risk analyze) the dependencies of transactions relevant to them, without | |
5491 | // having to download the entire memory pool. | |
5492 | pfrom->PushMessage("notfound", vNotFound); | |
5493 | } | |
5494 | } | |
5495 | ||
9f4da19b | 5496 | bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived) |
0a61b0df | 5497 | { |
e8e8904d | 5498 | const CChainParams& chainparams = Params(); |
28d4cff0 | 5499 | LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id); |
37782e4e | 5500 | //fprintf(stderr, "recv: %s peer=%d\n", SanitizeString(strCommand).c_str(), (int32_t)pfrom->GetId()); |
0a61b0df | 5501 | if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) |
5502 | { | |
881a85a2 | 5503 | LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n"); |
0a61b0df | 5504 | return true; |
5505 | } | |
8d655683 | 5506 | |
5507 | ||
5508 | ||
5509 | ||
0a61b0df | 5510 | if (strCommand == "version") |
5511 | { | |
5512 | // Each connection can only send one version message | |
5513 | if (pfrom->nVersion != 0) | |
806704c2 | 5514 | { |
358ce266 | 5515 | pfrom->PushMessage("reject", strCommand, REJECT_DUPLICATE, string("Duplicate version message")); |
b2864d2f | 5516 | Misbehaving(pfrom->GetId(), 1); |
0a61b0df | 5517 | return false; |
806704c2 | 5518 | } |
8d655683 | 5519 | |
51ed9ec9 | 5520 | int64_t nTime; |
0a61b0df | 5521 | CAddress addrMe; |
5522 | CAddress addrFrom; | |
51ed9ec9 | 5523 | uint64_t nNonce = 1; |
0a61b0df | 5524 | vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe; |
1ce41892 | 5525 | if (pfrom->nVersion < MIN_PEER_PROTO_VERSION) |
18c0fa97 | 5526 | { |
1ce41892 | 5527 | // disconnect from peers older than this proto version |
2e36866f | 5528 | LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion); |
358ce266 GA |
5529 | pfrom->PushMessage("reject", strCommand, REJECT_OBSOLETE, |
5530 | strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION)); | |
18c0fa97 PW |
5531 | pfrom->fDisconnect = true; |
5532 | return false; | |
5533 | } | |
8d655683 | 5534 | |
72b21929 S |
5535 | // When Overwinter is active, reject incoming connections from non-Overwinter nodes |
5536 | const Consensus::Params& params = Params().GetConsensus(); | |
5537 | if (NetworkUpgradeActive(GetHeight(), params, Consensus::UPGRADE_OVERWINTER) | |
5538 | && pfrom->nVersion < params.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion) | |
5539 | { | |
5540 | LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion); | |
5541 | pfrom->PushMessage("reject", strCommand, REJECT_OBSOLETE, | |
8d655683 | 5542 | strprintf("Version must be %d or greater", |
5543 | params.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion)); | |
72b21929 S |
5544 | pfrom->fDisconnect = true; |
5545 | return false; | |
5546 | } | |
8d655683 | 5547 | |
0a61b0df | 5548 | if (pfrom->nVersion == 10300) |
5549 | pfrom->nVersion = 300; | |
18c0fa97 | 5550 | if (!vRecv.empty()) |
0a61b0df | 5551 | vRecv >> addrFrom >> nNonce; |
a946aa8d | 5552 | if (!vRecv.empty()) { |
216e9a44 | 5553 | vRecv >> LIMITED_STRING(pfrom->strSubVer, 256); |
a946aa8d MH |
5554 | pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer); |
5555 | } | |
18c0fa97 | 5556 | if (!vRecv.empty()) |
0a61b0df | 5557 | vRecv >> pfrom->nStartingHeight; |
4c8fc1a5 MC |
5558 | if (!vRecv.empty()) |
5559 | vRecv >> pfrom->fRelayTxes; // set to true after we get the first filter* message | |
5560 | else | |
5561 | pfrom->fRelayTxes = true; | |
8d655683 | 5562 | |
0a61b0df | 5563 | // Disconnect if we connected to ourself |
5564 | if (nNonce == nLocalHostNonce && nNonce > 1) | |
5565 | { | |
7d9d134b | 5566 | LogPrintf("connected to self at %s, disconnecting\n", pfrom->addr.ToString()); |
0a61b0df | 5567 | pfrom->fDisconnect = true; |
5568 | return true; | |
5569 | } | |
8d655683 | 5570 | |
845c86d1 GM |
5571 | pfrom->addrLocal = addrMe; |
5572 | if (pfrom->fInbound && addrMe.IsRoutable()) | |
5573 | { | |
5574 | SeenLocal(addrMe); | |
5575 | } | |
8d655683 | 5576 | |
cbc920d4 GA |
5577 | // Be shy and don't send version until we hear |
5578 | if (pfrom->fInbound) | |
5579 | pfrom->PushVersion(); | |
8d655683 | 5580 | |
0a61b0df | 5581 | pfrom->fClient = !(pfrom->nServices & NODE_NETWORK); |
8d655683 | 5582 | |
b4ee0bdd PW |
5583 | // Potentially mark this peer as a preferred download peer. |
5584 | UpdatePreferredDownload(pfrom, State(pfrom->GetId())); | |
8d655683 | 5585 | |
0a61b0df | 5586 | // Change version |
18c0fa97 | 5587 | pfrom->PushMessage("verack"); |
41b052ad | 5588 | pfrom->ssSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); |
8d655683 | 5589 | |
c891967b | 5590 | if (!pfrom->fInbound) |
5591 | { | |
5592 | // Advertise our address | |
53a08815 | 5593 | if (fListen && !IsInitialBlockDownload()) |
c891967b | 5594 | { |
39857190 PW |
5595 | CAddress addr = GetLocalAddress(&pfrom->addr); |
5596 | if (addr.IsRoutable()) | |
845c86d1 | 5597 | { |
eb5f63fe | 5598 | LogPrintf("ProcessMessages: advertizing address %s\n", addr.ToString()); |
845c86d1 GM |
5599 | pfrom->PushAddress(addr); |
5600 | } else if (IsPeerAddrLocalGood(pfrom)) { | |
5601 | addr.SetIP(pfrom->addrLocal); | |
eb5f63fe | 5602 | LogPrintf("ProcessMessages: advertizing address %s\n", addr.ToString()); |
39857190 | 5603 | pfrom->PushAddress(addr); |
845c86d1 | 5604 | } |
c891967b | 5605 | } |
8d655683 | 5606 | |
c891967b | 5607 | // Get recent addresses |
478b01d9 | 5608 | if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000) |
c891967b | 5609 | { |
5610 | pfrom->PushMessage("getaddr"); | |
5611 | pfrom->fGetAddr = true; | |
5612 | } | |
5fee401f PW |
5613 | addrman.Good(pfrom->addr); |
5614 | } else { | |
5615 | if (((CNetAddr)pfrom->addr) == (CNetAddr)addrFrom) | |
5616 | { | |
5617 | addrman.Add(addrFrom, addrFrom); | |
5618 | addrman.Good(addrFrom); | |
5619 | } | |
c891967b | 5620 | } |
8d655683 | 5621 | |
0a61b0df | 5622 | // Relay alerts |
f8dcd5ca PW |
5623 | { |
5624 | LOCK(cs_mapAlerts); | |
223b6f1b | 5625 | BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) |
8d655683 | 5626 | item.second.RelayTo(pfrom); |
f8dcd5ca | 5627 | } |
8d655683 | 5628 | |
0a61b0df | 5629 | pfrom->fSuccessfullyConnected = true; |
8d655683 | 5630 | |
70b9d36a JG |
5631 | string remoteAddr; |
5632 | if (fLogIPs) | |
5633 | remoteAddr = ", peeraddr=" + pfrom->addr.ToString(); | |
8d655683 | 5634 | |
70b9d36a JG |
5635 | LogPrintf("receive version message: %s: version %d, blocks=%d, us=%s, peer=%d%s\n", |
5636 | pfrom->cleanSubVer, pfrom->nVersion, | |
5637 | pfrom->nStartingHeight, addrMe.ToString(), pfrom->id, | |
5638 | remoteAddr); | |
8d655683 | 5639 | |
26a6bae7 PJ |
5640 | int64_t nTimeOffset = nTime - GetTime(); |
5641 | pfrom->nTimeOffset = nTimeOffset; | |
5642 | AddTimeData(pfrom->addr, nTimeOffset); | |
0a61b0df | 5643 | } |
8d655683 | 5644 | |
5645 | ||
0a61b0df | 5646 | else if (pfrom->nVersion == 0) |
5647 | { | |
5648 | // Must have a version message before anything else | |
b2864d2f | 5649 | Misbehaving(pfrom->GetId(), 1); |
0a61b0df | 5650 | return false; |
5651 | } | |
8d655683 | 5652 | |
5653 | ||
0a61b0df | 5654 | else if (strCommand == "verack") |
5655 | { | |
607dbfde | 5656 | pfrom->SetRecvVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); |
8d655683 | 5657 | |
9c273790 PW |
5658 | // Mark this node as currently connected, so we update its timestamp later. |
5659 | if (pfrom->fNetworkNode) { | |
5660 | LOCK(cs_main); | |
5661 | State(pfrom->GetId())->fCurrentlyConnected = true; | |
5662 | } | |
0a61b0df | 5663 | } |
8d655683 | 5664 | |
5665 | ||
72b21929 S |
5666 | // Disconnect existing peer connection when: |
5667 | // 1. The version message has been received | |
5668 | // 2. Overwinter is active | |
5669 | // 3. Peer version is pre-Overwinter | |
5670 | else if (NetworkUpgradeActive(GetHeight(), chainparams.GetConsensus(), Consensus::UPGRADE_OVERWINTER) | |
8d655683 | 5671 | && (pfrom->nVersion < chainparams.GetConsensus().vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion)) |
72b21929 S |
5672 | { |
5673 | LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion); | |
5674 | pfrom->PushMessage("reject", strCommand, REJECT_OBSOLETE, | |
8d655683 | 5675 | strprintf("Version must be %d or greater", |
5676 | chainparams.GetConsensus().vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion)); | |
72b21929 S |
5677 | pfrom->fDisconnect = true; |
5678 | return false; | |
5679 | } | |
8d655683 | 5680 | |
5681 | ||
0a61b0df | 5682 | else if (strCommand == "addr") |
5683 | { | |
5684 | vector<CAddress> vAddr; | |
5685 | vRecv >> vAddr; | |
8d655683 | 5686 | |
c891967b | 5687 | // Don't want addr from older versions unless seeding |
8b09cd3a | 5688 | if (pfrom->nVersion < CADDR_TIME_VERSION && addrman.size() > 1000) |
0a61b0df | 5689 | return true; |
5690 | if (vAddr.size() > 1000) | |
806704c2 | 5691 | { |
b2864d2f | 5692 | Misbehaving(pfrom->GetId(), 20); |
783b182c | 5693 | return error("message addr size() = %u", vAddr.size()); |
806704c2 | 5694 | } |
8d655683 | 5695 | |
0a61b0df | 5696 | // Store the new addresses |
090e5b40 | 5697 | vector<CAddress> vAddrOk; |
51ed9ec9 BD |
5698 | int64_t nNow = GetAdjustedTime(); |
5699 | int64_t nSince = nNow - 10 * 60; | |
223b6f1b | 5700 | BOOST_FOREACH(CAddress& addr, vAddr) |
0a61b0df | 5701 | { |
b31499ec | 5702 | boost::this_thread::interruption_point(); |
8d655683 | 5703 | |
c891967b | 5704 | if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60) |
5705 | addr.nTime = nNow - 5 * 24 * 60 * 60; | |
0a61b0df | 5706 | pfrom->AddAddressKnown(addr); |
090e5b40 | 5707 | bool fReachable = IsReachable(addr); |
c891967b | 5708 | if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable()) |
0a61b0df | 5709 | { |
5710 | // Relay to a limited number of other nodes | |
0a61b0df | 5711 | { |
f8dcd5ca | 5712 | LOCK(cs_vNodes); |
5cbf7532 | 5713 | // Use deterministic randomness to send to the same nodes for 24 hours |
d81cff32 | 5714 | // at a time so the addrKnowns of the chosen nodes prevent repeats |
0a61b0df | 5715 | static uint256 hashSalt; |
4f152496 | 5716 | if (hashSalt.IsNull()) |
f718aedd | 5717 | hashSalt = GetRandHash(); |
51ed9ec9 | 5718 | uint64_t hashAddr = addr.GetHash(); |
734f85c4 | 5719 | uint256 hashRand = ArithToUint256(UintToArith256(hashSalt) ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60))); |
5cbf7532 | 5720 | hashRand = Hash(BEGIN(hashRand), END(hashRand)); |
0a61b0df | 5721 | multimap<uint256, CNode*> mapMix; |
223b6f1b | 5722 | BOOST_FOREACH(CNode* pnode, vNodes) |
5cbf7532 | 5723 | { |
8b09cd3a | 5724 | if (pnode->nVersion < CADDR_TIME_VERSION) |
c891967b | 5725 | continue; |
5cbf7532 | 5726 | unsigned int nPointer; |
5727 | memcpy(&nPointer, &pnode, sizeof(nPointer)); | |
734f85c4 | 5728 | uint256 hashKey = ArithToUint256(UintToArith256(hashRand) ^ nPointer); |
5cbf7532 | 5729 | hashKey = Hash(BEGIN(hashKey), END(hashKey)); |
5730 | mapMix.insert(make_pair(hashKey, pnode)); | |
5731 | } | |
090e5b40 | 5732 | int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s) |
0a61b0df | 5733 | for (multimap<uint256, CNode*>::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi) |
5734 | ((*mi).second)->PushAddress(addr); | |
5735 | } | |
5736 | } | |
090e5b40 PW |
5737 | // Do not store addresses outside our network |
5738 | if (fReachable) | |
5739 | vAddrOk.push_back(addr); | |
0a61b0df | 5740 | } |
090e5b40 | 5741 | addrman.Add(vAddrOk, pfrom->addr, 2 * 60 * 60); |
0a61b0df | 5742 | if (vAddr.size() < 1000) |
5743 | pfrom->fGetAddr = false; | |
478b01d9 PW |
5744 | if (pfrom->fOneShot) |
5745 | pfrom->fDisconnect = true; | |
0a61b0df | 5746 | } |
8d655683 | 5747 | |
5748 | ||
0a61b0df | 5749 | else if (strCommand == "inv") |
5750 | { | |
5751 | vector<CInv> vInv; | |
5752 | vRecv >> vInv; | |
05a85b2b | 5753 | if (vInv.size() > MAX_INV_SZ) |
806704c2 | 5754 | { |
b2864d2f | 5755 | Misbehaving(pfrom->GetId(), 20); |
783b182c | 5756 | return error("message inv size() = %u", vInv.size()); |
806704c2 | 5757 | } |
8d655683 | 5758 | |
7d38af3c | 5759 | LOCK(cs_main); |
8d655683 | 5760 | |
341735eb | 5761 | std::vector<CInv> vToFetch; |
8d655683 | 5762 | |
c376ac35 | 5763 | for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) |
0a61b0df | 5764 | { |
0aa89c08 | 5765 | const CInv &inv = vInv[nInv]; |
8d655683 | 5766 | |
b31499ec | 5767 | boost::this_thread::interruption_point(); |
0a61b0df | 5768 | pfrom->AddInventoryKnown(inv); |
8d655683 | 5769 | |
ae8bfd12 | 5770 | bool fAlreadyHave = AlreadyHave(inv); |
2e36866f | 5771 | LogPrint("net", "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom->id); |
8d655683 | 5772 | |
341735eb PW |
5773 | if (!fAlreadyHave && !fImporting && !fReindex && inv.type != MSG_BLOCK) |
5774 | pfrom->AskFor(inv); | |
8d655683 | 5775 | |
341735eb | 5776 | if (inv.type == MSG_BLOCK) { |
aa815647 | 5777 | UpdateBlockAvailability(pfrom->GetId(), inv.hash); |
341735eb | 5778 | if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) { |
7e6d23b1 | 5779 | // First request the headers preceding the announced block. In the normal fully-synced |
341735eb PW |
5780 | // case where a new block is announced that succeeds the current tip (no reorganization), |
5781 | // there are no such headers. | |
5782 | // Secondly, and only when we are close to being synced, we request the announced block directly, | |
5783 | // to avoid an extra round-trip. Note that we must *first* ask for the headers, so by the | |
5784 | // time the block arrives, the header chain leading up to it is already validated. Not | |
5785 | // doing this will result in the received block being rejected as an orphan in case it is | |
5786 | // not a direct successor. | |
5787 | pfrom->PushMessage("getheaders", chainActive.GetLocator(pindexBestHeader), inv.hash); | |
c9077043 | 5788 | CNodeState *nodestate = State(pfrom->GetId()); |
e8e8904d | 5789 | if (chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - chainparams.GetConsensus().nPowTargetSpacing * 20 && |
c9077043 | 5790 | nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { |
341735eb PW |
5791 | vToFetch.push_back(inv); |
5792 | // Mark block as in flight already, even though the actual "getdata" message only goes out | |
5793 | // later (within the same cs_main lock, though). | |
82737933 | 5794 | MarkBlockAsInFlight(pfrom->GetId(), inv.hash, chainparams.GetConsensus()); |
341735eb | 5795 | } |
4c933229 | 5796 | LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id); |
341735eb PW |
5797 | } |
5798 | } | |
8d655683 | 5799 | |
0a61b0df | 5800 | // Track requests for our stuff |
26c16d9d | 5801 | GetMainSignals().Inventory(inv.hash); |
8d655683 | 5802 | |
540ac451 JG |
5803 | if (pfrom->nSendSize > (SendBufferSize() * 2)) { |
5804 | Misbehaving(pfrom->GetId(), 50); | |
5805 | return error("send buffer size() = %u", pfrom->nSendSize); | |
5806 | } | |
0a61b0df | 5807 | } |
8d655683 | 5808 | |
341735eb PW |
5809 | if (!vToFetch.empty()) |
5810 | pfrom->PushMessage("getdata", vToFetch); | |
0a61b0df | 5811 | } |
8d655683 | 5812 | |
5813 | ||
0a61b0df | 5814 | else if (strCommand == "getdata") |
5815 | { | |
5816 | vector<CInv> vInv; | |
5817 | vRecv >> vInv; | |
05a85b2b | 5818 | if (vInv.size() > MAX_INV_SZ) |
806704c2 | 5819 | { |
b2864d2f | 5820 | Misbehaving(pfrom->GetId(), 20); |
783b182c | 5821 | return error("message getdata size() = %u", vInv.size()); |
806704c2 | 5822 | } |
8d655683 | 5823 | |
3b570559 | 5824 | if (fDebug || (vInv.size() != 1)) |
2e36866f | 5825 | LogPrint("net", "received getdata (%u invsz) peer=%d\n", vInv.size(), pfrom->id); |
8d655683 | 5826 | |
3b570559 | 5827 | if ((fDebug && vInv.size() > 0) || (vInv.size() == 1)) |
2e36866f | 5828 | LogPrint("net", "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom->id); |
8d655683 | 5829 | |
c7f039b6 PW |
5830 | pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end()); |
5831 | ProcessGetData(pfrom); | |
0a61b0df | 5832 | } |
8d655683 | 5833 | |
5834 | ||
0a61b0df | 5835 | else if (strCommand == "getblocks") |
5836 | { | |
5837 | CBlockLocator locator; | |
5838 | uint256 hashStop; | |
5839 | vRecv >> locator >> hashStop; | |
8d655683 | 5840 | |
7d38af3c | 5841 | LOCK(cs_main); |
8d655683 | 5842 | |
f03304a9 | 5843 | // Find the last block the caller has in the main chain |
6db83db3 | 5844 | CBlockIndex* pindex = FindForkInGlobalIndex(chainActive, locator); |
8d655683 | 5845 | |
0a61b0df | 5846 | // Send the rest of the chain |
5847 | if (pindex) | |
4c6d41b8 | 5848 | pindex = chainActive.Next(pindex); |
9d6cd04b | 5849 | int nLimit = 500; |
4f152496 | 5850 | LogPrint("net", "getblocks %d to %s limit %d from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), nLimit, pfrom->id); |
4c6d41b8 | 5851 | for (; pindex; pindex = chainActive.Next(pindex)) |
0a61b0df | 5852 | { |
5853 | if (pindex->GetBlockHash() == hashStop) | |
5854 | { | |
7d9d134b | 5855 | LogPrint("net", " getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); |
0a61b0df | 5856 | break; |
5857 | } | |
5858 | pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash())); | |
9d6cd04b | 5859 | if (--nLimit <= 0) |
0a61b0df | 5860 | { |
b05a89b2 LD |
5861 | // When this block is requested, we'll send an inv that'll |
5862 | // trigger the peer to getblocks the next batch of inventory. | |
7d9d134b | 5863 | LogPrint("net", " getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); |
0a61b0df | 5864 | pfrom->hashContinue = pindex->GetBlockHash(); |
5865 | break; | |
5866 | } | |
5867 | } | |
5868 | } | |
8d655683 | 5869 | |
5870 | ||
f03304a9 | 5871 | else if (strCommand == "getheaders") |
5872 | { | |
5873 | CBlockLocator locator; | |
5874 | uint256 hashStop; | |
5875 | vRecv >> locator >> hashStop; | |
8d655683 | 5876 | |
7d38af3c | 5877 | LOCK(cs_main); |
8d655683 | 5878 | |
b4bbad18 SD |
5879 | if (IsInitialBlockDownload()) |
5880 | return true; | |
8d655683 | 5881 | |
f03304a9 | 5882 | CBlockIndex* pindex = NULL; |
5883 | if (locator.IsNull()) | |
5884 | { | |
5885 | // If locator is null, return the hashStop block | |
145d5be8 | 5886 | BlockMap::iterator mi = mapBlockIndex.find(hashStop); |
f03304a9 | 5887 | if (mi == mapBlockIndex.end()) |
5888 | return true; | |
5889 | pindex = (*mi).second; | |
5890 | } | |
5891 | else | |
5892 | { | |
5893 | // Find the last block the caller has in the main chain | |
6db83db3 | 5894 | pindex = FindForkInGlobalIndex(chainActive, locator); |
f03304a9 | 5895 | if (pindex) |
4c6d41b8 | 5896 | pindex = chainActive.Next(pindex); |
f03304a9 | 5897 | } |
8d655683 | 5898 | |
e754cf41 | 5899 | // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end |
f03304a9 | 5900 | vector<CBlock> vHeaders; |
341735eb | 5901 | int nLimit = MAX_HEADERS_RESULTS; |
4c933229 | 5902 | LogPrint("net", "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString(), pfrom->id); |
f8a07170 | 5903 | //if ( pfrom->lasthdrsreq >= chainActive.Height()-MAX_HEADERS_RESULTS || pfrom->lasthdrsreq != (int32_t)(pindex ? pindex->nHeight : -1) )// no need to ever suppress this |
f03304a9 | 5904 | { |
164bbe6c | 5905 | pfrom->lasthdrsreq = (int32_t)(pindex ? pindex->nHeight : -1); |
336a60cf | 5906 | for (; pindex; pindex = chainActive.Next(pindex)) |
5907 | { | |
5908 | vHeaders.push_back(pindex->GetBlockHeader()); | |
5909 | if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop) | |
5910 | break; | |
5911 | } | |
5912 | pfrom->PushMessage("headers", vHeaders); | |
8dcf7f94 | 5913 | } |
f8a07170 | 5914 | /*else if ( NOTARY_PUBKEY33[0] != 0 ) |
bd901dd7 | 5915 | { |
5916 | static uint32_t counter; | |
5917 | if ( counter++ < 3 ) | |
5918 | fprintf(stderr,"you can ignore redundant getheaders from peer.%d %d prev.%d\n",(int32_t)pfrom->id,(int32_t)(pindex ? pindex->nHeight : -1),pfrom->lasthdrsreq); | |
f8a07170 | 5919 | }*/ |
f03304a9 | 5920 | } |
8d655683 | 5921 | |
5922 | ||
0a61b0df | 5923 | else if (strCommand == "tx") |
5924 | { | |
5925 | vector<uint256> vWorkQueue; | |
7a15109c | 5926 | vector<uint256> vEraseQueue; |
0a61b0df | 5927 | CTransaction tx; |
5928 | vRecv >> tx; | |
8d655683 | 5929 | |
805344dc | 5930 | CInv inv(MSG_TX, tx.GetHash()); |
0a61b0df | 5931 | pfrom->AddInventoryKnown(inv); |
8d655683 | 5932 | |
7d38af3c | 5933 | LOCK(cs_main); |
8d655683 | 5934 | |
0a61b0df | 5935 | bool fMissingInputs = false; |
ef3988ca | 5936 | CValidationState state; |
8d655683 | 5937 | |
e2190f80 | 5938 | pfrom->setAskFor.erase(inv.hash); |
604ee2aa | 5939 | mapAlreadyAskedFor.erase(inv); |
8d655683 | 5940 | |
60aed954 | 5941 | if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) |
0a61b0df | 5942 | { |
a0fa20a1 | 5943 | mempool.check(pcoinsTip); |
d38da59b | 5944 | RelayTransaction(tx); |
0a61b0df | 5945 | vWorkQueue.push_back(inv.hash); |
8d655683 | 5946 | |
5262fde0 | 5947 | LogPrint("mempool", "AcceptToMemoryPool: peer=%d %s: accepted %s (poolsz %u)\n", |
8d655683 | 5948 | pfrom->id, pfrom->cleanSubVer, |
5949 | tx.GetHash().ToString(), | |
5950 | mempool.mapTx.size()); | |
5951 | ||
0a61b0df | 5952 | // Recursively process any orphan transactions that depended on this one |
c74332c6 | 5953 | set<NodeId> setMisbehaving; |
c376ac35 | 5954 | for (unsigned int i = 0; i < vWorkQueue.size(); i++) |
0a61b0df | 5955 | { |
89d91f6a WL |
5956 | map<uint256, set<uint256> >::iterator itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue[i]); |
5957 | if (itByPrev == mapOrphanTransactionsByPrev.end()) | |
5958 | continue; | |
5959 | for (set<uint256>::iterator mi = itByPrev->second.begin(); | |
5960 | mi != itByPrev->second.end(); | |
0a61b0df | 5961 | ++mi) |
5962 | { | |
159bc481 | 5963 | const uint256& orphanHash = *mi; |
c74332c6 GA |
5964 | const CTransaction& orphanTx = mapOrphanTransactions[orphanHash].tx; |
5965 | NodeId fromPeer = mapOrphanTransactions[orphanHash].fromPeer; | |
7a15109c | 5966 | bool fMissingInputs2 = false; |
159bc481 GA |
5967 | // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan |
5968 | // resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get | |
5969 | // anyone relaying LegitTxX banned) | |
8c4e4313 | 5970 | CValidationState stateDummy; |
8d655683 | 5971 | |
5972 | ||
c74332c6 GA |
5973 | if (setMisbehaving.count(fromPeer)) |
5974 | continue; | |
319b1160 | 5975 | if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) |
0a61b0df | 5976 | { |
7d9d134b | 5977 | LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); |
d38da59b | 5978 | RelayTransaction(orphanTx); |
159bc481 | 5979 | vWorkQueue.push_back(orphanHash); |
37b4e425 | 5980 | vEraseQueue.push_back(orphanHash); |
7a15109c GA |
5981 | } |
5982 | else if (!fMissingInputs2) | |
5983 | { | |
c74332c6 GA |
5984 | int nDos = 0; |
5985 | if (stateDummy.IsInvalid(nDos) && nDos > 0) | |
5986 | { | |
5987 | // Punish peer that gave us an invalid orphan tx | |
5988 | Misbehaving(fromPeer, nDos); | |
5989 | setMisbehaving.insert(fromPeer); | |
5990 | LogPrint("mempool", " invalid orphan tx %s\n", orphanHash.ToString()); | |
5991 | } | |
37b4e425 AM |
5992 | // Has inputs but not accepted to mempool |
5993 | // Probably non-standard or insufficient fee/priority | |
7d9d134b | 5994 | LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString()); |
37b4e425 | 5995 | vEraseQueue.push_back(orphanHash); |
5094a81d | 5996 | assert(recentRejects); |
ec9b6c33 | 5997 | recentRejects->insert(orphanHash); |
0a61b0df | 5998 | } |
a0fa20a1 | 5999 | mempool.check(pcoinsTip); |
0a61b0df | 6000 | } |
6001 | } | |
8d655683 | 6002 | |
7a15109c | 6003 | BOOST_FOREACH(uint256 hash, vEraseQueue) |
8d655683 | 6004 | EraseOrphanTx(hash); |
0a61b0df | 6005 | } |
b7e4abd6 | 6006 | // TODO: currently, prohibit joinsplits from entering mapOrphans |
8675d94b | 6007 | else if (fMissingInputs && tx.vjoinsplit.size() == 0) |
0a61b0df | 6008 | { |
c74332c6 | 6009 | AddOrphanTx(tx, pfrom->GetId()); |
8d655683 | 6010 | |
142e6041 | 6011 | // DoS prevention: do not allow mapOrphanTransactions to grow unbounded |
aa3c697e GA |
6012 | unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, GetArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS)); |
6013 | unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx); | |
142e6041 | 6014 | if (nEvicted > 0) |
881a85a2 | 6015 | LogPrint("mempool", "mapOrphan overflow, removed %u tx\n", nEvicted); |
ec9b6c33 | 6016 | } else { |
36f14bf2 | 6017 | assert(recentRejects); |
805344dc | 6018 | recentRejects->insert(tx.GetHash()); |
8d655683 | 6019 | |
ec9b6c33 PT |
6020 | if (pfrom->fWhitelisted) { |
6021 | // Always relay transactions received from whitelisted peers, even | |
60aed954 PW |
6022 | // if they were already in the mempool or rejected from it due |
6023 | // to policy, allowing the node to function as a gateway for | |
6024 | // nodes hidden behind it. | |
ec9b6c33 | 6025 | // |
60aed954 PW |
6026 | // Never relay transactions that we would assign a non-zero DoS |
6027 | // score for, as we expect peers to do the same with us in that | |
6028 | // case. | |
6029 | int nDoS = 0; | |
6030 | if (!state.IsInvalid(nDoS) || nDoS == 0) { | |
6031 | LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id); | |
6032 | RelayTransaction(tx); | |
6033 | } else { | |
e63d14fd | 6034 | LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s (code %d))\n", |
8d655683 | 6035 | tx.GetHash().ToString(), pfrom->id, state.GetRejectReason(), state.GetRejectCode()); |
60aed954 | 6036 | } |
ec9b6c33 | 6037 | } |
0a61b0df | 6038 | } |
fbed9c9d | 6039 | int nDoS = 0; |
5ea66c54 | 6040 | if (state.IsInvalid(nDoS)) |
2b45345a | 6041 | { |
805344dc | 6042 | LogPrint("mempool", "%s from peer=%d %s was not accepted into the memory pool: %s\n", tx.GetHash().ToString(), |
8d655683 | 6043 | pfrom->id, pfrom->cleanSubVer, |
6044 | state.GetRejectReason()); | |
358ce266 | 6045 | pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), |
307f7d48 | 6046 | state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash); |
5ea66c54 | 6047 | if (nDoS > 0) |
b2864d2f | 6048 | Misbehaving(pfrom->GetId(), nDoS); |
358ce266 | 6049 | } |
0a61b0df | 6050 | } |
8d655683 | 6051 | |
6052 | ||
341735eb PW |
6053 | else if (strCommand == "headers" && !fImporting && !fReindex) // Ignore headers received while importing |
6054 | { | |
6055 | std::vector<CBlockHeader> headers; | |
8d655683 | 6056 | |
341735eb PW |
6057 | // Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks. |
6058 | unsigned int nCount = ReadCompactSize(vRecv); | |
6059 | if (nCount > MAX_HEADERS_RESULTS) { | |
6060 | Misbehaving(pfrom->GetId(), 20); | |
6061 | return error("headers message size = %u", nCount); | |
6062 | } | |
6063 | headers.resize(nCount); | |
6064 | for (unsigned int n = 0; n < nCount; n++) { | |
6065 | vRecv >> headers[n]; | |
6066 | ReadCompactSize(vRecv); // ignore tx count; assume it is 0. | |
6067 | } | |
8d655683 | 6068 | |
341735eb | 6069 | LOCK(cs_main); |
8d655683 | 6070 | |
341735eb PW |
6071 | if (nCount == 0) { |
6072 | // Nothing interesting. Stop asking this peers for more headers. | |
6073 | return true; | |
6074 | } | |
8d655683 | 6075 | |
341735eb PW |
6076 | CBlockIndex *pindexLast = NULL; |
6077 | BOOST_FOREACH(const CBlockHeader& header, headers) { | |
6078 | CValidationState state; | |
6079 | if (pindexLast != NULL && header.hashPrevBlock != pindexLast->GetBlockHash()) { | |
6080 | Misbehaving(pfrom->GetId(), 20); | |
6081 | return error("non-continuous headers sequence"); | |
6082 | } | |
531b9293 | 6083 | int32_t futureblock; |
66dd02d2 | 6084 | //fprintf(stderr,"headers msg nCount.%d\n",(int32_t)nCount); |
531b9293 | 6085 | if (!AcceptBlockHeader(&futureblock,header, state, &pindexLast)) { |
341735eb | 6086 | int nDoS; |
6477ad07 | 6087 | if (state.IsInvalid(nDoS)) |
6088 | { | |
531b9293 | 6089 | if (nDoS > 0 && futureblock == 0) |
0d2cefb0 | 6090 | Misbehaving(pfrom->GetId(), nDoS/nDoS); |
341735eb PW |
6091 | return error("invalid header received"); |
6092 | } | |
6093 | } | |
6094 | } | |
8d655683 | 6095 | |
341735eb PW |
6096 | if (pindexLast) |
6097 | UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash()); | |
8d655683 | 6098 | |
341735eb PW |
6099 | if (nCount == MAX_HEADERS_RESULTS && pindexLast) { |
6100 | // Headers message had its maximum size; the peer may have more headers. | |
6101 | // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue | |
6102 | // from there instead. | |
8ab425f8 | 6103 | if ( pfrom->sendhdrsreq >= chainActive.Height()-MAX_HEADERS_RESULTS || pindexLast->nHeight != pfrom->sendhdrsreq ) |
6104 | { | |
6105 | pfrom->sendhdrsreq = (int32_t)pindexLast->nHeight; | |
6106 | LogPrint("net", "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->id, pfrom->nStartingHeight); | |
6107 | pfrom->PushMessage("getheaders", chainActive.GetLocator(pindexLast), uint256()); | |
6108 | } | |
341735eb | 6109 | } |
8d655683 | 6110 | |
3fcfbc8a | 6111 | CheckBlockIndex(); |
341735eb | 6112 | } |
8d655683 | 6113 | |
7fea4846 | 6114 | else if (strCommand == "block" && !fImporting && !fReindex) // Ignore blocks received while importing |
0a61b0df | 6115 | { |
f03304a9 | 6116 | CBlock block; |
6117 | vRecv >> block; | |
8d655683 | 6118 | |
f03304a9 | 6119 | CInv inv(MSG_BLOCK, block.GetHash()); |
341735eb | 6120 | LogPrint("net", "received block %s peer=%d\n", inv.hash.ToString(), pfrom->id); |
8d655683 | 6121 | |
341735eb | 6122 | pfrom->AddInventoryKnown(inv); |
8d655683 | 6123 | |
ef3988ca | 6124 | CValidationState state; |
93b606ae SD |
6125 | // Process all blocks from whitelisted peers, even if not requested, |
6126 | // unless we're still syncing with the network. | |
6127 | // Such an unrequested block may still be processed, subject to the | |
6128 | // conditions in AcceptBlock(). | |
6129 | bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(); | |
7bb789bb | 6130 | ProcessNewBlock(0,0,state, pfrom, &block, forceProcessing, NULL); |
40f5cb87 PW |
6131 | int nDoS; |
6132 | if (state.IsInvalid(nDoS)) { | |
6133 | pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), | |
307f7d48 | 6134 | state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash); |
40f5cb87 PW |
6135 | if (nDoS > 0) { |
6136 | LOCK(cs_main); | |
6137 | Misbehaving(pfrom->GetId(), nDoS); | |
6138 | } | |
6139 | } | |
8d655683 | 6140 | |
0a61b0df | 6141 | } |
8d655683 | 6142 | |
6143 | ||
dca799e1 IP |
6144 | // This asymmetric behavior for inbound and outbound connections was introduced |
6145 | // to prevent a fingerprinting attack: an attacker can send specific fake addresses | |
b05a89b2 LD |
6146 | // to users' AddrMan and later request them by sending getaddr messages. |
6147 | // Making nodes which are behind NAT and can only make outgoing connections ignore | |
6148 | // the getaddr message mitigates the attack. | |
dca799e1 | 6149 | else if ((strCommand == "getaddr") && (pfrom->fInbound)) |
0a61b0df | 6150 | { |
a514cb29 GM |
6151 | // Only send one GetAddr response per connection to reduce resource waste |
6152 | // and discourage addr stamping of INV announcements. | |
6153 | if (pfrom->fSentAddr) { | |
6154 | LogPrint("net", "Ignoring repeated \"getaddr\". peer=%d\n", pfrom->id); | |
6155 | return true; | |
6156 | } | |
6157 | pfrom->fSentAddr = true; | |
8d655683 | 6158 | |
0a61b0df | 6159 | pfrom->vAddrToSend.clear(); |
5fee401f PW |
6160 | vector<CAddress> vAddr = addrman.GetAddr(); |
6161 | BOOST_FOREACH(const CAddress &addr, vAddr) | |
8d655683 | 6162 | pfrom->PushAddress(addr); |
0a61b0df | 6163 | } |
8d655683 | 6164 | |
6165 | ||
05a85b2b JG |
6166 | else if (strCommand == "mempool") |
6167 | { | |
319b1160 | 6168 | LOCK2(cs_main, pfrom->cs_filter); |
8d655683 | 6169 | |
05a85b2b JG |
6170 | std::vector<uint256> vtxid; |
6171 | mempool.queryHashes(vtxid); | |
6172 | vector<CInv> vInv; | |
c51694eb MC |
6173 | BOOST_FOREACH(uint256& hash, vtxid) { |
6174 | CInv inv(MSG_TX, hash); | |
319b1160 GA |
6175 | CTransaction tx; |
6176 | bool fInMemPool = mempool.lookup(hash, tx); | |
6177 | if (!fInMemPool) continue; // another thread removed since queryHashes, maybe... | |
d38da59b | 6178 | if ((pfrom->pfilter && pfrom->pfilter->IsRelevantAndUpdate(tx)) || |
8d655683 | 6179 | (!pfrom->pfilter)) |
c51694eb | 6180 | vInv.push_back(inv); |
1f3d3647 GA |
6181 | if (vInv.size() == MAX_INV_SZ) { |
6182 | pfrom->PushMessage("inv", vInv); | |
6183 | vInv.clear(); | |
6184 | } | |
05a85b2b JG |
6185 | } |
6186 | if (vInv.size() > 0) | |
6187 | pfrom->PushMessage("inv", vInv); | |
6188 | } | |
8d655683 | 6189 | |
6190 | ||
0a61b0df | 6191 | else if (strCommand == "ping") |
6192 | { | |
93e447b6 JG |
6193 | if (pfrom->nVersion > BIP0031_VERSION) |
6194 | { | |
51ed9ec9 | 6195 | uint64_t nonce = 0; |
93e447b6 JG |
6196 | vRecv >> nonce; |
6197 | // Echo the message back with the nonce. This allows for two useful features: | |
6198 | // | |
6199 | // 1) A remote node can quickly check if the connection is operational | |
6200 | // 2) Remote nodes can measure the latency of the network thread. If this node | |
6201 | // is overloaded it won't respond to pings quickly and the remote node can | |
6202 | // avoid sending us more work, like chain download requests. | |
6203 | // | |
6204 | // The nonce stops the remote getting confused between different pings: without | |
6205 | // it, if the remote node sends a ping once per second and this node takes 5 | |
6206 | // seconds to respond to each, the 5th ping the remote sends would appear to | |
6207 | // return very quickly. | |
6208 | pfrom->PushMessage("pong", nonce); | |
6209 | } | |
0a61b0df | 6210 | } |
8d655683 | 6211 | |
6212 | ||
971bb3e9 JL |
6213 | else if (strCommand == "pong") |
6214 | { | |
9f4da19b | 6215 | int64_t pingUsecEnd = nTimeReceived; |
51ed9ec9 | 6216 | uint64_t nonce = 0; |
971bb3e9 JL |
6217 | size_t nAvail = vRecv.in_avail(); |
6218 | bool bPingFinished = false; | |
6219 | std::string sProblem; | |
8d655683 | 6220 | |
971bb3e9 JL |
6221 | if (nAvail >= sizeof(nonce)) { |
6222 | vRecv >> nonce; | |
8d655683 | 6223 | |
971bb3e9 JL |
6224 | // Only process pong message if there is an outstanding ping (old ping without nonce should never pong) |
6225 | if (pfrom->nPingNonceSent != 0) { | |
6226 | if (nonce == pfrom->nPingNonceSent) { | |
6227 | // Matching pong received, this ping is no longer outstanding | |
6228 | bPingFinished = true; | |
51ed9ec9 | 6229 | int64_t pingUsecTime = pingUsecEnd - pfrom->nPingUsecStart; |
971bb3e9 JL |
6230 | if (pingUsecTime > 0) { |
6231 | // Successful ping time measurement, replace previous | |
6232 | pfrom->nPingUsecTime = pingUsecTime; | |
e279e5f9 | 6233 | pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime, pingUsecTime); |
971bb3e9 JL |
6234 | } else { |
6235 | // This should never happen | |
6236 | sProblem = "Timing mishap"; | |
6237 | } | |
6238 | } else { | |
6239 | // Nonce mismatches are normal when pings are overlapping | |
6240 | sProblem = "Nonce mismatch"; | |
6241 | if (nonce == 0) { | |
7e6d23b1 | 6242 | // This is most likely a bug in another implementation somewhere; cancel this ping |
971bb3e9 JL |
6243 | bPingFinished = true; |
6244 | sProblem = "Nonce zero"; | |
6245 | } | |
6246 | } | |
6247 | } else { | |
6248 | sProblem = "Unsolicited pong without ping"; | |
6249 | } | |
6250 | } else { | |
7e6d23b1 | 6251 | // This is most likely a bug in another implementation somewhere; cancel this ping |
971bb3e9 JL |
6252 | bPingFinished = true; |
6253 | sProblem = "Short payload"; | |
6254 | } | |
8d655683 | 6255 | |
971bb3e9 | 6256 | if (!(sProblem.empty())) { |
2e36866f | 6257 | LogPrint("net", "pong peer=%d %s: %s, %x expected, %x received, %u bytes\n", |
8d655683 | 6258 | pfrom->id, |
6259 | pfrom->cleanSubVer, | |
6260 | sProblem, | |
6261 | pfrom->nPingNonceSent, | |
6262 | nonce, | |
6263 | nAvail); | |
971bb3e9 JL |
6264 | } |
6265 | if (bPingFinished) { | |
6266 | pfrom->nPingNonceSent = 0; | |
6267 | } | |
6268 | } | |
8d655683 | 6269 | |
6270 | ||
4d9c7fe6 | 6271 | else if (fAlerts && strCommand == "alert") |
0a61b0df | 6272 | { |
6273 | CAlert alert; | |
6274 | vRecv >> alert; | |
8d655683 | 6275 | |
d5a52d9b GA |
6276 | uint256 alertHash = alert.GetHash(); |
6277 | if (pfrom->setKnown.count(alertHash) == 0) | |
0a61b0df | 6278 | { |
f14e687f | 6279 | if (alert.ProcessAlert(Params().AlertKey())) |
f8dcd5ca | 6280 | { |
d5a52d9b GA |
6281 | // Relay |
6282 | pfrom->setKnown.insert(alertHash); | |
6283 | { | |
6284 | LOCK(cs_vNodes); | |
6285 | BOOST_FOREACH(CNode* pnode, vNodes) | |
8d655683 | 6286 | alert.RelayTo(pnode); |
d5a52d9b GA |
6287 | } |
6288 | } | |
6289 | else { | |
6290 | // Small DoS penalty so peers that send us lots of | |
6291 | // duplicate/expired/invalid-signature/whatever alerts | |
6292 | // eventually get banned. | |
6293 | // This isn't a Misbehaving(100) (immediate ban) because the | |
6294 | // peer might be an older or different implementation with | |
6295 | // a different signature key, etc. | |
b2864d2f | 6296 | Misbehaving(pfrom->GetId(), 10); |
f8dcd5ca | 6297 | } |
0a61b0df | 6298 | } |
6299 | } | |
8d655683 | 6300 | |
6301 | ||
422d1225 MC |
6302 | else if (strCommand == "filterload") |
6303 | { | |
6304 | CBloomFilter filter; | |
6305 | vRecv >> filter; | |
8d655683 | 6306 | |
422d1225 MC |
6307 | if (!filter.IsWithinSizeConstraints()) |
6308 | // There is no excuse for sending a too-large filter | |
b2864d2f | 6309 | Misbehaving(pfrom->GetId(), 100); |
422d1225 MC |
6310 | else |
6311 | { | |
6312 | LOCK(pfrom->cs_filter); | |
6313 | delete pfrom->pfilter; | |
6314 | pfrom->pfilter = new CBloomFilter(filter); | |
a7f533a9 | 6315 | pfrom->pfilter->UpdateEmptyFull(); |
422d1225 | 6316 | } |
4c8fc1a5 | 6317 | pfrom->fRelayTxes = true; |
422d1225 | 6318 | } |
8d655683 | 6319 | |
6320 | ||
422d1225 MC |
6321 | else if (strCommand == "filteradd") |
6322 | { | |
6323 | vector<unsigned char> vData; | |
6324 | vRecv >> vData; | |
8d655683 | 6325 | |
422d1225 MC |
6326 | // Nodes must NEVER send a data item > 520 bytes (the max size for a script data object, |
6327 | // and thus, the maximum size any matched object can have) in a filteradd message | |
192cc910 | 6328 | if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) |
422d1225 | 6329 | { |
b2864d2f | 6330 | Misbehaving(pfrom->GetId(), 100); |
422d1225 MC |
6331 | } else { |
6332 | LOCK(pfrom->cs_filter); | |
6333 | if (pfrom->pfilter) | |
6334 | pfrom->pfilter->insert(vData); | |
6335 | else | |
b2864d2f | 6336 | Misbehaving(pfrom->GetId(), 100); |
422d1225 MC |
6337 | } |
6338 | } | |
8d655683 | 6339 | |
6340 | ||
422d1225 MC |
6341 | else if (strCommand == "filterclear") |
6342 | { | |
6343 | LOCK(pfrom->cs_filter); | |
6344 | delete pfrom->pfilter; | |
37c6389c | 6345 | pfrom->pfilter = new CBloomFilter(); |
4c8fc1a5 | 6346 | pfrom->fRelayTxes = true; |
422d1225 | 6347 | } |
8d655683 | 6348 | |
6349 | ||
358ce266 GA |
6350 | else if (strCommand == "reject") |
6351 | { | |
efad808a PW |
6352 | if (fDebug) { |
6353 | try { | |
6354 | string strMsg; unsigned char ccode; string strReason; | |
307f7d48 | 6355 | vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, MAX_REJECT_MESSAGE_LENGTH); |
8d655683 | 6356 | |
efad808a PW |
6357 | ostringstream ss; |
6358 | ss << strMsg << " code " << itostr(ccode) << ": " << strReason; | |
8d655683 | 6359 | |
efad808a PW |
6360 | if (strMsg == "block" || strMsg == "tx") |
6361 | { | |
6362 | uint256 hash; | |
6363 | vRecv >> hash; | |
6364 | ss << ": hash " << hash.ToString(); | |
6365 | } | |
6366 | LogPrint("net", "Reject %s\n", SanitizeString(ss.str())); | |
27df4123 | 6367 | } catch (const std::ios_base::failure&) { |
efad808a PW |
6368 | // Avoid feedback loops by preventing reject messages from triggering a new reject message. |
6369 | LogPrint("net", "Unparseable reject message received\n"); | |
358ce266 | 6370 | } |
358ce266 GA |
6371 | } |
6372 | } | |
432bc22a | 6373 | else if (strCommand == "notfound") { |
e496b2e3 WL |
6374 | // We do not care about the NOTFOUND message, but logging an Unknown Command |
6375 | // message would be undesirable as we transmit it ourselves. | |
6376 | } | |
8d655683 | 6377 | |
e496b2e3 | 6378 | else { |
0a61b0df | 6379 | // Ignore unknown commands for extensibility |
6ecf3edf | 6380 | LogPrint("net", "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->id); |
0a61b0df | 6381 | } |
8d655683 | 6382 | |
6383 | ||
6384 | ||
0a61b0df | 6385 | return true; |
6386 | } | |
6387 | ||
607dbfde | 6388 | // requires LOCK(cs_vRecvMsg) |
e89b9f6a PW |
6389 | bool ProcessMessages(CNode* pfrom) |
6390 | { | |
e89b9f6a | 6391 | //if (fDebug) |
30c1db1c | 6392 | // LogPrintf("%s(%u messages)\n", __func__, pfrom->vRecvMsg.size()); |
8d655683 | 6393 | |
e89b9f6a PW |
6394 | // |
6395 | // Message format | |
6396 | // (4) message start | |
6397 | // (12) command | |
6398 | // (4) size | |
6399 | // (4) checksum | |
6400 | // (x) data | |
6401 | // | |
967f2459 | 6402 | bool fOk = true; |
8d655683 | 6403 | |
c7f039b6 PW |
6404 | if (!pfrom->vRecvGetData.empty()) |
6405 | ProcessGetData(pfrom); | |
8d655683 | 6406 | |
75ef87dd PS |
6407 | // this maintains the order of responses |
6408 | if (!pfrom->vRecvGetData.empty()) return fOk; | |
8d655683 | 6409 | |
967f2459 | 6410 | std::deque<CNetMessage>::iterator it = pfrom->vRecvMsg.begin(); |
41b052ad | 6411 | while (!pfrom->fDisconnect && it != pfrom->vRecvMsg.end()) { |
9d6cd04b | 6412 | // Don't bother if send buffer is too full to respond anyway |
41b052ad | 6413 | if (pfrom->nSendSize >= SendBufferSize()) |
9d6cd04b | 6414 | break; |
8d655683 | 6415 | |
967f2459 PW |
6416 | // get next message |
6417 | CNetMessage& msg = *it; | |
8d655683 | 6418 | |
607dbfde | 6419 | //if (fDebug) |
30c1db1c | 6420 | // LogPrintf("%s(message %u msgsz, %u bytes, complete:%s)\n", __func__, |
607dbfde JG |
6421 | // msg.hdr.nMessageSize, msg.vRecv.size(), |
6422 | // msg.complete() ? "Y" : "N"); | |
8d655683 | 6423 | |
967f2459 | 6424 | // end, if an incomplete message is found |
607dbfde | 6425 | if (!msg.complete()) |
e89b9f6a | 6426 | break; |
8d655683 | 6427 | |
967f2459 PW |
6428 | // at this point, any failure means we can delete the current message |
6429 | it++; | |
8d655683 | 6430 | |
607dbfde | 6431 | // Scan for message start |
0e4b3175 | 6432 | if (memcmp(msg.hdr.pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE) != 0) { |
28d4cff0 | 6433 | LogPrintf("PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", SanitizeString(msg.hdr.GetCommand()), pfrom->id); |
967f2459 PW |
6434 | fOk = false; |
6435 | break; | |
e89b9f6a | 6436 | } |
8d655683 | 6437 | |
e89b9f6a | 6438 | // Read header |
607dbfde | 6439 | CMessageHeader& hdr = msg.hdr; |
eec37136 | 6440 | if (!hdr.IsValid(Params().MessageStart())) |
e89b9f6a | 6441 | { |
28d4cff0 | 6442 | LogPrintf("PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", SanitizeString(hdr.GetCommand()), pfrom->id); |
e89b9f6a PW |
6443 | continue; |
6444 | } | |
6445 | string strCommand = hdr.GetCommand(); | |
8d655683 | 6446 | |
e89b9f6a PW |
6447 | // Message size |
6448 | unsigned int nMessageSize = hdr.nMessageSize; | |
8d655683 | 6449 | |
e89b9f6a | 6450 | // Checksum |
607dbfde | 6451 | CDataStream& vRecv = msg.vRecv; |
18c0fa97 | 6452 | uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize); |
556814ec | 6453 | unsigned int nChecksum = ReadLE32((unsigned char*)&hash); |
18c0fa97 | 6454 | if (nChecksum != hdr.nChecksum) |
e89b9f6a | 6455 | { |
30c1db1c | 6456 | LogPrintf("%s(%s, %u bytes): CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n", __func__, |
8d655683 | 6457 | SanitizeString(strCommand), nMessageSize, nChecksum, hdr.nChecksum); |
18c0fa97 | 6458 | continue; |
e89b9f6a | 6459 | } |
8d655683 | 6460 | |
e89b9f6a PW |
6461 | // Process message |
6462 | bool fRet = false; | |
6463 | try | |
6464 | { | |
9f4da19b | 6465 | fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime); |
b31499ec | 6466 | boost::this_thread::interruption_point(); |
e89b9f6a | 6467 | } |
27df4123 | 6468 | catch (const std::ios_base::failure& e) |
e89b9f6a | 6469 | { |
358ce266 | 6470 | pfrom->PushMessage("reject", strCommand, REJECT_MALFORMED, string("error parsing message")); |
e89b9f6a PW |
6471 | if (strstr(e.what(), "end of data")) |
6472 | { | |
814efd6f | 6473 | // Allow exceptions from under-length message on vRecv |
30c1db1c | 6474 | LogPrintf("%s(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\n", __func__, SanitizeString(strCommand), nMessageSize, e.what()); |
e89b9f6a PW |
6475 | } |
6476 | else if (strstr(e.what(), "size too large")) | |
6477 | { | |
814efd6f | 6478 | // Allow exceptions from over-long size |
30c1db1c | 6479 | LogPrintf("%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what()); |
e89b9f6a PW |
6480 | } |
6481 | else | |
6482 | { | |
5970a0d7 | 6483 | //PrintExceptionContinue(&e, "ProcessMessages()"); |
e89b9f6a PW |
6484 | } |
6485 | } | |
27df4123 | 6486 | catch (const boost::thread_interrupted&) { |
b31499ec GA |
6487 | throw; |
6488 | } | |
27df4123 | 6489 | catch (const std::exception& e) { |
ea591ead | 6490 | PrintExceptionContinue(&e, "ProcessMessages()"); |
e89b9f6a | 6491 | } catch (...) { |
ea591ead | 6492 | PrintExceptionContinue(NULL, "ProcessMessages()"); |
e89b9f6a | 6493 | } |
8d655683 | 6494 | |
e89b9f6a | 6495 | if (!fRet) |
30c1db1c | 6496 | LogPrintf("%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(strCommand), nMessageSize, pfrom->id); |
8d655683 | 6497 | |
75ef87dd | 6498 | break; |
e89b9f6a | 6499 | } |
8d655683 | 6500 | |
41b052ad PW |
6501 | // In case the connection got shut down, its receive buffer was wiped |
6502 | if (!pfrom->fDisconnect) | |
6503 | pfrom->vRecvMsg.erase(pfrom->vRecvMsg.begin(), it); | |
8d655683 | 6504 | |
967f2459 | 6505 | return fOk; |
e89b9f6a | 6506 | } |
0a61b0df | 6507 | |
6508 | ||
0a61b0df | 6509 | bool SendMessages(CNode* pto, bool fSendTrickle) |
6510 | { | |
e8e8904d | 6511 | const Consensus::Params& consensusParams = Params().GetConsensus(); |
6055b910 | 6512 | { |
b05a89b2 | 6513 | // Don't send anything until we get its version message |
0a61b0df | 6514 | if (pto->nVersion == 0) |
6515 | return true; | |
8d655683 | 6516 | |
971bb3e9 JL |
6517 | // |
6518 | // Message: ping | |
6519 | // | |
6520 | bool pingSend = false; | |
6521 | if (pto->fPingQueued) { | |
6522 | // RPC ping request by user | |
6523 | pingSend = true; | |
6524 | } | |
f1920e86 PW |
6525 | if (pto->nPingNonceSent == 0 && pto->nPingUsecStart + PING_INTERVAL * 1000000 < GetTimeMicros()) { |
6526 | // Ping automatically sent as a latency probe & keepalive. | |
971bb3e9 JL |
6527 | pingSend = true; |
6528 | } | |
6529 | if (pingSend) { | |
51ed9ec9 | 6530 | uint64_t nonce = 0; |
971bb3e9 | 6531 | while (nonce == 0) { |
001a53d7 | 6532 | GetRandBytes((unsigned char*)&nonce, sizeof(nonce)); |
971bb3e9 | 6533 | } |
971bb3e9 | 6534 | pto->fPingQueued = false; |
f1920e86 | 6535 | pto->nPingUsecStart = GetTimeMicros(); |
971bb3e9 | 6536 | if (pto->nVersion > BIP0031_VERSION) { |
f1920e86 | 6537 | pto->nPingNonceSent = nonce; |
c971112d | 6538 | pto->PushMessage("ping", nonce); |
971bb3e9 | 6539 | } else { |
f1920e86 PW |
6540 | // Peer is too old to support ping command with nonce, pong will never arrive. |
6541 | pto->nPingNonceSent = 0; | |
93e447b6 | 6542 | pto->PushMessage("ping"); |
971bb3e9 | 6543 | } |
93e447b6 | 6544 | } |
8d655683 | 6545 | |
55a1db4f WL |
6546 | TRY_LOCK(cs_main, lockMain); // Acquire cs_main for IsInitialBlockDownload() and CNodeState() |
6547 | if (!lockMain) | |
6548 | return true; | |
8d655683 | 6549 | |
0a61b0df | 6550 | // Address refresh broadcast |
51ed9ec9 | 6551 | static int64_t nLastRebroadcast; |
5d1b8f17 | 6552 | if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60)) |
0a61b0df | 6553 | { |
845c86d1 GM |
6554 | LOCK(cs_vNodes); |
6555 | BOOST_FOREACH(CNode* pnode, vNodes) | |
0a61b0df | 6556 | { |
d81cff32 | 6557 | // Periodically clear addrKnown to allow refresh broadcasts |
845c86d1 | 6558 | if (nLastRebroadcast) |
83671efe | 6559 | pnode->addrKnown.reset(); |
8d655683 | 6560 | |
845c86d1 GM |
6561 | // Rebroadcast our address |
6562 | AdvertizeLocal(pnode); | |
0a61b0df | 6563 | } |
845c86d1 GM |
6564 | if (!vNodes.empty()) |
6565 | nLastRebroadcast = GetTime(); | |
0a61b0df | 6566 | } |
8d655683 | 6567 | |
0a61b0df | 6568 | // |
6569 | // Message: addr | |
6570 | // | |
6571 | if (fSendTrickle) | |
6572 | { | |
6573 | vector<CAddress> vAddr; | |
6574 | vAddr.reserve(pto->vAddrToSend.size()); | |
223b6f1b | 6575 | BOOST_FOREACH(const CAddress& addr, pto->vAddrToSend) |
0a61b0df | 6576 | { |
d81cff32 | 6577 | if (!pto->addrKnown.contains(addr.GetKey())) |
0a61b0df | 6578 | { |
d81cff32 | 6579 | pto->addrKnown.insert(addr.GetKey()); |
0a61b0df | 6580 | vAddr.push_back(addr); |
6581 | // receiver rejects addr messages larger than 1000 | |
6582 | if (vAddr.size() >= 1000) | |
6583 | { | |
6584 | pto->PushMessage("addr", vAddr); | |
6585 | vAddr.clear(); | |
6586 | } | |
6587 | } | |
6588 | } | |
6589 | pto->vAddrToSend.clear(); | |
6590 | if (!vAddr.empty()) | |
6591 | pto->PushMessage("addr", vAddr); | |
6592 | } | |
8d655683 | 6593 | |
75f51f2a PW |
6594 | CNodeState &state = *State(pto->GetId()); |
6595 | if (state.fShouldBan) { | |
dc942e6f PW |
6596 | if (pto->fWhitelisted) |
6597 | LogPrintf("Warning: not punishing whitelisted peer %s!\n", pto->addr.ToString()); | |
b2864d2f PW |
6598 | else { |
6599 | pto->fDisconnect = true; | |
dc942e6f PW |
6600 | if (pto->addr.IsLocal()) |
6601 | LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString()); | |
6602 | else | |
c74332c6 | 6603 | { |
dc942e6f | 6604 | CNode::Ban(pto->addr); |
c74332c6 | 6605 | } |
b2864d2f | 6606 | } |
75f51f2a | 6607 | state.fShouldBan = false; |
b2864d2f | 6608 | } |
8d655683 | 6609 | |
75f51f2a | 6610 | BOOST_FOREACH(const CBlockReject& reject, state.rejects) |
8d655683 | 6611 | pto->PushMessage("reject", (string)"block", reject.chRejectCode, reject.strRejectReason, reject.hashBlock); |
75f51f2a | 6612 | state.rejects.clear(); |
8d655683 | 6613 | |
6055b910 | 6614 | // Start block sync |
341735eb PW |
6615 | if (pindexBestHeader == NULL) |
6616 | pindexBestHeader = chainActive.Tip(); | |
b4ee0bdd | 6617 | bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->fOneShot); // Download if this is a nice peer, or we have no nice peers and this one might do. |
00dcaf4b | 6618 | if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) { |
341735eb | 6619 | // Only actively request headers from a single peer, unless we're close to today. |
00dcaf4b | 6620 | if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) { |
341735eb PW |
6621 | state.fSyncStarted = true; |
6622 | nSyncStarted++; | |
6623 | CBlockIndex *pindexStart = pindexBestHeader->pprev ? pindexBestHeader->pprev : pindexBestHeader; | |
4c933229 | 6624 | LogPrint("net", "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->id, pto->nStartingHeight); |
4f152496 | 6625 | pto->PushMessage("getheaders", chainActive.GetLocator(pindexStart), uint256()); |
341735eb | 6626 | } |
6055b910 | 6627 | } |
8d655683 | 6628 | |
6055b910 PW |
6629 | // Resend wallet transactions that haven't gotten in a block yet |
6630 | // Except during reindex, importing and IBD, when old wallet | |
6631 | // transactions become unconfirmed and spams other nodes. | |
6632 | if (!fReindex && !fImporting && !IsInitialBlockDownload()) | |
6633 | { | |
0f5954c4 | 6634 | GetMainSignals().Broadcast(nTimeBestReceived); |
6055b910 | 6635 | } |
8d655683 | 6636 | |
0a61b0df | 6637 | // |
6638 | // Message: inventory | |
6639 | // | |
6640 | vector<CInv> vInv; | |
6641 | vector<CInv> vInvWait; | |
0a61b0df | 6642 | { |
f8dcd5ca | 6643 | LOCK(pto->cs_inventory); |
0a61b0df | 6644 | vInv.reserve(pto->vInventoryToSend.size()); |
6645 | vInvWait.reserve(pto->vInventoryToSend.size()); | |
223b6f1b | 6646 | BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend) |
0a61b0df | 6647 | { |
6648 | if (pto->setInventoryKnown.count(inv)) | |
6649 | continue; | |
8d655683 | 6650 | |
0a61b0df | 6651 | // trickle out tx inv to protect privacy |
6652 | if (inv.type == MSG_TX && !fSendTrickle) | |
6653 | { | |
6654 | // 1/4 of tx invs blast to all immediately | |
6655 | static uint256 hashSalt; | |
4f152496 | 6656 | if (hashSalt.IsNull()) |
f718aedd | 6657 | hashSalt = GetRandHash(); |
734f85c4 | 6658 | uint256 hashRand = ArithToUint256(UintToArith256(inv.hash) ^ UintToArith256(hashSalt)); |
0a61b0df | 6659 | hashRand = Hash(BEGIN(hashRand), END(hashRand)); |
734f85c4 | 6660 | bool fTrickleWait = ((UintToArith256(hashRand) & 3) != 0); |
8d655683 | 6661 | |
0a61b0df | 6662 | if (fTrickleWait) |
6663 | { | |
6664 | vInvWait.push_back(inv); | |
6665 | continue; | |
6666 | } | |
6667 | } | |
8d655683 | 6668 | |
0a61b0df | 6669 | // returns true if wasn't already contained in the set |
6670 | if (pto->setInventoryKnown.insert(inv).second) | |
6671 | { | |
6672 | vInv.push_back(inv); | |
6673 | if (vInv.size() >= 1000) | |
6674 | { | |
6675 | pto->PushMessage("inv", vInv); | |
6676 | vInv.clear(); | |
6677 | } | |
6678 | } | |
6679 | } | |
6680 | pto->vInventoryToSend = vInvWait; | |
6681 | } | |
6682 | if (!vInv.empty()) | |
6683 | pto->PushMessage("inv", vInv); | |
8d655683 | 6684 | |
341735eb | 6685 | // Detect whether we're stalling |
f59d8f0b | 6686 | int64_t nNow = GetTimeMicros(); |
341735eb PW |
6687 | if (!pto->fDisconnect && state.nStallingSince && state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) { |
6688 | // Stalling only triggers when the block download window cannot move. During normal steady state, | |
6689 | // the download window should be much larger than the to-be-downloaded set of blocks, so disconnection | |
6690 | // should only happen during initial block download. | |
6691 | LogPrintf("Peer=%d is stalling block download, disconnecting\n", pto->id); | |
f59d8f0b PW |
6692 | pto->fDisconnect = true; |
6693 | } | |
3ff735c9 | 6694 | // In case there is a block that has been in flight from this peer for (2 + 0.5 * N) times the block interval |
91613034 PW |
6695 | // (with N the number of validated blocks that were in flight at the time it was requested), disconnect due to |
6696 | // timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link | |
7e6d23b1 | 6697 | // being saturated. We only count validated in-flight blocks so peers can't advertise non-existing block hashes |
91613034 | 6698 | // to unreasonably increase our timeout. |
8ba7f842 SD |
6699 | // We also compare the block download timeout originally calculated against the time at which we'd disconnect |
6700 | // if we assumed the block were being requested now (ignoring blocks we've requested from this peer, since we're | |
6701 | // only looking at this peer's oldest request). This way a large queue in the past doesn't result in a | |
6702 | // permanently large window for this block to be delivered (ie if the number of blocks in flight is decreasing | |
6703 | // more quickly than once every 5 minutes, then we'll shorten the download window for this block). | |
6704 | if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0) { | |
6705 | QueuedBlock &queuedBlock = state.vBlocksInFlight.front(); | |
82737933 | 6706 | int64_t nTimeoutIfRequestedNow = GetBlockTimeout(nNow, nQueuedValidatedHeaders - state.nBlocksInFlightValidHeaders, consensusParams); |
8ba7f842 SD |
6707 | if (queuedBlock.nTimeDisconnect > nTimeoutIfRequestedNow) { |
6708 | LogPrint("net", "Reducing block download timeout for peer=%d block=%s, orig=%d new=%d\n", pto->id, queuedBlock.hash.ToString(), queuedBlock.nTimeDisconnect, nTimeoutIfRequestedNow); | |
6709 | queuedBlock.nTimeDisconnect = nTimeoutIfRequestedNow; | |
6710 | } | |
6711 | if (queuedBlock.nTimeDisconnect < nNow) { | |
6712 | LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", queuedBlock.hash.ToString(), pto->id); | |
6713 | pto->fDisconnect = true; | |
6714 | } | |
91613034 | 6715 | } |
8d655683 | 6716 | |
0a61b0df | 6717 | // |
f59d8f0b | 6718 | // Message: getdata (blocks) |
0a61b0df | 6719 | // |
161f617d | 6720 | static uint256 zero; |
0a61b0df | 6721 | vector<CInv> vGetData; |
00dcaf4b | 6722 | if (!pto->fDisconnect && !pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { |
341735eb PW |
6723 | vector<CBlockIndex*> vToDownload; |
6724 | NodeId staller = -1; | |
6725 | FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller); | |
6726 | BOOST_FOREACH(CBlockIndex *pindex, vToDownload) { | |
6727 | vGetData.push_back(CInv(MSG_BLOCK, pindex->GetBlockHash())); | |
82737933 | 6728 | MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex); |
1af838b3 | 6729 | LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(), |
8d655683 | 6730 | pindex->nHeight, pto->id); |
341735eb PW |
6731 | } |
6732 | if (state.nBlocksInFlight == 0 && staller != -1) { | |
1bcee67e | 6733 | if (State(staller)->nStallingSince == 0) { |
341735eb | 6734 | State(staller)->nStallingSince = nNow; |
1bcee67e B |
6735 | LogPrint("net", "Stall started peer=%d\n", staller); |
6736 | } | |
f59d8f0b PW |
6737 | } |
6738 | } | |
8d725ab4 | 6739 | /*CBlockIndex *pindex; |
bddeaf5e | 6740 | if ( komodo_requestedhash != zero && komodo_requestedcount < 16 && (pindex= mapBlockIndex[komodo_requestedhash]) != 0 ) |
161f617d | 6741 | { |
bddeaf5e | 6742 | LogPrint("net","komodo_requestedhash.%d request %s to nodeid.%d\n",komodo_requestedcount,komodo_requestedhash.ToString().c_str(),pto->GetId()); |
6743 | fprintf(stderr,"komodo_requestedhash.%d request %s to nodeid.%d\n",komodo_requestedcount,komodo_requestedhash.ToString().c_str(),pto->GetId()); | |
161f617d | 6744 | vGetData.push_back(CInv(MSG_BLOCK, komodo_requestedhash)); |
6745 | MarkBlockAsInFlight(pto->GetId(), komodo_requestedhash, consensusParams, pindex); | |
bddeaf5e | 6746 | komodo_requestedcount++; |
6747 | if ( komodo_requestedcount > 16 ) | |
6748 | { | |
6749 | memset(&komodo_requestedhash,0,sizeof(komodo_requestedhash)); | |
6750 | komodo_requestedcount = 0; | |
6751 | } | |
8d725ab4 | 6752 | }*/ |
161f617d | 6753 | |
f59d8f0b PW |
6754 | // |
6755 | // Message: getdata (non-blocks) | |
6756 | // | |
6757 | while (!pto->fDisconnect && !pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow) | |
0a61b0df | 6758 | { |
6759 | const CInv& inv = (*pto->mapAskFor.begin()).second; | |
ae8bfd12 | 6760 | if (!AlreadyHave(inv)) |
0a61b0df | 6761 | { |
3b570559 | 6762 | if (fDebug) |
2e36866f | 6763 | LogPrint("net", "Requesting %s peer=%d\n", inv.ToString(), pto->id); |
0a61b0df | 6764 | vGetData.push_back(inv); |
6765 | if (vGetData.size() >= 1000) | |
6766 | { | |
6767 | pto->PushMessage("getdata", vGetData); | |
6768 | vGetData.clear(); | |
6769 | } | |
e2190f80 GM |
6770 | } else { |
6771 | //If we're not going to ask, don't expect a response. | |
6772 | pto->setAskFor.erase(inv.hash); | |
0a61b0df | 6773 | } |
6774 | pto->mapAskFor.erase(pto->mapAskFor.begin()); | |
6775 | } | |
6776 | if (!vGetData.empty()) | |
6777 | pto->PushMessage("getdata", vGetData); | |
8d655683 | 6778 | |
0a61b0df | 6779 | } |
6780 | return true; | |
6781 | } | |
6782 | ||
8d655683 | 6783 | std::string CBlockFileInfo::ToString() const { |
6784 | return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst), DateTimeStrFormat("%Y-%m-%d", nTimeLast)); | |
6785 | } | |
0a61b0df | 6786 | |
6787 | ||
6788 | ||
3427517d PW |
6789 | class CMainCleanup |
6790 | { | |
6791 | public: | |
6792 | CMainCleanup() {} | |
6793 | ~CMainCleanup() { | |
6794 | // block headers | |
145d5be8 | 6795 | BlockMap::iterator it1 = mapBlockIndex.begin(); |
3427517d PW |
6796 | for (; it1 != mapBlockIndex.end(); it1++) |
6797 | delete (*it1).second; | |
6798 | mapBlockIndex.clear(); | |
8d655683 | 6799 | |
3427517d | 6800 | // orphan transactions |
3427517d | 6801 | mapOrphanTransactions.clear(); |
c74332c6 | 6802 | mapOrphanTransactionsByPrev.clear(); |
3427517d PW |
6803 | } |
6804 | } instance_of_cmaincleanup; | |
431cce98 | 6805 | |
431cce98 | 6806 | extern "C" const char* getDataDir() |
6807 | { | |
8d655683 | 6808 | return GetDataDir().string().c_str(); |
431cce98 | 6809 | } |
6810 | ||
072099d7 S |
6811 | |
6812 | // Set default values of new CMutableTransaction based on consensus rules at given height. | |
6813 | CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight) | |
6814 | { | |
6815 | CMutableTransaction mtx; | |
8d655683 | 6816 | |
072099d7 S |
6817 | bool isOverwintered = NetworkUpgradeActive(nHeight, consensusParams, Consensus::UPGRADE_OVERWINTER); |
6818 | if (isOverwintered) { | |
6819 | mtx.fOverwintered = true; | |
6820 | mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; | |
6821 | mtx.nVersion = 3; | |
6822 | // Expiry height is not set. Only fields required for a parser to treat as a valid Overwinter V3 tx. | |
8d655683 | 6823 | |
072099d7 S |
6824 | // TODO: In future, when moving from Overwinter to Sapling, it will be useful |
6825 | // to set the expiry height to: min(activation_height - 1, default_expiry_height) | |
6826 | } | |
6827 | return mtx; | |
6828 | } |