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)
|
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;
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue