diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 91923ea70..81fd3274b 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -131,6 +131,9 @@ public: consensus.powLimit = uint256S("0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowTargetTimespan = 150; //retarget every block consensus.nPowTargetSpacing = 150; + consensus.nOriginalClaimExpirationTime = 262974; + consensus.nExtendedClaimExpirationTime = 2102400; + consensus.nExtendedClaimExpirationForkHeight = 400000; // FIXME: pick a real height consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowNoRetargeting = false; consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016 @@ -215,6 +218,9 @@ public: consensus.powLimit = uint256S("0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowTargetTimespan = 150; consensus.nPowTargetSpacing = 150; + consensus.nOriginalClaimExpirationTime = 262974; + consensus.nExtendedClaimExpirationTime = 2102400; + consensus.nExtendedClaimExpirationForkHeight = 400000; // FIXME: pick a real height consensus.fPowAllowMinDifficultyBlocks = true; consensus.fPowNoRetargeting = false; consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains @@ -292,6 +298,9 @@ public: consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowTargetTimespan = 1;//14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 1; + consensus.nOriginalClaimExpirationTime = 262974; + consensus.nExtendedClaimExpirationTime = 2102400; + consensus.nExtendedClaimExpirationForkHeight = 450; // FIXME: pick a real height consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowNoRetargeting = false; consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains diff --git a/src/claimtrie.cpp b/src/claimtrie.cpp index 2560610b6..55a921e1a 100644 --- a/src/claimtrie.cpp +++ b/src/claimtrie.cpp @@ -218,6 +218,7 @@ bool CClaimTrie::supportQueueEmpty() const void CClaimTrie::setExpirationTime(int t) { nExpirationTime = t; + LogPrintf("%s: Expiration time is now %d\n", __func__, nExpirationTime); } void CClaimTrie::clear() @@ -1663,8 +1664,14 @@ bool CClaimTrieCache::removeClaim(const std::string& name, const COutPoint& outP void CClaimTrieCache::addToExpirationQueue(int nExpirationHeight, nameOutPointType& entry) const { - expirationQueueType::iterator itQueueRow = getExpirationQueueCacheRow(nExpirationHeight, true); - itQueueRow->second.push_back(entry); + const Consensus::Params& consensusParams = Params().GetConsensus(); + // NOTE: To allow extended claim expiration times, remove this check + if ((nExpirationHeight < consensusParams.nExtendedClaimExpirationForkHeight) || + (base->nExpirationTime != consensusParams.nExtendedClaimExpirationTime)) + { + expirationQueueType::iterator itQueueRow = getExpirationQueueCacheRow(nExpirationHeight, true); + itQueueRow->second.push_back(entry); + } } void CClaimTrieCache::removeFromExpirationQueue(const std::string& name, const COutPoint& outPoint, int nHeight) const @@ -1679,10 +1686,11 @@ void CClaimTrieCache::removeFromExpirationQueue(const std::string& name, const C if (name == itQueue->name && outPoint == itQueue->outPoint) break; } - } - if (itQueue != itQueueRow->second.end()) - { - itQueueRow->second.erase(itQueue); + + if (itQueue != itQueueRow->second.end()) + { + itQueueRow->second.erase(itQueue); + } } } @@ -2104,6 +2112,7 @@ bool CClaimTrieCache::incrementBlock(insertUndoType& insertUndo, claimQueueRowTy CClaimValue claim; assert(removeClaimFromTrie(itEntry->name, itEntry->outPoint, claim, true)); expireUndo.push_back(std::make_pair(itEntry->name, claim)); + LogPrintf("Expiring claim %s: %s, nHeight: %d, nValidAtHeight: %d\n", claim.claimId.GetHex(), itEntry->name, claim.nHeight, claim.nValidAtHeight); } itExpirationRow->second.clear(); } @@ -2155,6 +2164,7 @@ bool CClaimTrieCache::incrementBlock(insertUndoType& insertUndo, claimQueueRowTy CSupportValue support; assert(removeSupportFromMap(itEntry->name, itEntry->outPoint, support, true)); expireSupportUndo.push_back(std::make_pair(itEntry->name, support)); + LogPrintf("Expiring support %s: %s, nHeight: %d, nValidAtHeight: %d\n", support.supportedClaimId.GetHex(), itEntry->name, support.nHeight, support.nValidAtHeight); } itSupportExpirationRow->second.clear(); } diff --git a/src/claimtrie.h b/src/claimtrie.h index 7b6ab254d..774ba506e 100644 --- a/src/claimtrie.h +++ b/src/claimtrie.h @@ -6,6 +6,7 @@ #include "uint256.h" #include "util.h" #include "dbwrapper.h" +#include "chainparams.h" #include "primitives/transaction.h" #include @@ -282,7 +283,7 @@ class CClaimTrie public: CClaimTrie(bool fMemory = false, bool fWipe = false, int nProportionalDelayFactor = 32) : db(GetDataDir() / "claimtrie", 100, fMemory, fWipe, false) - , nCurrentHeight(0), nExpirationTime(262974) + , nCurrentHeight(0), nExpirationTime(262974) , nProportionalDelayFactor(nProportionalDelayFactor) , root(uint256S("0000000000000000000000000000000000000000000000000000000000000001")) {} diff --git a/src/consensus/params.h b/src/consensus/params.h index f1be85e9c..5356cd515 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -58,6 +58,14 @@ struct Params { bool fPowNoRetargeting; int64_t nPowTargetSpacing; int64_t nPowTargetTimespan; + int64_t nOriginalClaimExpirationTime; + int64_t nExtendedClaimExpirationTime; + int64_t nExtendedClaimExpirationForkHeight; + int64_t GetExpirationTime(int64_t nHeight) const { + return nHeight < nExtendedClaimExpirationForkHeight ? + nOriginalClaimExpirationTime : + nExtendedClaimExpirationTime; + } int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; } }; } // namespace Consensus diff --git a/src/init.cpp b/src/init.cpp index c064dd334..299d86b6b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1229,6 +1229,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("* Using %.1fMiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024)); LogPrintf("* Using %.1fMiB for in-memory UTXO set\n", nCoinCacheUsage * (1.0 / 1024 / 1024)); + const Consensus::Params& consensusParams = Params().GetConsensus(); + bool fLoaded = false; while (!fLoaded) { bool fReset = fReindex; @@ -1266,7 +1268,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // If the loaded chain has a wrong genesis, bail out immediately // (we're likely using a testnet datadir, or the other way around). - if (!mapBlockIndex.empty() && mapBlockIndex.count(chainparams.GetConsensus().hashGenesisBlock) == 0) + if (!mapBlockIndex.empty() && mapBlockIndex.count(consensusParams.hashGenesisBlock) == 0) return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?")); // Initialize the block index (no-op if non-empty database was already loaded) @@ -1422,6 +1424,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) RandAddSeedPerfmon(); + pclaimTrie->setExpirationTime(consensusParams.GetExpirationTime(chainActive.Height())); + //// debug print LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size()); LogPrintf("nBestHeight = %d\n", chainActive.Height()); @@ -1437,7 +1441,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) StartNode(threadGroup, scheduler); // Monitor the chain, and alert if we get blocks much quicker or slower than expected - int64_t nPowTargetSpacing = Params().GetConsensus().nPowTargetSpacing; + int64_t nPowTargetSpacing = consensusParams.nPowTargetSpacing; CScheduler::Function f = boost::bind(&PartitionCheck, &IsInitialBlockDownload, boost::ref(cs_main), boost::cref(pindexBestHeader), nPowTargetSpacing); scheduler.scheduleEvery(f, nPowTargetSpacing); diff --git a/src/main.cpp b/src/main.cpp index d9556d3b6..2be5ce511 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2163,12 +2163,22 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI if (op == OP_CLAIM_NAME) { assert(vvchParams.size() == 2); + std::string name(vvchParams[0].begin(), vvchParams[0].end()); + std::string value(vvchParams[1].begin(), vvchParams[1].end()); claimId = ClaimIdHash(hash, i); + LogPrintf("--- %s[%lu]: OP_CLAIM_NAME \"%s\" = \"%s\" with claimId %s and tx prevout %s at index %d\n", + __func__, view.AccessCoins(hash)->nHeight, name, SanitizeString(value), + claimId.GetHex(), hash.ToString(), i); } else if (op == OP_UPDATE_CLAIM) { assert(vvchParams.size() == 3); + std::string name(vvchParams[0].begin(), vvchParams[0].end()); + std::string value(vvchParams[1].begin(), vvchParams[1].end()); claimId = uint160(vvchParams[1]); + LogPrintf("--- %s[%lu]: OP_UPDATE_CLAIM \"%s\" = \"%s\" with claimId %s and tx prevout %s at index %d\n", + __func__, view.AccessCoins(hash)->nHeight, name, SanitizeString(value), + claimId.GetHex(), hash.ToString(), i); } std::string name(vvchParams[0].begin(), vvchParams[0].end()); LogPrintf("%s: (txid: %s, nOut: %d) Trying to remove %s from the claim trie due to its block being disconnected\n", __func__, hash.ToString(), i, name.c_str()); @@ -2182,6 +2192,8 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI assert(vvchParams.size() == 2); std::string name(vvchParams[0].begin(), vvchParams[0].end()); uint160 supportedClaimId(vvchParams[1]); + LogPrintf("--- %s[%lu]: OP_SUPPORT_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n", + __func__, view.AccessCoins(hash)->nHeight, name, supportedClaimId.GetHex(), hash.ToString(), i); LogPrintf("%s: (txid: %s, nOut: %d) Removing support for claim id %s on %s due to its block being disconnected\n", __func__, hash.ToString(), i, supportedClaimId.ToString(), name.c_str()); if (!trieCache.undoAddSupport(name, COutPoint(hash, i), pindex->nHeight)) LogPrintf("%s: Something went wrong removing support for name %s in hash %s\n", __func__, name.c_str(), hash.ToString()); @@ -2212,6 +2224,8 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI assert(trieCache.finalizeDecrement()); trieCache.setBestBlock(pindex->pprev->GetBlockHash()); assert(trieCache.getMerkleHash() == pindex->pprev->hashClaimTrie); + if (pindex->pprev->nHeight >= Params().GetConsensus().nExtendedClaimExpirationForkHeight) + pclaimTrie->setExpirationTime(Params().GetConsensus().GetExpirationTime(pindex->pprev->nHeight)); if (pfClean) { *pfClean = fClean; @@ -2565,12 +2579,22 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (op == OP_CLAIM_NAME) { assert(vvchParams.size() == 2); + std::string name(vvchParams[0].begin(), vvchParams[0].end()); + std::string value(vvchParams[1].begin(), vvchParams[1].end()); claimId = ClaimIdHash(txin.prevout.hash, txin.prevout.n); + LogPrintf("+++ %s[%lu]: OP_CLAIM_NAME \"%s\" = \"%s\" with claimId %s and tx prevout %s at index %d\n", + __func__, view.AccessCoins(txin.prevout.hash)->nHeight, name, SanitizeString(value), + claimId.GetHex(), txin.prevout.hash.GetHex(), txin.prevout.n); } else if (op == OP_UPDATE_CLAIM) { assert(vvchParams.size() == 3); + std::string name(vvchParams[0].begin(), vvchParams[0].end()); + std::string value(vvchParams[1].begin(), vvchParams[1].end()); claimId = uint160(vvchParams[1]); + LogPrintf("+++ %s[%lu]: OP_UPDATE_CLAIM \"%s\" = \"%s\" with claimId %s and tx prevout %s at index %d\n", + __func__, view.AccessCoins(txin.prevout.hash)->nHeight, name, SanitizeString(value), + claimId.GetHex(), txin.prevout.hash.GetHex(), txin.prevout.n); } std::string name(vvchParams[0].begin(), vvchParams[0].end()); int nValidAtHeight; @@ -2587,6 +2611,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin assert(vvchParams.size() == 2); std::string name(vvchParams[0].begin(), vvchParams[0].end()); uint160 supportedClaimId(vvchParams[1]); + LogPrintf("+++ %s[%lu]: OP_SUPPORT_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n", + __func__, view.AccessCoins(txin.prevout.hash)->nHeight, name, + supportedClaimId.GetHex(), txin.prevout.hash.GetHex(), txin.prevout.n); int nValidAtHeight; LogPrintf("%s: Removing support for %s in %s. Tx: %s, nOut: %d, removed txid: %s\n", __func__, supportedClaimId.ToString(), name, txin.prevout.hash.ToString(), txin.prevout.n,tx.GetHash().ToString()); if (trieCache.spendSupport(name, COutPoint(txin.prevout.hash, txin.prevout.n), coins->nHeight, nValidAtHeight)) @@ -2736,6 +2763,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // add this block to the view's block chain view.SetBestBlock(pindex->GetBlockHash()); trieCache.setBestBlock(pindex->GetBlockHash()); + if (pindex->nHeight >= Params().GetConsensus().nExtendedClaimExpirationForkHeight) + pclaimTrie->setExpirationTime(chainparams.GetConsensus().GetExpirationTime(pindex->nHeight)); int64_t nTime5 = GetTimeMicros(); nTimeIndex += nTime5 - nTime4; LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeIndex * 0.000001); diff --git a/src/test/claimtriebranching_tests.cpp b/src/test/claimtriebranching_tests.cpp index 94a0d65ea..026b353a8 100644 --- a/src/test/claimtriebranching_tests.cpp +++ b/src/test/claimtriebranching_tests.cpp @@ -683,6 +683,7 @@ BOOST_AUTO_TEST_CASE(claimtriebranching_update) fixture.DecrementBlocks(11); } + /* expiration check claims expire and loses claim @@ -733,5 +734,67 @@ BOOST_AUTO_TEST_CASE(claimtriebranching_expire) } +/* + expiration + check claims do not expire post ExpirationForkHeight + check supports work post ExpirationForkHeight +*/ +BOOST_AUTO_TEST_CASE(claimtriebranching_no_expire) +{ + ClaimTrieChainFixture fixture; + + // To activate the expiration hard fork, the expiration time must + // be set to 10 years of blocks (not used as 10 years, but rather + // a sentinel value for hard fork activation) and we must advance + // past nExtendedClaimExpirationForkHeight. This is purposely set + // low enough for testing in the Regtest chain parameters. + pclaimTrie->setExpirationTime(5); + const int expirationForkHeight = + Params(CBaseChainParams::REGTEST).GetConsensus().nExtendedClaimExpirationForkHeight; + + // First create a claim and make sure it expires pre-fork + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",3); + fixture.IncrementBlocks(6); + BOOST_CHECK(!is_best_claim("test",tx1)); + fixture.DecrementBlocks(4); + BOOST_CHECK(is_best_claim("test",tx1)); + fixture.IncrementBlocks(4); + BOOST_CHECK(!is_best_claim("test",tx1)); + + // Disable future expirations and fast-forward past the fork height + fixture.IncrementBlocks(expirationForkHeight); + pclaimTrie->setExpirationTime(2102400); + + // This first claim is still expired since it's pre-fork, even + // after fork activation + BOOST_CHECK(!is_best_claim("test",tx1)); + + // This new claim cannot expire + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",1); + fixture.IncrementBlocks(6); + + BOOST_CHECK(is_best_claim("test",tx2)); + BOOST_CHECK(!is_best_claim("test",tx1)); + + // 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(!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(!is_best_claim("test",u1)); + + // Ensure that we can update the new post-fork claim + CMutableTransaction u2 = fixture.MakeUpdate(tx2,"test","two",ClaimIdHash(tx2.GetHash(),0), 1); + fixture.IncrementBlocks(1); + BOOST_CHECK(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(is_best_claim("test",u2)); +} + + BOOST_AUTO_TEST_SUITE_END()