diff --git a/src/chainparams.cpp b/src/chainparams.cpp index f16b27b41c..29df68e959 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -136,7 +136,7 @@ class CMainParams : public CChainParams { consensus.nAllowMinDiffMaxHeight = -1; consensus.nNormalizedNameForkHeight = 539940; // targeting 21 March 2019 consensus.nMinRemovalWorkaroundHeight = 297706; - consensus.nMaxRemovalWorkaroundHeight = 100000000; + consensus.nMaxRemovalWorkaroundHeight = 658300; consensus.nAllClaimsInMerkleForkHeight = 658310; // targeting 30 Oct 2019 consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowNoRetargeting = false; @@ -147,10 +147,10 @@ class CMainParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 // The best chain should have at least this much work. - consensus.nMinimumChainWork = uint256S("0000000000000000000000000000000000000000000002bfdb5232f364d6774e"); //700k + consensus.nMinimumChainWork = uint256S("0000000000000000000000000000000000000000000003253077412df5b49766"); //749k // By default assume that the signatures in ancestors of this block are valid. - consensus.defaultAssumeValid = uint256S("beaf6432c9a7be3ea8c333bd7a90d4b3e07b0f20c86aa2e5dfebc9eba340201c"); //700k + consensus.defaultAssumeValid = uint256S("b9676f45be594438a2011407c93bb530d817fa365846e7a6ecdf2790e4a0ad6b"); //749k /** * The message start string is designed to be unlikely to occur in normal data. @@ -256,10 +256,10 @@ class CTestNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 // The best chain should have at least this much work. - consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000000004f6bb06a9"); + consensus.nMinimumChainWork = uint256S("00000000000000000000000000000000000000000000000000000054b7d280af"); // 8400 // By default assume that the signatures in ancestors of this block are valid. - consensus.defaultAssumeValid = uint256S("0x079557d16edcd640c4057c9fddb81257263014fe384c4aa348c5b9d190650a46"); // 14 + consensus.defaultAssumeValid = uint256S("50b68b892f4e0f2ef649df37ef10b702e826c8913cc785c5e8ec16dd6be83f8b"); // 8400 pchMessageStart[0] = 0xfa; pchMessageStart[1] = 0xe4; diff --git a/src/claimtrie/trie.cpp b/src/claimtrie/trie.cpp index 4a74c6b825..17782156b9 100644 --- a/src/claimtrie/trie.cpp +++ b/src/claimtrie/trie.cpp @@ -200,6 +200,27 @@ bool CClaimTrieCacheBase::haveSupportInQueue(const std::string& name, const COut return false; } +bool emptyNodeShouldExistAt(const sqlite::database& db, const std::string& name, int nNextHeight, int requiredChildren) { + auto end = name + std::string(256, std::numeric_limits::max()); // 256 == MAX_CLAIM_NAME_SIZE + 1 + auto query = db << "SELECT DISTINCT nodeName FROM claim " + "WHERE nodeName BETWEEN ?1 AND ?2 " + "AND activationHeight < ?3 AND expirationHeight >= ?3 " + "ORDER BY nodeName" + << name << end << nNextHeight; + std::unordered_set ss; + for (auto&& row: query) { + std::string nn; + row >> nn; + if (nn == name) + return false; + assert(nn.size() > name.size()); + ss.insert(nn[name.size()]); + if (ss.size() >= requiredChildren) + return true; + } + return false; +} + bool CClaimTrieCacheBase::deleteNodeIfPossible(const std::string& name, std::string& parent, int64_t& claims) { if (name.empty()) return false; @@ -700,19 +721,10 @@ bool CClaimTrieCacheBase::removeClaim(const uint160& claimId, const COutPoint& o // because it's a parent one and should not be effectively erased // we had a bug in the old code where that situation would force a zero delay on re-add if (nNextHeight >= base->nMinRemovalWorkaroundHeight - && nNextHeight < base->nMaxRemovalWorkaroundHeight) { // TODO: hard fork this out (which we already tried once but failed) - // neither LIKE nor SUBSTR will use an index on a blob, but BETWEEN is a good, fast alternative - auto end = nodeName + std::string( 256, std::numeric_limits::max()); // 256 == MAX_CLAIM_NAME_SIZE + 1 - auto innerQuery = db << "SELECT nodeName FROM claim WHERE nodeName BETWEEN ?1 AND ?2 " - "AND activationHeight < ?3 AND expirationHeight >= ?3 ORDER BY nodeName LIMIT 1" - << nodeName << end << nNextHeight; - for (auto&& row: innerQuery) { - std::string shortestMatch; - row >> shortestMatch; - if (shortestMatch != nodeName) - // set this when there are no more claims on that name and that node still has children - removalWorkaround.insert(nodeName); - } + && nNextHeight < base->nMaxRemovalWorkaroundHeight + ) { + if (emptyNodeShouldExistAt(db, nodeName, nNextHeight, 1)) + removalWorkaround.insert(nodeName); } return true; } @@ -869,14 +881,30 @@ int CClaimTrieCacheBase::getDelayForName(const std::string& name, const uint160& return 0; } - // NOTE: old code had a bug in it where nodes with no claims but with children would get left in the cache after removal. - // This would cause the getNumBlocksOfContinuousOwnership to return zero (causing incorrect takeover height calc). - auto hit = removalWorkaround.find(name); - if (hit != removalWorkaround.end()) { - removalWorkaround.erase(hit); - return 0; + if (nNextHeight > base->nMaxRemovalWorkaroundHeight) { + if (!hasCurrentWinner) + return 0; + + // TODO: hard fork this out! It's wrong but kept for backwards compatibility + // Plan: if we have no claims for this node but we do have multiple children + // such that we have an implicit node here then return a 0 + if (emptyNodeShouldExistAt(db, name, nNextHeight, 2)) + return 0; + } + else { + // NOTE: old code had a bug in it where nodes with no claims but with children would get left in the cache after removal. + // This would cause the getNumBlocksOfContinuousOwnership to return zero (causing incorrect takeover height calc). + auto hit = removalWorkaround.find(name); + if (hit != removalWorkaround.end()) { + removalWorkaround.erase(hit); + return 0; + } } - return hasCurrentWinner ? std::min((nNextHeight - winningTakeoverHeight) / base->nProportionalDelayFactor, 4032) : 0; + + if (!hasCurrentWinner) + return 0; + + return std::min((nNextHeight - winningTakeoverHeight) / base->nProportionalDelayFactor, 4032); } std::string CClaimTrieCacheBase::adjustNameForValidHeight(const std::string& name, int validHeight) const diff --git a/src/test/claimtriebranching_tests.cpp b/src/test/claimtriebranching_tests.cpp index a0edc580e3..566a308a01 100644 --- a/src/test/claimtriebranching_tests.cpp +++ b/src/test/claimtriebranching_tests.cpp @@ -24,6 +24,32 @@ BOOST_AUTO_TEST_CASE(claim_replace_test) { BOOST_CHECK(fixture.is_best_claim("bassfisher", tx2)); } +BOOST_AUTO_TEST_CASE(triple_update_test) +{ + ClaimTrieChainFixture fixture; + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 10); + fixture.IncrementBlocks(1); + CMutableTransaction tx1a = fixture.MakeClaim(fixture.GetCoinbase(), "tester", "one", 3); + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 5); + auto height = ::ChainActive().Tip()->nHeight; + fixture.IncrementBlocks(9); + + CMutableTransaction tx3 = fixture.MakeUpdate(tx1, "test", "two", ClaimIdHash(tx1.GetHash(), 0), 10); + CMutableTransaction tx4 = fixture.MakeUpdate(tx2, "test", "two", ClaimIdHash(tx2.GetHash(), 0), 15); + CMutableTransaction tx5 = fixture.MakeUpdate(tx4, "test", "two", ClaimIdHash(tx2.GetHash(), 0), 5); + + fixture.IncrementBlocks(1); + BOOST_CHECK(fixture.is_best_claim("test", tx3)); + uint160 id; int takeover; + BOOST_REQUIRE(fixture.getLastTakeoverForName("test", id, takeover)); + BOOST_CHECK_EQUAL(takeover, height); + id = ClaimIdHash(tx2.GetHash(), 0); + std::string name; + CClaimValue value; + BOOST_REQUIRE(fixture.getClaimById(id, name, value)); + BOOST_CHECK_EQUAL(value.nValidAtHeight, height+20); +} + BOOST_AUTO_TEST_CASE(takeover_stability_test) { // no competing bids ClaimTrieChainFixture fixture; diff --git a/src/test/claimtrieexpirationfork_tests.cpp b/src/test/claimtrieexpirationfork_tests.cpp index 21f16384f7..8082cb2a8e 100644 --- a/src/test/claimtrieexpirationfork_tests.cpp +++ b/src/test/claimtrieexpirationfork_tests.cpp @@ -824,11 +824,12 @@ BOOST_AUTO_TEST_CASE(removal_workaround_functions) fixture.IncrementBlocks(1); BOOST_CHECK(fixture.is_best_claim("a", tx3a)); - fixture.IncrementBlocks(7); - CMutableTransaction tx4a = fixture.MakeUpdate(tx2a, "b", "b", ClaimIdHash(tx2a.GetHash(), 0), 4); - CMutableTransaction tx4b = fixture.MakeUpdate(tx2b, "b", "b", ClaimIdHash(tx2b.GetHash(), 0), 5); // trigger a takeover - fixture.IncrementBlocks(1); - BOOST_CHECK(fixture.is_best_claim("b", tx4b)); + // TODO: bring this back after we hard fork out the removal workaround part 2! +// fixture.IncrementBlocks(7); +// CMutableTransaction tx4a = fixture.MakeUpdate(tx2a, "b", "b", ClaimIdHash(tx2a.GetHash(), 0), 4); +// CMutableTransaction tx4b = fixture.MakeUpdate(tx2b, "b", "b", ClaimIdHash(tx2b.GetHash(), 0), 5); // trigger a takeover +// fixture.IncrementBlocks(1); +// BOOST_CHECK(fixture.is_best_claim("b", tx4b)); } BOOST_AUTO_TEST_SUITE_END()