diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 0e18a3ba8c..88ed87510c 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -66,6 +66,11 @@ BITCOIN_TESTS =\ test/net_tests.cpp \ test/claimtriecache_tests.cpp \ test/claimtriebranching_tests.cpp \ + test/claimtrieexpirationfork_tests.cpp \ + test/claimtriefixture.cpp \ + test/claimtriehashfork_tests.cpp \ + test/claimtrienormalization_tests.cpp \ + test/claimtrierpc_tests.cpp \ test/nameclaim_tests.cpp \ test/netbase_tests.cpp \ test/pmt_tests.cpp \ diff --git a/src/test/claimtriebranching_tests.cpp b/src/test/claimtriebranching_tests.cpp index 569e0bf0d9..9fa9e103de 100644 --- a/src/test/claimtriebranching_tests.cpp +++ b/src/test/claimtriebranching_tests.cpp @@ -1,530 +1,13 @@ -// Copyright (c) 2015 The LBRY Foundation +// Copyright (c) 2015-2019 The LBRY Foundation // Distributed under the MIT software license, see the accompanying // file COPYING or http://opensource.org/licenses/mit-license.php -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -extern ::CChainState g_chainstate; -extern ::ArgsManager gArgs; -extern std::vector random_strings(std::size_t count); -extern bool getClaimById(const uint160&, std::string&, CClaimValue*); +#include using namespace std; -CMutableTransaction BuildTransaction(const CTransaction& prev, uint32_t prevout=0, unsigned int numOutputs=1, int locktime=0) -{ - CMutableTransaction tx; - tx.nVersion = CTransaction::CURRENT_VERSION; - tx.vin.resize(1); - tx.vout.resize(numOutputs); - tx.vin[0].prevout.hash = prev.GetHash(); - tx.vin[0].prevout.n = prevout; - tx.vin[0].scriptSig = CScript(); - if (locktime != 0) - { - // Use a relative locktime for validity X blocks in the future - tx.nLockTime = chainActive.Height() + locktime; - tx.vin[0].nSequence = 0xffffffff - 1; - } - else - { - tx.nLockTime = 1 << 31; // Disable BIP68 - tx.vin[0].nSequence = std::numeric_limits::max(); - } - CAmount valuePerOutput = prev.vout[prevout].nValue; - unsigned int numOutputsCopy = numOutputs; - while ((numOutputsCopy = numOutputsCopy >> 1) > 0) - { - valuePerOutput = valuePerOutput >> 1; - } - for (unsigned int i = 0; i < numOutputs; ++i) - { - tx.vout[i].scriptPubKey = CScript(); - tx.vout[i].nValue = valuePerOutput; - } - - return tx; -} - -static BlockAssembler AssemblerForTest() -{ - BlockAssembler::Options options; - options.nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT; - options.blockMinFeeRate = CFeeRate(0); - return BlockAssembler(Params(), options); -} - -// Test Fixtures -struct ClaimTrieChainFixture: public CClaimTrieCache -{ - std::vector coinbase_txs; - std::vector marks; - int coinbase_txs_used; - int unique_block_counter; - int normalization_original; - unsigned int num_txs_for_next_block; - bool added_unchecked; - - int64_t expirationForkHeight; - int64_t originalExpiration; - int64_t extendedExpiration; - int64_t forkhash_original; - - using CClaimTrieCache::getSupportsForName; - - ClaimTrieChainFixture(): CClaimTrieCache(pclaimTrie), - unique_block_counter(0), normalization_original(-1), expirationForkHeight(-1), forkhash_original(-1) - { - fRequireStandard = false; - BOOST_CHECK_EQUAL(nNextHeight, chainActive.Height() + 1); - setNormalizationForkHeight(1000000); - - gArgs.ForceSetArg("-limitancestorcount", "1000000"); - gArgs.ForceSetArg("-limitancestorsize", "1000000"); - gArgs.ForceSetArg("-limitdescendantcount", "1000000"); - gArgs.ForceSetArg("-limitdescendantsize", "1000000"); - - num_txs_for_next_block = 0; - coinbase_txs_used = 0; - unique_block_counter = 0; - added_unchecked = false; - // generate coinbases to spend - CreateCoinbases(40, coinbase_txs); - } - - ~ClaimTrieChainFixture() - { - added_unchecked = false; - DecrementBlocks(chainActive.Height()); - auto& consensus = const_cast(Params().GetConsensus()); - if (normalization_original >= 0) - consensus.nNormalizedNameForkHeight = normalization_original; - - if (expirationForkHeight >= 0) { - consensus.nExtendedClaimExpirationForkHeight = expirationForkHeight; - consensus.nExtendedClaimExpirationTime = extendedExpiration; - consensus.nOriginalClaimExpirationTime = originalExpiration; - } - if (forkhash_original >= 0) { - consensus.nAllClaimsInMerkleForkHeight = forkhash_original; - } - } - - void setExpirationForkHeight(int targetMinusCurrent, int64_t preForkExpirationTime, int64_t postForkExpirationTime) { - int target = chainActive.Height() + targetMinusCurrent; - auto& consensus = const_cast(Params().GetConsensus()); - if (expirationForkHeight < 0) { - expirationForkHeight = consensus.nExtendedClaimExpirationForkHeight; - originalExpiration = consensus.nOriginalClaimExpirationTime; - extendedExpiration = consensus.nExtendedClaimExpirationTime; - } - consensus.nExtendedClaimExpirationForkHeight = target; - consensus.nExtendedClaimExpirationTime = postForkExpirationTime; - consensus.nOriginalClaimExpirationTime = preForkExpirationTime; - setExpirationTime(targetMinusCurrent >= 0 ? preForkExpirationTime : postForkExpirationTime); - } - - void setNormalizationForkHeight(int targetMinusCurrent) { - int target = chainActive.Height() + targetMinusCurrent; - auto& consensus = const_cast(Params().GetConsensus()); - if (normalization_original < 0) - normalization_original = consensus.nNormalizedNameForkHeight; - consensus.nNormalizedNameForkHeight = target; - } - - void setHashForkHeight(int targetMinusCurrent) - { - int target = chainActive.Height() + targetMinusCurrent; - auto& consensus = const_cast(Params().GetConsensus()); - if (forkhash_original < 0) - forkhash_original = consensus.nAllClaimsInMerkleForkHeight; - consensus.nAllClaimsInMerkleForkHeight = target; - } - - bool CreateBlock(const std::unique_ptr& pblocktemplate) - { - CBlock* pblock = &pblocktemplate->block; - { - LOCK(cs_main); - pblock->nVersion = 5; - pblock->hashPrevBlock = chainActive.Tip()->GetBlockHash(); - pblock->nTime = chainActive.Tip()->GetBlockTime() + Params().GetConsensus().nPowTargetSpacing; - CMutableTransaction txCoinbase(*pblock->vtx[0]); - txCoinbase.vin[0].scriptSig = CScript() << int(chainActive.Height() + 1) << int(++unique_block_counter); - txCoinbase.vout[0].nValue = GetBlockSubsidy(chainActive.Height() + 1, Params().GetConsensus()); - pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase)); - pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); - for (uint32_t i = 0;; ++i) { - pblock->nNonce = i; - if (CheckProofOfWork(pblock->GetPoWHash(), pblock->nBits, Params().GetConsensus())) { - break; - } - } - } - auto success = ProcessNewBlock(Params(), std::make_shared(*pblock), true, nullptr); - return success && pblock->GetHash() == chainActive.Tip()->GetBlockHash(); - } - - bool CreateCoinbases(unsigned int num_coinbases, std::vector& coinbases) - { - std::unique_ptr pblocktemplate; - coinbases.clear(); - BOOST_CHECK(pblocktemplate = AssemblerForTest().CreateNewBlock(CScript() << OP_TRUE)); - BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 1); - for (unsigned int i = 0; i < 100 + num_coinbases; ++i) { - BOOST_CHECK(CreateBlock(pblocktemplate)); - if (coinbases.size() < num_coinbases) - coinbases.push_back(std::move(*pblocktemplate->block.vtx[0])); - } - return true; - } - - void CommitTx(const CMutableTransaction &tx, bool has_locktime=false) { - num_txs_for_next_block++; - if (has_locktime) - { - added_unchecked = true; - TestMemPoolEntryHelper entry; - LOCK(mempool.cs); - mempool.addUnchecked(tx.GetHash(), entry.Fee(0).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); - } - else - { - CValidationState state; - CAmount txFeeRate = CAmount(0); - LOCK(cs_main); - BOOST_CHECK_EQUAL(AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), nullptr, nullptr, false, txFeeRate, false), true); - } - } - - //spend a bid into some non claimtrie related unspent - CMutableTransaction Spend(const CTransaction &prev) - { - CMutableTransaction tx = BuildTransaction(prev, 0); - tx.vout[0].scriptPubKey = CScript() << OP_TRUE; - tx.vout[0].nValue = prev.vout[0].nValue; - - CommitTx(tx); - return tx; - } - - //make claim at the current block - CMutableTransaction MakeClaim(const CTransaction& prev, std::string name, std::string value, CAmount quantity, int locktime=0) - { - uint32_t prevout = prev.vout.size() - 1; - while (prevout > 0 && prev.vout[prevout].nValue < quantity) - --prevout; - CMutableTransaction tx = BuildTransaction(prev, prevout, prev.vout[prevout].nValue > quantity ? 2 : 1, locktime); - tx.vout[0].scriptPubKey = ClaimNameScript(name, value); - tx.vout[0].nValue = quantity; - if (tx.vout.size() > 1) { - tx.vout[1].scriptPubKey = CScript() << OP_TRUE; - tx.vout[1].nValue = prev.vout[prevout].nValue - quantity; - } - - CommitTx(tx, locktime != 0); - return tx; - } - - CMutableTransaction MakeClaim(const CTransaction& prev, std::string name, std::string value) - { - return MakeClaim(prev, name, value, prev.vout[0].nValue, 0); - } - - //make support at the current block - CMutableTransaction MakeSupport(const CTransaction &prev, const CTransaction &claimtx, std::string name, CAmount quantity) - { - uint32_t prevout = prev.vout.size() - 1; - while (prevout > 0 && prev.vout[prevout].nValue < quantity) - --prevout; - CMutableTransaction tx = BuildTransaction(prev, prevout, prev.vout[prevout].nValue > quantity ? 2 : 1); - tx.vout[0].scriptPubKey = SupportClaimScript(name, ClaimIdHash(claimtx.GetHash(), 0)); - tx.vout[0].nValue = quantity; - if (tx.vout.size() > 1) { - tx.vout[1].scriptPubKey = CScript() << OP_TRUE; - tx.vout[1].nValue = prev.vout[prevout].nValue - quantity; - } - - CommitTx(tx); - return tx; - } - - //make update at the current block - CMutableTransaction MakeUpdate(const CTransaction &prev, std::string name, std::string value, - uint160 claimId, CAmount quantity) - { - CMutableTransaction tx = BuildTransaction(prev, 0); - tx.vout[0].scriptPubKey = UpdateClaimScript(name, claimId, value); - tx.vout[0].nValue = quantity; - - CommitTx(tx); - return tx; - } - - CTransaction GetCoinbase() - { - auto tx = coinbase_txs.at(coinbase_txs_used++); - return tx; - } - - //create i blocks - void IncrementBlocks(int num_blocks, bool mark = false) - { - if (mark) - marks.push_back(chainActive.Height()); - - clear(); // clears the internal cache - for (int i = 0; i < num_blocks; ++i) - { - CScript coinbase_scriptpubkey; - coinbase_scriptpubkey << CScriptNum(chainActive.Height()); - std::unique_ptr pblocktemplate = AssemblerForTest().CreateNewBlock(coinbase_scriptpubkey); - BOOST_CHECK(pblocktemplate != nullptr); - if (!added_unchecked) - BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), num_txs_for_next_block + 1); - BOOST_CHECK_EQUAL(CreateBlock(pblocktemplate), true); - num_txs_for_next_block = 0; - nNextHeight = chainActive.Height() + 1; - } - setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight - 1)); - } - - //disconnect i blocks from tip - void DecrementBlocks(int num_blocks) - { - clear(); // clears the internal cache - CValidationState state; - { - LOCK(cs_main); - CBlockIndex* pblockindex = chainActive[chainActive.Height() - num_blocks + 1]; - BOOST_CHECK_EQUAL(InvalidateBlock(state, Params(), pblockindex), true); - } - BOOST_CHECK_EQUAL(state.IsValid(), true); - BOOST_CHECK_EQUAL(ActivateBestChain(state, Params()), true); - mempool.clear(); - num_txs_for_next_block = 0; - nNextHeight = chainActive.Height() + 1; - setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight - 1)); - } - - // decrement back to last mark - void DecrementBlocks() - { - int mark = marks.back(); - marks.pop_back(); - DecrementBlocks(chainActive.Height() - mark); - } - - template - bool keyTypeEmpty(uint8_t keyType) - { - boost::scoped_ptr pcursor(base->db->NewIterator()); - pcursor->SeekToFirst(); - - while (pcursor->Valid()) { - std::pair key; - if (pcursor->GetKey(key)) { - if (key.first == keyType) - return false; - } - pcursor->Next(); - } - return true; - } - - bool queueEmpty() - { - for (const auto& claimQueue: claimQueueCache) { - if (!claimQueue.second.empty()) - return false; - } - return keyTypeEmpty(CLAIM_QUEUE_ROW); - } - - bool expirationQueueEmpty() - { - for (const auto& expirationQueue: expirationQueueCache) { - if (!expirationQueue.second.empty()) - return false; - } - return keyTypeEmpty(CLAIM_EXP_QUEUE_ROW); - } - - bool supportEmpty() - { - for (const auto& entry: supportCache) { - if (!entry.second.empty()) - return false; - } - return supportCache.empty() && keyTypeEmpty(SUPPORT); - } - - bool supportQueueEmpty() - { - for (const auto& support: supportQueueCache) { - if (!support.second.empty()) - return false; - } - return keyTypeEmpty(SUPPORT_QUEUE_ROW); - } - - int proportionalDelayFactor() - { - return base->nProportionalDelayFactor; - } - - //is a claim in queue - boost::test_tools::predicate_result - is_claim_in_queue(const std::string& name, const CTransaction &tx) - { - COutPoint outPoint(tx.GetHash(), 0); - int validAtHeight; - bool have_claim = haveClaimInQueue(name, outPoint, validAtHeight); - if (have_claim) { - return true; - } else { - boost::test_tools::predicate_result res(false); - res.message() << "Is not a claim in queue."; - return res; - } - } - - // check if tx is best claim based on outpoint - boost::test_tools::predicate_result - is_best_claim(const std::string& name, const CTransaction &tx) - { - CClaimValue val; - COutPoint outPoint(tx.GetHash(), 0); - bool have_claim = haveClaim(name, outPoint); - bool have_info = getInfoForName(name, val); - if (have_claim && have_info && val.outPoint == outPoint) { - return true; - } else { - boost::test_tools::predicate_result res(false); - res.message() << "Is not best claim"; - return res; - } - } - - // check effective quantity of best claim - boost::test_tools::predicate_result - best_claim_effective_amount_equals(const std::string& name, CAmount amount) - { - CClaimValue val; - bool have_info = getInfoForName(name, val); - if (!have_info) { - boost::test_tools::predicate_result res(false); - res.message() << "No claim found"; - return res; - } else { - CAmount effective_amount = getClaimsForName(name).find(val.claimId).effectiveAmount; - if (effective_amount != amount) { - boost::test_tools::predicate_result res(false); - res.message() << amount << " != " << effective_amount; - return res; - } else { - return true; - } - } - } - - std::size_t getTotalNamesInTrie() const { return base->getTotalNamesInTrie(); } -}; - BOOST_FIXTURE_TEST_SUITE(claimtriebranching_tests, RegTestingSetup) -#ifndef MAC_OSX // can't find a random number generator that produces the same sequence on OSX -BOOST_AUTO_TEST_CASE(triehash_fuzzer_test) -{ - ClaimTrieChainFixture fixture; - - auto envClaims = std::getenv("TRIEHASH_FUZZER_CLAIMS"); - auto envBlocks = std::getenv("TRIEHASH_FUZZER_BLOCKS"); - - const int claimsPerBlock = envClaims ? std::atoi(envClaims) : 100; - const int blocks = envBlocks ? std::atoi(envBlocks) : 13; - - auto names = random_strings(blocks * claimsPerBlock); - - FastRandomContext frc(true); - std::unordered_map> existingClaims; - std::vector existingSupports; - std::string value(1024, 'c'); - - std::vector cb {fixture.GetCoinbase()}; - for (int i = 0; i < blocks; ++i) { - for (int j = 0; j < claimsPerBlock; ++j) { - auto name = names[i * claimsPerBlock + j]; - auto supportFront = frc.randrange(4) == 0; - auto supportBack = frc.randrange(4) == 0; - auto removeClaim = frc.randrange(4) == 0; - auto removeSupport = frc.randrange(4) == 0; - auto hit = existingClaims.find(name); - if (supportFront && hit != existingClaims.end() && hit->second.size()) { - auto tx = fixture.MakeSupport(cb.back(), hit->second[frc.rand64() % hit->second.size()], name, 2); - existingSupports.push_back(tx); - cb.emplace_back(std::move(tx)); - } - if (removeClaim && hit != existingClaims.end() && hit->second.size()) { - auto idx = frc.rand64() % hit->second.size(); - fixture.Spend(hit->second[idx]); - hit->second.erase(hit->second.begin() + idx); - } - else { - auto tx = fixture.MakeClaim(cb.back(), name, value, 2); - existingClaims[name].push_back(tx); - hit = existingClaims.find(name); - cb.emplace_back(std::move(tx)); - } - if (supportBack && hit != existingClaims.end() && hit->second.size()) { - auto tx = fixture.MakeSupport(cb.back(), hit->second[frc.rand64() % hit->second.size()], name, 2); - existingSupports.push_back(tx); - cb.emplace_back(std::move(tx)); - } - if (removeSupport && (i & 7) == 7 && !existingSupports.empty()) { - const auto tidx = frc.rand64() % existingSupports.size(); - const auto tx = existingSupports[tidx]; - fixture.Spend(tx); - existingSupports.erase(existingSupports.begin() + tidx); - } - if (cb.back().GetValueOut() < 10 || cb.size() > 40000) { - cb.clear(); - cb.push_back(fixture.GetCoinbase()); - } - } - fixture.IncrementBlocks(1); - if (blocks > 13 && i % 50 == 0) // travisCI needs some periodic output - std::cerr << "In triehash_fuzzer_test with " << fixture.getTotalNamesInTrie() << " names at block " << i << std::endl; - } - - if (blocks == 1000 && claimsPerBlock == 100) - BOOST_CHECK_EQUAL(fixture.getMerkleHash().GetHex(), "28825257a129eef69cab87d6255c8359fc6dc083ca7f09222526e3a7971f382d"); - else if (blocks == 13 && claimsPerBlock == 100) - BOOST_CHECK_EQUAL(fixture.getMerkleHash().GetHex(), "4e5984d6984f5f05d50e821e6228d56bcfbd16ca2093cd0308f6ff1c2bc8689a"); - else - std::cerr << "Hash: " << fixture.getMerkleHash().GetHex() << std::endl; -} -#endif - BOOST_AUTO_TEST_CASE(claim_replace_test) { // no competing bids ClaimTrieChainFixture fixture; @@ -990,71 +473,6 @@ BOOST_AUTO_TEST_CASE(claimtrie_update_test) fixture.DecrementBlocks(11); } -/* - expiration - check claims expire and loses claim - check claims expire and is not updateable (may be changed in future soft fork) - check supports expire and can cause supported bid to lose claim -*/ -BOOST_AUTO_TEST_CASE(claimtrie_expire_test) -{ - ClaimTrieChainFixture fixture; - fixture.setExpirationForkHeight(1000000, 5, 1000000); - - // check claims expire and loses claim - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(),"test", "one", 2); - fixture.IncrementBlocks(fixture.expirationTime()); - BOOST_CHECK(fixture.is_best_claim("test", tx1)); - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test", "one", 1); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("test", tx2)); - - fixture.DecrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("test", tx1)); - fixture.DecrementBlocks(fixture.expirationTime()); - - // check claims expire and is not updateable (may be changed in future soft fork) - CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(),"test", "one", 2); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("test", tx3)); - fixture.IncrementBlocks(fixture.expirationTime()); - CMutableTransaction u1 = fixture.MakeUpdate(tx3, "test", "two", ClaimIdHash(tx3.GetHash(), 0), 2); - BOOST_CHECK(!fixture.is_best_claim("test",u1)); - - fixture.DecrementBlocks(fixture.expirationTime()); - BOOST_CHECK(fixture.is_best_claim("test", tx3)); - fixture.DecrementBlocks(1); - - // check supports expire and can cause supported bid to lose claim - CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 1); - CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 2); - CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(), tx4, "test", 2); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("test",tx4)); - CMutableTransaction u2 = fixture.MakeUpdate(tx4, "test", "two", ClaimIdHash(tx4.GetHash(),0), 1); - CMutableTransaction u3 = fixture.MakeUpdate(tx5, "test", "two", ClaimIdHash(tx5.GetHash(),0), 2); - fixture.IncrementBlocks(fixture.expirationTime()); - BOOST_CHECK(fixture.is_best_claim("test", u3)); - fixture.DecrementBlocks(fixture.expirationTime()); - BOOST_CHECK(fixture.is_best_claim("test", tx4)); - fixture.DecrementBlocks(1); - - // check updated claims will extend expiration - CMutableTransaction tx6 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 2); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("test", tx6)); - CMutableTransaction u4 = fixture.MakeUpdate(tx6, "test", "two", ClaimIdHash(tx6.GetHash(), 0), 2); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("test", u4)); - fixture.IncrementBlocks(fixture.expirationTime()-1); - BOOST_CHECK(fixture.is_best_claim("test", u4)); - fixture.IncrementBlocks(1); - BOOST_CHECK(!fixture.is_best_claim("test", u4)); - fixture.DecrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("test", u4)); - fixture.DecrementBlocks(fixture.expirationTime()); - BOOST_CHECK(fixture.is_best_claim("test", tx6)); -} /* * tests for effectiveAmount */ @@ -1161,821 +579,82 @@ BOOST_AUTO_TEST_CASE(get_claim_by_id_test) BOOST_CHECK(claimValue2.claimId != claimId); } -/* - claim expiration for hard fork - check claims do not expire post ExpirationForkHeight - check supports work post ExpirationForkHeight -*/ -BOOST_AUTO_TEST_CASE(hardfork_claim_test) +BOOST_AUTO_TEST_CASE(insert_update_claim_test) { ClaimTrieChainFixture fixture; - fixture.setExpirationForkHeight(7, 3, 6); - - // First create a claim and make sure it expires pre-fork - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",3); - fixture.IncrementBlocks(4); - BOOST_CHECK(!fixture.is_best_claim("test",tx1)); - fixture.DecrementBlocks(3); - BOOST_CHECK(fixture.is_best_claim("test",tx1)); - fixture.IncrementBlocks(3); - BOOST_CHECK(!fixture.is_best_claim("test",tx1)); - // Create a claim 1 block before the fork height that will expire after the fork height - fixture.IncrementBlocks(1); - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test2","one",3); - fixture.IncrementBlocks(1); - BOOST_CHECK_EQUAL(fixture.expirationTime(), 3); - - // Disable future expirations and fast-forward past the fork height - fixture.IncrementBlocks(1); - BOOST_CHECK_EQUAL(fixture.expirationTime(), 6); - // make sure decrementing to before the fork height will apppropriately set back the - // expiration time to the original expiraiton time - fixture.DecrementBlocks(1); - BOOST_CHECK_EQUAL(fixture.expirationTime(), 3); - fixture.IncrementBlocks(1); - BOOST_CHECK_EQUAL(fixture.expirationTime(), 6); + std::string sName1("atest"); + std::string sName2("btest"); + std::string sName3("atest123"); + std::string sValue1("testa"); + std::string sValue2("testb"); + std::string sValue3("123testa"); - // make sure that claim created 1 block before the fork expires as expected - // at the extended expiration times - BOOST_CHECK(fixture.is_best_claim("test2", tx2)); - fixture.IncrementBlocks(5); - BOOST_CHECK(!fixture.is_best_claim("test2", tx2)); - fixture.DecrementBlocks(5); - BOOST_CHECK(fixture.is_best_claim("test2", tx2)); + uint256 hash0(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); + BOOST_CHECK_EQUAL(fixture.getMerkleHash(), hash0); - // This first claim is still expired since it's pre-fork, even - // after fork activation - BOOST_CHECK(!fixture.is_best_claim("test", tx1)); + CMutableTransaction tx1 = BuildTransaction(fixture.GetCoinbase()); + tx1.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME + << std::vector(sName1.begin(), sName1.end()) + << std::vector(sValue1.begin(), sValue1.end()) << OP_2DROP << OP_DROP << OP_TRUE; + uint160 tx1ClaimId = ClaimIdHash(tx1.GetHash(), 0); + COutPoint tx1OutPoint(tx1.GetHash(), 0); - // This new claim created at the fork height cannot expire at original expiration - CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",1); - fixture.IncrementBlocks(1); - fixture.IncrementBlocks(3); - BOOST_CHECK(fixture.is_best_claim("test",tx3)); - BOOST_CHECK(!fixture.is_best_claim("test",tx1)); - fixture.DecrementBlocks(3); + CMutableTransaction tx7 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, tx1.vout[0].nValue - 10001); + uint160 tx7ClaimId = ClaimIdHash(tx7.GetHash(), 0); + COutPoint tx7OutPoint(tx7.GetHash(), 0); - // but it expires at the extended expiration, and not a single block below - fixture.IncrementBlocks(6); - BOOST_CHECK(!fixture.is_best_claim("test",tx3)); - fixture.DecrementBlocks(6); - fixture.IncrementBlocks(5); - BOOST_CHECK(fixture.is_best_claim("test",tx3)); - fixture.DecrementBlocks(5); + CClaimValue val; + int nThrowaway; - // Ensure that we cannot update the original pre-fork expired claim - CMutableTransaction u1 = fixture.MakeUpdate(tx1,"test","two",ClaimIdHash(tx1.GetHash(),0), 3); - fixture.IncrementBlocks(1); - BOOST_CHECK(!fixture.is_best_claim("test",u1)); + // Verify claims (tx7) for uncontrolled names go in immediately + fixture.IncrementBlocks(1, true); - // Ensure that supports for the expired claim don't support it - CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(),u1,"test",10); - BOOST_CHECK(!fixture.is_best_claim("test",u1)); + BOOST_CHECK(fixture.getInfoForName(sName1, val)); + BOOST_CHECK_EQUAL(val.outPoint, tx7OutPoint); - // Ensure that we can update the new post-fork claim - CMutableTransaction u2 = fixture.MakeUpdate(tx3,"test","two",ClaimIdHash(tx3.GetHash(),0), 1); + // Verify claims for controlled names are delayed, and that the bigger claim wins when inserted + fixture.IncrementBlocks(5); + fixture.CommitTx(tx1); fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("test",u2)); - // Ensure that supports for the new post-fork claim - CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(),u2,"test",3); - BOOST_CHECK(fixture.is_best_claim("test",u2)); -} + BOOST_CHECK(!fixture.queueEmpty()); -/* - support expiration for hard fork -*/ -BOOST_AUTO_TEST_CASE(hardfork_support_test) -{ - ClaimTrieChainFixture fixture; - fixture.setExpirationForkHeight(2, 2, 4); + fixture.IncrementBlocks(5); // 12 - // Create claim and support it before the fork height - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 1); - CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, "test", 2); - // this claim will win without the support - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",2); - fixture.IncrementBlocks(2); + BOOST_CHECK(!fixture.queueEmpty()); - // check that the claim expires as expected at the extended time, as does the support - fixture.IncrementBlocks(2); - BOOST_CHECK(fixture.is_best_claim("test",tx1)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",3)); - fixture.DecrementBlocks(2); - fixture.IncrementBlocks(3); - BOOST_CHECK(!fixture.is_best_claim("test",tx1)); - fixture.DecrementBlocks(3); fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("test",tx1)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",3)); - fixture.DecrementBlocks(1); - // update the claims at fork - fixture.DecrementBlocks(1); - CMutableTransaction u1 = fixture.MakeUpdate(tx1, "test", "two", ClaimIdHash(tx1.GetHash(),0), 1); - CMutableTransaction u2 = fixture.MakeUpdate(tx2, "test", "two", ClaimIdHash(tx2.GetHash(),0), 2); - fixture.IncrementBlocks(1); - BOOST_CHECK_EQUAL(Params().GetConsensus().nExtendedClaimExpirationForkHeight, chainActive.Height()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(fixture.getInfoForName(sName1, val)); + BOOST_CHECK_EQUAL(val.outPoint, tx1OutPoint); - BOOST_CHECK(fixture.is_best_claim("test", u1)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",3)); - BOOST_CHECK(!fixture.is_claim_in_queue("test", tx1)); - BOOST_CHECK(!fixture.is_claim_in_queue("test", tx2)); + // Verify updates to the best claim get inserted immediately, and others don't. + CMutableTransaction tx3 = fixture.MakeUpdate(tx1, sName1, sValue1, tx1ClaimId, tx1.vout[0].nValue - 10000); + COutPoint tx3OutPoint(tx3.GetHash(), 0); + CMutableTransaction tx9 = fixture.MakeUpdate(tx7, sName1, sValue2, tx7ClaimId, tx7.vout[0].nValue - 10000); + COutPoint tx9OutPoint(tx9.GetHash(), 0); + fixture.IncrementBlocks(1, true); // 14 - // check that the support expires as expected - fixture.IncrementBlocks(3); - BOOST_CHECK(fixture.is_best_claim("test", u2)); - fixture.DecrementBlocks(3); - fixture.IncrementBlocks(2); - BOOST_CHECK(fixture.is_best_claim("test",u1)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",3)); -} + BOOST_CHECK(!fixture.queueEmpty()); + BOOST_CHECK(!fixture.haveClaim(sName1, tx1OutPoint)); + BOOST_CHECK(!fixture.haveClaim(sName1, tx7OutPoint)); + BOOST_CHECK(fixture.getInfoForName(sName1, val)); + BOOST_CHECK_EQUAL(val.outPoint, tx3OutPoint); + BOOST_CHECK(fixture.haveClaimInQueue(sName1, tx9OutPoint, nThrowaway)); -/* - activation_fall_through and supports_fall_through - Tests for where claims/supports in queues would be undone properly in a decrement. - See https://github.com/lbryio/lbrycrd/issues/243 for more details -*/ + // Roll back the last block, make sure tx1 and tx7 are put back in the trie + fixture.DecrementBlocks(); // 13 -BOOST_AUTO_TEST_CASE(activations_fall_through) -{ - ClaimTrieChainFixture fixture; + BOOST_CHECK(fixture.getInfoForName(sName1, val)); + BOOST_CHECK_EQUAL(val.outPoint, tx1OutPoint); + BOOST_CHECK(fixture.haveClaim(sName1, tx7OutPoint)); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!pclaimTrie->empty()); - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1); - fixture.IncrementBlocks(3); - BOOST_CHECK_EQUAL(fixture.proportionalDelayFactor(), 1); - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "2", 3); - fixture.IncrementBlocks(1); - - BOOST_CHECK(fixture.is_best_claim("A", tx1)); - fixture.IncrementBlocks(3); - BOOST_CHECK(fixture.is_best_claim("A", tx2)); - fixture.DecrementBlocks(3); - fixture.Spend(tx1); // this will trigger early activation on tx2 claim - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("A", tx2)); - fixture.DecrementBlocks(1); //reorg the early activation - BOOST_CHECK(fixture.is_best_claim("A", tx1)); - fixture.Spend(tx1); - fixture.IncrementBlocks(1); // this should not cause tx2 to activate again and crash - BOOST_CHECK(fixture.is_best_claim("A", tx2)); -} - -BOOST_AUTO_TEST_CASE(supports_fall_through) -{ - ClaimTrieChainFixture fixture; - - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 3); - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "2", 1); - CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "3", 2); - fixture.IncrementBlocks(3); - BOOST_CHECK_EQUAL(fixture.proportionalDelayFactor(), 1); - CMutableTransaction sx2 = fixture.MakeSupport(fixture.GetCoinbase(), tx2, "A", 3); - fixture.IncrementBlocks(1); - - BOOST_CHECK(fixture.is_best_claim("A", tx1)); - fixture.IncrementBlocks(3); - BOOST_CHECK(fixture.is_best_claim("A", tx2)); - fixture.DecrementBlocks(3); - fixture.Spend(tx1); // this will trigger early activation - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("A", tx2)); - fixture.DecrementBlocks(1); // reorg the early activation - BOOST_CHECK(fixture.is_best_claim("A", tx1)); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("A", tx1)); //tx2 support should not be active - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("A", tx1)); //tx2 support should not be active - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("A", tx2)); //tx2 support should be active now -} - -/* - normalization - test normalization function indpendent from rest of the code - -*/ - -BOOST_AUTO_TEST_CASE(normalization_only) -{ - CClaimTrieCache ccache(pclaimTrie); - - // basic ASCII casing tests - BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("TESt", true)); - BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("tesT", true)); - BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("TesT", true)); - BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("test", true)); - BOOST_CHECK_EQUAL("test this", ccache.normalizeClaimName("Test This", true)); - - // test invalid utf8 bytes are returned as is - BOOST_CHECK_EQUAL("\xFF", ccache.normalizeClaimName("\xFF", true)); - BOOST_CHECK_EQUAL("\xC3\x28", ccache.normalizeClaimName("\xC3\x28", true)); - - // ohm sign unicode code point \x2126 should be transformed to equivalent - // unicode code point \x03C9 , greek small letter omega - BOOST_CHECK_EQUAL("\xCF\x89", ccache.normalizeClaimName("\xE2\x84\xA6", true)); - - // cyrillic capital ef code point \x0424 should be transformed to lower case - // \x0444 - BOOST_CHECK_EQUAL("\xD1\x84", ccache.normalizeClaimName("\xD0\xA4", true)); - - // armenian capital ben code point \x0532 should be transformed to lower case - // \x0562 - BOOST_CHECK_EQUAL("\xD5\xA2", ccache.normalizeClaimName("\xD4\xB2", true)); - - // japanese pbu code point \x3076 should be transformed by NFD decomposition - // into \x3075 and \x3099 - BOOST_CHECK_EQUAL("\xE3\x81\xB5\xE3\x82\x99", - ccache.normalizeClaimName("\xE3\x81\xB6", true)); - - // hangul ggwalg unicode code point \xAF51 should be transformed by NFD - // decomposition into unicode code points \x1101 \x116A \x11B0 - // source: http://unicode.org/L2/L2009/09052-tr47.html - BOOST_CHECK_EQUAL("\xE1\x84\x81\xE1\x85\xAA\xE1\x86\xB0", - ccache.normalizeClaimName("\xEA\xBD\x91", true)); -} - -/* - normalization - check claim name normalization before the fork - check claim name normalization after the fork -*/ -BOOST_AUTO_TEST_CASE(claimtriebranching_normalization) -{ - ClaimTrieChainFixture fixture; - - // check claim names are not normalized - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "normalizeTest", "one", 3); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1)); - fixture.DecrementBlocks(1); - BOOST_CHECK(fixture.getTotalNamesInTrie() == 0); - fixture.CommitTx(tx1); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1)); - - CMutableTransaction tx2a = fixture.MakeClaim(fixture.GetCoinbase(), "Normalizetest", "one_a", 2); - CMutableTransaction tx2 = fixture.MakeUpdate(tx2a, "Normalizetest", "one", ClaimIdHash(tx2a.GetHash(), 0), 2); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1)); - BOOST_CHECK(fixture.is_best_claim("Normalizetest", tx2)); - - // Activate the fork (which rebuilds the existing claimtrie and - // cache), flattening all previously existing name clashes due to - // the normalization - fixture.setNormalizationForkHeight(2); - - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1)); - BOOST_CHECK(fixture.is_best_claim("Normalizetest", tx2)); - - fixture.IncrementBlocks(1, true); - - // Post-fork, tx1 (the previous winning claim) assumes all name - // variants of what it originally was ... - BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("normalizetest", 3)); - - CClaimTrieData data; - BOOST_CHECK(!pclaimTrie->find("normalizeTest", data)); - - // Check equivalence of normalized claim names - BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1)); // collapsed tx2 - fixture.IncrementBlocks(1); - - CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "NORMALIZETEST", "one", 1); - fixture.IncrementBlocks(1); - BOOST_CHECK(!fixture.is_best_claim("normalizetest", tx3)); - - CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, "NoRmAlIzEtEsT", 2); - fixture.IncrementBlocks(1); - - // Ensure that supports work for normalized claim names - BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1)); // effective amount is 5 - BOOST_CHECK(fixture.best_claim_effective_amount_equals("normalizetest", 5)); - - CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), "foo", "bar", 1); - CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(), tx4, "Foo", 1); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("foo", tx4)); - - CMutableTransaction u1 = fixture.MakeUpdate(tx4, "foo", "baz", ClaimIdHash(tx4.GetHash(), 0), 1); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("foo", u1)); - - CMutableTransaction u2 = fixture.MakeUpdate(tx1, "nOrmalIzEtEst", "two", ClaimIdHash(tx1.GetHash(), 0), 3); - fixture.IncrementBlocks(1); - - BOOST_CHECK(fixture.is_best_claim("normalizetest", u2)); - - // Add another set of unicode claims that will collapse after the fork - CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), "Ame\u0301lie", "amelie", 2); - fixture.IncrementBlocks(1); - CClaimValue nval1; - fixture.getInfoForName("amélie", nval1); - BOOST_CHECK(nval1.claimId == ClaimIdHash(tx5.GetHash(), 0)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("amélie", 2)); - - // Check equivalence of normalized claim names - BOOST_CHECK(fixture.is_best_claim("amélie", tx5)); - - CMutableTransaction tx7 = fixture.MakeClaim(fixture.GetCoinbase(), "あてはまる", "jn1", 1); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("あてはまる", tx7)); - - CMutableTransaction tx8 = fixture.MakeClaim(fixture.GetCoinbase(), "AÑEJO", "es1", 1); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("añejo", tx8)); - - // Rewind to 1 block before the fork and be sure that the fork is no longer active - fixture.DecrementBlocks(); - - // Now check that our old (non-normalized) claims are 'alive' again - BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1)); - BOOST_CHECK(!fixture.is_best_claim("Normalizetest", tx1)); // no longer equivalent - BOOST_CHECK(fixture.is_best_claim("Normalizetest", tx2)); - - // Create new claim - CMutableTransaction tx9 = fixture.MakeClaim(fixture.GetCoinbase(), "blah", "blah", 1); - std::string invalidUtf8("\xFF\xFF"); - CMutableTransaction tx10 = fixture.MakeClaim(fixture.GetCoinbase(), invalidUtf8, "blah", 1); // invalid UTF8 - - // Roll forward to fork height again and check again that we're normalized - fixture.IncrementBlocks(1); - BOOST_CHECK(chainActive.Height() == Params().GetConsensus().nNormalizedNameForkHeight); - BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1)); // collapsed tx2 - BOOST_CHECK(fixture.is_best_claim(invalidUtf8, tx10)); - - // Rewind to 1 block before the fork and be sure that the fork is - // no longer active - fixture.DecrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("Normalizetest", tx2)); - - // Roll forward to fork height again and check again that we're normalized - fixture.IncrementBlocks(1); - BOOST_CHECK(chainActive.Height() == Params().GetConsensus().nNormalizedNameForkHeight); - BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1)); // collapsed tx2 -} - -BOOST_AUTO_TEST_CASE(claimtriecache_normalization) -{ - ClaimTrieChainFixture fixture; - - std::string name = "Ame\u0301lie"; - - std::string name_upper = "Amélie"; - std::string name_normd = "amélie"; // this accented e is not actually the same as the one above; this has been "normalized" - - BOOST_CHECK(name != name_upper); - - // Add another set of unicode claims that will collapse after the fork - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), name, "amilie", 2); - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), name_upper, "amelie", 2); - fixture.MakeClaim(fixture.GetCoinbase(), "amelie1", "amelie", 2); - fixture.IncrementBlocks(1); - - CClaimValue lookupClaim; - std::string lookupName; - BOOST_CHECK(getClaimById(ClaimIdHash(tx2.GetHash(), 0), lookupName, &lookupClaim)); - CClaimValue nval1; - BOOST_CHECK(fixture.getInfoForName("amelie1", nval1)); - // amélie is not found cause normalization still not appear - BOOST_CHECK(!fixture.getInfoForName(name_normd, nval1)); - - // Activate the fork (which rebuilds the existing claimtrie and - // cache), flattening all previously existing name clashes due to - // the normalization - fixture.setNormalizationForkHeight(1); - int currentHeight = chainActive.Height(); - - fixture.IncrementBlocks(1); - // Ok normalization fix the name problem - BOOST_CHECK(fixture.getInfoForName(name_normd, nval1)); - BOOST_CHECK(nval1.nHeight == currentHeight); - BOOST_CHECK(lookupClaim == nval1); - - CCoinsViewCache coins(pcoinsTip.get()); - CClaimTrieCache trieCache(pclaimTrie); - CBlockIndex* pindex = chainActive.Tip(); - CBlock block; - int amelieValidHeight; - BOOST_CHECK(trieCache.shouldNormalize()); - BOOST_CHECK(ReadBlockFromDisk(block, pindex, Params().GetConsensus())); - BOOST_CHECK(g_chainstate.DisconnectBlock(block, pindex, coins, trieCache) == DisconnectResult::DISCONNECT_OK); - BOOST_CHECK(!trieCache.shouldNormalize()); - BOOST_CHECK(!trieCache.spendClaim(name_normd, COutPoint(tx2.GetHash(), 0), currentHeight, amelieValidHeight)); - BOOST_CHECK(trieCache.spendClaim(name_upper, COutPoint(tx2.GetHash(), 0), currentHeight, amelieValidHeight)); - - CClaimTrieData data; - BOOST_CHECK(!pclaimTrie->find(name, data)); - BOOST_CHECK(trieCache.getInfoForName(name, nval1)); - BOOST_CHECK(trieCache.addClaim(name, COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), CAmount(2), currentHeight + 1)); - BOOST_CHECK(trieCache.getInfoForName(name, nval1)); - insertUndoType insertUndo; - claimQueueRowType expireUndo; - insertUndoType insertSupportUndo; - supportQueueRowType expireSupportUndo; - std::vector > takeoverHeightUndo; - BOOST_CHECK(trieCache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo)); - BOOST_CHECK(trieCache.shouldNormalize()); - - CClaimTrieDataNode node; - BOOST_CHECK(!pclaimTrie->find(name, node)); -} - -BOOST_AUTO_TEST_CASE(undo_normalization_does_not_kill_claim_order) -{ - ClaimTrieChainFixture fixture; - fixture.setNormalizationForkHeight(5); - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1); - CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "a", "3", 3); - fixture.IncrementBlocks(1); - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "2", 2); - fixture.IncrementBlocks(2); - BOOST_CHECK(fixture.is_best_claim("A", tx2)); - fixture.IncrementBlocks(3, true); - BOOST_CHECK(fixture.is_best_claim("a", tx3)); - fixture.DecrementBlocks(); - BOOST_CHECK(fixture.is_best_claim("A", tx2)); -} - -BOOST_AUTO_TEST_CASE(normalized_activations_fall_through) -{ - ClaimTrieChainFixture fixture; - fixture.setNormalizationForkHeight(5); - - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "AB", "1", 1); - fixture.IncrementBlocks(3); - BOOST_CHECK(fixture.proportionalDelayFactor() == 1); - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "Ab", "2", 4); - CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "aB", "2", 3); - CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), "ab", "2", 2); - fixture.IncrementBlocks(1); - - BOOST_CHECK(fixture.is_best_claim("AB", tx1)); - fixture.IncrementBlocks(3); - BOOST_CHECK(fixture.is_best_claim("ab", tx2)); - BOOST_CHECK(fixture.getClaimsForName("ab").claimsNsupports.size() == 4U); - fixture.DecrementBlocks(3); - fixture.Spend(tx1); - fixture.Spend(tx2); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("ab", tx3)); - BOOST_CHECK(fixture.getClaimsForName("ab").claimsNsupports.size() == 2U); - fixture.DecrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("AB", tx1)); - fixture.Spend(tx1); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("ab", tx2)); - - for (int i = 0; i < 7; ++i) { - fixture.IncrementBlocks(i, true); // well into normalized teritory - CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), "CD", "a", 1 + i); - fixture.IncrementBlocks(3); - CMutableTransaction tx6 = fixture.MakeClaim(fixture.GetCoinbase(), "Cd", "b", 2 + i); - CMutableTransaction tx7 = fixture.MakeClaim(fixture.GetCoinbase(), "cD", "c", 3 + i); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("cd", tx5)); - fixture.Spend(tx5); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("cd", tx7)); - fixture.DecrementBlocks(); - } -} - -BOOST_AUTO_TEST_CASE(normalization_removal_test) -{ - ClaimTrieChainFixture fixture; - fixture.setNormalizationForkHeight(2); - fixture.IncrementBlocks(3); - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "AB", "1", 1); - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "Ab", "2", 2); - CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "aB", "3", 3); - CMutableTransaction sx1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, "AB", 1); - CMutableTransaction sx2 = fixture.MakeSupport(fixture.GetCoinbase(), tx2, "Ab", 1); - - CClaimTrieCache cache(pclaimTrie); - int height = chainActive.Height() + 1; - cache.addClaim("AB", COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), 1, height); - cache.addClaim("Ab", COutPoint(tx2.GetHash(), 0), ClaimIdHash(tx2.GetHash(), 0), 2, height); - cache.addClaim("aB", COutPoint(tx3.GetHash(), 0), ClaimIdHash(tx3.GetHash(), 0), 3, height); - cache.addSupport("AB", COutPoint(sx1.GetHash(), 0), 1, ClaimIdHash(tx1.GetHash(), 0), height); - cache.addSupport("Ab", COutPoint(sx2.GetHash(), 0), 1, ClaimIdHash(tx2.GetHash(), 0), height); - insertUndoType insertUndo; - claimQueueRowType expireUndo; - insertUndoType insertSupportUndo; - supportQueueRowType expireSupportUndo; - std::vector > takeoverHeightUndo; - BOOST_CHECK(cache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo)); - BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports.size() == 3U); - BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[0].supports.size() == 1U); - BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[1].supports.size() == 0U); - BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[2].supports.size() == 1U); - BOOST_CHECK(cache.decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo)); - BOOST_CHECK(cache.finalizeDecrement(takeoverHeightUndo)); - BOOST_CHECK(cache.undoAddSupport("AB", COutPoint(sx1.GetHash(), 0), height)); - BOOST_CHECK(cache.undoAddSupport("Ab", COutPoint(sx2.GetHash(), 0), height)); - BOOST_CHECK(cache.undoAddClaim("AB", COutPoint(tx1.GetHash(), 0), height)); - BOOST_CHECK(cache.undoAddClaim("Ab", COutPoint(tx2.GetHash(), 0), height)); - BOOST_CHECK(cache.undoAddClaim("aB", COutPoint(tx3.GetHash(), 0), height)); - BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports.size() == 0U); -} - -BOOST_AUTO_TEST_CASE(normalization_does_not_kill_supports) -{ - ClaimTrieChainFixture fixture; - fixture.setNormalizationForkHeight(3); - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1); - fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2)); - fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 3)); - fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("a", 4)); - fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("a", 5)); - - fixture.DecrementBlocks(1); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("a", 4)); - fixture.DecrementBlocks(1); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 3)); - fixture.DecrementBlocks(1); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2)); - fixture.IncrementBlocks(5); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("a", 3)); -} - -BOOST_AUTO_TEST_CASE(normalization_does_not_fail_on_spend) -{ - ClaimTrieChainFixture fixture; - fixture.setNormalizationForkHeight(2); - - std::string sName1("testN"); - std::string sName2("testn"); - - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, "1", 3); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim(sName1, tx1)); - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, "2", 2); - CMutableTransaction tx1s = fixture.MakeSupport(fixture.GetCoinbase(), tx1, sName1, 2); - fixture.IncrementBlocks(2, true); - BOOST_CHECK(fixture.is_best_claim(sName2, tx1)); - - CMutableTransaction tx3 = fixture.Spend(tx1); // abandon the claim - CMutableTransaction tx3s = fixture.Spend(tx1s); - fixture.IncrementBlocks(2); - BOOST_CHECK(fixture.is_best_claim(sName2, tx2)); - fixture.DecrementBlocks(); - BOOST_CHECK(fixture.is_best_claim(sName1, tx1)); -} - -BOOST_AUTO_TEST_CASE(normalization_does_not_kill_sort_order) -{ - ClaimTrieChainFixture fixture; - fixture.setNormalizationForkHeight(2); - - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1); - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "2", 2); - CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "a", "3", 3); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("A", tx2)); - BOOST_CHECK(fixture.is_best_claim("a", tx3)); - - fixture.IncrementBlocks(1); - BOOST_CHECK(!fixture.is_best_claim("A", tx2)); - BOOST_CHECK(fixture.is_best_claim("a", tx3)); - BOOST_CHECK(fixture.getClaimsForName("a").claimsNsupports.size() == 3U); - - fixture.DecrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("A", tx2)); - BOOST_CHECK(fixture.is_best_claim("a", tx3)); -} - -BOOST_AUTO_TEST_CASE(normalization_does_not_kill_expirations) -{ - ClaimTrieChainFixture fixture; - auto& consensus = Params().GetConsensus(); - fixture.setExpirationForkHeight(consensus.nExtendedClaimExpirationForkHeight, 3, consensus.nExtendedClaimExpirationTime); - fixture.setNormalizationForkHeight(4); - // need to see that claims expiring on the frame when we normalize aren't kept - // need to see that supports expiring on the frame when we normalize aren't kept - // need to see that claims & supports carried through the normalization fork do expire - // and that they come back correctly when we roll backwards - - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1); - fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2)); - - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "B", "1", 1); - fixture.MakeSupport(fixture.GetCoinbase(), tx2, "B", 1); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("B", 2)); - - CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "C", "1", 1); - fixture.MakeSupport(fixture.GetCoinbase(), tx3, "C", 1); - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("B", 2)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("C", 2)); - - CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), "D", "1", 1); - fixture.MakeSupport(fixture.GetCoinbase(), tx4, "D", 1); - fixture.IncrementBlocks(1); - BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("b", 2)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("c", 2)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2)); - - fixture.IncrementBlocks(1); - BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2)); - BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("c", 2)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2)); - - fixture.IncrementBlocks(1); - BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2)); - BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2)); - BOOST_CHECK(!fixture.best_claim_effective_amount_equals("c", 2)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2)); - - fixture.IncrementBlocks(1); - BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2)); - BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2)); - BOOST_CHECK(!fixture.best_claim_effective_amount_equals("c", 2)); - BOOST_CHECK(!fixture.best_claim_effective_amount_equals("d", 2)); - - fixture.DecrementBlocks(2); - BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2)); - BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("c", 2)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2)); - - fixture.DecrementBlocks(1); - BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("b", 2)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("c", 2)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2)); - - fixture.DecrementBlocks(1); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("B", 2)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("C", 2)); - BOOST_CHECK(!fixture.best_claim_effective_amount_equals("d", 2)); - - fixture.IncrementBlocks(3); - BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2)); - BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2)); - BOOST_CHECK(!fixture.best_claim_effective_amount_equals("c", 2)); - BOOST_CHECK(!fixture.best_claim_effective_amount_equals("d", 2)); // (not re-added) -} - -/* - claim/support expiration for hard fork, but with checks for disk procedures -*/ -BOOST_AUTO_TEST_CASE(hardfork_disk_test) -{ - ClaimTrieChainFixture fixture; - fixture.setExpirationForkHeight(7, 3, 6); - - // Check that incrementing to fork height, reseting to disk will get proper expiration time - BOOST_CHECK_EQUAL(fixture.expirationTime(), 3); - fixture.IncrementBlocks(7, true); - BOOST_CHECK_EQUAL(fixture.expirationTime(), 6); - fixture.ReadFromDisk(chainActive.Tip()); - BOOST_CHECK_EQUAL(fixture.expirationTime(), 6); - - // Create a claim and support 1 block before the fork height that will expire after the fork height. - // Reset to disk, increment past the fork height and make sure we get - // proper behavior - fixture.DecrementBlocks(2); - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 1); - CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, "test", 1); - fixture.IncrementBlocks(1); - - fixture.ReadFromDisk(chainActive.Tip()); - BOOST_CHECK_EQUAL(fixture.expirationTime(), 3); - fixture.IncrementBlocks(1); - BOOST_CHECK_EQUAL(fixture.expirationTime(), 6); - BOOST_CHECK(fixture.is_best_claim("test", tx1)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",2)); - fixture.IncrementBlocks(2); - BOOST_CHECK(fixture.is_best_claim("test", tx1)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",2)); - fixture.DecrementBlocks(2); - fixture.IncrementBlocks(5); - BOOST_CHECK(!fixture.is_best_claim("test", tx1)); - - // Create a claim and support before the fork height, reset to disk, update the claim - // increment past the fork height and make sure we get proper behavior - fixture.DecrementBlocks(); - fixture.setExpirationForkHeight(3, 5, 6); - - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test2","one",1); - CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(),tx2,"test2",1); - fixture.IncrementBlocks(1); - fixture.ReadFromDisk(chainActive.Tip()); - CMutableTransaction u2 = fixture.MakeUpdate(tx2, "test2", "two", ClaimIdHash(tx2.GetHash(), 0), 1); - // increment to fork - fixture.IncrementBlocks(2); - BOOST_CHECK(fixture.is_best_claim("test2", u2)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("test2",2)); - // increment to original expiration, should not be expired - fixture.IncrementBlocks(2); - BOOST_CHECK(fixture.is_best_claim("test2", u2)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("test2", 2)); - fixture.DecrementBlocks(2); - // increment to extended expiration, should be expired and not one block before - fixture.IncrementBlocks(5); - BOOST_CHECK(!fixture.is_best_claim("test2", u2)); - fixture.DecrementBlocks(5); - fixture.IncrementBlocks(4); - BOOST_CHECK(fixture.is_best_claim("test2", u2)); - BOOST_CHECK(fixture.best_claim_effective_amount_equals("test2", 1)); // the support expires one block before -} - -BOOST_AUTO_TEST_CASE(insert_update_claim_test) -{ - ClaimTrieChainFixture fixture; - - std::string sName1("atest"); - std::string sName2("btest"); - std::string sName3("atest123"); - std::string sValue1("testa"); - std::string sValue2("testb"); - std::string sValue3("123testa"); - - uint256 hash0(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); - BOOST_CHECK_EQUAL(fixture.getMerkleHash(), hash0); - - CMutableTransaction tx1 = BuildTransaction(fixture.GetCoinbase()); - tx1.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME - << std::vector(sName1.begin(), sName1.end()) - << std::vector(sValue1.begin(), sValue1.end()) << OP_2DROP << OP_DROP << OP_TRUE; - uint160 tx1ClaimId = ClaimIdHash(tx1.GetHash(), 0); - COutPoint tx1OutPoint(tx1.GetHash(), 0); - - CMutableTransaction tx7 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, tx1.vout[0].nValue - 10001); - uint160 tx7ClaimId = ClaimIdHash(tx7.GetHash(), 0); - COutPoint tx7OutPoint(tx7.GetHash(), 0); - - CClaimValue val; - int nThrowaway; - - // Verify claims (tx7) for uncontrolled names go in immediately - fixture.IncrementBlocks(1, true); - - BOOST_CHECK(fixture.getInfoForName(sName1, val)); - BOOST_CHECK_EQUAL(val.outPoint, tx7OutPoint); - - // Verify claims for controlled names are delayed, and that the bigger claim wins when inserted - fixture.IncrementBlocks(5); - fixture.CommitTx(tx1); - fixture.IncrementBlocks(1); - - BOOST_CHECK(!fixture.queueEmpty()); - - fixture.IncrementBlocks(5); // 12 - - BOOST_CHECK(!fixture.queueEmpty()); - - fixture.IncrementBlocks(1); - - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(fixture.getInfoForName(sName1, val)); - BOOST_CHECK_EQUAL(val.outPoint, tx1OutPoint); - - // Verify updates to the best claim get inserted immediately, and others don't. - CMutableTransaction tx3 = fixture.MakeUpdate(tx1, sName1, sValue1, tx1ClaimId, tx1.vout[0].nValue - 10000); - COutPoint tx3OutPoint(tx3.GetHash(), 0); - CMutableTransaction tx9 = fixture.MakeUpdate(tx7, sName1, sValue2, tx7ClaimId, tx7.vout[0].nValue - 10000); - COutPoint tx9OutPoint(tx9.GetHash(), 0); - fixture.IncrementBlocks(1, true); // 14 - - BOOST_CHECK(!fixture.queueEmpty()); - BOOST_CHECK(!fixture.haveClaim(sName1, tx1OutPoint)); - BOOST_CHECK(!fixture.haveClaim(sName1, tx7OutPoint)); - BOOST_CHECK(fixture.getInfoForName(sName1, val)); - BOOST_CHECK_EQUAL(val.outPoint, tx3OutPoint); - BOOST_CHECK(fixture.haveClaimInQueue(sName1, tx9OutPoint, nThrowaway)); - - // Roll back the last block, make sure tx1 and tx7 are put back in the trie - fixture.DecrementBlocks(); // 13 - - BOOST_CHECK(fixture.getInfoForName(sName1, val)); - BOOST_CHECK_EQUAL(val.outPoint, tx1OutPoint); - BOOST_CHECK(fixture.haveClaim(sName1, tx7OutPoint)); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!pclaimTrie->empty()); - - // Roll all the way back, make sure all txs are out of the trie - fixture.DecrementBlocks(); + // Roll all the way back, make sure all txs are out of the trie + fixture.DecrementBlocks(); BOOST_CHECK(!fixture.getInfoForName(sName1, val)); BOOST_CHECK(pclaimTrie->empty()); @@ -2321,320 +1000,93 @@ BOOST_AUTO_TEST_CASE(insert_update_claim_test) fixture.IncrementBlocks(10); - BOOST_CHECK(!fixture.haveClaim(sName1, tx10OutPoint)); - BOOST_CHECK(!fixture.haveClaimInQueue(sName1, tx10OutPoint, nThrowaway)); - BOOST_CHECK(fixture.queueEmpty()); - - // update it - fixture.CommitTx(tx11); - fixture.IncrementBlocks(1); - - BOOST_CHECK(!fixture.haveClaimInQueue(sName1, tx11OutPoint, nThrowaway)); - BOOST_CHECK(!fixture.haveClaim(sName1, tx11OutPoint)); - BOOST_CHECK(fixture.queueEmpty()); - - // make sure tx11 would have gotten into the trie - - fixture.IncrementBlocks(20); - - BOOST_CHECK(!fixture.haveClaimInQueue(sName1, tx11OutPoint, nThrowaway)); - BOOST_CHECK(!fixture.haveClaim(sName1, tx11OutPoint)); - BOOST_CHECK(!fixture.haveClaimInQueue(sName1, tx10OutPoint, nThrowaway)); - BOOST_CHECK(!fixture.haveClaim(sName1, tx10OutPoint)); - BOOST_CHECK(fixture.queueEmpty()); - - // roll all the way back - fixture.DecrementBlocks(); - - // Put tx10 and tx11 in without tx1 in - fixture.CommitTx(tx10); - fixture.IncrementBlocks(1, true); - - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - - // update with tx11 - fixture.CommitTx(tx11); - fixture.IncrementBlocks(1, true); - - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - - // roll back to before tx11 - fixture.DecrementBlocks(); - - // spent tx10 with tx12 instead which is not a claim operation of any kind - CMutableTransaction tx12 = BuildTransaction(tx10); - - fixture.IncrementBlocks(1); - - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - - // roll all the way back - fixture.DecrementBlocks(); - - // make sure all claim for names which exist in the trie but have no - // values get inserted immediately - - CMutableTransaction tx13 = fixture.MakeClaim(fixture.GetCoinbase(), sName3, sValue3, 1); - fixture.IncrementBlocks(1, true); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - - fixture.CommitTx(tx1); - fixture.IncrementBlocks(1); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - - // roll back - fixture.DecrementBlocks(); -} - -BOOST_AUTO_TEST_CASE(basic_merkle_test) -{ - ClaimTrieChainFixture fixture; - - std::string sName("atest"); - std::string sValue("testa"); - - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue, 10); - fixture.IncrementBlocks(20); - uint256 tx1MerkleHash = fixture.getMerkleHash(); - fixture.DecrementBlocks(20); - BOOST_CHECK(tx1MerkleHash != fixture.getMerkleHash()); - fixture.CommitTx(tx1); - fixture.IncrementBlocks(20); - BOOST_CHECK_EQUAL(tx1MerkleHash, fixture.getMerkleHash()); -} - -BOOST_AUTO_TEST_CASE(claim_expiration_test) -{ - ClaimTrieChainFixture fixture; - - std::string sName("atest"); - std::string sValue("testa"); - - int nThrowaway; - - // set expiration time to 80 blocks after the block is created - fixture.setExpirationForkHeight(1000000, 80, 1000000); - - // create a claim. verify the expiration event has been scheduled. - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue, 10); - COutPoint tx1OutPoint(tx1.GetHash(), 0); - fixture.IncrementBlocks(1, true); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.expirationQueueEmpty()); - - // advance until the expiration event occurs. verify the expiration event occurs on time. - - fixture.IncrementBlocks(79); // 80 - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.expirationQueueEmpty()); - - fixture.IncrementBlocks(1); // 81 - - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(fixture.expirationQueueEmpty()); - - // roll forward a bit and then roll back to before the expiration event. verify the claim is reinserted. verify the expiration event is scheduled again. - fixture.IncrementBlocks(20); // 101 - - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(fixture.expirationQueueEmpty()); - - fixture.DecrementBlocks(21); // 80 - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.expirationQueueEmpty()); - - // advance until the expiration event occurs. verify the expiration event occurs on time. - fixture.IncrementBlocks(1); // 81 - - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(fixture.expirationQueueEmpty()); - - // roll back to before the expiration event. verify the claim is reinserted. verify the expiration event is scheduled again. - fixture.DecrementBlocks(2); // 79 - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.expirationQueueEmpty()); - - // roll back some more. - fixture.DecrementBlocks(39); // 40 - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.expirationQueueEmpty()); - - // spend the claim. verify the expiration event is removed. - CMutableTransaction tx2 = fixture.Spend(tx1); - fixture.IncrementBlocks(1); // 41 - - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(fixture.expirationQueueEmpty()); - - // roll back the spend. verify the expiration event is returned. - fixture.DecrementBlocks(1); // 40 - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.expirationQueueEmpty()); - - // advance until the expiration event occurs. verify the event occurs on time. - fixture.IncrementBlocks(40); // 80 - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.expirationQueueEmpty()); - - fixture.IncrementBlocks(1); // 81 - - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(fixture.expirationQueueEmpty()); - - // spend the expired claim - fixture.CommitTx(tx2); - fixture.IncrementBlocks(1); // 82 - - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(fixture.expirationQueueEmpty()); - - // undo the spend. verify everything remains empty. - fixture.DecrementBlocks(1); // 81 - - BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(!fixture.haveClaim(sName1, tx10OutPoint)); + BOOST_CHECK(!fixture.haveClaimInQueue(sName1, tx10OutPoint, nThrowaway)); BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(fixture.expirationQueueEmpty()); - // roll back to before the expiration event. verify the claim is reinserted. verify the expiration event is scheduled again. - fixture.DecrementBlocks(1); // 80 + // update it + fixture.CommitTx(tx11); + fixture.IncrementBlocks(1); - BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(!fixture.haveClaimInQueue(sName1, tx11OutPoint, nThrowaway)); + BOOST_CHECK(!fixture.haveClaim(sName1, tx11OutPoint)); BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.expirationQueueEmpty()); - // verify the expiration event happens at the right time again - fixture.IncrementBlocks(1); // 81 + // make sure tx11 would have gotten into the trie - BOOST_CHECK(pclaimTrie->empty()); + fixture.IncrementBlocks(20); + + BOOST_CHECK(!fixture.haveClaimInQueue(sName1, tx11OutPoint, nThrowaway)); + BOOST_CHECK(!fixture.haveClaim(sName1, tx11OutPoint)); + BOOST_CHECK(!fixture.haveClaimInQueue(sName1, tx10OutPoint, nThrowaway)); + BOOST_CHECK(!fixture.haveClaim(sName1, tx10OutPoint)); BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(fixture.expirationQueueEmpty()); - // roll back to before the expiration event. verify it gets reinserted and expiration gets scheduled. - fixture.DecrementBlocks(1); // 80 + // roll all the way back + fixture.DecrementBlocks(); - BOOST_CHECK(!pclaimTrie->empty()); + // Put tx10 and tx11 in without tx1 in + fixture.CommitTx(tx10); + fixture.IncrementBlocks(1, true); + + BOOST_CHECK(pclaimTrie->empty()); BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.expirationQueueEmpty()); - // roll all the way back. verify the claim is removed and the expiration event is removed. - fixture.DecrementBlocks(); // 0 + // update with tx11 + fixture.CommitTx(tx11); + fixture.IncrementBlocks(1, true); BOOST_CHECK(pclaimTrie->empty()); BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(fixture.expirationQueueEmpty()); - // Make sure that when a claim expires, a lesser claim for the same name takes over + // roll back to before tx11 + fixture.DecrementBlocks(); - CClaimValue val; + // spent tx10 with tx12 instead which is not a claim operation of any kind + CMutableTransaction tx12 = BuildTransaction(tx10); - // create one claim for the name - fixture.CommitTx(tx1); - fixture.IncrementBlocks(1, true); // 1 + fixture.IncrementBlocks(1); - BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->empty()); BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.expirationQueueEmpty()); - - // advance a little while and insert the second claim - fixture.IncrementBlocks(4); // 5 - CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue, 5); - COutPoint tx3OutPoint(tx3.GetHash(), 0); - fixture.IncrementBlocks(1); // 6 - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(!fixture.queueEmpty()); - BOOST_CHECK(!fixture.expirationQueueEmpty()); - // advance until tx3 is valid, ensure tx1 is winning - fixture.IncrementBlocks(4); // 10 + // roll all the way back + fixture.DecrementBlocks(); - BOOST_CHECK(!fixture.queueEmpty()); - BOOST_CHECK(fixture.haveClaimInQueue(sName, tx3OutPoint, nThrowaway)); + // make sure all claim for names which exist in the trie but have no + // values get inserted immediately - fixture.IncrementBlocks(1); // 11 + CMutableTransaction tx13 = fixture.MakeClaim(fixture.GetCoinbase(), sName3, sValue3, 1); + fixture.IncrementBlocks(1, true); BOOST_CHECK(!pclaimTrie->empty()); BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.expirationQueueEmpty()); - BOOST_CHECK(fixture.getInfoForName(sName, val)); - BOOST_CHECK_EQUAL(val.outPoint, tx1OutPoint); - uint256 tx1MerkleHash = fixture.getMerkleHash(); - - // roll back to before tx3 is valid - fixture.DecrementBlocks(1); // 10 - // advance again until tx is valid - fixture.IncrementBlocks(1); // 11 + fixture.CommitTx(tx1); + fixture.IncrementBlocks(1); BOOST_CHECK(!pclaimTrie->empty()); BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.expirationQueueEmpty()); - BOOST_CHECK(fixture.getInfoForName(sName, val)); - BOOST_CHECK_EQUAL(val.outPoint, tx1OutPoint); - BOOST_CHECK_EQUAL(tx1MerkleHash, fixture.getMerkleHash()); - // advance until the expiration event occurs. verify the expiration event occurs on time. - fixture.IncrementBlocks(69, true); // 80 + // roll back + fixture.DecrementBlocks(); +} - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.expirationQueueEmpty()); +BOOST_AUTO_TEST_CASE(basic_merkle_test) +{ + ClaimTrieChainFixture fixture; - fixture.IncrementBlocks(1); // 81 + std::string sName("atest"); + std::string sValue("testa"); - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.expirationQueueEmpty()); - BOOST_CHECK(fixture.getInfoForName(sName, val)); - BOOST_CHECK_EQUAL(val.outPoint, tx3OutPoint); + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue, 10); + fixture.IncrementBlocks(20); + uint256 tx1MerkleHash = fixture.getMerkleHash(); + fixture.DecrementBlocks(20); BOOST_CHECK(tx1MerkleHash != fixture.getMerkleHash()); - - // spend tx1 - fixture.CommitTx(tx2); - fixture.IncrementBlocks(1); // 82 - - // roll back to when tx1 and tx3 are in the trie and tx1 is winning - fixture.DecrementBlocks(); // 11 - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.expirationQueueEmpty()); - BOOST_CHECK(fixture.getInfoForName(sName, val)); - BOOST_CHECK_EQUAL(val.outPoint, tx1OutPoint); + fixture.CommitTx(tx1); + fixture.IncrementBlocks(20); BOOST_CHECK_EQUAL(tx1MerkleHash, fixture.getMerkleHash()); - - // roll all the way back - fixture.DecrementBlocks(); - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(fixture.expirationQueueEmpty()); } BOOST_AUTO_TEST_CASE(claimtrienode_serialize_unserialize) @@ -2700,88 +1152,6 @@ BOOST_AUTO_TEST_CASE(claimtrienode_remove_invalid_claim) BOOST_CHECK_EQUAL(invalidClaim, false); } - -BOOST_AUTO_TEST_CASE(invalid_claimid_test) -{ - ClaimTrieChainFixture fixture; - - std::string sName("atest"); - std::string sValue1("testa"); - std::string sValue2("testb"); - - CClaimValue val; - std::vector blocks_to_invalidate; - - // Verify that supports expire - - // Create a 1 LBC claim (tx1) - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue1, 1); - fixture.IncrementBlocks(1, true); // 1 - - BOOST_CHECK(pcoinsTip->HaveCoin(COutPoint(tx1.GetHash(), 0))); - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(fixture.supportEmpty()); - BOOST_CHECK(fixture.supportQueueEmpty()); - - // Make sure it gets way in there - fixture.IncrementBlocks(100); // 101 - - // Create a 5 LBC claim (tx2) - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue2, 5); - fixture.IncrementBlocks(1); // 102 - - BOOST_CHECK(pcoinsTip->HaveCoin(COutPoint(tx2.GetHash(), 0))); - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(!fixture.queueEmpty()); - - // Create a tx with a bogus claimId - uint160 tx1ClaimId = ClaimIdHash(tx1.GetHash(), 0); - CMutableTransaction tx3 = fixture.MakeUpdate(tx2, sName, sValue2, tx1ClaimId, 4); - CMutableTransaction tx4 = BuildTransaction(tx3); - COutPoint tx4OutPoint(tx4.GetHash(), 0); - - fixture.IncrementBlocks(1); // 103 - - BOOST_CHECK(pcoinsTip->HaveCoin(COutPoint(tx3.GetHash(), 0))); - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - - // Verify it's not in the claim trie - BOOST_CHECK(fixture.getInfoForName(sName, val)); - BOOST_CHECK_EQUAL(val.outPoint.hash, tx1.GetHash()); - - BOOST_CHECK(!fixture.haveClaim(sName, tx4OutPoint)); - - // Update the tx with the bogus claimId - fixture.CommitTx(tx4); - fixture.IncrementBlocks(1); // 104 - - BOOST_CHECK(pcoinsTip->HaveCoin(tx4OutPoint)); - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - - // Verify it's not in the claim trie - - BOOST_CHECK(!fixture.haveClaim(sName, tx4OutPoint)); - - BOOST_CHECK(fixture.getInfoForName(sName, val)); - BOOST_CHECK_EQUAL(val.outPoint.hash, tx1.GetHash()); - - // Go forward a few hundred blocks and verify it's not in there - - fixture.IncrementBlocks(101); // 205 - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.haveClaim(sName, tx4OutPoint)); - - // go all the way back - fixture.DecrementBlocks(); - BOOST_CHECK(pclaimTrie->empty()); -} - - BOOST_AUTO_TEST_CASE(supporting_claims_test) { ClaimTrieChainFixture fixture; @@ -3414,7 +1784,7 @@ BOOST_AUTO_TEST_CASE(supporting_claims2_test) BOOST_CHECK(fixture.supportQueueEmpty()); } -BOOST_AUTO_TEST_CASE(expiring_supports_test) +BOOST_AUTO_TEST_CASE(invalid_claimid_test) { ClaimTrieChainFixture fixture; @@ -3425,190 +1795,76 @@ BOOST_AUTO_TEST_CASE(expiring_supports_test) CClaimValue val; std::vector blocks_to_invalidate; - fixture.setExpirationForkHeight(1000000, 80, 1000000); - - // to be active bid must have: a higher block number and current block >= (current height - block number) / 32 - // Verify that supports expire // Create a 1 LBC claim (tx1) CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue1, 1); - fixture.IncrementBlocks(1); // 1, expires at 81 - - BOOST_CHECK(pcoinsTip->HaveCoin(COutPoint(tx1.GetHash(), 0))); - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(fixture.supportEmpty()); - BOOST_CHECK(fixture.supportQueueEmpty()); - - // Create a 5 LBC support (tx3) - CMutableTransaction tx3 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, sName, 5); - fixture.IncrementBlocks(1); // 2, expires at 82 - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.supportEmpty()); - BOOST_CHECK(fixture.supportQueueEmpty()); - - // Advance some, then insert 5 LBC claim (tx2) - fixture.IncrementBlocks(19); // 21 - - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue2, 5); - fixture.IncrementBlocks(1); // 22, activating in (22 - 2) / 1 = 20block (but not then active because support still holds tx1 up) - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(!fixture.queueEmpty()); - BOOST_CHECK(!fixture.supportEmpty()); - BOOST_CHECK(fixture.supportQueueEmpty()); - uint256 rootMerkleHash = fixture.getMerkleHash(); - - // Advance until tx2 is valid - fixture.IncrementBlocks(20); // 42 - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(!fixture.queueEmpty()); - BOOST_CHECK(!fixture.supportEmpty()); - BOOST_CHECK(fixture.supportQueueEmpty()); - BOOST_CHECK_EQUAL(rootMerkleHash, fixture.getMerkleHash()); - - fixture.IncrementBlocks(1); // 43 - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.supportEmpty()); - BOOST_CHECK(fixture.supportQueueEmpty()); - BOOST_CHECK(fixture.getInfoForName(sName, val)); - BOOST_CHECK_EQUAL(val.outPoint.hash, tx1.GetHash()); - rootMerkleHash = fixture.getMerkleHash(); - - // Update tx1 so that it expires after tx3 expires - uint160 claimId = ClaimIdHash(tx1.GetHash(), 0); - CMutableTransaction tx4 = fixture.MakeUpdate(tx1, sName, sValue1, claimId, tx1.vout[0].nValue); - - fixture.IncrementBlocks(1); // 104 - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.supportEmpty()); - BOOST_CHECK(fixture.supportQueueEmpty()); - BOOST_CHECK(fixture.getInfoForName(sName, val)); - BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash()); - BOOST_CHECK(rootMerkleHash != fixture.getMerkleHash()); - - // Advance until the support expires - fixture.IncrementBlocks(37); // 81 - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.supportEmpty()); - BOOST_CHECK(fixture.supportQueueEmpty()); - rootMerkleHash = fixture.getMerkleHash(); - - fixture.IncrementBlocks(1); // 82 - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(fixture.supportEmpty()); - BOOST_CHECK(fixture.supportQueueEmpty()); - BOOST_CHECK(fixture.getInfoForName(sName, val)); - BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash()); - BOOST_CHECK(rootMerkleHash != fixture.getMerkleHash()); - rootMerkleHash = fixture.getMerkleHash(); - - // undo the block, make sure control goes back - fixture.DecrementBlocks(1); // 81 - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.supportEmpty()); - BOOST_CHECK(fixture.supportQueueEmpty()); - BOOST_CHECK(fixture.getInfoForName(sName, val)); - BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash()); - BOOST_CHECK(rootMerkleHash != fixture.getMerkleHash()); - - // redo the block, make sure it expires again - fixture.IncrementBlocks(1); // 82 + fixture.IncrementBlocks(1, true); // 1 + BOOST_CHECK(pcoinsTip->HaveCoin(COutPoint(tx1.GetHash(), 0))); BOOST_CHECK(!pclaimTrie->empty()); BOOST_CHECK(fixture.queueEmpty()); BOOST_CHECK(fixture.supportEmpty()); BOOST_CHECK(fixture.supportQueueEmpty()); - BOOST_CHECK(fixture.getInfoForName(sName, val)); - BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash()); - rootMerkleHash = fixture.getMerkleHash(); - // roll back some, spend the support, and make sure nothing unexpected - // happens at the time the support should have expired + // Make sure it gets way in there + fixture.IncrementBlocks(100); // 101 - fixture.DecrementBlocks(19); // 63 + // Create a 5 LBC claim (tx2) + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue2, 5); + fixture.IncrementBlocks(1); // 102 + BOOST_CHECK(pcoinsTip->HaveCoin(COutPoint(tx2.GetHash(), 0))); BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.supportEmpty()); - BOOST_CHECK(fixture.supportQueueEmpty()); - BOOST_CHECK(fixture.getInfoForName(sName, val)); - BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash()); - BOOST_CHECK(rootMerkleHash != fixture.getMerkleHash()); + BOOST_CHECK(!fixture.queueEmpty()); - fixture.Spend(tx3); - fixture.IncrementBlocks(1); // 64 + // Create a tx with a bogus claimId + uint160 tx1ClaimId = ClaimIdHash(tx1.GetHash(), 0); + CMutableTransaction tx3 = fixture.MakeUpdate(tx2, sName, sValue2, tx1ClaimId, 4); + CMutableTransaction tx4 = BuildTransaction(tx3); + COutPoint tx4OutPoint(tx4.GetHash(), 0); - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + fixture.IncrementBlocks(1); // 103 + BOOST_CHECK(pcoinsTip->HaveCoin(COutPoint(tx3.GetHash(), 0))); BOOST_CHECK(!pclaimTrie->empty()); BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(fixture.supportEmpty()); - BOOST_CHECK(fixture.supportQueueEmpty()); - BOOST_CHECK(fixture.getInfoForName(sName, val)); - BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash()); - fixture.IncrementBlocks(20); // 84 - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(fixture.supportEmpty()); - BOOST_CHECK(fixture.supportQueueEmpty()); + // Verify it's not in the claim trie BOOST_CHECK(fixture.getInfoForName(sName, val)); - BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash()); + BOOST_CHECK_EQUAL(val.outPoint.hash, tx1.GetHash()); - //undo the spend, and make sure it still expires on time + BOOST_CHECK(!fixture.haveClaim(sName, tx4OutPoint)); - fixture.DecrementBlocks(21); // 63 + // Update the tx with the bogus claimId + fixture.CommitTx(tx4); + fixture.IncrementBlocks(1); // 104 + BOOST_CHECK(pcoinsTip->HaveCoin(tx4OutPoint)); BOOST_CHECK(!pclaimTrie->empty()); BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.supportEmpty()); - BOOST_CHECK(fixture.supportQueueEmpty()); - BOOST_CHECK(fixture.getInfoForName(sName, val)); - BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash()); - fixture.IncrementBlocks(18); // 81 + // Verify it's not in the claim trie + + BOOST_CHECK(!fixture.haveClaim(sName, tx4OutPoint)); - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(!fixture.supportEmpty()); - BOOST_CHECK(fixture.supportQueueEmpty()); BOOST_CHECK(fixture.getInfoForName(sName, val)); - BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash()); + BOOST_CHECK_EQUAL(val.outPoint.hash, tx1.GetHash()); - fixture.IncrementBlocks(1); // 82 + // Go forward a few hundred blocks and verify it's not in there + + fixture.IncrementBlocks(101); // 205 BOOST_CHECK(!pclaimTrie->empty()); BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(fixture.supportEmpty()); - BOOST_CHECK(fixture.supportQueueEmpty()); - BOOST_CHECK(fixture.getInfoForName(sName, val)); - BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash()); - - // roll all the way back - fixture.DecrementBlocks(82); + BOOST_CHECK(!fixture.haveClaim(sName, tx4OutPoint)); + // go all the way back + fixture.DecrementBlocks(); BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(fixture.queueEmpty()); - BOOST_CHECK(fixture.supportEmpty()); - BOOST_CHECK(fixture.supportQueueEmpty()); } + bool verify_proof(const CClaimTrieProof proof, uint256 rootHash, const std::string& name) { uint256 previousComputedHash; @@ -3878,236 +2134,6 @@ BOOST_AUTO_TEST_CASE(get_claim_by_id_test_2) BOOST_CHECK_EQUAL(claimValue.claimId, claimIdx); } -BOOST_AUTO_TEST_CASE(get_claim_by_id_test_3) -{ - ClaimTrieChainFixture fixture; - fixture.setExpirationForkHeight(1000000, 5, 1000000); - const std::string name = "test"; - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), name, "one", 1); - uint160 claimId = ClaimIdHash(tx1.GetHash(), 0); - - fixture.IncrementBlocks(1); - - CClaimValue claimValue; - std::string claimName; - BOOST_CHECK(getClaimById(claimId, claimName, &claimValue)); - BOOST_CHECK_EQUAL(claimName, name); - BOOST_CHECK_EQUAL(claimValue.claimId, claimId); - // make second claim with activation delay 1 - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), name, "one", 2); - uint160 claimId2 = ClaimIdHash(tx2.GetHash(), 0); - - fixture.IncrementBlocks(1); - // second claim is not activated yet, but can still access by claim id - BOOST_CHECK(fixture.is_best_claim(name, tx1)); - BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue)); - BOOST_CHECK_EQUAL(claimName, name); - BOOST_CHECK_EQUAL(claimValue.claimId, claimId2); - - fixture.IncrementBlocks(1); - // second claim has activated - BOOST_CHECK(fixture.is_best_claim(name, tx2)); - BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue)); - BOOST_CHECK_EQUAL(claimName, name); - BOOST_CHECK_EQUAL(claimValue.claimId, claimId2); - - - fixture.DecrementBlocks(1); - // second claim has been deactivated via decrement - // should still be accesible via claim id - BOOST_CHECK(fixture.is_best_claim(name, tx1)); - BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue)); - BOOST_CHECK_EQUAL(claimName, name); - BOOST_CHECK_EQUAL(claimValue.claimId, claimId2); - - fixture.IncrementBlocks(1); - // second claim should have been re activated via increment - BOOST_CHECK(fixture.is_best_claim(name, tx2)); - BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue)); - BOOST_CHECK_EQUAL(claimName, name); - BOOST_CHECK_EQUAL(claimValue.claimId, claimId2); -} - -BOOST_AUTO_TEST_CASE(getnamesintrie_test) -{ - ClaimTrieChainFixture fixture; - std::string sName1("test"); - std::string sValue1("test"); - - uint256 blockHash = chainActive.Tip()->GetBlockHash(); - - fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 42); - fixture.IncrementBlocks(1); - - rpcfn_type getnamesintrie = tableRPC["getnamesintrie"]->actor; - JSONRPCRequest req; - req.params = UniValue(UniValue::VARR); - - UniValue results = getnamesintrie(req); - BOOST_CHECK_EQUAL(results.size(), 1U); - - req.params.push_back(blockHash.GetHex()); - - results = getnamesintrie(req); - BOOST_CHECK_EQUAL(results.size(), 0U); -} - -BOOST_AUTO_TEST_CASE(getvalueforname_test) -{ - ClaimTrieChainFixture fixture; - std::string sName1("testN"); - std::string sValue1("testV"); - - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 2); - fixture.IncrementBlocks(1); - - uint256 blockHash = chainActive.Tip()->GetBlockHash(); - - fixture.MakeSupport(fixture.GetCoinbase(), tx1, sName1, 3); - fixture.IncrementBlocks(10); - - rpcfn_type getvalueforname = tableRPC["getvalueforname"]->actor; - JSONRPCRequest req; - req.params = UniValue(UniValue::VARR); - req.params.push_back(UniValue(sName1)); - - UniValue results = getvalueforname(req); - BOOST_CHECK_EQUAL(results[T_VALUE].get_str(), HexStr(sValue1)); - BOOST_CHECK_EQUAL(results[T_AMOUNT].get_int(), 2); - BOOST_CHECK_EQUAL(results[T_EFFECTIVEAMOUNT].get_int(), 5); - - req.params.push_back(blockHash.GetHex()); - - results = getvalueforname(req); - BOOST_CHECK_EQUAL(results[T_AMOUNT].get_int(), 2); - BOOST_CHECK_EQUAL(results[T_EFFECTIVEAMOUNT].get_int(), 2); -} - -BOOST_AUTO_TEST_CASE(getclaimsforname_test) -{ - ClaimTrieChainFixture fixture; - std::string sName1("testN"); - std::string sValue1("test1"); - std::string sValue2("test2"); - - int height = chainActive.Height(); - - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 2); - fixture.IncrementBlocks(1); - - uint256 blockHash = chainActive.Tip()->GetBlockHash(); - - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, 3); - fixture.IncrementBlocks(1); - - rpcfn_type getclaimsforname = tableRPC["getclaimsforname"]->actor; - JSONRPCRequest req; - req.params = UniValue(UniValue::VARR); - req.params.push_back(UniValue(sName1)); - - UniValue results = getclaimsforname(req); - UniValue claims = results[T_CLAIMS]; - BOOST_CHECK_EQUAL(claims.size(), 2U); - BOOST_CHECK_EQUAL(results[T_LASTTAKEOVERHEIGHT].get_int(), height + 1); - BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 2); - BOOST_CHECK_EQUAL(claims[0][T_SUPPORTS].size(), 0U); - - fixture.IncrementBlocks(1); - - results = getclaimsforname(req); - claims = results[T_CLAIMS]; - BOOST_CHECK_EQUAL(claims.size(), 2U); - BOOST_CHECK_EQUAL(results[T_LASTTAKEOVERHEIGHT].get_int(), height + 3); - BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 3); - BOOST_CHECK_EQUAL(claims[1][T_EFFECTIVEAMOUNT].get_int(), 2); - BOOST_CHECK_EQUAL(claims[0][T_SUPPORTS].size(), 0U); - BOOST_CHECK_EQUAL(claims[1][T_SUPPORTS].size(), 0U); - - req.params.push_back(blockHash.GetHex()); - - results = getclaimsforname(req); - claims = results[T_CLAIMS]; - BOOST_CHECK_EQUAL(claims.size(), 1U); - BOOST_CHECK_EQUAL(results[T_LASTTAKEOVERHEIGHT].get_int(), height + 1); - BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 2); - BOOST_CHECK_EQUAL(claims[0][T_SUPPORTS].size(), 0U); -} - -BOOST_AUTO_TEST_CASE(claim_rpcs_rollback2_test) -{ - ClaimTrieChainFixture fixture; - std::string sName1("testN"); - std::string sValue1("test1"); - std::string sValue2("test2"); - - int height = chainActive.Height(); - - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 1); - fixture.IncrementBlocks(2); - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, 2); - fixture.IncrementBlocks(3); - - uint256 blockHash = chainActive.Tip()->GetBlockHash(); - - CMutableTransaction tx3 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, sValue1, 3); - fixture.IncrementBlocks(1); - - rpcfn_type getclaimsforname = tableRPC["getclaimsforname"]->actor; - rpcfn_type getvalueforname = tableRPC["getvalueforname"]->actor; - JSONRPCRequest req; - req.params = UniValue(UniValue::VARR); - req.params.push_back(UniValue(sName1)); - req.params.push_back(blockHash.GetHex()); - - UniValue claimsResults = getclaimsforname(req); - BOOST_CHECK_EQUAL(claimsResults[T_LASTTAKEOVERHEIGHT].get_int(), height + 5); - BOOST_CHECK_EQUAL(claimsResults[T_CLAIMS][0][T_SUPPORTS].size(), 0U); - BOOST_CHECK_EQUAL(claimsResults[T_CLAIMS][1][T_SUPPORTS].size(), 0U); - - UniValue valueResults = getvalueforname(req); - BOOST_CHECK_EQUAL(valueResults[T_VALUE].get_str(), HexStr(sValue2)); - BOOST_CHECK_EQUAL(valueResults[T_AMOUNT].get_int(), 2); -} - -BOOST_AUTO_TEST_CASE(claim_rpcs_rollback3_test) -{ - ClaimTrieChainFixture fixture; - std::string sName1("testN"); - std::string sValue1("test1"); - std::string sValue2("test2"); - - int height = chainActive.Height(); - - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 3); - fixture.IncrementBlocks(1); - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, 2); - fixture.IncrementBlocks(2); - - uint256 blockHash = chainActive.Tip()->GetBlockHash(); - - CMutableTransaction tx3 = fixture.Spend(tx1); // abandon the claim - fixture.IncrementBlocks(1); - - rpcfn_type getclaimsforname = tableRPC["getclaimsforname"]->actor; - rpcfn_type getvalueforname = tableRPC["getvalueforname"]->actor; - rpcfn_type getblocktemplate = tableRPC["getblocktemplate"]->actor; - - JSONRPCRequest req; - req.params = UniValue(UniValue::VARR); - UniValue templateResults = getblocktemplate(req); - BOOST_CHECK_EQUAL(templateResults["claimtrie"].get_str(), chainActive.Tip()->hashClaimTrie.GetHex()); - - req.params.push_back(UniValue(sName1)); - req.params.push_back(blockHash.GetHex()); - - UniValue claimsResults = getclaimsforname(req); - BOOST_CHECK_EQUAL(claimsResults[T_LASTTAKEOVERHEIGHT].get_int(), height + 1); - - UniValue valueResults = getvalueforname(req); - BOOST_CHECK_EQUAL(valueResults[T_VALUE].get_str(), HexStr(sValue1)); - BOOST_CHECK_EQUAL(valueResults[T_AMOUNT].get_int(), 3); -} - BOOST_AUTO_TEST_CASE(update_on_support2_test) { ClaimTrieChainFixture fixture; @@ -4135,366 +2161,4 @@ BOOST_AUTO_TEST_CASE(update_on_support2_test) BOOST_CHECK_EQUAL(node.nHeightOfLastTakeover, height + 1); } -void ValidatePairs(CClaimTrieCache& cache, const std::vector>& pairs, uint256 claimHash) -{ - for (auto& pair : pairs) - if (pair.first) // we're on the right because we were an odd index number - claimHash = Hash(pair.second.begin(), pair.second.end(), claimHash.begin(), claimHash.end()); - else - claimHash = Hash(claimHash.begin(), claimHash.end(), pair.second.begin(), pair.second.end()); - - BOOST_CHECK_EQUAL(cache.getMerkleHash(), claimHash); -} - -BOOST_AUTO_TEST_CASE(hash_includes_all_claims_rollback_test) -{ - ClaimTrieChainFixture fixture; - fixture.setHashForkHeight(5); - - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 1); - fixture.IncrementBlocks(1); - - uint256 currentRoot = fixture.getMerkleHash(); - fixture.IncrementBlocks(1); - BOOST_CHECK_EQUAL(currentRoot, fixture.getMerkleHash()); - fixture.IncrementBlocks(3); - BOOST_CHECK_NE(currentRoot, fixture.getMerkleHash()); - fixture.DecrementBlocks(3); - BOOST_CHECK_EQUAL(currentRoot, fixture.getMerkleHash()); -} - -BOOST_AUTO_TEST_CASE(hash_includes_all_claims_single_test) -{ - ClaimTrieChainFixture fixture; - fixture.setHashForkHeight(2); - fixture.IncrementBlocks(4); - - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 1); - fixture.IncrementBlocks(1); - - COutPoint outPoint(tx1.GetHash(), 0); - uint160 claimId = ClaimIdHash(tx1.GetHash(), 0); - - CClaimTrieProof proof; - BOOST_CHECK(fixture.getProofForName("test", proof, [&claimId](const CClaimValue& claim) { - return claim.claimId == claimId; - })); - BOOST_CHECK(proof.hasValue); - BOOST_CHECK_EQUAL(proof.outPoint, outPoint); - auto claimHash = getValueHash(outPoint, proof.nHeightOfLastTakeover); - ValidatePairs(fixture, proof.pairs, claimHash); -} - -BOOST_AUTO_TEST_CASE(hash_includes_all_claims_triple_test) -{ - ClaimTrieChainFixture fixture; - fixture.setHashForkHeight(2); - fixture.IncrementBlocks(4); - - std::string names[] = {"test", "tester", "tester2"}; - CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "one", 1); - CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "two", 2); - CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "thr", 3); - CMutableTransaction tx7 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "for", 4); - CMutableTransaction tx8 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "fiv", 5); - CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), names[1], "two", 2); - CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), names[1], "thr", 3); - CMutableTransaction tx6 = fixture.MakeClaim(fixture.GetCoinbase(), names[2], "one", 1); - fixture.IncrementBlocks(1); - - for (const auto& name : names) { - for (auto& claimSupports : fixture.getClaimsForName(name).claimsNsupports) { - CClaimTrieProof proof; - auto& claim = claimSupports.claim; - BOOST_CHECK(fixture.getProofForName(name, proof, [&claim](const CClaimValue& value) { - return claim.claimId == value.claimId; - })); - BOOST_CHECK(proof.hasValue); - BOOST_CHECK_EQUAL(proof.outPoint, claim.outPoint); - uint256 claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover); - ValidatePairs(fixture, proof.pairs, claimHash); - } - } -} - -BOOST_AUTO_TEST_CASE(hash_includes_all_claims_branched_test) -{ - ClaimTrieChainFixture fixture; - fixture.setHashForkHeight(2); - fixture.IncrementBlocks(4); - - std::string names[] = {"test", "toast", "tot", "top", "toa", "toad"}; - for (const auto& name : names) - fixture.MakeClaim(fixture.GetCoinbase(), name, "one", 1); - - fixture.MakeClaim(fixture.GetCoinbase(), "toa", "two", 2); - fixture.MakeClaim(fixture.GetCoinbase(), "toa", "tre", 3); - fixture.MakeClaim(fixture.GetCoinbase(), "toa", "qua", 4); - fixture.MakeClaim(fixture.GetCoinbase(), "toa", "cin", 5); - fixture.IncrementBlocks(1); - - for (const auto& name : names) { - for (auto& claimSupports : fixture.getClaimsForName(name).claimsNsupports) { - CClaimTrieProof proof; - auto& claim = claimSupports.claim; - BOOST_CHECK(fixture.getProofForName(name, proof, [&claim](const CClaimValue& value) { - return claim.claimId == value.claimId; - })); - BOOST_CHECK(proof.hasValue); - BOOST_CHECK_EQUAL(proof.outPoint, claim.outPoint); - uint256 claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover); - ValidatePairs(fixture, proof.pairs, claimHash); - } - } -} - -BOOST_AUTO_TEST_CASE(hash_claims_children_fuzzer_test) -{ - ClaimTrieChainFixture fixture; - fixture.setHashForkHeight(2); - fixture.IncrementBlocks(4); - - std::size_t i = 0; - auto names = random_strings(300); - auto lastTx = MakeTransactionRef(fixture.GetCoinbase()); - for (const auto& name : names) { - auto tx = fixture.MakeClaim(*lastTx, name, "one", 1); - lastTx = MakeTransactionRef(std::move(tx)); - if (++i % 5 == 0) - for (std::size_t j = 0; j < (i / 5); ++j) { - auto tx = fixture.MakeClaim(*lastTx, name, "one", 1); - lastTx = MakeTransactionRef(std::move(tx)); - } - fixture.IncrementBlocks(1); - } - - for (const auto& name : names) { - for (auto& claimSupports : fixture.getClaimsForName(name).claimsNsupports) { - CClaimTrieProof proof; - auto& claim = claimSupports.claim; - BOOST_CHECK(fixture.getProofForName(name, proof, [&claim](const CClaimValue& value) { - return claim.claimId == value.claimId; - })); - BOOST_CHECK(proof.hasValue); - BOOST_CHECK_EQUAL(proof.outPoint, claim.outPoint); - uint256 claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover); - ValidatePairs(fixture, proof.pairs, claimHash); - } - } -} - -std::vector> jsonToPairs(const UniValue& jsonPair) -{ - std::vector> pairs; - for (std::size_t i = 0; i < jsonPair.size(); ++i) { - auto& jpair = jsonPair[i]; - pairs.emplace_back(jpair[T_ODD].get_bool(), uint256S(jpair[T_HASH].get_str())); - } - return pairs; -} - -BOOST_AUTO_TEST_CASE(hash_bid_seq_claim_changes_test) -{ - ClaimTrieChainFixture fixture; - fixture.setHashForkHeight(2); - fixture.IncrementBlocks(4); - - std::string name = "toa"; - std::string value1 = "one", value2 = "two", value3 = "tre", value4 = "for"; - - auto tx1 = fixture.MakeClaim(fixture.GetCoinbase(), name, value1, 1); - fixture.IncrementBlocks(1); - - CMutableTransaction tx2 = BuildTransaction(fixture.GetCoinbase(), 0, 2); - tx2.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME - << std::vector(name.begin(), name.end()) - << std::vector(value2.begin(), value2.end()) << OP_2DROP << OP_DROP << OP_TRUE; - tx2.vout[0].nValue = 3; - tx2.vout[1].scriptPubKey = CScript() << OP_CLAIM_NAME - << std::vector(name.begin(), name.end()) - << std::vector(value3.begin(), value3.end()) << OP_2DROP << OP_DROP << OP_TRUE; - tx2.vout[1].nValue = 2; - - fixture.CommitTx(tx2); - fixture.IncrementBlocks(1); - - auto tx3 = fixture.MakeClaim(fixture.GetCoinbase(), name, value4, 4); - fixture.IncrementBlocks(1); - - int height = chainActive.Height(); - - auto claimId1 = ClaimIdHash(tx1.GetHash(), 0); - auto claimId2 = ClaimIdHash(tx2.GetHash(), 0); - auto claimId3 = ClaimIdHash(tx2.GetHash(), 1); - auto claimId4 = ClaimIdHash(tx3.GetHash(), 0); - - int claim1bid = 3, claim1seq = 0; - int claim2bid = 1, claim2seq = 1; - int claim3bid = 2, claim3seq = 2; - int claim4bid = 0, claim4seq = 3; - - auto getclaimsforname = tableRPC["getclaimsforname"]->actor; - - JSONRPCRequest req; - req.params = UniValue(UniValue::VARR); - req.params.push_back(UniValue(name)); - - auto result = getclaimsforname(req); - auto claims = result[T_CLAIMS]; - BOOST_CHECK_EQUAL(claims.size(), 4U); - BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height); - BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 4); - BOOST_CHECK_EQUAL(claims[0][T_BID].get_int(), claim4bid); - BOOST_CHECK_EQUAL(claims[0][T_SEQUENCE].get_int(), claim4seq); - BOOST_CHECK_EQUAL(claims[0][T_CLAIMID].get_str(), claimId4.GetHex()); - BOOST_CHECK_EQUAL(claims[1][T_EFFECTIVEAMOUNT].get_int(), 3); - BOOST_CHECK_EQUAL(claims[1][T_BID].get_int(), claim2bid); - BOOST_CHECK_EQUAL(claims[1][T_SEQUENCE].get_int(), claim2seq); - BOOST_CHECK_EQUAL(claims[1][T_CLAIMID].get_str(), claimId2.GetHex()); - BOOST_CHECK_EQUAL(claims[2][T_EFFECTIVEAMOUNT].get_int(), 2); - BOOST_CHECK_EQUAL(claims[2][T_BID].get_int(), claim3bid); - BOOST_CHECK_EQUAL(claims[2][T_SEQUENCE].get_int(), claim3seq); - BOOST_CHECK_EQUAL(claims[2][T_CLAIMID].get_str(), claimId3.GetHex()); - BOOST_CHECK_EQUAL(claims[3][T_EFFECTIVEAMOUNT].get_int(), 1); - BOOST_CHECK_EQUAL(claims[3][T_BID].get_int(), claim1bid); - BOOST_CHECK_EQUAL(claims[3][T_SEQUENCE].get_int(), claim1seq); - BOOST_CHECK_EQUAL(claims[3][T_CLAIMID].get_str(), claimId1.GetHex()); - - auto getclaimbybid = tableRPC["getclaimbybid"]->actor; - req.params = UniValue(UniValue::VARR); - req.params.push_back(UniValue(name)); - req.params.push_back(UniValue(claim3bid)); - - result = getclaimbybid(req); - BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height); - BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 2); - BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim3bid); - BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim3seq); - BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId3.GetHex()); - - auto getclaimbyseq = tableRPC["getclaimbyseq"]->actor; - req.params = UniValue(UniValue::VARR); - req.params.push_back(UniValue(name)); - req.params.push_back(UniValue(claim2seq)); - - result = getclaimbyseq(req); - BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height); - BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 3); - BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim2bid); - BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim2seq); - BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId2.GetHex()); - - auto getclaimbyid = tableRPC["getclaimbyid"]->actor; - req.params = UniValue(UniValue::VARR); - req.params.push_back(UniValue(claimId1.GetHex())); - - result = getclaimbyid(req); - BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height); - BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 1); - BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim1bid); - BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim1seq); - BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId1.GetHex()); - - // check by partial id (at least 3 chars) - req.params = UniValue(UniValue::VARR); - req.params.push_back(UniValue(claimId3.GetHex().substr(0, 3))); - - result = getclaimbyid(req); - BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height); - BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 2); - BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim3bid); - BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim3seq); - BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId3.GetHex()); - - auto blockhash = chainActive.Tip()->GetBlockHash(); - - auto getnameproof = tableRPC["getnameproof"]->actor; - req.params = UniValue(UniValue::VARR); - req.params.push_back(UniValue(name)); - req.params.push_back(UniValue(blockhash.GetHex())); - req.params.push_back(UniValue(claimId3.GetHex())); - - result = getnameproof(req); - auto claimHash = getValueHash(COutPoint(tx2.GetHash(), 1), result[T_LASTTAKEOVERHEIGHT].get_int()); - ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash); - - // check by partial id (can be even 1 char) - req.params = UniValue(UniValue::VARR); - req.params.push_back(UniValue(name)); - req.params.push_back(UniValue(blockhash.GetHex())); - req.params.push_back(UniValue(claimId2.GetHex().substr(0, 2))); - - result = getnameproof(req); - claimHash = getValueHash(COutPoint(tx2.GetHash(), 0), result[T_LASTTAKEOVERHEIGHT].get_int()); - ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash); - - auto getclaimproofbybid = tableRPC["getclaimproofbybid"]->actor; - req.params = UniValue(UniValue::VARR); - req.params.push_back(UniValue(name)); - req.params.push_back(UniValue(claim1bid)); - - result = getclaimproofbybid(req); - claimHash = getValueHash(COutPoint(tx1.GetHash(), 0), result[T_LASTTAKEOVERHEIGHT].get_int()); - ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash); - - auto getclaimproofbyseq = tableRPC["getclaimproofbyseq"]->actor; - req.params = UniValue(UniValue::VARR); - req.params.push_back(UniValue(name)); - req.params.push_back(UniValue(claim4seq)); - - result = getclaimproofbyseq(req); - claimHash = getValueHash(COutPoint(tx3.GetHash(), 0), result[T_LASTTAKEOVERHEIGHT].get_int()); - ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash); - - auto getchangesinblock = tableRPC["getchangesinblock"]->actor; - req.params = UniValue(UniValue::VARR); - req.params.push_back(UniValue(blockhash.GetHex())); - - result = getchangesinblock(req); - BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED].size(), 3); - BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED][0].get_str(), claimId2.GetHex()); - BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED][1].get_str(), claimId3.GetHex()); - BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED][2].get_str(), claimId4.GetHex()); - BOOST_CHECK_EQUAL(result[T_CLAIMSREMOVED].size(), 0); - BOOST_CHECK_EQUAL(result[T_SUPPORTSADDEDORUPDATED].size(), 0); - BOOST_CHECK_EQUAL(result[T_SUPPORTSREMOVED].size(), 0); -} - -BOOST_AUTO_TEST_CASE(claim_rpc_pending_amount_test) -{ - ClaimTrieChainFixture fixture; - std::string sName1("test"); - std::string sValue1("test1"); - std::string sValue2("test2"); - - rpcfn_type getclaimsforname = tableRPC["getclaimsforname"]->actor; - - JSONRPCRequest req; - req.params = UniValue(UniValue::VARR); - req.params.push_back(UniValue(sName1)); - - fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 1); - fixture.IncrementBlocks(1); - - fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, 2); - fixture.IncrementBlocks(1); - - auto claims = getclaimsforname(req)[T_CLAIMS]; - BOOST_CHECK_EQUAL(claims.size(), 2U); - BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 1); - BOOST_CHECK(!claims[0].exists(T_PENDINGAMOUNT)); - BOOST_CHECK_EQUAL(claims[1][T_EFFECTIVEAMOUNT].get_int(), 0); - BOOST_CHECK(claims[1].exists(T_PENDINGAMOUNT)); - BOOST_CHECK_EQUAL(claims[1][T_PENDINGAMOUNT].get_int(), 2); - - fixture.IncrementBlocks(1); - - claims = getclaimsforname(req)[T_CLAIMS]; - BOOST_CHECK_EQUAL(claims.size(), 2U); - BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 2); - BOOST_CHECK(!claims[0].exists(T_PENDINGAMOUNT)); - BOOST_CHECK_EQUAL(claims[1][T_EFFECTIVEAMOUNT].get_int(), 1); - BOOST_CHECK(!claims[1].exists(T_PENDINGAMOUNT)); -} - BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/claimtriecache_tests.cpp b/src/test/claimtriecache_tests.cpp index 697b6e0af2..102ff32456 100644 --- a/src/test/claimtriecache_tests.cpp +++ b/src/test/claimtriecache_tests.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -42,23 +43,6 @@ class CClaimTrieCacheTest : public CClaimTrieCacheBase } }; -CMutableTransaction BuildTransaction(const uint256& prevhash) -{ - CMutableTransaction tx; - tx.nVersion = 1; - tx.nLockTime = 0; - tx.vin.resize(1); - tx.vout.resize(1); - tx.vin[0].prevout.hash = prevhash; - tx.vin[0].prevout.n = 0; - tx.vin[0].scriptSig = CScript(); - tx.vin[0].nSequence = std::numeric_limits::max(); - tx.vout[0].scriptPubKey = CScript(); - tx.vout[0].nValue = 0; - - return tx; -} - BOOST_FIXTURE_TEST_SUITE(claimtriecache_tests, RegTestingSetup) BOOST_AUTO_TEST_CASE(merkle_hash_single_test) diff --git a/src/test/claimtrieexpirationfork_tests.cpp b/src/test/claimtrieexpirationfork_tests.cpp new file mode 100644 index 0000000000..df6176d5bc --- /dev/null +++ b/src/test/claimtrieexpirationfork_tests.cpp @@ -0,0 +1,803 @@ +// Copyright (c) 2015-2019 The LBRY Foundation +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://opensource.org/licenses/mit-license.php + +#include + +using namespace std; + +BOOST_FIXTURE_TEST_SUITE(claimtrieexpirationfork_tests, RegTestingSetup) + +/* + expiration + check claims expire and loses claim + check claims expire and is not updateable (may be changed in future soft fork) + check supports expire and can cause supported bid to lose claim +*/ +BOOST_AUTO_TEST_CASE(claimtrie_expire_test) +{ + ClaimTrieChainFixture fixture; + fixture.setExpirationForkHeight(1000000, 5, 1000000); + + // check claims expire and loses claim + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(),"test", "one", 2); + fixture.IncrementBlocks(fixture.expirationTime()); + BOOST_CHECK(fixture.is_best_claim("test", tx1)); + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test", "one", 1); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("test", tx2)); + + fixture.DecrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("test", tx1)); + fixture.DecrementBlocks(fixture.expirationTime()); + + // check claims expire and is not updateable (may be changed in future soft fork) + CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(),"test", "one", 2); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("test", tx3)); + fixture.IncrementBlocks(fixture.expirationTime()); + CMutableTransaction u1 = fixture.MakeUpdate(tx3, "test", "two", ClaimIdHash(tx3.GetHash(), 0), 2); + BOOST_CHECK(!fixture.is_best_claim("test",u1)); + + fixture.DecrementBlocks(fixture.expirationTime()); + BOOST_CHECK(fixture.is_best_claim("test", tx3)); + fixture.DecrementBlocks(1); + + // check supports expire and can cause supported bid to lose claim + CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 1); + CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 2); + CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(), tx4, "test", 2); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("test",tx4)); + CMutableTransaction u2 = fixture.MakeUpdate(tx4, "test", "two", ClaimIdHash(tx4.GetHash(),0), 1); + CMutableTransaction u3 = fixture.MakeUpdate(tx5, "test", "two", ClaimIdHash(tx5.GetHash(),0), 2); + fixture.IncrementBlocks(fixture.expirationTime()); + BOOST_CHECK(fixture.is_best_claim("test", u3)); + fixture.DecrementBlocks(fixture.expirationTime()); + BOOST_CHECK(fixture.is_best_claim("test", tx4)); + fixture.DecrementBlocks(1); + + // check updated claims will extend expiration + CMutableTransaction tx6 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 2); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("test", tx6)); + CMutableTransaction u4 = fixture.MakeUpdate(tx6, "test", "two", ClaimIdHash(tx6.GetHash(), 0), 2); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("test", u4)); + fixture.IncrementBlocks(fixture.expirationTime()-1); + BOOST_CHECK(fixture.is_best_claim("test", u4)); + fixture.IncrementBlocks(1); + BOOST_CHECK(!fixture.is_best_claim("test", u4)); + fixture.DecrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("test", u4)); + fixture.DecrementBlocks(fixture.expirationTime()); + BOOST_CHECK(fixture.is_best_claim("test", tx6)); +} + +/* + claim expiration for hard fork + check claims do not expire post ExpirationForkHeight + check supports work post ExpirationForkHeight +*/ +BOOST_AUTO_TEST_CASE(hardfork_claim_test) +{ + ClaimTrieChainFixture fixture; + fixture.setExpirationForkHeight(7, 3, 6); + + // First create a claim and make sure it expires pre-fork + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",3); + fixture.IncrementBlocks(4); + BOOST_CHECK(!fixture.is_best_claim("test",tx1)); + fixture.DecrementBlocks(3); + BOOST_CHECK(fixture.is_best_claim("test",tx1)); + fixture.IncrementBlocks(3); + BOOST_CHECK(!fixture.is_best_claim("test",tx1)); + + // Create a claim 1 block before the fork height that will expire after the fork height + fixture.IncrementBlocks(1); + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test2","one",3); + fixture.IncrementBlocks(1); + BOOST_CHECK_EQUAL(fixture.expirationTime(), 3); + + // Disable future expirations and fast-forward past the fork height + fixture.IncrementBlocks(1); + BOOST_CHECK_EQUAL(fixture.expirationTime(), 6); + // make sure decrementing to before the fork height will apppropriately set back the + // expiration time to the original expiraiton time + fixture.DecrementBlocks(1); + BOOST_CHECK_EQUAL(fixture.expirationTime(), 3); + fixture.IncrementBlocks(1); + BOOST_CHECK_EQUAL(fixture.expirationTime(), 6); + + // make sure that claim created 1 block before the fork expires as expected + // at the extended expiration times + BOOST_CHECK(fixture.is_best_claim("test2", tx2)); + fixture.IncrementBlocks(5); + BOOST_CHECK(!fixture.is_best_claim("test2", tx2)); + fixture.DecrementBlocks(5); + BOOST_CHECK(fixture.is_best_claim("test2", tx2)); + + // This first claim is still expired since it's pre-fork, even + // after fork activation + BOOST_CHECK(!fixture.is_best_claim("test", tx1)); + + // This new claim created at the fork height cannot expire at original expiration + CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",1); + fixture.IncrementBlocks(1); + fixture.IncrementBlocks(3); + BOOST_CHECK(fixture.is_best_claim("test",tx3)); + BOOST_CHECK(!fixture.is_best_claim("test",tx1)); + fixture.DecrementBlocks(3); + + // but it expires at the extended expiration, and not a single block below + fixture.IncrementBlocks(6); + BOOST_CHECK(!fixture.is_best_claim("test",tx3)); + fixture.DecrementBlocks(6); + fixture.IncrementBlocks(5); + BOOST_CHECK(fixture.is_best_claim("test",tx3)); + fixture.DecrementBlocks(5); + + // Ensure that we cannot update the original pre-fork expired claim + CMutableTransaction u1 = fixture.MakeUpdate(tx1,"test","two",ClaimIdHash(tx1.GetHash(),0), 3); + fixture.IncrementBlocks(1); + BOOST_CHECK(!fixture.is_best_claim("test",u1)); + + // Ensure that supports for the expired claim don't support it + CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(),u1,"test",10); + BOOST_CHECK(!fixture.is_best_claim("test",u1)); + + // Ensure that we can update the new post-fork claim + CMutableTransaction u2 = fixture.MakeUpdate(tx3,"test","two",ClaimIdHash(tx3.GetHash(),0), 1); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("test",u2)); + + // Ensure that supports for the new post-fork claim + CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(),u2,"test",3); + BOOST_CHECK(fixture.is_best_claim("test",u2)); +} + +/* + support expiration for hard fork +*/ +BOOST_AUTO_TEST_CASE(hardfork_support_test) +{ + ClaimTrieChainFixture fixture; + fixture.setExpirationForkHeight(2, 2, 4); + + // Create claim and support it before the fork height + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 1); + CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, "test", 2); + // this claim will win without the support + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",2); + fixture.IncrementBlocks(2); + + // check that the claim expires as expected at the extended time, as does the support + fixture.IncrementBlocks(2); + BOOST_CHECK(fixture.is_best_claim("test",tx1)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",3)); + fixture.DecrementBlocks(2); + fixture.IncrementBlocks(3); + BOOST_CHECK(!fixture.is_best_claim("test",tx1)); + fixture.DecrementBlocks(3); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("test",tx1)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",3)); + fixture.DecrementBlocks(1); + + // update the claims at fork + fixture.DecrementBlocks(1); + CMutableTransaction u1 = fixture.MakeUpdate(tx1, "test", "two", ClaimIdHash(tx1.GetHash(),0), 1); + CMutableTransaction u2 = fixture.MakeUpdate(tx2, "test", "two", ClaimIdHash(tx2.GetHash(),0), 2); + fixture.IncrementBlocks(1); + BOOST_CHECK_EQUAL(Params().GetConsensus().nExtendedClaimExpirationForkHeight, chainActive.Height()); + + BOOST_CHECK(fixture.is_best_claim("test", u1)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",3)); + BOOST_CHECK(!fixture.is_claim_in_queue("test", tx1)); + BOOST_CHECK(!fixture.is_claim_in_queue("test", tx2)); + + // check that the support expires as expected + fixture.IncrementBlocks(3); + BOOST_CHECK(fixture.is_best_claim("test", u2)); + fixture.DecrementBlocks(3); + fixture.IncrementBlocks(2); + BOOST_CHECK(fixture.is_best_claim("test",u1)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",3)); +} + +/* + activation_fall_through and supports_fall_through + Tests for where claims/supports in queues would be undone properly in a decrement. + See https://github.com/lbryio/lbrycrd/issues/243 for more details +*/ + +BOOST_AUTO_TEST_CASE(activations_fall_through) +{ + ClaimTrieChainFixture fixture; + + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1); + fixture.IncrementBlocks(3); + BOOST_CHECK_EQUAL(fixture.proportionalDelayFactor(), 1); + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "2", 3); + fixture.IncrementBlocks(1); + + BOOST_CHECK(fixture.is_best_claim("A", tx1)); + fixture.IncrementBlocks(3); + BOOST_CHECK(fixture.is_best_claim("A", tx2)); + fixture.DecrementBlocks(3); + fixture.Spend(tx1); // this will trigger early activation on tx2 claim + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("A", tx2)); + fixture.DecrementBlocks(1); //reorg the early activation + BOOST_CHECK(fixture.is_best_claim("A", tx1)); + fixture.Spend(tx1); + fixture.IncrementBlocks(1); // this should not cause tx2 to activate again and crash + BOOST_CHECK(fixture.is_best_claim("A", tx2)); +} + +BOOST_AUTO_TEST_CASE(supports_fall_through) +{ + ClaimTrieChainFixture fixture; + + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 3); + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "2", 1); + CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "3", 2); + fixture.IncrementBlocks(3); + BOOST_CHECK_EQUAL(fixture.proportionalDelayFactor(), 1); + CMutableTransaction sx2 = fixture.MakeSupport(fixture.GetCoinbase(), tx2, "A", 3); + fixture.IncrementBlocks(1); + + BOOST_CHECK(fixture.is_best_claim("A", tx1)); + fixture.IncrementBlocks(3); + BOOST_CHECK(fixture.is_best_claim("A", tx2)); + fixture.DecrementBlocks(3); + fixture.Spend(tx1); // this will trigger early activation + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("A", tx2)); + fixture.DecrementBlocks(1); // reorg the early activation + BOOST_CHECK(fixture.is_best_claim("A", tx1)); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("A", tx1)); //tx2 support should not be active + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("A", tx1)); //tx2 support should not be active + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("A", tx2)); //tx2 support should be active now +} + +/* + claim/support expiration for hard fork, but with checks for disk procedures +*/ +BOOST_AUTO_TEST_CASE(hardfork_disk_test) +{ + ClaimTrieChainFixture fixture; + fixture.setExpirationForkHeight(7, 3, 6); + + // Check that incrementing to fork height, reseting to disk will get proper expiration time + BOOST_CHECK_EQUAL(fixture.expirationTime(), 3); + fixture.IncrementBlocks(7, true); + BOOST_CHECK_EQUAL(fixture.expirationTime(), 6); + fixture.ReadFromDisk(chainActive.Tip()); + BOOST_CHECK_EQUAL(fixture.expirationTime(), 6); + + // Create a claim and support 1 block before the fork height that will expire after the fork height. + // Reset to disk, increment past the fork height and make sure we get + // proper behavior + fixture.DecrementBlocks(2); + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 1); + CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, "test", 1); + fixture.IncrementBlocks(1); + + fixture.ReadFromDisk(chainActive.Tip()); + BOOST_CHECK_EQUAL(fixture.expirationTime(), 3); + fixture.IncrementBlocks(1); + BOOST_CHECK_EQUAL(fixture.expirationTime(), 6); + BOOST_CHECK(fixture.is_best_claim("test", tx1)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",2)); + fixture.IncrementBlocks(2); + BOOST_CHECK(fixture.is_best_claim("test", tx1)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",2)); + fixture.DecrementBlocks(2); + fixture.IncrementBlocks(5); + BOOST_CHECK(!fixture.is_best_claim("test", tx1)); + + // Create a claim and support before the fork height, reset to disk, update the claim + // increment past the fork height and make sure we get proper behavior + fixture.DecrementBlocks(); + fixture.setExpirationForkHeight(3, 5, 6); + + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test2","one",1); + CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(),tx2,"test2",1); + fixture.IncrementBlocks(1); + fixture.ReadFromDisk(chainActive.Tip()); + CMutableTransaction u2 = fixture.MakeUpdate(tx2, "test2", "two", ClaimIdHash(tx2.GetHash(), 0), 1); + // increment to fork + fixture.IncrementBlocks(2); + BOOST_CHECK(fixture.is_best_claim("test2", u2)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("test2",2)); + // increment to original expiration, should not be expired + fixture.IncrementBlocks(2); + BOOST_CHECK(fixture.is_best_claim("test2", u2)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("test2", 2)); + fixture.DecrementBlocks(2); + // increment to extended expiration, should be expired and not one block before + fixture.IncrementBlocks(5); + BOOST_CHECK(!fixture.is_best_claim("test2", u2)); + fixture.DecrementBlocks(5); + fixture.IncrementBlocks(4); + BOOST_CHECK(fixture.is_best_claim("test2", u2)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("test2", 1)); // the support expires one block before +} + +BOOST_AUTO_TEST_CASE(claim_expiration_test) +{ + ClaimTrieChainFixture fixture; + + std::string sName("atest"); + std::string sValue("testa"); + + int nThrowaway; + + // set expiration time to 80 blocks after the block is created + fixture.setExpirationForkHeight(1000000, 80, 1000000); + + // create a claim. verify the expiration event has been scheduled. + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue, 10); + COutPoint tx1OutPoint(tx1.GetHash(), 0); + fixture.IncrementBlocks(1, true); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.expirationQueueEmpty()); + + // advance until the expiration event occurs. verify the expiration event occurs on time. + + fixture.IncrementBlocks(79); // 80 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.expirationQueueEmpty()); + + fixture.IncrementBlocks(1); // 81 + + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(fixture.expirationQueueEmpty()); + + // roll forward a bit and then roll back to before the expiration event. verify the claim is reinserted. verify the expiration event is scheduled again. + fixture.IncrementBlocks(20); // 101 + + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(fixture.expirationQueueEmpty()); + + fixture.DecrementBlocks(21); // 80 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.expirationQueueEmpty()); + + // advance until the expiration event occurs. verify the expiration event occurs on time. + fixture.IncrementBlocks(1); // 81 + + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(fixture.expirationQueueEmpty()); + + // roll back to before the expiration event. verify the claim is reinserted. verify the expiration event is scheduled again. + fixture.DecrementBlocks(2); // 79 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.expirationQueueEmpty()); + + // roll back some more. + fixture.DecrementBlocks(39); // 40 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.expirationQueueEmpty()); + + // spend the claim. verify the expiration event is removed. + CMutableTransaction tx2 = fixture.Spend(tx1); + fixture.IncrementBlocks(1); // 41 + + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(fixture.expirationQueueEmpty()); + + // roll back the spend. verify the expiration event is returned. + fixture.DecrementBlocks(1); // 40 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.expirationQueueEmpty()); + + // advance until the expiration event occurs. verify the event occurs on time. + fixture.IncrementBlocks(40); // 80 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.expirationQueueEmpty()); + + fixture.IncrementBlocks(1); // 81 + + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(fixture.expirationQueueEmpty()); + + // spend the expired claim + fixture.CommitTx(tx2); + fixture.IncrementBlocks(1); // 82 + + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(fixture.expirationQueueEmpty()); + + // undo the spend. verify everything remains empty. + fixture.DecrementBlocks(1); // 81 + + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(fixture.expirationQueueEmpty()); + + // roll back to before the expiration event. verify the claim is reinserted. verify the expiration event is scheduled again. + fixture.DecrementBlocks(1); // 80 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.expirationQueueEmpty()); + + // verify the expiration event happens at the right time again + fixture.IncrementBlocks(1); // 81 + + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(fixture.expirationQueueEmpty()); + + // roll back to before the expiration event. verify it gets reinserted and expiration gets scheduled. + fixture.DecrementBlocks(1); // 80 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.expirationQueueEmpty()); + + // roll all the way back. verify the claim is removed and the expiration event is removed. + fixture.DecrementBlocks(); // 0 + + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(fixture.expirationQueueEmpty()); + + // Make sure that when a claim expires, a lesser claim for the same name takes over + + CClaimValue val; + + // create one claim for the name + fixture.CommitTx(tx1); + fixture.IncrementBlocks(1, true); // 1 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.expirationQueueEmpty()); + + // advance a little while and insert the second claim + fixture.IncrementBlocks(4); // 5 + CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue, 5); + COutPoint tx3OutPoint(tx3.GetHash(), 0); + fixture.IncrementBlocks(1); // 6 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(!fixture.queueEmpty()); + BOOST_CHECK(!fixture.expirationQueueEmpty()); + + // advance until tx3 is valid, ensure tx1 is winning + fixture.IncrementBlocks(4); // 10 + + BOOST_CHECK(!fixture.queueEmpty()); + BOOST_CHECK(fixture.haveClaimInQueue(sName, tx3OutPoint, nThrowaway)); + + fixture.IncrementBlocks(1); // 11 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.expirationQueueEmpty()); + BOOST_CHECK(fixture.getInfoForName(sName, val)); + BOOST_CHECK_EQUAL(val.outPoint, tx1OutPoint); + uint256 tx1MerkleHash = fixture.getMerkleHash(); + + // roll back to before tx3 is valid + fixture.DecrementBlocks(1); // 10 + + // advance again until tx is valid + fixture.IncrementBlocks(1); // 11 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.expirationQueueEmpty()); + BOOST_CHECK(fixture.getInfoForName(sName, val)); + BOOST_CHECK_EQUAL(val.outPoint, tx1OutPoint); + BOOST_CHECK_EQUAL(tx1MerkleHash, fixture.getMerkleHash()); + + // advance until the expiration event occurs. verify the expiration event occurs on time. + fixture.IncrementBlocks(69, true); // 80 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.expirationQueueEmpty()); + + fixture.IncrementBlocks(1); // 81 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.expirationQueueEmpty()); + BOOST_CHECK(fixture.getInfoForName(sName, val)); + BOOST_CHECK_EQUAL(val.outPoint, tx3OutPoint); + BOOST_CHECK(tx1MerkleHash != fixture.getMerkleHash()); + + // spend tx1 + fixture.CommitTx(tx2); + fixture.IncrementBlocks(1); // 82 + + // roll back to when tx1 and tx3 are in the trie and tx1 is winning + fixture.DecrementBlocks(); // 11 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.expirationQueueEmpty()); + BOOST_CHECK(fixture.getInfoForName(sName, val)); + BOOST_CHECK_EQUAL(val.outPoint, tx1OutPoint); + BOOST_CHECK_EQUAL(tx1MerkleHash, fixture.getMerkleHash()); + + // roll all the way back + fixture.DecrementBlocks(); + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(fixture.expirationQueueEmpty()); +} + +BOOST_AUTO_TEST_CASE(expiring_supports_test) +{ + ClaimTrieChainFixture fixture; + + std::string sName("atest"); + std::string sValue1("testa"); + std::string sValue2("testb"); + + CClaimValue val; + std::vector blocks_to_invalidate; + + fixture.setExpirationForkHeight(1000000, 80, 1000000); + + // to be active bid must have: a higher block number and current block >= (current height - block number) / 32 + + // Verify that supports expire + + // Create a 1 LBC claim (tx1) + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue1, 1); + fixture.IncrementBlocks(1); // 1, expires at 81 + + BOOST_CHECK(pcoinsTip->HaveCoin(COutPoint(tx1.GetHash(), 0))); + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(fixture.supportEmpty()); + BOOST_CHECK(fixture.supportQueueEmpty()); + + // Create a 5 LBC support (tx3) + CMutableTransaction tx3 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, sName, 5); + fixture.IncrementBlocks(1); // 2, expires at 82 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.supportEmpty()); + BOOST_CHECK(fixture.supportQueueEmpty()); + + // Advance some, then insert 5 LBC claim (tx2) + fixture.IncrementBlocks(19); // 21 + + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue2, 5); + fixture.IncrementBlocks(1); // 22, activating in (22 - 2) / 1 = 20block (but not then active because support still holds tx1 up) + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(!fixture.queueEmpty()); + BOOST_CHECK(!fixture.supportEmpty()); + BOOST_CHECK(fixture.supportQueueEmpty()); + uint256 rootMerkleHash = fixture.getMerkleHash(); + + // Advance until tx2 is valid + fixture.IncrementBlocks(20); // 42 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(!fixture.queueEmpty()); + BOOST_CHECK(!fixture.supportEmpty()); + BOOST_CHECK(fixture.supportQueueEmpty()); + BOOST_CHECK_EQUAL(rootMerkleHash, fixture.getMerkleHash()); + + fixture.IncrementBlocks(1); // 43 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.supportEmpty()); + BOOST_CHECK(fixture.supportQueueEmpty()); + BOOST_CHECK(fixture.getInfoForName(sName, val)); + BOOST_CHECK_EQUAL(val.outPoint.hash, tx1.GetHash()); + rootMerkleHash = fixture.getMerkleHash(); + + // Update tx1 so that it expires after tx3 expires + uint160 claimId = ClaimIdHash(tx1.GetHash(), 0); + CMutableTransaction tx4 = fixture.MakeUpdate(tx1, sName, sValue1, claimId, tx1.vout[0].nValue); + + fixture.IncrementBlocks(1); // 104 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.supportEmpty()); + BOOST_CHECK(fixture.supportQueueEmpty()); + BOOST_CHECK(fixture.getInfoForName(sName, val)); + BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash()); + BOOST_CHECK(rootMerkleHash != fixture.getMerkleHash()); + + // Advance until the support expires + fixture.IncrementBlocks(37); // 81 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.supportEmpty()); + BOOST_CHECK(fixture.supportQueueEmpty()); + rootMerkleHash = fixture.getMerkleHash(); + + fixture.IncrementBlocks(1); // 82 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(fixture.supportEmpty()); + BOOST_CHECK(fixture.supportQueueEmpty()); + BOOST_CHECK(fixture.getInfoForName(sName, val)); + BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash()); + BOOST_CHECK(rootMerkleHash != fixture.getMerkleHash()); + rootMerkleHash = fixture.getMerkleHash(); + + // undo the block, make sure control goes back + fixture.DecrementBlocks(1); // 81 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.supportEmpty()); + BOOST_CHECK(fixture.supportQueueEmpty()); + BOOST_CHECK(fixture.getInfoForName(sName, val)); + BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash()); + BOOST_CHECK(rootMerkleHash != fixture.getMerkleHash()); + + // redo the block, make sure it expires again + fixture.IncrementBlocks(1); // 82 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(fixture.supportEmpty()); + BOOST_CHECK(fixture.supportQueueEmpty()); + BOOST_CHECK(fixture.getInfoForName(sName, val)); + BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash()); + rootMerkleHash = fixture.getMerkleHash(); + + // roll back some, spend the support, and make sure nothing unexpected + // happens at the time the support should have expired + + fixture.DecrementBlocks(19); // 63 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.supportEmpty()); + BOOST_CHECK(fixture.supportQueueEmpty()); + BOOST_CHECK(fixture.getInfoForName(sName, val)); + BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash()); + BOOST_CHECK(rootMerkleHash != fixture.getMerkleHash()); + + fixture.Spend(tx3); + fixture.IncrementBlocks(1); // 64 + + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(fixture.supportEmpty()); + BOOST_CHECK(fixture.supportQueueEmpty()); + BOOST_CHECK(fixture.getInfoForName(sName, val)); + BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash()); + + fixture.IncrementBlocks(20); // 84 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(fixture.supportEmpty()); + BOOST_CHECK(fixture.supportQueueEmpty()); + BOOST_CHECK(fixture.getInfoForName(sName, val)); + BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash()); + + //undo the spend, and make sure it still expires on time + + fixture.DecrementBlocks(21); // 63 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.supportEmpty()); + BOOST_CHECK(fixture.supportQueueEmpty()); + BOOST_CHECK(fixture.getInfoForName(sName, val)); + BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash()); + + fixture.IncrementBlocks(18); // 81 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(!fixture.supportEmpty()); + BOOST_CHECK(fixture.supportQueueEmpty()); + BOOST_CHECK(fixture.getInfoForName(sName, val)); + BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash()); + + fixture.IncrementBlocks(1); // 82 + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(fixture.supportEmpty()); + BOOST_CHECK(fixture.supportQueueEmpty()); + BOOST_CHECK(fixture.getInfoForName(sName, val)); + BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash()); + + // roll all the way back + fixture.DecrementBlocks(82); + + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(fixture.queueEmpty()); + BOOST_CHECK(fixture.supportEmpty()); + BOOST_CHECK(fixture.supportQueueEmpty()); +} + +BOOST_AUTO_TEST_CASE(get_claim_by_id_test_3) +{ + ClaimTrieChainFixture fixture; + fixture.setExpirationForkHeight(1000000, 5, 1000000); + const std::string name = "test"; + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), name, "one", 1); + uint160 claimId = ClaimIdHash(tx1.GetHash(), 0); + + fixture.IncrementBlocks(1); + + CClaimValue claimValue; + std::string claimName; + BOOST_CHECK(getClaimById(claimId, claimName, &claimValue)); + BOOST_CHECK_EQUAL(claimName, name); + BOOST_CHECK_EQUAL(claimValue.claimId, claimId); + // make second claim with activation delay 1 + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), name, "one", 2); + uint160 claimId2 = ClaimIdHash(tx2.GetHash(), 0); + + fixture.IncrementBlocks(1); + // second claim is not activated yet, but can still access by claim id + BOOST_CHECK(fixture.is_best_claim(name, tx1)); + BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue)); + BOOST_CHECK_EQUAL(claimName, name); + BOOST_CHECK_EQUAL(claimValue.claimId, claimId2); + + fixture.IncrementBlocks(1); + // second claim has activated + BOOST_CHECK(fixture.is_best_claim(name, tx2)); + BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue)); + BOOST_CHECK_EQUAL(claimName, name); + BOOST_CHECK_EQUAL(claimValue.claimId, claimId2); + + + fixture.DecrementBlocks(1); + // second claim has been deactivated via decrement + // should still be accesible via claim id + BOOST_CHECK(fixture.is_best_claim(name, tx1)); + BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue)); + BOOST_CHECK_EQUAL(claimName, name); + BOOST_CHECK_EQUAL(claimValue.claimId, claimId2); + + fixture.IncrementBlocks(1); + // second claim should have been re activated via increment + BOOST_CHECK(fixture.is_best_claim(name, tx2)); + BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue)); + BOOST_CHECK_EQUAL(claimName, name); + BOOST_CHECK_EQUAL(claimValue.claimId, claimId2); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/claimtriefixture.cpp b/src/test/claimtriefixture.cpp new file mode 100644 index 0000000000..24042b5a36 --- /dev/null +++ b/src/test/claimtriefixture.cpp @@ -0,0 +1,409 @@ +// Copyright (c) 2015-2019 The LBRY Foundation +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://opensource.org/licenses/mit-license.php + +#include +#include + +using namespace std; + +CMutableTransaction BuildTransaction(const CTransaction& prev, uint32_t prevout, unsigned int numOutputs, int locktime) +{ + CMutableTransaction tx; + tx.nVersion = CTransaction::CURRENT_VERSION; + tx.vin.resize(1); + tx.vout.resize(numOutputs); + tx.vin[0].prevout.hash = prev.GetHash(); + tx.vin[0].prevout.n = prevout; + tx.vin[0].scriptSig = CScript(); + if (locktime != 0) { + // Use a relative locktime for validity X blocks in the future + tx.nLockTime = chainActive.Height() + locktime; + tx.vin[0].nSequence = 0xffffffff - 1; + } else { + tx.nLockTime = 1 << 31; // Disable BIP68 + tx.vin[0].nSequence = std::numeric_limits::max(); + } + CAmount valuePerOutput = prev.vout[prevout].nValue; + unsigned int numOutputsCopy = numOutputs; + while ((numOutputsCopy = numOutputsCopy >> 1) > 0) + valuePerOutput = valuePerOutput >> 1; + + for (unsigned int i = 0; i < numOutputs; ++i) { + tx.vout[i].scriptPubKey = CScript(); + tx.vout[i].nValue = valuePerOutput; + } + return tx; +} + +CMutableTransaction BuildTransaction(const uint256& prevhash) +{ + CMutableTransaction tx; + tx.nVersion = 1; + tx.nLockTime = 0; + tx.vin.resize(1); + tx.vout.resize(1); + tx.vin[0].prevout.hash = prevhash; + tx.vin[0].prevout.n = 0; + tx.vin[0].scriptSig = CScript(); + tx.vin[0].nSequence = std::numeric_limits::max(); + tx.vout[0].scriptPubKey = CScript(); + tx.vout[0].nValue = 0; + + return tx; +} + +BlockAssembler AssemblerForTest() +{ + BlockAssembler::Options options; + options.nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT; + options.blockMinFeeRate = CFeeRate(0); + return BlockAssembler(Params(), options); +} + +ClaimTrieChainFixture::ClaimTrieChainFixture() : CClaimTrieCache(pclaimTrie), + unique_block_counter(0), normalization_original(-1), expirationForkHeight(-1), forkhash_original(-1) +{ + fRequireStandard = false; + BOOST_CHECK_EQUAL(nNextHeight, chainActive.Height() + 1); + setNormalizationForkHeight(1000000); + + gArgs.ForceSetArg("-limitancestorcount", "1000000"); + gArgs.ForceSetArg("-limitancestorsize", "1000000"); + gArgs.ForceSetArg("-limitdescendantcount", "1000000"); + gArgs.ForceSetArg("-limitdescendantsize", "1000000"); + + num_txs_for_next_block = 0; + coinbase_txs_used = 0; + unique_block_counter = 0; + added_unchecked = false; + // generate coinbases to spend + CreateCoinbases(40, coinbase_txs); +} + +ClaimTrieChainFixture::~ClaimTrieChainFixture() +{ + added_unchecked = false; + DecrementBlocks(chainActive.Height()); + auto& consensus = const_cast(Params().GetConsensus()); + if (normalization_original >= 0) + consensus.nNormalizedNameForkHeight = normalization_original; + + if (expirationForkHeight >= 0) { + consensus.nExtendedClaimExpirationForkHeight = expirationForkHeight; + consensus.nExtendedClaimExpirationTime = extendedExpiration; + consensus.nOriginalClaimExpirationTime = originalExpiration; + } + if (forkhash_original >= 0) + consensus.nAllClaimsInMerkleForkHeight = forkhash_original; +} + +void ClaimTrieChainFixture::setExpirationForkHeight(int targetMinusCurrent, int64_t preForkExpirationTime, int64_t postForkExpirationTime) +{ + int target = chainActive.Height() + targetMinusCurrent; + auto& consensus = const_cast(Params().GetConsensus()); + if (expirationForkHeight < 0) { + expirationForkHeight = consensus.nExtendedClaimExpirationForkHeight; + originalExpiration = consensus.nOriginalClaimExpirationTime; + extendedExpiration = consensus.nExtendedClaimExpirationTime; + } + consensus.nExtendedClaimExpirationForkHeight = target; + consensus.nExtendedClaimExpirationTime = postForkExpirationTime; + consensus.nOriginalClaimExpirationTime = preForkExpirationTime; + setExpirationTime(targetMinusCurrent >= 0 ? preForkExpirationTime : postForkExpirationTime); +} + +void ClaimTrieChainFixture::setNormalizationForkHeight(int targetMinusCurrent) +{ + int target = chainActive.Height() + targetMinusCurrent; + auto& consensus = const_cast(Params().GetConsensus()); + if (normalization_original < 0) + normalization_original = consensus.nNormalizedNameForkHeight; + consensus.nNormalizedNameForkHeight = target; +} + +void ClaimTrieChainFixture::setHashForkHeight(int targetMinusCurrent) +{ + int target = chainActive.Height() + targetMinusCurrent; + auto& consensus = const_cast(Params().GetConsensus()); + if (forkhash_original < 0) + forkhash_original = consensus.nAllClaimsInMerkleForkHeight; + consensus.nAllClaimsInMerkleForkHeight = target; +} + +bool ClaimTrieChainFixture::CreateBlock(const std::unique_ptr& pblocktemplate) +{ + CBlock* pblock = &pblocktemplate->block; + { + LOCK(cs_main); + pblock->nVersion = 5; + pblock->hashPrevBlock = chainActive.Tip()->GetBlockHash(); + pblock->nTime = chainActive.Tip()->GetBlockTime() + Params().GetConsensus().nPowTargetSpacing; + CMutableTransaction txCoinbase(*pblock->vtx[0]); + txCoinbase.vin[0].scriptSig = CScript() << int(chainActive.Height() + 1) << int(++unique_block_counter); + txCoinbase.vout[0].nValue = GetBlockSubsidy(chainActive.Height() + 1, Params().GetConsensus()); + pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase)); + pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); + for (uint32_t i = 0;; ++i) { + pblock->nNonce = i; + if (CheckProofOfWork(pblock->GetPoWHash(), pblock->nBits, Params().GetConsensus())) + break; + } + } + auto success = ProcessNewBlock(Params(), std::make_shared(*pblock), true, nullptr); + return success && pblock->GetHash() == chainActive.Tip()->GetBlockHash(); +} + +bool ClaimTrieChainFixture::CreateCoinbases(unsigned int num_coinbases, std::vector& coinbases) +{ + std::unique_ptr pblocktemplate; + coinbases.clear(); + BOOST_CHECK(pblocktemplate = AssemblerForTest().CreateNewBlock(CScript() << OP_TRUE)); + BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 1); + for (unsigned int i = 0; i < 100 + num_coinbases; ++i) { + BOOST_CHECK(CreateBlock(pblocktemplate)); + if (coinbases.size() < num_coinbases) + coinbases.push_back(std::move(*pblocktemplate->block.vtx[0])); + } + return true; +} + +void ClaimTrieChainFixture::CommitTx(const CMutableTransaction &tx, bool has_locktime) +{ + num_txs_for_next_block++; + if (has_locktime) { + added_unchecked = true; + TestMemPoolEntryHelper entry; + LOCK(mempool.cs); + mempool.addUnchecked(tx.GetHash(), entry.Fee(0).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + } else { + CValidationState state; + CAmount txFeeRate = CAmount(0); + LOCK(cs_main); + BOOST_CHECK_EQUAL(AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), nullptr, nullptr, false, txFeeRate, false), true); + } +} + +// spend a bid into some non claimtrie related unspent +CMutableTransaction ClaimTrieChainFixture::Spend(const CTransaction &prev) +{ + CMutableTransaction tx = BuildTransaction(prev, 0); + tx.vout[0].scriptPubKey = CScript() << OP_TRUE; + tx.vout[0].nValue = prev.vout[0].nValue; + + CommitTx(tx); + return tx; +} + +// make claim at the current block +CMutableTransaction ClaimTrieChainFixture::MakeClaim(const CTransaction& prev, const std::string& name, const std::string& value, CAmount quantity, int locktime) +{ + uint32_t prevout = prev.vout.size() - 1; + while (prevout > 0 && prev.vout[prevout].nValue < quantity) + --prevout; + CMutableTransaction tx = BuildTransaction(prev, prevout, prev.vout[prevout].nValue > quantity ? 2 : 1, locktime); + tx.vout[0].scriptPubKey = ClaimNameScript(name, value); + tx.vout[0].nValue = quantity; + if (tx.vout.size() > 1) { + tx.vout[1].scriptPubKey = CScript() << OP_TRUE; + tx.vout[1].nValue = prev.vout[prevout].nValue - quantity; + } + + CommitTx(tx, locktime != 0); + return tx; +} + +CMutableTransaction ClaimTrieChainFixture::MakeClaim(const CTransaction& prev, const std::string& name, const std::string& value) +{ + return MakeClaim(prev, name, value, prev.vout[0].nValue, 0); +} + +// make support at the current block +CMutableTransaction ClaimTrieChainFixture::MakeSupport(const CTransaction &prev, const CTransaction &claimtx, const std::string& name, CAmount quantity) +{ + uint32_t prevout = prev.vout.size() - 1; + while (prevout > 0 && prev.vout[prevout].nValue < quantity) + --prevout; + CMutableTransaction tx = BuildTransaction(prev, prevout, prev.vout[prevout].nValue > quantity ? 2 : 1); + tx.vout[0].scriptPubKey = SupportClaimScript(name, ClaimIdHash(claimtx.GetHash(), 0)); + tx.vout[0].nValue = quantity; + if (tx.vout.size() > 1) { + tx.vout[1].scriptPubKey = CScript() << OP_TRUE; + tx.vout[1].nValue = prev.vout[prevout].nValue - quantity; + } + + CommitTx(tx); + return tx; +} + +// make update at the current block +CMutableTransaction ClaimTrieChainFixture::MakeUpdate(const CTransaction &prev, const std::string& name, const std::string& value, const uint160& claimId, CAmount quantity) +{ + CMutableTransaction tx = BuildTransaction(prev, 0); + tx.vout[0].scriptPubKey = UpdateClaimScript(name, claimId, value); + tx.vout[0].nValue = quantity; + + CommitTx(tx); + return tx; +} + +CTransaction ClaimTrieChainFixture::GetCoinbase() +{ + return coinbase_txs.at(coinbase_txs_used++); +} + +// create i blocks +void ClaimTrieChainFixture::IncrementBlocks(int num_blocks, bool mark) +{ + if (mark) + marks.push_back(chainActive.Height()); + + clear(); // clears the internal cache + for (int i = 0; i < num_blocks; ++i) { + CScript coinbase_scriptpubkey; + coinbase_scriptpubkey << CScriptNum(chainActive.Height()); + std::unique_ptr pblocktemplate = AssemblerForTest().CreateNewBlock(coinbase_scriptpubkey); + BOOST_CHECK(pblocktemplate != nullptr); + if (!added_unchecked) + BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), num_txs_for_next_block + 1); + BOOST_CHECK_EQUAL(CreateBlock(pblocktemplate), true); + num_txs_for_next_block = 0; + nNextHeight = chainActive.Height() + 1; + } + setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight - 1)); +} + +// disconnect i blocks from tip +void ClaimTrieChainFixture::DecrementBlocks(int num_blocks) +{ + clear(); // clears the internal cache + CValidationState state; + { + LOCK(cs_main); + CBlockIndex* pblockindex = chainActive[chainActive.Height() - num_blocks + 1]; + BOOST_CHECK_EQUAL(InvalidateBlock(state, Params(), pblockindex), true); + } + BOOST_CHECK_EQUAL(state.IsValid(), true); + BOOST_CHECK_EQUAL(ActivateBestChain(state, Params()), true); + mempool.clear(); + num_txs_for_next_block = 0; + nNextHeight = chainActive.Height() + 1; + setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight - 1)); +} + +// decrement back to last mark +void ClaimTrieChainFixture::DecrementBlocks() +{ + int mark = marks.back(); + marks.pop_back(); + DecrementBlocks(chainActive.Height() - mark); +} + +template +bool ClaimTrieChainFixture::keyTypeEmpty(uint8_t keyType) +{ + boost::scoped_ptr pcursor(base->db->NewIterator()); + pcursor->SeekToFirst(); + + while (pcursor->Valid()) { + std::pair key; + if (pcursor->GetKey(key)) + if (key.first == keyType) + return false; + pcursor->Next(); + } + return true; +} + +bool ClaimTrieChainFixture::queueEmpty() +{ + for (const auto& claimQueue: claimQueueCache) + if (!claimQueue.second.empty()) + return false; + return keyTypeEmpty(CLAIM_QUEUE_ROW); +} + +bool ClaimTrieChainFixture::expirationQueueEmpty() +{ + for (const auto& expirationQueue: expirationQueueCache) + if (!expirationQueue.second.empty()) + return false; + return keyTypeEmpty(CLAIM_EXP_QUEUE_ROW); +} + +bool ClaimTrieChainFixture::supportEmpty() +{ + for (const auto& entry: supportCache) + if (!entry.second.empty()) + return false; + return supportCache.empty() && keyTypeEmpty(SUPPORT); +} + +bool ClaimTrieChainFixture::supportQueueEmpty() +{ + for (const auto& support: supportQueueCache) + if (!support.second.empty()) + return false; + return keyTypeEmpty(SUPPORT_QUEUE_ROW); +} + +int ClaimTrieChainFixture::proportionalDelayFactor() +{ + return base->nProportionalDelayFactor; +} + +boost::test_tools::predicate_result negativeResult(const std::function& callback) +{ + boost::test_tools::predicate_result res(false); + callback(res.message()); + return res; +} + +boost::test_tools::predicate_result negativeResult(const std::string& message) +{ + return negativeResult([&message](boost::wrap_stringstream& stream) { + stream << message; + }); +} + +// is a claim in queue +boost::test_tools::predicate_result ClaimTrieChainFixture::is_claim_in_queue(const std::string& name, const CTransaction &tx) +{ + COutPoint outPoint(tx.GetHash(), 0); + int validAtHeight; + if (haveClaimInQueue(name, outPoint, validAtHeight)) + return true; + return negativeResult("Is not a claim in queue"); +} + +// check if tx is best claim based on outpoint +boost::test_tools::predicate_result ClaimTrieChainFixture::is_best_claim(const std::string& name, const CTransaction &tx) +{ + CClaimValue val; + COutPoint outPoint(tx.GetHash(), 0); + bool have_claim = haveClaim(name, outPoint); + bool have_info = getInfoForName(name, val); + if (have_claim && have_info && val.outPoint == outPoint) + return true; + return negativeResult("Is not best claim"); +} + +// check effective quantity of best claim +boost::test_tools::predicate_result ClaimTrieChainFixture::best_claim_effective_amount_equals(const std::string& name, CAmount amount) +{ + CClaimValue val; + bool have_info = getInfoForName(name, val); + if (!have_info) + return negativeResult("No claim found"); + CAmount effective_amount = getClaimsForName(name).find(val.claimId).effectiveAmount; + if (effective_amount != amount) + return negativeResult([amount, effective_amount](boost::wrap_stringstream& stream) { + stream << amount << " != " << effective_amount; + }); + return true; +} + +std::size_t ClaimTrieChainFixture::getTotalNamesInTrie() const +{ + return base->getTotalNamesInTrie(); +} diff --git a/src/test/claimtriefixture.h b/src/test/claimtriefixture.h new file mode 100644 index 0000000000..f1c1108606 --- /dev/null +++ b/src/test/claimtriefixture.h @@ -0,0 +1,124 @@ +// Copyright (c) 2015-2019 The LBRY Foundation +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://opensource.org/licenses/mit-license.php + +#ifndef _CLAIMTRIEFIXTURE_H_ +#define _CLAIMTRIEFIXTURE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +extern ::CChainState g_chainstate; +extern ::ArgsManager gArgs; +extern std::vector random_strings(std::size_t count); +extern bool getClaimById(const uint160&, std::string&, CClaimValue*); + +CMutableTransaction BuildTransaction(const uint256& prevhash); +CMutableTransaction BuildTransaction(const CTransaction& prev, uint32_t prevout=0, unsigned int numOutputs=1, int locktime=0); + +BlockAssembler AssemblerForTest(); + +// Test Fixtures +struct ClaimTrieChainFixture: public CClaimTrieCache +{ + std::vector coinbase_txs; + std::vector marks; + int coinbase_txs_used; + int unique_block_counter; + int normalization_original; + unsigned int num_txs_for_next_block; + bool added_unchecked; + + int64_t expirationForkHeight; + int64_t originalExpiration; + int64_t extendedExpiration; + int64_t forkhash_original; + + using CClaimTrieCache::getSupportsForName; + + ClaimTrieChainFixture(); + + ~ClaimTrieChainFixture(); + + void setExpirationForkHeight(int targetMinusCurrent, int64_t preForkExpirationTime, int64_t postForkExpirationTime); + + void setNormalizationForkHeight(int targetMinusCurrent); + + void setHashForkHeight(int targetMinusCurrent); + + bool CreateBlock(const std::unique_ptr& pblocktemplate); + + bool CreateCoinbases(unsigned int num_coinbases, std::vector& coinbases); + + void CommitTx(const CMutableTransaction &tx, bool has_locktime=false); + + // spend a bid into some non claimtrie related unspent + CMutableTransaction Spend(const CTransaction &prev); + + // make claim at the current block + CMutableTransaction MakeClaim(const CTransaction& prev, const std::string& name, const std::string& value, CAmount quantity, int locktime=0); + + CMutableTransaction MakeClaim(const CTransaction& prev, const std::string& name, const std::string& value); + + // make support at the current block + CMutableTransaction MakeSupport(const CTransaction &prev, const CTransaction &claimtx, const std::string& name, CAmount quantity); + + // make update at the current block + CMutableTransaction MakeUpdate(const CTransaction &prev, const std::string& name, const std::string& value, const uint160& claimId, CAmount quantity); + + CTransaction GetCoinbase(); + + // create i blocks + void IncrementBlocks(int num_blocks, bool mark = false); + + // disconnect i blocks from tip + void DecrementBlocks(int num_blocks); + + // decrement back to last mark + void DecrementBlocks(); + + bool queueEmpty(); + + bool expirationQueueEmpty(); + + bool supportEmpty(); + + bool supportQueueEmpty(); + + int proportionalDelayFactor(); + + // is a claim in queue + boost::test_tools::predicate_result is_claim_in_queue(const std::string& name, const CTransaction &tx); + + // check if tx is best claim based on outpoint + boost::test_tools::predicate_result is_best_claim(const std::string& name, const CTransaction &tx); + + // check effective quantity of best claim + boost::test_tools::predicate_result best_claim_effective_amount_equals(const std::string& name, CAmount amount); + + std::size_t getTotalNamesInTrie() const; + +private: + template + bool keyTypeEmpty(uint8_t keyType); +}; + +#endif // _CLAIMTRIEFIXTURE_H_ diff --git a/src/test/claimtriehashfork_tests.cpp b/src/test/claimtriehashfork_tests.cpp new file mode 100644 index 0000000000..d747f75477 --- /dev/null +++ b/src/test/claimtriehashfork_tests.cpp @@ -0,0 +1,159 @@ +// Copyright (c) 2015-2019 The LBRY Foundation +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://opensource.org/licenses/mit-license.php + +#include + +using namespace std; + +void ValidatePairs(CClaimTrieCache& cache, const std::vector>& pairs, uint256 claimHash) +{ + for (auto& pair : pairs) + if (pair.first) // we're on the right because we were an odd index number + claimHash = Hash(pair.second.begin(), pair.second.end(), claimHash.begin(), claimHash.end()); + else + claimHash = Hash(claimHash.begin(), claimHash.end(), pair.second.begin(), pair.second.end()); + + BOOST_CHECK_EQUAL(cache.getMerkleHash(), claimHash); +} + +BOOST_FIXTURE_TEST_SUITE(claimtriehashfork_tests, RegTestingSetup) + +BOOST_AUTO_TEST_CASE(hash_includes_all_claims_rollback_test) +{ + ClaimTrieChainFixture fixture; + fixture.setHashForkHeight(5); + + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 1); + fixture.IncrementBlocks(1); + + uint256 currentRoot = fixture.getMerkleHash(); + fixture.IncrementBlocks(1); + BOOST_CHECK_EQUAL(currentRoot, fixture.getMerkleHash()); + fixture.IncrementBlocks(3); + BOOST_CHECK_NE(currentRoot, fixture.getMerkleHash()); + fixture.DecrementBlocks(3); + BOOST_CHECK_EQUAL(currentRoot, fixture.getMerkleHash()); +} + +BOOST_AUTO_TEST_CASE(hash_includes_all_claims_single_test) +{ + ClaimTrieChainFixture fixture; + fixture.setHashForkHeight(2); + fixture.IncrementBlocks(4); + + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 1); + fixture.IncrementBlocks(1); + + COutPoint outPoint(tx1.GetHash(), 0); + uint160 claimId = ClaimIdHash(tx1.GetHash(), 0); + + CClaimTrieProof proof; + BOOST_CHECK(fixture.getProofForName("test", proof, [&claimId](const CClaimValue& claim) { + return claim.claimId == claimId; + })); + BOOST_CHECK(proof.hasValue); + BOOST_CHECK_EQUAL(proof.outPoint, outPoint); + auto claimHash = getValueHash(outPoint, proof.nHeightOfLastTakeover); + ValidatePairs(fixture, proof.pairs, claimHash); +} + +BOOST_AUTO_TEST_CASE(hash_includes_all_claims_triple_test) +{ + ClaimTrieChainFixture fixture; + fixture.setHashForkHeight(2); + fixture.IncrementBlocks(4); + + std::string names[] = {"test", "tester", "tester2"}; + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "one", 1); + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "two", 2); + CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "thr", 3); + CMutableTransaction tx7 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "for", 4); + CMutableTransaction tx8 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "fiv", 5); + CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), names[1], "two", 2); + CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), names[1], "thr", 3); + CMutableTransaction tx6 = fixture.MakeClaim(fixture.GetCoinbase(), names[2], "one", 1); + fixture.IncrementBlocks(1); + + for (const auto& name : names) { + for (auto& claimSupports : fixture.getClaimsForName(name).claimsNsupports) { + CClaimTrieProof proof; + auto& claim = claimSupports.claim; + BOOST_CHECK(fixture.getProofForName(name, proof, [&claim](const CClaimValue& value) { + return claim.claimId == value.claimId; + })); + BOOST_CHECK(proof.hasValue); + BOOST_CHECK_EQUAL(proof.outPoint, claim.outPoint); + uint256 claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover); + ValidatePairs(fixture, proof.pairs, claimHash); + } + } +} + +BOOST_AUTO_TEST_CASE(hash_includes_all_claims_branched_test) +{ + ClaimTrieChainFixture fixture; + fixture.setHashForkHeight(2); + fixture.IncrementBlocks(4); + + std::string names[] = {"test", "toast", "tot", "top", "toa", "toad"}; + for (const auto& name : names) + fixture.MakeClaim(fixture.GetCoinbase(), name, "one", 1); + + fixture.MakeClaim(fixture.GetCoinbase(), "toa", "two", 2); + fixture.MakeClaim(fixture.GetCoinbase(), "toa", "tre", 3); + fixture.MakeClaim(fixture.GetCoinbase(), "toa", "qua", 4); + fixture.MakeClaim(fixture.GetCoinbase(), "toa", "cin", 5); + fixture.IncrementBlocks(1); + + for (const auto& name : names) { + for (auto& claimSupports : fixture.getClaimsForName(name).claimsNsupports) { + CClaimTrieProof proof; + auto& claim = claimSupports.claim; + BOOST_CHECK(fixture.getProofForName(name, proof, [&claim](const CClaimValue& value) { + return claim.claimId == value.claimId; + })); + BOOST_CHECK(proof.hasValue); + BOOST_CHECK_EQUAL(proof.outPoint, claim.outPoint); + uint256 claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover); + ValidatePairs(fixture, proof.pairs, claimHash); + } + } +} + +BOOST_AUTO_TEST_CASE(hash_claims_children_fuzzer_test) +{ + ClaimTrieChainFixture fixture; + fixture.setHashForkHeight(2); + fixture.IncrementBlocks(4); + + std::size_t i = 0; + auto names = random_strings(300); + auto lastTx = MakeTransactionRef(fixture.GetCoinbase()); + for (const auto& name : names) { + auto tx = fixture.MakeClaim(*lastTx, name, "one", 1); + lastTx = MakeTransactionRef(std::move(tx)); + if (++i % 5 == 0) + for (std::size_t j = 0; j < (i / 5); ++j) { + auto tx = fixture.MakeClaim(*lastTx, name, "one", 1); + lastTx = MakeTransactionRef(std::move(tx)); + } + fixture.IncrementBlocks(1); + } + + for (const auto& name : names) { + for (auto& claimSupports : fixture.getClaimsForName(name).claimsNsupports) { + CClaimTrieProof proof; + auto& claim = claimSupports.claim; + BOOST_CHECK(fixture.getProofForName(name, proof, [&claim](const CClaimValue& value) { + return claim.claimId == value.claimId; + })); + BOOST_CHECK(proof.hasValue); + BOOST_CHECK_EQUAL(proof.outPoint, claim.outPoint); + uint256 claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover); + ValidatePairs(fixture, proof.pairs, claimHash); + } + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/claimtrienormalization_tests.cpp b/src/test/claimtrienormalization_tests.cpp new file mode 100644 index 0000000000..b36043ab98 --- /dev/null +++ b/src/test/claimtrienormalization_tests.cpp @@ -0,0 +1,495 @@ +// Copyright (c) 2015-2019 The LBRY Foundation +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://opensource.org/licenses/mit-license.php + +#include + +using namespace std; + +BOOST_FIXTURE_TEST_SUITE(claimtrienormalization_tests, RegTestingSetup) + +/* + normalization + test normalization function indpendent from rest of the code +*/ + +BOOST_AUTO_TEST_CASE(normalization_only) +{ + CClaimTrieCache ccache(pclaimTrie); + + // basic ASCII casing tests + BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("TESt", true)); + BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("tesT", true)); + BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("TesT", true)); + BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("test", true)); + BOOST_CHECK_EQUAL("test this", ccache.normalizeClaimName("Test This", true)); + + // test invalid utf8 bytes are returned as is + BOOST_CHECK_EQUAL("\xFF", ccache.normalizeClaimName("\xFF", true)); + BOOST_CHECK_EQUAL("\xC3\x28", ccache.normalizeClaimName("\xC3\x28", true)); + + // ohm sign unicode code point \x2126 should be transformed to equivalent + // unicode code point \x03C9 , greek small letter omega + BOOST_CHECK_EQUAL("\xCF\x89", ccache.normalizeClaimName("\xE2\x84\xA6", true)); + + // cyrillic capital ef code point \x0424 should be transformed to lower case + // \x0444 + BOOST_CHECK_EQUAL("\xD1\x84", ccache.normalizeClaimName("\xD0\xA4", true)); + + // armenian capital ben code point \x0532 should be transformed to lower case + // \x0562 + BOOST_CHECK_EQUAL("\xD5\xA2", ccache.normalizeClaimName("\xD4\xB2", true)); + + // japanese pbu code point \x3076 should be transformed by NFD decomposition + // into \x3075 and \x3099 + BOOST_CHECK_EQUAL("\xE3\x81\xB5\xE3\x82\x99", + ccache.normalizeClaimName("\xE3\x81\xB6", true)); + + // hangul ggwalg unicode code point \xAF51 should be transformed by NFD + // decomposition into unicode code points \x1101 \x116A \x11B0 + // source: http://unicode.org/L2/L2009/09052-tr47.html + BOOST_CHECK_EQUAL("\xE1\x84\x81\xE1\x85\xAA\xE1\x86\xB0", + ccache.normalizeClaimName("\xEA\xBD\x91", true)); +} + +/* + normalization + check claim name normalization before the fork + check claim name normalization after the fork +*/ +BOOST_AUTO_TEST_CASE(claimtriebranching_normalization) +{ + ClaimTrieChainFixture fixture; + + // check claim names are not normalized + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "normalizeTest", "one", 3); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1)); + fixture.DecrementBlocks(1); + BOOST_CHECK(fixture.getTotalNamesInTrie() == 0); + fixture.CommitTx(tx1); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1)); + + CMutableTransaction tx2a = fixture.MakeClaim(fixture.GetCoinbase(), "Normalizetest", "one_a", 2); + CMutableTransaction tx2 = fixture.MakeUpdate(tx2a, "Normalizetest", "one", ClaimIdHash(tx2a.GetHash(), 0), 2); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1)); + BOOST_CHECK(fixture.is_best_claim("Normalizetest", tx2)); + + // Activate the fork (which rebuilds the existing claimtrie and + // cache), flattening all previously existing name clashes due to + // the normalization + fixture.setNormalizationForkHeight(2); + + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1)); + BOOST_CHECK(fixture.is_best_claim("Normalizetest", tx2)); + + fixture.IncrementBlocks(1, true); + + // Post-fork, tx1 (the previous winning claim) assumes all name + // variants of what it originally was ... + BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("normalizetest", 3)); + + CClaimTrieData data; + BOOST_CHECK(!pclaimTrie->find("normalizeTest", data)); + + // Check equivalence of normalized claim names + BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1)); // collapsed tx2 + fixture.IncrementBlocks(1); + + CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "NORMALIZETEST", "one", 1); + fixture.IncrementBlocks(1); + BOOST_CHECK(!fixture.is_best_claim("normalizetest", tx3)); + + CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, "NoRmAlIzEtEsT", 2); + fixture.IncrementBlocks(1); + + // Ensure that supports work for normalized claim names + BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1)); // effective amount is 5 + BOOST_CHECK(fixture.best_claim_effective_amount_equals("normalizetest", 5)); + + CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), "foo", "bar", 1); + CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(), tx4, "Foo", 1); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("foo", tx4)); + + CMutableTransaction u1 = fixture.MakeUpdate(tx4, "foo", "baz", ClaimIdHash(tx4.GetHash(), 0), 1); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("foo", u1)); + + CMutableTransaction u2 = fixture.MakeUpdate(tx1, "nOrmalIzEtEst", "two", ClaimIdHash(tx1.GetHash(), 0), 3); + fixture.IncrementBlocks(1); + + BOOST_CHECK(fixture.is_best_claim("normalizetest", u2)); + + // Add another set of unicode claims that will collapse after the fork + CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), "Ame\u0301lie", "amelie", 2); + fixture.IncrementBlocks(1); + CClaimValue nval1; + fixture.getInfoForName("amélie", nval1); + BOOST_CHECK(nval1.claimId == ClaimIdHash(tx5.GetHash(), 0)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("amélie", 2)); + + // Check equivalence of normalized claim names + BOOST_CHECK(fixture.is_best_claim("amélie", tx5)); + + CMutableTransaction tx7 = fixture.MakeClaim(fixture.GetCoinbase(), "あてはまる", "jn1", 1); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("あてはまる", tx7)); + + CMutableTransaction tx8 = fixture.MakeClaim(fixture.GetCoinbase(), "AÑEJO", "es1", 1); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("añejo", tx8)); + + // Rewind to 1 block before the fork and be sure that the fork is no longer active + fixture.DecrementBlocks(); + + // Now check that our old (non-normalized) claims are 'alive' again + BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1)); + BOOST_CHECK(!fixture.is_best_claim("Normalizetest", tx1)); // no longer equivalent + BOOST_CHECK(fixture.is_best_claim("Normalizetest", tx2)); + + // Create new claim + CMutableTransaction tx9 = fixture.MakeClaim(fixture.GetCoinbase(), "blah", "blah", 1); + std::string invalidUtf8("\xFF\xFF"); + CMutableTransaction tx10 = fixture.MakeClaim(fixture.GetCoinbase(), invalidUtf8, "blah", 1); // invalid UTF8 + + // Roll forward to fork height again and check again that we're normalized + fixture.IncrementBlocks(1); + BOOST_CHECK(chainActive.Height() == Params().GetConsensus().nNormalizedNameForkHeight); + BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1)); // collapsed tx2 + BOOST_CHECK(fixture.is_best_claim(invalidUtf8, tx10)); + + // Rewind to 1 block before the fork and be sure that the fork is + // no longer active + fixture.DecrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("Normalizetest", tx2)); + + // Roll forward to fork height again and check again that we're normalized + fixture.IncrementBlocks(1); + BOOST_CHECK(chainActive.Height() == Params().GetConsensus().nNormalizedNameForkHeight); + BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1)); // collapsed tx2 +} + +BOOST_AUTO_TEST_CASE(claimtriecache_normalization) +{ + ClaimTrieChainFixture fixture; + + std::string name = "Ame\u0301lie"; + + std::string name_upper = "Amélie"; + std::string name_normd = "amélie"; // this accented e is not actually the same as the one above; this has been "normalized" + + BOOST_CHECK(name != name_upper); + + // Add another set of unicode claims that will collapse after the fork + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), name, "amilie", 2); + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), name_upper, "amelie", 2); + fixture.MakeClaim(fixture.GetCoinbase(), "amelie1", "amelie", 2); + fixture.IncrementBlocks(1); + + CClaimValue lookupClaim; + std::string lookupName; + BOOST_CHECK(getClaimById(ClaimIdHash(tx2.GetHash(), 0), lookupName, &lookupClaim)); + CClaimValue nval1; + BOOST_CHECK(fixture.getInfoForName("amelie1", nval1)); + // amélie is not found cause normalization still not appear + BOOST_CHECK(!fixture.getInfoForName(name_normd, nval1)); + + // Activate the fork (which rebuilds the existing claimtrie and + // cache), flattening all previously existing name clashes due to + // the normalization + fixture.setNormalizationForkHeight(1); + int currentHeight = chainActive.Height(); + + fixture.IncrementBlocks(1); + // Ok normalization fix the name problem + BOOST_CHECK(fixture.getInfoForName(name_normd, nval1)); + BOOST_CHECK(nval1.nHeight == currentHeight); + BOOST_CHECK(lookupClaim == nval1); + + CCoinsViewCache coins(pcoinsTip.get()); + CClaimTrieCache trieCache(pclaimTrie); + CBlockIndex* pindex = chainActive.Tip(); + CBlock block; + int amelieValidHeight; + BOOST_CHECK(trieCache.shouldNormalize()); + BOOST_CHECK(ReadBlockFromDisk(block, pindex, Params().GetConsensus())); + BOOST_CHECK(g_chainstate.DisconnectBlock(block, pindex, coins, trieCache) == DisconnectResult::DISCONNECT_OK); + BOOST_CHECK(!trieCache.shouldNormalize()); + BOOST_CHECK(!trieCache.spendClaim(name_normd, COutPoint(tx2.GetHash(), 0), currentHeight, amelieValidHeight)); + BOOST_CHECK(trieCache.spendClaim(name_upper, COutPoint(tx2.GetHash(), 0), currentHeight, amelieValidHeight)); + + CClaimTrieData data; + BOOST_CHECK(!pclaimTrie->find(name, data)); + BOOST_CHECK(trieCache.getInfoForName(name, nval1)); + BOOST_CHECK(trieCache.addClaim(name, COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), CAmount(2), currentHeight + 1)); + BOOST_CHECK(trieCache.getInfoForName(name, nval1)); + insertUndoType insertUndo; + claimQueueRowType expireUndo; + insertUndoType insertSupportUndo; + supportQueueRowType expireSupportUndo; + std::vector > takeoverHeightUndo; + BOOST_CHECK(trieCache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo)); + BOOST_CHECK(trieCache.shouldNormalize()); + + CClaimTrieDataNode node; + BOOST_CHECK(!pclaimTrie->find(name, node)); +} + +BOOST_AUTO_TEST_CASE(undo_normalization_does_not_kill_claim_order) +{ + ClaimTrieChainFixture fixture; + fixture.setNormalizationForkHeight(5); + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1); + CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "a", "3", 3); + fixture.IncrementBlocks(1); + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "2", 2); + fixture.IncrementBlocks(2); + BOOST_CHECK(fixture.is_best_claim("A", tx2)); + fixture.IncrementBlocks(3, true); + BOOST_CHECK(fixture.is_best_claim("a", tx3)); + fixture.DecrementBlocks(); + BOOST_CHECK(fixture.is_best_claim("A", tx2)); +} + +BOOST_AUTO_TEST_CASE(normalized_activations_fall_through) +{ + ClaimTrieChainFixture fixture; + fixture.setNormalizationForkHeight(5); + + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "AB", "1", 1); + fixture.IncrementBlocks(3); + BOOST_CHECK(fixture.proportionalDelayFactor() == 1); + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "Ab", "2", 4); + CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "aB", "2", 3); + CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), "ab", "2", 2); + fixture.IncrementBlocks(1); + + BOOST_CHECK(fixture.is_best_claim("AB", tx1)); + fixture.IncrementBlocks(3); + BOOST_CHECK(fixture.is_best_claim("ab", tx2)); + BOOST_CHECK(fixture.getClaimsForName("ab").claimsNsupports.size() == 4U); + fixture.DecrementBlocks(3); + fixture.Spend(tx1); + fixture.Spend(tx2); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("ab", tx3)); + BOOST_CHECK(fixture.getClaimsForName("ab").claimsNsupports.size() == 2U); + fixture.DecrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("AB", tx1)); + fixture.Spend(tx1); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("ab", tx2)); + + for (int i = 0; i < 7; ++i) { + fixture.IncrementBlocks(i, true); // well into normalized teritory + CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), "CD", "a", 1 + i); + fixture.IncrementBlocks(3); + CMutableTransaction tx6 = fixture.MakeClaim(fixture.GetCoinbase(), "Cd", "b", 2 + i); + CMutableTransaction tx7 = fixture.MakeClaim(fixture.GetCoinbase(), "cD", "c", 3 + i); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("cd", tx5)); + fixture.Spend(tx5); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("cd", tx7)); + fixture.DecrementBlocks(); + } +} + +BOOST_AUTO_TEST_CASE(normalization_removal_test) +{ + ClaimTrieChainFixture fixture; + fixture.setNormalizationForkHeight(2); + fixture.IncrementBlocks(3); + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "AB", "1", 1); + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "Ab", "2", 2); + CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "aB", "3", 3); + CMutableTransaction sx1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, "AB", 1); + CMutableTransaction sx2 = fixture.MakeSupport(fixture.GetCoinbase(), tx2, "Ab", 1); + + CClaimTrieCache cache(pclaimTrie); + int height = chainActive.Height() + 1; + cache.addClaim("AB", COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), 1, height); + cache.addClaim("Ab", COutPoint(tx2.GetHash(), 0), ClaimIdHash(tx2.GetHash(), 0), 2, height); + cache.addClaim("aB", COutPoint(tx3.GetHash(), 0), ClaimIdHash(tx3.GetHash(), 0), 3, height); + cache.addSupport("AB", COutPoint(sx1.GetHash(), 0), 1, ClaimIdHash(tx1.GetHash(), 0), height); + cache.addSupport("Ab", COutPoint(sx2.GetHash(), 0), 1, ClaimIdHash(tx2.GetHash(), 0), height); + insertUndoType insertUndo; + claimQueueRowType expireUndo; + insertUndoType insertSupportUndo; + supportQueueRowType expireSupportUndo; + std::vector > takeoverHeightUndo; + BOOST_CHECK(cache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo)); + BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports.size() == 3U); + BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[0].supports.size() == 1U); + BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[1].supports.size() == 0U); + BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[2].supports.size() == 1U); + BOOST_CHECK(cache.decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo)); + BOOST_CHECK(cache.finalizeDecrement(takeoverHeightUndo)); + BOOST_CHECK(cache.undoAddSupport("AB", COutPoint(sx1.GetHash(), 0), height)); + BOOST_CHECK(cache.undoAddSupport("Ab", COutPoint(sx2.GetHash(), 0), height)); + BOOST_CHECK(cache.undoAddClaim("AB", COutPoint(tx1.GetHash(), 0), height)); + BOOST_CHECK(cache.undoAddClaim("Ab", COutPoint(tx2.GetHash(), 0), height)); + BOOST_CHECK(cache.undoAddClaim("aB", COutPoint(tx3.GetHash(), 0), height)); + BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports.size() == 0U); +} + +BOOST_AUTO_TEST_CASE(normalization_does_not_kill_supports) +{ + ClaimTrieChainFixture fixture; + fixture.setNormalizationForkHeight(3); + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1); + fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2)); + fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 3)); + fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("a", 4)); + fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("a", 5)); + + fixture.DecrementBlocks(1); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("a", 4)); + fixture.DecrementBlocks(1); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 3)); + fixture.DecrementBlocks(1); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2)); + fixture.IncrementBlocks(5); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("a", 3)); +} + +BOOST_AUTO_TEST_CASE(normalization_does_not_fail_on_spend) +{ + ClaimTrieChainFixture fixture; + fixture.setNormalizationForkHeight(2); + + std::string sName1("testN"); + std::string sName2("testn"); + + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, "1", 3); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim(sName1, tx1)); + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, "2", 2); + CMutableTransaction tx1s = fixture.MakeSupport(fixture.GetCoinbase(), tx1, sName1, 2); + fixture.IncrementBlocks(2, true); + BOOST_CHECK(fixture.is_best_claim(sName2, tx1)); + + CMutableTransaction tx3 = fixture.Spend(tx1); // abandon the claim + CMutableTransaction tx3s = fixture.Spend(tx1s); + fixture.IncrementBlocks(2); + BOOST_CHECK(fixture.is_best_claim(sName2, tx2)); + fixture.DecrementBlocks(); + BOOST_CHECK(fixture.is_best_claim(sName1, tx1)); +} + +BOOST_AUTO_TEST_CASE(normalization_does_not_kill_sort_order) +{ + ClaimTrieChainFixture fixture; + fixture.setNormalizationForkHeight(2); + + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1); + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "2", 2); + CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "a", "3", 3); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("A", tx2)); + BOOST_CHECK(fixture.is_best_claim("a", tx3)); + + fixture.IncrementBlocks(1); + BOOST_CHECK(!fixture.is_best_claim("A", tx2)); + BOOST_CHECK(fixture.is_best_claim("a", tx3)); + BOOST_CHECK(fixture.getClaimsForName("a").claimsNsupports.size() == 3U); + + fixture.DecrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("A", tx2)); + BOOST_CHECK(fixture.is_best_claim("a", tx3)); +} + +BOOST_AUTO_TEST_CASE(normalization_does_not_kill_expirations) +{ + ClaimTrieChainFixture fixture; + auto& consensus = Params().GetConsensus(); + fixture.setExpirationForkHeight(consensus.nExtendedClaimExpirationForkHeight, 3, consensus.nExtendedClaimExpirationTime); + fixture.setNormalizationForkHeight(4); + // need to see that claims expiring on the frame when we normalize aren't kept + // need to see that supports expiring on the frame when we normalize aren't kept + // need to see that claims & supports carried through the normalization fork do expire + // and that they come back correctly when we roll backwards + + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1); + fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2)); + + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "B", "1", 1); + fixture.MakeSupport(fixture.GetCoinbase(), tx2, "B", 1); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("B", 2)); + + CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "C", "1", 1); + fixture.MakeSupport(fixture.GetCoinbase(), tx3, "C", 1); + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("B", 2)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("C", 2)); + + CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), "D", "1", 1); + fixture.MakeSupport(fixture.GetCoinbase(), tx4, "D", 1); + fixture.IncrementBlocks(1); + BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("b", 2)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("c", 2)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2)); + + fixture.IncrementBlocks(1); + BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2)); + BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("c", 2)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2)); + + fixture.IncrementBlocks(1); + BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2)); + BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2)); + BOOST_CHECK(!fixture.best_claim_effective_amount_equals("c", 2)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2)); + + fixture.IncrementBlocks(1); + BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2)); + BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2)); + BOOST_CHECK(!fixture.best_claim_effective_amount_equals("c", 2)); + BOOST_CHECK(!fixture.best_claim_effective_amount_equals("d", 2)); + + fixture.DecrementBlocks(2); + BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2)); + BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("c", 2)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2)); + + fixture.DecrementBlocks(1); + BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("b", 2)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("c", 2)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2)); + + fixture.DecrementBlocks(1); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("B", 2)); + BOOST_CHECK(fixture.best_claim_effective_amount_equals("C", 2)); + BOOST_CHECK(!fixture.best_claim_effective_amount_equals("d", 2)); + + fixture.IncrementBlocks(3); + BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2)); + BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2)); + BOOST_CHECK(!fixture.best_claim_effective_amount_equals("c", 2)); + BOOST_CHECK(!fixture.best_claim_effective_amount_equals("d", 2)); // (not re-added) +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/claimtrierpc_tests.cpp b/src/test/claimtrierpc_tests.cpp new file mode 100644 index 0000000000..7fa143f221 --- /dev/null +++ b/src/test/claimtrierpc_tests.cpp @@ -0,0 +1,407 @@ +// Copyright (c) 2015-2019 The LBRY Foundation +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://opensource.org/licenses/mit-license.php + +#include + +using namespace std; + +extern void ValidatePairs(CClaimTrieCache& cache, const std::vector>& pairs, uint256 claimHash); + +BOOST_FIXTURE_TEST_SUITE(claimtrierpc_tests, RegTestingSetup) + +BOOST_AUTO_TEST_CASE(getnamesintrie_test) +{ + ClaimTrieChainFixture fixture; + std::string sName1("test"); + std::string sValue1("test"); + + uint256 blockHash = chainActive.Tip()->GetBlockHash(); + + fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 42); + fixture.IncrementBlocks(1); + + rpcfn_type getnamesintrie = tableRPC["getnamesintrie"]->actor; + JSONRPCRequest req; + req.params = UniValue(UniValue::VARR); + + UniValue results = getnamesintrie(req); + BOOST_CHECK_EQUAL(results.size(), 1U); + + req.params.push_back(blockHash.GetHex()); + + results = getnamesintrie(req); + BOOST_CHECK_EQUAL(results.size(), 0U); +} + +BOOST_AUTO_TEST_CASE(getvalueforname_test) +{ + ClaimTrieChainFixture fixture; + std::string sName1("testN"); + std::string sValue1("testV"); + + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 2); + fixture.IncrementBlocks(1); + + uint256 blockHash = chainActive.Tip()->GetBlockHash(); + + fixture.MakeSupport(fixture.GetCoinbase(), tx1, sName1, 3); + fixture.IncrementBlocks(10); + + rpcfn_type getvalueforname = tableRPC["getvalueforname"]->actor; + JSONRPCRequest req; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(sName1)); + + UniValue results = getvalueforname(req); + BOOST_CHECK_EQUAL(results[T_VALUE].get_str(), HexStr(sValue1)); + BOOST_CHECK_EQUAL(results[T_AMOUNT].get_int(), 2); + BOOST_CHECK_EQUAL(results[T_EFFECTIVEAMOUNT].get_int(), 5); + + req.params.push_back(blockHash.GetHex()); + + results = getvalueforname(req); + BOOST_CHECK_EQUAL(results[T_AMOUNT].get_int(), 2); + BOOST_CHECK_EQUAL(results[T_EFFECTIVEAMOUNT].get_int(), 2); +} + +BOOST_AUTO_TEST_CASE(getclaimsforname_test) +{ + ClaimTrieChainFixture fixture; + std::string sName1("testN"); + std::string sValue1("test1"); + std::string sValue2("test2"); + + int height = chainActive.Height(); + + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 2); + fixture.IncrementBlocks(1); + + uint256 blockHash = chainActive.Tip()->GetBlockHash(); + + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, 3); + fixture.IncrementBlocks(1); + + rpcfn_type getclaimsforname = tableRPC["getclaimsforname"]->actor; + JSONRPCRequest req; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(sName1)); + + UniValue results = getclaimsforname(req); + UniValue claims = results[T_CLAIMS]; + BOOST_CHECK_EQUAL(claims.size(), 2U); + BOOST_CHECK_EQUAL(results[T_LASTTAKEOVERHEIGHT].get_int(), height + 1); + BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 2); + BOOST_CHECK_EQUAL(claims[0][T_SUPPORTS].size(), 0U); + + fixture.IncrementBlocks(1); + + results = getclaimsforname(req); + claims = results[T_CLAIMS]; + BOOST_CHECK_EQUAL(claims.size(), 2U); + BOOST_CHECK_EQUAL(results[T_LASTTAKEOVERHEIGHT].get_int(), height + 3); + BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 3); + BOOST_CHECK_EQUAL(claims[1][T_EFFECTIVEAMOUNT].get_int(), 2); + BOOST_CHECK_EQUAL(claims[0][T_SUPPORTS].size(), 0U); + BOOST_CHECK_EQUAL(claims[1][T_SUPPORTS].size(), 0U); + + req.params.push_back(blockHash.GetHex()); + + results = getclaimsforname(req); + claims = results[T_CLAIMS]; + BOOST_CHECK_EQUAL(claims.size(), 1U); + BOOST_CHECK_EQUAL(results[T_LASTTAKEOVERHEIGHT].get_int(), height + 1); + BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 2); + BOOST_CHECK_EQUAL(claims[0][T_SUPPORTS].size(), 0U); +} + +BOOST_AUTO_TEST_CASE(claim_rpcs_rollback2_test) +{ + ClaimTrieChainFixture fixture; + std::string sName1("testN"); + std::string sValue1("test1"); + std::string sValue2("test2"); + + int height = chainActive.Height(); + + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 1); + fixture.IncrementBlocks(2); + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, 2); + fixture.IncrementBlocks(3); + + uint256 blockHash = chainActive.Tip()->GetBlockHash(); + + CMutableTransaction tx3 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, sValue1, 3); + fixture.IncrementBlocks(1); + + rpcfn_type getclaimsforname = tableRPC["getclaimsforname"]->actor; + rpcfn_type getvalueforname = tableRPC["getvalueforname"]->actor; + JSONRPCRequest req; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(sName1)); + req.params.push_back(blockHash.GetHex()); + + UniValue claimsResults = getclaimsforname(req); + BOOST_CHECK_EQUAL(claimsResults[T_LASTTAKEOVERHEIGHT].get_int(), height + 5); + BOOST_CHECK_EQUAL(claimsResults[T_CLAIMS][0][T_SUPPORTS].size(), 0U); + BOOST_CHECK_EQUAL(claimsResults[T_CLAIMS][1][T_SUPPORTS].size(), 0U); + + UniValue valueResults = getvalueforname(req); + BOOST_CHECK_EQUAL(valueResults[T_VALUE].get_str(), HexStr(sValue2)); + BOOST_CHECK_EQUAL(valueResults[T_AMOUNT].get_int(), 2); +} + +BOOST_AUTO_TEST_CASE(claim_rpcs_rollback3_test) +{ + ClaimTrieChainFixture fixture; + std::string sName1("testN"); + std::string sValue1("test1"); + std::string sValue2("test2"); + + int height = chainActive.Height(); + + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 3); + fixture.IncrementBlocks(1); + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, 2); + fixture.IncrementBlocks(2); + + uint256 blockHash = chainActive.Tip()->GetBlockHash(); + + CMutableTransaction tx3 = fixture.Spend(tx1); // abandon the claim + fixture.IncrementBlocks(1); + + rpcfn_type getclaimsforname = tableRPC["getclaimsforname"]->actor; + rpcfn_type getvalueforname = tableRPC["getvalueforname"]->actor; + rpcfn_type getblocktemplate = tableRPC["getblocktemplate"]->actor; + + JSONRPCRequest req; + req.params = UniValue(UniValue::VARR); + UniValue templateResults = getblocktemplate(req); + BOOST_CHECK_EQUAL(templateResults["claimtrie"].get_str(), chainActive.Tip()->hashClaimTrie.GetHex()); + + req.params.push_back(UniValue(sName1)); + req.params.push_back(blockHash.GetHex()); + + UniValue claimsResults = getclaimsforname(req); + BOOST_CHECK_EQUAL(claimsResults[T_LASTTAKEOVERHEIGHT].get_int(), height + 1); + + UniValue valueResults = getvalueforname(req); + BOOST_CHECK_EQUAL(valueResults[T_VALUE].get_str(), HexStr(sValue1)); + BOOST_CHECK_EQUAL(valueResults[T_AMOUNT].get_int(), 3); +} + +std::vector> jsonToPairs(const UniValue& jsonPair) +{ + std::vector> pairs; + for (std::size_t i = 0; i < jsonPair.size(); ++i) { + auto& jpair = jsonPair[i]; + pairs.emplace_back(jpair[T_ODD].get_bool(), uint256S(jpair[T_HASH].get_str())); + } + return pairs; +} + +BOOST_AUTO_TEST_CASE(hash_bid_seq_claim_changes_test) +{ + ClaimTrieChainFixture fixture; + fixture.setHashForkHeight(2); + fixture.IncrementBlocks(4); + + std::string name = "toa"; + std::string value1 = "one", value2 = "two", value3 = "tre", value4 = "for"; + + auto tx1 = fixture.MakeClaim(fixture.GetCoinbase(), name, value1, 1); + fixture.IncrementBlocks(1); + + CMutableTransaction tx2 = BuildTransaction(fixture.GetCoinbase(), 0, 2); + tx2.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME + << std::vector(name.begin(), name.end()) + << std::vector(value2.begin(), value2.end()) << OP_2DROP << OP_DROP << OP_TRUE; + tx2.vout[0].nValue = 3; + tx2.vout[1].scriptPubKey = CScript() << OP_CLAIM_NAME + << std::vector(name.begin(), name.end()) + << std::vector(value3.begin(), value3.end()) << OP_2DROP << OP_DROP << OP_TRUE; + tx2.vout[1].nValue = 2; + + fixture.CommitTx(tx2); + fixture.IncrementBlocks(1); + + auto tx3 = fixture.MakeClaim(fixture.GetCoinbase(), name, value4, 4); + fixture.IncrementBlocks(1); + + int height = chainActive.Height(); + + auto claimId1 = ClaimIdHash(tx1.GetHash(), 0); + auto claimId2 = ClaimIdHash(tx2.GetHash(), 0); + auto claimId3 = ClaimIdHash(tx2.GetHash(), 1); + auto claimId4 = ClaimIdHash(tx3.GetHash(), 0); + + int claim1bid = 3, claim1seq = 0; + int claim2bid = 1, claim2seq = 1; + int claim3bid = 2, claim3seq = 2; + int claim4bid = 0, claim4seq = 3; + + auto getclaimsforname = tableRPC["getclaimsforname"]->actor; + + JSONRPCRequest req; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(name)); + + auto result = getclaimsforname(req); + auto claims = result[T_CLAIMS]; + BOOST_CHECK_EQUAL(claims.size(), 4U); + BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height); + BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 4); + BOOST_CHECK_EQUAL(claims[0][T_BID].get_int(), claim4bid); + BOOST_CHECK_EQUAL(claims[0][T_SEQUENCE].get_int(), claim4seq); + BOOST_CHECK_EQUAL(claims[0][T_CLAIMID].get_str(), claimId4.GetHex()); + BOOST_CHECK_EQUAL(claims[1][T_EFFECTIVEAMOUNT].get_int(), 3); + BOOST_CHECK_EQUAL(claims[1][T_BID].get_int(), claim2bid); + BOOST_CHECK_EQUAL(claims[1][T_SEQUENCE].get_int(), claim2seq); + BOOST_CHECK_EQUAL(claims[1][T_CLAIMID].get_str(), claimId2.GetHex()); + BOOST_CHECK_EQUAL(claims[2][T_EFFECTIVEAMOUNT].get_int(), 2); + BOOST_CHECK_EQUAL(claims[2][T_BID].get_int(), claim3bid); + BOOST_CHECK_EQUAL(claims[2][T_SEQUENCE].get_int(), claim3seq); + BOOST_CHECK_EQUAL(claims[2][T_CLAIMID].get_str(), claimId3.GetHex()); + BOOST_CHECK_EQUAL(claims[3][T_EFFECTIVEAMOUNT].get_int(), 1); + BOOST_CHECK_EQUAL(claims[3][T_BID].get_int(), claim1bid); + BOOST_CHECK_EQUAL(claims[3][T_SEQUENCE].get_int(), claim1seq); + BOOST_CHECK_EQUAL(claims[3][T_CLAIMID].get_str(), claimId1.GetHex()); + + auto getclaimbybid = tableRPC["getclaimbybid"]->actor; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(name)); + req.params.push_back(UniValue(claim3bid)); + + result = getclaimbybid(req); + BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height); + BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 2); + BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim3bid); + BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim3seq); + BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId3.GetHex()); + + auto getclaimbyseq = tableRPC["getclaimbyseq"]->actor; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(name)); + req.params.push_back(UniValue(claim2seq)); + + result = getclaimbyseq(req); + BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height); + BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 3); + BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim2bid); + BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim2seq); + BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId2.GetHex()); + + auto getclaimbyid = tableRPC["getclaimbyid"]->actor; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(claimId1.GetHex())); + + result = getclaimbyid(req); + BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height); + BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 1); + BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim1bid); + BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim1seq); + BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId1.GetHex()); + + // check by partial id (at least 3 chars) + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(claimId3.GetHex().substr(0, 3))); + + result = getclaimbyid(req); + BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height); + BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 2); + BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim3bid); + BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim3seq); + BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId3.GetHex()); + + auto blockhash = chainActive.Tip()->GetBlockHash(); + + auto getnameproof = tableRPC["getnameproof"]->actor; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(name)); + req.params.push_back(UniValue(blockhash.GetHex())); + req.params.push_back(UniValue(claimId3.GetHex())); + + result = getnameproof(req); + auto claimHash = getValueHash(COutPoint(tx2.GetHash(), 1), result[T_LASTTAKEOVERHEIGHT].get_int()); + ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash); + + // check by partial id (can be even 1 char) + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(name)); + req.params.push_back(UniValue(blockhash.GetHex())); + req.params.push_back(UniValue(claimId2.GetHex().substr(0, 2))); + + result = getnameproof(req); + claimHash = getValueHash(COutPoint(tx2.GetHash(), 0), result[T_LASTTAKEOVERHEIGHT].get_int()); + ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash); + + auto getclaimproofbybid = tableRPC["getclaimproofbybid"]->actor; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(name)); + req.params.push_back(UniValue(claim1bid)); + + result = getclaimproofbybid(req); + claimHash = getValueHash(COutPoint(tx1.GetHash(), 0), result[T_LASTTAKEOVERHEIGHT].get_int()); + ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash); + + auto getclaimproofbyseq = tableRPC["getclaimproofbyseq"]->actor; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(name)); + req.params.push_back(UniValue(claim4seq)); + + result = getclaimproofbyseq(req); + claimHash = getValueHash(COutPoint(tx3.GetHash(), 0), result[T_LASTTAKEOVERHEIGHT].get_int()); + ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash); + + auto getchangesinblock = tableRPC["getchangesinblock"]->actor; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(blockhash.GetHex())); + + result = getchangesinblock(req); + BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED].size(), 3); + BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED][0].get_str(), claimId2.GetHex()); + BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED][1].get_str(), claimId3.GetHex()); + BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED][2].get_str(), claimId4.GetHex()); + BOOST_CHECK_EQUAL(result[T_CLAIMSREMOVED].size(), 0); + BOOST_CHECK_EQUAL(result[T_SUPPORTSADDEDORUPDATED].size(), 0); + BOOST_CHECK_EQUAL(result[T_SUPPORTSREMOVED].size(), 0); +} + +BOOST_AUTO_TEST_CASE(claim_rpc_pending_amount_test) +{ + ClaimTrieChainFixture fixture; + std::string sName1("test"); + std::string sValue1("test1"); + std::string sValue2("test2"); + + rpcfn_type getclaimsforname = tableRPC["getclaimsforname"]->actor; + + JSONRPCRequest req; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(sName1)); + + fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 1); + fixture.IncrementBlocks(1); + + fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, 2); + fixture.IncrementBlocks(1); + + auto claims = getclaimsforname(req)[T_CLAIMS]; + BOOST_CHECK_EQUAL(claims.size(), 2U); + BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 1); + BOOST_CHECK(!claims[0].exists(T_PENDINGAMOUNT)); + BOOST_CHECK_EQUAL(claims[1][T_EFFECTIVEAMOUNT].get_int(), 0); + BOOST_CHECK(claims[1].exists(T_PENDINGAMOUNT)); + BOOST_CHECK_EQUAL(claims[1][T_PENDINGAMOUNT].get_int(), 2); + + fixture.IncrementBlocks(1); + + claims = getclaimsforname(req)[T_CLAIMS]; + BOOST_CHECK_EQUAL(claims.size(), 2U); + BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 2); + BOOST_CHECK(!claims[0].exists(T_PENDINGAMOUNT)); + BOOST_CHECK_EQUAL(claims[1][T_EFFECTIVEAMOUNT].get_int(), 1); + BOOST_CHECK(!claims[1].exists(T_PENDINGAMOUNT)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/prefixtrie_tests.cpp b/src/test/prefixtrie_tests.cpp index 0d9ec0a65c..36cc411d2f 100644 --- a/src/test/prefixtrie_tests.cpp +++ b/src/test/prefixtrie_tests.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -37,7 +38,79 @@ std::vector random_strings(std::size_t count) using namespace std; -BOOST_FIXTURE_TEST_SUITE(prefixtrie_tests, BasicTestingSetup) +BOOST_FIXTURE_TEST_SUITE(prefixtrie_tests, RegTestingSetup) + +#ifndef MAC_OSX // can't find a random number generator that produces the same sequence on OSX +BOOST_AUTO_TEST_CASE(triehash_fuzzer_test) +{ + ClaimTrieChainFixture fixture; + + auto envClaims = std::getenv("TRIEHASH_FUZZER_CLAIMS"); + auto envBlocks = std::getenv("TRIEHASH_FUZZER_BLOCKS"); + + const int claimsPerBlock = envClaims ? std::atoi(envClaims) : 100; + const int blocks = envBlocks ? std::atoi(envBlocks) : 13; + + auto names = random_strings(blocks * claimsPerBlock); + + FastRandomContext frc(true); + std::unordered_map> existingClaims; + std::vector existingSupports; + std::string value(1024, 'c'); + + std::vector cb {fixture.GetCoinbase()}; + for (int i = 0; i < blocks; ++i) { + for (int j = 0; j < claimsPerBlock; ++j) { + auto name = names[i * claimsPerBlock + j]; + auto supportFront = frc.randrange(4) == 0; + auto supportBack = frc.randrange(4) == 0; + auto removeClaim = frc.randrange(4) == 0; + auto removeSupport = frc.randrange(4) == 0; + auto hit = existingClaims.find(name); + if (supportFront && hit != existingClaims.end() && hit->second.size()) { + auto tx = fixture.MakeSupport(cb.back(), hit->second[frc.rand64() % hit->second.size()], name, 2); + existingSupports.push_back(tx); + cb.emplace_back(std::move(tx)); + } + if (removeClaim && hit != existingClaims.end() && hit->second.size()) { + auto idx = frc.rand64() % hit->second.size(); + fixture.Spend(hit->second[idx]); + hit->second.erase(hit->second.begin() + idx); + } else { + auto tx = fixture.MakeClaim(cb.back(), name, value, 2); + existingClaims[name].push_back(tx); + hit = existingClaims.find(name); + cb.emplace_back(std::move(tx)); + } + if (supportBack && hit != existingClaims.end() && hit->second.size()) { + auto tx = fixture.MakeSupport(cb.back(), hit->second[frc.rand64() % hit->second.size()], name, 2); + existingSupports.push_back(tx); + cb.emplace_back(std::move(tx)); + } + if (removeSupport && (i & 7) == 7 && !existingSupports.empty()) { + const auto tidx = frc.rand64() % existingSupports.size(); + const auto tx = existingSupports[tidx]; + fixture.Spend(tx); + existingSupports.erase(existingSupports.begin() + tidx); + } + if (cb.back().GetValueOut() < 10 || cb.size() > 40000) { + cb.clear(); + cb.push_back(fixture.GetCoinbase()); + } + } + fixture.IncrementBlocks(1); + if (blocks > 13 && i % 50 == 0) // travisCI needs some periodic output + std::cerr << "In triehash_fuzzer_test with " << fixture.getTotalNamesInTrie() << " names at block " << i << std::endl; + } + + if (blocks == 1000 && claimsPerBlock == 100) + BOOST_CHECK_EQUAL(fixture.getMerkleHash().GetHex(), "28825257a129eef69cab87d6255c8359fc6dc083ca7f09222526e3a7971f382d"); + else if (blocks == 13 && claimsPerBlock == 100) + BOOST_CHECK_EQUAL(fixture.getMerkleHash().GetHex(), "4e5984d6984f5f05d50e821e6228d56bcfbd16ca2093cd0308f6ff1c2bc8689a"); + else + std::cerr << "Hash: " << fixture.getMerkleHash().GetHex() << std::endl; +} +#endif BOOST_AUTO_TEST_CASE(insert_erase_test) {