From c759aebfab2b97088ab2d59b3ecf171362ee490d Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Wed, 9 Dec 2015 23:37:16 -0500 Subject: [PATCH] handle situation where expired claim is spent correctly --- src/claimtrie.cpp | 2 +- src/miner.cpp | 3 +- src/test/claimtrie_tests.cpp | 103 ++++++++++++++++++++++++++++++++++- 3 files changed, 102 insertions(+), 6 deletions(-) diff --git a/src/claimtrie.cpp b/src/claimtrie.cpp index 34b55798a..713622531 100644 --- a/src/claimtrie.cpp +++ b/src/claimtrie.cpp @@ -1222,12 +1222,12 @@ bool CClaimTrieCache::removeClaimFromTrie(const std::string name, uint256 txhash if (!success) { LogPrintf("%s: Removing a claim was unsuccessful. name = %s, txhash = %s, nOut = %d", __func__, name.c_str(), txhash.GetHex(), nOut); + return false; } else { nValidAtHeight = claim.nValidAtHeight; } - assert(success); if (fChanged) { for (std::string::const_iterator itCur = name.begin(); itCur != name.end(); ++itCur) diff --git a/src/miner.cpp b/src/miner.cpp index 380467523..f09734224 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -324,8 +324,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) assert(vvchParams.size() == 2); std::string name(vvchParams[0].begin(), vvchParams[0].end()); int throwaway; - if (!trieCache.spendClaim(name, txin.prevout.hash, txin.prevout.n, coins->nHeight, throwaway)) - LogPrintf("%s: Something went wrong removing the name\n", __func__); + trieCache.spendClaim(name, txin.prevout.hash, txin.prevout.n, coins->nHeight, throwaway); std::pair val(txin.prevout.hash, txin.prevout.n); std::pair >entry(name, val); spentClaims.insert(entry); diff --git a/src/test/claimtrie_tests.cpp b/src/test/claimtrie_tests.cpp index 097ad012c..24cd3ad9a 100644 --- a/src/test/claimtrie_tests.cpp +++ b/src/test/claimtrie_tests.cpp @@ -706,13 +706,16 @@ BOOST_AUTO_TEST_CASE(claimtrie_claim_expiration) tx1.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName << vchValue << OP_2DROP << OP_DROP << OP_TRUE; CMutableTransaction tx2 = BuildTransaction(tx1); tx2.vout[0].scriptPubKey = CScript() << OP_TRUE; - + CMutableTransaction tx3 = BuildTransaction(coinbases[1]); + tx3.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName << vchValue << OP_2DROP << OP_DROP << OP_TRUE; + tx3.vout[0].nValue = tx1.vout[0].nValue >> 1; + std::vector blocks_to_invalidate; // set expiration time to 100 blocks after the block becomes valid. (more correctly, 200 blocks after the block is created) pclaimTrie->setExpirationTime(200); - // create a claim. verify no expiration event has been scheduled. + // create a claim. verify the expiration event has been scheduled. AddToMempool(tx1); @@ -723,7 +726,7 @@ BOOST_AUTO_TEST_CASE(claimtrie_claim_expiration) BOOST_CHECK(!pclaimTrie->queueEmpty()); BOOST_CHECK(!pclaimTrie->expirationQueueEmpty()); - // advance until the claim is valid. verify the expiration event is scheduled. + // advance until the claim is valid. BOOST_CHECK(CreateBlocks(99, 1)); @@ -930,6 +933,100 @@ BOOST_AUTO_TEST_CASE(claimtrie_claim_expiration) BOOST_CHECK(pclaimTrie->queueEmpty()); BOOST_CHECK(pclaimTrie->expirationQueueEmpty()); BOOST_CHECK(blocks_to_invalidate.empty()); + + // Make sure that when a claim expires, a lesser claim for the same name takes over + + CClaimValue val; + + // create one claims for the name + + AddToMempool(tx1); + + BOOST_CHECK(CreateBlocks(1, 2)); + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(!pclaimTrie->queueEmpty()); + BOOST_CHECK(!pclaimTrie->expirationQueueEmpty()); + + // advance a little while and insert the second claim + + BOOST_CHECK(CreateBlocks(49, 1)); + + AddToMempool(tx3); + + BOOST_CHECK(CreateBlocks(1, 2)); + + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(!pclaimTrie->queueEmpty()); + BOOST_CHECK(!pclaimTrie->expirationQueueEmpty()); + + // advance until tx1 is valid + + BOOST_CHECK(CreateBlocks(49, 1)); + + BOOST_CHECK(pclaimTrie->empty()); + + BOOST_CHECK(CreateBlocks(1, 1)); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(!pclaimTrie->queueEmpty()); + BOOST_CHECK(!pclaimTrie->expirationQueueEmpty()); + + // advance until tx3 is valid, ensure tx1 is winning + + BOOST_CHECK(CreateBlocks(49, 1)); + + BOOST_CHECK(CreateBlocks(1, 1)); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + BOOST_CHECK(!pclaimTrie->expirationQueueEmpty()); + BOOST_CHECK(pclaimTrie->getInfoForName(sName, val)); + BOOST_CHECK(val.txhash == tx1.GetHash()); + + // advance until the expiration event occurs. verify the expiration event occurs on time. + + BOOST_CHECK(CreateBlocks(1, 1)); + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + BOOST_CHECK(CreateBlocks(48, 1)); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + BOOST_CHECK(!pclaimTrie->expirationQueueEmpty()); + + BOOST_CHECK(CreateBlocks(1, 1)); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + BOOST_CHECK(!pclaimTrie->expirationQueueEmpty()); + BOOST_CHECK(pclaimTrie->getInfoForName(sName, val)); + BOOST_CHECK(val.txhash == tx3.GetHash()); + + // spend tx1 + + AddToMempool(tx2); + + BOOST_CHECK(CreateBlocks(1, 2)); + + // roll back to when tx1 and tx3 are in the trie and tx1 is winning + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + BOOST_CHECK(!pclaimTrie->expirationQueueEmpty()); + BOOST_CHECK(pclaimTrie->getInfoForName(sName, val)); + BOOST_CHECK(val.txhash == tx1.GetHash()); + + // roll all the way back + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + BOOST_CHECK(pclaimTrie->expirationQueueEmpty()); + BOOST_CHECK(blocks_to_invalidate.empty()); } BOOST_AUTO_TEST_CASE(claimtrie_supporting_claims)