2017-08-22 11:42:33 +02:00
/*
2017-11-09 19:34:51 +01:00
* This file is part of the Flowee project
2017-08-22 11:42:33 +02:00
* Copyright (c) 2009-2010 Satoshi Nakamoto
* Copyright (c) 2009-2015 The Bitcoin Core developers
2020-02-27 13:35:56 +01:00
* Copyright (C) 2017-2020 Tom Zander <tomz@freedommail.ch>
2017-08-22 11:42:33 +02:00
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
2012-05-18 22:02:28 +08:00
2013-04-13 00:13:08 -05:00
# include "main.h"
# include "addrman.h"
2013-08-27 15:51:57 +10:00
# include "chainparams.h"
2015-06-24 07:25:30 +02:00
# include "consensus/consensus.h"
2019-10-15 14:09:23 +02:00
# include "merkleblock.h"
2015-01-24 15:57:12 +01:00
# include "consensus/validation.h"
2019-09-02 23:35:14 +02:00
# include "DoubleSpendProof.h"
# include "DoubleSpendProofStorage.h"
2019-10-15 14:09:23 +02:00
# include "UiInterface.h"
2013-08-27 15:51:57 +10:00
# include "init.h"
2015-07-05 14:30:07 +02:00
# include "script/sigcache.h"
2019-10-15 14:09:23 +02:00
# include "serverutil.h"
# include "timedata.h"
2013-08-27 15:51:57 +10:00
# include "txmempool.h"
2017-02-08 17:17:38 +01:00
# include "txorphancache.h"
2019-10-15 14:09:23 +02:00
# include "thinblock.h"
# include "validation/Engine.h"
# include <Application.h>
# include <SettingsDefaults.h>
# include <Logger.h>
# include "checkpoints.h"
# include <util.h>
# include <utils/hash.h>
# include <utiltime.h>
2015-02-05 01:11:44 +01:00
# include "validationinterface.h"
2019-10-15 14:09:23 +02:00
# include <primitives/FastBlock.h>
2018-07-23 18:05:43 +02:00
# include <utxo/UnspentOutputDatabase.h>
# include <BlocksDB.h>
2013-04-13 00:13:08 -05:00
# include <boost/algorithm/string/replace.hpp>
# include <boost/filesystem.hpp>
2018-12-30 15:33:11 +01:00
# include <boost/foreach.hpp>
2013-08-27 15:51:57 +10:00
2014-12-01 09:39:44 +08:00
/**
* Global state
*/
2010-08-29 16:58:15 +00:00
CCriticalSection cs_main ;
2013-10-10 23:07:44 +02:00
CChain chainActive ;
2018-06-12 20:43:50 +02:00
CBlockIndex * pindexBestHeader = nullptr ;
2012-05-13 04:43:24 +00:00
CWaitableCriticalSection csBestBlock ;
CConditionVariable cvBlockChange ;
2018-02-12 14:15:24 +01:00
bool fIsBareMultisigStd = Settings : : DefaultPermitBareMultisig ;
2015-06-24 03:36:22 +00:00
bool fRequireStandard = true ;
2018-02-12 14:15:24 +01:00
bool fCheckpointsEnabled = Settings : : DefaultCheckpointsEnabled ;
2010-08-29 16:58:15 +00:00
2015-10-25 03:01:20 +01:00
/** Fees smaller than this (in satoshi) are considered zero fee (for relaying, mining and transaction creation) */
2018-02-12 14:15:24 +01:00
CFeeRate minRelayTxFee = CFeeRate ( Settings : : DefaultMinRelayTxFee ) ;
2014-07-03 14:25:32 -04:00
2019-06-28 12:38:46 +02:00
CTxMemPool mempool ;
2013-04-25 20:11:27 -04:00
2017-08-15 10:24:20 -06:00
const std : : string strMessageMagic = " Bitcoin Signed Message: \n " ;
2011-12-23 10:14:57 -05:00
2017-09-03 21:17:27 +02:00
CCriticalSection cs_LastBlockFile ;
std : : vector < CBlockFileInfo > vinfoBlockFile ;
int nLastBlockFile = 0 ;
/** Dirty block file entries. */
std : : set < int > setDirtyFileInfo ;
2013-10-14 02:13:44 +02:00
// Internal stuff
namespace {
2014-06-24 14:17:43 +02:00
2014-04-30 14:57:11 +08:00
struct CBlockIndexWorkComparator
{
2015-03-13 09:25:34 -07:00
bool operator ( ) ( CBlockIndex * pa , CBlockIndex * pb ) const {
2014-04-30 14:57:11 +08:00
// First sort by most total work, ...
if ( pa - > nChainWork > pb - > nChainWork ) return false ;
if ( pa - > nChainWork < pb - > nChainWork ) return true ;
2011-03-26 13:01:27 +01:00
2014-04-30 14:57:11 +08:00
// ... then by earliest time received, ...
if ( pa - > nSequenceId < pb - > nSequenceId ) return false ;
if ( pa - > nSequenceId > pb - > nSequenceId ) return true ;
2013-10-14 02:13:44 +02:00
2014-04-30 14:57:11 +08:00
// Use pointer address as tie breaker (should only happen with blocks
// loaded from disk, as those all have id 0).
if ( pa < pb ) return false ;
if ( pa > pb ) return true ;
2013-11-16 19:28:24 +01:00
2014-04-30 14:57:11 +08:00
// Identical blocks.
return false ;
}
} ;
2013-10-14 02:13:44 +02:00
2014-12-01 09:39:44 +08:00
/** Number of nodes with fSyncStarted. */
2014-07-12 00:02:35 +02:00
int nSyncStarted = 0 ;
2013-11-16 19:28:24 +01:00
2014-12-01 09:39:44 +08:00
/**
* Every received block is assigned a unique and increasing identifier, so we
* know which one to give priority in case of a fork.
*/
2014-04-30 14:57:11 +08:00
CCriticalSection cs_nBlockSequenceId ;
2014-12-01 09:39:44 +08:00
/** Blocks loaded from disk are assigned id 0, so start the counter at 1. */
2014-04-30 14:57:11 +08:00
uint32_t nBlockSequenceId = 1 ;
2013-11-16 19:28:24 +01:00
2014-12-01 09:39:44 +08:00
/**
2015-04-28 14:47:17 +00:00
* Sources of received blocks, saved to be able to send them reject
* messages or ban them when processing happens afterwards. Protected by
* cs_main.
2014-12-01 09:39:44 +08:00
*/
2017-08-15 10:24:20 -06:00
std : : map < uint256 , NodeId > mapBlockSource ;
2014-01-10 13:23:26 +01:00
2015-07-17 06:46:48 -04:00
/**
* Filter for transactions that were recently rejected by
* AcceptToMemoryPool. These are not rerequested until the chain tip
* changes, at which point the entire filter is reset. Protected by
* cs_main.
*
* Without this filter we'd be re-requesting txs from each of our peers,
* increasing bandwidth consumption considerably. For instance, with 100
* peers, half of which relay a tx we don't accept, that might be a 50x
* bandwidth increase. A flooding attacker attempting to roll-over the
* filter using minimum-sized, 60byte, transactions might manage to send
* 1000/sec if we have fast peers, so we pick 120,000 to give our peers a
* two minute window to send invs to us.
*
* Decreasing the false positive rate is fairly cheap, so we pick one in a
* million to make it highly unlikely for users to have issues with this
* filter.
*
* Memory used: 1.7MB
*/
boost : : scoped_ptr < CRollingBloomFilter > recentRejects ;
uint256 hashRecentRejectsChainTip ;
2014-12-01 09:39:44 +08:00
/** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
2014-04-30 14:57:11 +08:00
struct QueuedBlock {
uint256 hash ;
2016-04-03 15:24:09 +02:00
CBlockIndex * pindex ; //!< Optional.
bool fValidatedHeaders ; //!< Whether this block has validated headers at the time of request.
2014-04-30 14:57:11 +08:00
} ;
2017-08-15 10:24:20 -06:00
std : : map < uint256 , std : : pair < NodeId , std : : list < QueuedBlock > : : iterator > > mapBlocksInFlight ;
2014-06-24 14:17:43 +02:00
2014-12-01 09:39:44 +08:00
/** Number of preferable block download peers. */
2014-10-28 09:33:55 -07:00
int nPreferredDownload = 0 ;
2014-11-07 02:38:35 -08:00
2018-01-15 15:26:12 +00:00
/** Dirty block index entries. The block index instances not yet persisted to (index) DB */
2017-08-15 10:24:20 -06:00
std : : set < CBlockIndex * > setDirtyBlockIndex ;
2014-11-07 02:38:35 -08:00
2016-04-03 15:24:09 +02:00
/** Number of peers from which we're downloading blocks. */
int nPeersWithValidatedDownloads = 0 ;
2014-06-24 14:17:43 +02:00
} // anon namespace
2010-08-29 16:58:15 +00:00
2013-06-05 20:21:41 -07:00
//////////////////////////////////////////////////////////////////////////////
//
// Registration of network node signals.
//
2011-06-01 18:28:20 +02:00
2013-11-18 01:25:17 +01:00
namespace {
2013-11-16 19:28:24 +01:00
struct CBlockReject {
unsigned char chRejectCode ;
2017-08-15 10:24:20 -06:00
std : : string strRejectReason ;
2013-11-16 19:28:24 +01:00
uint256 hashBlock ;
} ;
2014-12-01 09:39:44 +08:00
/**
* Maintain validation-specific state about nodes, protected by cs_main, instead
* by CNode's own locks. This simplifies asynchronous operation, where
* processing of incoming data is done after the ProcessMessage call returns,
* and we're no longer holding the node's locks.
*/
2013-11-18 01:25:17 +01:00
struct CNodeState {
2015-03-05 04:01:22 -08:00
//! The peer's address
CService address ;
//! Whether we have a fully established connection.
bool fCurrentlyConnected ;
2014-12-01 09:39:44 +08:00
//! Accumulated misbehaviour score for this peer.
2013-11-18 01:25:17 +01:00
int nMisbehavior ;
2014-12-01 09:39:44 +08:00
//! Whether this peer should be disconnected and banned (unless whitelisted).
2013-11-18 01:25:17 +01:00
bool fShouldBan ;
2014-12-01 09:39:44 +08:00
//! List of asynchronously-determined block rejections to notify this peer about.
2013-11-16 19:28:24 +01:00
std : : vector < CBlockReject > rejects ;
2014-12-01 09:39:44 +08:00
//! The best known block we know this peer has announced.
2014-06-23 00:00:26 +02:00
CBlockIndex * pindexBestKnownBlock ;
2014-12-01 09:39:44 +08:00
//! The hash of the last unknown block this peer has announced.
2014-06-23 00:00:26 +02:00
uint256 hashLastUnknownBlock ;
2014-12-01 09:39:44 +08:00
//! The last full block we both have.
2014-07-12 00:02:35 +02:00
CBlockIndex * pindexLastCommonBlock ;
2014-11-18 22:16:32 +01:00
//! The best header we have sent our peer.
CBlockIndex * pindexBestHeaderSent ;
2014-12-01 09:39:44 +08:00
//! Whether we've started headers synchronization with this peer.
2014-07-12 00:02:35 +02:00
bool fSyncStarted ;
2014-12-01 09:39:44 +08:00
//! Since when we're stalling block download progress (in microseconds), or 0.
2014-07-12 00:02:35 +02:00
int64_t nStallingSince ;
2017-08-15 10:24:20 -06:00
std : : list < QueuedBlock > vBlocksInFlight ;
2016-04-03 15:24:09 +02:00
//! When the first entry in vBlocksInFlight started downloading. Don't care when vBlocksInFlight is empty.
int64_t nDownloadingSince ;
2014-01-10 13:23:26 +01:00
int nBlocksInFlight ;
2015-04-06 13:10:33 -04:00
int nBlocksInFlightValidHeaders ;
2014-12-01 09:39:44 +08:00
//! Whether we consider this a preferred download peer.
2014-10-28 09:33:55 -07:00
bool fPreferredDownload ;
2014-11-18 22:16:32 +01:00
//! Whether this peer wants invs or headers (when possible) for block announcements.
bool fPreferHeaders ;
2013-11-18 01:25:17 +01:00
CNodeState ( ) {
2015-03-05 04:01:22 -08:00
fCurrentlyConnected = false ;
2013-11-18 01:25:17 +01:00
nMisbehavior = 0 ;
fShouldBan = false ;
2018-06-12 20:43:50 +02:00
pindexBestKnownBlock = nullptr ;
2014-12-15 09:11:16 +01:00
hashLastUnknownBlock . SetNull ( ) ;
2018-06-12 20:43:50 +02:00
pindexLastCommonBlock = nullptr ;
pindexBestHeaderSent = nullptr ;
2020-08-10 12:12:08 +02:00
ResetASERTAnchorBlockCache ( ) ;
2014-07-12 00:02:35 +02:00
fSyncStarted = false ;
nStallingSince = 0 ;
2016-04-03 15:24:09 +02:00
nDownloadingSince = 0 ;
2014-01-10 13:23:26 +01:00
nBlocksInFlight = 0 ;
2015-04-06 13:10:33 -04:00
nBlocksInFlightValidHeaders = 0 ;
2014-10-28 09:33:55 -07:00
fPreferredDownload = false ;
2014-11-18 22:16:32 +01:00
fPreferHeaders = false ;
2013-11-18 01:25:17 +01:00
}
} ;
2014-12-01 09:39:44 +08:00
/** Map maintaining per-node state. Requires cs_main. */
2017-08-15 10:24:20 -06:00
std : : map < NodeId , CNodeState > mapNodeState ;
2013-11-18 01:25:17 +01:00
// Requires cs_main.
CNodeState * State ( NodeId pnode ) {
2017-08-15 10:24:20 -06:00
std : : map < NodeId , CNodeState > : : iterator it = mapNodeState . find ( pnode ) ;
2013-11-18 01:25:17 +01:00
if ( it = = mapNodeState . end ( ) )
2018-06-12 20:43:50 +02:00
return nullptr ;
2013-11-18 01:25:17 +01:00
return & it - > second ;
}
int GetHeight ( )
2013-10-10 23:07:44 +02:00
{
LOCK ( cs_main ) ;
return chainActive . Height ( ) ;
}
2014-10-28 09:33:55 -07:00
void UpdatePreferredDownload ( CNode * node , CNodeState * state )
{
nPreferredDownload - = state - > fPreferredDownload ;
// Whether this node should be marked as a preferred download node.
state - > fPreferredDownload = ( ! node - > fInbound | | node - > fWhitelisted ) & & ! node - > fOneShot & & ! node - > fClient ;
nPreferredDownload + = state - > fPreferredDownload ;
}
2013-11-18 01:25:17 +01:00
void InitializeNode ( NodeId nodeid , const CNode * pnode ) {
LOCK ( cs_main ) ;
CNodeState & state = mapNodeState . insert ( std : : make_pair ( nodeid , CNodeState ( ) ) ) . first - > second ;
2015-03-05 04:01:22 -08:00
state . address = pnode - > addr ;
2013-11-18 01:25:17 +01:00
}
void FinalizeNode ( NodeId nodeid ) {
LOCK ( cs_main ) ;
2014-01-10 13:23:26 +01:00
CNodeState * state = State ( nodeid ) ;
2017-04-20 10:22:10 +02:00
assert ( state ) ;
2014-01-10 13:23:26 +01:00
2014-07-12 00:02:35 +02:00
if ( state - > fSyncStarted )
nSyncStarted - - ;
2015-03-05 04:01:22 -08:00
if ( state - > nMisbehavior = = 0 & & state - > fCurrentlyConnected ) {
AddressCurrentlyConnected ( state - > address ) ;
}
2018-12-30 15:33:11 +01:00
for ( const QueuedBlock & entry : state - > vBlocksInFlight ) {
2014-01-10 13:23:26 +01:00
mapBlocksInFlight . erase ( entry . hash ) ;
2016-02-08 15:32:29 -05:00
}
2014-10-28 09:33:55 -07:00
nPreferredDownload - = state - > fPreferredDownload ;
2016-04-03 15:24:09 +02:00
nPeersWithValidatedDownloads - = ( state - > nBlocksInFlightValidHeaders ! = 0 ) ;
assert ( nPeersWithValidatedDownloads > = 0 ) ;
2014-01-10 13:23:26 +01:00
2013-11-18 01:25:17 +01:00
mapNodeState . erase ( nodeid ) ;
2016-04-03 15:24:09 +02:00
if ( mapNodeState . empty ( ) ) {
// Do a consistency check after the last peer is removed.
assert ( mapBlocksInFlight . empty ( ) ) ;
assert ( nPreferredDownload = = 0 ) ;
assert ( nPeersWithValidatedDownloads = = 0 ) ;
}
2013-11-18 01:25:17 +01:00
}
2018-01-15 15:26:12 +00:00
}
2014-01-10 13:23:26 +01:00
// Requires cs_main.
2015-04-09 13:21:11 -04:00
// Returns a bool indicating whether we requested this block.
bool MarkBlockAsReceived ( const uint256 & hash ) {
2017-08-15 10:24:20 -06:00
std : : map < uint256 , std : : pair < NodeId , std : : list < QueuedBlock > : : iterator > > : : iterator itInFlight = mapBlocksInFlight . find ( hash ) ;
2014-01-10 13:23:26 +01:00
if ( itInFlight ! = mapBlocksInFlight . end ( ) ) {
CNodeState * state = State ( itInFlight - > second . first ) ;
2015-04-06 13:10:33 -04:00
state - > nBlocksInFlightValidHeaders - = itInFlight - > second . second - > fValidatedHeaders ;
2016-04-03 15:24:09 +02:00
if ( state - > nBlocksInFlightValidHeaders = = 0 & & itInFlight - > second . second - > fValidatedHeaders ) {
// Last validated block on the queue was received.
nPeersWithValidatedDownloads - - ;
}
if ( state - > vBlocksInFlight . begin ( ) = = itInFlight - > second . second ) {
// First block on the queue was received, update the start download time for the next one
state - > nDownloadingSince = std : : max ( state - > nDownloadingSince , GetTimeMicros ( ) ) ;
}
2014-01-10 13:23:26 +01:00
state - > vBlocksInFlight . erase ( itInFlight - > second . second ) ;
state - > nBlocksInFlight - - ;
2014-07-12 00:02:35 +02:00
state - > nStallingSince = 0 ;
2014-01-10 13:23:26 +01:00
mapBlocksInFlight . erase ( itInFlight ) ;
2015-04-09 13:21:11 -04:00
return true ;
2014-01-10 13:23:26 +01:00
}
2015-04-09 13:21:11 -04:00
return false ;
2014-01-10 13:23:26 +01:00
}
2018-01-15 15:26:12 +00:00
bool IsBlockInFlight ( const uint256 & hash )
{
return mapBlocksInFlight . count ( hash ) > 0 ;
}
namespace {
2014-01-10 13:23:26 +01:00
// Requires cs_main.
2018-06-12 20:43:50 +02:00
void MarkBlockAsInFlight ( NodeId nodeid , const uint256 & hash , const Consensus : : Params & , CBlockIndex * pindex = nullptr ) {
2014-01-10 13:23:26 +01:00
CNodeState * state = State ( nodeid ) ;
2018-06-12 20:43:50 +02:00
assert ( state ! = nullptr ) ;
2014-01-10 13:23:26 +01:00
// Make sure it's not listed somewhere already.
MarkBlockAsReceived ( hash ) ;
2018-06-12 20:43:50 +02:00
QueuedBlock newentry = { hash , pindex , pindex ! = nullptr } ;
2017-08-15 10:24:20 -06:00
std : : list < QueuedBlock > : : iterator it = state - > vBlocksInFlight . insert ( state - > vBlocksInFlight . end ( ) , newentry ) ;
2014-01-10 13:23:26 +01:00
state - > nBlocksInFlight + + ;
2015-04-06 13:10:33 -04:00
state - > nBlocksInFlightValidHeaders + = newentry . fValidatedHeaders ;
2016-04-03 15:24:09 +02:00
if ( state - > nBlocksInFlight = = 1 ) {
// We're starting a block download (batch) from this peer.
state - > nDownloadingSince = GetTimeMicros ( ) ;
}
2018-06-12 20:43:50 +02:00
if ( state - > nBlocksInFlightValidHeaders = = 1 & & pindex ! = nullptr ) {
2016-04-03 15:24:09 +02:00
nPeersWithValidatedDownloads + + ;
}
2014-01-10 13:23:26 +01:00
mapBlocksInFlight [ hash ] = std : : make_pair ( nodeid , it ) ;
}
2016-02-12 11:35:32 -07:00
/** Check whether the last unknown block a peer advertised is not yet known. */
2014-06-23 00:00:26 +02:00
void ProcessBlockAvailability ( NodeId nodeid ) {
CNodeState * state = State ( nodeid ) ;
2018-06-12 20:43:50 +02:00
assert ( state ! = nullptr ) ;
2014-06-23 00:00:26 +02:00
2014-12-15 09:11:16 +01:00
if ( ! state - > hashLastUnknownBlock . IsNull ( ) ) {
2018-01-15 15:26:12 +00:00
auto bi = Blocks : : Index : : get ( state - > hashLastUnknownBlock ) ;
if ( bi & & bi - > nChainWork > 0 ) {
if ( state - > pindexBestKnownBlock = = nullptr | | bi - > nChainWork > = state - > pindexBestKnownBlock - > nChainWork )
state - > pindexBestKnownBlock = bi ;
2014-12-15 09:11:16 +01:00
state - > hashLastUnknownBlock . SetNull ( ) ;
2014-06-23 00:00:26 +02:00
}
}
}
/** Update tracking information about which blocks a peer is assumed to have. */
void UpdateBlockAvailability ( NodeId nodeid , const uint256 & hash ) {
CNodeState * state = State ( nodeid ) ;
2018-06-12 20:43:50 +02:00
assert ( state ! = nullptr ) ;
2014-06-23 00:00:26 +02:00
ProcessBlockAvailability ( nodeid ) ;
2018-01-15 15:26:12 +00:00
auto bi = Blocks : : Index : : get ( hash ) ;
if ( bi & & bi - > nChainWork > 0 ) {
2014-06-23 00:00:26 +02:00
// An actually better block was announced.
2018-06-12 20:43:50 +02:00
if ( state - > pindexBestKnownBlock = = nullptr | | bi - > nChainWork > = state - > pindexBestKnownBlock - > nChainWork )
2018-01-15 15:26:12 +00:00
state - > pindexBestKnownBlock = bi ;
2014-06-23 00:00:26 +02:00
} else {
// An unknown block was announced; just assume that the latest one is the best one.
state - > hashLastUnknownBlock = hash ;
}
}
2014-11-18 22:16:32 +01:00
// Requires cs_main
bool CanDirectFetch ( const Consensus : : Params & consensusParams )
{
return chainActive . Tip ( ) - > GetBlockTime ( ) > GetAdjustedTime ( ) - consensusParams . nPowTargetSpacing * 20 ;
}
// Requires cs_main
bool PeerHasHeader ( CNodeState * state , CBlockIndex * pindex )
{
if ( state - > pindexBestKnownBlock & & pindex = = state - > pindexBestKnownBlock - > GetAncestor ( pindex - > nHeight ) )
return true ;
if ( state - > pindexBestHeaderSent & & pindex = = state - > pindexBestHeaderSent - > GetAncestor ( pindex - > nHeight ) )
return true ;
return false ;
}
2014-07-12 00:02:35 +02:00
/** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has
* at most count entries. */
void FindNextBlocksToDownload ( NodeId nodeid , unsigned int count , std : : vector < CBlockIndex * > & vBlocks , NodeId & nodeStaller ) {
if ( count = = 0 )
return ;
vBlocks . reserve ( vBlocks . size ( ) + count ) ;
CNodeState * state = State ( nodeid ) ;
2018-06-12 20:43:50 +02:00
assert ( state ! = nullptr ) ;
2014-07-12 00:02:35 +02:00
// Make sure pindexBestKnownBlock is up to date, we'll need it.
ProcessBlockAvailability ( nodeid ) ;
2018-06-12 20:43:50 +02:00
if ( state - > pindexBestKnownBlock = = nullptr | | state - > pindexBestKnownBlock - > nChainWork < chainActive . Tip ( ) - > nChainWork ) {
2014-07-12 00:02:35 +02:00
// This peer has nothing interesting.
return ;
}
2018-06-12 20:43:50 +02:00
if ( state - > pindexLastCommonBlock = = nullptr ) {
2014-07-12 00:02:35 +02:00
// Bootstrap quickly by guessing a parent of our best tip is the forking point.
// Guessing wrong in either direction is not a problem.
state - > pindexLastCommonBlock = chainActive [ std : : min ( state - > pindexBestKnownBlock - > nHeight , chainActive . Height ( ) ) ] ;
}
// If the peer reorganized, our previous pindexLastCommonBlock may not be an ancestor
2015-04-28 14:47:17 +00:00
// of its current tip anymore. Go back enough to fix that.
2019-05-26 13:27:16 +02:00
state - > pindexLastCommonBlock = Blocks : : Index : : lastCommonAncestor ( state - > pindexLastCommonBlock , state - > pindexBestKnownBlock ) ;
2014-07-12 00:02:35 +02:00
if ( state - > pindexLastCommonBlock = = state - > pindexBestKnownBlock )
return ;
std : : vector < CBlockIndex * > vToFetch ;
CBlockIndex * pindexWalk = state - > pindexLastCommonBlock ;
2014-10-14 15:41:23 -07:00
// Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last
// linked block we have in common with this peer. The +1 is so we can detect stalling, namely if we would be able to
// download that next block if the window were 1 larger.
int nWindowEnd = state - > pindexLastCommonBlock - > nHeight + BLOCK_DOWNLOAD_WINDOW ;
int nMaxHeight = std : : min < int > ( state - > pindexBestKnownBlock - > nHeight , nWindowEnd + 1 ) ;
2014-07-12 00:02:35 +02:00
NodeId waitingfor = - 1 ;
while ( pindexWalk - > nHeight < nMaxHeight ) {
// Read up to 128 (or more, if more blocks than that are needed) successors of pindexWalk (towards
// pindexBestKnownBlock) into vToFetch. We fetch 128, because CBlockIndex::GetAncestor may be as expensive
// as iterating over ~100 CBlockIndex* entries anyway.
int nToFetch = std : : min ( nMaxHeight - pindexWalk - > nHeight , std : : max < int > ( count - vBlocks . size ( ) , 128 ) ) ;
vToFetch . resize ( nToFetch ) ;
pindexWalk = state - > pindexBestKnownBlock - > GetAncestor ( pindexWalk - > nHeight + nToFetch ) ;
vToFetch [ nToFetch - 1 ] = pindexWalk ;
for ( unsigned int i = nToFetch - 1 ; i > 0 ; i - - ) {
vToFetch [ i - 1 ] = vToFetch [ i ] - > pprev ;
}
// Iterate over those blocks in vToFetch (in forward direction), adding the ones that
// are not yet downloaded and not in flight to vBlocks. In the mean time, update
2015-06-04 13:00:26 -04:00
// pindexLastCommonBlock as long as all ancestors are already downloaded, or if it's
// already part of our chain (and therefore don't need it even if pruned).
2018-12-30 15:33:11 +01:00
for ( CBlockIndex * pindex : vToFetch ) {
2014-12-11 13:35:14 +01:00
if ( ! pindex - > IsValid ( BLOCK_VALID_TREE ) ) {
// We consider the chain that this peer is on invalid.
return ;
}
2015-06-04 13:00:26 -04:00
if ( pindex - > nStatus & BLOCK_HAVE_DATA | | chainActive . Contains ( pindex ) ) {
2014-07-12 00:02:35 +02:00
if ( pindex - > nChainTx )
state - > pindexLastCommonBlock = pindex ;
} else if ( mapBlocksInFlight . count ( pindex - > GetBlockHash ( ) ) = = 0 ) {
// The block is not already downloaded, and not yet in flight.
2014-10-14 15:41:23 -07:00
if ( pindex - > nHeight > nWindowEnd ) {
2014-07-12 00:02:35 +02:00
// We reached the end of the window.
if ( vBlocks . size ( ) = = 0 & & waitingfor ! = nodeid ) {
// We aren't able to fetch anything, but we would be if the download window was one larger.
nodeStaller = waitingfor ;
}
return ;
}
vBlocks . push_back ( pindex ) ;
if ( vBlocks . size ( ) = = count ) {
return ;
}
} else if ( waitingfor = = - 1 ) {
// This is the first already-in-flight block.
waitingfor = mapBlocksInFlight [ pindex - > GetBlockHash ( ) ] . first ;
}
}
}
}
2014-06-24 14:17:43 +02:00
} // anon namespace
2013-11-18 01:25:17 +01:00
bool GetNodeStateStats ( NodeId nodeid , CNodeStateStats & stats ) {
LOCK ( cs_main ) ;
CNodeState * state = State ( nodeid ) ;
2018-06-12 20:43:50 +02:00
if ( state = = nullptr )
2013-11-18 01:25:17 +01:00
return false ;
stats . nMisbehavior = state - > nMisbehavior ;
2014-06-23 00:00:26 +02:00
stats . nSyncHeight = state - > pindexBestKnownBlock ? state - > pindexBestKnownBlock - > nHeight : - 1 ;
2014-07-12 00:03:10 +02:00
stats . nCommonHeight = state - > pindexLastCommonBlock ? state - > pindexLastCommonBlock - > nHeight : - 1 ;
2018-12-30 15:33:11 +01:00
for ( const QueuedBlock & queue : state - > vBlocksInFlight ) {
2014-07-12 00:03:10 +02:00
if ( queue . pindex )
stats . vHeightInFlight . push_back ( queue . pindex - > nHeight ) ;
}
2013-11-18 01:25:17 +01:00
return true ;
}
2013-06-05 20:21:41 -07:00
void RegisterNodeSignals ( CNodeSignals & nodeSignals )
{
2013-10-10 23:07:44 +02:00
nodeSignals . GetHeight . connect ( & GetHeight ) ;
2013-06-05 20:21:41 -07:00
nodeSignals . ProcessMessages . connect ( & ProcessMessages ) ;
nodeSignals . SendMessages . connect ( & SendMessages ) ;
2013-11-18 01:25:17 +01:00
nodeSignals . InitializeNode . connect ( & InitializeNode ) ;
nodeSignals . FinalizeNode . connect ( & FinalizeNode ) ;
2013-06-05 20:21:41 -07:00
}
void UnregisterNodeSignals ( CNodeSignals & nodeSignals )
{
2013-10-10 23:07:44 +02:00
nodeSignals . GetHeight . disconnect ( & GetHeight ) ;
2013-06-05 20:21:41 -07:00
nodeSignals . ProcessMessages . disconnect ( & ProcessMessages ) ;
nodeSignals . SendMessages . disconnect ( & SendMessages ) ;
2013-11-18 01:25:17 +01:00
nodeSignals . InitializeNode . disconnect ( & InitializeNode ) ;
nodeSignals . FinalizeNode . disconnect ( & FinalizeNode ) ;
2013-06-05 20:21:41 -07:00
}
2011-06-01 18:28:20 +02:00
2014-09-03 02:52:01 +02:00
CBlockIndex * FindForkInGlobalIndex ( const CChain & chain , const CBlockLocator & locator )
{
2013-10-12 15:18:08 +02:00
// Find the first block the caller has in the main chain
2018-12-30 15:33:11 +01:00
for ( const uint256 & hash : locator . vHave ) {
2018-01-15 15:26:12 +00:00
auto pindex = Blocks : : Index : : get ( hash ) ;
if ( pindex ) {
2014-09-03 02:52:01 +02:00
if ( chain . Contains ( pindex ) )
2013-10-12 15:18:08 +02:00
return pindex ;
}
}
2014-09-03 02:52:01 +02:00
return chain . Genesis ( ) ;
2014-05-06 00:54:10 +02:00
}
2013-04-13 00:13:08 -05:00
bool IsFinalTx ( const CTransaction & tx , int nBlockHeight , int64_t nBlockTime )
2013-01-08 04:17:15 -08:00
{
if ( tx . nLockTime = = 0 )
return true ;
2013-04-13 00:13:08 -05:00
if ( ( int64_t ) tx . nLockTime < ( ( int64_t ) tx . nLockTime < LOCKTIME_THRESHOLD ? ( int64_t ) nBlockHeight : nBlockTime ) )
2013-01-08 04:17:15 -08:00
return true ;
2018-12-30 15:33:11 +01:00
for ( const CTxIn & txin : tx . vin ) {
2015-12-07 15:44:16 -05:00
if ( ! ( txin . nSequence = = CTxIn : : SEQUENCE_FINAL ) )
2013-01-08 04:17:15 -08:00
return false ;
2015-12-07 15:44:16 -05:00
}
2013-01-08 04:17:15 -08:00
return true ;
}
2015-11-03 17:12:36 +00:00
bool CheckFinalTx ( const CTransaction & tx , int flags )
2015-05-25 00:48:33 -04:00
{
AssertLockHeld ( cs_main ) ;
2015-11-03 17:12:36 +00:00
// By convention a negative value for flags indicates that the
// current network-enforced consensus rules should be used. In
// a future soft-fork scenario that would mean checking which
// rules would be enforced for the next block and setting the
2018-01-15 15:26:12 +00:00
// appropriate flags.
2015-11-03 17:12:36 +00:00
flags = std : : max ( flags , 0 ) ;
// CheckFinalTx() uses chainActive.Height()+1 to evaluate
// nLockTime because when IsFinalTx() is called within
// CBlock::AcceptBlock(), the height of the block *being*
// evaluated is what is used. Thus if we want to know if a
// transaction can be part of the *next* block, we need to call
// IsFinalTx() with one more than chainActive.Height().
const int nBlockHeight = chainActive . Height ( ) + 1 ;
2015-11-13 16:36:54 -05:00
// BIP113 will require that time-locked transactions have nLockTime set to
// less than the median time of the previous block they're contained in.
// When the next block is created its previous block will be the current
// chain tip, so we use that to calculate the median time passed to
// IsFinalTx() if LOCKTIME_MEDIAN_TIME_PAST is set.
2015-11-03 17:12:36 +00:00
const int64_t nBlockTime = ( flags & LOCKTIME_MEDIAN_TIME_PAST )
? chainActive . Tip ( ) - > GetMedianTimePast ( )
: GetAdjustedTime ( ) ;
return IsFinalTx ( tx , nBlockHeight , nBlockTime ) ;
2015-05-25 00:48:33 -04:00
}
2015-12-07 15:44:16 -05:00
/**
* Calculates the block height and previous block's median time past at
* which the transaction will be considered final in the context of BIP 68.
* Also removes from the vector of input heights any entries which did not
* correspond to sequence locked inputs as they do not affect the calculation.
*/
static std : : pair < int , int64_t > CalculateSequenceLocks ( const CTransaction & tx , int flags , std : : vector < int > * prevHeights , const CBlockIndex & block )
{
assert ( prevHeights - > size ( ) = = tx . vin . size ( ) ) ;
// Will be set to the equivalent height- and time-based nLockTime
// values that would be necessary to satisfy all relative lock-
// time constraints given our view of block chain history.
// The semantics of nLockTime are the last invalid height/time, so
// use -1 to have the effect of any height or time being valid.
int nMinHeight = - 1 ;
int64_t nMinTime = - 1 ;
// tx.nVersion is signed integer so requires cast to unsigned otherwise
// we would be doing a signed comparison and half the range of nVersion
// wouldn't support BIP 68.
bool fEnforceBIP68 = static_cast < uint32_t > ( tx . nVersion ) > = 2
& & flags & LOCKTIME_VERIFY_SEQUENCE ;
// Do not enforce sequence numbers as a relative lock time
// unless we have been instructed to
if ( ! fEnforceBIP68 ) {
return std : : make_pair ( nMinHeight , nMinTime ) ;
}
for ( size_t txinIndex = 0 ; txinIndex < tx . vin . size ( ) ; txinIndex + + ) {
const CTxIn & txin = tx . vin [ txinIndex ] ;
// Sequence numbers with the most significant bit set are not
// treated as relative lock-times, nor are they given any
// consensus-enforced meaning at this point.
if ( txin . nSequence & CTxIn : : SEQUENCE_LOCKTIME_DISABLE_FLAG ) {
// The height of this input is not relevant for sequence locks
( * prevHeights ) [ txinIndex ] = 0 ;
continue ;
}
int nCoinHeight = ( * prevHeights ) [ txinIndex ] ;
if ( txin . nSequence & CTxIn : : SEQUENCE_LOCKTIME_TYPE_FLAG ) {
int64_t nCoinTime = block . GetAncestor ( std : : max ( nCoinHeight - 1 , 0 ) ) - > GetMedianTimePast ( ) ;
// NOTE: Subtract 1 to maintain nLockTime semantics
// BIP 68 relative lock times have the semantics of calculating
// the first block or time at which the transaction would be
// valid. When calculating the effective block time or height
// for the entire transaction, we switch to using the
// semantics of nLockTime which is the last invalid block
// time or height. Thus we subtract 1 from the calculated
// time or height.
// Time-based relative lock-times are measured from the
// smallest allowed timestamp of the block containing the
// txout being spent, which is the median time past of the
// block prior.
nMinTime = std : : max ( nMinTime , nCoinTime + ( int64_t ) ( ( txin . nSequence & CTxIn : : SEQUENCE_LOCKTIME_MASK ) < < CTxIn : : SEQUENCE_LOCKTIME_GRANULARITY ) - 1 ) ;
} else {
nMinHeight = std : : max ( nMinHeight , nCoinHeight + ( int ) ( txin . nSequence & CTxIn : : SEQUENCE_LOCKTIME_MASK ) - 1 ) ;
}
}
return std : : make_pair ( nMinHeight , nMinTime ) ;
}
static bool EvaluateSequenceLocks ( const CBlockIndex & block , std : : pair < int , int64_t > lockPair )
{
assert ( block . pprev ) ;
int64_t nBlockTime = block . pprev - > GetMedianTimePast ( ) ;
if ( lockPair . first > = block . nHeight | | lockPair . second > = nBlockTime )
return false ;
return true ;
}
bool SequenceLocks ( const CTransaction & tx , int flags , std : : vector < int > * prevHeights , const CBlockIndex & block )
{
return EvaluateSequenceLocks ( block , CalculateSequenceLocks ( tx , flags , prevHeights , block ) ) ;
}
2015-12-04 15:01:22 -05:00
bool TestLockPointValidity ( const LockPoints * lp )
{
AssertLockHeld ( cs_main ) ;
assert ( lp ) ;
// If there are relative lock times then the maxInputBlock will be set
// If there are no relative lock times, the LockPoints don't depend on the chain
if ( lp - > maxInputBlock ) {
// Check whether chainActive is an extension of the block at which the LockPoints
// calculation was valid. If not LockPoints are no longer valid
if ( ! chainActive . Contains ( lp - > maxInputBlock ) ) {
return false ;
}
}
// LockPoints still valid
return true ;
}
2018-01-15 15:26:12 +00:00
bool CheckSequenceLocks ( CTxMemPool & mp , const CTransaction & tx , int flags , LockPoints * lp , bool useExistingLockPoints , CBlockIndex * tip )
2015-12-07 15:44:16 -05:00
{
2018-01-15 15:26:12 +00:00
if ( ! tip ) {
AssertLockHeld ( cs_main ) ;
tip = chainActive . Tip ( ) ;
}
2015-12-07 15:44:16 -05:00
CBlockIndex index ;
index . pprev = tip ;
// CheckSequenceLocks() uses chainActive.Height()+1 to evaluate
// height based locks because when SequenceLocks() is called within
2016-02-11 15:34:04 -05:00
// ConnectBlock(), the height of the block *being*
// evaluated is what is used.
// Thus if we want to know if a transaction can be part of the
// *next* block, we need to use one more than chainActive.Height()
2015-12-07 15:44:16 -05:00
index . nHeight = tip - > nHeight + 1 ;
2015-12-04 15:01:22 -05:00
std : : pair < int , int64_t > lockPair ;
if ( useExistingLockPoints ) {
assert ( lp ) ;
lockPair . first = lp - > height ;
lockPair . second = lp - > time ;
}
else {
std : : vector < int > prevheights ;
prevheights . resize ( tx . vin . size ( ) ) ;
for ( size_t txinIndex = 0 ; txinIndex < tx . vin . size ( ) ; txinIndex + + ) {
const CTxIn & txin = tx . vin [ txinIndex ] ;
2018-07-23 18:05:43 +02:00
Tx prevTx ;
if ( mp . lookup ( txin . prevout . hash , prevTx ) ) {
2015-12-04 15:01:22 -05:00
// Assume all mempool transaction confirm in the next block
prevheights [ txinIndex ] = tip - > nHeight + 1 ;
} else {
2018-07-23 18:05:43 +02:00
// try UTXO
UnspentOutput output = g_utxo - > find ( txin . prevout . hash , txin . prevout . n ) ;
if ( ! output . isValid ( ) )
return error ( " %s: Missing input " , __func__ ) ;
prevheights [ txinIndex ] = output . blockHeight ( ) ;
2015-12-04 15:01:22 -05:00
}
2015-12-07 15:44:16 -05:00
}
2015-12-04 15:01:22 -05:00
lockPair = CalculateSequenceLocks ( tx , flags , & prevheights , index ) ;
if ( lp ) {
lp - > height = lockPair . first ;
lp - > time = lockPair . second ;
// Also store the hash of the block with the highest height of
// all the blocks which have sequence locked prevouts.
// This hash needs to still be on the chain
// for these LockPoint calculations to be valid
// Note: It is impossible to correctly calculate a maxInputBlock
// if any of the sequence locked inputs depend on unconfirmed txs,
// except in the special case where the relative lock time/height
// is 0, which is equivalent to no sequence lock. Since we assume
// input height of tip+1 for mempool txs and test the resulting
// lockPair from CalculateSequenceLocks against tip+1. We know
// EvaluateSequenceLocks will fail if there was a non-zero sequence
// lock on a mempool input, so we can use the return value of
// CheckSequenceLocks to indicate the LockPoints validity
int maxInputHeight = 0 ;
2018-12-30 15:33:11 +01:00
for ( int height : prevheights ) {
2015-12-04 15:01:22 -05:00
// Can ignore mempool inputs since we'll fail if they had non-zero locks
if ( height ! = tip - > nHeight + 1 ) {
maxInputHeight = std : : max ( maxInputHeight , height ) ;
}
}
lp - > maxInputBlock = tip - > GetAncestor ( maxInputHeight ) ;
2015-12-07 15:44:16 -05:00
}
}
return EvaluateSequenceLocks ( index , lockPair ) ;
}
2013-01-08 04:17:15 -08:00
bool CheckTransaction ( const CTransaction & tx , CValidationState & state )
2010-09-30 16:23:07 +00:00
{
// Basic checks that don't depend on any context
2013-01-08 04:17:15 -08:00
if ( tx . vin . empty ( ) )
2015-08-06 09:59:09 +02:00
return state . DoS ( 10 , false , REJECT_INVALID , " bad-txns-vin-empty " ) ;
2013-01-08 04:17:15 -08:00
if ( tx . vout . empty ( ) )
2015-08-06 09:59:09 +02:00
return state . DoS ( 10 , false , REJECT_INVALID , " bad-txns-vout-empty " ) ;
2010-09-30 16:23:07 +00:00
// Size limits
2017-08-14 15:01:24 +02:00
if ( : : GetSerializeSize ( tx , SER_NETWORK , PROTOCOL_VERSION ) > MAX_TX_SIZE )
2015-08-06 09:59:09 +02:00
return state . DoS ( 100 , false , REJECT_INVALID , " bad-txns-oversize " ) ;
2010-09-30 16:23:07 +00:00
// Check for negative or overflow output values
2014-04-22 15:46:19 -07:00
CAmount nValueOut = 0 ;
2018-12-30 15:33:11 +01:00
for ( const CTxOut & txout : tx . vout ) {
2010-09-30 16:23:07 +00:00
if ( txout . nValue < 0 )
2015-08-06 09:59:09 +02:00
return state . DoS ( 100 , false , REJECT_INVALID , " bad-txns-vout-negative " ) ;
2010-09-30 16:23:07 +00:00
if ( txout . nValue > MAX_MONEY )
2015-08-06 09:59:09 +02:00
return state . DoS ( 100 , false , REJECT_INVALID , " bad-txns-vout-toolarge " ) ;
2010-09-30 16:23:07 +00:00
nValueOut + = txout . nValue ;
if ( ! MoneyRange ( nValueOut ) )
2015-08-06 09:59:09 +02:00
return state . DoS ( 100 , false , REJECT_INVALID , " bad-txns-txouttotal-toolarge " ) ;
2010-09-30 16:23:07 +00:00
}
2011-07-30 23:01:45 +02:00
// Check for duplicate inputs
2017-08-15 10:24:20 -06:00
std : : set < COutPoint > vInOutPoints ;
2018-12-30 15:33:11 +01:00
for ( const CTxIn & txin : tx . vin ) {
2011-07-30 23:01:45 +02:00
if ( vInOutPoints . count ( txin . prevout ) )
2015-08-06 09:59:09 +02:00
return state . DoS ( 100 , false , REJECT_INVALID , " bad-txns-inputs-duplicate " ) ;
2011-07-30 23:01:45 +02:00
vInOutPoints . insert ( txin . prevout ) ;
}
2013-01-08 04:17:15 -08:00
if ( tx . IsCoinBase ( ) )
2010-09-30 16:23:07 +00:00
{
2013-01-08 04:17:15 -08:00
if ( tx . vin [ 0 ] . scriptSig . size ( ) < 2 | | tx . vin [ 0 ] . scriptSig . size ( ) > 100 )
2015-08-06 09:59:09 +02:00
return state . DoS ( 100 , false , REJECT_INVALID , " bad-cb-length " ) ;
2010-09-30 16:23:07 +00:00
}
else
{
2018-12-30 15:33:11 +01:00
for ( const CTxIn & txin : tx . vin )
2010-09-30 16:23:07 +00:00
if ( txin . prevout . IsNull ( ) )
2015-08-06 09:59:09 +02:00
return state . DoS ( 10 , false , REJECT_INVALID , " bad-txns-prevout-null " ) ;
2010-09-30 16:23:07 +00:00
}
return true ;
}
2015-10-22 11:52:55 -07:00
void LimitMempoolSize ( CTxMemPool & pool , size_t limit , unsigned long age ) {
int expired = pool . Expire ( GetTime ( ) - age ) ;
if ( expired ! = 0 )
LogPrint ( " mempool " , " Expired %i transactions from the memory pool \n " , expired ) ;
2018-07-23 18:05:43 +02:00
pool . TrimToSize ( limit , nullptr ) ;
2015-10-22 11:52:55 -07:00
}
2010-08-29 16:58:15 +00:00
//////////////////////////////////////////////////////////////////////////////
//
// CBlock and CBlockIndex
//
2015-04-17 14:19:21 +02:00
bool ReadBlockFromDisk ( CBlock & block , const CDiskBlockPos & pos , const Consensus : : Params & consensusParams )
2013-06-23 18:21:33 -07:00
{
block . SetNull ( ) ;
// Open history file to read
2018-01-15 15:26:12 +00:00
FastBlock fb = Blocks : : DB : : instance ( ) - > loadBlock ( pos ) ;
if ( fb . size ( ) = = 0 ) {
LogPrintf ( " ReadBlockFromDisk: Unable to open file %d \n " , pos . nFile ) ;
return false ;
}
2013-06-23 18:21:33 -07:00
// Read block
try {
2018-01-15 15:26:12 +00:00
block = fb . createOldBlock ( ) ;
2013-06-23 18:21:33 -07:00
}
2014-12-07 13:29:06 +01:00
catch ( const std : : exception & e ) {
2015-01-26 09:47:59 +01:00
return error ( " %s: Deserialize or I/O error - %s at %s " , __func__ , e . what ( ) , pos . ToString ( ) ) ;
2013-06-23 18:21:33 -07:00
}
// Check the header
2015-04-17 14:19:21 +02:00
if ( ! CheckProofOfWork ( block . GetHash ( ) , block . nBits , consensusParams ) )
2015-01-26 09:47:59 +01:00
return error ( " ReadBlockFromDisk: Errors in block header at %s " , pos . ToString ( ) ) ;
2013-06-23 18:21:33 -07:00
return true ;
}
2015-04-17 14:19:21 +02:00
bool ReadBlockFromDisk ( CBlock & block , const CBlockIndex * pindex , const Consensus : : Params & consensusParams )
2010-08-29 16:58:15 +00:00
{
2015-04-17 14:19:21 +02:00
if ( ! ReadBlockFromDisk ( block , pindex - > GetBlockPos ( ) , consensusParams ) )
2010-08-29 16:58:15 +00:00
return false ;
2013-06-23 18:10:02 -07:00
if ( block . GetHash ( ) ! = pindex - > GetBlockHash ( ) )
2015-01-26 09:47:59 +01:00
return error ( " ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s " ,
pindex - > ToString ( ) , pindex - > GetBlockPos ( ) . ToString ( ) ) ;
2010-08-29 16:58:15 +00:00
return true ;
}
2015-04-01 16:03:11 +02:00
CAmount GetBlockSubsidy ( int nHeight , const Consensus : : Params & consensusParams )
2010-08-29 16:58:15 +00:00
{
2015-04-01 16:03:11 +02:00
int halvings = nHeight / consensusParams . nSubsidyHalvingInterval ;
2014-03-10 19:02:36 -05:00
// Force block reward to zero when right shift is undefined.
if ( halvings > = 64 )
2015-04-01 16:03:11 +02:00
return 0 ;
2010-08-29 16:58:15 +00:00
2015-04-01 16:03:11 +02:00
CAmount nSubsidy = 50 * COIN ;
2013-05-07 15:16:25 +02:00
// Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years.
2014-03-10 19:02:36 -05:00
nSubsidy > > = halvings ;
2015-04-01 16:03:11 +02:00
return nSubsidy ;
2010-08-29 16:58:15 +00:00
}
bool IsInitialBlockDownload ( )
{
2018-01-15 15:26:12 +00:00
if ( Blocks : : DB : : instance ( ) - > isReindexing ( ) )
2015-04-22 23:22:36 -04:00
return true ;
2019-08-05 22:40:33 +02:00
return Blocks : : DB : : instance ( ) - > headerChain ( ) . Height ( ) - chainActive . Height ( ) > 1000 ;
2010-08-29 16:58:15 +00:00
}
2018-01-15 15:26:12 +00:00
void AlertNotify ( const std : : string & strMessage , bool fThread )
2016-03-07 19:44:09 +00:00
{
uiInterface . NotifyAlertChanged ( ) ;
std : : string strCmd = GetArg ( " -alertnotify " , " " ) ;
if ( strCmd . empty ( ) ) return ;
// Alert text should be plain ascii coming from a trusted source, but to
// be safe we first strip anything not in safeChars, then add single quotes around
// the whole string before passing it to the shell:
std : : string singleQuote ( " ' " ) ;
std : : string safeStatus = SanitizeString ( strMessage ) ;
safeStatus = singleQuote + safeStatus + singleQuote ;
boost : : replace_all ( strCmd , " %s " , safeStatus ) ;
if ( fThread )
boost : : thread t ( runCommand , strCmd ) ; // thread runs free
else
runCommand ( strCmd ) ;
}
2014-01-10 13:23:26 +01:00
// Requires cs_main.
2017-04-20 10:21:56 +02:00
void Misbehaving ( NodeId nodeId , int howmuch )
2013-11-16 19:28:24 +01:00
{
if ( howmuch = = 0 )
return ;
2017-04-20 10:21:56 +02:00
CNodeState * state = State ( nodeId ) ;
2018-06-12 20:43:50 +02:00
if ( state = = nullptr )
2013-11-16 19:28:24 +01:00
return ;
state - > nMisbehavior + = howmuch ;
2018-02-12 14:15:24 +01:00
int banscore = GetArg ( " -banscore " , Settings : : DefaultBanscoreThreshold ) ;
2018-01-15 15:26:12 +00:00
if ( ! state - > fShouldBan & & state - > nMisbehavior > = banscore & & state - > nMisbehavior - howmuch < banscore ) {
2017-08-29 11:42:11 +02:00
logCritical ( Log : : Net ) < < " Id: " < < nodeId < < state - > nMisbehavior - howmuch < < " => " < < state - > nMisbehavior
< < " Ban threshold exceeded " ;
2013-11-16 19:28:24 +01:00
state - > fShouldBan = true ;
2017-10-06 16:34:20 +02:00
addrman . increaseUselessness ( state - > address , 2 ) ;
2017-04-20 10:21:56 +02:00
} else {
2017-08-29 11:42:11 +02:00
logWarning ( Log : : Net ) < < " Misbehaving " < < " Id: " < < nodeId < < state - > nMisbehavior - howmuch < < " => " < < state - > nMisbehavior ;
2017-04-20 10:21:56 +02:00
}
2013-11-16 19:28:24 +01:00
}
2018-01-15 15:26:12 +00:00
void queueRejectMessage ( int peerId , const uint256 & blockHash , uint8_t rejectCode , const std : : string & rejectReason )
2010-08-29 16:58:15 +00:00
{
2018-01-15 15:26:12 +00:00
LOCK ( cs_main ) ;
auto state = State ( peerId ) ;
if ( state ) {
CBlockReject reject = { rejectCode , rejectReason . substr ( 0 , MAX_REJECT_MESSAGE_LENGTH ) , blockHash } ;
state - > rejects . push_back ( reject ) ;
2013-11-16 19:28:24 +01:00
}
2012-08-19 00:33:01 +02:00
}
2015-01-16 18:57:14 -05:00
/** Abort with a message */
bool AbortNode ( const std : : string & strMessage , const std : : string & userMessage = " " )
{
strMiscWarning = strMessage ;
LogPrintf ( " *** %s \n " , strMessage ) ;
uiInterface . ThreadSafeMessageBox (
2018-11-21 12:18:32 +01:00
userMessage . empty ( ) ? _ ( " Error: A fatal internal error occurred, see hub.log for details " ) : userMessage ,
2015-01-16 18:57:14 -05:00
" " , CClientUIInterface : : MSG_ERROR ) ;
StartShutdown ( ) ;
return false ;
}
bool AbortNode ( CValidationState & state , const std : : string & strMessage , const std : : string & userMessage = " " )
{
AbortNode ( strMessage , userMessage ) ;
return state . Error ( strMessage ) ;
}
2018-01-15 15:26:12 +00:00
bool FlushStateToDisk ( CValidationState & state , FlushStateMode mode ) {
2015-02-23 14:27:44 -05:00
LOCK2 ( cs_main , cs_LastBlockFile ) ;
2013-11-16 19:28:24 +01:00
static int64_t nLastWrite = 0 ;
2015-05-04 22:00:19 +02:00
static int64_t nLastFlush = 0 ;
static int64_t nLastSetChain = 0 ;
2015-01-04 19:11:44 +01:00
try {
2015-05-04 22:00:19 +02:00
int64_t nNow = GetTimeMicros ( ) ;
// Avoid writing/flushing immediately after startup.
if ( nLastWrite = = 0 ) {
nLastWrite = nNow ;
}
if ( nLastFlush = = 0 ) {
nLastFlush = nNow ;
}
if ( nLastSetChain = = 0 ) {
nLastSetChain = nNow ;
}
// 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.
bool fPeriodicWrite = mode = = FLUSH_STATE_PERIODIC & & nNow > nLastWrite + ( int64_t ) DATABASE_WRITE_INTERVAL * 1000000 ;
// It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage.
bool fPeriodicFlush = mode = = FLUSH_STATE_PERIODIC & & nNow > nLastFlush + ( int64_t ) DATABASE_FLUSH_INTERVAL * 1000000 ;
// Combine all conditions that result in a full cache flush.
2019-04-22 19:47:07 +02:00
bool fDoFullFlush = ( mode = = FLUSH_STATE_ALWAYS ) | | fPeriodicFlush ;
2015-05-04 22:00:19 +02:00
// Write blocks and block index to disk.
if ( fDoFullFlush | | fPeriodicWrite ) {
2015-05-11 11:18:39 -04:00
// Depend on nMinDiskSpace to ensure we can write block index
if ( ! CheckDiskSpace ( 0 ) )
2012-09-10 02:02:35 +00:00
return state . Error ( " out of disk space " ) ;
2014-11-07 02:38:35 -08:00
// First make sure all block and undo data is flushed to disk.
// Then update all block file information (which may refer to block and undo files).
2014-11-25 16:26:20 +01:00
{
std : : vector < std : : pair < int , const CBlockFileInfo * > > vFiles ;
vFiles . reserve ( setDirtyFileInfo . size ( ) ) ;
2017-08-15 10:24:20 -06:00
for ( std : : set < int > : : iterator it = setDirtyFileInfo . begin ( ) ; it ! = setDirtyFileInfo . end ( ) ; ) {
vFiles . push_back ( std : : make_pair ( * it , & vinfoBlockFile [ * it ] ) ) ;
2014-11-25 16:26:20 +01:00
setDirtyFileInfo . erase ( it + + ) ;
}
std : : vector < const CBlockIndex * > vBlocks ;
vBlocks . reserve ( setDirtyBlockIndex . size ( ) ) ;
2017-08-15 10:24:20 -06:00
for ( std : : set < CBlockIndex * > : : iterator it = setDirtyBlockIndex . begin ( ) ; it ! = setDirtyBlockIndex . end ( ) ; ) {
2014-11-25 16:26:20 +01:00
vBlocks . push_back ( * it ) ;
setDirtyBlockIndex . erase ( it + + ) ;
}
2019-03-09 22:34:47 +01:00
if ( Blocks : : DB : : instance ( ) ) { // only when we actually finished init
if ( ! Blocks : : DB : : instance ( ) - > WriteBatchSync ( vFiles , nLastBlockFile , vBlocks ) )
return AbortNode ( state , " Files to write to block index database " ) ;
2014-11-07 02:38:35 -08:00
}
}
2015-05-04 22:00:19 +02:00
nLastWrite = nNow ;
}
// Flush best chain related state. This can only be done if the blocks / block index write was also done.
if ( fDoFullFlush ) {
2018-07-23 18:05:43 +02:00
if ( ! CheckDiskSpace ( 50000000 ) )
2015-05-11 11:18:39 -04:00
return state . Error ( " out of disk space " ) ;
2015-05-04 22:00:19 +02:00
nLastFlush = nNow ;
}
2016-02-10 15:47:06 +01:00
if ( fDoFullFlush | | ( ( mode = = FLUSH_STATE_ALWAYS | | mode = = FLUSH_STATE_PERIODIC ) & & nNow > nLastSetChain + ( int64_t ) DATABASE_WRITE_INTERVAL * 1000000 ) ) {
2014-11-07 02:38:35 -08:00
// Update best block in wallet (so we can detect restored wallets).
2018-02-15 18:06:38 +01:00
ValidationNotifier ( ) . SetBestChain ( chainActive . GetLocator ( ) ) ;
2015-05-04 22:00:19 +02:00
nLastSetChain = nNow ;
2012-09-06 03:21:18 +02:00
}
2015-01-04 19:11:44 +01:00
} catch ( const std : : runtime_error & e ) {
2015-01-16 18:57:14 -05:00
return AbortNode ( state , std : : string ( " System error while flushing: " ) + e . what ( ) ) ;
2015-01-04 19:11:44 +01:00
}
2013-11-16 18:40:55 +01:00
return true ;
}
2012-07-01 18:54:00 +02:00
2014-11-07 02:38:35 -08:00
void FlushStateToDisk ( ) {
CValidationState state ;
2014-11-14 18:19:26 +01:00
FlushStateToDisk ( state , FLUSH_STATE_ALWAYS ) ;
2014-11-07 02:38:35 -08:00
}
2014-03-11 17:36:21 +01:00
bool CheckBlockHeader ( const CBlockHeader & block , CValidationState & state , bool fCheckPOW )
2010-08-29 16:58:15 +00:00
{
2010-09-19 21:20:34 +00:00
// Check proof of work matches claimed amount
2015-02-15 02:21:42 +01:00
if ( fCheckPOW & & ! CheckProofOfWork ( block . GetHash ( ) , block . nBits , Params ( ) . GetConsensus ( ) ) )
2015-01-08 11:44:25 +01:00
return state . DoS ( 50 , error ( " CheckBlockHeader(): proof of work failed " ) ,
2012-09-10 02:02:35 +00:00
REJECT_INVALID , " high-hash " ) ;
2010-09-19 21:20:34 +00:00
2010-08-29 16:58:15 +00:00
// Check timestamp
2013-06-23 19:14:11 -07:00
if ( block . GetBlockTime ( ) > GetAdjustedTime ( ) + 2 * 60 * 60 )
2015-01-08 11:44:25 +01:00
return state . Invalid ( error ( " CheckBlockHeader(): block timestamp too far in the future " ) ,
2012-09-10 02:02:35 +00:00
REJECT_INVALID , " time-too-new " ) ;
2010-08-29 16:58:15 +00:00
2014-03-11 17:36:21 +01:00
return true ;
}
2013-04-13 00:13:08 -05:00
bool CheckDiskSpace ( uint64_t nAdditionalBytes )
2010-08-29 16:58:15 +00:00
{
2014-12-19 15:21:29 -05:00
uint64_t nFreeBytesAvailable = boost : : filesystem : : space ( GetDataDir ( ) ) . available ;
2010-08-29 16:58:15 +00:00
2012-05-14 07:49:17 +02:00
// Check for nMinDiskSpace bytes (currently 50MB)
if ( nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes )
2014-10-02 22:17:57 +02:00
return AbortNode ( " Disk space is low! " , _ ( " Error: Disk space is low! " ) ) ;
2013-01-27 01:24:06 +01:00
2010-08-29 16:58:15 +00:00
return true ;
}
2020-02-27 13:35:56 +01:00
bool LoadBlockIndexDB ( const UnspentOutputDatabase * utxo )
2012-09-03 21:14:03 +02:00
{
2020-02-27 13:35:56 +01:00
if ( ! Blocks : : DB : : instance ( ) - > CacheAllBlockInfos ( utxo ) )
2012-09-03 21:14:03 +02:00
return false ;
// Load block file info
2018-01-15 15:26:12 +00:00
if ( Blocks : : DB : : instance ( ) - > ReadLastBlockFile ( nLastBlockFile ) ) {
vinfoBlockFile . resize ( nLastBlockFile + 1 ) ;
logInfo ( Log : : DB ) < < " last block file: " < < nLastBlockFile ;
for ( int nFile = 0 ; nFile < = nLastBlockFile ; nFile + + ) {
Blocks : : DB : : instance ( ) - > ReadBlockFileInfo ( nFile , vinfoBlockFile [ nFile ] ) ;
}
logInfo ( Log : : DB ) < < " last block file info: " < < vinfoBlockFile [ nLastBlockFile ] . ToString ( ) ;
for ( int nFile = nLastBlockFile + 1 ; true ; nFile + + ) {
CBlockFileInfo info ;
if ( Blocks : : DB : : instance ( ) - > ReadBlockFileInfo ( nFile , info ) ) {
vinfoBlockFile . push_back ( info ) ;
} else {
break ;
}
2014-09-25 08:21:21 +02:00
}
}
2012-10-05 19:22:21 +02:00
2014-05-11 07:05:04 -05:00
// Check presence of blk files
2018-01-15 15:26:12 +00:00
logInfo ( Log : : DB ) < < " Checking all blk files are present... " ;
std : : set < int > setBlkDataFiles = Blocks : : Index : : fileIndexes ( ) ;
2020-02-27 13:35:56 +01:00
for ( std : : set < int > : : iterator it = setBlkDataFiles . begin ( ) ; it ! = setBlkDataFiles . end ( ) ; it + + ) {
2018-01-15 15:26:12 +00:00
Streaming : : ConstBuffer dataFile = Blocks : : DB : : instance ( ) - > loadBlockFile ( * it ) ;
if ( ! dataFile . isValid ( ) )
2014-05-11 07:05:04 -05:00
return false ;
}
2013-01-03 15:29:07 +01:00
return true ;
}
2013-02-16 17:58:45 +01:00
void UnloadBlockIndex ( )
{
2015-03-03 07:49:12 -08:00
LOCK ( cs_main ) ;
2018-06-12 20:43:50 +02:00
chainActive . SetTip ( nullptr ) ;
pindexBestHeader = nullptr ;
2015-03-03 07:49:12 -08:00
mempool . clear ( ) ;
2017-02-08 17:17:38 +01:00
CTxOrphanCache : : clear ( ) ;
2015-03-03 07:49:12 -08:00
nSyncStarted = 0 ;
vinfoBlockFile . clear ( ) ;
nLastBlockFile = 0 ;
nBlockSequenceId = 1 ;
mapBlockSource . clear ( ) ;
mapBlocksInFlight . clear ( ) ;
nPreferredDownload = 0 ;
setDirtyBlockIndex . clear ( ) ;
setDirtyFileInfo . clear ( ) ;
mapNodeState . clear ( ) ;
2018-06-12 20:43:50 +02:00
recentRejects . reset ( nullptr ) ;
2015-03-03 07:49:12 -08:00
2018-01-15 15:26:12 +00:00
Blocks : : Index : : unload ( ) ;
2013-02-16 17:58:45 +01:00
}
2016-05-23 10:19:12 +01:00
bool InitBlockIndex ( const CChainParams & chainparams )
2015-04-17 14:40:24 +02:00
{
2015-07-31 17:55:05 +02:00
// Initialize global variables that cannot be constructed at startup.
recentRejects . reset ( new CRollingBloomFilter ( 120000 , 0.000001 ) ) ;
2013-01-30 21:43:36 +01:00
// Check whether we're already initialized
2018-06-12 20:43:50 +02:00
if ( chainActive . Genesis ( ) ! = nullptr )
2013-01-30 21:43:36 +01:00
return true ;
2019-04-22 20:33:35 +02:00
logCritical ( Log : : Bitcoin ) < < " Initializing databases... " ;
2013-01-30 21:43:36 +01:00
// Only add the genesis block if not reindexing (in which case we reuse the one already on disk)
2017-02-27 17:22:39 +01:00
if ( ! Blocks : : DB : : instance ( ) - > isReindexing ( ) ) {
2018-01-15 15:26:12 +00:00
CBlock & block = const_cast < CBlock & > ( chainparams . GenesisBlock ( ) ) ;
auto * bv = Application : : instance ( ) - > validation ( ) ;
auto future = bv - > addBlock ( FastBlock : : fromOldBlock ( block ) , Validation : : SaveGoodToDisk ) . start ( ) ;
future . waitUntilFinished ( ) ;
if ( ! future . error ( ) . empty ( ) ) {
logCritical ( Log : : Bitcoin ) < < " Failed to add the genesisblock due to: " < < future . error ( ) ;
return false ;
2013-01-30 21:43:36 +01:00
}
2018-01-15 15:26:12 +00:00
// Force a chainstate write so that when we VerifyDB in a moment, it doesn't check stale data
CValidationState state ;
return FlushStateToDisk ( state , FLUSH_STATE_ALWAYS ) ;
2010-08-29 16:58:15 +00:00
}
return true ;
}
2015-05-31 15:36:44 +02:00
std : : string GetWarnings ( const std : : string & strFor )
2010-08-29 16:58:15 +00:00
{
2017-08-15 10:24:20 -06:00
std : : string strStatusBar ;
std : : string strRPC ;
std : : string strGUI ;
2012-10-24 21:47:07 +02:00
2015-12-01 09:47:13 +01:00
if ( ! CLIENT_VERSION_IS_RELEASE ) {
strStatusBar = " This is a pre-release test build - use at your own risk - do not use for mining or merchant applications " ;
strGUI = _ ( " This is a pre-release test build - use at your own risk - do not use for mining or merchant applications " ) ;
}
2012-10-24 21:47:07 +02:00
2018-02-12 14:15:24 +01:00
if ( GetBoolArg ( " -testsafemode " , Settings : : DefaultTestSafeMode ) )
2015-12-01 09:47:13 +01:00
strStatusBar = strRPC = strGUI = " testsafemode enabled " ;
2014-11-23 13:10:31 +01:00
2010-08-29 16:58:15 +00:00
// Misc warnings like out of disk space and clock is wrong
if ( strMiscWarning ! = " " )
{
2015-12-01 09:47:13 +01:00
strStatusBar = strGUI = strMiscWarning ;
2010-08-29 16:58:15 +00:00
}
2015-12-01 09:47:13 +01:00
if ( strFor = = " gui " )
return strGUI ;
else if ( strFor = = " statusbar " )
2010-08-29 16:58:15 +00:00
return strStatusBar ;
else if ( strFor = = " rpc " )
return strRPC ;
2015-01-08 11:44:25 +01:00
assert ( ! " GetWarnings(): invalid parameter " ) ;
2010-08-29 16:58:15 +00:00
return " error " ;
}
//////////////////////////////////////////////////////////////////////////////
//
// Messages
//
2015-06-16 04:08:26 -04:00
bool static AlreadyHave ( const CInv & inv ) EXCLUSIVE_LOCKS_REQUIRED ( cs_main )
2010-08-29 16:58:15 +00:00
{
switch ( inv . type )
{
2018-01-15 15:26:12 +00:00
case MSG_TX : {
2018-01-16 16:40:34 +00:00
auto validation = flApp - > validation ( ) ;
2018-01-15 15:26:12 +00:00
if ( validation - > isRecentlyRejectedTransaction ( inv . hash ) )
return true ;
return validation - > mempool ( ) - > exists ( inv . hash ) ;
2012-04-13 18:24:55 -04:00
}
case MSG_BLOCK :
2018-01-15 15:26:12 +00:00
return Blocks : : Index : : exists ( inv . hash ) ;
2019-09-02 23:35:14 +02:00
case MSG_DOUBLESPENDPROOF :
return mempool . doubleSpendProofStorage ( ) - > exists ( inv . hash )
| | mempool . doubleSpendProofStorage ( ) - > isRecentlyRejectedProof ( inv . hash ) ;
2010-08-29 16:58:15 +00:00
}
// Don't know what it is, just say we already got one
return true ;
}
2015-04-17 14:19:21 +02:00
void static ProcessGetData ( CNode * pfrom , const Consensus : : Params & consensusParams )
2013-03-29 23:49:38 +01:00
{
2018-01-15 15:26:12 +00:00
logDebug ( 106 ) < < pfrom - > vRecvGetData . size ( ) ;
2013-03-29 23:49:38 +01:00
std : : deque < CInv > : : iterator it = pfrom - > vRecvGetData . begin ( ) ;
2017-08-15 10:24:20 -06:00
std : : vector < CInv > vNotFound ;
2013-03-29 23:49:38 +01:00
2013-07-25 02:34:42 +02:00
LOCK ( cs_main ) ;
2013-03-29 23:49:38 +01:00
while ( it ! = pfrom - > vRecvGetData . end ( ) ) {
// Don't bother if send buffer is too full to respond anyway
if ( pfrom - > nSendSize > = SendBufferSize ( ) )
break ;
const CInv & inv = * it ;
2018-01-15 15:26:12 +00:00
logDebug ( 106 ) < < " + handling " < < inv . ToString ( ) ;
2013-03-29 23:49:38 +01:00
{
2013-03-09 12:02:57 -05:00
boost : : this_thread : : interruption_point ( ) ;
2013-03-29 23:49:38 +01:00
it + + ;
2016-04-25 14:36:03 +01:00
if ( inv . type = = MSG_BLOCK | | inv . type = = MSG_FILTERED_BLOCK
| | inv . type = = MSG_THINBLOCK | | inv . type = = MSG_XTHINBLOCK )
2013-03-29 23:49:38 +01:00
{
2014-01-19 17:59:57 -06:00
bool send = false ;
2018-01-15 15:26:12 +00:00
auto mi = Blocks : : Index : : get ( inv . hash ) ;
if ( mi ) {
if ( chainActive . Contains ( mi ) ) {
2014-02-10 16:31:06 +01:00
send = true ;
2015-02-24 04:27:25 -08:00
} else {
2015-03-17 06:35:59 -07:00
static const int nOneMonth = 30 * 24 * 60 * 60 ;
2015-02-24 04:27:25 -08:00
// To prevent fingerprinting attacks, only send blocks outside of the active
2015-03-17 06:35:59 -07:00
// chain if they are valid, and no more than a month older (both in time, and in
// best equivalent proof of work) than the best header chain we know about.
2018-06-12 20:43:50 +02:00
send = mi - > IsValid ( BLOCK_VALID_SCRIPTS ) & & ( pindexBestHeader ! = nullptr ) & &
2018-01-15 15:26:12 +00:00
( pindexBestHeader - > GetBlockTime ( ) - mi - > GetBlockTime ( ) < nOneMonth ) & &
( GetBlockProofEquivalentTime ( * pindexBestHeader , * mi , * pindexBestHeader , consensusParams ) < nOneMonth ) ;
2015-02-24 04:27:25 -08:00
if ( ! send ) {
2019-02-25 21:35:05 +01:00
logDebug ( Log : : Net ) < < " ProcessGetData ignoring request from peer "
< < pfrom - > GetId ( ) < < " for old block that isn't in the main chain " ;
2015-02-24 04:27:25 -08:00
}
2014-01-19 17:59:57 -06:00
}
}
2015-09-02 17:03:27 +02:00
// disconnect node in case we have reached the outbound limit for serving historical blocks
2015-11-11 10:10:48 +01:00
// never disconnect whitelisted nodes
2015-09-02 17:03:27 +02:00
static const int nOneWeek = 7 * 24 * 60 * 60 ; // assume > 1 week = historical
2018-06-12 20:43:50 +02:00
if ( send & & CNode : : OutboundTargetReached ( true ) & & ( ( ( pindexBestHeader ! = nullptr ) & & ( pindexBestHeader - > GetBlockTime ( ) - mi - > GetBlockTime ( ) > nOneWeek ) ) | | inv . type = = MSG_FILTERED_BLOCK ) & & ! pfrom - > fWhitelisted )
2015-09-02 17:03:27 +02:00
{
2019-02-25 21:35:05 +01:00
logCritical ( Log : : Net ) < < " historical block serving limit reached, disconnect peer " < < pfrom - > GetId ( ) ;
2015-09-02 17:03:27 +02:00
//disconnect node
pfrom - > fDisconnect = true ;
send = false ;
}
2015-02-23 14:27:44 -05:00
// Pruned nodes may have deleted the block, so check whether
// it's available before trying to send.
2018-01-15 15:26:12 +00:00
if ( send & & ( mi - > nStatus & BLOCK_HAVE_DATA ) )
2014-01-19 17:59:57 -06:00
{
2018-01-15 15:26:12 +00:00
logDebug ( 107 ) < < " requested block available " ;
2014-01-19 17:59:57 -06:00
// Send block from disk
2013-03-29 23:49:38 +01:00
CBlock block ;
2018-01-15 15:26:12 +00:00
if ( ! ReadBlockFromDisk ( block , mi , consensusParams ) )
2014-06-04 12:27:44 +02:00
assert ( ! " cannot load block from disk " ) ;
2016-01-15 21:37:25 -08:00
2016-07-08 16:05:57 +02:00
bool sendFullBlock = true ;
if ( inv . type = = MSG_XTHINBLOCK ) {
CXThinBlock xThinBlock ( block , pfrom - > pThinBlockFilter ) ;
if ( ! xThinBlock . collision ) {
const int nSizeBlock = : : GetSerializeSize ( block , SER_NETWORK , PROTOCOL_VERSION ) ;
// Only send a thinblock if smaller than a regular block
const int nSizeThinBlock = : : GetSerializeSize ( xThinBlock , SER_NETWORK , PROTOCOL_VERSION ) ;
if ( nSizeThinBlock < nSizeBlock ) {
pfrom - > PushMessage ( NetMsgType : : XTHINBLOCK , xThinBlock ) ;
sendFullBlock = false ;
2019-02-25 21:35:05 +01:00
logInfo ( Log : : ThinBlocks ) < < " Sent xthinblock - size: " < < nSizeThinBlock < < " vs block size: "
< < nSizeBlock < < " => tx hashes: " < < xThinBlock . vTxHashes . size ( )
< < " transactions: " < < xThinBlock . vMissingTx . size ( ) < < " peerid "
< < pfrom - > id ;
2016-07-08 16:05:57 +02:00
}
}
2016-07-06 20:16:18 +02:00
}
2016-07-08 16:05:57 +02:00
else if ( inv . type = = MSG_FILTERED_BLOCK )
2013-03-29 23:49:38 +01:00
{
LOCK ( pfrom - > cs_filter ) ;
if ( pfrom - > pfilter )
{
CMerkleBlock merkleBlock ( block , * pfrom - > pfilter ) ;
2015-12-07 15:31:32 +01:00
pfrom - > PushMessage ( NetMsgType : : MERKLEBLOCK , merkleBlock ) ;
2013-03-29 23:49:38 +01:00
// CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see
// This avoids hurting performance by pointlessly requiring a round-trip
2015-04-28 14:48:28 +00:00
// Note that there is currently no way for a node to request any single transactions we didn't send here -
2013-03-29 23:49:38 +01:00
// they must either disconnect and retry or request the full block.
// Thus, the protocol spec specified allows for us to provide duplicate txn here,
// however we MUST always provide at least what the remote peer needs
typedef std : : pair < unsigned int , uint256 > PairType ;
2018-12-30 15:33:11 +01:00
for ( PairType & pair : merkleBlock . vMatchedTxn )
2015-12-07 15:31:32 +01:00
pfrom - > PushMessage ( NetMsgType : : TX , block . vtx [ pair . first ] ) ;
2016-07-08 16:05:57 +02:00
sendFullBlock = false ;
2013-03-29 23:49:38 +01:00
}
}
2016-07-08 16:05:57 +02:00
if ( sendFullBlock ) // if none of the other methods were actually executed;
pfrom - > PushMessage ( NetMsgType : : BLOCK , block ) ;
2013-03-29 23:49:38 +01:00
2015-04-28 14:47:17 +00:00
// Trigger the peer node to send a getblocks request for the next batch of inventory
2013-03-29 23:49:38 +01:00
if ( inv . hash = = pfrom - > hashContinue )
{
// Bypass PushInventory, this must send even if redundant,
// and we want it right after the last block so they don't
// wait for other stuff first.
2017-08-15 10:24:20 -06:00
std : : vector < CInv > vInv ;
2013-10-10 23:07:44 +02:00
vInv . push_back ( CInv ( MSG_BLOCK , chainActive . Tip ( ) - > GetBlockHash ( ) ) ) ;
2015-12-07 15:31:32 +01:00
pfrom - > PushMessage ( NetMsgType : : INV , vInv ) ;
2014-12-15 09:11:16 +01:00
pfrom - > hashContinue . SetNull ( ) ;
2013-03-29 23:49:38 +01:00
}
}
}
2019-09-02 23:35:14 +02:00
else if ( inv . IsKnownType ( ) ) {
2013-03-29 23:49:38 +01:00
// Send stream from relay memory
bool pushed = false ;
{
LOCK ( cs_mapRelay ) ;
2017-08-15 10:24:20 -06:00
std : : map < CInv , CDataStream > : : iterator mi = mapRelay . find ( inv ) ;
2013-03-29 23:49:38 +01:00
if ( mi ! = mapRelay . end ( ) ) {
pfrom - > PushMessage ( inv . GetCommand ( ) , ( * mi ) . second ) ;
2019-11-22 19:01:43 +01:00
pushed = true ;
2013-03-29 23:49:38 +01:00
}
}
2019-11-22 19:01:43 +01:00
if ( ! pushed & & inv . type = = MSG_TX ) {
2013-08-27 15:51:57 +10:00
CTransaction tx ;
if ( mempool . lookup ( inv . hash , tx ) ) {
2013-03-29 23:49:38 +01:00
CDataStream ss ( SER_NETWORK , PROTOCOL_VERSION ) ;
ss . reserve ( 1000 ) ;
ss < < tx ;
2015-12-07 15:31:32 +01:00
pfrom - > PushMessage ( NetMsgType : : TX , ss ) ;
2013-03-29 23:49:38 +01:00
pushed = true ;
}
}
2019-09-02 23:35:14 +02:00
else if ( inv . type = = MSG_DOUBLESPENDPROOF ) {
DoubleSpendProof dsp = mempool . doubleSpendProofStorage ( ) - > lookup ( inv . hash ) ;
if ( ! dsp . isEmpty ( ) ) {
CDataStream ss ( SER_NETWORK , PROTOCOL_VERSION ) ;
ss . reserve ( 600 ) ;
ss < < dsp ;
pfrom - > PushMessage ( NetMsgType : : DSPROOF , ss ) ;
pushed = true ;
}
2013-03-29 23:49:38 +01:00
}
2019-09-02 23:35:14 +02:00
if ( ! pushed )
vNotFound . push_back ( inv ) ;
2013-03-29 23:49:38 +01:00
}
// Track requests for our stuff.
2018-02-15 18:06:38 +01:00
ValidationNotifier ( ) . Inventory ( inv . hash ) ;
2013-11-11 16:20:39 +01:00
2016-04-25 14:36:03 +01:00
if ( inv . type = = MSG_BLOCK | | inv . type = = MSG_FILTERED_BLOCK
| | inv . type = = MSG_THINBLOCK | | inv . type = = MSG_XTHINBLOCK )
2013-10-28 13:20:21 -07:00
break ;
2013-03-29 23:49:38 +01:00
}
}
pfrom - > vRecvGetData . erase ( pfrom - > vRecvGetData . begin ( ) , it ) ;
if ( ! vNotFound . empty ( ) ) {
// Let the peer know that we didn't find what it asked for, so it doesn't
// have to wait around forever. Currently only SPV clients actually care
// about this message: it's needed when they are recursively walking the
// dependencies of relevant unconfirmed transactions. SPV clients want to
// do that because they want to know about (and store and rebroadcast and
// risk analyze) the dependencies of transactions relevant to them, without
// having to download the entire memory pool.
2015-12-07 15:31:32 +01:00
pfrom - > PushMessage ( NetMsgType : : NOTFOUND , vNotFound ) ;
2013-03-29 23:49:38 +01:00
}
}
2017-08-15 10:24:20 -06:00
bool static ProcessMessage ( CNode * pfrom , std : : string strCommand , CDataStream & vRecv , int64_t nTimeReceived )
2010-08-29 16:58:15 +00:00
{
2015-04-10 18:35:09 +02:00
const CChainParams & chainparams = Params ( ) ;
2010-08-29 16:58:15 +00:00
RandAddSeedPerfmon ( ) ;
2017-02-27 17:22:39 +01:00
const bool fReindex = Blocks : : DB : : instance ( ) - > isReindexing ( ) ;
2017-07-23 22:16:30 +02:00
logDebug ( Log : : Net ) < < " received: " < < SanitizeString ( strCommand ) < < " bytes: " < < vRecv . size ( ) < < " peer: " < < pfrom - > id ;
2010-08-29 16:58:15 +00:00
if ( mapArgs . count ( " -dropmessagestest " ) & & GetRand ( atoi ( mapArgs [ " -dropmessagestest " ] ) ) = = 0 )
{
2013-09-18 20:38:08 +10:00
LogPrintf ( " dropmessagestest DROPPING RECV MESSAGE \n " ) ;
2010-08-29 16:58:15 +00:00
return true ;
}
2017-03-21 23:54:31 +01:00
const bool xthinEnabled = IsThinBlocksEnabled ( ) ;
2016-07-07 12:25:25 +02:00
2015-12-07 15:31:32 +01:00
if ( strCommand = = NetMsgType : : VERSION )
2010-08-29 16:58:15 +00:00
{
// Each connection can only send one version message
if ( pfrom - > nVersion ! = 0 )
2011-09-06 17:41:51 -04:00
{
2017-08-15 10:24:20 -06:00
pfrom - > PushMessage ( NetMsgType : : REJECT , strCommand , REJECT_DUPLICATE , std : : string ( " Duplicate version message " ) ) ;
2019-05-08 10:51:46 +02:00
Misbehaving ( pfrom - > GetId ( ) , 10 ) ;
2010-08-29 16:58:15 +00:00
return false ;
2011-09-06 17:41:51 -04:00
}
2010-08-29 16:58:15 +00:00
2013-04-13 00:13:08 -05:00
int64_t nTime ;
2010-08-29 16:58:15 +00:00
CAddress addrMe ;
CAddress addrFrom ;
2013-04-13 00:13:08 -05:00
uint64_t nNonce = 1 ;
2020-03-29 12:31:38 +02:00
int nVersion ;
vRecv > > nVersion > > pfrom - > nServices > > nTime > > addrMe ;
2016-01-15 21:37:25 -08:00
2020-03-29 12:31:38 +02:00
if ( nVersion < MIN_PEER_PROTO_VERSION )
2012-02-20 01:33:31 +01:00
{
2013-10-25 23:21:21 -10:00
// disconnect from peers older than this proto version
2020-03-29 12:31:38 +02:00
logWarning ( Log : : Net ) < < " peer: " < < pfrom - > id < < " using obsolete version " < < nVersion < < " disconnecting " ;
2015-12-07 15:31:32 +01:00
pfrom - > PushMessage ( NetMsgType : : REJECT , strCommand , REJECT_OBSOLETE ,
2013-10-28 16:36:11 +10:00
strprintf ( " Version must be %d or greater " , MIN_PEER_PROTO_VERSION ) ) ;
2012-02-20 01:33:31 +01:00
pfrom - > fDisconnect = true ;
2017-10-06 16:34:20 +02:00
addrman . increaseUselessness ( pfrom - > addr , 2 ) ;
2012-02-20 01:33:31 +01:00
return false ;
}
2020-03-29 12:31:38 +02:00
if ( nVersion = = 10300 )
nVersion = 300 ;
if ( ! vRecv . empty ( ) ) {
vRecv > > addrFrom ;
vRecv > > nNonce ;
}
2013-11-26 12:52:21 +01:00
if ( ! vRecv . empty ( ) ) {
2015-07-31 18:05:42 +02:00
vRecv > > LIMITED_STRING ( pfrom - > strSubVer , MAX_SUBVERSION_LENGTH ) ;
2013-11-26 12:52:21 +01:00
pfrom - > cleanSubVer = SanitizeString ( pfrom - > strSubVer ) ;
}
2012-02-20 01:33:31 +01:00
if ( ! vRecv . empty ( ) )
2010-08-29 16:58:15 +00:00
vRecv > > pfrom - > nStartingHeight ;
2012-08-20 21:10:25 -04:00
if ( ! vRecv . empty ( ) )
vRecv > > pfrom - > fRelayTxes ; // set to true after we get the first filter* message
else
pfrom - > fRelayTxes = true ;
2010-08-29 16:58:15 +00:00
2020-03-29 12:31:38 +02:00
// only approve connection as the whole version message parsed correctly.
pfrom - > nVersion = nVersion ;
2010-08-29 16:58:15 +00:00
// Disconnect if we connected to ourself
if ( nNonce = = nLocalHostNonce & & nNonce > 1 )
{
2018-03-19 22:41:13 +01:00
logCritical ( Log : : Net ) < < " connected to self at " < < pfrom - > addr < < " disconnecting " ;
2010-08-29 16:58:15 +00:00
pfrom - > fDisconnect = true ;
return true ;
}
2014-07-20 23:32:25 -07:00
pfrom - > addrLocal = addrMe ;
if ( pfrom - > fInbound & & addrMe . IsRoutable ( ) )
{
SeenLocal ( addrMe ) ;
}
2011-01-24 10:42:17 -05:00
// Be shy and don't send version until we hear
if ( pfrom - > fInbound )
pfrom - > PushVersion ( ) ;
2010-08-29 16:58:15 +00:00
pfrom - > fClient = ! ( pfrom - > nServices & NODE_NETWORK ) ;
2014-10-28 09:33:55 -07:00
// Potentially mark this peer as a preferred download peer.
UpdatePreferredDownload ( pfrom , State ( pfrom - > GetId ( ) ) ) ;
2010-08-29 16:58:15 +00:00
// Change version
2015-12-07 15:31:32 +01:00
pfrom - > PushMessage ( NetMsgType : : VERACK ) ;
2017-08-15 10:24:20 -06:00
pfrom - > ssSend . SetVersion ( std : : min ( pfrom - > nVersion , PROTOCOL_VERSION ) ) ;
2010-08-29 16:58:15 +00:00
2010-10-23 17:43:53 +00:00
if ( ! pfrom - > fInbound )
{
// Advertise our address
2014-05-29 12:33:17 +02:00
if ( fListen & & ! IsInitialBlockDownload ( ) )
2010-10-23 17:43:53 +00:00
{
2012-02-12 13:45:24 +01:00
CAddress addr = GetLocalAddress ( & pfrom - > addr ) ;
if ( addr . IsRoutable ( ) )
2014-07-20 23:32:25 -07:00
{
2018-03-19 22:41:13 +01:00
logInfo ( Log : : Net ) < < " ProcessMessages: advertising address " < < addr ;
2012-02-12 13:45:24 +01:00
pfrom - > PushAddress ( addr ) ;
2014-07-20 23:32:25 -07:00
} else if ( IsPeerAddrLocalGood ( pfrom ) ) {
addr . SetIP ( pfrom - > addrLocal ) ;
2018-03-19 22:41:13 +01:00
logInfo ( Log : : Net ) < < " ProcessMessages: advertising address " < < addr ;
2014-07-20 23:32:25 -07:00
pfrom - > PushAddress ( addr ) ;
}
2010-10-23 17:43:53 +00:00
}
// Get recent addresses
2012-04-24 02:15:00 +02:00
if ( pfrom - > fOneShot | | pfrom - > nVersion > = CADDR_TIME_VERSION | | addrman . size ( ) < 1000 )
2010-10-23 17:43:53 +00:00
{
2015-12-07 15:31:32 +01:00
pfrom - > PushMessage ( NetMsgType : : GETADDR ) ;
2010-10-23 17:43:53 +00:00
pfrom - > fGetAddr = true ;
}
2012-01-04 23:39:45 +01:00
addrman . Good ( pfrom - > addr ) ;
} else {
if ( ( ( CNetAddr ) pfrom - > addr ) = = ( CNetAddr ) addrFrom )
{
addrman . Add ( addrFrom , addrFrom ) ;
addrman . Good ( addrFrom ) ;
}
2010-10-23 17:43:53 +00:00
}
2010-08-29 16:58:15 +00:00
pfrom - > fSuccessfullyConnected = true ;
2018-03-19 22:41:13 +01:00
logInfo ( Log : : Net ) < < " receive version message: " < < pfrom - > addr < < pfrom - > cleanSubVer < < " version: "
2017-08-29 11:42:11 +02:00
< < pfrom - > nVersion < < " blocks: " < < pfrom - > nStartingHeight < < " id: " < < pfrom - > id ;
2014-12-15 11:06:15 +01:00
int64_t nTimeOffset = nTime - GetTime ( ) ;
pfrom - > nTimeOffset = nTimeOffset ;
AddTimeData ( pfrom - > addr , nTimeOffset ) ;
2010-08-29 16:58:15 +00:00
}
else if ( pfrom - > nVersion = = 0 )
{
// Must have a version message before anything else
2020-03-29 12:31:38 +02:00
pfrom - > fDisconnect = true ;
2010-08-29 16:58:15 +00:00
return false ;
}
2015-12-07 15:31:32 +01:00
else if ( strCommand = = NetMsgType : : VERACK )
2010-08-29 16:58:15 +00:00
{
2017-08-15 10:24:20 -06:00
pfrom - > SetRecvVersion ( std : : min ( pfrom - > nVersion , PROTOCOL_VERSION ) ) ;
2015-03-05 04:01:22 -08:00
// Mark this node as currently connected, so we update its timestamp later.
if ( pfrom - > fNetworkNode ) {
LOCK ( cs_main ) ;
State ( pfrom - > GetId ( ) ) - > fCurrentlyConnected = true ;
}
2014-11-18 22:16:32 +01:00
if ( pfrom - > nVersion > = SENDHEADERS_VERSION ) {
// Tell our peer we prefer to receive headers rather than inv's
// We send this to non-NODE NETWORK peers as well, because even
// non-NODE NETWORK peers can announce blocks (such as pruning
// nodes)
2016-01-15 21:37:25 -08:00
// BUIP010 Extreme Thinblocks: We only do inv/getdata for xthinblocks and so we must have headersfirst turned off
2017-03-21 23:54:31 +01:00
if ( ! xthinEnabled )
2016-01-15 21:37:25 -08:00
pfrom - > PushMessage ( NetMsgType : : SENDHEADERS ) ;
2014-11-18 22:16:32 +01:00
}
2010-08-29 16:58:15 +00:00
}
2018-12-30 13:33:25 +01:00
else if ( strCommand = = NetMsgType : : ADDR & & ( pfrom - > nServices & NODE_BITCOIN_CASH ) )
2010-08-29 16:58:15 +00:00
{
2017-08-15 10:24:20 -06:00
std : : vector < CAddress > vAddr ;
2010-08-29 16:58:15 +00:00
vRecv > > vAddr ;
2010-10-23 17:43:53 +00:00
// Don't want addr from older versions unless seeding
2012-04-12 20:07:49 -04:00
if ( pfrom - > nVersion < CADDR_TIME_VERSION & & addrman . size ( ) > 1000 )
2010-08-29 16:58:15 +00:00
return true ;
if ( vAddr . size ( ) > 1000 )
2011-09-06 17:41:51 -04:00
{
2013-11-18 01:25:17 +01:00
Misbehaving ( pfrom - > GetId ( ) , 20 ) ;
2014-05-06 15:25:01 +02:00
return error ( " message addr size() = %u " , vAddr . size ( ) ) ;
2011-09-06 17:41:51 -04:00
}
2010-08-29 16:58:15 +00:00
// Store the new addresses
2017-08-15 10:24:20 -06:00
std : : vector < CAddress > vAddrOk ;
2013-04-13 00:13:08 -05:00
int64_t nNow = GetAdjustedTime ( ) ;
int64_t nSince = nNow - 10 * 60 ;
2018-12-30 15:33:11 +01:00
for ( CAddress & addr : vAddr ) {
2013-03-09 12:02:57 -05:00
boost : : this_thread : : interruption_point ( ) ;
2010-10-23 17:43:53 +00:00
if ( addr . nTime < = 100000000 | | addr . nTime > nNow + 10 * 60 )
addr . nTime = nNow - 5 * 24 * 60 * 60 ;
2010-08-29 16:58:15 +00:00
pfrom - > AddAddressKnown ( addr ) ;
2012-04-10 20:22:04 +02:00
bool fReachable = IsReachable ( addr ) ;
2010-10-23 17:43:53 +00:00
if ( addr . nTime > nSince & & ! pfrom - > fGetAddr & & vAddr . size ( ) < = 10 & & addr . IsRoutable ( ) )
2010-08-29 16:58:15 +00:00
{
// Relay to a limited number of other nodes
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_vNodes ) ;
2010-10-19 17:16:51 +00:00
// Use deterministic randomness to send to the same nodes for 24 hours
2015-04-25 16:25:44 -04:00
// at a time so the addrKnowns of the chosen nodes prevent repeats
2010-08-29 16:58:15 +00:00
static uint256 hashSalt ;
2014-12-15 09:11:16 +01:00
if ( hashSalt . IsNull ( ) )
2012-05-17 12:13:14 -04:00
hashSalt = GetRandHash ( ) ;
2013-04-13 00:13:08 -05:00
uint64_t hashAddr = addr . GetHash ( ) ;
2014-12-16 15:43:03 +01:00
uint256 hashRand = ArithToUint256 ( UintToArith256 ( hashSalt ) ^ ( hashAddr < < 32 ) ^ ( ( GetTime ( ) + hashAddr ) / ( 24 * 60 * 60 ) ) ) ;
2010-10-19 17:16:51 +00:00
hashRand = Hash ( BEGIN ( hashRand ) , END ( hashRand ) ) ;
2017-08-15 10:24:20 -06:00
std : : multimap < uint256 , CNode * > mapMix ;
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodes ) {
2012-04-12 20:07:49 -04:00
if ( pnode - > nVersion < CADDR_TIME_VERSION )
2010-10-23 17:43:53 +00:00
continue ;
2010-10-19 17:16:51 +00:00
unsigned int nPointer ;
memcpy ( & nPointer , & pnode , sizeof ( nPointer ) ) ;
2014-12-16 15:43:03 +01:00
uint256 hashKey = ArithToUint256 ( UintToArith256 ( hashRand ) ^ nPointer ) ;
2010-10-19 17:16:51 +00:00
hashKey = Hash ( BEGIN ( hashKey ) , END ( hashKey ) ) ;
2017-08-15 10:24:20 -06:00
mapMix . insert ( std : : make_pair ( hashKey , pnode ) ) ;
2010-10-19 17:16:51 +00:00
}
2012-04-10 20:22:04 +02:00
int nRelayNodes = fReachable ? 2 : 1 ; // limited relaying of addresses outside our network(s)
2017-08-15 10:24:20 -06:00
for ( std : : multimap < uint256 , CNode * > : : iterator mi = mapMix . begin ( ) ; mi ! = mapMix . end ( ) & & nRelayNodes - - > 0 ; + + mi )
2010-08-29 16:58:15 +00:00
( ( * mi ) . second ) - > PushAddress ( addr ) ;
}
}
2012-04-10 20:22:04 +02:00
// Do not store addresses outside our network
if ( fReachable )
vAddrOk . push_back ( addr ) ;
2010-08-29 16:58:15 +00:00
}
2012-04-10 20:22:04 +02:00
addrman . Add ( vAddrOk , pfrom - > addr , 2 * 60 * 60 ) ;
2010-08-29 16:58:15 +00:00
if ( vAddr . size ( ) < 1000 )
pfrom - > fGetAddr = false ;
2012-04-24 02:15:00 +02:00
if ( pfrom - > fOneShot )
pfrom - > fDisconnect = true ;
2010-08-29 16:58:15 +00:00
}
2015-12-07 15:31:32 +01:00
else if ( strCommand = = NetMsgType : : SENDHEADERS )
2014-11-18 22:16:32 +01:00
{
LOCK ( cs_main ) ;
2016-01-15 21:37:25 -08:00
// BUIP010 Xtreme Thinblocks: We only do inv/getdata for xthinblocks and so we must have headersfirst turned off
2017-03-21 23:54:31 +01:00
if ( xthinEnabled )
2016-01-15 21:37:25 -08:00
State ( pfrom - > GetId ( ) ) - > fPreferHeaders = false ;
else
State ( pfrom - > GetId ( ) ) - > fPreferHeaders = true ;
2014-11-18 22:16:32 +01:00
}
2010-08-29 16:58:15 +00:00
2015-12-07 15:31:32 +01:00
else if ( strCommand = = NetMsgType : : INV )
2010-08-29 16:58:15 +00:00
{
2017-08-15 10:24:20 -06:00
std : : vector < CInv > vInv ;
2010-08-29 16:58:15 +00:00
vRecv > > vInv ;
2019-09-02 23:35:14 +02:00
if ( vInv . size ( ) > MAX_INV_SZ ) {
2013-11-18 01:25:17 +01:00
Misbehaving ( pfrom - > GetId ( ) , 20 ) ;
2014-05-06 15:25:01 +02:00
return error ( " message inv size() = %u " , vInv . size ( ) ) ;
2011-09-06 17:41:51 -04:00
}
2010-08-29 16:58:15 +00:00
2018-02-12 14:15:24 +01:00
bool fBlocksOnly = GetBoolArg ( " -blocksonly " , Settings : : DefaultBlocksOnly ) ;
2015-11-17 16:59:18 -08:00
2019-08-05 22:40:33 +02:00
// When catching up, avoid accepting transactions before we reach the tip, since they could get blacklisted.
if ( Blocks : : DB : : instance ( ) - > headerChain ( ) . Height ( ) - chainActive . Height ( ) > 6 )
fBlocksOnly = true ;
2015-11-25 23:00:23 +00:00
// Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistrelay is true
2019-11-06 23:35:50 +01:00
else if ( pfrom - > fWhitelisted & & GetBoolArg ( " -whitelistrelay " , Settings : : DefaultWhitelistRelay ) )
2015-11-17 16:59:18 -08:00
fBlocksOnly = false ;
2013-07-25 02:34:42 +02:00
LOCK ( cs_main ) ;
2014-07-12 00:02:35 +02:00
std : : vector < CInv > vToFetch ;
2019-09-02 23:35:14 +02:00
for ( unsigned int nInv = 0 ; nInv < vInv . size ( ) ; nInv + + ) {
2012-03-18 23:47:26 +01:00
const CInv & inv = vInv [ nInv ] ;
2010-08-29 16:58:15 +00:00
pfrom - > AddInventoryKnown ( inv ) ;
2012-07-06 16:33:34 +02:00
bool fAlreadyHave = AlreadyHave ( inv ) ;
2019-08-05 22:40:33 +02:00
logDebug ( Log : : Net ) < < " got inv: " < < inv < < ( fAlreadyHave ? " have. " : " new. " ) < < " Peer: " < < pfrom - > id ;
2010-08-29 16:58:15 +00:00
2014-07-12 00:02:35 +02:00
if ( inv . type = = MSG_BLOCK ) {
2014-06-23 00:00:26 +02:00
UpdateBlockAvailability ( pfrom - > GetId ( ) , inv . hash ) ;
2018-01-15 15:26:12 +00:00
if ( ! fAlreadyHave & & ! fReindex & & ! mapBlocksInFlight . count ( inv . hash ) ) {
2015-04-28 14:48:28 +00:00
// First request the headers preceding the announced block. In the normal fully-synced
2014-07-12 00:02:35 +02:00
// case where a new block is announced that succeeds the current tip (no reorganization),
// there are no such headers.
// Secondly, and only when we are close to being synced, we request the announced block directly,
// to avoid an extra round-trip. Note that we must *first* ask for the headers, so by the
// time the block arrives, the header chain leading up to it is already validated. Not
// doing this will result in the received block being rejected as an orphan in case it is
// not a direct successor.
2015-12-07 15:31:32 +01:00
pfrom - > PushMessage ( NetMsgType : : GETHEADERS , chainActive . GetLocator ( pindexBestHeader ) , inv . hash ) ;
2014-12-18 18:28:29 -05:00
CNodeState * nodestate = State ( pfrom - > GetId ( ) ) ;
2014-11-18 22:16:32 +01:00
if ( CanDirectFetch ( chainparams . GetConsensus ( ) ) & &
2014-12-18 18:28:29 -05:00
nodestate - > nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER ) {
2016-01-15 21:37:25 -08:00
// BUIP010 Xtreme Thinblocks: begin section
CInv inv2 ( inv ) ;
2016-02-29 13:15:11 -08:00
CDataStream ss ( SER_NETWORK , PROTOCOL_VERSION ) ;
2017-03-21 23:54:31 +01:00
if ( xthinEnabled & & IsChainNearlySyncd ( ) ) {
2016-07-08 12:14:24 +02:00
if ( HaveThinblockNodes ( ) & & CheckThinblockTimer ( inv . hash ) ) {
2016-01-15 21:37:25 -08:00
// Must download a block from a ThinBlock peer
2016-03-07 15:02:51 -08:00
if ( pfrom - > mapThinBlocksInFlight . size ( ) < 1 & & pfrom - > ThinBlockCapable ( ) ) { // We can only send one thinblock per peer at a time
2016-01-15 21:37:25 -08:00
pfrom - > mapThinBlocksInFlight [ inv2 . hash ] = GetTime ( ) ;
inv2 . type = MSG_XTHINBLOCK ;
2017-02-08 17:17:38 +01:00
CBloomFilter filterMemPool = createSeededBloomFilter ( CTxOrphanCache : : instance ( ) - > fetchTransactionIds ( ) ) ;
2016-02-29 13:15:11 -08:00
ss < < inv2 ;
ss < < filterMemPool ;
pfrom - > PushMessage ( NetMsgType : : GET_XTHIN , ss ) ;
2016-01-15 21:37:25 -08:00
MarkBlockAsInFlight ( pfrom - > GetId ( ) , inv . hash , chainparams . GetConsensus ( ) ) ;
2016-02-16 16:31:25 -05:00
LogPrint ( " thin " , " Requesting Thinblock %s from peer %s (%d) \n " , inv2 . hash . ToString ( ) , pfrom - > addrName . c_str ( ) , pfrom - > id ) ;
2016-01-15 21:37:25 -08:00
}
}
else {
// Try to download a thinblock if possible otherwise just download a regular block
2016-03-07 15:02:51 -08:00
if ( pfrom - > mapThinBlocksInFlight . size ( ) < 1 & & pfrom - > ThinBlockCapable ( ) ) { // We can only send one thinblock per peer at a time
2016-01-15 21:37:25 -08:00
pfrom - > mapThinBlocksInFlight [ inv2 . hash ] = GetTime ( ) ;
inv2 . type = MSG_XTHINBLOCK ;
2017-02-08 17:17:38 +01:00
CBloomFilter filterMemPool = createSeededBloomFilter ( CTxOrphanCache : : instance ( ) - > fetchTransactionIds ( ) ) ;
2016-02-29 13:15:11 -08:00
ss < < inv2 ;
ss < < filterMemPool ;
pfrom - > PushMessage ( NetMsgType : : GET_XTHIN , ss ) ;
2016-02-16 16:31:25 -05:00
LogPrint ( " thin " , " Requesting Thinblock %s from peer %s (%d) \n " , inv2 . hash . ToString ( ) , pfrom - > addrName . c_str ( ) , pfrom - > id ) ;
2016-01-15 21:37:25 -08:00
}
2016-02-29 13:15:11 -08:00
else {
2016-02-16 16:31:25 -05:00
LogPrint ( " thin " , " Requesting Regular Block %s from peer %s (%d) \n " , inv2 . hash . ToString ( ) , pfrom - > addrName . c_str ( ) , pfrom - > id ) ;
2016-02-29 13:15:11 -08:00
vToFetch . push_back ( inv2 ) ;
}
2016-01-15 21:37:25 -08:00
MarkBlockAsInFlight ( pfrom - > GetId ( ) , inv . hash , chainparams . GetConsensus ( ) ) ;
}
}
else {
vToFetch . push_back ( inv2 ) ;
MarkBlockAsInFlight ( pfrom - > GetId ( ) , inv . hash , chainparams . GetConsensus ( ) ) ;
2016-02-16 16:31:25 -05:00
LogPrint ( " thin " , " Requesting Regular Block %s from peer %s (%d) \n " , inv2 . hash . ToString ( ) , pfrom - > addrName . c_str ( ) , pfrom - > id ) ;
2016-01-15 21:37:25 -08:00
}
// BUIP010 Xtreme Thinblocks: end section
2014-07-12 00:02:35 +02:00
}
2018-11-20 21:07:53 +01:00
logDebug ( Log : : Net ) < < " getheaders " < < pindexBestHeader - > nHeight < < inv . hash
< < " to peer: " < < pfrom - > id ;
2014-07-12 00:02:35 +02:00
}
}
2019-09-02 23:35:14 +02:00
else if ( ( inv . type = = MSG_DOUBLESPENDPROOF | | inv . type = = MSG_TX )
& & ! fBlocksOnly & & ! fAlreadyHave & & ! fReindex ) {
2019-08-05 22:40:33 +02:00
pfrom - > AskFor ( inv ) ;
2015-11-17 16:59:18 -08:00
}
2014-06-23 00:00:26 +02:00
2010-08-29 16:58:15 +00:00
// Track requests for our stuff
2018-02-15 18:06:38 +01:00
ValidationNotifier ( ) . Inventory ( inv . hash ) ;
2014-09-09 09:26:52 +02:00
if ( pfrom - > nSendSize > ( SendBufferSize ( ) * 2 ) ) {
Misbehaving ( pfrom - > GetId ( ) , 50 ) ;
return error ( " send buffer size() = %u " , pfrom - > nSendSize ) ;
}
2010-08-29 16:58:15 +00:00
}
2014-07-12 00:02:35 +02:00
if ( ! vToFetch . empty ( ) )
2015-12-07 15:31:32 +01:00
pfrom - > PushMessage ( NetMsgType : : GETDATA , vToFetch ) ;
2010-08-29 16:58:15 +00:00
}
2015-12-07 15:31:32 +01:00
else if ( strCommand = = NetMsgType : : GETDATA )
2010-08-29 16:58:15 +00:00
{
2017-08-15 10:24:20 -06:00
std : : vector < CInv > vInv ;
2010-08-29 16:58:15 +00:00
vRecv > > vInv ;
2012-07-31 17:42:35 -04:00
if ( vInv . size ( ) > MAX_INV_SZ )
2011-09-06 17:41:51 -04:00
{
2013-11-18 01:25:17 +01:00
Misbehaving ( pfrom - > GetId ( ) , 20 ) ;
2014-05-06 15:25:01 +02:00
return error ( " message getdata size() = %u " , vInv . size ( ) ) ;
2011-09-06 17:41:51 -04:00
}
2010-08-29 16:58:15 +00:00
2018-02-15 16:14:35 +01:00
if ( vInv . size ( ) ! = 1 )
2017-08-17 10:05:11 +02:00
logDebug ( Log : : Net ) < < " received getdata ( " < < vInv . size ( ) < < " invsz) peer: " < < pfrom - > id ;
2012-06-23 21:38:33 -04:00
2018-02-15 16:14:35 +01:00
if ( ( vInv . size ( ) > 0 ) | | ( vInv . size ( ) = = 1 ) )
2017-08-17 10:05:11 +02:00
logDebug ( Log : : Net ) < < " received getdata for: " < < vInv [ 0 ] . ToString ( ) < < " peer: " < < pfrom - > id ;
2010-08-29 16:58:15 +00:00
2013-03-29 23:49:38 +01:00
pfrom - > vRecvGetData . insert ( pfrom - > vRecvGetData . end ( ) , vInv . begin ( ) , vInv . end ( ) ) ;
2015-04-17 14:19:21 +02:00
ProcessGetData ( pfrom , chainparams . GetConsensus ( ) ) ;
2010-08-29 16:58:15 +00:00
}
2015-12-07 15:31:32 +01:00
else if ( strCommand = = NetMsgType : : GETBLOCKS )
2010-08-29 16:58:15 +00:00
{
CBlockLocator locator ;
uint256 hashStop ;
vRecv > > locator > > hashStop ;
2013-07-25 02:34:42 +02:00
LOCK ( cs_main ) ;
2010-12-05 09:29:30 +00:00
// Find the last block the caller has in the main chain
2014-09-03 02:52:01 +02:00
CBlockIndex * pindex = FindForkInGlobalIndex ( chainActive , locator ) ;
2010-08-29 16:58:15 +00:00
// Send the rest of the chain
if ( pindex )
2013-10-10 23:07:44 +02:00
pindex = chainActive . Next ( pindex ) ;
2012-03-21 22:10:50 -04:00
int nLimit = 500 ;
2014-12-15 09:11:16 +01:00
LogPrint ( " net " , " getblocks %d to %s limit %d from peer=%d \n " , ( pindex ? pindex - > nHeight : - 1 ) , hashStop . IsNull ( ) ? " end " : hashStop . ToString ( ) , nLimit , pfrom - > id ) ;
2019-04-22 19:47:07 +02:00
for ( ; pindex ; pindex = chainActive . Next ( pindex ) ) {
if ( pindex - > GetBlockHash ( ) = = hashStop ) {
2014-01-16 16:15:27 +01:00
LogPrint ( " net " , " getblocks stopping at %d %s \n " , pindex - > nHeight , pindex - > GetBlockHash ( ) . ToString ( ) ) ;
2010-08-29 16:58:15 +00:00
break ;
}
pfrom - > PushInventory ( CInv ( MSG_BLOCK , pindex - > GetBlockHash ( ) ) ) ;
2019-04-22 19:47:07 +02:00
if ( - - nLimit < = 0 ) {
2015-04-28 14:47:17 +00:00
// When this block is requested, we'll send an inv that'll
// trigger the peer to getblocks the next batch of inventory.
2014-01-16 16:15:27 +01:00
LogPrint ( " net " , " getblocks stopping at limit %d %s \n " , pindex - > nHeight , pindex - > GetBlockHash ( ) . ToString ( ) ) ;
2010-08-29 16:58:15 +00:00
pfrom - > hashContinue = pindex - > GetBlockHash ( ) ;
break ;
}
}
}
2015-12-07 15:31:32 +01:00
else if ( strCommand = = NetMsgType : : GETHEADERS )
2010-12-05 09:29:30 +00:00
{
CBlockLocator locator ;
uint256 hashStop ;
vRecv > > locator > > hashStop ;
2013-07-25 02:34:42 +02:00
LOCK ( cs_main ) ;
2015-11-09 14:27:08 +01:00
if ( IsInitialBlockDownload ( ) & & ! pfrom - > fWhitelisted ) {
2019-06-17 22:07:17 +02:00
logDebug ( Log : : Net ) < < " Ignoring getheaders from peer: " < < pfrom - > id < < " because node is in initial block download " ;
2015-05-21 13:29:09 -04:00
return true ;
2015-11-09 14:27:08 +01:00
}
2014-11-18 22:16:32 +01:00
CNodeState * nodestate = State ( pfrom - > GetId ( ) ) ;
2018-06-12 20:43:50 +02:00
CBlockIndex * pindex = nullptr ;
2010-12-05 09:29:30 +00:00
if ( locator . IsNull ( ) )
{
// If locator is null, return the hashStop block
2018-01-15 15:26:12 +00:00
pindex = Blocks : : Index : : get ( hashStop ) ;
if ( ! pindex )
2010-12-05 09:29:30 +00:00
return true ;
}
else
{
// Find the last block the caller has in the main chain
2014-09-03 02:52:01 +02:00
pindex = FindForkInGlobalIndex ( chainActive , locator ) ;
2019-05-08 10:51:46 +02:00
if ( pindex ) {
if ( pindex - > nStatus & BLOCK_FAILED_MASK ) {
// his TIP is one we rejected. We don't like them.
Misbehaving ( pfrom - > GetId ( ) , 100 ) ;
return error ( " peer follows a different chain. " ) ;
}
2013-10-10 23:07:44 +02:00
pindex = chainActive . Next ( pindex ) ;
2019-05-08 10:51:46 +02:00
}
2010-12-05 09:29:30 +00:00
}
2012-11-14 22:18:10 +01:00
// we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end
2017-08-15 10:24:20 -06:00
std : : vector < CBlock > vHeaders ;
2014-07-12 00:02:35 +02:00
int nLimit = MAX_HEADERS_RESULTS ;
2018-11-20 21:07:53 +01:00
logDebug ( Log : : Net ) < < " getheaders " < < ( pindex ? pindex - > nHeight : - 1 ) < < " to "
< < hashStop < < " from peer: " < < pfrom - > id ;
for ( ; pindex ; pindex = chainActive . Next ( pindex ) ) {
2010-12-05 09:29:30 +00:00
vHeaders . push_back ( pindex - > GetBlockHeader ( ) ) ;
if ( - - nLimit < = 0 | | pindex - > GetBlockHash ( ) = = hashStop )
break ;
}
2018-06-12 20:43:50 +02:00
// pindex can be nullptr either if we sent chainActive.Tip() OR
2014-11-18 22:16:32 +01:00
// if our peer has chainActive.Tip() (and thus we are sending an empty
// headers message). In both cases it's safe to update
// pindexBestHeaderSent to be our tip.
nodestate - > pindexBestHeaderSent = pindex ? pindex : chainActive . Tip ( ) ;
2015-12-07 15:31:32 +01:00
pfrom - > PushMessage ( NetMsgType : : HEADERS , vHeaders ) ;
2010-12-05 09:29:30 +00:00
}
2015-12-07 15:31:32 +01:00
else if ( strCommand = = NetMsgType : : TX )
2010-08-29 16:58:15 +00:00
{
2015-11-17 17:01:43 -08:00
// Stop processing the transaction early if
2015-11-25 23:00:23 +00:00
// We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off
2018-09-12 21:59:23 +02:00
if ( GetBoolArg ( " -blocksonly " , Settings : : DefaultBlocksOnly ) & & ( ! pfrom - > fWhitelisted | | ! GetBoolArg ( " -whitelistrelay " , Settings : : DefaultWhitelistRelay ) ) ) {
2015-11-20 15:54:27 -08:00
LogPrint ( " net " , " transaction sent in violation of protocol peer=%d \n " , pfrom - > id ) ;
2015-11-17 17:01:43 -08:00
return true ;
}
2010-08-29 16:58:15 +00:00
CTransaction tx ;
vRecv > > tx ;
CInv inv ( MSG_TX , tx . GetHash ( ) ) ;
pfrom - > AddInventoryKnown ( inv ) ;
2015-11-23 01:54:23 +00:00
pfrom - > setAskFor . erase ( inv . hash ) ;
2018-01-15 15:26:12 +00:00
{
LOCK ( cs_main ) ;
mapAlreadyAskedFor . erase ( inv . hash ) ;
}
2014-07-03 15:28:38 +07:00
2019-11-22 18:58:58 +01:00
uint32_t opts = Validation : : ForwardGoodToPeers ;
if ( ! pfrom - > fWhitelisted )
opts + = Validation : : PunishBadNode + Validation : : RateLimitFreeTx ;
flApp - > validation ( ) - > addTransaction ( Tx : : fromOldTransaction ( tx ) , opts , pfrom ) ;
2018-01-15 15:26:12 +00:00
CValidationState val ;
if ( ! FlushStateToDisk ( val , FLUSH_STATE_PERIODIC ) )
AbortNode ( val . GetRejectReason ( ) . c_str ( ) ) ;
2010-08-29 16:58:15 +00:00
}
2018-01-15 15:26:12 +00:00
else if ( strCommand = = NetMsgType : : HEADERS & & ! fReindex ) // Ignore headers received while importing
2014-07-12 00:02:35 +02:00
{
std : : vector < CBlockHeader > headers ;
// Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks.
unsigned int nCount = ReadCompactSize ( vRecv ) ;
if ( nCount > MAX_HEADERS_RESULTS ) {
Misbehaving ( pfrom - > GetId ( ) , 20 ) ;
return error ( " headers message size = %u " , nCount ) ;
}
headers . resize ( nCount ) ;
for ( unsigned int n = 0 ; n < nCount ; n + + ) {
vRecv > > headers [ n ] ;
ReadCompactSize ( vRecv ) ; // ignore tx count; assume it is 0.
}
if ( nCount = = 0 ) {
// Nothing interesting. Stop asking this peers for more headers.
return true ;
}
2018-01-29 17:35:19 +00:00
auto * engine = Application : : instance ( ) - > validation ( ) ;
2018-01-15 15:26:12 +00:00
Streaming : : BufferPool pool ( 100 * nCount ) ;
2018-01-29 17:35:19 +00:00
std : : list < Validation : : Settings > futures ;
2018-01-15 15:26:12 +00:00
for ( const CBlockHeader & header : headers ) {
auto block = FastBlock : : fromOldBlock ( header , & pool ) ;
2019-05-08 10:51:46 +02:00
futures . push_back ( engine - > addBlock ( block , 0 ) . start ( ) ) ;
2018-01-29 17:35:19 +00:00
}
for ( const Validation : : Settings & future : futures ) {
future . waitHeaderFinished ( ) ;
if ( ! future . error ( ) . empty ( ) ) {
2019-12-09 15:15:52 +01:00
logWarning ( Log : : Net ) < < " HEADERS received from peer: " < < pfrom - > GetId ( ) < < " returned: " < < future . error ( ) ;
2018-01-29 17:35:19 +00:00
LOCK ( cs_main ) ;
2019-05-08 10:51:46 +02:00
Misbehaving ( pfrom - > GetId ( ) , Settings : : DefaultBanscoreThreshold ) ;
2017-08-17 10:05:11 +02:00
return false ;
2014-07-12 00:02:35 +02:00
}
}
2018-01-29 17:35:19 +00:00
CBlockIndex * pindexLast = futures . back ( ) . blockIndex ( ) ;
2018-01-15 15:26:12 +00:00
assert ( pindexLast ) ;
UpdateBlockAvailability ( pfrom - > GetId ( ) , pindexLast - > GetBlockHash ( ) ) ;
2014-07-12 00:02:35 +02:00
2018-01-15 15:26:12 +00:00
if ( nCount = = MAX_HEADERS_RESULTS ) {
2014-07-12 00:02:35 +02:00
// Headers message had its maximum size; the peer may have more headers.
// TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue
// from there instead.
2017-08-17 10:05:11 +02:00
logDebug ( Log : : Net ) . nospace ( ) < < " more getheaders ( " < < pindexLast - > nHeight
< < " ) to end to peer= " < < pfrom - > id < < " (startheight: " < < pfrom - > nStartingHeight < < " ) " ;
2015-12-07 15:31:32 +01:00
pfrom - > PushMessage ( NetMsgType : : GETHEADERS , chainActive . GetLocator ( pindexLast ) , uint256 ( ) ) ;
2014-07-12 00:02:35 +02:00
}
2015-03-13 09:25:34 -07:00
2018-01-15 15:26:12 +00:00
LOCK ( cs_main ) ;
2017-03-21 23:54:31 +01:00
2014-11-18 22:16:32 +01:00
bool fCanDirectFetch = CanDirectFetch ( chainparams . GetConsensus ( ) ) ;
CNodeState * nodestate = State ( pfrom - > GetId ( ) ) ;
// If this set of headers is valid and ends in a block with at least as
// much work as our tip, download as much as possible.
2018-01-15 15:26:12 +00:00
logDebug ( 106 ) < < " canDirectFetch " < < fCanDirectFetch < < " tree " < < pindexLast - > IsValid ( BLOCK_VALID_TREE ) < < " more chain work: " < <
( chainActive . Tip ( ) - > nChainWork < = pindexLast - > nChainWork ) ;
2014-11-18 22:16:32 +01:00
if ( fCanDirectFetch & & pindexLast - > IsValid ( BLOCK_VALID_TREE ) & & chainActive . Tip ( ) - > nChainWork < = pindexLast - > nChainWork ) {
2017-08-15 10:24:20 -06:00
std : : vector < CBlockIndex * > vToFetch ;
2014-11-18 22:16:32 +01:00
CBlockIndex * pindexWalk = pindexLast ;
// Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
while ( pindexWalk & & ! chainActive . Contains ( pindexWalk ) & & vToFetch . size ( ) < = MAX_BLOCKS_IN_TRANSIT_PER_PEER ) {
2018-01-15 15:26:12 +00:00
logDebug ( 106 ) < < " starting fetch " < < pindexWalk - > nHeight ;
2014-11-18 22:16:32 +01:00
if ( ! ( pindexWalk - > nStatus & BLOCK_HAVE_DATA ) & &
! mapBlocksInFlight . count ( pindexWalk - > GetBlockHash ( ) ) ) {
// We don't have this block, and it's not yet in flight.
vToFetch . push_back ( pindexWalk ) ;
}
pindexWalk = pindexWalk - > pprev ;
}
2018-01-15 15:26:12 +00:00
logDebug ( 106 ) < < " first block that has data; " < < pindexWalk - > nHeight ;
logDebug ( 106 ) < < " fetch " < < vToFetch ;
2014-11-18 22:16:32 +01:00
// If pindexWalk still isn't on our main chain, we're looking at a
// very large reorg at a time we think we're close to caught up to
// the main chain -- this shouldn't really happen. Bail out on the
// direct fetch and rely on parallel download instead.
if ( ! chainActive . Contains ( pindexWalk ) ) {
2018-01-15 15:26:12 +00:00
logWarning ( Log : : Net ) < < " Large reorg, won't direct fetch to " < < pindexLast - > GetBlockHash ( ) < < " at height: " < < pindexLast - > nHeight ;
} else if ( ! ( xthinEnabled & & pfrom - > nServices & NODE_XTHIN ) ) { // xthin based downloads are done elsewhere
2017-08-15 10:24:20 -06:00
std : : vector < CInv > vGetData ;
2014-11-18 22:16:32 +01:00
// Download as much as possible, from earliest to latest.
BOOST_REVERSE_FOREACH ( CBlockIndex * pindex , vToFetch ) {
if ( nodestate - > nBlocksInFlight > = MAX_BLOCKS_IN_TRANSIT_PER_PEER ) {
// Can't download any more from this peer
break ;
}
vGetData . push_back ( CInv ( MSG_BLOCK , pindex - > GetBlockHash ( ) ) ) ;
MarkBlockAsInFlight ( pfrom - > GetId ( ) , pindex - > GetBlockHash ( ) , chainparams . GetConsensus ( ) , pindex ) ;
2017-07-23 22:16:30 +02:00
logDebug ( Log : : Net ) < < " Requesting block " < < pindex - > GetBlockHash ( ) < < " from peer: " < < pfrom - > id ;
2014-11-18 22:16:32 +01:00
}
if ( vGetData . size ( ) > 1 ) {
2017-07-23 22:16:30 +02:00
logDebug ( Log : : Net ) < < " Downloading blocks toward " < < pindexLast - > GetBlockHash ( ) < < " height: " < < pindexLast - > nHeight ;
2014-11-18 22:16:32 +01:00
}
if ( vGetData . size ( ) > 0 ) {
2015-12-07 15:31:32 +01:00
pfrom - > PushMessage ( NetMsgType : : GETDATA , vGetData ) ;
2014-11-18 22:16:32 +01:00
}
}
}
2014-07-12 00:02:35 +02:00
}
2016-01-15 21:37:25 -08:00
// BUIP010 Xtreme Thinblocks: begin section
2018-01-15 15:26:12 +00:00
else if ( strCommand = = NetMsgType : : GET_XTHIN & & ! fReindex ) // Ignore blocks received while importing
2016-02-29 13:15:11 -08:00
{
2017-03-21 23:54:31 +01:00
if ( ! xthinEnabled ) {
LOCK ( cs_main ) ;
Misbehaving ( pfrom - > GetId ( ) , 100 ) ;
return false ;
}
2016-02-29 13:15:11 -08:00
CBloomFilter filterMemPool ;
CInv inv ;
vRecv > > inv > > filterMemPool ;
2017-03-21 23:54:31 +01:00
if ( inv . type ! = MSG_XTHINBLOCK & & inv . type ! = MSG_THINBLOCK ) {
2017-03-23 20:34:57 +01:00
LOCK ( cs_main ) ;
2017-03-21 23:54:31 +01:00
Misbehaving ( pfrom - > GetId ( ) , 20 ) ;
return false ;
}
2016-02-29 13:15:11 -08:00
LoadFilter ( pfrom , & filterMemPool ) ;
pfrom - > vRecvGetData . insert ( pfrom - > vRecvGetData . end ( ) , inv ) ;
ProcessGetData ( pfrom , chainparams . GetConsensus ( ) ) ;
}
2018-01-15 15:26:12 +00:00
else if ( strCommand = = NetMsgType : : XTHINBLOCK & & ! fReindex ) // Ignore blocks received while importing
2016-01-15 21:37:25 -08:00
{
2017-03-21 23:54:31 +01:00
if ( ! xthinEnabled ) {
LOCK ( cs_main ) ;
Misbehaving ( pfrom - > GetId ( ) , 100 ) ;
return false ;
}
2016-01-15 21:37:25 -08:00
CXThinBlock thinBlock ;
vRecv > > thinBlock ;
2018-01-15 15:26:12 +00:00
logDebug ( 106 ) < < " received XThinBlock " < < thinBlock . header . GetHash ( ) ;
2016-01-15 21:37:25 -08:00
2017-02-08 17:28:21 +01:00
// Send expedited ASAP
CValidationState state ;
if ( ! CheckBlockHeader ( thinBlock . header , state , true ) ) { // block header is bad
LogPrint ( " thin " , " Thinblock %s received with bad header from peer %s (%d) \n " , thinBlock . header . GetHash ( ) . ToString ( ) , pfrom - > addrName . c_str ( ) , pfrom - > id ) ;
Misbehaving ( pfrom - > id , 20 ) ;
return false ;
}
else if ( ! IsRecentlyExpeditedAndStore ( thinBlock . header . GetHash ( ) ) )
SendExpeditedBlock ( thinBlock , 0 , pfrom ) ;
2016-01-15 21:37:25 -08:00
CInv inv ( MSG_BLOCK , thinBlock . header . GetHash ( ) ) ;
2017-02-08 17:28:21 +01:00
bool fAlreadyHave = false ;
// An expedited block or re-requested xthin can arrive and beat the original thin block request/response
2016-01-15 21:37:25 -08:00
if ( ! pfrom - > mapThinBlocksInFlight . count ( inv . hash ) ) {
2017-02-08 17:28:21 +01:00
LogPrint ( " thin " , " Thinblock %s from peer %s (%d) received but we already have it \n " , inv . hash . ToString ( ) , pfrom - > addrName . c_str ( ) , pfrom - > id ) ;
LOCK ( cs_main ) ;
fAlreadyHave = AlreadyHave ( inv ) ; // I'll still continue processing if we don't have an accepted block yet
2016-01-15 21:37:25 -08:00
}
2017-02-08 17:28:21 +01:00
if ( ! fAlreadyHave ) {
if ( thinBlock . process ( pfrom ) )
HandleBlockMessage ( pfrom , strCommand , pfrom - > thinBlock , thinBlock . GetInv ( ) ) ; // clears the thin block
2016-01-15 21:37:25 -08:00
}
2018-01-15 15:26:12 +00:00
else {
logDebug ( 106 ) < < " already have this xthin block " ;
}
2016-01-15 21:37:25 -08:00
}
2018-01-15 15:26:12 +00:00
else if ( strCommand = = NetMsgType : : XBLOCKTX & & ! fReindex ) // handle Re-requested thinblock transactions
2016-01-15 21:37:25 -08:00
{
2017-03-21 23:54:31 +01:00
if ( ! xthinEnabled ) {
LOCK ( cs_main ) ;
Misbehaving ( pfrom - > GetId ( ) , 100 ) ;
return false ;
}
if ( pfrom - > xThinBlockHashes . size ( ) ! = pfrom - > thinBlock . vtx . size ( ) ) { // crappy, but fast solution.
LogPrint ( " thin " , " Inconsistent thin block data while processing xblock-tx \n " ) ;
return true ;
}
2016-01-15 21:37:25 -08:00
CXThinBlockTx thinBlockTx ;
vRecv > > thinBlockTx ;
CInv inv ( MSG_XTHINBLOCK , thinBlockTx . blockhash ) ;
2017-07-23 22:16:30 +02:00
logDebug ( Log : : Net ) < < " received blocktxs for " < < inv . hash < < " peer " < < pfrom - > id ;
2016-01-15 21:37:25 -08:00
if ( ! pfrom - > mapThinBlocksInFlight . count ( inv . hash ) ) {
2017-03-22 15:58:22 +01:00
LogPrint ( " thin " , " ThinblockTx received but it was either not requested or it was beaten by another block %s peer=%d \n " , inv . hash . ToString ( ) , pfrom - > id ) ;
2017-02-08 17:28:21 +01:00
return true ;
2016-01-15 21:37:25 -08:00
}
2016-03-08 10:52:19 -08:00
// Create the mapMissingTx from all the supplied tx's in the xthinblock
std : : map < uint64_t , CTransaction > mapMissingTx ;
2018-12-30 15:33:11 +01:00
for ( CTransaction tx : thinBlockTx . vMissingTx ) {
2016-03-08 10:52:19 -08:00
mapMissingTx [ tx . GetHash ( ) . GetCheapHash ( ) ] = tx ;
2016-01-15 21:37:25 -08:00
}
2017-02-08 17:28:21 +01:00
int count = 0 ;
for ( size_t i = 0 ; i < pfrom - > thinBlock . vtx . size ( ) ; + + i ) {
if ( pfrom - > thinBlock . vtx [ i ] . IsNull ( ) ) {
auto val = mapMissingTx . find ( pfrom - > xThinBlockHashes [ i ] ) ;
if ( val ! = mapMissingTx . end ( ) ) {
pfrom - > thinBlock . vtx [ i ] = val - > second ;
- - pfrom - > thinBlockWaitingForTxns ;
}
count + + ;
}
}
LogPrint ( " thin " , " Got %d Re-requested txs, needed %d of them \n " , thinBlockTx . vMissingTx . size ( ) , count ) ;
2016-01-15 21:37:25 -08:00
if ( pfrom - > thinBlockWaitingForTxns = = 0 ) {
// We have all the transactions now that are in this block: try to reassemble and process.
pfrom - > thinBlockWaitingForTxns = - 1 ;
2016-03-02 13:20:55 +01:00
pfrom - > AddInventoryKnown ( inv ) ;
2017-02-08 17:17:38 +01:00
// For correctness sake, assume all came from the orphans cache
std : : vector < uint256 > orphans ;
orphans . reserve ( pfrom - > thinBlock . vtx . size ( ) ) ;
for ( unsigned int i = 0 ; i < pfrom - > thinBlock . vtx . size ( ) ; i + + ) {
orphans . push_back ( pfrom - > thinBlock . vtx [ i ] . GetHash ( ) ) ;
}
2016-01-15 21:37:25 -08:00
HandleBlockMessage ( pfrom , strCommand , pfrom - > thinBlock , inv ) ;
2019-11-21 20:03:26 +01:00
CTxOrphanCache : : instance ( ) - > eraseOrphans ( orphans ) ;
2016-01-15 21:37:25 -08:00
}
else {
2017-02-08 17:28:21 +01:00
LogPrint ( " thin " , " Failed to retrieve all transactions for block \n " ) ;
2016-01-15 21:37:25 -08:00
}
}
2018-01-15 15:26:12 +00:00
else if ( strCommand = = NetMsgType : : GET_XBLOCKTX & & ! fReindex ) // return Re-requested xthinblock transactions
2016-01-15 21:37:25 -08:00
{
2017-03-21 23:54:31 +01:00
if ( ! xthinEnabled ) {
LOCK ( cs_main ) ;
Misbehaving ( pfrom - > GetId ( ) , 100 ) ;
return false ;
}
2016-03-08 10:52:19 -08:00
CXRequestThinBlockTx thinRequestBlockTx ;
vRecv > > thinRequestBlockTx ;
2016-01-15 21:37:25 -08:00
2017-03-21 23:54:31 +01:00
if ( thinRequestBlockTx . setCheapHashesToRequest . empty ( ) ) { // empty request??
LOCK ( cs_main ) ;
Misbehaving ( pfrom - > GetId ( ) , 100 ) ;
return false ;
}
2016-04-25 14:36:03 +01:00
// We use MSG_TX here even though we refer to blockhash because we need to track
2016-01-15 21:37:25 -08:00
// how many xblocktx requests we make in case of DOS
2016-04-25 14:36:03 +01:00
CInv inv ( MSG_TX , thinRequestBlockTx . blockhash ) ;
2016-01-15 21:37:25 -08:00
LogPrint ( " thin " , " received get_xblocktx for %s peer=%d \n " , inv . hash . ToString ( ) , pfrom - > id ) ;
// Check for Misbehaving and DOS
// If they make more than 20 requests in 10 minutes then disconnect them
{
2016-07-06 20:16:18 +02:00
const uint64_t nNow = GetTime ( ) ;
2016-01-15 21:37:25 -08:00
if ( pfrom - > nGetXBlockTxLastTime < = 0 )
2016-07-06 20:16:18 +02:00
pfrom - > nGetXBlockTxLastTime = nNow ;
2016-01-15 21:37:25 -08:00
pfrom - > nGetXBlockTxCount * = pow ( 1.0 - 1.0 / 600.0 , ( double ) ( nNow - pfrom - > nGetXBlockTxLastTime ) ) ;
pfrom - > nGetXBlockTxLastTime = nNow ;
pfrom - > nGetXBlockTxCount + = 1 ;
LogPrint ( " thin " , " nGetXBlockTxCount is %f \n " , pfrom - > nGetXBlockTxCount ) ;
if ( pfrom - > nGetXBlockTxCount > = 20 ) {
LogPrintf ( " DOS: Misbehaving - requesting too many xblocktx: %s \n " , inv . hash . ToString ( ) ) ;
LOCK ( cs_main ) ;
Misbehaving ( pfrom - > GetId ( ) , 100 ) ; // If they exceed the limit then disconnect them
}
}
2018-01-15 15:26:12 +00:00
CBlockIndex * index = Blocks : : Index : : get ( inv . hash ) ;
if ( ! index ) {
LOCK ( cs_main ) ;
2017-03-15 09:28:50 +01:00
Misbehaving ( pfrom - > GetId ( ) , 100 ) ;
return false ;
}
2017-03-21 23:54:31 +01:00
if ( index - > nHeight + 100 < chainActive . Height ( ) ) {
// a node that is behind should never use this method.
2018-01-15 15:26:12 +00:00
LOCK ( cs_main ) ;
2017-03-21 23:54:31 +01:00
Misbehaving ( pfrom - > GetId ( ) , 10 ) ;
return false ;
}
if ( ( index - > nStatus & BLOCK_HAVE_DATA ) = = 0 ) {
LogPrintf ( " GET_XBLOCKTX requested block-data not available %s \n " , inv . hash . ToString ( ) . c_str ( ) ) ;
return false ;
}
2016-01-15 21:37:25 -08:00
CBlock block ;
2018-10-11 12:04:40 +02:00
const Consensus : : Params & consensusParams = chainparams . GetConsensus ( ) ;
2018-01-15 15:26:12 +00:00
LOCK ( cs_main ) ;
2017-03-21 23:54:31 +01:00
if ( ! ReadBlockFromDisk ( block , index , consensusParams ) ) {
LogPrintf ( " Internal error, file missing datafile %d (block: %d) \n " , index - > nFile , index - > nHeight ) ;
return false ;
}
2016-04-25 14:36:03 +01:00
2016-03-08 10:52:19 -08:00
std : : vector < CTransaction > vTx ;
2017-03-21 23:54:31 +01:00
int todo = thinRequestBlockTx . setCheapHashesToRequest . size ( ) ;
2017-03-23 20:34:57 +01:00
for ( size_t i = 1 ; i < block . vtx . size ( ) ; i + + ) {
2016-01-15 21:37:25 -08:00
uint64_t cheapHash = block . vtx [ i ] . GetHash ( ) . GetCheapHash ( ) ;
2017-03-21 23:54:31 +01:00
if ( thinRequestBlockTx . setCheapHashesToRequest . count ( cheapHash ) ) {
2016-03-08 10:52:19 -08:00
vTx . push_back ( block . vtx [ i ] ) ;
2017-03-21 23:54:31 +01:00
if ( - - todo = = 0 )
break ;
}
}
if ( todo > 0 ) { // node send us a request for transactions which were not in the block.
Misbehaving ( pfrom - > GetId ( ) , 100 ) ;
return false ;
2016-01-15 21:37:25 -08:00
}
2016-03-08 10:52:19 -08:00
2016-01-15 21:37:25 -08:00
pfrom - > AddInventoryKnown ( inv ) ;
2016-03-08 10:52:19 -08:00
CXThinBlockTx thinBlockTx ( thinRequestBlockTx . blockhash , vTx ) ;
2016-01-15 21:37:25 -08:00
pfrom - > PushMessage ( NetMsgType : : XBLOCKTX , thinBlockTx ) ;
}
// BUIP010 Xtreme Thinblocks: end section
2018-01-15 15:26:12 +00:00
else if ( strCommand = = NetMsgType : : BLOCK & & ! fReindex ) // Ignore blocks received while importing
2010-08-29 16:58:15 +00:00
{
2018-01-15 15:26:12 +00:00
logDebug ( 106 ) < < " Received a block " ;
2010-12-05 09:29:30 +00:00
CBlock block ;
2016-10-27 10:35:38 +02:00
try {
vRecv > > block ;
} catch ( std : : exception & e ) {
LogPrint ( " net " , " ProcessMessage/block failed to parse message and got error: %s \n " , e . what ( ) ) ;
pfrom - > fDisconnect = true ;
return true ;
}
2018-01-15 15:26:12 +00:00
logDebug ( 106 ) < < " -> " < < block . GetHash ( ) ;
2010-08-29 16:58:15 +00:00
2010-12-05 09:29:30 +00:00
CInv inv ( MSG_BLOCK , block . GetHash ( ) ) ;
2018-01-15 15:26:12 +00:00
logDebug ( Log : : Net ) < < " received " < < inv < < " peer " < < pfrom - > id ;
2010-08-29 16:58:15 +00:00
2014-07-12 00:02:35 +02:00
pfrom - > AddInventoryKnown ( inv ) ;
2013-07-25 02:34:42 +02:00
2016-01-15 21:37:25 -08:00
// BUIP010 Extreme Thinblocks: Handle Block Message
HandleBlockMessage ( pfrom , strCommand , block , inv ) ;
2017-02-08 17:17:38 +01:00
std : : vector < uint256 > orphans ;
orphans . reserve ( block . vtx . size ( ) ) ;
for ( unsigned int i = 0 ; i < block . vtx . size ( ) ; i + + ) {
orphans . push_back ( block . vtx [ i ] . GetHash ( ) ) ;
}
2019-11-21 20:03:26 +01:00
CTxOrphanCache : : instance ( ) - > eraseOrphans ( orphans ) ;
2010-08-29 16:58:15 +00:00
}
2015-06-26 22:38:07 +03:00
else if ( strCommand = = NetMsgType : : GETADDR )
2010-08-29 16:58:15 +00:00
{
2015-06-26 22:38:07 +03:00
// This asymmetric behavior for inbound and outbound connections was introduced
// to prevent a fingerprinting attack: an attacker can send specific fake addresses
// to users' AddrMan and later request them by sending getaddr messages.
// Making nodes which are behind NAT and can only make outgoing connections ignore
// the getaddr message mitigates the attack.
if ( ! pfrom - > fInbound ) {
LogPrint ( " net " , " Ignoring \" getaddr \" from outbound connection. peer=%d \n " , pfrom - > id ) ;
return true ;
}
2016-04-11 01:09:34 +00:00
// Only send one GetAddr response per connection to reduce resource waste
// and discourage addr stamping of INV announcements.
if ( pfrom - > fSentAddr ) {
LogPrint ( " net " , " Ignoring repeated \" getaddr \" . peer=%d \n " , pfrom - > id ) ;
return true ;
}
pfrom - > fSentAddr = true ;
2010-08-29 16:58:15 +00:00
pfrom - > vAddrToSend . clear ( ) ;
2017-08-15 10:24:20 -06:00
std : : vector < CAddress > vAddr = addrman . GetAddr ( ) ;
2018-12-30 15:33:11 +01:00
for ( const CAddress & addr : vAddr )
2012-01-04 23:39:45 +01:00
pfrom - > PushAddress ( addr ) ;
2010-08-29 16:58:15 +00:00
}
2015-12-07 15:31:32 +01:00
else if ( strCommand = = NetMsgType : : MEMPOOL )
2012-07-31 17:42:35 -04:00
{
2015-12-03 20:13:10 +00:00
if ( CNode : : OutboundTargetReached ( false ) & & ! pfrom - > fWhitelisted )
{
LogPrint ( " net " , " mempool request with bandwidth limit reached, disconnect peer=%d \n " , pfrom - > GetId ( ) ) ;
pfrom - > fDisconnect = true ;
return true ;
}
2013-08-27 15:51:57 +10:00
LOCK2 ( cs_main , pfrom - > cs_filter ) ;
2013-07-25 02:34:42 +02:00
2012-07-31 17:42:35 -04:00
std : : vector < uint256 > vtxid ;
mempool . queryHashes ( vtxid ) ;
2017-08-15 10:24:20 -06:00
std : : vector < CInv > vInv ;
2018-12-30 15:33:11 +01:00
for ( uint256 & hash : vtxid ) {
2013-01-10 14:06:30 -05:00
CInv inv ( MSG_TX , hash ) ;
2015-12-05 17:45:44 +08:00
if ( pfrom - > pfilter ) {
CTransaction tx ;
bool fInMemPool = mempool . lookup ( hash , tx ) ;
if ( ! fInMemPool ) continue ; // another thread removed since queryHashes, maybe...
2020-04-10 12:21:49 +02:00
if ( ! pfrom - > pfilter - > isRelevantAndUpdate ( tx ) ) continue ;
2015-12-05 17:45:44 +08:00
}
vInv . push_back ( inv ) ;
2013-08-27 16:12:43 +10:00
if ( vInv . size ( ) = = MAX_INV_SZ ) {
2015-12-07 15:31:32 +01:00
pfrom - > PushMessage ( NetMsgType : : INV , vInv ) ;
2013-08-27 16:12:43 +10:00
vInv . clear ( ) ;
}
2012-07-31 17:42:35 -04:00
}
if ( vInv . size ( ) > 0 )
2015-12-07 15:31:32 +01:00
pfrom - > PushMessage ( NetMsgType : : INV , vInv ) ;
2012-07-31 17:42:35 -04:00
}
2015-12-07 15:31:32 +01:00
else if ( strCommand = = NetMsgType : : PING )
2010-08-29 16:58:15 +00:00
{
2012-04-11 12:38:03 -04:00
if ( pfrom - > nVersion > BIP0031_VERSION )
{
2013-04-13 00:13:08 -05:00
uint64_t nonce = 0 ;
2012-04-11 12:38:03 -04:00
vRecv > > nonce ;
// Echo the message back with the nonce. This allows for two useful features:
//
// 1) A remote node can quickly check if the connection is operational
// 2) Remote nodes can measure the latency of the network thread. If this node
// is overloaded it won't respond to pings quickly and the remote node can
// avoid sending us more work, like chain download requests.
//
// The nonce stops the remote getting confused between different pings: without
// it, if the remote node sends a ping once per second and this node takes 5
// seconds to respond to each, the 5th ping the remote sends would appear to
// return very quickly.
2015-12-07 15:31:32 +01:00
pfrom - > PushMessage ( NetMsgType : : PONG , nonce ) ;
2012-04-11 12:38:03 -04:00
}
2010-08-29 16:58:15 +00:00
}
2015-12-07 15:31:32 +01:00
else if ( strCommand = = NetMsgType : : PONG )
2013-08-22 04:34:33 -07:00
{
2014-07-06 16:06:46 +02:00
int64_t pingUsecEnd = nTimeReceived ;
2013-04-13 00:13:08 -05:00
uint64_t nonce = 0 ;
2013-08-22 04:34:33 -07:00
size_t nAvail = vRecv . in_avail ( ) ;
bool bPingFinished = false ;
std : : string sProblem ;
2013-11-11 16:20:39 +01:00
2013-08-22 04:34:33 -07:00
if ( nAvail > = sizeof ( nonce ) ) {
vRecv > > nonce ;
2013-11-11 16:20:39 +01:00
2013-08-22 04:34:33 -07:00
// Only process pong message if there is an outstanding ping (old ping without nonce should never pong)
if ( pfrom - > nPingNonceSent ! = 0 ) {
if ( nonce = = pfrom - > nPingNonceSent ) {
// Matching pong received, this ping is no longer outstanding
bPingFinished = true ;
2013-04-13 00:13:08 -05:00
int64_t pingUsecTime = pingUsecEnd - pfrom - > nPingUsecStart ;
2013-08-22 04:34:33 -07:00
if ( pingUsecTime > 0 ) {
// Successful ping time measurement, replace previous
pfrom - > nPingUsecTime = pingUsecTime ;
2015-08-13 02:31:46 -07:00
pfrom - > nMinPingUsecTime = std : : min ( pfrom - > nMinPingUsecTime , pingUsecTime ) ;
2013-08-22 04:34:33 -07:00
} else {
// This should never happen
sProblem = " Timing mishap " ;
}
} else {
// Nonce mismatches are normal when pings are overlapping
sProblem = " Nonce mismatch " ;
if ( nonce = = 0 ) {
2015-04-28 14:48:28 +00:00
// This is most likely a bug in another implementation somewhere; cancel this ping
2013-08-22 04:34:33 -07:00
bPingFinished = true ;
sProblem = " Nonce zero " ;
}
}
} else {
sProblem = " Unsolicited pong without ping " ;
}
} else {
2015-04-28 14:48:28 +00:00
// This is most likely a bug in another implementation somewhere; cancel this ping
2013-08-22 04:34:33 -07:00
bPingFinished = true ;
sProblem = " Short payload " ;
}
2013-11-11 16:20:39 +01:00
2013-08-22 04:34:33 -07:00
if ( ! ( sProblem . empty ( ) ) ) {
2015-09-07 08:19:57 +00:00
LogPrint ( " net " , " pong peer=%d: %s, %x expected, %x received, %u bytes \n " ,
2014-02-26 17:55:04 -08:00
pfrom - > id ,
2014-01-16 16:15:27 +01:00
sProblem ,
2013-10-15 14:50:58 +02:00
pfrom - > nPingNonceSent ,
nonce ,
nAvail ) ;
2013-08-22 04:34:33 -07:00
}
if ( bPingFinished ) {
pfrom - > nPingNonceSent = 0 ;
}
2010-08-29 16:58:15 +00:00
}
2015-12-07 15:31:32 +01:00
else if ( strCommand = = NetMsgType : : FILTERLOAD )
2012-08-13 05:26:29 +02:00
{
2017-04-25 10:06:26 +02:00
if ( ! GetBoolArg ( " -peerbloomfilters " , true ) ) {
2017-03-21 23:54:31 +01:00
LOCK ( cs_main ) ;
2017-03-23 20:34:57 +01:00
Misbehaving ( pfrom - > GetId ( ) , 100 ) ;
2017-03-21 23:54:31 +01:00
return false ;
}
2012-08-13 05:26:29 +02:00
CBloomFilter filter ;
vRecv > > filter ;
2016-07-06 20:16:18 +02:00
2017-03-21 23:54:31 +01:00
if ( ! filter . IsWithinSizeConstraints ( ) ) {
2012-08-13 05:26:29 +02:00
// There is no excuse for sending a too-large filter
2017-03-21 23:54:31 +01:00
LOCK ( cs_main ) ;
2013-11-18 01:25:17 +01:00
Misbehaving ( pfrom - > GetId ( ) , 100 ) ;
2017-03-21 23:54:31 +01:00
return false ;
} else {
2012-08-13 05:26:29 +02:00
LOCK ( pfrom - > cs_filter ) ;
delete pfrom - > pfilter ;
pfrom - > pfilter = new CBloomFilter ( filter ) ;
2020-04-10 12:21:49 +02:00
pfrom - > pfilter - > updateEmptyFull ( ) ;
2012-08-13 05:26:29 +02:00
}
2012-08-20 21:10:25 -04:00
pfrom - > fRelayTxes = true ;
2012-08-13 05:26:29 +02:00
}
2015-12-07 15:31:32 +01:00
else if ( strCommand = = NetMsgType : : FILTERADD )
2012-08-13 05:26:29 +02:00
{
2017-04-25 10:06:26 +02:00
if ( ! GetBoolArg ( " -peerbloomfilters " , true ) ) {
2017-03-21 23:54:31 +01:00
LOCK ( cs_main ) ;
2017-03-23 20:34:57 +01:00
Misbehaving ( pfrom - > GetId ( ) , 100 ) ;
2017-03-21 23:54:31 +01:00
return false ;
}
2017-08-15 10:24:20 -06:00
std : : vector < unsigned char > vData ;
2012-08-13 05:26:29 +02:00
vRecv > > vData ;
// Nodes must NEVER send a data item > 520 bytes (the max size for a script data object,
// and thus, the maximum size any matched object can have) in a filteradd message
2017-03-21 23:54:31 +01:00
if ( vData . size ( ) > MAX_SCRIPT_ELEMENT_SIZE ) {
LOCK ( cs_main ) ;
2013-11-18 01:25:17 +01:00
Misbehaving ( pfrom - > GetId ( ) , 100 ) ;
2017-03-21 23:54:31 +01:00
return false ;
2012-08-13 05:26:29 +02:00
} else {
LOCK ( pfrom - > cs_filter ) ;
if ( pfrom - > pfilter )
pfrom - > pfilter - > insert ( vData ) ;
else
2013-11-18 01:25:17 +01:00
Misbehaving ( pfrom - > GetId ( ) , 100 ) ;
2012-08-13 05:26:29 +02:00
}
}
2015-12-07 15:31:32 +01:00
else if ( strCommand = = NetMsgType : : FILTERCLEAR )
2012-08-13 05:26:29 +02:00
{
2017-04-25 10:06:26 +02:00
if ( ! GetBoolArg ( " -peerbloomfilters " , true ) ) {
2017-03-21 23:54:31 +01:00
LOCK ( cs_main ) ;
2017-03-23 20:34:57 +01:00
Misbehaving ( pfrom - > GetId ( ) , 100 ) ;
2017-03-21 23:54:31 +01:00
return false ;
}
2012-08-13 05:26:29 +02:00
LOCK ( pfrom - > cs_filter ) ;
delete pfrom - > pfilter ;
2013-08-18 20:21:06 -07:00
pfrom - > pfilter = new CBloomFilter ( ) ;
2012-08-20 21:10:25 -04:00
pfrom - > fRelayTxes = true ;
2012-08-13 05:26:29 +02:00
}
2019-09-02 23:35:14 +02:00
else if ( strCommand = = NetMsgType : : DSPROOF ) {
2020-01-12 17:03:13 +01:00
logInfo ( Log : : DSProof ) < < " Got DSPROOF message " ;
2019-09-02 23:35:14 +02:00
uint256 hash ;
try {
DoubleSpendProof dsp ;
vRecv > > dsp ;
if ( dsp . isEmpty ( ) )
throw std : : runtime_error ( " DSP empty " ) ;
hash = dsp . createHash ( ) ;
2020-01-12 17:03:13 +01:00
const CInv inv ( MSG_DOUBLESPENDPROOF , hash ) ;
logDebug ( Log : : DSProof ) < < " DSP " < < inv ;
2019-09-02 23:35:14 +02:00
pfrom - > setAskFor . erase ( inv . hash ) ;
{
LOCK ( cs_main ) ;
mapAlreadyAskedFor . erase ( hash ) ;
}
2020-01-08 16:22:14 +01:00
switch ( dsp . validate ( mempool ) ) {
2019-09-02 23:35:14 +02:00
case DoubleSpendProof : : Valid : {
const auto tx = mempool . addDoubleSpendProof ( dsp ) ;
if ( tx . size ( ) > 0 ) { // added to mempool correctly, then forward to nodes.
2020-01-11 13:06:58 +01:00
logDebug ( Log : : DSProof ) < < " Good DSP, broadcasting an INV " ;
2019-09-02 23:35:14 +02:00
ValidationNotifier ( ) . DoubleSpendFound ( tx , dsp ) ;
2020-01-12 17:03:13 +01:00
CTransaction dspTx = tx . createOldTransaction ( ) ;
2019-09-02 23:35:14 +02:00
LOCK ( cs_vNodes ) ;
for ( CNode * pnode : vNodes ) {
2020-01-12 17:03:13 +01:00
if ( ! pnode - > fRelayTxes | | pnode = = pfrom )
2019-09-02 23:35:14 +02:00
continue ;
LOCK ( pnode - > cs_filter ) ;
if ( pnode - > pfilter ) {
// For nodes that we sent this Tx before, send a proof.
2020-04-10 12:21:49 +02:00
if ( pnode - > pfilter - > isRelevantAndUpdate ( dspTx ) )
2019-09-02 23:35:14 +02:00
pnode - > PushInventory ( inv ) ;
} else {
pnode - > PushInventory ( inv ) ;
}
}
}
2020-01-11 13:06:58 +01:00
else logDebug ( Log : : DSProof ) < < " valid, not propagating " ;
2019-09-02 23:35:14 +02:00
break ;
}
case DoubleSpendProof : : MissingUTXO :
2020-01-12 17:03:13 +01:00
case DoubleSpendProof : : MissingTransaction :
logInfo ( Log : : DSProof ) < < " DoubleSpend Proof postponed: is orphan " ;
mempool . doubleSpendProofStorage ( ) - > addOrphan ( dsp , pfrom - > id ) ;
break ;
2019-09-02 23:35:14 +02:00
case DoubleSpendProof : : Invalid :
throw std : : runtime_error ( " Proof didn't validate " ) ;
default :
assert ( false ) ;
return false ;
}
} catch ( const std : : exception & e ) {
2020-01-12 17:03:13 +01:00
logWarning ( Log : : DSProof ) < < " Failure handling double spend proof. Peer: " < < pfrom - > GetId ( ) < < " Reason: " < < e ;
2019-09-02 23:35:14 +02:00
if ( ! hash . IsNull ( ) )
mempool . doubleSpendProofStorage ( ) - > markProofRejected ( hash ) ;
LOCK ( cs_main ) ;
Misbehaving ( pfrom - > GetId ( ) , 10 ) ;
return false ;
}
}
2012-08-13 05:26:29 +02:00
2015-12-07 15:31:32 +01:00
else if ( strCommand = = NetMsgType : : REJECT )
2013-10-28 16:36:11 +10:00
{
2018-02-15 16:14:35 +01:00
# ifndef NDEBUG
try {
std : : string strMsg ; unsigned char ccode ; std : : string strReason ;
vRecv > > LIMITED_STRING ( strMsg , CMessageHeader : : COMMAND_SIZE ) > > ccode > > LIMITED_STRING ( strReason , MAX_REJECT_MESSAGE_LENGTH ) ;
2013-10-28 16:36:11 +10:00
2018-02-15 16:14:35 +01:00
std : : ostringstream ss ;
ss < < strMsg < < " code " < < itostr ( ccode ) < < " : " < < strReason ;
2013-10-28 16:36:11 +10:00
2018-02-15 16:14:35 +01:00
if ( strMsg = = NetMsgType : : BLOCK | | strMsg = = NetMsgType : : TX )
{
uint256 hash ;
vRecv > > hash ;
ss < < " : hash " < < hash . ToString ( ) ;
2013-10-28 16:36:11 +10:00
}
2018-02-15 16:14:35 +01:00
LogPrint ( " net " , " Reject %s \n " , SanitizeString ( ss . str ( ) ) ) ;
} catch ( const std : : ios_base : : failure & ) {
// Avoid feedback loops by preventing reject messages from triggering a new reject message.
LogPrint ( " net " , " Unparseable reject message received \n " ) ;
2013-10-28 16:36:11 +10:00
}
2018-02-15 16:14:35 +01:00
# endif
2013-10-28 16:36:11 +10:00
}
2010-08-29 16:58:15 +00:00
else
{
// Ignore unknown commands for extensibility
2017-07-23 22:16:30 +02:00
logDebug ( Log : : Net ) < < " Unknown command " < < SanitizeString ( strCommand ) < < " from peer: " < < pfrom - > id ;
2010-08-29 16:58:15 +00:00
}
return true ;
}
2012-11-15 19:41:12 -05:00
// requires LOCK(cs_vRecvMsg)
2011-06-01 18:27:05 +02:00
bool ProcessMessages ( CNode * pfrom )
{
2015-04-17 14:19:21 +02:00
const CChainParams & chainparams = Params ( ) ;
2011-06-01 18:27:05 +02:00
//if (fDebug)
2015-02-24 18:32:34 +01:00
// LogPrintf("%s(%u messages)\n", __func__, pfrom->vRecvMsg.size());
2010-08-29 16:58:15 +00:00
2011-06-01 18:27:05 +02:00
//
// Message format
// (4) message start
// (12) command
// (4) size
// (4) checksum
// (x) data
//
2013-03-01 01:41:28 +01:00
bool fOk = true ;
2010-08-29 16:58:15 +00:00
2013-03-29 23:49:38 +01:00
if ( ! pfrom - > vRecvGetData . empty ( ) )
2015-04-17 14:19:21 +02:00
ProcessGetData ( pfrom , chainparams . GetConsensus ( ) ) ;
2013-11-11 16:20:39 +01:00
2013-10-28 13:20:21 -07:00
// this maintains the order of responses
if ( ! pfrom - > vRecvGetData . empty ( ) ) return fOk ;
2013-11-11 16:20:39 +01:00
2013-03-01 01:41:28 +01:00
std : : deque < CNetMessage > : : iterator it = pfrom - > vRecvMsg . begin ( ) ;
2013-03-24 16:52:24 +01:00
while ( ! pfrom - > fDisconnect & & it ! = pfrom - > vRecvMsg . end ( ) ) {
2012-03-21 22:10:50 -04:00
// Don't bother if send buffer is too full to respond anyway
2013-03-24 16:52:24 +01:00
if ( pfrom - > nSendSize > = SendBufferSize ( ) )
2012-03-21 22:10:50 -04:00
break ;
2013-03-01 01:41:28 +01:00
// get next message
CNetMessage & msg = * it ;
2012-11-15 19:41:12 -05:00
//if (fDebug)
2015-02-24 18:32:34 +01:00
// LogPrintf("%s(message %u msgsz, %u bytes, complete:%s)\n", __func__,
2012-11-15 19:41:12 -05:00
// msg.hdr.nMessageSize, msg.vRecv.size(),
// msg.complete() ? "Y" : "N");
2013-03-01 01:41:28 +01:00
// end, if an incomplete message is found
2012-11-15 19:41:12 -05:00
if ( ! msg . complete ( ) )
2011-06-01 18:27:05 +02:00
break ;
2012-11-15 19:41:12 -05:00
2013-03-01 01:41:28 +01:00
// at this point, any failure means we can delete the current message
it + + ;
2012-11-15 19:41:12 -05:00
// Scan for message start
2017-07-30 18:11:00 +02:00
if ( pfrom - > nVersion = = 0 ) { // uninitialized.
2017-09-18 15:38:45 +02:00
if ( ! pfrom - > fInbound // we already set isCashNode bool to right value.
2018-10-11 12:04:40 +02:00
& & memcmp ( msg . hdr . pchMessageStart , chainparams . magic ( ) , MESSAGE_START_SIZE ) ! = 0 ) {
2017-10-06 16:34:20 +02:00
addrman . increaseUselessness ( pfrom - > addr ) ;
2017-09-18 15:38:45 +02:00
fOk = false ;
break ;
}
2018-04-15 22:35:34 +02:00
if ( memcmp ( msg . hdr . pchMessageStart , chainparams . magic ( ) , MESSAGE_START_SIZE ) ! = 0 ) {
logWarning ( Log : : Net ) < < " ProcessMessage: handshake invalid messageStart "
< < SanitizeString ( msg . hdr . GetCommand ( ) ) < < " peer: " < < pfrom - > id ;
addrman . increaseUselessness ( pfrom - > addr ) ;
fOk = false ;
break ;
2017-07-30 18:11:00 +02:00
}
2018-04-15 22:35:34 +02:00
assert ( memcmp ( msg . hdr . pchMessageStart , Params ( ) . magic ( ) , MESSAGE_START_SIZE ) = = 0 ) ;
2017-10-06 16:34:20 +02:00
addrman . increaseUselessness ( pfrom - > addr , - 1 ) ;
2011-06-01 18:27:05 +02:00
}
2010-08-29 16:58:15 +00:00
2011-06-01 18:27:05 +02:00
// Read header
2012-11-15 19:41:12 -05:00
CMessageHeader & hdr = msg . hdr ;
2018-04-15 22:35:34 +02:00
if ( ! hdr . IsValid ( Params ( ) . magic ( ) ) ) {
2017-09-18 15:38:45 +02:00
logWarning ( Log : : Net ) < < " PROCESSMESSAGE: ERRORS IN HEADER " < < SanitizeString ( msg . hdr . GetCommand ( ) ) < < " peer: " < < pfrom - > id ;
LOCK ( cs_main ) ;
Misbehaving ( pfrom - > id , 5 ) ;
2011-06-01 18:27:05 +02:00
continue ;
}
2017-08-15 10:24:20 -06:00
std : : string strCommand = hdr . GetCommand ( ) ;
2011-06-01 18:27:05 +02:00
// Message size
unsigned int nMessageSize = hdr . nMessageSize ;
// Checksum
2012-11-15 19:41:12 -05:00
CDataStream & vRecv = msg . vRecv ;
2012-02-20 01:33:31 +01:00
uint256 hash = Hash ( vRecv . begin ( ) , vRecv . begin ( ) + nMessageSize ) ;
2014-12-19 11:38:30 +01:00
unsigned int nChecksum = ReadLE32 ( ( unsigned char * ) & hash ) ;
2012-02-20 01:33:31 +01:00
if ( nChecksum ! = hdr . nChecksum )
2011-06-01 18:27:05 +02:00
{
2015-02-24 18:32:34 +01:00
LogPrintf ( " %s(%s, %u bytes): CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x \n " , __func__ ,
2015-02-08 00:59:58 +00:00
SanitizeString ( strCommand ) , nMessageSize , nChecksum , hdr . nChecksum ) ;
2012-02-20 01:33:31 +01:00
continue ;
2011-06-01 18:27:05 +02:00
}
// Process message
bool fRet = false ;
try
{
2014-07-06 16:06:46 +02:00
fRet = ProcessMessage ( pfrom , strCommand , vRecv , msg . nTime ) ;
2013-03-09 12:02:57 -05:00
boost : : this_thread : : interruption_point ( ) ;
2011-06-01 18:27:05 +02:00
}
2014-12-07 13:29:06 +01:00
catch ( const std : : ios_base : : failure & e )
2011-06-01 18:27:05 +02:00
{
2017-08-15 10:24:20 -06:00
pfrom - > PushMessage ( NetMsgType : : REJECT , strCommand , REJECT_MALFORMED , std : : string ( " error parsing message " ) ) ;
2011-06-01 18:27:05 +02:00
if ( strstr ( e . what ( ) , " end of data " ) )
{
2012-07-26 00:48:39 +00:00
// Allow exceptions from under-length message on vRecv
2015-02-24 18:32:34 +01:00
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 ( ) ) ;
2011-06-01 18:27:05 +02:00
}
else if ( strstr ( e . what ( ) , " size too large " ) )
{
2012-07-26 00:48:39 +00:00
// Allow exceptions from over-long size
2015-02-24 18:32:34 +01:00
LogPrintf ( " %s(%s, %u bytes): Exception '%s' caught \n " , __func__ , SanitizeString ( strCommand ) , nMessageSize , e . what ( ) ) ;
2011-06-01 18:27:05 +02:00
}
else
{
2012-05-22 12:06:08 +01:00
PrintExceptionContinue ( & e , " ProcessMessages() " ) ;
2011-06-01 18:27:05 +02:00
}
}
2014-12-07 13:29:06 +01:00
catch ( const boost : : thread_interrupted & ) {
2013-03-09 12:02:57 -05:00
throw ;
}
2014-12-07 13:29:06 +01:00
catch ( const std : : exception & e ) {
2012-05-22 12:06:08 +01:00
PrintExceptionContinue ( & e , " ProcessMessages() " ) ;
2011-06-01 18:27:05 +02:00
} catch ( . . . ) {
2018-06-12 20:43:50 +02:00
PrintExceptionContinue ( nullptr , " ProcessMessages() " ) ;
2011-06-01 18:27:05 +02:00
}
if ( ! fRet )
2015-02-24 18:32:34 +01:00
LogPrintf ( " %s(%s, %u bytes) FAILED peer=%d \n " , __func__ , SanitizeString ( strCommand ) , nMessageSize , pfrom - > id ) ;
2013-11-11 16:20:39 +01:00
2013-10-28 13:20:21 -07:00
break ;
2011-06-01 18:27:05 +02:00
}
2013-03-24 16:52:24 +01:00
// In case the connection got shut down, its receive buffer was wiped
if ( ! pfrom - > fDisconnect )
pfrom - > vRecvMsg . erase ( pfrom - > vRecvMsg . begin ( ) , it ) ;
2013-03-01 01:41:28 +01:00
return fOk ;
2011-06-01 18:27:05 +02:00
}
2010-08-29 16:58:15 +00:00
2015-04-08 11:20:00 -07:00
bool SendMessages ( CNode * pto )
2010-08-29 16:58:15 +00:00
{
2017-02-27 17:22:39 +01:00
const bool fReindex = Blocks : : DB : : instance ( ) - > isReindexing ( ) ;
2015-04-10 18:35:09 +02:00
const Consensus : : Params & consensusParams = Params ( ) . GetConsensus ( ) ;
2013-07-20 14:34:16 +02:00
{
2015-04-28 14:47:17 +00:00
// Don't send anything until we get its version message
2010-08-29 16:58:15 +00:00
if ( pto - > nVersion = = 0 )
return true ;
2013-08-22 04:34:33 -07:00
//
// Message: ping
//
bool pingSend = false ;
if ( pto - > fPingQueued ) {
// RPC ping request by user
pingSend = true ;
}
2013-10-15 00:34:20 +02:00
if ( pto - > nPingNonceSent = = 0 & & pto - > nPingUsecStart + PING_INTERVAL * 1000000 < GetTimeMicros ( ) ) {
// Ping automatically sent as a latency probe & keepalive.
2013-08-22 04:34:33 -07:00
pingSend = true ;
}
if ( pingSend ) {
2013-04-13 00:13:08 -05:00
uint64_t nonce = 0 ;
2013-08-22 04:34:33 -07:00
while ( nonce = = 0 ) {
2014-06-24 14:27:32 +02:00
GetRandBytes ( ( unsigned char * ) & nonce , sizeof ( nonce ) ) ;
2013-08-22 04:34:33 -07:00
}
pto - > fPingQueued = false ;
2013-10-15 00:34:20 +02:00
pto - > nPingUsecStart = GetTimeMicros ( ) ;
2013-08-22 04:34:33 -07:00
if ( pto - > nVersion > BIP0031_VERSION ) {
2013-10-15 00:34:20 +02:00
pto - > nPingNonceSent = nonce ;
2015-12-07 15:31:32 +01:00
pto - > PushMessage ( NetMsgType : : PING , nonce ) ;
2013-08-22 04:34:33 -07:00
} else {
2013-10-15 00:34:20 +02:00
// Peer is too old to support ping command with nonce, pong will never arrive.
pto - > nPingNonceSent = 0 ;
2015-12-07 15:31:32 +01:00
pto - > PushMessage ( NetMsgType : : PING ) ;
2013-08-22 04:34:33 -07:00
}
2012-04-11 12:38:03 -04:00
}
2010-08-29 16:58:15 +00:00
2014-04-15 17:38:25 +02:00
TRY_LOCK ( cs_main , lockMain ) ; // Acquire cs_main for IsInitialBlockDownload() and CNodeState()
if ( ! lockMain )
return true ;
2010-08-29 16:58:15 +00:00
// Address refresh broadcast
2019-06-17 22:07:17 +02:00
if ( pindexBestHeader = = nullptr )
pindexBestHeader = chainActive . Tip ( ) ;
2015-04-08 11:20:00 -07:00
int64_t nNow = GetTimeMicros ( ) ;
if ( ! IsInitialBlockDownload ( ) & & pto - > nNextLocalAddrSend < nNow ) {
2016-02-12 11:35:32 -07:00
AdvertiseLocal ( pto ) ;
2017-05-10 17:56:20 +02:00
pto - > nNextLocalAddrSend = nNow + AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL * 1000000 + rand ( ) % 500000000 ;
2010-08-29 16:58:15 +00:00
}
//
// Message: addr
//
2015-04-08 11:20:00 -07:00
if ( pto - > nNextAddrSend < nNow ) {
pto - > nNextAddrSend = PoissonNextSend ( nNow , AVG_ADDRESS_BROADCAST_INTERVAL ) ;
2017-08-15 10:24:20 -06:00
std : : vector < CAddress > vAddr ;
2010-08-29 16:58:15 +00:00
vAddr . reserve ( pto - > vAddrToSend . size ( ) ) ;
2018-12-30 15:33:11 +01:00
for ( const CAddress & addr : pto - > vAddrToSend ) {
2015-04-25 16:25:44 -04:00
if ( ! pto - > addrKnown . contains ( addr . GetKey ( ) ) )
2010-08-29 16:58:15 +00:00
{
2015-04-25 16:25:44 -04:00
pto - > addrKnown . insert ( addr . GetKey ( ) ) ;
2010-08-29 16:58:15 +00:00
vAddr . push_back ( addr ) ;
// receiver rejects addr messages larger than 1000
if ( vAddr . size ( ) > = 1000 )
{
2015-12-07 15:31:32 +01:00
pto - > PushMessage ( NetMsgType : : ADDR , vAddr ) ;
2010-08-29 16:58:15 +00:00
vAddr . clear ( ) ;
}
}
}
pto - > vAddrToSend . clear ( ) ;
if ( ! vAddr . empty ( ) )
2015-12-07 15:31:32 +01:00
pto - > PushMessage ( NetMsgType : : ADDR , vAddr ) ;
2010-08-29 16:58:15 +00:00
}
2013-11-16 19:28:24 +01:00
CNodeState & state = * State ( pto - > GetId ( ) ) ;
if ( state . fShouldBan ) {
2014-06-21 13:34:36 +02:00
if ( pto - > fWhitelisted )
LogPrintf ( " Warning: not punishing whitelisted peer %s! \n " , pto - > addr . ToString ( ) ) ;
2013-11-18 01:25:17 +01:00
else {
pto - > fDisconnect = true ;
2014-06-21 13:34:36 +02:00
if ( pto - > addr . IsLocal ( ) )
LogPrintf ( " Warning: not banning local peer %s! \n " , pto - > addr . ToString ( ) ) ;
else
2014-08-28 13:23:24 -04:00
{
2015-06-26 21:38:33 +02:00
CNode : : Ban ( pto - > addr , BanReasonNodeMisbehaving ) ;
2014-08-28 13:23:24 -04:00
}
2013-11-18 01:25:17 +01:00
}
2013-11-16 19:28:24 +01:00
state . fShouldBan = false ;
2013-11-18 01:25:17 +01:00
}
2018-12-30 15:33:11 +01:00
for ( const CBlockReject & reject : state . rejects )
2017-08-15 10:24:20 -06:00
pto - > PushMessage ( NetMsgType : : REJECT , ( std : : string ) NetMsgType : : BLOCK , reject . chRejectCode , reject . strRejectReason , reject . hashBlock ) ;
2013-11-16 19:28:24 +01:00
state . rejects . clear ( ) ;
2013-07-20 14:34:16 +02:00
// Start block sync
2014-10-28 09:33:55 -07:00
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.
2018-01-15 15:26:12 +00:00
if ( ! state . fSyncStarted & & ! pto - > fClient & & ! fReindex ) {
2019-08-05 22:40:33 +02:00
// Only actively request headers from small number of peers, unless we're close to today.
if ( nSyncStarted < 5 | | pindexBestHeader - > GetBlockTime ( ) > GetAdjustedTime ( ) - 24 * 60 * 60 ) {
2014-07-12 00:02:35 +02:00
state . fSyncStarted = true ;
nSyncStarted + + ;
2015-10-14 20:42:49 +02:00
const CBlockIndex * pindexStart = pindexBestHeader ;
/* If possible, start at the block preceding the currently
best known header. This ensures that we always get a
non-empty list of headers back as long as the peer
is up-to-date. With a non-empty response, we can initialise
the peer's known best block. This wouldn't be possible
if we requested starting at pindexBestHeader and
got back an empty response. */
if ( pindexStart - > pprev )
pindexStart = pindexStart - > pprev ;
2017-07-23 22:16:30 +02:00
logDebug ( Log : : Net ) < < " initial getheaders " < < pindexStart - > nHeight < < " to peer: " < < pto - > id < < " startheight: " < < pto - > nStartingHeight ;
2015-12-07 15:31:32 +01:00
pto - > PushMessage ( NetMsgType : : GETHEADERS , chainActive . GetLocator ( pindexStart ) , uint256 ( ) ) ;
2014-07-12 00:02:35 +02:00
}
2013-07-20 14:34:16 +02:00
}
// Resend wallet transactions that haven't gotten in a block yet
// Except during reindex, importing and IBD, when old wallet
// transactions become unconfirmed and spams other nodes.
2018-01-15 15:26:12 +00:00
if ( ! fReindex & & ! IsInitialBlockDownload ( ) )
2013-07-20 14:34:16 +02:00
{
2018-06-12 20:43:50 +02:00
ValidationNotifier ( ) . ResendWalletTransactions ( Blocks : : DB : : instance ( ) - > headerChain ( ) . Tip ( ) - > GetBlockTime ( ) ) ;
2013-07-20 14:34:16 +02:00
}
2010-08-29 16:58:15 +00:00
2014-11-18 22:16:32 +01:00
//
// Try sending block announcements via headers
//
{
// If we have less than MAX_BLOCKS_TO_ANNOUNCE in our
// list of block hashes we're relaying, and our peer wants
// headers announcements, then find the first header
// not yet known to our peer but would connect, and send.
// If no header would connect, or if we have too many
// blocks, or if the peer doesn't want headers, just
// add all to the inv queue.
LOCK ( pto - > cs_inventory ) ;
2017-08-15 10:24:20 -06:00
std : : vector < CBlock > vHeaders ;
2014-11-18 22:16:32 +01:00
bool fRevertToInv = ( ! state . fPreferHeaders | | pto - > vBlockHashesToAnnounce . size ( ) > MAX_BLOCKS_TO_ANNOUNCE ) ;
2018-06-12 20:43:50 +02:00
CBlockIndex * pBestIndex = nullptr ; // last header queued for delivery
2014-11-18 22:16:32 +01:00
ProcessBlockAvailability ( pto - > id ) ; // ensure pindexBestKnownBlock is up-to-date
if ( ! fRevertToInv ) {
bool fFoundStartingHeader = false ;
// Try to find first header that our peer doesn't have, and
// then send all headers past that one. If we come across any
// headers that aren't on chainActive, give up.
2018-12-30 15:33:11 +01:00
for ( const uint256 & hash : pto - > vBlockHashesToAnnounce ) {
2018-01-15 15:26:12 +00:00
CBlockIndex * pindex = Blocks : : Index : : get ( hash ) ;
assert ( pindex ) ;
2014-11-18 22:16:32 +01:00
if ( chainActive [ pindex - > nHeight ] ! = pindex ) {
// Bail out if we reorged away from this block
fRevertToInv = true ;
break ;
}
2018-06-12 20:43:50 +02:00
if ( pBestIndex ! = nullptr & & pindex - > pprev ! = pBestIndex ) {
2016-04-20 13:49:55 -04:00
// This means that the list of blocks to announce don't
// connect to each other.
// This shouldn't really be possible to hit during
// regular operation (because reorgs should take us to
// a chain that has some block not on the prior chain,
// which should be caught by the prior check), but one
// way this could happen is by using invalidateblock /
// reconsiderblock repeatedly on the tip, causing it to
// be added multiple times to vBlockHashesToAnnounce.
// Robustly deal with this rare situation by reverting
// to an inv.
fRevertToInv = true ;
break ;
}
2014-11-18 22:16:32 +01:00
pBestIndex = pindex ;
if ( fFoundStartingHeader ) {
// add this to the headers message
vHeaders . push_back ( pindex - > GetBlockHeader ( ) ) ;
} else if ( PeerHasHeader ( & state , pindex ) ) {
continue ; // keep looking for the first new block
2018-06-12 20:43:50 +02:00
} else if ( pindex - > pprev = = nullptr | | PeerHasHeader ( & state , pindex - > pprev ) ) {
2014-11-18 22:16:32 +01:00
// Peer doesn't have this header but they do have the prior one.
// Start sending headers.
fFoundStartingHeader = true ;
vHeaders . push_back ( pindex - > GetBlockHeader ( ) ) ;
} else {
// Peer doesn't have this header or the prior one -- nothing will
// connect, so bail out.
fRevertToInv = true ;
break ;
}
}
}
if ( fRevertToInv ) {
// If falling back to using an inv, just try to inv the tip.
// The last entry in vBlockHashesToAnnounce was our tip at some point
// in the past.
if ( ! pto - > vBlockHashesToAnnounce . empty ( ) ) {
const uint256 & hashToAnnounce = pto - > vBlockHashesToAnnounce . back ( ) ;
2018-01-15 15:26:12 +00:00
CBlockIndex * pindex = Blocks : : Index : : get ( hashToAnnounce ) ;
assert ( pindex ) ;
2014-11-18 22:16:32 +01:00
// Warn if we're announcing a block that is not on the main chain.
// This should be very rare and could be optimized out.
// Just log for now.
if ( chainActive [ pindex - > nHeight ] ! = pindex ) {
LogPrint ( " net " , " Announcing block %s not on main chain (tip=%s) \n " ,
hashToAnnounce . ToString ( ) , chainActive . Tip ( ) - > GetBlockHash ( ) . ToString ( ) ) ;
}
// If the peer announced this block to us, don't inv it back.
// (Since block announcements may not be via inv's, we can't solely rely on
// setInventoryKnown to track this.)
if ( ! PeerHasHeader ( & state , pindex ) ) {
pto - > PushInventory ( CInv ( MSG_BLOCK , hashToAnnounce ) ) ;
LogPrint ( " net " , " %s: sending inv peer=%d hash=%s \n " , __func__ ,
pto - > id , hashToAnnounce . ToString ( ) ) ;
}
}
} else if ( ! vHeaders . empty ( ) ) {
if ( vHeaders . size ( ) > 1 ) {
LogPrint ( " net " , " %s: %u headers, range (%s, %s), to peer=%d \n " , __func__ ,
vHeaders . size ( ) ,
vHeaders . front ( ) . GetHash ( ) . ToString ( ) ,
vHeaders . back ( ) . GetHash ( ) . ToString ( ) , pto - > id ) ;
} else {
LogPrint ( " net " , " %s: sending header %s to peer=%d \n " , __func__ ,
vHeaders . front ( ) . GetHash ( ) . ToString ( ) , pto - > id ) ;
}
2015-12-07 15:31:32 +01:00
pto - > PushMessage ( NetMsgType : : HEADERS , vHeaders ) ;
2014-11-18 22:16:32 +01:00
state . pindexBestHeaderSent = pBestIndex ;
}
pto - > vBlockHashesToAnnounce . clear ( ) ;
}
2010-08-29 16:58:15 +00:00
//
// Message: inventory
//
2017-08-15 10:24:20 -06:00
std : : vector < CInv > vInv ;
std : : vector < CInv > vInvWait ;
2010-08-29 16:58:15 +00:00
{
2015-04-08 11:20:00 -07:00
bool fSendTrickle = pto - > fWhitelisted ;
if ( pto - > nNextInvSend < nNow ) {
fSendTrickle = true ;
pto - > nNextInvSend = PoissonNextSend ( nNow , AVG_INVENTORY_BROADCAST_INTERVAL ) ;
}
2012-04-06 18:39:12 +02:00
LOCK ( pto - > cs_inventory ) ;
2015-04-08 11:20:00 -07:00
vInv . reserve ( std : : min < size_t > ( 1000 , pto - > vInventoryToSend . size ( ) ) ) ;
2010-08-29 16:58:15 +00:00
vInvWait . reserve ( pto - > vInventoryToSend . size ( ) ) ;
2018-12-30 15:33:11 +01:00
for ( const CInv & inv : pto - > vInventoryToSend ) {
2015-11-26 05:25:30 +00:00
if ( inv . type = = MSG_TX & & pto - > filterInventoryKnown . contains ( inv . hash ) )
2010-08-29 16:58:15 +00:00
continue ;
// trickle out tx inv to protect privacy
if ( inv . type = = MSG_TX & & ! fSendTrickle )
{
// 1/4 of tx invs blast to all immediately
static uint256 hashSalt ;
2014-12-15 09:11:16 +01:00
if ( hashSalt . IsNull ( ) )
2012-05-17 12:13:14 -04:00
hashSalt = GetRandHash ( ) ;
2014-12-16 15:43:03 +01:00
uint256 hashRand = ArithToUint256 ( UintToArith256 ( inv . hash ) ^ UintToArith256 ( hashSalt ) ) ;
2010-08-29 16:58:15 +00:00
hashRand = Hash ( BEGIN ( hashRand ) , END ( hashRand ) ) ;
2014-12-16 15:43:03 +01:00
bool fTrickleWait = ( ( UintToArith256 ( hashRand ) & 3 ) ! = 0 ) ;
2010-08-29 16:58:15 +00:00
if ( fTrickleWait )
{
vInvWait . push_back ( inv ) ;
continue ;
}
}
2015-11-26 05:25:30 +00:00
pto - > filterInventoryKnown . insert ( inv . hash ) ;
vInv . push_back ( inv ) ;
if ( vInv . size ( ) > = 1000 )
2010-08-29 16:58:15 +00:00
{
2015-12-07 15:31:32 +01:00
pto - > PushMessage ( NetMsgType : : INV , vInv ) ;
2015-11-26 05:25:30 +00:00
vInv . clear ( ) ;
2010-08-29 16:58:15 +00:00
}
}
pto - > vInventoryToSend = vInvWait ;
}
if ( ! vInv . empty ( ) )
2015-12-07 15:31:32 +01:00
pto - > PushMessage ( NetMsgType : : INV , vInv ) ;
2010-08-29 16:58:15 +00:00
2014-07-12 00:02:35 +02:00
// Detect whether we're stalling
2015-04-08 11:20:00 -07:00
nNow = GetTimeMicros ( ) ;
2014-07-12 00:02:35 +02:00
if ( ! pto - > fDisconnect & & state . nStallingSince & & state . nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT ) {
// Stalling only triggers when the block download window cannot move. During normal steady state,
// the download window should be much larger than the to-be-downloaded set of blocks, so disconnection
// should only happen during initial block download.
2019-02-25 21:35:05 +01:00
logCritical ( Log : : Net ) < < " Peer " < < pto - > id < < " is stalling block download, disconnecting " ;
2014-01-10 13:23:26 +01:00
pto - > fDisconnect = true ;
}
2016-04-03 15:24:09 +02:00
// In case there is a block that has been in flight from this peer for 2 + 0.5 * N times the block interval
// (with N the number of peers from which we're downloading validated blocks), disconnect due to timeout.
// We compensate for other peers to prevent killing off peers due to our own downstream link
2015-04-28 14:48:28 +00:00
// being saturated. We only count validated in-flight blocks so peers can't advertise non-existing block hashes
2015-01-06 17:05:46 +01:00
// to unreasonably increase our timeout.
2015-04-06 13:10:33 -04:00
if ( ! pto - > fDisconnect & & state . vBlocksInFlight . size ( ) > 0 ) {
QueuedBlock & queuedBlock = state . vBlocksInFlight . front ( ) ;
2016-04-03 15:24:09 +02:00
int nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - ( state . nBlocksInFlightValidHeaders > 0 ) ;
if ( nNow > state . nDownloadingSince + consensusParams . nPowTargetSpacing * ( BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads ) ) {
2019-02-25 21:35:05 +01:00
logCritical ( Log : : Net ) < < " Timeout downloading block " < < queuedBlock . hash < < " from peer " < < pto - > id < < " disconnecting " ;
2015-04-06 13:10:33 -04:00
pto - > fDisconnect = true ;
}
2015-01-06 17:05:46 +01:00
}
2014-01-10 13:23:26 +01:00
2010-08-29 16:58:15 +00:00
//
2014-01-10 13:23:26 +01:00
// Message: getdata (blocks)
2010-08-29 16:58:15 +00:00
//
2017-08-15 10:24:20 -06:00
std : : vector < CInv > vGetData ;
2015-01-12 09:55:48 -05:00
if ( ! pto - > fDisconnect & & ! pto - > fClient & & ( fFetch | | ! IsInitialBlockDownload ( ) ) & & state . nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER ) {
2017-08-15 10:24:20 -06:00
std : : vector < CBlockIndex * > vToDownload ;
2014-07-12 00:02:35 +02:00
NodeId staller = - 1 ;
FindNextBlocksToDownload ( pto - > GetId ( ) , MAX_BLOCKS_IN_TRANSIT_PER_PEER - state . nBlocksInFlight , vToDownload , staller ) ;
2018-12-30 15:33:11 +01:00
for ( CBlockIndex * pindex : vToDownload ) {
2016-01-15 21:37:25 -08:00
// BUIP010 Xtreme Thinblocks: begin section
if ( IsThinBlocksEnabled ( ) & & IsChainNearlySyncd ( ) ) {
2016-02-29 13:15:11 -08:00
CDataStream ss ( SER_NETWORK , PROTOCOL_VERSION ) ;
2016-07-08 12:14:24 +02:00
if ( HaveThinblockNodes ( ) & & CheckThinblockTimer ( pindex - > GetBlockHash ( ) ) ) {
2016-01-15 21:37:25 -08:00
// Must download a block from a ThinBlock peer
2016-03-07 15:02:51 -08:00
if ( pto - > mapThinBlocksInFlight . size ( ) < 1 & & pto - > ThinBlockCapable ( ) ) { // We can only send one thinblock per peer at a time
2016-01-15 21:37:25 -08:00
pto - > mapThinBlocksInFlight [ pindex - > GetBlockHash ( ) ] = GetTime ( ) ;
2017-02-08 17:17:38 +01:00
CBloomFilter filterMemPool = createSeededBloomFilter ( CTxOrphanCache : : instance ( ) - > fetchTransactionIds ( ) ) ;
2016-02-29 13:15:11 -08:00
ss < < CInv ( MSG_XTHINBLOCK , pindex - > GetBlockHash ( ) ) ;
ss < < filterMemPool ;
pto - > PushMessage ( NetMsgType : : GET_XTHIN , ss ) ;
2016-01-15 21:37:25 -08:00
MarkBlockAsInFlight ( pto - > GetId ( ) , pindex - > GetBlockHash ( ) , consensusParams , pindex ) ;
2016-02-16 16:31:25 -05:00
LogPrint ( " thin " , " Requesting thinblock %s (%d) from peer %s (%d) \n " , pindex - > GetBlockHash ( ) . ToString ( ) ,
pindex - > nHeight , pto - > addrName . c_str ( ) , pto - > id ) ;
2016-01-15 21:37:25 -08:00
}
}
else {
// Try to download a thinblock if possible otherwise just download a regular block
2016-03-07 15:02:51 -08:00
if ( pto - > mapThinBlocksInFlight . size ( ) < 1 & & pto - > ThinBlockCapable ( ) ) { // We can only send one thinblock per peer at a time
2016-01-15 21:37:25 -08:00
pto - > mapThinBlocksInFlight [ pindex - > GetBlockHash ( ) ] = GetTime ( ) ;
2017-02-08 17:17:38 +01:00
CBloomFilter filterMemPool = createSeededBloomFilter ( CTxOrphanCache : : instance ( ) - > fetchTransactionIds ( ) ) ;
2016-02-29 13:15:11 -08:00
ss < < CInv ( MSG_XTHINBLOCK , pindex - > GetBlockHash ( ) ) ;
ss < < filterMemPool ;
pto - > PushMessage ( NetMsgType : : GET_XTHIN , ss ) ;
2016-02-16 16:31:25 -05:00
LogPrint ( " thin " , " Requesting Thinblock %s (%d) from peer %s (%d) \n " , pindex - > GetBlockHash ( ) . ToString ( ) ,
pindex - > nHeight , pto - > addrName . c_str ( ) , pto - > id ) ;
2016-01-15 21:37:25 -08:00
}
else {
2016-04-25 14:36:03 +01:00
vGetData . push_back ( CInv ( MSG_BLOCK , pindex - > GetBlockHash ( ) ) ) ;
2017-07-23 22:16:30 +02:00
logDebug ( Log : : Net ) < < " Requesting block " < < pindex - > GetBlockHash ( ) < < pindex - > nHeight < < " from peer " < < pto - > addrName < < pto - > id ;
2016-01-15 21:37:25 -08:00
}
MarkBlockAsInFlight ( pto - > GetId ( ) , pindex - > GetBlockHash ( ) , consensusParams , pindex ) ;
}
}
else {
2016-04-25 14:36:03 +01:00
vGetData . push_back ( CInv ( MSG_BLOCK , pindex - > GetBlockHash ( ) ) ) ;
2016-01-15 21:37:25 -08:00
MarkBlockAsInFlight ( pto - > GetId ( ) , pindex - > GetBlockHash ( ) , consensusParams , pindex ) ;
2017-07-23 22:16:30 +02:00
logDebug ( Log : : Net ) < < " Requesting block " < < pindex - > GetBlockHash ( ) < < pindex - > nHeight < < " from peer " < < pto - > id ;
2016-01-15 21:37:25 -08:00
}
// BUIP010 Xtreme Thinblocks: end section
2014-07-12 00:02:35 +02:00
}
if ( state . nBlocksInFlight = = 0 & & staller ! = - 1 ) {
2014-09-04 01:31:01 +07:00
if ( State ( staller ) - > nStallingSince = = 0 ) {
2014-07-12 00:02:35 +02:00
State ( staller ) - > nStallingSince = nNow ;
2019-05-26 13:27:16 +02:00
logDebug ( Log : : Net ) < < " Stall started peer " < < staller ;
2014-09-04 01:31:01 +07:00
}
2014-01-10 13:23:26 +01:00
}
}
//
// Message: getdata (non-blocks)
//
while ( ! pto - > fDisconnect & & ! pto - > mapAskFor . empty ( ) & & ( * pto - > mapAskFor . begin ( ) ) . first < = nNow )
2010-08-29 16:58:15 +00:00
{
const CInv & inv = ( * pto - > mapAskFor . begin ( ) ) . second ;
2012-07-06 16:33:34 +02:00
if ( ! AlreadyHave ( inv ) )
2010-08-29 16:58:15 +00:00
{
2017-07-23 22:16:30 +02:00
logDebug ( Log : : Net ) < < " Requesting " < < inv < < " peer: " < < pto - > id ;
2010-08-29 16:58:15 +00:00
vGetData . push_back ( inv ) ;
if ( vGetData . size ( ) > = 1000 )
{
2015-12-07 15:31:32 +01:00
pto - > PushMessage ( NetMsgType : : GETDATA , vGetData ) ;
2010-08-29 16:58:15 +00:00
vGetData . clear ( ) ;
}
2015-11-23 01:54:23 +00:00
} else {
//If we're not going to ask, don't expect a response.
pto - > setAskFor . erase ( inv . hash ) ;
2010-08-29 16:58:15 +00:00
}
pto - > mapAskFor . erase ( pto - > mapAskFor . begin ( ) ) ;
}
if ( ! vGetData . empty ( ) )
2015-12-07 15:31:32 +01:00
pto - > PushMessage ( NetMsgType : : GETDATA , vGetData ) ;
2010-08-29 16:58:15 +00:00
}
return true ;
}
2017-08-15 10:24:20 -06:00
std : : string CBlockFileInfo : : ToString ( ) const {
2018-01-15 15:26:12 +00:00
return strprintf ( " CBlockFileInfo(blocks=%u, size=%u) " , nBlocks, nSize) ;
2017-08-15 10:24:20 -06:00
}
2010-08-29 16:58:15 +00:00
2018-01-29 17:35:19 +00:00
void MarkIndexUnsaved ( CBlockIndex * index )
2018-01-15 15:26:12 +00:00
{
LOCK ( cs_main ) ;
setDirtyBlockIndex . insert ( index ) ;
}
2019-11-13 11:46:09 +01:00
2013-03-29 02:17:10 +01:00
class CMainCleanup
{
public :
CMainCleanup ( ) { }
~ CMainCleanup ( ) {
2018-01-15 15:26:12 +00:00
Blocks : : Index : : unload ( ) ;
2013-03-29 02:17:10 +01:00
}
} instance_of_cmaincleanup ;