aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorMax K <[email protected]>2019-07-14 19:35:30 +0200
committerGitHub <[email protected]>2019-07-14 19:35:30 +0200
commitcee13699a5676355487f8eb2d91985f63438eae4 (patch)
treecf12be6180f950a25ee2ee7f3f2126542835d6e3 /src/test
parentCorrect build and test net seed (diff)
parentHandle legacy v2 block at #66064 (diff)
downloaddiscoin-1.17-dev.tar.xz
discoin-1.17-dev.zip
Merge pull request #1546 from rnicoll/1.17-auxpow1.17-dev
1.17 AuxPoW support
Diffstat (limited to 'src/test')
-rw-r--r--src/test/auxpow_tests.cpp591
-rw-r--r--src/test/coins_tests.cpp9
-rw-r--r--src/test/dogecoin_tests.cpp95
-rw-r--r--src/test/merkle_tests.cpp2
-rw-r--r--src/test/test_bitcoin.cpp9
-rw-r--r--src/test/test_bitcoin.h8
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