Fix removing expired claim
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
This commit is contained in:
parent
02091d564b
commit
f47826232f
6 changed files with 139 additions and 154 deletions
|
@ -63,7 +63,7 @@ bool CClaimTrieCacheExpirationFork::finalizeDecrement(takeoverUndoType& takeover
|
|||
|
||||
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
|
||||
|
@ -73,24 +73,22 @@ bool CClaimTrieCacheExpirationFork::forkForExpirationChange(bool increment)
|
|||
will have their expiration extension removed.
|
||||
*/
|
||||
|
||||
auto extension = base->nExtendedClaimExpirationTime - base->nOriginalClaimExpirationTime;
|
||||
if (increment) {
|
||||
db << "UPDATE claims SET expirationHeight = expirationHeight + ? WHERE expirationHeight >= ?"
|
||||
<< extension << nNextHeight;
|
||||
db << "UPDATE supports SET expirationHeight = expirationHeight + ? WHERE expirationHeight >= ?"
|
||||
<< 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;
|
||||
auto height = nNextHeight;
|
||||
int extension = base->nExtendedClaimExpirationTime - base->nOriginalClaimExpirationTime;
|
||||
if (!increment) {
|
||||
height += extension;
|
||||
extension *= -1;
|
||||
}
|
||||
|
||||
db << "UPDATE claims SET expirationHeight = expirationHeight + ? WHERE expirationHeight >= ?" << extension << height;
|
||||
db << "UPDATE supports SET expirationHeight = expirationHeight + ? WHERE expirationHeight >= ?" << extension << height;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CClaimTrieCacheNormalizationFork::CClaimTrieCacheNormalizationFork(CClaimTrie* base) : CClaimTrieCacheExpirationFork(base)
|
||||
{
|
||||
db.define("NORMALIZED", [this](const std::string& str) { return normalizeClaimName(str, true); });
|
||||
}
|
||||
|
||||
bool CClaimTrieCacheNormalizationFork::shouldNormalize() const
|
||||
|
@ -141,10 +139,7 @@ std::string CClaimTrieCacheNormalizationFork::normalizeClaimName(const std::stri
|
|||
|
||||
bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary(takeoverUndoType& takeoverUndo)
|
||||
{
|
||||
if (!transacting) { transacting = true; db << "begin"; }
|
||||
|
||||
// run the one-time upgrade of all names that need to change
|
||||
db.define("NORMALIZED", [this](const std::string& str) { return normalizeClaimName(str, true); });
|
||||
ensureTransacting();
|
||||
|
||||
// make the new nodes
|
||||
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()
|
||||
{
|
||||
if (!transacting) { transacting = true; db << "begin"; }
|
||||
|
||||
// run the one-time upgrade of all names that need to change
|
||||
db.define("NORMALIZED", [this](const std::string& str) { return normalizeClaimName(str, true); });
|
||||
ensureTransacting();
|
||||
|
||||
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;
|
||||
|
@ -376,11 +368,7 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const CUi
|
|||
// cache the parent nodes
|
||||
getMerkleHash();
|
||||
proof = CClaimTrieProof();
|
||||
auto nodeQuery = db << "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" << name;
|
||||
for (auto&& row: nodeQuery) {
|
||||
for (auto&& row: db << proofClaimQuery << name) {
|
||||
std::string key;
|
||||
int takeoverHeight;
|
||||
row >> key >> takeoverHeight;
|
||||
|
@ -416,12 +404,12 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const CUi
|
|||
// else it will be hash(x, claims)
|
||||
if (key == name) {
|
||||
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);
|
||||
if (!claimHashes.empty())
|
||||
fillPairs(claimHashes, claimIdx);
|
||||
} else {
|
||||
auto hash = claimHashes.empty() ? emptyHash : ComputeMerkleRoot(claimHashes);
|
||||
auto hash = claimHashes.empty() ? emptyHash : ComputeMerkleRoot(std::move(claimHashes));
|
||||
proof.pairs.emplace_back(false, hash);
|
||||
if (!childHashes.empty())
|
||||
fillPairs(childHashes, nextCurrentIdx);
|
||||
|
@ -436,7 +424,7 @@ void CClaimTrieCacheHashFork::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)
|
||||
if (nNextHeight == base->nAllClaimsInMerkleForkHeight - 1) {
|
||||
if (!transacting) { transacting = true; db << "begin"; }
|
||||
ensureTransacting();
|
||||
db << "UPDATE nodes SET hash = NULL";
|
||||
}
|
||||
}
|
||||
|
@ -445,7 +433,7 @@ bool CClaimTrieCacheHashFork::finalizeDecrement(takeoverUndoType& takeoverUndo)
|
|||
{
|
||||
auto ret = CClaimTrieCacheNormalizationFork::finalizeDecrement(takeoverUndo);
|
||||
if (ret && nNextHeight == base->nAllClaimsInMerkleForkHeight - 1) {
|
||||
if (!transacting) { transacting = true; db << "begin"; }
|
||||
ensureTransacting();
|
||||
db << "UPDATE nodes SET hash = NULL";
|
||||
}
|
||||
return ret;
|
||||
|
|
|
@ -117,14 +117,14 @@ bool CClaimTrie::SyncToDisk()
|
|||
bool CClaimTrie::empty()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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 "
|
||||
"AND validHeight < ?4 AND expirationHeight >= ?4 LIMIT 1"
|
||||
"AND validHeight < ?4 AND expirationHeight >= ?4 LIMIT 1"
|
||||
<< name << outPoint.hash << outPoint.n << nNextHeight;
|
||||
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
|
||||
{
|
||||
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;
|
||||
return query.begin() != query.end();
|
||||
}
|
||||
|
@ -141,13 +141,13 @@ supportEntryType CClaimTrieCacheBase::getSupportsForName(const std::string& name
|
|||
{
|
||||
// includes values that are not yet valid
|
||||
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;
|
||||
for (auto&& row: query) {
|
||||
CSupportValue value;
|
||||
row >> value.supportedClaimId >> value.outPoint.hash >> value.outPoint.n
|
||||
>> value.nHeight >> value.nValidAtHeight >> value.nAmount;
|
||||
ret.push_back(value);
|
||||
ret.push_back(std::move(value));
|
||||
}
|
||||
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
|
||||
{
|
||||
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;
|
||||
for (auto&& row: query) {
|
||||
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
|
||||
{
|
||||
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;
|
||||
for (auto&& row: query) {
|
||||
row >> nValidAtHeight;
|
||||
|
@ -180,7 +180,7 @@ bool CClaimTrieCacheBase::deleteNodeIfPossible(const std::string& name, std::str
|
|||
{
|
||||
if (name.empty()) return false;
|
||||
// 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;
|
||||
if (claims > 0) return false; // still has claims
|
||||
// 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;
|
||||
// this line assumes that we've set the parent on child nodes already,
|
||||
// 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
|
||||
logPrint << "Removing node " << name << " with " << count << " children" << Clog::endl;
|
||||
// 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
|
||||
std::size_t ret;
|
||||
db << "SELECT COUNT(DISTINCT nodeName) FROM claims WHERE validHeight < ?1 AND expirationHeight >= ?1"
|
||||
<< nNextHeight >> ret;
|
||||
<< nNextHeight >> ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -315,7 +314,7 @@ std::size_t CClaimTrieCacheBase::getTotalClaimsInTrie() const
|
|||
{
|
||||
std::size_t ret;
|
||||
db << "SELECT COUNT(*) FROM claims WHERE validHeight < ?1 AND expirationHeight >= ?1"
|
||||
<< nNextHeight >> ret;
|
||||
<< nNextHeight >> ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -348,15 +347,12 @@ bool CClaimTrieCacheBase::getInfoForName(const std::string& name, CClaimValue& c
|
|||
CClaimSupportToName CClaimTrieCacheBase::getClaimsForName(const std::string& name) const
|
||||
{
|
||||
int nLastTakeoverHeight = 0;
|
||||
{
|
||||
auto query = db << "SELECT takeoverHeight FROM nodes WHERE name = ?" << name;
|
||||
auto it = query.begin();
|
||||
if (it != query.end())
|
||||
*it >> nLastTakeoverHeight;
|
||||
}
|
||||
db << "SELECT takeoverHeight FROM nodes WHERE name = ?" << name
|
||||
>> [&nLastTakeoverHeight](int takeoverHeight) {
|
||||
nLastTakeoverHeight = takeoverHeight;
|
||||
};
|
||||
|
||||
claimEntryType claims;
|
||||
auto supports = getSupportsForName(name);
|
||||
{
|
||||
auto query = db << "SELECT claimID, txID, txN, blockHeight, validHeight, amount "
|
||||
"FROM claims WHERE nodeName = ? AND expirationHeight >= ?"
|
||||
|
@ -365,10 +361,11 @@ CClaimSupportToName CClaimTrieCacheBase::getClaimsForName(const std::string& nam
|
|||
CClaimValue claim;
|
||||
row >> claim.claimId >> claim.outPoint.hash >> claim.outPoint.n
|
||||
>> 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) {
|
||||
it = std::find_if(it, supports.end(), [&claim](const CSupportValue& support) {
|
||||
return claim.claimId == support.supportedClaimId;
|
||||
|
@ -496,10 +493,14 @@ CClaimTrieCacheBase::CClaimTrieCacheBase(CClaimTrie* base)
|
|||
: base(base), db(base->dbFile, sharedConfig), transacting(false),
|
||||
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, "
|
||||
"(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 "
|
||||
"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")
|
||||
"(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 "
|
||||
"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"),
|
||||
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);
|
||||
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; });
|
||||
}
|
||||
|
||||
void CClaimTrieCacheBase::ensureTransacting()
|
||||
{
|
||||
if (!transacting) {
|
||||
transacting = true;
|
||||
db << "begin";
|
||||
}
|
||||
}
|
||||
|
||||
int CClaimTrieCacheBase::expirationTime() const
|
||||
{
|
||||
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,
|
||||
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 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;
|
||||
|
||||
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;
|
||||
"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" << claimId << name << nodeName
|
||||
<< outPoint.hash << outPoint.n << nAmount << nHeight << nValidHeight << expires << metadata;
|
||||
|
||||
if (nValidHeight < nNextHeight)
|
||||
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,
|
||||
int64_t nAmount, int nHeight, int nValidHeight, const std::vector<unsigned char>& metadata)
|
||||
{
|
||||
if (!transacting) { transacting = true; db << "begin"; }
|
||||
ensureTransacting();
|
||||
|
||||
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) "
|
||||
"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" << supportedClaimId << name << nodeName
|
||||
<< outPoint.hash << outPoint.n << nAmount << nHeight << nValidHeight << expires << metadata;
|
||||
"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" << supportedClaimId << name << nodeName
|
||||
<< outPoint.hash << outPoint.n << nAmount << nHeight << nValidHeight << expires << metadata;
|
||||
|
||||
if (nValidHeight < nNextHeight)
|
||||
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)
|
||||
{
|
||||
if (!transacting) { transacting = true; db << "begin"; }
|
||||
ensureTransacting();
|
||||
|
||||
// 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)
|
||||
|
@ -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
|
||||
// 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 = ?"
|
||||
<< claimId << outPoint.hash << outPoint.n;
|
||||
auto query = db << "SELECT nodeName, validHeight FROM claims 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;
|
||||
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())
|
||||
return false;
|
||||
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
|
||||
// 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)
|
||||
auto workaroundQuery = db << "SELECT nodeName FROM claims WHERE nodeName LIKE ?1 "
|
||||
"AND validHeight < ?2 AND expirationHeight >= ?2 ORDER BY nodeName LIMIT 1"
|
||||
<< nodeName + "%" << nNextHeight;
|
||||
auto wit = workaroundQuery.begin();
|
||||
if (wit != workaroundQuery.end()) {
|
||||
std::string shortestMatch;
|
||||
*wit >> shortestMatch;
|
||||
if (shortestMatch != nodeName) {
|
||||
// set this when there are no more claims on that name and that node still has children
|
||||
removalWorkaround.insert(nodeName);
|
||||
}
|
||||
}
|
||||
db << "SELECT nodeName FROM claims WHERE nodeName LIKE ?1 "
|
||||
"AND validHeight < ?2 AND expirationHeight > ?2 ORDER BY nodeName LIMIT 1"
|
||||
<< nodeName + '%' << nNextHeight
|
||||
>> [this, &nodeName](const std::string& shortestMatch) {
|
||||
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;
|
||||
}
|
||||
|
||||
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 = ?"
|
||||
<< outPoint.hash << outPoint.n;
|
||||
auto query = db << "SELECT nodeName, validHeight FROM supports WHERE txID = ? AND txN = ? AND expirationHeight >= ?"
|
||||
<< outPoint.hash << outPoint.n << nNextHeight;
|
||||
auto it = query.begin();
|
||||
if (it == query.end()) return false;
|
||||
*it >> nodeName >> validHeight;
|
||||
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;
|
||||
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 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
|
||||
if (!transacting) { transacting = true; db << "begin"; }
|
||||
ensureTransacting();
|
||||
|
||||
db << "INSERT INTO nodes(name) SELECT nodeName FROM claims "
|
||||
"WHERE validHeight = ?1 AND expirationHeight > ?1 "
|
||||
|
@ -1117,11 +1125,11 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimUndoTy
|
|||
std::string name;
|
||||
row >> value.outPoint.hash >> value.outPoint.n >> name
|
||||
>> 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());
|
||||
{
|
||||
|
@ -1132,12 +1140,11 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimUndoTy
|
|||
std::string name;
|
||||
row >> value.outPoint.hash >> value.outPoint.n >> name
|
||||
>> 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 = ?)"
|
||||
<< nNextHeight;
|
||||
db << "UPDATE nodes SET hash = NULL WHERE name IN (SELECT nodeName FROM supports WHERE expirationHeight = ?)" << nNextHeight;
|
||||
|
||||
// takeover handling:
|
||||
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 hasCandidateQuery = db << "UPDATE nodes SET takeoverHeight = ?, takeoverID = ? WHERE name = ?";
|
||||
auto noCandidateQuery = db << "UPDATE nodes SET takeoverHeight = NULL, takeoverID = NULL WHERE name = ?";
|
||||
auto candidateQuery = db << "UPDATE nodes SET takeoverHeight = ?, takeoverID = ? WHERE name = ?";
|
||||
|
||||
for (const auto& nameWithTakeover : takeovers) {
|
||||
// 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) {
|
||||
takeoverUndo.emplace_back(nameWithTakeover, std::make_pair(existingHeight, hasBeenSetBefore ? *existingID : CUint160()));
|
||||
if (hasCandidate) {
|
||||
hasCandidateQuery << nNextHeight << candidateValue.claimId << nameWithTakeover;
|
||||
hasCandidateQuery++;
|
||||
}
|
||||
else {
|
||||
noCandidateQuery << nameWithTakeover;
|
||||
noCandidateQuery++;
|
||||
}
|
||||
if (hasCandidate)
|
||||
candidateQuery << nNextHeight << candidateValue.claimId << nameWithTakeover;
|
||||
else
|
||||
candidateQuery << nullptr << nullptr << nameWithTakeover;
|
||||
candidateQuery++;
|
||||
assert(db.rows_modified());
|
||||
}
|
||||
}
|
||||
|
||||
getTakeoverQuery.used(true);
|
||||
hasCandidateQuery.used(true);
|
||||
noCandidateQuery.used(true);
|
||||
candidateQuery.used(true);
|
||||
nNextHeight++;
|
||||
return true;
|
||||
}
|
||||
|
@ -1201,38 +1203,30 @@ bool CClaimTrieCacheBase::activateAllFor(insertUndoType& insertUndo, insertUndoT
|
|||
// now that we know a takeover is happening, we bring everybody in:
|
||||
auto ret = false;
|
||||
{
|
||||
auto query = db << "SELECT txID, txN, validHeight FROM claims WHERE nodeName = ?1 AND validHeight > ?2 AND expirationHeight > ?2"
|
||||
<< name << nNextHeight;
|
||||
for (auto &&row: query) {
|
||||
CUint256 hash;
|
||||
uint32_t n;
|
||||
int 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;
|
||||
}
|
||||
db << "SELECT txID, txN, validHeight FROM claims WHERE nodeName = ?1 AND validHeight > ?2 AND expirationHeight > ?2"
|
||||
<< name << nNextHeight
|
||||
>> [this, &insertUndo, &name](CUint256 txId, uint32_t n, int oldValidHeight) {
|
||||
CTxOutPoint outPoint(std::move(txId), n);
|
||||
logPrint << "Early activation of claim " << name << ", " << outPoint.ToString() << " at " << nNextHeight << Clog::endl;
|
||||
insertUndo.emplace_back(name, std::move(outPoint), oldValidHeight);
|
||||
};
|
||||
}
|
||||
// and then update them all to activate now:
|
||||
db << "UPDATE claims SET validHeight = ?1 WHERE nodeName = ?2 AND validHeight > ?1 AND expirationHeight > ?1"
|
||||
<< nNextHeight << name;
|
||||
db << "UPDATE claims SET validHeight = ?1 WHERE nodeName = ?2 AND validHeight > ?1 AND expirationHeight > ?1" << nNextHeight << name;
|
||||
ret |= db.rows_modified() > 0;
|
||||
|
||||
// then do the same for supports:
|
||||
{
|
||||
auto query = db << "SELECT txID, txN, validHeight FROM supports WHERE nodeName = ?1 AND validHeight > ?2 AND expirationHeight > ?2"
|
||||
<< name << nNextHeight;
|
||||
for (auto &&row: query) {
|
||||
CUint256 hash;
|
||||
uint32_t n;
|
||||
int 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;
|
||||
}
|
||||
db << "SELECT txID, txN, validHeight FROM supports WHERE nodeName = ?1 AND validHeight > ?2 AND expirationHeight > ?2"
|
||||
<< name << nNextHeight
|
||||
>> [this, &insertSupportUndo, &name](CUint256 txId, uint32_t n, int oldValidHeight) {
|
||||
CTxOutPoint outPoint(std::move(txId), n);
|
||||
logPrint << "Early activation of support " << name << ", " << outPoint.ToString() << " at " << nNextHeight << Clog::endl;
|
||||
insertSupportUndo.emplace_back(name, std::move(outPoint), oldValidHeight);
|
||||
};
|
||||
}
|
||||
// and then update them all to activate now:
|
||||
db << "UPDATE supports SET validHeight = ?1 WHERE nodeName = ?2 AND validHeight > ?1 AND expirationHeight > ?1"
|
||||
<< nNextHeight << name;
|
||||
db << "UPDATE supports SET validHeight = ?1 WHERE nodeName = ?2 AND validHeight > ?1 AND expirationHeight > ?1" << nNextHeight << name;
|
||||
ret |= db.rows_modified() > 0;
|
||||
return ret;
|
||||
}
|
||||
|
@ -1240,32 +1234,32 @@ bool CClaimTrieCacheBase::activateAllFor(insertUndoType& insertUndo, insertUndoT
|
|||
bool CClaimTrieCacheBase::decrementBlock(insertUndoType& insertUndo, claimUndoType& expireUndo,
|
||||
insertUndoType& insertSupportUndo, supportUndoType& expireSupportUndo)
|
||||
{
|
||||
if (!transacting) { transacting = true; db << "begin"; }
|
||||
ensureTransacting();
|
||||
|
||||
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
|
||||
// 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 << "INSERT INTO nodes(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET hash = NULL" << it->first;
|
||||
}
|
||||
for (auto it = expireSupportUndo.crbegin(); it != expireSupportUndo.crend(); ++it)
|
||||
db << updateNodes << it->first;
|
||||
|
||||
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;
|
||||
}
|
||||
for (auto it = expireUndo.crbegin(); it != expireUndo.crend(); ++it)
|
||||
db << updateNodes << it->first;
|
||||
|
||||
for (auto it = insertSupportUndo.crbegin(); it != insertSupportUndo.crend(); ++it) {
|
||||
logPrint << "Resetting support valid height to " << it->nValidHeight << " for " << it->name << Clog::endl;
|
||||
db << "UPDATE supports SET validHeight = ? WHERE txID = ? AND txN = ?"
|
||||
<< 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) {
|
||||
logPrint << "Resetting valid height to " << it->nValidHeight << " for " << it->name << Clog::endl;
|
||||
db << "UPDATE claims SET validHeight = ? WHERE nodeName = ? AND txID = ? AND txN = ?"
|
||||
<< 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;
|
||||
|
@ -1278,12 +1272,13 @@ bool CClaimTrieCacheBase::finalizeDecrement(takeoverUndoType& takeoverUndo)
|
|||
db << "UPDATE nodes SET hash = NULL WHERE name IN "
|
||||
"(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) {
|
||||
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
|
||||
db << "UPDATE nodes SET takeoverHeight = ?, takeoverID = ?, hash = NULL WHERE name = ?"
|
||||
<< it->second.first << it->second.second << it->first;
|
||||
db << updateNodes << it->second.first << it->second.second << it->first;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1319,11 +1314,7 @@ bool CClaimTrieCacheBase::getProofForName(const std::string& name, const CUint16
|
|||
// cache the parent nodes
|
||||
getMerkleHash();
|
||||
proof = CClaimTrieProof();
|
||||
auto nodeQuery = db << "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" << name;
|
||||
for (auto&& row: nodeQuery) {
|
||||
for (auto&& row: db << proofClaimQuery << name) {
|
||||
CClaimValue claim;
|
||||
std::string key;
|
||||
int takeoverHeight;
|
||||
|
@ -1371,7 +1362,7 @@ bool CClaimTrieCacheBase::findNameForClaim(std::vector<unsigned char> claim, CCl
|
|||
{
|
||||
std::reverse(claim.begin(), claim.end());
|
||||
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;
|
||||
auto hit = false;
|
||||
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
|
||||
{
|
||||
auto query = db << "SELECT DISTINCT nodeName FROM claims WHERE validHeight < ? AND expirationHeight >= ?"
|
||||
<< nNextHeight << nNextHeight;
|
||||
for (auto&& row: query) {
|
||||
std::string name;
|
||||
row >> name;
|
||||
callback(name);
|
||||
}
|
||||
db << "SELECT DISTINCT nodeName FROM claims WHERE validHeight < ? AND expirationHeight >= ?"
|
||||
<< nNextHeight << nNextHeight
|
||||
>> [&callback](const std::string& name) {
|
||||
callback(name);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -130,10 +130,10 @@ public:
|
|||
bool findNameForClaim(std::vector<unsigned char> claim, CClaimValue& value, std::string& name) const;
|
||||
|
||||
protected:
|
||||
int nNextHeight; // Height of the block that is being worked on, which is
|
||||
CClaimTrie* base;
|
||||
mutable sqlite::database db;
|
||||
int nNextHeight; // Height of the block that is being worked on, which is
|
||||
bool transacting;
|
||||
const std::string proofClaimQuery;
|
||||
mutable std::unordered_set<std::string> removalWorkaround;
|
||||
|
||||
mutable sqlite::database_binder claimHashQuery, childHashQuery;
|
||||
|
@ -145,8 +145,10 @@ protected:
|
|||
|
||||
bool deleteNodeIfPossible(const std::string& name, std::string& parent, int64_t& claims);
|
||||
void ensureTreeStructureIsUpToDate();
|
||||
void ensureTransacting();
|
||||
|
||||
private:
|
||||
bool transacting;
|
||||
// for unit test
|
||||
friend struct ClaimTrieChainFixture;
|
||||
friend class CClaimTrieCacheTest;
|
||||
|
|
|
@ -140,11 +140,14 @@ BOOST_AUTO_TEST_CASE(hardfork_claim_test)
|
|||
// Ensure that we cannot update the original pre-fork expired claim
|
||||
CMutableTransaction u1 = fixture.MakeUpdate(tx1,"test","two",ClaimIdHash(tx1.GetHash(),0), 3);
|
||||
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
|
||||
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
|
||||
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
|
||||
CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(),u2,"test",3);
|
||||
fixture.IncrementBlocks(1);
|
||||
BOOST_CHECK(fixture.is_best_claim("test",u2));
|
||||
}
|
||||
|
||||
|
|
|
@ -401,7 +401,8 @@ boost::test_tools::predicate_result ClaimTrieChainFixture::best_claim_effective_
|
|||
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 "
|
||||
"FROM claims WHERE claimID = ?" << claimId;
|
||||
auto hit = false;
|
||||
|
@ -414,7 +415,8 @@ bool ClaimTrieChainFixture::getClaimById(const uint160 &claimId, std::string &na
|
|||
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;
|
||||
for (auto&& row: db << "SELECT name FROM nodes WHERE parent = ?" << name) {
|
||||
ret.emplace_back();
|
||||
|
|
|
@ -105,7 +105,7 @@ struct ClaimTrieChainFixture: public CClaimTrieCache
|
|||
|
||||
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
|
||||
boost::test_tools::predicate_result is_claim_in_queue(const std::string& name, const CTransaction &tx);
|
||||
|
|
Loading…
Reference in a new issue