Page MenuHomePhabricator

No OneTemporary

diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 6b363f868..e5cf0335c 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -1,519 +1,528 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "chainparams.h"
#include "consensus/merkle.h"
#include "tinyformat.h"
#include "util.h"
#include "utilstrencodings.h"
#include <cassert>
#include "chainparamsseeds.h"
// Far into the future.
static const std::string ANTI_REPLAY_COMMITMENT =
"Bitcoin: A Peer-to-Peer Electronic Cash System";
static std::vector<uint8_t> GetAntiReplayCommitment() {
return std::vector<uint8_t>(std::begin(ANTI_REPLAY_COMMITMENT),
std::end(ANTI_REPLAY_COMMITMENT));
}
static CBlock CreateGenesisBlock(const char *pszTimestamp,
const CScript &genesisOutputScript,
uint32_t nTime, uint32_t nNonce,
uint32_t nBits, int32_t nVersion,
const Amount genesisReward) {
CMutableTransaction txNew;
txNew.nVersion = 1;
txNew.vin.resize(1);
txNew.vout.resize(1);
txNew.vin[0].scriptSig =
CScript() << 486604799 << CScriptNum(4)
<< std::vector<uint8_t>((const uint8_t *)pszTimestamp,
(const uint8_t *)pszTimestamp +
strlen(pszTimestamp));
txNew.vout[0].nValue = genesisReward;
txNew.vout[0].scriptPubKey = genesisOutputScript;
CBlock genesis;
genesis.nTime = nTime;
genesis.nBits = nBits;
genesis.nNonce = nNonce;
genesis.nVersion = nVersion;
genesis.vtx.push_back(MakeTransactionRef(std::move(txNew)));
genesis.hashPrevBlock.SetNull();
genesis.hashMerkleRoot = BlockMerkleRoot(genesis);
return genesis;
}
/**
* Build the genesis block. Note that the output of its generation transaction
* cannot be spent since it did not originally exist in the database.
*
* CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000,
* hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893,
* vtx=1)
* CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
* CTxIn(COutPoint(000000, -1), coinbase
* 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73)
* CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
* vMerkleTree: 4a5e1e
*/
static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce,
uint32_t nBits, int32_t nVersion,
const Amount genesisReward) {
const char *pszTimestamp =
"The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
const CScript genesisOutputScript =
CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909"
"a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112"
"de5c384df7ba0b8d578a4c702b6bf11d5f")
<< OP_CHECKSIG;
return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce,
nBits, nVersion, genesisReward);
}
/**
* Main network
*/
/**
* What makes a good checkpoint block?
* + Is surrounded by blocks with reasonable timestamps
* (no blocks before with a timestamp after, none after with
* timestamp before)
* + Contains no strange transactions
*/
class CMainParams : public CChainParams {
public:
CMainParams() {
strNetworkID = "main";
consensus.nSubsidyHalvingInterval = 210000;
consensus.BIP34Height = 227931;
consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb4"
"4ab7bd1b19115dd6a759c0808b8");
// 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0
consensus.BIP65Height = 388381;
// 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931
consensus.BIP66Height = 363725;
consensus.antiReplayOpReturnSunsetHeight = 530000;
consensus.antiReplayOpReturnCommitment = GetAntiReplayCommitment();
consensus.powLimit = uint256S(
"00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
// two weeks
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60;
consensus.nPowTargetSpacing = 10 * 60;
consensus.fPowAllowMinDifficultyBlocks = false;
consensus.fPowNoRetargeting = false;
// 95% of 2016
consensus.nRuleChangeActivationThreshold = 1916;
// nPowTargetTimespan / nPowTargetSpacing
consensus.nMinerConfirmationWindow = 2016;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
// January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime =
1199145601;
// December 31, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout =
1230767999;
// Deployment of BIP68, BIP112, and BIP113.
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;
// May 1st, 2016
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime =
1462060800;
// May 1st, 2017
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800;
// The best chain should have at least this much work.
consensus.nMinimumChainWork =
uint256S("0x000000000000000000000000000000000000000000796b6d5908f8d"
"b26c3cf44");
// By default assume that the signatures in ancestors of this block are
// valid.
consensus.defaultAssumeValid =
uint256S("0x000000000000000004694d6c74b532faf99fc072181f870bfb4a6c9"
"930f7440c");
// Aug, 1 hard fork
consensus.uahfHeight = 478559;
+ // Nov, 13 hard fork
+ consensus.cashHardForkActivationTime = 1510600000;
+
/**
* The message start string is designed to be unlikely to occur in
* normal data. The characters are rarely used upper ASCII, not valid as
* UTF-8, and produce a large 32-bit integer with any alignment.
*/
pchMessageStart[0] = 0xf9;
pchMessageStart[1] = 0xbe;
pchMessageStart[2] = 0xb4;
pchMessageStart[3] = 0xd9;
pchCashMessageStart[0] = 0xe3;
pchCashMessageStart[1] = 0xe1;
pchCashMessageStart[2] = 0xf3;
pchCashMessageStart[3] = 0xe8;
nDefaultPort = 8333;
nPruneAfterHeight = 100000;
genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1,
50 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
assert(consensus.hashGenesisBlock ==
uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3"
"f1b60a8ce26f"));
assert(genesis.hashMerkleRoot ==
uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab212"
"7b7afdeda33b"));
// Note that of those with the service bits flag, most only support a
// subset of possible options.
// Bitcoin ABC seeder
vSeeds.push_back(
CDNSSeedData("bitcoinabc.org", "seed.bitcoinabc.org", true));
// bitcoinforks seeders
vSeeds.push_back(CDNSSeedData("bitcoinforks.org",
"seed-abc.bitcoinforks.org", true));
// BU backed seeder
vSeeds.push_back(CDNSSeedData("bitcoinunlimited.info",
"btccash-seeder.bitcoinunlimited.info",
true));
// Bitprim
vSeeds.push_back(CDNSSeedData("bitprim.org", "seed.bitprim.org", true));
// Amaury SÉCHET
vSeeds.push_back(
CDNSSeedData("deadalnix.me", "seed.deadalnix.me", true));
// criptolayer.net
vSeeds.push_back(
CDNSSeedData("criptolayer.net", "seeder.criptolayer.net", true));
base58Prefixes[PUBKEY_ADDRESS] = std::vector<uint8_t>(1, 0);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<uint8_t>(1, 5);
base58Prefixes[SECRET_KEY] = std::vector<uint8_t>(1, 128);
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};
vFixedSeeds = std::vector<SeedSpec6>(
pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
fMiningRequiresPeers = true;
fDefaultConsistencyChecks = false;
fRequireStandard = true;
fMineBlocksOnDemand = false;
checkpointData = {
.mapCheckpoints = {
{11111, uint256S("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2"
"ee92559f542fdb26e7c1d")},
{33333, uint256S("0x000000002dd5588a74784eaa7ab0507a18ad16a236e"
"7b1ce69f00d7ddfb5d0a6")},
{74000, uint256S("0x0000000000573993a3c9e41ce34471c079dcf5f52a0"
"e824a81e7f953b8661a20")},
{105000, uint256S("0x00000000000291ce28027faea320c8d2b054b2e0fe"
"44a773f3eefb151d6bdc97")},
{134444, uint256S("0x00000000000005b12ffd4cd315cd34ffd4a594f430"
"ac814c91184a0d42d2b0fe")},
{168000, uint256S("0x000000000000099e61ea72015e79632f216fe6cb33"
"d7899acb35b75c8303b763")},
{193000, uint256S("0x000000000000059f452a5f7340de6682a977387c17"
"010ff6e6c3bd83ca8b1317")},
{210000, uint256S("0x000000000000048b95347e83192f69cf0366076336"
"c639f9b7228e9ba171342e")},
{216116, uint256S("0x00000000000001b4f4b433e81ee46494af945cf960"
"14816a4e2370f11b23df4e")},
{225430, uint256S("0x00000000000001c108384350f74090433e7fcf79a6"
"06b8e797f065b130575932")},
{250000, uint256S("0x000000000000003887df1f29024b06fc2200b55f8a"
"f8f35453d7be294df2d214")},
{279000, uint256S("0x0000000000000001ae8c72a0b0c301f67e3afca10e"
"819efa9041e458e9bd7e40")},
{295000, uint256S("0x00000000000000004d9b4ef50f0f9d686fd69db2e0"
"3af35a100370c64632a983")},
// UAHF fork block
{478559, uint256S("0x000000000000000000651ef99cb9fcbe0dadde1d42"
"4bd9f15ff20136191a5eec")},
// Sept 30, 2017
{490000, uint256S("0x0000000000000000018ade0e75b4c21db72f05db1e"
"4fffb870c26d6c765dc6d1")}}};
// Data as of block
// 00000000000000000166d612d5595e2b1cd88d71d695fc580af64d8da8658c23
// (height 446482).
chainTxData = ChainTxData{
// UNIX timestamp of last known number of transactions.
1483472411,
// Total number of transactions between genesis and that timestamp
// (the tx=... number in the SetBestChain debug.log lines)
184495391,
// Estimated number of transactions per second after that timestamp.
3.2};
}
};
static CMainParams mainParams;
/**
* Testnet (v3)
*/
class CTestNetParams : public CChainParams {
public:
CTestNetParams() {
strNetworkID = "test";
consensus.nSubsidyHalvingInterval = 210000;
consensus.BIP34Height = 21111;
consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d4"
"1500f8e2a5c3f0dd01299cd8ef8");
// 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
consensus.BIP65Height = 581885;
// 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182
consensus.BIP66Height = 330776;
consensus.antiReplayOpReturnSunsetHeight = 1250000;
consensus.antiReplayOpReturnCommitment = GetAntiReplayCommitment();
consensus.powLimit = uint256S(
"00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
// two weeks
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60;
consensus.nPowTargetSpacing = 10 * 60;
consensus.fPowAllowMinDifficultyBlocks = true;
consensus.fPowNoRetargeting = false;
// 75% for testchains
consensus.nRuleChangeActivationThreshold = 1512;
// nPowTargetTimespan / nPowTargetSpacing
consensus.nMinerConfirmationWindow = 2016;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
// January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime =
1199145601;
// December 31, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout =
1230767999;
// Deployment of BIP68, BIP112, and BIP113.
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;
// March 1st, 2016
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime =
1456790400;
// May 1st, 2017
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800;
// The best chain should have at least this much work.
consensus.nMinimumChainWork =
uint256S("0x0000000000000000000000000000000000000000000000288002666"
"863267524");
// By default assume that the signatures in ancestors of this block are
// valid.
consensus.defaultAssumeValid =
uint256S("0x00000000ba37a638c096da8e1a843df68f4cc9754124f11034a0b61"
"3bbf4ca3e");
// Aug, 1 hard fork
consensus.uahfHeight = 1155876;
+ // Nov, 13 hard fork
+ consensus.cashHardForkActivationTime = 1510600000;
+
pchMessageStart[0] = 0x0b;
pchMessageStart[1] = 0x11;
pchMessageStart[2] = 0x09;
pchMessageStart[3] = 0x07;
pchCashMessageStart[0] = 0xf4;
pchCashMessageStart[1] = 0xe5;
pchCashMessageStart[2] = 0xf3;
pchCashMessageStart[3] = 0xf4;
nDefaultPort = 18333;
nPruneAfterHeight = 1000;
genesis =
CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
assert(consensus.hashGenesisBlock ==
uint256S("0x000000000933ea01ad0ee984209779baaec3ced90fa3f4087195"
"26f8d77f4943"));
assert(genesis.hashMerkleRoot ==
uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab212"
"7b7afdeda33b"));
vFixedSeeds.clear();
vSeeds.clear();
// nodes with support for servicebits filtering should be at the top
// Bitcoin ABC seeder
vSeeds.push_back(CDNSSeedData("bitcoinabc.org",
"testnet-seed.bitcoinabc.org", true));
// bitcoinforks seeders
vSeeds.push_back(CDNSSeedData(
"bitcoinforks.org", "testnet-seed-abc.bitcoinforks.org", true));
// Bitprim
vSeeds.push_back(
CDNSSeedData("bitprim.org", "testnet-seed.bitprim.org", true));
// Amaury SÉCHET
vSeeds.push_back(
CDNSSeedData("deadalnix.me", "testnet-seed.deadalnix.me", true));
// criptolayer.net
vSeeds.push_back(CDNSSeedData("criptolayer.net",
"testnet-seeder.criptolayer.net", true));
base58Prefixes[PUBKEY_ADDRESS] = std::vector<uint8_t>(1, 111);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<uint8_t>(1, 196);
base58Prefixes[SECRET_KEY] = std::vector<uint8_t>(1, 239);
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
vFixedSeeds = std::vector<SeedSpec6>(
pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));
fMiningRequiresPeers = true;
fDefaultConsistencyChecks = false;
fRequireStandard = false;
fMineBlocksOnDemand = false;
checkpointData = {
.mapCheckpoints = {
{546, uint256S("000000002a936ca763904c3c35fce2f3556c559c0214345"
"d31b1bcebf76acb70")},
// UAHF fork block
{1155876,
uint256S("00000000000e38fef93ed9582a7df43815d5c2ba9fd37ef"
"70c9a0ea4a285b8f5")},
}};
// Data as of block
// 00000000c2872f8f8a8935c8e3c5862be9038c97d4de2cf37ed496991166928a
// (height 1063660)
chainTxData = ChainTxData{1483546230, 12834668, 0.15};
}
};
static CTestNetParams testNetParams;
/**
* Regression test
*/
class CRegTestParams : public CChainParams {
public:
CRegTestParams() {
strNetworkID = "regtest";
consensus.nSubsidyHalvingInterval = 150;
// BIP34 has not activated on regtest (far in the future so block v1 are
// not rejected in tests)
consensus.BIP34Height = 100000000;
consensus.BIP34Hash = uint256();
// BIP65 activated on regtest (Used in rpc activation tests)
consensus.BIP65Height = 1351;
// BIP66 activated on regtest (Used in rpc activation tests)
consensus.BIP66Height = 1251;
consensus.antiReplayOpReturnSunsetHeight = 530000;
consensus.antiReplayOpReturnCommitment = GetAntiReplayCommitment();
consensus.powLimit = uint256S(
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
// two weeks
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60;
consensus.nPowTargetSpacing = 10 * 60;
consensus.fPowAllowMinDifficultyBlocks = true;
consensus.fPowNoRetargeting = true;
// 75% for testchains
consensus.nRuleChangeActivationThreshold = 108;
// Faster than normal for regtest (144 instead of 2016)
consensus.nMinerConfirmationWindow = 144;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout =
999999999999ULL;
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout =
999999999999ULL;
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00");
// By default assume that the signatures in ancestors of this block are
// valid.
consensus.defaultAssumeValid = uint256S("0x00");
// Hard fork is always enabled on regtest.
consensus.uahfHeight = 0;
+ // Nov, 13 hard fork
+ consensus.cashHardForkActivationTime = 0;
+
pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0xbf;
pchMessageStart[2] = 0xb5;
pchMessageStart[3] = 0xda;
pchCashMessageStart[0] = 0xda;
pchCashMessageStart[1] = 0xb5;
pchCashMessageStart[2] = 0xbf;
pchCashMessageStart[3] = 0xfa;
nDefaultPort = 18444;
nPruneAfterHeight = 1000;
genesis = CreateGenesisBlock(1296688602, 2, 0x207fffff, 1, 50 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
assert(consensus.hashGenesisBlock ==
uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b"
"1a11466e2206"));
assert(genesis.hashMerkleRoot ==
uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab212"
"7b7afdeda33b"));
//!< Regtest mode doesn't have any fixed seeds.
vFixedSeeds.clear();
//!< Regtest mode doesn't have any DNS seeds.
vSeeds.clear();
fMiningRequiresPeers = false;
fDefaultConsistencyChecks = true;
fRequireStandard = false;
fMineBlocksOnDemand = true;
checkpointData = {.mapCheckpoints = {
{0, uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5"
"beb436012afca590b1a11466e2206")},
}};
chainTxData = ChainTxData{0, 0, 0};
base58Prefixes[PUBKEY_ADDRESS] = std::vector<uint8_t>(1, 111);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<uint8_t>(1, 196);
base58Prefixes[SECRET_KEY] = std::vector<uint8_t>(1, 239);
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
}
void UpdateBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime,
int64_t nTimeout) {
consensus.vDeployments[d].nStartTime = nStartTime;
consensus.vDeployments[d].nTimeout = nTimeout;
}
};
static CRegTestParams regTestParams;
static CChainParams *pCurrentParams = 0;
const CChainParams &Params() {
assert(pCurrentParams);
return *pCurrentParams;
}
CChainParams &Params(const std::string &chain) {
if (chain == CBaseChainParams::MAIN) {
return mainParams;
}
if (chain == CBaseChainParams::TESTNET) {
return testNetParams;
}
if (chain == CBaseChainParams::REGTEST) {
return regTestParams;
}
throw std::runtime_error(
strprintf("%s: Unknown chain %s.", __func__, chain));
}
void SelectParams(const std::string &network) {
SelectBaseParams(network);
pCurrentParams = &Params(network);
}
void UpdateRegtestBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime,
int64_t nTimeout) {
regTestParams.UpdateBIP9Parameters(d, nStartTime, nTimeout);
}
diff --git a/src/consensus/params.h b/src/consensus/params.h
index ae36f4f49..0b5ac95f1 100644
--- a/src/consensus/params.h
+++ b/src/consensus/params.h
@@ -1,79 +1,82 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_CONSENSUS_PARAMS_H
#define BITCOIN_CONSENSUS_PARAMS_H
#include "uint256.h"
#include <map>
#include <string>
namespace Consensus {
enum DeploymentPos {
DEPLOYMENT_TESTDUMMY,
// Deployment of BIP68, BIP112, and BIP113.
DEPLOYMENT_CSV,
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in
// versionbits.cpp
MAX_VERSION_BITS_DEPLOYMENTS
};
/**
* Struct for each individual consensus rule change using BIP9.
*/
struct BIP9Deployment {
/** Bit position to select the particular bit in nVersion. */
int bit;
/** Start MedianTime for version bits miner confirmation. Can be a date in
* the past */
int64_t nStartTime;
/** Timeout/expiry MedianTime for the deployment attempt. */
int64_t nTimeout;
};
/**
* Parameters that influence chain consensus.
*/
struct Params {
uint256 hashGenesisBlock;
int nSubsidyHalvingInterval;
/** Block height and hash at which BIP34 becomes active */
int BIP34Height;
uint256 BIP34Hash;
/** Block height at which BIP65 becomes active */
int BIP65Height;
/** Block height at which BIP66 becomes active */
int BIP66Height;
/** Block height at which UAHF kicks in */
int uahfHeight;
/** Block height at which OP_RETURN replay protection stops */
int antiReplayOpReturnSunsetHeight;
/** Committed OP_RETURN value for replay protection */
std::vector<uint8_t> antiReplayOpReturnCommitment;
/**
* Minimum blocks including miner confirmation of the total of 2016 blocks
* in a retargeting period, (nPowTargetTimespan / nPowTargetSpacing) which
* is also used for BIP9 deployments.
* Examples: 1916 for 95%, 1512 for testchains.
*/
uint32_t nRuleChangeActivationThreshold;
uint32_t nMinerConfirmationWindow;
BIP9Deployment vDeployments[MAX_VERSION_BITS_DEPLOYMENTS];
/** Proof of work parameters */
uint256 powLimit;
bool fPowAllowMinDifficultyBlocks;
bool fPowNoRetargeting;
int64_t nPowTargetSpacing;
int64_t nPowTargetTimespan;
int64_t DifficultyAdjustmentInterval() const {
return nPowTargetTimespan / nPowTargetSpacing;
}
uint256 nMinimumChainWork;
uint256 defaultAssumeValid;
+
+ /** Activation time at which the cash HF kicks in. */
+ int64_t cashHardForkActivationTime;
};
} // namespace Consensus
#endif // BITCOIN_CONSENSUS_PARAMS_H
diff --git a/src/validation.cpp b/src/validation.cpp
index f939623b1..f82a679cf 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -1,5041 +1,5054 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Copyright (c) 2017 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "validation.h"
#include "arith_uint256.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "checkqueue.h"
#include "config.h"
#include "consensus/consensus.h"
#include "consensus/merkle.h"
#include "consensus/validation.h"
#include "hash.h"
#include "init.h"
#include "policy/fees.h"
#include "policy/policy.h"
#include "pow.h"
#include "primitives/block.h"
#include "primitives/transaction.h"
#include "random.h"
#include "script/script.h"
#include "script/scriptcache.h"
#include "script/sigcache.h"
#include "script/standard.h"
#include "timedata.h"
#include "tinyformat.h"
#include "txdb.h"
#include "txmempool.h"
#include "ui_interface.h"
#include "undo.h"
#include "util.h"
#include "utilmoneystr.h"
#include "utilstrencodings.h"
#include "validationinterface.h"
#include "versionbits.h"
#include "warnings.h"
#include <atomic>
#include <sstream>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/math/distributions/poisson.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <boost/thread.hpp>
#if defined(NDEBUG)
#error "Bitcoin cannot be compiled without assertions."
#endif
/**
* Global state
*/
CCriticalSection cs_main;
BlockMap mapBlockIndex;
CChain chainActive;
CBlockIndex *pindexBestHeader = nullptr;
CWaitableCriticalSection csBestBlock;
CConditionVariable cvBlockChange;
int nScriptCheckThreads = 0;
std::atomic_bool fImporting(false);
bool fReindex = false;
bool fTxIndex = false;
bool fHavePruned = false;
bool fPruneMode = false;
bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
bool fRequireStandard = true;
bool fCheckBlockIndex = false;
bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
size_t nCoinCacheUsage = 5000 * 300;
uint64_t nPruneTarget = 0;
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
uint256 hashAssumeValid;
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE.GetSatoshis();
CTxMemPool mempool(::minRelayTxFee);
static void CheckBlockIndex(const Consensus::Params &consensusParams);
/** Constant stuff for coinbase transactions we create: */
CScript COINBASE_FLAGS;
const std::string strMessageMagic = "Bitcoin Signed Message:\n";
// Internal stuff
namespace {
struct CBlockIndexWorkComparator {
bool operator()(CBlockIndex *pa, CBlockIndex *pb) const {
// 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;
/**
* The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself
* and all ancestors) and as good as our current tip or better. Entries may be
* failed, though, and pruning nodes may be missing the data for the block.
*/
std::set<CBlockIndex *, CBlockIndexWorkComparator> setBlockIndexCandidates;
/**
* All pairs A->B, where A (or one of its ancestors) misses transactions, but B
* has transactions. Pruned nodes may have entries where B is missing data.
*/
std::multimap<CBlockIndex *, CBlockIndex *> mapBlocksUnlinked;
CCriticalSection cs_LastBlockFile;
std::vector<CBlockFileInfo> vinfoBlockFile;
int nLastBlockFile = 0;
/**
* 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;
/**
* Every received block is assigned a unique and increasing identifier, so we
* know which one to give priority in case of a fork.
*/
CCriticalSection cs_nBlockSequenceId;
/** Blocks loaded from disk are assigned id 0, so start the counter at 1. */
int32_t nBlockSequenceId = 1;
/** Decreasing counter (used by subsequent preciousblock calls). */
int32_t nBlockReverseSequenceId = -1;
/** chainwork for the last block that preciousblock has been applied to. */
arith_uint256 nLastPreciousChainwork = 0;
/** Dirty block index entries. */
std::set<CBlockIndex *> setDirtyBlockIndex;
/** Dirty block file entries. */
std::set<int> setDirtyFileInfo;
} // namespace
/* Use this class to start tracking transactions that are removed from the
* mempool and pass all those transactions through SyncTransaction when the
* object goes out of scope. This is currently only used to call SyncTransaction
* on conflicts removed from the mempool during block connection. Applied in
* ActivateBestChain around ActivateBestStep which in turn calls:
* ConnectTip->removeForBlock->removeConflicts
*/
class MemPoolConflictRemovalTracker {
private:
std::vector<CTransactionRef> conflictedTxs;
CTxMemPool &pool;
public:
MemPoolConflictRemovalTracker(CTxMemPool &_pool) : pool(_pool) {
pool.NotifyEntryRemoved.connect(boost::bind(
&MemPoolConflictRemovalTracker::NotifyEntryRemoved, this, _1, _2));
}
void NotifyEntryRemoved(CTransactionRef txRemoved,
MemPoolRemovalReason reason) {
if (reason == MemPoolRemovalReason::CONFLICT) {
conflictedTxs.push_back(txRemoved);
}
}
~MemPoolConflictRemovalTracker() {
pool.NotifyEntryRemoved.disconnect(boost::bind(
&MemPoolConflictRemovalTracker::NotifyEntryRemoved, this, _1, _2));
for (const auto &tx : conflictedTxs) {
GetMainSignals().SyncTransaction(
*tx, nullptr, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
}
conflictedTxs.clear();
}
};
CBlockIndex *FindForkInGlobalIndex(const CChain &chain,
const CBlockLocator &locator) {
// Find the first block the caller has in the main chain
for (const uint256 &hash : locator.vHave) {
BlockMap::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end()) {
CBlockIndex *pindex = (*mi).second;
if (chain.Contains(pindex)) return pindex;
if (pindex->GetAncestor(chain.Height()) == chain.Tip()) {
return chain.Tip();
}
}
}
return chain.Genesis();
}
CCoinsViewCache *pcoinsTip = nullptr;
CBlockTreeDB *pblocktree = nullptr;
enum FlushStateMode {
FLUSH_STATE_NONE,
FLUSH_STATE_IF_NEEDED,
FLUSH_STATE_PERIODIC,
FLUSH_STATE_ALWAYS
};
// See definition for documentation
static bool FlushStateToDisk(CValidationState &state, FlushStateMode mode,
int nManualPruneHeight = 0);
static void FindFilesToPruneManual(std::set<int> &setFilesToPrune,
int nManualPruneHeight);
static uint32_t GetBlockScriptFlags(const CBlockIndex *pindex,
const Config &config);
static bool IsFinalTx(const CTransaction &tx, int nBlockHeight,
int64_t nBlockTime) {
if (tx.nLockTime == 0) {
return true;
}
int64_t lockTime = tx.nLockTime;
int64_t lockTimeLimit =
(lockTime < LOCKTIME_THRESHOLD) ? nBlockHeight : nBlockTime;
if (lockTime < lockTimeLimit) {
return true;
}
for (const auto &txin : tx.vin) {
if (txin.nSequence != CTxIn::SEQUENCE_FINAL) {
return false;
}
}
return true;
}
/**
* Calculates the block height and previous block's median time past at
* which the transaction will be considered final in the context of BIP 68.
* Also removes from the vector of input heights any entries which did not
* correspond to sequence locked inputs as they do not affect the calculation.
*/
static std::pair<int, int64_t>
CalculateSequenceLocks(const CTransaction &tx, int flags,
std::vector<int> *prevHeights,
const CBlockIndex &block) {
assert(prevHeights->size() == tx.vin.size());
// Will be set to the equivalent height- and time-based nLockTime
// values that would be necessary to satisfy all relative lock-
// time constraints given our view of block chain history.
// The semantics of nLockTime are the last invalid height/time, so
// use -1 to have the effect of any height or time being valid.
int nMinHeight = -1;
int64_t nMinTime = -1;
// tx.nVersion is signed integer so requires cast to unsigned otherwise
// we would be doing a signed comparison and half the range of nVersion
// wouldn't support BIP 68.
bool fEnforceBIP68 = static_cast<uint32_t>(tx.nVersion) >= 2 &&
flags & LOCKTIME_VERIFY_SEQUENCE;
// Do not enforce sequence numbers as a relative lock time
// unless we have been instructed to
if (!fEnforceBIP68) {
return std::make_pair(nMinHeight, nMinTime);
}
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
const CTxIn &txin = tx.vin[txinIndex];
// Sequence numbers with the most significant bit set are not
// treated as relative lock-times, nor are they given any
// consensus-enforced meaning at this point.
if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) {
// The height of this input is not relevant for sequence locks
(*prevHeights)[txinIndex] = 0;
continue;
}
int nCoinHeight = (*prevHeights)[txinIndex];
if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) {
int64_t nCoinTime = block.GetAncestor(std::max(nCoinHeight - 1, 0))
->GetMedianTimePast();
// NOTE: Subtract 1 to maintain nLockTime semantics.
// BIP 68 relative lock times have the semantics of calculating the
// first block or time at which the transaction would be valid. When
// calculating the effective block time or height for the entire
// transaction, we switch to using the semantics of nLockTime which
// is the last invalid block time or height. Thus we subtract 1 from
// the calculated time or height.
// Time-based relative lock-times are measured from the smallest
// allowed timestamp of the block containing the txout being spent,
// which is the median time past of the block prior.
nMinTime = std::max(
nMinTime,
nCoinTime +
(int64_t)((txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK)
<< CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) -
1);
} else {
nMinHeight = std::max(
nMinHeight,
nCoinHeight +
(int)(txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) - 1);
}
}
return std::make_pair(nMinHeight, nMinTime);
}
static bool EvaluateSequenceLocks(const CBlockIndex &block,
std::pair<int, int64_t> lockPair) {
assert(block.pprev);
int64_t nBlockTime = block.pprev->GetMedianTimePast();
if (lockPair.first >= block.nHeight || lockPair.second >= nBlockTime)
return false;
return true;
}
bool SequenceLocks(const CTransaction &tx, int flags,
std::vector<int> *prevHeights, const CBlockIndex &block) {
return EvaluateSequenceLocks(
block, CalculateSequenceLocks(tx, flags, prevHeights, block));
}
bool TestLockPointValidity(const LockPoints *lp) {
AssertLockHeld(cs_main);
assert(lp);
// If there are relative lock times then the maxInputBlock will be set
// If there are no relative lock times, the LockPoints don't depend on the
// chain
if (lp->maxInputBlock) {
// Check whether chainActive is an extension of the block at which the
// LockPoints
// calculation was valid. If not LockPoints are no longer valid
if (!chainActive.Contains(lp->maxInputBlock)) {
return false;
}
}
// LockPoints still valid
return true;
}
bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints *lp,
bool useExistingLockPoints) {
AssertLockHeld(cs_main);
AssertLockHeld(mempool.cs);
CBlockIndex *tip = chainActive.Tip();
CBlockIndex index;
index.pprev = tip;
// CheckSequenceLocks() uses chainActive.Height()+1 to evaluate height based
// locks because when SequenceLocks() is called within ConnectBlock(), the
// height of the block *being* evaluated is what is used. Thus if we want to
// know if a transaction can be part of the *next* block, we need to use one
// more than chainActive.Height()
index.nHeight = tip->nHeight + 1;
std::pair<int, int64_t> lockPair;
if (useExistingLockPoints) {
assert(lp);
lockPair.first = lp->height;
lockPair.second = lp->time;
} else {
// pcoinsTip contains the UTXO set for chainActive.Tip()
CCoinsViewMemPool viewMemPool(pcoinsTip, mempool);
std::vector<int> prevheights;
prevheights.resize(tx.vin.size());
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
const CTxIn &txin = tx.vin[txinIndex];
Coin coin;
if (!viewMemPool.GetCoin(txin.prevout, coin)) {
return error("%s: Missing input", __func__);
}
if (coin.GetHeight() == MEMPOOL_HEIGHT) {
// Assume all mempool transaction confirm in the next block
prevheights[txinIndex] = tip->nHeight + 1;
} else {
prevheights[txinIndex] = coin.GetHeight();
}
}
lockPair = CalculateSequenceLocks(tx, flags, &prevheights, index);
if (lp) {
lp->height = lockPair.first;
lp->time = lockPair.second;
// Also store the hash of the block with the highest height of all
// the blocks which have sequence locked prevouts. This hash needs
// to still be on the chain for these LockPoint calculations to be
// valid.
// Note: It is impossible to correctly calculate a maxInputBlock if
// any of the sequence locked inputs depend on unconfirmed txs,
// except in the special case where the relative lock time/height is
// 0, which is equivalent to no sequence lock. Since we assume input
// height of tip+1 for mempool txs and test the resulting lockPair
// from CalculateSequenceLocks against tip+1. We know
// EvaluateSequenceLocks will fail if there was a non-zero sequence
// lock on a mempool input, so we can use the return value of
// CheckSequenceLocks to indicate the LockPoints validity
int maxInputHeight = 0;
for (int height : prevheights) {
// Can ignore mempool inputs since we'll fail if they had
// non-zero locks
if (height != tip->nHeight + 1) {
maxInputHeight = std::max(maxInputHeight, height);
}
}
lp->maxInputBlock = tip->GetAncestor(maxInputHeight);
}
}
return EvaluateSequenceLocks(index, lockPair);
}
uint64_t GetSigOpCountWithoutP2SH(const CTransaction &tx) {
uint64_t nSigOps = 0;
for (const auto &txin : tx.vin) {
nSigOps += txin.scriptSig.GetSigOpCount(false);
}
for (const auto &txout : tx.vout) {
nSigOps += txout.scriptPubKey.GetSigOpCount(false);
}
return nSigOps;
}
uint64_t GetP2SHSigOpCount(const CTransaction &tx,
const CCoinsViewCache &inputs) {
if (tx.IsCoinBase()) {
return 0;
}
uint64_t nSigOps = 0;
for (auto &i : tx.vin) {
const CTxOut &prevout = inputs.GetOutputFor(i);
if (prevout.scriptPubKey.IsPayToScriptHash()) {
nSigOps += prevout.scriptPubKey.GetSigOpCount(i.scriptSig);
}
}
return nSigOps;
}
uint64_t GetTransactionSigOpCount(const CTransaction &tx,
const CCoinsViewCache &inputs, int flags) {
uint64_t nSigOps = GetSigOpCountWithoutP2SH(tx);
if (tx.IsCoinBase()) {
return nSigOps;
}
if (flags & SCRIPT_VERIFY_P2SH) {
nSigOps += GetP2SHSigOpCount(tx, inputs);
}
return nSigOps;
}
static bool CheckTransactionCommon(const CTransaction &tx,
CValidationState &state,
bool fCheckDuplicateInputs) {
// Basic checks that don't depend on any context
if (tx.vin.empty()) {
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty");
}
if (tx.vout.empty()) {
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty");
}
// Size limit
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_TX_SIZE) {
return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize");
}
// Check for negative or overflow output values
Amount nValueOut = 0;
for (const auto &txout : tx.vout) {
if (txout.nValue < 0) {
return state.DoS(100, false, REJECT_INVALID,
"bad-txns-vout-negative");
}
if (txout.nValue > MAX_MONEY) {
return state.DoS(100, false, REJECT_INVALID,
"bad-txns-vout-toolarge");
}
nValueOut += txout.nValue;
if (!MoneyRange(nValueOut)) {
return state.DoS(100, false, REJECT_INVALID,
"bad-txns-txouttotal-toolarge");
}
}
if (GetSigOpCountWithoutP2SH(tx) > MAX_TX_SIGOPS_COUNT) {
return state.DoS(100, false, REJECT_INVALID, "bad-txn-sigops");
}
// Check for duplicate inputs - note that this check is slow so we skip it
// in CheckBlock
if (fCheckDuplicateInputs) {
std::set<COutPoint> vInOutPoints;
for (const auto &txin : tx.vin) {
if (!vInOutPoints.insert(txin.prevout).second) {
return state.DoS(100, false, REJECT_INVALID,
"bad-txns-inputs-duplicate");
}
}
}
return true;
}
bool CheckCoinbase(const CTransaction &tx, CValidationState &state,
bool fCheckDuplicateInputs) {
if (!tx.IsCoinBase()) {
return state.DoS(100, false, REJECT_INVALID, "bad-cb-missing", false,
"first tx is not coinbase");
}
if (!CheckTransactionCommon(tx, state, fCheckDuplicateInputs)) {
// CheckTransactionCommon fill in the state.
return false;
}
if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100) {
return state.DoS(100, false, REJECT_INVALID, "bad-cb-length");
}
return true;
}
bool CheckRegularTransaction(const CTransaction &tx, CValidationState &state,
bool fCheckDuplicateInputs) {
if (tx.IsCoinBase()) {
return state.DoS(100, false, REJECT_INVALID, "bad-tx-coinbase");
}
if (!CheckTransactionCommon(tx, state, fCheckDuplicateInputs)) {
// CheckTransactionCommon fill in the state.
return false;
}
for (const auto &txin : tx.vin) {
if (txin.prevout.IsNull()) {
return state.DoS(10, false, REJECT_INVALID,
"bad-txns-prevout-null");
}
}
return true;
}
void LimitMempoolSize(CTxMemPool &pool, size_t limit, unsigned long age) {
int expired = pool.Expire(GetTime() - age);
if (expired != 0) {
LogPrint("mempool", "Expired %i transactions from the memory pool\n",
expired);
}
std::vector<COutPoint> vNoSpendsRemaining;
pool.TrimToSize(limit, &vNoSpendsRemaining);
for (const COutPoint &removed : vNoSpendsRemaining) {
pcoinsTip->Uncache(removed);
}
}
/** Convert CValidationState to a human-readable message for logging */
std::string FormatStateMessage(const CValidationState &state) {
return strprintf(
"%s%s (code %i)", state.GetRejectReason(),
state.GetDebugMessage().empty() ? "" : ", " + state.GetDebugMessage(),
state.GetRejectCode());
}
static bool IsCurrentForFeeEstimation() {
AssertLockHeld(cs_main);
if (IsInitialBlockDownload()) {
return false;
}
if (chainActive.Tip()->GetBlockTime() <
(GetTime() - MAX_FEE_ESTIMATION_TIP_AGE)) {
return false;
}
if (chainActive.Height() < pindexBestHeader->nHeight - 1) {
return false;
}
return true;
}
static bool IsUAHFenabled(const Config &config, int nHeight) {
return nHeight >= config.GetChainParams().GetConsensus().uahfHeight;
}
bool IsUAHFenabled(const Config &config, const CBlockIndex *pindexPrev) {
if (pindexPrev == nullptr) {
return false;
}
return IsUAHFenabled(config, pindexPrev->nHeight);
}
+static bool IsCashHFEnabled(const Config &config, int64_t nMedianTimePast) {
+ return nMedianTimePast >=
+ config.GetChainParams().GetConsensus().cashHardForkActivationTime;
+}
+
+bool IsCashHFEnabled(const Config &config, const CBlockIndex *pindexPrev) {
+ if (pindexPrev == nullptr) {
+ return false;
+ }
+
+ return IsCashHFEnabled(config, pindexPrev->GetMedianTimePast());
+}
+
// Used to avoid mempool polluting consensus critical paths if CCoinsViewMempool
// were somehow broken and returning the wrong scriptPubKeys
static bool CheckInputsFromMempoolAndCache(const CTransaction &tx,
CValidationState &state,
const CCoinsViewCache &view,
CTxMemPool &pool, uint32_t flags,
bool cacheSigStore,
PrecomputedTransactionData &txdata) {
AssertLockHeld(cs_main);
// pool.cs should be locked already, but go ahead and re-take the lock here
// to enforce that mempool doesn't change between when we check the view and
// when we actually call through to CheckInputs
LOCK(pool.cs);
assert(!tx.IsCoinBase());
for (const CTxIn &txin : tx.vin) {
const Coin &coin = view.AccessCoin(txin.prevout);
// At this point we haven't actually checked if the coins are all
// available (or shouldn't assume we have, since CheckInputs does). So
// we just return failure if the inputs are not available here, and then
// only have to check equivalence for available inputs.
if (coin.IsSpent()) {
return false;
}
const CTransactionRef &txFrom = pool.get(txin.prevout.hash);
if (txFrom) {
assert(txFrom->GetHash() == txin.prevout.hash);
assert(txFrom->vout.size() > txin.prevout.n);
assert(txFrom->vout[txin.prevout.n] == coin.GetTxOut());
} else {
const Coin &coinFromDisk = pcoinsTip->AccessCoin(txin.prevout);
assert(!coinFromDisk.IsSpent());
assert(coinFromDisk.GetTxOut() == coin.GetTxOut());
}
}
return CheckInputs(tx, state, view, true, flags, cacheSigStore, true,
txdata);
}
static bool AcceptToMemoryPoolWorker(
const Config &config, CTxMemPool &pool, CValidationState &state,
const CTransactionRef &ptx, bool fLimitFree, bool *pfMissingInputs,
int64_t nAcceptTime, std::list<CTransactionRef> *plTxnReplaced,
bool fOverrideMempoolLimit, const CAmount &nAbsurdFee,
std::vector<COutPoint> &coins_to_uncache) {
AssertLockHeld(cs_main);
const CTransaction &tx = *ptx;
const uint256 txid = tx.GetId();
if (pfMissingInputs) {
*pfMissingInputs = false;
}
// Coinbase is only valid in a block, not as a loose transaction.
if (!CheckRegularTransaction(tx, state, true)) {
// state filled in by CheckRegularTransaction.
return false;
}
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
std::string reason;
if (fRequireStandard && !IsStandardTx(tx, reason)) {
return state.DoS(0, false, REJECT_NONSTANDARD, reason);
}
// 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.
CValidationState ctxState;
if (!ContextualCheckTransactionForCurrentBlock(
config, tx, ctxState, config.GetChainParams().GetConsensus(),
STANDARD_LOCKTIME_VERIFY_FLAGS)) {
// We copy the state from a dummy to ensure we don't increase the
// ban score of peer for transaction that could be valid in the future.
return state.DoS(
0, false, REJECT_NONSTANDARD, ctxState.GetRejectReason(),
ctxState.CorruptionPossible(), ctxState.GetDebugMessage());
}
// Is it already in the memory pool?
if (pool.exists(txid)) {
return state.Invalid(false, REJECT_ALREADY_KNOWN,
"txn-already-in-mempool");
}
// Check for conflicts with in-memory transactions
{
// Protect pool.mapNextTx
LOCK(pool.cs);
for (const CTxIn &txin : tx.vin) {
auto itConflicting = pool.mapNextTx.find(txin.prevout);
if (itConflicting != pool.mapNextTx.end()) {
// Disable replacement feature for good
return state.Invalid(false, REJECT_CONFLICT,
"txn-mempool-conflict");
}
}
}
{
CCoinsView dummy;
CCoinsViewCache view(&dummy);
Amount nValueIn = 0;
LockPoints lp;
{
LOCK(pool.cs);
CCoinsViewMemPool viewMemPool(pcoinsTip, pool);
view.SetBackend(viewMemPool);
// Do we already have it?
for (size_t out = 0; out < tx.vout.size(); out++) {
COutPoint outpoint(txid, out);
bool had_coin_in_cache = pcoinsTip->HaveCoinInCache(outpoint);
if (view.HaveCoin(outpoint)) {
if (!had_coin_in_cache) {
coins_to_uncache.push_back(outpoint);
}
return state.Invalid(false, REJECT_ALREADY_KNOWN,
"txn-already-known");
}
}
// Do all inputs exist?
for (const CTxIn txin : tx.vin) {
if (!pcoinsTip->HaveCoinInCache(txin.prevout)) {
coins_to_uncache.push_back(txin.prevout);
}
if (!view.HaveCoin(txin.prevout)) {
if (pfMissingInputs) {
*pfMissingInputs = true;
}
// fMissingInputs and !state.IsInvalid() is used to detect
// this condition, don't set state.Invalid()
return false;
}
}
// Are the actual inputs available?
if (!view.HaveInputs(tx)) {
return state.Invalid(false, REJECT_DUPLICATE,
"bad-txns-inputs-spent");
}
// Bring the best block into scope.
view.GetBestBlock();
nValueIn = view.GetValueIn(tx);
// We have all inputs cached now, so switch back to dummy, so we
// don't need to keep lock on mempool.
view.SetBackend(dummy);
// Only accept BIP68 sequence locked 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. Must keep pool.cs for this
// unless we change CheckSequenceLocks to take a CoinsViewCache
// instead of create its own.
if (!CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) {
return state.DoS(0, false, REJECT_NONSTANDARD,
"non-BIP68-final");
}
}
// Check for non-standard pay-to-script-hash in inputs
if (fRequireStandard && !AreInputsStandard(tx, view)) {
return state.Invalid(false, REJECT_NONSTANDARD,
"bad-txns-nonstandard-inputs");
}
int64_t nSigOpsCount =
GetTransactionSigOpCount(tx, view, STANDARD_SCRIPT_VERIFY_FLAGS);
Amount nValueOut = tx.GetValueOut();
Amount nFees = nValueIn - nValueOut;
// nModifiedFees includes any fee deltas from PrioritiseTransaction
CAmount nModifiedFees = nFees.GetSatoshis();
double nPriorityDummy = 0;
pool.ApplyDeltas(txid, nPriorityDummy, nModifiedFees);
Amount inChainInputValue;
double dPriority =
view.GetPriority(tx, chainActive.Height(), inChainInputValue);
// Keep track of transactions that spend a coinbase, which we re-scan
// during reorgs to ensure COINBASE_MATURITY is still met.
bool fSpendsCoinbase = false;
for (const CTxIn &txin : tx.vin) {
const Coin &coin = view.AccessCoin(txin.prevout);
if (coin.IsCoinBase()) {
fSpendsCoinbase = true;
break;
}
}
CTxMemPoolEntry entry(ptx, nFees.GetSatoshis(), nAcceptTime, dPriority,
chainActive.Height(),
inChainInputValue.GetSatoshis(), fSpendsCoinbase,
nSigOpsCount, lp);
unsigned int nSize = entry.GetTxSize();
// Check that the transaction doesn't have an excessive number of
// sigops, making it impossible to mine. Since the coinbase transaction
// itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than
// MAX_BLOCK_SIGOPS_PER_MB; we still consider this an invalid rather
// than merely non-standard transaction.
if (nSigOpsCount > MAX_STANDARD_TX_SIGOPS) {
return state.DoS(0, false, REJECT_NONSTANDARD,
"bad-txns-too-many-sigops", false,
strprintf("%d", nSigOpsCount));
}
CAmount mempoolRejectFee =
pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) *
1000000)
.GetFee(nSize)
.GetSatoshis();
if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) {
return state.DoS(0, false, REJECT_INSUFFICIENTFEE,
"mempool min fee not met", false,
strprintf("%d < %d", nFees, mempoolRejectFee));
}
if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) &&
nModifiedFees < ::minRelayTxFee.GetFee(nSize) &&
!AllowFree(entry.GetPriority(chainActive.Height() + 1))) {
// Require that free transactions have sufficient priority to be
// mined in the next block.
return state.DoS(0, false, REJECT_INSUFFICIENTFEE,
"insufficient priority");
}
// Continuously rate-limit free (really, very-low-fee) transactions.
// This mitigates 'penny-flooding' -- sending thousands of free
// transactions just to be annoying or make others' transactions take
// longer to confirm.
if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize)) {
static CCriticalSection csFreeLimiter;
static double dFreeCount;
static int64_t nLastTime;
int64_t nNow = GetTime();
LOCK(csFreeLimiter);
// 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 + nSize >=
GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) * 10 * 1000) {
return state.DoS(0, false, REJECT_INSUFFICIENTFEE,
"rate limited free transaction");
}
LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount,
dFreeCount + nSize);
dFreeCount += nSize;
}
if (nAbsurdFee && nFees > nAbsurdFee) {
return state.Invalid(false, REJECT_HIGHFEE, "absurdly-high-fee",
strprintf("%d > %d", nFees, nAbsurdFee));
}
// Calculate in-mempool ancestors, up to a limit.
CTxMemPool::setEntries setAncestors;
size_t nLimitAncestors =
GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
size_t nLimitAncestorSize =
GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT) * 1000;
size_t nLimitDescendants =
GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT);
size_t nLimitDescendantSize =
GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) *
1000;
std::string errString;
if (!pool.CalculateMemPoolAncestors(
entry, setAncestors, nLimitAncestors, nLimitAncestorSize,
nLimitDescendants, nLimitDescendantSize, errString)) {
return state.DoS(0, false, REJECT_NONSTANDARD,
"too-long-mempool-chain", false, errString);
}
uint32_t scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;
if (!Params().RequireStandard()) {
scriptVerifyFlags =
GetArg("-promiscuousmempoolflags", scriptVerifyFlags);
}
// Check against previous transactions. This is done last to help
// prevent CPU exhaustion denial-of-service attacks.
PrecomputedTransactionData txdata(tx);
if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, false,
txdata)) {
// State filled in by CheckInputs.
return false;
}
// Check again against the current block tip's script verification flags
// to cache our script execution flags. This is, of course, useless if
// the next block has different script flags from the previous one, but
// because the cache tracks script flags for us it will auto-invalidate
// and we'll just have a few blocks of extra misses on soft-fork
// activation.
//
// This is also useful 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 (using TestBlockValidity), however allowing such
// transactions into the mempool can be exploited as a DoS attack.
uint32_t currentBlockScriptVerifyFlags =
GetBlockScriptFlags(chainActive.Tip(), config);
if (!CheckInputsFromMempoolAndCache(tx, state, view, pool,
currentBlockScriptVerifyFlags, true,
txdata)) {
// If we're using promiscuousmempoolflags, we may hit this normally.
// Check if current block has some flags that scriptVerifyFlags does
// not before printing an ominous warning.
if (!(~scriptVerifyFlags & currentBlockScriptVerifyFlags)) {
return error(
"%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against "
"MANDATORY but not STANDARD flags %s, %s",
__func__, txid.ToString(), FormatStateMessage(state));
}
if (!CheckInputs(tx, state, view, true,
MANDATORY_SCRIPT_VERIFY_FLAGS, true, false,
txdata)) {
return error(
"%s: ConnectInputs failed against MANDATORY but not "
"STANDARD flags due to promiscuous mempool %s, %s",
__func__, txid.ToString(), FormatStateMessage(state));
}
LogPrintf("Warning: -promiscuousmempool flags set to not include "
"currently enforced soft forks, this may break mining or "
"otherwise cause instability!\n");
}
// This transaction should only count for fee estimation if
// the node is not behind and it is not dependent on any other
// transactions in the mempool.
bool validForFeeEstimation =
IsCurrentForFeeEstimation() && pool.HasNoInputsOf(tx);
// Store transaction in memory.
pool.addUnchecked(txid, entry, setAncestors, validForFeeEstimation);
// Trim mempool and check if tx was trimmed.
if (!fOverrideMempoolLimit) {
LimitMempoolSize(
pool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000,
GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
if (!pool.exists(txid)) {
return state.DoS(0, false, REJECT_INSUFFICIENTFEE,
"mempool full");
}
}
}
GetMainSignals().SyncTransaction(
tx, nullptr, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
return true;
}
static bool AcceptToMemoryPoolWithTime(
const Config &config, CTxMemPool &pool, CValidationState &state,
const CTransactionRef &tx, bool fLimitFree, bool *pfMissingInputs,
int64_t nAcceptTime, std::list<CTransactionRef> *plTxnReplaced = nullptr,
bool fOverrideMempoolLimit = false, const CAmount nAbsurdFee = 0) {
std::vector<COutPoint> coins_to_uncache;
bool res = AcceptToMemoryPoolWorker(
config, pool, state, tx, fLimitFree, pfMissingInputs, nAcceptTime,
plTxnReplaced, fOverrideMempoolLimit, nAbsurdFee, coins_to_uncache);
if (!res) {
for (const COutPoint &outpoint : coins_to_uncache) {
pcoinsTip->Uncache(outpoint);
}
}
// After we've (potentially) uncached entries, ensure our coins cache is
// still within its size limits
CValidationState stateDummy;
FlushStateToDisk(stateDummy, FLUSH_STATE_PERIODIC);
return res;
}
bool AcceptToMemoryPool(const Config &config, CTxMemPool &pool,
CValidationState &state, const CTransactionRef &tx,
bool fLimitFree, bool *pfMissingInputs,
std::list<CTransactionRef> *plTxnReplaced,
bool fOverrideMempoolLimit, const CAmount nAbsurdFee) {
return AcceptToMemoryPoolWithTime(config, pool, state, tx, fLimitFree,
pfMissingInputs, GetTime(), plTxnReplaced,
fOverrideMempoolLimit, nAbsurdFee);
}
/** Return transaction in txOut, and if it was found inside a block, its hash is
* placed in hashBlock */
bool GetTransaction(const Config &config, const uint256 &txid,
CTransactionRef &txOut, uint256 &hashBlock,
bool fAllowSlow) {
CBlockIndex *pindexSlow = nullptr;
LOCK(cs_main);
CTransactionRef ptx = mempool.get(txid);
if (ptx) {
txOut = ptx;
return true;
}
if (fTxIndex) {
CDiskTxPos postx;
if (pblocktree->ReadTxIndex(txid, 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());
}
hashBlock = header.GetHash();
if (txOut->GetId() != txid)
return error("%s: txid mismatch", __func__);
return true;
}
}
// use coin database to locate block that contains transaction, and scan it
if (fAllowSlow) {
const Coin &coin = AccessByTxid(*pcoinsTip, txid);
if (!coin.IsSpent()) {
pindexSlow = chainActive[coin.GetHeight()];
}
}
if (pindexSlow) {
auto &params = config.GetChainParams().GetConsensus();
CBlock block;
if (ReadBlockFromDisk(block, pindexSlow, params)) {
for (const auto &tx : block.vtx) {
if (tx->GetId() == txid) {
txOut = tx;
hashBlock = pindexSlow->GetBlockHash();
return true;
}
}
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////////
//
// CBlock and CBlockIndex
//
bool WriteBlockToDisk(const CBlock &block, CDiskBlockPos &pos,
const CMessageHeader::MessageStartChars &messageStart) {
// Open history file to append
CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION);
if (fileout.IsNull())
return error("WriteBlockToDisk: OpenBlockFile failed");
// Write index header
unsigned int nSize = GetSerializeSize(fileout, block);
fileout << FLATDATA(messageStart) << nSize;
// Write block
long fileOutPos = ftell(fileout.Get());
if (fileOutPos < 0) return error("WriteBlockToDisk: ftell failed");
pos.nPos = (unsigned int)fileOutPos;
fileout << block;
return true;
}
bool ReadBlockFromDisk(CBlock &block, const CDiskBlockPos &pos,
const Consensus::Params &consensusParams) {
block.SetNull();
// Open history file to read
CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION);
if (filein.IsNull())
return error("ReadBlockFromDisk: OpenBlockFile failed for %s",
pos.ToString());
// Read block
try {
filein >> block;
} catch (const std::exception &e) {
return error("%s: Deserialize or I/O error - %s at %s", __func__,
e.what(), pos.ToString());
}
// Check the header
if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))
return error("ReadBlockFromDisk: Errors in block header at %s",
pos.ToString());
return true;
}
bool ReadBlockFromDisk(CBlock &block, const CBlockIndex *pindex,
const Consensus::Params &consensusParams) {
if (!ReadBlockFromDisk(block, pindex->GetBlockPos(), consensusParams))
return false;
if (block.GetHash() != pindex->GetBlockHash())
return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() "
"doesn't match index for %s at %s",
pindex->ToString(), pindex->GetBlockPos().ToString());
return true;
}
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams) {
int halvings = nHeight / consensusParams.nSubsidyHalvingInterval;
// Force block reward to zero when right shift is undefined.
if (halvings >= 64) return 0;
CAmount nSubsidy = 50 * COIN.GetSatoshis();
// Subsidy is cut in half every 210,000 blocks which will occur
// approximately every 4 years.
nSubsidy >>= halvings;
return nSubsidy;
}
bool IsInitialBlockDownload() {
const CChainParams &chainParams = Params();
// 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;
LOCK(cs_main);
if (latchToFalse.load(std::memory_order_relaxed)) return false;
if (fImporting || fReindex) return true;
if (chainActive.Tip() == nullptr) return true;
if (chainActive.Tip()->nChainWork <
UintToArith256(chainParams.GetConsensus().nMinimumChainWork))
return true;
if (chainActive.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge))
return true;
latchToFalse.store(true, std::memory_order_relaxed);
return false;
}
CBlockIndex *pindexBestForkTip = nullptr, *pindexBestForkBase = nullptr;
static void AlertNotify(const std::string &strMessage) {
uiInterface.NotifyAlertChanged();
std::string strCmd = GetArg("-alertnotify", "");
if (strCmd.empty()) return;
// Alert text should be plain ascii coming from a trusted source, but to be
// safe we first strip anything not in safeChars, then add single quotes
// around the whole string before passing it to the shell:
std::string singleQuote("'");
std::string safeStatus = SanitizeString(strMessage);
safeStatus = singleQuote + safeStatus + singleQuote;
boost::replace_all(strCmd, "%s", safeStatus);
boost::thread t(runCommand, strCmd); // thread runs free
}
void CheckForkWarningConditions() {
AssertLockHeld(cs_main);
// Before we get past initial download, we cannot reliably alert about forks
// (we assume we don't get stuck on a fork before finishing our initial
// sync)
if (IsInitialBlockDownload()) return;
// If our best fork is no longer within 72 blocks (+/- 12 hours if no one
// mines it) of our head, drop it
if (pindexBestForkTip &&
chainActive.Height() - pindexBestForkTip->nHeight >= 72)
pindexBestForkTip = nullptr;
if (pindexBestForkTip ||
(pindexBestInvalid &&
pindexBestInvalid->nChainWork >
chainActive.Tip()->nChainWork +
(GetBlockProof(*chainActive.Tip()) * 6))) {
if (!GetfLargeWorkForkFound() && pindexBestForkBase) {
std::string warning =
std::string("'Warning: Large-work fork detected, forking after "
"block ") +
pindexBestForkBase->phashBlock->ToString() + std::string("'");
AlertNotify(warning);
}
if (pindexBestForkTip && pindexBestForkBase) {
LogPrintf("%s: Warning: Large valid fork found\n forking the "
"chain at height %d (%s)\n lasting to height %d "
"(%s).\nChain state database corruption likely.\n",
__func__, pindexBestForkBase->nHeight,
pindexBestForkBase->phashBlock->ToString(),
pindexBestForkTip->nHeight,
pindexBestForkTip->phashBlock->ToString());
SetfLargeWorkForkFound(true);
} else {
LogPrintf("%s: Warning: Found invalid chain at least ~6 blocks "
"longer than our best chain.\nChain state database "
"corruption likely.\n",
__func__);
SetfLargeWorkInvalidChainFound(true);
}
} else {
SetfLargeWorkForkFound(false);
SetfLargeWorkInvalidChainFound(false);
}
}
void CheckForkWarningConditionsOnNewFork(CBlockIndex *pindexNewForkTip) {
AssertLockHeld(cs_main);
// If we are on a fork that is sufficiently large, set a warning flag
CBlockIndex *pfork = pindexNewForkTip;
CBlockIndex *plonger = chainActive.Tip();
while (pfork && pfork != plonger) {
while (plonger && plonger->nHeight > pfork->nHeight)
plonger = plonger->pprev;
if (pfork == plonger) break;
pfork = pfork->pprev;
}
// We define a condition where we should warn the user about as a fork of at
// least 7 blocks with a tip within 72 blocks (+/- 12 hours if no one mines
// it) of ours. 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)) &&
pindexNewForkTip->nChainWork - pfork->nChainWork >
(GetBlockProof(*pfork) * 7) &&
chainActive.Height() - pindexNewForkTip->nHeight < 72) {
pindexBestForkTip = pindexNewForkTip;
pindexBestForkBase = pfork;
}
CheckForkWarningConditions();
}
static void InvalidChainFound(CBlockIndex *pindexNew) {
if (!pindexBestInvalid ||
pindexNew->nChainWork > pindexBestInvalid->nChainWork)
pindexBestInvalid = pindexNew;
LogPrintf(
"%s: invalid block=%s height=%d log2_work=%.8g date=%s\n", __func__,
pindexNew->GetBlockHash().ToString(), pindexNew->nHeight,
log(pindexNew->nChainWork.getdouble()) / log(2.0),
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexNew->GetBlockTime()));
CBlockIndex *tip = chainActive.Tip();
assert(tip);
LogPrintf("%s: current best=%s height=%d log2_work=%.8g date=%s\n",
__func__, tip->GetBlockHash().ToString(), chainActive.Height(),
log(tip->nChainWork.getdouble()) / log(2.0),
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", tip->GetBlockTime()));
CheckForkWarningConditions();
}
static void InvalidBlockFound(CBlockIndex *pindex,
const CValidationState &state) {
if (!state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID;
setDirtyBlockIndex.insert(pindex);
setBlockIndexCandidates.erase(pindex);
InvalidChainFound(pindex);
}
}
void UpdateCoins(const CTransaction &tx, CCoinsViewCache &inputs,
CTxUndo &txundo, int nHeight) {
// Mark inputs spent.
if (!tx.IsCoinBase()) {
txundo.vprevout.reserve(tx.vin.size());
for (const CTxIn &txin : tx.vin) {
txundo.vprevout.emplace_back();
bool is_spent =
inputs.SpendCoin(txin.prevout, &txundo.vprevout.back());
assert(is_spent);
}
}
// Add outputs.
AddCoins(inputs, tx, nHeight);
}
void UpdateCoins(const CTransaction &tx, CCoinsViewCache &inputs, int nHeight) {
CTxUndo txundo;
UpdateCoins(tx, inputs, txundo, nHeight);
}
bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
if (!VerifyScript(scriptSig, scriptPubKey, nFlags,
CachingTransactionSignatureChecker(ptxTo, nIn, amount,
cacheStore, txdata),
&error)) {
return false;
}
return true;
}
int GetSpendHeight(const CCoinsViewCache &inputs) {
LOCK(cs_main);
CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second;
return pindexPrev->nHeight + 1;
}
namespace Consensus {
bool CheckTxInputs(const CTransaction &tx, CValidationState &state,
const CCoinsViewCache &inputs, int nSpendHeight) {
// 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.
if (!inputs.HaveInputs(tx)) {
return state.Invalid(false, 0, "", "Inputs unavailable");
}
CAmount nValueIn = 0;
CAmount nFees = 0;
for (size_t i = 0; i < tx.vin.size(); i++) {
const COutPoint &prevout = tx.vin[i].prevout;
const Coin &coin = inputs.AccessCoin(prevout);
assert(!coin.IsSpent());
// If prev is coinbase, check that it's matured
if (coin.IsCoinBase()) {
if (nSpendHeight - coin.GetHeight() < COINBASE_MATURITY) {
return state.Invalid(
false, REJECT_INVALID,
"bad-txns-premature-spend-of-coinbase",
strprintf("tried to spend coinbase at depth %d",
nSpendHeight - coin.GetHeight()));
}
}
// Check for negative or overflow input values
nValueIn += coin.GetTxOut().nValue.GetSatoshis();
if (!MoneyRange(coin.GetTxOut().nValue) || !MoneyRange(nValueIn)) {
return state.DoS(100, false, REJECT_INVALID,
"bad-txns-inputvalues-outofrange");
}
}
if (nValueIn < tx.GetValueOut()) {
return state.DoS(
100, false, REJECT_INVALID, "bad-txns-in-belowout", false,
strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn),
FormatMoney(tx.GetValueOut().GetSatoshis())));
}
// Tally transaction fees
CAmount nTxFee = nValueIn - tx.GetValueOut().GetSatoshis();
if (nTxFee < 0) {
return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-negative");
}
nFees += nTxFee;
if (!MoneyRange(nFees)) {
return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-outofrange");
}
return true;
}
} // namespace Consensus
bool CheckInputs(const CTransaction &tx, CValidationState &state,
const CCoinsViewCache &inputs, bool fScriptChecks,
uint32_t flags, bool sigCacheStore, bool scriptCacheStore,
const PrecomputedTransactionData &txdata,
std::vector<CScriptCheck> *pvChecks) {
assert(!tx.IsCoinBase());
if (!Consensus::CheckTxInputs(tx, state, inputs, GetSpendHeight(inputs))) {
return false;
}
if (pvChecks) {
pvChecks->reserve(tx.vin.size());
}
// 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.
// Skip script verification when connecting blocks under the assumedvalid
// block. Assuming the assumedvalid block is valid this is safe because
// block merkle hashes are still computed and checked, of course, if an
// assumed valid block is invalid due to false scriptSigs this optimization
// would allow an invalid chain to be accepted.
if (!fScriptChecks) {
return true;
}
// First check if script executions have been cached with the same flags.
// Note that this assumes that the inputs provided are correct (ie that the
// transaction hash which is in tx's prevouts properly commits to the
// scriptPubKey in the inputs view of that transaction).
uint256 hashCacheEntry = GetScriptCacheKey(tx, flags);
if (IsKeyInScriptCache(hashCacheEntry, !scriptCacheStore)) {
return true;
}
for (size_t i = 0; i < tx.vin.size(); i++) {
const COutPoint &prevout = tx.vin[i].prevout;
const Coin &coin = inputs.AccessCoin(prevout);
assert(!coin.IsSpent());
// We very carefully only pass in things to CScriptCheck which are
// clearly committed to by tx' witness hash. This provides a sanity
// check that our caching is not introducing consensus failures through
// additional data in, eg, the coins being spent being checked as a part
// of CScriptCheck.
const CScript &scriptPubKey = coin.GetTxOut().scriptPubKey;
const CAmount amount = coin.GetTxOut().nValue.GetSatoshis();
// Verify signature
CScriptCheck check(scriptPubKey, amount, tx, i, flags, sigCacheStore,
txdata);
if (pvChecks) {
pvChecks->push_back(std::move(check));
} else if (!check()) {
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.
CScriptCheck check2(scriptPubKey, amount, tx, i,
flags &
~STANDARD_NOT_MANDATORY_VERIFY_FLAGS,
sigCacheStore, txdata);
if (check2()) {
return state.Invalid(
false, REJECT_NONSTANDARD,
strprintf("non-mandatory-script-verify-flag (%s)",
ScriptErrorString(check.GetScriptError())));
}
}
// 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
// soft-fork super-majority signaling has occurred.
return state.DoS(
100, false, REJECT_INVALID,
strprintf("mandatory-script-verify-flag-failed (%s)",
ScriptErrorString(check.GetScriptError())));
}
}
if (scriptCacheStore && !pvChecks) {
// We executed all of the provided scripts, and were told to cache the
// result. Do so now.
AddKeyInScriptCache(hashCacheEntry);
}
return true;
}
namespace {
bool UndoWriteToDisk(const CBlockUndo &blockundo, CDiskBlockPos &pos,
const uint256 &hashBlock,
const CMessageHeader::MessageStartChars &messageStart) {
// Open history file to append
CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
if (fileout.IsNull()) return error("%s: OpenUndoFile failed", __func__);
// Write index header
unsigned int nSize = GetSerializeSize(fileout, blockundo);
fileout << FLATDATA(messageStart) << nSize;
// Write undo data
long fileOutPos = ftell(fileout.Get());
if (fileOutPos < 0) return error("%s: ftell failed", __func__);
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()) {
return error("%s: OpenUndoFile failed", __func__);
}
// Read block
uint256 hashChecksum;
// We need a CHashVerifier as reserializing may lose data
CHashVerifier<CAutoFile> verifier(&filein);
try {
verifier << hashBlock;
verifier >> blockundo;
filein >> hashChecksum;
} catch (const std::exception &e) {
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
}
// Verify checksum
if (hashChecksum != verifier.GetHash()) {
return error("%s: Checksum mismatch", __func__);
}
return true;
}
/** Abort with a message */
bool AbortNode(const std::string &strMessage,
const std::string &userMessage = "") {
SetMiscWarning(strMessage);
LogPrintf("*** %s\n", strMessage);
uiInterface.ThreadSafeMessageBox(
userMessage.empty() ? _("Error: A fatal internal error occurred, see "
"debug.log for details")
: userMessage,
"", 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);
}
} // namespace
/** Restore the UTXO in a Coin at a given COutPoint. */
DisconnectResult UndoCoinSpend(const Coin &undo, CCoinsViewCache &view,
const COutPoint &out) {
bool fClean = true;
if (view.HaveCoin(out)) {
// Overwriting transaction output.
fClean = false;
}
if (undo.GetHeight() == 0) {
// Missing undo metadata (height and coinbase). Older versions included
// this information only in undo records for the last spend of a
// transactions' outputs. This implies that it must be present for some
// other output of the same tx.
const Coin &alternate = AccessByTxid(view, out.hash);
if (alternate.IsSpent()) {
// Adding output for transaction without known metadata
return DISCONNECT_FAILED;
}
// This is somewhat ugly, but hopefully utility is limited. This is only
// useful when working from legacy on disck data. In any case, putting
// the correct information in there doesn't hurt.
const_cast<Coin &>(undo) = Coin(undo.GetTxOut(), alternate.GetHeight(),
alternate.IsCoinBase());
}
view.AddCoin(out, undo, undo.IsCoinBase());
return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
}
/**
* Undo the effects of this block (with given index) on the UTXO set represented
* by coins. When UNCLEAN or FAILED is returned, view is left in an
* indeterminate state.
*/
static DisconnectResult DisconnectBlock(const CBlock &block,
const CBlockIndex *pindex,
CCoinsViewCache &view) {
assert(pindex->GetBlockHash() == view.GetBestBlock());
CBlockUndo blockUndo;
CDiskBlockPos pos = pindex->GetUndoPos();
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;
}
return ApplyBlockUndo(blockUndo, block, pindex, view);
}
DisconnectResult ApplyBlockUndo(const CBlockUndo &blockUndo,
const CBlock &block, const CBlockIndex *pindex,
CCoinsViewCache &view) {
bool fClean = true;
if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) {
error("DisconnectBlock(): block and undo data inconsistent");
return DISCONNECT_FAILED;
}
// Undo transactions in reverse order.
size_t i = block.vtx.size();
while (i-- > 0) {
const CTransaction &tx = *(block.vtx[i]);
uint256 txid = tx.GetId();
// Check that all outputs are available and match the outputs in the
// block itself exactly.
for (size_t o = 0; o < tx.vout.size(); o++) {
if (tx.vout[o].scriptPubKey.IsUnspendable()) {
continue;
}
COutPoint out(txid, o);
Coin coin;
bool is_spent = view.SpendCoin(out, &coin);
if (!is_spent || tx.vout[o] != coin.GetTxOut()) {
// transaction output mismatch
fClean = false;
}
}
// Restore inputs.
if (i < 1) {
// Skip the coinbase.
continue;
}
const CTxUndo &txundo = blockUndo.vtxundo[i - 1];
if (txundo.vprevout.size() != tx.vin.size()) {
error("DisconnectBlock(): transaction and undo data inconsistent");
return DISCONNECT_FAILED;
}
for (size_t j = tx.vin.size(); j-- > 0;) {
const COutPoint &out = tx.vin[j].prevout;
const Coin &undo = txundo.vprevout[j];
DisconnectResult res = UndoCoinSpend(undo, view, out);
if (res == DISCONNECT_FAILED) {
return DISCONNECT_FAILED;
}
fClean = fClean && res != DISCONNECT_UNCLEAN;
}
}
// Move best block pointer to previous block.
view.SetBestBlock(block.hashPrevBlock);
return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
}
static void FlushBlockFile(bool fFinalize = false) {
LOCK(cs_LastBlockFile);
CDiskBlockPos posOld(nLastBlockFile, 0);
FILE *fileOld = OpenBlockFile(posOld);
if (fileOld) {
if (fFinalize)
TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nSize);
FileCommit(fileOld);
fclose(fileOld);
}
fileOld = OpenUndoFile(posOld);
if (fileOld) {
if (fFinalize)
TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nUndoSize);
FileCommit(fileOld);
fclose(fileOld);
}
}
bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos,
unsigned int nAddSize);
static CCheckQueue<CScriptCheck> scriptcheckqueue(128);
void ThreadScriptCheck() {
RenameThread("bitcoin-scriptch");
scriptcheckqueue.Thread();
}
// Protected by cs_main
VersionBitsCache versionbitscache;
int32_t ComputeBlockVersion(const CBlockIndex *pindexPrev,
const Consensus::Params &params) {
LOCK(cs_main);
int32_t nVersion = VERSIONBITS_TOP_BITS;
for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
ThresholdState state = VersionBitsState(
pindexPrev, params, (Consensus::DeploymentPos)i, versionbitscache);
if (state == THRESHOLD_LOCKED_IN || state == THRESHOLD_STARTED) {
nVersion |= VersionBitsMask(params, (Consensus::DeploymentPos)i);
}
}
return nVersion;
}
/**
* Threshold condition checker that triggers when unknown versionbits are seen
* on the network.
*/
class WarningBitsConditionChecker : public AbstractThresholdConditionChecker {
private:
int bit;
public:
WarningBitsConditionChecker(int bitIn) : bit(bitIn) {}
int64_t BeginTime(const Consensus::Params &params) const { return 0; }
int64_t EndTime(const Consensus::Params &params) const {
return std::numeric_limits<int64_t>::max();
}
int Period(const Consensus::Params &params) const {
return params.nMinerConfirmationWindow;
}
int Threshold(const Consensus::Params &params) const {
return params.nRuleChangeActivationThreshold;
}
bool Condition(const CBlockIndex *pindex,
const Consensus::Params &params) const {
return ((pindex->nVersion & VERSIONBITS_TOP_MASK) ==
VERSIONBITS_TOP_BITS) &&
((pindex->nVersion >> bit) & 1) != 0 &&
((ComputeBlockVersion(pindex->pprev, params) >> bit) & 1) == 0;
}
};
// Protected by cs_main
static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS];
// Returns the script flags which should be checked for a given block
static uint32_t GetBlockScriptFlags(const CBlockIndex *pindex,
const Config &config) {
AssertLockHeld(cs_main);
const Consensus::Params &consensusparams =
config.GetChainParams().GetConsensus();
// BIP16 didn't become active until Apr 1 2012
int64_t nBIP16SwitchTime = 1333238400;
bool fStrictPayToScriptHash = (pindex->GetBlockTime() >= nBIP16SwitchTime);
unsigned int flags =
fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE;
// Start enforcing the DERSIG (BIP66) rule
if (pindex->nHeight >= consensusparams.BIP66Height) {
flags |= SCRIPT_VERIFY_DERSIG;
}
// Start enforcing CHECKLOCKTIMEVERIFY (BIP65) rule
if (pindex->nHeight >= consensusparams.BIP65Height) {
flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
}
// Start enforcing BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic.
if (VersionBitsState(pindex->pprev, consensusparams,
Consensus::DEPLOYMENT_CSV,
versionbitscache) == THRESHOLD_ACTIVE) {
flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY;
}
// If the UAHF is enabled, we start accepting replay protected txns
if (IsUAHFenabled(config, pindex->pprev)) {
flags |= SCRIPT_VERIFY_STRICTENC;
flags |= SCRIPT_ENABLE_SIGHASH_FORKID;
}
return flags;
}
static int64_t nTimeCheck = 0;
static int64_t nTimeForks = 0;
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;
/**
* Apply the effects of this block (with given index) on the UTXO set
* represented by coins. Validity checks that depend on the UTXO set are also
* done; ConnectBlock() can fail if those validity checks fail (among other
* reasons).
*/
static bool ConnectBlock(const Config &config, const CBlock &block,
CValidationState &state, CBlockIndex *pindex,
CCoinsViewCache &view, const CChainParams &chainparams,
bool fJustCheck = false) {
AssertLockHeld(cs_main);
int64_t nTimeStart = GetTimeMicros();
// Check it again in case a previous version let a bad block in
if (!CheckBlock(config, block, state, chainparams.GetConsensus(),
!fJustCheck, !fJustCheck)) {
return error("%s: Consensus::CheckBlock: %s", __func__,
FormatStateMessage(state));
}
// Verify that the view's current state corresponds to the previous block
uint256 hashPrevBlock =
pindex->pprev == nullptr ? uint256() : pindex->pprev->GetBlockHash();
assert(hashPrevBlock == view.GetBestBlock());
// Special case for the genesis block, skipping connection of its
// transactions (its coinbase is unspendable)
if (block.GetHash() == chainparams.GetConsensus().hashGenesisBlock) {
if (!fJustCheck) {
view.SetBestBlock(pindex->GetBlockHash());
}
return true;
}
bool fScriptChecks = true;
if (!hashAssumeValid.IsNull()) {
// We've been configured with the hash of a block which has been
// externally verified to have a valid history. A suitable default value
// is included with the software and updated from time to time. Because
// validity relative to a piece of software is an objective fact these
// defaults can be easily reviewed. This setting doesn't force the
// selection of any particular chain but makes validating some faster by
// effectively caching the result of part of the verification.
BlockMap::const_iterator it = mapBlockIndex.find(hashAssumeValid);
if (it != mapBlockIndex.end()) {
if (it->second->GetAncestor(pindex->nHeight) == pindex &&
pindexBestHeader->GetAncestor(pindex->nHeight) == pindex &&
pindexBestHeader->nChainWork >=
UintToArith256(
chainparams.GetConsensus().nMinimumChainWork)) {
// This block is a member of the assumed verified chain and an
// ancestor of the best header. The equivalent time check
// discourages hashpower from extorting the network via DOS
// attack into accepting an invalid block through telling users
// they must manually set assumevalid. Requiring a software
// change or burying the invalid block, regardless of the
// setting, makes it hard to hide the implication of the demand.
// This also avoids having release candidates that are hardly
// doing any signature verification at all in testing without
// having to artificially set the default assumed verified block
// further back. The test against nMinimumChainWork prevents the
// skipping when denied access to any chain at least as good as
// the expected chain.
fScriptChecks =
(GetBlockProofEquivalentTime(
*pindexBestHeader, *pindex, *pindexBestHeader,
chainparams.GetConsensus()) <= 60 * 60 * 24 * 7 * 2);
}
}
}
int64_t nTime1 = GetTimeMicros();
nTimeCheck += nTime1 - nTimeStart;
LogPrint("bench", " - Sanity checks: %.2fms [%.2fs]\n",
0.001 * (nTime1 - nTimeStart), nTimeCheck * 0.000001);
// Do not allow blocks that contain transactions which 'overwrite' older
// transactions, unless those are already completely spent. If such
// overwrites are allowed, coinbases and transactions depending upon those
// can be duplicated to remove the ability to spend the first instance --
// even after being sent to another address. See BIP30 and
// http://r6.ca/blog/20120206T005236Z.html for more information. This logic
// is not necessary for memory pool transactions, as AcceptToMemoryPool
// already refuses previously-known transaction ids entirely. This rule was
// originally applied to all blocks with a timestamp after March 15, 2012,
// 0:00 UTC. Now that the whole chain is irreversibly beyond that time it is
// applied to all blocks except the two in the chain that violate it. This
// prevents exploiting the issue against nodes during their initial block
// download.
bool fEnforceBIP30 = (!pindex->phashBlock) || // Enforce on CreateNewBlock
// invocations which don't
// have a hash.
!((pindex->nHeight == 91842 &&
pindex->GetBlockHash() ==
uint256S("0x00000000000a4d0a398161ffc163c503763"
"b1f4360639393e0e4c8e300e0caec")) ||
(pindex->nHeight == 91880 &&
pindex->GetBlockHash() ==
uint256S("0x00000000000743f190a18c5577a3c2d2a1f"
"610ae9601ac046a38084ccb7cd721")));
// Once BIP34 activated it was not possible to create new duplicate
// coinbases and thus other than starting with the 2 existing duplicate
// coinbase pairs, not possible to create overwriting txs. But by the time
// BIP34 activated, in each of the existing pairs the duplicate coinbase had
// overwritten the first before the first had been spent. Since those
// coinbases are sufficiently buried its no longer possible to create
// further duplicate transactions descending from the known pairs either. If
// we're on the known chain at height greater than where BIP34 activated, we
// can save the db accesses needed for the BIP30 check.
CBlockIndex *pindexBIP34height =
pindex->pprev->GetAncestor(chainparams.GetConsensus().BIP34Height);
// Only continue to enforce if we're below BIP34 activation height or the
// block hash at that height doesn't correspond.
fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height ||
!(pindexBIP34height->GetBlockHash() ==
chainparams.GetConsensus().BIP34Hash));
if (fEnforceBIP30) {
for (const auto &tx : block.vtx) {
for (size_t o = 0; o < tx->vout.size(); o++) {
if (view.HaveCoin(COutPoint(tx->GetHash(), o))) {
return state.DoS(
100,
error("ConnectBlock(): tried to overwrite transaction"),
REJECT_INVALID, "bad-txns-BIP30");
}
}
}
}
// Start enforcing BIP68 (sequence locks) using versionbits logic.
int nLockTimeFlags = 0;
if (VersionBitsState(pindex->pprev, chainparams.GetConsensus(),
Consensus::DEPLOYMENT_CSV,
versionbitscache) == THRESHOLD_ACTIVE) {
nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE;
}
uint32_t flags = GetBlockScriptFlags(pindex, config);
int64_t nTime2 = GetTimeMicros();
nTimeForks += nTime2 - nTime1;
LogPrint("bench", " - Fork checks: %.2fms [%.2fs]\n",
0.001 * (nTime2 - nTime1), nTimeForks * 0.000001);
CBlockUndo blockundo;
CCheckQueueControl<CScriptCheck> control(fScriptChecks ? &scriptcheckqueue
: nullptr);
std::vector<int> prevheights;
CAmount nFees = 0;
int nInputs = 0;
// Sigops counting. We need to do it again because of P2SH.
uint64_t nSigOpsCount = 0;
const uint64_t currentBlockSize =
::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION);
const uint64_t nMaxSigOpsCount = GetMaxBlockSigOpsCount(currentBlockSize);
CDiskTxPos pos(pindex->GetBlockPos(),
GetSizeOfCompactSize(block.vtx.size()));
std::vector<std::pair<uint256, CDiskTxPos>> vPos;
vPos.reserve(block.vtx.size());
blockundo.vtxundo.reserve(block.vtx.size() - 1);
for (size_t i = 0; i < block.vtx.size(); i++) {
const CTransaction &tx = *(block.vtx[i]);
nInputs += tx.vin.size();
if (!tx.IsCoinBase()) {
if (!view.HaveInputs(tx)) {
return state.DoS(
100, error("ConnectBlock(): inputs missing/spent"),
REJECT_INVALID, "bad-txns-inputs-missingorspent");
}
// Check that transaction is BIP68 final BIP68 lock checks (as
// opposed to nLockTime checks) must be in ConnectBlock because they
// require the UTXO set.
prevheights.resize(tx.vin.size());
for (size_t j = 0; j < tx.vin.size(); j++) {
prevheights[j] = view.AccessCoin(tx.vin[j].prevout).GetHeight();
}
if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) {
return state.DoS(
100, error("%s: contains a non-BIP68-final transaction",
__func__),
REJECT_INVALID, "bad-txns-nonfinal");
}
}
// GetTransactionSigOpCount counts 2 types of sigops:
// * legacy (always)
// * p2sh (when P2SH enabled in flags and excludes coinbase)
auto txSigOpsCount = GetTransactionSigOpCount(tx, view, flags);
if (txSigOpsCount > MAX_TX_SIGOPS_COUNT) {
return state.DoS(100, false, REJECT_INVALID, "bad-txn-sigops");
}
nSigOpsCount += txSigOpsCount;
if (nSigOpsCount > nMaxSigOpsCount) {
return state.DoS(100, error("ConnectBlock(): too many sigops"),
REJECT_INVALID, "bad-blk-sigops");
}
if (!tx.IsCoinBase()) {
Amount fee = view.GetValueIn(tx) - tx.GetValueOut();
nFees += fee.GetSatoshis();
// Don't cache results if we're actually connecting blocks (still
// consult the cache, though).
bool fCacheResults = fJustCheck;
std::vector<CScriptCheck> vChecks;
if (!CheckInputs(tx, state, view, fScriptChecks, flags,
fCacheResults, fCacheResults,
PrecomputedTransactionData(tx), &vChecks)) {
return error("ConnectBlock(): CheckInputs on %s failed with %s",
tx.GetId().ToString(), FormatStateMessage(state));
}
control.Add(vChecks);
}
CTxUndo undoDummy;
if (i > 0) {
blockundo.vtxundo.push_back(CTxUndo());
}
UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(),
pindex->nHeight);
vPos.push_back(std::make_pair(tx.GetId(), pos));
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
int64_t nTime3 = GetTimeMicros();
nTimeConnect += nTime3 - nTime2;
LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, "
"%.3fms/txin) [%.2fs]\n",
(unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2),
0.001 * (nTime3 - nTime2) / block.vtx.size(),
nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs - 1),
nTimeConnect * 0.000001);
CAmount blockReward =
nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus());
if (block.vtx[0]->GetValueOut() > blockReward) {
return state.DoS(100, error("ConnectBlock(): coinbase pays too much "
"(actual=%d vs limit=%d)",
block.vtx[0]->GetValueOut(), blockReward),
REJECT_INVALID, "bad-cb-amount");
}
if (!control.Wait()) {
return state.DoS(100, false, REJECT_INVALID, "blk-bad-inputs", false,
"parallel script check failed");
}
int64_t nTime4 = GetTimeMicros();
nTimeVerify += nTime4 - nTime2;
LogPrint("bench", " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs]\n",
nInputs - 1, 0.001 * (nTime4 - nTime2),
nInputs <= 1 ? 0 : 0.001 * (nTime4 - nTime2) / (nInputs - 1),
nTimeVerify * 0.000001);
if (fJustCheck) {
return true;
}
// Write undo information to disk
if (pindex->GetUndoPos().IsNull() ||
!pindex->IsValid(BLOCK_VALID_SCRIPTS)) {
if (pindex->GetUndoPos().IsNull()) {
CDiskBlockPos _pos;
if (!FindUndoPos(
state, pindex->nFile, _pos,
::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) +
40)) {
return error("ConnectBlock(): FindUndoPos failed");
}
if (!UndoWriteToDisk(blockundo, _pos, pindex->pprev->GetBlockHash(),
chainparams.MessageStart())) {
return AbortNode(state, "Failed to write undo data");
}
// update nUndoPos in block index
pindex->nUndoPos = _pos.nPos;
pindex->nStatus |= BLOCK_HAVE_UNDO;
}
pindex->RaiseValidity(BLOCK_VALID_SCRIPTS);
setDirtyBlockIndex.insert(pindex);
}
if (fTxIndex && !pblocktree->WriteTxIndex(vPos)) {
return AbortNode(state, "Failed to write transaction index");
}
// add this block to the view's block chain
view.SetBestBlock(pindex->GetBlockHash());
int64_t nTime5 = GetTimeMicros();
nTimeIndex += nTime5 - nTime4;
LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n",
0.001 * (nTime5 - nTime4), nTimeIndex * 0.000001);
// Watch for changes to the previous coinbase transaction.
static uint256 hashPrevBestCoinBase;
GetMainSignals().UpdatedTransaction(hashPrevBestCoinBase);
hashPrevBestCoinBase = block.vtx[0]->GetId();
int64_t nTime6 = GetTimeMicros();
nTimeCallbacks += nTime6 - nTime5;
LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n",
0.001 * (nTime6 - nTime5), nTimeCallbacks * 0.000001);
return true;
}
/**
* Update the on-disk chain state.
* 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.
*/
static bool FlushStateToDisk(CValidationState &state, FlushStateMode mode,
int nManualPruneHeight) {
int64_t nMempoolUsage = mempool.DynamicMemoryUsage();
const CChainParams &chainparams = Params();
LOCK2(cs_main, cs_LastBlockFile);
static int64_t nLastWrite = 0;
static int64_t nLastFlush = 0;
static int64_t nLastSetChain = 0;
std::set<int> setFilesToPrune;
bool fFlushForPrune = false;
try {
if (fPruneMode && (fCheckForPruning || nManualPruneHeight > 0) &&
!fReindex) {
if (nManualPruneHeight > 0) {
FindFilesToPruneManual(setFilesToPrune, nManualPruneHeight);
} else {
FindFilesToPrune(setFilesToPrune,
chainparams.PruneAfterHeight());
fCheckForPruning = false;
}
if (!setFilesToPrune.empty()) {
fFlushForPrune = true;
if (!fHavePruned) {
pblocktree->WriteFlag("prunedblockfiles", true);
fHavePruned = true;
}
}
}
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;
}
int64_t nMempoolSizeMax =
GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
int64_t cacheSize =
pcoinsTip->DynamicMemoryUsage() * DB_PEAK_USAGE_FACTOR;
int64_t nTotalSpace =
nCoinCacheUsage +
std::max<int64_t>(nMempoolSizeMax - nMempoolUsage, 0);
// The cache is large and we're within 10% and 200 MiB or 50% and 50MiB
// of the limit, but we have time now (not in the middle of a block
// processing).
bool fCacheLarge =
mode == FLUSH_STATE_PERIODIC &&
cacheSize >
std::min(std::max(nTotalSpace / 2,
nTotalSpace -
MIN_BLOCK_COINSDB_USAGE * 1024 * 1024),
std::max((9 * nTotalSpace) / 10,
nTotalSpace -
MAX_BLOCK_COINSDB_USAGE * 1024 * 1024));
// The cache is over the limit, we have to write now.
bool fCacheCritical =
mode == FLUSH_STATE_IF_NEEDED && cacheSize > nTotalSpace;
// 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) {
// Depend on nMinDiskSpace to ensure we can write block index
if (!CheckDiskSpace(0)) return state.Error("out of disk space");
// First make sure all block and undo data is flushed to disk.
FlushBlockFile();
// Then update all block file information (which may refer to block
// and undo files).
{
std::vector<std::pair<int, const CBlockFileInfo *>> vFiles;
vFiles.reserve(setDirtyFileInfo.size());
for (std::set<int>::iterator it = setDirtyFileInfo.begin();
it != setDirtyFileInfo.end();) {
vFiles.push_back(std::make_pair(*it, &vinfoBlockFile[*it]));
setDirtyFileInfo.erase(it++);
}
std::vector<const CBlockIndex *> vBlocks;
vBlocks.reserve(setDirtyBlockIndex.size());
for (std::set<CBlockIndex *>::iterator it =
setDirtyBlockIndex.begin();
it != setDirtyBlockIndex.end();) {
vBlocks.push_back(*it);
setDirtyBlockIndex.erase(it++);
}
if (!pblocktree->WriteBatchSync(vFiles, nLastBlockFile,
vBlocks)) {
return AbortNode(state,
"Failed to write to block index database");
}
}
// Finally remove any pruned files
if (fFlushForPrune) UnlinkPrunedFiles(setFilesToPrune);
nLastWrite = nNow;
}
// Flush best chain related state. This can only be done if the blocks /
// block index write was also done.
if (fDoFullFlush) {
// Typical Coin structures on disk are around 48 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(48 * 2 * 2 * pcoinsTip->GetCacheSize())) {
return state.Error("out of disk space");
}
// Flush the chainstate (which may refer to block index entries).
if (!pcoinsTip->Flush()) {
return AbortNode(state, "Failed to write to coin database");
}
nLastFlush = nNow;
}
if (fDoFullFlush ||
((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) &&
nNow >
nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000)) {
// Update best block in wallet (so we can detect restored wallets).
GetMainSignals().SetBestChain(chainActive.GetLocator());
nLastSetChain = nNow;
}
} catch (const std::runtime_error &e) {
return AbortNode(state, std::string("System error while flushing: ") +
e.what());
}
return true;
}
void FlushStateToDisk() {
CValidationState state;
FlushStateToDisk(state, FLUSH_STATE_ALWAYS);
}
void PruneAndFlush() {
CValidationState state;
fCheckForPruning = true;
FlushStateToDisk(state, FLUSH_STATE_NONE);
}
/** Update chainActive and related internal data structures. */
static void UpdateTip(const Config &config, CBlockIndex *pindexNew) {
const CChainParams &chainParams = config.GetChainParams();
chainActive.SetTip(pindexNew);
// New best block
mempool.AddTransactionsUpdated(1);
cvBlockChange.notify_all();
static bool fWarned = false;
std::vector<std::string> warningMessages;
if (!IsInitialBlockDownload()) {
int nUpgraded = 0;
const CBlockIndex *pindex = chainActive.Tip();
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
WarningBitsConditionChecker checker(bit);
ThresholdState state = checker.GetStateFor(
pindex, chainParams.GetConsensus(), warningcache[bit]);
if (state == THRESHOLD_ACTIVE || state == THRESHOLD_LOCKED_IN) {
if (state == THRESHOLD_ACTIVE) {
std::string strWarning =
strprintf(_("Warning: unknown new rules activated "
"(versionbit %i)"),
bit);
SetMiscWarning(strWarning);
if (!fWarned) {
AlertNotify(strWarning);
fWarned = true;
}
} else {
warningMessages.push_back(
strprintf("unknown new rules are about to activate "
"(versionbit %i)",
bit));
}
}
}
// Check the version of the last 100 blocks to see if we need to
// upgrade:
for (int i = 0; i < 100 && pindex != nullptr; i++) {
int32_t nExpectedVersion =
ComputeBlockVersion(pindex->pprev, chainParams.GetConsensus());
if (pindex->nVersion > VERSIONBITS_LAST_OLD_BLOCK_VERSION &&
(pindex->nVersion & ~nExpectedVersion) != 0)
++nUpgraded;
pindex = pindex->pprev;
}
if (nUpgraded > 0)
warningMessages.push_back(strprintf(
"%d of last 100 blocks have unexpected version", nUpgraded));
if (nUpgraded > 100 / 2) {
std::string strWarning =
_("Warning: Unknown block versions being mined! It's possible "
"unknown rules are in effect");
// notify GetWarnings(), called by Qt and the JSON-RPC code to warn
// the user:
SetMiscWarning(strWarning);
if (!fWarned) {
AlertNotify(strWarning);
fWarned = true;
}
}
}
LogPrintf(
"%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu "
"date='%s' progress=%f cache=%.1fMiB(%utxo)",
__func__, chainActive.Tip()->GetBlockHash().ToString(),
chainActive.Height(), chainActive.Tip()->nVersion,
log(chainActive.Tip()->nChainWork.getdouble()) / log(2.0),
(unsigned long)chainActive.Tip()->nChainTx,
DateTimeStrFormat("%Y-%m-%d %H:%M:%S",
chainActive.Tip()->GetBlockTime()),
GuessVerificationProgress(chainParams.TxData(), chainActive.Tip()),
pcoinsTip->DynamicMemoryUsage() * (1.0 / (1 << 20)),
pcoinsTip->GetCacheSize());
if (!warningMessages.empty())
LogPrintf(" warning='%s'",
boost::algorithm::join(warningMessages, ", "));
LogPrintf("\n");
}
/**
* Disconnect chainActive's tip. You probably want to call
* mempool.removeForReorg and manually re-limit mempool size after this, with
* cs_main held.
*/
static bool DisconnectTip(const Config &config, CValidationState &state,
bool fBare = false) {
const Consensus::Params &consensusParams =
config.GetChainParams().GetConsensus();
CBlockIndex *pindexDelete = chainActive.Tip();
assert(pindexDelete);
// Read block from disk.
CBlock block;
if (!ReadBlockFromDisk(block, pindexDelete, consensusParams)) {
return AbortNode(state, "Failed to read block");
}
// Apply the block atomically to the chain state.
int64_t nStart = GetTimeMicros();
{
CCoinsViewCache view(pcoinsTip);
if (DisconnectBlock(block, pindexDelete, view) != DISCONNECT_OK) {
return error("DisconnectTip(): DisconnectBlock %s failed",
pindexDelete->GetBlockHash().ToString());
}
bool flushed = view.Flush();
assert(flushed);
}
LogPrint("bench", "- Disconnect block: %.2fms\n",
(GetTimeMicros() - nStart) * 0.001);
// Write the chain state to disk, if necessary.
if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED)) {
return false;
}
if (!fBare) {
// Resurrect mempool transactions from the disconnected block.
std::vector<uint256> vHashUpdate;
for (const auto &it : block.vtx) {
const CTransaction &tx = *it;
// ignore validation errors in resurrected transactions
CValidationState stateDummy;
if (tx.IsCoinBase() ||
!AcceptToMemoryPool(config, mempool, stateDummy, it, false,
nullptr, nullptr, true)) {
mempool.removeRecursive(tx, MemPoolRemovalReason::REORG);
} else if (mempool.exists(tx.GetId())) {
vHashUpdate.push_back(tx.GetId());
}
}
// AcceptToMemoryPool/addUnchecked all assume that new mempool entries
// have no in-mempool children, which is generally not true when adding
// previously-confirmed transactions back to the mempool.
// UpdateTransactionsFromBlock finds descendants of any transactions in
// this block that were added back and cleans up the mempool state.
mempool.UpdateTransactionsFromBlock(vHashUpdate);
}
// Update chainActive and related variables.
UpdateTip(config, pindexDelete->pprev);
// Let wallets know transactions went from 1-confirmed to
// 0-confirmed or conflicted:
for (const auto &tx : block.vtx) {
GetMainSignals().SyncTransaction(
*tx, pindexDelete->pprev,
CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
}
return true;
}
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;
/**
* Used to track blocks whose transactions were applied to the UTXO state as a
* part of a single ActivateBestChainStep call.
*/
struct ConnectTrace {
std::vector<std::pair<CBlockIndex *, std::shared_ptr<const CBlock>>>
blocksConnected;
};
/**
* Connect a new block to chainActive. pblock is either nullptr or a pointer to
* a CBlock corresponding to pindexNew, to bypass loading it again from disk.
*
* The block is always added to connectTrace (either after loading from disk or
* by copying pblock) - if that is not intended, care must be taken to remove
* the last entry in blocksConnected in case of failure.
*/
static bool ConnectTip(const Config &config, CValidationState &state,
CBlockIndex *pindexNew,
const std::shared_ptr<const CBlock> &pblock,
ConnectTrace &connectTrace) {
const CChainParams &chainparams = config.GetChainParams();
assert(pindexNew->pprev == chainActive.Tip());
// Read block from disk.
int64_t nTime1 = GetTimeMicros();
if (!pblock) {
std::shared_ptr<CBlock> pblockNew = std::make_shared<CBlock>();
connectTrace.blocksConnected.emplace_back(pindexNew, pblockNew);
if (!ReadBlockFromDisk(*pblockNew, pindexNew,
chainparams.GetConsensus()))
return AbortNode(state, "Failed to read block");
} else {
connectTrace.blocksConnected.emplace_back(pindexNew, pblock);
}
const CBlock &blockConnecting = *connectTrace.blocksConnected.back().second;
// Apply the block atomically to the chain state.
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);
{
CCoinsViewCache view(pcoinsTip);
bool rv = ConnectBlock(config, blockConnecting, state, pindexNew, view,
chainparams);
GetMainSignals().BlockChecked(blockConnecting, state);
if (!rv) {
if (state.IsInvalid()) {
InvalidBlockFound(pindexNew, state);
}
return error("ConnectTip(): ConnectBlock %s failed",
pindexNew->GetBlockHash().ToString());
}
nTime3 = GetTimeMicros();
nTimeConnectTotal += nTime3 - nTime2;
LogPrint("bench", " - Connect total: %.2fms [%.2fs]\n",
(nTime3 - nTime2) * 0.001, nTimeConnectTotal * 0.000001);
bool flushed = view.Flush();
assert(flushed);
}
int64_t nTime4 = GetTimeMicros();
nTimeFlush += nTime4 - nTime3;
LogPrint("bench", " - Flush: %.2fms [%.2fs]\n", (nTime4 - nTime3) * 0.001,
nTimeFlush * 0.000001);
// Write the chain state to disk, if necessary.
if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED)) return false;
int64_t nTime5 = GetTimeMicros();
nTimeChainState += nTime5 - nTime4;
LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n",
(nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001);
// Remove conflicting transactions from the mempool.;
mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight);
// Update chainActive & related variables.
UpdateTip(config, pindexNew);
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);
return true;
}
/**
* 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).
*/
static CBlockIndex *FindMostWorkChain() {
do {
CBlockIndex *pindexNew = nullptr;
// Find the best candidate header.
{
std::set<CBlockIndex *, CBlockIndexWorkComparator>::reverse_iterator
it = setBlockIndexCandidates.rbegin();
if (it == setBlockIndexCandidates.rend()) return nullptr;
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)) {
assert(pindexTest->nChainTx || pindexTest->nHeight == 0);
// 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 == nullptr ||
pindexNew->nChainWork > pindexBestInvalid->nChainWork))
pindexBestInvalid = pindexNew;
CBlockIndex *pindexFailed = pindexNew;
// Remove the entire chain from the set.
while (pindexTest != pindexFailed) {
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));
}
setBlockIndexCandidates.erase(pindexFailed);
pindexFailed = pindexFailed->pprev;
}
setBlockIndexCandidates.erase(pindexTest);
fInvalidAncestor = true;
break;
}
pindexTest = pindexTest->pprev;
}
if (!fInvalidAncestor) return pindexNew;
} while (true);
}
/** Delete all entries in setBlockIndexCandidates that are worse than the
* current tip. */
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();
while (it != setBlockIndexCandidates.end() &&
setBlockIndexCandidates.value_comp()(*it, chainActive.Tip())) {
setBlockIndexCandidates.erase(it++);
}
// Either the current tip or a successor of it we're working towards is left
// in setBlockIndexCandidates.
assert(!setBlockIndexCandidates.empty());
}
/**
* Try to make some progress towards making pindexMostWork the active block.
* pblock is either nullptr or a pointer to a CBlock corresponding to
* pindexMostWork.
*/
static bool ActivateBestChainStep(const Config &config, CValidationState &state,
CBlockIndex *pindexMostWork,
const std::shared_ptr<const CBlock> &pblock,
bool &fInvalidFound,
ConnectTrace &connectTrace) {
AssertLockHeld(cs_main);
const CBlockIndex *pindexOldTip = chainActive.Tip();
const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
// Disconnect active blocks which are no longer in the best chain.
bool fBlocksDisconnected = false;
while (chainActive.Tip() && chainActive.Tip() != pindexFork) {
if (!DisconnectTip(config, state)) return false;
fBlocksDisconnected = true;
}
// Build list of new blocks to connect.
std::vector<CBlockIndex *> vpindexToConnect;
bool fContinue = true;
int nHeight = pindexFork ? pindexFork->nHeight : -1;
while (fContinue && nHeight != pindexMostWork->nHeight) {
// 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.
for (CBlockIndex *pindexConnect :
boost::adaptors::reverse(vpindexToConnect)) {
if (!ConnectTip(config, state, pindexConnect,
pindexConnect == pindexMostWork
? pblock
: std::shared_ptr<const CBlock>(),
connectTrace)) {
if (state.IsInvalid()) {
// The block violates a consensus rule.
if (!state.CorruptionPossible())
InvalidChainFound(vpindexToConnect.back());
state = CValidationState();
fInvalidFound = true;
fContinue = false;
// If we didn't actually connect the block, don't notify
// listeners about it
connectTrace.blocksConnected.pop_back();
break;
} else {
// A system error occurred (disk space, database error,
// ...).
return false;
}
} else {
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;
}
}
}
}
if (fBlocksDisconnected) {
mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1,
STANDARD_LOCKTIME_VERIFY_FLAGS);
LimitMempoolSize(
mempool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000,
GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
}
mempool.check(pcoinsTip);
// Callbacks/notifications for a new best chain.
if (fInvalidFound)
CheckForkWarningConditionsOnNewFork(vpindexToConnect.back());
else
CheckForkWarningConditions();
return true;
}
static void NotifyHeaderTip() {
bool fNotify = false;
bool fInitialBlockDownload = false;
static CBlockIndex *pindexHeaderOld = nullptr;
CBlockIndex *pindexHeader = nullptr;
{
LOCK(cs_main);
pindexHeader = pindexBestHeader;
if (pindexHeader != pindexHeaderOld) {
fNotify = true;
fInitialBlockDownload = IsInitialBlockDownload();
pindexHeaderOld = pindexHeader;
}
}
// Send block tip changed notifications without cs_main
if (fNotify) {
uiInterface.NotifyHeaderTip(fInitialBlockDownload, pindexHeader);
}
}
/**
* Make the best chain active, in multiple steps. The result is either failure
* or an activated best chain. pblock is either nullptr or a pointer to a block
* that is already loaded (to avoid loading it again from disk).
*/
bool ActivateBestChain(const Config &config, CValidationState &state,
std::shared_ptr<const CBlock> pblock) {
// Note that while we're often called here from ProcessNewBlock, this is
// far from a guarantee. Things in the P2P/RPC will often end up calling
// us in the middle of ProcessNewBlock - do not assume pblock is set
// sanely for performance or correctness!
CBlockIndex *pindexMostWork = nullptr;
CBlockIndex *pindexNewTip = nullptr;
do {
boost::this_thread::interruption_point();
if (ShutdownRequested()) break;
const CBlockIndex *pindexFork;
ConnectTrace connectTrace;
bool fInitialDownload;
{
LOCK(cs_main);
{
// TODO: Tempoarily ensure that mempool removals are notified
// before connected transactions. This shouldn't matter, but the
// abandoned state of transactions in our wallet is currently
// cleared when we receive another notification and there is a
// race condition where notification of a connected conflict
// might cause an outside process to abandon a transaction and
// then have it inadvertantly cleared by the notification that
// the conflicted transaction was evicted.
MemPoolConflictRemovalTracker mrt(mempool);
CBlockIndex *pindexOldTip = chainActive.Tip();
if (pindexMostWork == nullptr) {
pindexMostWork = FindMostWorkChain();
}
// Whether we have anything to do at all.
if (pindexMostWork == nullptr ||
pindexMostWork == chainActive.Tip())
return true;
bool fInvalidFound = false;
std::shared_ptr<const CBlock> nullBlockPtr;
if (!ActivateBestChainStep(
config, state, pindexMostWork,
pblock &&
pblock->GetHash() ==
pindexMostWork->GetBlockHash()
? pblock
: nullBlockPtr,
fInvalidFound, connectTrace))
return false;
if (fInvalidFound) {
// Wipe cache, we may need another branch now.
pindexMostWork = nullptr;
}
pindexNewTip = chainActive.Tip();
pindexFork = chainActive.FindFork(pindexOldTip);
fInitialDownload = IsInitialBlockDownload();
// throw all transactions though the signal-interface
} // MemPoolConflictRemovalTracker destroyed and conflict evictions
// are notified
// Transactions in the connnected block are notified
for (const auto &pair : connectTrace.blocksConnected) {
assert(pair.second);
const CBlock &block = *(pair.second);
for (unsigned int i = 0; i < block.vtx.size(); i++)
GetMainSignals().SyncTransaction(*block.vtx[i], pair.first,
i);
}
}
// When we reach this point, we switched to a new tip (stored in
// pindexNewTip).
// Notifications/callbacks that can run without cs_main
// Notify external listeners about the new tip.
GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork,
fInitialDownload);
// Always notify the UI if a new block tip was connected
if (pindexFork != pindexNewTip) {
uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip);
}
} while (pindexNewTip != pindexMostWork);
CheckBlockIndex(config.GetChainParams().GetConsensus());
// Write changes periodically to disk, after relay.
if (!FlushStateToDisk(state, FLUSH_STATE_PERIODIC)) {
return false;
}
return true;
}
bool PreciousBlock(const Config &config, CValidationState &state,
CBlockIndex *pindex) {
{
LOCK(cs_main);
if (pindex->nChainWork < chainActive.Tip()->nChainWork) {
// Nothing to do, this block is not at the tip.
return true;
}
if (chainActive.Tip()->nChainWork > nLastPreciousChainwork) {
// The chain has been extended since the last call, reset the
// counter.
nBlockReverseSequenceId = -1;
}
nLastPreciousChainwork = chainActive.Tip()->nChainWork;
setBlockIndexCandidates.erase(pindex);
pindex->nSequenceId = nBlockReverseSequenceId;
if (nBlockReverseSequenceId > std::numeric_limits<int32_t>::min()) {
// We can't keep reducing the counter if somebody really wants to
// call preciousblock 2**31-1 times on the same set of tips...
nBlockReverseSequenceId--;
}
if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && pindex->nChainTx) {
setBlockIndexCandidates.insert(pindex);
PruneBlockIndexCandidates();
}
}
return ActivateBestChain(config, state);
}
bool InvalidateBlock(const Config &config, CValidationState &state,
CBlockIndex *pindex) {
AssertLockHeld(cs_main);
// Mark the block itself as invalid.
pindex->nStatus |= BLOCK_FAILED_VALID;
setDirtyBlockIndex.insert(pindex);
setBlockIndexCandidates.erase(pindex);
while (chainActive.Contains(pindex)) {
CBlockIndex *pindexWalk = chainActive.Tip();
pindexWalk->nStatus |= BLOCK_FAILED_CHILD;
setDirtyBlockIndex.insert(pindexWalk);
setBlockIndexCandidates.erase(pindexWalk);
// ActivateBestChain considers blocks already in chainActive
// unconditionally valid already, so force disconnect away from it.
if (!DisconnectTip(config, state)) {
mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1,
STANDARD_LOCKTIME_VERIFY_FLAGS);
return false;
}
}
LimitMempoolSize(
mempool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000,
GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
// The resulting new best tip may not be in setBlockIndexCandidates anymore,
// so add it again.
BlockMap::iterator it = mapBlockIndex.begin();
while (it != mapBlockIndex.end()) {
if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) &&
it->second->nChainTx &&
!setBlockIndexCandidates.value_comp()(it->second,
chainActive.Tip())) {
setBlockIndexCandidates.insert(it->second);
}
it++;
}
InvalidChainFound(pindex);
mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1,
STANDARD_LOCKTIME_VERIFY_FLAGS);
uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev);
return true;
}
bool ResetBlockFailureFlags(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;
setDirtyBlockIndex.insert(it->second);
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 = nullptr;
}
}
it++;
}
// Remove the invalidity flag from all ancestors too.
while (pindex != nullptr) {
if (pindex->nStatus & BLOCK_FAILED_MASK) {
pindex->nStatus &= ~BLOCK_FAILED_MASK;
setDirtyBlockIndex.insert(pindex);
}
pindex = pindex->pprev;
}
return true;
}
CBlockIndex *AddToBlockIndex(const CBlockHeader &block) {
// Check for duplicate
uint256 hash = block.GetHash();
BlockMap::iterator it = mapBlockIndex.find(hash);
if (it != mapBlockIndex.end()) return it->second;
// Construct new block index object
CBlockIndex *pindexNew = new CBlockIndex(block);
assert(pindexNew);
// 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;
BlockMap::iterator mi =
mapBlockIndex.insert(std::make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first);
BlockMap::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock);
if (miPrev != mapBlockIndex.end()) {
pindexNew->pprev = (*miPrev).second;
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
pindexNew->BuildSkip();
}
pindexNew->nTimeMax =
(pindexNew->pprev
? std::max(pindexNew->pprev->nTimeMax, pindexNew->nTime)
: pindexNew->nTime);
pindexNew->nChainWork =
(pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) +
GetBlockProof(*pindexNew);
pindexNew->RaiseValidity(BLOCK_VALID_TREE);
if (pindexBestHeader == nullptr ||
pindexBestHeader->nChainWork < pindexNew->nChainWork) {
pindexBestHeader = pindexNew;
}
setDirtyBlockIndex.insert(pindexNew);
return pindexNew;
}
/**
* Mark a block as having its data received and checked (up to
* BLOCK_VALID_TRANSACTIONS).
*/
bool ReceivedBlockTransactions(const CBlock &block, CValidationState &state,
CBlockIndex *pindexNew,
const CDiskBlockPos &pos) {
pindexNew->nTx = block.vtx.size();
pindexNew->nChainTx = 0;
pindexNew->nFile = pos.nFile;
pindexNew->nDataPos = pos.nPos;
pindexNew->nUndoPos = 0;
pindexNew->nStatus |= BLOCK_HAVE_DATA;
pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS);
setDirtyBlockIndex.insert(pindexNew);
if (pindexNew->pprev == nullptr || pindexNew->pprev->nChainTx) {
// If pindexNew is the genesis block or all parents are
// BLOCK_VALID_TRANSACTIONS.
std::deque<CBlockIndex *> queue;
queue.push_back(pindexNew);
// 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;
{
LOCK(cs_nBlockSequenceId);
pindex->nSequenceId = nBlockSequenceId++;
}
if (chainActive.Tip() == nullptr ||
!setBlockIndexCandidates.value_comp()(pindex,
chainActive.Tip())) {
setBlockIndexCandidates.insert(pindex);
}
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));
}
}
return true;
}
bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos,
unsigned int nAddSize, unsigned int nHeight, uint64_t nTime,
bool fKnown = false) {
LOCK(cs_LastBlockFile);
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);
}
}
pos.nFile = nFile;
pos.nPos = vinfoBlockFile[nFile].nSize;
}
if ((int)nFile != nLastBlockFile) {
if (!fKnown) {
LogPrintf("Leaving block file %i: %s\n", nLastBlockFile,
vinfoBlockFile[nLastBlockFile].ToString());
}
FlushBlockFile(!fKnown);
nLastBlockFile = nFile;
}
vinfoBlockFile[nFile].AddBlock(nHeight, nTime);
if (fKnown)
vinfoBlockFile[nFile].nSize =
std::max(pos.nPos + nAddSize, vinfoBlockFile[nFile].nSize);
else
vinfoBlockFile[nFile].nSize += nAddSize;
if (!fKnown) {
unsigned int nOldChunks =
(pos.nPos + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE;
unsigned int nNewChunks =
(vinfoBlockFile[nFile].nSize + BLOCKFILE_CHUNK_SIZE - 1) /
BLOCKFILE_CHUNK_SIZE;
if (nNewChunks > nOldChunks) {
if (fPruneMode) fCheckForPruning = true;
if (CheckDiskSpace(nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos)) {
FILE *file = OpenBlockFile(pos);
if (file) {
LogPrintf(
"Pre-allocating up to position 0x%x in blk%05u.dat\n",
nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile);
AllocateFileRange(file, pos.nPos,
nNewChunks * BLOCKFILE_CHUNK_SIZE -
pos.nPos);
fclose(file);
}
} else
return state.Error("out of disk space");
}
}
setDirtyFileInfo.insert(nFile);
return true;
}
bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos,
unsigned int nAddSize) {
pos.nFile = nFile;
LOCK(cs_LastBlockFile);
unsigned int nNewSize;
pos.nPos = vinfoBlockFile[nFile].nUndoSize;
nNewSize = vinfoBlockFile[nFile].nUndoSize += nAddSize;
setDirtyFileInfo.insert(nFile);
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) {
if (fPruneMode) fCheckForPruning = true;
if (CheckDiskSpace(nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos)) {
FILE *file = OpenUndoFile(pos);
if (file) {
LogPrintf("Pre-allocating up to position 0x%x in rev%05u.dat\n",
nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile);
AllocateFileRange(file, pos.nPos,
nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos);
fclose(file);
}
} else
return state.Error("out of disk space");
}
return true;
}
bool CheckBlockHeader(const CBlockHeader &block, CValidationState &state,
const Consensus::Params &consensusParams,
bool fCheckPOW) {
// Check proof of work matches claimed amount
if (fCheckPOW &&
!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))
return state.DoS(50, false, REJECT_INVALID, "high-hash", false,
"proof of work failed");
return true;
}
bool CheckBlock(const Config &config, const CBlock &block,
CValidationState &state,
const Consensus::Params &consensusParams, bool fCheckPOW,
bool fCheckMerkleRoot) {
// These are checks that are independent of context.
if (block.fChecked) {
return true;
}
// Check that the header is valid (particularly PoW). This is mostly
// redundant with the call in AcceptBlockHeader.
if (!CheckBlockHeader(block, state, consensusParams, fCheckPOW)) {
return false;
}
// Check the merkle root.
if (fCheckMerkleRoot) {
bool mutated;
uint256 hashMerkleRoot2 = BlockMerkleRoot(block, &mutated);
if (block.hashMerkleRoot != hashMerkleRoot2) {
return state.DoS(100, false, REJECT_INVALID, "bad-txnmrklroot",
true, "hashMerkleRoot mismatch");
}
// 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) {
return state.DoS(100, false, REJECT_INVALID, "bad-txns-duplicate",
true, "duplicate transaction");
}
}
// 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.
// First transaction must be coinbase.
if (block.vtx.empty()) {
return state.DoS(100, false, REJECT_INVALID, "bad-cb-missing", false,
"first tx is not coinbase");
}
// Size limits.
auto nMaxBlockSize = config.GetMaxBlockSize();
// Bail early if there is no way this block is of reasonable size.
if ((block.vtx.size() * MIN_TRANSACTION_SIZE) > nMaxBlockSize) {
return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false,
"size limits failed");
}
auto currentBlockSize =
::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION);
if (currentBlockSize > nMaxBlockSize) {
return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false,
"size limits failed");
}
// And a valid coinbase.
if (!CheckCoinbase(*block.vtx[0], state, false)) {
return state.Invalid(false, state.GetRejectCode(),
state.GetRejectReason(),
strprintf("Coinbase check failed (txid %s) %s",
block.vtx[0]->GetId().ToString(),
state.GetDebugMessage()));
}
// Keep track of the sigops count.
uint64_t nSigOps = 0;
auto nMaxSigOpsCount = GetMaxBlockSigOpsCount(currentBlockSize);
// Check transactions
auto txCount = block.vtx.size();
auto *tx = block.vtx[0].get();
size_t i = 0;
while (true) {
// Count the sigops for the current transaction. If the total sigops
// count is too high, the the block is invalid.
nSigOps += GetSigOpCountWithoutP2SH(*tx);
if (nSigOps > nMaxSigOpsCount) {
return state.DoS(100, false, REJECT_INVALID, "bad-blk-sigops",
false, "out-of-bounds SigOpCount");
}
// Go to the next transaction.
i++;
// We reached the end of the block, success.
if (i >= txCount) {
break;
}
// Check that the transaction is valid. because this check differs for
// the coinbase, the loos is arranged such as this only runs after at
// least one increment.
tx = block.vtx[i].get();
if (!CheckRegularTransaction(*tx, state, false)) {
return state.Invalid(
false, state.GetRejectCode(), state.GetRejectReason(),
strprintf("Transaction check failed (txid %s) %s",
tx->GetId().ToString(), state.GetDebugMessage()));
}
}
if (fCheckPOW && fCheckMerkleRoot) {
block.fChecked = true;
}
return true;
}
static bool CheckIndexAgainstCheckpoint(const CBlockIndex *pindexPrev,
CValidationState &state,
const CChainParams &chainparams,
const uint256 &hash) {
if (*pindexPrev->phashBlock ==
chainparams.GetConsensus().hashGenesisBlock) {
return true;
}
int nHeight = pindexPrev->nHeight + 1;
// 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));
}
return true;
}
bool ContextualCheckBlockHeader(const CBlockHeader &block,
CValidationState &state,
const Consensus::Params &consensusParams,
const CBlockIndex *pindexPrev,
int64_t nAdjustedTime) {
const int nHeight = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1;
// Check proof of work
if (block.nBits !=
GetNextWorkRequired(pindexPrev, &block, consensusParams)) {
return state.DoS(100, false, REJECT_INVALID, "bad-diffbits", false,
"incorrect proof of work");
}
// Check timestamp against prev
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) {
return state.Invalid(false, REJECT_INVALID, "time-too-old",
"block's timestamp is too early");
}
// Check timestamp
if (block.GetBlockTime() > nAdjustedTime + 2 * 60 * 60) {
return state.Invalid(false, REJECT_INVALID, "time-too-new",
"block timestamp too far in the future");
}
// Reject outdated version blocks when 95% (75% on testnet) of the network
// has upgraded:
// check for version 2, 3 and 4 upgrades
if ((block.nVersion < 2 && nHeight >= consensusParams.BIP34Height) ||
(block.nVersion < 3 && nHeight >= consensusParams.BIP66Height) ||
(block.nVersion < 4 && nHeight >= consensusParams.BIP65Height)) {
return state.Invalid(
false, REJECT_OBSOLETE,
strprintf("bad-version(0x%08x)", block.nVersion),
strprintf("rejected nVersion=0x%08x block", block.nVersion));
}
return true;
}
bool ContextualCheckTransaction(const Config &config, const CTransaction &tx,
CValidationState &state,
const Consensus::Params &consensusParams,
int nHeight, int64_t nLockTimeCutoff) {
if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) {
// While this is only one transaction, we use txns in the error to
// ensure continuity with other clients.
return state.DoS(10, false, REJECT_INVALID, "bad-txns-nonfinal", false,
"non-final transaction");
}
if (IsUAHFenabled(config, nHeight) &&
nHeight <= consensusParams.antiReplayOpReturnSunsetHeight) {
for (const CTxOut &o : tx.vout) {
if (o.scriptPubKey.IsCommitment(
consensusParams.antiReplayOpReturnCommitment)) {
return state.DoS(10, false, REJECT_INVALID, "bad-txn-replay",
false, "non playable transaction");
}
}
}
return true;
}
bool ContextualCheckTransactionForCurrentBlock(
const Config &config, const CTransaction &tx, CValidationState &state,
const Consensus::Params &consensusParams, int flags) {
AssertLockHeld(cs_main);
// 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);
// ContextualCheckTransactionForCurrentBlock() 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 ContextualCheckTransaction() with one more
// than chainActive.Height().
const int nBlockHeight = chainActive.Height() + 1;
// BIP113 will require that time-locked transactions have nLockTime set to
// less than the median time of the previous block they're contained in.
// When the next block is created its previous block will be the current
// chain tip, so we use that to calculate the median time passed to
// ContextualCheckTransaction() if LOCKTIME_MEDIAN_TIME_PAST is set.
const int64_t nLockTimeCutoff = (flags & LOCKTIME_MEDIAN_TIME_PAST)
? chainActive.Tip()->GetMedianTimePast()
: GetAdjustedTime();
return ContextualCheckTransaction(config, tx, state, consensusParams,
nBlockHeight, nLockTimeCutoff);
}
bool ContextualCheckBlock(const Config &config, const CBlock &block,
CValidationState &state,
const Consensus::Params &consensusParams,
const CBlockIndex *pindexPrev) {
const int nHeight = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1;
// Start enforcing BIP113 (Median Time Past) using versionbits logic.
int nLockTimeFlags = 0;
if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CSV,
versionbitscache) == THRESHOLD_ACTIVE) {
nLockTimeFlags |= LOCKTIME_MEDIAN_TIME_PAST;
}
const int64_t nMedianTimePast =
pindexPrev == nullptr ? 0 : pindexPrev->GetMedianTimePast();
const int64_t nLockTimeCutoff = (nLockTimeFlags & LOCKTIME_MEDIAN_TIME_PAST)
? nMedianTimePast
: block.GetBlockTime();
// Check that all transactions are finalized
for (const auto &tx : block.vtx) {
if (!ContextualCheckTransaction(config, *tx, state, consensusParams,
nHeight, nLockTimeCutoff)) {
// state set by ContextualCheckTransaction.
return false;
}
}
// Enforce rule that the coinbase starts with serialized block height
if (nHeight >= consensusParams.BIP34Height) {
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())) {
return state.DoS(100, false, REJECT_INVALID, "bad-cb-height", false,
"block height mismatch in coinbase");
}
}
return true;
}
static bool AcceptBlockHeader(const Config &config, const CBlockHeader &block,
CValidationState &state, CBlockIndex **ppindex) {
AssertLockHeld(cs_main);
const CChainParams &chainparams = config.GetChainParams();
// Check for duplicate
uint256 hash = block.GetHash();
BlockMap::iterator miSelf = mapBlockIndex.find(hash);
CBlockIndex *pindex = nullptr;
if (hash != chainparams.GetConsensus().hashGenesisBlock) {
if (miSelf != mapBlockIndex.end()) {
// Block header is already known.
pindex = miSelf->second;
if (ppindex) {
*ppindex = pindex;
}
if (pindex->nStatus & BLOCK_FAILED_MASK) {
return state.Invalid(error("%s: block %s is marked invalid",
__func__, hash.ToString()),
0, "duplicate");
}
return true;
}
if (!CheckBlockHeader(block, state, chainparams.GetConsensus())) {
return error("%s: Consensus::CheckBlockHeader: %s, %s", __func__,
hash.ToString(), FormatStateMessage(state));
}
// Get prev block index
CBlockIndex *pindexPrev = nullptr;
BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
if (mi == mapBlockIndex.end()) {
return state.DoS(10, error("%s: prev block not found", __func__), 0,
"bad-prevblk");
}
pindexPrev = (*mi).second;
if (pindexPrev->nStatus & BLOCK_FAILED_MASK) {
return state.DoS(100, error("%s: prev block invalid", __func__),
REJECT_INVALID, "bad-prevblk");
}
assert(pindexPrev);
if (fCheckpointsEnabled &&
!CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams,
hash)) {
return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__,
state.GetRejectReason().c_str());
}
if (!ContextualCheckBlockHeader(block, state,
chainparams.GetConsensus(), pindexPrev,
GetAdjustedTime())) {
return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s",
__func__, hash.ToString(), FormatStateMessage(state));
}
}
if (pindex == nullptr) {
pindex = AddToBlockIndex(block);
}
if (ppindex) {
*ppindex = pindex;
}
CheckBlockIndex(chainparams.GetConsensus());
return true;
}
// Exposed wrapper for AcceptBlockHeader
bool ProcessNewBlockHeaders(const Config &config,
const std::vector<CBlockHeader> &headers,
CValidationState &state,
const CBlockIndex **ppindex) {
{
LOCK(cs_main);
for (const CBlockHeader &header : headers) {
// Use a temp pindex instead of ppindex to avoid a const_cast
CBlockIndex *pindex = nullptr;
if (!AcceptBlockHeader(config, header, state, &pindex)) {
return false;
}
if (ppindex) {
*ppindex = pindex;
}
}
}
NotifyHeaderTip();
return true;
}
/**
* Store block on disk. If dbp is non-null, the file is known to already reside
* on disk.
*/
static bool AcceptBlock(const Config &config,
const std::shared_ptr<const CBlock> &pblock,
CValidationState &state, CBlockIndex **ppindex,
bool fRequested, const CDiskBlockPos *dbp,
bool *fNewBlock) {
AssertLockHeld(cs_main);
const CBlock &block = *pblock;
if (fNewBlock) {
*fNewBlock = false;
}
CBlockIndex *pindexDummy = nullptr;
CBlockIndex *&pindex = ppindex ? *ppindex : pindexDummy;
if (!AcceptBlockHeader(config, block, state, &pindex)) {
return false;
}
// 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
// advance our tip, and isn't too many blocks ahead.
bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA;
bool fHasMoreWork =
(chainActive.Tip() ? pindex->nChainWork > chainActive.Tip()->nChainWork
: true);
// 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));
// TODO: Decouple this function from the block download logic by removing
// fRequested
// This requires some new chain datastructure to efficiently look up if a
// block is in a chain leading to a candidate for best tip, despite not
// being such a candidate itself.
// TODO: deal better with return value and error conditions for duplicate
// and unrequested blocks.
if (fAlreadyHave) {
return true;
}
// If we didn't ask for it:
if (!fRequested) {
// This is a previously-processed block that was pruned.
if (pindex->nTx != 0) {
return true;
}
// Don't process less-work chains.
if (!fHasMoreWork) {
return true;
}
// Block height is too high.
if (fTooFarAhead) {
return true;
}
}
if (fNewBlock) {
*fNewBlock = true;
}
const CChainParams &chainparams = config.GetChainParams();
if (!CheckBlock(config, block, state, chainparams.GetConsensus()) ||
!ContextualCheckBlock(config, block, state, chainparams.GetConsensus(),
pindex->pprev)) {
if (state.IsInvalid() && !state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID;
setDirtyBlockIndex.insert(pindex);
}
return error("%s: %s (block %s)", __func__, FormatStateMessage(state),
block.GetHash().ToString());
}
// Header is valid/has work, merkle tree and segwit merkle tree are
// good...RELAY NOW (but if it does not build on our best tip, let the
// SendMessages loop relay it)
if (!IsInitialBlockDownload() && chainActive.Tip() == pindex->pprev) {
GetMainSignals().NewPoWValidBlock(pindex, pblock);
}
int nHeight = pindex->nHeight;
// Write block to history file
try {
unsigned int nBlockSize =
::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
CDiskBlockPos blockPos;
if (dbp != nullptr) {
blockPos = *dbp;
}
if (!FindBlockPos(state, blockPos, nBlockSize + 8, nHeight,
block.GetBlockTime(), dbp != nullptr)) {
return error("AcceptBlock(): FindBlockPos failed");
}
if (dbp == nullptr) {
if (!WriteBlockToDisk(block, blockPos,
chainparams.MessageStart())) {
AbortNode(state, "Failed to write block");
}
}
if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) {
return error("AcceptBlock(): ReceivedBlockTransactions failed");
}
} catch (const std::runtime_error &e) {
return AbortNode(state, std::string("System error: ") + e.what());
}
if (fCheckForPruning) {
// we just allocated more disk space for block files.
FlushStateToDisk(state, FLUSH_STATE_NONE);
}
return true;
}
bool ProcessNewBlock(const Config &config,
const std::shared_ptr<const CBlock> pblock,
bool fForceProcessing, bool *fNewBlock) {
{
CBlockIndex *pindex = nullptr;
if (fNewBlock) *fNewBlock = false;
const CChainParams &chainparams = config.GetChainParams();
CValidationState state;
// Ensure that CheckBlock() passes before calling AcceptBlock, as
// belt-and-suspenders.
bool ret =
CheckBlock(config, *pblock, state, chainparams.GetConsensus());
LOCK(cs_main);
if (ret) {
// Store to disk
ret = AcceptBlock(config, pblock, state, &pindex, fForceProcessing,
nullptr, fNewBlock);
}
CheckBlockIndex(chainparams.GetConsensus());
if (!ret) {
GetMainSignals().BlockChecked(*pblock, state);
return error("%s: AcceptBlock FAILED", __func__);
}
}
NotifyHeaderTip();
// Only used to report errors, not invalidity - ignore it
CValidationState state;
if (!ActivateBestChain(config, state, pblock))
return error("%s: ActivateBestChain failed", __func__);
return true;
}
bool TestBlockValidity(const Config &config, CValidationState &state,
const CChainParams &chainparams, const CBlock &block,
CBlockIndex *pindexPrev, bool fCheckPOW,
bool fCheckMerkleRoot) {
AssertLockHeld(cs_main);
assert(pindexPrev && pindexPrev == chainActive.Tip());
if (fCheckpointsEnabled &&
!CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams,
block.GetHash())) {
return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__,
state.GetRejectReason().c_str());
}
CCoinsViewCache viewNew(pcoinsTip);
CBlockIndex indexDummy(block);
indexDummy.pprev = pindexPrev;
indexDummy.nHeight = pindexPrev->nHeight + 1;
// NOTE: CheckBlockHeader is called by CheckBlock
if (!ContextualCheckBlockHeader(block, state, chainparams.GetConsensus(),
pindexPrev, GetAdjustedTime())) {
return error("%s: Consensus::ContextualCheckBlockHeader: %s", __func__,
FormatStateMessage(state));
}
if (!CheckBlock(config, block, state, chainparams.GetConsensus(), fCheckPOW,
fCheckMerkleRoot)) {
return error("%s: Consensus::CheckBlock: %s", __func__,
FormatStateMessage(state));
}
if (!ContextualCheckBlock(config, block, state, chainparams.GetConsensus(),
pindexPrev)) {
return error("%s: Consensus::ContextualCheckBlock: %s", __func__,
FormatStateMessage(state));
}
if (!ConnectBlock(config, block, state, &indexDummy, viewNew, chainparams,
true)) {
return false;
}
assert(state.IsValid());
return true;
}
/**
* BLOCK PRUNING CODE
*/
/* Calculate the amount of disk space the block & undo files currently use */
uint64_t CalculateCurrentUsage() {
uint64_t retval = 0;
for (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(const std::set<int> &setFilesToPrune) {
for (std::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 to delete based on height specified by user
* with RPC command pruneblockchain.
*/
static void FindFilesToPruneManual(std::set<int> &setFilesToPrune,
int nManualPruneHeight) {
assert(fPruneMode && nManualPruneHeight > 0);
LOCK2(cs_main, cs_LastBlockFile);
if (chainActive.Tip() == nullptr) {
return;
}
// last block to prune is the lesser of (user-specified height,
// MIN_BLOCKS_TO_KEEP from the tip)
unsigned int nLastBlockWeCanPrune =
std::min((unsigned)nManualPruneHeight,
chainActive.Tip()->nHeight - MIN_BLOCKS_TO_KEEP);
int count = 0;
for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) {
if (vinfoBlockFile[fileNumber].nSize == 0 ||
vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) {
continue;
}
PruneOneBlockFile(fileNumber);
setFilesToPrune.insert(fileNumber);
count++;
}
LogPrintf("Prune (Manual): prune_height=%d removed %d blk/rev pairs\n",
nLastBlockWeCanPrune, count);
}
/* This function is called from the RPC code for pruneblockchain */
void PruneBlockFilesManual(int nManualPruneHeight) {
CValidationState state;
FlushStateToDisk(state, FLUSH_STATE_NONE, nManualPruneHeight);
}
/* Calculate the block/rev files that should be deleted to remain under target*/
void FindFilesToPrune(std::set<int> &setFilesToPrune,
uint64_t nPruneAfterHeight) {
LOCK2(cs_main, cs_LastBlockFile);
if (chainActive.Tip() == nullptr || nPruneTarget == 0) {
return;
}
if (uint64_t(chainActive.Tip()->nHeight) <= nPruneAfterHeight) {
return;
}
unsigned int nLastBlockWeCanPrune =
chainActive.Tip()->nHeight - MIN_BLOCKS_TO_KEEP;
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;
}
// are we below our target?
if (nCurrentUsage + nBuffer < nPruneTarget) {
break;
}
// don't prune files that could have a block within
// MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning
if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) {
continue;
}
PruneOneBlockFile(fileNumber);
// Queue up the files for removal
setFilesToPrune.insert(fileNumber);
nCurrentUsage -= nBytesToPrune;
count++;
}
}
LogPrint("prune", "Prune: target=%dMiB actual=%dMiB diff=%dMiB "
"max_prune_height=%d removed %d blk/rev pairs\n",
nPruneTarget / 1024 / 1024, nCurrentUsage / 1024 / 1024,
((int64_t)nPruneTarget - (int64_t)nCurrentUsage) / 1024 / 1024,
nLastBlockWeCanPrune, count);
}
bool CheckDiskSpace(uint64_t nAdditionalBytes) {
uint64_t nFreeBytesAvailable =
boost::filesystem::space(GetDataDir()).available;
// Check for nMinDiskSpace bytes (currently 50MB)
if (nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes)
return AbortNode("Disk space is low!", _("Error: Disk space is low!"));
return true;
}
FILE *OpenDiskFile(const CDiskBlockPos &pos, const char *prefix,
bool fReadOnly) {
if (pos.IsNull()) return nullptr;
boost::filesystem::path path = GetBlockPosFilename(pos, prefix);
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+");
if (!file) {
LogPrintf("Unable to open file %s\n", path.string());
return nullptr;
}
if (pos.nPos) {
if (fseek(file, pos.nPos, SEEK_SET)) {
LogPrintf("Unable to seek to position %u of %s\n", pos.nPos,
path.string());
fclose(file);
return nullptr;
}
}
return file;
}
FILE *OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly) {
return OpenDiskFile(pos, "blk", fReadOnly);
}
FILE *OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly) {
return OpenDiskFile(pos, "rev", fReadOnly);
}
boost::filesystem::path GetBlockPosFilename(const CDiskBlockPos &pos,
const char *prefix) {
return GetDataDir() / "blocks" / strprintf("%s%05u.dat", prefix, pos.nFile);
}
CBlockIndex *InsertBlockIndex(uint256 hash) {
if (hash.IsNull()) return nullptr;
// Return existing
BlockMap::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end()) return (*mi).second;
// Create new
CBlockIndex *pindexNew = new CBlockIndex();
if (!pindexNew)
throw std::runtime_error(std::string(__func__) +
": new CBlockIndex failed");
mi = mapBlockIndex.insert(std::make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first);
return pindexNew;
}
static bool LoadBlockIndexDB(const CChainParams &chainparams) {
if (!pblocktree->LoadBlockIndexGuts(InsertBlockIndex)) return false;
boost::this_thread::interruption_point();
// Calculate nChainWork
std::vector<std::pair<int, CBlockIndex *>> vSortedByHeight;
vSortedByHeight.reserve(mapBlockIndex.size());
for (const std::pair<uint256, CBlockIndex *> &item : mapBlockIndex) {
CBlockIndex *pindex = item.second;
vSortedByHeight.push_back(std::make_pair(pindex->nHeight, pindex));
}
sort(vSortedByHeight.begin(), vSortedByHeight.end());
for (const std::pair<int, CBlockIndex *> &item : vSortedByHeight) {
CBlockIndex *pindex = item.second;
pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) +
GetBlockProof(*pindex);
pindex->nTimeMax =
(pindex->pprev ? std::max(pindex->pprev->nTimeMax, pindex->nTime)
: pindex->nTime);
// 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) {
if (pindex->pprev) {
if (pindex->pprev->nChainTx) {
pindex->nChainTx = pindex->pprev->nChainTx + pindex->nTx;
} else {
pindex->nChainTx = 0;
mapBlocksUnlinked.insert(
std::make_pair(pindex->pprev, pindex));
}
} else {
pindex->nChainTx = pindex->nTx;
}
}
if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) &&
(pindex->nChainTx || pindex->pprev == nullptr)) {
setBlockIndexCandidates.insert(pindex);
}
if (pindex->nStatus & BLOCK_FAILED_MASK &&
(!pindexBestInvalid ||
pindex->nChainWork > pindexBestInvalid->nChainWork)) {
pindexBestInvalid = pindex;
}
if (pindex->pprev) {
pindex->BuildSkip();
}
if (pindex->IsValid(BLOCK_VALID_TREE) &&
(pindexBestHeader == nullptr ||
CBlockIndexWorkComparator()(pindexBestHeader, pindex))) {
pindexBestHeader = pindex;
}
}
// Load block file info
pblocktree->ReadLastBlockFile(nLastBlockFile);
vinfoBlockFile.resize(nLastBlockFile + 1);
LogPrintf("%s: last block file = %i\n", __func__, nLastBlockFile);
for (int nFile = 0; nFile <= nLastBlockFile; nFile++) {
pblocktree->ReadBlockFileInfo(nFile, vinfoBlockFile[nFile]);
}
LogPrintf("%s: last block file info: %s\n", __func__,
vinfoBlockFile[nLastBlockFile].ToString());
for (int nFile = nLastBlockFile + 1; true; nFile++) {
CBlockFileInfo info;
if (pblocktree->ReadBlockFileInfo(nFile, info)) {
vinfoBlockFile.push_back(info);
} else {
break;
}
}
// Check presence of blk files
LogPrintf("Checking all blk files are present...\n");
std::set<int> setBlkDataFiles;
for (const std::pair<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);
if (CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION)
.IsNull()) {
return false;
}
}
// Check whether we have ever pruned block & undo files
pblocktree->ReadFlag("prunedblockfiles", fHavePruned);
if (fHavePruned) {
LogPrintf(
"LoadBlockIndexDB(): Block files have previously been pruned\n");
}
// Check whether we need to continue reindexing
bool fReindexing = false;
pblocktree->ReadReindexing(fReindexing);
fReindex |= fReindexing;
// Check whether we have a transaction index
pblocktree->ReadFlag("txindex", fTxIndex);
LogPrintf("%s: transaction index %s\n", __func__,
fTxIndex ? "enabled" : "disabled");
// Load pointer to end of best chain
BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
if (it == mapBlockIndex.end()) {
return true;
}
chainActive.SetTip(it->second);
PruneBlockIndexCandidates();
LogPrintf(
"%s: hashBestChain=%s height=%d date=%s progress=%f\n", __func__,
chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(),
DateTimeStrFormat("%Y-%m-%d %H:%M:%S",
chainActive.Tip()->GetBlockTime()),
GuessVerificationProgress(chainparams.TxData(), chainActive.Tip()));
return true;
}
CVerifyDB::CVerifyDB() {
uiInterface.ShowProgress(_("Verifying blocks..."), 0);
}
CVerifyDB::~CVerifyDB() {
uiInterface.ShowProgress("", 100);
}
bool CVerifyDB::VerifyDB(const Config &config, const CChainParams &chainparams,
CCoinsView *coinsview, int nCheckLevel,
int nCheckDepth) {
LOCK(cs_main);
if (chainActive.Tip() == nullptr || chainActive.Tip()->pprev == nullptr) {
return true;
}
// Verify blocks in the best chain
if (nCheckDepth <= 0) {
// suffices until the year 19000
nCheckDepth = 1000000000;
}
if (nCheckDepth > chainActive.Height()) {
nCheckDepth = chainActive.Height();
}
nCheckLevel = std::max(0, std::min(4, nCheckLevel));
LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth,
nCheckLevel);
CCoinsViewCache coins(coinsview);
CBlockIndex *pindexState = chainActive.Tip();
CBlockIndex *pindexFailure = nullptr;
int nGoodTransactions = 0;
CValidationState state;
int reportDone = 0;
LogPrintf("[0%%]...");
for (CBlockIndex *pindex = chainActive.Tip(); pindex && pindex->pprev;
pindex = pindex->pprev) {
boost::this_thread::interruption_point();
int percentageDone = std::max(
1, std::min(
99,
(int)(((double)(chainActive.Height() - pindex->nHeight)) /
(double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))));
if (reportDone < percentageDone / 10) {
// report every 10% step
LogPrintf("[%d%%]...", percentageDone);
reportDone = percentageDone / 10;
}
uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone);
if (pindex->nHeight < chainActive.Height() - nCheckDepth) {
break;
}
if (fPruneMode && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
// If pruning, only go back as far as we have data.
LogPrintf("VerifyDB(): block verification stopping at height %d "
"(pruning, no data)\n",
pindex->nHeight);
break;
}
CBlock block;
// check level 0: read from disk
if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) {
return error(
"VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s",
pindex->nHeight, pindex->GetBlockHash().ToString());
}
// check level 1: verify block validity
if (nCheckLevel >= 1 &&
!CheckBlock(config, block, state, chainparams.GetConsensus())) {
return error("%s: *** found bad block at %d, hash=%s (%s)\n",
__func__, pindex->nHeight,
pindex->GetBlockHash().ToString(),
FormatStateMessage(state));
}
// check level 2: verify undo validity
if (nCheckLevel >= 2 && pindex) {
CBlockUndo undo;
CDiskBlockPos pos = pindex->GetUndoPos();
if (!pos.IsNull()) {
if (!UndoReadFromDisk(undo, pos,
pindex->pprev->GetBlockHash())) {
return error(
"VerifyDB(): *** found bad undo data at %d, hash=%s\n",
pindex->nHeight, pindex->GetBlockHash().ToString());
}
}
}
// check level 3: check for inconsistencies during memory-only
// disconnect of tip blocks
if (nCheckLevel >= 3 && pindex == pindexState &&
(coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <=
nCoinCacheUsage) {
DisconnectResult res = DisconnectBlock(block, pindex, coins);
if (res == DISCONNECT_FAILED) {
return error("VerifyDB(): *** irrecoverable inconsistency in "
"block data at %d, hash=%s",
pindex->nHeight,
pindex->GetBlockHash().ToString());
}
pindexState = pindex->pprev;
if (res == DISCONNECT_UNCLEAN) {
nGoodTransactions = 0;
pindexFailure = pindex;
} else {
nGoodTransactions += block.vtx.size();
}
}
if (ShutdownRequested()) {
return true;
}
}
if (pindexFailure) {
return error("VerifyDB(): *** coin database inconsistencies found "
"(last %i blocks, %i good transactions before that)\n",
chainActive.Height() - pindexFailure->nHeight + 1,
nGoodTransactions);
}
// check level 4: try reconnecting blocks
if (nCheckLevel >= 4) {
CBlockIndex *pindex = pindexState;
while (pindex != chainActive.Tip()) {
boost::this_thread::interruption_point();
uiInterface.ShowProgress(
_("Verifying blocks..."),
std::max(
1, std::min(99, 100 - (int)(((double)(chainActive.Height() -
pindex->nHeight)) /
(double)nCheckDepth * 50))));
pindex = chainActive.Next(pindex);
CBlock block;
if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) {
return error(
"VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s",
pindex->nHeight, pindex->GetBlockHash().ToString());
}
if (!ConnectBlock(config, block, state, pindex, coins,
chainparams)) {
return error(
"VerifyDB(): *** found unconnectable block at %d, hash=%s",
pindex->nHeight, pindex->GetBlockHash().ToString());
}
}
}
LogPrintf("[DONE].\n");
LogPrintf("No coin database inconsistencies in last %i blocks (%i "
"transactions)\n",
chainActive.Height() - pindexState->nHeight, nGoodTransactions);
return true;
}
bool RewindBlockIndex(const Config &config, const CChainParams &params) {
LOCK(cs_main);
int nHeight = chainActive.Height() + 1;
// nHeight is now the height of the first insufficiently-validated block, or
// tipheight + 1
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;
}
if (!DisconnectTip(config, state, true)) {
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;
}
}
// Reduce validity flag and have-data flags.
// 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.
for (BlockMap::iterator it = mapBlockIndex.begin();
it != mapBlockIndex.end(); it++) {
CBlockIndex *pindexIter = it->second;
if (pindexIter->IsValid(BLOCK_VALID_TRANSACTIONS) &&
pindexIter->nChainTx) {
setBlockIndexCandidates.insert(pindexIter);
}
}
PruneBlockIndexCandidates();
CheckBlockIndex(params.GetConsensus());
if (!FlushStateToDisk(state, FLUSH_STATE_ALWAYS)) {
return false;
}
return true;
}
// May NOT be used after any connections are up as much of the peer-processing
// logic assumes a consistent block index state
void UnloadBlockIndex() {
LOCK(cs_main);
setBlockIndexCandidates.clear();
chainActive.SetTip(nullptr);
pindexBestInvalid = nullptr;
pindexBestHeader = nullptr;
mempool.clear();
mapBlocksUnlinked.clear();
vinfoBlockFile.clear();
nLastBlockFile = 0;
nBlockSequenceId = 1;
setDirtyBlockIndex.clear();
setDirtyFileInfo.clear();
versionbitscache.Clear();
for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {
warningcache[b].clear();
}
for (BlockMap::value_type &entry : mapBlockIndex) {
delete entry.second;
}
mapBlockIndex.clear();
fHavePruned = false;
}
bool LoadBlockIndex(const CChainParams &chainparams) {
// Load block index from databases
if (!fReindex && !LoadBlockIndexDB(chainparams)) {
return false;
}
return true;
}
bool InitBlockIndex(const Config &config) {
LOCK(cs_main);
// Check whether we're already initialized
if (chainActive.Genesis() != nullptr) {
return true;
}
// Use the provided setting for -txindex in the new database
fTxIndex = GetBoolArg("-txindex", DEFAULT_TXINDEX);
pblocktree->WriteFlag("txindex", fTxIndex);
LogPrintf("Initializing databases...\n");
// Only add the genesis block if not reindexing (in which case we reuse the
// one already on disk)
if (!fReindex) {
try {
const CChainParams &chainparams = config.GetChainParams();
CBlock &block = const_cast<CBlock &>(chainparams.GenesisBlock());
// Start new block file
unsigned int nBlockSize =
::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
CDiskBlockPos blockPos;
CValidationState state;
if (!FindBlockPos(state, blockPos, nBlockSize + 8, 0,
block.GetBlockTime())) {
return error("LoadBlockIndex(): FindBlockPos failed");
}
if (!WriteBlockToDisk(block, blockPos,
chainparams.MessageStart())) {
return error(
"LoadBlockIndex(): writing genesis block to disk failed");
}
CBlockIndex *pindex = AddToBlockIndex(block);
if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) {
return error("LoadBlockIndex(): genesis block not accepted");
}
// Force a chainstate write so that when we VerifyDB in a moment, it
// doesn't check stale data
return FlushStateToDisk(state, FLUSH_STATE_ALWAYS);
} catch (const std::runtime_error &e) {
return error(
"LoadBlockIndex(): failed to initialize block database: %s",
e.what());
}
}
return true;
}
bool LoadExternalBlockFile(const Config &config, FILE *fileIn,
CDiskBlockPos *dbp) {
// Map of disk positions for blocks with unknown parent (only used for
// reindex)
static std::multimap<uint256, CDiskBlockPos> mapBlocksUnknownParent;
int64_t nStart = GetTimeMillis();
const CChainParams &chainparams = config.GetChainParams();
int nLoaded = 0;
try {
// This takes over fileIn and calls fclose() on it in the CBufferedFile
// destructor. Make sure we have at least 2*MAX_TX_SIZE space in there
// so any transaction can fit in the buffer.
CBufferedFile blkdat(fileIn, 2 * MAX_TX_SIZE, MAX_TX_SIZE + 8, SER_DISK,
CLIENT_VERSION);
uint64_t nRewind = blkdat.GetPos();
while (!blkdat.eof()) {
boost::this_thread::interruption_point();
blkdat.SetPos(nRewind);
// Start one byte further next time, in case of failure.
nRewind++;
// Remove former limit.
blkdat.SetLimit();
unsigned int nSize = 0;
try {
// Locate a header.
uint8_t buf[CMessageHeader::MESSAGE_START_SIZE];
blkdat.FindByte(chainparams.MessageStart()[0]);
nRewind = blkdat.GetPos() + 1;
blkdat >> FLATDATA(buf);
if (memcmp(buf, chainparams.MessageStart(),
CMessageHeader::MESSAGE_START_SIZE)) {
continue;
}
// Read size.
blkdat >> nSize;
if (nSize < 80) {
continue;
}
} catch (const std::exception &) {
// No valid block header found; don't complain.
break;
}
try {
// read block
uint64_t nBlockPos = blkdat.GetPos();
if (dbp) {
dbp->nPos = nBlockPos;
}
blkdat.SetLimit(nBlockPos + nSize);
blkdat.SetPos(nBlockPos);
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
CBlock &block = *pblock;
blkdat >> block;
nRewind = blkdat.GetPos();
// detect out of order blocks, and store them for later
uint256 hash = block.GetHash();
if (hash != chainparams.GetConsensus().hashGenesisBlock &&
mapBlockIndex.find(block.hashPrevBlock) ==
mapBlockIndex.end()) {
LogPrint("reindex",
"%s: Out of order block %s, parent %s not known\n",
__func__, hash.ToString(),
block.hashPrevBlock.ToString());
if (dbp) {
mapBlocksUnknownParent.insert(
std::make_pair(block.hashPrevBlock, *dbp));
}
continue;
}
// process in case the block isn't known yet
if (mapBlockIndex.count(hash) == 0 ||
(mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) {
LOCK(cs_main);
CValidationState state;
if (AcceptBlock(config, pblock, state, nullptr, true, dbp,
nullptr)) {
nLoaded++;
}
if (state.IsError()) {
break;
}
} else if (hash !=
chainparams.GetConsensus().hashGenesisBlock &&
mapBlockIndex[hash]->nHeight % 1000 == 0) {
LogPrint(
"reindex",
"Block Import: already had block %s at height %d\n",
hash.ToString(), mapBlockIndex[hash]->nHeight);
}
// Activate the genesis block so normal node progress can
// continue
if (hash == chainparams.GetConsensus().hashGenesisBlock) {
CValidationState state;
if (!ActivateBestChain(config, state)) {
break;
}
}
NotifyHeaderTip();
// Recursively process earlier encountered successors of this
// block
std::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;
std::shared_ptr<CBlock> pblockrecursive =
std::make_shared<CBlock>();
if (ReadBlockFromDisk(*pblockrecursive, it->second,
chainparams.GetConsensus())) {
LogPrint(
"reindex",
"%s: Processing out of order child %s of %s\n",
__func__, pblockrecursive->GetHash().ToString(),
head.ToString());
LOCK(cs_main);
CValidationState dummy;
if (AcceptBlock(config, pblockrecursive, dummy,
nullptr, true, &it->second,
nullptr)) {
nLoaded++;
queue.push_back(pblockrecursive->GetHash());
}
}
range.first++;
mapBlocksUnknownParent.erase(it);
NotifyHeaderTip();
}
}
} catch (const std::exception &e) {
LogPrintf("%s: Deserialize or I/O error - %s\n", __func__,
e.what());
}
}
} catch (const std::runtime_error &e) {
AbortNode(std::string("System error: ") + e.what());
}
if (nLoaded > 0) {
LogPrintf("Loaded %i blocks from external file in %dms\n", nLoaded,
GetTimeMillis() - nStart);
}
return nLoaded > 0;
}
static void CheckBlockIndex(const Consensus::Params &consensusParams) {
if (!fCheckBlockIndex) {
return;
}
LOCK(cs_main);
// 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;
}
// 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(nullptr);
CBlockIndex *pindex = rangeGenesis.first->second;
rangeGenesis.first++;
// There is only one index entry with parent nullptr.
assert(rangeGenesis.first == rangeGenesis.second);
// 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;
// Oldest ancestor of pindex which is invalid.
CBlockIndex *pindexFirstInvalid = nullptr;
// Oldest ancestor of pindex which does not have BLOCK_HAVE_DATA.
CBlockIndex *pindexFirstMissing = nullptr;
// Oldest ancestor of pindex for which nTx == 0.
CBlockIndex *pindexFirstNeverProcessed = nullptr;
// Oldest ancestor of pindex which does not have BLOCK_VALID_TREE
// (regardless of being valid or not).
CBlockIndex *pindexFirstNotTreeValid = nullptr;
// Oldest ancestor of pindex which does not have BLOCK_VALID_TRANSACTIONS
// (regardless of being valid or not).
CBlockIndex *pindexFirstNotTransactionsValid = nullptr;
// Oldest ancestor of pindex which does not have BLOCK_VALID_CHAIN
// (regardless of being valid or not).
CBlockIndex *pindexFirstNotChainValid = nullptr;
// Oldest ancestor of pindex which does not have BLOCK_VALID_SCRIPTS
// (regardless of being valid or not).
CBlockIndex *pindexFirstNotScriptsValid = nullptr;
while (pindex != nullptr) {
nNodes++;
if (pindexFirstInvalid == nullptr &&
pindex->nStatus & BLOCK_FAILED_VALID) {
pindexFirstInvalid = pindex;
}
if (pindexFirstMissing == nullptr &&
!(pindex->nStatus & BLOCK_HAVE_DATA)) {
pindexFirstMissing = pindex;
}
if (pindexFirstNeverProcessed == nullptr && pindex->nTx == 0) {
pindexFirstNeverProcessed = pindex;
}
if (pindex->pprev != nullptr && pindexFirstNotTreeValid == nullptr &&
(pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TREE) {
pindexFirstNotTreeValid = pindex;
}
if (pindex->pprev != nullptr &&
pindexFirstNotTransactionsValid == nullptr &&
(pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TRANSACTIONS) {
pindexFirstNotTransactionsValid = pindex;
}
if (pindex->pprev != nullptr && pindexFirstNotChainValid == nullptr &&
(pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_CHAIN) {
pindexFirstNotChainValid = pindex;
}
if (pindex->pprev != nullptr && pindexFirstNotScriptsValid == nullptr &&
(pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_SCRIPTS) {
pindexFirstNotScriptsValid = pindex;
}
// Begin: actual consistency checks.
if (pindex->pprev == nullptr) {
// Genesis block checks.
// Genesis block's hash must match.
assert(pindex->GetBlockHash() == consensusParams.hashGenesisBlock);
// The current active chain's genesis block must be this block.
assert(pindex == chainActive.Genesis());
}
if (pindex->nChainTx == 0) {
// nSequenceId can't be set positive for blocks that aren't linked
// (negative is used for preciousblock)
assert(pindex->nSequenceId <= 0);
}
// 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);
}
// This is pruning-independent.
assert(((pindex->nStatus & BLOCK_VALID_MASK) >=
BLOCK_VALID_TRANSACTIONS) == (pindex->nTx > 0));
// All parents having had data (at some point) is equivalent to all
// parents being VALID_TRANSACTIONS, which is equivalent to nChainTx
// being set.
// nChainTx != 0 is used to signal that all parent blocks have been
// processed (but may have been pruned).
assert((pindexFirstNeverProcessed != nullptr) ==
(pindex->nChainTx == 0));
assert((pindexFirstNotTransactionsValid != nullptr) ==
(pindex->nChainTx == 0));
// nHeight must be consistent.
assert(pindex->nHeight == nHeight);
// For every block except the genesis block, the chainwork must be
// larger than the parent's.
assert(pindex->pprev == nullptr ||
pindex->nChainWork >= pindex->pprev->nChainWork);
// The pskip pointer must point back for all but the first 2 blocks.
assert(nHeight < 2 ||
(pindex->pskip && (pindex->pskip->nHeight < nHeight)));
// All mapBlockIndex entries must at least be TREE valid
assert(pindexFirstNotTreeValid == nullptr);
if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TREE) {
// TREE valid implies all parents are TREE valid
assert(pindexFirstNotTreeValid == nullptr);
}
if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_CHAIN) {
// CHAIN valid implies all parents are CHAIN valid
assert(pindexFirstNotChainValid == nullptr);
}
if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_SCRIPTS) {
// SCRIPTS valid implies all parents are SCRIPTS valid
assert(pindexFirstNotScriptsValid == nullptr);
}
if (pindexFirstInvalid == nullptr) {
// Checks for not-invalid blocks.
// The failed mask cannot be set for blocks without invalid parents.
assert((pindex->nStatus & BLOCK_FAILED_MASK) == 0);
}
if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) &&
pindexFirstNeverProcessed == nullptr) {
if (pindexFirstInvalid == nullptr) {
// 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 == nullptr ||
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.
}
} else {
// If this block sorts worse than the current tip or some ancestor's
// block has never been seen, it cannot be in
// setBlockIndexCandidates.
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++;
}
if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) &&
pindexFirstNeverProcessed != nullptr &&
pindexFirstInvalid == nullptr) {
// 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)) {
// Can't be in mapBlocksUnlinked if we don't HAVE_DATA
assert(!foundInUnlinked);
}
if (pindexFirstMissing == nullptr) {
// We aren't missing data for any parent -- cannot be in
// mapBlocksUnlinked.
assert(!foundInUnlinked);
}
if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) &&
pindexFirstNeverProcessed == nullptr &&
pindexFirstMissing != nullptr) {
// We HAVE_DATA for this block, have received data for all parents
// at some point, but we're currently missing data for some parent.
// We must have pruned.
assert(fHavePruned);
// 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 == nullptr) {
assert(foundInUnlinked);
}
}
}
// 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 = nullptr;
}
if (pindex == pindexFirstMissing) {
pindexFirstMissing = nullptr;
}
if (pindex == pindexFirstNeverProcessed) {
pindexFirstNeverProcessed = nullptr;
}
if (pindex == pindexFirstNotTreeValid) {
pindexFirstNotTreeValid = nullptr;
}
if (pindex == pindexFirstNotTransactionsValid) {
pindexFirstNotTransactionsValid = nullptr;
}
if (pindex == pindexFirstNotChainValid) {
pindexFirstNotChainValid = nullptr;
}
if (pindex == pindexFirstNotScriptsValid) {
pindexFirstNotScriptsValid = nullptr;
}
// 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) {
// Our parent must have at least the node we're coming from as
// child.
assert(rangePar.first != rangePar.second);
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());
}
std::string CBlockFileInfo::ToString() const {
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));
}
CBlockFileInfo *GetBlockFileInfo(size_t n) {
return &vinfoBlockFile.at(n);
}
ThresholdState VersionBitsTipState(const Consensus::Params &params,
Consensus::DeploymentPos pos) {
LOCK(cs_main);
return VersionBitsState(chainActive.Tip(), params, pos, versionbitscache);
}
int VersionBitsTipStateSinceHeight(const Consensus::Params &params,
Consensus::DeploymentPos pos) {
LOCK(cs_main);
return VersionBitsStateSinceHeight(chainActive.Tip(), params, pos,
versionbitscache);
}
static const uint64_t MEMPOOL_DUMP_VERSION = 1;
bool LoadMempool(const Config &config) {
int64_t nExpiryTimeout =
GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60;
FILE *filestr =
fopen((GetDataDir() / "mempool.dat").string().c_str(), "rb");
CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
if (file.IsNull()) {
LogPrintf(
"Failed to open mempool file from disk. Continuing anyway.\n");
return false;
}
int64_t count = 0;
int64_t skipped = 0;
int64_t failed = 0;
int64_t nNow = GetTime();
try {
uint64_t version;
file >> version;
if (version != MEMPOOL_DUMP_VERSION) {
return false;
}
uint64_t num;
file >> num;
double prioritydummy = 0;
while (num--) {
CTransactionRef tx;
int64_t nTime;
int64_t nFeeDelta;
file >> tx;
file >> nTime;
file >> nFeeDelta;
CAmount amountdelta = nFeeDelta;
if (amountdelta) {
mempool.PrioritiseTransaction(tx->GetId(),
tx->GetId().ToString(),
prioritydummy, amountdelta);
}
CValidationState state;
if (nTime + nExpiryTimeout > nNow) {
LOCK(cs_main);
AcceptToMemoryPoolWithTime(config, mempool, state, tx, true,
nullptr, nTime);
if (state.IsValid()) {
++count;
} else {
++failed;
}
} else {
++skipped;
}
if (ShutdownRequested()) return false;
}
std::map<uint256, CAmount> mapDeltas;
file >> mapDeltas;
for (const auto &i : mapDeltas) {
mempool.PrioritiseTransaction(i.first, i.first.ToString(),
prioritydummy, i.second);
}
} catch (const std::exception &e) {
LogPrintf("Failed to deserialize mempool data on disk: %s. Continuing "
"anyway.\n",
e.what());
return false;
}
LogPrintf("Imported mempool transactions from disk: %i successes, %i "
"failed, %i expired\n",
count, failed, skipped);
return true;
}
void DumpMempool(void) {
int64_t start = GetTimeMicros();
std::map<uint256, CAmount> mapDeltas;
std::vector<TxMempoolInfo> vinfo;
{
LOCK(mempool.cs);
for (const auto &i : mempool.mapDeltas) {
mapDeltas[i.first] = i.second.second.GetSatoshis();
}
vinfo = mempool.infoAll();
}
int64_t mid = GetTimeMicros();
try {
FILE *filestr =
fopen((GetDataDir() / "mempool.dat.new").string().c_str(), "wb");
if (!filestr) {
return;
}
CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
uint64_t version = MEMPOOL_DUMP_VERSION;
file << version;
file << (uint64_t)vinfo.size();
for (const auto &i : vinfo) {
file << *(i.tx);
file << (int64_t)i.nTime;
file << (int64_t)i.nFeeDelta.GetSatoshis();
mapDeltas.erase(i.tx->GetId());
}
file << mapDeltas;
FileCommit(file.Get());
file.fclose();
RenameOver(GetDataDir() / "mempool.dat.new",
GetDataDir() / "mempool.dat");
int64_t last = GetTimeMicros();
LogPrintf("Dumped mempool: %gs to copy, %gs to dump\n",
(mid - start) * 0.000001, (last - mid) * 0.000001);
} catch (const std::exception &e) {
LogPrintf("Failed to dump mempool: %s. Continuing anyway.\n", e.what());
}
}
//! Guess how far we are in the verification process at the given block index
double GuessVerificationProgress(const ChainTxData &data, CBlockIndex *pindex) {
if (pindex == nullptr) return 0.0;
int64_t nNow = time(nullptr);
double fTxTotal;
if (pindex->nChainTx <= data.nTxCount) {
fTxTotal = data.nTxCount + (nNow - data.nTime) * data.dTxRate;
} else {
fTxTotal =
pindex->nChainTx + (nNow - pindex->GetBlockTime()) * data.dTxRate;
}
return pindex->nChainTx / fTxTotal;
}
class CMainCleanup {
public:
CMainCleanup() {}
~CMainCleanup() {
// block headers
BlockMap::iterator it1 = mapBlockIndex.begin();
for (; it1 != mapBlockIndex.end(); it1++)
delete (*it1).second;
mapBlockIndex.clear();
}
} instance_of_cmaincleanup;
diff --git a/src/validation.h b/src/validation.h
index f4ec19244..13c1e183a 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -1,684 +1,687 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Copyright (c) 2017 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_VALIDATION_H
#define BITCOIN_VALIDATION_H
#if defined(HAVE_CONFIG_H)
#include "config/bitcoin-config.h"
#endif
#include "amount.h"
#include "chain.h"
#include "coins.h"
#include "protocol.h" // For CMessageHeader::MessageStartChars
#include "script/script_error.h"
#include "sync.h"
#include "versionbits.h"
#include <algorithm>
#include <cstdint>
#include <exception>
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include <atomic>
#include <boost/filesystem/path.hpp>
#include <unordered_map>
class CBlockIndex;
class CBlockTreeDB;
class CBloomFilter;
class CChainParams;
class CConnman;
class CInv;
class Config;
class CScriptCheck;
class CTxMemPool;
class CTxUndo;
class CValidationInterface;
class CValidationState;
struct ChainTxData;
struct PrecomputedTransactionData;
struct LockPoints;
#define MIN_TRANSACTION_SIZE \
(::GetSerializeSize(CTransaction(), SER_NETWORK, PROTOCOL_VERSION))
/** Default for DEFAULT_WHITELISTRELAY. */
static const bool DEFAULT_WHITELISTRELAY = true;
/** Default for DEFAULT_WHITELISTFORCERELAY. */
static const bool DEFAULT_WHITELISTFORCERELAY = true;
/** Default for -minrelaytxfee, minimum relay fee for transactions */
static const Amount DEFAULT_MIN_RELAY_TX_FEE(1000);
//! -maxtxfee default
static const Amount DEFAULT_TRANSACTION_MAXFEE(COIN / 10);
//! Discourage users to set fees higher than this amount (in satoshis) per kB
static const Amount HIGH_TX_FEE_PER_KB(COIN / 100);
/** -maxtxfee will warn if called with a higher fee than this amount (in
* satoshis */
static const Amount HIGH_MAX_TX_FEE(100 * HIGH_TX_FEE_PER_KB);
/** Default for -limitancestorcount, max number of in-mempool ancestors */
static const unsigned int DEFAULT_ANCESTOR_LIMIT = 25;
/** Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool
* ancestors */
static const unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT = 101;
/** Default for -limitdescendantcount, max number of in-mempool descendants */
static const unsigned int DEFAULT_DESCENDANT_LIMIT = 25;
/** Default for -limitdescendantsize, maximum kilobytes of in-mempool
* descendants */
static const unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT = 101;
/** Default for -mempoolexpiry, expiration time for mempool transactions in
* hours */
static const unsigned int DEFAULT_MEMPOOL_EXPIRY = 336;
/** The maximum size of a blk?????.dat file (since 0.8) */
static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */
static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB
/** The pre-allocation chunk size for rev?????.dat files (since 0.8) */
static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB
/** Maximum number of script-checking threads allowed */
static const int MAX_SCRIPTCHECK_THREADS = 16;
/** -par default (number of script-checking threads, 0 = auto) */
static const int DEFAULT_SCRIPTCHECK_THREADS = 0;
/** Number of blocks that can be requested at any given time from a single peer.
*/
static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16;
/** Timeout in seconds during which a peer must stall block download progress
* before being disconnected. */
static const unsigned int BLOCK_STALLING_TIMEOUT = 2;
/** Number of headers sent in one getheaders result. We rely on the assumption
* that if a peer sends
* less than this number, we reached its tip. Changing this value is a protocol
* upgrade. */
static const unsigned int MAX_HEADERS_RESULTS = 2000;
/** Maximum depth of blocks we're willing to serve as compact blocks to peers
* when requested. For older blocks, a regular BLOCK response will be sent. */
static const int MAX_CMPCTBLOCK_DEPTH = 5;
/** Maximum depth of blocks we're willing to respond to GETBLOCKTXN requests
* for. */
static const int MAX_BLOCKTXN_DEPTH = 10;
/** Size of the "block download window": how far ahead of our current height do
* we fetch ? Larger windows tolerate larger download speed differences between
* peer, but increase the potential degree of disordering of blocks on disk
* (which make reindexing and in the future perhaps pruning harder). We'll
* probably want to make this a per-peer adaptive value at some point. */
static const unsigned int BLOCK_DOWNLOAD_WINDOW = 1024;
/** Time to wait (in seconds) between writing blocks/block index to disk. */
static const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60;
/** Time to wait (in seconds) between flushing chainstate to disk. */
static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60;
/** Maximum length of reject messages. */
static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
/** Average delay between local address broadcasts in seconds. */
static const unsigned int AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL = 24 * 24 * 60;
/** Average delay between peer address broadcasts in seconds. */
static const unsigned int AVG_ADDRESS_BROADCAST_INTERVAL = 30;
/** Average delay between trickled inventory transmissions in seconds.
* Blocks and whitelisted receivers bypass this, outbound peers get half this
* delay. */
static const unsigned int INVENTORY_BROADCAST_INTERVAL = 5;
/** Maximum number of inventory items to send per transmission.
* Limits the impact of low-fee transaction floods. */
static const unsigned int INVENTORY_BROADCAST_MAX =
7 * INVENTORY_BROADCAST_INTERVAL;
/** Average delay between feefilter broadcasts in seconds. */
static const unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60;
/** Maximum feefilter broadcast delay after significant change. */
static const unsigned int MAX_FEEFILTER_CHANGE_DELAY = 5 * 60;
/** Block download timeout base, expressed in millionths of the block interval
* (i.e. 10 min) */
static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 1000000;
/** Additional block download timeout per parallel downloading peer (i.e. 5 min)
*/
static const int64_t BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 500000;
static const unsigned int DEFAULT_LIMITFREERELAY = 0;
static const bool DEFAULT_RELAYPRIORITY = true;
static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60;
/** Maximum age of our tip in seconds for us to be considered current for fee
* estimation */
static const int64_t MAX_FEE_ESTIMATION_TIP_AGE = 3 * 60 * 60;
/** Default for -permitbaremultisig */
static const bool DEFAULT_PERMIT_BAREMULTISIG = true;
static const bool DEFAULT_CHECKPOINTS_ENABLED = true;
static const bool DEFAULT_TXINDEX = false;
static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100;
/** Default for using fee filter */
static const bool DEFAULT_FEEFILTER = true;
/** Maximum number of headers to announce when relaying blocks with headers
* message.*/
static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8;
/** Maximum number of unconnecting headers announcements before DoS score */
static const int MAX_UNCONNECTING_HEADERS = 10;
static const bool DEFAULT_PEERBLOOMFILTERS = true;
struct BlockHasher {
size_t operator()(const uint256 &hash) const { return hash.GetCheapHash(); }
};
extern CScript COINBASE_FLAGS;
extern CCriticalSection cs_main;
extern CTxMemPool mempool;
typedef std::unordered_map<uint256, CBlockIndex *, BlockHasher> BlockMap;
extern BlockMap mapBlockIndex;
extern uint64_t nLastBlockTx;
extern uint64_t nLastBlockSize;
extern const std::string strMessageMagic;
extern CWaitableCriticalSection csBestBlock;
extern CConditionVariable cvBlockChange;
extern std::atomic_bool fImporting;
extern bool fReindex;
extern int nScriptCheckThreads;
extern bool fTxIndex;
extern bool fIsBareMultisigStd;
extern bool fRequireStandard;
extern bool fCheckBlockIndex;
extern bool fCheckpointsEnabled;
extern size_t nCoinCacheUsage;
/** A fee rate smaller than this is considered zero fee (for relaying, mining
* and transaction creation) */
extern CFeeRate minRelayTxFee;
/** Absolute maximum transaction fee (in satoshis) used by wallet and mempool
* (rejects high fee in sendrawtransaction) */
extern CAmount maxTxFee;
/** If the tip is older than this (in seconds), the node is considered to be in
* initial block download. */
extern int64_t nMaxTipAge;
/** Block hash whose ancestors we will assume to have valid scripts without
* checking them. */
extern uint256 hashAssumeValid;
/** Best header we've seen so far (used for getheaders queries' starting
* points). */
extern CBlockIndex *pindexBestHeader;
/** Minimum disk space required - used in CheckDiskSpace() */
static const uint64_t nMinDiskSpace = 52428800;
/** Pruning-related variables and constants */
/** True if any block files have ever been pruned. */
extern bool fHavePruned;
/** True if we're running in -prune mode. */
extern bool fPruneMode;
/** Number of MiB of block files that we're trying to stay below. */
extern uint64_t nPruneTarget;
/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of
* chainActive.Tip() will not be pruned. */
static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
static const signed int DEFAULT_CHECKBLOCKS = 6;
static const unsigned int DEFAULT_CHECKLEVEL = 3;
// Require that user allocate at least 550MB for block & undo files (blk???.dat
// and rev???.dat)
// At 1MB per block, 288 blocks = 288MB.
// Add 15% for Undo data = 331MB
// Add 20% for Orphan block rate = 397MB
// We want the low water mark after pruning to be at least 397 MB and since we
// prune in full block file chunks, we need the high water mark which triggers
// the prune to be one 128MB block file + added 15% undo data = 147MB greater
// for a total of 545MB. Setting the target to > than 550MB will make it likely
// we can respect the target.
static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;
/**
* Process an incoming block. This only returns after the best known valid
* block is made active. Note that it does not, however, guarantee that the
* specific block passed to it has been checked for validity!
*
* If you want to *possibly* get feedback on whether pblock is valid, you must
* install a CValidationInterface (see validationinterface.h) - this will have
* its BlockChecked method called whenever *any* block completes validation.
*
* Note that we guarantee that either the proof-of-work is valid on pblock, or
* (and possibly also) BlockChecked will have been called.
*
* Call without cs_main held.
*
* @param[in] pblock The block we want to process.
* @param[in] fForceProcessing Process this block even if unrequested; used
* for non-network block sources and whitelisted peers.
* @param[out] fNewBlock A boolean which is set to indicate if the block was
* first received via this call
* @return True if state.IsValid()
*/
bool ProcessNewBlock(const Config &config,
const std::shared_ptr<const CBlock> pblock,
bool fForceProcessing, bool *fNewBlock);
/**
* Process incoming block headers.
*
* Call without cs_main held.
*
* @param[in] block The block headers themselves
* @param[out] state This may be set to an Error state if any error occurred
* processing them
* @param[in] chainparams The params for the chain we want to connect to
* @param[out] ppindex If set, the pointer will be set to point to the last new
* block index object for the given headers
*/
bool ProcessNewBlockHeaders(const Config &config,
const std::vector<CBlockHeader> &block,
CValidationState &state,
const CBlockIndex **ppindex = nullptr);
/** Check whether enough disk space is available for an incoming block */
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
/** Open a block file (blk?????.dat) */
FILE *OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false);
/** Open an undo file (rev?????.dat) */
FILE *OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false);
/** Translation to a filesystem path */
boost::filesystem::path GetBlockPosFilename(const CDiskBlockPos &pos,
const char *prefix);
/** Import blocks from an external file */
bool LoadExternalBlockFile(const Config &config, FILE *fileIn,
CDiskBlockPos *dbp = nullptr);
/** Initialize a new block tree database + block data on disk */
bool InitBlockIndex(const Config &config);
/** Load the block tree and coins database from disk */
bool LoadBlockIndex(const CChainParams &chainparams);
/** Unload database information */
void UnloadBlockIndex();
/** Run an instance of the script checking thread */
void ThreadScriptCheck();
/** Check whether we are doing an initial block download (synchronizing from
* disk or network) */
bool IsInitialBlockDownload();
/** Format a string that describes several potential problems detected by the
* core.
* strFor can have three values:
* - "rpc": get critical warnings, which should put the client in safe mode if
* non-empty
* - "statusbar": get all warnings
* - "gui": get all warnings, translated (where possible) for GUI
* This function only returns the highest priority warning of the set selected
* by strFor.
*/
std::string GetWarnings(const std::string &strFor);
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
bool GetTransaction(const Config &config, const uint256 &hash,
CTransactionRef &tx, uint256 &hashBlock,
bool fAllowSlow = false);
/** Find the best known block, and make it the tip of the block chain */
bool ActivateBestChain(
const Config &config, CValidationState &state,
std::shared_ptr<const CBlock> pblock = std::shared_ptr<const CBlock>());
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams);
/** Guess verification progress (as a fraction between 0.0=genesis and
* 1.0=current tip). */
double GuessVerificationProgress(const ChainTxData &data, CBlockIndex *pindex);
/**
* Prune block and undo files (blk???.dat and undo???.dat) so that the disk
* space used is less than a user-defined target. The user sets the target (in
* MB) on the command line or in config file. This will be run on startup and
* whenever new space is allocated in a block or undo file, staying below the
* target. Changing back to unpruned requires a reindex (which in this case
* means the blockchain must be re-downloaded.)
*
* Pruning functions are called from FlushStateToDisk when the global
* fCheckForPruning flag has been set. Block and undo files are deleted in
* lock-step (when blk00003.dat is deleted, so is rev00003.dat.) Pruning cannot
* take place until the longest chain is at least a certain length (100000 on
* mainnet, 1000 on testnet, 1000 on regtest). Pruning will never delete a block
* within a defined distance (currently 288) from the active chain's tip. The
* block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks
* that were stored in the deleted files. A db flag records the fact that at
* least some block files have been pruned.
*
* @param[out] setFilesToPrune The set of file indices that can be unlinked
* will be returned
*/
void FindFilesToPrune(std::set<int> &setFilesToPrune,
uint64_t nPruneAfterHeight);
/**
* Mark one block file as pruned.
*/
void PruneOneBlockFile(const int fileNumber);
/**
* Actually unlink the specified files
*/
void UnlinkPrunedFiles(const std::set<int> &setFilesToPrune);
/** Create a new block index entry for a given block hash */
CBlockIndex *InsertBlockIndex(uint256 hash);
/** Flush all state, indexes and buffers to disk. */
void FlushStateToDisk();
/** Prune block files and flush state to disk. */
void PruneAndFlush();
/** Prune block files up to a given height */
void PruneBlockFilesManual(int nPruneUpToHeight);
/** Check is UAHF has activated. */
bool IsUAHFenabled(const Config &config, const CBlockIndex *pindexPrev);
+/** Check is Cash HF has activated. */
+bool IsCashHFEnabled(const Config &config, const CBlockIndex *pindexPrev);
+
/** (try to) add transaction to memory pool
* plTxnReplaced will be appended to with all transactions replaced from mempool
* **/
bool AcceptToMemoryPool(const Config &config, CTxMemPool &pool,
CValidationState &state, const CTransactionRef &tx,
bool fLimitFree, bool *pfMissingInputs,
std::list<CTransactionRef> *plTxnReplaced = nullptr,
bool fOverrideMempoolLimit = false,
const CAmount nAbsurdFee = 0);
/** Convert CValidationState to a human-readable message for logging */
std::string FormatStateMessage(const CValidationState &state);
/** Get the BIP9 state for a given deployment at the current tip. */
ThresholdState VersionBitsTipState(const Consensus::Params &params,
Consensus::DeploymentPos pos);
/** Get the block height at which the BIP9 deployment switched into the state
* for the block building on the current tip. */
int VersionBitsTipStateSinceHeight(const Consensus::Params &params,
Consensus::DeploymentPos pos);
/**
* Count ECDSA signature operations the old-fashioned (pre-0.6) way
* @return number of sigops this transaction's outputs will produce when spent
* @see CTransaction::FetchInputs
*/
uint64_t GetSigOpCountWithoutP2SH(const CTransaction &tx);
/**
* Count ECDSA signature operations in pay-to-script-hash inputs.
*
* @param[in] mapInputs Map of previous transactions that have outputs we're
* spending
* @return maximum number of sigops required to validate this transaction's
* inputs
* @see CTransaction::FetchInputs
*/
uint64_t GetP2SHSigOpCount(const CTransaction &tx,
const CCoinsViewCache &mapInputs);
/**
* Compute total signature operation of a transaction.
* @param[in] tx Transaction for which we are computing the cost
* @param[in] inputs Map of previous transactions that have outputs we're
* spending
* @param[out] flags Script verification flags
* @return Total signature operation cost of tx
*/
uint64_t GetTransactionSigOpCount(const CTransaction &tx,
const CCoinsViewCache &inputs, int flags);
/**
* Check whether all inputs of this transaction are valid (no double spends,
* scripts & sigs, amounts). This does not modify the UTXO set.
*
* If pvChecks is not nullptr, script checks are pushed onto it instead of being
* performed inline. Any script checks which are not necessary (eg due to script
* execution cache hits) are, obviously, not pushed onto pvChecks/run.
*
* Setting sigCacheStore/scriptCacheStore to false will remove elements from the
* corresponding cache which are matched. This is useful for checking blocks
* where we will likely never need the cache entry again.
*/
bool CheckInputs(const CTransaction &tx, CValidationState &state,
const CCoinsViewCache &view, bool fScriptChecks,
uint32_t flags, bool sigCacheStore, bool scriptCacheStore,
const PrecomputedTransactionData &txdata,
std::vector<CScriptCheck> *pvChecks = nullptr);
/** Apply the effects of this transaction on the UTXO set represented by view */
void UpdateCoins(const CTransaction &tx, CCoinsViewCache &inputs, int nHeight);
void UpdateCoins(const CTransaction &tx, CCoinsViewCache &inputs,
CTxUndo &txundo, int nHeight);
/** Transaction validation functions */
/** Context-independent validity checks for coinbase and non-coinbase
* transactions */
bool CheckRegularTransaction(const CTransaction &tx, CValidationState &state,
bool fCheckDuplicateInputs = true);
bool CheckCoinbase(const CTransaction &tx, CValidationState &state,
bool fCheckDuplicateInputs = true);
namespace Consensus {
/**
* Check whether all inputs of this transaction are valid (no double spends and
* amounts). This does not modify the UTXO set. This does not check scripts and
* sigs. Preconditions: tx.IsCoinBase() is false.
*/
bool CheckTxInputs(const CTransaction &tx, CValidationState &state,
const CCoinsViewCache &inputs, int nSpendHeight);
} // namespace Consensus
/**
* Test whether the LockPoints height and time are still valid on the current
* chain.
*/
bool TestLockPointValidity(const LockPoints *lp);
/**
* Check if transaction is final per BIP 68 sequence numbers and can be included
* in a block. Consensus critical. Takes as input a list of heights at which
* tx's inputs (in order) confirmed.
*/
bool SequenceLocks(const CTransaction &tx, int flags,
std::vector<int> *prevHeights, const CBlockIndex &block);
/**
* Check if transaction will be BIP 68 final in the next block to be created.
*
* Simulates calling SequenceLocks() with data from the tip of the current
* active chain. Optionally stores in LockPoints the resulting height and time
* calculated and the hash of the block needed for calculation or skips the
* calculation and uses the LockPoints passed in for evaluation. The LockPoints
* should not be considered valid if CheckSequenceLocks returns false.
*
* See consensus/consensus.h for flag definitions.
*/
bool CheckSequenceLocks(const CTransaction &tx, int flags,
LockPoints *lp = nullptr,
bool useExistingLockPoints = false);
/**
* Closure representing one script verification.
* Note that this stores references to the spending transaction.
*/
class CScriptCheck {
private:
CScript scriptPubKey;
CAmount amount;
const CTransaction *ptxTo;
unsigned int nIn;
uint32_t nFlags;
bool cacheStore;
ScriptError error;
PrecomputedTransactionData txdata;
public:
CScriptCheck()
: amount(0), ptxTo(0), nIn(0), nFlags(0), cacheStore(false),
error(SCRIPT_ERR_UNKNOWN_ERROR), txdata() {}
CScriptCheck(const CScript &scriptPubKeyIn, const CAmount amountIn,
const CTransaction &txToIn, unsigned int nInIn,
uint32_t nFlagsIn, bool cacheIn,
const PrecomputedTransactionData &txdataIn)
: scriptPubKey(scriptPubKeyIn), amount(amountIn), ptxTo(&txToIn),
nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn),
error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) {}
bool operator()();
void swap(CScriptCheck &check) {
scriptPubKey.swap(check.scriptPubKey);
std::swap(ptxTo, check.ptxTo);
std::swap(amount, check.amount);
std::swap(nIn, check.nIn);
std::swap(nFlags, check.nFlags);
std::swap(cacheStore, check.cacheStore);
std::swap(error, check.error);
std::swap(txdata, check.txdata);
}
ScriptError GetScriptError() const { return error; }
};
/** Functions for disk access for blocks */
bool WriteBlockToDisk(const CBlock &block, CDiskBlockPos &pos,
const CMessageHeader::MessageStartChars &messageStart);
bool ReadBlockFromDisk(CBlock &block, const CDiskBlockPos &pos,
const Consensus::Params &consensusParams);
bool ReadBlockFromDisk(CBlock &block, const CBlockIndex *pindex,
const Consensus::Params &consensusParams);
/** Functions for validating blocks and updating the block tree */
/** Context-independent validity checks */
bool CheckBlockHeader(const CBlockHeader &block, CValidationState &state,
const Consensus::Params &consensusParams,
bool fCheckPOW = true);
bool CheckBlock(const Config &Config, const CBlock &block,
CValidationState &state,
const Consensus::Params &consensusParams, bool fCheckPOW = true,
bool fCheckMerkleRoot = true);
/**
* Context dependent validity checks for non coinbase transactions. This
* doesn't check the validity of the transaction against the UTXO set, but
* simply characteristic that are suceptible to change over time such as feature
* activation/deactivation and CLTV.
*/
bool ContextualCheckTransaction(const Config &config, const CTransaction &tx,
CValidationState &state,
const Consensus::Params &consensusParams,
int nHeight, int64_t nLockTimeCutoff);
/**
* This is a variant of ContextualCheckTransaction which computes the contextual
* check for a transaction based on the chain tip.
*
* See consensus/consensus.h for flag definitions.
*/
bool ContextualCheckTransactionForCurrentBlock(
const Config &config, const CTransaction &tx, CValidationState &state,
const Consensus::Params &consensusParams, int flags = -1);
/** Context-dependent validity checks.
* By "context", we mean only the previous block headers, but not the UTXO
* set; UTXO-related validity checks are done in ConnectBlock(). */
bool ContextualCheckBlockHeader(const CBlockHeader &block,
CValidationState &state,
const Consensus::Params &consensusParams,
const CBlockIndex *pindexPrev,
int64_t nAdjustedTime);
bool ContextualCheckBlock(const Config &config, const CBlock &block,
CValidationState &state,
const Consensus::Params &consensusParams,
const CBlockIndex *pindexPrev);
/** Check a block is completely valid from start to finish (only works on top of
* our current best block, with cs_main held) */
bool TestBlockValidity(const Config &config, CValidationState &state,
const CChainParams &chainparams, const CBlock &block,
CBlockIndex *pindexPrev, bool fCheckPOW = true,
bool fCheckMerkleRoot = true);
/** When there are blocks in the active chain with missing data, rewind the
* chainstate and remove them from the block index */
bool RewindBlockIndex(const Config &config, const CChainParams &params);
/** RAII wrapper for VerifyDB: Verify consistency of the block and coin
* databases */
class CVerifyDB {
public:
CVerifyDB();
~CVerifyDB();
bool VerifyDB(const Config &config, const CChainParams &chainparams,
CCoinsView *coinsview, int nCheckLevel, int nCheckDepth);
};
/** Find the last common block between the parameter chain and a locator. */
CBlockIndex *FindForkInGlobalIndex(const CChain &chain,
const CBlockLocator &locator);
/** Mark a block as precious and reorganize. */
bool PreciousBlock(const Config &config, CValidationState &state,
CBlockIndex *pindex);
/** Mark a block as invalid. */
bool InvalidateBlock(const Config &config, CValidationState &state,
CBlockIndex *pindex);
/** Remove invalidity status from a block and its descendants. */
bool ResetBlockFailureFlags(CBlockIndex *pindex);
/** The currently-connected chain of blocks (protected by cs_main). */
extern CChain chainActive;
/** Global variable that points to the active CCoinsView (protected by cs_main)
*/
extern CCoinsViewCache *pcoinsTip;
/** Global variable that points to the active block tree (protected by cs_main)
*/
extern CBlockTreeDB *pblocktree;
/**
* Return the spend height, which is one more than the inputs.GetBestBlock().
* While checking, GetBestBlock() refers to the parent block. (protected by
* cs_main)
* This is also true for mempool checks.
*/
int GetSpendHeight(const CCoinsViewCache &inputs);
extern VersionBitsCache versionbitscache;
/**
* Determine what nVersion a new block should use.
*/
int32_t ComputeBlockVersion(const CBlockIndex *pindexPrev,
const Consensus::Params &params);
/**
* Reject codes greater or equal to this can be returned by AcceptToMemPool for
* transactions, to signal internal conditions. They cannot and should not be
* sent over the P2P network.
*/
static const unsigned int REJECT_INTERNAL = 0x100;
/** Too high fee. Can not be triggered by P2P transactions */
static const unsigned int REJECT_HIGHFEE = 0x100;
/** Transaction is already known (either in mempool or blockchain) */
static const unsigned int REJECT_ALREADY_KNOWN = 0x101;
/** Transaction conflicts with a transaction already known */
static const unsigned int REJECT_CONFLICT = 0x102;
/** Get block file info entry for one block file */
CBlockFileInfo *GetBlockFileInfo(size_t n);
/** Dump the mempool to disk. */
void DumpMempool();
/** Load the mempool from disk. */
bool LoadMempool(const Config &config);
#endif // BITCOIN_VALIDATION_H

File Metadata

Mime Type
text/x-diff
Expires
Thu, May 22, 01:30 (15 h, 23 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5866265
Default Alt Text
(254 KB)

Event Timeline