2010-08-29 09:58:15 -07:00
// Copyright (c) 2009-2010 Satoshi Nakamoto
2014-12-16 17:47:57 -08:00
// Copyright (c) 2009-2014 The Bitcoin Core developers
2014-11-30 17:39:44 -08:00
// Distributed under the MIT software license, see the accompanying
2012-05-18 07:02:28 -07:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2013-04-12 22:13:08 -07:00
# include "main.h"
2013-08-26 22:51:57 -07:00
2016-05-30 09:59:20 -07:00
# include "sodium.h"
2013-04-12 22:13:08 -07:00
# include "addrman.h"
2012-08-28 14:04:54 -07:00
# include "alert.h"
2015-02-04 16:11:44 -08:00
# include "arith_uint256.h"
2013-08-26 22:51:57 -07:00
# include "chainparams.h"
2011-09-08 13:50:58 -07:00
# include "checkpoints.h"
2013-08-26 22:51:57 -07:00
# include "checkqueue.h"
2018-01-27 15:37:43 -08:00
# include "consensus/upgrades.h"
2015-01-24 06:57:12 -08:00
# include "consensus/validation.h"
2017-04-24 23:06:29 -07:00
# include "deprecation.h"
2011-05-15 14:52:31 -07:00
# include "init.h"
2014-10-30 15:50:15 -07:00
# include "merkleblock.h"
2016-09-03 09:39:45 -07:00
# include "metrics.h"
2013-08-26 22:51:57 -07:00
# include "net.h"
2014-03-10 08:46:53 -07:00
# include "pow.h"
2013-08-26 22:51:57 -07:00
# include "txdb.h"
# include "txmempool.h"
2012-04-15 13:10:54 -07:00
# include "ui_interface.h"
2014-10-27 06:42:49 -07:00
# include "undo.h"
2013-04-12 22:13:08 -07:00
# include "util.h"
2013-08-05 18:27:09 -07:00
# include "utilmoneystr.h"
2015-02-04 16:11:44 -08:00
# include "validationinterface.h"
2016-11-14 11:48:55 -08:00
# include "wallet/asyncrpcoperation_sendmany.h"
2017-09-15 12:59:27 -07:00
# include "wallet/asyncrpcoperation_shieldcoinbase.h"
2013-04-12 22:13:08 -07:00
2018-05-03 04:27:56 -07:00
# include <algorithm>
2016-04-26 17:21:22 -07:00
# include <atomic>
2013-10-27 23:36:11 -07:00
# include <sstream>
2013-04-12 22:13:08 -07:00
# include <boost/algorithm/string/replace.hpp>
# include <boost/filesystem.hpp>
# include <boost/filesystem/fstream.hpp>
2015-03-26 08:20:59 -07:00
# include <boost/math/distributions/poisson.hpp>
Split up util.cpp/h
Split up util.cpp/h into:
- string utilities (hex, base32, base64): no internal dependencies, no dependency on boost (apart from foreach)
- money utilities (parsesmoney, formatmoney)
- time utilities (gettime*, sleep, format date):
- and the rest (logging, argument parsing, config file parsing)
The latter is basically the environment and OS handling,
and is stripped of all utility functions, so we may want to
rename it to something else than util.cpp/h for clarity (Matt suggested
osinterface).
Breaks dependency of sha256.cpp on all the things pulled in by util.
2014-08-21 07:11:09 -07:00
# include <boost/thread.hpp>
2016-05-30 20:38:44 -07:00
# include <boost/static_assert.hpp>
2010-08-29 09:58:15 -07:00
2014-10-06 04:04:02 -07:00
using namespace std ;
2010-08-29 09:58:15 -07:00
2013-12-02 11:33:44 -08:00
# if defined(NDEBUG)
2016-10-26 12:57:22 -07:00
# error "Zcash cannot be compiled without assertions."
2013-12-02 11:33:44 -08:00
# endif
2018-05-08 13:28:55 -07:00
# include "librustzcash.h"
2014-11-30 17:39:44 -08:00
/**
* Global state
*/
2010-08-29 09:58:15 -07:00
CCriticalSection cs_main ;
2014-09-03 17:02:44 -07:00
BlockMap mapBlockIndex ;
2013-10-10 14:07:44 -07:00
CChain chainActive ;
2014-07-11 15:03:10 -07:00
CBlockIndex * pindexBestHeader = NULL ;
2018-01-14 08:23:05 -08:00
static int64_t nTimeBestReceived = 0 ;
2012-05-12 21:43:24 -07:00
CWaitableCriticalSection csBestBlock ;
CConditionVariable cvBlockChange ;
2012-12-01 14:04:14 -08:00
int nScriptCheckThreads = 0 ;
2017-01-31 14:28:33 -08:00
bool fExperimentalMode = false ;
2012-09-13 05:33:52 -07:00
bool fImporting = false ;
2012-10-21 12:23:13 -07:00
bool fReindex = false ;
2013-01-10 16:47:57 -08:00
bool fTxIndex = false ;
2019-03-19 12:28:02 -07:00
bool fInsightExplorer = false ; // insightexplorer
bool fAddressIndex = false ; // insightexplorer
2019-04-23 10:06:23 -07:00
bool fSpentIndex = false ; // insightexplorer
2019-02-21 13:01:12 -08:00
bool fTimestampIndex = false ; // insightexplorer
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
bool fHavePruned = false ;
bool fPruneMode = false ;
2014-07-16 17:04:04 -07:00
bool fIsBareMultisigStd = true ;
2015-03-13 09:25:34 -07:00
bool fCheckBlockIndex = false ;
2015-04-22 20:22:36 -07:00
bool fCheckpointsEnabled = true ;
2016-06-14 14:18:52 -07:00
bool fCoinbaseEnforcedProtectionEnabled = true ;
2015-05-03 16:38:08 -07:00
size_t nCoinCacheUsage = 5000 * 300 ;
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
uint64_t nPruneTarget = 0 ;
2015-06-12 03:00:39 -07:00
bool fAlerts = DEFAULT_ALERTS ;
2015-12-14 04:23:45 -08:00
/* If the tip is older than this (in seconds), the node is considered to be in initial block download.
*/
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE ;
2010-08-29 09:58:15 -07:00
2018-02-21 20:21:06 -08:00
unsigned int expiryDelta = DEFAULT_TX_EXPIRY_DELTA ;
2014-03-10 10:59:12 -07:00
/** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */
2016-11-13 20:38:24 -08:00
CFeeRate minRelayTxFee = CFeeRate ( DEFAULT_MIN_RELAY_TX_FEE ) ;
2014-07-03 11:25:32 -07:00
CTxMemPool mempool ( : : minRelayTxFee ) ;
2013-04-25 17:11:27 -07:00
2014-08-28 10:23:24 -07:00
struct COrphanTx {
CTransaction tx ;
NodeId fromPeer ;
} ;
2015-06-16 01:08:26 -07:00
map < uint256 , COrphanTx > mapOrphanTransactions GUARDED_BY ( cs_main ) ; ;
map < uint256 , set < uint256 > > mapOrphanTransactionsByPrev GUARDED_BY ( cs_main ) ; ;
void EraseOrphansFor ( NodeId peer ) EXCLUSIVE_LOCKS_REQUIRED ( cs_main ) ;
2010-08-29 09:58:15 -07:00
2014-11-24 05:51:10 -08:00
/**
* Returns true if there are nRequired or more blocks of minVersion or above
2015-04-01 07:10:37 -07:00
* in the last Consensus : : Params : : nMajorityWindow blocks , starting at pstart and going backwards .
2014-11-24 05:51:10 -08:00
*/
2015-04-01 07:10:37 -07:00
static bool IsSuperMajority ( int minVersion , const CBlockIndex * pstart , unsigned nRequired , const Consensus : : Params & consensusParams ) ;
2015-04-17 05:19:21 -07:00
static void CheckBlockIndex ( const Consensus : : Params & consensusParams ) ;
2014-11-24 05:51:10 -08:00
2014-11-30 17:39:44 -08:00
/** Constant stuff for coinbase transactions we create: */
2012-02-06 12:48:00 -08:00
CScript COINBASE_FLAGS ;
2010-08-29 09:58:15 -07:00
2016-09-12 11:01:28 -07:00
const string strMessageMagic = " Zcash Signed Message: \n " ;
2011-12-23 07:14:57 -08:00
2013-10-13 17:13:44 -07:00
// Internal stuff
namespace {
2014-06-24 05:17:43 -07:00
2014-04-29 23:57:11 -07:00
struct CBlockIndexWorkComparator
{
2015-03-13 09:25:34 -07:00
bool operator ( ) ( CBlockIndex * pa , CBlockIndex * pb ) const {
2014-04-29 23:57:11 -07:00
// First sort by most total work, ...
if ( pa - > nChainWork > pb - > nChainWork ) return false ;
if ( pa - > nChainWork < pb - > nChainWork ) return true ;
// ... then by earliest time received, ...
if ( pa - > nSequenceId < pb - > nSequenceId ) return false ;
if ( pa - > nSequenceId > pb - > nSequenceId ) return true ;
// 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 ;
// Identical blocks.
return false ;
}
} ;
CBlockIndex * pindexBestInvalid ;
2014-07-09 09:04:18 -07:00
2014-11-30 17:39:44 -08:00
/**
2015-03-13 09:25:34 -07:00
* The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS ( for itself and all ancestors ) and
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
* as good as our current tip or better . Entries may be failed , though , and pruning nodes may be
* missing the data for the block .
2014-11-30 17:39:44 -08:00
*/
2014-10-05 23:31:33 -07:00
set < CBlockIndex * , CBlockIndexWorkComparator > setBlockIndexCandidates ;
2014-11-30 17:39:44 -08:00
/** Number of nodes with fSyncStarted. */
2014-07-11 15:02:35 -07:00
int nSyncStarted = 0 ;
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
/** All pairs A->B, where A (or one if its ancestors) misses transactions, but B has transactions.
* Pruned nodes may have entries where B is missing data .
*/
2014-07-11 15:02:35 -07:00
multimap < CBlockIndex * , CBlockIndex * > mapBlocksUnlinked ;
2014-04-29 23:57:11 -07:00
CCriticalSection cs_LastBlockFile ;
2014-09-24 23:21:21 -07:00
std : : vector < CBlockFileInfo > vinfoBlockFile ;
2014-04-29 23:57:11 -07:00
int nLastBlockFile = 0 ;
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
/** Global flag to indicate we should check to see if there are
* block / undo files that should be deleted . Set on startup
* or if we allocate more file space when we ' re in prune mode
*/
bool fCheckForPruning = false ;
2014-04-29 23:57:11 -07:00
2014-11-30 17: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-29 23:57:11 -07:00
CCriticalSection cs_nBlockSequenceId ;
2014-11-30 17:39:44 -08:00
/** Blocks loaded from disk are assigned id 0, so start the counter at 1. */
2014-04-29 23:57:11 -07:00
uint32_t nBlockSequenceId = 1 ;
2014-11-30 17:39:44 -08:00
/**
2015-04-28 07:47:17 -07: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-11-30 17:39:44 -08:00
*/
2014-04-29 23:57:11 -07:00
map < uint256 , NodeId > mapBlockSource ;
2015-07-17 03:46:48 -07: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 50 x
* bandwidth increase . A flooding attacker attempting to roll - over the
* filter using minimum - sized , 60 byte , 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.7 MB
*/
boost : : scoped_ptr < CRollingBloomFilter > recentRejects ;
uint256 hashRecentRejectsChainTip ;
2014-11-30 17:39:44 -08:00
/** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
2014-04-29 23:57:11 -07:00
struct QueuedBlock {
uint256 hash ;
2016-04-03 02:49:36 -07:00
CBlockIndex * pindex ; //!< Optional.
int64_t nTime ; //!< Time of "getdata" request in microseconds.
bool fValidatedHeaders ; //!< Whether this block has validated headers at the time of request.
int64_t nTimeDisconnect ; //!< The timeout for this block request (for disconnecting a slow peer)
2014-04-29 23:57:11 -07:00
} ;
map < uint256 , pair < NodeId , list < QueuedBlock > : : iterator > > mapBlocksInFlight ;
2014-06-24 05:17:43 -07:00
2015-01-06 08:05:46 -08:00
/** Number of blocks in flight with validated headers. */
int nQueuedValidatedHeaders = 0 ;
2014-11-30 17:39:44 -08:00
/** Number of preferable block download peers. */
2014-10-28 09:33:55 -07:00
int nPreferredDownload = 0 ;
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
2014-11-30 17:39:44 -08:00
/** Dirty block index entries. */
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
set < CBlockIndex * > setDirtyBlockIndex ;
2014-11-30 17:39:44 -08:00
/** Dirty block file entries. */
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
set < int > setDirtyFileInfo ;
2014-06-24 05:17:43 -07:00
} // anon namespace
2010-08-29 09:58:15 -07:00
2013-06-05 20:21:41 -07:00
//////////////////////////////////////////////////////////////////////////////
//
// Registration of network node signals.
//
2013-11-17 16:25:17 -08:00
namespace {
2013-11-16 10:28:24 -08:00
struct CBlockReject {
unsigned char chRejectCode ;
string strRejectReason ;
uint256 hashBlock ;
} ;
2014-11-30 17: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-17 16:25:17 -08: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-11-30 17:39:44 -08:00
//! Accumulated misbehaviour score for this peer.
2013-11-17 16:25:17 -08:00
int nMisbehavior ;
2014-11-30 17:39:44 -08:00
//! Whether this peer should be disconnected and banned (unless whitelisted).
2013-11-17 16:25:17 -08:00
bool fShouldBan ;
2014-11-30 17:39:44 -08:00
//! String name of this peer (debugging/logging purposes).
2013-11-17 16:25:17 -08:00
std : : string name ;
2014-11-30 17:39:44 -08:00
//! List of asynchronously-determined block rejections to notify this peer about.
2013-11-16 10:28:24 -08:00
std : : vector < CBlockReject > rejects ;
2014-11-30 17:39:44 -08:00
//! The best known block we know this peer has announced.
2014-06-22 15:00:26 -07:00
CBlockIndex * pindexBestKnownBlock ;
2014-11-30 17:39:44 -08:00
//! The hash of the last unknown block this peer has announced.
2014-06-22 15:00:26 -07:00
uint256 hashLastUnknownBlock ;
2014-11-30 17:39:44 -08:00
//! The last full block we both have.
2014-07-11 15:02:35 -07:00
CBlockIndex * pindexLastCommonBlock ;
2014-11-30 17:39:44 -08:00
//! Whether we've started headers synchronization with this peer.
2014-07-11 15:02:35 -07:00
bool fSyncStarted ;
2014-11-30 17:39:44 -08:00
//! Since when we're stalling block download progress (in microseconds), or 0.
2014-07-11 15:02:35 -07:00
int64_t nStallingSince ;
2014-01-10 04:23:26 -08:00
list < QueuedBlock > vBlocksInFlight ;
int nBlocksInFlight ;
2015-04-06 10:10:33 -07:00
int nBlocksInFlightValidHeaders ;
2014-11-30 17:39:44 -08:00
//! Whether we consider this a preferred download peer.
2014-10-28 09:33:55 -07:00
bool fPreferredDownload ;
2013-11-17 16:25:17 -08:00
CNodeState ( ) {
2015-03-05 04:01:22 -08:00
fCurrentlyConnected = false ;
2013-11-17 16:25:17 -08:00
nMisbehavior = 0 ;
fShouldBan = false ;
2014-06-22 15:00:26 -07:00
pindexBestKnownBlock = NULL ;
2014-12-15 00:11:16 -08:00
hashLastUnknownBlock . SetNull ( ) ;
2014-07-11 15:02:35 -07:00
pindexLastCommonBlock = NULL ;
fSyncStarted = false ;
nStallingSince = 0 ;
2014-01-10 04:23:26 -08:00
nBlocksInFlight = 0 ;
2015-04-06 10:10:33 -07:00
nBlocksInFlightValidHeaders = 0 ;
2014-10-28 09:33:55 -07:00
fPreferredDownload = false ;
2013-11-17 16:25:17 -08:00
}
} ;
2014-11-30 17:39:44 -08:00
/** Map maintaining per-node state. Requires cs_main. */
2013-11-17 16:25:17 -08:00
map < NodeId , CNodeState > mapNodeState ;
// Requires cs_main.
CNodeState * State ( NodeId pnode ) {
map < NodeId , CNodeState > : : iterator it = mapNodeState . find ( pnode ) ;
if ( it = = mapNodeState . end ( ) )
return NULL ;
return & it - > second ;
}
int GetHeight ( )
2013-10-10 14:07:44 -07: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 ;
}
2015-04-06 10:10:33 -07:00
// Returns time at which to timeout block request (nTime in microseconds)
2015-05-27 07:57:17 -07:00
int64_t GetBlockTimeout ( int64_t nTime , int nValidatedQueuedBefore , const Consensus : : Params & consensusParams )
2015-04-06 10:10:33 -07:00
{
2015-05-27 07:57:17 -07:00
return nTime + 500000 * consensusParams . nPowTargetSpacing * ( 4 + nValidatedQueuedBefore ) ;
2015-04-06 10:10:33 -07:00
}
2013-11-17 16:25:17 -08:00
void InitializeNode ( NodeId nodeid , const CNode * pnode ) {
LOCK ( cs_main ) ;
CNodeState & state = mapNodeState . insert ( std : : make_pair ( nodeid , CNodeState ( ) ) ) . first - > second ;
state . name = pnode - > addrName ;
2015-03-05 04:01:22 -08:00
state . address = pnode - > addr ;
2013-11-17 16:25:17 -08:00
}
void FinalizeNode ( NodeId nodeid ) {
LOCK ( cs_main ) ;
2014-01-10 04:23:26 -08:00
CNodeState * state = State ( nodeid ) ;
2014-07-11 15:02:35 -07:00
if ( state - > fSyncStarted )
nSyncStarted - - ;
2015-03-05 04:01:22 -08:00
if ( state - > nMisbehavior = = 0 & & state - > fCurrentlyConnected ) {
AddressCurrentlyConnected ( state - > address ) ;
}
2014-01-10 04:23:26 -08:00
BOOST_FOREACH ( const QueuedBlock & entry , state - > vBlocksInFlight )
mapBlocksInFlight . erase ( entry . hash ) ;
2014-08-28 10:23:24 -07:00
EraseOrphansFor ( nodeid ) ;
2014-10-28 09:33:55 -07:00
nPreferredDownload - = state - > fPreferredDownload ;
2014-01-10 04:23:26 -08:00
2013-11-17 16:25:17 -08:00
mapNodeState . erase ( nodeid ) ;
}
2014-01-10 04:23:26 -08:00
// Requires cs_main.
2015-04-09 10:21:11 -07:00
// Returns a bool indicating whether we requested this block.
bool MarkBlockAsReceived ( const uint256 & hash ) {
2014-01-10 04:23:26 -08:00
map < uint256 , pair < NodeId , list < QueuedBlock > : : iterator > > : : iterator itInFlight = mapBlocksInFlight . find ( hash ) ;
if ( itInFlight ! = mapBlocksInFlight . end ( ) ) {
CNodeState * state = State ( itInFlight - > second . first ) ;
2015-01-06 08:05:46 -08:00
nQueuedValidatedHeaders - = itInFlight - > second . second - > fValidatedHeaders ;
2015-04-06 10:10:33 -07:00
state - > nBlocksInFlightValidHeaders - = itInFlight - > second . second - > fValidatedHeaders ;
2014-01-10 04:23:26 -08:00
state - > vBlocksInFlight . erase ( itInFlight - > second . second ) ;
state - > nBlocksInFlight - - ;
2014-07-11 15:02:35 -07:00
state - > nStallingSince = 0 ;
2014-01-10 04:23:26 -08:00
mapBlocksInFlight . erase ( itInFlight ) ;
2015-04-09 10:21:11 -07:00
return true ;
2014-01-10 04:23:26 -08:00
}
2015-04-09 10:21:11 -07:00
return false ;
2014-01-10 04:23:26 -08:00
}
// Requires cs_main.
2015-05-27 07:57:17 -07:00
void MarkBlockAsInFlight ( NodeId nodeid , const uint256 & hash , const Consensus : : Params & consensusParams , CBlockIndex * pindex = NULL ) {
2014-01-10 04:23:26 -08:00
CNodeState * state = State ( nodeid ) ;
assert ( state ! = NULL ) ;
// Make sure it's not listed somewhere already.
MarkBlockAsReceived ( hash ) ;
2015-04-06 10:10:33 -07:00
int64_t nNow = GetTimeMicros ( ) ;
2015-05-27 07:57:17 -07:00
QueuedBlock newentry = { hash , pindex , nNow , pindex ! = NULL , GetBlockTimeout ( nNow , nQueuedValidatedHeaders , consensusParams ) } ;
2015-01-06 08:05:46 -08:00
nQueuedValidatedHeaders + = newentry . fValidatedHeaders ;
2014-01-10 04:23:26 -08:00
list < QueuedBlock > : : iterator it = state - > vBlocksInFlight . insert ( state - > vBlocksInFlight . end ( ) , newentry ) ;
state - > nBlocksInFlight + + ;
2015-04-06 10:10:33 -07:00
state - > nBlocksInFlightValidHeaders + = newentry . fValidatedHeaders ;
2014-01-10 04:23:26 -08:00
mapBlocksInFlight [ hash ] = std : : make_pair ( nodeid , it ) ;
}
2014-06-22 15:00:26 -07:00
/** Check whether the last unknown block a peer advertized is not yet known. */
void ProcessBlockAvailability ( NodeId nodeid ) {
CNodeState * state = State ( nodeid ) ;
assert ( state ! = NULL ) ;
2014-12-15 00:11:16 -08:00
if ( ! state - > hashLastUnknownBlock . IsNull ( ) ) {
2014-09-03 17:02:44 -07:00
BlockMap : : iterator itOld = mapBlockIndex . find ( state - > hashLastUnknownBlock ) ;
2014-06-22 15:00:26 -07:00
if ( itOld ! = mapBlockIndex . end ( ) & & itOld - > second - > nChainWork > 0 ) {
if ( state - > pindexBestKnownBlock = = NULL | | itOld - > second - > nChainWork > = state - > pindexBestKnownBlock - > nChainWork )
state - > pindexBestKnownBlock = itOld - > second ;
2014-12-15 00:11:16 -08:00
state - > hashLastUnknownBlock . SetNull ( ) ;
2014-06-22 15:00:26 -07:00
}
}
}
/** Update tracking information about which blocks a peer is assumed to have. */
void UpdateBlockAvailability ( NodeId nodeid , const uint256 & hash ) {
CNodeState * state = State ( nodeid ) ;
assert ( state ! = NULL ) ;
ProcessBlockAvailability ( nodeid ) ;
2014-09-03 17:02:44 -07:00
BlockMap : : iterator it = mapBlockIndex . find ( hash ) ;
2014-06-22 15:00:26 -07:00
if ( it ! = mapBlockIndex . end ( ) & & it - > second - > nChainWork > 0 ) {
// An actually better block was announced.
if ( state - > pindexBestKnownBlock = = NULL | | it - > second - > nChainWork > = state - > pindexBestKnownBlock - > nChainWork )
state - > pindexBestKnownBlock = it - > second ;
} else {
// An unknown block was announced; just assume that the latest one is the best one.
state - > hashLastUnknownBlock = hash ;
}
}
2014-07-11 15:02:35 -07:00
/** Find the last common ancestor two blocks have.
* Both pa and pb must be non - NULL . */
CBlockIndex * LastCommonAncestor ( CBlockIndex * pa , CBlockIndex * pb ) {
if ( pa - > nHeight > pb - > nHeight ) {
pa = pa - > GetAncestor ( pb - > nHeight ) ;
} else if ( pb - > nHeight > pa - > nHeight ) {
pb = pb - > GetAncestor ( pa - > nHeight ) ;
}
while ( pa ! = pb & & pa & & pb ) {
pa = pa - > pprev ;
pb = pb - > pprev ;
}
// Eventually all chain branches meet at the genesis block.
assert ( pa = = pb ) ;
return pa ;
}
/** 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 ) ;
assert ( state ! = NULL ) ;
// Make sure pindexBestKnownBlock is up to date, we'll need it.
ProcessBlockAvailability ( nodeid ) ;
if ( state - > pindexBestKnownBlock = = NULL | | state - > pindexBestKnownBlock - > nChainWork < chainActive . Tip ( ) - > nChainWork ) {
// This peer has nothing interesting.
return ;
}
if ( state - > pindexLastCommonBlock = = NULL ) {
// 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 07:47:17 -07:00
// of its current tip anymore. Go back enough to fix that.
2014-07-11 15:02:35 -07:00
state - > pindexLastCommonBlock = LastCommonAncestor ( state - > pindexLastCommonBlock , state - > pindexBestKnownBlock ) ;
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-11 15:02:35 -07: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
2018-03-02 03:45:05 -08:00
// are not yet downloaded and not in flight to vBlocks. In the meantime, update
2015-06-04 10:00:26 -07: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).
2014-07-11 15:02:35 -07:00
BOOST_FOREACH ( CBlockIndex * pindex , vToFetch ) {
2014-12-11 04:35:14 -08:00
if ( ! pindex - > IsValid ( BLOCK_VALID_TREE ) ) {
// We consider the chain that this peer is on invalid.
return ;
}
2015-06-04 10:00:26 -07:00
if ( pindex - > nStatus & BLOCK_HAVE_DATA | | chainActive . Contains ( pindex ) ) {
2014-07-11 15:02:35 -07: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-11 15:02:35 -07: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 05:17:43 -07:00
} // anon namespace
2013-11-17 16:25:17 -08:00
bool GetNodeStateStats ( NodeId nodeid , CNodeStateStats & stats ) {
LOCK ( cs_main ) ;
CNodeState * state = State ( nodeid ) ;
if ( state = = NULL )
return false ;
stats . nMisbehavior = state - > nMisbehavior ;
2014-06-22 15:00:26 -07:00
stats . nSyncHeight = state - > pindexBestKnownBlock ? state - > pindexBestKnownBlock - > nHeight : - 1 ;
2014-07-11 15:03:10 -07:00
stats . nCommonHeight = state - > pindexLastCommonBlock ? state - > pindexLastCommonBlock - > nHeight : - 1 ;
BOOST_FOREACH ( const QueuedBlock & queue , state - > vBlocksInFlight ) {
if ( queue . pindex )
stats . vHeightInFlight . push_back ( queue . pindex - > nHeight ) ;
}
2013-11-17 16:25:17 -08:00
return true ;
}
2013-06-05 20:21:41 -07:00
void RegisterNodeSignals ( CNodeSignals & nodeSignals )
{
2013-10-10 14:07:44 -07:00
nodeSignals . GetHeight . connect ( & GetHeight ) ;
2013-06-05 20:21:41 -07:00
nodeSignals . ProcessMessages . connect ( & ProcessMessages ) ;
nodeSignals . SendMessages . connect ( & SendMessages ) ;
2013-11-17 16:25:17 -08:00
nodeSignals . InitializeNode . connect ( & InitializeNode ) ;
nodeSignals . FinalizeNode . connect ( & FinalizeNode ) ;
2013-06-05 20:21:41 -07:00
}
CWallet class
* A new class CKeyStore manages private keys, and script.cpp depends on access to CKeyStore.
* A new class CWallet extends CKeyStore, and contains all former wallet-specific globals; CWallet depends on script.cpp, not the other way around.
* Wallet-specific functions in CTransaction/CTxIn/CTxOut (GetDebit, GetCredit, GetChange, IsMine, IsFromMe), are moved to CWallet, taking their former 'this' argument as an explicit parameter
* CWalletTx objects know which CWallet they belong to, for convenience, so they have their own direct (and caching) GetDebit/... functions.
* Some code was moved from CWalletDB to CWallet, such as handling of reserve keys.
* Main.cpp keeps a set of all 'registered' wallets, which should be informed about updates to the block chain, and does not have any notion about any 'main' wallet. Function in main.cpp that require a wallet (such as GenerateCoins), take an explicit CWallet* argument.
* The actual CWallet instance used by the application is defined in init.cpp as "CWallet* pwalletMain". rpc.cpp and ui.cpp use this variable.
* Functions in main.cpp and db.cpp that are not used by other modules are marked static.
* The code for handling the 'submitorder' message is removed, as it not really compatible with the idea that a node is independent from the wallet(s) connected to it, and obsolete anyway.
2011-06-01 09:28:20 -07:00
2013-06-05 20:21:41 -07:00
void UnregisterNodeSignals ( CNodeSignals & nodeSignals )
{
2013-10-10 14:07:44 -07:00
nodeSignals . GetHeight . disconnect ( & GetHeight ) ;
2013-06-05 20:21:41 -07:00
nodeSignals . ProcessMessages . disconnect ( & ProcessMessages ) ;
nodeSignals . SendMessages . disconnect ( & SendMessages ) ;
2013-11-17 16:25:17 -08:00
nodeSignals . InitializeNode . disconnect ( & InitializeNode ) ;
nodeSignals . FinalizeNode . disconnect ( & FinalizeNode ) ;
2013-06-05 20:21:41 -07:00
}
CWallet class
* A new class CKeyStore manages private keys, and script.cpp depends on access to CKeyStore.
* A new class CWallet extends CKeyStore, and contains all former wallet-specific globals; CWallet depends on script.cpp, not the other way around.
* Wallet-specific functions in CTransaction/CTxIn/CTxOut (GetDebit, GetCredit, GetChange, IsMine, IsFromMe), are moved to CWallet, taking their former 'this' argument as an explicit parameter
* CWalletTx objects know which CWallet they belong to, for convenience, so they have their own direct (and caching) GetDebit/... functions.
* Some code was moved from CWalletDB to CWallet, such as handling of reserve keys.
* Main.cpp keeps a set of all 'registered' wallets, which should be informed about updates to the block chain, and does not have any notion about any 'main' wallet. Function in main.cpp that require a wallet (such as GenerateCoins), take an explicit CWallet* argument.
* The actual CWallet instance used by the application is defined in init.cpp as "CWallet* pwalletMain". rpc.cpp and ui.cpp use this variable.
* Functions in main.cpp and db.cpp that are not used by other modules are marked static.
* The code for handling the 'submitorder' message is removed, as it not really compatible with the idea that a node is independent from the wallet(s) connected to it, and obsolete anyway.
2011-06-01 09:28:20 -07:00
2014-09-02 17:52:01 -07:00
CBlockIndex * FindForkInGlobalIndex ( const CChain & chain , const CBlockLocator & locator )
{
2013-05-07 04:59:29 -07:00
// Find the first block the caller has in the main chain
2013-10-12 06:18:08 -07:00
BOOST_FOREACH ( const uint256 & hash , locator . vHave ) {
2014-09-03 17:02:44 -07:00
BlockMap : : iterator mi = mapBlockIndex . find ( hash ) ;
2013-05-07 04:59:29 -07:00
if ( mi ! = mapBlockIndex . end ( ) )
{
CBlockIndex * pindex = ( * mi ) . second ;
2014-09-02 17:52:01 -07:00
if ( chain . Contains ( pindex ) )
2013-05-07 04:59:29 -07:00
return pindex ;
2016-03-18 09:20:12 -07:00
if ( pindex - > GetAncestor ( chain . Height ( ) ) = = chain . Tip ( ) ) {
return chain . Tip ( ) ;
}
2013-05-07 04:59:29 -07:00
}
}
2014-09-02 17:52:01 -07:00
return chain . Genesis ( ) ;
2014-05-05 15:54:10 -07:00
}
2012-07-06 07:33:34 -07:00
CCoinsViewCache * pcoinsTip = NULL ;
2012-09-03 06:26:57 -07:00
CBlockTreeDB * pblocktree = NULL ;
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
2010-08-29 09:58:15 -07:00
//////////////////////////////////////////////////////////////////////////////
//
// mapOrphanTransactions
//
2015-06-16 01:08:26 -07:00
bool AddOrphanTx ( const CTransaction & tx , NodeId peer ) EXCLUSIVE_LOCKS_REQUIRED ( cs_main )
2010-08-29 09:58:15 -07:00
{
2016-08-30 12:49:38 -07:00
uint256 hash = tx . GetHash ( ) ;
2010-08-29 09:58:15 -07:00
if ( mapOrphanTransactions . count ( hash ) )
2012-05-15 12:53:30 -07:00
return false ;
// Ignore big transactions, to avoid a
// send-big-orphans memory exhaustion attack. If a peer has a legitimate
// large transaction with a missing parent then we assume
// it will rebroadcast it later, after the parent transaction(s)
// have been mined or received.
// 10,000 orphans, each of which is at most 5,000 bytes big is
// at most 500 megabytes of orphans:
2018-03-09 04:32:02 -08:00
unsigned int sz = GetSerializeSize ( tx , SER_NETWORK , tx . nVersion ) ;
2013-08-01 22:14:44 -07:00
if ( sz > 5000 )
2012-05-15 12:53:30 -07:00
{
2014-01-16 07:15:27 -08:00
LogPrint ( " mempool " , " ignoring large orphan tx (size: %u, hash: %s) \n " , sz , hash . ToString ( ) ) ;
2012-05-15 12:53:30 -07:00
return false ;
}
2012-02-29 07:14:18 -08:00
2014-08-28 10:23:24 -07:00
mapOrphanTransactions [ hash ] . tx = tx ;
mapOrphanTransactions [ hash ] . fromPeer = peer ;
2011-05-15 00:11:04 -07:00
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
2013-08-01 22:14:44 -07:00
mapOrphanTransactionsByPrev [ txin . prevout . hash ] . insert ( hash ) ;
2012-05-15 12:53:30 -07:00
2014-08-28 10:23:24 -07:00
LogPrint ( " mempool " , " stored orphan tx %s (mapsz %u prevsz %u) \n " , hash . ToString ( ) ,
mapOrphanTransactions . size ( ) , mapOrphanTransactionsByPrev . size ( ) ) ;
2012-05-15 12:53:30 -07:00
return true ;
2010-08-29 09:58:15 -07:00
}
2015-06-16 01:08:26 -07:00
void static EraseOrphanTx ( uint256 hash ) EXCLUSIVE_LOCKS_REQUIRED ( cs_main )
2010-08-29 09:58:15 -07:00
{
2014-08-28 10:23:24 -07:00
map < uint256 , COrphanTx > : : iterator it = mapOrphanTransactions . find ( hash ) ;
2014-09-08 08:37:26 -07:00
if ( it = = mapOrphanTransactions . end ( ) )
2010-08-29 09:58:15 -07:00
return ;
2014-08-28 10:23:24 -07:00
BOOST_FOREACH ( const CTxIn & txin , it - > second . tx . vin )
2010-08-29 09:58:15 -07:00
{
2014-09-08 08:37:26 -07:00
map < uint256 , set < uint256 > > : : iterator itPrev = mapOrphanTransactionsByPrev . find ( txin . prevout . hash ) ;
2014-09-09 11:01:11 -07:00
if ( itPrev = = mapOrphanTransactionsByPrev . end ( ) )
continue ;
2014-09-08 08:37:26 -07:00
itPrev - > second . erase ( hash ) ;
if ( itPrev - > second . empty ( ) )
mapOrphanTransactionsByPrev . erase ( itPrev ) ;
2010-08-29 09:58:15 -07:00
}
2014-09-08 08:37:26 -07:00
mapOrphanTransactions . erase ( it ) ;
2010-08-29 09:58:15 -07:00
}
2014-08-28 10:23:24 -07:00
void EraseOrphansFor ( NodeId peer )
{
int nErased = 0 ;
map < uint256 , COrphanTx > : : iterator iter = mapOrphanTransactions . begin ( ) ;
while ( iter ! = mapOrphanTransactions . end ( ) )
{
map < uint256 , COrphanTx > : : iterator maybeErase = iter + + ; // increment to avoid iterator becoming invalid
if ( maybeErase - > second . fromPeer = = peer )
{
2016-08-30 12:49:38 -07:00
EraseOrphanTx ( maybeErase - > second . tx . GetHash ( ) ) ;
2014-08-28 10:23:24 -07:00
+ + nErased ;
}
}
if ( nErased > 0 ) LogPrint ( " mempool " , " Erased %d orphan tx from peer %d \n " , nErased , peer ) ;
}
2015-06-16 01:08:26 -07:00
unsigned int LimitOrphanTxSize ( unsigned int nMaxOrphans ) EXCLUSIVE_LOCKS_REQUIRED ( cs_main )
2012-02-29 07:14:18 -08:00
{
2012-04-23 11:14:03 -07:00
unsigned int nEvicted = 0 ;
2012-02-29 07:14:18 -08:00
while ( mapOrphanTransactions . size ( ) > nMaxOrphans )
{
// Evict a random orphan:
2012-05-17 09:13:14 -07:00
uint256 randomhash = GetRandHash ( ) ;
2014-08-28 10:23:24 -07:00
map < uint256 , COrphanTx > : : iterator it = mapOrphanTransactions . lower_bound ( randomhash ) ;
2012-02-29 07:14:18 -08:00
if ( it = = mapOrphanTransactions . end ( ) )
it = mapOrphanTransactions . begin ( ) ;
EraseOrphanTx ( it - > first ) ;
+ + nEvicted ;
}
return nEvicted ;
}
2010-08-29 09:58:15 -07:00
2019-03-14 03:57:14 -07:00
bool IsStandardTx ( const CTransaction & tx , string & reason , const CChainParams & chainparams , const int nHeight )
2013-04-25 17:11:27 -07:00
{
2019-03-14 03:57:14 -07:00
bool overwinterActive = NetworkUpgradeActive ( nHeight , chainparams . GetConsensus ( ) , Consensus : : UPGRADE_OVERWINTER ) ;
bool saplingActive = NetworkUpgradeActive ( nHeight , chainparams . GetConsensus ( ) , Consensus : : UPGRADE_SAPLING ) ;
2018-02-15 22:19:36 -08:00
2018-04-19 08:25:04 -07:00
if ( saplingActive ) {
// Sapling standard rules apply
if ( tx . nVersion > CTransaction : : SAPLING_MAX_CURRENT_VERSION | | tx . nVersion < CTransaction : : SAPLING_MIN_CURRENT_VERSION ) {
reason = " sapling-version " ;
return false ;
}
} else if ( overwinterActive ) {
2018-02-15 22:19:36 -08:00
// Overwinter standard rules apply
if ( tx . nVersion > CTransaction : : OVERWINTER_MAX_CURRENT_VERSION | | tx . nVersion < CTransaction : : OVERWINTER_MIN_CURRENT_VERSION ) {
reason = " overwinter-version " ;
return false ;
}
} else {
// Sprout standard rules apply
if ( tx . nVersion > CTransaction : : SPROUT_MAX_CURRENT_VERSION | | tx . nVersion < CTransaction : : SPROUT_MIN_CURRENT_VERSION ) {
reason = " version " ;
return false ;
}
2013-06-22 23:05:25 -07:00
}
2012-06-27 09:43:19 -07:00
2013-01-08 04:17:15 -08:00
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
2011-10-03 10:05:43 -07:00
{
2014-03-10 13:38:44 -07:00
// Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
// keys. (remember the 520 byte limit on redeemScript size) That works
2014-06-28 05:57:46 -07:00
// out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
2014-03-10 13:38:44 -07:00
// bytes of scriptSig, which we round off to 1650 bytes for some minor
// future-proofing. That's also enough to spend a 20-of-20
// CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
// considered standard)
if ( txin . scriptSig . size ( ) > 1650 ) {
2013-06-22 23:05:25 -07:00
reason = " scriptsig-size " ;
2012-01-04 18:40:52 -08:00
return false ;
2013-06-22 23:05:25 -07:00
}
if ( ! txin . scriptSig . IsPushOnly ( ) ) {
reason = " scriptsig-not-pushonly " ;
2012-01-04 18:40:52 -08:00
return false ;
2013-09-23 15:48:00 -07:00
}
2011-10-03 10:05:43 -07:00
}
2013-06-24 12:09:50 -07:00
unsigned int nDataOut = 0 ;
txnouttype whichType ;
2013-01-08 04:17:15 -08:00
BOOST_FOREACH ( const CTxOut & txout , tx . vout ) {
2013-06-24 12:09:50 -07:00
if ( ! : : IsStandard ( txout . scriptPubKey , whichType ) ) {
2013-06-22 23:05:25 -07:00
reason = " scriptpubkey " ;
2012-01-04 18:40:52 -08:00
return false ;
2013-06-22 23:05:25 -07:00
}
2014-07-16 17:04:04 -07:00
2013-06-24 12:09:50 -07:00
if ( whichType = = TX_NULL_DATA )
nDataOut + + ;
2014-07-16 17:04:04 -07:00
else if ( ( whichType = = TX_MULTISIG ) & & ( ! fIsBareMultisigStd ) ) {
reason = " bare-multisig " ;
return false ;
} else if ( txout . IsDust ( : : minRelayTxFee ) ) {
2013-06-22 23:05:25 -07:00
reason = " dust " ;
2012-08-24 03:14:48 -07:00
return false ;
2013-06-22 23:05:25 -07:00
}
2012-08-24 03:14:48 -07:00
}
2013-06-22 23:05:25 -07:00
2013-06-24 12:09:50 -07:00
// only one OP_RETURN txout is permitted
if ( nDataOut > 1 ) {
2014-01-27 03:13:00 -08:00
reason = " multi-op-return " ;
2013-06-24 12:09:50 -07:00
return false ;
}
2011-10-03 10:05:43 -07:00
return true ;
}
2013-04-12 22:13:08 -07: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-12 22:13:08 -07: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 ;
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
if ( ! txin . IsFinal ( ) )
return false ;
return true ;
}
2018-02-21 20:21:06 -08:00
bool IsExpiredTx ( const CTransaction & tx , int nBlockHeight )
{
if ( tx . nExpiryHeight = = 0 | | tx . IsCoinBase ( ) ) {
return false ;
}
return static_cast < uint32_t > ( nBlockHeight ) > tx . nExpiryHeight ;
}
2018-11-05 10:24:20 -08:00
bool IsExpiringSoonTx ( const CTransaction & tx , int nNextBlockHeight )
{
return IsExpiredTx ( tx , nNextBlockHeight + TX_EXPIRING_SOON_THRESHOLD ) ;
}
2015-06-03 12:55:45 -07:00
bool CheckFinalTx ( const CTransaction & tx , int flags )
2015-05-24 21:48:33 -07:00
{
AssertLockHeld ( cs_main ) ;
2015-06-03 12:55:45 -07: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
// appropriate flags. At the present time no soft-forks are
// scheduled, so no flags are set.
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 ;
// Timestamps on the other hand don't get any special treatment,
// because we can't know what timestamp the next block will have,
// and there aren't timestamp applications where it matters.
// However this changes once median past time-locks are enforced:
const int64_t nBlockTime = ( flags & LOCKTIME_MEDIAN_TIME_PAST )
? chainActive . Tip ( ) - > GetMedianTimePast ( )
: GetAdjustedTime ( ) ;
return IsFinalTx ( tx , nBlockHeight , nBlockTime ) ;
2015-05-24 21:48:33 -07:00
}
2014-11-30 17:39:44 -08:00
/**
* Check transaction inputs to mitigate two
* potential denial - of - service attacks :
2015-05-31 06:36:44 -07:00
*
2014-11-30 17:39:44 -08:00
* 1. scriptSigs with extra data stuffed into them ,
* not consumed by scriptPubKey ( or P2SH script )
* 2. P2SH scripts with a crazy number of expensive
* CHECKSIG / CHECKMULTISIG operations
*/
2018-02-01 17:49:42 -08:00
bool AreInputsStandard ( const CTransaction & tx , const CCoinsViewCache & mapInputs , uint32_t consensusBranchId )
2011-10-03 10:05:43 -07:00
{
2013-01-08 04:17:15 -08:00
if ( tx . IsCoinBase ( ) )
2012-01-20 17:59:04 -08:00
return true ; // Coinbases don't use vin normally
2012-01-10 17:18:00 -08:00
2013-01-08 04:17:15 -08:00
for ( unsigned int i = 0 ; i < tx . vin . size ( ) ; i + + )
2011-10-03 10:05:43 -07:00
{
2013-01-08 04:17:15 -08:00
const CTxOut & prev = mapInputs . GetOutputFor ( tx . vin [ i ] ) ;
2011-10-03 10:05:43 -07:00
vector < vector < unsigned char > > vSolutions ;
2011-11-08 10:20:29 -08:00
txnouttype whichType ;
// get the scriptPubKey corresponding to this input:
2012-01-10 17:18:00 -08:00
const CScript & prevScript = prev . scriptPubKey ;
2011-11-08 10:20:29 -08:00
if ( ! Solver ( prevScript , whichType , vSolutions ) )
2012-01-04 18:40:52 -08:00
return false ;
2012-01-19 10:30:54 -08:00
int nArgsExpected = ScriptSigArgsExpected ( whichType , vSolutions ) ;
2012-04-22 10:44:12 -07:00
if ( nArgsExpected < 0 )
return false ;
2012-01-19 10:30:54 -08:00
// Transactions with extra stuff in their scriptSigs are
// non-standard. Note that this EvalScript() call will
// be quick, because if there are any operations
2014-06-17 11:18:13 -07:00
// beside "push data" in the scriptSig
2015-01-14 01:25:06 -08:00
// IsStandardTx() will have already returned false
2014-06-17 11:18:13 -07:00
// and this method isn't called.
2012-01-19 10:30:54 -08:00
vector < vector < unsigned char > > stack ;
2018-02-01 17:49:42 -08:00
if ( ! EvalScript ( stack , tx . vin [ i ] . scriptSig , SCRIPT_VERIFY_NONE , BaseSignatureChecker ( ) , consensusBranchId ) )
2012-01-19 10:30:54 -08:00
return false ;
2011-10-03 10:05:43 -07:00
if ( whichType = = TX_SCRIPTHASH )
{
2012-01-04 18:40:52 -08:00
if ( stack . empty ( ) )
2011-10-03 10:05:43 -07:00
return false ;
2011-11-08 10:20:29 -08:00
CScript subscript ( stack . back ( ) . begin ( ) , stack . back ( ) . end ( ) ) ;
2012-01-19 10:30:54 -08:00
vector < vector < unsigned char > > vSolutions2 ;
txnouttype whichType2 ;
2014-06-17 11:18:13 -07:00
if ( Solver ( subscript , whichType2 , vSolutions2 ) )
{
int tmpExpected = ScriptSigArgsExpected ( whichType2 , vSolutions2 ) ;
if ( tmpExpected < 0 )
return false ;
nArgsExpected + = tmpExpected ;
}
else
{
// Any other Script with less than 15 sigops OK:
unsigned int sigops = subscript . GetSigOpCount ( true ) ;
// ... extra data left on the stack after execution is OK, too:
return ( sigops < = MAX_P2SH_SIGOPS ) ;
}
2011-10-03 10:05:43 -07:00
}
2012-01-19 10:30:54 -08:00
2012-04-22 10:44:12 -07:00
if ( stack . size ( ) ! = ( unsigned int ) nArgsExpected )
2012-01-19 10:30:54 -08:00
return false ;
2011-10-03 10:05:43 -07:00
}
return true ;
}
2013-01-08 04:17:15 -08:00
unsigned int GetLegacySigOpCount ( const CTransaction & tx )
2012-01-04 18:40:52 -08:00
{
2012-04-23 11:14:03 -07:00
unsigned int nSigOps = 0 ;
2013-01-08 04:17:15 -08:00
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
2012-01-04 18:40:52 -08:00
{
nSigOps + = txin . scriptSig . GetSigOpCount ( false ) ;
}
2013-01-08 04:17:15 -08:00
BOOST_FOREACH ( const CTxOut & txout , tx . vout )
2012-01-04 18:40:52 -08:00
{
nSigOps + = txout . scriptPubKey . GetSigOpCount ( false ) ;
}
return nSigOps ;
}
2010-08-29 09:58:15 -07:00
2014-07-19 08:14:23 -07:00
unsigned int GetP2SHSigOpCount ( const CTransaction & tx , const CCoinsViewCache & inputs )
2013-01-08 04:17:15 -08:00
{
if ( tx . IsCoinBase ( ) )
return 0 ;
unsigned int nSigOps = 0 ;
for ( unsigned int i = 0 ; i < tx . vin . size ( ) ; i + + )
{
const CTxOut & prevout = inputs . GetOutputFor ( tx . vin [ i ] ) ;
if ( prevout . scriptPubKey . IsPayToScriptHash ( ) )
nSigOps + = prevout . scriptPubKey . GetSigOpCount ( tx . vin [ i ] . scriptSig ) ;
}
return nSigOps ;
}
2010-08-29 09:58:15 -07:00
2018-02-15 22:19:36 -08:00
/**
* Check a transaction contextually against a set of consensus rules valid at a given block height .
*
* Notes :
* 1. AcceptToMemoryPool calls CheckTransaction and this function .
* 2. ProcessNewBlock calls AcceptBlock , which calls CheckBlock ( which calls CheckTransaction )
* and ContextualCheckBlock ( which calls this function ) .
2018-08-08 15:19:12 -07:00
* 3. The isInitBlockDownload argument is only to assist with testing .
2018-02-15 22:19:36 -08:00
*/
2018-08-08 15:19:12 -07:00
bool ContextualCheckTransaction (
const CTransaction & tx ,
CValidationState & state ,
2019-03-14 04:11:10 -07:00
const CChainParams & chainparams ,
2018-08-08 15:19:12 -07:00
const int nHeight ,
const int dosLevel ,
bool ( * isInitBlockDownload ) ( ) )
2018-02-15 22:19:36 -08:00
{
2019-03-14 04:11:10 -07:00
bool overwinterActive = NetworkUpgradeActive ( nHeight , chainparams . GetConsensus ( ) , Consensus : : UPGRADE_OVERWINTER ) ;
bool saplingActive = NetworkUpgradeActive ( nHeight , chainparams . GetConsensus ( ) , Consensus : : UPGRADE_SAPLING ) ;
2018-04-15 06:55:55 -07:00
bool isSprout = ! overwinterActive ;
2018-02-15 22:19:36 -08:00
// If Sprout rules apply, reject transactions which are intended for Overwinter and beyond
if ( isSprout & & tx . fOverwintered ) {
2018-08-08 15:19:12 -07:00
return state . DoS ( isInitBlockDownload ( ) ? 0 : dosLevel ,
2018-07-26 11:29:04 -07:00
error ( " ContextualCheckTransaction(): overwinter is not active yet " ) ,
2018-02-15 22:19:36 -08:00
REJECT_INVALID , " tx-overwinter-not-active " ) ;
}
2018-04-15 06:55:55 -07:00
if ( saplingActive ) {
// Reject transactions with valid version but missing overwintered flag
if ( tx . nVersion > = SAPLING_MIN_TX_VERSION & & ! tx . fOverwintered ) {
return state . DoS ( dosLevel , error ( " ContextualCheckTransaction(): overwintered flag must be set " ) ,
REJECT_INVALID , " tx-overwintered-flag-not-set " ) ;
}
// Reject transactions with non-Sapling version group ID
if ( tx . fOverwintered & & tx . nVersionGroupId ! = SAPLING_VERSION_GROUP_ID ) {
2018-11-13 16:37:59 -08:00
return state . DoS ( isInitBlockDownload ( ) ? 0 : dosLevel ,
error ( " CheckTransaction(): invalid Sapling tx version " ) ,
2018-04-15 06:55:55 -07:00
REJECT_INVALID , " bad-sapling-tx-version-group-id " ) ;
}
// Reject transactions with invalid version
if ( tx . fOverwintered & & tx . nVersion < SAPLING_MIN_TX_VERSION ) {
return state . DoS ( 100 , error ( " CheckTransaction(): Sapling version too low " ) ,
REJECT_INVALID , " bad-tx-sapling-version-too-low " ) ;
}
// Reject transactions with invalid version
if ( tx . fOverwintered & & tx . nVersion > SAPLING_MAX_TX_VERSION ) {
return state . DoS ( 100 , error ( " CheckTransaction(): Sapling version too high " ) ,
REJECT_INVALID , " bad-tx-sapling-version-too-high " ) ;
}
} else if ( overwinterActive ) {
2018-02-15 22:19:36 -08:00
// Reject transactions with valid version but missing overwinter flag
if ( tx . nVersion > = OVERWINTER_MIN_TX_VERSION & & ! tx . fOverwintered ) {
return state . DoS ( dosLevel , error ( " ContextualCheckTransaction(): overwinter flag must be set " ) ,
REJECT_INVALID , " tx-overwinter-flag-not-set " ) ;
}
2018-04-15 06:55:55 -07:00
// Reject transactions with non-Overwinter version group ID
if ( tx . fOverwintered & & tx . nVersionGroupId ! = OVERWINTER_VERSION_GROUP_ID ) {
2018-11-13 16:37:59 -08:00
return state . DoS ( isInitBlockDownload ( ) ? 0 : dosLevel ,
error ( " CheckTransaction(): invalid Overwinter tx version " ) ,
2018-04-15 06:55:55 -07:00
REJECT_INVALID , " bad-overwinter-tx-version-group-id " ) ;
}
2018-02-15 22:19:36 -08:00
// Reject transactions with invalid version
if ( tx . fOverwintered & & tx . nVersion > OVERWINTER_MAX_TX_VERSION ) {
return state . DoS ( 100 , error ( " CheckTransaction(): overwinter version too high " ) ,
REJECT_INVALID , " bad-tx-overwinter-version-too-high " ) ;
}
2018-04-15 06:55:55 -07:00
}
2018-02-15 22:19:36 -08:00
2018-04-15 06:55:55 -07:00
// Rules that apply to Overwinter or later:
if ( overwinterActive ) {
2018-02-15 22:19:36 -08:00
// Reject transactions intended for Sprout
if ( ! tx . fOverwintered ) {
return state . DoS ( dosLevel , error ( " ContextualCheckTransaction: overwinter is active " ) ,
REJECT_INVALID , " tx-overwinter-active " ) ;
}
2018-02-21 20:21:06 -08:00
// Check that all transactions are unexpired
if ( IsExpiredTx ( tx , nHeight ) ) {
2018-04-03 17:28:57 -07:00
// Don't increase banscore if the transaction only just expired
int expiredDosLevel = IsExpiredTx ( tx , nHeight - 1 ) ? dosLevel : 0 ;
return state . DoS ( expiredDosLevel , error ( " ContextualCheckTransaction(): transaction is expired " ) , REJECT_INVALID , " tx-overwinter-expired " ) ;
2018-02-21 20:21:06 -08:00
}
2018-02-15 22:19:36 -08:00
}
2018-04-26 06:18:36 -07:00
// Rules that apply before Sapling:
if ( ! saplingActive ) {
// Size limits
BOOST_STATIC_ASSERT ( MAX_BLOCK_SIZE > MAX_TX_SIZE_BEFORE_SAPLING ) ; // sanity
if ( : : GetSerializeSize ( tx , SER_NETWORK , PROTOCOL_VERSION ) > MAX_TX_SIZE_BEFORE_SAPLING )
return state . DoS ( 100 , error ( " ContextualCheckTransaction(): size limits failed " ) ,
REJECT_INVALID , " bad-txns-oversize " ) ;
}
2018-05-08 13:28:01 -07:00
uint256 dataToBeSigned ;
2018-05-08 13:28:55 -07:00
if ( ! tx . vjoinsplit . empty ( ) | |
! tx . vShieldedSpend . empty ( ) | |
! tx . vShieldedOutput . empty ( ) )
2018-05-08 13:28:01 -07:00
{
2019-03-14 04:11:10 -07:00
auto consensusBranchId = CurrentEpochBranchId ( nHeight , chainparams . GetConsensus ( ) ) ;
2018-02-01 17:49:42 -08:00
// Empty output script.
CScript scriptCode ;
try {
dataToBeSigned = SignatureHash ( scriptCode , tx , NOT_AN_INPUT , SIGHASH_ALL , 0 , consensusBranchId ) ;
} catch ( std : : logic_error ex ) {
return state . DoS ( 100 , error ( " CheckTransaction(): error computing signature hash " ) ,
REJECT_INVALID , " error-computing-signature-hash " ) ;
}
2018-05-08 13:28:01 -07:00
}
2018-02-01 17:49:42 -08:00
2018-05-08 13:28:01 -07:00
if ( ! tx . vjoinsplit . empty ( ) )
{
2018-02-01 17:49:42 -08:00
BOOST_STATIC_ASSERT ( crypto_sign_PUBLICKEYBYTES = = 32 ) ;
// We rely on libsodium to check that the signature is canonical.
// https://github.com/jedisct1/libsodium/commit/62911edb7ff2275cccd74bf1c8aefcc4d76924e0
if ( crypto_sign_verify_detached ( & tx . joinSplitSig [ 0 ] ,
dataToBeSigned . begin ( ) , 32 ,
tx . joinSplitPubKey . begin ( )
) ! = 0 ) {
2018-08-08 15:19:12 -07:00
return state . DoS ( isInitBlockDownload ( ) ? 0 : 100 ,
2018-07-26 11:29:04 -07:00
error ( " CheckTransaction(): invalid joinsplit signature " ) ,
2018-02-01 17:49:42 -08:00
REJECT_INVALID , " bad-txns-invalid-joinsplit-signature " ) ;
}
}
2018-05-08 13:28:55 -07:00
if ( ! tx . vShieldedSpend . empty ( ) | |
! tx . vShieldedOutput . empty ( ) )
{
auto ctx = librustzcash_sapling_verification_ctx_init ( ) ;
for ( const SpendDescription & spend : tx . vShieldedSpend ) {
if ( ! librustzcash_sapling_check_spend (
ctx ,
spend . cv . begin ( ) ,
spend . anchor . begin ( ) ,
spend . nullifier . begin ( ) ,
spend . rk . begin ( ) ,
spend . zkproof . begin ( ) ,
spend . spendAuthSig . begin ( ) ,
dataToBeSigned . begin ( )
) )
{
librustzcash_sapling_verification_ctx_free ( ctx ) ;
return state . DoS ( 100 , error ( " ContextualCheckTransaction(): Sapling spend description invalid " ) ,
REJECT_INVALID , " bad-txns-sapling-spend-description-invalid " ) ;
}
}
for ( const OutputDescription & output : tx . vShieldedOutput ) {
if ( ! librustzcash_sapling_check_output (
ctx ,
output . cv . begin ( ) ,
output . cm . begin ( ) ,
output . ephemeralKey . begin ( ) ,
output . zkproof . begin ( )
) )
{
librustzcash_sapling_verification_ctx_free ( ctx ) ;
return state . DoS ( 100 , error ( " ContextualCheckTransaction(): Sapling output description invalid " ) ,
REJECT_INVALID , " bad-txns-sapling-output-description-invalid " ) ;
}
}
if ( ! librustzcash_sapling_final_check (
ctx ,
tx . valueBalance ,
tx . bindingSig . begin ( ) ,
dataToBeSigned . begin ( )
) )
{
librustzcash_sapling_verification_ctx_free ( ctx ) ;
return state . DoS ( 100 , error ( " ContextualCheckTransaction(): Sapling binding signature invalid " ) ,
REJECT_INVALID , " bad-txns-sapling-binding-signature-invalid " ) ;
}
librustzcash_sapling_verification_ctx_free ( ctx ) ;
}
2018-02-15 22:19:36 -08:00
return true ;
}
2016-11-22 20:04:20 -08:00
bool CheckTransaction ( const CTransaction & tx , CValidationState & state ,
libzcash : : ProofVerifier & verifier )
2016-06-23 15:35:31 -07:00
{
2016-09-03 09:39:45 -07:00
// Don't count coinbase transactions because mining skews the count
if ( ! tx . IsCoinBase ( ) ) {
transactionsValidated . increment ( ) ;
}
2016-06-23 15:35:31 -07:00
if ( ! CheckTransactionWithoutProofVerification ( tx , state ) ) {
return false ;
} else {
// Ensure that zk-SNARKs verify
2016-07-14 15:10:41 -07:00
BOOST_FOREACH ( const JSDescription & joinsplit , tx . vjoinsplit ) {
2016-11-23 23:03:12 -08:00
if ( ! joinsplit . Verify ( * pzcashParams , verifier , tx . joinSplitPubKey ) ) {
2016-07-14 15:10:41 -07:00
return state . DoS ( 100 , error ( " CheckTransaction(): joinsplit does not verify " ) ,
REJECT_INVALID , " bad-txns-joinsplit-verification-failed " ) ;
2016-06-23 15:35:31 -07:00
}
}
return true ;
}
}
bool CheckTransactionWithoutProofVerification ( const CTransaction & tx , CValidationState & state )
2010-09-30 09:23:07 -07:00
{
// Basic checks that don't depend on any context
2015-12-29 19:20:30 -08:00
2018-02-15 22:19:36 -08:00
/**
* Previously :
* 1. The consensus rule below was :
* if ( tx . nVersion < SPROUT_MIN_TX_VERSION ) { . . . }
* which checked if tx . nVersion fell within the range :
* INT32_MIN < = tx . nVersion < SPROUT_MIN_TX_VERSION
* 2. The parser allowed tx . nVersion to be negative
*
* Now :
* 1. The consensus rule checks to see if tx . Version falls within the range :
* 0 < = tx . nVersion < SPROUT_MIN_TX_VERSION
* 2. The previous consensus rule checked for negative values within the range :
* INT32_MIN < = tx . nVersion < 0
* This is unnecessary for Overwinter transactions since the parser now
* interprets the sign bit as fOverwintered , so tx . nVersion is always > = 0 ,
* and when Overwinter is not active ContextualCheckTransaction rejects
* transactions with fOverwintered set . When fOverwintered is set ,
* this function and ContextualCheckTransaction will together check to
* ensure tx . nVersion avoids the following ranges :
* 0 < = tx . nVersion < OVERWINTER_MIN_TX_VERSION
* OVERWINTER_MAX_TX_VERSION < tx . nVersion < = INT32_MAX
*/
if ( ! tx . fOverwintered & & tx . nVersion < SPROUT_MIN_TX_VERSION ) {
2016-10-21 21:07:50 -07:00
return state . DoS ( 100 , error ( " CheckTransaction(): version too low " ) ,
2016-10-22 05:26:44 -07:00
REJECT_INVALID , " bad-txns-version-too-low " ) ;
2016-10-21 21:07:50 -07:00
}
2018-02-15 22:19:36 -08:00
else if ( tx . fOverwintered ) {
if ( tx . nVersion < OVERWINTER_MIN_TX_VERSION ) {
return state . DoS ( 100 , error ( " CheckTransaction(): overwinter version too low " ) ,
REJECT_INVALID , " bad-tx-overwinter-version-too-low " ) ;
}
2018-04-15 06:55:55 -07:00
if ( tx . nVersionGroupId ! = OVERWINTER_VERSION_GROUP_ID & &
tx . nVersionGroupId ! = SAPLING_VERSION_GROUP_ID ) {
2018-02-15 22:19:36 -08:00
return state . DoS ( 100 , error ( " CheckTransaction(): unknown tx version group id " ) ,
REJECT_INVALID , " bad-tx-version-group-id " ) ;
}
if ( tx . nExpiryHeight > = TX_EXPIRY_HEIGHT_THRESHOLD ) {
return state . DoS ( 100 , error ( " CheckTransaction(): expiry height is too high " ) ,
REJECT_INVALID , " bad-tx-expiry-height-too-high " ) ;
}
}
2016-10-21 21:07:50 -07:00
2018-04-26 14:24:59 -07:00
// Transactions containing empty `vin` must have either non-empty
// `vjoinsplit` or non-empty `vShieldedSpend`.
2018-04-25 16:10:34 -07:00
if ( tx . vin . empty ( ) & & tx . vjoinsplit . empty ( ) & & tx . vShieldedSpend . empty ( ) )
2015-01-08 02:44:25 -08:00
return state . DoS ( 10 , error ( " CheckTransaction(): vin empty " ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " bad-txns-vin-empty " ) ;
2018-04-26 14:24:59 -07:00
// Transactions containing empty `vout` must have either non-empty
// `vjoinsplit` or non-empty `vShieldedOutput`.
if ( tx . vout . empty ( ) & & tx . vjoinsplit . empty ( ) & & tx . vShieldedOutput . empty ( ) )
2015-01-08 02:44:25 -08:00
return state . DoS ( 10 , error ( " CheckTransaction(): vout empty " ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " bad-txns-vout-empty " ) ;
2015-12-29 19:20:30 -08:00
2010-09-30 09:23:07 -07:00
// Size limits
2018-04-30 07:13:32 -07:00
BOOST_STATIC_ASSERT ( MAX_BLOCK_SIZE > = MAX_TX_SIZE_AFTER_SAPLING ) ; // sanity
BOOST_STATIC_ASSERT ( MAX_TX_SIZE_AFTER_SAPLING > MAX_TX_SIZE_BEFORE_SAPLING ) ; // sanity
if ( : : GetSerializeSize ( tx , SER_NETWORK , PROTOCOL_VERSION ) > MAX_TX_SIZE_AFTER_SAPLING )
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " CheckTransaction(): size limits failed " ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " bad-txns-oversize " ) ;
2010-09-30 09:23:07 -07:00
// Check for negative or overflow output values
2014-04-22 15:46:19 -07:00
CAmount nValueOut = 0 ;
2013-01-08 04:17:15 -08:00
BOOST_FOREACH ( const CTxOut & txout , tx . vout )
2010-09-30 09:23:07 -07:00
{
if ( txout . nValue < 0 )
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " CheckTransaction(): txout.nValue negative " ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " bad-txns-vout-negative " ) ;
2010-09-30 09:23:07 -07:00
if ( txout . nValue > MAX_MONEY )
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " CheckTransaction(): txout.nValue too high " ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " bad-txns-vout-toolarge " ) ;
2010-09-30 09:23:07 -07:00
nValueOut + = txout . nValue ;
if ( ! MoneyRange ( nValueOut ) )
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " CheckTransaction(): txout total out of range " ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " bad-txns-txouttotal-toolarge " ) ;
2010-09-30 09:23:07 -07:00
}
2018-05-08 05:51:54 -07:00
// Check for non-zero valueBalance when there are no Sapling inputs or outputs
if ( tx . vShieldedSpend . empty ( ) & & tx . vShieldedOutput . empty ( ) & & tx . valueBalance ! = 0 ) {
return state . DoS ( 100 , error ( " CheckTransaction(): tx.valueBalance has no sources or sinks " ) ,
REJECT_INVALID , " bad-txns-valuebalance-nonzero " ) ;
}
// Check for overflow valueBalance
if ( tx . valueBalance > MAX_MONEY | | tx . valueBalance < - MAX_MONEY ) {
return state . DoS ( 100 , error ( " CheckTransaction(): abs(tx.valueBalance) too large " ) ,
REJECT_INVALID , " bad-txns-valuebalance-toolarge " ) ;
}
if ( tx . valueBalance < = 0 ) {
// NB: negative valueBalance "takes" money from the transparent value pool just as outputs do
nValueOut + = - tx . valueBalance ;
if ( ! MoneyRange ( nValueOut ) ) {
return state . DoS ( 100 , error ( " CheckTransaction(): txout total out of range " ) ,
REJECT_INVALID , " bad-txns-txouttotal-toolarge " ) ;
}
}
2016-07-14 15:10:41 -07:00
// Ensure that joinsplit values are well-formed
BOOST_FOREACH ( const JSDescription & joinsplit , tx . vjoinsplit )
2015-12-29 19:20:30 -08:00
{
2016-07-14 15:10:41 -07:00
if ( joinsplit . vpub_old < 0 ) {
return state . DoS ( 100 , error ( " CheckTransaction(): joinsplit.vpub_old negative " ) ,
2015-12-29 19:20:30 -08:00
REJECT_INVALID , " bad-txns-vpub_old-negative " ) ;
2016-04-13 15:52:24 -07:00
}
2015-12-29 19:20:30 -08:00
2016-07-14 15:10:41 -07:00
if ( joinsplit . vpub_new < 0 ) {
return state . DoS ( 100 , error ( " CheckTransaction(): joinsplit.vpub_new negative " ) ,
2015-12-29 19:20:30 -08:00
REJECT_INVALID , " bad-txns-vpub_new-negative " ) ;
2016-04-13 15:52:24 -07:00
}
2015-12-29 19:20:30 -08:00
2016-07-14 15:10:41 -07:00
if ( joinsplit . vpub_old > MAX_MONEY ) {
return state . DoS ( 100 , error ( " CheckTransaction(): joinsplit.vpub_old too high " ) ,
2015-12-29 19:20:30 -08:00
REJECT_INVALID , " bad-txns-vpub_old-toolarge " ) ;
2016-04-13 15:52:24 -07:00
}
2015-12-29 19:20:30 -08:00
2016-07-14 15:10:41 -07:00
if ( joinsplit . vpub_new > MAX_MONEY ) {
return state . DoS ( 100 , error ( " CheckTransaction(): joinsplit.vpub_new too high " ) ,
2015-12-29 19:20:30 -08:00
REJECT_INVALID , " bad-txns-vpub_new-toolarge " ) ;
2016-04-13 15:52:24 -07:00
}
2016-07-14 15:10:41 -07:00
if ( joinsplit . vpub_new ! = 0 & & joinsplit . vpub_old ! = 0 ) {
return state . DoS ( 100 , error ( " CheckTransaction(): joinsplit.vpub_new and joinsplit.vpub_old both nonzero " ) ,
2016-04-13 15:52:24 -07:00
REJECT_INVALID , " bad-txns-vpubs-both-nonzero " ) ;
}
2015-12-29 19:20:30 -08:00
2016-09-05 11:18:43 -07:00
nValueOut + = joinsplit . vpub_old ;
2016-04-13 15:52:24 -07:00
if ( ! MoneyRange ( nValueOut ) ) {
2015-12-29 19:20:30 -08:00
return state . DoS ( 100 , error ( " CheckTransaction(): txout total out of range " ) ,
REJECT_INVALID , " bad-txns-txouttotal-toolarge " ) ;
2016-04-13 15:52:24 -07:00
}
2015-12-29 19:20:30 -08:00
}
2016-09-05 11:18:43 -07:00
// Ensure input values do not exceed MAX_MONEY
// We have not resolved the txin values at this stage,
// but we do know what the joinsplits claim to add
// to the value pool.
{
CAmount nValueIn = 0 ;
for ( std : : vector < JSDescription > : : const_iterator it ( tx . vjoinsplit . begin ( ) ) ; it ! = tx . vjoinsplit . end ( ) ; + + it )
{
nValueIn + = it - > vpub_new ;
if ( ! MoneyRange ( it - > vpub_new ) | | ! MoneyRange ( nValueIn ) ) {
return state . DoS ( 100 , error ( " CheckTransaction(): txin total out of range " ) ,
REJECT_INVALID , " bad-txns-txintotal-toolarge " ) ;
}
}
2018-07-30 21:35:31 -07:00
// Also check for Sapling
if ( tx . valueBalance > = 0 ) {
// NB: positive valueBalance "adds" money to the transparent value pool, just as inputs do
nValueIn + = tx . valueBalance ;
if ( ! MoneyRange ( nValueIn ) ) {
return state . DoS ( 100 , error ( " CheckTransaction(): txin total out of range " ) ,
REJECT_INVALID , " bad-txns-txintotal-toolarge " ) ;
}
}
}
2015-12-29 19:20:30 -08:00
2011-07-30 14:01:45 -07:00
// Check for duplicate inputs
set < COutPoint > vInOutPoints ;
2013-01-08 04:17:15 -08:00
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
2011-07-30 14:01:45 -07:00
{
if ( vInOutPoints . count ( txin . prevout ) )
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " CheckTransaction(): duplicate inputs " ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " bad-txns-inputs-duplicate " ) ;
2011-07-30 14:01:45 -07:00
vInOutPoints . insert ( txin . prevout ) ;
}
2016-07-14 15:10:41 -07:00
// Check for duplicate joinsplit nullifiers in this transaction
2015-12-29 19:20:30 -08:00
{
2018-04-25 16:10:34 -07:00
set < uint256 > vJoinSplitNullifiers ;
BOOST_FOREACH ( const JSDescription & joinsplit , tx . vjoinsplit )
{
BOOST_FOREACH ( const uint256 & nf , joinsplit . nullifiers )
{
if ( vJoinSplitNullifiers . count ( nf ) )
return state . DoS ( 100 , error ( " CheckTransaction(): duplicate nullifiers " ) ,
REJECT_INVALID , " bad-joinsplits-nullifiers-duplicate " ) ;
vJoinSplitNullifiers . insert ( nf ) ;
}
}
}
// Check for duplicate sapling nullifiers in this transaction
{
set < uint256 > vSaplingNullifiers ;
BOOST_FOREACH ( const SpendDescription & spend_desc , tx . vShieldedSpend )
2015-12-29 19:20:30 -08:00
{
2018-04-25 16:10:34 -07:00
if ( vSaplingNullifiers . count ( spend_desc . nullifier ) )
2016-07-10 22:18:53 -07:00
return state . DoS ( 100 , error ( " CheckTransaction(): duplicate nullifiers " ) ,
2018-04-25 16:10:34 -07:00
REJECT_INVALID , " bad-spend-description-nullifiers-duplicate " ) ;
2015-12-29 19:20:30 -08:00
2018-04-25 16:10:34 -07:00
vSaplingNullifiers . insert ( spend_desc . nullifier ) ;
2015-12-29 19:20:30 -08:00
}
}
2013-01-08 04:17:15 -08:00
if ( tx . IsCoinBase ( ) )
2010-09-30 09:23:07 -07:00
{
2016-07-14 15:10:41 -07:00
// There should be no joinsplits in a coinbase transaction
2016-07-10 22:08:20 -07:00
if ( tx . vjoinsplit . size ( ) > 0 )
2016-07-14 15:10:41 -07:00
return state . DoS ( 100 , error ( " CheckTransaction(): coinbase has joinsplits " ) ,
REJECT_INVALID , " bad-cb-has-joinsplits " ) ;
2015-12-29 19:20:30 -08:00
2018-04-26 14:53:26 -07:00
// A coinbase transaction cannot have spend descriptions or output descriptions
if ( tx . vShieldedSpend . size ( ) > 0 )
return state . DoS ( 100 , error ( " CheckTransaction(): coinbase has spend descriptions " ) ,
REJECT_INVALID , " bad-cb-has-spend-description " ) ;
if ( tx . vShieldedOutput . size ( ) > 0 )
return state . DoS ( 100 , error ( " CheckTransaction(): coinbase has output descriptions " ) ,
REJECT_INVALID , " bad-cb-has-output-description " ) ;
2013-01-08 04:17:15 -08:00
if ( tx . vin [ 0 ] . scriptSig . size ( ) < 2 | | tx . vin [ 0 ] . scriptSig . size ( ) > 100 )
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " CheckTransaction(): coinbase script size " ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " bad-cb-length " ) ;
2010-09-30 09:23:07 -07:00
}
else
{
2013-01-08 04:17:15 -08:00
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
2010-09-30 09:23:07 -07:00
if ( txin . prevout . IsNull ( ) )
2015-01-08 02:44:25 -08:00
return state . DoS ( 10 , error ( " CheckTransaction(): prevout is null " ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " bad-txns-prevout-null " ) ;
2010-09-30 09:23:07 -07:00
}
return true ;
}
2014-04-22 15:46:19 -07:00
CAmount GetMinRelayFee ( const CTransaction & tx , unsigned int nBytes , bool fAllowFree )
2012-09-09 13:39:45 -07:00
{
2012-07-11 11:52:41 -07:00
{
LOCK ( mempool . cs ) ;
2016-08-30 12:49:38 -07:00
uint256 hash = tx . GetHash ( ) ;
2012-07-11 11:52:41 -07:00
double dPriorityDelta = 0 ;
2014-04-22 15:46:19 -07:00
CAmount nFeeDelta = 0 ;
2012-07-11 11:52:41 -07:00
mempool . ApplyDeltas ( hash , dPriorityDelta , nFeeDelta ) ;
if ( dPriorityDelta > 0 | | nFeeDelta > 0 )
return 0 ;
}
2014-04-22 15:46:19 -07:00
CAmount nMinFee = : : minRelayTxFee . GetFee ( nBytes ) ;
2012-09-09 13:39:45 -07:00
if ( fAllowFree )
{
2013-05-17 03:07:02 -07:00
// There is a free transaction area in blocks created by most miners,
// * If we are relaying we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 1000
2013-09-17 19:04:29 -07:00
// to be considered to fall into this category. We don't want to encourage sending
// multiple transactions instead of one big transaction to avoid fees.
2014-05-27 12:44:57 -07:00
if ( nBytes < ( DEFAULT_BLOCK_PRIORITY_SIZE - 1000 ) )
2013-05-17 03:07:02 -07:00
nMinFee = 0 ;
2012-09-09 13:39:45 -07:00
}
if ( ! MoneyRange ( nMinFee ) )
nMinFee = MAX_MONEY ;
return nMinFee ;
}
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
2013-08-26 22:51:57 -07:00
bool AcceptToMemoryPool ( CTxMemPool & pool , CValidationState & state , const CTransaction & tx , bool fLimitFree ,
2015-01-30 18:54:55 -08:00
bool * pfMissingInputs , bool fRejectAbsurdFee )
2010-08-29 09:58:15 -07:00
{
2014-04-15 03:43:17 -07:00
AssertLockHeld ( cs_main ) ;
2010-08-29 09:58:15 -07:00
if ( pfMissingInputs )
* pfMissingInputs = false ;
2018-02-01 17:49:42 -08:00
int nextBlockHeight = chainActive . Height ( ) + 1 ;
auto consensusBranchId = CurrentEpochBranchId ( nextBlockHeight , Params ( ) . GetConsensus ( ) ) ;
2017-05-04 11:35:08 -07:00
// Node operator can choose to reject tx by number of transparent inputs
static_assert ( std : : numeric_limits < size_t > : : max ( ) > = std : : numeric_limits < int64_t > : : max ( ) , " size_t too small " ) ;
size_t limit = ( size_t ) GetArg ( " -mempooltxinputlimit " , 0 ) ;
2018-03-19 07:13:10 -07:00
if ( NetworkUpgradeActive ( nextBlockHeight , Params ( ) . GetConsensus ( ) , Consensus : : UPGRADE_OVERWINTER ) ) {
limit = 0 ;
}
2017-05-04 11:35:08 -07:00
if ( limit > 0 ) {
size_t n = tx . vin . size ( ) ;
if ( n > limit ) {
LogPrint ( " mempool " , " Dropping txid %s : too many transparent inputs %zu > limit %zu \n " , tx . GetHash ( ) . ToString ( ) , n , limit ) ;
return false ;
}
}
2016-11-22 20:04:20 -08:00
auto verifier = libzcash : : ProofVerifier : : Strict ( ) ;
if ( ! CheckTransaction ( tx , state , verifier ) )
2014-12-30 14:02:46 -08:00
return error ( " AcceptToMemoryPool: CheckTransaction failed " ) ;
2010-09-30 09:23:07 -07:00
2018-02-15 22:19:36 -08:00
// DoS level set to 10 to be more forgiving.
// Check transaction contextually against the set of consensus rules which apply in the next block to be mined.
2019-03-14 04:11:10 -07:00
if ( ! ContextualCheckTransaction ( tx , state , Params ( ) , nextBlockHeight , 10 ) ) {
2018-02-15 22:19:36 -08:00
return error ( " AcceptToMemoryPool: ContextualCheckTransaction failed " ) ;
}
2018-11-05 10:24:20 -08:00
// DoS mitigation: reject transactions expiring soon
// Note that if a valid transaction belonging to the wallet is in the mempool and the node is shutdown,
// upon restart, CWalletTx::AcceptToMemoryPool() will be invoked which might result in rejection.
if ( IsExpiringSoonTx ( tx , nextBlockHeight ) ) {
return state . DoS ( 0 , error ( " AcceptToMemoryPool(): transaction is expiring soon " ) , REJECT_INVALID , " tx-expiring-soon " ) ;
}
2010-08-29 09:58:15 -07:00
// Coinbase is only valid in a block, not as a loose transaction
2012-04-13 14:34:22 -07:00
if ( tx . IsCoinBase ( ) )
2014-12-30 14:02:46 -08:00
return state . DoS ( 100 , error ( " AcceptToMemoryPool: coinbase as individual tx " ) ,
2013-10-27 23:36:11 -07:00
REJECT_INVALID , " coinbase " ) ;
2010-09-06 18:12:53 -07:00
2013-07-23 08:46:05 -07:00
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
2013-06-22 23:05:25 -07:00
string reason ;
2019-03-14 03:57:14 -07:00
if ( Params ( ) . RequireStandard ( ) & & ! IsStandardTx ( tx , reason , Params ( ) , nextBlockHeight ) )
2013-10-27 23:36:11 -07:00
return state . DoS ( 0 ,
2015-01-08 02:44:25 -08:00
error ( " AcceptToMemoryPool: nonstandard transaction: %s " , reason ) ,
2013-10-27 23:36:11 -07:00
REJECT_NONSTANDARD , reason ) ;
2010-12-12 10:20:36 -08:00
2014-12-20 14:04:21 -08:00
// Only accept nLockTime-using transactions that can be mined in the next
// block; we don't want our mempool filled up with transactions that can't
// be mined yet.
2015-06-03 12:55:45 -07:00
if ( ! CheckFinalTx ( tx , STANDARD_LOCKTIME_VERIFY_FLAGS ) )
return state . DoS ( 0 , false , REJECT_NONSTANDARD , " non-final " ) ;
2014-12-20 14:04:21 -08:00
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
// is it already in the memory pool?
2016-08-30 12:49:38 -07:00
uint256 hash = tx . GetHash ( ) ;
2013-08-26 22:51:57 -07:00
if ( pool . exists ( hash ) )
return false ;
2010-08-29 09:58:15 -07:00
// Check for conflicts with in-memory transactions
2013-08-26 22:51:57 -07:00
{
LOCK ( pool . cs ) ; // protect pool.mapNextTx
2012-04-17 11:12:48 -07:00
for ( unsigned int i = 0 ; i < tx . vin . size ( ) ; i + + )
2010-08-29 09:58:15 -07:00
{
2012-04-13 14:34:22 -07:00
COutPoint outpoint = tx . vin [ i ] . prevout ;
2014-07-17 05:09:55 -07:00
if ( pool . mapNextTx . count ( outpoint ) )
2010-08-29 09:58:15 -07:00
{
2014-07-17 05:09:55 -07:00
// Disable replacement feature for now
2014-07-17 05:08:01 -07:00
return false ;
2010-08-29 09:58:15 -07:00
}
}
2016-07-14 15:10:41 -07:00
BOOST_FOREACH ( const JSDescription & joinsplit , tx . vjoinsplit ) {
2016-07-14 15:32:34 -07:00
BOOST_FOREACH ( const uint256 & nf , joinsplit . nullifiers ) {
2018-04-25 16:55:33 -07:00
if ( pool . nullifierExists ( nf , SPROUT ) ) {
2016-01-08 07:37:17 -08:00
return false ;
2018-04-25 10:26:38 -07:00
}
2016-01-08 07:37:17 -08:00
}
}
2018-04-24 16:16:43 -07:00
for ( const SpendDescription & spendDescription : tx . vShieldedSpend ) {
2018-04-25 16:55:33 -07:00
if ( pool . nullifierExists ( spendDescription . nullifier , SAPLING ) ) {
2018-04-24 16:16:43 -07:00
return false ;
2018-04-25 10:26:38 -07:00
}
2018-04-24 16:16:43 -07:00
}
2013-08-26 22:51:57 -07:00
}
2010-08-29 09:58:15 -07:00
{
2012-10-22 16:16:26 -07:00
CCoinsView dummy ;
2014-09-23 18:19:04 -07:00
CCoinsViewCache view ( & dummy ) ;
2012-10-22 16:16:26 -07:00
2014-04-22 15:46:19 -07:00
CAmount nValueIn = 0 ;
2012-10-22 16:16:26 -07:00
{
2013-08-26 22:51:57 -07:00
LOCK ( pool . cs ) ;
2014-09-23 18:19:04 -07:00
CCoinsViewMemPool viewMemPool ( pcoinsTip , pool ) ;
2012-10-22 16:16:26 -07:00
view . SetBackend ( viewMemPool ) ;
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
// do we already have it?
if ( view . HaveCoins ( hash ) )
2012-05-10 17:31:46 -07:00
return false ;
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
// do all inputs exist?
2012-10-22 15:21:16 -07:00
// Note that this does not check for the presence of actual outputs (see the next check for that),
2015-04-28 07:48:28 -07:00
// and only helps with filling in pfMissingInputs (to determine missing vs spent).
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
BOOST_FOREACH ( const CTxIn txin , tx . vin ) {
if ( ! view . HaveCoins ( txin . prevout . hash ) ) {
if ( pfMissingInputs )
* pfMissingInputs = true ;
return false ;
}
2011-10-03 10:05:43 -07:00
}
2012-10-22 15:21:16 -07:00
// are the actual inputs available?
2013-01-08 04:17:15 -08:00
if ( ! view . HaveInputs ( tx ) )
2015-01-08 02:44:25 -08:00
return state . Invalid ( error ( " AcceptToMemoryPool: inputs already spent " ) ,
2012-09-09 19:02:35 -07:00
REJECT_DUPLICATE , " bad-txns-inputs-spent " ) ;
2012-11-11 04:11:42 -08:00
2018-10-26 06:44:18 -07:00
// are the joinsplits' and sapling spends' requirements met in tx(valid anchors/nullifiers)?
if ( ! view . HaveShieldedRequirements ( tx ) )
2016-07-14 15:10:41 -07:00
return state . Invalid ( error ( " AcceptToMemoryPool: joinsplit requirements not met " ) ,
REJECT_DUPLICATE , " bad-txns-joinsplit-requirements-not-met " ) ;
2016-01-07 11:09:58 -08:00
2012-10-22 16:16:26 -07:00
// Bring the best block into scope
view . GetBestBlock ( ) ;
2014-03-17 05:19:54 -07:00
nValueIn = view . GetValueIn ( tx ) ;
2012-10-22 16:16:26 -07:00
// we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool
view . SetBackend ( dummy ) ;
}
2012-07-08 10:04:05 -07:00
2012-01-04 18:40:52 -08:00
// Check for non-standard pay-to-script-hash in inputs
2018-02-01 17:49:42 -08:00
if ( Params ( ) . RequireStandard ( ) & & ! AreInputsStandard ( tx , view , consensusBranchId ) )
2014-12-30 14:02:46 -08:00
return error ( " AcceptToMemoryPool: nonstandard transaction input " ) ;
2011-10-03 10:05:43 -07:00
2014-05-07 21:18:57 -07:00
// Check that the transaction doesn't have an excessive number of
// sigops, making it impossible to mine. Since the coinbase transaction
2015-01-01 03:35:29 -08:00
// itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than
2014-05-07 21:18:57 -07:00
// MAX_BLOCK_SIGOPS; we still consider this an invalid rather than
// merely non-standard transaction.
unsigned int nSigOps = GetLegacySigOpCount ( tx ) ;
nSigOps + = GetP2SHSigOpCount ( tx , view ) ;
2015-01-01 03:35:29 -08:00
if ( nSigOps > MAX_STANDARD_TX_SIGOPS )
2014-05-07 21:18:57 -07:00
return state . DoS ( 0 ,
2015-01-08 02:44:25 -08:00
error ( " AcceptToMemoryPool: too many sigops %s, %d > %d " ,
2015-01-01 03:35:29 -08:00
hash . ToString ( ) , nSigOps , MAX_STANDARD_TX_SIGOPS ) ,
2014-05-07 21:18:57 -07:00
REJECT_NONSTANDARD , " bad-txns-too-many-sigops " ) ;
2012-01-20 14:07:40 -08:00
2014-04-22 15:46:19 -07:00
CAmount nValueOut = tx . GetValueOut ( ) ;
CAmount nFees = nValueIn - nValueOut ;
2013-11-10 23:35:14 -08:00
double dPriority = view . GetPriority ( tx , chainActive . Height ( ) ) ;
2015-10-29 11:06:13 -07:00
// Keep track of transactions that spend a coinbase, which we re-scan
// during reorgs to ensure COINBASE_MATURITY is still met.
bool fSpendsCoinbase = false ;
BOOST_FOREACH ( const CTxIn & txin , tx . vin ) {
const CCoins * coins = view . AccessCoins ( txin . prevout . hash ) ;
if ( coins - > IsCoinBase ( ) ) {
fSpendsCoinbase = true ;
break ;
}
}
2018-02-09 15:16:55 -08:00
// Grab the branch ID we expect this transaction to commit to. We don't
// yet know if it does, but if the entry gets added to the mempool, then
// it has passed ContextualCheckInputs and therefore this is correct.
auto consensusBranchId = CurrentEpochBranchId ( chainActive . Height ( ) + 1 , Params ( ) . GetConsensus ( ) ) ;
CTxMemPoolEntry entry ( tx , nFees , GetTime ( ) , dPriority , chainActive . Height ( ) , mempool . HasNoInputsOf ( tx ) , fSpendsCoinbase , consensusBranchId ) ;
2013-11-10 23:35:14 -08:00
unsigned int nSize = entry . GetTxSize ( ) ;
2012-01-10 17:18:00 -08:00
2016-11-14 11:48:55 -08:00
// Accept a tx if it contains joinsplits and has at least the default fee specified by z_sendmany.
if ( tx . vjoinsplit . size ( ) > 0 & & nFees > = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE ) {
// In future we will we have more accurate and dynamic computation of fees for tx with joinsplits.
} else {
// Don't accept it if it can't get into a block
CAmount txMinFee = GetMinRelayFee ( tx , nSize , true ) ;
if ( fLimitFree & & nFees < txMinFee )
return state . DoS ( 0 , error ( " AcceptToMemoryPool: not enough fees %s, %d < %d " ,
hash . ToString ( ) , nFees , txMinFee ) ,
REJECT_INSUFFICIENTFEE , " insufficient fee " ) ;
}
2012-01-04 18:40:52 -08:00
2014-12-23 14:50:21 -08:00
// Require that free transactions have sufficient priority to be mined in the next block.
2016-06-07 02:11:57 -07:00
if ( GetBoolArg ( " -relaypriority " , false ) & & nFees < : : minRelayTxFee . GetFee ( nSize ) & & ! AllowFree ( view . GetPriority ( tx , chainActive . Height ( ) + 1 ) ) ) {
2014-12-23 14:50:21 -08:00
return state . DoS ( 0 , false , REJECT_INSUFFICIENTFEE , " insufficient priority " ) ;
}
2014-11-25 09:54:36 -08:00
// Continuously rate-limit free (really, very-low-fee) transactions
2011-03-13 11:38:07 -07:00
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
2012-07-25 20:25:26 -07:00
// be annoying or make others' transactions take longer to confirm.
2014-07-03 11:25:32 -07:00
if ( fLimitFree & & nFees < : : minRelayTxFee . GetFee ( nSize ) )
2010-12-12 10:20:36 -08:00
{
2014-07-17 05:09:55 -07:00
static CCriticalSection csFreeLimiter ;
2011-03-11 08:50:16 -08:00
static double dFreeCount ;
2014-07-17 05:09:55 -07:00
static int64_t nLastTime ;
int64_t nNow = GetTime ( ) ;
LOCK ( csFreeLimiter ) ;
2013-01-14 13:52:33 -08:00
2014-07-17 05:09:55 -07:00
// Use an exponentially decaying ~10-minute window:
dFreeCount * = pow ( 1.0 - 1.0 / 600.0 , ( double ) ( nNow - nLastTime ) ) ;
nLastTime = nNow ;
// -limitfreerelay unit is thousand-bytes-per-minute
// At default rate it would take over a month to fill 1GB
if ( dFreeCount > = GetArg ( " -limitfreerelay " , 15 ) * 10 * 1000 )
2015-01-08 02:44:25 -08:00
return state . DoS ( 0 , error ( " AcceptToMemoryPool: free transaction rejected by rate limiter " ) ,
2014-12-23 14:50:21 -08:00
REJECT_INSUFFICIENTFEE , " rate limited free transaction " ) ;
2013-08-26 22:51:57 -07:00
LogPrint ( " mempool " , " Rate limit dFreeCount: %g => %g \n " , dFreeCount , dFreeCount + nSize ) ;
2014-07-17 05:09:55 -07:00
dFreeCount + = nSize ;
2010-12-12 10:20:36 -08:00
}
2012-01-10 17:18:00 -08:00
2018-03-27 10:23:24 -07:00
if ( fRejectAbsurdFee & & nFees > : : minRelayTxFee . GetFee ( nSize ) * 10000 ) {
string errmsg = strprintf ( " absurdly high fees %s, %d > %d " ,
hash . ToString ( ) ,
nFees , : : minRelayTxFee . GetFee ( nSize ) * 10000 ) ;
LogPrint ( " mempool " , errmsg . c_str ( ) ) ;
return state . Error ( " AcceptToMemoryPool: " + errmsg ) ;
}
2013-08-28 15:41:46 -07:00
2012-01-10 17:18:00 -08:00
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
2016-08-26 09:38:20 -07:00
PrecomputedTransactionData txdata ( tx ) ;
2018-02-01 17:49:42 -08:00
if ( ! ContextualCheckInputs ( tx , state , view , true , STANDARD_SCRIPT_VERIFY_FLAGS , true , txdata , Params ( ) . GetConsensus ( ) , consensusBranchId ) )
2012-01-10 17:18:00 -08:00
{
2014-11-25 09:54:36 -08:00
return error ( " AcceptToMemoryPool: ConnectInputs failed %s " , hash . ToString ( ) ) ;
2012-01-10 17:18:00 -08:00
}
2014-11-09 23:52:28 -08:00
// Check again against just the consensus-critical mandatory script
// verification flags, in case of bugs in the standard flags that cause
// transactions to pass as valid when they're actually invalid. For
// instance the STRICTENC flag was incorrectly allowing certain
// CHECKSIG NOT scripts to pass, even though they were invalid.
//
// There is a similar check in CreateNewBlock() to prevent creating
// invalid blocks, however allowing such transactions into the mempool
// can be exploited as a DoS attack.
2018-02-01 17:49:42 -08:00
if ( ! ContextualCheckInputs ( tx , state , view , true , MANDATORY_SCRIPT_VERIFY_FLAGS , true , txdata , Params ( ) . GetConsensus ( ) , consensusBranchId ) )
2014-11-09 23:52:28 -08:00
{
2014-12-30 14:02:46 -08:00
return error ( " AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s " , hash . ToString ( ) ) ;
2014-11-09 23:52:28 -08:00
}
2014-07-17 05:08:01 -07:00
// Store transaction in memory
2014-08-26 13:28:32 -07:00
pool . addUnchecked ( hash , entry , ! IsInitialBlockDownload ( ) ) ;
2014-06-25 23:41:44 -07:00
}
2014-08-17 08:38:26 -07:00
SyncWithWallets ( tx , NULL ) ;
2014-06-25 23:41:44 -07:00
2014-07-17 05:08:01 -07:00
return true ;
2014-06-25 23:41:44 -07:00
}
2014-11-30 17:39:44 -08:00
/** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */
2015-04-17 05:19:21 -07:00
bool GetTransaction ( const uint256 & hash , CTransaction & txOut , const Consensus : : Params & consensusParams , uint256 & hashBlock , bool fAllowSlow )
2012-02-15 08:49:04 -08:00
{
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
CBlockIndex * pindexSlow = NULL ;
2015-09-17 14:43:34 -07:00
LOCK ( cs_main ) ;
if ( mempool . lookup ( hash , txOut ) )
2012-02-15 08:49:04 -08:00
{
2015-09-17 14:43:34 -07:00
return true ;
}
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
2015-09-17 14:43:34 -07:00
if ( fTxIndex ) {
CDiskTxPos postx ;
if ( pblocktree - > ReadTxIndex ( hash , postx ) ) {
CAutoFile file ( OpenBlockFile ( postx , true ) , SER_DISK , CLIENT_VERSION ) ;
if ( file . IsNull ( ) )
return error ( " %s: OpenBlockFile failed " , __func__ ) ;
CBlockHeader header ;
try {
file > > header ;
fseek ( file . Get ( ) , postx . nTxOffset , SEEK_CUR ) ;
file > > txOut ;
} catch ( const std : : exception & e ) {
return error ( " %s: Deserialize or I/O error - %s " , __func__ , e . what ( ) ) ;
2013-01-10 16:47:57 -08:00
}
2015-09-17 14:43:34 -07:00
hashBlock = header . GetHash ( ) ;
2016-08-30 12:49:38 -07:00
if ( txOut . GetHash ( ) ! = hash )
2015-09-17 14:43:34 -07:00
return error ( " %s: txid mismatch " , __func__ ) ;
return true ;
2013-01-10 16:47:57 -08:00
}
2015-09-17 14:43:34 -07:00
}
2013-01-10 16:47:57 -08:00
2015-09-17 14:43:34 -07:00
if ( fAllowSlow ) { // use coin database to locate block that contains transaction, and scan it
int nHeight = - 1 ;
{
CCoinsViewCache & view = * pcoinsTip ;
const CCoins * coins = view . AccessCoins ( hash ) ;
if ( coins )
nHeight = coins - > nHeight ;
2012-02-15 08:49:04 -08:00
}
2015-09-17 14:43:34 -07:00
if ( nHeight > 0 )
pindexSlow = chainActive [ nHeight ] ;
2012-02-15 08:49:04 -08:00
}
2010-08-29 09:58:15 -07:00
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
if ( pindexSlow ) {
CBlock block ;
2015-04-17 05:19:21 -07:00
if ( ReadBlockFromDisk ( block , pindexSlow , consensusParams ) ) {
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
BOOST_FOREACH ( const CTransaction & tx , block . vtx ) {
2016-08-30 12:49:38 -07:00
if ( tx . GetHash ( ) = = hash ) {
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
txOut = tx ;
hashBlock = pindexSlow - > GetBlockHash ( ) ;
return true ;
}
}
}
}
2010-08-29 09:58:15 -07:00
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
return false ;
}
2010-08-29 09:58:15 -07:00
//////////////////////////////////////////////////////////////////////////////
//
// CBlock and CBlockIndex
//
2015-08-08 09:18:41 -07:00
bool WriteBlockToDisk ( const CBlock & block , CDiskBlockPos & pos , const CMessageHeader : : MessageStartChars & messageStart )
2013-06-23 17:47:47 -07:00
{
// Open history file to append
2014-09-25 16:25:19 -07:00
CAutoFile fileout ( OpenBlockFile ( pos ) , SER_DISK , CLIENT_VERSION ) ;
2014-10-13 16:48:34 -07:00
if ( fileout . IsNull ( ) )
2015-01-08 02:44:25 -08:00
return error ( " WriteBlockToDisk: OpenBlockFile failed " ) ;
2013-06-23 17:47:47 -07:00
// Write index header
2016-10-28 16:51:33 -07:00
unsigned int nSize = GetSerializeSize ( fileout , block ) ;
2015-04-19 14:48:25 -07:00
fileout < < FLATDATA ( messageStart ) < < nSize ;
2013-06-23 17:47:47 -07:00
// Write block
2014-10-20 03:45:50 -07:00
long fileOutPos = ftell ( fileout . Get ( ) ) ;
2013-06-23 17:47:47 -07:00
if ( fileOutPos < 0 )
2015-01-08 02:44:25 -08:00
return error ( " WriteBlockToDisk: ftell failed " ) ;
2013-06-23 17:47:47 -07:00
pos . nPos = ( unsigned int ) fileOutPos ;
fileout < < block ;
return true ;
}
2015-04-17 05:19:21 -07: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
2014-09-25 16:25:19 -07:00
CAutoFile filein ( OpenBlockFile ( pos , true ) , SER_DISK , CLIENT_VERSION ) ;
2014-10-13 16:48:34 -07:00
if ( filein . IsNull ( ) )
2015-01-26 00:47:59 -08:00
return error ( " ReadBlockFromDisk: OpenBlockFile failed for %s " , pos . ToString ( ) ) ;
2013-06-23 18:21:33 -07:00
// Read block
try {
filein > > block ;
}
2014-12-07 04:29:06 -08:00
catch ( const std : : exception & e ) {
2015-01-26 00:47:59 -08: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 05:19:21 -07:00
if ( ! ( CheckEquihashSolution ( & block , consensusParams ) & &
CheckProofOfWork ( block . GetHash ( ) , block . nBits , consensusParams ) ) )
2015-01-26 00:47:59 -08: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 05:19:21 -07:00
bool ReadBlockFromDisk ( CBlock & block , const CBlockIndex * pindex , const Consensus : : Params & consensusParams )
2010-08-29 09:58:15 -07:00
{
2015-04-17 05:19:21 -07:00
if ( ! ReadBlockFromDisk ( block , pindex - > GetBlockPos ( ) , consensusParams ) )
2010-08-29 09:58:15 -07:00
return false ;
2013-06-23 18:10:02 -07:00
if ( block . GetHash ( ) ! = pindex - > GetBlockHash ( ) )
2015-01-26 00:47:59 -08:00
return error ( " ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s " ,
pindex - > ToString ( ) , pindex - > GetBlockPos ( ) . ToString ( ) ) ;
2010-08-29 09:58:15 -07:00
return true ;
}
2015-04-01 07:03:11 -07:00
CAmount GetBlockSubsidy ( int nHeight , const Consensus : : Params & consensusParams )
2010-08-29 09:58:15 -07:00
{
2016-06-03 00:09:39 -07:00
CAmount nSubsidy = 12.5 * COIN ;
2016-04-18 23:50:52 -07:00
// Mining slow start
// The subsidy is ramped up linearly, skipping the middle payout of
// MAX_SUBSIDY/2 to keep the monetary curve consistent with no slow start.
if ( nHeight < consensusParams . nSubsidySlowStartInterval / 2 ) {
nSubsidy / = consensusParams . nSubsidySlowStartInterval ;
nSubsidy * = nHeight ;
return nSubsidy ;
} else if ( nHeight < consensusParams . nSubsidySlowStartInterval ) {
nSubsidy / = consensusParams . nSubsidySlowStartInterval ;
nSubsidy * = ( nHeight + 1 ) ;
return nSubsidy ;
}
assert ( nHeight > consensusParams . SubsidySlowStartShift ( ) ) ;
int halvings = ( nHeight - consensusParams . SubsidySlowStartShift ( ) ) / consensusParams . nSubsidyHalvingInterval ;
2014-03-10 17:02:36 -07:00
// Force block reward to zero when right shift is undefined.
if ( halvings > = 64 )
2015-04-01 07:03:11 -07:00
return 0 ;
2010-08-29 09:58:15 -07:00
2016-06-03 00:09:39 -07:00
// Subsidy is cut in half every 840,000 blocks which will occur approximately every 4 years.
2014-03-10 17:02:36 -07:00
nSubsidy > > = halvings ;
2015-04-01 07:03:11 -07:00
return nSubsidy ;
2010-08-29 09:58:15 -07:00
}
bool IsInitialBlockDownload ( )
{
2015-04-22 15:19:11 -07:00
const CChainParams & chainParams = Params ( ) ;
2016-04-26 17:21:22 -07:00
// Once this function has returned false, it must remain false.
static std : : atomic < bool > latchToFalse { false } ;
// Optimization: pre-test latch before taking the lock.
if ( latchToFalse . load ( std : : memory_order_relaxed ) )
return false ;
2014-04-15 08:38:25 -07:00
LOCK ( cs_main ) ;
2016-04-26 17:21:22 -07:00
if ( latchToFalse . load ( std : : memory_order_relaxed ) )
return false ;
2015-04-22 20:22:36 -07:00
if ( fImporting | | fReindex )
return true ;
2016-10-21 22:33:25 -07:00
if ( chainActive . Tip ( ) = = NULL )
2010-08-29 09:58:15 -07:00
return true ;
2016-10-21 22:33:25 -07:00
if ( chainActive . Tip ( ) - > nChainWork < UintToArith256 ( chainParams . GetConsensus ( ) . nMinimumChainWork ) )
2010-08-29 09:58:15 -07:00
return true ;
2016-10-31 17:37:54 -07:00
if ( chainActive . Tip ( ) - > GetBlockTime ( ) < ( GetTime ( ) - nMaxTipAge ) )
return true ;
2017-05-11 10:11:36 -07:00
LogPrintf ( " Leaving InitialBlockDownload (latching to false) \n " ) ;
2016-10-31 17:37:54 -07:00
latchToFalse . store ( true , std : : memory_order_relaxed ) ;
return false ;
2010-08-29 09:58:15 -07:00
}
2018-01-14 08:23:05 -08:00
static bool fLargeWorkForkFound = false ;
static bool fLargeWorkInvalidChainFound = false ;
static CBlockIndex * pindexBestForkTip = NULL ;
static CBlockIndex * pindexBestForkBase = NULL ;
2013-05-07 09:33:52 -07:00
void CheckForkWarningConditions ( )
{
2014-04-15 03:43:17 -07:00
AssertLockHeld ( cs_main ) ;
2013-09-03 19:06:02 -07:00
// Before we get past initial download, we cannot reliably alert about forks
2016-10-21 22:33:25 -07:00
// (we assume we don't get stuck on a fork before finishing our initial sync)
2013-09-03 19:06:02 -07:00
if ( IsInitialBlockDownload ( ) )
return ;
2016-06-09 16:43:40 -07:00
// If our best fork is no longer within 288 blocks (+/- 12 hours if no one mines it)
2013-05-07 09:33:52 -07:00
// of our head, drop it
2016-06-09 16:43:40 -07:00
if ( pindexBestForkTip & & chainActive . Height ( ) - pindexBestForkTip - > nHeight > = 288 )
2013-05-07 09:33:52 -07:00
pindexBestForkTip = NULL ;
2014-10-29 09:00:02 -07:00
if ( pindexBestForkTip | | ( pindexBestInvalid & & pindexBestInvalid - > nChainWork > chainActive . Tip ( ) - > nChainWork + ( GetBlockProof ( * chainActive . Tip ( ) ) * 6 ) ) )
2013-05-07 09:33:52 -07:00
{
2014-10-27 20:00:55 -07:00
if ( ! fLargeWorkForkFound & & pindexBestForkBase )
2013-05-07 09:37:37 -07:00
{
2014-10-07 10:11:48 -07:00
std : : string warning = std : : string ( " 'Warning: Large-work fork detected, forking after block " ) +
pindexBestForkBase - > phashBlock - > ToString ( ) + std : : string ( " ' " ) ;
CAlert : : Notify ( warning , true ) ;
2013-05-07 09:37:37 -07:00
}
2014-10-27 20:00:55 -07:00
if ( pindexBestForkTip & & pindexBestForkBase )
2013-05-17 18:09:28 -07:00
{
2015-02-24 09:32:34 -08:00
LogPrintf ( " %s: Warning: Large valid fork found \n forking the chain at height %d (%s) \n lasting to height %d (%s). \n Chain state database corruption likely. \n " , __func__ ,
2014-01-16 07:15:27 -08:00
pindexBestForkBase - > nHeight , pindexBestForkBase - > phashBlock - > ToString ( ) ,
pindexBestForkTip - > nHeight , pindexBestForkTip - > phashBlock - > ToString ( ) ) ;
2013-05-17 18:09:28 -07:00
fLargeWorkForkFound = true ;
}
else
{
2016-06-09 12:48:04 -07:00
std : : string warning = std : : string ( " Warning: Found invalid chain at least ~6 blocks longer than our best chain. \n Chain state database corruption likely. " ) ;
LogPrintf ( " %s: %s \n " , warning . c_str ( ) , __func__ ) ;
CAlert : : Notify ( warning , true ) ;
2013-05-17 18:09:28 -07:00
fLargeWorkInvalidChainFound = true ;
}
}
else
{
2013-05-07 09:33:52 -07:00
fLargeWorkForkFound = false ;
2013-05-17 18:09:28 -07:00
fLargeWorkInvalidChainFound = false ;
}
2013-05-07 09:33:52 -07:00
}
void CheckForkWarningConditionsOnNewFork ( CBlockIndex * pindexNewForkTip )
{
2014-04-15 03:43:17 -07:00
AssertLockHeld ( cs_main ) ;
2013-05-07 09:33:52 -07:00
// If we are on a fork that is sufficiently large, set a warning flag
CBlockIndex * pfork = pindexNewForkTip ;
2013-10-10 14:07:44 -07:00
CBlockIndex * plonger = chainActive . Tip ( ) ;
2013-05-07 09:33:52 -07:00
while ( pfork & & pfork ! = plonger )
{
while ( plonger & & plonger - > nHeight > pfork - > nHeight )
plonger = plonger - > pprev ;
if ( pfork = = plonger )
break ;
pfork = pfork - > pprev ;
}
2015-04-28 07:48:28 -07:00
// We define a condition where we should warn the user about as a fork of at least 7 blocks
2016-11-18 10:26:20 -08:00
// with a tip within 72 blocks (+/- 3 hours if no one mines it) of ours
2013-05-07 09:33:52 -07:00
// We use 7 blocks rather arbitrarily as it represents just under 10% of sustained network
// hash rate operating on the fork.
// or a chain that is entirely longer than ours and invalid (note that this should be detected by both)
// We define it this way because it allows us to only store the highest fork tip (+ base) which meets
// the 7-block condition and from this always have the most-likely-to-cause-warning fork
if ( pfork & & ( ! pindexBestForkTip | | ( pindexBestForkTip & & pindexNewForkTip - > nHeight > pindexBestForkTip - > nHeight ) ) & &
2014-10-29 09:00:02 -07:00
pindexNewForkTip - > nChainWork - pfork - > nChainWork > ( GetBlockProof ( * pfork ) * 7 ) & &
2013-10-10 14:07:44 -07:00
chainActive . Height ( ) - pindexNewForkTip - > nHeight < 72 )
2013-05-07 09:33:52 -07:00
{
pindexBestForkTip = pindexNewForkTip ;
pindexBestForkBase = pfork ;
}
CheckForkWarningConditions ( ) ;
}
2014-01-10 04:23:26 -08:00
// Requires cs_main.
2013-11-16 10:28:24 -08:00
void Misbehaving ( NodeId pnode , int howmuch )
{
if ( howmuch = = 0 )
return ;
CNodeState * state = State ( pnode ) ;
if ( state = = NULL )
return ;
state - > nMisbehavior + = howmuch ;
2014-06-21 04:34:36 -07:00
int banscore = GetArg ( " -banscore " , 100 ) ;
if ( state - > nMisbehavior > = banscore & & state - > nMisbehavior - howmuch < banscore )
2013-11-16 10:28:24 -08:00
{
2015-02-24 09:32:34 -08:00
LogPrintf ( " %s: %s (%d -> %d) BAN THRESHOLD EXCEEDED \n " , __func__ , state - > name , state - > nMisbehavior - howmuch , state - > nMisbehavior ) ;
2013-11-16 10:28:24 -08:00
state - > fShouldBan = true ;
} else
2015-02-24 09:32:34 -08:00
LogPrintf ( " %s: %s (%d -> %d) \n " , __func__ , state - > name , state - > nMisbehavior - howmuch , state - > nMisbehavior ) ;
2013-11-16 10:28:24 -08:00
}
CWallet class
* A new class CKeyStore manages private keys, and script.cpp depends on access to CKeyStore.
* A new class CWallet extends CKeyStore, and contains all former wallet-specific globals; CWallet depends on script.cpp, not the other way around.
* Wallet-specific functions in CTransaction/CTxIn/CTxOut (GetDebit, GetCredit, GetChange, IsMine, IsFromMe), are moved to CWallet, taking their former 'this' argument as an explicit parameter
* CWalletTx objects know which CWallet they belong to, for convenience, so they have their own direct (and caching) GetDebit/... functions.
* Some code was moved from CWalletDB to CWallet, such as handling of reserve keys.
* Main.cpp keeps a set of all 'registered' wallets, which should be informed about updates to the block chain, and does not have any notion about any 'main' wallet. Function in main.cpp that require a wallet (such as GenerateCoins), take an explicit CWallet* argument.
* The actual CWallet instance used by the application is defined in init.cpp as "CWallet* pwalletMain". rpc.cpp and ui.cpp use this variable.
* Functions in main.cpp and db.cpp that are not used by other modules are marked static.
* The code for handling the 'submitorder' message is removed, as it not really compatible with the idea that a node is independent from the wallet(s) connected to it, and obsolete anyway.
2011-06-01 09:28:20 -07:00
void static InvalidChainFound ( CBlockIndex * pindexNew )
2010-08-29 09:58:15 -07:00
{
2013-10-13 13:15:48 -07:00
if ( ! pindexBestInvalid | | pindexNew - > nChainWork > pindexBestInvalid - > nChainWork )
pindexBestInvalid = pindexNew ;
2014-07-29 07:53:38 -07:00
2015-02-24 09:32:34 -08:00
LogPrintf ( " %s: invalid block=%s height=%d log2_work=%.8g date=%s \n " , __func__ ,
2014-01-16 07:15:27 -08:00
pindexNew - > GetBlockHash ( ) . ToString ( ) , pindexNew - > nHeight ,
2013-03-28 15:51:50 -07:00
log ( pindexNew - > nChainWork . getdouble ( ) ) / log ( 2.0 ) , DateTimeStrFormat ( " %Y-%m-%d %H:%M:%S " ,
2014-01-16 07:15:27 -08:00
pindexNew - > GetBlockTime ( ) ) ) ;
2015-07-04 12:14:03 -07:00
CBlockIndex * tip = chainActive . Tip ( ) ;
assert ( tip ) ;
2015-02-24 09:32:34 -08:00
LogPrintf ( " %s: current best=%s height=%d log2_work=%.8g date=%s \n " , __func__ ,
2015-07-04 12:14:03 -07:00
tip - > GetBlockHash ( ) . ToString ( ) , chainActive . Height ( ) , log ( tip - > nChainWork . getdouble ( ) ) / log ( 2.0 ) ,
DateTimeStrFormat ( " %Y-%m-%d %H:%M:%S " , tip - > GetBlockTime ( ) ) ) ;
2013-05-07 09:33:52 -07:00
CheckForkWarningConditions ( ) ;
2010-08-29 09:58:15 -07:00
}
2013-11-16 10:28:24 -08:00
void static InvalidBlockFound ( CBlockIndex * pindex , const CValidationState & state ) {
int nDoS = 0 ;
if ( state . IsInvalid ( nDoS ) ) {
std : : map < uint256 , NodeId > : : iterator it = mapBlockSource . find ( pindex - > GetBlockHash ( ) ) ;
if ( it ! = mapBlockSource . end ( ) & & State ( it - > second ) ) {
2014-11-29 07:01:37 -08:00
CBlockReject reject = { state . GetRejectCode ( ) , state . GetRejectReason ( ) . substr ( 0 , MAX_REJECT_MESSAGE_LENGTH ) , pindex - > GetBlockHash ( ) } ;
2013-11-16 10:28:24 -08:00
State ( it - > second ) - > rejects . push_back ( reject ) ;
if ( nDoS > 0 )
Misbehaving ( it - > second , nDoS ) ;
2012-08-18 15:33:01 -07:00
}
2013-11-16 10:28:24 -08:00
}
if ( ! state . CorruptionPossible ( ) ) {
pindex - > nStatus | = BLOCK_FAILED_VALID ;
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
setDirtyBlockIndex . insert ( pindex ) ;
2014-10-05 23:31:33 -07:00
setBlockIndexCandidates . erase ( pindex ) ;
2013-11-16 10:28:24 -08:00
InvalidChainFound ( pindex ) ;
}
2012-08-18 15:33:01 -07:00
}
2016-04-29 20:45:20 -07:00
void UpdateCoins ( const CTransaction & tx , CCoinsViewCache & inputs , CTxUndo & txundo , int nHeight )
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
{
// mark inputs spent
2013-01-08 04:17:15 -08:00
if ( ! tx . IsCoinBase ( ) ) {
2014-09-03 06:54:37 -07:00
txundo . vprevout . reserve ( tx . vin . size ( ) ) ;
2014-09-03 00:01:24 -07:00
BOOST_FOREACH ( const CTxIn & txin , tx . vin ) {
2014-10-18 17:57:02 -07:00
CCoinsModifier coins = inputs . ModifyCoins ( txin . prevout . hash ) ;
unsigned nPos = txin . prevout . n ;
if ( nPos > = coins - > vout . size ( ) | | coins - > vout [ nPos ] . IsNull ( ) )
assert ( false ) ;
// mark an outpoint spent, and construct undo information
txundo . vprevout . push_back ( CTxInUndo ( coins - > vout [ nPos ] ) ) ;
coins - > Spend ( nPos ) ;
if ( coins - > vout . size ( ) = = 0 ) {
CTxInUndo & undo = txundo . vprevout . back ( ) ;
undo . nHeight = coins - > nHeight ;
undo . fCoinBase = coins - > fCoinBase ;
undo . nVersion = coins - > nVersion ;
}
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
}
}
2016-07-10 22:18:53 -07:00
// spend nullifiers
2018-04-18 12:18:57 -07:00
inputs . SetNullifiers ( tx , true ) ;
2016-01-08 07:37:17 -08:00
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
// add outputs
2015-11-02 18:27:15 -08:00
inputs . ModifyNewCoins ( tx . GetHash ( ) ) - > FromTx ( tx , nHeight ) ;
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
}
2016-04-29 20:45:20 -07:00
void UpdateCoins ( const CTransaction & tx , CCoinsViewCache & inputs , int nHeight )
2014-10-27 08:07:50 -07:00
{
CTxUndo txundo ;
2016-04-29 20:45:20 -07:00
UpdateCoins ( tx , inputs , txundo , nHeight ) ;
2014-10-27 08:07:50 -07:00
}
2014-11-29 07:01:37 -08:00
bool CScriptCheck : : operator ( ) ( ) {
2012-12-01 13:30:06 -08:00
const CScript & scriptSig = ptxTo - > vin [ nIn ] . scriptSig ;
2018-02-01 17:49:42 -08:00
if ( ! VerifyScript ( scriptSig , scriptPubKey , nFlags , CachingTransactionSignatureChecker ( ptxTo , nIn , amount , cacheStore , * txdata ) , consensusBranchId , & error ) ) {
2016-08-30 12:49:38 -07:00
return : : error ( " CScriptCheck(): %s:%d VerifySignature failed: %s " , ptxTo - > GetHash ( ) . ToString ( ) , nIn , ScriptErrorString ( error ) ) ;
2014-11-29 07:01:37 -08:00
}
2012-12-01 13:30:06 -08:00
return true ;
}
2015-04-24 07:45:16 -07:00
int GetSpendHeight ( const CCoinsViewCache & inputs )
2010-08-29 09:58:15 -07:00
{
2015-04-24 07:45:16 -07:00
LOCK ( cs_main ) ;
CBlockIndex * pindexPrev = mapBlockIndex . find ( inputs . GetBestBlock ( ) ) - > second ;
return pindexPrev - > nHeight + 1 ;
}
2012-12-01 14:04:14 -08:00
2015-04-24 07:45:16 -07:00
namespace Consensus {
bool CheckTxInputs ( const CTransaction & tx , CValidationState & state , const CCoinsViewCache & inputs , int nSpendHeight , const Consensus : : Params & consensusParams )
{
2012-07-08 10:04:05 -07:00
// This doesn't trigger the DoS code on purpose; if it did, it would make it easier
// for an attacker to attempt to split the network.
2013-01-08 04:17:15 -08:00
if ( ! inputs . HaveInputs ( tx ) )
2016-08-30 12:49:38 -07:00
return state . Invalid ( error ( " CheckInputs(): %s inputs unavailable " , tx . GetHash ( ) . ToString ( ) ) ) ;
2012-07-08 10:04:05 -07:00
2016-07-14 15:10:41 -07:00
// are the JoinSplit's requirements met?
2018-10-26 06:44:18 -07:00
if ( ! inputs . HaveShieldedRequirements ( tx ) )
2016-08-30 12:49:38 -07:00
return state . Invalid ( error ( " CheckInputs(): %s JoinSplit requirements not met " , tx . GetHash ( ) . ToString ( ) ) ) ;
2016-01-07 11:09:58 -08:00
2014-04-22 15:46:19 -07:00
CAmount nValueIn = 0 ;
CAmount nFees = 0 ;
2013-01-08 04:17:15 -08:00
for ( unsigned int i = 0 ; i < tx . vin . size ( ) ; i + + )
2010-08-29 09:58:15 -07:00
{
2013-01-08 04:17:15 -08:00
const COutPoint & prevout = tx . vin [ i ] . prevout ;
2014-09-02 12:21:15 -07:00
const CCoins * coins = inputs . AccessCoins ( prevout . hash ) ;
assert ( coins ) ;
2010-08-29 09:58:15 -07:00
2014-09-02 12:21:15 -07:00
if ( coins - > IsCoinBase ( ) ) {
2015-04-24 07:45:16 -07:00
// Ensure that coinbases are matured
if ( nSpendHeight - coins - > nHeight < COINBASE_MATURITY ) {
return state . Invalid (
error ( " CheckInputs(): tried to spend coinbase at depth %d " , nSpendHeight - coins - > nHeight ) ,
REJECT_INVALID , " bad-txns-premature-spend-of-coinbase " ) ;
}
2016-06-13 10:58:10 -07:00
// Ensure that coinbases cannot be spent to transparent outputs
2016-06-13 11:23:55 -07:00
// Disabled on regtest
2016-06-14 14:18:52 -07:00
if ( fCoinbaseEnforcedProtectionEnabled & &
consensusParams . fCoinbaseMustBeProtected & &
! tx . vout . empty ( ) ) {
2013-10-27 23:36:11 -07:00
return state . Invalid (
2016-06-13 10:58:10 -07:00
error ( " CheckInputs(): tried to spend coinbase with transparent outputs " ) ,
REJECT_INVALID , " bad-txns-coinbase-spend-has-transparent-outputs " ) ;
}
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
}
2010-08-29 09:58:15 -07:00
2012-05-16 08:26:56 -07:00
// Check for negative or overflow input values
2014-09-02 12:21:15 -07:00
nValueIn + = coins - > vout [ prevout . n ] . nValue ;
if ( ! MoneyRange ( coins - > vout [ prevout . n ] . nValue ) | | ! MoneyRange ( nValueIn ) )
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " CheckInputs(): txin values out of range " ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " bad-txns-inputvalues-outofrange " ) ;
2012-05-16 08:26:56 -07:00
}
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
2018-05-08 05:51:54 -07:00
nValueIn + = tx . GetShieldedValueIn ( ) ;
2016-01-04 05:02:01 -08:00
if ( ! MoneyRange ( nValueIn ) )
2018-05-08 05:51:54 -07:00
return state . DoS ( 100 , error ( " CheckInputs(): shielded input to transparent value pool out of range " ) ,
2016-01-04 05:02:01 -08:00
REJECT_INVALID , " bad-txns-inputvalues-outofrange " ) ;
2013-11-10 22:03:51 -08:00
if ( nValueIn < tx . GetValueOut ( ) )
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " CheckInputs(): %s value in (%s) < value out (%s) " ,
2016-08-30 12:49:38 -07:00
tx . GetHash ( ) . ToString ( ) , FormatMoney ( nValueIn ) , FormatMoney ( tx . GetValueOut ( ) ) ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " bad-txns-in-belowout " ) ;
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
// Tally transaction fees
2014-04-22 15:46:19 -07:00
CAmount nTxFee = nValueIn - tx . GetValueOut ( ) ;
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
if ( nTxFee < 0 )
2016-08-30 12:49:38 -07:00
return state . DoS ( 100 , error ( " CheckInputs(): %s nTxFee < 0 " , tx . GetHash ( ) . ToString ( ) ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " bad-txns-fee-negative " ) ;
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
nFees + = nTxFee ;
if ( ! MoneyRange ( nFees ) )
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " CheckInputs(): nFees out of range " ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " bad-txns-fee-outofrange " ) ;
2015-04-24 07:45:16 -07:00
return true ;
}
} // namespace Consensus
2018-02-19 16:57:02 -08:00
bool ContextualCheckInputs (
const CTransaction & tx ,
CValidationState & state ,
const CCoinsViewCache & inputs ,
bool fScriptChecks ,
unsigned int flags ,
bool cacheStore ,
PrecomputedTransactionData & txdata ,
const Consensus : : Params & consensusParams ,
uint32_t consensusBranchId ,
std : : vector < CScriptCheck > * pvChecks )
2015-04-24 07:45:16 -07:00
{
if ( ! tx . IsCoinBase ( ) )
{
2017-05-17 18:21:00 -07:00
if ( ! Consensus : : CheckTxInputs ( tx , state , inputs , GetSpendHeight ( inputs ) , consensusParams ) ) {
return false ;
}
2015-04-24 07:45:16 -07:00
if ( pvChecks )
pvChecks - > reserve ( tx . vin . size ( ) ) ;
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
2012-05-16 08:26:56 -07:00
// The first loop above does all the inexpensive checks.
// Only if ALL inputs pass do we perform expensive ECDSA signature checks.
// Helps prevent CPU exhaustion attacks.
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
// Skip ECDSA signature verification when connecting blocks
2012-10-05 10:22:21 -07:00
// before the last block chain checkpoint. This is safe because block merkle hashes are
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
// still computed and checked, and any change will be caught at the next checkpoint.
2012-12-01 13:51:10 -08:00
if ( fScriptChecks ) {
2013-01-08 04:17:15 -08:00
for ( unsigned int i = 0 ; i < tx . vin . size ( ) ; i + + ) {
const COutPoint & prevout = tx . vin [ i ] . prevout ;
2014-09-02 12:21:15 -07:00
const CCoins * coins = inputs . AccessCoins ( prevout . hash ) ;
assert ( coins ) ;
2012-01-10 17:18:00 -08:00
2011-09-02 13:59:47 -07:00
// Verify signature
2018-02-01 17:49:42 -08:00
CScriptCheck check ( * coins , tx , i , flags , cacheStore , consensusBranchId , & txdata ) ;
2012-12-01 14:04:14 -08:00
if ( pvChecks ) {
pvChecks - > push_back ( CScriptCheck ( ) ) ;
check . swap ( pvChecks - > back ( ) ) ;
2013-04-18 13:17:05 -07:00
} else if ( ! check ( ) ) {
2014-03-10 19:36:46 -07:00
if ( flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS ) {
// Check whether the failure was caused by a
// non-mandatory script verification check, such as
// non-standard DER encodings or non-null dummy
// arguments; if so, don't trigger DoS protection to
// avoid splitting the network between upgraded and
// non-upgraded nodes.
2016-01-03 07:50:31 -08:00
CScriptCheck check2 ( * coins , tx , i ,
2018-02-01 17:49:42 -08:00
flags & ~ STANDARD_NOT_MANDATORY_VERIFY_FLAGS , cacheStore , consensusBranchId , & txdata ) ;
2016-01-03 07:50:31 -08:00
if ( check2 ( ) )
2014-11-29 07:01:37 -08:00
return state . Invalid ( false , REJECT_NONSTANDARD , strprintf ( " non-mandatory-script-verify-flag (%s) " , ScriptErrorString ( check . GetScriptError ( ) ) ) ) ;
2013-04-18 13:17:05 -07:00
}
2014-03-10 19:36:46 -07:00
// Failures of other flags indicate a transaction that is
// invalid in new blocks, e.g. a invalid P2SH. We DoS ban
// such nodes as they are not following the protocol. That
// said during an upgrade careful thought should be taken
// as to the correct behavior - we may want to continue
// peering with non-upgraded nodes even after a soft-fork
// super-majority vote has passed.
2014-11-29 07:01:37 -08:00
return state . DoS ( 100 , false , REJECT_INVALID , strprintf ( " mandatory-script-verify-flag-failed (%s) " , ScriptErrorString ( check . GetScriptError ( ) ) ) ) ;
2013-04-18 13:17:05 -07:00
}
2011-11-08 10:20:29 -08:00
}
2010-08-29 09:58:15 -07:00
}
}
return true ;
}
2014-12-02 15:39:03 -08:00
namespace {
2015-04-19 14:48:25 -07:00
bool UndoWriteToDisk ( const CBlockUndo & blockundo , CDiskBlockPos & pos , const uint256 & hashBlock , const CMessageHeader : : MessageStartChars & messageStart )
2014-12-02 15:39:03 -08:00
{
// Open history file to append
CAutoFile fileout ( OpenUndoFile ( pos ) , SER_DISK , CLIENT_VERSION ) ;
if ( fileout . IsNull ( ) )
2015-01-08 02:44:25 -08:00
return error ( " %s: OpenUndoFile failed " , __func__ ) ;
2014-12-02 15:39:03 -08:00
// Write index header
2016-10-28 16:51:33 -07:00
unsigned int nSize = GetSerializeSize ( fileout , blockundo ) ;
2015-04-19 14:48:25 -07:00
fileout < < FLATDATA ( messageStart ) < < nSize ;
2014-12-02 15:39:03 -08:00
// Write undo data
long fileOutPos = ftell ( fileout . Get ( ) ) ;
if ( fileOutPos < 0 )
2015-01-08 02:44:25 -08:00
return error ( " %s: ftell failed " , __func__ ) ;
2014-12-02 15:39:03 -08:00
pos . nPos = ( unsigned int ) fileOutPos ;
fileout < < blockundo ;
// calculate & write checksum
CHashWriter hasher ( SER_GETHASH , PROTOCOL_VERSION ) ;
hasher < < hashBlock ;
hasher < < blockundo ;
fileout < < hasher . GetHash ( ) ;
return true ;
}
bool UndoReadFromDisk ( CBlockUndo & blockundo , const CDiskBlockPos & pos , const uint256 & hashBlock )
{
// Open history file to read
CAutoFile filein ( OpenUndoFile ( pos , true ) , SER_DISK , CLIENT_VERSION ) ;
if ( filein . IsNull ( ) )
2015-01-08 02:44:25 -08:00
return error ( " %s: OpenBlockFile failed " , __func__ ) ;
2014-12-02 15:39:03 -08:00
// Read block
uint256 hashChecksum ;
try {
filein > > blockundo ;
filein > > hashChecksum ;
}
catch ( const std : : exception & e ) {
2015-01-08 02:44:25 -08:00
return error ( " %s: Deserialize or I/O error - %s " , __func__ , e . what ( ) ) ;
2014-12-02 15:39:03 -08:00
}
// Verify checksum
CHashWriter hasher ( SER_GETHASH , PROTOCOL_VERSION ) ;
hasher < < hashBlock ;
hasher < < blockundo ;
if ( hashChecksum ! = hasher . GetHash ( ) )
2015-01-08 02:44:25 -08:00
return error ( " %s: Checksum mismatch " , __func__ ) ;
2014-12-02 15:39:03 -08:00
return true ;
}
2015-01-16 15:57:14 -08:00
/** Abort with a message */
bool AbortNode ( const std : : string & strMessage , const std : : string & userMessage = " " )
{
strMiscWarning = strMessage ;
LogPrintf ( " *** %s \n " , strMessage ) ;
uiInterface . ThreadSafeMessageBox (
2015-08-08 16:17:27 -07:00
userMessage . empty ( ) ? _ ( " Error: A fatal internal error occurred, see debug.log for details " ) : userMessage ,
2015-01-16 15:57:14 -08: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 ) ;
}
2014-12-02 15:39:03 -08:00
} // anon namespace
2010-08-29 09:58:15 -07:00
2015-02-03 06:44:39 -08:00
/**
* Apply the undo operation of a CTxInUndo to the given chain state .
* @ param undo The undo object .
* @ param view The coins view to which to apply the changes .
* @ param out The out point that corresponds to the tx input .
* @ return True on success .
*/
static bool ApplyTxInUndo ( const CTxInUndo & undo , CCoinsViewCache & view , const COutPoint & out )
{
bool fClean = true ;
CCoinsModifier coins = view . ModifyCoins ( out . hash ) ;
if ( undo . nHeight ! = 0 ) {
// undo data contains height: this is the last output of the prevout tx being spent
if ( ! coins - > IsPruned ( ) )
fClean = fClean & & error ( " %s: undo data overwriting existing transaction " , __func__ ) ;
coins - > Clear ( ) ;
coins - > fCoinBase = undo . fCoinBase ;
coins - > nHeight = undo . nHeight ;
coins - > nVersion = undo . nVersion ;
} else {
if ( coins - > IsPruned ( ) )
fClean = fClean & & error ( " %s: undo data adding output to missing transaction " , __func__ ) ;
}
if ( coins - > IsAvailable ( out . n ) )
fClean = fClean & & error ( " %s: undo data overwriting existing output " , __func__ ) ;
if ( coins - > vout . size ( ) < out . n + 1 )
coins - > vout . resize ( out . n + 1 ) ;
coins - > vout [ out . n ] = undo . txout ;
return fClean ;
}
2017-04-28 16:08:39 -07:00
enum DisconnectResult
2010-08-29 09:58:15 -07:00
{
2017-04-28 16:08:39 -07:00
DISCONNECT_OK , // All good.
DISCONNECT_UNCLEAN , // Rolled back, but UTXO set was inconsistent with block.
DISCONNECT_FAILED // Something else went wrong.
} ;
2010-08-29 09:58:15 -07:00
2017-04-28 16:08:39 -07:00
/** Undo the effects of this block (with given index) on the UTXO set represented by coins.
2019-03-19 12:28:02 -07:00
* When UNCLEAN or FAILED is returned , view is left in an indeterminate state .
2019-04-23 10:06:23 -07:00
* The addressIndex and spentIndex will be updated if requested .
2019-03-19 12:28:02 -07:00
*/
static DisconnectResult DisconnectBlock ( const CBlock & block , CValidationState & state ,
2019-03-14 04:24:53 -07:00
const CBlockIndex * pindex , CCoinsViewCache & view , const CChainParams & chainparams ,
const bool updateIndices )
2017-04-28 16:08:39 -07:00
{
assert ( pindex - > GetBlockHash ( ) = = view . GetBestBlock ( ) ) ;
2012-12-30 06:29:39 -08:00
bool fClean = true ;
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
CBlockUndo blockUndo ;
2012-12-30 14:41:41 -08:00
CDiskBlockPos pos = pindex - > GetUndoPos ( ) ;
2017-04-28 16:08:39 -07:00
if ( pos . IsNull ( ) ) {
error ( " DisconnectBlock(): no undo data available " ) ;
return DISCONNECT_FAILED ;
}
if ( ! UndoReadFromDisk ( blockUndo , pos , pindex - > pprev - > GetBlockHash ( ) ) ) {
error ( " DisconnectBlock(): failure reading undo data " ) ;
return DISCONNECT_FAILED ;
}
2010-08-29 09:58:15 -07:00
2017-04-28 16:08:39 -07:00
if ( blockUndo . vtxundo . size ( ) + 1 ! = block . vtx . size ( ) ) {
error ( " DisconnectBlock(): block and undo data inconsistent " ) ;
return DISCONNECT_FAILED ;
}
2019-03-19 12:28:02 -07:00
std : : vector < CAddressIndexDbEntry > addressIndex ;
std : : vector < CAddressUnspentDbEntry > addressUnspentIndex ;
2019-04-23 10:06:23 -07:00
std : : vector < CSpentIndexDbEntry > spentIndex ;
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
// undo transactions in reverse order
2013-06-23 18:32:58 -07:00
for ( int i = block . vtx . size ( ) - 1 ; i > = 0 ; i - - ) {
const CTransaction & tx = block . vtx [ i ] ;
2019-03-19 12:28:02 -07:00
uint256 const hash = tx . GetHash ( ) ;
// insightexplorer
// https://github.com/bitpay/bitcoin/commit/017f548ea6d89423ef568117447e61dd5707ec42#diff-7ec3c68a81efff79b6ca22ac1f1eabbaR2236
2019-04-23 10:06:23 -07:00
if ( fAddressIndex & & updateIndices ) {
2019-03-19 12:28:02 -07:00
for ( unsigned int k = tx . vout . size ( ) ; k - - > 0 ; ) {
const CTxOut & out = tx . vout [ k ] ;
int const scriptType = out . scriptPubKey . Type ( ) ;
if ( scriptType > 0 ) {
uint160 const addrHash = out . scriptPubKey . AddressHash ( ) ;
// undo receiving activity
addressIndex . push_back ( make_pair (
CAddressIndexKey ( scriptType , addrHash , pindex - > nHeight , i , hash , k , false ) ,
out . nValue ) ) ;
// undo unspent index
addressUnspentIndex . push_back ( make_pair (
CAddressUnspentKey ( scriptType , addrHash , hash , k ) ,
CAddressUnspentValue ( ) ) ) ;
}
}
}
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
2013-10-26 12:26:29 -07:00
// Check that all outputs are available and match the outputs in the block itself
2015-02-03 06:44:39 -08:00
// exactly.
2014-09-03 00:01:24 -07:00
{
CCoinsModifier outs = view . ModifyCoins ( hash ) ;
outs - > ClearUnspendable ( ) ;
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
2014-09-03 00:01:24 -07:00
CCoins outsBlock ( tx , pindex - > nHeight ) ;
2013-09-09 02:11:11 -07:00
// The CCoins serialization does not serialize negative numbers.
// No network rules currently depend on the version here, so an inconsistency is harmless
// but it must be corrected before txout nversion ever influences a network rule.
if ( outsBlock . nVersion < 0 )
2014-09-03 00:01:24 -07:00
outs - > nVersion = outsBlock . nVersion ;
if ( * outs ! = outsBlock )
2015-01-08 02:44:25 -08:00
fClean = fClean & & error ( " DisconnectBlock(): added transaction mismatch? database corrupted " ) ;
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
// remove outputs
2014-09-03 00:01:24 -07:00
outs - > Clear ( ) ;
}
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
2016-07-10 22:18:53 -07:00
// unspend nullifiers
2018-04-18 12:18:57 -07:00
view . SetNullifiers ( tx , false ) ;
2016-01-08 07:37:17 -08:00
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
// restore inputs
if ( i > 0 ) { // not coinbases
const CTxUndo & txundo = blockUndo . vtxundo [ i - 1 ] ;
2017-04-28 16:08:39 -07:00
if ( txundo . vprevout . size ( ) ! = tx . vin . size ( ) ) {
error ( " DisconnectBlock(): transaction and undo data inconsistent " ) ;
return DISCONNECT_FAILED ;
}
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
for ( unsigned int j = tx . vin . size ( ) ; j - - > 0 ; ) {
const COutPoint & out = tx . vin [ j ] . prevout ;
const CTxInUndo & undo = txundo . vprevout [ j ] ;
2015-02-03 06:44:39 -08:00
if ( ! ApplyTxInUndo ( undo , view , out ) )
fClean = false ;
2019-03-19 12:28:02 -07:00
// insightexplorer
// https://github.com/bitpay/bitcoin/commit/017f548ea6d89423ef568117447e61dd5707ec42#diff-7ec3c68a81efff79b6ca22ac1f1eabbaR2304
2019-04-23 10:06:23 -07:00
const CTxIn input = tx . vin [ j ] ;
if ( fAddressIndex & & updateIndices ) {
2019-03-19 12:28:02 -07:00
const CTxOut & prevout = view . GetOutputFor ( input ) ;
int const scriptType = prevout . scriptPubKey . Type ( ) ;
if ( scriptType > 0 ) {
uint160 const addrHash = prevout . scriptPubKey . AddressHash ( ) ;
// undo spending activity
addressIndex . push_back ( make_pair (
CAddressIndexKey ( scriptType , addrHash , pindex - > nHeight , i , hash , j , true ) ,
prevout . nValue * - 1 ) ) ;
// restore unspent index
addressUnspentIndex . push_back ( make_pair (
CAddressUnspentKey ( scriptType , addrHash , input . prevout . hash , input . prevout . n ) ,
CAddressUnspentValue ( prevout . nValue , prevout . scriptPubKey , undo . nHeight ) ) ) ;
}
}
2019-04-23 10:06:23 -07:00
// insightexplorer
if ( fSpentIndex & & updateIndices ) {
// undo and delete the spent index
spentIndex . push_back ( make_pair (
CSpentIndexKey ( input . prevout . hash , input . prevout . n ) ,
CSpentIndexValue ( ) ) ) ;
}
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
}
}
}
2018-05-06 22:27:52 -07:00
// set the old best Sprout anchor back
view . PopAnchor ( blockUndo . old_sprout_tree_root , SPROUT ) ;
// set the old best Sapling anchor back
// We can get this from the `hashFinalSaplingRoot` of the last block
// However, this is only reliable if the last block was on or after
// the Sapling activation height. Otherwise, the last anchor was the
// empty root.
2019-03-14 04:24:53 -07:00
if ( NetworkUpgradeActive ( pindex - > pprev - > nHeight , chainparams . GetConsensus ( ) , Consensus : : UPGRADE_SAPLING ) ) {
2018-05-06 22:27:52 -07:00
view . PopAnchor ( pindex - > pprev - > hashFinalSaplingRoot , SAPLING ) ;
} else {
2018-08-01 09:31:09 -07:00
view . PopAnchor ( SaplingMerkleTree : : empty_root ( ) , SAPLING ) ;
2018-05-06 22:27:52 -07:00
}
2016-01-07 11:09:58 -08:00
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
// move best block pointer to prevout block
2013-11-04 17:27:39 -08:00
view . SetBestBlock ( pindex - > pprev - > GetBlockHash ( ) ) ;
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
2019-03-19 12:28:02 -07:00
// insightexplorer
2019-04-23 10:06:23 -07:00
if ( fAddressIndex & & updateIndices ) {
2019-03-19 12:28:02 -07:00
if ( ! pblocktree - > EraseAddressIndex ( addressIndex ) ) {
AbortNode ( state , " Failed to delete address index " ) ;
return DISCONNECT_FAILED ;
}
if ( ! pblocktree - > UpdateAddressUnspentIndex ( addressUnspentIndex ) ) {
AbortNode ( state , " Failed to write address unspent index " ) ;
return DISCONNECT_FAILED ;
}
}
2019-04-23 10:06:23 -07:00
// insightexplorer
if ( fSpentIndex & & updateIndices ) {
if ( ! pblocktree - > UpdateSpentIndex ( spentIndex ) ) {
AbortNode ( state , " Failed to write transaction index " ) ;
return DISCONNECT_FAILED ;
}
}
2017-04-28 16:08:39 -07:00
return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN ;
2010-08-29 09:58:15 -07:00
}
2013-01-29 19:17:33 -08:00
void static FlushBlockFile ( bool fFinalize = false )
2012-09-05 18:21:18 -07:00
{
LOCK ( cs_LastBlockFile ) ;
2012-12-03 01:14:54 -08:00
CDiskBlockPos posOld ( nLastBlockFile , 0 ) ;
2012-09-05 18:21:18 -07:00
FILE * fileOld = OpenBlockFile ( posOld ) ;
2012-12-01 02:36:53 -08:00
if ( fileOld ) {
2013-01-29 19:17:33 -08:00
if ( fFinalize )
2014-09-24 23:21:21 -07:00
TruncateFile ( fileOld , vinfoBlockFile [ nLastBlockFile ] . nSize ) ;
2012-12-01 02:36:53 -08:00
FileCommit ( fileOld ) ;
fclose ( fileOld ) ;
}
2012-09-05 18:21:18 -07:00
fileOld = OpenUndoFile ( posOld ) ;
2012-12-01 02:36:53 -08:00
if ( fileOld ) {
2013-01-29 19:17:33 -08:00
if ( fFinalize )
2014-09-24 23:21:21 -07:00
TruncateFile ( fileOld , vinfoBlockFile [ nLastBlockFile ] . nUndoSize ) ;
2012-12-01 02:36:53 -08:00
FileCommit ( fileOld ) ;
fclose ( fileOld ) ;
}
2012-09-05 18:21:18 -07:00
}
2013-01-26 15:14:11 -08:00
bool FindUndoPos ( CValidationState & state , int nFile , CDiskBlockPos & pos , unsigned int nAddSize ) ;
2012-08-13 10:11:05 -07:00
2012-12-01 14:04:14 -08:00
static CCheckQueue < CScriptCheck > scriptcheckqueue ( 128 ) ;
2013-03-06 19:31:26 -08:00
void ThreadScriptCheck ( ) {
2016-10-26 12:57:22 -07:00
RenameThread ( " zcash-scriptch " ) ;
2012-12-01 14:04:14 -08:00
scriptcheckqueue . Thread ( ) ;
}
2015-03-26 08:20:59 -07:00
//
// Called periodically asynchronously; alerts if it smells like
// we're being fed a bad chain (blocks being generated much
// too slowly or too quickly).
//
2015-06-08 13:34:58 -07:00
void PartitionCheck ( bool ( * initialDownloadCheck ) ( ) , CCriticalSection & cs , const CBlockIndex * const & bestHeader ,
int64_t nPowTargetSpacing )
2015-03-26 08:20:59 -07:00
{
2015-06-08 13:34:58 -07:00
if ( bestHeader = = NULL | | initialDownloadCheck ( ) ) return ;
2015-03-26 08:20:59 -07:00
static int64_t lastAlertTime = 0 ;
int64_t now = GetAdjustedTime ( ) ;
if ( lastAlertTime > now - 60 * 60 * 24 ) return ; // Alert at most once per day
const int SPAN_HOURS = 4 ;
const int SPAN_SECONDS = SPAN_HOURS * 60 * 60 ;
int BLOCKS_EXPECTED = SPAN_SECONDS / nPowTargetSpacing ;
boost : : math : : poisson_distribution < double > poisson ( BLOCKS_EXPECTED ) ;
std : : string strWarning ;
int64_t startTime = GetAdjustedTime ( ) - SPAN_SECONDS ;
LOCK ( cs ) ;
2015-06-08 13:34:58 -07:00
const CBlockIndex * i = bestHeader ;
int nBlocks = 0 ;
while ( i - > GetBlockTime ( ) > = startTime ) {
+ + nBlocks ;
i = i - > pprev ;
2018-03-02 03:45:05 -08:00
if ( i = = NULL ) return ; // Ran out of chain, we must not be fully synced
2015-06-08 13:34:58 -07:00
}
2015-03-26 08:20:59 -07:00
// How likely is it to find that many by chance?
double p = boost : : math : : pdf ( poisson , nBlocks ) ;
LogPrint ( " partitioncheck " , " %s : Found %d blocks in the last %d hours \n " , __func__ , nBlocks , SPAN_HOURS ) ;
LogPrint ( " partitioncheck " , " %s : likelihood: %g \n " , __func__ , p ) ;
// Aim for one false-positive about every fifty years of normal running:
const int FIFTY_YEARS = 50 * 365 * 24 * 60 * 60 ;
double alertThreshold = 1.0 / ( FIFTY_YEARS / SPAN_SECONDS ) ;
if ( p < = alertThreshold & & nBlocks < BLOCKS_EXPECTED )
{
// Many fewer blocks than expected: alert!
strWarning = strprintf ( _ ( " WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) " ) ,
nBlocks , SPAN_HOURS , BLOCKS_EXPECTED ) ;
}
else if ( p < = alertThreshold & & nBlocks > BLOCKS_EXPECTED )
{
// Many more blocks than expected: alert!
strWarning = strprintf ( _ ( " WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected) " ) ,
nBlocks , SPAN_HOURS , BLOCKS_EXPECTED ) ;
}
if ( ! strWarning . empty ( ) )
{
strMiscWarning = strWarning ;
CAlert : : Notify ( strWarning , true ) ;
lastAlertTime = now ;
}
}
2014-07-26 13:49:17 -07:00
static int64_t nTimeVerify = 0 ;
static int64_t nTimeConnect = 0 ;
static int64_t nTimeIndex = 0 ;
static int64_t nTimeCallbacks = 0 ;
static int64_t nTimeTotal = 0 ;
2016-04-19 06:16:39 -07:00
bool ConnectBlock ( const CBlock & block , CValidationState & state , CBlockIndex * pindex ,
CCoinsViewCache & view , const CChainParams & chainparams , bool fJustCheck )
2010-08-29 09:58:15 -07:00
{
2014-04-22 23:55:24 -07:00
AssertLockHeld ( cs_main ) ;
2016-11-22 20:04:20 -08:00
2015-03-19 05:34:06 -07:00
bool fExpensiveChecks = true ;
if ( fCheckpointsEnabled ) {
CBlockIndex * pindexLastCheckpoint = Checkpoints : : GetLastCheckpoint ( chainparams . Checkpoints ( ) ) ;
if ( pindexLastCheckpoint & & pindexLastCheckpoint - > GetAncestor ( pindex - > nHeight ) = = pindex ) {
// This block is an ancestor of a checkpoint: disable script checks
fExpensiveChecks = false ;
}
}
2016-11-22 20:04:20 -08:00
auto verifier = libzcash : : ProofVerifier : : Strict ( ) ;
auto disabledVerifier = libzcash : : ProofVerifier : : Disabled ( ) ;
// Check it again to verify JoinSplit proofs, and in case a previous version let a bad block in
2019-03-14 04:02:47 -07:00
if ( ! CheckBlock ( block , state , chainparams , fExpensiveChecks ? verifier : disabledVerifier , ! fJustCheck , ! fJustCheck ) )
2010-08-29 09:58:15 -07:00
return false ;
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
// verify that the view's current state corresponds to the previous block
2014-12-15 00:11:16 -08:00
uint256 hashPrevBlock = pindex - > pprev = = NULL ? uint256 ( ) : pindex - > pprev - > GetBlockHash ( ) ;
2013-11-04 17:27:39 -08:00
assert ( hashPrevBlock = = view . GetBestBlock ( ) ) ;
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
2013-01-18 15:35:17 -08:00
// Special case for the genesis block, skipping connection of its transactions
// (its coinbase is unspendable)
2015-04-09 06:58:34 -07:00
if ( block . GetHash ( ) = = chainparams . GetConsensus ( ) . hashGenesisBlock ) {
2016-10-17 09:09:24 -07:00
if ( ! fJustCheck ) {
2014-12-30 19:28:05 -08:00
view . SetBestBlock ( pindex - > GetBlockHash ( ) ) ;
2016-10-17 09:09:24 -07:00
// Before the genesis block, there was an empty tree
2018-08-01 09:31:09 -07:00
SproutMerkleTree tree ;
2018-04-25 18:15:30 -07:00
pindex - > hashSproutAnchor = tree . root ( ) ;
2017-03-09 23:04:14 -08:00
// The genesis block contained no JoinSplits
2018-05-06 14:21:49 -07:00
pindex - > hashFinalSproutRoot = pindex - > hashSproutAnchor ;
2016-10-17 09:09:24 -07:00
}
2013-01-18 15:35:17 -08:00
return true ;
}
2019-03-14 13:20:51 -07:00
// Reject a block that results in a negative shielded value pool balance.
2019-03-18 10:32:26 -07:00
if ( chainparams . ZIP209Enabled ( ) ) {
2019-03-12 23:54:29 -07:00
// Sprout
//
// We can expect nChainSproutValue to be valid after the hardcoded
// height, and this will be enforced on all descendant blocks. If
// the node was reindexed then this will be enforced for all blocks.
if ( pindex - > nChainSproutValue ) {
if ( * pindex - > nChainSproutValue < 0 ) {
return state . DoS ( 100 , error ( " ConnectBlock(): turnstile violation in Sprout shielded value pool " ) ,
REJECT_INVALID , " turnstile-violation-sprout-shielded-pool " ) ;
}
}
// Sapling
//
// If we've reached ConnectBlock, we have all transactions of
// parents and can expect nChainSaplingValue not to be boost::none.
2019-03-18 13:09:32 -07:00
// However, the miner and mining RPCs may not have populated this
// value and will call `TestBlockValidity`. So, we act
// conditionally.
if ( pindex - > nChainSaplingValue ) {
if ( * pindex - > nChainSaplingValue < 0 ) {
return state . DoS ( 100 , error ( " ConnectBlock(): turnstile violation in Sapling shielded value pool " ) ,
REJECT_INVALID , " turnstile-violation-sapling-shielded-pool " ) ;
}
2019-03-12 23:54:29 -07:00
}
}
2012-02-17 08:58:02 -08:00
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
// unless those are already completely spent.
2016-06-10 15:04:15 -07:00
BOOST_FOREACH ( const CTransaction & tx , block . vtx ) {
2016-08-30 12:49:38 -07:00
const CCoins * coins = view . AccessCoins ( tx . GetHash ( ) ) ;
2016-06-10 15:04:15 -07:00
if ( coins & & ! coins - > IsPruned ( ) )
return state . DoS ( 100 , error ( " ConnectBlock(): tried to overwrite transaction " ) ,
REJECT_INVALID , " bad-txns-BIP30 " ) ;
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
}
2012-02-17 08:58:02 -08:00
2017-05-07 11:46:41 -07:00
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY ;
2012-12-08 13:49:04 -08:00
2017-05-07 11:46:41 -07:00
// DERSIG (BIP66) is also always enforced, but does not have a flag.
2015-06-28 11:30:50 -07:00
2012-06-23 05:17:13 -07:00
CBlockUndo blockundo ;
2016-11-22 20:04:20 -08:00
CCheckQueueControl < CScriptCheck > control ( fExpensiveChecks & & nScriptCheckThreads ? & scriptcheckqueue : NULL ) ;
2012-12-01 14:04:14 -08:00
2014-07-26 13:49:17 -07:00
int64_t nTimeStart = GetTimeMicros ( ) ;
2014-04-22 15:46:19 -07:00
CAmount nFees = 0 ;
2012-12-01 11:10:23 -08:00
int nInputs = 0 ;
2012-04-23 11:14:03 -07:00
unsigned int nSigOps = 0 ;
2013-06-23 18:50:06 -07:00
CDiskTxPos pos ( pindex - > GetBlockPos ( ) , GetSizeOfCompactSize ( block . vtx . size ( ) ) ) ;
2013-01-10 16:47:57 -08:00
std : : vector < std : : pair < uint256 , CDiskTxPos > > vPos ;
2013-06-23 18:50:06 -07:00
vPos . reserve ( block . vtx . size ( ) ) ;
2014-09-03 06:54:37 -07:00
blockundo . vtxundo . reserve ( block . vtx . size ( ) - 1 ) ;
2019-03-19 12:28:02 -07:00
std : : vector < CAddressIndexDbEntry > addressIndex ;
std : : vector < CAddressUnspentDbEntry > addressUnspentIndex ;
2019-04-23 10:06:23 -07:00
std : : vector < CSpentIndexDbEntry > spentIndex ;
2016-01-07 11:09:58 -08:00
// Construct the incremental merkle tree at the current
// block position,
2018-05-06 22:27:52 -07:00
auto old_sprout_tree_root = view . GetBestAnchor ( SPROUT ) ;
2016-10-12 23:02:13 -07:00
// saving the top anchor in the block index as we go.
2016-10-17 09:09:24 -07:00
if ( ! fJustCheck ) {
2018-05-06 22:27:52 -07:00
pindex - > hashSproutAnchor = old_sprout_tree_root ;
2016-10-17 09:09:24 -07:00
}
2018-08-01 09:31:09 -07:00
SproutMerkleTree sprout_tree ;
2016-01-07 11:09:58 -08:00
// This should never fail: we should always be able to get the root
// that is on the tip of our chain
2018-05-06 22:27:52 -07:00
assert ( view . GetSproutAnchorAt ( old_sprout_tree_root , sprout_tree ) ) ;
2016-01-07 11:09:58 -08:00
{
// Consistency check: the root of the tree we're given should
// match what we asked for.
2018-05-06 22:27:52 -07:00
assert ( sprout_tree . root ( ) = = old_sprout_tree_root ) ;
2016-01-07 11:09:58 -08:00
}
2018-08-01 09:31:09 -07:00
SaplingMerkleTree sapling_tree ;
2018-05-06 22:27:52 -07:00
assert ( view . GetSaplingAnchorAt ( view . GetBestAnchor ( SAPLING ) , sapling_tree ) ) ;
2018-02-01 17:49:42 -08:00
// Grab the consensus branch ID for the block's height
2018-03-09 06:07:04 -08:00
auto consensusBranchId = CurrentEpochBranchId ( pindex - > nHeight , chainparams . GetConsensus ( ) ) ;
2018-02-01 17:49:42 -08:00
2016-08-26 09:38:20 -07:00
std : : vector < PrecomputedTransactionData > txdata ;
txdata . reserve ( block . vtx . size ( ) ) ; // Required so that pointers to individual PrecomputedTransactionData don't get invalidated
2013-06-23 18:50:06 -07:00
for ( unsigned int i = 0 ; i < block . vtx . size ( ) ; i + + )
2010-08-29 09:58:15 -07:00
{
2013-06-23 18:50:06 -07:00
const CTransaction & tx = block . vtx [ i ] ;
2019-03-19 12:28:02 -07:00
const uint256 hash = tx . GetHash ( ) ;
2012-07-07 15:06:34 -07:00
2012-12-01 11:10:23 -08:00
nInputs + = tx . vin . size ( ) ;
2013-01-08 04:17:15 -08:00
nSigOps + = GetLegacySigOpCount ( tx ) ;
2012-01-20 14:07:40 -08:00
if ( nSigOps > MAX_BLOCK_SIGOPS )
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " ConnectBlock(): too many sigops " ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " bad-blk-sigops " ) ;
2012-01-20 14:07:40 -08:00
2012-01-10 17:18:00 -08:00
if ( ! tx . IsCoinBase ( ) )
{
2013-01-08 04:17:15 -08:00
if ( ! view . HaveInputs ( tx ) )
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " ConnectBlock(): inputs missing/spent " ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " bad-txns-inputs-missingorspent " ) ;
2012-01-04 18:40:52 -08:00
2016-07-14 15:10:41 -07:00
// are the JoinSplit's requirements met?
2018-10-26 06:44:18 -07:00
if ( ! view . HaveShieldedRequirements ( tx ) )
2016-07-14 15:10:41 -07:00
return state . DoS ( 100 , error ( " ConnectBlock(): JoinSplit requirements not met " ) ,
REJECT_INVALID , " bad-txns-joinsplit-requirements-not-met " ) ;
2016-01-07 11:09:58 -08:00
2019-03-19 12:28:02 -07:00
// insightexplorer
// https://github.com/bitpay/bitcoin/commit/017f548ea6d89423ef568117447e61dd5707ec42#diff-7ec3c68a81efff79b6ca22ac1f1eabbaR2597
2019-04-23 10:06:23 -07:00
if ( fAddressIndex | | fSpentIndex ) {
2019-03-19 12:28:02 -07:00
for ( size_t j = 0 ; j < tx . vin . size ( ) ; j + + ) {
const CTxIn input = tx . vin [ j ] ;
const CTxOut & prevout = view . GetOutputFor ( tx . vin [ j ] ) ;
int const scriptType = prevout . scriptPubKey . Type ( ) ;
2019-04-23 10:06:23 -07:00
const uint160 addrHash = prevout . scriptPubKey . AddressHash ( ) ;
if ( fAddressIndex & & scriptType > 0 ) {
2019-03-19 12:28:02 -07:00
// record spending activity
addressIndex . push_back ( make_pair (
CAddressIndexKey ( scriptType , addrHash , pindex - > nHeight , i , hash , j , true ) ,
prevout . nValue * - 1 ) ) ;
// remove address from unspent index
addressUnspentIndex . push_back ( make_pair (
CAddressUnspentKey ( scriptType , addrHash , input . prevout . hash , input . prevout . n ) ,
CAddressUnspentValue ( ) ) ) ;
}
2019-04-23 10:06:23 -07:00
if ( fSpentIndex ) {
// Add the spent index to determine the txid and input that spent an output
// and to find the amount and address from an input.
// If we do not recognize the script type, we still add an entry to the
// spentindex db, with a script type of 0 and addrhash of all zeroes.
spentIndex . push_back ( make_pair (
CSpentIndexKey ( input . prevout . hash , input . prevout . n ) ,
CSpentIndexValue ( hash , j , pindex - > nHeight , prevout . nValue , scriptType , addrHash ) ) ) ;
}
2019-03-19 12:28:02 -07:00
}
}
2016-06-10 15:04:15 -07:00
// Add in sigops done by pay-to-script-hash inputs;
// this is to prevent a "rogue miner" from creating
// an incredibly-expensive-to-validate block.
nSigOps + = GetP2SHSigOpCount ( tx , view ) ;
if ( nSigOps > MAX_BLOCK_SIGOPS )
return state . DoS ( 100 , error ( " ConnectBlock(): too many sigops " ) ,
REJECT_INVALID , " bad-blk-sigops " ) ;
2018-01-01 03:27:59 -08:00
}
2016-08-26 09:38:20 -07:00
txdata . emplace_back ( tx ) ;
2012-01-04 18:40:52 -08:00
2018-01-01 03:27:59 -08:00
if ( ! tx . IsCoinBase ( ) )
{
2013-11-10 22:03:51 -08:00
nFees + = view . GetValueIn ( tx ) - tx . GetValueOut ( ) ;
2012-06-23 05:17:13 -07:00
2012-12-01 14:04:14 -08:00
std : : vector < CScriptCheck > vChecks ;
2015-11-01 17:01:45 -08:00
bool fCacheResults = fJustCheck ; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
if ( ! ContextualCheckInputs ( tx , state , view , fExpensiveChecks , flags , fCacheResults , txdata [ i ] , chainparams . GetConsensus ( ) , consensusBranchId , nScriptCheckThreads ? & vChecks : NULL ) )
2012-01-10 17:45:55 -08:00
return false ;
2012-12-01 14:04:14 -08:00
control . Add ( vChecks ) ;
2012-01-10 17:18:00 -08:00
}
2019-03-19 12:28:02 -07:00
// insightexplorer
// https://github.com/bitpay/bitcoin/commit/017f548ea6d89423ef568117447e61dd5707ec42#diff-7ec3c68a81efff79b6ca22ac1f1eabbaR2656
if ( fAddressIndex ) {
for ( unsigned int k = 0 ; k < tx . vout . size ( ) ; k + + ) {
const CTxOut & out = tx . vout [ k ] ;
int const scriptType = out . scriptPubKey . Type ( ) ;
if ( scriptType > 0 ) {
uint160 const addrHash = out . scriptPubKey . AddressHash ( ) ;
// record receiving activity
addressIndex . push_back ( make_pair (
CAddressIndexKey ( scriptType , addrHash , pindex - > nHeight , i , hash , k , false ) ,
out . nValue ) ) ;
// record unspent output
addressUnspentIndex . push_back ( make_pair (
CAddressUnspentKey ( scriptType , addrHash , hash , k ) ,
CAddressUnspentValue ( out . nValue , out . scriptPubKey , pindex - > nHeight ) ) ) ;
}
}
}
2014-09-03 06:54:37 -07:00
CTxUndo undoDummy ;
if ( i > 0 ) {
blockundo . vtxundo . push_back ( CTxUndo ( ) ) ;
}
2016-04-29 20:45:20 -07:00
UpdateCoins ( tx , view , i = = 0 ? undoDummy : blockundo . vtxundo . back ( ) , pindex - > nHeight ) ;
2012-12-01 11:10:23 -08:00
2016-07-14 15:10:41 -07:00
BOOST_FOREACH ( const JSDescription & joinsplit , tx . vjoinsplit ) {
2016-07-14 15:22:27 -07:00
BOOST_FOREACH ( const uint256 & note_commitment , joinsplit . commitments ) {
// Insert the note commitments into our temporary tree.
2016-01-07 11:09:58 -08:00
2018-05-06 22:27:52 -07:00
sprout_tree . append ( note_commitment ) ;
2016-01-07 11:09:58 -08:00
}
}
2018-05-06 22:27:52 -07:00
BOOST_FOREACH ( const OutputDescription & outputDescription , tx . vShieldedOutput ) {
sapling_tree . append ( outputDescription . cm ) ;
}
2016-08-30 12:49:38 -07:00
vPos . push_back ( std : : make_pair ( tx . GetHash ( ) , pos ) ) ;
2013-01-10 16:47:57 -08:00
pos . nTxOffset + = : : GetSerializeSize ( tx , SER_DISK , CLIENT_VERSION ) ;
2010-08-29 09:58:15 -07:00
}
2016-01-07 11:09:58 -08:00
2018-05-16 09:31:53 -07:00
view . PushAnchor ( sprout_tree ) ;
view . PushAnchor ( sapling_tree ) ;
2017-03-09 23:04:14 -08:00
if ( ! fJustCheck ) {
2018-05-06 22:27:52 -07:00
pindex - > hashFinalSproutRoot = sprout_tree . root ( ) ;
}
blockundo . old_sprout_tree_root = old_sprout_tree_root ;
// If Sapling is active, block.hashFinalSaplingRoot must be the
// same as the root of the Sapling tree
if ( NetworkUpgradeActive ( pindex - > nHeight , chainparams . GetConsensus ( ) , Consensus : : UPGRADE_SAPLING ) ) {
if ( block . hashFinalSaplingRoot ! = sapling_tree . root ( ) ) {
return state . DoS ( 100 ,
error ( " ConnectBlock(): block's hashFinalSaplingRoot is incorrect " ) ,
REJECT_INVALID , " bad-sapling-root-in-block " ) ;
}
2017-03-09 23:04:14 -08:00
}
2016-01-07 11:09:58 -08:00
2014-07-26 13:49:17 -07:00
int64_t nTime1 = GetTimeMicros ( ) ; nTimeConnect + = nTime1 - nTimeStart ;
LogPrint ( " bench " , " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs] \n " , ( unsigned ) block . vtx . size ( ) , 0.001 * ( nTime1 - nTimeStart ) , 0.001 * ( nTime1 - nTimeStart ) / block . vtx . size ( ) , nInputs < = 1 ? 0 : 0.001 * ( nTime1 - nTimeStart ) / ( nInputs - 1 ) , nTimeConnect * 0.000001 ) ;
2011-10-03 10:05:43 -07:00
2015-04-01 07:03:11 -07:00
CAmount blockReward = nFees + GetBlockSubsidy ( pindex - > nHeight , chainparams . GetConsensus ( ) ) ;
if ( block . vtx [ 0 ] . GetValueOut ( ) > blockReward )
2013-10-27 23:36:11 -07:00
return state . DoS ( 100 ,
2015-01-08 02:44:25 -08:00
error ( " ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d) " ,
2015-04-01 07:03:11 -07:00
block . vtx [ 0 ] . GetValueOut ( ) , blockReward ) ,
2014-02-10 07:31:06 -08:00
REJECT_INVALID , " bad-cb-amount " ) ;
2012-10-22 12:46:00 -07:00
2012-12-01 14:04:14 -08:00
if ( ! control . Wait ( ) )
2013-01-26 15:14:11 -08:00
return state . DoS ( 100 , false ) ;
2014-07-26 13:49:17 -07:00
int64_t nTime2 = GetTimeMicros ( ) ; nTimeVerify + = nTime2 - nTimeStart ;
LogPrint ( " bench " , " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs] \n " , nInputs - 1 , 0.001 * ( nTime2 - nTimeStart ) , nInputs < = 1 ? 0 : 0.001 * ( nTime2 - nTimeStart ) / ( nInputs - 1 ) , nTimeVerify * 0.000001 ) ;
2012-12-01 14:04:14 -08:00
2012-05-09 10:24:44 -07:00
if ( fJustCheck )
return true ;
2012-08-13 10:11:05 -07:00
// Write undo information to disk
2014-03-12 19:48:27 -07:00
if ( pindex - > GetUndoPos ( ) . IsNull ( ) | | ! pindex - > IsValid ( BLOCK_VALID_SCRIPTS ) )
2012-08-13 10:11:05 -07:00
{
2012-08-18 15:33:01 -07:00
if ( pindex - > GetUndoPos ( ) . IsNull ( ) ) {
CDiskBlockPos pos ;
2013-01-26 15:14:11 -08:00
if ( ! FindUndoPos ( state , pindex - > nFile , pos , : : GetSerializeSize ( blockundo , SER_DISK , CLIENT_VERSION ) + 40 ) )
2015-01-08 02:44:25 -08:00
return error ( " ConnectBlock() : FindUndoPos failed " ) ;
2015-04-19 14:48:25 -07:00
if ( ! UndoWriteToDisk ( blockundo , pos , pindex - > pprev - > GetBlockHash ( ) , chainparams . MessageStart ( ) ) )
2015-01-16 15:57:14 -08:00
return AbortNode ( state , " Failed to write undo data " ) ;
2012-08-18 15:33:01 -07:00
// update nUndoPos in block index
pindex - > nUndoPos = pos . nPos ;
pindex - > nStatus | = BLOCK_HAVE_UNDO ;
}
2018-02-06 04:39:20 -08:00
// Now that all consensus rules have been validated, set nCachedBranchId.
2018-01-27 15:37:43 -08:00
// Move this if BLOCK_VALID_CONSENSUS is ever altered.
static_assert ( BLOCK_VALID_CONSENSUS = = BLOCK_VALID_SCRIPTS ,
2018-02-06 04:39:20 -08:00
" nCachedBranchId must be set after all consensus rules have been validated. " ) ;
2018-03-09 06:07:04 -08:00
if ( IsActivationHeightForAnyUpgrade ( pindex - > nHeight , chainparams . GetConsensus ( ) ) ) {
2018-01-27 15:37:43 -08:00
pindex - > nStatus | = BLOCK_ACTIVATES_UPGRADE ;
2018-02-06 04:39:20 -08:00
pindex - > nCachedBranchId = CurrentEpochBranchId ( pindex - > nHeight , chainparams . GetConsensus ( ) ) ;
2018-01-27 15:37:43 -08:00
} else if ( pindex - > pprev ) {
2018-02-06 04:39:20 -08:00
pindex - > nCachedBranchId = pindex - > pprev - > nCachedBranchId ;
2018-01-27 15:37:43 -08:00
}
2014-03-12 19:48:27 -07:00
pindex - > RaiseValidity ( BLOCK_VALID_SCRIPTS ) ;
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
setDirtyBlockIndex . insert ( pindex ) ;
2010-08-29 09:58:15 -07:00
}
2013-01-10 16:47:57 -08:00
if ( fTxIndex )
2013-01-26 15:14:11 -08:00
if ( ! pblocktree - > WriteTxIndex ( vPos ) )
2015-01-16 15:57:14 -08:00
return AbortNode ( state , " Failed to write transaction index " ) ;
2013-01-10 16:47:57 -08:00
2019-02-21 13:01:12 -08:00
// START insightexplorer
2019-03-19 12:28:02 -07:00
if ( fAddressIndex ) {
if ( ! pblocktree - > WriteAddressIndex ( addressIndex ) ) {
return AbortNode ( state , " Failed to write address index " ) ;
}
if ( ! pblocktree - > UpdateAddressUnspentIndex ( addressUnspentIndex ) ) {
return AbortNode ( state , " Failed to write address unspent index " ) ;
}
}
2019-04-23 10:06:23 -07:00
if ( fSpentIndex ) {
if ( ! pblocktree - > UpdateSpentIndex ( spentIndex ) ) {
return AbortNode ( state , " Failed to write spent index " ) ;
}
}
2019-02-21 13:01:12 -08:00
if ( fTimestampIndex ) {
unsigned int logicalTS = pindex - > nTime ;
unsigned int prevLogicalTS = 0 ;
// retrieve logical timestamp of the previous block
if ( pindex - > pprev )
if ( ! pblocktree - > ReadTimestampBlockIndex ( pindex - > pprev - > GetBlockHash ( ) , prevLogicalTS ) )
LogPrintf ( " %s: Failed to read previous block's logical timestamp \n " , __func__ ) ;
if ( logicalTS < = prevLogicalTS ) {
logicalTS = prevLogicalTS + 1 ;
LogPrintf ( " %s: Previous logical timestamp is newer Actual[%d] prevLogical[%d] Logical[%d] \n " , __func__ , pindex - > nTime , prevLogicalTS , logicalTS ) ;
}
if ( ! pblocktree - > WriteTimestampIndex ( CTimestampIndexKey ( logicalTS , pindex - > GetBlockHash ( ) ) ) )
return AbortNode ( state , " Failed to write timestamp index " ) ;
if ( ! pblocktree - > WriteTimestampBlockIndex ( CTimestampBlockIndexKey ( pindex - > GetBlockHash ( ) ) , CTimestampBlockIndexValue ( logicalTS ) ) )
return AbortNode ( state , " Failed to write blockhash index " ) ;
}
// END insightexplorer
2019-03-19 12:28:02 -07:00
2012-10-05 10:22:21 -07:00
// add this block to the view's block chain
2014-09-03 00:25:32 -07:00
view . SetBestBlock ( pindex - > GetBlockHash ( ) ) ;
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
2014-07-26 13:49:17 -07:00
int64_t nTime3 = GetTimeMicros ( ) ; nTimeIndex + = nTime3 - nTime2 ;
LogPrint ( " bench " , " - Index writing: %.2fms [%.2fs] \n " , 0.001 * ( nTime3 - nTime2 ) , nTimeIndex * 0.000001 ) ;
2014-05-07 07:45:33 -07:00
// Watch for changes to the previous coinbase transaction.
static uint256 hashPrevBestCoinBase ;
2015-02-04 16:11:44 -08:00
GetMainSignals ( ) . UpdatedTransaction ( hashPrevBestCoinBase ) ;
2016-08-30 12:49:38 -07:00
hashPrevBestCoinBase = block . vtx [ 0 ] . GetHash ( ) ;
2014-05-07 07:45:33 -07:00
2014-07-26 13:49:17 -07:00
int64_t nTime4 = GetTimeMicros ( ) ; nTimeCallbacks + = nTime4 - nTime3 ;
LogPrint ( " bench " , " - Callbacks: %.2fms [%.2fs] \n " , 0.001 * ( nTime4 - nTime3 ) , nTimeCallbacks * 0.000001 ) ;
2010-08-29 09:58:15 -07:00
return true ;
}
2014-11-14 09:19:26 -08:00
enum FlushStateMode {
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
FLUSH_STATE_NONE ,
2014-11-14 09:19:26 -08:00
FLUSH_STATE_IF_NEEDED ,
FLUSH_STATE_PERIODIC ,
FLUSH_STATE_ALWAYS
} ;
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
/**
* Update the on - disk chain state .
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
* The caches and indexes are flushed depending on the mode we ' re called with
* if they ' re too large , if it ' s been a while since the last write ,
* or always and in all cases if we ' re in prune mode and are deleting files .
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
*/
2014-11-14 09:19:26 -08:00
bool static FlushStateToDisk ( CValidationState & state , FlushStateMode mode ) {
2015-04-17 05:40:24 -07:00
const CChainParams & chainparams = Params ( ) ;
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
LOCK2 ( cs_main , cs_LastBlockFile ) ;
2013-11-16 10:28:24 -08:00
static int64_t nLastWrite = 0 ;
2015-05-04 13:00:19 -07:00
static int64_t nLastFlush = 0 ;
static int64_t nLastSetChain = 0 ;
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
std : : set < int > setFilesToPrune ;
bool fFlushForPrune = false ;
2015-01-04 10:11:44 -08:00
try {
2015-10-19 11:43:04 -07:00
if ( fPruneMode & & fCheckForPruning & & ! fReindex ) {
2015-04-17 05:40:24 -07:00
FindFilesToPrune ( setFilesToPrune , chainparams . PruneAfterHeight ( ) ) ;
2015-05-13 08:13:13 -07:00
fCheckForPruning = false ;
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
if ( ! setFilesToPrune . empty ( ) ) {
fFlushForPrune = true ;
if ( ! fHavePruned ) {
pblocktree - > WriteFlag ( " prunedblockfiles " , true ) ;
fHavePruned = true ;
}
}
}
2015-05-04 13:00:19 -07: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 ;
}
size_t cacheSize = pcoinsTip - > DynamicMemoryUsage ( ) ;
// The cache is large and close to the limit, but we have time now (not in the middle of a block processing).
bool fCacheLarge = mode = = FLUSH_STATE_PERIODIC & & cacheSize * ( 10.0 / 9 ) > nCoinCacheUsage ;
// The cache is over the limit, we have to write now.
bool fCacheCritical = mode = = FLUSH_STATE_IF_NEEDED & & cacheSize > nCoinCacheUsage ;
// 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.
bool fDoFullFlush = ( mode = = FLUSH_STATE_ALWAYS ) | | fCacheLarge | | fCacheCritical | | fPeriodicFlush | | fFlushForPrune ;
// Write blocks and block index to disk.
if ( fDoFullFlush | | fPeriodicWrite ) {
2015-05-11 08:18:39 -07:00
// Depend on nMinDiskSpace to ensure we can write block index
if ( ! CheckDiskSpace ( 0 ) )
2012-09-09 19:02:35 -07:00
return state . Error ( " out of disk space " ) ;
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
// First make sure all block and undo data is flushed to disk.
2012-09-05 18:21:18 -07:00
FlushBlockFile ( ) ;
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
// Then update all block file information (which may refer to block and undo files).
2014-11-25 07:26:20 -08:00
{
std : : vector < std : : pair < int , const CBlockFileInfo * > > vFiles ;
vFiles . reserve ( setDirtyFileInfo . size ( ) ) ;
for ( set < int > : : iterator it = setDirtyFileInfo . begin ( ) ; it ! = setDirtyFileInfo . end ( ) ; ) {
vFiles . push_back ( make_pair ( * it , & vinfoBlockFile [ * it ] ) ) ;
setDirtyFileInfo . erase ( it + + ) ;
}
std : : vector < const CBlockIndex * > vBlocks ;
vBlocks . reserve ( setDirtyBlockIndex . size ( ) ) ;
for ( set < CBlockIndex * > : : iterator it = setDirtyBlockIndex . begin ( ) ; it ! = setDirtyBlockIndex . end ( ) ; ) {
vBlocks . push_back ( * it ) ;
setDirtyBlockIndex . erase ( it + + ) ;
}
if ( ! pblocktree - > WriteBatchSync ( vFiles , nLastBlockFile , vBlocks ) ) {
2015-01-16 15:57:14 -08:00
return AbortNode ( state , " Files to write to block index database " ) ;
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
}
}
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
// Finally remove any pruned files
2015-05-13 08:13:13 -07:00
if ( fFlushForPrune )
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
UnlinkPrunedFiles ( setFilesToPrune ) ;
2015-05-04 13:00:19 -07:00
nLastWrite = nNow ;
}
// Flush best chain related state. This can only be done if the blocks / block index write was also done.
if ( fDoFullFlush ) {
2015-05-11 08:18:39 -07:00
// Typical CCoins structures on disk are around 128 bytes in size.
// Pushing a new one to the database can cause it to be written
// twice (once in the log, and once in the tables). This is already
// an overestimation, as most will delete an existing entry or
// overwrite one. Still, use a conservative safety factor of 2.
if ( ! CheckDiskSpace ( 128 * 2 * 2 * pcoinsTip - > GetCacheSize ( ) ) )
return state . Error ( " out of disk space " ) ;
2015-05-04 13:00:19 -07:00
// Flush the chainstate (which may refer to block index entries).
if ( ! pcoinsTip - > Flush ( ) )
2015-01-16 15:57:14 -08:00
return AbortNode ( state , " Failed to write to coin database " ) ;
2015-05-04 13:00:19 -07:00
nLastFlush = nNow ;
}
if ( ( mode = = FLUSH_STATE_ALWAYS | | mode = = FLUSH_STATE_PERIODIC ) & & nNow > nLastSetChain + ( int64_t ) DATABASE_WRITE_INTERVAL * 1000000 ) {
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
// Update best block in wallet (so we can detect restored wallets).
2015-05-04 13:00:19 -07:00
GetMainSignals ( ) . SetBestChain ( chainActive . GetLocator ( ) ) ;
nLastSetChain = nNow ;
2012-09-05 18:21:18 -07:00
}
2015-01-04 10:11:44 -08:00
} catch ( const std : : runtime_error & e ) {
2015-01-16 15:57:14 -08:00
return AbortNode ( state , std : : string ( " System error while flushing: " ) + e . what ( ) ) ;
2015-01-04 10:11:44 -08:00
}
2013-11-16 09:40:55 -08:00
return true ;
}
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
void FlushStateToDisk ( ) {
CValidationState state ;
2014-11-14 09:19:26 -08:00
FlushStateToDisk ( state , FLUSH_STATE_ALWAYS ) ;
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
}
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
void PruneAndFlush ( ) {
CValidationState state ;
fCheckForPruning = true ;
FlushStateToDisk ( state , FLUSH_STATE_NONE ) ;
}
2014-11-30 17:39:44 -08:00
/** Update chainActive and related internal data structures. */
2016-04-06 07:36:32 -07:00
void static UpdateTip ( CBlockIndex * pindexNew , const CChainParams & chainParams ) {
2013-10-10 14:07:44 -07:00
chainActive . SetTip ( pindexNew ) ;
2010-08-29 09:58:15 -07:00
// New best block
nTimeBestReceived = GetTime ( ) ;
2013-08-26 22:51:57 -07:00
mempool . AddTransactionsUpdated ( 1 ) ;
2012-05-12 21:43:24 -07:00
2015-05-03 16:56:42 -07:00
LogPrintf ( " %s: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%.1fMiB(%utx) \n " , __func__ ,
2013-11-16 09:40:55 -08:00
chainActive . Tip ( ) - > GetBlockHash ( ) . ToString ( ) , chainActive . Height ( ) , log ( chainActive . Tip ( ) - > nChainWork . getdouble ( ) ) / log ( 2.0 ) , ( unsigned long ) chainActive . Tip ( ) - > nChainTx ,
2014-01-16 07:15:27 -08:00
DateTimeStrFormat ( " %Y-%m-%d %H:%M:%S " , chainActive . Tip ( ) - > GetBlockTime ( ) ) ,
2015-05-03 16:56:42 -07:00
Checkpoints : : GuessVerificationProgress ( chainParams . Checkpoints ( ) , chainActive . Tip ( ) ) , pcoinsTip - > DynamicMemoryUsage ( ) * ( 1.0 / ( 1 < < 20 ) ) , pcoinsTip - > GetCacheSize ( ) ) ;
2010-08-29 09:58:15 -07:00
2012-05-12 21:43:24 -07:00
cvBlockChange . notify_all ( ) ;
2012-06-27 10:51:51 -07:00
// Check the version of the last 100 blocks to see if we need to upgrade:
2014-10-07 11:22:58 -07:00
static bool fWarned = false ;
if ( ! IsInitialBlockDownload ( ) & & ! fWarned )
2012-06-27 10:51:51 -07:00
{
int nUpgraded = 0 ;
2013-10-10 14:07:44 -07:00
const CBlockIndex * pindex = chainActive . Tip ( ) ;
2012-06-27 10:51:51 -07:00
for ( int i = 0 ; i < 100 & & pindex ! = NULL ; i + + )
{
if ( pindex - > nVersion > CBlock : : CURRENT_VERSION )
+ + nUpgraded ;
pindex = pindex - > pprev ;
}
if ( nUpgraded > 0 )
2015-02-24 09:32:34 -08:00
LogPrintf ( " %s: %d of last 100 blocks above version %d \n " , __func__ , nUpgraded , ( int ) CBlock : : CURRENT_VERSION ) ;
2012-06-27 10:51:51 -07:00
if ( nUpgraded > 100 / 2 )
2014-10-07 11:22:58 -07:00
{
2017-03-09 17:04:59 -08:00
// strMiscWarning is read by GetWarnings(), called by the JSON-RPC code to warn the user:
2015-04-28 07:48:28 -07:00
strMiscWarning = _ ( " Warning: This version is obsolete; upgrade required! " ) ;
2014-10-07 11:22:58 -07:00
CAlert : : Notify ( strMiscWarning , true ) ;
fWarned = true ;
}
2012-06-27 10:51:51 -07:00
}
2013-11-16 10:28:24 -08:00
}
2012-06-27 10:51:51 -07:00
2018-02-09 15:16:55 -08:00
/**
* Disconnect chainActive ' s tip . You probably want to call mempool . removeForReorg and
* mempool . removeWithoutBranchId after this , with cs_main held .
*/
2016-04-17 00:58:50 -07:00
bool static DisconnectTip ( CValidationState & state , const CChainParams & chainparams , bool fBare = false )
2016-04-06 07:36:32 -07:00
{
2013-11-16 10:28:24 -08:00
CBlockIndex * pindexDelete = chainActive . Tip ( ) ;
assert ( pindexDelete ) ;
// Read block from disk.
CBlock block ;
2016-04-17 00:58:50 -07:00
if ( ! ReadBlockFromDisk ( block , pindexDelete , chainparams . GetConsensus ( ) ) )
2015-01-16 15:57:14 -08:00
return AbortNode ( state , " Failed to read block " ) ;
2013-11-16 10:28:24 -08:00
// Apply the block atomically to the chain state.
2018-05-06 23:16:14 -07:00
uint256 sproutAnchorBeforeDisconnect = pcoinsTip - > GetBestAnchor ( SPROUT ) ;
uint256 saplingAnchorBeforeDisconnect = pcoinsTip - > GetBestAnchor ( SAPLING ) ;
2013-11-16 10:28:24 -08:00
int64_t nStart = GetTimeMicros ( ) ;
2012-01-03 12:24:28 -08:00
{
2014-09-23 18:19:04 -07:00
CCoinsViewCache view ( pcoinsTip ) ;
2019-03-19 12:28:02 -07:00
// insightexplorer: update indices (true)
2019-03-14 04:24:53 -07:00
if ( DisconnectBlock ( block , state , pindexDelete , view , chainparams , true ) ! = DISCONNECT_OK )
2015-01-08 02:44:25 -08:00
return error ( " DisconnectTip() : DisconnectBlock % s failed " , pindexDelete->GetBlockHash().ToString()) ;
2013-11-16 10:28:24 -08:00
assert ( view . Flush ( ) ) ;
2012-01-03 12:24:28 -08:00
}
2014-07-26 13:49:17 -07:00
LogPrint ( " bench " , " - Disconnect block: %.2fms \n " , ( GetTimeMicros ( ) - nStart ) * 0.001 ) ;
2018-05-06 23:16:14 -07:00
uint256 sproutAnchorAfterDisconnect = pcoinsTip - > GetBestAnchor ( SPROUT ) ;
uint256 saplingAnchorAfterDisconnect = pcoinsTip - > GetBestAnchor ( SAPLING ) ;
2013-11-16 10:28:24 -08:00
// Write the chain state to disk, if necessary.
2014-11-14 09:19:26 -08:00
if ( ! FlushStateToDisk ( state , FLUSH_STATE_IF_NEEDED ) )
2013-11-16 10:28:24 -08:00
return false ;
2016-03-18 09:20:12 -07:00
if ( ! fBare ) {
// Resurrect mempool transactions from the disconnected block.
BOOST_FOREACH ( const CTransaction & tx , block . vtx ) {
// ignore validation errors in resurrected transactions
list < CTransaction > removed ;
CValidationState stateDummy ;
if ( tx . IsCoinBase ( ) | | ! AcceptToMemoryPool ( mempool , stateDummy , tx , false , NULL ) )
mempool . remove ( tx , removed , true ) ;
}
2018-05-06 23:16:14 -07:00
if ( sproutAnchorBeforeDisconnect ! = sproutAnchorAfterDisconnect ) {
2016-03-18 09:20:12 -07:00
// The anchor may not change between block disconnects,
// in which case we don't want to evict from the mempool yet!
2018-05-06 23:16:14 -07:00
mempool . removeWithAnchor ( sproutAnchorBeforeDisconnect , SPROUT ) ;
}
if ( saplingAnchorBeforeDisconnect ! = saplingAnchorAfterDisconnect ) {
2016-03-18 09:20:12 -07:00
// The anchor may not change between block disconnects,
// in which case we don't want to evict from the mempool yet!
2018-05-06 23:16:14 -07:00
mempool . removeWithAnchor ( saplingAnchorBeforeDisconnect , SAPLING ) ;
2016-03-18 09:20:12 -07:00
}
}
2013-11-16 10:28:24 -08:00
// Update chainActive and related variables.
2016-04-06 07:36:32 -07:00
UpdateTip ( pindexDelete - > pprev , chainparams ) ;
2016-08-30 07:00:11 -07:00
// Get the current commitment tree
2018-08-01 09:31:09 -07:00
SproutMerkleTree newSproutTree ;
SaplingMerkleTree newSaplingTree ;
2018-07-17 10:56:01 -07:00
assert ( pcoinsTip - > GetSproutAnchorAt ( pcoinsTip - > GetBestAnchor ( SPROUT ) , newSproutTree ) ) ;
assert ( pcoinsTip - > GetSaplingAnchorAt ( pcoinsTip - > GetBestAnchor ( SAPLING ) , newSaplingTree ) ) ;
2014-02-15 13:38:28 -08:00
// Let wallets know transactions went from 1-confirmed to
// 0-confirmed or conflicted:
BOOST_FOREACH ( const CTransaction & tx , block . vtx ) {
2014-06-09 01:02:00 -07:00
SyncWithWallets ( tx , NULL ) ;
2014-02-15 13:38:28 -08:00
}
2016-08-23 20:52:43 -07:00
// Update cached incremental witnesses
2018-07-17 10:56:01 -07:00
GetMainSignals ( ) . ChainTip ( pindexDelete , & block , newSproutTree , newSaplingTree , false ) ;
2013-11-16 10:28:24 -08:00
return true ;
2013-11-16 09:40:55 -08:00
}
2012-01-03 12:24:28 -08:00
2014-07-26 13:49:17 -07:00
static int64_t nTimeReadFromDisk = 0 ;
static int64_t nTimeConnectTotal = 0 ;
static int64_t nTimeFlush = 0 ;
static int64_t nTimeChainState = 0 ;
static int64_t nTimePostConnect = 0 ;
2015-05-31 06:36:44 -07:00
/**
2014-11-30 17:39:44 -08:00
* Connect a new block to chainActive . pblock is either NULL or a pointer to a CBlock
* corresponding to pindexNew , to bypass loading it again from disk .
2018-02-09 15:16:55 -08:00
* You probably want to call mempool . removeWithoutBranchId after this , with cs_main held .
2014-11-30 17:39:44 -08:00
*/
2015-04-17 05:40:24 -07:00
bool static ConnectTip ( CValidationState & state , const CChainParams & chainparams , CBlockIndex * pindexNew , const CBlock * pblock )
{
2013-11-16 10:28:24 -08:00
assert ( pindexNew - > pprev = = chainActive . Tip ( ) ) ;
// Read block from disk.
2014-07-26 13:49:17 -07:00
int64_t nTime1 = GetTimeMicros ( ) ;
2013-11-16 10:28:24 -08:00
CBlock block ;
2014-08-25 17:26:41 -07:00
if ( ! pblock ) {
2015-04-17 05:19:21 -07:00
if ( ! ReadBlockFromDisk ( block , pindexNew , chainparams . GetConsensus ( ) ) )
2015-01-16 15:57:14 -08:00
return AbortNode ( state , " Failed to read block " ) ;
2014-08-25 17:26:41 -07:00
pblock = & block ;
}
2016-08-30 07:00:11 -07:00
// Get the current commitment tree
2018-08-01 09:31:09 -07:00
SproutMerkleTree oldSproutTree ;
SaplingMerkleTree oldSaplingTree ;
2018-07-17 10:56:01 -07:00
assert ( pcoinsTip - > GetSproutAnchorAt ( pcoinsTip - > GetBestAnchor ( SPROUT ) , oldSproutTree ) ) ;
assert ( pcoinsTip - > GetSaplingAnchorAt ( pcoinsTip - > GetBestAnchor ( SAPLING ) , oldSaplingTree ) ) ;
2013-11-16 10:28:24 -08:00
// Apply the block atomically to the chain state.
2014-07-26 13:49:17 -07:00
int64_t nTime2 = GetTimeMicros ( ) ; nTimeReadFromDisk + = nTime2 - nTime1 ;
int64_t nTime3 ;
LogPrint ( " bench " , " - Load block from disk: %.2fms [%.2fs] \n " , ( nTime2 - nTime1 ) * 0.001 , nTimeReadFromDisk * 0.000001 ) ;
2010-08-29 09:58:15 -07:00
{
2014-09-23 18:19:04 -07:00
CCoinsViewCache view ( pcoinsTip ) ;
2016-04-19 06:16:39 -07:00
bool rv = ConnectBlock ( * pblock , state , pindexNew , view , chainparams ) ;
2015-02-04 16:11:44 -08:00
GetMainSignals ( ) . BlockChecked ( * pblock , state ) ;
2014-10-19 20:55:04 -07:00
if ( ! rv ) {
2013-11-16 10:28:24 -08:00
if ( state . IsInvalid ( ) )
InvalidBlockFound ( pindexNew , state ) ;
2015-01-08 02:44:25 -08:00
return error ( " ConnectTip() : ConnectBlock % s failed " , pindexNew->GetBlockHash().ToString()) ;
2013-01-26 16:24:06 -08:00
}
2015-06-30 13:10:27 -07:00
mapBlockSource . erase ( pindexNew - > GetBlockHash ( ) ) ;
2014-07-26 13:49:17 -07:00
nTime3 = GetTimeMicros ( ) ; nTimeConnectTotal + = nTime3 - nTime2 ;
LogPrint ( " bench " , " - Connect total: %.2fms [%.2fs] \n " , ( nTime3 - nTime2 ) * 0.001 , nTimeConnectTotal * 0.000001 ) ;
2013-11-16 10:28:24 -08:00
assert ( view . Flush ( ) ) ;
2010-08-29 09:58:15 -07:00
}
2014-07-26 13:49:17 -07:00
int64_t nTime4 = GetTimeMicros ( ) ; nTimeFlush + = nTime4 - nTime3 ;
LogPrint ( " bench " , " - Flush: %.2fms [%.2fs] \n " , ( nTime4 - nTime3 ) * 0.001 , nTimeFlush * 0.000001 ) ;
2013-11-16 10:28:24 -08:00
// Write the chain state to disk, if necessary.
2014-11-14 09:19:26 -08:00
if ( ! FlushStateToDisk ( state , FLUSH_STATE_IF_NEEDED ) )
2013-11-16 10:28:24 -08:00
return false ;
2014-07-26 13:49:17 -07:00
int64_t nTime5 = GetTimeMicros ( ) ; nTimeChainState + = nTime5 - nTime4 ;
LogPrint ( " bench " , " - Writing chainstate: %.2fms [%.2fs] \n " , ( nTime5 - nTime4 ) * 0.001 , nTimeChainState * 0.000001 ) ;
2013-11-16 10:28:24 -08:00
// Remove conflicting transactions from the mempool.
2014-02-15 13:38:28 -08:00
list < CTransaction > txConflicted ;
2014-08-26 13:28:32 -07:00
mempool . removeForBlock ( pblock - > vtx , pindexNew - > nHeight , txConflicted , ! IsInitialBlockDownload ( ) ) ;
2018-02-21 20:21:06 -08:00
// Remove transactions that expire at new block height from mempool
mempool . removeExpired ( pindexNew - > nHeight ) ;
2013-11-16 10:28:24 -08:00
// Update chainActive & related variables.
2016-04-06 07:36:32 -07:00
UpdateTip ( pindexNew , chainparams ) ;
2014-02-15 13:38:28 -08:00
// Tell wallet about transactions that went from mempool
// to conflicted:
BOOST_FOREACH ( const CTransaction & tx , txConflicted ) {
2014-06-09 01:02:00 -07:00
SyncWithWallets ( tx , NULL ) ;
2014-02-15 13:38:28 -08:00
}
// ... and about transactions that got confirmed:
2014-08-25 17:26:41 -07:00
BOOST_FOREACH ( const CTransaction & tx , pblock - > vtx ) {
SyncWithWallets ( tx , pblock ) ;
2014-02-15 13:38:28 -08:00
}
2016-08-23 20:52:43 -07:00
// Update cached incremental witnesses
2018-07-17 10:56:01 -07:00
GetMainSignals ( ) . ChainTip ( pindexNew , pblock , oldSproutTree , oldSaplingTree , true ) ;
2014-08-10 09:01:55 -07:00
2017-04-24 23:06:29 -07:00
EnforceNodeDeprecation ( pindexNew - > nHeight ) ;
2014-07-26 13:49:17 -07:00
int64_t nTime6 = GetTimeMicros ( ) ; nTimePostConnect + = nTime6 - nTime5 ; nTimeTotal + = nTime6 - nTime1 ;
LogPrint ( " bench " , " - Connect postprocess: %.2fms [%.2fs] \n " , ( nTime6 - nTime5 ) * 0.001 , nTimePostConnect * 0.000001 ) ;
LogPrint ( " bench " , " - Connect block: %.2fms [%.2fs] \n " , ( nTime6 - nTime1 ) * 0.001 , nTimeTotal * 0.000001 ) ;
2010-08-29 09:58:15 -07:00
return true ;
}
2014-11-30 17:39:44 -08:00
/**
* Return the tip of the chain with the most work in it , that isn ' t
* known to be invalid ( it ' s however far from certain to be valid ) .
*/
2014-05-05 15:54:10 -07:00
static CBlockIndex * FindMostWorkChain ( ) {
2013-11-16 10:28:24 -08:00
do {
2014-05-05 15:54:10 -07:00
CBlockIndex * pindexNew = NULL ;
2013-11-16 10:28:24 -08:00
// Find the best candidate header.
{
2014-10-05 23:31:33 -07:00
std : : set < CBlockIndex * , CBlockIndexWorkComparator > : : reverse_iterator it = setBlockIndexCandidates . rbegin ( ) ;
if ( it = = setBlockIndexCandidates . rend ( ) )
2014-05-05 15:54:10 -07:00
return NULL ;
2013-11-16 10:28:24 -08:00
pindexNew = * it ;
}
// Check whether all blocks on the path between the currently active chain and the candidate are valid.
// Just going until the active chain is an optimization, as we know all blocks in it are valid already.
CBlockIndex * pindexTest = pindexNew ;
bool fInvalidAncestor = false ;
while ( pindexTest & & ! chainActive . Contains ( pindexTest ) ) {
2014-07-11 15:02:35 -07:00
assert ( pindexTest - > nChainTx | | pindexTest - > nHeight = = 0 ) ;
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
// Pruned nodes may have entries in setBlockIndexCandidates for
// which block files have been deleted. Remove those as candidates
// for the most work chain if we come across them; we can't switch
// to a chain unless we have all the non-active-chain parent blocks.
bool fFailedChain = pindexTest - > nStatus & BLOCK_FAILED_MASK ;
bool fMissingData = ! ( pindexTest - > nStatus & BLOCK_HAVE_DATA ) ;
if ( fFailedChain | | fMissingData ) {
// Candidate chain is not usable (either invalid or missing data)
if ( fFailedChain & & ( pindexBestInvalid = = NULL | | pindexNew - > nChainWork > pindexBestInvalid - > nChainWork ) )
2014-03-12 19:48:27 -07:00
pindexBestInvalid = pindexNew ;
CBlockIndex * pindexFailed = pindexNew ;
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
// Remove the entire chain from the set.
2013-11-16 10:28:24 -08:00
while ( pindexTest ! = pindexFailed ) {
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
if ( fFailedChain ) {
pindexFailed - > nStatus | = BLOCK_FAILED_CHILD ;
} else if ( fMissingData ) {
// If we're missing data, then add back to mapBlocksUnlinked,
// so that if the block arrives in the future we can try adding
// to setBlockIndexCandidates again.
mapBlocksUnlinked . insert ( std : : make_pair ( pindexFailed - > pprev , pindexFailed ) ) ;
}
2014-10-05 23:31:33 -07:00
setBlockIndexCandidates . erase ( pindexFailed ) ;
2013-11-16 10:28:24 -08:00
pindexFailed = pindexFailed - > pprev ;
}
2014-10-05 23:31:33 -07:00
setBlockIndexCandidates . erase ( pindexTest ) ;
2013-11-16 10:28:24 -08:00
fInvalidAncestor = true ;
break ;
2013-01-26 15:14:11 -08:00
}
2013-11-16 10:28:24 -08:00
pindexTest = pindexTest - > pprev ;
2010-08-29 09:58:15 -07:00
}
2014-05-05 15:54:10 -07:00
if ( ! fInvalidAncestor )
return pindexNew ;
2013-11-16 10:28:24 -08:00
} while ( true ) ;
}
2010-08-29 09:58:15 -07:00
2014-11-30 17:39:44 -08:00
/** Delete all entries in setBlockIndexCandidates that are worse than the current tip. */
2014-11-01 14:42:12 -07:00
static void PruneBlockIndexCandidates ( ) {
// Note that we can't delete the current block itself, as we may need to return to it later in case a
// reorganization to a better block fails.
std : : set < CBlockIndex * , CBlockIndexWorkComparator > : : iterator it = setBlockIndexCandidates . begin ( ) ;
2014-11-20 03:43:50 -08:00
while ( it ! = setBlockIndexCandidates . end ( ) & & setBlockIndexCandidates . value_comp ( ) ( * it , chainActive . Tip ( ) ) ) {
2014-11-01 14:42:12 -07:00
setBlockIndexCandidates . erase ( it + + ) ;
}
2014-11-20 03:43:50 -08:00
// Either the current tip or a successor of it we're working towards is left in setBlockIndexCandidates.
assert ( ! setBlockIndexCandidates . empty ( ) ) ;
2014-11-01 14:42:12 -07:00
}
2014-11-30 17:39:44 -08:00
/**
* Try to make some progress towards making pindexMostWork the active block .
* pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork .
*/
2015-04-17 05:40:24 -07:00
static bool ActivateBestChainStep ( CValidationState & state , const CChainParams & chainparams , CBlockIndex * pindexMostWork , const CBlock * pblock )
{
2014-05-05 16:23:13 -07:00
AssertLockHeld ( cs_main ) ;
2014-05-07 07:45:33 -07:00
bool fInvalidFound = false ;
2014-08-03 09:12:19 -07:00
const CBlockIndex * pindexOldTip = chainActive . Tip ( ) ;
const CBlockIndex * pindexFork = chainActive . FindFork ( pindexMostWork ) ;
2010-08-29 09:58:15 -07:00
2017-06-21 04:53:01 -07:00
// - On ChainDB initialization, pindexOldTip will be null, so there are no removable blocks.
// - If pindexMostWork is in a chain that doesn't have the same genesis block as our chain,
// then pindexFork will be null, and we would need to remove the entire chain including
// our genesis block. In practice this (probably) won't happen because of checks elsewhere.
auto reorgLength = pindexOldTip ? pindexOldTip - > nHeight - ( pindexFork ? pindexFork - > nHeight : - 1 ) : 0 ;
static_assert ( MAX_REORG_LENGTH > 0 , " We must be able to reorg some distance " ) ;
if ( reorgLength > MAX_REORG_LENGTH ) {
auto msg = strprintf ( _ (
" A block chain reorganization has been detected that would roll back %d blocks! "
" This is larger than the maximum of %d blocks, and so the node is shutting down for your safety. "
) , reorgLength , MAX_REORG_LENGTH ) + " \n \n " +
_ ( " Reorganization details " ) + " : \n " +
" - " + strprintf ( _ ( " Current tip: %s, height %d, work %s " ) ,
pindexOldTip - > phashBlock - > GetHex ( ) , pindexOldTip - > nHeight , pindexOldTip - > nChainWork . GetHex ( ) ) + " \n " +
" - " + strprintf ( _ ( " New tip: %s, height %d, work %s " ) ,
pindexMostWork - > phashBlock - > GetHex ( ) , pindexMostWork - > nHeight , pindexMostWork - > nChainWork . GetHex ( ) ) + " \n " +
" - " + strprintf ( _ ( " Fork point: %s, height %d " ) ,
pindexFork - > phashBlock - > GetHex ( ) , pindexFork - > nHeight ) + " \n \n " +
_ ( " Please help, human! " ) ;
LogPrintf ( " *** %s \n " , msg ) ;
uiInterface . ThreadSafeMessageBox ( msg , " " , CClientUIInterface : : MSG_ERROR ) ;
StartShutdown ( ) ;
return false ;
}
2014-05-05 16:23:13 -07:00
// Disconnect active blocks which are no longer in the best chain.
2015-09-09 16:31:20 -07:00
bool fBlocksDisconnected = false ;
2014-05-05 16:23:13 -07:00
while ( chainActive . Tip ( ) & & chainActive . Tip ( ) ! = pindexFork ) {
2016-04-17 00:58:50 -07:00
if ( ! DisconnectTip ( state , chainparams ) )
2014-05-05 16:23:13 -07:00
return false ;
2015-09-09 16:31:20 -07:00
fBlocksDisconnected = true ;
2014-05-05 16:23:13 -07:00
}
2013-11-16 10:28:24 -08:00
2014-05-05 16:23:13 -07:00
// Build list of new blocks to connect.
std : : vector < CBlockIndex * > vpindexToConnect ;
2014-10-10 13:13:47 -07:00
bool fContinue = true ;
int nHeight = pindexFork ? pindexFork - > nHeight : - 1 ;
while ( fContinue & & nHeight ! = pindexMostWork - > nHeight ) {
2015-09-09 14:54:11 -07:00
// Don't iterate the entire list of potential improvements toward the best tip, as we likely only need
// a few blocks along the way.
int nTargetHeight = std : : min ( nHeight + 32 , pindexMostWork - > nHeight ) ;
vpindexToConnect . clear ( ) ;
vpindexToConnect . reserve ( nTargetHeight - nHeight ) ;
CBlockIndex * pindexIter = pindexMostWork - > GetAncestor ( nTargetHeight ) ;
while ( pindexIter & & pindexIter - > nHeight ! = nHeight ) {
vpindexToConnect . push_back ( pindexIter ) ;
pindexIter = pindexIter - > pprev ;
}
nHeight = nTargetHeight ;
// Connect new blocks.
BOOST_REVERSE_FOREACH ( CBlockIndex * pindexConnect , vpindexToConnect ) {
2015-04-17 05:40:24 -07:00
if ( ! ConnectTip ( state , chainparams , pindexConnect , pindexConnect = = pindexMostWork ? pblock : NULL ) ) {
2015-09-09 14:54:11 -07:00
if ( state . IsInvalid ( ) ) {
// The block violates a consensus rule.
if ( ! state . CorruptionPossible ( ) )
InvalidChainFound ( vpindexToConnect . back ( ) ) ;
state = CValidationState ( ) ;
fInvalidFound = true ;
fContinue = false ;
break ;
} else {
// A system error occurred (disk space, database error, ...).
return false ;
}
2014-05-05 16:23:13 -07:00
} else {
2015-09-09 14:54:11 -07:00
PruneBlockIndexCandidates ( ) ;
if ( ! pindexOldTip | | chainActive . Tip ( ) - > nChainWork > pindexOldTip - > nChainWork ) {
// We're in a better position than we were. Return temporarily to release the lock.
fContinue = false ;
break ;
}
2013-11-16 10:28:24 -08:00
}
}
2012-11-24 05:26:51 -08:00
}
2010-08-29 09:58:15 -07:00
2015-09-09 16:31:20 -07:00
if ( fBlocksDisconnected ) {
2015-11-23 13:06:12 -08:00
mempool . removeForReorg ( pcoinsTip , chainActive . Tip ( ) - > nHeight + 1 , STANDARD_LOCKTIME_VERIFY_FLAGS ) ;
2014-10-10 13:13:47 -07:00
}
2018-02-09 15:16:55 -08:00
mempool . removeWithoutBranchId (
2018-03-09 06:07:04 -08:00
CurrentEpochBranchId ( chainActive . Tip ( ) - > nHeight + 1 , chainparams . GetConsensus ( ) ) ) ;
2015-09-09 16:31:20 -07:00
mempool . check ( pcoinsTip ) ;
2010-08-29 09:58:15 -07:00
2014-05-07 07:45:33 -07:00
// Callbacks/notifications for a new best chain.
if ( fInvalidFound )
CheckForkWarningConditionsOnNewFork ( vpindexToConnect . back ( ) ) ;
else
CheckForkWarningConditions ( ) ;
2010-08-29 09:58:15 -07:00
return true ;
}
2014-11-30 17:39:44 -08:00
/**
* Make the best chain active , in multiple steps . The result is either failure
* or an activated best chain . pblock is either NULL or a pointer to a block
* that is already loaded ( to avoid loading it again from disk ) .
*/
2015-04-17 05:40:24 -07:00
bool ActivateBestChain ( CValidationState & state , const CChainParams & chainparams , const CBlock * pblock )
{
2014-05-07 07:45:33 -07:00
CBlockIndex * pindexNewTip = NULL ;
CBlockIndex * pindexMostWork = NULL ;
2014-05-05 16:23:13 -07:00
do {
boost : : this_thread : : interruption_point ( ) ;
2014-05-07 07:45:33 -07:00
bool fInitialDownload ;
{
LOCK ( cs_main ) ;
pindexMostWork = FindMostWorkChain ( ) ;
2014-05-05 16:23:13 -07:00
2014-05-07 07:45:33 -07:00
// Whether we have anything to do at all.
if ( pindexMostWork = = NULL | | pindexMostWork = = chainActive . Tip ( ) )
return true ;
2014-05-05 16:23:13 -07:00
2015-04-17 05:40:24 -07:00
if ( ! ActivateBestChainStep ( state , chainparams , pindexMostWork , pblock & & pblock - > GetHash ( ) = = pindexMostWork - > GetBlockHash ( ) ? pblock : NULL ) )
2014-05-07 07:45:33 -07:00
return false ;
2014-05-05 16:23:13 -07:00
2014-05-07 07:45:33 -07:00
pindexNewTip = chainActive . Tip ( ) ;
fInitialDownload = IsInitialBlockDownload ( ) ;
}
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
// Notifications/callbacks that can run without cs_main
if ( ! fInitialDownload ) {
uint256 hashNewTip = pindexNewTip - > GetBlockHash ( ) ;
// Relay inventory, but don't relay old inventory during initial block download.
2015-04-22 20:22:36 -07:00
int nBlockEstimate = 0 ;
if ( fCheckpointsEnabled )
2015-04-17 05:19:21 -07:00
nBlockEstimate = Checkpoints : : GetTotalBlocksEstimate ( chainparams . Checkpoints ( ) ) ;
2015-05-15 14:07:11 -07:00
{
2014-10-06 04:04:02 -07:00
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
if ( chainActive . Height ( ) > ( pnode - > nStartingHeight ! = - 1 ? pnode - > nStartingHeight - 2000 : nBlockEstimate ) )
pnode - > PushInventory ( CInv ( MSG_BLOCK , hashNewTip ) ) ;
2014-05-07 07:45:33 -07:00
}
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
// Notify external listeners about the new tip.
2015-09-16 07:42:23 -07:00
GetMainSignals ( ) . UpdatedBlockTip ( pindexNewTip ) ;
2014-08-14 09:32:34 -07:00
uiInterface . NotifyBlockTip ( hashNewTip ) ;
2014-05-07 07:45:33 -07:00
}
} while ( pindexMostWork ! = chainActive . Tip ( ) ) ;
2015-04-17 05:19:21 -07:00
CheckBlockIndex ( chainparams . GetConsensus ( ) ) ;
2014-05-05 16:23:13 -07:00
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
// Write changes periodically to disk, after relay.
2014-11-14 09:19:26 -08:00
if ( ! FlushStateToDisk ( state , FLUSH_STATE_PERIODIC ) ) {
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
return false ;
}
2014-05-05 16:23:13 -07:00
return true ;
}
2014-03-12 19:48:27 -07:00
2016-04-17 00:58:50 -07:00
bool InvalidateBlock ( CValidationState & state , const CChainParams & chainparams , CBlockIndex * pindex )
2015-04-17 05:19:21 -07:00
{
2014-11-19 00:39:42 -08:00
AssertLockHeld ( cs_main ) ;
// Mark the block itself as invalid.
pindex - > nStatus | = BLOCK_FAILED_VALID ;
2014-11-25 03:33:43 -08:00
setDirtyBlockIndex . insert ( pindex ) ;
2014-11-19 00:39:42 -08:00
setBlockIndexCandidates . erase ( pindex ) ;
while ( chainActive . Contains ( pindex ) ) {
CBlockIndex * pindexWalk = chainActive . Tip ( ) ;
pindexWalk - > nStatus | = BLOCK_FAILED_CHILD ;
2014-11-25 03:33:43 -08:00
setDirtyBlockIndex . insert ( pindexWalk ) ;
2014-11-19 00:39:42 -08:00
setBlockIndexCandidates . erase ( pindexWalk ) ;
// ActivateBestChain considers blocks already in chainActive
// unconditionally valid already, so force disconnect away from it.
2016-04-17 00:58:50 -07:00
if ( ! DisconnectTip ( state , chainparams ) ) {
2015-11-23 13:06:12 -08:00
mempool . removeForReorg ( pcoinsTip , chainActive . Tip ( ) - > nHeight + 1 , STANDARD_LOCKTIME_VERIFY_FLAGS ) ;
2018-02-09 15:16:55 -08:00
mempool . removeWithoutBranchId (
2016-04-17 00:58:50 -07:00
CurrentEpochBranchId ( chainActive . Tip ( ) - > nHeight + 1 , chainparams . GetConsensus ( ) ) ) ;
2014-11-19 00:39:42 -08:00
return false ;
}
}
// The resulting new best tip may not be in setBlockIndexCandidates anymore, so
2015-04-28 07:47:17 -07:00
// add it again.
2014-11-19 00:39:42 -08:00
BlockMap : : iterator it = mapBlockIndex . begin ( ) ;
while ( it ! = mapBlockIndex . end ( ) ) {
2015-03-12 13:03:23 -07:00
if ( it - > second - > IsValid ( BLOCK_VALID_TRANSACTIONS ) & & it - > second - > nChainTx & & ! setBlockIndexCandidates . value_comp ( ) ( it - > second , chainActive . Tip ( ) ) ) {
2015-03-11 08:56:44 -07:00
setBlockIndexCandidates . insert ( it - > second ) ;
2014-11-19 00:39:42 -08:00
}
it + + ;
}
InvalidChainFound ( pindex ) ;
2015-11-23 13:06:12 -08:00
mempool . removeForReorg ( pcoinsTip , chainActive . Tip ( ) - > nHeight + 1 , STANDARD_LOCKTIME_VERIFY_FLAGS ) ;
2018-02-09 15:16:55 -08:00
mempool . removeWithoutBranchId (
2016-04-17 00:58:50 -07:00
CurrentEpochBranchId ( chainActive . Tip ( ) - > nHeight + 1 , chainparams . GetConsensus ( ) ) ) ;
2014-11-19 00:39:42 -08:00
return true ;
}
bool ReconsiderBlock ( CValidationState & state , CBlockIndex * pindex ) {
AssertLockHeld ( cs_main ) ;
int nHeight = pindex - > nHeight ;
// Remove the invalidity flag from this block and all its descendants.
BlockMap : : iterator it = mapBlockIndex . begin ( ) ;
while ( it ! = mapBlockIndex . end ( ) ) {
if ( ! it - > second - > IsValid ( ) & & it - > second - > GetAncestor ( nHeight ) = = pindex ) {
it - > second - > nStatus & = ~ BLOCK_FAILED_MASK ;
2014-11-25 03:33:43 -08:00
setDirtyBlockIndex . insert ( it - > second ) ;
2014-11-19 00:39:42 -08:00
if ( it - > second - > IsValid ( BLOCK_VALID_TRANSACTIONS ) & & it - > second - > nChainTx & & setBlockIndexCandidates . value_comp ( ) ( chainActive . Tip ( ) , it - > second ) ) {
setBlockIndexCandidates . insert ( it - > second ) ;
}
if ( it - > second = = pindexBestInvalid ) {
// Reset invalid block marker if it was pointing to one of those.
pindexBestInvalid = NULL ;
}
}
it + + ;
}
// Remove the invalidity flag from all ancestors too.
while ( pindex ! = NULL ) {
2014-11-25 03:33:43 -08:00
if ( pindex - > nStatus & BLOCK_FAILED_MASK ) {
pindex - > nStatus & = ~ BLOCK_FAILED_MASK ;
setDirtyBlockIndex . insert ( pindex ) ;
2014-11-19 00:39:42 -08:00
}
pindex = pindex - > pprev ;
}
return true ;
}
2014-07-11 15:02:35 -07:00
CBlockIndex * AddToBlockIndex ( const CBlockHeader & block )
2010-08-29 09:58:15 -07:00
{
// Check for duplicate
2013-06-23 19:00:18 -07:00
uint256 hash = block . GetHash ( ) ;
2014-09-03 17:02:44 -07:00
BlockMap : : iterator it = mapBlockIndex . find ( hash ) ;
2014-03-12 19:48:27 -07:00
if ( it ! = mapBlockIndex . end ( ) )
return it - > second ;
2010-08-29 09:58:15 -07:00
// Construct new block index object
2013-06-23 19:00:18 -07:00
CBlockIndex * pindexNew = new CBlockIndex ( block ) ;
2014-04-05 22:11:16 -07:00
assert ( pindexNew ) ;
2014-07-11 15:02:35 -07:00
// We assign the sequence id to blocks only when the full data is available,
// to avoid miners withholding blocks but broadcasting headers, to get a
// competitive advantage.
pindexNew - > nSequenceId = 0 ;
2014-09-03 17:02:44 -07:00
BlockMap : : iterator mi = mapBlockIndex . insert ( make_pair ( hash , pindexNew ) ) . first ;
2010-08-29 09:58:15 -07:00
pindexNew - > phashBlock = & ( ( * mi ) . first ) ;
2014-09-03 17:02:44 -07:00
BlockMap : : iterator miPrev = mapBlockIndex . find ( block . hashPrevBlock ) ;
2010-08-29 09:58:15 -07:00
if ( miPrev ! = mapBlockIndex . end ( ) )
{
pindexNew - > pprev = ( * miPrev ) . second ;
pindexNew - > nHeight = pindexNew - > pprev - > nHeight + 1 ;
2014-06-24 15:56:47 -07:00
pindexNew - > BuildSkip ( ) ;
2010-08-29 09:58:15 -07:00
}
2014-10-29 09:00:02 -07:00
pindexNew - > nChainWork = ( pindexNew - > pprev ? pindexNew - > pprev - > nChainWork : 0 ) + GetBlockProof ( * pindexNew ) ;
2014-03-12 19:48:27 -07:00
pindexNew - > RaiseValidity ( BLOCK_VALID_TREE ) ;
2014-07-11 15:02:35 -07:00
if ( pindexBestHeader = = NULL | | pindexBestHeader - > nChainWork < pindexNew - > nChainWork )
pindexBestHeader = pindexNew ;
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
setDirtyBlockIndex . insert ( pindexNew ) ;
2014-03-12 19:48:27 -07:00
return pindexNew ;
}
2019-03-12 23:43:54 -07:00
void FallbackSproutValuePoolBalance (
CBlockIndex * pindex ,
const CChainParams & chainparams
)
{
2019-03-18 10:32:26 -07:00
if ( ! chainparams . ZIP209Enabled ( ) ) {
2019-03-14 13:20:51 -07:00
return ;
}
2019-04-19 10:54:51 -07:00
// When developer option -developersetpoolsizezero is enabled, we don't need a fallback balance.
2019-04-24 08:40:17 -07:00
if ( fExperimentalMode & & mapArgs . count ( " -developersetpoolsizezero " ) ) {
2019-04-19 10:54:51 -07:00
return ;
}
2019-03-12 23:43:54 -07:00
// Check if the height of this block matches the checkpoint
if ( pindex - > nHeight = = chainparams . SproutValuePoolCheckpointHeight ( ) ) {
2019-03-14 14:39:11 -07:00
if ( pindex - > GetBlockHash ( ) = = chainparams . SproutValuePoolCheckpointBlockHash ( ) ) {
// Are we monitoring the Sprout pool?
if ( ! pindex - > nChainSproutValue ) {
// Apparently not. Introduce the hardcoded value so we monitor for
// this point onwards (assuming the checkpoint is late enough)
pindex - > nChainSproutValue = chainparams . SproutValuePoolCheckpointBalance ( ) ;
} else {
// Apparently we have been. So, we should expect the current
// value to match the hardcoded one.
assert ( * pindex - > nChainSproutValue = = chainparams . SproutValuePoolCheckpointBalance ( ) ) ;
// And we should expect non-none for the delta stored in the block index here,
// or the checkpoint is too early.
assert ( pindex - > nSproutValue ! = boost : : none ) ;
}
2019-03-12 23:43:54 -07:00
} else {
2019-03-14 14:39:11 -07:00
LogPrintf (
" FallbackSproutValuePoolBalance(): fallback block hash is incorrect, we got %s \n " ,
pindex - > GetBlockHash ( ) . ToString ( )
) ;
2019-03-12 23:43:54 -07:00
}
}
}
2014-11-30 17:39:44 -08:00
/** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */
2014-03-12 19:48:27 -07:00
bool ReceivedBlockTransactions ( const CBlock & block , CValidationState & state , CBlockIndex * pindexNew , const CDiskBlockPos & pos )
{
2019-03-12 23:43:54 -07:00
const CChainParams & chainparams = Params ( ) ;
2014-03-12 19:48:27 -07:00
pindexNew - > nTx = block . vtx . size ( ) ;
2014-07-11 15:02:35 -07:00
pindexNew - > nChainTx = 0 ;
2017-11-09 14:09:54 -08:00
CAmount sproutValue = 0 ;
2018-05-09 04:15:46 -07:00
CAmount saplingValue = 0 ;
2017-11-09 14:09:54 -08:00
for ( auto tx : block . vtx ) {
2018-05-09 04:15:46 -07:00
// Negative valueBalance "takes" money from the transparent value pool
// and adds it to the Sapling value pool. Positive valueBalance "gives"
// money to the transparent value pool, removing from the Sapling value
// pool. So we invert the sign here.
saplingValue + = - tx . valueBalance ;
2017-11-09 14:09:54 -08:00
for ( auto js : tx . vjoinsplit ) {
sproutValue + = js . vpub_old ;
sproutValue - = js . vpub_new ;
}
}
pindexNew - > nSproutValue = sproutValue ;
pindexNew - > nChainSproutValue = boost : : none ;
2018-05-09 04:15:46 -07:00
pindexNew - > nSaplingValue = saplingValue ;
pindexNew - > nChainSaplingValue = boost : : none ;
2012-08-18 15:33:01 -07:00
pindexNew - > nFile = pos . nFile ;
pindexNew - > nDataPos = pos . nPos ;
2012-08-13 10:11:05 -07:00
pindexNew - > nUndoPos = 0 ;
2014-03-12 19:48:27 -07:00
pindexNew - > nStatus | = BLOCK_HAVE_DATA ;
2014-07-11 15:02:35 -07:00
pindexNew - > RaiseValidity ( BLOCK_VALID_TRANSACTIONS ) ;
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
setDirtyBlockIndex . insert ( pindexNew ) ;
2014-03-12 19:48:27 -07:00
2014-07-11 15:02:35 -07:00
if ( pindexNew - > pprev = = NULL | | pindexNew - > pprev - > nChainTx ) {
// If pindexNew is the genesis block or all parents are BLOCK_VALID_TRANSACTIONS.
deque < CBlockIndex * > queue ;
queue . push_back ( pindexNew ) ;
2010-08-29 09:58:15 -07:00
2014-07-11 15:02:35 -07:00
// Recursively process any descendant blocks that now may be eligible to be connected.
while ( ! queue . empty ( ) ) {
CBlockIndex * pindex = queue . front ( ) ;
queue . pop_front ( ) ;
pindex - > nChainTx = ( pindex - > pprev ? pindex - > pprev - > nChainTx : 0 ) + pindex - > nTx ;
2017-11-09 14:09:54 -08:00
if ( pindex - > pprev ) {
if ( pindex - > pprev - > nChainSproutValue & & pindex - > nSproutValue ) {
pindex - > nChainSproutValue = * pindex - > pprev - > nChainSproutValue + * pindex - > nSproutValue ;
} else {
pindex - > nChainSproutValue = boost : : none ;
}
2018-05-09 04:15:46 -07:00
if ( pindex - > pprev - > nChainSaplingValue ) {
pindex - > nChainSaplingValue = * pindex - > pprev - > nChainSaplingValue + pindex - > nSaplingValue ;
} else {
pindex - > nChainSaplingValue = boost : : none ;
}
2017-11-09 14:09:54 -08:00
} else {
pindex - > nChainSproutValue = pindex - > nSproutValue ;
2018-05-09 04:15:46 -07:00
pindex - > nChainSaplingValue = pindex - > nSaplingValue ;
2017-11-09 14:09:54 -08:00
}
2019-03-12 23:43:54 -07:00
2019-03-14 13:20:51 -07:00
// Fall back to hardcoded Sprout value pool balance
FallbackSproutValuePoolBalance ( pindex , chainparams ) ;
2019-03-12 23:43:54 -07:00
2015-04-13 09:26:28 -07:00
{
LOCK ( cs_nBlockSequenceId ) ;
pindex - > nSequenceId = nBlockSequenceId + + ;
}
2015-03-13 09:25:34 -07:00
if ( chainActive . Tip ( ) = = NULL | | ! setBlockIndexCandidates . value_comp ( ) ( pindex , chainActive . Tip ( ) ) ) {
setBlockIndexCandidates . insert ( pindex ) ;
}
2014-07-11 15:02:35 -07:00
std : : pair < std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator , std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator > range = mapBlocksUnlinked . equal_range ( pindex ) ;
while ( range . first ! = range . second ) {
std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator it = range . first ;
queue . push_back ( it - > second ) ;
range . first + + ;
mapBlocksUnlinked . erase ( it ) ;
}
}
} else {
if ( pindexNew - > pprev & & pindexNew - > pprev - > IsValid ( BLOCK_VALID_TREE ) ) {
mapBlocksUnlinked . insert ( std : : make_pair ( pindexNew - > pprev , pindexNew ) ) ;
}
}
2010-08-29 09:58:15 -07:00
2014-05-07 08:10:35 -07:00
return true ;
2010-08-29 09:58:15 -07:00
}
2013-04-12 22:13:08 -07:00
bool FindBlockPos ( CValidationState & state , CDiskBlockPos & pos , unsigned int nAddSize , unsigned int nHeight , uint64_t nTime , bool fKnown = false )
2012-08-13 10:11:05 -07:00
{
LOCK ( cs_LastBlockFile ) ;
2014-09-24 23:21:21 -07:00
unsigned int nFile = fKnown ? pos . nFile : nLastBlockFile ;
if ( vinfoBlockFile . size ( ) < = nFile ) {
vinfoBlockFile . resize ( nFile + 1 ) ;
}
if ( ! fKnown ) {
while ( vinfoBlockFile [ nFile ] . nSize + nAddSize > = MAX_BLOCKFILE_SIZE ) {
nFile + + ;
if ( vinfoBlockFile . size ( ) < = nFile ) {
vinfoBlockFile . resize ( nFile + 1 ) ;
}
2012-10-21 12:23:13 -07:00
}
2014-09-24 23:21:21 -07:00
pos . nFile = nFile ;
pos . nPos = vinfoBlockFile [ nFile ] . nSize ;
2012-08-13 10:11:05 -07:00
}
2015-11-04 15:16:49 -08:00
if ( nFile ! = nLastBlockFile ) {
if ( ! fKnown ) {
LogPrintf ( " Leaving block file %i: %s \n " , nFile , vinfoBlockFile [ nFile ] . ToString ( ) ) ;
}
FlushBlockFile ( ! fKnown ) ;
nLastBlockFile = nFile ;
}
2014-09-24 23:21:21 -07:00
vinfoBlockFile [ nFile ] . AddBlock ( nHeight , nTime ) ;
2015-03-06 17:26:09 -08:00
if ( fKnown )
vinfoBlockFile [ nFile ] . nSize = std : : max ( pos . nPos + nAddSize , vinfoBlockFile [ nFile ] . nSize ) ;
else
vinfoBlockFile [ nFile ] . nSize + = nAddSize ;
2012-08-13 10:11:05 -07:00
2012-10-21 12:23:13 -07:00
if ( ! fKnown ) {
unsigned int nOldChunks = ( pos . nPos + BLOCKFILE_CHUNK_SIZE - 1 ) / BLOCKFILE_CHUNK_SIZE ;
2014-09-24 23:21:21 -07:00
unsigned int nNewChunks = ( vinfoBlockFile [ nFile ] . nSize + BLOCKFILE_CHUNK_SIZE - 1 ) / BLOCKFILE_CHUNK_SIZE ;
2012-10-21 12:23:13 -07:00
if ( nNewChunks > nOldChunks ) {
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
if ( fPruneMode )
fCheckForPruning = true ;
2012-12-03 22:48:57 -08:00
if ( CheckDiskSpace ( nNewChunks * BLOCKFILE_CHUNK_SIZE - pos . nPos ) ) {
FILE * file = OpenBlockFile ( pos ) ;
if ( file ) {
2013-09-18 03:38:08 -07:00
LogPrintf ( " Pre-allocating up to position 0x%x in blk%05u.dat \n " , nNewChunks * BLOCKFILE_CHUNK_SIZE , pos . nFile ) ;
2012-12-03 22:48:57 -08:00
AllocateFileRange ( file , pos . nPos , nNewChunks * BLOCKFILE_CHUNK_SIZE - pos . nPos ) ;
fclose ( file ) ;
}
2012-10-21 12:23:13 -07:00
}
2012-12-03 22:48:57 -08:00
else
2012-09-09 19:02:35 -07:00
return state . Error ( " out of disk space " ) ;
2012-08-15 17:21:28 -07:00
}
}
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
setDirtyFileInfo . insert ( nFile ) ;
2012-08-13 10:11:05 -07:00
return true ;
}
2013-01-26 15:14:11 -08:00
bool FindUndoPos ( CValidationState & state , int nFile , CDiskBlockPos & pos , unsigned int nAddSize )
2012-08-13 10:11:05 -07:00
{
pos . nFile = nFile ;
LOCK ( cs_LastBlockFile ) ;
2012-08-15 17:21:28 -07:00
unsigned int nNewSize ;
2014-09-24 23:21:21 -07:00
pos . nPos = vinfoBlockFile [ nFile ] . nUndoSize ;
nNewSize = vinfoBlockFile [ nFile ] . nUndoSize + = nAddSize ;
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
setDirtyFileInfo . insert ( nFile ) ;
2012-08-15 17:21:28 -07:00
unsigned int nOldChunks = ( pos . nPos + UNDOFILE_CHUNK_SIZE - 1 ) / UNDOFILE_CHUNK_SIZE ;
unsigned int nNewChunks = ( nNewSize + UNDOFILE_CHUNK_SIZE - 1 ) / UNDOFILE_CHUNK_SIZE ;
if ( nNewChunks > nOldChunks ) {
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
if ( fPruneMode )
fCheckForPruning = true ;
2012-12-03 22:48:57 -08:00
if ( CheckDiskSpace ( nNewChunks * UNDOFILE_CHUNK_SIZE - pos . nPos ) ) {
FILE * file = OpenUndoFile ( pos ) ;
if ( file ) {
2013-09-18 03:38:08 -07:00
LogPrintf ( " Pre-allocating up to position 0x%x in rev%05u.dat \n " , nNewChunks * UNDOFILE_CHUNK_SIZE , pos . nFile ) ;
2012-12-03 22:48:57 -08:00
AllocateFileRange ( file , pos . nPos , nNewChunks * UNDOFILE_CHUNK_SIZE - pos . nPos ) ;
fclose ( file ) ;
}
2012-08-15 17:21:28 -07:00
}
2012-12-03 22:48:57 -08:00
else
2012-09-09 19:02:35 -07:00
return state . Error ( " out of disk space " ) ;
2012-08-13 10:11:05 -07:00
}
return true ;
}
2019-03-14 04:02:47 -07:00
bool CheckBlockHeader (
const CBlockHeader & block ,
CValidationState & state ,
const CChainParams & chainparams ,
bool fCheckPOW )
2010-08-29 09:58:15 -07:00
{
2016-10-20 13:26:34 -07:00
// Check block version
if ( block . nVersion < MIN_BLOCK_VERSION )
return state . DoS ( 100 , error ( " CheckBlockHeader(): block version too low " ) ,
REJECT_INVALID , " version-too-low " ) ;
2016-02-28 12:19:07 -08:00
// Check Equihash solution is valid
2019-03-14 04:02:47 -07:00
if ( fCheckPOW & & ! CheckEquihashSolution ( & block , chainparams . GetConsensus ( ) ) )
2016-02-28 12:19:07 -08:00
return state . DoS ( 100 , error ( " CheckBlockHeader(): Equihash solution invalid " ) ,
REJECT_INVALID , " invalid-solution " ) ;
2010-09-19 14:20:34 -07:00
// Check proof of work matches claimed amount
2019-03-14 04:02:47 -07:00
if ( fCheckPOW & & ! CheckProofOfWork ( block . GetHash ( ) , block . nBits , chainparams . GetConsensus ( ) ) )
2015-01-08 02:44:25 -08:00
return state . DoS ( 50 , error ( " CheckBlockHeader(): proof of work failed " ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " high-hash " ) ;
2010-09-19 14:20:34 -07:00
2010-08-29 09:58:15 -07:00
// Check timestamp
2013-06-23 19:14:11 -07:00
if ( block . GetBlockTime ( ) > GetAdjustedTime ( ) + 2 * 60 * 60 )
2015-01-08 02:44:25 -08:00
return state . Invalid ( error ( " CheckBlockHeader(): block timestamp too far in the future " ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " time-too-new " ) ;
2010-08-29 09:58:15 -07:00
2014-03-11 09:36:21 -07:00
return true ;
}
2016-11-22 20:04:20 -08:00
bool CheckBlock ( const CBlock & block , CValidationState & state ,
2019-03-14 04:02:47 -07:00
const CChainParams & chainparams ,
2016-11-22 20:04:20 -08:00
libzcash : : ProofVerifier & verifier ,
bool fCheckPOW , bool fCheckMerkleRoot )
2010-08-29 09:58:15 -07:00
{
2014-07-11 15:02:35 -07:00
// These are checks that are independent of context.
2010-08-29 09:58:15 -07:00
2014-11-19 23:28:19 -08:00
// Check that the header is valid (particularly PoW). This is mostly
// redundant with the call in AcceptBlockHeader.
2019-03-14 04:02:47 -07:00
if ( ! CheckBlockHeader ( block , state , chainparams , fCheckPOW ) )
2014-03-11 09:36:21 -07:00
return false ;
2014-07-11 15:02:35 -07:00
// Check the merkle root.
if ( fCheckMerkleRoot ) {
bool mutated ;
uint256 hashMerkleRoot2 = block . BuildMerkleTree ( & mutated ) ;
if ( block . hashMerkleRoot ! = hashMerkleRoot2 )
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " CheckBlock(): hashMerkleRoot mismatch " ) ,
2014-07-11 15:02:35 -07:00
REJECT_INVALID , " bad-txnmrklroot " , true ) ;
// Check for merkle tree malleability (CVE-2012-2459): repeating sequences
// of transactions in a block without affecting the merkle root of a block,
// while still invalidating it.
if ( mutated )
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " CheckBlock(): duplicate transaction " ) ,
2014-07-11 15:02:35 -07:00
REJECT_INVALID , " bad-txns-duplicate " , true ) ;
}
// All potential-corruption validation must be done before we do any
// transaction validation, as otherwise we may mark the header as invalid
// because we receive the wrong transactions for it.
2010-08-29 09:58:15 -07:00
// Size limits
2013-06-23 19:14:11 -07:00
if ( block . vtx . empty ( ) | | block . vtx . size ( ) > MAX_BLOCK_SIZE | | : : GetSerializeSize ( block , SER_NETWORK , PROTOCOL_VERSION ) > MAX_BLOCK_SIZE )
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " CheckBlock(): size limits failed " ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " bad-blk-length " ) ;
2010-08-29 09:58:15 -07:00
// First transaction must be coinbase, the rest must not be
2013-06-23 19:14:11 -07:00
if ( block . vtx . empty ( ) | | ! block . vtx [ 0 ] . IsCoinBase ( ) )
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " CheckBlock(): first tx is not coinbase " ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " bad-cb-missing " ) ;
2013-06-23 19:14:11 -07:00
for ( unsigned int i = 1 ; i < block . vtx . size ( ) ; i + + )
if ( block . vtx [ i ] . IsCoinBase ( ) )
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " CheckBlock(): more than one coinbase " ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " bad-cb-multiple " ) ;
2010-08-29 09:58:15 -07:00
// Check transactions
2013-06-23 19:14:11 -07:00
BOOST_FOREACH ( const CTransaction & tx , block . vtx )
2016-11-22 20:04:20 -08:00
if ( ! CheckTransaction ( tx , state , verifier ) )
2015-01-08 02:44:25 -08:00
return error ( " CheckBlock() : CheckTransaction failed " ) ;
2010-08-29 09:58:15 -07:00
2012-04-23 11:14:03 -07:00
unsigned int nSigOps = 0 ;
2013-06-23 19:14:11 -07:00
BOOST_FOREACH ( const CTransaction & tx , block . vtx )
2011-10-03 10:05:43 -07:00
{
2013-01-08 04:17:15 -08:00
nSigOps + = GetLegacySigOpCount ( tx ) ;
2011-10-03 10:05:43 -07:00
}
if ( nSigOps > MAX_BLOCK_SIGOPS )
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " CheckBlock(): out-of-bounds SigOpCount " ) ,
2012-09-09 19:02:35 -07:00
REJECT_INVALID , " bad-blk-sigops " , true ) ;
2010-08-29 09:58:15 -07:00
return true ;
}
2019-03-14 04:18:32 -07:00
bool ContextualCheckBlockHeader (
const CBlockHeader & block , CValidationState & state ,
const CChainParams & chainParams , CBlockIndex * const pindexPrev )
2014-10-19 16:09:50 -07:00
{
2015-04-22 15:19:11 -07:00
const Consensus : : Params & consensusParams = chainParams . GetConsensus ( ) ;
2014-10-19 16:09:50 -07:00
uint256 hash = block . GetHash ( ) ;
2015-04-09 06:58:34 -07:00
if ( hash = = consensusParams . hashGenesisBlock )
2014-10-19 16:09:50 -07:00
return true ;
assert ( pindexPrev ) ;
int nHeight = pindexPrev - > nHeight + 1 ;
// Check proof of work
2015-04-22 15:19:11 -07:00
if ( block . nBits ! = GetNextWorkRequired ( pindexPrev , & block , consensusParams ) )
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " %s: incorrect proof of work " , __func__ ) ,
2014-10-19 16:09:50 -07:00
REJECT_INVALID , " bad-diffbits " ) ;
// Check timestamp against prev
if ( block . GetBlockTime ( ) < = pindexPrev - > GetMedianTimePast ( ) )
2015-01-08 02:44:25 -08:00
return state . Invalid ( error ( " %s: block's timestamp is too early " , __func__ ) ,
2014-10-19 16:09:50 -07:00
REJECT_INVALID , " time-too-old " ) ;
2015-03-19 05:34:06 -07:00
if ( fCheckpointsEnabled )
2015-04-22 20:22:36 -07:00
{
// Don't accept any forks from the main chain prior to last checkpoint
CBlockIndex * pcheckpoint = Checkpoints : : GetLastCheckpoint ( chainParams . Checkpoints ( ) ) ;
if ( pcheckpoint & & nHeight < pcheckpoint - > nHeight )
return state . DoS ( 100 , error ( " %s: forked chain older than last checkpoint (height %d) " , __func__ , nHeight ) ) ;
}
2014-10-19 16:09:50 -07:00
2016-06-14 08:48:02 -07:00
// Reject block.nVersion < 4 blocks
if ( block . nVersion < 4 )
return state . Invalid ( error ( " %s : rejected nVersion<4 block " , __func__ ) ,
2015-06-28 11:30:50 -07:00
REJECT_OBSOLETE , " bad-version " ) ;
2014-10-19 16:09:50 -07:00
return true ;
}
2019-03-14 04:18:32 -07:00
bool ContextualCheckBlock (
const CBlock & block , CValidationState & state ,
const CChainParams & chainparams , CBlockIndex * const pindexPrev )
2014-10-19 16:09:50 -07:00
{
const int nHeight = pindexPrev = = NULL ? 0 : pindexPrev - > nHeight + 1 ;
2019-03-14 04:18:32 -07:00
const Consensus : : Params & consensusParams = chainparams . GetConsensus ( ) ;
2014-10-19 16:09:50 -07:00
// Check that all transactions are finalized
2015-06-03 12:55:45 -07:00
BOOST_FOREACH ( const CTransaction & tx , block . vtx ) {
2018-02-15 22:19:36 -08:00
// Check transaction contextually against consensus rules at block height
2019-03-14 04:18:32 -07:00
if ( ! ContextualCheckTransaction ( tx , state , chainparams , nHeight , 100 ) ) {
2018-02-15 22:19:36 -08:00
return false ; // Failure reason has been set in validation state object
}
2015-06-03 12:55:45 -07:00
int nLockTimeFlags = 0 ;
int64_t nLockTimeCutoff = ( nLockTimeFlags & LOCKTIME_MEDIAN_TIME_PAST )
? pindexPrev - > GetMedianTimePast ( )
: block . GetBlockTime ( ) ;
if ( ! IsFinalTx ( tx , nHeight , nLockTimeCutoff ) ) {
2015-01-08 02:44:25 -08:00
return state . DoS ( 10 , error ( " %s: contains a non-final transaction " , __func__ ) , REJECT_INVALID , " bad-txns-nonfinal " ) ;
2014-10-19 16:09:50 -07:00
}
2015-06-03 12:55:45 -07:00
}
2014-10-19 16:09:50 -07:00
2017-06-07 07:29:58 -07:00
// Enforce BIP 34 rule that the coinbase starts with serialized block height.
// In Zcash this has been enforced since launch, except that the genesis
// block didn't include the height in the coinbase (see Zcash protocol spec
// section '6.8 Bitcoin Improvement Proposals').
2016-11-01 17:58:56 -07:00
if ( nHeight > 0 )
2014-10-19 16:09:50 -07:00
{
CScript expect = CScript ( ) < < nHeight ;
if ( block . vtx [ 0 ] . vin [ 0 ] . scriptSig . size ( ) < expect . size ( ) | |
! std : : equal ( expect . begin ( ) , expect . end ( ) , block . vtx [ 0 ] . vin [ 0 ] . scriptSig . begin ( ) ) ) {
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " %s: block height mismatch in coinbase " , __func__ ) , REJECT_INVALID , " bad-cb-height " ) ;
2014-10-19 16:09:50 -07:00
}
}
2016-04-08 12:45:19 -07:00
// Coinbase transaction must include an output sending 20% of
2016-09-29 19:37:38 -07:00
// the block reward to a founders reward script, until the last founders
// reward block is reached, with exception of the genesis block.
// The last founders reward block is defined as the block just before the
// first subsidy halving block, which occurs at halving_interval + slow_start_shift
2016-09-21 12:02:36 -07:00
if ( ( nHeight > 0 ) & & ( nHeight < = consensusParams . GetLastFoundersRewardBlockHeight ( ) ) ) {
2016-04-08 12:45:19 -07:00
bool found = false ;
BOOST_FOREACH ( const CTxOut & output , block . vtx [ 0 ] . vout ) {
2019-03-14 04:18:32 -07:00
if ( output . scriptPubKey = = chainparams . GetFoundersRewardScriptAtHeight ( nHeight ) ) {
2016-04-08 12:45:19 -07:00
if ( output . nValue = = ( GetBlockSubsidy ( nHeight , consensusParams ) / 5 ) ) {
found = true ;
break ;
}
}
}
if ( ! found ) {
return state . DoS ( 100 , error ( " %s: founders reward missing " , __func__ ) , REJECT_INVALID , " cb-no-founders-reward " ) ;
}
}
2014-10-19 16:09:50 -07:00
return true ;
}
2015-11-10 10:28:56 -08:00
static bool AcceptBlockHeader ( const CBlockHeader & block , CValidationState & state , const CChainParams & chainparams , CBlockIndex * * ppindex = NULL )
2010-08-29 09:58:15 -07:00
{
2014-04-15 03:43:17 -07:00
AssertLockHeld ( cs_main ) ;
2010-08-29 09:58:15 -07:00
// Check for duplicate
2013-06-23 19:27:02 -07:00
uint256 hash = block . GetHash ( ) ;
2014-09-03 17:02:44 -07:00
BlockMap : : iterator miSelf = mapBlockIndex . find ( hash ) ;
2014-03-12 19:48:27 -07:00
CBlockIndex * pindex = NULL ;
if ( miSelf ! = mapBlockIndex . end ( ) ) {
2014-07-11 15:02:35 -07:00
// Block header is already known.
2014-03-12 19:48:27 -07:00
pindex = miSelf - > second ;
2014-07-11 15:02:35 -07:00
if ( ppindex )
* ppindex = pindex ;
2014-03-12 19:48:27 -07:00
if ( pindex - > nStatus & BLOCK_FAILED_MASK )
2015-01-08 02:44:25 -08:00
return state . Invalid ( error ( " %s: block is marked invalid " , __func__ ) , 0 , " duplicate " ) ;
2014-07-11 15:02:35 -07:00
return true ;
2014-03-12 19:48:27 -07:00
}
2010-08-29 09:58:15 -07:00
2019-03-14 04:02:47 -07:00
if ( ! CheckBlockHeader ( block , state , chainparams ) )
2014-11-19 23:28:19 -08:00
return false ;
2010-08-29 09:58:15 -07:00
// Get prev block index
2012-10-21 12:23:13 -07:00
CBlockIndex * pindexPrev = NULL ;
2015-04-09 06:58:34 -07:00
if ( hash ! = chainparams . GetConsensus ( ) . hashGenesisBlock ) {
2014-09-03 17:02:44 -07:00
BlockMap : : iterator mi = mapBlockIndex . find ( block . hashPrevBlock ) ;
2012-11-10 05:26:34 -08:00
if ( mi = = mapBlockIndex . end ( ) )
2015-01-08 02:44:25 -08:00
return state . DoS ( 10 , error ( " %s: prev block not found " , __func__ ) , 0 , " bad-prevblk " ) ;
2012-11-10 05:26:34 -08:00
pindexPrev = ( * mi ) . second ;
2014-12-11 04:35:14 -08:00
if ( pindexPrev - > nStatus & BLOCK_FAILED_MASK )
2015-01-08 02:44:25 -08:00
return state . DoS ( 100 , error ( " %s: prev block invalid " , __func__ ) , REJECT_INVALID , " bad-prevblk " ) ;
2014-03-12 19:48:27 -07:00
}
2019-03-14 04:18:32 -07:00
if ( ! ContextualCheckBlockHeader ( block , state , chainparams , pindexPrev ) )
2014-10-19 16:09:50 -07:00
return false ;
2014-03-12 19:48:27 -07:00
if ( pindex = = NULL )
pindex = AddToBlockIndex ( block ) ;
if ( ppindex )
* ppindex = pindex ;
return true ;
}
2015-04-17 05:40:24 -07:00
/**
* Store block on disk .
* JoinSplit proofs are never verified , because :
* - AcceptBlock doesn ' t perform script checks either .
* - The only caller of AcceptBlock verifies JoinSplit proofs elsewhere .
* If dbp is non - NULL , the file is known to already reside on disk
*/
static bool AcceptBlock ( const CBlock & block , CValidationState & state , const CChainParams & chainparams , CBlockIndex * * ppindex , bool fRequested , CDiskBlockPos * dbp )
2014-03-12 19:48:27 -07:00
{
AssertLockHeld ( cs_main ) ;
CBlockIndex * & pindex = * ppindex ;
2015-11-10 10:28:56 -08:00
if ( ! AcceptBlockHeader ( block , state , chainparams , & pindex ) )
2014-03-12 19:48:27 -07:00
return false ;
2015-04-09 10:21:11 -07:00
// Try to process all requested blocks that we don't have, but only
// process an unrequested block if it's new and has enough work to
2015-06-02 12:17:36 -07:00
// advance our tip, and isn't too many blocks ahead.
2015-04-09 10:21:11 -07:00
bool fAlreadyHave = pindex - > nStatus & BLOCK_HAVE_DATA ;
bool fHasMoreWork = ( chainActive . Tip ( ) ? pindex - > nChainWork > chainActive . Tip ( ) - > nChainWork : true ) ;
2015-06-02 12:17:36 -07:00
// Blocks that are too out-of-order needlessly limit the effectiveness of
// pruning, because pruning will not delete block files that contain any
// blocks which are too close in height to the tip. Apply this test
// regardless of whether pruning is enabled; it should generally be safe to
// not process unrequested blocks.
bool fTooFarAhead = ( pindex - > nHeight > int ( chainActive . Height ( ) + MIN_BLOCKS_TO_KEEP ) ) ;
2015-04-09 10:21:11 -07:00
// TODO: deal better with return value and error conditions for duplicate
// and unrequested blocks.
if ( fAlreadyHave ) return true ;
if ( ! fRequested ) { // If we didn't ask for it:
if ( pindex - > nTx ! = 0 ) return true ; // This is a previously-processed block that was pruned
if ( ! fHasMoreWork ) return true ; // Don't process less-work chains
2015-06-02 12:17:36 -07:00
if ( fTooFarAhead ) return true ; // Block height is too high
2014-07-11 15:02:35 -07:00
}
2016-11-22 20:04:20 -08:00
// See method docstring for why this is always disabled
auto verifier = libzcash : : ProofVerifier : : Disabled ( ) ;
2019-03-14 04:18:32 -07:00
if ( ( ! CheckBlock ( block , state , chainparams , verifier ) ) | | ! ContextualCheckBlock ( block , state , chainparams , pindex - > pprev ) ) {
2014-07-14 18:24:21 -07:00
if ( state . IsInvalid ( ) & & ! state . CorruptionPossible ( ) ) {
2014-03-12 19:48:27 -07:00
pindex - > nStatus | = BLOCK_FAILED_VALID ;
Improve chainstate/blockindex disk writing policy
There are 3 pieces of data that are maintained on disk. The actual block
and undo data, the block index (which can refer to positions on disk),
and the chainstate (which refers to the best block hash).
Earlier, there was no guarantee that blocks were written to disk before
block index entries referring to them were written. This commit introduces
dirty flags for block index data, and delays writing entries until the actual
block data is flushed.
With this stricter ordering in writes, it is now safe to not always flush
after every block, so there is no need for the IsInitialBlockDownload()
check there - instead we just write whenever enough time has passed or
the cache size grows too large. Also updating the wallet's best known block
is delayed until this is done, otherwise the wallet may end up referring to an
unknown block.
In addition, only do a write inside the block processing loop if necessary
(because of cache size exceeded). Otherwise, move the writing to a point
after processing is done, after relaying.
2014-11-07 02:38:35 -08:00
setDirtyBlockIndex . insert ( pindex ) ;
2014-03-12 19:48:27 -07:00
}
return false ;
}
int nHeight = pindex - > nHeight ;
2010-08-29 09:58:15 -07:00
// Write block to history file
2013-01-28 16:44:19 -08:00
try {
2013-06-23 19:27:02 -07:00
unsigned int nBlockSize = : : GetSerializeSize ( block , SER_DISK , CLIENT_VERSION ) ;
2013-01-28 16:44:19 -08:00
CDiskBlockPos blockPos ;
if ( dbp ! = NULL )
blockPos = * dbp ;
2014-06-28 14:36:06 -07:00
if ( ! FindBlockPos ( state , blockPos , nBlockSize + 8 , nHeight , block . GetBlockTime ( ) , dbp ! = NULL ) )
2015-01-08 02:44:25 -08:00
return error ( " AcceptBlock() : FindBlockPos failed " ) ;
2013-01-28 16:44:19 -08:00
if ( dbp = = NULL )
2015-04-19 14:48:25 -07:00
if ( ! WriteBlockToDisk ( block , blockPos , chainparams . MessageStart ( ) ) )
2015-01-16 15:57:14 -08:00
AbortNode ( state , " Failed to write block " ) ;
2014-03-12 19:48:27 -07:00
if ( ! ReceivedBlockTransactions ( block , state , pindex , blockPos ) )
2015-01-08 02:44:25 -08:00
return error ( " AcceptBlock() : ReceivedBlockTransactions failed " ) ;
2014-12-07 04:29:06 -08:00
} catch ( const std : : runtime_error & e ) {
2015-01-16 15:57:14 -08:00
return AbortNode ( state , std : : string ( " System error: " ) + e . what ( ) ) ;
2013-01-28 16:44:19 -08:00
}
2010-08-29 09:58:15 -07:00
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
if ( fCheckForPruning )
FlushStateToDisk ( state , FLUSH_STATE_NONE ) ; // we just allocated more disk space for block files
2010-08-29 09:58:15 -07:00
return true ;
}
2015-04-01 07:10:37 -07:00
static bool IsSuperMajority ( int minVersion , const CBlockIndex * pstart , unsigned nRequired , const Consensus : : Params & consensusParams )
2012-06-27 16:30:39 -07:00
{
unsigned int nFound = 0 ;
2015-04-01 07:10:37 -07:00
for ( int i = 0 ; i < consensusParams . nMajorityWindow & & nFound < nRequired & & pstart ! = NULL ; i + + )
2012-06-27 16:30:39 -07:00
{
if ( pstart - > nVersion > = minVersion )
+ + nFound ;
pstart = pstart - > pprev ;
}
return ( nFound > = nRequired ) ;
}
2014-06-24 15:56:47 -07:00
2015-04-19 15:17:11 -07:00
bool ProcessNewBlock ( CValidationState & state , const CChainParams & chainparams , const CNode * pfrom , const CBlock * pblock , bool fForceProcessing , CDiskBlockPos * dbp )
2010-08-29 09:58:15 -07:00
{
// Preliminary checks
2016-11-22 20:04:20 -08:00
auto verifier = libzcash : : ProofVerifier : : Disabled ( ) ;
2019-03-14 04:02:47 -07:00
bool checked = CheckBlock ( * pblock , state , chainparams , verifier ) ;
2010-08-29 09:58:15 -07:00
{
2014-07-11 15:02:35 -07:00
LOCK ( cs_main ) ;
2015-04-09 10:21:11 -07:00
bool fRequested = MarkBlockAsReceived ( pblock - > GetHash ( ) ) ;
fRequested | = fForceProcessing ;
2014-07-11 15:02:35 -07:00
if ( ! checked ) {
2015-01-08 02:44:25 -08:00
return error ( " %s: CheckBlock FAILED " , __func__ ) ;
2012-08-21 10:18:53 -07:00
}
2010-08-29 09:58:15 -07:00
2014-07-11 15:02:35 -07:00
// Store to disk
CBlockIndex * pindex = NULL ;
2015-04-17 05:40:24 -07:00
bool ret = AcceptBlock ( * pblock , state , chainparams , & pindex , fRequested , dbp ) ;
2014-07-11 15:02:35 -07:00
if ( pindex & & pfrom ) {
mapBlockSource [ pindex - > GetBlockHash ( ) ] = pfrom - > GetId ( ) ;
2010-08-29 09:58:15 -07:00
}
2015-04-17 05:19:21 -07:00
CheckBlockIndex ( chainparams . GetConsensus ( ) ) ;
2014-07-11 15:02:35 -07:00
if ( ! ret )
2015-01-08 02:44:25 -08:00
return error ( " %s: AcceptBlock FAILED " , __func__ ) ;
2014-05-07 08:10:35 -07:00
}
2015-04-17 05:40:24 -07:00
if ( ! ActivateBestChain ( state , chainparams , pblock ) )
2015-01-08 02:44:25 -08:00
return error ( " %s: ActivateBestChain failed " , __func__ ) ;
2014-05-07 08:10:35 -07:00
2010-08-29 09:58:15 -07:00
return true ;
}
2015-04-19 15:17:11 -07:00
bool TestBlockValidity ( CValidationState & state , const CChainParams & chainparams , const CBlock & block , CBlockIndex * pindexPrev , bool fCheckPOW , bool fCheckMerkleRoot )
2014-10-19 19:10:03 -07:00
{
AssertLockHeld ( cs_main ) ;
assert ( pindexPrev = = chainActive . Tip ( ) ) ;
CCoinsViewCache viewNew ( pcoinsTip ) ;
CBlockIndex indexDummy ( block ) ;
indexDummy . pprev = pindexPrev ;
indexDummy . nHeight = pindexPrev - > nHeight + 1 ;
2016-11-22 20:04:20 -08:00
// JoinSplit proofs are verified in ConnectBlock
auto verifier = libzcash : : ProofVerifier : : Disabled ( ) ;
2014-10-19 19:10:03 -07:00
// NOTE: CheckBlockHeader is called by CheckBlock
2019-03-14 04:18:32 -07:00
if ( ! ContextualCheckBlockHeader ( block , state , chainparams , pindexPrev ) )
2014-10-19 19:10:03 -07:00
return false ;
2019-03-14 04:02:47 -07:00
if ( ! CheckBlock ( block , state , chainparams , verifier , fCheckPOW , fCheckMerkleRoot ) )
2014-10-19 19:10:03 -07:00
return false ;
2019-03-14 04:18:32 -07:00
if ( ! ContextualCheckBlock ( block , state , chainparams , pindexPrev ) )
2014-10-19 19:10:03 -07:00
return false ;
2016-04-19 06:16:39 -07:00
if ( ! ConnectBlock ( block , state , & indexDummy , viewNew , chainparams , true ) )
2014-10-19 19:10:03 -07:00
return false ;
assert ( state . IsValid ( ) ) ;
return true ;
}
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
/**
* BLOCK PRUNING CODE
*/
/* Calculate the amount of disk space the block & undo files currently use */
uint64_t CalculateCurrentUsage ( )
{
uint64_t retval = 0 ;
BOOST_FOREACH ( const CBlockFileInfo & file , vinfoBlockFile ) {
retval + = file . nSize + file . nUndoSize ;
}
return retval ;
}
/* Prune a block file (modify associated database entries)*/
void PruneOneBlockFile ( const int fileNumber )
{
for ( BlockMap : : iterator it = mapBlockIndex . begin ( ) ; it ! = mapBlockIndex . end ( ) ; + + it ) {
CBlockIndex * pindex = it - > second ;
if ( pindex - > nFile = = fileNumber ) {
pindex - > nStatus & = ~ BLOCK_HAVE_DATA ;
pindex - > nStatus & = ~ BLOCK_HAVE_UNDO ;
pindex - > nFile = 0 ;
pindex - > nDataPos = 0 ;
pindex - > nUndoPos = 0 ;
setDirtyBlockIndex . insert ( pindex ) ;
// Prune from mapBlocksUnlinked -- any block we prune would have
// to be downloaded again in order to consider its chain, at which
// point it would be considered as a candidate for
// mapBlocksUnlinked or setBlockIndexCandidates.
std : : pair < std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator , std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator > range = mapBlocksUnlinked . equal_range ( pindex - > pprev ) ;
while ( range . first ! = range . second ) {
std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator it = range . first ;
range . first + + ;
if ( it - > second = = pindex ) {
mapBlocksUnlinked . erase ( it ) ;
}
}
}
}
vinfoBlockFile [ fileNumber ] . SetNull ( ) ;
setDirtyFileInfo . insert ( fileNumber ) ;
}
void UnlinkPrunedFiles ( std : : set < int > & setFilesToPrune )
{
for ( set < int > : : iterator it = setFilesToPrune . begin ( ) ; it ! = setFilesToPrune . end ( ) ; + + it ) {
CDiskBlockPos pos ( * it , 0 ) ;
boost : : filesystem : : remove ( GetBlockPosFilename ( pos , " blk " ) ) ;
boost : : filesystem : : remove ( GetBlockPosFilename ( pos , " rev " ) ) ;
LogPrintf ( " Prune: %s deleted blk/rev (%05u) \n " , __func__ , * it ) ;
}
}
/* Calculate the block/rev files that should be deleted to remain under target*/
2015-04-17 05:40:24 -07:00
void FindFilesToPrune ( std : : set < int > & setFilesToPrune , uint64_t nPruneAfterHeight )
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
{
LOCK2 ( cs_main , cs_LastBlockFile ) ;
if ( chainActive . Tip ( ) = = NULL | | nPruneTarget = = 0 ) {
return ;
}
2015-04-17 05:40:24 -07:00
if ( chainActive . Tip ( ) - > nHeight < = nPruneAfterHeight ) {
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
return ;
}
2015-04-23 06:40:21 -07:00
unsigned int nLastBlockWeCanPrune = chainActive . Tip ( ) - > nHeight - MIN_BLOCKS_TO_KEEP ;
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
uint64_t nCurrentUsage = CalculateCurrentUsage ( ) ;
// We don't check to prune until after we've allocated new space for files
// So we should leave a buffer under our target to account for another allocation
// before the next pruning.
uint64_t nBuffer = BLOCKFILE_CHUNK_SIZE + UNDOFILE_CHUNK_SIZE ;
uint64_t nBytesToPrune ;
int count = 0 ;
if ( nCurrentUsage + nBuffer > = nPruneTarget ) {
for ( int fileNumber = 0 ; fileNumber < nLastBlockFile ; fileNumber + + ) {
nBytesToPrune = vinfoBlockFile [ fileNumber ] . nSize + vinfoBlockFile [ fileNumber ] . nUndoSize ;
if ( vinfoBlockFile [ fileNumber ] . nSize = = 0 )
continue ;
if ( nCurrentUsage + nBuffer < nPruneTarget ) // are we below our target?
break ;
2015-06-02 12:24:53 -07:00
// don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning
2015-04-23 06:40:21 -07:00
if ( vinfoBlockFile [ fileNumber ] . nHeightLast > nLastBlockWeCanPrune )
2015-06-02 12:24:53 -07:00
continue ;
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
PruneOneBlockFile ( fileNumber ) ;
// Queue up the files for removal
setFilesToPrune . insert ( fileNumber ) ;
nCurrentUsage - = nBytesToPrune ;
count + + ;
}
}
2015-04-23 06:40:21 -07:00
LogPrint ( " prune " , " Prune: target=%dMiB actual=%dMiB diff=%dMiB max_prune_height=%d removed %d blk/rev pairs \n " ,
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
nPruneTarget / 1024 / 1024 , nCurrentUsage / 1024 / 1024 ,
( ( int64_t ) nPruneTarget - ( int64_t ) nCurrentUsage ) / 1024 / 1024 ,
2015-04-23 06:40:21 -07:00
nLastBlockWeCanPrune , count ) ;
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
}
2013-04-12 22:13:08 -07:00
bool CheckDiskSpace ( uint64_t nAdditionalBytes )
2010-08-29 09:58:15 -07:00
{
2014-12-19 12:21:29 -08:00
uint64_t nFreeBytesAvailable = boost : : filesystem : : space ( GetDataDir ( ) ) . available ;
2010-08-29 09:58:15 -07:00
2012-05-13 22:49:17 -07:00
// Check for nMinDiskSpace bytes (currently 50MB)
if ( nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes )
2014-10-02 13:17:57 -07:00
return AbortNode ( " Disk space is low! " , _ ( " Error: Disk space is low! " ) ) ;
2013-01-26 16:24:06 -08:00
2010-08-29 09:58:15 -07:00
return true ;
}
2012-08-13 10:11:05 -07:00
FILE * OpenDiskFile ( const CDiskBlockPos & pos , const char * prefix , bool fReadOnly )
2012-09-04 18:40:26 -07:00
{
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
if ( pos . IsNull ( ) )
2010-08-29 09:58:15 -07:00
return NULL ;
2014-09-08 10:29:14 -07:00
boost : : filesystem : : path path = GetBlockPosFilename ( pos , prefix ) ;
2012-08-13 10:11:05 -07:00
boost : : filesystem : : create_directories ( path . parent_path ( ) ) ;
FILE * file = fopen ( path . string ( ) . c_str ( ) , " rb+ " ) ;
if ( ! file & & ! fReadOnly )
file = fopen ( path . string ( ) . c_str ( ) , " wb+ " ) ;
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
if ( ! file ) {
2014-01-16 07:15:27 -08:00
LogPrintf ( " Unable to open file %s \n " , path . string ( ) ) ;
2010-08-29 09:58:15 -07:00
return NULL ;
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
2012-07-01 09:54:00 -07:00
}
2012-08-13 10:11:05 -07:00
if ( pos . nPos ) {
if ( fseek ( file , pos . nPos , SEEK_SET ) ) {
2014-01-16 07:15:27 -08:00
LogPrintf ( " Unable to seek to position %u of %s \n " , pos . nPos , path . string ( ) ) ;
2012-08-13 10:11:05 -07:00
fclose ( file ) ;
return NULL ;
}
}
2010-08-29 09:58:15 -07:00
return file ;
}
2012-08-13 10:11:05 -07:00
FILE * OpenBlockFile ( const CDiskBlockPos & pos , bool fReadOnly ) {
return OpenDiskFile ( pos , " blk " , fReadOnly ) ;
}
2013-01-18 06:07:05 -08:00
FILE * OpenUndoFile ( const CDiskBlockPos & pos , bool fReadOnly ) {
2012-08-13 10:11:05 -07:00
return OpenDiskFile ( pos , " rev " , fReadOnly ) ;
}
2014-09-08 10:29:14 -07:00
boost : : filesystem : : path GetBlockPosFilename ( const CDiskBlockPos & pos , const char * prefix )
{
2014-09-15 06:56:10 -07:00
return GetDataDir ( ) / " blocks " / strprintf ( " %s%05u.dat " , prefix , pos . nFile ) ;
2014-09-08 10:29:14 -07:00
}
2012-09-03 12:14:03 -07:00
CBlockIndex * InsertBlockIndex ( uint256 hash )
{
2014-12-15 00:11:16 -08:00
if ( hash . IsNull ( ) )
2012-09-03 12:14:03 -07:00
return NULL ;
// Return existing
2014-09-03 17:02:44 -07:00
BlockMap : : iterator mi = mapBlockIndex . find ( hash ) ;
2012-09-03 12:14:03 -07:00
if ( mi ! = mapBlockIndex . end ( ) )
return ( * mi ) . second ;
// Create new
CBlockIndex * pindexNew = new CBlockIndex ( ) ;
if ( ! pindexNew )
2015-01-08 02:44:25 -08:00
throw runtime_error ( " LoadBlockIndex() : new CBlockIndex failed " ) ;
2012-09-03 12:14:03 -07:00
mi = mapBlockIndex . insert ( make_pair ( hash , pindexNew ) ) . first ;
pindexNew - > phashBlock = & ( ( * mi ) . first ) ;
return pindexNew ;
}
bool static LoadBlockIndexDB ( )
{
2015-04-22 15:19:11 -07:00
const CChainParams & chainparams = Params ( ) ;
2016-04-05 06:14:48 -07:00
if ( ! pblocktree - > LoadBlockIndexGuts ( InsertBlockIndex ) )
2012-09-03 12:14:03 -07:00
return false ;
2013-03-09 09:02:57 -08:00
boost : : this_thread : : interruption_point ( ) ;
2012-09-03 12:14:03 -07:00
2013-03-28 15:51:50 -07:00
// Calculate nChainWork
2012-09-03 12:14:03 -07:00
vector < pair < int , CBlockIndex * > > vSortedByHeight ;
vSortedByHeight . reserve ( mapBlockIndex . size ( ) ) ;
BOOST_FOREACH ( const PAIRTYPE ( uint256 , CBlockIndex * ) & item , mapBlockIndex )
{
CBlockIndex * pindex = item . second ;
vSortedByHeight . push_back ( make_pair ( pindex - > nHeight , pindex ) ) ;
}
sort ( vSortedByHeight . begin ( ) , vSortedByHeight . end ( ) ) ;
BOOST_FOREACH ( const PAIRTYPE ( int , CBlockIndex * ) & item , vSortedByHeight )
{
CBlockIndex * pindex = item . second ;
2014-10-29 09:00:02 -07:00
pindex - > nChainWork = ( pindex - > pprev ? pindex - > pprev - > nChainWork : 0 ) + GetBlockProof ( * pindex ) ;
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
// We can link the chain of blocks for which we've received transactions at some point.
// Pruned nodes may have deleted the block.
if ( pindex - > nTx > 0 ) {
2014-07-11 15:02:35 -07:00
if ( pindex - > pprev ) {
if ( pindex - > pprev - > nChainTx ) {
pindex - > nChainTx = pindex - > pprev - > nChainTx + pindex - > nTx ;
2017-11-09 14:09:54 -08:00
if ( pindex - > pprev - > nChainSproutValue & & pindex - > nSproutValue ) {
pindex - > nChainSproutValue = * pindex - > pprev - > nChainSproutValue + * pindex - > nSproutValue ;
} else {
pindex - > nChainSproutValue = boost : : none ;
}
2018-05-09 04:15:46 -07:00
if ( pindex - > pprev - > nChainSaplingValue ) {
pindex - > nChainSaplingValue = * pindex - > pprev - > nChainSaplingValue + pindex - > nSaplingValue ;
} else {
pindex - > nChainSaplingValue = boost : : none ;
}
2014-07-11 15:02:35 -07:00
} else {
pindex - > nChainTx = 0 ;
2017-11-09 14:09:54 -08:00
pindex - > nChainSproutValue = boost : : none ;
2018-05-09 04:15:46 -07:00
pindex - > nChainSaplingValue = boost : : none ;
2014-07-11 15:02:35 -07:00
mapBlocksUnlinked . insert ( std : : make_pair ( pindex - > pprev , pindex ) ) ;
}
} else {
pindex - > nChainTx = pindex - > nTx ;
2017-11-09 14:09:54 -08:00
pindex - > nChainSproutValue = pindex - > nSproutValue ;
2018-05-09 04:15:46 -07:00
pindex - > nChainSaplingValue = pindex - > nSaplingValue ;
2014-07-11 15:02:35 -07:00
}
2019-03-12 23:43:54 -07:00
2019-03-14 13:20:51 -07:00
// Fall back to hardcoded Sprout value pool balance
FallbackSproutValuePoolBalance ( pindex , chainparams ) ;
2019-04-19 10:54:51 -07:00
2019-04-24 08:40:17 -07:00
// If developer option -developersetpoolsizezero has been enabled,
2019-04-19 10:54:51 -07:00
// override and set the in-memory size of shielded pools to zero. An unshielding transaction
// can then be used to trigger and test the handling of turnstile violations.
2019-04-24 08:40:17 -07:00
if ( fExperimentalMode & & mapArgs . count ( " -developersetpoolsizezero " ) ) {
2019-04-19 10:54:51 -07:00
pindex - > nChainSproutValue = 0 ;
pindex - > nChainSaplingValue = 0 ;
}
2014-07-11 15:02:35 -07:00
}
2018-01-27 15:37:43 -08:00
// Construct in-memory chain of branch IDs.
// Relies on invariant: a block that does not activate a network upgrade
// will always be valid under the same consensus rules as its parent.
2018-02-06 04:39:20 -08:00
// Genesis block has a branch ID of zero by definition, but has no
// validity status because it is side-loaded into a fresh chain.
// Activation blocks will have branch IDs set (read from disk).
if ( pindex - > pprev ) {
if ( pindex - > IsValid ( BLOCK_VALID_CONSENSUS ) & & ! pindex - > nCachedBranchId ) {
pindex - > nCachedBranchId = pindex - > pprev - > nCachedBranchId ;
}
} else {
2018-02-01 17:49:42 -08:00
pindex - > nCachedBranchId = SPROUT_BRANCH_ID ;
2018-01-27 15:37:43 -08:00
}
2014-07-11 15:02:35 -07:00
if ( pindex - > IsValid ( BLOCK_VALID_TRANSACTIONS ) & & ( pindex - > nChainTx | | pindex - > pprev = = NULL ) )
2014-10-05 23:31:33 -07:00
setBlockIndexCandidates . insert ( pindex ) ;
2013-10-13 13:15:48 -07:00
if ( pindex - > nStatus & BLOCK_FAILED_MASK & & ( ! pindexBestInvalid | | pindex - > nChainWork > pindexBestInvalid - > nChainWork ) )
pindexBestInvalid = pindex ;
2014-06-24 15:56:47 -07:00
if ( pindex - > pprev )
pindex - > BuildSkip ( ) ;
2014-07-11 15:02:35 -07:00
if ( pindex - > IsValid ( BLOCK_VALID_TREE ) & & ( pindexBestHeader = = NULL | | CBlockIndexWorkComparator ( ) ( pindexBestHeader , pindex ) ) )
pindexBestHeader = pindex ;
2012-09-03 12:14:03 -07:00
}
// Load block file info
pblocktree - > ReadLastBlockFile ( nLastBlockFile ) ;
2014-09-24 23:21:21 -07:00
vinfoBlockFile . resize ( nLastBlockFile + 1 ) ;
2014-10-21 16:17:13 -07:00
LogPrintf ( " %s: last block file = %i \n " , __func__ , nLastBlockFile ) ;
2014-09-24 23:21:21 -07:00
for ( int nFile = 0 ; nFile < = nLastBlockFile ; nFile + + ) {
pblocktree - > ReadBlockFileInfo ( nFile , vinfoBlockFile [ nFile ] ) ;
}
2014-10-21 16:17:13 -07:00
LogPrintf ( " %s: last block file info: %s \n " , __func__ , vinfoBlockFile [ nLastBlockFile ] . ToString ( ) ) ;
2014-09-24 23:21:21 -07:00
for ( int nFile = nLastBlockFile + 1 ; true ; nFile + + ) {
CBlockFileInfo info ;
if ( pblocktree - > ReadBlockFileInfo ( nFile , info ) ) {
vinfoBlockFile . push_back ( info ) ;
} else {
break ;
}
}
2012-10-05 10:22:21 -07:00
2014-05-11 05:05:04 -07:00
// Check presence of blk files
LogPrintf ( " Checking all blk files are present... \n " ) ;
set < int > setBlkDataFiles ;
BOOST_FOREACH ( const PAIRTYPE ( uint256 , CBlockIndex * ) & item , mapBlockIndex )
{
CBlockIndex * pindex = item . second ;
if ( pindex - > nStatus & BLOCK_HAVE_DATA ) {
setBlkDataFiles . insert ( pindex - > nFile ) ;
}
}
for ( std : : set < int > : : iterator it = setBlkDataFiles . begin ( ) ; it ! = setBlkDataFiles . end ( ) ; it + + )
{
CDiskBlockPos pos ( * it , 0 ) ;
2014-10-20 03:45:50 -07:00
if ( CAutoFile ( OpenBlockFile ( pos , true ) , SER_DISK , CLIENT_VERSION ) . IsNull ( ) ) {
2014-05-11 05:05:04 -07:00
return false ;
}
}
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
// Check whether we have ever pruned block & undo files
pblocktree - > ReadFlag ( " prunedblockfiles " , fHavePruned ) ;
if ( fHavePruned )
LogPrintf ( " LoadBlockIndexDB(): Block files have previously been pruned \n " ) ;
2012-12-02 12:59:22 -08:00
// Check whether we need to continue reindexing
bool fReindexing = false ;
pblocktree - > ReadReindexing ( fReindexing ) ;
fReindex | = fReindexing ;
2013-01-10 16:47:57 -08:00
// Check whether we have a transaction index
pblocktree - > ReadFlag ( " txindex " , fTxIndex ) ;
2015-02-25 09:40:32 -08:00
LogPrintf ( " %s: transaction index %s \n " , __func__ , fTxIndex ? " enabled " : " disabled " ) ;
2013-01-10 16:47:57 -08:00
2019-03-19 12:28:02 -07:00
// insightexplorer
// Check whether block explorer features are enabled
pblocktree - > ReadFlag ( " insightexplorer " , fInsightExplorer ) ;
LogPrintf ( " %s: insight explorer %s \n " , __func__ , fAddressIndex ? " enabled " : " disabled " ) ;
fAddressIndex = fInsightExplorer ;
2019-04-23 10:06:23 -07:00
fSpentIndex = fInsightExplorer ;
2019-03-19 12:28:02 -07:00
2017-03-09 23:04:14 -08:00
// Fill in-memory data
BOOST_FOREACH ( const PAIRTYPE ( uint256 , CBlockIndex * ) & item , mapBlockIndex )
{
CBlockIndex * pindex = item . second ;
// - This relationship will always be true even if pprev has multiple
2018-04-25 18:15:30 -07:00
// children, because hashSproutAnchor is technically a property of pprev,
2017-03-09 23:04:14 -08:00
// not its children.
// - This will miss chain tips; we handle the best tip below, and other
// tips will be handled by ConnectTip during a re-org.
if ( pindex - > pprev ) {
2018-05-06 14:21:49 -07:00
pindex - > pprev - > hashFinalSproutRoot = pindex - > hashSproutAnchor ;
2017-03-09 23:04:14 -08:00
}
}
2013-10-13 13:15:48 -07:00
// Load pointer to end of best chain
2014-09-03 17:02:44 -07:00
BlockMap : : iterator it = mapBlockIndex . find ( pcoinsTip - > GetBestBlock ( ) ) ;
2013-11-04 17:27:39 -08:00
if ( it = = mapBlockIndex . end ( ) )
2012-12-02 12:59:22 -08:00
return true ;
2013-11-04 17:27:39 -08:00
chainActive . SetTip ( it - > second ) ;
2018-05-06 14:21:49 -07:00
// Set hashFinalSproutRoot for the end of best chain
it - > second - > hashFinalSproutRoot = pcoinsTip - > GetBestAnchor ( SPROUT ) ;
2014-11-01 14:42:12 -07:00
PruneBlockIndexCandidates ( ) ;
2015-02-25 09:40:32 -08:00
LogPrintf ( " %s: hashBestChain=%s height=%d date=%s progress=%f \n " , __func__ ,
2014-01-16 07:15:27 -08:00
chainActive . Tip ( ) - > GetBlockHash ( ) . ToString ( ) , chainActive . Height ( ) ,
2014-02-18 11:04:06 -08:00
DateTimeStrFormat ( " %Y-%m-%d %H:%M:%S " , chainActive . Tip ( ) - > GetBlockTime ( ) ) ,
2015-04-22 15:19:11 -07:00
Checkpoints : : GuessVerificationProgress ( chainparams . Checkpoints ( ) , chainActive . Tip ( ) ) ) ;
2012-09-03 12:14:03 -07:00
2017-04-24 23:06:29 -07:00
EnforceNodeDeprecation ( chainActive . Height ( ) , true ) ;
2013-01-03 06:29:07 -08:00
return true ;
}
2014-05-23 09:04:09 -07:00
CVerifyDB : : CVerifyDB ( )
{
uiInterface . ShowProgress ( _ ( " Verifying blocks... " ) , 0 ) ;
}
CVerifyDB : : ~ CVerifyDB ( )
{
uiInterface . ShowProgress ( " " , 100 ) ;
}
2015-04-17 05:40:24 -07:00
bool CVerifyDB : : VerifyDB ( const CChainParams & chainparams , CCoinsView * coinsview , int nCheckLevel , int nCheckDepth )
2013-06-19 08:32:49 -07:00
{
2014-05-07 06:12:31 -07:00
LOCK ( cs_main ) ;
2013-10-10 14:07:44 -07:00
if ( chainActive . Tip ( ) = = NULL | | chainActive . Tip ( ) - > pprev = = NULL )
2013-01-03 06:29:07 -08:00
return true ;
2012-09-03 12:14:03 -07:00
// Verify blocks in the best chain
2013-06-19 08:53:02 -07:00
if ( nCheckDepth < = 0 )
2012-09-03 12:14:03 -07:00
nCheckDepth = 1000000000 ; // suffices until the year 19000
2013-10-10 14:07:44 -07:00
if ( nCheckDepth > chainActive . Height ( ) )
nCheckDepth = chainActive . Height ( ) ;
2013-01-03 06:29:07 -08:00
nCheckLevel = std : : max ( 0 , std : : min ( 4 , nCheckLevel ) ) ;
2013-09-18 03:38:08 -07:00
LogPrintf ( " Verifying last %i blocks at level %i \n " , nCheckDepth , nCheckLevel ) ;
2014-09-23 18:19:04 -07:00
CCoinsViewCache coins ( coinsview ) ;
2013-10-10 14:07:44 -07:00
CBlockIndex * pindexState = chainActive . Tip ( ) ;
2013-01-03 06:29:07 -08:00
CBlockIndex * pindexFailure = NULL ;
int nGoodTransactions = 0 ;
2013-01-26 15:14:11 -08:00
CValidationState state ;
2016-11-22 20:04:20 -08:00
// No need to verify JoinSplits twice
auto verifier = libzcash : : ProofVerifier : : Disabled ( ) ;
2013-10-10 14:07:44 -07:00
for ( CBlockIndex * pindex = chainActive . Tip ( ) ; pindex & & pindex - > pprev ; pindex = pindex - > pprev )
2012-09-03 12:14:03 -07:00
{
2013-03-09 09:02:57 -08:00
boost : : this_thread : : interruption_point ( ) ;
2014-05-23 09:04:09 -07:00
uiInterface . ShowProgress ( _ ( " Verifying blocks... " ) , std : : max ( 1 , std : : min ( 99 , ( int ) ( ( ( double ) ( chainActive . Height ( ) - pindex - > nHeight ) ) / ( double ) nCheckDepth * ( nCheckLevel > = 4 ? 50 : 100 ) ) ) ) ) ;
2013-10-10 14:07:44 -07:00
if ( pindex - > nHeight < chainActive . Height ( ) - nCheckDepth )
2012-09-03 12:14:03 -07:00
break ;
CBlock block ;
2013-01-03 06:29:07 -08:00
// check level 0: read from disk
2015-04-17 05:19:21 -07:00
if ( ! ReadBlockFromDisk ( block , pindex , chainparams . GetConsensus ( ) ) )
2015-01-08 02:44:25 -08:00
return error ( " VerifyDB() : * * * ReadBlockFromDisk failed at % d , hash = % s " , pindex->nHeight, pindex->GetBlockHash().ToString()) ;
2012-09-03 12:14:03 -07:00
// check level 1: verify block validity
2019-03-14 04:02:47 -07:00
if ( nCheckLevel > = 1 & & ! CheckBlock ( block , state , chainparams , verifier ) )
2015-01-08 02:44:25 -08:00
return error ( " VerifyDB() : * * * found bad block at % d , hash = % s \ n " , pindex->nHeight, pindex->GetBlockHash().ToString()) ;
2013-01-03 06:29:07 -08:00
// check level 2: verify undo validity
if ( nCheckLevel > = 2 & & pindex ) {
CBlockUndo undo ;
CDiskBlockPos pos = pindex - > GetUndoPos ( ) ;
if ( ! pos . IsNull ( ) ) {
2014-10-27 06:35:52 -07:00
if ( ! UndoReadFromDisk ( undo , pos , pindex - > pprev - > GetBlockHash ( ) ) )
2015-01-08 02:44:25 -08:00
return error ( " VerifyDB() : * * * found bad undo data at % d , hash = % s \ n " , pindex->nHeight, pindex->GetBlockHash().ToString()) ;
2013-01-03 06:29:07 -08:00
}
}
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
2015-05-03 16:38:08 -07:00
if ( nCheckLevel > = 3 & & pindex = = pindexState & & ( coins . DynamicMemoryUsage ( ) + pcoinsTip - > DynamicMemoryUsage ( ) ) < = nCoinCacheUsage ) {
2019-03-19 12:28:02 -07:00
// insightexplorer: do not update indices (false)
2019-03-14 04:24:53 -07:00
DisconnectResult res = DisconnectBlock ( block , state , pindex , coins , chainparams , false ) ;
2017-04-28 16:08:39 -07:00
if ( res = = DISCONNECT_FAILED ) {
2015-01-08 02:44:25 -08:00
return error ( " VerifyDB() : * * * irrecoverable inconsistency in block data at % d , hash = % s " , pindex->nHeight, pindex->GetBlockHash().ToString()) ;
2017-04-28 16:08:39 -07:00
}
2013-01-03 06:29:07 -08:00
pindexState = pindex - > pprev ;
2017-04-28 16:08:39 -07:00
if ( res = = DISCONNECT_UNCLEAN ) {
2013-01-03 06:29:07 -08:00
nGoodTransactions = 0 ;
pindexFailure = pindex ;
2017-04-28 16:08:39 -07:00
} else {
2013-01-03 06:29:07 -08:00
nGoodTransactions + = block . vtx . size ( ) ;
2017-04-28 16:08:39 -07:00
}
2012-09-03 12:14:03 -07:00
}
2014-12-28 13:39:53 -08:00
if ( ShutdownRequested ( ) )
return true ;
2012-09-03 12:14:03 -07:00
}
2013-01-03 06:29:07 -08:00
if ( pindexFailure )
2015-01-08 02:44:25 -08:00
return error ( " VerifyDB() : * * * coin database inconsistencies found ( last % i blocks , % i good transactions before that ) \ n " , chainActive.Height() - pindexFailure->nHeight + 1, nGoodTransactions) ;
2013-01-03 06:29:07 -08:00
// check level 4: try reconnecting blocks
if ( nCheckLevel > = 4 ) {
CBlockIndex * pindex = pindexState ;
2013-10-10 14:07:44 -07:00
while ( pindex ! = chainActive . Tip ( ) ) {
2013-03-09 09:02:57 -08:00
boost : : this_thread : : interruption_point ( ) ;
2014-05-23 09:04:09 -07:00
uiInterface . ShowProgress ( _ ( " Verifying blocks... " ) , std : : max ( 1 , std : : min ( 99 , 100 - ( int ) ( ( ( double ) ( chainActive . Height ( ) - pindex - > nHeight ) ) / ( double ) nCheckDepth * 50 ) ) ) ) ;
2013-10-10 14:07:44 -07:00
pindex = chainActive . Next ( pindex ) ;
2013-04-04 02:30:55 -07:00
CBlock block ;
2015-04-17 05:19:21 -07:00
if ( ! ReadBlockFromDisk ( block , pindex , chainparams . GetConsensus ( ) ) )
2015-01-08 02:44:25 -08:00
return error ( " VerifyDB() : * * * ReadBlockFromDisk failed at % d , hash = % s " , pindex->nHeight, pindex->GetBlockHash().ToString()) ;
2016-04-19 06:16:39 -07:00
if ( ! ConnectBlock ( block , state , pindex , coins , chainparams ) )
2015-01-08 02:44:25 -08:00
return error ( " VerifyDB() : * * * found unconnectable block at % d , hash = % s " , pindex->nHeight, pindex->GetBlockHash().ToString()) ;
2013-01-03 06:29:07 -08:00
}
2012-09-03 12:14:03 -07:00
}
2013-10-10 14:07:44 -07:00
LogPrintf ( " No coin database inconsistencies in last %i blocks (%i transactions) \n " , chainActive . Height ( ) - pindexState - > nHeight , nGoodTransactions ) ;
2013-01-03 06:29:07 -08:00
2012-09-03 12:14:03 -07:00
return true ;
}
2019-04-01 18:07:02 -07:00
bool RewindBlockIndex ( const CChainParams & chainparams , bool & clearWitnessCaches )
2016-03-18 09:20:12 -07:00
{
LOCK ( cs_main ) ;
2018-01-27 15:37:43 -08:00
// RewindBlockIndex is called after LoadBlockIndex, so at this point every block
2018-02-06 04:39:20 -08:00
// index will have nCachedBranchId set based on the values previously persisted
// to disk. By definition, a set nCachedBranchId means that the block was
2018-01-27 15:37:43 -08:00
// fully-validated under the corresponding consensus rules. Thus we can quickly
// identify whether the current active chain matches our expected sequence of
// consensus rule changes, with two checks:
//
// - BLOCK_ACTIVATES_UPGRADE is set only on blocks that activate upgrades.
2018-02-06 04:39:20 -08:00
// - nCachedBranchId for each block matches what we expect.
2019-04-01 18:07:02 -07:00
auto sufficientlyValidated = [ & chainparams ] ( const CBlockIndex * pindex ) {
auto consensus = chainparams . GetConsensus ( ) ;
2018-01-27 15:37:43 -08:00
bool fFlagSet = pindex - > nStatus & BLOCK_ACTIVATES_UPGRADE ;
bool fFlagExpected = IsActivationHeightForAnyUpgrade ( pindex - > nHeight , consensus ) ;
2018-02-06 04:39:20 -08:00
return fFlagSet = = fFlagExpected & &
pindex - > nCachedBranchId & &
* pindex - > nCachedBranchId = = CurrentEpochBranchId ( pindex - > nHeight , consensus ) ;
2018-01-27 15:37:43 -08:00
} ;
2016-03-18 09:20:12 -07:00
int nHeight = 1 ;
while ( nHeight < = chainActive . Height ( ) ) {
2018-01-27 15:37:43 -08:00
if ( ! sufficientlyValidated ( chainActive [ nHeight ] ) ) {
2016-03-18 09:20:12 -07:00
break ;
}
nHeight + + ;
}
// nHeight is now the height of the first insufficiently-validated block, or tipheight + 1
2018-02-03 16:35:41 -08:00
auto rewindLength = chainActive . Height ( ) - nHeight ;
2018-07-31 14:29:14 -07:00
clearWitnessCaches = false ;
if ( rewindLength > 0 ) {
2018-08-08 04:08:29 -07:00
LogPrintf ( " *** First insufficiently validated block at height %d, rewind length %d \n " , nHeight , rewindLength ) ;
2018-07-31 14:29:14 -07:00
const uint256 * phashFirstInsufValidated = chainActive [ nHeight ] - > phashBlock ;
2019-04-01 18:07:02 -07:00
auto networkID = chainparams . NetworkIDString ( ) ;
2018-07-31 14:29:14 -07:00
// This is true when we intend to do a long rewind.
bool intendedRewind =
( networkID = = " test " & & nHeight = = 252500 & & * phashFirstInsufValidated = =
uint256S ( " 0018bd16a9c6f15795a754c498d2b2083ab78f14dae44a66a8d0e90ba8464d9c " ) ) ;
clearWitnessCaches = ( rewindLength > MAX_REORG_LENGTH & & intendedRewind ) ;
if ( clearWitnessCaches ) {
auto msg = strprintf ( _ (
" An intended block chain rewind has been detected: network %s, hash %s, height %d "
) , networkID , phashFirstInsufValidated - > GetHex ( ) , nHeight ) ;
LogPrintf ( " *** %s \n " , msg ) ;
}
if ( rewindLength > MAX_REORG_LENGTH & & ! intendedRewind ) {
auto pindexOldTip = chainActive . Tip ( ) ;
auto pindexRewind = chainActive [ nHeight - 1 ] ;
auto msg = strprintf ( _ (
" A block chain rewind has been detected that would roll back %d blocks! "
" This is larger than the maximum of %d blocks, and so the node is shutting down for your safety. "
) , rewindLength , MAX_REORG_LENGTH ) + " \n \n " +
_ ( " Rewind details " ) + " : \n " +
" - " + strprintf ( _ ( " Current tip: %s, height %d " ) ,
pindexOldTip - > phashBlock - > GetHex ( ) , pindexOldTip - > nHeight ) + " \n " +
" - " + strprintf ( _ ( " Rewinding to: %s, height %d " ) ,
pindexRewind - > phashBlock - > GetHex ( ) , pindexRewind - > nHeight ) + " \n \n " +
_ ( " Please help, human! " ) ;
LogPrintf ( " *** %s \n " , msg ) ;
uiInterface . ThreadSafeMessageBox ( msg , " " , CClientUIInterface : : MSG_ERROR ) ;
StartShutdown ( ) ;
return false ;
}
2018-02-03 16:35:41 -08:00
}
2016-03-18 09:20:12 -07:00
CValidationState state ;
CBlockIndex * pindex = chainActive . Tip ( ) ;
while ( chainActive . Height ( ) > = nHeight ) {
if ( fPruneMode & & ! ( chainActive . Tip ( ) - > nStatus & BLOCK_HAVE_DATA ) ) {
// If pruning, don't try rewinding past the HAVE_DATA point;
// since older blocks can't be served anyway, there's
// no need to walk further, and trying to DisconnectTip()
// will fail (and require a needless reindex/redownload
// of the blockchain).
break ;
}
2019-04-01 18:07:02 -07:00
if ( ! DisconnectTip ( state , chainparams , true ) ) {
2016-03-18 09:20:12 -07:00
return error ( " RewindBlockIndex: unable to disconnect block at height %i " , pindex - > nHeight ) ;
}
// Occasionally flush state to disk.
if ( ! FlushStateToDisk ( state , FLUSH_STATE_PERIODIC ) )
return false ;
}
2018-03-15 03:49:30 -07:00
// Collect blocks to be removed (blocks in mapBlockIndex must be at least BLOCK_VALID_TREE).
2016-03-18 09:20:12 -07:00
// We do this after actual disconnecting, otherwise we'll end up writing the lack of data
// to disk before writing the chainstate, resulting in a failure to continue if interrupted.
2018-03-15 03:49:30 -07:00
std : : vector < const CBlockIndex * > vBlocks ;
2016-03-18 09:20:12 -07:00
for ( BlockMap : : iterator it = mapBlockIndex . begin ( ) ; it ! = mapBlockIndex . end ( ) ; it + + ) {
CBlockIndex * pindexIter = it - > second ;
// Note: If we encounter an insufficiently validated block that
// is on chainActive, it must be because we are a pruning node, and
// this block or some successor doesn't HAVE_DATA, so we were unable to
// rewind all the way. Blocks remaining on chainActive at this point
// must not have their validity reduced.
2018-01-27 15:37:43 -08:00
if ( ! sufficientlyValidated ( pindexIter ) & & ! chainActive . Contains ( pindexIter ) ) {
2018-03-15 03:49:30 -07:00
// Add to the list of blocks to remove
vBlocks . push_back ( pindexIter ) ;
2018-04-11 20:46:58 -07:00
if ( pindexIter = = pindexBestInvalid ) {
// Reset invalid block marker if it was pointing to this block
pindexBestInvalid = NULL ;
}
2018-01-27 15:37:43 -08:00
// Update indices
2016-03-18 09:20:12 -07:00
setBlockIndexCandidates . erase ( pindexIter ) ;
2018-01-27 15:37:43 -08:00
auto ret = mapBlocksUnlinked . equal_range ( pindexIter - > pprev ) ;
2016-03-18 09:20:12 -07:00
while ( ret . first ! = ret . second ) {
if ( ret . first - > second = = pindexIter ) {
mapBlocksUnlinked . erase ( ret . first + + ) ;
} else {
+ + ret . first ;
}
}
} else if ( pindexIter - > IsValid ( BLOCK_VALID_TRANSACTIONS ) & & pindexIter - > nChainTx ) {
setBlockIndexCandidates . insert ( pindexIter ) ;
}
}
2018-03-15 03:49:30 -07:00
// Set pindexBestHeader to the current chain tip
// (since we are about to delete the block it is pointing to)
pindexBestHeader = chainActive . Tip ( ) ;
// Erase block indices on-disk
if ( ! pblocktree - > EraseBatchSync ( vBlocks ) ) {
return AbortNode ( state , " Failed to erase from block index database " ) ;
}
// Erase block indices in-memory
for ( auto pindex : vBlocks ) {
auto ret = mapBlockIndex . find ( * pindex - > phashBlock ) ;
if ( ret ! = mapBlockIndex . end ( ) ) {
mapBlockIndex . erase ( ret ) ;
delete pindex ;
}
}
2016-03-18 09:20:12 -07:00
PruneBlockIndexCandidates ( ) ;
2019-04-01 18:07:02 -07:00
CheckBlockIndex ( chainparams . GetConsensus ( ) ) ;
2016-03-18 09:20:12 -07:00
if ( ! FlushStateToDisk ( state , FLUSH_STATE_ALWAYS ) ) {
return false ;
}
return true ;
}
2013-02-16 08:58:45 -08:00
void UnloadBlockIndex ( )
{
2015-03-03 07:49:12 -08:00
LOCK ( cs_main ) ;
2014-10-05 23:31:33 -07:00
setBlockIndexCandidates . clear ( ) ;
2013-10-10 14:07:44 -07:00
chainActive . SetTip ( NULL ) ;
2013-10-13 13:15:48 -07:00
pindexBestInvalid = NULL ;
2015-03-03 07:49:12 -08:00
pindexBestHeader = NULL ;
mempool . clear ( ) ;
mapOrphanTransactions . clear ( ) ;
mapOrphanTransactionsByPrev . clear ( ) ;
nSyncStarted = 0 ;
mapBlocksUnlinked . clear ( ) ;
vinfoBlockFile . clear ( ) ;
nLastBlockFile = 0 ;
nBlockSequenceId = 1 ;
mapBlockSource . clear ( ) ;
mapBlocksInFlight . clear ( ) ;
nQueuedValidatedHeaders = 0 ;
nPreferredDownload = 0 ;
setDirtyBlockIndex . clear ( ) ;
setDirtyFileInfo . clear ( ) ;
mapNodeState . clear ( ) ;
2015-07-17 03:46:48 -07:00
recentRejects . reset ( NULL ) ;
2015-03-03 07:49:12 -08:00
BOOST_FOREACH ( BlockMap : : value_type & entry , mapBlockIndex ) {
delete entry . second ;
}
mapBlockIndex . clear ( ) ;
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
fHavePruned = false ;
2013-02-16 08:58:45 -08:00
}
2012-10-21 12:23:13 -07:00
bool LoadBlockIndex ( )
2010-08-29 09:58:15 -07:00
{
2012-09-03 06:26:57 -07:00
// Load block index from databases
2013-01-10 16:47:57 -08:00
if ( ! fReindex & & ! LoadBlockIndexDB ( ) )
2010-08-29 09:58:15 -07:00
return false ;
2013-01-30 12:43:36 -08:00
return true ;
}
2013-01-10 16:47:57 -08:00
2015-04-17 05:40:24 -07:00
bool InitBlockIndex ( const CChainParams & chainparams )
{
2014-04-15 08:38:25 -07:00
LOCK ( cs_main ) ;
2015-07-31 08:55:05 -07:00
// Initialize global variables that cannot be constructed at startup.
recentRejects . reset ( new CRollingBloomFilter ( 120000 , 0.000001 ) ) ;
2013-01-30 12:43:36 -08:00
// Check whether we're already initialized
2013-10-10 14:07:44 -07:00
if ( chainActive . Genesis ( ) ! = NULL )
2013-01-30 12:43:36 -08:00
return true ;
// Use the provided setting for -txindex in the new database
fTxIndex = GetBoolArg ( " -txindex " , false ) ;
pblocktree - > WriteFlag ( " txindex " , fTxIndex ) ;
2019-03-19 12:28:02 -07:00
// Use the provided setting for -insightexplorer in the new database
fInsightExplorer = GetBoolArg ( " -insightexplorer " , false ) ;
pblocktree - > WriteFlag ( " insightexplorer " , fInsightExplorer ) ;
fAddressIndex = fInsightExplorer ;
2019-04-23 10:06:23 -07:00
fSpentIndex = fInsightExplorer ;
2019-02-21 13:01:12 -08:00
fTimestampIndex = fInsightExplorer ;
2019-03-19 12:28:02 -07:00
2013-09-18 03:38:08 -07:00
LogPrintf ( " Initializing databases... \n " ) ;
2013-01-30 12:43:36 -08:00
// Only add the genesis block if not reindexing (in which case we reuse the one already on disk)
if ( ! fReindex ) {
try {
2015-04-17 05:40:24 -07:00
CBlock & block = const_cast < CBlock & > ( chainparams . GenesisBlock ( ) ) ;
2013-05-07 06:16:25 -07:00
// Start new block file
2013-01-30 12:43:36 -08:00
unsigned int nBlockSize = : : GetSerializeSize ( block , SER_DISK , CLIENT_VERSION ) ;
CDiskBlockPos blockPos ;
CValidationState state ;
2014-06-28 14:36:06 -07:00
if ( ! FindBlockPos ( state , blockPos , nBlockSize + 8 , 0 , block . GetBlockTime ( ) ) )
2015-01-08 02:44:25 -08:00
return error ( " LoadBlockIndex() : FindBlockPos failed " ) ;
2015-04-19 14:48:25 -07:00
if ( ! WriteBlockToDisk ( block , blockPos , chainparams . MessageStart ( ) ) )
2015-01-08 02:44:25 -08:00
return error ( " LoadBlockIndex() : writing genesis block to disk failed " ) ;
2014-03-12 19:48:27 -07:00
CBlockIndex * pindex = AddToBlockIndex ( block ) ;
if ( ! ReceivedBlockTransactions ( block , state , pindex , blockPos ) )
2015-01-08 02:44:25 -08:00
return error ( " LoadBlockIndex() : genesis block not accepted " ) ;
2015-04-17 05:40:24 -07:00
if ( ! ActivateBestChain ( state , chainparams , & block ) )
2015-01-08 02:44:25 -08:00
return error ( " LoadBlockIndex() : genesis block cannot be activated " ) ;
2014-11-25 09:54:36 -08:00
// Force a chainstate write so that when we VerifyDB in a moment, it doesn't check stale data
2014-11-14 09:19:26 -08:00
return FlushStateToDisk ( state , FLUSH_STATE_ALWAYS ) ;
2014-12-07 04:29:06 -08:00
} catch ( const std : : runtime_error & e ) {
2015-01-08 02:44:25 -08:00
return error ( " LoadBlockIndex() : failed to initialize block database : % s " , e.what()) ;
2013-01-30 12:43:36 -08:00
}
2010-08-29 09:58:15 -07:00
}
return true ;
}
2015-04-17 05:40:24 -07:00
bool LoadExternalBlockFile ( const CChainParams & chainparams , FILE * fileIn , CDiskBlockPos * dbp )
2012-02-20 11:50:26 -08:00
{
2014-10-07 09:06:30 -07:00
// Map of disk positions for blocks with unknown parent (only used for reindex)
static std : : multimap < uint256 , CDiskBlockPos > mapBlocksUnknownParent ;
2013-04-12 22:13:08 -07:00
int64_t nStart = GetTimeMillis ( ) ;
2012-08-16 15:14:40 -07:00
2012-02-20 11:50:26 -08:00
int nLoaded = 0 ;
2013-01-28 16:44:19 -08:00
try {
2014-09-24 23:53:43 -07:00
// This takes over fileIn and calls fclose() on it in the CBufferedFile destructor
2012-10-27 13:01:38 -07:00
CBufferedFile blkdat ( fileIn , 2 * MAX_BLOCK_SIZE , MAX_BLOCK_SIZE + 8 , SER_DISK , CLIENT_VERSION ) ;
2013-04-12 22:13:08 -07:00
uint64_t nRewind = blkdat . GetPos ( ) ;
2014-08-01 13:57:55 -07:00
while ( ! blkdat . eof ( ) ) {
2013-03-06 19:31:26 -08:00
boost : : this_thread : : interruption_point ( ) ;
2012-10-27 13:01:38 -07:00
blkdat . SetPos ( nRewind ) ;
nRewind + + ; // start one byte further next time, in case of failure
blkdat . SetLimit ( ) ; // remove former limit
2012-10-21 12:23:13 -07:00
unsigned int nSize = 0 ;
2012-10-27 13:01:38 -07:00
try {
// locate a header
2014-04-24 05:32:11 -07:00
unsigned char buf [ MESSAGE_START_SIZE ] ;
2015-04-17 05:40:24 -07:00
blkdat . FindByte ( chainparams . MessageStart ( ) [ 0 ] ) ;
2012-10-27 13:01:38 -07:00
nRewind = blkdat . GetPos ( ) + 1 ;
blkdat > > FLATDATA ( buf ) ;
2015-04-17 05:40:24 -07:00
if ( memcmp ( buf , chainparams . MessageStart ( ) , MESSAGE_START_SIZE ) )
2012-10-27 13:01:38 -07:00
continue ;
// read size
2012-02-20 11:50:26 -08:00
blkdat > > nSize ;
2012-10-27 13:01:38 -07:00
if ( nSize < 80 | | nSize > MAX_BLOCK_SIZE )
continue ;
2014-12-07 04:29:06 -08:00
} catch ( const std : : exception & ) {
2012-10-21 12:23:13 -07:00
// no valid block header found; don't complain
break ;
}
try {
2012-10-27 13:01:38 -07:00
// read block
2013-04-12 22:13:08 -07:00
uint64_t nBlockPos = blkdat . GetPos ( ) ;
2014-10-07 09:06:30 -07:00
if ( dbp )
dbp - > nPos = nBlockPos ;
2012-10-21 12:23:13 -07:00
blkdat . SetLimit ( nBlockPos + nSize ) ;
2014-10-07 12:15:32 -07:00
blkdat . SetPos ( nBlockPos ) ;
CBlock block ;
blkdat > > block ;
2014-10-07 09:06:30 -07:00
nRewind = blkdat . GetPos ( ) ;
2014-10-07 12:15:32 -07:00
// detect out of order blocks, and store them for later
uint256 hash = block . GetHash ( ) ;
2015-04-09 06:58:34 -07:00
if ( hash ! = chainparams . GetConsensus ( ) . hashGenesisBlock & & mapBlockIndex . find ( block . hashPrevBlock ) = = mapBlockIndex . end ( ) ) {
2014-10-07 09:06:30 -07:00
LogPrint ( " reindex " , " %s: Out of order block %s, parent %s not known \n " , __func__ , hash . ToString ( ) ,
2014-10-07 12:15:32 -07:00
block . hashPrevBlock . ToString ( ) ) ;
2014-10-07 09:06:30 -07:00
if ( dbp )
2014-10-07 12:15:32 -07:00
mapBlocksUnknownParent . insert ( std : : make_pair ( block . hashPrevBlock , * dbp ) ) ;
2014-10-07 09:06:30 -07:00
continue ;
}
2014-10-07 12:15:32 -07:00
// process in case the block isn't known yet
2014-10-29 17:01:18 -07:00
if ( mapBlockIndex . count ( hash ) = = 0 | | ( mapBlockIndex [ hash ] - > nStatus & BLOCK_HAVE_DATA ) = = 0 ) {
2014-10-07 12:15:32 -07:00
CValidationState state ;
2015-04-19 15:17:11 -07:00
if ( ProcessNewBlock ( state , chainparams , NULL , & block , true , dbp ) )
2014-10-07 12:15:32 -07:00
nLoaded + + ;
if ( state . IsError ( ) )
break ;
2015-04-09 06:58:34 -07:00
} else if ( hash ! = chainparams . GetConsensus ( ) . hashGenesisBlock & & mapBlockIndex [ hash ] - > nHeight % 1000 = = 0 ) {
2014-10-29 17:02:48 -07:00
LogPrintf ( " Block Import: already had block %s at height %d \n " , hash . ToString ( ) , mapBlockIndex [ hash ] - > nHeight ) ;
2014-10-07 12:15:32 -07:00
}
2014-10-07 09:06:30 -07:00
// Recursively process earlier encountered successors of this block
deque < uint256 > queue ;
queue . push_back ( hash ) ;
while ( ! queue . empty ( ) ) {
uint256 head = queue . front ( ) ;
queue . pop_front ( ) ;
std : : pair < std : : multimap < uint256 , CDiskBlockPos > : : iterator , std : : multimap < uint256 , CDiskBlockPos > : : iterator > range = mapBlocksUnknownParent . equal_range ( head ) ;
while ( range . first ! = range . second ) {
std : : multimap < uint256 , CDiskBlockPos > : : iterator it = range . first ;
2015-04-17 05:19:21 -07:00
if ( ReadBlockFromDisk ( block , it - > second , chainparams . GetConsensus ( ) ) )
2014-10-07 09:06:30 -07:00
{
LogPrintf ( " %s: Processing out of order child %s of %s \n " , __func__ , block . GetHash ( ) . ToString ( ) ,
head . ToString ( ) ) ;
CValidationState dummy ;
2015-04-19 15:17:11 -07:00
if ( ProcessNewBlock ( dummy , chainparams , NULL , & block , true , & it - > second ) )
2014-10-07 09:06:30 -07:00
{
nLoaded + + ;
queue . push_back ( block . GetHash ( ) ) ;
}
}
range . first + + ;
mapBlocksUnknownParent . erase ( it ) ;
}
2012-02-20 11:50:26 -08:00
}
2014-12-07 04:29:06 -08:00
} catch ( const std : : exception & e ) {
2015-07-31 07:41:06 -07:00
LogPrintf ( " %s: Deserialize or I/O error - %s \n " , __func__ , e . what ( ) ) ;
2012-02-20 11:50:26 -08:00
}
}
2014-12-07 04:29:06 -08:00
} catch ( const std : : runtime_error & e ) {
2014-10-02 13:17:57 -07:00
AbortNode ( std : : string ( " System error: " ) + e . what ( ) ) ;
2012-02-20 11:50:26 -08:00
}
2012-10-21 12:23:13 -07:00
if ( nLoaded > 0 )
2014-02-24 00:08:56 -08:00
LogPrintf ( " Loaded %i blocks from external file in %dms \n " , nLoaded , GetTimeMillis ( ) - nStart ) ;
2012-02-20 11:50:26 -08:00
return nLoaded > 0 ;
}
2010-08-29 09:58:15 -07:00
2015-04-17 05:19:21 -07:00
void static CheckBlockIndex ( const Consensus : : Params & consensusParams )
2015-03-13 09:25:34 -07:00
{
if ( ! fCheckBlockIndex ) {
return ;
}
LOCK ( cs_main ) ;
2015-04-09 08:08:39 -07:00
// During a reindex, we read the genesis block and call CheckBlockIndex before ActivateBestChain,
// so we have the genesis block in mapBlockIndex but no active chain. (A few of the tests when
// iterating the block tree require that chainActive has been initialized.)
if ( chainActive . Height ( ) < 0 ) {
assert ( mapBlockIndex . size ( ) < = 1 ) ;
return ;
}
2015-03-13 09:25:34 -07:00
// Build forward-pointing map of the entire block tree.
std : : multimap < CBlockIndex * , CBlockIndex * > forward ;
for ( BlockMap : : iterator it = mapBlockIndex . begin ( ) ; it ! = mapBlockIndex . end ( ) ; it + + ) {
forward . insert ( std : : make_pair ( it - > second - > pprev , it - > second ) ) ;
}
assert ( forward . size ( ) = = mapBlockIndex . size ( ) ) ;
std : : pair < std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator , std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator > rangeGenesis = forward . equal_range ( NULL ) ;
CBlockIndex * pindex = rangeGenesis . first - > second ;
rangeGenesis . first + + ;
assert ( rangeGenesis . first = = rangeGenesis . second ) ; // There is only one index entry with parent NULL.
// Iterate over the entire block tree, using depth-first search.
// Along the way, remember whether there are blocks on the path from genesis
// block being explored which are the first to have certain properties.
size_t nNodes = 0 ;
int nHeight = 0 ;
CBlockIndex * pindexFirstInvalid = NULL ; // Oldest ancestor of pindex which is invalid.
CBlockIndex * pindexFirstMissing = NULL ; // Oldest ancestor of pindex which does not have BLOCK_HAVE_DATA.
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
CBlockIndex * pindexFirstNeverProcessed = NULL ; // Oldest ancestor of pindex for which nTx == 0.
2015-03-13 09:25:34 -07:00
CBlockIndex * pindexFirstNotTreeValid = NULL ; // Oldest ancestor of pindex which does not have BLOCK_VALID_TREE (regardless of being valid or not).
2015-04-01 10:12:50 -07:00
CBlockIndex * pindexFirstNotTransactionsValid = NULL ; // Oldest ancestor of pindex which does not have BLOCK_VALID_TRANSACTIONS (regardless of being valid or not).
2015-03-13 09:25:34 -07:00
CBlockIndex * pindexFirstNotChainValid = NULL ; // Oldest ancestor of pindex which does not have BLOCK_VALID_CHAIN (regardless of being valid or not).
CBlockIndex * pindexFirstNotScriptsValid = NULL ; // Oldest ancestor of pindex which does not have BLOCK_VALID_SCRIPTS (regardless of being valid or not).
while ( pindex ! = NULL ) {
nNodes + + ;
if ( pindexFirstInvalid = = NULL & & pindex - > nStatus & BLOCK_FAILED_VALID ) pindexFirstInvalid = pindex ;
if ( pindexFirstMissing = = NULL & & ! ( pindex - > nStatus & BLOCK_HAVE_DATA ) ) pindexFirstMissing = pindex ;
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
if ( pindexFirstNeverProcessed = = NULL & & pindex - > nTx = = 0 ) pindexFirstNeverProcessed = pindex ;
2015-03-13 09:25:34 -07:00
if ( pindex - > pprev ! = NULL & & pindexFirstNotTreeValid = = NULL & & ( pindex - > nStatus & BLOCK_VALID_MASK ) < BLOCK_VALID_TREE ) pindexFirstNotTreeValid = pindex ;
2015-04-01 10:12:50 -07:00
if ( pindex - > pprev ! = NULL & & pindexFirstNotTransactionsValid = = NULL & & ( pindex - > nStatus & BLOCK_VALID_MASK ) < BLOCK_VALID_TRANSACTIONS ) pindexFirstNotTransactionsValid = pindex ;
2015-03-13 09:25:34 -07:00
if ( pindex - > pprev ! = NULL & & pindexFirstNotChainValid = = NULL & & ( pindex - > nStatus & BLOCK_VALID_MASK ) < BLOCK_VALID_CHAIN ) pindexFirstNotChainValid = pindex ;
if ( pindex - > pprev ! = NULL & & pindexFirstNotScriptsValid = = NULL & & ( pindex - > nStatus & BLOCK_VALID_MASK ) < BLOCK_VALID_SCRIPTS ) pindexFirstNotScriptsValid = pindex ;
// Begin: actual consistency checks.
if ( pindex - > pprev = = NULL ) {
// Genesis block checks.
2015-04-09 06:58:34 -07:00
assert ( pindex - > GetBlockHash ( ) = = consensusParams . hashGenesisBlock ) ; // Genesis block's hash must match.
2015-03-13 09:25:34 -07:00
assert ( pindex = = chainActive . Genesis ( ) ) ; // The current active chain's genesis block must be this block.
}
2015-04-13 09:26:28 -07:00
if ( pindex - > nChainTx = = 0 ) assert ( pindex - > nSequenceId = = 0 ) ; // nSequenceId can't be set for blocks that aren't linked
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
// VALID_TRANSACTIONS is equivalent to nTx > 0 for all nodes (whether or not pruning has occurred).
// HAVE_DATA is only equivalent to nTx > 0 (or VALID_TRANSACTIONS) if no pruning has occurred.
if ( ! fHavePruned ) {
// If we've never pruned, then HAVE_DATA should be equivalent to nTx > 0
assert ( ! ( pindex - > nStatus & BLOCK_HAVE_DATA ) = = ( pindex - > nTx = = 0 ) ) ;
assert ( pindexFirstMissing = = pindexFirstNeverProcessed ) ;
} else {
// If we have pruned, then we can only say that HAVE_DATA implies nTx > 0
if ( pindex - > nStatus & BLOCK_HAVE_DATA ) assert ( pindex - > nTx > 0 ) ;
}
if ( pindex - > nStatus & BLOCK_HAVE_UNDO ) assert ( pindex - > nStatus & BLOCK_HAVE_DATA ) ;
assert ( ( ( pindex - > nStatus & BLOCK_VALID_MASK ) > = BLOCK_VALID_TRANSACTIONS ) = = ( pindex - > nTx > 0 ) ) ; // This is pruning-independent.
// All parents having had data (at some point) is equivalent to all parents being VALID_TRANSACTIONS, which is equivalent to nChainTx being set.
assert ( ( pindexFirstNeverProcessed ! = NULL ) = = ( pindex - > nChainTx = = 0 ) ) ; // nChainTx != 0 is used to signal that all parent blocks have been processed (but may have been pruned).
2015-04-01 10:12:50 -07:00
assert ( ( pindexFirstNotTransactionsValid ! = NULL ) = = ( pindex - > nChainTx = = 0 ) ) ;
2015-03-13 09:25:34 -07:00
assert ( pindex - > nHeight = = nHeight ) ; // nHeight must be consistent.
assert ( pindex - > pprev = = NULL | | pindex - > nChainWork > = pindex - > pprev - > nChainWork ) ; // For every block except the genesis block, the chainwork must be larger than the parent's.
assert ( nHeight < 2 | | ( pindex - > pskip & & ( pindex - > pskip - > nHeight < nHeight ) ) ) ; // The pskip pointer must point back for all but the first 2 blocks.
assert ( pindexFirstNotTreeValid = = NULL ) ; // All mapBlockIndex entries must at least be TREE valid
if ( ( pindex - > nStatus & BLOCK_VALID_MASK ) > = BLOCK_VALID_TREE ) assert ( pindexFirstNotTreeValid = = NULL ) ; // TREE valid implies all parents are TREE valid
if ( ( pindex - > nStatus & BLOCK_VALID_MASK ) > = BLOCK_VALID_CHAIN ) assert ( pindexFirstNotChainValid = = NULL ) ; // CHAIN valid implies all parents are CHAIN valid
if ( ( pindex - > nStatus & BLOCK_VALID_MASK ) > = BLOCK_VALID_SCRIPTS ) assert ( pindexFirstNotScriptsValid = = NULL ) ; // SCRIPTS valid implies all parents are SCRIPTS valid
if ( pindexFirstInvalid = = NULL ) {
// Checks for not-invalid blocks.
assert ( ( pindex - > nStatus & BLOCK_FAILED_MASK ) = = 0 ) ; // The failed mask cannot be set for blocks without invalid parents.
}
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
if ( ! CBlockIndexWorkComparator ( ) ( pindex , chainActive . Tip ( ) ) & & pindexFirstNeverProcessed = = NULL ) {
if ( pindexFirstInvalid = = NULL ) {
// If this block sorts at least as good as the current tip and
// is valid and we have all data for its parents, it must be in
// setBlockIndexCandidates. chainActive.Tip() must also be there
// even if some data has been pruned.
if ( pindexFirstMissing = = NULL | | pindex = = chainActive . Tip ( ) ) {
assert ( setBlockIndexCandidates . count ( pindex ) ) ;
}
// If some parent is missing, then it could be that this block was in
// setBlockIndexCandidates but had to be removed because of the missing data.
// In this case it must be in mapBlocksUnlinked -- see test below.
2015-03-13 09:25:34 -07:00
}
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
} else { // If this block sorts worse than the current tip or some ancestor's block has never been seen, it cannot be in setBlockIndexCandidates.
2015-03-13 09:25:34 -07:00
assert ( setBlockIndexCandidates . count ( pindex ) = = 0 ) ;
}
// Check whether this block is in mapBlocksUnlinked.
std : : pair < std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator , std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator > rangeUnlinked = mapBlocksUnlinked . equal_range ( pindex - > pprev ) ;
bool foundInUnlinked = false ;
while ( rangeUnlinked . first ! = rangeUnlinked . second ) {
assert ( rangeUnlinked . first - > first = = pindex - > pprev ) ;
if ( rangeUnlinked . first - > second = = pindex ) {
foundInUnlinked = true ;
break ;
}
rangeUnlinked . first + + ;
}
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
if ( pindex - > pprev & & ( pindex - > nStatus & BLOCK_HAVE_DATA ) & & pindexFirstNeverProcessed ! = NULL & & pindexFirstInvalid = = NULL ) {
// If this block has block data available, some parent was never received, and has no invalid parents, it must be in mapBlocksUnlinked.
assert ( foundInUnlinked ) ;
}
if ( ! ( pindex - > nStatus & BLOCK_HAVE_DATA ) ) assert ( ! foundInUnlinked ) ; // Can't be in mapBlocksUnlinked if we don't HAVE_DATA
if ( pindexFirstMissing = = NULL ) assert ( ! foundInUnlinked ) ; // We aren't missing data for any parent -- cannot be in mapBlocksUnlinked.
if ( pindex - > pprev & & ( pindex - > nStatus & BLOCK_HAVE_DATA ) & & pindexFirstNeverProcessed = = NULL & & pindexFirstMissing ! = NULL ) {
// We HAVE_DATA for this block, have received data for all parents at some point, but we're currently missing data for some parent.
assert ( fHavePruned ) ; // We must have pruned.
// This block may have entered mapBlocksUnlinked if:
// - it has a descendant that at some point had more work than the
// tip, and
// - we tried switching to that descendant but were missing
// data for some intermediate block between chainActive and the
// tip.
// So if this block is itself better than chainActive.Tip() and it wasn't in
// setBlockIndexCandidates, then it must be in mapBlocksUnlinked.
if ( ! CBlockIndexWorkComparator ( ) ( pindex , chainActive . Tip ( ) ) & & setBlockIndexCandidates . count ( pindex ) = = 0 ) {
if ( pindexFirstInvalid = = NULL ) {
assert ( foundInUnlinked ) ;
}
2015-03-13 09:25:34 -07:00
}
}
// assert(pindex->GetBlockHash() == pindex->GetBlockHeader().GetHash()); // Perhaps too slow
// End: actual consistency checks.
// Try descending into the first subnode.
std : : pair < std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator , std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator > range = forward . equal_range ( pindex ) ;
if ( range . first ! = range . second ) {
// A subnode was found.
pindex = range . first - > second ;
nHeight + + ;
continue ;
}
// This is a leaf node.
// Move upwards until we reach a node of which we have not yet visited the last child.
while ( pindex ) {
// We are going to either move to a parent or a sibling of pindex.
// If pindex was the first with a certain property, unset the corresponding variable.
if ( pindex = = pindexFirstInvalid ) pindexFirstInvalid = NULL ;
if ( pindex = = pindexFirstMissing ) pindexFirstMissing = NULL ;
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
if ( pindex = = pindexFirstNeverProcessed ) pindexFirstNeverProcessed = NULL ;
2015-03-13 09:25:34 -07:00
if ( pindex = = pindexFirstNotTreeValid ) pindexFirstNotTreeValid = NULL ;
2015-04-01 10:12:50 -07:00
if ( pindex = = pindexFirstNotTransactionsValid ) pindexFirstNotTransactionsValid = NULL ;
2015-03-13 09:25:34 -07:00
if ( pindex = = pindexFirstNotChainValid ) pindexFirstNotChainValid = NULL ;
if ( pindex = = pindexFirstNotScriptsValid ) pindexFirstNotScriptsValid = NULL ;
// Find our parent.
CBlockIndex * pindexPar = pindex - > pprev ;
// Find which child we just visited.
std : : pair < std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator , std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator > rangePar = forward . equal_range ( pindexPar ) ;
while ( rangePar . first - > second ! = pindex ) {
assert ( rangePar . first ! = rangePar . second ) ; // Our parent must have at least the node we're coming from as child.
rangePar . first + + ;
}
// Proceed to the next one.
rangePar . first + + ;
if ( rangePar . first ! = rangePar . second ) {
// Move to the sibling.
pindex = rangePar . first - > second ;
break ;
} else {
// Move up further.
pindex = pindexPar ;
nHeight - - ;
continue ;
}
}
}
// Check that we actually traversed the entire map.
assert ( nNodes = = forward . size ( ) ) ;
}
2010-08-29 09:58:15 -07:00
//////////////////////////////////////////////////////////////////////////////
//
// CAlert
//
2015-05-31 06:36:44 -07:00
std : : string GetWarnings ( const std : : string & strFor )
2010-08-29 09:58:15 -07:00
{
int nPriority = 0 ;
string strStatusBar ;
string strRPC ;
2012-10-24 12:47:07 -07: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 " ) ;
2014-11-23 04:10:31 -08:00
if ( GetBoolArg ( " -testsafemode " , false ) )
strStatusBar = strRPC = " testsafemode enabled " ;
2010-08-29 09:58:15 -07:00
// Misc warnings like out of disk space and clock is wrong
if ( strMiscWarning ! = " " )
{
nPriority = 1000 ;
strStatusBar = strMiscWarning ;
}
2013-05-07 09:33:52 -07:00
if ( fLargeWorkForkFound )
2010-08-29 09:58:15 -07:00
{
nPriority = 2000 ;
2013-05-17 18:09:28 -07:00
strStatusBar = strRPC = _ ( " Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. " ) ;
}
else if ( fLargeWorkInvalidChainFound )
2010-08-29 09:58:15 -07:00
{
nPriority = 2000 ;
2013-05-17 18:09:28 -07:00
strStatusBar = strRPC = _ ( " Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. " ) ;
2010-08-29 09:58:15 -07:00
}
// Alerts
{
2012-04-06 09:39:12 -07:00
LOCK ( cs_mapAlerts ) ;
2011-05-15 00:11:04 -07:00
BOOST_FOREACH ( PAIRTYPE ( const uint256 , CAlert ) & item , mapAlerts )
2010-08-29 09:58:15 -07:00
{
const CAlert & alert = item . second ;
if ( alert . AppliesToMe ( ) & & alert . nPriority > nPriority )
{
nPriority = alert . nPriority ;
strStatusBar = alert . strStatusBar ;
2016-09-03 23:25:33 -07:00
if ( alert . nPriority > = ALERT_PRIORITY_SAFE_MODE ) {
strRPC = alert . strRPCError ;
}
2010-08-29 09:58:15 -07:00
}
}
}
if ( strFor = = " statusbar " )
return strStatusBar ;
else if ( strFor = = " rpc " )
return strRPC ;
2015-01-08 02:44:25 -08:00
assert ( ! " GetWarnings(): invalid parameter " ) ;
2010-08-29 09:58:15 -07:00
return " error " ;
}
//////////////////////////////////////////////////////////////////////////////
//
// Messages
//
2015-06-16 01:08:26 -07:00
bool static AlreadyHave ( const CInv & inv ) EXCLUSIVE_LOCKS_REQUIRED ( cs_main )
2010-08-29 09:58:15 -07:00
{
switch ( inv . type )
{
2012-04-13 15:24:55 -07:00
case MSG_TX :
{
2015-07-31 08:55:05 -07:00
assert ( recentRejects ) ;
2015-07-17 03:46:48 -07:00
if ( chainActive . Tip ( ) - > GetBlockHash ( ) ! = hashRecentRejectsChainTip )
{
// If the chain tip has changed previously rejected transactions
// might be now valid, e.g. due to a nLockTime'd tx becoming valid,
// or a double-spend. Reset the rejects filter and give those
// txs a second chance.
hashRecentRejectsChainTip = chainActive . Tip ( ) - > GetBlockHash ( ) ;
recentRejects - > reset ( ) ;
}
return recentRejects - > contains ( inv . hash ) | |
mempool . exists ( inv . hash ) | |
mapOrphanTransactions . count ( inv . hash ) | |
pcoinsTip - > HaveCoins ( inv . hash ) ;
2012-04-13 15:24:55 -07:00
}
case MSG_BLOCK :
2014-07-11 15:02:35 -07:00
return mapBlockIndex . count ( inv . hash ) ;
2010-08-29 09:58:15 -07:00
}
// Don't know what it is, just say we already got one
return true ;
}
2015-04-17 05:19:21 -07:00
void static ProcessGetData ( CNode * pfrom , const Consensus : : Params & consensusParams )
2013-03-29 15:49:38 -07:00
{
2018-11-06 17:33:27 -08:00
int currentHeight = GetHeight ( ) ;
2013-03-29 15:49:38 -07:00
std : : deque < CInv > : : iterator it = pfrom - > vRecvGetData . begin ( ) ;
vector < CInv > vNotFound ;
2013-07-24 17:34:42 -07:00
LOCK ( cs_main ) ;
2013-03-29 15:49:38 -07: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 ;
{
2013-03-09 09:02:57 -08:00
boost : : this_thread : : interruption_point ( ) ;
2013-03-29 15:49:38 -07:00
it + + ;
if ( inv . type = = MSG_BLOCK | | inv . type = = MSG_FILTERED_BLOCK )
{
2014-01-19 15:59:57 -08:00
bool send = false ;
2014-09-03 17:02:44 -07:00
BlockMap : : iterator mi = mapBlockIndex . find ( inv . hash ) ;
2013-03-29 15:49:38 -07:00
if ( mi ! = mapBlockIndex . end ( ) )
{
2015-02-24 04:27:25 -08:00
if ( chainActive . Contains ( mi - > second ) ) {
2014-02-10 07:31:06 -08: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.
2015-02-24 04:27:25 -08:00
send = mi - > second - > IsValid ( BLOCK_VALID_SCRIPTS ) & & ( pindexBestHeader ! = NULL ) & &
2015-03-17 06:35:59 -07:00
( pindexBestHeader - > GetBlockTime ( ) - mi - > second - > GetBlockTime ( ) < nOneMonth ) & &
2015-04-17 05:40:24 -07:00
( GetBlockProofEquivalentTime ( * pindexBestHeader , * mi - > second , * pindexBestHeader , consensusParams ) < nOneMonth ) ;
2015-02-24 04:27:25 -08:00
if ( ! send ) {
2015-02-24 09:32:34 -08:00
LogPrintf ( " %s: ignoring request from peer=%i for old block that isn't in the main chain \n " , __func__ , pfrom - > GetId ( ) ) ;
2015-02-24 04:27:25 -08:00
}
2014-01-19 15:59:57 -08:00
}
}
Add block pruning functionality
This adds a -prune=N option to bitcoind, which if set to N>0 will enable block
file pruning. When pruning is enabled, block and undo files will be deleted to
try to keep total space used by those files to below the prune target (N, in
MB) specified by the user, subject to some constraints:
- The last 288 blocks on the main chain are always kept (MIN_BLOCKS_TO_KEEP),
- N must be at least 550MB (chosen as a value for the target that could
reasonably be met, with some assumptions about block sizes, orphan rates,
etc; see comment in main.h),
- No blocks are pruned until chainActive is at least 100,000 blocks long (on
mainnet; defined separately for mainnet, testnet, and regtest in chainparams
as nPruneAfterHeight).
This unsets NODE_NETWORK if pruning is enabled.
Also included is an RPC test for pruning (pruning.py).
Thanks to @rdponticelli for earlier work on this feature; this is based in
part off that work.
2015-02-23 11:27:44 -08:00
// Pruned nodes may have deleted the block, so check whether
// it's available before trying to send.
if ( send & & ( mi - > second - > nStatus & BLOCK_HAVE_DATA ) )
2014-01-19 15:59:57 -08:00
{
// Send block from disk
2013-03-29 15:49:38 -07:00
CBlock block ;
2015-04-17 05:19:21 -07:00
if ( ! ReadBlockFromDisk ( block , ( * mi ) . second , consensusParams ) )
2014-06-04 03:27:44 -07:00
assert ( ! " cannot load block from disk " ) ;
2013-03-29 15:49:38 -07:00
if ( inv . type = = MSG_BLOCK )
pfrom - > PushMessage ( " block " , block ) ;
else // MSG_FILTERED_BLOCK)
{
LOCK ( pfrom - > cs_filter ) ;
if ( pfrom - > pfilter )
{
CMerkleBlock merkleBlock ( block , * pfrom - > pfilter ) ;
pfrom - > PushMessage ( " merkleblock " , merkleBlock ) ;
// 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 07:48:28 -07:00
// Note that there is currently no way for a node to request any single transactions we didn't send here -
2013-03-29 15:49:38 -07: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 ;
BOOST_FOREACH ( PairType & pair , merkleBlock . vMatchedTxn )
if ( ! pfrom - > setInventoryKnown . count ( CInv ( MSG_TX , pair . second ) ) )
pfrom - > PushMessage ( " tx " , block . vtx [ pair . first ] ) ;
}
// else
// no response
}
2015-04-28 07:47:17 -07:00
// Trigger the peer node to send a getblocks request for the next batch of inventory
2013-03-29 15:49:38 -07: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.
vector < CInv > vInv ;
2013-10-10 14:07:44 -07:00
vInv . push_back ( CInv ( MSG_BLOCK , chainActive . Tip ( ) - > GetBlockHash ( ) ) ) ;
2013-03-29 15:49:38 -07:00
pfrom - > PushMessage ( " inv " , vInv ) ;
2014-12-15 00:11:16 -08:00
pfrom - > hashContinue . SetNull ( ) ;
2013-03-29 15:49:38 -07:00
}
}
}
else if ( inv . IsKnownType ( ) )
{
2018-11-06 17:33:27 -08:00
// Check the mempool to see if a transaction is expiring soon. If so, do not send to peer.
// Note that a transaction enters the mempool first, before the serialized form is cached
// in mapRelay after a successful relay.
bool isExpiringSoon = false ;
2013-03-29 15:49:38 -07:00
bool pushed = false ;
2018-11-06 17:33:27 -08:00
CTransaction tx ;
bool isInMempool = mempool . lookup ( inv . hash , tx ) ;
if ( isInMempool ) {
isExpiringSoon = IsExpiringSoonTx ( tx , currentHeight + 1 ) ;
2013-03-29 15:49:38 -07:00
}
2018-11-06 17:33:27 -08:00
if ( ! isExpiringSoon ) {
// Send stream from relay memory
{
LOCK ( cs_mapRelay ) ;
map < CInv , CDataStream > : : iterator mi = mapRelay . find ( inv ) ;
if ( mi ! = mapRelay . end ( ) ) {
pfrom - > PushMessage ( inv . GetCommand ( ) , ( * mi ) . second ) ;
pushed = true ;
}
}
if ( ! pushed & & inv . type = = MSG_TX ) {
if ( isInMempool ) {
CDataStream ss ( SER_NETWORK , PROTOCOL_VERSION ) ;
ss . reserve ( 1000 ) ;
ss < < tx ;
pfrom - > PushMessage ( " tx " , ss ) ;
pushed = true ;
}
2013-03-29 15:49:38 -07:00
}
}
2018-11-06 17:33:27 -08:00
2013-03-29 15:49:38 -07:00
if ( ! pushed ) {
vNotFound . push_back ( inv ) ;
}
}
// Track requests for our stuff.
2015-02-04 16:11:44 -08:00
GetMainSignals ( ) . Inventory ( inv . hash ) ;
2013-11-11 07:20:39 -08:00
2013-10-28 13:20:21 -07:00
if ( inv . type = = MSG_BLOCK | | inv . type = = MSG_FILTERED_BLOCK )
break ;
2013-03-29 15:49:38 -07: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.
pfrom - > PushMessage ( " notfound " , vNotFound ) ;
}
}
2014-07-06 07:06:46 -07:00
bool static ProcessMessage ( CNode * pfrom , string strCommand , CDataStream & vRecv , int64_t nTimeReceived )
2010-08-29 09:58:15 -07:00
{
2015-04-10 09:35:09 -07:00
const CChainParams & chainparams = Params ( ) ;
2015-02-07 16:59:58 -08:00
LogPrint ( " net " , " received: %s (%u bytes) peer=%d \n " , SanitizeString ( strCommand ) , vRecv . size ( ) , pfrom - > id ) ;
2010-08-29 09:58:15 -07:00
if ( mapArgs . count ( " -dropmessagestest " ) & & GetRand ( atoi ( mapArgs [ " -dropmessagestest " ] ) ) = = 0 )
{
2013-09-18 03:38:08 -07:00
LogPrintf ( " dropmessagestest DROPPING RECV MESSAGE \n " ) ;
2010-08-29 09:58:15 -07:00
return true ;
}
if ( strCommand = = " version " )
{
// Each connection can only send one version message
if ( pfrom - > nVersion ! = 0 )
2011-09-06 14:41:51 -07:00
{
2013-10-27 23:36:11 -07:00
pfrom - > PushMessage ( " reject " , strCommand , REJECT_DUPLICATE , string ( " Duplicate version message " ) ) ;
2013-11-17 16:25:17 -08:00
Misbehaving ( pfrom - > GetId ( ) , 1 ) ;
2010-08-29 09:58:15 -07:00
return false ;
2011-09-06 14:41:51 -07:00
}
2010-08-29 09:58:15 -07:00
2013-04-12 22:13:08 -07:00
int64_t nTime ;
2010-08-29 09:58:15 -07:00
CAddress addrMe ;
CAddress addrFrom ;
2013-04-12 22:13:08 -07:00
uint64_t nNonce = 1 ;
2010-08-29 09:58:15 -07:00
vRecv > > pfrom - > nVersion > > pfrom - > nServices > > nTime > > addrMe ;
2013-10-26 02:21:21 -07:00
if ( pfrom - > nVersion < MIN_PEER_PROTO_VERSION )
2012-02-19 16:33:31 -08:00
{
2013-10-26 02:21:21 -07:00
// disconnect from peers older than this proto version
2014-02-26 17:55:04 -08:00
LogPrintf ( " peer=%d using obsolete version %i; disconnecting \n " , pfrom - > id , pfrom - > nVersion ) ;
2013-10-27 23:36:11 -07:00
pfrom - > PushMessage ( " reject " , strCommand , REJECT_OBSOLETE ,
strprintf ( " Version must be %d or greater " , MIN_PEER_PROTO_VERSION ) ) ;
2012-02-19 16:33:31 -08:00
pfrom - > fDisconnect = true ;
return false ;
}
2018-09-12 01:27:28 -07:00
// Reject incoming connections from nodes that don't know about the current epoch
2019-04-01 18:07:02 -07:00
const Consensus : : Params & consensusParams = chainparams . GetConsensus ( ) ;
auto currentEpoch = CurrentEpoch ( GetHeight ( ) , consensusParams ) ;
if ( pfrom - > nVersion < consensusParams . vUpgrades [ currentEpoch ] . nProtocolVersion )
2018-02-20 11:03:40 -08:00
{
LogPrintf ( " peer=%d using obsolete version %i; disconnecting \n " , pfrom - > id , pfrom - > nVersion ) ;
pfrom - > PushMessage ( " reject " , strCommand , REJECT_OBSOLETE ,
strprintf ( " Version must be %d or greater " ,
2019-04-01 18:07:02 -07:00
consensusParams . vUpgrades [ currentEpoch ] . nProtocolVersion ) ) ;
2018-02-20 11:03:40 -08:00
pfrom - > fDisconnect = true ;
return false ;
}
2017-06-23 17:19:17 -07:00
if ( pfrom - > nVersion = = 10300 )
pfrom - > nVersion = 300 ;
2012-02-19 16:33:31 -08:00
if ( ! vRecv . empty ( ) )
2010-08-29 09:58:15 -07:00
vRecv > > addrFrom > > nNonce ;
2013-11-26 03:52:21 -08:00
if ( ! vRecv . empty ( ) ) {
2015-07-31 09:05:42 -07:00
vRecv > > LIMITED_STRING ( pfrom - > strSubVer , MAX_SUBVERSION_LENGTH ) ;
2013-11-26 03:52:21 -08:00
pfrom - > cleanSubVer = SanitizeString ( pfrom - > strSubVer ) ;
}
2012-02-19 16:33:31 -08:00
if ( ! vRecv . empty ( ) )
2010-08-29 09:58:15 -07:00
vRecv > > pfrom - > nStartingHeight ;
2012-08-20 18:10:25 -07:00
if ( ! vRecv . empty ( ) )
vRecv > > pfrom - > fRelayTxes ; // set to true after we get the first filter* message
else
pfrom - > fRelayTxes = true ;
2010-08-29 09:58:15 -07:00
// Disconnect if we connected to ourself
if ( nNonce = = nLocalHostNonce & & nNonce > 1 )
{
2014-01-16 07:15:27 -08:00
LogPrintf ( " connected to self at %s, disconnecting \n " , pfrom - > addr . ToString ( ) ) ;
2010-08-29 09:58:15 -07: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 07:42:17 -08:00
// Be shy and don't send version until we hear
if ( pfrom - > fInbound )
pfrom - > PushVersion ( ) ;
2010-08-29 09:58:15 -07: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 09:58:15 -07:00
// Change version
2012-02-19 16:33:31 -08:00
pfrom - > PushMessage ( " verack " ) ;
2013-03-24 08:52:24 -07:00
pfrom - > ssSend . SetVersion ( min ( pfrom - > nVersion , PROTOCOL_VERSION ) ) ;
2010-08-29 09:58:15 -07:00
2010-10-23 10:43:53 -07:00
if ( ! pfrom - > fInbound )
{
// Advertise our address
2014-05-29 03:33:17 -07:00
if ( fListen & & ! IsInitialBlockDownload ( ) )
2010-10-23 10:43:53 -07:00
{
2012-02-12 04:45:24 -08:00
CAddress addr = GetLocalAddress ( & pfrom - > addr ) ;
if ( addr . IsRoutable ( ) )
2014-07-20 23:32:25 -07:00
{
2015-08-25 11:12:08 -07:00
LogPrintf ( " ProcessMessages: advertizing address %s \n " , addr . ToString ( ) ) ;
2014-07-20 23:32:25 -07:00
pfrom - > PushAddress ( addr ) ;
} else if ( IsPeerAddrLocalGood ( pfrom ) ) {
addr . SetIP ( pfrom - > addrLocal ) ;
2015-08-25 11:12:08 -07:00
LogPrintf ( " ProcessMessages: advertizing address %s \n " , addr . ToString ( ) ) ;
2012-02-12 04:45:24 -08:00
pfrom - > PushAddress ( addr ) ;
2014-07-20 23:32:25 -07:00
}
2010-10-23 10:43:53 -07:00
}
// Get recent addresses
2017-06-23 17:19:25 -07:00
if ( pfrom - > fOneShot | | pfrom - > nVersion > = CADDR_TIME_VERSION | | addrman . size ( ) < 1000 )
{
pfrom - > PushMessage ( " getaddr " ) ;
pfrom - > fGetAddr = true ;
}
2012-01-04 14:39:45 -08:00
addrman . Good ( pfrom - > addr ) ;
} else {
if ( ( ( CNetAddr ) pfrom - > addr ) = = ( CNetAddr ) addrFrom )
{
addrman . Add ( addrFrom , addrFrom ) ;
addrman . Good ( addrFrom ) ;
}
2010-10-23 10:43:53 -07:00
}
2010-08-29 09:58:15 -07:00
// Relay alerts
2012-04-06 09:39:12 -07:00
{
LOCK ( cs_mapAlerts ) ;
2011-05-15 00:11:04 -07:00
BOOST_FOREACH ( PAIRTYPE ( const uint256 , CAlert ) & item , mapAlerts )
2010-08-29 09:58:15 -07:00
item . second . RelayTo ( pfrom ) ;
2012-04-06 09:39:12 -07:00
}
2010-08-29 09:58:15 -07:00
pfrom - > fSuccessfullyConnected = true ;
2014-07-31 08:43:50 -07:00
string remoteAddr ;
if ( fLogIPs )
remoteAddr = " , peeraddr= " + pfrom - > addr . ToString ( ) ;
LogPrintf ( " receive version message: %s: version %d, blocks=%d, us=%s, peer=%d%s \n " ,
pfrom - > cleanSubVer , pfrom - > nVersion ,
pfrom - > nStartingHeight , addrMe . ToString ( ) , pfrom - > id ,
remoteAddr ) ;
2011-09-28 12:35:58 -07:00
2014-12-15 02:06:15 -08:00
int64_t nTimeOffset = nTime - GetTime ( ) ;
pfrom - > nTimeOffset = nTimeOffset ;
AddTimeData ( pfrom - > addr , nTimeOffset ) ;
2010-08-29 09:58:15 -07:00
}
else if ( pfrom - > nVersion = = 0 )
{
// Must have a version message before anything else
2013-11-17 16:25:17 -08:00
Misbehaving ( pfrom - > GetId ( ) , 1 ) ;
2010-08-29 09:58:15 -07:00
return false ;
}
else if ( strCommand = = " verack " )
{
2012-11-15 16:41:12 -08:00
pfrom - > SetRecvVersion ( 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 ;
}
2010-08-29 09:58:15 -07:00
}
2018-02-20 11:03:40 -08:00
// Disconnect existing peer connection when:
// 1. The version message has been received
2018-09-12 02:17:33 -07:00
// 2. Peer version is below the minimum version for the current epoch
else if ( pfrom - > nVersion < chainparams . GetConsensus ( ) . vUpgrades [
CurrentEpoch ( GetHeight ( ) , chainparams . GetConsensus ( ) ) ] . nProtocolVersion )
2018-02-20 11:03:40 -08:00
{
LogPrintf ( " peer=%d using obsolete version %i; disconnecting \n " , pfrom - > id , pfrom - > nVersion ) ;
pfrom - > PushMessage ( " reject " , strCommand , REJECT_OBSOLETE ,
strprintf ( " Version must be %d or greater " ,
2018-09-12 02:17:33 -07:00
chainparams . GetConsensus ( ) . vUpgrades [
CurrentEpoch ( GetHeight ( ) , chainparams . GetConsensus ( ) ) ] . nProtocolVersion ) ) ;
2018-02-20 11:03:40 -08:00
pfrom - > fDisconnect = true ;
return false ;
}
2010-08-29 09:58:15 -07:00
else if ( strCommand = = " addr " )
{
vector < CAddress > vAddr ;
vRecv > > vAddr ;
2010-10-23 10:43:53 -07:00
2017-06-23 17:19:25 -07:00
// Don't want addr from older versions unless seeding
if ( pfrom - > nVersion < CADDR_TIME_VERSION & & addrman . size ( ) > 1000 )
return true ;
2010-08-29 09:58:15 -07:00
if ( vAddr . size ( ) > 1000 )
2011-09-06 14:41:51 -07:00
{
2013-11-17 16:25:17 -08:00
Misbehaving ( pfrom - > GetId ( ) , 20 ) ;
2014-05-06 06:25:01 -07:00
return error ( " message addr size() = % u " , vAddr.size()) ;
2011-09-06 14:41:51 -07:00
}
2010-08-29 09:58:15 -07:00
// Store the new addresses
2012-04-10 11:22:04 -07:00
vector < CAddress > vAddrOk ;
2013-04-12 22:13:08 -07:00
int64_t nNow = GetAdjustedTime ( ) ;
int64_t nSince = nNow - 10 * 60 ;
2011-05-15 00:11:04 -07:00
BOOST_FOREACH ( CAddress & addr , vAddr )
2010-08-29 09:58:15 -07:00
{
2013-03-09 09:02:57 -08:00
boost : : this_thread : : interruption_point ( ) ;
2010-10-23 10:43:53 -07:00
if ( addr . nTime < = 100000000 | | addr . nTime > nNow + 10 * 60 )
addr . nTime = nNow - 5 * 24 * 60 * 60 ;
2010-08-29 09:58:15 -07:00
pfrom - > AddAddressKnown ( addr ) ;
2012-04-10 11:22:04 -07:00
bool fReachable = IsReachable ( addr ) ;
2010-10-23 10:43:53 -07:00
if ( addr . nTime > nSince & & ! pfrom - > fGetAddr & & vAddr . size ( ) < = 10 & & addr . IsRoutable ( ) )
2010-08-29 09:58:15 -07:00
{
// Relay to a limited number of other nodes
{
2012-04-06 09:39:12 -07:00
LOCK ( cs_vNodes ) ;
2010-10-19 10:16:51 -07:00
// Use deterministic randomness to send to the same nodes for 24 hours
2015-04-25 13:25:44 -07:00
// at a time so the addrKnowns of the chosen nodes prevent repeats
2010-08-29 09:58:15 -07:00
static uint256 hashSalt ;
2014-12-15 00:11:16 -08:00
if ( hashSalt . IsNull ( ) )
2012-05-17 09:13:14 -07:00
hashSalt = GetRandHash ( ) ;
2013-04-12 22:13:08 -07:00
uint64_t hashAddr = addr . GetHash ( ) ;
2014-12-16 06:43:03 -08:00
uint256 hashRand = ArithToUint256 ( UintToArith256 ( hashSalt ) ^ ( hashAddr < < 32 ) ^ ( ( GetTime ( ) + hashAddr ) / ( 24 * 60 * 60 ) ) ) ;
2010-10-19 10:16:51 -07:00
hashRand = Hash ( BEGIN ( hashRand ) , END ( hashRand ) ) ;
2010-08-29 09:58:15 -07:00
multimap < uint256 , CNode * > mapMix ;
2011-05-15 00:11:04 -07:00
BOOST_FOREACH ( CNode * pnode , vNodes )
2010-10-19 10:16:51 -07:00
{
2017-06-23 17:19:25 -07:00
if ( pnode - > nVersion < CADDR_TIME_VERSION )
continue ;
2010-10-19 10:16:51 -07:00
unsigned int nPointer ;
memcpy ( & nPointer , & pnode , sizeof ( nPointer ) ) ;
2014-12-16 06:43:03 -08:00
uint256 hashKey = ArithToUint256 ( UintToArith256 ( hashRand ) ^ nPointer ) ;
2010-10-19 10:16:51 -07:00
hashKey = Hash ( BEGIN ( hashKey ) , END ( hashKey ) ) ;
mapMix . insert ( make_pair ( hashKey , pnode ) ) ;
}
2012-04-10 11:22:04 -07:00
int nRelayNodes = fReachable ? 2 : 1 ; // limited relaying of addresses outside our network(s)
2010-08-29 09:58:15 -07:00
for ( multimap < uint256 , CNode * > : : iterator mi = mapMix . begin ( ) ; mi ! = mapMix . end ( ) & & nRelayNodes - - > 0 ; + + mi )
( ( * mi ) . second ) - > PushAddress ( addr ) ;
}
}
2012-04-10 11:22:04 -07:00
// Do not store addresses outside our network
if ( fReachable )
vAddrOk . push_back ( addr ) ;
2010-08-29 09:58:15 -07:00
}
2012-04-10 11:22:04 -07:00
addrman . Add ( vAddrOk , pfrom - > addr , 2 * 60 * 60 ) ;
2010-08-29 09:58:15 -07:00
if ( vAddr . size ( ) < 1000 )
pfrom - > fGetAddr = false ;
2012-04-23 17:15:00 -07:00
if ( pfrom - > fOneShot )
pfrom - > fDisconnect = true ;
2010-08-29 09:58:15 -07:00
}
else if ( strCommand = = " inv " )
{
vector < CInv > vInv ;
vRecv > > vInv ;
2012-07-31 14:42:35 -07:00
if ( vInv . size ( ) > MAX_INV_SZ )
2011-09-06 14:41:51 -07:00
{
2013-11-17 16:25:17 -08:00
Misbehaving ( pfrom - > GetId ( ) , 20 ) ;
2014-05-06 06:25:01 -07:00
return error ( " message inv size() = % u " , vInv.size()) ;
2011-09-06 14:41:51 -07:00
}
2010-08-29 09:58:15 -07:00
2013-07-24 17:34:42 -07:00
LOCK ( cs_main ) ;
2014-07-11 15:02:35 -07:00
std : : vector < CInv > vToFetch ;
2012-04-15 13:52:09 -07:00
for ( unsigned int nInv = 0 ; nInv < vInv . size ( ) ; nInv + + )
2010-08-29 09:58:15 -07:00
{
2012-03-18 15:47:26 -07:00
const CInv & inv = vInv [ nInv ] ;
2013-03-09 09:02:57 -08:00
boost : : this_thread : : interruption_point ( ) ;
2010-08-29 09:58:15 -07:00
pfrom - > AddInventoryKnown ( inv ) ;
2012-07-06 07:33:34 -07:00
bool fAlreadyHave = AlreadyHave ( inv ) ;
2014-02-26 17:55:04 -08:00
LogPrint ( " net " , " got inv: %s %s peer=%d \n " , inv . ToString ( ) , fAlreadyHave ? " have " : " new " , pfrom - > id ) ;
2010-08-29 09:58:15 -07:00
2014-07-11 15:02:35 -07:00
if ( ! fAlreadyHave & & ! fImporting & & ! fReindex & & inv . type ! = MSG_BLOCK )
pfrom - > AskFor ( inv ) ;
2010-08-29 09:58:15 -07:00
2014-07-11 15:02:35 -07:00
if ( inv . type = = MSG_BLOCK ) {
2014-06-22 15:00:26 -07:00
UpdateBlockAvailability ( pfrom - > GetId ( ) , inv . hash ) ;
2014-07-11 15:02:35 -07:00
if ( ! fAlreadyHave & & ! fImporting & & ! fReindex & & ! mapBlocksInFlight . count ( inv . hash ) ) {
2015-04-28 07:48:28 -07:00
// First request the headers preceding the announced block. In the normal fully-synced
2014-07-11 15:02:35 -07: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.
pfrom - > PushMessage ( " getheaders " , chainActive . GetLocator ( pindexBestHeader ) , inv . hash ) ;
2014-12-18 15:28:29 -08:00
CNodeState * nodestate = State ( pfrom - > GetId ( ) ) ;
2015-04-10 09:35:09 -07:00
if ( chainActive . Tip ( ) - > GetBlockTime ( ) > GetAdjustedTime ( ) - chainparams . GetConsensus ( ) . nPowTargetSpacing * 20 & &
2014-12-18 15:28:29 -08:00
nodestate - > nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER ) {
2014-07-11 15:02:35 -07:00
vToFetch . push_back ( inv ) ;
// Mark block as in flight already, even though the actual "getdata" message only goes out
// later (within the same cs_main lock, though).
2015-05-27 07:57:17 -07:00
MarkBlockAsInFlight ( pfrom - > GetId ( ) , inv . hash , chainparams . GetConsensus ( ) ) ;
2014-07-11 15:02:35 -07:00
}
2014-09-02 03:16:32 -07:00
LogPrint ( " net " , " getheaders (%d) %s to peer=%d \n " , pindexBestHeader - > nHeight , inv . hash . ToString ( ) , pfrom - > id ) ;
2014-07-11 15:02:35 -07:00
}
}
2014-06-22 15:00:26 -07:00
2010-08-29 09:58:15 -07:00
// Track requests for our stuff
2015-02-04 16:11:44 -08:00
GetMainSignals ( ) . Inventory ( inv . hash ) ;
2014-09-09 00:26:52 -07:00
if ( pfrom - > nSendSize > ( SendBufferSize ( ) * 2 ) ) {
Misbehaving ( pfrom - > GetId ( ) , 50 ) ;
return error ( " send buffer size() = % u " , pfrom->nSendSize) ;
}
2010-08-29 09:58:15 -07:00
}
2014-07-11 15:02:35 -07:00
if ( ! vToFetch . empty ( ) )
pfrom - > PushMessage ( " getdata " , vToFetch ) ;
2010-08-29 09:58:15 -07:00
}
else if ( strCommand = = " getdata " )
{
vector < CInv > vInv ;
vRecv > > vInv ;
2012-07-31 14:42:35 -07:00
if ( vInv . size ( ) > MAX_INV_SZ )
2011-09-06 14:41:51 -07:00
{
2013-11-17 16:25:17 -08:00
Misbehaving ( pfrom - > GetId ( ) , 20 ) ;
2014-05-06 06:25:01 -07:00
return error ( " message getdata size() = % u " , vInv.size()) ;
2011-09-06 14:41:51 -07:00
}
2010-08-29 09:58:15 -07:00
2013-10-08 03:09:40 -07:00
if ( fDebug | | ( vInv . size ( ) ! = 1 ) )
2014-02-26 17:55:04 -08:00
LogPrint ( " net " , " received getdata (%u invsz) peer=%d \n " , vInv . size ( ) , pfrom - > id ) ;
2012-06-23 18:38:33 -07:00
2013-10-08 03:09:40 -07:00
if ( ( fDebug & & vInv . size ( ) > 0 ) | | ( vInv . size ( ) = = 1 ) )
2014-02-26 17:55:04 -08:00
LogPrint ( " net " , " received getdata for: %s peer=%d \n " , vInv [ 0 ] . ToString ( ) , pfrom - > id ) ;
2010-08-29 09:58:15 -07:00
2013-03-29 15:49:38 -07:00
pfrom - > vRecvGetData . insert ( pfrom - > vRecvGetData . end ( ) , vInv . begin ( ) , vInv . end ( ) ) ;
2015-04-17 05:19:21 -07:00
ProcessGetData ( pfrom , chainparams . GetConsensus ( ) ) ;
2010-08-29 09:58:15 -07:00
}
else if ( strCommand = = " getblocks " )
{
CBlockLocator locator ;
uint256 hashStop ;
vRecv > > locator > > hashStop ;
2013-07-24 17:34:42 -07:00
LOCK ( cs_main ) ;
2010-12-05 01:29:30 -08:00
// Find the last block the caller has in the main chain
2014-09-02 17:52:01 -07:00
CBlockIndex * pindex = FindForkInGlobalIndex ( chainActive , locator ) ;
2010-08-29 09:58:15 -07:00
// Send the rest of the chain
if ( pindex )
2013-10-10 14:07:44 -07:00
pindex = chainActive . Next ( pindex ) ;
2012-03-21 19:10:50 -07:00
int nLimit = 500 ;
2014-12-15 00:11:16 -08: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 ) ;
2013-10-10 14:07:44 -07:00
for ( ; pindex ; pindex = chainActive . Next ( pindex ) )
2010-08-29 09:58:15 -07:00
{
if ( pindex - > GetBlockHash ( ) = = hashStop )
{
2014-01-16 07:15:27 -08:00
LogPrint ( " net " , " getblocks stopping at %d %s \n " , pindex - > nHeight , pindex - > GetBlockHash ( ) . ToString ( ) ) ;
2010-08-29 09:58:15 -07:00
break ;
}
2015-05-12 17:56:50 -07:00
// If pruning, don't inv blocks unless we have on disk and are likely to still have
// for some reasonable time window (1 hour) that block relay might require.
const int nPrunedBlocksLikelyToHave = MIN_BLOCKS_TO_KEEP - 3600 / chainparams . GetConsensus ( ) . nPowTargetSpacing ;
if ( fPruneMode & & ( ! ( pindex - > nStatus & BLOCK_HAVE_DATA ) | | pindex - > nHeight < = chainActive . Tip ( ) - > nHeight - nPrunedBlocksLikelyToHave ) )
{
LogPrint ( " net " , " getblocks stopping, pruned or too old block at %d %s \n " , pindex - > nHeight , pindex - > GetBlockHash ( ) . ToString ( ) ) ;
break ;
}
2010-08-29 09:58:15 -07:00
pfrom - > PushInventory ( CInv ( MSG_BLOCK , pindex - > GetBlockHash ( ) ) ) ;
2012-03-21 19:10:50 -07:00
if ( - - nLimit < = 0 )
2010-08-29 09:58:15 -07:00
{
2015-04-28 07:47:17 -07: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 07:15:27 -08:00
LogPrint ( " net " , " getblocks stopping at limit %d %s \n " , pindex - > nHeight , pindex - > GetBlockHash ( ) . ToString ( ) ) ;
2010-08-29 09:58:15 -07:00
pfrom - > hashContinue = pindex - > GetBlockHash ( ) ;
break ;
}
}
}
2010-12-05 01:29:30 -08:00
else if ( strCommand = = " getheaders " )
{
CBlockLocator locator ;
uint256 hashStop ;
vRecv > > locator > > hashStop ;
2013-07-24 17:34:42 -07:00
LOCK ( cs_main ) ;
2015-05-21 10:29:09 -07:00
if ( IsInitialBlockDownload ( ) )
return true ;
2010-12-05 01:29:30 -08:00
CBlockIndex * pindex = NULL ;
if ( locator . IsNull ( ) )
{
// If locator is null, return the hashStop block
2014-09-03 17:02:44 -07:00
BlockMap : : iterator mi = mapBlockIndex . find ( hashStop ) ;
2010-12-05 01:29:30 -08:00
if ( mi = = mapBlockIndex . end ( ) )
return true ;
pindex = ( * mi ) . second ;
}
else
{
// Find the last block the caller has in the main chain
2014-09-02 17:52:01 -07:00
pindex = FindForkInGlobalIndex ( chainActive , locator ) ;
2010-12-05 01:29:30 -08:00
if ( pindex )
2013-10-10 14:07:44 -07:00
pindex = chainActive . Next ( pindex ) ;
2010-12-05 01:29:30 -08:00
}
2012-11-14 13:18:10 -08:00
// we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end
2010-12-05 01:29:30 -08:00
vector < CBlock > vHeaders ;
2014-07-11 15:02:35 -07:00
int nLimit = MAX_HEADERS_RESULTS ;
2014-09-02 03:16:32 -07:00
LogPrint ( " net " , " getheaders %d to %s from peer=%d \n " , ( pindex ? pindex - > nHeight : - 1 ) , hashStop . ToString ( ) , pfrom - > id ) ;
2013-10-10 14:07:44 -07:00
for ( ; pindex ; pindex = chainActive . Next ( pindex ) )
2010-12-05 01:29:30 -08:00
{
vHeaders . push_back ( pindex - > GetBlockHeader ( ) ) ;
if ( - - nLimit < = 0 | | pindex - > GetBlockHash ( ) = = hashStop )
break ;
}
pfrom - > PushMessage ( " headers " , vHeaders ) ;
}
2010-08-29 09:58:15 -07:00
else if ( strCommand = = " tx " )
{
vector < uint256 > vWorkQueue ;
2012-05-17 07:12:04 -07:00
vector < uint256 > vEraseQueue ;
2010-08-29 09:58:15 -07:00
CTransaction tx ;
vRecv > > tx ;
2016-08-30 12:49:38 -07:00
CInv inv ( MSG_TX , tx . GetHash ( ) ) ;
2010-08-29 09:58:15 -07:00
pfrom - > AddInventoryKnown ( inv ) ;
2013-07-24 17:34:42 -07:00
LOCK ( cs_main ) ;
2010-08-29 09:58:15 -07:00
bool fMissingInputs = false ;
2013-01-26 15:14:11 -08:00
CValidationState state ;
2014-07-03 01:28:38 -07:00
2015-11-22 17:54:23 -08:00
pfrom - > setAskFor . erase ( inv . hash ) ;
2014-07-03 01:28:38 -07:00
mapAlreadyAskedFor . erase ( inv ) ;
2015-11-26 13:05:34 -08:00
if ( ! AlreadyHave ( inv ) & & AcceptToMemoryPool ( mempool , state , tx , true , & fMissingInputs ) )
2010-08-29 09:58:15 -07:00
{
2013-11-04 17:47:07 -08:00
mempool . check ( pcoinsTip ) ;
2014-06-09 01:02:00 -07:00
RelayTransaction ( tx ) ;
2010-08-29 09:58:15 -07:00
vWorkQueue . push_back ( inv . hash ) ;
2015-01-08 02:44:25 -08:00
LogPrint ( " mempool " , " AcceptToMemoryPool: peer=%d %s: accepted %s (poolsz %u) \n " ,
2014-02-26 17:55:04 -08:00
pfrom - > id , pfrom - > cleanSubVer ,
2016-08-30 12:49:38 -07:00
tx . GetHash ( ) . ToString ( ) ,
2013-11-21 05:38:29 -08:00
mempool . mapTx . size ( ) ) ;
2010-08-29 09:58:15 -07:00
// Recursively process any orphan transactions that depended on this one
2014-08-28 10:23:24 -07:00
set < NodeId > setMisbehaving ;
2012-04-15 13:52:09 -07:00
for ( unsigned int i = 0 ; i < vWorkQueue . size ( ) ; i + + )
2010-08-29 09:58:15 -07:00
{
2014-09-08 08:37:26 -07:00
map < uint256 , set < uint256 > > : : iterator itByPrev = mapOrphanTransactionsByPrev . find ( vWorkQueue [ i ] ) ;
if ( itByPrev = = mapOrphanTransactionsByPrev . end ( ) )
continue ;
for ( set < uint256 > : : iterator mi = itByPrev - > second . begin ( ) ;
mi ! = itByPrev - > second . end ( ) ;
2010-08-29 09:58:15 -07:00
+ + mi )
{
2013-08-01 22:14:44 -07:00
const uint256 & orphanHash = * mi ;
2014-08-28 10:23:24 -07:00
const CTransaction & orphanTx = mapOrphanTransactions [ orphanHash ] . tx ;
NodeId fromPeer = mapOrphanTransactions [ orphanHash ] . fromPeer ;
2012-05-17 07:12:04 -07:00
bool fMissingInputs2 = false ;
2013-08-01 22:14:44 -07:00
// Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan
// resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get
// anyone relaying LegitTxX banned)
2013-01-30 19:53:21 -08:00
CValidationState stateDummy ;
2010-08-29 09:58:15 -07:00
2014-08-28 10:23:24 -07:00
if ( setMisbehaving . count ( fromPeer ) )
continue ;
2013-08-26 22:51:57 -07:00
if ( AcceptToMemoryPool ( mempool , stateDummy , orphanTx , true , & fMissingInputs2 ) )
2010-08-29 09:58:15 -07:00
{
2014-01-16 07:15:27 -08:00
LogPrint ( " mempool " , " accepted orphan tx %s \n " , orphanHash . ToString ( ) ) ;
2014-06-09 01:02:00 -07:00
RelayTransaction ( orphanTx ) ;
2013-08-01 22:14:44 -07:00
vWorkQueue . push_back ( orphanHash ) ;
2015-04-08 06:57:19 -07:00
vEraseQueue . push_back ( orphanHash ) ;
2012-05-17 07:12:04 -07:00
}
else if ( ! fMissingInputs2 )
{
2014-08-28 10:23:24 -07:00
int nDos = 0 ;
if ( stateDummy . IsInvalid ( nDos ) & & nDos > 0 )
{
// Punish peer that gave us an invalid orphan tx
Misbehaving ( fromPeer , nDos ) ;
setMisbehaving . insert ( fromPeer ) ;
LogPrint ( " mempool " , " invalid orphan tx %s \n " , orphanHash . ToString ( ) ) ;
}
2015-04-08 06:57:19 -07:00
// Has inputs but not accepted to mempool
// Probably non-standard or insufficient fee/priority
2014-01-16 07:15:27 -08:00
LogPrint ( " mempool " , " removed orphan tx %s \n " , orphanHash . ToString ( ) ) ;
2015-04-08 06:57:19 -07:00
vEraseQueue . push_back ( orphanHash ) ;
2015-07-31 08:55:05 -07:00
assert ( recentRejects ) ;
2015-07-17 03:46:48 -07:00
recentRejects - > insert ( orphanHash ) ;
2010-08-29 09:58:15 -07:00
}
2013-11-04 17:47:07 -08:00
mempool . check ( pcoinsTip ) ;
2010-08-29 09:58:15 -07:00
}
}
2012-05-17 07:12:04 -07:00
BOOST_FOREACH ( uint256 hash , vEraseQueue )
2010-08-29 09:58:15 -07:00
EraseOrphanTx ( hash ) ;
}
2018-10-05 10:48:03 -07:00
// TODO: currently, prohibit joinsplits and shielded spends/outputs from entering mapOrphans
else if ( fMissingInputs & &
tx . vjoinsplit . empty ( ) & &
tx . vShieldedSpend . empty ( ) & &
tx . vShieldedOutput . empty ( ) )
2010-08-29 09:58:15 -07:00
{
2014-08-28 10:23:24 -07:00
AddOrphanTx ( tx , pfrom - > GetId ( ) ) ;
2012-02-29 07:14:18 -08:00
// DoS prevention: do not allow mapOrphanTransactions to grow unbounded
2014-09-10 11:08:03 -07:00
unsigned int nMaxOrphanTx = ( unsigned int ) std : : max ( ( int64_t ) 0 , GetArg ( " -maxorphantx " , DEFAULT_MAX_ORPHAN_TRANSACTIONS ) ) ;
unsigned int nEvicted = LimitOrphanTxSize ( nMaxOrphanTx ) ;
2012-02-29 07:14:18 -08:00
if ( nEvicted > 0 )
2013-09-18 03:38:08 -07:00
LogPrint ( " mempool " , " mapOrphan overflow, removed %u tx \n " , nEvicted ) ;
2015-07-17 03:46:48 -07:00
} else {
2015-08-24 14:02:24 -07:00
assert ( recentRejects ) ;
2016-08-30 12:49:38 -07:00
recentRejects - > insert ( tx . GetHash ( ) ) ;
2015-08-24 14:02:24 -07:00
2015-07-17 03:46:48 -07:00
if ( pfrom - > fWhitelisted ) {
// Always relay transactions received from whitelisted peers, even
2015-11-26 13:05:34 -08:00
// if they were already in the mempool or rejected from it due
// to policy, allowing the node to function as a gateway for
// nodes hidden behind it.
2015-07-17 03:46:48 -07:00
//
2015-11-26 13:05:34 -08:00
// Never relay transactions that we would assign a non-zero DoS
// score for, as we expect peers to do the same with us in that
// case.
int nDoS = 0 ;
if ( ! state . IsInvalid ( nDoS ) | | nDoS = = 0 ) {
LogPrintf ( " Force relaying tx %s from whitelisted peer=%d \n " , tx . GetHash ( ) . ToString ( ) , pfrom - > id ) ;
RelayTransaction ( tx ) ;
} else {
2016-09-19 09:36:26 -07:00
LogPrintf ( " Not relaying invalid transaction %s from whitelisted peer=%d (%s (code %d)) \n " ,
2016-09-16 17:51:46 -07:00
tx . GetHash ( ) . ToString ( ) , pfrom - > id , state . GetRejectReason ( ) , state . GetRejectCode ( ) ) ;
2015-11-26 13:05:34 -08:00
}
2015-07-17 03:46:48 -07:00
}
2010-08-29 09:58:15 -07:00
}
2013-10-01 07:26:42 -07:00
int nDoS = 0 ;
2013-10-06 23:55:04 -07:00
if ( state . IsInvalid ( nDoS ) )
2014-02-10 07:31:06 -08:00
{
2016-08-30 12:49:38 -07:00
LogPrint ( " mempool " , " %s from peer=%d %s was not accepted into the memory pool: %s \n " , tx . GetHash ( ) . ToString ( ) ,
2014-02-26 17:55:04 -08:00
pfrom - > id , pfrom - > cleanSubVer ,
2014-01-16 07:15:27 -08:00
state . GetRejectReason ( ) ) ;
2013-10-27 23:36:11 -07:00
pfrom - > PushMessage ( " reject " , strCommand , state . GetRejectCode ( ) ,
2014-11-29 07:01:37 -08:00
state . GetRejectReason ( ) . substr ( 0 , MAX_REJECT_MESSAGE_LENGTH ) , inv . hash ) ;
2013-10-06 23:55:04 -07:00
if ( nDoS > 0 )
2013-11-17 16:25:17 -08:00
Misbehaving ( pfrom - > GetId ( ) , nDoS ) ;
2013-10-27 23:36:11 -07:00
}
2010-08-29 09:58:15 -07:00
}
2014-07-11 15:02:35 -07:00
else if ( strCommand = = " headers " & & ! fImporting & & ! fReindex ) // Ignore headers received while importing
{
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.
}
LOCK ( cs_main ) ;
if ( nCount = = 0 ) {
// Nothing interesting. Stop asking this peers for more headers.
return true ;
}
CBlockIndex * pindexLast = NULL ;
BOOST_FOREACH ( const CBlockHeader & header , headers ) {
CValidationState state ;
if ( pindexLast ! = NULL & & header . hashPrevBlock ! = pindexLast - > GetBlockHash ( ) ) {
Misbehaving ( pfrom - > GetId ( ) , 20 ) ;
return error ( " non-continuous headers sequence " ) ;
}
2015-11-10 10:28:56 -08:00
if ( ! AcceptBlockHeader ( header , state , chainparams , & pindexLast ) ) {
2014-07-11 15:02:35 -07:00
int nDoS ;
if ( state . IsInvalid ( nDoS ) ) {
if ( nDoS > 0 )
Misbehaving ( pfrom - > GetId ( ) , nDoS ) ;
return error ( " invalid header received " ) ;
}
}
}
if ( pindexLast )
UpdateBlockAvailability ( pfrom - > GetId ( ) , pindexLast - > GetBlockHash ( ) ) ;
if ( nCount = = MAX_HEADERS_RESULTS & & pindexLast ) {
// 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.
2014-09-02 03:16:32 -07:00
LogPrint ( " net " , " more getheaders (%d) to end to peer=%d (startheight:%d) \n " , pindexLast - > nHeight , pfrom - > id , pfrom - > nStartingHeight ) ;
2014-12-15 00:11:16 -08:00
pfrom - > PushMessage ( " getheaders " , chainActive . GetLocator ( pindexLast ) , uint256 ( ) ) ;
2014-07-11 15:02:35 -07:00
}
2015-03-13 09:25:34 -07:00
2015-04-17 05:19:21 -07:00
CheckBlockIndex ( chainparams . GetConsensus ( ) ) ;
2014-07-11 15:02:35 -07:00
}
2012-10-21 12:23:13 -07:00
else if ( strCommand = = " block " & & ! fImporting & & ! fReindex ) // Ignore blocks received while importing
2010-08-29 09:58:15 -07:00
{
2010-12-05 01:29:30 -08:00
CBlock block ;
vRecv > > block ;
2010-08-29 09:58:15 -07:00
2010-12-05 01:29:30 -08:00
CInv inv ( MSG_BLOCK , block . GetHash ( ) ) ;
2014-07-11 15:02:35 -07:00
LogPrint ( " net " , " received block %s peer=%d \n " , inv . hash . ToString ( ) , pfrom - > id ) ;
2010-08-29 09:58:15 -07:00
2014-07-11 15:02:35 -07:00
pfrom - > AddInventoryKnown ( inv ) ;
2013-07-24 17:34:42 -07:00
2013-01-26 15:14:11 -08:00
CValidationState state ;
2015-06-02 12:17:36 -07:00
// Process all blocks from whitelisted peers, even if not requested,
// unless we're still syncing with the network.
// Such an unrequested block may still be processed, subject to the
// conditions in AcceptBlock().
bool forceProcessing = pfrom - > fWhitelisted & & ! IsInitialBlockDownload ( ) ;
2015-04-19 15:17:11 -07:00
ProcessNewBlock ( state , chainparams , pfrom , & block , forceProcessing , NULL ) ;
2014-07-06 05:47:23 -07:00
int nDoS ;
if ( state . IsInvalid ( nDoS ) ) {
pfrom - > PushMessage ( " reject " , strCommand , state . GetRejectCode ( ) ,
2014-11-29 07:01:37 -08:00
state . GetRejectReason ( ) . substr ( 0 , MAX_REJECT_MESSAGE_LENGTH ) , inv . hash ) ;
2014-07-06 05:47:23 -07:00
if ( nDoS > 0 ) {
LOCK ( cs_main ) ;
Misbehaving ( pfrom - > GetId ( ) , nDoS ) ;
}
}
2010-08-29 09:58:15 -07:00
}
2014-12-07 08:30:57 -08:00
// This asymmetric behavior for inbound and outbound connections was introduced
// to prevent a fingerprinting attack: an attacker can send specific fake addresses
2015-04-28 07:47:17 -07:00
// 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.
2014-12-07 08:30:57 -08:00
else if ( ( strCommand = = " getaddr " ) & & ( pfrom - > fInbound ) )
2010-08-29 09:58:15 -07:00
{
2016-04-10 18:09:34 -07: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 09:58:15 -07:00
pfrom - > vAddrToSend . clear ( ) ;
2012-01-04 14:39:45 -08:00
vector < CAddress > vAddr = addrman . GetAddr ( ) ;
BOOST_FOREACH ( const CAddress & addr , vAddr )
pfrom - > PushAddress ( addr ) ;
2010-08-29 09:58:15 -07:00
}
2012-07-31 14:42:35 -07:00
else if ( strCommand = = " mempool " )
{
2018-11-06 17:33:27 -08:00
int currentHeight = GetHeight ( ) ;
2013-08-26 22:51:57 -07:00
LOCK2 ( cs_main , pfrom - > cs_filter ) ;
2013-07-24 17:34:42 -07:00
2012-07-31 14:42:35 -07:00
std : : vector < uint256 > vtxid ;
mempool . queryHashes ( vtxid ) ;
vector < CInv > vInv ;
2013-01-10 11:06:30 -08:00
BOOST_FOREACH ( uint256 & hash , vtxid ) {
2018-11-06 17:33:27 -08:00
CTransaction tx ;
bool fInMemPool = mempool . lookup ( hash , tx ) ;
if ( fInMemPool & & IsExpiringSoonTx ( tx , currentHeight + 1 ) ) {
continue ;
}
2013-01-10 11:06:30 -08:00
CInv inv ( MSG_TX , hash ) ;
2015-12-05 01:45:44 -08:00
if ( pfrom - > pfilter ) {
if ( ! fInMemPool ) continue ; // another thread removed since queryHashes, maybe...
if ( ! pfrom - > pfilter - > IsRelevantAndUpdate ( tx ) ) continue ;
}
vInv . push_back ( inv ) ;
2013-08-26 23:12:43 -07:00
if ( vInv . size ( ) = = MAX_INV_SZ ) {
pfrom - > PushMessage ( " inv " , vInv ) ;
vInv . clear ( ) ;
}
2012-07-31 14:42:35 -07:00
}
if ( vInv . size ( ) > 0 )
pfrom - > PushMessage ( " inv " , vInv ) ;
}
2010-08-29 09:58:15 -07:00
else if ( strCommand = = " ping " )
{
2017-06-23 17:19:25 -07:00
if ( pfrom - > nVersion > BIP0031_VERSION )
{
uint64_t nonce = 0 ;
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.
pfrom - > PushMessage ( " pong " , nonce ) ;
}
2010-08-29 09:58:15 -07:00
}
2013-08-22 04:34:33 -07:00
else if ( strCommand = = " pong " )
{
2014-07-06 07:06:46 -07:00
int64_t pingUsecEnd = nTimeReceived ;
2013-04-12 22:13:08 -07: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 07:20:39 -08:00
2013-08-22 04:34:33 -07:00
if ( nAvail > = sizeof ( nonce ) ) {
vRecv > > nonce ;
2013-11-11 07:20:39 -08: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-12 22:13:08 -07: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 07:48:28 -07: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 07:48:28 -07: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 07:20:39 -08:00
2013-08-22 04:34:33 -07:00
if ( ! ( sProblem . empty ( ) ) ) {
2014-02-26 17:55:04 -08:00
LogPrint ( " net " , " pong peer=%d %s: %s, %x expected, %x received, %u bytes \n " ,
pfrom - > id ,
2014-01-16 07:15:27 -08:00
pfrom - > cleanSubVer ,
sProblem ,
2013-10-15 05:50:58 -07:00
pfrom - > nPingNonceSent ,
nonce ,
nAvail ) ;
2013-08-22 04:34:33 -07:00
}
if ( bPingFinished ) {
pfrom - > nPingNonceSent = 0 ;
}
}
2013-11-11 07:20:39 -08:00
2015-06-12 03:00:39 -07:00
else if ( fAlerts & & strCommand = = " alert " )
2010-08-29 09:58:15 -07:00
{
CAlert alert ;
vRecv > > alert ;
2012-08-26 14:08:18 -07:00
uint256 alertHash = alert . GetHash ( ) ;
if ( pfrom - > setKnown . count ( alertHash ) = = 0 )
2010-08-29 09:58:15 -07:00
{
2015-04-17 05:40:24 -07:00
if ( alert . ProcessAlert ( chainparams . AlertKey ( ) ) )
2012-04-06 09:39:12 -07:00
{
2012-08-26 14:08:18 -07:00
// Relay
pfrom - > setKnown . insert ( alertHash ) ;
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
alert . RelayTo ( pnode ) ;
}
}
else {
// Small DoS penalty so peers that send us lots of
// duplicate/expired/invalid-signature/whatever alerts
// eventually get banned.
// This isn't a Misbehaving(100) (immediate ban) because the
// peer might be an older or different implementation with
// a different signature key, etc.
2013-11-17 16:25:17 -08:00
Misbehaving ( pfrom - > GetId ( ) , 10 ) ;
2012-04-06 09:39:12 -07:00
}
2010-08-29 09:58:15 -07:00
}
}
2018-04-04 04:19:30 -07:00
else if ( ! ( nLocalServices & NODE_BLOOM ) & &
( strCommand = = " filterload " | |
2016-09-12 19:10:22 -07:00
strCommand = = " filteradd " ) )
2018-04-04 04:19:30 -07:00
{
if ( pfrom - > nVersion > = NO_BLOOM_VERSION ) {
Misbehaving ( pfrom - > GetId ( ) , 100 ) ;
return false ;
} else if ( GetBoolArg ( " -enforcenodebloom " , false ) ) {
pfrom - > fDisconnect = true ;
return false ;
}
}
2012-08-12 20:26:29 -07:00
else if ( strCommand = = " filterload " )
{
CBloomFilter filter ;
vRecv > > filter ;
if ( ! filter . IsWithinSizeConstraints ( ) )
// There is no excuse for sending a too-large filter
2013-11-17 16:25:17 -08:00
Misbehaving ( pfrom - > GetId ( ) , 100 ) ;
2012-08-12 20:26:29 -07:00
else
{
LOCK ( pfrom - > cs_filter ) ;
delete pfrom - > pfilter ;
pfrom - > pfilter = new CBloomFilter ( filter ) ;
2013-08-20 17:41:42 -07:00
pfrom - > pfilter - > UpdateEmptyFull ( ) ;
2012-08-12 20:26:29 -07:00
}
2012-08-20 18:10:25 -07:00
pfrom - > fRelayTxes = true ;
2012-08-12 20:26:29 -07:00
}
else if ( strCommand = = " filteradd " )
{
vector < unsigned char > vData ;
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
2013-01-18 10:55:18 -08:00
if ( vData . size ( ) > MAX_SCRIPT_ELEMENT_SIZE )
2012-08-12 20:26:29 -07:00
{
2013-11-17 16:25:17 -08:00
Misbehaving ( pfrom - > GetId ( ) , 100 ) ;
2012-08-12 20:26:29 -07:00
} else {
LOCK ( pfrom - > cs_filter ) ;
if ( pfrom - > pfilter )
pfrom - > pfilter - > insert ( vData ) ;
else
2013-11-17 16:25:17 -08:00
Misbehaving ( pfrom - > GetId ( ) , 100 ) ;
2012-08-12 20:26:29 -07:00
}
}
else if ( strCommand = = " filterclear " )
{
LOCK ( pfrom - > cs_filter ) ;
2016-09-12 19:10:22 -07:00
if ( nLocalServices & NODE_BLOOM ) {
delete pfrom - > pfilter ;
pfrom - > pfilter = new CBloomFilter ( ) ;
}
2012-08-20 18:10:25 -07:00
pfrom - > fRelayTxes = true ;
2012-08-12 20:26:29 -07:00
}
2013-10-27 23:36:11 -07:00
else if ( strCommand = = " reject " )
{
2014-09-12 07:37:53 -07:00
if ( fDebug ) {
try {
string strMsg ; unsigned char ccode ; string strReason ;
2014-11-29 07:01:37 -08:00
vRecv > > LIMITED_STRING ( strMsg , CMessageHeader : : COMMAND_SIZE ) > > ccode > > LIMITED_STRING ( strReason , MAX_REJECT_MESSAGE_LENGTH ) ;
2013-10-27 23:36:11 -07:00
2014-09-12 07:37:53 -07:00
ostringstream ss ;
ss < < strMsg < < " code " < < itostr ( ccode ) < < " : " < < strReason ;
2013-10-27 23:36:11 -07:00
2014-09-12 07:37:53 -07:00
if ( strMsg = = " block " | | strMsg = = " tx " )
{
uint256 hash ;
vRecv > > hash ;
ss < < " : hash " < < hash . ToString ( ) ;
}
LogPrint ( " net " , " Reject %s \n " , SanitizeString ( ss . str ( ) ) ) ;
2014-12-07 04:29:06 -08:00
} catch ( const std : : ios_base : : failure & ) {
2014-09-12 07:37:53 -07:00
// Avoid feedback loops by preventing reject messages from triggering a new reject message.
LogPrint ( " net " , " Unparseable reject message received \n " ) ;
2013-10-27 23:36:11 -07:00
}
}
}
2016-10-22 09:49:35 -07:00
else if ( strCommand = = " notfound " ) {
2016-07-29 08:42:12 -07:00
// We do not care about the NOTFOUND message, but logging an Unknown Command
// message would be undesirable as we transmit it ourselves.
}
else {
2010-08-29 09:58:15 -07:00
// Ignore unknown commands for extensibility
2014-06-26 21:03:24 -07:00
LogPrint ( " net " , " Unknown command \" %s \" from peer=%d \n " , SanitizeString ( strCommand ) , pfrom - > id ) ;
2010-08-29 09:58:15 -07:00
}
return true ;
}
2012-11-15 16:41:12 -08:00
// requires LOCK(cs_vRecvMsg)
2011-06-01 09:27:05 -07:00
bool ProcessMessages ( CNode * pfrom )
{
2015-04-17 05:19:21 -07:00
const CChainParams & chainparams = Params ( ) ;
2011-06-01 09:27:05 -07:00
//if (fDebug)
2015-02-24 09:32:34 -08:00
// LogPrintf("%s(%u messages)\n", __func__, pfrom->vRecvMsg.size());
2010-08-29 09:58:15 -07:00
2011-06-01 09:27:05 -07:00
//
// Message format
// (4) message start
// (12) command
// (4) size
// (4) checksum
// (x) data
//
2013-02-28 16:41:28 -08:00
bool fOk = true ;
2010-08-29 09:58:15 -07:00
2013-03-29 15:49:38 -07:00
if ( ! pfrom - > vRecvGetData . empty ( ) )
2015-04-17 05:19:21 -07:00
ProcessGetData ( pfrom , chainparams . GetConsensus ( ) ) ;
2013-11-11 07:20:39 -08:00
2013-10-28 13:20:21 -07:00
// this maintains the order of responses
if ( ! pfrom - > vRecvGetData . empty ( ) ) return fOk ;
2013-11-11 07:20:39 -08:00
2013-02-28 16:41:28 -08:00
std : : deque < CNetMessage > : : iterator it = pfrom - > vRecvMsg . begin ( ) ;
2013-03-24 08:52:24 -07:00
while ( ! pfrom - > fDisconnect & & it ! = pfrom - > vRecvMsg . end ( ) ) {
2012-03-21 19:10:50 -07:00
// Don't bother if send buffer is too full to respond anyway
2013-03-24 08:52:24 -07:00
if ( pfrom - > nSendSize > = SendBufferSize ( ) )
2012-03-21 19:10:50 -07:00
break ;
2013-02-28 16:41:28 -08:00
// get next message
CNetMessage & msg = * it ;
2012-11-15 16:41:12 -08:00
//if (fDebug)
2015-02-24 09:32:34 -08:00
// LogPrintf("%s(message %u msgsz, %u bytes, complete:%s)\n", __func__,
2012-11-15 16:41:12 -08:00
// msg.hdr.nMessageSize, msg.vRecv.size(),
// msg.complete() ? "Y" : "N");
2013-02-28 16:41:28 -08:00
// end, if an incomplete message is found
2012-11-15 16:41:12 -08:00
if ( ! msg . complete ( ) )
2011-06-01 09:27:05 -07:00
break ;
2012-11-15 16:41:12 -08:00
2013-02-28 16:41:28 -08:00
// at this point, any failure means we can delete the current message
it + + ;
2012-11-15 16:41:12 -08:00
// Scan for message start
2015-04-17 05:19:21 -07:00
if ( memcmp ( msg . hdr . pchMessageStart , chainparams . MessageStart ( ) , MESSAGE_START_SIZE ) ! = 0 ) {
2015-02-07 16:59:58 -08:00
LogPrintf ( " PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d \n " , SanitizeString ( msg . hdr . GetCommand ( ) ) , pfrom - > id ) ;
2013-02-28 16:41:28 -08:00
fOk = false ;
break ;
2011-06-01 09:27:05 -07:00
}
2010-08-29 09:58:15 -07:00
2011-06-01 09:27:05 -07:00
// Read header
2012-11-15 16:41:12 -08:00
CMessageHeader & hdr = msg . hdr ;
2015-04-17 05:19:21 -07:00
if ( ! hdr . IsValid ( chainparams . MessageStart ( ) ) )
2011-06-01 09:27:05 -07:00
{
2015-02-07 16:59:58 -08:00
LogPrintf ( " PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d \n " , SanitizeString ( hdr . GetCommand ( ) ) , pfrom - > id ) ;
2011-06-01 09:27:05 -07:00
continue ;
}
string strCommand = hdr . GetCommand ( ) ;
// Message size
unsigned int nMessageSize = hdr . nMessageSize ;
// Checksum
2012-11-15 16:41:12 -08:00
CDataStream & vRecv = msg . vRecv ;
2012-02-19 16:33:31 -08:00
uint256 hash = Hash ( vRecv . begin ( ) , vRecv . begin ( ) + nMessageSize ) ;
2014-12-19 02:38:30 -08:00
unsigned int nChecksum = ReadLE32 ( ( unsigned char * ) & hash ) ;
2012-02-19 16:33:31 -08:00
if ( nChecksum ! = hdr . nChecksum )
2011-06-01 09:27:05 -07:00
{
2015-02-24 09:32:34 -08:00
LogPrintf ( " %s(%s, %u bytes): CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x \n " , __func__ ,
2015-02-07 16:59:58 -08:00
SanitizeString ( strCommand ) , nMessageSize , nChecksum , hdr . nChecksum ) ;
2012-02-19 16:33:31 -08:00
continue ;
2011-06-01 09:27:05 -07:00
}
// Process message
bool fRet = false ;
try
{
2014-07-06 07:06:46 -07:00
fRet = ProcessMessage ( pfrom , strCommand , vRecv , msg . nTime ) ;
2013-03-09 09:02:57 -08:00
boost : : this_thread : : interruption_point ( ) ;
2011-06-01 09:27:05 -07:00
}
2014-12-07 04:29:06 -08:00
catch ( const std : : ios_base : : failure & e )
2011-06-01 09:27:05 -07:00
{
2013-10-27 23:36:11 -07:00
pfrom - > PushMessage ( " reject " , strCommand , REJECT_MALFORMED , string ( " error parsing message " ) ) ;
2011-06-01 09:27:05 -07:00
if ( strstr ( e . what ( ) , " end of data " ) )
{
2012-07-25 17:48:39 -07:00
// Allow exceptions from under-length message on vRecv
2015-02-24 09:32:34 -08: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 09:27:05 -07:00
}
else if ( strstr ( e . what ( ) , " size too large " ) )
{
2012-07-25 17:48:39 -07:00
// Allow exceptions from over-long size
2015-02-24 09:32:34 -08:00
LogPrintf ( " %s(%s, %u bytes): Exception '%s' caught \n " , __func__ , SanitizeString ( strCommand ) , nMessageSize , e . what ( ) ) ;
2011-06-01 09:27:05 -07:00
}
else
{
2012-05-22 04:06:08 -07:00
PrintExceptionContinue ( & e , " ProcessMessages() " ) ;
2011-06-01 09:27:05 -07:00
}
}
2014-12-07 04:29:06 -08:00
catch ( const boost : : thread_interrupted & ) {
2013-03-09 09:02:57 -08:00
throw ;
}
2014-12-07 04:29:06 -08:00
catch ( const std : : exception & e ) {
2012-05-22 04:06:08 -07:00
PrintExceptionContinue ( & e , " ProcessMessages() " ) ;
2011-06-01 09:27:05 -07:00
} catch ( . . . ) {
2012-05-22 04:06:08 -07:00
PrintExceptionContinue ( NULL , " ProcessMessages() " ) ;
2011-06-01 09:27:05 -07:00
}
if ( ! fRet )
2015-02-24 09:32:34 -08:00
LogPrintf ( " %s(%s, %u bytes) FAILED peer=%d \n " , __func__ , SanitizeString ( strCommand ) , nMessageSize , pfrom - > id ) ;
2013-11-11 07:20:39 -08:00
2013-10-28 13:20:21 -07:00
break ;
2011-06-01 09:27:05 -07:00
}
2013-03-24 08:52:24 -07:00
// In case the connection got shut down, its receive buffer was wiped
if ( ! pfrom - > fDisconnect )
pfrom - > vRecvMsg . erase ( pfrom - > vRecvMsg . begin ( ) , it ) ;
2013-02-28 16:41:28 -08:00
return fOk ;
2011-06-01 09:27:05 -07:00
}
2010-08-29 09:58:15 -07:00
bool SendMessages ( CNode * pto , bool fSendTrickle )
{
2015-04-10 09:35:09 -07:00
const Consensus : : Params & consensusParams = Params ( ) . GetConsensus ( ) ;
2013-07-20 05:34:16 -07:00
{
2015-04-28 07:47:17 -07:00
// Don't send anything until we get its version message
2010-08-29 09:58:15 -07: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-14 15:34:20 -07: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-12 22:13:08 -07:00
uint64_t nonce = 0 ;
2013-08-22 04:34:33 -07:00
while ( nonce = = 0 ) {
2014-06-24 05:27:32 -07:00
GetRandBytes ( ( unsigned char * ) & nonce , sizeof ( nonce ) ) ;
2013-08-22 04:34:33 -07:00
}
pto - > fPingQueued = false ;
2013-10-14 15:34:20 -07:00
pto - > nPingUsecStart = GetTimeMicros ( ) ;
2017-06-23 17:19:25 -07:00
if ( pto - > nVersion > BIP0031_VERSION ) {
pto - > nPingNonceSent = nonce ;
pto - > PushMessage ( " ping " , nonce ) ;
} else {
// Peer is too old to support ping command with nonce, pong will never arrive.
pto - > nPingNonceSent = 0 ;
pto - > PushMessage ( " ping " ) ;
}
2012-04-11 09:38:03 -07:00
}
2010-08-29 09:58:15 -07:00
2014-04-15 08:38:25 -07:00
TRY_LOCK ( cs_main , lockMain ) ; // Acquire cs_main for IsInitialBlockDownload() and CNodeState()
if ( ! lockMain )
return true ;
2010-08-29 09:58:15 -07:00
// Address refresh broadcast
2013-04-12 22:13:08 -07:00
static int64_t nLastRebroadcast ;
2012-02-01 15:08:03 -08:00
if ( ! IsInitialBlockDownload ( ) & & ( GetTime ( ) - nLastRebroadcast > 24 * 60 * 60 ) )
2010-08-29 09:58:15 -07:00
{
2014-07-20 23:32:25 -07:00
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
2010-08-29 09:58:15 -07:00
{
2015-04-25 13:25:44 -07:00
// Periodically clear addrKnown to allow refresh broadcasts
2014-07-20 23:32:25 -07:00
if ( nLastRebroadcast )
2015-07-19 12:43:34 -07:00
pnode - > addrKnown . reset ( ) ;
2010-08-29 09:58:15 -07:00
2014-07-20 23:32:25 -07:00
// Rebroadcast our address
AdvertizeLocal ( pnode ) ;
2010-08-29 09:58:15 -07:00
}
2014-07-20 23:32:25 -07:00
if ( ! vNodes . empty ( ) )
nLastRebroadcast = GetTime ( ) ;
2010-08-29 09:58:15 -07:00
}
//
// Message: addr
//
if ( fSendTrickle )
{
vector < CAddress > vAddr ;
vAddr . reserve ( pto - > vAddrToSend . size ( ) ) ;
2011-05-15 00:11:04 -07:00
BOOST_FOREACH ( const CAddress & addr , pto - > vAddrToSend )
2010-08-29 09:58:15 -07:00
{
2015-04-25 13:25:44 -07:00
if ( ! pto - > addrKnown . contains ( addr . GetKey ( ) ) )
2010-08-29 09:58:15 -07:00
{
2015-04-25 13:25:44 -07:00
pto - > addrKnown . insert ( addr . GetKey ( ) ) ;
2010-08-29 09:58:15 -07:00
vAddr . push_back ( addr ) ;
// receiver rejects addr messages larger than 1000
if ( vAddr . size ( ) > = 1000 )
{
pto - > PushMessage ( " addr " , vAddr ) ;
vAddr . clear ( ) ;
}
}
}
pto - > vAddrToSend . clear ( ) ;
if ( ! vAddr . empty ( ) )
pto - > PushMessage ( " addr " , vAddr ) ;
}
2013-11-16 10:28:24 -08:00
CNodeState & state = * State ( pto - > GetId ( ) ) ;
if ( state . fShouldBan ) {
2014-06-21 04:34:36 -07:00
if ( pto - > fWhitelisted )
LogPrintf ( " Warning: not punishing whitelisted peer %s! \n " , pto - > addr . ToString ( ) ) ;
2013-11-17 16:25:17 -08:00
else {
pto - > fDisconnect = true ;
2014-06-21 04:34:36 -07:00
if ( pto - > addr . IsLocal ( ) )
LogPrintf ( " Warning: not banning local peer %s! \n " , pto - > addr . ToString ( ) ) ;
else
2014-08-28 10:23:24 -07:00
{
2014-06-21 04:34:36 -07:00
CNode : : Ban ( pto - > addr ) ;
2014-08-28 10:23:24 -07:00
}
2013-11-17 16:25:17 -08:00
}
2013-11-16 10:28:24 -08:00
state . fShouldBan = false ;
2013-11-17 16:25:17 -08:00
}
2013-11-16 10:28:24 -08:00
BOOST_FOREACH ( const CBlockReject & reject , state . rejects )
pto - > PushMessage ( " reject " , ( string ) " block " , reject . chRejectCode , reject . strRejectReason , reject . hashBlock ) ;
state . rejects . clear ( ) ;
2013-07-20 05:34:16 -07:00
// Start block sync
2014-07-11 15:02:35 -07:00
if ( pindexBestHeader = = NULL )
pindexBestHeader = chainActive . Tip ( ) ;
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.
2015-01-12 06:55:48 -08:00
if ( ! state . fSyncStarted & & ! pto - > fClient & & ! fImporting & & ! fReindex ) {
2014-07-11 15:02:35 -07:00
// Only actively request headers from a single peer, unless we're close to today.
2015-01-12 06:55:48 -08:00
if ( ( nSyncStarted = = 0 & & fFetch ) | | pindexBestHeader - > GetBlockTime ( ) > GetAdjustedTime ( ) - 24 * 60 * 60 ) {
2014-07-11 15:02:35 -07:00
state . fSyncStarted = true ;
nSyncStarted + + ;
CBlockIndex * pindexStart = pindexBestHeader - > pprev ? pindexBestHeader - > pprev : pindexBestHeader ;
2014-09-02 03:16:32 -07:00
LogPrint ( " net " , " initial getheaders (%d) to peer=%d (startheight:%d) \n " , pindexStart - > nHeight , pto - > id , pto - > nStartingHeight ) ;
2014-12-15 00:11:16 -08:00
pto - > PushMessage ( " getheaders " , chainActive . GetLocator ( pindexStart ) , uint256 ( ) ) ;
2014-07-11 15:02:35 -07:00
}
2013-07-20 05:34:16 -07: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.
if ( ! fReindex & & ! fImporting & & ! IsInitialBlockDownload ( ) )
{
2015-03-23 10:47:18 -07:00
GetMainSignals ( ) . Broadcast ( nTimeBestReceived ) ;
2013-07-20 05:34:16 -07:00
}
2010-08-29 09:58:15 -07:00
//
// Message: inventory
//
vector < CInv > vInv ;
vector < CInv > vInvWait ;
{
2012-04-06 09:39:12 -07:00
LOCK ( pto - > cs_inventory ) ;
2010-08-29 09:58:15 -07:00
vInv . reserve ( pto - > vInventoryToSend . size ( ) ) ;
vInvWait . reserve ( pto - > vInventoryToSend . size ( ) ) ;
2011-05-15 00:11:04 -07:00
BOOST_FOREACH ( const CInv & inv , pto - > vInventoryToSend )
2010-08-29 09:58:15 -07:00
{
if ( pto - > setInventoryKnown . count ( inv ) )
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 00:11:16 -08:00
if ( hashSalt . IsNull ( ) )
2012-05-17 09:13:14 -07:00
hashSalt = GetRandHash ( ) ;
2014-12-16 06:43:03 -08:00
uint256 hashRand = ArithToUint256 ( UintToArith256 ( inv . hash ) ^ UintToArith256 ( hashSalt ) ) ;
2010-08-29 09:58:15 -07:00
hashRand = Hash ( BEGIN ( hashRand ) , END ( hashRand ) ) ;
2014-12-16 06:43:03 -08:00
bool fTrickleWait = ( ( UintToArith256 ( hashRand ) & 3 ) ! = 0 ) ;
2010-08-29 09:58:15 -07:00
if ( fTrickleWait )
{
vInvWait . push_back ( inv ) ;
continue ;
}
}
// returns true if wasn't already contained in the set
if ( pto - > setInventoryKnown . insert ( inv ) . second )
{
vInv . push_back ( inv ) ;
if ( vInv . size ( ) > = 1000 )
{
pto - > PushMessage ( " inv " , vInv ) ;
vInv . clear ( ) ;
}
}
}
pto - > vInventoryToSend = vInvWait ;
}
if ( ! vInv . empty ( ) )
pto - > PushMessage ( " inv " , vInv ) ;
2014-07-11 15:02:35 -07:00
// Detect whether we're stalling
2014-01-10 04:23:26 -08:00
int64_t nNow = GetTimeMicros ( ) ;
2014-07-11 15:02:35 -07: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.
LogPrintf ( " Peer=%d is stalling block download, disconnecting \n " , pto - > id ) ;
2014-01-10 04:23:26 -08:00
pto - > fDisconnect = true ;
}
2015-01-12 09:53:10 -08:00
// In case there is a block that has been in flight from this peer for (2 + 0.5 * N) times the block interval
2015-01-06 08:05:46 -08:00
// (with N the number of validated blocks that were in flight at the time it was requested), disconnect due to
// timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link
2015-04-28 07:48:28 -07:00
// being saturated. We only count validated in-flight blocks so peers can't advertise non-existing block hashes
2015-01-06 08:05:46 -08:00
// to unreasonably increase our timeout.
2015-04-06 10:10:33 -07:00
// We also compare the block download timeout originally calculated against the time at which we'd disconnect
// if we assumed the block were being requested now (ignoring blocks we've requested from this peer, since we're
// only looking at this peer's oldest request). This way a large queue in the past doesn't result in a
// permanently large window for this block to be delivered (ie if the number of blocks in flight is decreasing
// more quickly than once every 5 minutes, then we'll shorten the download window for this block).
if ( ! pto - > fDisconnect & & state . vBlocksInFlight . size ( ) > 0 ) {
QueuedBlock & queuedBlock = state . vBlocksInFlight . front ( ) ;
2015-05-27 07:57:17 -07:00
int64_t nTimeoutIfRequestedNow = GetBlockTimeout ( nNow , nQueuedValidatedHeaders - state . nBlocksInFlightValidHeaders , consensusParams ) ;
2015-04-06 10:10:33 -07:00
if ( queuedBlock . nTimeDisconnect > nTimeoutIfRequestedNow ) {
LogPrint ( " net " , " Reducing block download timeout for peer=%d block=%s, orig=%d new=%d \n " , pto - > id , queuedBlock . hash . ToString ( ) , queuedBlock . nTimeDisconnect , nTimeoutIfRequestedNow ) ;
queuedBlock . nTimeDisconnect = nTimeoutIfRequestedNow ;
}
if ( queuedBlock . nTimeDisconnect < nNow ) {
LogPrintf ( " Timeout downloading block %s from peer=%d, disconnecting \n " , queuedBlock . hash . ToString ( ) , pto - > id ) ;
pto - > fDisconnect = true ;
}
2015-01-06 08:05:46 -08:00
}
2014-01-10 04:23:26 -08:00
2010-08-29 09:58:15 -07:00
//
2014-01-10 04:23:26 -08:00
// Message: getdata (blocks)
2010-08-29 09:58:15 -07:00
//
vector < CInv > vGetData ;
2015-01-12 06:55:48 -08:00
if ( ! pto - > fDisconnect & & ! pto - > fClient & & ( fFetch | | ! IsInitialBlockDownload ( ) ) & & state . nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER ) {
2014-07-11 15:02:35 -07:00
vector < CBlockIndex * > vToDownload ;
NodeId staller = - 1 ;
FindNextBlocksToDownload ( pto - > GetId ( ) , MAX_BLOCKS_IN_TRANSIT_PER_PEER - state . nBlocksInFlight , vToDownload , staller ) ;
BOOST_FOREACH ( CBlockIndex * pindex , vToDownload ) {
vGetData . push_back ( CInv ( MSG_BLOCK , pindex - > GetBlockHash ( ) ) ) ;
2015-05-27 07:57:17 -07:00
MarkBlockAsInFlight ( pto - > GetId ( ) , pindex - > GetBlockHash ( ) , consensusParams , pindex ) ;
2014-09-05 08:32:22 -07:00
LogPrint ( " net " , " Requesting block %s (%d) peer=%d \n " , pindex - > GetBlockHash ( ) . ToString ( ) ,
pindex - > nHeight , pto - > id ) ;
2014-07-11 15:02:35 -07:00
}
if ( state . nBlocksInFlight = = 0 & & staller ! = - 1 ) {
2014-09-03 11:31:01 -07:00
if ( State ( staller ) - > nStallingSince = = 0 ) {
2014-07-11 15:02:35 -07:00
State ( staller ) - > nStallingSince = nNow ;
2014-09-03 11:31:01 -07:00
LogPrint ( " net " , " Stall started peer=%d \n " , staller ) ;
}
2014-01-10 04:23:26 -08:00
}
}
//
// Message: getdata (non-blocks)
//
while ( ! pto - > fDisconnect & & ! pto - > mapAskFor . empty ( ) & & ( * pto - > mapAskFor . begin ( ) ) . first < = nNow )
2010-08-29 09:58:15 -07:00
{
const CInv & inv = ( * pto - > mapAskFor . begin ( ) ) . second ;
2012-07-06 07:33:34 -07:00
if ( ! AlreadyHave ( inv ) )
2010-08-29 09:58:15 -07:00
{
2013-10-08 03:09:40 -07:00
if ( fDebug )
2014-02-26 17:55:04 -08:00
LogPrint ( " net " , " Requesting %s peer=%d \n " , inv . ToString ( ) , pto - > id ) ;
2010-08-29 09:58:15 -07:00
vGetData . push_back ( inv ) ;
if ( vGetData . size ( ) > = 1000 )
{
pto - > PushMessage ( " getdata " , vGetData ) ;
vGetData . clear ( ) ;
}
2015-11-22 17:54:23 -08:00
} else {
//If we're not going to ask, don't expect a response.
pto - > setAskFor . erase ( inv . hash ) ;
2010-08-29 09:58:15 -07:00
}
pto - > mapAskFor . erase ( pto - > mapAskFor . begin ( ) ) ;
}
if ( ! vGetData . empty ( ) )
pto - > PushMessage ( " getdata " , vGetData ) ;
}
return true ;
}
2014-08-20 20:17:21 -07:00
std : : string CBlockFileInfo : : ToString ( ) const {
2014-09-08 03:25:52 -07:00
return strprintf ( " CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s) " , nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat( " % Y - % m - % d " , nTimeFirst), DateTimeStrFormat( " % Y - % m - % d " , nTimeLast)) ;
2014-08-20 20:17:21 -07:00
}
2010-08-29 09:58:15 -07:00
2018-01-14 08:23:05 -08:00
static class CMainCleanup
2013-03-28 18:17:10 -07:00
{
public :
CMainCleanup ( ) { }
~ CMainCleanup ( ) {
// block headers
2014-09-03 17:02:44 -07:00
BlockMap : : iterator it1 = mapBlockIndex . begin ( ) ;
2013-03-28 18:17:10 -07:00
for ( ; it1 ! = mapBlockIndex . end ( ) ; it1 + + )
delete ( * it1 ) . second ;
mapBlockIndex . clear ( ) ;
// orphan transactions
mapOrphanTransactions . clear ( ) ;
2014-08-28 10:23:24 -07:00
mapOrphanTransactionsByPrev . clear ( ) ;
2013-03-28 18:17:10 -07:00
}
} instance_of_cmaincleanup ;
2018-02-15 22:19:36 -08:00
// Set default values of new CMutableTransaction based on consensus rules at given height.
CMutableTransaction CreateNewContextualCMutableTransaction ( const Consensus : : Params & consensusParams , int nHeight )
{
2019-05-10 03:39:03 -07:00
return CreateNewContextualCMutableTransaction ( consensusParams , nHeight , expiryDelta ) ;
}
2018-02-15 22:19:36 -08:00
2019-05-10 03:39:03 -07:00
CMutableTransaction CreateNewContextualCMutableTransaction ( const Consensus : : Params & consensusParams , int nHeight , int nExpiryDelta ) {
CMutableTransaction mtx ;
2018-02-15 22:19:36 -08:00
bool isOverwintered = NetworkUpgradeActive ( nHeight , consensusParams , Consensus : : UPGRADE_OVERWINTER ) ;
if ( isOverwintered ) {
mtx . fOverwintered = true ;
2019-05-10 03:39:03 -07:00
mtx . nExpiryHeight = nHeight + nExpiryDelta ;
if ( mtx . nExpiryHeight < = 0 | | mtx . nExpiryHeight > = TX_EXPIRY_HEIGHT_THRESHOLD ) {
throw new std : : runtime_error ( " CreateNewContextualCMutableTransaction: invalid expiry height " ) ;
}
2018-02-15 22:19:36 -08:00
2018-11-05 10:24:20 -08:00
// NOTE: If the expiry height crosses into an incompatible consensus epoch, and it is changed to the last block
// of the current epoch (see below: Overwinter->Sapling), the transaction will be rejected if it falls within
// the expiring soon threshold of 3 blocks (for DoS mitigation) based on the current height.
// TODO: Generalise this code so behaviour applies to all post-Overwinter epochs
2018-05-03 04:02:51 -07:00
if ( NetworkUpgradeActive ( nHeight , consensusParams , Consensus : : UPGRADE_SAPLING ) ) {
mtx . nVersionGroupId = SAPLING_VERSION_GROUP_ID ;
mtx . nVersion = SAPLING_TX_VERSION ;
} else {
mtx . nVersionGroupId = OVERWINTER_VERSION_GROUP_ID ;
mtx . nVersion = OVERWINTER_TX_VERSION ;
2018-05-03 04:27:56 -07:00
mtx . nExpiryHeight = std : : min (
mtx . nExpiryHeight ,
static_cast < uint32_t > ( consensusParams . vUpgrades [ Consensus : : UPGRADE_SAPLING ] . nActivationHeight - 1 ) ) ;
2018-05-03 04:02:51 -07:00
}
2018-02-15 22:19:36 -08:00
}
return mtx ;
}