diff --git a/src/chainparams.cpp b/src/chainparams.cpp index af2c9885e..e0be9fe1c 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -1,523 +1,548 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Copyright (c) 2017-2020 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include #include #include #include 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((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 */ 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 */ class CMainParams : public CChainParams { public: CMainParams() { strNetworkID = CBaseChainParams::MAIN; consensus.nSubsidyHalvingInterval = 210000; // 00000000000000ce80a7e057163a4db1d5ad7b20fb6f598c9597b9665c8fb0d4 - // April 1, 2012 consensus.BIP16Height = 173805; consensus.BIP34Height = 227931; consensus.BIP34Hash = BlockHash::fromHex( "000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8"); // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0 consensus.BIP65Height = 388381; // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931 consensus.BIP66Height = 363725; // 000000000000000004a1b34462cb8aeebd5799177f7a29cf28f2d1961716b5b5 consensus.CSVHeight = 419328; consensus.powLimit = uint256S( "00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // two weeks consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; consensus.nPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowNoRetargeting = false; // two days consensus.nDAAHalfLife = 2 * 24 * 60 * 60; // nPowTargetTimespan / nPowTargetSpacing consensus.nMinerConfirmationWindow = 2016; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY] = { .bit = 28, // 95% of 2016 .nActivationThreshold = 1916, // January 1, 2008 .nStartTime = 1199145601, // December 31, 2008 .nTimeout = 1230767999, }; // The miner fund is enabled by default on mainnet. consensus.enableMinerFund = ENABLE_MINER_FUND; // The best chain should have at least this much work. consensus.nMinimumChainWork = ChainParamsConstants::MAINNET_MINIMUM_CHAIN_WORK; // By default assume that the signatures in ancestors of this block are // valid. consensus.defaultAssumeValid = ChainParamsConstants::MAINNET_DEFAULT_ASSUME_VALID; // August 1, 2017 hard fork consensus.uahfHeight = 478558; // November 13, 2017 hard fork consensus.daaHeight = 504031; // November 15, 2018 hard fork consensus.magneticAnomalyHeight = 556766; // November 15, 2019 protocol upgrade consensus.gravitonHeight = 609135; // May 15, 2020 12:00:00 UTC protocol upgrade consensus.phononHeight = 635258; // Nov 15, 2020 12:00:00 UTC protocol upgrade consensus.axionHeight = 661647; // May 15, 2022 12:00:00 UTC protocol upgrade consensus.gluonActivationTime = 1652616000; // Nov 15, 2022 12:00:00 UTC protocol upgrade consensus.jeffersonActivationTime = 1668513600; /** * 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. */ diskMagic[0] = 0xf9; diskMagic[1] = 0xbe; diskMagic[2] = 0xb4; diskMagic[3] = 0xd9; netMagic[0] = 0xe3; netMagic[1] = 0xe1; netMagic[2] = 0xf3; netMagic[3] = 0xe8; nDefaultPort = 8333; nPruneAfterHeight = 100000; m_assumed_blockchain_size = ChainParamsConstants::MAINNET_ASSUMED_BLOCKCHAIN_SIZE; m_assumed_chain_state_size = ChainParamsConstants::MAINNET_ASSUMED_CHAINSTATE_SIZE; genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); assert(consensus.hashGenesisBlock == uint256S("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1" "b60a8ce26f")); assert(genesis.hashMerkleRoot == uint256S("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b" "7afdeda33b")); // Note that of those which support the service bits prefix, most only // support a subset of possible options. This is fine at runtime as // we'll fall back to using them as an addrfetch if they don't support // the service bits we want, but we should get them updated to support // all service bits wanted by any release ASAP to avoid it where // possible. // Bitcoin ABC seeder vSeeds.emplace_back("seed.bitcoinabc.org"); // BU backed seeder vSeeds.emplace_back("btccash-seeder.bitcoinunlimited.info"); // Jason B. Cox vSeeds.emplace_back("seeder.jasonbcox.com"); // Amaury SÉCHET vSeeds.emplace_back("seed.deadalnix.me"); // BCHD vSeeds.emplace_back("seed.bchd.cash"); // Fabien vSeeds.emplace_back("seeder.fabien.cash"); // status.cash vSeeds.emplace_back("seeder.status.cash"); base58Prefixes[PUBKEY_ADDRESS] = std::vector(1, 0); base58Prefixes[SCRIPT_ADDRESS] = std::vector(1, 5); base58Prefixes[SECRET_KEY] = std::vector(1, 128); base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E}; base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4}; cashaddrPrefix = gArgs.GetBoolArg("-ecash", DEFAULT_ECASH) ? "ecash" : "bitcoincash"; vFixedSeeds = std::vector(std::begin(pnSeed6_main), std::end(pnSeed6_main)); fDefaultConsistencyChecks = false; fRequireStandard = true; m_is_test_chain = false; m_is_mockable_chain = false; checkpointData = CheckpointData(CBaseChainParams::MAIN); + m_assumeutxo_data = MapAssumeutxo{ + // TODO to be specified in a future patch. + }; + // Data as of block // 000000000000000001d2ce557406b017a928be25ee98906397d339c3f68eec5d // (height 523992). chainTxData = ChainTxData{ // UNIX timestamp of last known number of transactions. 1522608016, // Total number of transactions between genesis and that timestamp // (the tx=... number in the ChainStateFlushed debug.log lines) 248589038, // Estimated number of transactions per second after that timestamp. 3.2, }; } }; /** * Testnet (v3) */ class CTestNetParams : public CChainParams { public: CTestNetParams() { strNetworkID = CBaseChainParams::TESTNET; consensus.nSubsidyHalvingInterval = 210000; // 00000000040b4e986385315e14bee30ad876d8b47f748025b26683116d21aa65 consensus.BIP16Height = 514; consensus.BIP34Height = 21111; consensus.BIP34Hash = BlockHash::fromHex( "0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8"); // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6 consensus.BIP65Height = 581885; // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182 consensus.BIP66Height = 330776; // 00000000025e930139bac5c6c31a403776da130831ab85be56578f3fa75369bb consensus.CSVHeight = 770112; consensus.powLimit = uint256S( "00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // two weeks consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; consensus.nPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = true; consensus.fPowNoRetargeting = false; // two days consensus.nDAAHalfLife = 2 * 24 * 60 * 60; // nPowTargetTimespan / nPowTargetSpacing consensus.nMinerConfirmationWindow = 2016; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY] = { .bit = 28, // 75% of 2016 .nActivationThreshold = 1512, // January 1, 2008 .nStartTime = 1199145601, // December 31, 2008 .nTimeout = 1230767999, }; // The miner fund is disabled by default on testnet. consensus.enableMinerFund = false; // The best chain should have at least this much work. consensus.nMinimumChainWork = ChainParamsConstants::TESTNET_MINIMUM_CHAIN_WORK; // By default assume that the signatures in ancestors of this block are // valid. consensus.defaultAssumeValid = ChainParamsConstants::TESTNET_DEFAULT_ASSUME_VALID; // August 1, 2017 hard fork consensus.uahfHeight = 1155875; // November 13, 2017 hard fork consensus.daaHeight = 1188697; // November 15, 2018 hard fork consensus.magneticAnomalyHeight = 1267996; // November 15, 2019 protocol upgrade consensus.gravitonHeight = 1341711; // May 15, 2020 12:00:00 UTC protocol upgrade consensus.phononHeight = 1378460; // Nov 15, 2020 12:00:00 UTC protocol upgrade consensus.axionHeight = 1421481; // May 15, 2022 12:00:00 UTC protocol upgrade consensus.gluonActivationTime = 1652616000; // Nov 15, 2022 12:00:00 UTC protocol upgrade consensus.jeffersonActivationTime = 1668513600; diskMagic[0] = 0x0b; diskMagic[1] = 0x11; diskMagic[2] = 0x09; diskMagic[3] = 0x07; netMagic[0] = 0xf4; netMagic[1] = 0xe5; netMagic[2] = 0xf3; netMagic[3] = 0xf4; nDefaultPort = 18333; nPruneAfterHeight = 1000; m_assumed_blockchain_size = ChainParamsConstants::TESTNET_ASSUMED_BLOCKCHAIN_SIZE; m_assumed_chain_state_size = ChainParamsConstants::TESTNET_ASSUMED_CHAINSTATE_SIZE; genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); assert(consensus.hashGenesisBlock == uint256S("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526" "f8d77f4943")); assert(genesis.hashMerkleRoot == uint256S("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b" "7afdeda33b")); vFixedSeeds.clear(); vSeeds.clear(); // nodes with support for servicebits filtering should be at the top // Bitcoin ABC seeder vSeeds.emplace_back("testnet-seed.bitcoinabc.org"); // Amaury SÉCHET vSeeds.emplace_back("testnet-seed.deadalnix.me"); // BCHD vSeeds.emplace_back("testnet-seed.bchd.cash"); // Fabien vSeeds.emplace_back("testnet-seeder.fabien.cash"); // status.cash vSeeds.emplace_back("testnet-seeder.status.cash"); base58Prefixes[PUBKEY_ADDRESS] = std::vector(1, 111); base58Prefixes[SCRIPT_ADDRESS] = std::vector(1, 196); base58Prefixes[SECRET_KEY] = std::vector(1, 239); base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF}; base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94}; cashaddrPrefix = gArgs.GetBoolArg("-ecash", DEFAULT_ECASH) ? "ectest" : "bchtest"; vFixedSeeds = std::vector(std::begin(pnSeed6_test), std::end(pnSeed6_test)); fDefaultConsistencyChecks = false; fRequireStandard = false; m_is_test_chain = true; m_is_mockable_chain = false; checkpointData = CheckpointData(CBaseChainParams::TESTNET); + m_assumeutxo_data = MapAssumeutxo{ + // TODO to be specified in a future patch. + }; + // Data as of block // 000000000005b07ecf85563034d13efd81c1a29e47e22b20f4fc6919d5b09cd6 // (height 1223263) chainTxData = ChainTxData{1522608381, 15052068, 0.15}; } }; /** * Regression test */ class CRegTestParams : public CChainParams { public: CRegTestParams() { strNetworkID = CBaseChainParams::REGTEST; consensus.nSubsidyHalvingInterval = 150; // always enforce P2SH BIP16 on regtest consensus.BIP16Height = 0; // BIP34 activated on regtest (Used in functional tests) consensus.BIP34Height = 500; consensus.BIP34Hash = BlockHash(); // BIP65 activated on regtest (Used in functional tests) consensus.BIP65Height = 1351; // BIP66 activated on regtest (Used in functional tests) consensus.BIP66Height = 1251; // CSV activated on regtest (Used in functional tests) consensus.CSVHeight = 576; consensus.powLimit = uint256S( "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // two weeks consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; consensus.nPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = true; consensus.fPowNoRetargeting = true; // two days consensus.nDAAHalfLife = 2 * 24 * 60 * 60; // Faster than normal for regtest (144 instead of 2016) consensus.nMinerConfirmationWindow = 144; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY] = { .bit = 28, // 75% of 144 .nActivationThreshold = 108, }; // The miner fund is disabled by default on regnet. consensus.enableMinerFund = false; // 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 = BlockHash(); // UAHF is always enabled on regtest. consensus.uahfHeight = 0; // November 13, 2017 hard fork is always on on regtest. consensus.daaHeight = 0; // November 15, 2018 hard fork is always on on regtest. consensus.magneticAnomalyHeight = 0; // November 15, 2019 protocol upgrade consensus.gravitonHeight = 0; // May 15, 2020 12:00:00 UTC protocol upgrade consensus.phononHeight = 0; // Nov 15, 2020 12:00:00 UTC protocol upgrade consensus.axionHeight = 0; // May 15, 2022 12:00:00 UTC protocol upgrade consensus.gluonActivationTime = 1652616000; // Nov 15, 2022 12:00:00 UTC protocol upgrade consensus.jeffersonActivationTime = 1668513600; diskMagic[0] = 0xfa; diskMagic[1] = 0xbf; diskMagic[2] = 0xb5; diskMagic[3] = 0xda; netMagic[0] = 0xda; netMagic[1] = 0xb5; netMagic[2] = 0xbf; netMagic[3] = 0xfa; nDefaultPort = 18444; nPruneAfterHeight = gArgs.GetBoolArg("-fastprune", false) ? 100 : 1000; m_assumed_blockchain_size = 0; m_assumed_chain_state_size = 0; 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(); fDefaultConsistencyChecks = true; fRequireStandard = true; m_is_test_chain = true; m_is_mockable_chain = true; checkpointData = CheckpointData(CBaseChainParams::REGTEST); + m_assumeutxo_data = MapAssumeutxo{ + { + 110, + {AssumeutxoHash{uint256S( + "0xf5a6cff6749a5a2e1f01a706cd6d139739cd029d14912c2fab" + "284f1d22e79268")}, + 110}, + }, + { + 210, + {AssumeutxoHash{uint256S( + "0x37636b5bb17459fe77f2d77fcae80992ae03dff848033c7225" + "dab8a9722821a6")}, + 210}, + }, + }; + chainTxData = ChainTxData{0, 0, 0}; base58Prefixes[PUBKEY_ADDRESS] = std::vector(1, 111); base58Prefixes[SCRIPT_ADDRESS] = std::vector(1, 196); base58Prefixes[SECRET_KEY] = std::vector(1, 239); base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF}; base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94}; cashaddrPrefix = gArgs.GetBoolArg("-ecash", DEFAULT_ECASH) ? "ecregtest" : "bchreg"; } }; static std::unique_ptr globalChainParams; const CChainParams &Params() { assert(globalChainParams); return *globalChainParams; } std::unique_ptr CreateChainParams(const std::string &chain) { if (chain == CBaseChainParams::MAIN) { return std::make_unique(); } if (chain == CBaseChainParams::TESTNET) { return std::make_unique(); } if (chain == CBaseChainParams::REGTEST) { return std::make_unique(); } throw std::runtime_error( strprintf("%s: Unknown chain %s.", __func__, chain)); } void SelectParams(const std::string &network) { SelectBaseParams(network); globalChainParams = CreateChainParams(network); } diff --git a/src/chainparams.h b/src/chainparams.h index f913ea94b..aeb3cd67b 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -1,157 +1,188 @@ // 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_CHAINPARAMS_H #define BITCOIN_CHAINPARAMS_H #include #include #include #include #include +#include #include #include #include struct SeedSpec6 { uint8_t addr[16]; uint16_t port; }; typedef std::map MapCheckpoints; struct CCheckpointData { MapCheckpoints mapCheckpoints; }; +struct AssumeutxoHash : public BaseHash { + explicit AssumeutxoHash(const uint256 &hash) : BaseHash(hash) {} +}; + +/** + * Holds configuration for use during UTXO snapshot load and validation. The + * contents here are security critical, since they dictate which UTXO snapshots + * are recognized as valid. + */ +struct AssumeutxoData { + //! The expected hash of the deserialized UTXO set. + const AssumeutxoHash hash_serialized; + + //! Used to populate the nChainTx value, which is used during + //! BlockManager::LoadBlockIndex(). + //! + //! We need to hardcode the value here because this is computed cumulatively + //! using block data, which we do not necessarily have at the time of + //! snapshot load. + const unsigned int nChainTx; +}; + +using MapAssumeutxo = std::map; + /** * Holds various statistics on transactions within a chain. Used to estimate * verification progress during chain sync. * * See also: CChainParams::TxData, GuessVerificationProgress. */ struct ChainTxData { int64_t nTime; int64_t nTxCount; double dTxRate; }; /** * CChainParams defines various tweakable parameters of a given instance of the * Bitcoin system. There are three: the main network on which people trade goods * and services, the public test network which gets reset from time to time and * a regression test mode which is intended for private networks only. It has * minimal difficulty to ensure that blocks can be found instantly. */ class CChainParams { public: enum Base58Type { PUBKEY_ADDRESS, SCRIPT_ADDRESS, SECRET_KEY, EXT_PUBLIC_KEY, EXT_SECRET_KEY, MAX_BASE58_TYPES }; const Consensus::Params &GetConsensus() const { return consensus; } const CMessageHeader::MessageMagic &DiskMagic() const { return diskMagic; } const CMessageHeader::MessageMagic &NetMagic() const { return netMagic; } uint16_t GetDefaultPort() const { return nDefaultPort; } uint16_t GetDefaultPort(Network net) const { return net == NET_I2P ? I2P_SAM31_PORT : GetDefaultPort(); } uint16_t GetDefaultPort(const std::string &addr) const { CNetAddr a; return a.SetSpecial(addr) ? GetDefaultPort(a.GetNetwork()) : GetDefaultPort(); } const CBlock &GenesisBlock() const { return genesis; } /** Default value for -checkmempool and -checkblockindex argument */ bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; } /** Policy: Filter transactions that do not match well-defined patterns */ bool RequireStandard() const { return fRequireStandard; } /** If this chain is exclusively used for testing */ bool IsTestChain() const { return m_is_test_chain; } /** If this chain allows time to be mocked */ bool IsMockableChain() const { return m_is_mockable_chain; } uint64_t PruneAfterHeight() const { return nPruneAfterHeight; } /** Minimum free space (in GB) needed for data directory */ uint64_t AssumedBlockchainSize() const { return m_assumed_blockchain_size; } /** * Minimum free space (in GB) needed for data directory when pruned; Does * not include prune target */ uint64_t AssumedChainStateSize() const { return m_assumed_chain_state_size; } /** Whether it is possible to mine blocks on demand (no retargeting) */ bool MineBlocksOnDemand() const { return consensus.fPowNoRetargeting; } /** Return the BIP70 network string (main, test or regtest) */ std::string NetworkIDString() const { return strNetworkID; } /** Return the list of hostnames to look up for DNS seeds */ const std::vector &Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } const std::string &CashAddrPrefix() const { return cashaddrPrefix; } const std::vector &FixedSeeds() const { return vFixedSeeds; } const CCheckpointData &Checkpoints() const { return checkpointData; } + + //! Get allowed assumeutxo configuration. + //! @see ChainstateManager + const MapAssumeutxo &Assumeutxo() const { return m_assumeutxo_data; } + const ChainTxData &TxData() const { return chainTxData; } protected: CChainParams() {} Consensus::Params consensus; CMessageHeader::MessageMagic diskMagic; CMessageHeader::MessageMagic netMagic; uint16_t nDefaultPort; uint64_t nPruneAfterHeight; uint64_t m_assumed_blockchain_size; uint64_t m_assumed_chain_state_size; std::vector vSeeds; std::vector base58Prefixes[MAX_BASE58_TYPES]; std::string cashaddrPrefix; std::string strNetworkID; CBlock genesis; std::vector vFixedSeeds; bool fDefaultConsistencyChecks; bool fRequireStandard; bool m_is_test_chain; bool m_is_mockable_chain; CCheckpointData checkpointData; + MapAssumeutxo m_assumeutxo_data; ChainTxData chainTxData; friend const std::vector GetRandomizedDNSSeeds(const CChainParams ¶ms); }; /** * Creates and returns a std::unique_ptr of the chosen chain. * @returns a CChainParams* of the chosen chain. * @throws a std::runtime_error if the chain is not supported. */ std::unique_ptr CreateChainParams(const std::string &chain); CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const Amount genesisReward); /** * Return the currently selected parameters. This won't change after app * startup, except for unit tests. */ const CChainParams &Params(); /** * Sets the params returned by Params() to those for the given BIP70 chain name. * @throws std::runtime_error when the chain is not supported. */ void SelectParams(const std::string &chain); const CCheckpointData &CheckpointData(const std::string &chain); #endif // BITCOIN_CHAINPARAMS_H diff --git a/src/node/coinstats.cpp b/src/node/coinstats.cpp index 9693096aa..fdaa738e0 100644 --- a/src/node/coinstats.cpp +++ b/src/node/coinstats.cpp @@ -1,154 +1,166 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2019 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 #include #include #include #include #include #include #include #include static uint64_t GetBogoSize(const CScript &scriptPubKey) { return 32 /* txid */ + 4 /* vout index */ + 4 /* height + coinbase */ + 8 /* amount */ + 2 /* scriptPubKey len */ + scriptPubKey.size() /* scriptPubKey */; } static void ApplyHash(CCoinsStats &stats, CHashWriter &ss, const TxId &txid, const std::map &outputs, std::map::const_iterator it) { if (it == outputs.begin()) { ss << txid; ss << VARINT(it->second.GetHeight() * 2 + it->second.IsCoinBase()); } ss << VARINT(it->first + 1); ss << it->second.GetTxOut().scriptPubKey; ss << VARINT_MODE(it->second.GetTxOut().nValue / SATOSHI, VarIntMode::NONNEGATIVE_SIGNED); if (it == std::prev(outputs.end())) { ss << VARINT(0u); } } static void ApplyHash(CCoinsStats &stats, std::nullptr_t, const TxId &txid, const std::map &outputs, std::map::const_iterator it) {} static void ApplyHash(CCoinsStats &stats, MuHash3072 &muhash, const TxId &txid, const std::map &outputs, std::map::const_iterator it) { COutPoint outpoint = COutPoint(txid, it->first); Coin coin = it->second; CDataStream ss(SER_DISK, PROTOCOL_VERSION); ss << outpoint; ss << static_cast(coin.GetHeight() * 2 + coin.IsCoinBase()); ss << coin.GetTxOut(); muhash.Insert(MakeUCharSpan(ss)); } +//! Warning: be very careful when changing this! assumeutxo and UTXO snapshot +//! validation commitments are reliant on the hash constructed by this +//! function. +//! +//! If the construction of this hash is changed, it will invalidate +//! existing UTXO snapshots. This will not result in any kind of consensus +//! failure, but it will force clients that were expecting to make use of +//! assumeutxo to do traditional IBD instead. +//! +//! It is also possible, though very unlikely, that a change in this +//! construction could cause a previously invalid (and potentially malicious) +//! UTXO snapshot to be considered valid. template static void ApplyStats(CCoinsStats &stats, T &hash_obj, const TxId &txid, const std::map &outputs) { assert(!outputs.empty()); stats.nTransactions++; for (auto it = outputs.begin(); it != outputs.end(); ++it) { ApplyHash(stats, hash_obj, txid, outputs, it); stats.nTransactionOutputs++; stats.nTotalAmount += it->second.GetTxOut().nValue; stats.nBogoSize += GetBogoSize(it->second.GetTxOut().scriptPubKey); } } //! Calculate statistics about the unspent transaction output set template static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats, T hash_obj, const std::function &interruption_point) { stats = CCoinsStats(); std::unique_ptr pcursor(view->Cursor()); assert(pcursor); stats.hashBlock = pcursor->GetBestBlock(); { LOCK(cs_main); stats.nHeight = g_chainman.m_blockman.LookupBlockIndex(stats.hashBlock)->nHeight; } PrepareHash(hash_obj, stats); TxId prevkey; std::map outputs; while (pcursor->Valid()) { interruption_point(); COutPoint key; Coin coin; if (pcursor->GetKey(key) && pcursor->GetValue(coin)) { if (!outputs.empty() && key.GetTxId() != prevkey) { ApplyStats(stats, hash_obj, prevkey, outputs); outputs.clear(); } prevkey = key.GetTxId(); outputs[key.GetN()] = std::move(coin); stats.coins_count++; } else { return error("%s: unable to read value", __func__); } pcursor->Next(); } if (!outputs.empty()) { ApplyStats(stats, hash_obj, prevkey, outputs); } FinalizeHash(hash_obj, stats); stats.nDiskSize = view->EstimateSize(); return true; } bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats, CoinStatsHashType hash_type, const std::function &interruption_point) { switch (hash_type) { case (CoinStatsHashType::HASH_SERIALIZED): { CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); return GetUTXOStats(view, stats, ss, interruption_point); } case (CoinStatsHashType::MUHASH): { MuHash3072 muhash; return GetUTXOStats(view, stats, muhash, interruption_point); } case (CoinStatsHashType::NONE): { return GetUTXOStats(view, stats, nullptr, interruption_point); } } // no default case, so the compiler can warn about missing cases assert(false); } // The legacy hash serializes the hashBlock static void PrepareHash(CHashWriter &ss, const CCoinsStats &stats) { ss << stats.hashBlock; } // MuHash does not need the prepare step static void PrepareHash(MuHash3072 &muhash, CCoinsStats &stats) {} static void PrepareHash(std::nullptr_t, CCoinsStats &stats) {} static void FinalizeHash(CHashWriter &ss, CCoinsStats &stats) { stats.hashSerialized = ss.GetHash(); } static void FinalizeHash(MuHash3072 &muhash, CCoinsStats &stats) { uint256 out; muhash.Finalize(out); stats.hashSerialized = out; } static void FinalizeHash(std::nullptr_t, CCoinsStats &stats) {} diff --git a/src/test/validation_tests.cpp b/src/test/validation_tests.cpp index 4a87a2325..c8399f320 100644 --- a/src/test/validation_tests.cpp +++ b/src/test/validation_tests.cpp @@ -1,134 +1,161 @@ // Copyright (c) 2011-2019 The Bitcoin Core developers // Copyright (c) 2017-2019 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include BOOST_FIXTURE_TEST_SUITE(validation_tests, TestingSetup) static void TestBlockSubsidyHalvings(const Consensus::Params &consensusParams) { int maxHalvings = 64; Amount nInitialSubsidy = 50 * COIN; // for height == 0 Amount nPreviousSubsidy = 2 * nInitialSubsidy; BOOST_CHECK_EQUAL(nPreviousSubsidy, 2 * nInitialSubsidy); for (int nHalvings = 0; nHalvings < maxHalvings; nHalvings++) { int nHeight = nHalvings * consensusParams.nSubsidyHalvingInterval; Amount nSubsidy = GetBlockSubsidy(nHeight, consensusParams); BOOST_CHECK(nSubsidy <= nInitialSubsidy); BOOST_CHECK_EQUAL(nSubsidy, nPreviousSubsidy / 2); nPreviousSubsidy = nSubsidy; } BOOST_CHECK_EQUAL( GetBlockSubsidy(maxHalvings * consensusParams.nSubsidyHalvingInterval, consensusParams), Amount::zero()); } static void TestBlockSubsidyHalvings(int nSubsidyHalvingInterval) { Consensus::Params consensusParams; consensusParams.nSubsidyHalvingInterval = nSubsidyHalvingInterval; TestBlockSubsidyHalvings(consensusParams); } BOOST_AUTO_TEST_CASE(block_subsidy_test) { const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); // As in main TestBlockSubsidyHalvings(chainParams->GetConsensus()); // As in regtest TestBlockSubsidyHalvings(150); // Just another interval TestBlockSubsidyHalvings(1000); } BOOST_AUTO_TEST_CASE(subsidy_limit_test) { const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); Amount nSum = Amount::zero(); for (int nHeight = 0; nHeight < 14000000; nHeight += 1000) { Amount nSubsidy = GetBlockSubsidy(nHeight, chainParams->GetConsensus()); BOOST_CHECK(nSubsidy <= 50 * COIN); nSum += 1000 * nSubsidy; BOOST_CHECK(MoneyRange(nSum)); } BOOST_CHECK_EQUAL(nSum, int64_t(2099999997690000LL) * SATOSHI); } static CBlock makeLargeDummyBlock(const size_t num_tx) { CBlock block; block.vtx.reserve(num_tx); CTransaction tx; for (size_t i = 0; i < num_tx; i++) { block.vtx.push_back(MakeTransactionRef(tx)); } return block; } /** * Test that LoadExternalBlockFile works with the buffer size set below the * size of a large block. Currently, LoadExternalBlockFile has the buffer size * for CBufferedFile set to 2 * MAX_TX_SIZE. Test with a value of * 10 * MAX_TX_SIZE. */ BOOST_AUTO_TEST_CASE(validation_load_external_block_file) { fs::path tmpfile_name = GetDataDir() / "block.dat"; FILE *fp = fopen(fs::PathToString(tmpfile_name).c_str(), "wb+"); BOOST_CHECK(fp != nullptr); const Config &config = GetConfig(); const CChainParams &chainparams = config.GetChainParams(); // serialization format is: // message start magic, size of block, block size_t nwritten = fwrite(std::begin(chainparams.DiskMagic()), CMessageHeader::MESSAGE_START_SIZE, 1, fp); BOOST_CHECK_EQUAL(nwritten, 1UL); CTransaction empty_tx; size_t empty_tx_size = GetSerializeSize(empty_tx, CLIENT_VERSION); size_t num_tx = (10 * MAX_TX_SIZE) / empty_tx_size; CBlock block = makeLargeDummyBlock(num_tx); BOOST_CHECK(GetSerializeSize(block, CLIENT_VERSION) > 2 * MAX_TX_SIZE); unsigned int size = GetSerializeSize(block, CLIENT_VERSION); { CAutoFile outs(fp, SER_DISK, CLIENT_VERSION); outs << size; outs << block; outs.release(); } fseek(fp, 0, SEEK_SET); BOOST_CHECK_NO_THROW( { ::ChainstateActive().LoadExternalBlockFile(config, fp, 0); }); } +//! Test retrieval of valid assumeutxo values. +BOOST_AUTO_TEST_CASE(test_assumeutxo) { + const auto params = CreateChainParams(CBaseChainParams::REGTEST); + + // These heights don't have assumeutxo configurations associated, per the + // contents of chainparams.cpp. + std::vector bad_heights{0, 100, 111, 115, 209, 211}; + + for (auto empty : bad_heights) { + const auto out = ExpectedAssumeutxo(empty, *params); + BOOST_CHECK(!out); + } + + const auto out110 = *ExpectedAssumeutxo(110, *params); + BOOST_CHECK_EQUAL( + out110.hash_serialized.ToString(), + "f5a6cff6749a5a2e1f01a706cd6d139739cd029d14912c2fab284f1d22e79268"); + BOOST_CHECK_EQUAL(out110.nChainTx, (unsigned int)110); + + const auto out210 = *ExpectedAssumeutxo(210, *params); + BOOST_CHECK_EQUAL( + out210.hash_serialized.ToString(), + "37636b5bb17459fe77f2d77fcae80992ae03dff848033c7225dab8a9722821a6"); + BOOST_CHECK_EQUAL(out210.nChainTx, (unsigned int)210); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/validation.cpp b/src/validation.cpp index 602613c8e..d986fb525 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1,6199 +1,6211 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2018 The Bitcoin Core developers // Copyright (c) 2017-2020 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include