Fix removing expired claim

Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
This commit is contained in:
Anthony Fieroni 2019-11-28 18:29:24 +02:00 committed by Brannon King
parent 02091d564b
commit f47826232f
6 changed files with 139 additions and 154 deletions

View file

@ -63,7 +63,7 @@ bool CClaimTrieCacheExpirationFork::finalizeDecrement(takeoverUndoType& takeover
bool CClaimTrieCacheExpirationFork::forkForExpirationChange(bool increment) bool CClaimTrieCacheExpirationFork::forkForExpirationChange(bool increment)
{ {
if (!transacting) { transacting = true; db << "begin"; } ensureTransacting();
/* /*
If increment is True, we have forked to extend the expiration time, thus items in the expiration queue If increment is True, we have forked to extend the expiration time, thus items in the expiration queue
@ -73,24 +73,22 @@ bool CClaimTrieCacheExpirationFork::forkForExpirationChange(bool increment)
will have their expiration extension removed. will have their expiration extension removed.
*/ */
auto extension = base->nExtendedClaimExpirationTime - base->nOriginalClaimExpirationTime; auto height = nNextHeight;
if (increment) { int extension = base->nExtendedClaimExpirationTime - base->nOriginalClaimExpirationTime;
db << "UPDATE claims SET expirationHeight = expirationHeight + ? WHERE expirationHeight >= ?" if (!increment) {
<< extension << nNextHeight; height += extension;
db << "UPDATE supports SET expirationHeight = expirationHeight + ? WHERE expirationHeight >= ?" extension *= -1;
<< extension << nNextHeight;
}
else {
db << "UPDATE claims SET expirationHeight = expirationHeight - ? WHERE expirationHeight >= ?"
<< extension << nNextHeight + extension;
db << "UPDATE supports SET expirationHeight = expirationHeight - ? WHERE expirationHeight >= ?"
<< extension << nNextHeight + extension;
} }
db << "UPDATE claims SET expirationHeight = expirationHeight + ? WHERE expirationHeight >= ?" << extension << height;
db << "UPDATE supports SET expirationHeight = expirationHeight + ? WHERE expirationHeight >= ?" << extension << height;
return true; return true;
} }
CClaimTrieCacheNormalizationFork::CClaimTrieCacheNormalizationFork(CClaimTrie* base) : CClaimTrieCacheExpirationFork(base) CClaimTrieCacheNormalizationFork::CClaimTrieCacheNormalizationFork(CClaimTrie* base) : CClaimTrieCacheExpirationFork(base)
{ {
db.define("NORMALIZED", [this](const std::string& str) { return normalizeClaimName(str, true); });
} }
bool CClaimTrieCacheNormalizationFork::shouldNormalize() const bool CClaimTrieCacheNormalizationFork::shouldNormalize() const
@ -141,10 +139,7 @@ std::string CClaimTrieCacheNormalizationFork::normalizeClaimName(const std::stri
bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary(takeoverUndoType& takeoverUndo) bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary(takeoverUndoType& takeoverUndo)
{ {
if (!transacting) { transacting = true; db << "begin"; } ensureTransacting();
// run the one-time upgrade of all names that need to change
db.define("NORMALIZED", [this](const std::string& str) { return normalizeClaimName(str, true); });
// make the new nodes // make the new nodes
db << "INSERT INTO nodes(name) SELECT NORMALIZED(name) AS nn FROM claims WHERE nn != nodeName " db << "INSERT INTO nodes(name) SELECT NORMALIZED(name) AS nn FROM claims WHERE nn != nodeName "
@ -182,10 +177,7 @@ bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary(takeov
bool CClaimTrieCacheNormalizationFork::unnormalizeAllNamesInTrieIfNecessary() bool CClaimTrieCacheNormalizationFork::unnormalizeAllNamesInTrieIfNecessary()
{ {
if (!transacting) { transacting = true; db << "begin"; } ensureTransacting();
// run the one-time upgrade of all names that need to change
db.define("NORMALIZED", [this](const std::string& str) { return normalizeClaimName(str, true); });
db << "INSERT INTO nodes(name) SELECT name FROM claims WHERE name != nodeName " db << "INSERT INTO nodes(name) SELECT name FROM claims WHERE name != nodeName "
"AND validHeight < ?1 AND expirationHeight > ?1 ON CONFLICT(name) DO UPDATE SET hash = NULL" << nNextHeight; "AND validHeight < ?1 AND expirationHeight > ?1 ON CONFLICT(name) DO UPDATE SET hash = NULL" << nNextHeight;
@ -376,11 +368,7 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const CUi
// cache the parent nodes // cache the parent nodes
getMerkleHash(); getMerkleHash();
proof = CClaimTrieProof(); proof = CClaimTrieProof();
auto nodeQuery = db << "SELECT name, IFNULL(takeoverHeight, 0) FROM nodes WHERE " for (auto&& row: db << proofClaimQuery << name) {
"name IN (WITH RECURSIVE prefix(p) AS (VALUES(?) UNION ALL "
"SELECT POPS(p) FROM prefix WHERE p != '') SELECT p FROM prefix) "
"ORDER BY name" << name;
for (auto&& row: nodeQuery) {
std::string key; std::string key;
int takeoverHeight; int takeoverHeight;
row >> key >> takeoverHeight; row >> key >> takeoverHeight;
@ -416,12 +404,12 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const CUi
// else it will be hash(x, claims) // else it will be hash(x, claims)
if (key == name) { if (key == name) {
proof.nHeightOfLastTakeover = takeoverHeight; proof.nHeightOfLastTakeover = takeoverHeight;
auto hash = childHashes.empty() ? leafHash : ComputeMerkleRoot(childHashes); auto hash = childHashes.empty() ? leafHash : ComputeMerkleRoot(std::move(childHashes));
proof.pairs.emplace_back(true, hash); proof.pairs.emplace_back(true, hash);
if (!claimHashes.empty()) if (!claimHashes.empty())
fillPairs(claimHashes, claimIdx); fillPairs(claimHashes, claimIdx);
} else { } else {
auto hash = claimHashes.empty() ? emptyHash : ComputeMerkleRoot(claimHashes); auto hash = claimHashes.empty() ? emptyHash : ComputeMerkleRoot(std::move(claimHashes));
proof.pairs.emplace_back(false, hash); proof.pairs.emplace_back(false, hash);
if (!childHashes.empty()) if (!childHashes.empty())
fillPairs(childHashes, nextCurrentIdx); fillPairs(childHashes, nextCurrentIdx);
@ -436,7 +424,7 @@ void CClaimTrieCacheHashFork::initializeIncrement()
CClaimTrieCacheNormalizationFork::initializeIncrement(); CClaimTrieCacheNormalizationFork::initializeIncrement();
// we could do this in the constructor, but that would not allow for multiple increments in a row (as done in unit tests) // we could do this in the constructor, but that would not allow for multiple increments in a row (as done in unit tests)
if (nNextHeight == base->nAllClaimsInMerkleForkHeight - 1) { if (nNextHeight == base->nAllClaimsInMerkleForkHeight - 1) {
if (!transacting) { transacting = true; db << "begin"; } ensureTransacting();
db << "UPDATE nodes SET hash = NULL"; db << "UPDATE nodes SET hash = NULL";
} }
} }
@ -445,7 +433,7 @@ bool CClaimTrieCacheHashFork::finalizeDecrement(takeoverUndoType& takeoverUndo)
{ {
auto ret = CClaimTrieCacheNormalizationFork::finalizeDecrement(takeoverUndo); auto ret = CClaimTrieCacheNormalizationFork::finalizeDecrement(takeoverUndo);
if (ret && nNextHeight == base->nAllClaimsInMerkleForkHeight - 1) { if (ret && nNextHeight == base->nAllClaimsInMerkleForkHeight - 1) {
if (!transacting) { transacting = true; db << "begin"; } ensureTransacting();
db << "UPDATE nodes SET hash = NULL"; db << "UPDATE nodes SET hash = NULL";
} }
return ret; return ret;

View file

@ -117,14 +117,14 @@ bool CClaimTrie::SyncToDisk()
bool CClaimTrie::empty() bool CClaimTrie::empty()
{ {
int64_t count; int64_t count;
db << "SELECT COUNT(*) FROM claims WHERE validHeight < ?1 AND expirationHeight >= ?1" << nNextHeight >> count; db << "SELECT COUNT(*) FROM (SELECT 1 FROM claims WHERE validHeight < ?1 AND expirationHeight >= ?1 LIMIT 1)" << nNextHeight >> count;
return count == 0; return count == 0;
} }
bool CClaimTrieCacheBase::haveClaim(const std::string& name, const CTxOutPoint& outPoint) const bool CClaimTrieCacheBase::haveClaim(const std::string& name, const CTxOutPoint& outPoint) const
{ {
auto query = db << "SELECT 1 FROM claims WHERE nodeName = ?1 AND txID = ?2 AND txN = ?3 " auto query = db << "SELECT 1 FROM claims WHERE nodeName = ?1 AND txID = ?2 AND txN = ?3 "
"AND validHeight < ?4 AND expirationHeight >= ?4 LIMIT 1" "AND validHeight < ?4 AND expirationHeight >= ?4 LIMIT 1"
<< name << outPoint.hash << outPoint.n << nNextHeight; << name << outPoint.hash << outPoint.n << nNextHeight;
return query.begin() != query.end(); return query.begin() != query.end();
} }
@ -132,7 +132,7 @@ bool CClaimTrieCacheBase::haveClaim(const std::string& name, const CTxOutPoint&
bool CClaimTrieCacheBase::haveSupport(const std::string& name, const CTxOutPoint& outPoint) const bool CClaimTrieCacheBase::haveSupport(const std::string& name, const CTxOutPoint& outPoint) const
{ {
auto query = db << "SELECT 1 FROM supports WHERE nodeName = ?1 AND txID = ?2 AND txN = ?3 " auto query = db << "SELECT 1 FROM supports WHERE nodeName = ?1 AND txID = ?2 AND txN = ?3 "
"AND validHeight < ?4 AND expirationHeight >= ?4 LIMIT 1" "AND validHeight < ?4 AND expirationHeight >= ?4 LIMIT 1"
<< name << outPoint.hash << outPoint.n << nNextHeight; << name << outPoint.hash << outPoint.n << nNextHeight;
return query.begin() != query.end(); return query.begin() != query.end();
} }
@ -141,13 +141,13 @@ supportEntryType CClaimTrieCacheBase::getSupportsForName(const std::string& name
{ {
// includes values that are not yet valid // includes values that are not yet valid
auto query = db << "SELECT supportedClaimID, txID, txN, blockHeight, validHeight, amount " auto query = db << "SELECT supportedClaimID, txID, txN, blockHeight, validHeight, amount "
"FROM supports WHERE nodeName = ? AND expirationHeight >= ?" << name << nNextHeight; "FROM supports WHERE nodeName = ? AND expirationHeight >= ?" << name << nNextHeight;
supportEntryType ret; supportEntryType ret;
for (auto&& row: query) { for (auto&& row: query) {
CSupportValue value; CSupportValue value;
row >> value.supportedClaimId >> value.outPoint.hash >> value.outPoint.n row >> value.supportedClaimId >> value.outPoint.hash >> value.outPoint.n
>> value.nHeight >> value.nValidAtHeight >> value.nAmount; >> value.nHeight >> value.nValidAtHeight >> value.nAmount;
ret.push_back(value); ret.push_back(std::move(value));
} }
return ret; return ret;
} }
@ -155,7 +155,7 @@ supportEntryType CClaimTrieCacheBase::getSupportsForName(const std::string& name
bool CClaimTrieCacheBase::haveClaimInQueue(const std::string& name, const CTxOutPoint& outPoint, int& nValidAtHeight) const bool CClaimTrieCacheBase::haveClaimInQueue(const std::string& name, const CTxOutPoint& outPoint, int& nValidAtHeight) const
{ {
auto query = db << "SELECT validHeight FROM claims WHERE nodeName = ? AND txID = ? AND txN = ? " auto query = db << "SELECT validHeight FROM claims WHERE nodeName = ? AND txID = ? AND txN = ? "
"AND validHeight >= ? AND expirationHeight > validHeight LIMIT 1" "AND validHeight >= ? AND expirationHeight >= validHeight LIMIT 1"
<< name << outPoint.hash << outPoint.n << nNextHeight; << name << outPoint.hash << outPoint.n << nNextHeight;
for (auto&& row: query) { for (auto&& row: query) {
row >> nValidAtHeight; row >> nValidAtHeight;
@ -167,7 +167,7 @@ bool CClaimTrieCacheBase::haveClaimInQueue(const std::string& name, const CTxOut
bool CClaimTrieCacheBase::haveSupportInQueue(const std::string& name, const CTxOutPoint& outPoint, int& nValidAtHeight) const bool CClaimTrieCacheBase::haveSupportInQueue(const std::string& name, const CTxOutPoint& outPoint, int& nValidAtHeight) const
{ {
auto query = db << "SELECT validHeight FROM supports WHERE nodeName = ? AND txID = ? AND txN = ? " auto query = db << "SELECT validHeight FROM supports WHERE nodeName = ? AND txID = ? AND txN = ? "
"AND validHeight >= ? AND expirationHeight > validHeight LIMIT 1" "AND validHeight >= ? AND expirationHeight >= validHeight LIMIT 1"
<< name << outPoint.hash << outPoint.n << nNextHeight; << name << outPoint.hash << outPoint.n << nNextHeight;
for (auto&& row: query) { for (auto&& row: query) {
row >> nValidAtHeight; row >> nValidAtHeight;
@ -180,7 +180,7 @@ bool CClaimTrieCacheBase::deleteNodeIfPossible(const std::string& name, std::str
{ {
if (name.empty()) return false; if (name.empty()) return false;
// to remove a node it must have one or less children and no claims // to remove a node it must have one or less children and no claims
db << "SELECT COUNT(*) FROM claims WHERE nodeName = ?1 AND validHeight < ?2 AND expirationHeight >= ?2 " db << "SELECT COUNT(*) FROM (SELECT 1 FROM claims WHERE nodeName = ?1 AND validHeight < ?2 AND expirationHeight >= ?2 LIMIT 1)"
<< name << nNextHeight >> claims; << name << nNextHeight >> claims;
if (claims > 0) return false; // still has claims if (claims > 0) return false; // still has claims
// we now know it has no claims, but we need to check its children // we now know it has no claims, but we need to check its children
@ -188,8 +188,7 @@ bool CClaimTrieCacheBase::deleteNodeIfPossible(const std::string& name, std::str
std::string childName; std::string childName;
// this line assumes that we've set the parent on child nodes already, // this line assumes that we've set the parent on child nodes already,
// which means we are len(name) desc in our parent method // which means we are len(name) desc in our parent method
// alternately: SELECT COUNT(DISTINCT nodeName) FROM claims WHERE SUBSTR(nodeName, 1, len(?)) == ? AND LENGTH(nodeName) > len(?) db << "SELECT COUNT(*), MAX(name) FROM nodes WHERE parent = ?" << name >> std::tie(count, childName);
db << "SELECT COUNT(*),MAX(name) FROM nodes WHERE parent = ?" << name >> std::tie(count, childName);
if (count > 1) return false; // still has multiple children if (count > 1) return false; // still has multiple children
logPrint << "Removing node " << name << " with " << count << " children" << Clog::endl; logPrint << "Removing node " << name << " with " << count << " children" << Clog::endl;
// okay. it's going away // okay. it's going away
@ -307,7 +306,7 @@ std::size_t CClaimTrieCacheBase::getTotalNamesInTrie() const
// you could do this select from the nodes table, but you would have to ensure it is not dirty first // you could do this select from the nodes table, but you would have to ensure it is not dirty first
std::size_t ret; std::size_t ret;
db << "SELECT COUNT(DISTINCT nodeName) FROM claims WHERE validHeight < ?1 AND expirationHeight >= ?1" db << "SELECT COUNT(DISTINCT nodeName) FROM claims WHERE validHeight < ?1 AND expirationHeight >= ?1"
<< nNextHeight >> ret; << nNextHeight >> ret;
return ret; return ret;
} }
@ -315,7 +314,7 @@ std::size_t CClaimTrieCacheBase::getTotalClaimsInTrie() const
{ {
std::size_t ret; std::size_t ret;
db << "SELECT COUNT(*) FROM claims WHERE validHeight < ?1 AND expirationHeight >= ?1" db << "SELECT COUNT(*) FROM claims WHERE validHeight < ?1 AND expirationHeight >= ?1"
<< nNextHeight >> ret; << nNextHeight >> ret;
return ret; return ret;
} }
@ -348,15 +347,12 @@ bool CClaimTrieCacheBase::getInfoForName(const std::string& name, CClaimValue& c
CClaimSupportToName CClaimTrieCacheBase::getClaimsForName(const std::string& name) const CClaimSupportToName CClaimTrieCacheBase::getClaimsForName(const std::string& name) const
{ {
int nLastTakeoverHeight = 0; int nLastTakeoverHeight = 0;
{ db << "SELECT takeoverHeight FROM nodes WHERE name = ?" << name
auto query = db << "SELECT takeoverHeight FROM nodes WHERE name = ?" << name; >> [&nLastTakeoverHeight](int takeoverHeight) {
auto it = query.begin(); nLastTakeoverHeight = takeoverHeight;
if (it != query.end()) };
*it >> nLastTakeoverHeight;
}
claimEntryType claims; claimEntryType claims;
auto supports = getSupportsForName(name);
{ {
auto query = db << "SELECT claimID, txID, txN, blockHeight, validHeight, amount " auto query = db << "SELECT claimID, txID, txN, blockHeight, validHeight, amount "
"FROM claims WHERE nodeName = ? AND expirationHeight >= ?" "FROM claims WHERE nodeName = ? AND expirationHeight >= ?"
@ -365,10 +361,11 @@ CClaimSupportToName CClaimTrieCacheBase::getClaimsForName(const std::string& nam
CClaimValue claim; CClaimValue claim;
row >> claim.claimId >> claim.outPoint.hash >> claim.outPoint.n row >> claim.claimId >> claim.outPoint.hash >> claim.outPoint.n
>> claim.nHeight >> claim.nValidAtHeight >> claim.nAmount; >> claim.nHeight >> claim.nValidAtHeight >> claim.nAmount;
claims.push_back(claim); claims.push_back(std::move(claim));
} }
} }
auto supports = getSupportsForName(name);
auto find = [&supports](decltype(supports)::iterator& it, const CClaimValue& claim) { auto find = [&supports](decltype(supports)::iterator& it, const CClaimValue& claim) {
it = std::find_if(it, supports.end(), [&claim](const CSupportValue& support) { it = std::find_if(it, supports.end(), [&claim](const CSupportValue& support) {
return claim.claimId == support.supportedClaimId; return claim.claimId == support.supportedClaimId;
@ -496,10 +493,14 @@ CClaimTrieCacheBase::CClaimTrieCacheBase(CClaimTrie* base)
: base(base), db(base->dbFile, sharedConfig), transacting(false), : base(base), db(base->dbFile, sharedConfig), transacting(false),
childHashQuery(db << "SELECT name, hash, IFNULL(takeoverHeight, 0) FROM nodes WHERE parent = ? ORDER BY name"), childHashQuery(db << "SELECT name, hash, IFNULL(takeoverHeight, 0) FROM nodes WHERE parent = ? ORDER BY name"),
claimHashQuery(db << "SELECT c.txID, c.txN, c.claimID, c.blockHeight, c.validHeight, c.amount, " claimHashQuery(db << "SELECT c.txID, c.txN, c.claimID, c.blockHeight, c.validHeight, c.amount, "
"(SELECT IFNULL(SUM(s.amount),0)+c.amount FROM supports s WHERE s.supportedClaimID = c.claimID " "(SELECT IFNULL(SUM(s.amount),0)+c.amount FROM supports s WHERE s.supportedClaimID = c.claimID "
"AND s.nodeName = c.nodeName AND s.validHeight < ?1 AND s.expirationHeight >= ?1) as effectiveAmount " "AND s.nodeName = c.nodeName AND s.validHeight < ?1 AND s.expirationHeight >= ?1) as effectiveAmount "
"FROM claims c WHERE c.nodeName = ?2 AND c.validHeight < ?1 AND c.expirationHeight >= ?1 " "FROM claims c WHERE c.nodeName = ?2 AND c.validHeight < ?1 AND c.expirationHeight >= ?1 "
"ORDER BY effectiveAmount DESC, c.blockHeight, c.txID, c.txN") "ORDER BY effectiveAmount DESC, c.blockHeight, c.txID, c.txN"),
proofClaimQuery("SELECT name, IFNULL(takeoverHeight, 0) FROM nodes WHERE "
"name IN (WITH RECURSIVE prefix(p) AS (VALUES(?) UNION ALL "
"SELECT POPS(p) FROM prefix WHERE p != '') SELECT p FROM prefix) "
"ORDER BY name")
{ {
assert(base); assert(base);
nNextHeight = base->nNextHeight; nNextHeight = base->nNextHeight;
@ -513,6 +514,14 @@ CClaimTrieCacheBase::CClaimTrieCacheBase(CClaimTrie* base)
db.define("POPS", [](std::string s) -> std::string { if (!s.empty()) s.pop_back(); return s; }); db.define("POPS", [](std::string s) -> std::string { if (!s.empty()) s.pop_back(); return s; });
} }
void CClaimTrieCacheBase::ensureTransacting()
{
if (!transacting) {
transacting = true;
db << "begin";
}
}
int CClaimTrieCacheBase::expirationTime() const int CClaimTrieCacheBase::expirationTime() const
{ {
return base->nOriginalClaimExpirationTime; return base->nOriginalClaimExpirationTime;
@ -545,7 +554,7 @@ bool CClaimTrieCacheBase::getLastTakeoverForName(const std::string& name, CUint1
bool CClaimTrieCacheBase::addClaim(const std::string& name, const CTxOutPoint& outPoint, const CUint160& claimId, bool CClaimTrieCacheBase::addClaim(const std::string& name, const CTxOutPoint& outPoint, const CUint160& claimId,
int64_t nAmount, int nHeight, int nValidHeight, const std::vector<unsigned char>& metadata) int64_t nAmount, int nHeight, int nValidHeight, const std::vector<unsigned char>& metadata)
{ {
if (!transacting) { transacting = true; db << "begin"; } ensureTransacting();
// in the update scenario the previous one should be removed already // 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 // in the downgrade scenario, the one ahead will be removed already and the old one's valid height is input
@ -564,8 +573,8 @@ bool CClaimTrieCacheBase::addClaim(const std::string& name, const CTxOutPoint& o
auto expires = expirationTime() + nHeight; auto expires = expirationTime() + nHeight;
db << "INSERT INTO claims(claimID, name, nodeName, txID, txN, amount, blockHeight, validHeight, expirationHeight, metadata) " db << "INSERT INTO claims(claimID, name, nodeName, txID, txN, amount, blockHeight, validHeight, expirationHeight, metadata) "
"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" << claimId << name << nodeName "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" << claimId << name << nodeName
<< outPoint.hash << outPoint.n << nAmount << nHeight << nValidHeight << expires << metadata; << outPoint.hash << outPoint.n << nAmount << nHeight << nValidHeight << expires << metadata;
if (nValidHeight < nNextHeight) if (nValidHeight < nNextHeight)
db << "INSERT INTO nodes(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET hash = NULL" << nodeName; db << "INSERT INTO nodes(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET hash = NULL" << nodeName;
@ -576,15 +585,16 @@ bool CClaimTrieCacheBase::addClaim(const std::string& name, const CTxOutPoint& o
bool CClaimTrieCacheBase::addSupport(const std::string& name, const CTxOutPoint& outPoint, const CUint160& supportedClaimId, bool CClaimTrieCacheBase::addSupport(const std::string& name, const CTxOutPoint& outPoint, const CUint160& supportedClaimId,
int64_t nAmount, int nHeight, int nValidHeight, const std::vector<unsigned char>& metadata) int64_t nAmount, int nHeight, int nValidHeight, const std::vector<unsigned char>& metadata)
{ {
if (!transacting) { transacting = true; db << "begin"; } ensureTransacting();
if (nValidHeight < 0) if (nValidHeight < 0)
nValidHeight = nHeight + getDelayForName(name, supportedClaimId); nValidHeight = nHeight + getDelayForName(name, supportedClaimId);
auto nodeName = adjustNameForValidHeight(name, nValidHeight); auto nodeName = adjustNameForValidHeight(name, nValidHeight);
auto expires = expirationTime() + nHeight; auto expires = expirationTime() + nHeight;
db << "INSERT INTO supports(supportedClaimID, name, nodeName, txID, txN, amount, blockHeight, validHeight, expirationHeight, metadata) " db << "INSERT INTO supports(supportedClaimID, name, nodeName, txID, txN, amount, blockHeight, validHeight, expirationHeight, metadata) "
"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" << supportedClaimId << name << nodeName "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" << supportedClaimId << name << nodeName
<< outPoint.hash << outPoint.n << nAmount << nHeight << nValidHeight << expires << metadata; << outPoint.hash << outPoint.n << nAmount << nHeight << nValidHeight << expires << metadata;
if (nValidHeight < nNextHeight) if (nValidHeight < nNextHeight)
db << "UPDATE nodes SET hash = NULL WHERE name = ?" << nodeName; db << "UPDATE nodes SET hash = NULL WHERE name = ?" << nodeName;
@ -594,7 +604,7 @@ bool CClaimTrieCacheBase::addSupport(const std::string& name, const CTxOutPoint&
bool CClaimTrieCacheBase::removeClaim(const CUint160& claimId, const CTxOutPoint& outPoint, std::string& nodeName, int& validHeight) bool CClaimTrieCacheBase::removeClaim(const CUint160& claimId, const CTxOutPoint& outPoint, std::string& nodeName, int& validHeight)
{ {
if (!transacting) { transacting = true; db << "begin"; } ensureTransacting();
// this gets tricky in that we may be removing an update // this gets tricky in that we may be removing an update
// when going forward we spend a claim (aka, call removeClaim) before updating it (aka, call addClaim) // when going forward we spend a claim (aka, call removeClaim) before updating it (aka, call addClaim)
@ -602,12 +612,12 @@ bool CClaimTrieCacheBase::removeClaim(const CUint160& claimId, const CTxOutPoint
// we then undo the spend of the previous one by calling addClaim with the original data // 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 udpater will need to use our height returned here
auto query = db << "SELECT nodeName, validHeight FROM claims WHERE claimID = ? and txID = ? and txN = ?" auto query = db << "SELECT nodeName, validHeight FROM claims WHERE claimID = ? AND txID = ? AND txN = ? AND expirationHeight >= ?"
<< claimId << outPoint.hash << outPoint.n; << claimId << outPoint.hash << outPoint.n << nNextHeight;
auto it = query.begin(); auto it = query.begin();
if (it == query.end()) return false; if (it == query.end()) return false;
*it >> nodeName >> validHeight; *it >> nodeName >> validHeight;
db << "DELETE FROM claims WHERE claimID = ? AND txID = ? and txN = ?" << claimId << outPoint.hash << outPoint.n; db << "DELETE FROM claims WHERE claimID = ? AND txID = ? and txN = ?" << claimId << outPoint.hash << outPoint.n;
if (!db.rows_modified()) if (!db.rows_modified())
return false; return false;
db << "UPDATE nodes SET hash = NULL WHERE name = ?" << nodeName; db << "UPDATE nodes SET hash = NULL WHERE name = ?" << nodeName;
@ -616,32 +626,30 @@ bool CClaimTrieCacheBase::removeClaim(const CUint160& claimId, const CTxOutPoint
// because it's a parent one and should not be effectively erased // 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 // we had a bug in the old code where that situation would force a zero delay on re-add
if (true) { // TODO: hard fork this out (which we already tried once but failed) if (true) { // TODO: hard fork this out (which we already tried once but failed)
auto workaroundQuery = db << "SELECT nodeName FROM claims WHERE nodeName LIKE ?1 " db << "SELECT nodeName FROM claims WHERE nodeName LIKE ?1 "
"AND validHeight < ?2 AND expirationHeight >= ?2 ORDER BY nodeName LIMIT 1" "AND validHeight < ?2 AND expirationHeight > ?2 ORDER BY nodeName LIMIT 1"
<< nodeName + "%" << nNextHeight; << nodeName + '%' << nNextHeight
auto wit = workaroundQuery.begin(); >> [this, &nodeName](const std::string& shortestMatch) {
if (wit != workaroundQuery.end()) { if (shortestMatch != nodeName)
std::string shortestMatch; // set this when there are no more claims on that name and that node still has children
*wit >> shortestMatch; removalWorkaround.insert(nodeName);
if (shortestMatch != nodeName) { };
// set this when there are no more claims on that name and that node still has children
removalWorkaround.insert(nodeName);
}
}
} }
return true; return true;
} }
bool CClaimTrieCacheBase::removeSupport(const CTxOutPoint& outPoint, std::string& nodeName, int& validHeight) bool CClaimTrieCacheBase::removeSupport(const CTxOutPoint& outPoint, std::string& nodeName, int& validHeight)
{ {
if (!transacting) { transacting = true; db << "begin"; } ensureTransacting();
auto query = db << "SELECT nodeName, validHeight FROM supports WHERE txID = ? AND txN = ?" auto query = db << "SELECT nodeName, validHeight FROM supports WHERE txID = ? AND txN = ? AND expirationHeight >= ?"
<< outPoint.hash << outPoint.n; << outPoint.hash << outPoint.n << nNextHeight;
auto it = query.begin(); auto it = query.begin();
if (it == query.end()) return false; if (it == query.end()) return false;
*it >> nodeName >> validHeight; *it >> nodeName >> validHeight;
db << "DELETE FROM supports WHERE txID = ? AND txN = ?" << outPoint.hash << outPoint.n; db << "DELETE FROM supports WHERE txID = ? AND txN = ?" << outPoint.hash << outPoint.n;
if (!db.rows_modified())
return false;
db << "UPDATE nodes SET hash = NULL WHERE name = ?" << nodeName; db << "UPDATE nodes SET hash = NULL WHERE name = ?" << nodeName;
return true; return true;
} }
@ -1100,7 +1108,7 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimUndoTy
// for every claim and support that becomes active this block set its node hash to null (aka, dirty) // for every claim and support that becomes active this block set its node hash to null (aka, dirty)
// for every claim and support that expires this block set its node hash to null and add it to the expire(Support)Undo // for every claim and support that expires this block set its node hash to null and add it to the expire(Support)Undo
// for all dirty nodes look for new takeovers // for all dirty nodes look for new takeovers
if (!transacting) { transacting = true; db << "begin"; } ensureTransacting();
db << "INSERT INTO nodes(name) SELECT nodeName FROM claims " db << "INSERT INTO nodes(name) SELECT nodeName FROM claims "
"WHERE validHeight = ?1 AND expirationHeight > ?1 " "WHERE validHeight = ?1 AND expirationHeight > ?1 "
@ -1117,11 +1125,11 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimUndoTy
std::string name; std::string name;
row >> value.outPoint.hash >> value.outPoint.n >> name row >> value.outPoint.hash >> value.outPoint.n >> name
>> value.claimId >> value.nValidAtHeight >> value.nHeight >> value.nAmount; >> value.claimId >> value.nValidAtHeight >> value.nHeight >> value.nAmount;
expireUndo.emplace_back(name, value); expireUndo.emplace_back(std::move(name), std::move(value));
} }
} }
db << "UPDATE nodes SET hash = NULL WHERE name IN (SELECT nodeName FROM claims WHERE expirationHeight = ?)"
<< nNextHeight; db << "UPDATE nodes SET hash = NULL WHERE name IN (SELECT nodeName FROM claims WHERE expirationHeight = ?)" << nNextHeight;
assert(expireSupportUndo.empty()); assert(expireSupportUndo.empty());
{ {
@ -1132,12 +1140,11 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimUndoTy
std::string name; std::string name;
row >> value.outPoint.hash >> value.outPoint.n >> name row >> value.outPoint.hash >> value.outPoint.n >> name
>> value.supportedClaimId >> value.nValidAtHeight >> value.nHeight >> value.nAmount; >> value.supportedClaimId >> value.nValidAtHeight >> value.nHeight >> value.nAmount;
expireSupportUndo.emplace_back(name, value); expireSupportUndo.emplace_back(std::move(name), std::move(value));
} }
} }
db << "UPDATE nodes SET hash = NULL WHERE name IN (SELECT nodeName FROM supports WHERE expirationHeight = ?)" db << "UPDATE nodes SET hash = NULL WHERE name IN (SELECT nodeName FROM supports WHERE expirationHeight = ?)" << nNextHeight;
<< nNextHeight;
// takeover handling: // takeover handling:
std::vector<std::string> takeovers; std::vector<std::string> takeovers;
@ -1147,8 +1154,7 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimUndoTy
}; };
auto getTakeoverQuery = db << "SELECT IFNULL(takeoverHeight, 0), takeoverID FROM nodes WHERE name = ?"; auto getTakeoverQuery = db << "SELECT IFNULL(takeoverHeight, 0), takeoverID FROM nodes WHERE name = ?";
auto hasCandidateQuery = db << "UPDATE nodes SET takeoverHeight = ?, takeoverID = ? WHERE name = ?"; auto candidateQuery = db << "UPDATE nodes SET takeoverHeight = ?, takeoverID = ? WHERE name = ?";
auto noCandidateQuery = db << "UPDATE nodes SET takeoverHeight = NULL, takeoverID = NULL WHERE name = ?";
for (const auto& nameWithTakeover : takeovers) { for (const auto& nameWithTakeover : takeovers) {
// if somebody activates on this block and they are the new best, then everybody activates on this block // if somebody activates on this block and they are the new best, then everybody activates on this block
@ -1177,21 +1183,17 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimUndoTy
if (takeoverHappening || !hasBeenSetBefore) { if (takeoverHappening || !hasBeenSetBefore) {
takeoverUndo.emplace_back(nameWithTakeover, std::make_pair(existingHeight, hasBeenSetBefore ? *existingID : CUint160())); takeoverUndo.emplace_back(nameWithTakeover, std::make_pair(existingHeight, hasBeenSetBefore ? *existingID : CUint160()));
if (hasCandidate) { if (hasCandidate)
hasCandidateQuery << nNextHeight << candidateValue.claimId << nameWithTakeover; candidateQuery << nNextHeight << candidateValue.claimId << nameWithTakeover;
hasCandidateQuery++; else
} candidateQuery << nullptr << nullptr << nameWithTakeover;
else { candidateQuery++;
noCandidateQuery << nameWithTakeover;
noCandidateQuery++;
}
assert(db.rows_modified()); assert(db.rows_modified());
} }
} }
getTakeoverQuery.used(true); getTakeoverQuery.used(true);
hasCandidateQuery.used(true); candidateQuery.used(true);
noCandidateQuery.used(true);
nNextHeight++; nNextHeight++;
return true; return true;
} }
@ -1201,38 +1203,30 @@ bool CClaimTrieCacheBase::activateAllFor(insertUndoType& insertUndo, insertUndoT
// now that we know a takeover is happening, we bring everybody in: // now that we know a takeover is happening, we bring everybody in:
auto ret = false; auto ret = false;
{ {
auto query = db << "SELECT txID, txN, validHeight FROM claims WHERE nodeName = ?1 AND validHeight > ?2 AND expirationHeight > ?2" db << "SELECT txID, txN, validHeight FROM claims WHERE nodeName = ?1 AND validHeight > ?2 AND expirationHeight > ?2"
<< name << nNextHeight; << name << nNextHeight
for (auto &&row: query) { >> [this, &insertUndo, &name](CUint256 txId, uint32_t n, int oldValidHeight) {
CUint256 hash; CTxOutPoint outPoint(std::move(txId), n);
uint32_t n; logPrint << "Early activation of claim " << name << ", " << outPoint.ToString() << " at " << nNextHeight << Clog::endl;
int oldValidHeight; insertUndo.emplace_back(name, std::move(outPoint), oldValidHeight);
row >> hash >> n >> oldValidHeight; };
insertUndo.emplace_back(name, CTxOutPoint(hash, n), oldValidHeight);
logPrint << "Early activation of claim " << name << ", " << CTxOutPoint(hash, n).ToString() << " at " << nNextHeight << Clog::endl;
}
} }
// and then update them all to activate now: // and then update them all to activate now:
db << "UPDATE claims SET validHeight = ?1 WHERE nodeName = ?2 AND validHeight > ?1 AND expirationHeight > ?1" db << "UPDATE claims SET validHeight = ?1 WHERE nodeName = ?2 AND validHeight > ?1 AND expirationHeight > ?1" << nNextHeight << name;
<< nNextHeight << name;
ret |= db.rows_modified() > 0; ret |= db.rows_modified() > 0;
// then do the same for supports: // then do the same for supports:
{ {
auto query = db << "SELECT txID, txN, validHeight FROM supports WHERE nodeName = ?1 AND validHeight > ?2 AND expirationHeight > ?2" db << "SELECT txID, txN, validHeight FROM supports WHERE nodeName = ?1 AND validHeight > ?2 AND expirationHeight > ?2"
<< name << nNextHeight; << name << nNextHeight
for (auto &&row: query) { >> [this, &insertSupportUndo, &name](CUint256 txId, uint32_t n, int oldValidHeight) {
CUint256 hash; CTxOutPoint outPoint(std::move(txId), n);
uint32_t n; logPrint << "Early activation of support " << name << ", " << outPoint.ToString() << " at " << nNextHeight << Clog::endl;
int oldValidHeight; insertSupportUndo.emplace_back(name, std::move(outPoint), oldValidHeight);
row >> hash >> n >> oldValidHeight; };
insertSupportUndo.emplace_back(name, CTxOutPoint(hash, n), oldValidHeight);
logPrint << "Early activation of support " << name << ", " << CTxOutPoint(hash, n).ToString() << " at " << nNextHeight << Clog::endl;
}
} }
// and then update them all to activate now: // and then update them all to activate now:
db << "UPDATE supports SET validHeight = ?1 WHERE nodeName = ?2 AND validHeight > ?1 AND expirationHeight > ?1" db << "UPDATE supports SET validHeight = ?1 WHERE nodeName = ?2 AND validHeight > ?1 AND expirationHeight > ?1" << nNextHeight << name;
<< nNextHeight << name;
ret |= db.rows_modified() > 0; ret |= db.rows_modified() > 0;
return ret; return ret;
} }
@ -1240,32 +1234,32 @@ bool CClaimTrieCacheBase::activateAllFor(insertUndoType& insertUndo, insertUndoT
bool CClaimTrieCacheBase::decrementBlock(insertUndoType& insertUndo, claimUndoType& expireUndo, bool CClaimTrieCacheBase::decrementBlock(insertUndoType& insertUndo, claimUndoType& expireUndo,
insertUndoType& insertSupportUndo, supportUndoType& expireSupportUndo) insertUndoType& insertSupportUndo, supportUndoType& expireSupportUndo)
{ {
if (!transacting) { transacting = true; db << "begin"; } ensureTransacting();
nNextHeight--; nNextHeight--;
auto updateNodes = "INSERT INTO nodes(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET hash = NULL";
// to actually delete the expired items and then restore them here I would have to look up the metadata in the block // 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 // 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) { for (auto it = expireSupportUndo.crbegin(); it != expireSupportUndo.crend(); ++it)
db << "INSERT INTO nodes(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET hash = NULL" << it->first; db << updateNodes << it->first;
}
for (auto it = expireUndo.crbegin(); it != expireUndo.crend(); ++it) { for (auto it = expireUndo.crbegin(); it != expireUndo.crend(); ++it)
db << "INSERT INTO nodes(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET hash = NULL" << it->first; db << updateNodes << it->first;
}
for (auto it = insertSupportUndo.crbegin(); it != insertSupportUndo.crend(); ++it) { for (auto it = insertSupportUndo.crbegin(); it != insertSupportUndo.crend(); ++it) {
logPrint << "Resetting support valid height to " << it->nValidHeight << " for " << it->name << Clog::endl; logPrint << "Resetting support valid height to " << it->nValidHeight << " for " << it->name << Clog::endl;
db << "UPDATE supports SET validHeight = ? WHERE txID = ? AND txN = ?" db << "UPDATE supports SET validHeight = ? WHERE txID = ? AND txN = ?"
<< it->nValidHeight << it->outPoint.hash << it->outPoint.n; << it->nValidHeight << it->outPoint.hash << it->outPoint.n;
db << "INSERT INTO nodes(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET hash = NULL" << it->name; db << updateNodes << it->name;
} }
for (auto it = insertUndo.crbegin(); it != insertUndo.crend(); ++it) { for (auto it = insertUndo.crbegin(); it != insertUndo.crend(); ++it) {
logPrint << "Resetting valid height to " << it->nValidHeight << " for " << it->name << Clog::endl; logPrint << "Resetting valid height to " << it->nValidHeight << " for " << it->name << Clog::endl;
db << "UPDATE claims SET validHeight = ? WHERE nodeName = ? AND txID = ? AND txN = ?" db << "UPDATE claims SET validHeight = ? WHERE nodeName = ? AND txID = ? AND txN = ?"
<< it->nValidHeight << it->name << it->outPoint.hash << it->outPoint.n; << it->nValidHeight << it->name << it->outPoint.hash << it->outPoint.n;
db << "INSERT INTO nodes(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET hash = NULL" << it->name; db << updateNodes << it->name;
} }
return true; return true;
@ -1278,12 +1272,13 @@ bool CClaimTrieCacheBase::finalizeDecrement(takeoverUndoType& takeoverUndo)
db << "UPDATE nodes SET hash = NULL WHERE name IN " db << "UPDATE nodes SET hash = NULL WHERE name IN "
"(SELECT nodeName FROM supports WHERE validHeight = ?1 AND expirationHeight > ?1)" << nNextHeight; "(SELECT nodeName FROM supports WHERE validHeight = ?1 AND expirationHeight > ?1)" << nNextHeight;
auto updateNodes = "UPDATE nodes SET takeoverHeight = ?, takeoverID = ?, hash = NULL WHERE name = ?";
for (auto it = takeoverUndo.crbegin(); it != takeoverUndo.crend(); ++it) { for (auto it = takeoverUndo.crbegin(); it != takeoverUndo.crend(); ++it) {
if (it->second.second.IsNull()) if (it->second.second.IsNull())
db << "UPDATE nodes SET takeoverHeight = NULL, takeoverID = NULL, hash = NULL WHERE name = ?" << it->first; db << updateNodes << nullptr << nullptr << it->first;
else else
db << "UPDATE nodes SET takeoverHeight = ?, takeoverID = ?, hash = NULL WHERE name = ?" db << updateNodes << it->second.first << it->second.second << it->first;
<< it->second.first << it->second.second << it->first;
} }
return true; return true;
} }
@ -1319,11 +1314,7 @@ bool CClaimTrieCacheBase::getProofForName(const std::string& name, const CUint16
// cache the parent nodes // cache the parent nodes
getMerkleHash(); getMerkleHash();
proof = CClaimTrieProof(); proof = CClaimTrieProof();
auto nodeQuery = db << "SELECT name, IFNULL(takeoverHeight, 0) FROM nodes WHERE " for (auto&& row: db << proofClaimQuery << name) {
"name IN (WITH RECURSIVE prefix(p) AS (VALUES(?) UNION ALL "
"SELECT POPS(p) FROM prefix WHERE p != '') SELECT p FROM prefix) "
"ORDER BY name" << name;
for (auto&& row: nodeQuery) {
CClaimValue claim; CClaimValue claim;
std::string key; std::string key;
int takeoverHeight; int takeoverHeight;
@ -1371,7 +1362,7 @@ bool CClaimTrieCacheBase::findNameForClaim(std::vector<unsigned char> claim, CCl
{ {
std::reverse(claim.begin(), claim.end()); std::reverse(claim.begin(), claim.end());
auto query = db << "SELECT nodeName, claimId, txID, txN, amount, validHeight, blockHeight " auto query = db << "SELECT nodeName, claimId, txID, txN, amount, validHeight, blockHeight "
"FROM claims WHERE SUBSTR(claimID, ?) = ? AND validHeight < ? AND expirationHeight >= ?" "FROM claims WHERE SUBSTR(claimID, ?) = ? AND validHeight < ? AND expirationHeight >= ?"
<< -int(claim.size()) << claim << nNextHeight << nNextHeight; << -int(claim.size()) << claim << nNextHeight << nNextHeight;
auto hit = false; auto hit = false;
for (auto&& row: query) { for (auto&& row: query) {
@ -1385,11 +1376,9 @@ bool CClaimTrieCacheBase::findNameForClaim(std::vector<unsigned char> claim, CCl
void CClaimTrieCacheBase::getNamesInTrie(std::function<void(const std::string&)> callback) const void CClaimTrieCacheBase::getNamesInTrie(std::function<void(const std::string&)> callback) const
{ {
auto query = db << "SELECT DISTINCT nodeName FROM claims WHERE validHeight < ? AND expirationHeight >= ?" db << "SELECT DISTINCT nodeName FROM claims WHERE validHeight < ? AND expirationHeight >= ?"
<< nNextHeight << nNextHeight; << nNextHeight << nNextHeight
for (auto&& row: query) { >> [&callback](const std::string& name) {
std::string name; callback(name);
row >> name; };
callback(name);
}
} }

View file

@ -130,10 +130,10 @@ public:
bool findNameForClaim(std::vector<unsigned char> claim, CClaimValue& value, std::string& name) const; bool findNameForClaim(std::vector<unsigned char> claim, CClaimValue& value, std::string& name) const;
protected: protected:
int nNextHeight; // Height of the block that is being worked on, which is
CClaimTrie* base; CClaimTrie* base;
mutable sqlite::database db; mutable sqlite::database db;
int nNextHeight; // Height of the block that is being worked on, which is const std::string proofClaimQuery;
bool transacting;
mutable std::unordered_set<std::string> removalWorkaround; mutable std::unordered_set<std::string> removalWorkaround;
mutable sqlite::database_binder claimHashQuery, childHashQuery; mutable sqlite::database_binder claimHashQuery, childHashQuery;
@ -145,8 +145,10 @@ protected:
bool deleteNodeIfPossible(const std::string& name, std::string& parent, int64_t& claims); bool deleteNodeIfPossible(const std::string& name, std::string& parent, int64_t& claims);
void ensureTreeStructureIsUpToDate(); void ensureTreeStructureIsUpToDate();
void ensureTransacting();
private: private:
bool transacting;
// for unit test // for unit test
friend struct ClaimTrieChainFixture; friend struct ClaimTrieChainFixture;
friend class CClaimTrieCacheTest; friend class CClaimTrieCacheTest;

View file

@ -140,11 +140,14 @@ BOOST_AUTO_TEST_CASE(hardfork_claim_test)
// Ensure that we cannot update the original pre-fork expired claim // Ensure that we cannot update the original pre-fork expired claim
CMutableTransaction u1 = fixture.MakeUpdate(tx1,"test","two",ClaimIdHash(tx1.GetHash(),0), 3); CMutableTransaction u1 = fixture.MakeUpdate(tx1,"test","two",ClaimIdHash(tx1.GetHash(),0), 3);
fixture.IncrementBlocks(1); fixture.IncrementBlocks(1);
BOOST_CHECK(!fixture.is_best_claim("test",u1)); BOOST_CHECK(!fixture.haveClaim("test", COutPoint(u1.GetHash(), 0)));
BOOST_CHECK(fixture.is_best_claim("test",tx3));
// Ensure that supports for the expired claim don't support it // Ensure that supports for the expired claim don't support it
CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(),u1,"test",10); CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(),u1,"test",10);
BOOST_CHECK(!fixture.is_best_claim("test",u1)); fixture.IncrementBlocks(1);
BOOST_CHECK(!fixture.haveClaim("test", COutPoint(u1.GetHash(), 0)));
BOOST_CHECK(fixture.is_best_claim("test",tx3));
// Ensure that we can update the new post-fork claim // Ensure that we can update the new post-fork claim
CMutableTransaction u2 = fixture.MakeUpdate(tx3,"test","two",ClaimIdHash(tx3.GetHash(),0), 1); CMutableTransaction u2 = fixture.MakeUpdate(tx3,"test","two",ClaimIdHash(tx3.GetHash(),0), 1);
@ -153,6 +156,7 @@ BOOST_AUTO_TEST_CASE(hardfork_claim_test)
// Ensure that supports for the new post-fork claim // Ensure that supports for the new post-fork claim
CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(),u2,"test",3); CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(),u2,"test",3);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test",u2)); BOOST_CHECK(fixture.is_best_claim("test",u2));
} }

View file

@ -401,7 +401,8 @@ boost::test_tools::predicate_result ClaimTrieChainFixture::best_claim_effective_
return true; return true;
} }
bool ClaimTrieChainFixture::getClaimById(const uint160 &claimId, std::string &name, CClaimValue &value) { bool ClaimTrieChainFixture::getClaimById(const CUint160 &claimId, std::string &name, CClaimValue &value)
{
auto query = db << "SELECT nodeName, claimID, txID, txN, amount, validHeight, blockHeight " auto query = db << "SELECT nodeName, claimID, txID, txN, amount, validHeight, blockHeight "
"FROM claims WHERE claimID = ?" << claimId; "FROM claims WHERE claimID = ?" << claimId;
auto hit = false; auto hit = false;
@ -414,7 +415,8 @@ bool ClaimTrieChainFixture::getClaimById(const uint160 &claimId, std::string &na
return hit; return hit;
} }
std::vector<std::string> ClaimTrieChainFixture::getNodeChildren(const std::string &name) { std::vector<std::string> ClaimTrieChainFixture::getNodeChildren(const std::string &name)
{
std::vector<std::string> ret; std::vector<std::string> ret;
for (auto&& row: db << "SELECT name FROM nodes WHERE parent = ?" << name) { for (auto&& row: db << "SELECT name FROM nodes WHERE parent = ?" << name) {
ret.emplace_back(); ret.emplace_back();

View file

@ -105,7 +105,7 @@ struct ClaimTrieChainFixture: public CClaimTrieCache
int proportionalDelayFactor() const; int proportionalDelayFactor() const;
bool getClaimById(const uint160& claimId, std::string& name, CClaimValue& value); bool getClaimById(const CUint160& claimId, std::string& name, CClaimValue& value);
// is a claim in queue // is a claim in queue
boost::test_tools::predicate_result is_claim_in_queue(const std::string& name, const CTransaction &tx); boost::test_tools::predicate_result is_claim_in_queue(const std::string& name, const CTransaction &tx);