diff --git a/src/claimscriptop.cpp b/src/claimscriptop.cpp index 9b733607e..6c1f84401 100644 --- a/src/claimscriptop.cpp +++ b/src/claimscriptop.cpp @@ -15,7 +15,7 @@ bool CClaimScriptAddOp::claimName(CClaimTrieCache& trieCache, const std::string& const std::vector& metadata) { auto claimId = ClaimIdHash(point.hash, point.n); - LogPrint(BCLog::CLAIMS, "+++ Claim added: %s, c: %.6s, t: %.6s:%d, h: %.6d, a: %du\n", + LogPrint(BCLog::CLAIMS, "+++ Claim added: %s, c: %.6s, t: %.6s:%d, h: %.6d, a: %d\n", name, claimId.GetHex(), point.hash.GetHex(), point.n, nHeight, nValue); return addClaim(trieCache, name, claimId, -1, metadata); } @@ -23,7 +23,7 @@ bool CClaimScriptAddOp::claimName(CClaimTrieCache& trieCache, const std::string& bool CClaimScriptAddOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId, const std::vector& metadata) { - LogPrint(BCLog::CLAIMS, "+++ Claim updated: %s, c: %.6s, t: %.6s:%d, h: %.6d, a: %du\n", + LogPrint(BCLog::CLAIMS, "+++ Claim updated: %s, c: %.6s, t: %.6s:%d, h: %.6d, a: %d\n", name, claimId.GetHex(), point.hash.GetHex(), point.n, nHeight, nValue); return addClaim(trieCache, name, claimId, -1, metadata); } @@ -37,7 +37,7 @@ bool CClaimScriptAddOp::addClaim(CClaimTrieCache& trieCache, const std::string& bool CClaimScriptAddOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId, const std::vector& metadata) { - LogPrint(BCLog::CLAIMS, "+++ Support added: %s, c: %.6s, t: %.6s:%d, h: %.6d, a: %du\n", + LogPrint(BCLog::CLAIMS, "+++ Support added: %s, c: %.6s, t: %.6s:%d, h: %.6d, a: %d\n", name, claimId.GetHex(), point.hash.GetHex(), point.n, nHeight, nValue); return trieCache.addSupport(name, point, nValue, claimId, nHeight, -1, metadata); } diff --git a/src/claimtrie.cpp b/src/claimtrie.cpp index b6b97e34e..3626cdfd4 100644 --- a/src/claimtrie.cpp +++ b/src/claimtrie.cpp @@ -99,6 +99,8 @@ CClaimTrieCacheBase::~CClaimTrieCacheBase() { db << "rollback"; transacting = false; } + claimHashQuery.used(true); + childHashQuery.used(true); } bool CClaimTrie::SyncToDisk() @@ -234,6 +236,12 @@ void CClaimTrieCacheBase::ensureTreeStructureIsUpToDate() { "SELECT SUBSTR(p, 1, LENGTH(p)-1) FROM prefix WHERE p != '') SELECT p FROM prefix) " "ORDER BY name DESC LIMIT 1"; + auto insertQuery = db << "INSERT INTO nodes(name, parent, hash) VALUES(?, ?, NULL) " + "ON CONFLICT(name) DO UPDATE SET parent = excluded.parent, hash = NULL"; + + auto updateUnaffectedsQuery = db << "UPDATE nodes SET parent = ? WHERE name LIKE ? AND LENGTH(parent) < ?"; + + for (auto& name: names) { std::vector claims; std::string parent; @@ -273,26 +281,43 @@ void CClaimTrieCacheBase::ensureTreeStructureIsUpToDate() { break; } // insert the split node: - LogPrint(BCLog::CLAIMS, "Inserting split node %s, parent %s\n", newNodeName, parent); - db << "INSERT INTO nodes(name, parent, hash) VALUES(?, ?, NULL) " - "ON CONFLICT(name) DO UPDATE SET parent = excluded.parent, hash = NULL" - << newNodeName << parent; + LogPrint(BCLog::CLAIMS, "Inserting split node %s near %s, parent %s\n", newNodeName, sibling, parent); + insertQuery << newNodeName << parent; + insertQuery++; + + if (newNodeName.find('_') == std::string::npos && newNodeName.find('%') == std::string::npos) { + updateUnaffectedsQuery << newNodeName << newNodeName + "_%" << newNodeName.size(); + updateUnaffectedsQuery++; + } + else + db << "UPDATE nodes SET parent = ?1 WHERE SUBSTR(name, 1, ?2) = ?1 AND LENGTH(parent) < ?2 AND name != ?1" + << newNodeName << newNodeName.size(); + + parent = std::move(newNodeName); break; } } LogPrint(BCLog::CLAIMS, "Inserting or updating node %s, parent %s\n", name, parent); - db << "INSERT INTO nodes(name, parent, hash) VALUES(?, ?, NULL) " - "ON CONFLICT(name) DO UPDATE SET parent = excluded.parent, hash = NULL" - << name << parent; + insertQuery << name << parent; + insertQuery++; if (splitPos == 0) db << "UPDATE nodes SET hash = NULL WHERE name = ?" << parent; - db << "UPDATE nodes SET parent = ?1 WHERE SUBSTR(name, 1, ?2) = ?1 AND LENGTH(parent) < ?2 AND name != ?1" - << name << name.size(); + if (name.find('_') == std::string::npos && name.find('%') == std::string::npos) { + updateUnaffectedsQuery << name << name + "_%" << name.size(); + updateUnaffectedsQuery++; + } + else + db << "UPDATE nodes SET parent = ?1 WHERE SUBSTR(name, 1, ?2) = ?1 AND LENGTH(parent) < ?2 AND name != ?1" + << name << name.size(); } + parentQuery.used(true); + insertQuery.used(true); + updateUnaffectedsQuery.used(true); + // now we need to percolate the nulls up the tree // parents should all be set right db << "UPDATE nodes SET hash = NULL WHERE name IN (WITH RECURSIVE prefix(p) AS " @@ -320,7 +345,7 @@ std::size_t CClaimTrieCacheBase::getTotalClaimsInTrie() const CAmount CClaimTrieCacheBase::getTotalValueOfClaimsInTrie(bool fControllingOnly) const { CAmount ret = 0; - std::string query("SELECT (SELECT TOTAL(s.amount)+c.amount FROM supports s " + std::string query("SELECT TOTAL(SELECT TOTAL(s.amount)+c.amount FROM supports s " "WHERE s.supportedClaimID = c.claimID AND s.validHeight < ?1 AND s.expirationHeight >= ?1) " "FROM claims c WHERE c.validHeight < ?1 AND s.expirationHeight >= ?1"); if (fControllingOnly) @@ -417,6 +442,7 @@ uint256 CClaimTrieCacheBase::recursiveComputeMerkleHash(const std::string& name, if (child.hash->IsNull()) { *child.hash = recursiveComputeMerkleHash(child.name, child.takeoverHeight, checkOnly); } + LogPrint(BCLog::CLAIMS, "Hash of %s: %s, takeover: %d\n", child.name, (*child.hash).GetHex(), child.takeoverHeight); completeHash(*child.hash, child.name, pos); vchToHash.push_back(child.name[pos]); vchToHash.insert(vchToHash.end(), child.hash->begin(), child.hash->end()); @@ -1003,6 +1029,10 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimUndoTy } } + getTakeoverQuery.used(true); + hasCandidateQuery.used(true); + noCandidateQuery.used(true); + nNextHeight++; return true; } @@ -1302,8 +1332,7 @@ bool CClaimTrieCacheBase::getProofForName(const std::string& name, const uint160 const auto pos = key.size(); std::vector> children; - auto childQuery = db << "SELECT name, hash FROM nodes WHERE parent = ?" << key; - for (auto&& child : childQuery) { + for (auto&& child : childHashQuery << key) { std::string childKey; uint256 hash; child >> childKey >> hash; @@ -1321,6 +1350,7 @@ bool CClaimTrieCacheBase::getProofForName(const std::string& name, const uint160 completeHash(hash, childKey, pos); children.emplace_back(childKey[pos], hash); } + childHashQuery++; if (key == name) { proof.hasValue = fNodeHasValue && claim.claimId == finalClaim; if (proof.hasValue) { diff --git a/src/test/claimtriebranching_tests.cpp b/src/test/claimtriebranching_tests.cpp index c8d0d2c0e..ad6a96eca 100644 --- a/src/test/claimtriebranching_tests.cpp +++ b/src/test/claimtriebranching_tests.cpp @@ -42,6 +42,22 @@ BOOST_AUTO_TEST_CASE(takeover_stability_test) { BOOST_CHECK_EQUAL(takeover, height); } +BOOST_AUTO_TEST_CASE(unaffected_children_get_new_parents_test) { + // this happens first on block 193976 + ClaimTrieChainFixture fixture; + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "longest123", "one", 1); + fixture.IncrementBlocks(1); + CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "longest", "two", 2); + CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "longest1", "three", 3); + CMutableTransaction tx4 = fixture.MakeClaim(tx3, "longest1", "three1234", 2); + fixture.IncrementBlocks(1); + auto n1 = fixture.getNodeChildren("longest"); + auto n2 = fixture.getNodeChildren("longest1"); + BOOST_CHECK_EQUAL(n1[0], "longest1"); + BOOST_CHECK_EQUAL(n2[0], "longest123"); + // TODO: this test at present fails to cover the split node case of the same thing (which occurs on block 202577) +} + /* claims no competing bids diff --git a/src/test/claimtriefixture.cpp b/src/test/claimtriefixture.cpp index 1685b8730..a4a78845d 100644 --- a/src/test/claimtriefixture.cpp +++ b/src/test/claimtriefixture.cpp @@ -403,3 +403,12 @@ bool ClaimTrieChainFixture::getClaimById(const uint160 &claimId, std::string &na } return hit; } + +std::vector ClaimTrieChainFixture::getNodeChildren(const std::string &name) { + std::vector ret; + for (auto&& row: db << "SELECT name FROM nodes WHERE parent = ?" << name) { + ret.emplace_back(); + row >> ret.back(); + } + return ret; +} diff --git a/src/test/claimtriefixture.h b/src/test/claimtriefixture.h index d6fd06268..1624d35a8 100644 --- a/src/test/claimtriefixture.h +++ b/src/test/claimtriefixture.h @@ -113,6 +113,8 @@ struct ClaimTrieChainFixture: public CClaimTrieCache // check effective quantity of best claim boost::test_tools::predicate_result best_claim_effective_amount_equals(const std::string& name, CAmount amount); + + std::vector getNodeChildren(const std::string& name); }; #endif // _CLAIMTRIEFIXTURE_H_