diff options
Diffstat (limited to 'src/test')
| -rw-r--r-- | src/test/auxpow_tests.cpp | 591 | ||||
| -rw-r--r-- | src/test/coins_tests.cpp | 9 | ||||
| -rw-r--r-- | src/test/dogecoin_tests.cpp | 95 | ||||
| -rw-r--r-- | src/test/merkle_tests.cpp | 2 | ||||
| -rw-r--r-- | src/test/test_bitcoin.cpp | 9 | ||||
| -rw-r--r-- | src/test/test_bitcoin.h | 8 |
6 files changed, 701 insertions, 13 deletions
diff --git a/src/test/auxpow_tests.cpp b/src/test/auxpow_tests.cpp new file mode 100644 index 000000000..6447ef9fd --- /dev/null +++ b/src/test/auxpow_tests.cpp @@ -0,0 +1,591 @@ +// Copyright (c) 2014-2018 Daniel Kraft +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <arith_uint256.h> +#include <auxpow.h> +#include <chainparams.h> +#include <coins.h> +#include <consensus/merkle.h> +#include <dogecoin.h> +#include <validation.h> +#include <pow.h> +#include <primitives/block.h> +#include <rpc/auxpow_miner.h> +#include <script/script.h> +#include <utilstrencodings.h> +#include <utiltime.h> +#include <uint256.h> +#include <univalue.h> + +#include <test/test_bitcoin.h> + +#include <boost/test/unit_test.hpp> + +#include <algorithm> +#include <vector> + +/* No space between BOOST_AUTO_TEST_SUITE and '(', so that extraction of + the test-suite name works with grep as done in the Makefile. */ +BOOST_AUTO_TEST_SUITE(auxpow_tests) + +/* ************************************************************************** */ + +/** + * Tamper with a uint256 (modify it). + * @param num The number to modify. + */ +static void +tamperWith(uint256& num) +{ + arith_uint256 modifiable = UintToArith256(num); + modifiable += 1; + num = ArithToUint256(modifiable); +} + +/** + * Helper class that is friend to CAuxPow and makes the internals accessible + * to the test code. + */ +class CAuxPowForTest : public CAuxPow +{ + +public: + + explicit inline CAuxPowForTest (CTransactionRef txIn) + : CAuxPow (txIn) + {} + + using CAuxPow::coinbaseTx; + using CAuxPow::vChainMerkleBranch; + using CAuxPow::nChainIndex; + using CAuxPow::parentBlock; + + using CAuxPow::CheckMerkleBranch; + +}; + +/** + * Utility class to construct auxpow's and manipulate them. This is used + * to simulate various scenarios. + */ +class CAuxpowBuilder +{ +public: + + /** The parent block (with coinbase, not just header). */ + CBlock parentBlock; + + /** The auxpow's merkle branch (connecting it to the coinbase). */ + std::vector<uint256> auxpowChainMerkleBranch; + /** The auxpow's merkle tree index. */ + int auxpowChainIndex; + + /** + * Initialise everything. + * @param baseVersion The parent block's base version to use. + * @param chainId The parent block's chain ID to use. + */ + CAuxpowBuilder(int baseVersion, int chainId); + + /** + * Set the coinbase's script. + * @param scr Set it to this script. + */ + void setCoinbase(const CScript& scr); + + /** + * Build the auxpow merkle branch. The member variables will be + * set accordingly. This has to be done before constructing the coinbase + * itself (which must contain the root merkle hash). When we have the + * coinbase afterwards, the member variables can be used to initialise + * the CAuxPow object from it. + * @param hashAux The merge-mined chain's block hash. + * @param h Height of the merkle tree to build. + * @param index Index to use in the merkle tree. + * @return The root hash, with reversed endian. + */ + std::vector<unsigned char> buildAuxpowChain(const uint256& hashAux, unsigned h, int index); + + /** + * Build the finished CAuxPow object. We assume that the auxpowChain + * member variables are already set. We use the passed in transaction + * as the base. It should (probably) be the parent block's coinbase. + * @param tx The base tx to use. + * @return The constructed CAuxPow object. + */ + CAuxPow get(const CTransactionRef tx) const; + + /** + * Build the finished CAuxPow object from the parent block's coinbase. + * @return The constructed CAuxPow object. + */ + inline CAuxPow + get() const + { + assert(!parentBlock.vtx.empty()); + return get(parentBlock.vtx[0]); + } + + /** + * Returns the finished CAuxPow object and returns it as std::unique_ptr. + */ + inline std::unique_ptr<CAuxPow> + getUnique () const + { + return std::unique_ptr<CAuxPow>(new CAuxPow (get ())); + } + + /** + * Build a data vector to be included in the coinbase. It consists + * of the aux hash, the merkle tree size and the nonce. Optionally, + * the header can be added as well. + * @param header Add the header? + * @param hashAux The aux merkle root hash. + * @param h Height of the merkle tree. + * @param nonce The nonce value to use. + * @return The constructed data. + */ + static std::vector<unsigned char> buildCoinbaseData (bool header, const std::vector<unsigned char>& auxRoot, + unsigned h, int nonce); + +}; + +CAuxpowBuilder::CAuxpowBuilder(int baseVersion, int chainId) + : auxpowChainIndex(-1) +{ + parentBlock.SetBaseVersion(baseVersion, chainId); +} + +void +CAuxpowBuilder::setCoinbase (const CScript& scr) +{ + CMutableTransaction mtx; + mtx.vin.resize(1); + mtx.vin[0].prevout.SetNull(); + mtx.vin[0].scriptSig = scr; + + parentBlock.vtx.clear(); + parentBlock.vtx.push_back(MakeTransactionRef(std::move(mtx))); + parentBlock.hashMerkleRoot = BlockMerkleRoot(parentBlock); +} + +std::vector<unsigned char> +CAuxpowBuilder::buildAuxpowChain(const uint256& hashAux, unsigned h, int index) +{ + auxpowChainIndex = index; + + /* Just use "something" for the branch. Doesn't really matter. */ + auxpowChainMerkleBranch.clear(); + for (unsigned i = 0; i < h; ++i) + auxpowChainMerkleBranch.push_back(ArithToUint256(arith_uint256(i))); + + const uint256 hash + = CAuxPowForTest::CheckMerkleBranch (hashAux, auxpowChainMerkleBranch, + index); + + std::vector<unsigned char> res = ToByteVector(hash); + std::reverse(res.begin(), res.end()); + + return res; +} + +CAuxPow +CAuxpowBuilder::get(const CTransactionRef tx) const +{ + LOCK(cs_main); + + CAuxPowForTest res(tx); + res.coinbaseTx.hashBlock = parentBlock.GetHash (); + res.coinbaseTx.nIndex = 0; + res.coinbaseTx.vMerkleBranch + = merkle_tests::BlockMerkleBranch (parentBlock, res.coinbaseTx.nIndex); + + res.vChainMerkleBranch = auxpowChainMerkleBranch; + res.nChainIndex = auxpowChainIndex; + res.parentBlock = parentBlock; + + return res; +} + +std::vector<unsigned char> +CAuxpowBuilder::buildCoinbaseData (bool header, const std::vector<unsigned char>& auxRoot, + unsigned h, int nonce) +{ + std::vector<unsigned char> res; + + if (header) + res.insert(res.end(), UBEGIN(pchMergedMiningHeader), + UEND(pchMergedMiningHeader)); + res.insert(res.end(), auxRoot.begin(), auxRoot.end()); + + const int size = (1 << h); + res.insert(res.end(), UBEGIN(size), UEND(size)); + res.insert(res.end(), UBEGIN(nonce), UEND(nonce)); + + return res; +} + +/* ************************************************************************** */ + +BOOST_FIXTURE_TEST_CASE (check_auxpow, BasicTestingSetup) +{ + const Consensus::Params& params = Params().GetConsensus(); + CAuxpowBuilder builder(5, 42); + CAuxPow auxpow; + + const uint256 hashAux = ArithToUint256(arith_uint256(12345)); + const int32_t ourChainId = params.nAuxpowChainId; + const unsigned height = 30; + const int nonce = 7; + int index; + + std::vector<unsigned char> auxRoot, data; + CScript scr; + + /* Build a correct auxpow. The height is the maximally allowed one. */ + index = CAuxPow::getExpectedIndex(nonce, ourChainId, height); + auxRoot = builder.buildAuxpowChain(hashAux, height, index); + data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height, nonce); + scr = (CScript() << 2809 << 2013) + COINBASE_FLAGS; + scr = (scr << OP_2 << data); + builder.setCoinbase(scr); + BOOST_CHECK(builder.get().check(hashAux, ourChainId, params)); + + /* Check that the auxpow is invalid if we change either the aux block's + hash or the chain ID. */ + uint256 modifiedAux(hashAux); + tamperWith(modifiedAux); + BOOST_CHECK(!builder.get().check(modifiedAux, ourChainId, params)); + BOOST_CHECK(!builder.get().check(hashAux, ourChainId + 1, params)); + + /* Non-coinbase parent tx should fail. Note that we can't just copy + the coinbase literally, as we have to get a tx with different hash. */ + const CTransactionRef oldCoinbase = builder.parentBlock.vtx[0]; + builder.setCoinbase(scr << 5); + builder.parentBlock.vtx.push_back(oldCoinbase); + builder.parentBlock.hashMerkleRoot = BlockMerkleRoot(builder.parentBlock); + auxpow = builder.get(builder.parentBlock.vtx[0]); + BOOST_CHECK(auxpow.check(hashAux, ourChainId, params)); + auxpow = builder.get(builder.parentBlock.vtx[1]); + BOOST_CHECK(!auxpow.check(hashAux, ourChainId, params)); + + /* The parent chain can't have the same chain ID. */ + CAuxpowBuilder builder2(builder); + builder2.parentBlock.SetChainId(100); + BOOST_CHECK(builder2.get().check(hashAux, ourChainId, params)); + builder2.parentBlock.SetChainId(ourChainId); + BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params)); + + /* Disallow too long merkle branches. */ + builder2 = builder; + index = CAuxPow::getExpectedIndex(nonce, ourChainId, height + 1); + auxRoot = builder2.buildAuxpowChain(hashAux, height + 1, index); + data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height + 1, nonce); + scr = (CScript() << 2809 << 2013) + COINBASE_FLAGS; + scr = (scr << OP_2 << data); + builder2.setCoinbase(scr); + BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params)); + + /* Verify that we compare correctly to the parent block's merkle root. */ + builder2 = builder; + BOOST_CHECK(builder2.get().check(hashAux, ourChainId, params)); + tamperWith(builder2.parentBlock.hashMerkleRoot); + BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params)); + + /* Build a non-header legacy version and check that it is also accepted. */ + builder2 = builder; + index = CAuxPow::getExpectedIndex(nonce, ourChainId, height); + auxRoot = builder2.buildAuxpowChain(hashAux, height, index); + data = CAuxpowBuilder::buildCoinbaseData(false, auxRoot, height, nonce); + scr = (CScript() << 2809 << 2013) + COINBASE_FLAGS; + scr = (scr << OP_2 << data); + builder2.setCoinbase(scr); + BOOST_CHECK(builder2.get().check(hashAux, ourChainId, params)); + + /* However, various attempts at smuggling two roots in should be detected. */ + + const std::vector<unsigned char> wrongAuxRoot + = builder2.buildAuxpowChain (modifiedAux, height, index); + std::vector<unsigned char> data2 + = CAuxpowBuilder::buildCoinbaseData (false, wrongAuxRoot, height, nonce); + builder2.setCoinbase(CScript() << data << data2); + BOOST_CHECK(builder2.get().check(hashAux, ourChainId, params)); + builder2.setCoinbase(CScript() << data2 << data); + BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params)); + + data2 = CAuxpowBuilder::buildCoinbaseData(true, wrongAuxRoot, height, nonce); + builder2.setCoinbase(CScript() << data << data2); + BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params)); + builder2.setCoinbase(CScript() << data2 << data); + BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params)); + + data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height, nonce); + builder2.setCoinbase(CScript() << data << data2); + BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params)); + builder2.setCoinbase(CScript() << data2 << data); + BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params)); + + data2 = CAuxpowBuilder::buildCoinbaseData(false, wrongAuxRoot, + height, nonce); + builder2.setCoinbase(CScript() << data << data2); + BOOST_CHECK(builder2.get().check(hashAux, ourChainId, params)); + builder2.setCoinbase(CScript() << data2 << data); + BOOST_CHECK(builder2.get().check(hashAux, ourChainId, params)); + + /* Verify that the appended nonce/size values are checked correctly. */ + + data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height, nonce); + builder2.setCoinbase(CScript() << data); + BOOST_CHECK(builder2.get().check(hashAux, ourChainId, params)); + + data.pop_back(); + builder2.setCoinbase(CScript() << data); + BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params)); + + data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height - 1, nonce); + builder2.setCoinbase(CScript() << data); + BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params)); + + data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height, nonce + 3); + builder2.setCoinbase(CScript() << data); + BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params)); + + /* Put the aux hash in an invalid merkle tree position. */ + + auxRoot = builder.buildAuxpowChain(hashAux, height, index + 1); + data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height, nonce); + builder2.setCoinbase(CScript() << data); + BOOST_CHECK(!builder2.get().check(hashAux, ourChainId, params)); + + auxRoot = builder.buildAuxpowChain(hashAux, height, index); + data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height, nonce); + builder2.setCoinbase(CScript() << data); + BOOST_CHECK(builder2.get().check(hashAux, ourChainId, params)); +} + +/* ************************************************************************** */ + +/** + * Mine a block (assuming minimal difficulty) that either matches + * or doesn't match the difficulty target specified in the block header. + * @param block The block to mine (by updating nonce). + * @param ok Whether the block should be ok for PoW. + * @param nBits Use this as difficulty if specified. + */ +static void +mineBlock(CBlockHeader& block, bool ok, int nBits = -1) +{ + if (nBits == -1) + nBits = block.nBits; + + arith_uint256 target; + target.SetCompact(nBits); + + block.nNonce = 0; + while (true) + { + const bool nowOk = (UintToArith256(block.GetHash()) <= target); + if ((ok && nowOk) || (!ok && !nowOk)) + break; + + ++block.nNonce; + } + + if (ok) + BOOST_CHECK(CheckProofOfWork(block.GetHash(), nBits, Params().GetConsensus())); + else + BOOST_CHECK(!CheckProofOfWork(block.GetHash(), nBits, Params().GetConsensus())); +} + +BOOST_FIXTURE_TEST_CASE (auxpow_pow, BasicTestingSetup) +{ + /* Use regtest parameters to allow mining with easy difficulty. */ + SelectParams(CBaseChainParams::REGTEST); + const Consensus::Params& params = Params().GetConsensus(); + + const arith_uint256 target = (~arith_uint256(0) >> 1); + CBlockHeader block; + block.nBits = target.GetCompact(); + + /* Verify the block version checks. */ + + block.nVersion = 1; + mineBlock(block, true); + BOOST_CHECK(CheckAuxPowProofOfWork(block, params)); + + // Dogecoin block version 2 can be both AuxPoW and regular, so test 3 + + block.nVersion = 3; + mineBlock(block, true); + BOOST_CHECK(!CheckAuxPowProofOfWork(block, params)); + + block.SetBaseVersion(2, params.nAuxpowChainId); + mineBlock(block, true); + BOOST_CHECK(CheckAuxPowProofOfWork(block, params)); + + block.SetChainId(params.nAuxpowChainId + 1); + mineBlock(block, true); + BOOST_CHECK(!CheckAuxPowProofOfWork(block, params)); + + /* Check the case when the block does not have auxpow (this is true + right now). */ + + block.SetChainId(params.nAuxpowChainId); + block.SetAuxpowFlag(true); + mineBlock(block, true); + BOOST_CHECK(!CheckAuxPowProofOfWork(block, params)); + + block.SetAuxpowFlag(false); + mineBlock(block, true); + BOOST_CHECK(CheckAuxPowProofOfWork(block, params)); + mineBlock(block, false); + BOOST_CHECK(!CheckAuxPowProofOfWork(block, params)); + + /* ****************************************** */ + /* Check the case that the block has auxpow. */ + + CAuxpowBuilder builder(5, 42); + CAuxPow auxpow; + const int32_t ourChainId = params.nAuxpowChainId; + const unsigned height = 3; + const int nonce = 7; + const int index = CAuxPow::getExpectedIndex(nonce, ourChainId, height); + std::vector<unsigned char> auxRoot, data; + + /* Valid auxpow, PoW check of parent block. */ + block.SetAuxpowFlag(true); + auxRoot = builder.buildAuxpowChain(block.GetHash(), height, index); + data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height, nonce); + builder.setCoinbase(CScript() << data); + mineBlock(builder.parentBlock, false, block.nBits); + block.SetAuxpow (builder.getUnique ()); + BOOST_CHECK (!CheckAuxPowProofOfWork (block, params)); + mineBlock(builder.parentBlock, true, block.nBits); + block.SetAuxpow (builder.getUnique ()); + BOOST_CHECK (CheckAuxPowProofOfWork (block, params)); + + /* Mismatch between auxpow being present and block.nVersion. Note that + block.SetAuxpow sets also the version and that we want to ensure + that the block hash itself doesn't change due to version changes. + This requires some work arounds. */ + block.SetAuxpowFlag(false); + const uint256 hashAux = block.GetHash(); + auxRoot = builder.buildAuxpowChain(hashAux, height, index); + data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height, nonce); + builder.setCoinbase(CScript() << data); + mineBlock(builder.parentBlock, true, block.nBits); + block.SetAuxpow (builder.getUnique ()); + BOOST_CHECK(hashAux != block.GetHash()); + block.SetAuxpowFlag(false); + BOOST_CHECK(hashAux == block.GetHash()); + BOOST_CHECK(!CheckAuxPowProofOfWork(block, params)); + + /* Modifying the block invalidates the PoW. */ + block.SetAuxpowFlag(true); + auxRoot = builder.buildAuxpowChain(block.GetHash(), height, index); + data = CAuxpowBuilder::buildCoinbaseData(true, auxRoot, height, nonce); + builder.setCoinbase(CScript() << data); + mineBlock(builder.parentBlock, true, block.nBits); + block.SetAuxpow (builder.getUnique ()); + BOOST_CHECK (CheckAuxPowProofOfWork (block, params)); + tamperWith(block.hashMerkleRoot); + BOOST_CHECK (!CheckAuxPowProofOfWork (block, params)); +} + +/* ************************************************************************** */ + +/** + * Helper class that is friend to AuxpowMiner and makes the tested methods + * accessible to the test code. + */ +class AuxpowMinerForTest : public AuxpowMiner +{ + +public: + + using AuxpowMiner::cs; + + using AuxpowMiner::getCurrentBlock; + using AuxpowMiner::lookupSavedBlock; + +}; + +BOOST_FIXTURE_TEST_CASE (auxpow_miner_blockRegeneration, TestChain240Setup) +{ + AuxpowMinerForTest miner; + LOCK (miner.cs); + + /* We use mocktime so that we can control GetTime() as it is used in the + logic that determines whether or not to reconstruct a block. The "base" + time is set such that the blocks we have from the fixture are fresh. */ + const int64_t baseTime = chainActive.Tip ()->GetMedianTimePast () + 1; + SetMockTime (baseTime); + + /* Construct a first block. */ + CScript scriptPubKey; + uint256 target; + const CBlock* pblock1 = miner.getCurrentBlock (scriptPubKey, target); + BOOST_CHECK (pblock1 != nullptr); + const uint256 hash1 = pblock1->GetHash (); + + /* Verify target computation. */ + arith_uint256 expected; + expected.SetCompact (pblock1->nBits); + BOOST_CHECK (target == ArithToUint256 (expected)); + + /* Calling the method again should return the same, cached block a second + time (even if we advance the clock, since there are no new + transactions). */ + SetMockTime (baseTime + 240); + const CBlock* pblock = miner.getCurrentBlock (scriptPubKey, target); + BOOST_CHECK (pblock == pblock1 && pblock->GetHash () == hash1); + + /* Mine a block, then we should get a new auxpow block constructed. Note that + it can be the same *pointer* if the memory was reused after clearing it, + so we can only verify that the hash is different. */ + CreateAndProcessBlock ({}, scriptPubKey); + const CBlock* pblock2 = miner.getCurrentBlock (scriptPubKey, target); + BOOST_CHECK (pblock2 != nullptr); + const uint256 hash2 = pblock2->GetHash (); + BOOST_CHECK (hash2 != hash1); + + /* Add a new transaction to the mempool. */ + TestMemPoolEntryHelper entry; + CMutableTransaction mtx; + mtx.vout.emplace_back (1234, scriptPubKey); + { + LOCK (mempool.cs); + mempool.addUnchecked (mtx.GetHash (), entry.FromTx (mtx)); + } + + /* We should still get back the cached block, for now. */ + SetMockTime (baseTime + 300); + pblock = miner.getCurrentBlock (scriptPubKey, target); + BOOST_CHECK (pblock == pblock2 && pblock->GetHash () == hash2); + + /* With time advanced too far, we get a new block. This time, we should also + definitely get a different pointer, as there is no clearing. The old + blocks are freed only after a new tip is found. */ + SetMockTime (baseTime + 301); + const CBlock* pblock3 = miner.getCurrentBlock (scriptPubKey, target); + BOOST_CHECK (pblock3 != pblock2 && pblock3->GetHash () != hash2); +} + +BOOST_FIXTURE_TEST_CASE (auxpow_miner_createAndLookupBlock, TestChain240Setup) +{ + AuxpowMinerForTest miner; + LOCK (miner.cs); + + CScript scriptPubKey; + uint256 target; + const CBlock* pblock = miner.getCurrentBlock (scriptPubKey, target); + BOOST_CHECK (pblock != nullptr); + + BOOST_CHECK (miner.lookupSavedBlock (pblock->GetHash ().GetHex ()) == pblock); + BOOST_CHECK_THROW (miner.lookupSavedBlock ("foobar"), UniValue); +} + +/* ************************************************************************** */ + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 63b91b74c..0eb5b90da 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -21,15 +21,6 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txund namespace { -//! equality test -bool operator==(const Coin &a, const Coin &b) { - // Empty Coin objects are always equal. - if (a.IsSpent() && b.IsSpent()) return true; - return a.fCoinBase == b.fCoinBase && - a.nHeight == b.nHeight && - a.out == b.out; -} - class CCoinsViewTest : public CCoinsView { uint256 hashBestBlock_; diff --git a/src/test/dogecoin_tests.cpp b/src/test/dogecoin_tests.cpp index f1d60f709..b5d7716d5 100644 --- a/src/test/dogecoin_tests.cpp +++ b/src/test/dogecoin_tests.cpp @@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(subsidy_limit_test) CAmount nSubsidy = GetDogecoinBlockSubsidy(nHeight, params, prevHash); CAmount nExpectedSubsidy = (500000 >> (nHeight / 100000)) * COIN; BOOST_CHECK(MoneyRange(nSubsidy)); - BOOST_CHECK(nSubsidy == nExpectedSubsidy); + BOOST_CHECK_EQUAL(nSubsidy, nExpectedSubsidy); nSum += nSubsidy * nStepSize; } @@ -96,10 +96,99 @@ BOOST_AUTO_TEST_CASE(subsidy_limit_test) // Test reward at 600k+ is constant CAmount nConstantSubsidy = GetDogecoinBlockSubsidy(600000, params, prevHash); - BOOST_CHECK(nConstantSubsidy == 10000 * COIN); + BOOST_CHECK_EQUAL(nConstantSubsidy, 10000 * COIN); nConstantSubsidy = GetDogecoinBlockSubsidy(700000, params, prevHash); - BOOST_CHECK(nConstantSubsidy == 10000 * COIN); + BOOST_CHECK_EQUAL(nConstantSubsidy, 10000 * COIN); +} + +BOOST_AUTO_TEST_CASE(get_next_work_difficulty_limit) +{ + SelectParams(CBaseChainParams::MAIN); + const Consensus::Params& params = Params().GetConsensus(); + + CBlockIndex pindexLast; + int64_t nLastRetargetTime = 1386474927; // Block # 1 + + pindexLast.nHeight = 239; + pindexLast.nTime = 1386475638; // Block #239 + pindexLast.nBits = 0x1e0ffff0; + BOOST_CHECK_EQUAL(CalculateDogecoinNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1e00ffff); +} + +BOOST_AUTO_TEST_CASE(get_next_work_pre_digishield) +{ + SelectParams(CBaseChainParams::MAIN); + const Consensus::Params& params = Params().GetConsensus(); + + CBlockIndex pindexLast; + int64_t nLastRetargetTime = 1386942008; // Block 9359 + + pindexLast.nHeight = 9599; + pindexLast.nTime = 1386954113; + pindexLast.nBits = 0x1c1a1206; + BOOST_CHECK_EQUAL(CalculateDogecoinNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1c15ea59); +} + +BOOST_AUTO_TEST_CASE(get_next_work_digishield) +{ + SelectParams(CBaseChainParams::MAIN); + const Consensus::Params& params = Params().GetConsensus(); + + CBlockIndex pindexLast; + int64_t nLastRetargetTime = 1395094427; + + // First hard-fork at 145,000, which applies to block 145,001 onwards + pindexLast.nHeight = 145000; + pindexLast.nTime = 1395094679; + pindexLast.nBits = 0x1b499dfd; + BOOST_CHECK_EQUAL(CalculateDogecoinNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1b671062); +} + +BOOST_AUTO_TEST_CASE(get_next_work_digishield_modulated_upper) +{ + SelectParams(CBaseChainParams::MAIN); + const Consensus::Params& params = Params().GetConsensus(); + + CBlockIndex pindexLast; + int64_t nLastRetargetTime = 1395100835; + + // Test the upper bound on modulated time using mainnet block #145,107 + pindexLast.nHeight = 145107; + pindexLast.nTime = 1395101360; + pindexLast.nBits = 0x1b3439cd; + BOOST_CHECK_EQUAL(CalculateDogecoinNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1b4e56b3); +} + +BOOST_AUTO_TEST_CASE(get_next_work_digishield_modulated_lower) +{ + SelectParams(CBaseChainParams::MAIN); + const Consensus::Params& params = Params().GetConsensus(); + + CBlockIndex pindexLast; + int64_t nLastRetargetTime = 1395380517; + + // Test the lower bound on modulated time using mainnet block #149,423 + pindexLast.nHeight = 149423; + pindexLast.nTime = 1395380447; + pindexLast.nBits = 0x1b446f21; + BOOST_CHECK_EQUAL(CalculateDogecoinNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1b335358); +} + +BOOST_AUTO_TEST_CASE(get_next_work_digishield_rounding) +{ + SelectParams(CBaseChainParams::MAIN); + const Consensus::Params& params = Params().GetConsensus(); + + CBlockIndex pindexLast; + int64_t nLastRetargetTime = 1395094679; + + // Test case for correct rounding of modulated time - this depends on + // handling of integer division, and is not obvious from the code + pindexLast.nHeight = 145001; + pindexLast.nTime = 1395094727; + pindexLast.nBits = 0x1b671062; + BOOST_CHECK_EQUAL(CalculateDogecoinNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1b6558a4); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp index 5e55ad662..5e88e8fee 100644 --- a/src/test/merkle_tests.cpp +++ b/src/test/merkle_tests.cpp @@ -116,7 +116,7 @@ static std::vector<uint256> ComputeMerkleBranch(const std::vector<uint256>& leav return ret; } -static std::vector<uint256> BlockMerkleBranch(const CBlock& block, uint32_t position) +std::vector<uint256> BlockMerkleBranch(const CBlock& block, uint32_t position) { std::vector<uint256> leaves; leaves.resize(block.vtx.size()); diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 4e88bd4c4..6dd0d8b22 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -197,3 +197,12 @@ CBlock getBlock13b8a() stream >> block; return block; } + +//! equality test +bool operator==(const Coin &a, const Coin &b) { + // Empty Coin objects are always equal. + if (a.IsSpent() && b.IsSpent()) return true; + return a.fCoinBase == b.fCoinBase && + a.nHeight == b.nHeight && + a.out == b.out; +} diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index 0643e6e04..82bf98da6 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -127,4 +127,12 @@ CBlock getBlock13b8a(); // define an implicit conversion here so that uint256 may be used directly in BOOST_CHECK_* std::ostream& operator<<(std::ostream& os, const uint256& num); +/* This is defined in merkle_tests.cpp, but also used by auxpow_tests.cpp. */ +namespace merkle_tests { +std::vector<uint256> BlockMerkleBranch(const CBlock& block, uint32_t position); +} + +// Define == for coin equality (used by multiple tests). +bool operator==(const Coin &a, const Coin &b); + #endif |