diff --git a/src/claimscriptop.cpp b/src/claimscriptop.cpp index 62d8db381..e5e1e0cdd 100644 --- a/src/claimscriptop.cpp +++ b/src/claimscriptop.cpp @@ -16,20 +16,20 @@ bool CClaimScriptAddOp::claimName(CClaimTrieCache& trieCache, const std::string& auto claimId = ClaimIdHash(point.hash, point.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); + return addClaim(trieCache, name, claimId, -1, -1); } bool CClaimScriptAddOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) { 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); + return addClaim(trieCache, name, claimId, -1, -1); } bool CClaimScriptAddOp::addClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId, - int takeoverHeight) + int takeoverHeight, int originalHeight) { - return trieCache.addClaim(name, point, claimId, nValue, nHeight, takeoverHeight); + return trieCache.addClaim(name, point, claimId, nValue, nHeight, takeoverHeight, originalHeight); } bool CClaimScriptAddOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) @@ -61,8 +61,8 @@ bool CClaimScriptUndoAddOp::updateClaim(CClaimTrieCache& trieCache, const std::s bool CClaimScriptUndoAddOp::undoAddClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) { std::string nodeName; - int validHeight; - bool res = trieCache.removeClaim(claimId, point, nodeName, validHeight); + int validHeight, originalHeight; + bool res = trieCache.removeClaim(claimId, point, nodeName, validHeight, originalHeight); if (!res) LogPrint(BCLog::CLAIMS, "Remove claim failed for %s with claimid %s\n", name, claimId.GetHex().substr(0, 6)); return res; @@ -105,7 +105,7 @@ bool CClaimScriptSpendOp::updateClaim(CClaimTrieCache& trieCache, const std::str bool CClaimScriptSpendOp::spendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) { std::string nodeName; - bool res = trieCache.removeClaim(claimId, point, nodeName, nValidHeight); + bool res = trieCache.removeClaim(claimId, point, nodeName, nValidHeight, nOriginalHeight); if (!res) LogPrint(BCLog::CLAIMS, "Remove claim failed for %s with claimid %s\n", name, claimId.GetHex().substr(0, 6)); return res; @@ -122,8 +122,8 @@ bool CClaimScriptSpendOp::supportClaim(CClaimTrieCache& trieCache, const std::st return res; } -CClaimScriptUndoSpendOp::CClaimScriptUndoSpendOp(const COutPoint& point, CAmount nValue, int nHeight, int nValidHeight) - : point(point), nValue(nValue), nHeight(nHeight), nValidHeight(nValidHeight) +CClaimScriptUndoSpendOp::CClaimScriptUndoSpendOp(const COutPoint& point, CAmount nValue, int nHeight, int nValidHeight, int nOriginalHeight) + : point(point), nValue(nValue), nHeight(nHeight), nValidHeight(nValidHeight), nOriginalHeight(nOriginalHeight) { } @@ -144,7 +144,8 @@ bool CClaimScriptUndoSpendOp::updateClaim(CClaimTrieCache& trieCache, const std: bool CClaimScriptUndoSpendOp::undoSpendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) { - return trieCache.addClaim(name, point, claimId, nValue, nHeight, nValidHeight); + return trieCache.addClaim(name, point, claimId, nValue, nHeight, + nValidHeight, nOriginalHeight); } bool CClaimScriptUndoSpendOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) @@ -188,17 +189,17 @@ 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); + callback(name, claimId, nOriginalHeight); return true; } return false; } - std::function callback; + std::function callback; }; spentClaimsType spentClaims; - for (std::size_t j = 0; j < tx.vin.size(); j++) { + for (uint32_t j = 0; j < tx.vin.size(); j++) { const CTxIn& txin = tx.vin[j]; const Coin& coin = view.AccessCoin(txin.prevout); @@ -214,13 +215,16 @@ void UpdateCache(const CTransaction& tx, CClaimTrieCache& trieCache, const CCoin if (scriptPubKey.empty()) continue; - int nValidAtHeight; + int nValidAtHeight, nOriginalHeight = 0; CSpendClaimHistory spendClaim(COutPoint(txin.prevout.hash, txin.prevout.n), scriptHeight, nValidAtHeight); - spendClaim.callback = [&spentClaims](const std::string& name, const uint160& claimId) { - spentClaims.emplace_back(name, claimId); + spendClaim.callback = [&spentClaims, &nOriginalHeight](const std::string& name, const uint160& claimId, int originalHeight) { + spentClaims.push_back({name, claimId, originalHeight}); + nOriginalHeight = originalHeight; }; - if (ProcessClaim(spendClaim, trieCache, scriptPubKey) && callbacks.claimUndoHeights) - callbacks.claimUndoHeights(j, nValidAtHeight); + if (ProcessClaim(spendClaim, trieCache, scriptPubKey) && callbacks.claimUndoHeights) { + // assert(nValidAtHeight > 0 && nOriginalHeight > 0); // fails on tests + callbacks.claimUndoHeights(j, uint32_t(nValidAtHeight), uint32_t(nOriginalHeight)); + } } class CAddSpendClaim : public CClaimScriptAddOp @@ -230,11 +234,15 @@ void UpdateCache(const CTransaction& tx, CClaimTrieCache& trieCache, const CCoin bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override { - if (callback(name, claimId)) - return CClaimScriptAddOp::updateClaim(trieCache, name, claimId); + auto originalHeight = callback(name, claimId); + if (originalHeight >= 0) { + 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 CClaimScriptAddOp::addClaim(trieCache, name, claimId, -1, originalHeight); + } return false; } - std::function callback; + std::function callback; }; for (std::size_t j = 0; j < tx.vout.size(); j++) { @@ -244,14 +252,14 @@ 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) -> bool { + addClaim.callback = [&trieCache, &spentClaims](const std::string& name, const uint160& claimId) -> int { for (auto itSpent = spentClaims.begin(); itSpent != spentClaims.end(); ++itSpent) { - if (itSpent->second == claimId && trieCache.normalizeClaimName(name) == trieCache.normalizeClaimName(itSpent->first)) { + if (itSpent->id == claimId && trieCache.normalizeClaimName(name) == trieCache.normalizeClaimName(itSpent->name)) { spentClaims.erase(itSpent); - return true; + return itSpent->originalHeight; } } - return false; + return -1; }; ProcessClaim(addClaim, trieCache, txout.scriptPubKey); } diff --git a/src/claimscriptop.h b/src/claimscriptop.h index 915ff1dc0..3bbff29e9 100644 --- a/src/claimscriptop.h +++ b/src/claimscriptop.h @@ -81,7 +81,8 @@ protected: * @param[in] name name of the claim * @param[in] claimId id of the claim */ - virtual bool addClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId, int takeoverHeight); + virtual bool addClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId, + int takeoverHeight, int originalHeight); const COutPoint point; const CAmount nValue; const int nHeight; @@ -167,6 +168,7 @@ protected: const COutPoint point; const int nHeight; int& nValidHeight; + int nOriginalHeight; }; /** @@ -182,7 +184,7 @@ public: * @param[in] nHeight entry height of the claim * @param[in] nValidHeight valid height of the claim */ - CClaimScriptUndoSpendOp(const COutPoint& point, CAmount nValue, int nHeight, int nValidHeight); + CClaimScriptUndoSpendOp(const COutPoint& point, CAmount nValue, int nHeight, int nValidHeight, int nOriginalHeight); /** * Implementation of OP_CLAIM_NAME handler * @see CClaimScriptOp::claimName @@ -211,6 +213,7 @@ protected: const CAmount nValue; const int nHeight; const int nValidHeight; + const int nOriginalHeight; }; /** @@ -221,13 +224,13 @@ protected: */ bool ProcessClaim(CClaimScriptOp& claimOp, CClaimTrieCache& trieCache, const CScript& scriptPubKey); -typedef std::pair spentClaimType; +struct spentClaimType { std::string name; uint160 id; int originalHeight; }; typedef std::vector spentClaimsType; struct CUpdateCacheCallbacks { std::function findScriptKey; - std::function claimUndoHeights; + std::function claimUndoHeights; }; /** diff --git a/src/claimtrie/data.cpp b/src/claimtrie/data.cpp index 85cc1eac5..0c4df5bda 100644 --- a/src/claimtrie/data.cpp +++ b/src/claimtrie/data.cpp @@ -75,8 +75,8 @@ CNameOutPointHeightType::CNameOutPointHeightType(std::string name, COutPoint out { } -CClaimNsupports::CClaimNsupports(CClaimValue claim, int64_t effectiveAmount, std::vector supports) - : claim(std::move(claim)), effectiveAmount(effectiveAmount), supports(std::move(supports)) +CClaimNsupports::CClaimNsupports(CClaimValue claim, int64_t effectiveAmount, int originalHeight, std::vector supports) + : claim(std::move(claim)), effectiveAmount(effectiveAmount), originalHeight(originalHeight), supports(std::move(supports)) { } diff --git a/src/claimtrie/data.h b/src/claimtrie/data.h index 4b1138980..82acdee26 100644 --- a/src/claimtrie/data.h +++ b/src/claimtrie/data.h @@ -78,12 +78,14 @@ struct CClaimNsupports CClaimNsupports& operator=(CClaimNsupports&&) = default; CClaimNsupports& operator=(const CClaimNsupports&) = default; - CClaimNsupports(CClaimValue claim, int64_t effectiveAmount, std::vector supports = {}); + CClaimNsupports(CClaimValue claim, int64_t effectiveAmount, int originalHeight, + std::vector supports = {}); bool IsNull() const; CClaimValue claim; int64_t effectiveAmount = 0; + int originalHeight = -1; std::vector supports; }; diff --git a/src/claimtrie/forks.cpp b/src/claimtrie/forks.cpp index dea3e7909..24d231034 100644 --- a/src/claimtrie/forks.cpp +++ b/src/claimtrie/forks.cpp @@ -157,7 +157,7 @@ bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary() // work around a bug in the old implementation: db << "UPDATE claim SET activationHeight = ?1 " // force a takeover on these - "WHERE blockHeight < ?1 AND activationHeight > ?1 AND nodeName != name" << nNextHeight; + "WHERE updateHeight < ?1 AND activationHeight > ?1 AND nodeName != name" << nNextHeight; return true; } diff --git a/src/claimtrie/sqlite.h b/src/claimtrie/sqlite.h index 3a5014a2f..83c1ee5f3 100644 --- a/src/claimtrie/sqlite.h +++ b/src/claimtrie/sqlite.h @@ -57,7 +57,7 @@ namespace sqlite return ret; } - inline int commit(database& db, std::size_t attempts = 60) + inline int commit(database& db, std::size_t attempts = 200) { int code = SQLITE_OK; for (auto i = 0u; i < attempts; ++i) { @@ -67,7 +67,7 @@ namespace sqlite code = e.get_code(); if (code == SQLITE_LOCKED || code == SQLITE_BUSY) { using namespace std::chrono_literals; - std::this_thread::sleep_for(1s); + std::this_thread::sleep_for(100ms); continue; } return code; diff --git a/src/claimtrie/trie.cpp b/src/claimtrie/trie.cpp index 23b0e43a0..dc8ffe8ae 100644 --- a/src/claimtrie/trie.cpp +++ b/src/claimtrie/trie.cpp @@ -88,7 +88,7 @@ CClaimTrie::CClaimTrie(std::size_t cacheBytes, bool fWipe, int height, db << "CREATE TABLE IF NOT EXISTS claim (claimID BLOB NOT NULL PRIMARY KEY, name BLOB NOT NULL, " "nodeName BLOB NOT NULL REFERENCES node(name) DEFERRABLE INITIALLY DEFERRED, " - "txID BLOB NOT NULL, txN INTEGER NOT NULL, blockHeight INTEGER NOT NULL, " + "txID BLOB NOT NULL, txN INTEGER NOT NULL, originalHeight INTEGER NOT NULL, updateHeight INTEGER NOT NULL, " "validHeight INTEGER NOT NULL, activationHeight INTEGER NOT NULL, " "expirationHeight INTEGER NOT NULL, amount INTEGER NOT NULL);"; @@ -383,7 +383,7 @@ CClaimSupportToName CClaimTrieCacheBase::getClaimsForName(const std::string& nam return it != supports.end(); }; - auto query = db << "SELECT claimID, txID, txN, blockHeight, activationHeight, amount " + auto query = db << "SELECT claimID, txID, txN, originalHeight, updateHeight, activationHeight, amount " "FROM claim WHERE nodeName = ? AND expirationHeight >= ?" << name << nNextHeight; @@ -391,10 +391,11 @@ CClaimSupportToName CClaimTrieCacheBase::getClaimsForName(const std::string& nam std::vector claimsNsupports; for (auto &&row: query) { CClaimValue claim; + int originalHeight; row >> claim.claimId >> claim.outPoint.hash >> claim.outPoint.n - >> claim.nHeight >> claim.nValidAtHeight >> claim.nAmount; + >> originalHeight >> claim.nHeight >> claim.nValidAtHeight >> claim.nAmount; int64_t nAmount = claim.nValidAtHeight < nNextHeight ? claim.nAmount : 0; - auto ic = claimsNsupports.emplace(claimsNsupports.end(), claim, nAmount); + auto ic = claimsNsupports.emplace(claimsNsupports.end(), claim, nAmount, originalHeight); for (auto it = supports.begin(); find(it, claim); it = supports.erase(it)) { if (it->nValidAtHeight < nNextHeight) ic->effectiveAmount += it->nAmount; @@ -492,12 +493,12 @@ bool CClaimTrieCacheBase::flush() const std::string childHashQuery_s = "SELECT name, hash FROM node WHERE parent = ? ORDER BY name"; const std::string claimHashQuery_s = - "SELECT c.txID, c.txN, c.claimID, c.blockHeight, c.activationHeight, c.amount, " + "SELECT c.txID, c.txN, c.claimID, c.updateHeight, c.activationHeight, c.amount, " "(SELECT IFNULL(SUM(s.amount),0)+c.amount FROM support s " "WHERE s.supportedClaimID = c.claimID AND s.nodeName = c.nodeName " "AND s.activationHeight < ?1 AND s.expirationHeight >= ?1) as effectiveAmount " "FROM claim c WHERE c.nodeName = ?2 AND c.activationHeight < ?1 AND c.expirationHeight >= ?1 " - "ORDER BY effectiveAmount DESC, c.blockHeight, c.txID, c.txN"; + "ORDER BY effectiveAmount DESC, c.updateHeight, c.txID, c.txN"; const std::string claimHashQueryLimit_s = claimHashQuery_s + " LIMIT 1"; @@ -574,7 +575,7 @@ bool CClaimTrieCacheBase::getLastTakeoverForName(const std::string& name, uint16 } bool CClaimTrieCacheBase::addClaim(const std::string& name, const COutPoint& outPoint, const uint160& claimId, - int64_t nAmount, int nHeight, int nValidHeight) + int64_t nAmount, int nHeight, int nValidHeight, int originalHeight) { ensureTransacting(); @@ -589,15 +590,19 @@ bool CClaimTrieCacheBase::addClaim(const std::string& name, const COutPoint& out // 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) + if (nValidHeight <= 0) nValidHeight = nHeight + getDelayForName(name, claimId); // sets nValidHeight to the old value + if (originalHeight <= 0) + originalHeight = nHeight; + auto nodeName = adjustNameForValidHeight(name, nValidHeight); auto expires = expirationTime() + nHeight; - db << "INSERT INTO claim(claimID, name, nodeName, txID, txN, amount, blockHeight, validHeight, activationHeight, expirationHeight) " - "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" - << claimId << name << nodeName << outPoint.hash << outPoint.n << nAmount << nHeight << nValidHeight << nValidHeight << expires; + db << "INSERT INTO claim(claimID, name, nodeName, txID, txN, amount, originalHeight, updateHeight, " + "validHeight, activationHeight, expirationHeight) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + << claimId << name << nodeName << outPoint.hash << outPoint.n << nAmount + << originalHeight << nHeight << nValidHeight << nValidHeight << expires; if (nValidHeight < nNextHeight) db << "INSERT INTO node(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET hash = NULL" << nodeName; @@ -626,7 +631,8 @@ bool CClaimTrieCacheBase::addSupport(const std::string& name, const COutPoint& o return true; } -bool CClaimTrieCacheBase::removeClaim(const uint160& claimId, const COutPoint& outPoint, std::string& nodeName, int& validHeight) +bool CClaimTrieCacheBase::removeClaim(const uint160& claimId, const COutPoint& outPoint, std::string& nodeName, + int& validHeight, int& originalHeight) { ensureTransacting(); @@ -634,16 +640,19 @@ bool CClaimTrieCacheBase::removeClaim(const uint160& claimId, const COutPoint& o // when going forward we spend a claim (aka, call removeClaim) before updating it (aka, call addClaim) // when going backwards we first remove the update by calling removeClaim // we then undo the spend of the previous one by calling addClaim with the original data - // in order to maintain the proper takeover height the udpater will need to use our height returned here + // in order to maintain the proper takeover height the updater will need to use our height returned here - auto query = db << "SELECT nodeName, activationHeight FROM claim WHERE claimID = ? AND txID = ? AND txN = ? AND expirationHeight >= ?" + auto query = db << "SELECT nodeName, activationHeight, originalHeight FROM claim WHERE claimID = ? AND txID = ? AND txN = ? AND expirationHeight >= ?" << claimId << outPoint.hash << outPoint.n << nNextHeight; auto it = query.begin(); - if (it == query.end()) return false; - *it >> nodeName >> validHeight; + if (it == query.end()) + return false; + + *it >> nodeName >> validHeight >> originalHeight; db << "DELETE FROM claim WHERE claimID = ? AND txID = ? and txN = ?" << claimId << outPoint.hash << outPoint.n; if (!db.rows_modified()) return false; + db << "UPDATE node SET hash = NULL WHERE name = ?" << nodeName; // when node should be deleted from cache but instead it's kept @@ -653,10 +662,10 @@ bool CClaimTrieCacheBase::removeClaim(const uint160& claimId, const COutPoint& o && 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 query = db << "SELECT nodeName FROM claim WHERE nodeName BETWEEN ?1 AND ?2 " + 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: query) { + for (auto&& row: innerQuery) { std::string shortestMatch; row >> shortestMatch; if (shortestMatch != nodeName) @@ -878,7 +887,7 @@ bool CClaimTrieCacheBase::findNameForClaim(std::vector claim, CCl return false; auto maximum = claim; maximum.insert(maximum.end(), 20 - claim.size(), std::numeric_limits::max()); - auto query = db << "SELECT nodeName, claimID, txID, txN, amount, activationHeight, blockHeight " + auto query = db << "SELECT nodeName, claimID, txID, txN, amount, activationHeight, updateHeight " "FROM claim WHERE REVERSE(claimID) BETWEEN ?1 AND ?2 " "AND activationHeight < ?3 AND expirationHeight >= ?3 LIMIT 2" << claim << maximum << nNextHeight; @@ -902,7 +911,7 @@ void CClaimTrieCacheBase::getNamesInTrie(std::function std::vector CClaimTrieCacheBase::getActivatedClaims(int height) { std::vector ret; - auto query = db << "SELECT DISTINCT claimID FROM claim WHERE activationHeight = ?1 AND blockHeight < ?1" << height; + auto query = db << "SELECT DISTINCT claimID FROM claim WHERE activationHeight = ?1 AND updateHeight < ?1" << height; for (auto&& row: query) { ret.emplace_back(); row >> ret.back(); @@ -911,7 +920,7 @@ std::vector CClaimTrieCacheBase::getActivatedClaims(int height) { } std::vector CClaimTrieCacheBase::getClaimsWithActivatedSupports(int height) { std::vector ret; - auto query = db << "SELECT DISTINCT supportedClaimID FROM support WHERE activationHeight = ?1 AND blockHeight < ?1" << height; + auto query = db << "SELECT DISTINCT supportedClaimID FROM support WHERE activationHeight = ?1 AND updateHeight < ?1" << height; for (auto&& row: query) { ret.emplace_back(); row >> ret.back(); @@ -920,7 +929,7 @@ std::vector CClaimTrieCacheBase::getClaimsWithActivatedSupports(int hei } std::vector CClaimTrieCacheBase::getExpiredClaims(int height) { std::vector ret; - auto query = db << "SELECT DISTINCT claimID FROM claim WHERE expirationHeight = ?1 AND blockHeight < ?1" << height; + auto query = db << "SELECT DISTINCT claimID FROM claim WHERE expirationHeight = ?1 AND updateHeight < ?1" << height; for (auto&& row: query) { ret.emplace_back(); row >> ret.back(); @@ -929,7 +938,7 @@ std::vector CClaimTrieCacheBase::getExpiredClaims(int height) { } std::vector CClaimTrieCacheBase::getClaimsWithExpiredSupports(int height) { std::vector ret; - auto query = db << "SELECT DISTINCT supportedClaimID FROM support WHERE expirationHeight = ?1 AND blockHeight < ?1" << height; + auto query = db << "SELECT DISTINCT supportedClaimID FROM support WHERE expirationHeight = ?1 AND updateHeight < ?1" << height; for (auto&& row: query) { ret.emplace_back(); row >> ret.back(); diff --git a/src/claimtrie/trie.h b/src/claimtrie/trie.h index 5beea596d..7807eb4b3 100644 --- a/src/claimtrie/trie.h +++ b/src/claimtrie/trie.h @@ -81,12 +81,13 @@ 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, int64_t nAmount, - int nHeight, int nValidHeight = -1); + int nHeight, int nValidHeight = -1, int originalHeight = -1); bool addSupport(const std::string& name, const COutPoint& outPoint, const uint160& supportedClaimId, int64_t nAmount, int nHeight, int nValidHeight = -1); - bool removeClaim(const uint160& claimId, const COutPoint& outPoint, std::string& nodeName, int& validHeight); + bool removeClaim(const uint160& claimId, const COutPoint& outPoint, std::string& nodeName, + int& validHeight, int& originalHeight); bool removeSupport(const COutPoint& outPoint, std::string& nodeName, int& validHeight); virtual bool incrementBlock(); diff --git a/src/rpc/claimrpchelp.h b/src/rpc/claimrpchelp.h index e4e3ff108..109e6f0f1 100644 --- a/src/rpc/claimrpchelp.h +++ b/src/rpc/claimrpchelp.h @@ -17,6 +17,7 @@ #define T_NAMES "names" #define T_EFFECTIVEAMOUNT "effectiveAmount" #define T_LASTTAKEOVERHEIGHT "lastTakeoverHeight" +#define T_ORIGINALHEIGHT "originalHeight" #define T_SUPPORTS "supports" #define T_SUPPORTSWITHOUTCLAIM "supportsWithoutClaim" #define T_TOTALNAMES "totalNames" @@ -83,12 +84,13 @@ S3(" ", T_NAME, " (string) the original name of this claim S3(" ", T_VALUE, " (string) the value of this claim") \ S3(" ", T_ADDRESS, " (string) the destination address of this claim") \ S3(" ", T_CLAIMID, " (string) the claimId of the claim") \ -S3(" ", T_TXID, " (string) the txid of the claim") \ +S3(" ", T_TXID, " (string) the txid of the claim or its most recent update") \ S3(" ", T_N, " (numeric) the index of the claim in the transaction's list of outputs") \ S3(" ", T_HEIGHT, " (numeric) the height of the block in which this transaction is located") \ S3(" ", T_VALIDATHEIGHT, " (numeric) the height at which the support became/becomes valid") \ -S3(" ", T_AMOUNT, " (numeric) the amount of the claim") \ +S3(" ", T_AMOUNT, " (numeric) the amount of the claim or its most recent update") \ S3(" ", T_EFFECTIVEAMOUNT, " (numeric) the amount plus amount from all supports associated with the claim") \ +S3(" ", T_ORIGINALHEIGHT, " (numeric) the block height where the claim was first created") \ S3(" ", T_PENDINGAMOUNT, " (numeric) expected amount when claim and its supports are all valid") \ S3(" ", T_SUPPORTS, ": [ (array of object) supports for this claim") \ S3(" ", T_VALUE, " (string) the metadata of the support if any") \ @@ -159,12 +161,13 @@ S3(" ", T_NAME, " (string) the original name of this claim S3(" ", T_VALUE, " (string) the value of this claim") S3(" ", T_ADDRESS, " (string) the destination address of this claim") S3(" ", T_CLAIMID, " (string) the claimId of the claim") -S3(" ", T_TXID, " (string) the txid of the claim") +S3(" ", T_TXID, " (string) the txid of the claim or its most recent update") S3(" ", T_N, " (numeric) the index of the claim in the transaction's list of outputs") S3(" ", T_HEIGHT, " (numeric) the height of the block in which this transaction is located") S3(" ", T_VALIDATHEIGHT, " (numeric) the height at which the claim became/becomes valid") -S3(" ", T_AMOUNT, " (numeric) the amount of the claim") +S3(" ", T_AMOUNT, " (numeric) the amount of the claim or its most recent update") S3(" ", T_EFFECTIVEAMOUNT, " (numeric) the amount plus amount from all supports associated with the claim") +S3(" ", T_ORIGINALHEIGHT, " (numeric) the block height where the claim was first created") \ S3(" ", T_PENDINGAMOUNT, " (numeric) expected amount when claim and its support got valid") S3(" ", T_SUPPORTS, ": [ (array of object) supports for this claim") S3(" ", T_VALUE, " (string) the metadata of the support if any") diff --git a/src/rpc/claimtrie.cpp b/src/rpc/claimtrie.cpp index d9464e731..835bbc873 100644 --- a/src/rpc/claimtrie.cpp +++ b/src/rpc/claimtrie.cpp @@ -209,6 +209,8 @@ UniValue claimAndSupportsToJSON(const CCoinsViewCache& coinsCache, const CClaimN auto result = claimToJSON(coinsCache, claim); result.pushKV(T_EFFECTIVEAMOUNT, claimNsupports.effectiveAmount); + if (claimNsupports.originalHeight > 0) + result.pushKV(T_ORIGINALHEIGHT, claimNsupports.originalHeight); auto fullAmount = amountToClaim(claimNsupports); if (fullAmount > claimNsupports.effectiveAmount) diff --git a/src/test/claimtriecache_tests.cpp b/src/test/claimtriecache_tests.cpp index 30305e1c2..c9702e8ee 100644 --- a/src/test/claimtriecache_tests.cpp +++ b/src/test/claimtriecache_tests.cpp @@ -31,14 +31,14 @@ public: } bool removeClaimFromTrie(const std::string& key, const COutPoint& outPoint) { - int validHeight; + int validHeight, originalHeight; std::string nodeName; auto p = outPoint; if (p.hash.IsNull()) p.hash = Hash(key.begin(), key.end()); - auto ret = removeClaim(ClaimIdHash(uint256(p.hash), p.n), p, nodeName, validHeight); + auto ret = removeClaim(ClaimIdHash(uint256(p.hash), p.n), p, nodeName, validHeight, originalHeight); assert(!ret || nodeName == key); return ret; } diff --git a/src/test/claimtrienormalization_tests.cpp b/src/test/claimtrienormalization_tests.cpp index 6f127bf16..06f0f1873 100644 --- a/src/test/claimtrienormalization_tests.cpp +++ b/src/test/claimtrienormalization_tests.cpp @@ -215,13 +215,13 @@ BOOST_AUTO_TEST_CASE(claimtriecache_normalization) CClaimTrieCache trieCache(pclaimTrie); CBlockIndex* pindex = chainActive.Tip(); CBlock block; - int amelieValidHeight; + int amelieValidHeight, ameliaOriginalHeight; std::string removed; BOOST_CHECK(trieCache.shouldNormalize()); BOOST_CHECK(ReadBlockFromDisk(block, pindex, Params().GetConsensus())); BOOST_CHECK(g_chainstate.DisconnectBlock(block, pindex, coins, trieCache) == DisconnectResult::DISCONNECT_OK); BOOST_CHECK(!trieCache.shouldNormalize()); - BOOST_CHECK(trieCache.removeClaim(ClaimIdHash(tx2.GetHash(), 0), COutPoint(tx2.GetHash(), 0), removed, amelieValidHeight)); + BOOST_CHECK(trieCache.removeClaim(ClaimIdHash(tx2.GetHash(), 0), COutPoint(tx2.GetHash(), 0), removed, amelieValidHeight, ameliaOriginalHeight)); BOOST_CHECK(trieCache.getInfoForName(name, nval1)); BOOST_CHECK_EQUAL(nval1.claimId, ClaimIdHash(tx1.GetHash(), 0)); @@ -301,7 +301,7 @@ BOOST_AUTO_TEST_CASE(normalization_removal_test) CMutableTransaction sx2 = fixture.MakeSupport(fixture.GetCoinbase(), tx2, "Ab", 1); CClaimTrieCache cache(pclaimTrie); - int height = chainActive.Height() + 1; + int height = chainActive.Height() + 1, originalHeight; 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); @@ -317,9 +317,9 @@ BOOST_AUTO_TEST_CASE(normalization_removal_test) std::string unused; BOOST_CHECK(cache.removeSupport(COutPoint(sx1.GetHash(), 0), unused, height)); BOOST_CHECK(cache.removeSupport(COutPoint(sx2.GetHash(), 0), unused, height)); - BOOST_CHECK(cache.removeClaim(ClaimIdHash(tx1.GetHash(), 0), COutPoint(tx1.GetHash(), 0), unused, height)); - BOOST_CHECK(cache.removeClaim(ClaimIdHash(tx2.GetHash(), 0), COutPoint(tx2.GetHash(), 0), unused, height)); - BOOST_CHECK(cache.removeClaim(ClaimIdHash(tx3.GetHash(), 0), COutPoint(tx3.GetHash(), 0), unused, height)); + BOOST_CHECK(cache.removeClaim(ClaimIdHash(tx1.GetHash(), 0), COutPoint(tx1.GetHash(), 0), unused, height, originalHeight)); + BOOST_CHECK(cache.removeClaim(ClaimIdHash(tx2.GetHash(), 0), COutPoint(tx2.GetHash(), 0), unused, height, originalHeight)); + BOOST_CHECK(cache.removeClaim(ClaimIdHash(tx3.GetHash(), 0), COutPoint(tx3.GetHash(), 0), unused, height, originalHeight)); BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports.size() == 0U); } diff --git a/src/undo.h b/src/undo.h index 38370153e..8a0bbbe04 100644 --- a/src/undo.h +++ b/src/undo.h @@ -26,10 +26,11 @@ public: uint32_t nHeight; // if the outpoint was the last unspent: its height uint32_t nClaimValidHeight; // If the outpoint was a claim or support, the height at which the claim or support should be inserted into the trie bool fIsClaim; // if the outpoint was a claim or support + uint32_t nClaimOriginalHeight; // If we are a claim, we need to track the original insertion height for that claim - CTxInUndo() : txout(), fCoinBase(false), nHeight(0), nClaimValidHeight(0), fIsClaim(false) {} + CTxInUndo() : txout(), fCoinBase(false), nHeight(0), nClaimValidHeight(0), fIsClaim(false), nClaimOriginalHeight(0) {} CTxInUndo(const CTxOut &txoutIn, bool fCoinBaseIn = false, uint32_t nHeightIn = 0) : - txout(txoutIn), fCoinBase(fCoinBaseIn), nHeight(nHeightIn), nClaimValidHeight(0), fIsClaim(false) {} + txout(txoutIn), fCoinBase(fCoinBaseIn), nHeight(nHeightIn), nClaimValidHeight(0), fIsClaim(false), nClaimOriginalHeight(0) {} ADD_SERIALIZE_METHODS; @@ -50,6 +51,7 @@ public: READWRITE(REF(CTxOutCompressor(REF(txout)))); READWRITE(VARINT(nClaimValidHeight)); READWRITE(fIsClaim); + READWRITE(VARINT(nClaimOriginalHeight)); } }; diff --git a/src/validation.cpp b/src/validation.cpp index dd9e1b698..b66565c62 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1489,7 +1489,10 @@ int ApplyTxInUndo(unsigned int index, CTxUndo& txUndo, CCoinsViewCache& view, CC // restore claim if applicable if (undo.fIsClaim && !undo.txout.scriptPubKey.empty()) { auto nValidHeight = undo.nClaimValidHeight; - CClaimScriptUndoSpendOp undoSpend(COutPoint(out.hash, out.n), undo.txout.nValue, undo.nHeight, nValidHeight); + auto nOriginalHeight = undo.nClaimOriginalHeight; + // assert(nValidHeight > 0 && nOriginalHeight > 0); // fails unit tests + CClaimScriptUndoSpendOp undoSpend(COutPoint(out.hash, out.n), undo.txout.nValue, undo.nHeight, + nValidHeight, nOriginalHeight); ProcessClaim(undoSpend, trieCache, undo.txout.scriptPubKey); } @@ -1966,7 +1969,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl for (unsigned int i = 0; i < block.vtx.size(); i++) { const CTransaction &tx = *(block.vtx[i]); - std::map mClaimUndoHeights; + std::map> mClaimUndoHeights; nInputs += tx.vin.size(); @@ -2016,8 +2019,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl control.Add(vChecks); CUpdateCacheCallbacks callbacks = { .findScriptKey = {}, - .claimUndoHeights = [&mClaimUndoHeights](int index, int nValidAtHeight) { - mClaimUndoHeights.emplace(index, nValidAtHeight); + .claimUndoHeights = [&mClaimUndoHeights](uint32_t index, uint32_t nValidAtHeight, uint32_t nOriginalHeight) { + mClaimUndoHeights.emplace(index, std::make_pair(nValidAtHeight, nOriginalHeight)); } }; UpdateCache(tx, trieCache, view, pindex->nHeight, callbacks); @@ -2033,7 +2036,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl auto& txinUndos = blockundo.vtxundo.back().vprevout; for (auto itHeight = mClaimUndoHeights.begin(); itHeight != mClaimUndoHeights.end(); ++itHeight) { - txinUndos[itHeight->first].nClaimValidHeight = itHeight->second; + txinUndos[itHeight->first].nClaimValidHeight = itHeight->second.first; + txinUndos[itHeight->first].nClaimOriginalHeight = itHeight->second.second; txinUndos[itHeight->first].fIsClaim = true; } }