diff --git a/src/claimscriptop.cpp b/src/claimscriptop.cpp index 3109db36d..43f68c58f 100644 --- a/src/claimscriptop.cpp +++ b/src/claimscriptop.cpp @@ -174,8 +174,9 @@ bool ProcessClaim(CClaimScriptOp& claimOp, CClaimTrieCache& trieCache, const CSc case OP_UPDATE_CLAIM: return claimOp.updateClaim(trieCache, vchToString(vvchParams[0]), uint160(vvchParams[1]), vvchParams[2]); + default: + throw std::runtime_error("Unimplemented OP handler."); } - throw std::runtime_error("Unimplemented OP handler."); } void UpdateCache(const CTransaction& tx, CClaimTrieCache& trieCache, const CCoinsViewCache& view, int nHeight, const CUpdateCacheCallbacks& callbacks) @@ -188,12 +189,12 @@ void UpdateCache(const CTransaction& tx, CClaimTrieCache& trieCache, const CCoin bool spendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override { if (CClaimScriptSpendOp::spendClaim(trieCache, name, claimId)) { - callback(name, claimId, nValidHeight); + callback(name, claimId); return true; } return false; } - std::function callback; + std::function callback; }; spentClaimsType spentClaims; @@ -216,8 +217,8 @@ void UpdateCache(const CTransaction& tx, CClaimTrieCache& trieCache, const CCoin int nValidAtHeight; CSpendClaimHistory spendClaim(COutPoint(txin.prevout.hash, txin.prevout.n), scriptHeight, nValidAtHeight); - spendClaim.callback = [&spentClaims](const std::string& name, const uint160& claimId, const int takeoverHeight) { - spentClaims.emplace_back(name, claimId, takeoverHeight); + spendClaim.callback = [&spentClaims](const std::string& name, const uint160& claimId) { + spentClaims.emplace_back(name, claimId); }; if (ProcessClaim(spendClaim, trieCache, scriptPubKey) && callbacks.claimUndoHeights) callbacks.claimUndoHeights(j, nValidAtHeight); @@ -231,12 +232,11 @@ void UpdateCache(const CTransaction& tx, CClaimTrieCache& trieCache, const CCoin bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId, const std::vector& metadata) override { - int takeoverHeight = -1; - if (callback(name, claimId, takeoverHeight)) - return CClaimScriptAddOp::addClaim(trieCache, name, claimId, takeoverHeight, metadata); + if (callback(name, claimId)) + return CClaimScriptAddOp::addClaim(trieCache, name, claimId, -1, metadata); return false; } - std::function callback; + std::function callback; }; for (std::size_t j = 0; j < tx.vout.size(); j++) { @@ -246,10 +246,9 @@ void UpdateCache(const CTransaction& tx, CClaimTrieCache& trieCache, const CCoin continue; CAddSpendClaim addClaim(COutPoint(tx.GetHash(), j), txout.nValue, nHeight); - addClaim.callback = [&trieCache, &spentClaims](const std::string& name, const uint160& claimId, int& takeoverHeight) -> bool { + addClaim.callback = [&trieCache, &spentClaims](const std::string& name, const uint160& claimId) -> bool { for (auto itSpent = spentClaims.begin(); itSpent != spentClaims.end(); ++itSpent) { - if (std::get<1>(*itSpent) == claimId && trieCache.normalizeClaimName(name) == trieCache.normalizeClaimName(std::get<0>(*itSpent))) { - takeoverHeight = std::get<2>(*itSpent); + if (itSpent->second == claimId && trieCache.normalizeClaimName(name) == trieCache.normalizeClaimName(itSpent->first)) { spentClaims.erase(itSpent); return true; } diff --git a/src/claimscriptop.h b/src/claimscriptop.h index 583db10bf..b36fb2cd0 100644 --- a/src/claimscriptop.h +++ b/src/claimscriptop.h @@ -238,8 +238,7 @@ protected: */ bool ProcessClaim(CClaimScriptOp& claimOp, CClaimTrieCache& trieCache, const CScript& scriptPubKey); -typedef std::tuple spentClaimType; - +typedef std::pair spentClaimType; typedef std::vector spentClaimsType; struct CUpdateCacheCallbacks diff --git a/src/claimtrie.cpp b/src/claimtrie.cpp index 80ac2c0d3..c3202fb61 100644 --- a/src/claimtrie.cpp +++ b/src/claimtrie.cpp @@ -56,7 +56,7 @@ CClaimTrie::CClaimTrie(bool fWipe, int height, int proportionalDelayFactor) db.define("MERKLE_PAIR", [](const std::vector& blob1, const std::vector& blob2) { return Hash(blob1.begin(), blob1.end(), blob2.begin(), blob2.end()); }); db.define("MERKLE", [](const std::vector& blob1) { return Hash(blob1.begin(), blob1.end()); }); - db << "CREATE TABLE IF NOT EXISTS nodes (name TEXT NOT NULL PRIMARY KEY, parent TEXT, hash BLOB)"; + db << "CREATE TABLE IF NOT EXISTS nodes (name TEXT NOT NULL PRIMARY KEY, parent TEXT, hash BLOB, takeoverHeight INTEGER, takeoverID BLOB)"; db << "CREATE INDEX IF NOT EXISTS nodes_hash ON nodes (hash)"; db << "CREATE INDEX IF NOT EXISTS nodes_parent ON nodes (parent)"; @@ -325,13 +325,14 @@ CAmount CClaimTrieCacheBase::getTotalValueOfClaimsInTrie(bool fControllingOnly) return ret; } -bool CClaimTrieCacheBase::getInfoForName(const std::string& name, CClaimValue& claim) const +bool CClaimTrieCacheBase::getInfoForName(const std::string& name, CClaimValue& claim, int heightOffset) const { + auto nextHeight = nNextHeight + heightOffset; auto query = db << "SELECT c.claimID, c.txID, c.txN, c.blockHeight, c.validHeight, c.amount, " "(SELECT TOTAL(s.amount)+c.amount FROM supports s WHERE s.supportedClaimID = c.claimID AND s.validHeight < ? AND s.expirationHeight >= ?) as effectiveAmount " "FROM claims c WHERE c.nodeName = ? AND c.validHeight < ? AND c.expirationHeight >= ? " "ORDER BY effectiveAmount DESC, c.blockHeight, c.txID, c.txN LIMIT 1" - << nNextHeight << nNextHeight << name << nNextHeight << nNextHeight; + << nextHeight << nextHeight << name << nextHeight << nextHeight; for (auto&& row: query) { row >> claim.claimId >> claim.outPoint.hash >> claim.outPoint.n >> claim.nHeight >> claim.nValidAtHeight >> claim.nAmount >> claim.nEffectiveAmount; @@ -391,18 +392,19 @@ void completeHash(uint256& partialHash, const std::string& key, std::size_t to) .Finalize(partialHash.begin()); } -uint256 CClaimTrieCacheBase::recursiveComputeMerkleHash(const std::string& name, bool checkOnly) +uint256 CClaimTrieCacheBase::recursiveComputeMerkleHash(const std::string& name, int takeoverHeight, bool checkOnly) { std::vector vchToHash; const auto pos = name.size(); - auto query = db << "SELECT name, hash FROM nodes WHERE parent = ? ORDER BY name" << name; + auto query = db << "SELECT name, hash, IFNULL(takeoverHeight,0) FROM nodes WHERE parent = ? ORDER BY name" << name; for (auto&& row : query) { std::string key; + int childTakeoverHeight; std::unique_ptr hash; - row >> key >> hash; + row >> key >> hash >> childTakeoverHeight; if (hash == nullptr) hash = std::make_unique(); if (hash->IsNull()) { - *hash = recursiveComputeMerkleHash(key, checkOnly); + *hash = recursiveComputeMerkleHash(key, childTakeoverHeight, checkOnly); } completeHash(*hash, key, pos); vchToHash.push_back(key[pos]); @@ -411,7 +413,7 @@ uint256 CClaimTrieCacheBase::recursiveComputeMerkleHash(const std::string& name, CClaimValue claim; if (getInfoForName(name, claim)) { - uint256 valueHash = getValueHash(claim.outPoint, claim.nValidAtHeight); + uint256 valueHash = getValueHash(claim.outPoint, takeoverHeight); vchToHash.insert(vchToHash.end(), valueHash.begin(), valueHash.end()); } @@ -425,12 +427,13 @@ bool CClaimTrieCacheBase::checkConsistency() { // verify that all claims hash to the values on the nodes - auto query = db << "SELECT name, hash FROM nodes"; + auto query = db << "SELECT name, hash, IFNULL(takeoverHeight, 0) FROM nodes"; for (auto&& row: query) { std::string name; uint256 hash; - row >> name >> hash; - auto computedHash = recursiveComputeMerkleHash(name, true); + int takeoverHeight; + row >> name >> hash >> takeoverHeight; + auto computedHash = recursiveComputeMerkleHash(name, takeoverHeight, true); if (computedHash != hash) return false; } @@ -504,22 +507,23 @@ uint256 CClaimTrieCacheBase::getMerkleHash() { ensureTreeStructureIsUpToDate(); std::unique_ptr hash; - db << "SELECT hash FROM nodes WHERE name = ''" >> hash; + int takeoverHeight; + db << "SELECT hash, IFNULL(takeoverHeight, 0) FROM nodes WHERE name = ''" >> std::tie(hash, takeoverHeight); if (hash == nullptr || hash->IsNull()) { assert(transacting); // no data changed but we didn't have the root hash there already? - return recursiveComputeMerkleHash("", false); + return recursiveComputeMerkleHash("", takeoverHeight, false); } return *hash; } bool CClaimTrieCacheBase::getLastTakeoverForName(const std::string& name, uint160& claimId, int& takeoverHeight) const { - CClaimValue value; - if (!getInfoForName(name, value)) + auto query = db << "SELECT takeoverHeight, takeoverID FROM nodes WHERE name = ? AND takeoverID IS NOT NULL" << name; + auto it = query.begin(); + if (it == query.end()) return false; - takeoverHeight = value.nValidAtHeight; - claimId = value.claimId; - return true; + *it >> takeoverHeight >> claimId; + return !claimId.IsNull(); } bool CClaimTrieCacheBase::addClaim(const std::string& name, const COutPoint& outPoint, const uint160& claimId, @@ -528,18 +532,26 @@ bool CClaimTrieCacheBase::addClaim(const std::string& name, const COutPoint& out if (!transacting) { transacting = true; db << "begin"; } // in the update scenario the previous one should be removed already + // in the downgrade scenario, the one ahead will be removed already and the old one's valid height is input + // revisiting the update scenario we have two options: + // 1. let them pull the old one first, in which case they will be responsible to pass in validHeight (since we can't determine it's a 0 delay) + // 2. don't remove the old one; have this method do a kinder "update" situation. + // Option 2 has the issue in that we don't actually update if we don't have an existing match, + // and no way to know that here without an 'update' flag + // In addition, as we currently do option 1 they use that to get the old valid height and store that for undo + // We would have to make this method return that if we go without the removal + // The other problem with 1 is that the outer shell would need to know if the one they removed was a winner or not - if (nValidHeight <= 0) { - auto delay = getDelayForName(name, claimId); - nValidHeight = nHeight + delay; - } + if (nValidHeight < 0) + nValidHeight = nHeight + getDelayForName(name, claimId); // sets nValidHeight to the old value auto nodeName = adjustNameForValidHeight(name, nValidHeight); auto expires = expirationTime() + nHeight; - db << "INSERT INTO claims(claimID, name, nodeName, txID, txN, amount, blockHeight, validHeight, expirationHeight, metadata) " - "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" << claimId << name << nodeName - << outPoint.hash << outPoint.n << nAmount << nHeight << nValidHeight << expires << metadata; + db << "INSERT INTO claims(claimID, name, nodeName, txID, txN, amount, blockHeight, validHeight, expirationHeight, metadata) " + "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" << claimId << name << nodeName + << outPoint.hash << outPoint.n << nAmount << nHeight << nValidHeight << expires << metadata; db << "INSERT INTO nodes(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET hash = NULL" << nodeName; + return true; } @@ -548,10 +560,8 @@ bool CClaimTrieCacheBase::addSupport(const std::string& name, const COutPoint& o { if (!transacting) { transacting = true; db << "begin"; } - if (nValidHeight <= 0) { - auto delay = getDelayForName(name, supportedClaimId); - nValidHeight = nHeight + delay; - } + if (nValidHeight < 0) + nValidHeight = nHeight + getDelayForName(name, supportedClaimId); auto nodeName = adjustNameForValidHeight(name, nValidHeight); auto expires = expirationTime() + nHeight; db << "INSERT INTO supports(supportedClaimID, name, nodeName, txID, txN, amount, blockHeight, validHeight, expirationHeight, metadata) " @@ -884,7 +894,9 @@ static const boost::container::flat_map, int> takeov {{ 653524, "celtic-folk-music-full-live-concert-mps" }, 589762}, }; -bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo) +bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimUndoType& expireUndo, + insertUndoType& insertSupportUndo, supportUndoType& expireSupportUndo, + takeoverUndoType& takeoverUndo) { // the plan: // for every claim and support that becomes active this block set its node hash to null (aka, dirty) @@ -932,18 +944,32 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimQueueR db << "SELECT name FROM nodes WHERE hash IS NULL" >> takeovers; for (const auto& nameWithTakeover : takeovers) { + auto needsActivate = false; if (nNextHeight >= 496856 && nNextHeight <= 653524) { auto wit = takeoverWorkarounds.find(std::make_pair(nNextHeight, nameWithTakeover)); - if (wit != takeoverWorkarounds.end()) { - activateAllFor(insertUndo, insertSupportUndo, nameWithTakeover); - continue; - } + needsActivate = wit != takeoverWorkarounds.end(); } // if somebody activates on this block and they are the new best, then everybody activates on this block CClaimValue value; - if (!getInfoForName(nameWithTakeover, value) || value.nValidAtHeight == nNextHeight) + if (needsActivate || !getInfoForName(nameWithTakeover, value, 1) || value.nValidAtHeight == nNextHeight) { activateAllFor(insertUndo, insertSupportUndo, nameWithTakeover); + + // now that they're all in get the winner: + if (getInfoForName(nameWithTakeover, value, 1)) { + int existingHeight; + std::unique_ptr existingID; + db << "SELECT IFNULL(takeoverHeight, 0), takeoverID FROM nodes WHERE name = ?" + << nameWithTakeover >> std::tie(existingHeight, existingID); + if (existingID == nullptr || *existingID != value.claimId) { + takeoverUndo.emplace_back(nameWithTakeover, + std::make_pair(existingHeight, existingID == nullptr ? uint160() : *existingID)); + db << "UPDATE nodes SET takeoverHeight = ?, takeoverID = ? WHERE name = ?" + << nNextHeight << value.claimId << nameWithTakeover; + assert(db.rows_modified()); + } + } + } } nNextHeight++; @@ -985,12 +1011,15 @@ void CClaimTrieCacheBase::activateAllFor(insertUndoType& insertUndo, insertUndoT << nNextHeight << name << nNextHeight << nNextHeight; } -bool CClaimTrieCacheBase::decrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo) +bool CClaimTrieCacheBase::decrementBlock(insertUndoType& insertUndo, claimUndoType& expireUndo, + insertUndoType& insertSupportUndo, supportUndoType& expireSupportUndo) { if (!transacting) { transacting = true; db << "begin"; } nNextHeight--; + // to actually delete the expired items and then restore them here I would have to look up the metadata in the block + // that doesn't sound very fun so we modified the other queries to exclude expired items for (auto it = expireSupportUndo.crbegin(); it != expireSupportUndo.crend(); ++it) { db << "UPDATE supports SET validHeight = ? WHERE txID = ? AND txN = ?" << it->second.nValidAtHeight << it->second.outPoint.hash << it->second.outPoint.n; @@ -1017,16 +1046,20 @@ bool CClaimTrieCacheBase::decrementBlock(insertUndoType& insertUndo, claimQueueR db << "UPDATE nodes SET hash = NULL WHERE name = ?" << it->name; } + return true; +} + +bool CClaimTrieCacheBase::finalizeDecrement(takeoverUndoType& takeoverUndo) +{ db << "UPDATE nodes SET hash = NULL WHERE name IN " "(SELECT nodeName FROM claims WHERE validHeight = ?)" << nNextHeight; db << "UPDATE nodes SET hash = NULL WHERE name IN " "(SELECT nodeName FROM supports WHERE validHeight = ?)" << nNextHeight; - return true; -} + for (auto it = takeoverUndo.crbegin(); it != takeoverUndo.crend(); ++it) + db << "UPDATE nodes SET takeoverHeight = ?, takeoverID = ?, hash = NULL WHERE name = ?" + << it->second.first << it->second.second << it->first; -bool CClaimTrieCacheBase::finalizeDecrement() -{ return true; } @@ -1191,33 +1224,20 @@ static const boost::container::flat_set> ownershipWo { 646584, "calling-tech-support-scammers-live-3" }, }; -int CClaimTrieCacheBase::getNumBlocksOfContinuousOwnership(const std::string& name) const -{ - if (nNextHeight <= 646584 && ownershipWorkaround.find(std::make_pair(nNextHeight, name)) != ownershipWorkaround.end()) - return 0; - - CClaimValue value; - if (getInfoForName(name, value)) - return nNextHeight - value.nValidAtHeight; - - return 0; -} - -int CClaimTrieCacheBase::getDelayForName(const std::string& name) const -{ - int nBlocksOfContinuousOwnership = getNumBlocksOfContinuousOwnership(name); - return std::min(nBlocksOfContinuousOwnership / base->nProportionalDelayFactor, 4032); -} - int CClaimTrieCacheBase::getDelayForName(const std::string& name, const uint160& claimId) const { uint160 winningClaimId; int winningTakeoverHeight; - if (getLastTakeoverForName(name, winningClaimId, winningTakeoverHeight) && winningClaimId == claimId) { + auto found = getLastTakeoverForName(name, winningClaimId, winningTakeoverHeight); + if (found && winningClaimId == claimId) { assert(winningTakeoverHeight <= nNextHeight); return 0; } - return getDelayForName(name); + + if (nNextHeight <= 646584 && ownershipWorkaround.find(std::make_pair(nNextHeight, name)) != ownershipWorkaround.end()) + return 0; + + return found ? std::min((nNextHeight - winningTakeoverHeight) / base->nProportionalDelayFactor, 4032) : 0; } std::string CClaimTrieCacheBase::adjustNameForValidHeight(const std::string& name, int validHeight) const diff --git a/src/claimtrie.h b/src/claimtrie.h index 7540d2b27..5b2469e86 100644 --- a/src/claimtrie.h +++ b/src/claimtrie.h @@ -199,33 +199,6 @@ struct CNameOutPointHeightType } }; -struct CNameOutPointType -{ - std::string name; - COutPoint outPoint; - - CNameOutPointType() = default; - - CNameOutPointType(std::string name, const COutPoint& outPoint) - : name(std::move(name)), outPoint(outPoint) - { - } - - bool operator==(const CNameOutPointType& other) const - { - return name == other.name && outPoint == other.outPoint; - } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) - { - READWRITE(name); - READWRITE(outPoint); - } -}; - struct CClaimNsupports { CClaimNsupports() = default; @@ -347,9 +320,10 @@ struct CClaimTrieProof template using queueEntryType = std::pair; -typedef std::vector> claimQueueRowType; -typedef std::vector> supportQueueRowType; +typedef std::vector> claimUndoType; +typedef std::vector> supportUndoType; typedef std::vector insertUndoType; +typedef std::vector>> takeoverUndoType; class CClaimTrieCacheBase { @@ -370,29 +344,30 @@ public: bool haveSupportInQueue(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight) const; bool addClaim(const std::string& name, const COutPoint& outPoint, const uint160& claimId, CAmount nAmount, - int nHeight, int nValidHeight, const std::vector& metadata); + int nHeight, int nValidHeight = -1, const std::vector& metadata = {}); bool addSupport(const std::string& name, const COutPoint& outPoint, CAmount nAmount, - const uint160& supportedClaimId, int nHeight, int nValidHeight, const std::vector& metadata); + const uint160& supportedClaimId, int nHeight, int nValidHeight = -1, const std::vector& metadata = {}); bool removeSupport(const COutPoint& outPoint, std::string& nodeName, int& validHeight); bool removeClaim(const uint160& claimId, const COutPoint& outPoint, std::string& nodeName, int& validHeight); virtual bool incrementBlock(insertUndoType& insertUndo, - claimQueueRowType& expireUndo, - insertUndoType& insertSupportUndo, - supportQueueRowType& expireSupportUndo); + claimUndoType& expireUndo, + insertUndoType& insertSupportUndo, + supportUndoType& expireSupportUndo, + takeoverUndoType& takeovers); virtual bool decrementBlock(insertUndoType& insertUndo, - claimQueueRowType& expireUndo, - insertUndoType& insertSupportUndo, - supportQueueRowType& expireSupportUndo); + claimUndoType& expireUndo, + insertUndoType& insertSupportUndo, + supportUndoType& expireSupportUndo); - virtual bool getInfoForName(const std::string& name, CClaimValue& claim) const; + virtual bool getInfoForName(const std::string& name, CClaimValue& claim, int heightOffset = 0) const; virtual bool getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof); virtual int expirationTime() const; - virtual bool finalizeDecrement(); + virtual bool finalizeDecrement(takeoverUndoType& takeovers); virtual CClaimSupportToName getClaimsForName(const std::string& name) const; virtual std::string adjustNameForValidHeight(const std::string& name, int validHeight) const; @@ -412,14 +387,11 @@ protected: bool transacting; // one greater than the height of the chain's tip - virtual uint256 recursiveComputeMerkleHash(const std::string& name, bool checkOnly); + virtual uint256 recursiveComputeMerkleHash(const std::string& name, int takeoverHeight, bool checkOnly); supportEntryType getSupportsForName(const std::string& name) const; - int getDelayForName(const std::string& name) const; virtual int getDelayForName(const std::string& name, const uint160& claimId) const; - int getNumBlocksOfContinuousOwnership(const std::string& name) const; - bool deleteNodeIfPossible(const std::string& name, std::string& parent, std::vector& claims); void ensureTreeStructureIsUpToDate(); @@ -441,17 +413,18 @@ public: int expirationTime() const override; virtual void initializeIncrement(); - bool finalizeDecrement() override; + bool finalizeDecrement(takeoverUndoType& takeovers) override; bool incrementBlock(insertUndoType& insertUndo, - claimQueueRowType& expireUndo, - insertUndoType& insertSupportUndo, - supportQueueRowType& expireSupportUndo) override; + claimUndoType& expireUndo, + insertUndoType& insertSupportUndo, + supportUndoType& expireSupportUndo, + takeoverUndoType& takeovers) override; bool decrementBlock(insertUndoType& insertUndo, - claimQueueRowType& expireUndo, - insertUndoType& insertSupportUndo, - supportQueueRowType& expireSupportUndo) override; + claimUndoType& expireUndo, + insertUndoType& insertSupportUndo, + supportUndoType& expireSupportUndo) override; private: int nExpirationTime; @@ -473,17 +446,18 @@ public: std::string normalizeClaimName(const std::string& name, bool force = false) const; // public only for validating name field on update op bool incrementBlock(insertUndoType& insertUndo, - claimQueueRowType& expireUndo, - insertUndoType& insertSupportUndo, - supportQueueRowType& expireSupportUndo) override; + claimUndoType& expireUndo, + insertUndoType& insertSupportUndo, + supportUndoType& expireSupportUndo, + takeoverUndoType& takeovers) override; bool decrementBlock(insertUndoType& insertUndo, - claimQueueRowType& expireUndo, - insertUndoType& insertSupportUndo, - supportQueueRowType& expireSupportUndo) override; + claimUndoType& expireUndo, + insertUndoType& insertSupportUndo, + supportUndoType& expireSupportUndo) override; bool getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof) override; - bool getInfoForName(const std::string& name, CClaimValue& claim) const override; + bool getInfoForName(const std::string& name, CClaimValue& claim, int heightOffset = 0) const override; CClaimSupportToName getClaimsForName(const std::string& name) const override; std::string adjustNameForValidHeight(const std::string& name, int validHeight) const override; @@ -501,12 +475,12 @@ public: bool getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof) override; void initializeIncrement() override; - bool finalizeDecrement() override; + bool finalizeDecrement(takeoverUndoType& takeovers) override; bool allowSupportMetadata() const; protected: - uint256 recursiveComputeMerkleHash(const std::string& name, bool checkOnly) override; + uint256 recursiveComputeMerkleHash(const std::string& name, int takeoverHeight, bool checkOnly) override; }; typedef CClaimTrieCacheHashFork CClaimTrieCache; diff --git a/src/claimtrieforks.cpp b/src/claimtrieforks.cpp index 0baccb86a..8df98dd39 100644 --- a/src/claimtrieforks.cpp +++ b/src/claimtrieforks.cpp @@ -25,16 +25,17 @@ int CClaimTrieCacheExpirationFork::expirationTime() const return nExpirationTime; } -bool CClaimTrieCacheExpirationFork::incrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo) +bool CClaimTrieCacheExpirationFork::incrementBlock(insertUndoType& insertUndo, claimUndoType& expireUndo, + insertUndoType& insertSupportUndo, supportUndoType& expireSupportUndo, takeoverUndoType& takeoverUndo) { - if (CClaimTrieCacheBase::incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo)) { + if (CClaimTrieCacheBase::incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverUndo)) { setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight)); return true; } return false; } -bool CClaimTrieCacheExpirationFork::decrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo) +bool CClaimTrieCacheExpirationFork::decrementBlock(insertUndoType& insertUndo, claimUndoType& expireUndo, insertUndoType& insertSupportUndo, supportUndoType& expireSupportUndo) { if (CClaimTrieCacheBase::decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo)) { setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight)); @@ -52,9 +53,9 @@ void CClaimTrieCacheExpirationFork::initializeIncrement() forkForExpirationChange(true); } -bool CClaimTrieCacheExpirationFork::finalizeDecrement() +bool CClaimTrieCacheExpirationFork::finalizeDecrement(takeoverUndoType& takeoverUndo) { - auto ret = CClaimTrieCacheBase::finalizeDecrement(); + auto ret = CClaimTrieCacheBase::finalizeDecrement(takeoverUndo); if (ret && nNextHeight == Params().GetConsensus().nExtendedClaimExpirationForkHeight) forkForExpirationChange(false); return ret; @@ -152,13 +153,14 @@ bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary(bool f return true; } -bool CClaimTrieCacheNormalizationFork::incrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo) +bool CClaimTrieCacheNormalizationFork::incrementBlock(insertUndoType& insertUndo, claimUndoType& expireUndo, + insertUndoType& insertSupportUndo, supportUndoType& expireSupportUndo, takeoverUndoType& takeoverUndo) { normalizeAllNamesInTrieIfNecessary(true); - return CClaimTrieCacheExpirationFork::incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo); + return CClaimTrieCacheExpirationFork::incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverUndo); } -bool CClaimTrieCacheNormalizationFork::decrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo) +bool CClaimTrieCacheNormalizationFork::decrementBlock(insertUndoType& insertUndo, claimUndoType& expireUndo, insertUndoType& insertSupportUndo, supportUndoType& expireSupportUndo) { auto ret = CClaimTrieCacheExpirationFork::decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo); if (ret) @@ -171,9 +173,9 @@ bool CClaimTrieCacheNormalizationFork::getProofForName(const std::string& name, return CClaimTrieCacheExpirationFork::getProofForName(normalizeClaimName(name), finalClaim, proof); } -bool CClaimTrieCacheNormalizationFork::getInfoForName(const std::string& name, CClaimValue& claim) const +bool CClaimTrieCacheNormalizationFork::getInfoForName(const std::string& name, CClaimValue& claim, int offsetHeight) const { - return CClaimTrieCacheExpirationFork::getInfoForName(normalizeClaimName(name), claim); + return CClaimTrieCacheExpirationFork::getInfoForName(normalizeClaimName(name), claim, offsetHeight); } CClaimSupportToName CClaimTrieCacheNormalizationFork::getClaimsForName(const std::string& name) const @@ -198,26 +200,27 @@ CClaimTrieCacheHashFork::CClaimTrieCacheHashFork(CClaimTrie* base) : CClaimTrieC static const uint256 leafHash = uint256S("0000000000000000000000000000000000000000000000000000000000000002"); static const uint256 emptyHash = uint256S("0000000000000000000000000000000000000000000000000000000000000003"); -uint256 CClaimTrieCacheHashFork::recursiveComputeMerkleHash(const std::string& name, bool checkOnly) +uint256 CClaimTrieCacheHashFork::recursiveComputeMerkleHash(const std::string& name, int takeoverHeight, bool checkOnly) { if (nNextHeight < Params().GetConsensus().nAllClaimsInMerkleForkHeight) - return CClaimTrieCacheNormalizationFork::recursiveComputeMerkleHash(name, checkOnly); + return CClaimTrieCacheNormalizationFork::recursiveComputeMerkleHash(name, takeoverHeight, checkOnly); - auto childQuery = db << "SELECT name, hash FROM nodes WHERE parent = ? ORDER BY name" << name; + auto childQuery = db << "SELECT name, hash, IFNULL(takeoverHeight, 0) FROM nodes WHERE parent = ? ORDER BY name" << name; std::vector childHashes; for (auto&& row: childQuery) { std::string key; std::unique_ptr hash; - row >> key >> hash; + int childTakeoverHeight; + row >> key >> hash >> childTakeoverHeight; if (hash == nullptr) hash = std::make_unique(); if (hash->IsNull()) { - *hash = recursiveComputeMerkleHash(key, checkOnly); + *hash = recursiveComputeMerkleHash(key, childTakeoverHeight, checkOnly); } childHashes.push_back(*hash); } - auto claimQuery = db << "SELECT c.txID, c.txN, c.validHeight, " + auto claimQuery = db << "SELECT c.txID, c.txN, " "(SELECT TOTAL(s.amount)+c.amount FROM supports s WHERE s.supportedClaimID = c.claimID " "AND s.validHeight < ? AND s.expirationHeight >= ?) as effectiveAmount" "FROM claims c WHERE c.nodeName = ? AND c.validHeight < ? AND c.expirationHeight >= ? " @@ -226,9 +229,8 @@ uint256 CClaimTrieCacheHashFork::recursiveComputeMerkleHash(const std::string& n std::vector claimHashes; for (auto&& row: claimQuery) { COutPoint p; - int validHeight; - row >> p.hash >> p.n >> validHeight; - auto claimHash = getValueHash(p, validHeight); + row >> p.hash >> p.n; + auto claimHash = getValueHash(p, takeoverHeight); claimHashes.push_back(claimHash); } @@ -310,13 +312,14 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const uin // cache the parent nodes getMerkleHash(); proof = CClaimTrieProof(); - auto nodeQuery = db << "SELECT name FROM nodes WHERE " + auto nodeQuery = db << "SELECT name, IFNULL(takeoverHeight, 0) FROM nodes WHERE " "name IN (WITH RECURSIVE prefix(p) AS (VALUES(?) UNION ALL " "SELECT SUBSTR(p, 1, LENGTH(p)-1) FROM prefix WHERE p != '') SELECT p FROM prefix) " "ORDER BY LENGTH(name)" << name; for (auto&& row: nodeQuery) { std::string key;; - row >> key; + int takeoverHeight; + row >> key >> takeoverHeight; std::vector childHashes; uint32_t nextCurrentIdx = 0; auto childQuery = db << "SELECT name, hash FROM nodes WHERE parent = ?" << key; @@ -335,7 +338,7 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const uin COutPoint finalOutPoint; for (uint32_t i = 0; i < cns.claimsNsupports.size(); ++i) { auto& child = cns.claimsNsupports[i].claim; - claimHashes.push_back(getValueHash(child.outPoint, child.nValidAtHeight)); + claimHashes.push_back(getValueHash(child.outPoint, takeoverHeight)); if (child.claimId == finalClaim) { finalClaimIdx = i; finalOutPoint = child.outPoint; @@ -372,9 +375,9 @@ void CClaimTrieCacheHashFork::initializeIncrement() db << "UPDATE nodes SET hash = NULL"; } -bool CClaimTrieCacheHashFork::finalizeDecrement() +bool CClaimTrieCacheHashFork::finalizeDecrement(takeoverUndoType& takeoverUndo) { - auto ret = CClaimTrieCacheNormalizationFork::finalizeDecrement(); + auto ret = CClaimTrieCacheNormalizationFork::finalizeDecrement(takeoverUndo); if (ret && nNextHeight == Params().GetConsensus().nAllClaimsInMerkleForkHeight - 1) db << "UPDATE nodes SET hash = NULL"; return ret; diff --git a/src/miner.cpp b/src/miner.cpp index de4011ba9..8c04e5b77 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -46,9 +46,10 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam void blockToCache(const CBlock* pblock, CClaimTrieCache& trieCache, int nHeight) { insertUndoType dummyInsertUndo; - claimQueueRowType dummyExpireUndo; + claimUndoType dummyExpireUndo; insertUndoType dummyInsertSupportUndo; - supportQueueRowType dummyExpireSupportUndo; + supportUndoType dummyExpireSupportUndo; + takeoverUndoType dummyTakeoverUndo; CUpdateCacheCallbacks callbacks = { .findScriptKey = [&pblock](const COutPoint& point) { @@ -68,7 +69,7 @@ void blockToCache(const CBlock* pblock, CClaimTrieCache& trieCache, int nHeight) if (!tx->IsCoinBase()) UpdateCache(*tx, trieCache, view, nHeight, callbacks); - trieCache.incrementBlock(dummyInsertUndo, dummyExpireUndo, dummyInsertSupportUndo, dummyExpireSupportUndo); + trieCache.incrementBlock(dummyInsertUndo, dummyExpireUndo, dummyInsertSupportUndo, dummyExpireSupportUndo, dummyTakeoverUndo); } BlockAssembler::Options::Options() { diff --git a/src/test/claimtriebranching_tests.cpp b/src/test/claimtriebranching_tests.cpp index 7bef002e4..b129fb3c6 100644 --- a/src/test/claimtriebranching_tests.cpp +++ b/src/test/claimtriebranching_tests.cpp @@ -384,6 +384,38 @@ BOOST_AUTO_TEST_CASE(support_spend_test) fixture.DecrementBlocks(1); BOOST_CHECK(fixture.is_best_claim("test",tx5)); } + +BOOST_AUTO_TEST_CASE(claimtrie_update_takeover_test) +{ + ClaimTrieChainFixture fixture; + CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 5); + auto cid = ClaimIdHash(tx1.GetHash(), 0); + fixture.IncrementBlocks(1); + uint160 cid2; + int takeover; + fixture.getLastTakeoverForName("test", cid2, takeover); + BOOST_CHECK_EQUAL(chainActive.Tip()->nHeight, takeover); + CMutableTransaction u1 = fixture.MakeUpdate(tx1, "test", "a", cid, 4); + fixture.IncrementBlocks(1); + fixture.getLastTakeoverForName("test", cid2, takeover); + BOOST_CHECK_EQUAL(chainActive.Tip()->nHeight, takeover); + CMutableTransaction u2 = fixture.MakeUpdate(u1, "test", "b", cid, 3); + fixture.IncrementBlocks(1); + fixture.getLastTakeoverForName("test", cid2, takeover); + CClaimValue value; + BOOST_REQUIRE(fixture.getInfoForName("test", value) && value.nAmount == 3); + BOOST_CHECK_EQUAL(cid, cid2); + BOOST_CHECK_EQUAL(chainActive.Tip()->nHeight, takeover); + fixture.DecrementBlocks(1); + fixture.getLastTakeoverForName("test", cid2, takeover); + BOOST_CHECK_EQUAL(cid, cid2); + BOOST_CHECK_EQUAL(chainActive.Tip()->nHeight, takeover); + fixture.DecrementBlocks(1); + fixture.getLastTakeoverForName("test", cid2, takeover); + BOOST_CHECK_EQUAL(cid, cid2); + BOOST_CHECK_EQUAL(chainActive.Tip()->nHeight, takeover); +} + /* update update preserves claim id @@ -447,7 +479,7 @@ BOOST_AUTO_TEST_CASE(claimtrie_update_test) CMutableTransaction tx; tx.nVersion = CTransaction::CURRENT_VERSION; - tx.nLockTime = 1U << 31; // Disable BIP68 + tx.nLockTime = 1U << 31U; // Disable BIP68 tx.vin.resize(2); tx.vout.resize(1); tx.vin[0].prevout.hash = tx8.GetHash(); diff --git a/src/test/claimtriecache_tests.cpp b/src/test/claimtriecache_tests.cpp index 57cb4d6ec..220e4cc0e 100644 --- a/src/test/claimtriecache_tests.cpp +++ b/src/test/claimtriecache_tests.cpp @@ -26,7 +26,7 @@ public: if (c.IsNull()) c = ClaimIdHash(p.hash, p.n); - return addClaim(key, p, c, value.nAmount, value.nHeight, -1, {}); + return addClaim(key, p, c, value.nAmount, value.nHeight); } bool removeClaimFromTrie(const std::string& key, const COutPoint& outPoint) { @@ -47,7 +47,7 @@ public: if (p.hash.IsNull()) p.hash = Hash(key.begin(), key.end()); - return addSupport(key, p, value.nAmount, value.supportedClaimId, value.nHeight, -1, {}); + return addSupport(key, p, value.nAmount, value.supportedClaimId, value.nHeight); } bool removeSupportFromMap(const std::string& key, const COutPoint& outPoint) { @@ -337,8 +337,8 @@ BOOST_AUTO_TEST_CASE(takeover_workaround_triggers) CClaimTrie trie(false, 0, 1); CClaimTrieCacheTest cache(&trie); - insertUndoType icu, isu; claimQueueRowType ecu; supportQueueRowType esu; - BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu)); + insertUndoType icu, isu; claimUndoType ecu; supportUndoType esu; takeoverUndoType tut; + BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu, tut)); CClaimValue value; value.nHeight = 1; @@ -351,9 +351,9 @@ BOOST_AUTO_TEST_CASE(takeover_workaround_triggers) BOOST_CHECK(cache.insertClaimIntoTrie("cc", value)); BOOST_CHECK(cache.insertSupportIntoMap("aa", CSupportValue())); - BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu)); + BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu, tut)); BOOST_CHECK(cache.flush()); - BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu)); + BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu, tut)); CSupportValue temp; CClaimValue cv; @@ -369,7 +369,7 @@ BOOST_AUTO_TEST_CASE(takeover_workaround_triggers) BOOST_CHECK(cache.insertClaimIntoTrie("bb", value)); BOOST_CHECK(cache.insertClaimIntoTrie("cc", value)); - BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu)); + BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu, tut)); BOOST_CHECK(cache.getInfoForName("aa", cv)); BOOST_CHECK_EQUAL(3, cv.nValidAtHeight); diff --git a/src/test/claimtriefixture.cpp b/src/test/claimtriefixture.cpp index a6d3b85fe..3c35b5152 100644 --- a/src/test/claimtriefixture.cpp +++ b/src/test/claimtriefixture.cpp @@ -189,7 +189,7 @@ void ClaimTrieChainFixture::CommitTx(const CMutableTransaction &tx, bool has_loc CValidationState state; CAmount txFeeRate = CAmount(0); LOCK(cs_main); - BOOST_CHECK_EQUAL(AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), nullptr, nullptr, false, txFeeRate, false), true); + BOOST_REQUIRE(AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), nullptr, nullptr, false, txFeeRate, false)); } } @@ -272,10 +272,10 @@ void ClaimTrieChainFixture::IncrementBlocks(int num_blocks, bool mark) CScript coinbase_scriptpubkey; coinbase_scriptpubkey << CScriptNum(chainActive.Height()); std::unique_ptr pblocktemplate = AssemblerForTest().CreateNewBlock(coinbase_scriptpubkey); - BOOST_CHECK(pblocktemplate != nullptr); + BOOST_REQUIRE(pblocktemplate != nullptr); if (!added_unchecked) BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), num_txs_for_next_block + 1); - BOOST_CHECK_EQUAL(CreateBlock(pblocktemplate), true); + BOOST_REQUIRE(CreateBlock(pblocktemplate)); num_txs_for_next_block = 0; nNextHeight = chainActive.Height() + 1; } diff --git a/src/test/claimtrienormalization_tests.cpp b/src/test/claimtrienormalization_tests.cpp index 533b56429..00828ab6c 100644 --- a/src/test/claimtrienormalization_tests.cpp +++ b/src/test/claimtrienormalization_tests.cpp @@ -221,13 +221,14 @@ BOOST_AUTO_TEST_CASE(claimtriecache_normalization) BOOST_CHECK(trieCache.removeClaim(ClaimIdHash(tx2.GetHash(), 0), COutPoint(tx2.GetHash(), 0), name_upper, amelieValidHeight)); BOOST_CHECK(trieCache.getInfoForName(name, nval1)); - BOOST_CHECK(trieCache.addClaim(name, COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), CAmount(2), currentHeight + 1, -1, {})); + 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; + claimUndoType expireUndo; insertUndoType insertSupportUndo; - supportQueueRowType expireSupportUndo; - BOOST_CHECK(trieCache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo)); + supportUndoType expireSupportUndo; + takeoverUndoType takeoverUndo; + BOOST_CHECK(trieCache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverUndo)); BOOST_CHECK(trieCache.shouldNormalize()); } @@ -304,22 +305,23 @@ BOOST_AUTO_TEST_CASE(normalization_removal_test) CClaimTrieCache cache(pclaimTrie); int height = chainActive.Height() + 1; - cache.addClaim("AB", COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), 1, height, -1, {}); - cache.addClaim("Ab", COutPoint(tx2.GetHash(), 0), ClaimIdHash(tx2.GetHash(), 0), 2, height, -1, {}); - cache.addClaim("aB", COutPoint(tx3.GetHash(), 0), ClaimIdHash(tx3.GetHash(), 0), 3, height, -1, {}); - cache.addSupport("AB", COutPoint(sx1.GetHash(), 0), 1, ClaimIdHash(tx1.GetHash(), 0), height, -1, {}); - cache.addSupport("Ab", COutPoint(sx2.GetHash(), 0), 1, ClaimIdHash(tx2.GetHash(), 0), 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; + claimUndoType expireUndo; insertUndoType insertSupportUndo; - supportQueueRowType expireSupportUndo; - BOOST_CHECK(cache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo)); + supportUndoType expireSupportUndo; + takeoverUndoType takeoverUndo; + BOOST_CHECK(cache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverUndo)); 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()); + BOOST_CHECK(cache.finalizeDecrement(takeoverUndo)); std::string unused; BOOST_CHECK(cache.removeSupport(COutPoint(sx1.GetHash(), 0), unused, height)); BOOST_CHECK(cache.removeSupport(COutPoint(sx2.GetHash(), 0), unused, height)); diff --git a/src/undo.h b/src/undo.h index 69a8bdb18..c3897585a 100644 --- a/src/undo.h +++ b/src/undo.h @@ -77,9 +77,10 @@ class CBlockUndo public: std::vector vtxundo; // for all but the coinbase insertUndoType insertUndo; // any claims that went from the queue to the trie - claimQueueRowType expireUndo; // any claims that expired + claimUndoType expireUndo; // any claims that expired insertUndoType insertSupportUndo; // any supports that went from the support queue to the support map - supportQueueRowType expireSupportUndo; // any supports that expired + supportUndoType expireSupportUndo; // any supports that expired + takeoverUndoType takeoverUndo; ADD_SERIALIZE_METHODS; @@ -90,6 +91,7 @@ public: READWRITE(expireUndo); READWRITE(insertSupportUndo); READWRITE(expireSupportUndo); + READWRITE(takeoverUndo); } }; diff --git a/src/validation.cpp b/src/validation.cpp index d686713fd..3f7514648 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1819,7 +1819,7 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI // move best block pointer to prevout block view.SetBestBlock(pindex->pprev->GetBlockHash()); - assert(trieCache.finalizeDecrement()); + assert(trieCache.finalizeDecrement(blockUndo.takeoverUndo)); auto merkleHash = trieCache.getMerkleHash(); if (merkleHash != pindex->pprev->hashClaimTrie) { LogPrintf("Hash comparison failure at block %d\n", pindex->nHeight); @@ -2304,7 +2304,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl } // TODO: if the "just check" flag is set, we should reduce the work done here. Incrementing blocks twice per mine is not efficient. - const auto incremented = trieCache.incrementBlock(blockundo.insertUndo, blockundo.expireUndo, blockundo.insertSupportUndo, blockundo.expireSupportUndo); + const auto incremented = trieCache.incrementBlock(blockundo.insertUndo, blockundo.expireUndo, + blockundo.insertSupportUndo, blockundo.expireSupportUndo, blockundo.takeoverUndo); assert(incremented); if (trieCache.getMerkleHash() != block.hashClaimTrie)