diff --git a/src/addrdb.cpp b/src/addrdb.cpp index 96fb1fe27..492f5dea3 100644 --- a/src/addrdb.cpp +++ b/src/addrdb.cpp @@ -1,147 +1,146 @@ // 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. #include #include #include #include -#include #include #include #include #include #include namespace { template bool SerializeDB(const CChainParams &chainParams, Stream &stream, const Data &data) { // Write and commit header, data try { CHashWriter hasher(SER_DISK, CLIENT_VERSION); stream << chainParams.DiskMagic() << data; hasher << chainParams.DiskMagic() << data; stream << hasher.GetHash(); } catch (const std::exception &e) { return error("%s: Serialize or I/O error - %s", __func__, e.what()); } return true; } template bool SerializeFileDB(const CChainParams &chainParams, const std::string &prefix, const fs::path &path, const Data &data) { // Generate random temporary filename unsigned short randv = 0; GetRandBytes((uint8_t *)&randv, sizeof(randv)); std::string tmpfn = strprintf("%s.%04x", prefix, randv); // open temp output file, and associate with CAutoFile fs::path pathTmp = GetDataDir() / tmpfn; FILE *file = fsbridge::fopen(pathTmp, "wb"); CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); if (fileout.IsNull()) { return error("%s: Failed to open file %s", __func__, pathTmp.string()); } // Serialize if (!SerializeDB(chainParams, fileout, data)) { return false; } if (!FileCommit(fileout.Get())) { return error("%s: Failed to flush file %s", __func__, pathTmp.string()); } fileout.fclose(); // replace existing file, if any, with new file if (!RenameOver(pathTmp, path)) { return error("%s: Rename-into-place failed", __func__); } return true; } template bool DeserializeDB(const CChainParams &chainParams, Stream &stream, Data &data, bool fCheckSum = true) { try { CHashVerifier verifier(&stream); // de-serialize file header (network specific magic number) and .. uint8_t pchMsgTmp[4]; verifier >> pchMsgTmp; // ... verify the network matches ours if (memcmp(pchMsgTmp, std::begin(chainParams.DiskMagic()), sizeof(pchMsgTmp))) { return error("%s: Invalid network magic number", __func__); } // de-serialize data verifier >> data; // verify checksum if (fCheckSum) { uint256 hashTmp; stream >> hashTmp; if (hashTmp != verifier.GetHash()) { return error("%s: Checksum mismatch, data corrupted", __func__); } } } catch (const std::exception &e) { return error("%s: Deserialize or I/O error - %s", __func__, e.what()); } return true; } template bool DeserializeFileDB(const CChainParams &chainParams, const fs::path &path, Data &data) { // open input file, and associate with CAutoFile FILE *file = fsbridge::fopen(path, "rb"); CAutoFile filein(file, SER_DISK, CLIENT_VERSION); if (filein.IsNull()) { return error("%s: Failed to open file %s", __func__, path.string()); } return DeserializeDB(chainParams, filein, data); } } // namespace CBanDB::CBanDB(fs::path ban_list_path, const CChainParams &_chainParams) : m_ban_list_path(std::move(ban_list_path)), chainParams(_chainParams) {} bool CBanDB::Write(const banmap_t &banSet) { return SerializeFileDB(chainParams, "banlist", m_ban_list_path, banSet); } bool CBanDB::Read(banmap_t &banSet) { return DeserializeFileDB(chainParams, m_ban_list_path, banSet); } CAddrDB::CAddrDB(const CChainParams &chainParamsIn) : chainParams(chainParamsIn) { pathAddr = GetDataDir() / "peers.dat"; } bool CAddrDB::Write(const CAddrMan &addr) { return SerializeFileDB(chainParams, "peers", pathAddr, addr); } bool CAddrDB::Read(CAddrMan &addr) { return DeserializeFileDB(chainParams, pathAddr, addr); } bool CAddrDB::Read(CAddrMan &addr, CDataStream &ssPeers) { bool ret = DeserializeDB(chainParams, ssPeers, addr, false); if (!ret) { // Ensure addrman is left in a clean state addr.Clear(); } return ret; } diff --git a/src/chainparams.cpp b/src/chainparams.cpp index c9f3b846a..10a5cac60 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -1,675 +1,674 @@ // 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; // 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, }; consensus.vDeployments[Consensus::DEPLOYEMENT_MINER_FUND] = { .bit = 0, // 66% of 2016 .nActivationThreshold = 1344, // Nov 15, 2019 12:00:00 UTC .nStartTime = 1573819200, // May 15, 2020 12:00:00 UTC .nTimeout = 1589544000, }; consensus.vDeployments[Consensus::DEPLOYEMENT_MINER_FUND_ABC] = { .bit = 1, // 66% of 2016 .nActivationThreshold = 1344, // Nov 15, 2019 12:00:00 UTC .nStartTime = 1573819200, // May 15, 2020 12:00:00 UTC .nTimeout = 1589544000, }; consensus.vDeployments[Consensus::DEPLOYEMENT_MINER_FUND_BCHD] = { .bit = 2, // 66% of 2016 .nActivationThreshold = 1344, // Nov 15, 2019 12:00:00 UTC .nStartTime = 1573819200, // May 15, 2020 12:00:00 UTC .nTimeout = 1589544000, }; consensus .vDeployments[Consensus::DEPLOYEMENT_MINER_FUND_ELECTRON_CASH] = { .bit = 3, // 66% of 2016 .nActivationThreshold = 1344, // Nov 15, 2019 12:00:00 UTC .nStartTime = 1573819200, // May 15, 2020 12:00:00 UTC .nTimeout = 1589544000, }; // The miner fund is enabled by default on mainnet. consensus.enableMinerFund = true; // 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.phononActivationTime = 1589544000; // Nov 15, 2020 12:00:00 UTC protocol upgrade consensus.axionActivationTime = 1605441600; /** * 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 a oneshot 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"); // bitcoinforks seeders vSeeds.emplace_back("seed-abc.bitcoinforks.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"); 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 = "bitcoincash"; vFixedSeeds = std::vector( pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main)); fDefaultConsistencyChecks = false; fRequireStandard = true; m_is_test_chain = false; m_is_mockable_chain = false; checkpointData = { .mapCheckpoints = { {11111, BlockHash::fromHex("0000000069e244f73d78e8fd29ba2fd2ed6" "18bd6fa2ee92559f542fdb26e7c1d")}, {33333, BlockHash::fromHex("000000002dd5588a74784eaa7ab0507a18a" "d16a236e7b1ce69f00d7ddfb5d0a6")}, {74000, BlockHash::fromHex("0000000000573993a3c9e41ce34471c079d" "cf5f52a0e824a81e7f953b8661a20")}, {105000, BlockHash::fromHex("00000000000291ce28027faea320c8d2b0" "54b2e0fe44a773f3eefb151d6bdc97")}, {134444, BlockHash::fromHex("00000000000005b12ffd4cd315cd34ffd4" "a594f430ac814c91184a0d42d2b0fe")}, {168000, BlockHash::fromHex("000000000000099e61ea72015e79632f21" "6fe6cb33d7899acb35b75c8303b763")}, {193000, BlockHash::fromHex("000000000000059f452a5f7340de6682a9" "77387c17010ff6e6c3bd83ca8b1317")}, {210000, BlockHash::fromHex("000000000000048b95347e83192f69cf03" "66076336c639f9b7228e9ba171342e")}, {216116, BlockHash::fromHex("00000000000001b4f4b433e81ee46494af" "945cf96014816a4e2370f11b23df4e")}, {225430, BlockHash::fromHex("00000000000001c108384350f74090433e" "7fcf79a606b8e797f065b130575932")}, {250000, BlockHash::fromHex("000000000000003887df1f29024b06fc22" "00b55f8af8f35453d7be294df2d214")}, {279000, BlockHash::fromHex("0000000000000001ae8c72a0b0c301f67e" "3afca10e819efa9041e458e9bd7e40")}, {295000, BlockHash::fromHex("00000000000000004d9b4ef50f0f9d686f" "d69db2e03af35a100370c64632a983")}, // UAHF fork block. {478558, BlockHash::fromHex("0000000000000000011865af4122fe3b14" "4e2cbeea86142e8ff2fb4107352d43")}, // Nov, 13 DAA activation block. {504031, BlockHash::fromHex("0000000000000000011ebf65b60d0a3de8" "0b8175be709d653b4c1a1beeb6ab9c")}, // Monolith activation. {530359, BlockHash::fromHex("0000000000000000011ada8bd08f46074f" "44a8f155396f43e38acf9501c49103")}, // Magnetic anomaly activation. {556767, BlockHash::fromHex("0000000000000000004626ff6e3b936941" "d341c5932ece4357eeccac44e6d56c")}, // Great wall activation. {582680, BlockHash::fromHex("000000000000000001b4b8e36aec7d4f96" "71a47872cb9a74dc16ca398c7dcc18")}, // Graviton activation. {609136, BlockHash::fromHex("000000000000000000b48bb207faac5ac6" "55c313e41ac909322eaa694f5bc5b1")}, // Phonon activation. {635259, BlockHash::fromHex("00000000000000000033dfef1fc2d6a5d5" "520b078c55193a9bf498c5b27530f7")}, }}; // 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; // 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, }; consensus.vDeployments[Consensus::DEPLOYEMENT_MINER_FUND] = { .bit = 0, // 66% of 2016 .nActivationThreshold = 1344, // Nov 15, 2019 12:00:00 UTC .nStartTime = 1573819200, // May 15, 2020 12:00:00 UTC .nTimeout = 1589544000, }; consensus.vDeployments[Consensus::DEPLOYEMENT_MINER_FUND_ABC] = { .bit = 1, // 66% of 2016 .nActivationThreshold = 1344, // Nov 15, 2019 12:00:00 UTC .nStartTime = 1573819200, // May 15, 2020 12:00:00 UTC .nTimeout = 1589544000, }; consensus.vDeployments[Consensus::DEPLOYEMENT_MINER_FUND_BCHD] = { .bit = 2, // 66% of 2016 .nActivationThreshold = 1344, // Nov 15, 2019 12:00:00 UTC .nStartTime = 1573819200, // May 15, 2020 12:00:00 UTC .nTimeout = 1589544000, }; consensus .vDeployments[Consensus::DEPLOYEMENT_MINER_FUND_ELECTRON_CASH] = { .bit = 3, // 66% of 2016 .nActivationThreshold = 1344, // Nov 15, 2019 12:00:00 UTC .nStartTime = 1573819200, // May 15, 2020 12:00:00 UTC .nTimeout = 1589544000, }; // 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.phononActivationTime = 1589544000; // Nov 15, 2020 12:00:00 UTC protocol upgrade consensus.axionActivationTime = 1605441600; 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"); // bitcoinforks seeders vSeeds.emplace_back("testnet-seed-abc.bitcoinforks.org"); // Amaury SÉCHET vSeeds.emplace_back("testnet-seed.deadalnix.me"); // BCHD vSeeds.emplace_back("testnet-seed.bchd.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 = "bchtest"; vFixedSeeds = std::vector( pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test)); fDefaultConsistencyChecks = false; fRequireStandard = false; m_is_test_chain = true; m_is_mockable_chain = false; checkpointData = { .mapCheckpoints = { {546, BlockHash::fromHex("000000002a936ca763904c3c35fce2f3556c5" "59c0214345d31b1bcebf76acb70")}, // UAHF fork block. {1155875, BlockHash::fromHex("00000000f17c850672894b9a75b63a1e72830bbd5f" "4c8889b5c1a80e7faef138")}, // Nov, 13. DAA activation block. {1188697, BlockHash::fromHex("0000000000170ed0918077bde7b4d36cc4c91be69f" "a09211f748240dabe047fb")}, // Great wall activation. {1303885, BlockHash::fromHex("00000000000000479138892ef0e4fa478ccc938fb9" "4df862ef5bde7e8dee23d3")}, // Graviton activation. {1341712, BlockHash::fromHex("00000000fffc44ea2e202bd905a9fbbb9491ef9e9d" "5a9eed4039079229afa35b")}, // Phonon activation. {1378461, BlockHash::fromHex( "0000000099f5509b5f36b1926bcf82b21d936ebeade" "e811030dfbbb7fae915d7")}, }}; // 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; // Faster than normal for regtest (144 instead of 2016) consensus.nMinerConfirmationWindow = 144; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY] = { .bit = 28, // 75% of 144 .nActivationThreshold = 108, }; consensus.vDeployments[Consensus::DEPLOYEMENT_MINER_FUND] = { .bit = 0, // 66% of 144 .nActivationThreshold = 96, // Nov 15, 2019 12:00:00 UTC .nStartTime = 1573819200, // May 15, 2020 12:00:00 UTC .nTimeout = 1589544000, }; consensus.vDeployments[Consensus::DEPLOYEMENT_MINER_FUND_ABC] = { .bit = 1, // 66% of 144 .nActivationThreshold = 96, // Nov 15, 2019 12:00:00 UTC .nStartTime = 1573819200, // May 15, 2020 12:00:00 UTC .nTimeout = 1589544000, }; consensus.vDeployments[Consensus::DEPLOYEMENT_MINER_FUND_BCHD] = { .bit = 2, // 66% of 144 .nActivationThreshold = 96, // Nov 15, 2019 12:00:00 UTC .nStartTime = 1573819200, // May 15, 2020 12:00:00 UTC .nTimeout = 1589544000, }; consensus .vDeployments[Consensus::DEPLOYEMENT_MINER_FUND_ELECTRON_CASH] = { .bit = 3, // 66% of 144 .nActivationThreshold = 96, // Nov 15, 2019 12:00:00 UTC .nStartTime = 1573819200, // May 15, 2020 12:00:00 UTC .nTimeout = 1589544000, }; // 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.phononActivationTime = 1589544000; // Nov 15, 2020 12:00:00 UTC protocol upgrade consensus.axionActivationTime = 1605441600; 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 = 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 = { .mapCheckpoints = { {0, BlockHash::fromHex("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb4" "36012afca590b1a11466e2206")}, }}; 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 = "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/chainparamsbase.cpp b/src/chainparamsbase.cpp index ce5be070c..bec8d6f0f 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -1,62 +1,61 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2015 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 const std::string CBaseChainParams::MAIN = "main"; const std::string CBaseChainParams::TESTNET = "test"; const std::string CBaseChainParams::REGTEST = "regtest"; void SetupChainParamsBaseOptions() { gArgs.AddArg("-chain=", "Use the chain (default: main). Allowed values: main, " "test, regtest", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); gArgs.AddArg( "-regtest", "Enter regression test mode, which uses a special chain in which " "blocks can be solved instantly. This is intended for regression " "testing tools and app development. Equivalent to -chain=regtest.", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); gArgs.AddArg("-testnet", "Use the test chain. Equivalent to -chain=test.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); } static std::unique_ptr globalChainBaseParams; const CBaseChainParams &BaseParams() { assert(globalChainBaseParams); return *globalChainBaseParams; } std::unique_ptr CreateBaseChainParams(const std::string &chain) { if (chain == CBaseChainParams::MAIN) { return std::make_unique("", 8332); } if (chain == CBaseChainParams::TESTNET) { return std::make_unique("testnet3", 18332); } if (chain == CBaseChainParams::REGTEST) { return std::make_unique("regtest", 18443); } throw std::runtime_error( strprintf("%s: Unknown chain %s.", __func__, chain)); } void SelectBaseParams(const std::string &chain) { globalChainBaseParams = CreateBaseChainParams(chain); gArgs.SelectConfigNetwork(chain); } diff --git a/src/clientversion.cpp b/src/clientversion.cpp index 5450fb056..d07ebf014 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -1,117 +1,115 @@ // Copyright (c) 2012-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 #include -#include - /** * Name of client reported in the 'version' message. Report the same name * for both bitcoind and bitcoin-qt, to make it harder for attackers to * target servers or GUI users specifically. */ const std::string CLIENT_NAME("Bitcoin ABC"); /** * Client version number */ #define CLIENT_VERSION_SUFFIX "" /** * The following part of the code determines the CLIENT_BUILD variable. * Several mechanisms are used for this: * * first, if HAVE_BUILD_INFO is defined, include build.h, a file that is * generated by the build environment, possibly containing the output * of git-describe in a macro called BUILD_DESC * * secondly, if this is an exported version of the code, GIT_ARCHIVE will * be defined (automatically using the export-subst git attribute), and * GIT_COMMIT will contain the commit id. * * then, three options exist for determining CLIENT_BUILD: * * if BUILD_DESC is defined, use that literally (output of git-describe) * * if not, but GIT_COMMIT is defined, use * v[maj].[min].[rev].[build]-g[commit] * * otherwise, use v[maj].[min].[rev].[build]-unk * finally CLIENT_VERSION_SUFFIX is added */ //! First, include build.h if requested #ifdef HAVE_BUILD_INFO #include #endif //! git will put "#define GIT_ARCHIVE 1" on the next line inside archives. //! $Format:%n#define GIT_ARCHIVE 1$ #ifdef GIT_ARCHIVE #define GIT_COMMIT_ID "$Format:%h$" #define GIT_COMMIT_DATE "$Format:%cD$" #endif #define BUILD_DESC_WITH_SUFFIX(maj, min, rev, suffix) \ "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE( \ rev) "-" DO_STRINGIZE(suffix) #define BUILD_DESC_FROM_COMMIT(maj, min, rev, commit) \ "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE( \ rev) "-g" commit #define BUILD_DESC_FROM_UNKNOWN(maj, min, rev) \ "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "-unk" #ifndef BUILD_DESC #ifdef BUILD_SUFFIX #define BUILD_DESC \ BUILD_DESC_WITH_SUFFIX(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, \ CLIENT_VERSION_REVISION, BUILD_SUFFIX) #elif defined(GIT_COMMIT_ID) #define BUILD_DESC \ BUILD_DESC_FROM_COMMIT(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, \ CLIENT_VERSION_REVISION, GIT_COMMIT_ID) #else #define BUILD_DESC \ BUILD_DESC_FROM_UNKNOWN(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, \ CLIENT_VERSION_REVISION) #endif #endif const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX); static std::string FormatVersion(int nVersion) { if (nVersion % 100 == 0) { return strprintf("%d.%d.%d", nVersion / 1000000, (nVersion / 10000) % 100, (nVersion / 100) % 100); } else { return strprintf("%d.%d.%d.%d", nVersion / 1000000, (nVersion / 10000) % 100, (nVersion / 100) % 100, nVersion % 100); } } std::string FormatFullVersion() { return CLIENT_BUILD; } /** * Format the subversion field according to BIP 14 spec * (https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki) */ std::string FormatSubVersion(const std::string &name, int nClientVersion, const std::vector &comments) { std::ostringstream ss; ss << "/"; ss << name << ":" << FormatVersion(nClientVersion); if (!comments.empty()) { std::vector::const_iterator it(comments.begin()); ss << "(" << *it; for (++it; it != comments.end(); ++it) { ss << "; " << *it; } ss << ")"; } ss << "/"; return ss.str(); } diff --git a/src/coins.cpp b/src/coins.cpp index 01e978b1a..4e3951896 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -1,346 +1,343 @@ // Copyright (c) 2012-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 #include #include -#include #include #include -#include - bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; } BlockHash CCoinsView::GetBestBlock() const { return BlockHash(); } std::vector CCoinsView::GetHeadBlocks() const { return std::vector(); } bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const BlockHash &hashBlock) { return false; } CCoinsViewCursor *CCoinsView::Cursor() const { return nullptr; } bool CCoinsView::HaveCoin(const COutPoint &outpoint) const { Coin coin; return GetCoin(outpoint, coin); } CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) {} bool CCoinsViewBacked::GetCoin(const COutPoint &outpoint, Coin &coin) const { return base->GetCoin(outpoint, coin); } bool CCoinsViewBacked::HaveCoin(const COutPoint &outpoint) const { return base->HaveCoin(outpoint); } BlockHash CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); } std::vector CCoinsViewBacked::GetHeadBlocks() const { return base->GetHeadBlocks(); } void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const BlockHash &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); } CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); } size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); } SaltedOutpointHasher::SaltedOutpointHasher() : k0(GetRand(std::numeric_limits::max())), k1(GetRand(std::numeric_limits::max())) {} CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), cachedCoinsUsage(0) {} size_t CCoinsViewCache::DynamicMemoryUsage() const { return memusage::DynamicUsage(cacheCoins) + cachedCoinsUsage; } CCoinsMap::iterator CCoinsViewCache::FetchCoin(const COutPoint &outpoint) const { CCoinsMap::iterator it = cacheCoins.find(outpoint); if (it != cacheCoins.end()) { return it; } Coin tmp; if (!base->GetCoin(outpoint, tmp)) { return cacheCoins.end(); } CCoinsMap::iterator ret = cacheCoins .emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::forward_as_tuple(std::move(tmp))) .first; if (ret->second.coin.IsSpent()) { // The parent only has an empty entry for this outpoint; we can consider // our version as fresh. ret->second.flags = CCoinsCacheEntry::FRESH; } cachedCoinsUsage += ret->second.coin.DynamicMemoryUsage(); return ret; } bool CCoinsViewCache::GetCoin(const COutPoint &outpoint, Coin &coin) const { CCoinsMap::const_iterator it = FetchCoin(outpoint); if (it == cacheCoins.end()) { return false; } coin = it->second.coin; return !coin.IsSpent(); } void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin coin, bool possible_overwrite) { assert(!coin.IsSpent()); if (coin.GetTxOut().scriptPubKey.IsUnspendable()) { return; } CCoinsMap::iterator it; bool inserted; std::tie(it, inserted) = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>()); bool fresh = false; if (!inserted) { cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage(); } if (!possible_overwrite) { if (!it->second.coin.IsSpent()) { throw std::logic_error( "Adding new coin that replaces non-pruned entry"); } fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY); } it->second.coin = std::move(coin); it->second.flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0); cachedCoinsUsage += it->second.coin.DynamicMemoryUsage(); } void AddCoins(CCoinsViewCache &cache, const CTransaction &tx, int nHeight, bool check) { bool fCoinbase = tx.IsCoinBase(); const TxId txid = tx.GetId(); for (size_t i = 0; i < tx.vout.size(); ++i) { const COutPoint outpoint(txid, i); bool overwrite = check ? cache.HaveCoin(outpoint) : fCoinbase; // Always set the possible_overwrite flag to AddCoin for coinbase txn, // in order to correctly deal with the pre-BIP30 occurrences of // duplicate coinbase transactions. cache.AddCoin(outpoint, Coin(tx.vout[i], nHeight, fCoinbase), overwrite); } } bool CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin *moveout) { CCoinsMap::iterator it = FetchCoin(outpoint); if (it == cacheCoins.end()) { return false; } cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage(); if (moveout) { *moveout = std::move(it->second.coin); } if (it->second.flags & CCoinsCacheEntry::FRESH) { cacheCoins.erase(it); } else { it->second.flags |= CCoinsCacheEntry::DIRTY; it->second.coin.Clear(); } return true; } static const Coin coinEmpty; const Coin &CCoinsViewCache::AccessCoin(const COutPoint &outpoint) const { CCoinsMap::const_iterator it = FetchCoin(outpoint); if (it == cacheCoins.end()) { return coinEmpty; } return it->second.coin; } bool CCoinsViewCache::HaveCoin(const COutPoint &outpoint) const { CCoinsMap::const_iterator it = FetchCoin(outpoint); return it != cacheCoins.end() && !it->second.coin.IsSpent(); } bool CCoinsViewCache::HaveCoinInCache(const COutPoint &outpoint) const { CCoinsMap::const_iterator it = cacheCoins.find(outpoint); return (it != cacheCoins.end() && !it->second.coin.IsSpent()); } BlockHash CCoinsViewCache::GetBestBlock() const { if (hashBlock.IsNull()) { hashBlock = base->GetBestBlock(); } return hashBlock; } void CCoinsViewCache::SetBestBlock(const BlockHash &hashBlockIn) { hashBlock = hashBlockIn; } bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const BlockHash &hashBlockIn) { for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); it = mapCoins.erase(it)) { // Ignore non-dirty entries (optimization). if (!(it->second.flags & CCoinsCacheEntry::DIRTY)) { continue; } CCoinsMap::iterator itUs = cacheCoins.find(it->first); if (itUs == cacheCoins.end()) { // The parent cache does not have an entry, while the child does // We can ignore it if it's both FRESH and pruned in the child if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent())) { // Otherwise we will need to create it in the parent and // move the data up and mark it as dirty CCoinsCacheEntry &entry = cacheCoins[it->first]; entry.coin = std::move(it->second.coin); cachedCoinsUsage += entry.coin.DynamicMemoryUsage(); entry.flags = CCoinsCacheEntry::DIRTY; // We can mark it FRESH in the parent if it was FRESH in the // child. Otherwise it might have just been flushed from the // parent's cache and already exist in the grandparent if (it->second.flags & CCoinsCacheEntry::FRESH) { entry.flags |= CCoinsCacheEntry::FRESH; } } } else { // Assert that the child cache entry was not marked FRESH if the // parent cache entry has unspent outputs. If this ever happens, // it means the FRESH flag was misapplied and there is a logic // error in the calling code. if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent()) { throw std::logic_error("FRESH flag misapplied to cache " "entry for base transaction with " "spendable outputs"); } // Found the entry in the parent cache if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent()) { // The grandparent does not have an entry, and the child is // modified and being pruned. This means we can just delete // it from the parent. cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage(); cacheCoins.erase(itUs); } else { // A normal modification. cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage(); itUs->second.coin = std::move(it->second.coin); cachedCoinsUsage += itUs->second.coin.DynamicMemoryUsage(); itUs->second.flags |= CCoinsCacheEntry::DIRTY; // NOTE: It is possible the child has a FRESH flag here in // the event the entry we found in the parent is pruned. But // we must not copy that FRESH flag to the parent as that // pruned state likely still needs to be communicated to the // grandparent. } } } hashBlock = hashBlockIn; return true; } bool CCoinsViewCache::Flush() { bool fOk = base->BatchWrite(cacheCoins, hashBlock); cacheCoins.clear(); cachedCoinsUsage = 0; return fOk; } void CCoinsViewCache::Uncache(const COutPoint &outpoint) { CCoinsMap::iterator it = cacheCoins.find(outpoint); if (it != cacheCoins.end() && it->second.flags == 0) { cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage(); cacheCoins.erase(it); } } unsigned int CCoinsViewCache::GetCacheSize() const { return cacheCoins.size(); } const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn &input) const { const Coin &coin = AccessCoin(input.prevout); assert(!coin.IsSpent()); return coin.GetTxOut(); } Amount CCoinsViewCache::GetValueIn(const CTransaction &tx) const { if (tx.IsCoinBase()) { return Amount::zero(); } Amount nResult = Amount::zero(); for (size_t i = 0; i < tx.vin.size(); i++) { nResult += GetOutputFor(tx.vin[i]).nValue; } return nResult; } bool CCoinsViewCache::HaveInputs(const CTransaction &tx) const { if (tx.IsCoinBase()) { return true; } for (size_t i = 0; i < tx.vin.size(); i++) { if (!HaveCoin(tx.vin[i].prevout)) { return false; } } return true; } // TODO: merge with similar definition in undo.h. static const size_t MAX_OUTPUTS_PER_TX = MAX_TX_SIZE / ::GetSerializeSize(CTxOut(), PROTOCOL_VERSION); const Coin &AccessByTxid(const CCoinsViewCache &view, const TxId &txid) { for (uint32_t n = 0; n < MAX_OUTPUTS_PER_TX; n++) { const Coin &alternate = view.AccessCoin(COutPoint(txid, n)); if (!alternate.IsSpent()) { return alternate; } } return coinEmpty; } bool CCoinsViewErrorCatcher::GetCoin(const COutPoint &outpoint, Coin &coin) const { try { return CCoinsViewBacked::GetCoin(outpoint, coin); } catch (const std::runtime_error &e) { for (auto f : m_err_callbacks) { f(); } LogPrintf("Error reading from database: %s\n", e.what()); // Starting the shutdown sequence and returning false to the caller // would be interpreted as 'entry not found' (as opposed to unable to // read data), and could lead to invalid interpretation. Just exit // immediately, as we can't continue anyway, and all writes should be // atomic. std::abort(); } } diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index 573d82a1b..b49f1e135 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -1,270 +1,268 @@ // Copyright (c) 2012-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 -#include #include -#include #include #include #include #include #include #include #include class CBitcoinLevelDBLogger : public leveldb::Logger { public: // This code is adapted from posix_logger.h, which is why it is using // vsprintf. // Please do not do this in normal code void Logv(const char *format, va_list ap) override { if (!LogAcceptCategory(BCLog::LEVELDB)) { return; } char buffer[500]; for (int iter = 0; iter < 2; iter++) { char *base; int bufsize; if (iter == 0) { bufsize = sizeof(buffer); base = buffer; } else { bufsize = 30000; base = new char[bufsize]; } char *p = base; char *limit = base + bufsize; // Print the message if (p < limit) { va_list backup_ap; va_copy(backup_ap, ap); // Do not use vsnprintf elsewhere in bitcoin source code, see // above. p += vsnprintf(p, limit - p, format, backup_ap); va_end(backup_ap); } // Truncate to available space if necessary if (p >= limit) { if (iter == 0) { continue; // Try again with larger buffer } else { p = limit - 1; } } // Add newline if necessary if (p == base || p[-1] != '\n') { *p++ = '\n'; } assert(p <= limit); base[std::min(bufsize - 1, (int)(p - base))] = '\0'; LogPrintfToBeContinued("leveldb: %s", base); if (base != buffer) { delete[] base; } break; } } }; static void SetMaxOpenFiles(leveldb::Options *options) { // On most platforms the default setting of max_open_files (which is 1000) // is optimal. On Windows using a large file count is OK because the handles // do not interfere with select() loops. On 64-bit Unix hosts this value is // also OK, because up to that amount LevelDB will use an mmap // implementation that does not use extra file descriptors (the fds are // closed after being mmaped). // // Increasing the value beyond the default is dangerous because LevelDB will // fall back to a non-mmap implementation when the file count is too large. // On 32-bit Unix host we should decrease the value because the handles use // up real fds, and we want to avoid fd exhaustion issues. // // See PR #12495 for further discussion. int default_open_files = options->max_open_files; #ifndef WIN32 if (sizeof(void *) < 8) { options->max_open_files = 64; } #endif LogPrint(BCLog::LEVELDB, "LevelDB using max_open_files=%d (default=%d)\n", options->max_open_files, default_open_files); } static leveldb::Options GetOptions(size_t nCacheSize) { leveldb::Options options; options.block_cache = leveldb::NewLRUCache(nCacheSize / 2); // up to two write buffers may be held in memory simultaneously options.write_buffer_size = nCacheSize / 4; options.filter_policy = leveldb::NewBloomFilterPolicy(10); options.compression = leveldb::kNoCompression; options.info_log = new CBitcoinLevelDBLogger(); if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) { // LevelDB versions before 1.16 consider short writes to be corruption. // Only trigger error on corruption in later versions. options.paranoid_checks = true; } SetMaxOpenFiles(&options); return options; } CDBWrapper::CDBWrapper(const fs::path &path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : m_name(fs::basename(path)) { penv = nullptr; readoptions.verify_checksums = true; iteroptions.verify_checksums = true; iteroptions.fill_cache = false; syncoptions.sync = true; options = GetOptions(nCacheSize); options.create_if_missing = true; if (fMemory) { penv = leveldb::NewMemEnv(leveldb::Env::Default()); options.env = penv; } else { if (fWipe) { LogPrintf("Wiping LevelDB in %s\n", path.string()); leveldb::Status result = leveldb::DestroyDB(path.string(), options); dbwrapper_private::HandleError(result); } TryCreateDirectories(path); LogPrintf("Opening LevelDB in %s\n", path.string()); } leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb); dbwrapper_private::HandleError(status); LogPrintf("Opened LevelDB successfully\n"); if (gArgs.GetBoolArg("-forcecompactdb", false)) { LogPrintf("Starting database compaction of %s\n", path.string()); pdb->CompactRange(nullptr, nullptr); LogPrintf("Finished database compaction of %s\n", path.string()); } // The base-case obfuscation key, which is a noop. obfuscate_key = std::vector(OBFUSCATE_KEY_NUM_BYTES, '\000'); bool key_exists = Read(OBFUSCATE_KEY_KEY, obfuscate_key); if (!key_exists && obfuscate && IsEmpty()) { // Initialize non-degenerate obfuscation if it won't upset existing, // non-obfuscated data. std::vector new_key = CreateObfuscateKey(); // Write `new_key` so we don't obfuscate the key with itself Write(OBFUSCATE_KEY_KEY, new_key); obfuscate_key = new_key; LogPrintf("Wrote new obfuscate key for %s: %s\n", path.string(), HexStr(obfuscate_key)); } LogPrintf("Using obfuscation key for %s: %s\n", path.string(), HexStr(obfuscate_key)); } CDBWrapper::~CDBWrapper() { delete pdb; pdb = nullptr; delete options.filter_policy; options.filter_policy = nullptr; delete options.info_log; options.info_log = nullptr; delete options.block_cache; options.block_cache = nullptr; delete penv; options.env = nullptr; } bool CDBWrapper::WriteBatch(CDBBatch &batch, bool fSync) { const bool log_memory = LogAcceptCategory(BCLog::LEVELDB); double mem_before = 0; if (log_memory) { mem_before = DynamicMemoryUsage() / 1024.0 / 1024; } leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch); dbwrapper_private::HandleError(status); if (log_memory) { double mem_after = DynamicMemoryUsage() / 1024.0 / 1024; LogPrint( BCLog::LEVELDB, "WriteBatch memory usage: db=%s, before=%.1fMiB, after=%.1fMiB\n", m_name, mem_before, mem_after); } return true; } size_t CDBWrapper::DynamicMemoryUsage() const { std::string memory; if (!pdb->GetProperty("leveldb.approximate-memory-usage", &memory)) { LogPrint(BCLog::LEVELDB, "Failed to get approximate-memory-usage property\n"); return 0; } return stoul(memory); } // Prefixed with null character to avoid collisions with other keys // // We must use a string constructor which specifies length so that we copy past // the null-terminator. const std::string CDBWrapper::OBFUSCATE_KEY_KEY("\000obfuscate_key", 14); const unsigned int CDBWrapper::OBFUSCATE_KEY_NUM_BYTES = 8; /** * Returns a string (consisting of 8 random bytes) suitable for use as an * obfuscating XOR key. */ std::vector CDBWrapper::CreateObfuscateKey() const { uint8_t buff[OBFUSCATE_KEY_NUM_BYTES]; GetRandBytes(buff, OBFUSCATE_KEY_NUM_BYTES); return std::vector(&buff[0], &buff[OBFUSCATE_KEY_NUM_BYTES]); } bool CDBWrapper::IsEmpty() { std::unique_ptr it(NewIterator()); it->SeekToFirst(); return !(it->Valid()); } CDBIterator::~CDBIterator() { delete piter; } bool CDBIterator::Valid() const { return piter->Valid(); } void CDBIterator::SeekToFirst() { piter->SeekToFirst(); } void CDBIterator::Next() { piter->Next(); } namespace dbwrapper_private { void HandleError(const leveldb::Status &status) { if (status.ok()) { return; } const std::string errmsg = "Fatal LevelDB error: " + status.ToString(); LogPrintf("%s\n", errmsg); LogPrintf("You can use -debug=leveldb to get more complete diagnostic " "messages\n"); throw dbwrapper_error(errmsg); } const std::vector &GetObfuscateKey(const CDBWrapper &w) { return w.obfuscate_key; } }; // namespace dbwrapper_private diff --git a/src/feerate.cpp b/src/feerate.cpp index 7966acfa9..12f189a3c 100644 --- a/src/feerate.cpp +++ b/src/feerate.cpp @@ -1,61 +1,60 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 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 CFeeRate::CFeeRate(const Amount nFeePaid, size_t nBytes_) { assert(nBytes_ <= uint64_t(std::numeric_limits::max())); int64_t nSize = int64_t(nBytes_); if (nSize > 0) { nSatoshisPerK = 1000 * nFeePaid / nSize; } else { nSatoshisPerK = Amount::zero(); } } template static Amount GetFee(size_t nBytes_, Amount nSatoshisPerK) { assert(nBytes_ <= uint64_t(std::numeric_limits::max())); int64_t nSize = int64_t(nBytes_); // Ensure fee is rounded up when truncated if ceil is true. Amount nFee = Amount::zero(); if (ceil) { nFee = Amount(nSize * nSatoshisPerK % 1000 > Amount::zero() ? nSize * nSatoshisPerK / 1000 + SATOSHI : nSize * nSatoshisPerK / 1000); } else { nFee = nSize * nSatoshisPerK / 1000; } if (nFee == Amount::zero() && nSize != 0) { if (nSatoshisPerK > Amount::zero()) { nFee = SATOSHI; } if (nSatoshisPerK < Amount::zero()) { nFee = -SATOSHI; } } return nFee; } Amount CFeeRate::GetFee(size_t nBytes) const { return ::GetFee(nBytes, nSatoshisPerK); } Amount CFeeRate::GetFeeCeiling(size_t nBytes) const { return ::GetFee(nBytes, nSatoshisPerK); } std::string CFeeRate::ToString() const { return strprintf("%d.%08d %s/kB", nSatoshisPerK / COIN, (nSatoshisPerK % COIN) / SATOSHI, CURRENCY_UNIT); } diff --git a/src/fs.cpp b/src/fs.cpp index da00d6d26..b788cf4ab 100644 --- a/src/fs.cpp +++ b/src/fs.cpp @@ -1,244 +1,243 @@ // Copyright (c) 2017 The Bitcoin Core developers // Copyright (c) 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 #ifndef WIN32 #include -#include #include #include #else #define NOMINMAX #include #include #endif namespace fsbridge { FILE *fopen(const fs::path &p, const char *mode) { return ::fopen(p.string().c_str(), mode); } #ifndef WIN32 static std::string GetErrorReason() { return std::strerror(errno); } FileLock::FileLock(const fs::path &file) { fd = open(file.string().c_str(), O_RDWR); if (fd == -1) { reason = GetErrorReason(); } } FileLock::~FileLock() { if (fd != -1) { close(fd); } } static bool IsWSL() { struct utsname uname_data; return uname(&uname_data) == 0 && std::string(uname_data.version).find("Microsoft") != std::string::npos; } bool FileLock::TryLock() { if (fd == -1) { return false; } // Exclusive file locking is broken on WSL using fcntl (issue #18622) // This workaround can be removed once the bug on WSL is fixed static const bool is_wsl = IsWSL(); if (is_wsl) { if (flock(fd, LOCK_EX | LOCK_NB) == -1) { reason = GetErrorReason(); return false; } } else { struct flock lock; lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; if (fcntl(fd, F_SETLK, &lock) == -1) { reason = GetErrorReason(); return false; } } return true; } #else static std::string GetErrorReason() { wchar_t *err; FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast(&err), 0, nullptr); std::wstring err_str(err); LocalFree(err); return std::wstring_convert>().to_bytes( err_str); } FileLock::FileLock(const fs::path &file) { hFile = CreateFileW(file.wstring().c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if (hFile == INVALID_HANDLE_VALUE) { reason = GetErrorReason(); } } FileLock::~FileLock() { if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); } } bool FileLock::TryLock() { if (hFile == INVALID_HANDLE_VALUE) { return false; } _OVERLAPPED overlapped = {0}; if (!LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, std::numeric_limits::max(), std::numeric_limits::max(), &overlapped)) { reason = GetErrorReason(); return false; } return true; } #endif std::string get_filesystem_error_message(const fs::filesystem_error &e) { #ifndef WIN32 return e.what(); #else // Convert from Multi Byte to utf-16 std::string mb_string(e.what()); int size = MultiByteToWideChar(CP_ACP, 0, mb_string.c_str(), mb_string.size(), nullptr, 0); std::wstring utf16_string(size, L'\0'); MultiByteToWideChar(CP_ACP, 0, mb_string.c_str(), mb_string.size(), &*utf16_string.begin(), size); // Convert from utf-16 to utf-8 return std::wstring_convert, wchar_t>() .to_bytes(utf16_string); #endif } #ifdef WIN32 #ifdef __GLIBCXX__ // reference: // https://github.com/gcc-mirror/gcc/blob/gcc-7_3_0-release/libstdc%2B%2B-v3/include/std/fstream#L270 static std::string openmodeToStr(std::ios_base::openmode mode) { switch (mode & ~std::ios_base::ate) { case std::ios_base::out: case std::ios_base::out | std::ios_base::trunc: return "w"; case std::ios_base::out | std::ios_base::app: case std::ios_base::app: return "a"; case std::ios_base::in: return "r"; case std::ios_base::in | std::ios_base::out: return "r+"; case std::ios_base::in | std::ios_base::out | std::ios_base::trunc: return "w+"; case std::ios_base::in | std::ios_base::out | std::ios_base::app: case std::ios_base::in | std::ios_base::app: return "a+"; case std::ios_base::out | std::ios_base::binary: case std::ios_base::out | std::ios_base::trunc | std::ios_base::binary: return "wb"; case std::ios_base::out | std::ios_base::app | std::ios_base::binary: case std::ios_base::app | std::ios_base::binary: return "ab"; case std::ios_base::in | std::ios_base::binary: return "rb"; case std::ios_base::in | std::ios_base::out | std::ios_base::binary: return "r+b"; case std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::binary: return "w+b"; case std::ios_base::in | std::ios_base::out | std::ios_base::app | std::ios_base::binary: case std::ios_base::in | std::ios_base::app | std::ios_base::binary: return "a+b"; default: return std::string(); } } void ifstream::open(const fs::path &p, std::ios_base::openmode mode) { close(); mode |= std::ios_base::in; m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str()); if (m_file == nullptr) { return; } m_filebuf = __gnu_cxx::stdio_filebuf(m_file, mode); rdbuf(&m_filebuf); if (mode & std::ios_base::ate) { seekg(0, std::ios_base::end); } } void ifstream::close() { if (m_file != nullptr) { m_filebuf.close(); fclose(m_file); } m_file = nullptr; } void ofstream::open(const fs::path &p, std::ios_base::openmode mode) { close(); mode |= std::ios_base::out; m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str()); if (m_file == nullptr) { return; } m_filebuf = __gnu_cxx::stdio_filebuf(m_file, mode); rdbuf(&m_filebuf); if (mode & std::ios_base::ate) { seekp(0, std::ios_base::end); } } void ofstream::close() { if (m_file != nullptr) { m_filebuf.close(); fclose(m_file); } m_file = nullptr; } #else // __GLIBCXX__ static_assert( sizeof(*fs::path().BOOST_FILESYSTEM_C_STR) == sizeof(wchar_t), "Warning: This build is using boost::filesystem ofstream and ifstream " "implementations which will fail to open paths containing multibyte " "characters. You should delete this static_assert to ignore this warning, " "or switch to a different C++ standard library like the Microsoft C++ " "Standard Library (where boost uses non-standard extensions to construct " "stream objects with wide filenames), or the GNU libstdc++ library (where " "a more complicated workaround has been implemented above)."); #endif // __GLIBCXX__ #endif // WIN32 } // namespace fsbridge diff --git a/src/hash.cpp b/src/hash.cpp index 4e2445a1e..6a22b583c 100644 --- a/src/hash.cpp +++ b/src/hash.cpp @@ -1,85 +1,84 @@ // Copyright (c) 2013-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 -#include #include inline uint32_t ROTL32(uint32_t x, int8_t r) { return (x << r) | (x >> (32 - r)); } uint32_t MurmurHash3(uint32_t nHashSeed, const std::vector &vDataToHash) { // The following is MurmurHash3 (x86_32), see // http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp uint32_t h1 = nHashSeed; const uint32_t c1 = 0xcc9e2d51; const uint32_t c2 = 0x1b873593; const int nblocks = vDataToHash.size() / 4; //---------- // body const uint8_t *blocks = vDataToHash.data(); for (int i = 0; i < nblocks; ++i) { uint32_t k1 = ReadLE32(blocks + i * 4); k1 *= c1; k1 = ROTL32(k1, 15); k1 *= c2; h1 ^= k1; h1 = ROTL32(h1, 13); h1 = h1 * 5 + 0xe6546b64; } //---------- // tail const uint8_t *tail = vDataToHash.data() + nblocks * 4; uint32_t k1 = 0; switch (vDataToHash.size() & 3) { case 3: k1 ^= tail[2] << 16; // FALLTHROUGH case 2: k1 ^= tail[1] << 8; // FALLTHROUGH case 1: k1 ^= tail[0]; k1 *= c1; k1 = ROTL32(k1, 15); k1 *= c2; h1 ^= k1; } //---------- // finalization h1 ^= vDataToHash.size(); h1 ^= h1 >> 16; h1 *= 0x85ebca6b; h1 ^= h1 >> 13; h1 *= 0xc2b2ae35; h1 ^= h1 >> 16; return h1; } void BIP32Hash(const ChainCode &chainCode, uint32_t nChild, uint8_t header, const uint8_t data[32], uint8_t output[64]) { uint8_t num[4]; num[0] = (nChild >> 24) & 0xFF; num[1] = (nChild >> 16) & 0xFF; num[2] = (nChild >> 8) & 0xFF; num[3] = (nChild >> 0) & 0xFF; CHMAC_SHA512(chainCode.begin(), chainCode.size()) .Write(&header, 1) .Write(data, 32) .Write(num, 4) .Finalize(output); } diff --git a/src/httprpc.cpp b/src/httprpc.cpp index bfabe9051..936f00b3b 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -1,491 +1,489 @@ // Copyright (c) 2015-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 #include #include #include -#include #include -#include #include #include #include #include #include #include // boost::trim #include #include #include #include #include #include #include /** WWW-Authenticate to present with 401 Unauthorized response */ static const char *WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\""; /** RPC auth failure delay to make brute-forcing expensive */ static const int64_t RPC_AUTH_BRUTE_FORCE_DELAY = 250; /** * Simple one-shot callback timer to be used by the RPC mechanism to e.g. * re-lock the wallet. */ class HTTPRPCTimer : public RPCTimerBase { public: HTTPRPCTimer(struct event_base *eventBase, std::function &func, int64_t millis) : ev(eventBase, false, func) { struct timeval tv; tv.tv_sec = millis / 1000; tv.tv_usec = (millis % 1000) * 1000; ev.trigger(&tv); } private: HTTPEvent ev; }; class HTTPRPCTimerInterface : public RPCTimerInterface { public: explicit HTTPRPCTimerInterface(struct event_base *_base) : base(_base) {} const char *Name() override { return "HTTP"; } RPCTimerBase *NewTimer(std::function &func, int64_t millis) override { return new HTTPRPCTimer(base, func, millis); } private: struct event_base *base; }; /* Pre-base64-encoded authentication token */ static std::string strRPCUserColonPass; /* Pre-base64-encoded authentication token */ static std::string strRPCCORSDomain; /* Stored RPC timer interface (for unregistration) */ static std::unique_ptr httpRPCTimerInterface; /* RPC Auth Whitelist */ static std::map> g_rpc_whitelist; static bool g_rpc_whitelist_default = false; static void JSONErrorReply(HTTPRequest *req, const UniValue &objError, const UniValue &id) { // Send error reply from json-rpc error object. int nStatus = HTTP_INTERNAL_SERVER_ERROR; int code = find_value(objError, "code").get_int(); if (code == RPC_INVALID_REQUEST) { nStatus = HTTP_BAD_REQUEST; } else if (code == RPC_METHOD_NOT_FOUND) { nStatus = HTTP_NOT_FOUND; } std::string strReply = JSONRPCReply(NullUniValue, objError, id); req->WriteHeader("Content-Type", "application/json"); req->WriteReply(nStatus, strReply); } /* * This function checks username and password against -rpcauth entries from * config file. */ static bool multiUserAuthorized(std::string strUserPass) { if (strUserPass.find(':') == std::string::npos) { return false; } std::string strUser = strUserPass.substr(0, strUserPass.find(':')); std::string strPass = strUserPass.substr(strUserPass.find(':') + 1); for (const std::string &strRPCAuth : gArgs.GetArgs("-rpcauth")) { // Search for multi-user login/pass "rpcauth" from config std::vector vFields; boost::split(vFields, strRPCAuth, boost::is_any_of(":$")); if (vFields.size() != 3) { // Incorrect formatting in config file continue; } std::string strName = vFields[0]; if (!TimingResistantEqual(strName, strUser)) { continue; } std::string strSalt = vFields[1]; std::string strHash = vFields[2]; static const unsigned int KEY_SIZE = 32; uint8_t out[KEY_SIZE]; CHMAC_SHA256(reinterpret_cast(strSalt.c_str()), strSalt.size()) .Write(reinterpret_cast(strPass.c_str()), strPass.size()) .Finalize(out); std::vector hexvec(out, out + KEY_SIZE); std::string strHashFromPass = HexStr(hexvec); if (TimingResistantEqual(strHashFromPass, strHash)) { return true; } } return false; } static bool RPCAuthorized(const std::string &strAuth, std::string &strAuthUsernameOut) { // Belt-and-suspenders measure if InitRPCAuthentication was not called. if (strRPCUserColonPass.empty()) { return false; } if (strAuth.substr(0, 6) != "Basic ") { return false; } std::string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64); std::string strUserPass = DecodeBase64(strUserPass64); if (strUserPass.find(':') != std::string::npos) { strAuthUsernameOut = strUserPass.substr(0, strUserPass.find(':')); } // Check if authorized under single-user field if (TimingResistantEqual(strUserPass, strRPCUserColonPass)) { return true; } return multiUserAuthorized(strUserPass); } static bool checkCORS(HTTPRequest *req) { // https://www.w3.org/TR/cors/#resource-requests // 1. If the Origin header is not present terminate this set of steps. // The request is outside the scope of this specification. std::pair origin = req->GetHeader("origin"); if (!origin.first) { return false; } // 2. If the value of the Origin header is not a case-sensitive match for // any of the values in list of origins do not set any additional headers // and terminate this set of steps. // Note: Always matching is acceptable since the list of origins can be // unbounded. if (origin.second != strRPCCORSDomain) { return false; } if (req->GetRequestMethod() == HTTPRequest::OPTIONS) { // 6.2 Preflight Request // In response to a preflight request the resource indicates which // methods and headers (other than simple methods and simple // headers) it is willing to handle and whether it supports // credentials. // Resources must use the following set of steps to determine which // additional headers to use in the response: // 3. Let method be the value as result of parsing the // Access-Control-Request-Method header. // If there is no Access-Control-Request-Method header or if parsing // failed, do not set any additional headers and terminate this set // of steps. The request is outside the scope of this specification. std::pair method = req->GetHeader("access-control-request-method"); if (!method.first) { return false; } // 4. Let header field-names be the values as result of parsing // the Access-Control-Request-Headers headers. // If there are no Access-Control-Request-Headers headers let header // field-names be the empty list. // If parsing failed do not set any additional headers and terminate // this set of steps. The request is outside the scope of this // specification. std::pair header_field_names = req->GetHeader("access-control-request-headers"); // 5. If method is not a case-sensitive match for any of the // values in list of methods do not set any additional headers // and terminate this set of steps. // Note: Always matching is acceptable since the list of methods // can be unbounded. if (method.second != "POST") { return false; } // 6. If any of the header field-names is not a ASCII case- // insensitive match for any of the values in list of headers do not // set any additional headers and terminate this set of steps. // Note: Always matching is acceptable since the list of headers can // be unbounded. const std::string &list_of_headers = "authorization,content-type"; // 7. If the resource supports credentials add a single // Access-Control-Allow-Origin header, with the value of the Origin // header as value, and add a single // Access-Control-Allow-Credentials header with the case-sensitive // string "true" as value. req->WriteHeader("Access-Control-Allow-Origin", origin.second); req->WriteHeader("Access-Control-Allow-Credentials", "true"); // 8. Optionally add a single Access-Control-Max-Age header with as // value the amount of seconds the user agent is allowed to cache // the result of the request. // 9. If method is a simple method this step may be skipped. // Add one or more Access-Control-Allow-Methods headers consisting // of (a subset of) the list of methods. // If a method is a simple method it does not need to be listed, but // this is not prohibited. // Note: Since the list of methods can be unbounded, simply // returning the method indicated by // Access-Control-Request-Method (if supported) can be enough. req->WriteHeader("Access-Control-Allow-Methods", method.second); // 10. If each of the header field-names is a simple header and none // is Content-Type, this step may be skipped. // Add one or more Access-Control-Allow-Headers headers consisting // of (a subset of) the list of headers. req->WriteHeader("Access-Control-Allow-Headers", header_field_names.first ? header_field_names.second : list_of_headers); req->WriteReply(HTTP_OK); return true; } // 6.1 Simple Cross-Origin Request, Actual Request, and Redirects // In response to a simple cross-origin request or actual request the // resource indicates whether or not to share the response. // If the resource has been relocated, it indicates whether to share its // new URL. // Resources must use the following set of steps to determine which // additional headers to use in the response: // 3. If the resource supports credentials add a single // Access-Control-Allow-Origin header, with the value of the Origin // header as value, and add a single Access-Control-Allow-Credentials // header with the case-sensitive string "true" as value. req->WriteHeader("Access-Control-Allow-Origin", origin.second); req->WriteHeader("Access-Control-Allow-Credentials", "true"); // 4. If the list of exposed headers is not empty add one or more // Access-Control-Expose-Headers headers, with as values the header // field names given in the list of exposed headers. req->WriteHeader("Access-Control-Expose-Headers", "WWW-Authenticate"); return false; } bool HTTPRPCRequestProcessor::ProcessHTTPRequest(HTTPRequest *req) { // First, check and/or set CORS headers if (checkCORS(req)) { return true; } // JSONRPC handles only POST if (req->GetRequestMethod() != HTTPRequest::POST) { req->WriteReply(HTTP_BAD_METHOD, "JSONRPC server handles only POST requests"); return false; } // Check authorization std::pair authHeader = req->GetHeader("authorization"); if (!authHeader.first) { req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA); req->WriteReply(HTTP_UNAUTHORIZED); return false; } JSONRPCRequest jreq; jreq.peerAddr = req->GetPeer().ToString(); if (!RPCAuthorized(authHeader.second, jreq.authUser)) { LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", jreq.peerAddr); /** * Deter brute-forcing. * If this results in a DoS the user really shouldn't have their RPC * port exposed. */ UninterruptibleSleep( std::chrono::milliseconds{RPC_AUTH_BRUTE_FORCE_DELAY}); req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA); req->WriteReply(HTTP_UNAUTHORIZED); return false; } try { // Parse request UniValue valRequest; if (!valRequest.read(req->ReadBody())) { throw JSONRPCError(RPC_PARSE_ERROR, "Parse error"); } // Set the URI jreq.URI = req->GetURI(); std::string strReply; bool user_has_whitelist = g_rpc_whitelist.count(jreq.authUser); if (!user_has_whitelist && g_rpc_whitelist_default) { LogPrintf("RPC User %s not allowed to call any methods\n", jreq.authUser); req->WriteReply(HTTP_FORBIDDEN); return false; // singleton request } else if (valRequest.isObject()) { jreq.parse(valRequest); if (user_has_whitelist && !g_rpc_whitelist[jreq.authUser].count(jreq.strMethod)) { LogPrintf("RPC User %s not allowed to call method %s\n", jreq.authUser, jreq.strMethod); req->WriteReply(HTTP_FORBIDDEN); return false; } UniValue result = rpcServer.ExecuteCommand(config, jreq); // Send reply strReply = JSONRPCReply(result, NullUniValue, jreq.id); // array of requests } else if (valRequest.isArray()) { if (user_has_whitelist) { for (unsigned int reqIdx = 0; reqIdx < valRequest.size(); reqIdx++) { if (!valRequest[reqIdx].isObject()) { throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object"); } else { const UniValue &request = valRequest[reqIdx].get_obj(); // Parse method std::string strMethod = find_value(request, "method").get_str(); if (!g_rpc_whitelist[jreq.authUser].count(strMethod)) { LogPrintf( "RPC User %s not allowed to call method %s\n", jreq.authUser, strMethod); req->WriteReply(HTTP_FORBIDDEN); return false; } } } } strReply = JSONRPCExecBatch(config, rpcServer, jreq, valRequest.get_array()); } else { throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error"); } req->WriteHeader("Content-Type", "application/json"); req->WriteReply(HTTP_OK, strReply); } catch (const UniValue &objError) { JSONErrorReply(req, objError, jreq.id); return false; } catch (const std::exception &e) { JSONErrorReply(req, JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id); return false; } return true; } static bool InitRPCAuthentication() { if (gArgs.GetArg("-rpcpassword", "") == "") { LogPrintf("No rpcpassword set - using random cookie authentication.\n"); if (!GenerateAuthCookie(&strRPCUserColonPass)) { // Same message as AbortNode. uiInterface.ThreadSafeMessageBox( _("Error: A fatal internal error occurred, see debug.log for " "details") .translated, "", CClientUIInterface::MSG_ERROR); return false; } } else { LogPrintf("Config options rpcuser and rpcpassword will soon be " "deprecated. Locally-run instances may remove rpcuser to use " "cookie-based auth, or may be replaced with rpcauth. Please " "see share/rpcauth for rpcauth auth generation.\n"); strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", ""); } strRPCCORSDomain = gArgs.GetArg("-rpccorsdomain", ""); if (gArgs.GetArg("-rpcauth", "") != "") { LogPrintf("Using rpcauth authentication.\n"); } g_rpc_whitelist_default = gArgs.GetBoolArg("-rpcwhitelistdefault", gArgs.IsArgSet("-rpcwhitelist")); for (const std::string &strRPCWhitelist : gArgs.GetArgs("-rpcwhitelist")) { auto pos = strRPCWhitelist.find(':'); std::string strUser = strRPCWhitelist.substr(0, pos); bool intersect = g_rpc_whitelist.count(strUser); std::set &whitelist = g_rpc_whitelist[strUser]; if (pos != std::string::npos) { std::string strWhitelist = strRPCWhitelist.substr(pos + 1); std::set new_whitelist; boost::split(new_whitelist, strWhitelist, boost::is_any_of(", ")); if (intersect) { std::set tmp_whitelist; std::set_intersection( new_whitelist.begin(), new_whitelist.end(), whitelist.begin(), whitelist.end(), std::inserter(tmp_whitelist, tmp_whitelist.end())); new_whitelist = std::move(tmp_whitelist); } whitelist = std::move(new_whitelist); } } return true; } bool StartHTTPRPC(HTTPRPCRequestProcessor &httpRPCRequestProcessor) { LogPrint(BCLog::RPC, "Starting HTTP RPC server\n"); if (!InitRPCAuthentication()) { return false; } const std::function &rpcFunction = std::bind(&HTTPRPCRequestProcessor::DelegateHTTPRequest, &httpRPCRequestProcessor, std::placeholders::_2); RegisterHTTPHandler("/", true, rpcFunction); if (g_wallet_init_interface.HasWalletSupport()) { RegisterHTTPHandler("/wallet/", false, rpcFunction); } struct event_base *eventBase = EventBase(); assert(eventBase); httpRPCTimerInterface = std::make_unique(eventBase); RPCSetTimerInterface(httpRPCTimerInterface.get()); return true; } void InterruptHTTPRPC() { LogPrint(BCLog::RPC, "Interrupting HTTP RPC server\n"); } void StopHTTPRPC() { LogPrint(BCLog::RPC, "Stopping HTTP RPC server\n"); UnregisterHTTPHandler("/", true); if (g_wallet_init_interface.HasWalletSupport()) { UnregisterHTTPHandler("/wallet/", false); } if (httpRPCTimerInterface) { RPCUnsetTimerInterface(httpRPCTimerInterface.get()); httpRPCTimerInterface.reset(); } } diff --git a/src/init.cpp b/src/init.cpp index 0e320d176..20d061f1b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1,2802 +1,2800 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2018 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #if defined(HAVE_CONFIG_H) #include #endif #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 #include #include #include