Don't call lsn_reset at periodic time #360

Closed
bvbfan wants to merge 75 commits from lsn_reset into master
5 changed files with 162 additions and 109 deletions
Showing only changes of commit dfc5ebf3f6 - Show all commits

View file

@ -14,12 +14,17 @@ CClaimScriptAddOp::CClaimScriptAddOp(const COutPoint& point, CAmount nValue, int
bool CClaimScriptAddOp::claimName(CClaimTrieCache& trieCache, const std::string& name, bool CClaimScriptAddOp::claimName(CClaimTrieCache& trieCache, const std::string& name,
const std::vector<unsigned char>& metadata) const std::vector<unsigned char>& metadata)
{ {
return addClaim(trieCache, name, ClaimIdHash(point.hash, point.n), -1, metadata); auto claimId = ClaimIdHash(point.hash, point.n);
LogPrint(BCLog::CLAIMS, "+++ Claim added: %s, c: %.6s, t: %.6s:%d, h: %.6d, a: %du\n",
name, claimId.GetHex(), point.hash.GetHex(), point.n, nHeight, nValue);
return addClaim(trieCache, name, claimId, -1, metadata);
} }
bool CClaimScriptAddOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId, bool CClaimScriptAddOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
const std::vector<unsigned char>& metadata) const std::vector<unsigned char>& metadata)
{ {
LogPrint(BCLog::CLAIMS, "+++ Claim updated: %s, c: %.6s, t: %.6s:%d, h: %.6d, a: %du\n",
name, claimId.GetHex(), point.hash.GetHex(), point.n, nHeight, nValue);
return addClaim(trieCache, name, claimId, -1, metadata); return addClaim(trieCache, name, claimId, -1, metadata);
} }
@ -32,6 +37,8 @@ bool CClaimScriptAddOp::addClaim(CClaimTrieCache& trieCache, const std::string&
bool CClaimScriptAddOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId, bool CClaimScriptAddOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
const std::vector<unsigned char>& metadata) const std::vector<unsigned char>& metadata)
{ {
LogPrint(BCLog::CLAIMS, "+++ Support added: %s, c: %.6s, t: %.6s:%d, h: %.6d, a: %du\n",
name, claimId.GetHex(), point.hash.GetHex(), point.n, nHeight, nValue);
return trieCache.addSupport(name, point, nValue, claimId, nHeight, -1, metadata); return trieCache.addSupport(name, point, nValue, claimId, nHeight, -1, metadata);
} }
@ -43,14 +50,16 @@ bool CClaimScriptUndoAddOp::claimName(CClaimTrieCache& trieCache, const std::str
const std::vector<unsigned char>& metadata) const std::vector<unsigned char>& metadata)
{ {
auto claimId = ClaimIdHash(point.hash, point.n); auto claimId = ClaimIdHash(point.hash, point.n);
LogPrint(BCLog::CLAIMS, "--- [%lu]: Undoing OP_CLAIM_NAME \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name, claimId.GetHex(), point.hash.ToString(), point.n); LogPrint(BCLog::CLAIMS, "--- Undoing claim add: %s, c: %.6s, t: %.6s:%d, h: %.6d\n",
name, claimId.GetHex(), point.hash.GetHex(), point.n, nHeight);
return undoAddClaim(trieCache, name, claimId); return undoAddClaim(trieCache, name, claimId);
} }
bool CClaimScriptUndoAddOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId, bool CClaimScriptUndoAddOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
const std::vector<unsigned char>& metadata) const std::vector<unsigned char>& metadata)
{ {
LogPrint(BCLog::CLAIMS, "--- [%lu]: Undoing OP_UPDATE_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name, claimId.GetHex(), point.hash.ToString(), point.n); LogPrint(BCLog::CLAIMS, "--- Undoing claim update: %s, c: %.6s, t: %.6s:%d, h: %.6d\n",
name, claimId.GetHex(), point.hash.GetHex(), point.n, nHeight);
return undoAddClaim(trieCache, name, claimId); return undoAddClaim(trieCache, name, claimId);
} }
@ -60,22 +69,20 @@ bool CClaimScriptUndoAddOp::undoAddClaim(CClaimTrieCache& trieCache, const std::
int validHeight; int validHeight;
bool res = trieCache.removeClaim(claimId, point, nodeName, validHeight); bool res = trieCache.removeClaim(claimId, point, nodeName, validHeight);
if (!res) if (!res)
LogPrint(BCLog::CLAIMS, "%s: Removing claim fails\n", __func__); LogPrint(BCLog::CLAIMS, "Remove claim failed for %s with claimid %s\n", name, claimId.GetHex().substr(0, 6));
return res; return res;
} }
bool CClaimScriptUndoAddOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId, bool CClaimScriptUndoAddOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
const std::vector<unsigned char>& metadata) const std::vector<unsigned char>& metadata)
{ {
if (LogAcceptCategory(BCLog::CLAIMS)) { LogPrint(BCLog::CLAIMS, "--- Undoing support add: %s, c: %.6s, t: %.6s:%d, h: %.6d\n",
LogPrintf("--- [%lu]: Undoing OP_SUPPORT_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name, name, claimId.GetHex(), point.hash.GetHex(), point.n, nHeight);
claimId.GetHex(), point.hash.ToString(), point.n);
}
std::string nodeName; std::string nodeName;
int validHeight; int validHeight;
bool res = trieCache.removeSupport(point, nodeName, validHeight); bool res = trieCache.removeSupport(point, nodeName, validHeight);
if (!res) if (!res)
LogPrint(BCLog::CLAIMS, "%s: Removing support fails\n", __func__); LogPrint(BCLog::CLAIMS, "Remove support failed for %s with claimid %s\n", name, claimId.GetHex().substr(0, 6));
return res; return res;
} }
@ -88,15 +95,19 @@ bool CClaimScriptSpendOp::claimName(CClaimTrieCache& trieCache, const std::strin
const std::vector<unsigned char>& metadata) const std::vector<unsigned char>& metadata)
{ {
auto claimId = ClaimIdHash(point.hash, point.n); auto claimId = ClaimIdHash(point.hash, point.n);
LogPrint(BCLog::CLAIMS, "+++ [%lu]: Spending OP_CLAIM_NAME \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name, claimId.GetHex(), point.hash.ToString(), point.n); auto ret = spendClaim(trieCache, name, claimId);
return spendClaim(trieCache, name, claimId); LogPrint(BCLog::CLAIMS, "--- Spending original claim: %s, c: %.6s, t: %.6s:%d, h: %.6d, vh: %d\n",
name, claimId.GetHex(), point.hash.GetHex(), point.n, nHeight, nValidHeight);
return ret;
} }
bool CClaimScriptSpendOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId, bool CClaimScriptSpendOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
const std::vector<unsigned char>& metadata) const std::vector<unsigned char>& metadata)
{ {
LogPrint(BCLog::CLAIMS, "+++ [%lu]: Spending OP_UPDATE_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name, claimId.GetHex(), point.hash.ToString(), point.n); auto ret = spendClaim(trieCache, name, claimId);
return spendClaim(trieCache, name, claimId); LogPrint(BCLog::CLAIMS, "--- Spending updated claim: %s, c: %.6s, t: %.6s:%d, h: %.6d, vh: %d\n",
name, claimId.GetHex(), point.hash.GetHex(), point.n, nHeight, nValidHeight);
return ret;
} }
bool CClaimScriptSpendOp::spendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) bool CClaimScriptSpendOp::spendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
@ -104,21 +115,19 @@ bool CClaimScriptSpendOp::spendClaim(CClaimTrieCache& trieCache, const std::stri
std::string nodeName; std::string nodeName;
bool res = trieCache.removeClaim(claimId, point, nodeName, nValidHeight); bool res = trieCache.removeClaim(claimId, point, nodeName, nValidHeight);
if (!res) if (!res)
LogPrint(BCLog::CLAIMS, "%s: Removing fails\n", __func__); LogPrint(BCLog::CLAIMS, "Remove claim failed for %s with claimid %s\n", name, claimId.GetHex().substr(0, 6));
return res; return res;
} }
bool CClaimScriptSpendOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId, bool CClaimScriptSpendOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
const std::vector<unsigned char>& metadata) const std::vector<unsigned char>& metadata)
{ {
if (LogAcceptCategory(BCLog::CLAIMS)) {
LogPrintf("+++ [%lu]: Spending OP_SUPPORT_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name,
claimId.GetHex(), point.hash.ToString(), point.n);
}
std::string nodeName; std::string nodeName;
bool res = trieCache.removeSupport(point, nodeName, nValidHeight); bool res = trieCache.removeSupport(point, nodeName, nValidHeight);
LogPrint(BCLog::CLAIMS, "--- Spending support: %s, c: %.6s, t: %.6s:%d, h: %.6d, vh: %d\n",
name, claimId.GetHex(), point.hash.GetHex(), point.n, nHeight, nValidHeight);
if (!res) if (!res)
LogPrint(BCLog::CLAIMS, "%s: Removing support fails\n", __func__); LogPrint(BCLog::CLAIMS, "Remove support failed for %s with claimid %s\n", name, claimId.GetHex().substr(0, 6));
return res; return res;
} }
@ -130,26 +139,31 @@ CClaimScriptUndoSpendOp::CClaimScriptUndoSpendOp(const COutPoint& point, CAmount
bool CClaimScriptUndoSpendOp::claimName(CClaimTrieCache& trieCache, const std::string& name, bool CClaimScriptUndoSpendOp::claimName(CClaimTrieCache& trieCache, const std::string& name,
const std::vector<unsigned char>& metadata) const std::vector<unsigned char>& metadata)
{ {
return undoSpendClaim(trieCache, name, ClaimIdHash(point.hash, point.n), metadata); auto claimId = ClaimIdHash(point.hash, point.n);
LogPrint(BCLog::CLAIMS, "+++ Undoing original claim spend: %s, c: %.6s, t: %.6s:%d, h: %.6d, vh: %d\n",
name, claimId.GetHex(), point.hash.GetHex(), point.n, nHeight, nValidHeight);
return undoSpendClaim(trieCache, name, claimId, metadata);
} }
bool CClaimScriptUndoSpendOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId, bool CClaimScriptUndoSpendOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
const std::vector<unsigned char>& metadata) const std::vector<unsigned char>& metadata)
{ {
LogPrint(BCLog::CLAIMS, "+++ Undoing updated claim spend: %s, c: %.6s, t: %.6s:%d, h: %.6d, vh: %d\n",
name, claimId.GetHex(), point.hash.GetHex(), point.n, nHeight, nValidHeight);
return undoSpendClaim(trieCache, name, claimId, metadata); return undoSpendClaim(trieCache, name, claimId, metadata);
} }
bool CClaimScriptUndoSpendOp::undoSpendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId, bool CClaimScriptUndoSpendOp::undoSpendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
const std::vector<unsigned char>& metadata) const std::vector<unsigned char>& metadata)
{ {
LogPrint(BCLog::CLAIMS, "%s: (txid: %s, nOut: %d) Undoing spend of %s, claimId: %s, to the claim trie due to block disconnect\n", __func__, point.hash.ToString(), point.n, name, claimId.ToString());
return trieCache.addClaim(name, point, claimId, nValue, nHeight, nValidHeight, metadata); return trieCache.addClaim(name, point, claimId, nValue, nHeight, nValidHeight, metadata);
} }
bool CClaimScriptUndoSpendOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId, bool CClaimScriptUndoSpendOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
const std::vector<unsigned char>& metadata) const std::vector<unsigned char>& metadata)
{ {
LogPrint(BCLog::CLAIMS, "%s: (txid: %s, nOut: %d) Restoring support for %s, claimId: %s, to the claim trie due to block disconnect\n", __func__, point.hash.ToString(), point.n, name, claimId.ToString()); LogPrint(BCLog::CLAIMS, "+++ Undoing support spend: %s, c: %.6s, t: %.6s:%d, h: %.6d, vh: %d\n",
name, claimId.GetHex(), point.hash.GetHex(), point.n, nHeight, nValidHeight);
return trieCache.addSupport(name, point, nValue, claimId, nHeight, nValidHeight, metadata); return trieCache.addSupport(name, point, nValue, claimId, nHeight, nValidHeight, metadata);
} }
@ -233,7 +247,7 @@ void UpdateCache(const CTransaction& tx, CClaimTrieCache& trieCache, const CCoin
const std::vector<unsigned char>& metadata) override const std::vector<unsigned char>& metadata) override
{ {
if (callback(name, claimId)) if (callback(name, claimId))
return CClaimScriptAddOp::addClaim(trieCache, name, claimId, -1, metadata); return CClaimScriptAddOp::updateClaim(trieCache, name, claimId, metadata);
return false; return false;
} }
std::function<bool(const std::string& name, const uint160& claimId)> callback; std::function<bool(const std::string& name, const uint160& claimId)> callback;

View file

@ -56,7 +56,8 @@ CClaimTrie::CClaimTrie(bool fWipe, int height, int proportionalDelayFactor)
// db.define("MERKLE_PAIR", [](const std::vector<unsigned char>& blob1, const std::vector<unsigned char>& blob2) { return Hash(blob1.begin(), blob1.end(), blob2.begin(), blob2.end()); }); // db.define("MERKLE_PAIR", [](const std::vector<unsigned char>& blob1, const std::vector<unsigned char>& blob2) { return Hash(blob1.begin(), blob1.end(), blob2.begin(), blob2.end()); });
// db.define("MERKLE", [](const std::vector<unsigned char>& blob1) { return Hash(blob1.begin(), blob1.end()); }); // db.define("MERKLE", [](const std::vector<unsigned char>& blob1) { return Hash(blob1.begin(), blob1.end()); });
db << "CREATE TABLE IF NOT EXISTS nodes (name TEXT NOT NULL PRIMARY KEY, parent TEXT, hash BLOB COLLATE BINARY, takeoverHeight INTEGER, takeoverID BLOB COLLATE BINARY)"; db << "CREATE TABLE IF NOT EXISTS nodes (name TEXT NOT NULL PRIMARY KEY, parent TEXT REFERENCES nodes(name) DEFERRABLE INITIALLY DEFERRED, "
"hash BLOB COLLATE BINARY, takeoverHeight INTEGER, takeoverID BLOB COLLATE BINARY)";
db << "CREATE INDEX IF NOT EXISTS nodes_hash ON nodes (hash)"; db << "CREATE INDEX IF NOT EXISTS nodes_hash ON nodes (hash)";
db << "CREATE INDEX IF NOT EXISTS nodes_parent ON nodes (parent)"; db << "CREATE INDEX IF NOT EXISTS nodes_parent ON nodes (parent)";
@ -109,23 +110,23 @@ bool CClaimTrie::SyncToDisk()
bool CClaimTrie::empty() { bool CClaimTrie::empty() {
int64_t count; int64_t count;
db << "SELECT COUNT(*) FROM claims WHERE validHeight < ? AND expirationHeight >= ?" << nNextHeight << nNextHeight >> count; db << "SELECT COUNT(*) FROM claims WHERE validHeight < ?1 AND expirationHeight >= ?1" << nNextHeight >> count;
return count == 0; return count == 0;
} }
bool CClaimTrieCacheBase::haveClaim(const std::string& name, const COutPoint& outPoint) const bool CClaimTrieCacheBase::haveClaim(const std::string& name, const COutPoint& outPoint) const
{ {
auto query = db << "SELECT 1 FROM claims WHERE nodeName = ? AND txID = ? AND txN = ? " auto query = db << "SELECT 1 FROM claims WHERE nodeName = ?1 AND txID = ?2 AND txN = ?3 "
"AND validHeight < ? AND expirationHeight >= ? LIMIT 1" "AND validHeight < ?4 AND expirationHeight >= ?4 LIMIT 1"
<< name << outPoint.hash << outPoint.n << nNextHeight << nNextHeight; << name << outPoint.hash << outPoint.n << nNextHeight;
return query.begin() != query.end(); return query.begin() != query.end();
} }
bool CClaimTrieCacheBase::haveSupport(const std::string& name, const COutPoint& outPoint) const bool CClaimTrieCacheBase::haveSupport(const std::string& name, const COutPoint& outPoint) const
{ {
auto query = db << "SELECT 1 FROM supports WHERE nodeName = ? AND txID = ? AND txN = ? " auto query = db << "SELECT 1 FROM supports WHERE nodeName = ?1 AND txID = ?2 AND txN = ?3 "
"AND validHeight < ? AND expirationHeight >= ? LIMIT 1" "AND validHeight < ?4 AND expirationHeight >= ?4 LIMIT 1"
<< name << outPoint.hash << outPoint.n << nNextHeight << nNextHeight; << name << outPoint.hash << outPoint.n << nNextHeight;
return query.begin() != query.end(); return query.begin() != query.end();
} }
@ -181,8 +182,8 @@ 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
vector_builder<std::string, std::string> claimsBuilder; vector_builder<std::string, std::string> claimsBuilder;
db << "SELECT name FROM claims WHERE nodeName = ? AND validHeight < ? AND expirationHeight >= ? " db << "SELECT name FROM claims WHERE nodeName = ?1 AND validHeight < ?2 AND expirationHeight >= ?2 "
<< name << nNextHeight << nNextHeight >> claimsBuilder; << name << nNextHeight >> claimsBuilder;
claims = std::move(claimsBuilder); claims = std::move(claimsBuilder);
if (!claims.empty()) return false; // still has claims if (!claims.empty()) 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
@ -193,6 +194,7 @@ bool CClaimTrieCacheBase::deleteNodeIfPossible(const std::string& name, std::str
// alternately: SELECT COUNT(DISTINCT nodeName) FROM claims WHERE SUBSTR(nodeName, 1, len(?)) == ? AND LENGTH(nodeName) > len(?) // 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(BCLog::CLAIMS, "Removing node %s with %d children\n", name, count);
// okay. it's going away // okay. it's going away
auto query = db << "SELECT parent FROM nodes WHERE name = ?" << name; auto query = db << "SELECT parent FROM nodes WHERE name = ?" << name;
auto it = query.begin(); auto it = query.begin();
@ -271,6 +273,7 @@ void CClaimTrieCacheBase::ensureTreeStructureIsUpToDate() {
break; break;
} }
// insert the split node: // insert the split node:
LogPrint(BCLog::CLAIMS, "Inserting split node %s, parent %s\n", newNodeName, parent);
db << "INSERT INTO nodes(name, parent, hash) VALUES(?, ?, NULL) " db << "INSERT INTO nodes(name, parent, hash) VALUES(?, ?, NULL) "
"ON CONFLICT(name) DO UPDATE SET parent = excluded.parent, hash = NULL" "ON CONFLICT(name) DO UPDATE SET parent = excluded.parent, hash = NULL"
<< newNodeName << parent; << newNodeName << parent;
@ -279,11 +282,15 @@ void CClaimTrieCacheBase::ensureTreeStructureIsUpToDate() {
} }
} }
LogPrint(BCLog::CLAIMS, "Inserting or updating node %s, parent %s\n", name, parent);
db << "INSERT INTO nodes(name, parent, hash) VALUES(?, ?, NULL) " db << "INSERT INTO nodes(name, parent, hash) VALUES(?, ?, NULL) "
"ON CONFLICT(name) DO UPDATE SET parent = excluded.parent, hash = NULL" "ON CONFLICT(name) DO UPDATE SET parent = excluded.parent, hash = NULL"
<< name << parent; << name << parent;
if (splitPos == 0) if (splitPos == 0)
db << "UPDATE nodes SET hash = NULL WHERE name = ?" << parent; db << "UPDATE nodes SET hash = NULL WHERE name = ?" << parent;
db << "UPDATE nodes SET parent = ?1 WHERE SUBSTR(name, 1, ?2) = ?1 AND LENGTH(parent) < ?2 AND name != ?1"
<< name << name.size();
} }
// now we need to percolate the nulls up the tree // now we need to percolate the nulls up the tree
@ -297,16 +304,16 @@ 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 < ? AND expirationHeight >= ?" db << "SELECT COUNT(DISTINCT nodeName) FROM claims WHERE validHeight < ?1 AND expirationHeight >= ?1"
<< nNextHeight << nNextHeight >> ret; << nNextHeight >> ret;
return ret; return ret;
} }
std::size_t CClaimTrieCacheBase::getTotalClaimsInTrie() const std::size_t CClaimTrieCacheBase::getTotalClaimsInTrie() const
{ {
std::size_t ret; std::size_t ret;
db << "SELECT COUNT(*) FROM claims WHERE validHeight < ? AND expirationHeight >= ?" db << "SELECT COUNT(*) FROM claims WHERE validHeight < ?1 AND expirationHeight >= ?1"
<< nNextHeight << nNextHeight >> ret; << nNextHeight >> ret;
return ret; return ret;
} }
@ -314,28 +321,26 @@ CAmount CClaimTrieCacheBase::getTotalValueOfClaimsInTrie(bool fControllingOnly)
{ {
CAmount ret = 0; CAmount ret = 0;
std::string query("SELECT (SELECT TOTAL(s.amount)+c.amount FROM supports s " std::string query("SELECT (SELECT TOTAL(s.amount)+c.amount FROM supports s "
"WHERE s.supportedClaimID = c.claimID AND s.validHeight < ? AND s.expirationHeight >= ?) " "WHERE s.supportedClaimID = c.claimID AND s.validHeight < ?1 AND s.expirationHeight >= ?1) "
"FROM claims c WHERE c.validHeight < ? AND s.expirationHeight >= ?"); "FROM claims c WHERE c.validHeight < ?1 AND s.expirationHeight >= ?1");
if (fControllingOnly) if (fControllingOnly)
throw std::runtime_error("not implemented yet"); // TODO: finish this throw std::runtime_error("not implemented yet"); // TODO: finish this
db << query << nNextHeight << nNextHeight << nNextHeight << nNextHeight >> ret; db << query << nNextHeight >> ret;
return ret; return ret;
} }
bool CClaimTrieCacheBase::getInfoForName(const std::string& name, CClaimValue& claim, int heightOffset) const bool CClaimTrieCacheBase::getInfoForName(const std::string& name, CClaimValue& claim, int heightOffset) const
{ {
auto nextHeight = nNextHeight + heightOffset; auto nextHeight = nNextHeight + heightOffset;
auto query = db << "SELECT c.claimID, c.txID, c.txN, c.blockHeight, c.validHeight, c.amount, " auto ret = false;
"(SELECT TOTAL(s.amount)+c.amount FROM supports s WHERE s.supportedClaimID = c.claimID AND s.validHeight < ? AND s.expirationHeight >= ?) as effectiveAmount " for (auto&& row: claimHashQuery << nextHeight << name) {
"FROM claims c WHERE c.nodeName = ? AND c.validHeight < ? AND c.expirationHeight >= ? " row >> claim.outPoint.hash >> claim.outPoint.n >> claim.claimId
"ORDER BY effectiveAmount DESC, c.blockHeight, REVERSE_BYTES(c.txID), c.txN LIMIT 1"
<< nextHeight << nextHeight << name << nextHeight << nextHeight;
for (auto&& row: query) {
row >> claim.claimId >> claim.outPoint.hash >> claim.outPoint.n
>> claim.nHeight >> claim.nValidAtHeight >> claim.nAmount >> claim.nEffectiveAmount; >> claim.nHeight >> claim.nValidAtHeight >> claim.nAmount >> claim.nEffectiveAmount;
return true; ret = true;
break;
} }
return false; claimHashQuery++;
return ret;
} }
CClaimSupportToName CClaimTrieCacheBase::getClaimsForName(const std::string& name) const CClaimSupportToName CClaimTrieCacheBase::getClaimsForName(const std::string& name) const
@ -398,19 +403,23 @@ uint256 CClaimTrieCacheBase::recursiveComputeMerkleHash(const std::string& name,
{ {
std::vector<uint8_t> vchToHash; std::vector<uint8_t> vchToHash;
const auto pos = name.size(); const auto pos = name.size();
auto query = db << "SELECT name, hash, IFNULL(takeoverHeight,0) FROM nodes WHERE parent = ? ORDER BY name" << name; // we have to free up the hash query so it can be reused by a child
for (auto&& row : query) { struct Triple { std::string name; std::unique_ptr<uint256> hash; int takeoverHeight; };
std::string key; std::vector<Triple> children;
int childTakeoverHeight; for (auto&& row : childHashQuery << name) {
std::unique_ptr<uint256> hash; children.emplace_back();
row >> key >> hash >> childTakeoverHeight; auto& b = children.back();
if (hash == nullptr) hash = std::make_unique<uint256>(); row >> b.name >> b.hash >> b.takeoverHeight;
if (hash->IsNull()) {
*hash = recursiveComputeMerkleHash(key, childTakeoverHeight, checkOnly);
} }
completeHash(*hash, key, pos); childHashQuery++;
vchToHash.push_back(key[pos]); for (auto& child: children) {
vchToHash.insert(vchToHash.end(), hash->begin(), hash->end()); if (child.hash == nullptr) child.hash = std::make_unique<uint256>();
if (child.hash->IsNull()) {
*child.hash = recursiveComputeMerkleHash(child.name, child.takeoverHeight, checkOnly);
}
completeHash(*child.hash, child.name, pos);
vchToHash.push_back(child.name[pos]);
vchToHash.insert(vchToHash.end(), child.hash->begin(), child.hash->end());
} }
CClaimValue claim; CClaimValue claim;
@ -488,7 +497,13 @@ bool CClaimTrieCacheBase::ValidateTipMatches(const CBlockIndex* tip)
} }
CClaimTrieCacheBase::CClaimTrieCacheBase(CClaimTrie* base) CClaimTrieCacheBase::CClaimTrieCacheBase(CClaimTrie* base)
: base(base), db(base->dbPath, sharedConfig), transacting(false) : base(base), db(base->dbPath, 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 TOTAL(s.amount)+c.amount FROM supports s WHERE s.supportedClaimID = c.claimID "
"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")
{ {
assert(base); assert(base);
nNextHeight = base->nNextHeight; nNextHeight = base->nNextHeight;
@ -498,8 +513,6 @@ CClaimTrieCacheBase::CClaimTrieCacheBase(CClaimTrie* base)
db << "PRAGMA journal_mode=MEMORY"; db << "PRAGMA journal_mode=MEMORY";
db << "PRAGMA temp_store=MEMORY"; db << "PRAGMA temp_store=MEMORY";
db << "PRAGMA case_sensitive_like=true"; db << "PRAGMA case_sensitive_like=true";
db.define("REVERSE_BYTES", [](std::vector<unsigned char> blob) { std::reverse(blob.begin(), blob.end()); return blob; });
} }
int CClaimTrieCacheBase::expirationTime() const int CClaimTrieCacheBase::expirationTime() const
@ -512,6 +525,7 @@ uint256 CClaimTrieCacheBase::getMerkleHash()
ensureTreeStructureIsUpToDate(); ensureTreeStructureIsUpToDate();
std::unique_ptr<uint256> hash; std::unique_ptr<uint256> hash;
int takeoverHeight; int takeoverHeight;
// can't use childHashQuery here because "IS NULL" must be used instead of parent = NULL
db << "SELECT hash, IFNULL(takeoverHeight, 0) FROM nodes WHERE name = ''" >> std::tie(hash, takeoverHeight); db << "SELECT hash, IFNULL(takeoverHeight, 0) FROM nodes WHERE name = ''" >> std::tie(hash, takeoverHeight);
if (hash == nullptr || hash->IsNull()) { if (hash == nullptr || hash->IsNull()) {
assert(transacting); // no data changed but we didn't have the root hash there already? assert(transacting); // no data changed but we didn't have the root hash there already?
@ -592,6 +606,8 @@ bool CClaimTrieCacheBase::removeClaim(const uint160& claimId, const COutPoint& o
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())
return false;
db << "UPDATE nodes SET hash = NULL WHERE name = ?" << nodeName; db << "UPDATE nodes SET hash = NULL WHERE name = ?" << nodeName;
return true; return true;
} }
@ -946,6 +962,9 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimUndoTy
// takeover handling: // takeover handling:
vector_builder<std::string, std::string> takeovers; vector_builder<std::string, std::string> takeovers;
db << "SELECT name FROM nodes WHERE hash IS NULL" >> takeovers; db << "SELECT name FROM nodes WHERE hash IS NULL" >> takeovers;
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 = ?";
for (const auto& nameWithTakeover : takeovers) { for (const auto& nameWithTakeover : takeovers) {
auto needsActivate = false; auto needsActivate = false;
@ -960,21 +979,26 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimUndoTy
// now that they're all in get the winner: // now that they're all in get the winner:
int existingHeight; int existingHeight;
std::unique_ptr<uint160> existingID; std::unique_ptr<uint160> existingID;
db << "SELECT IFNULL(takeoverHeight, 0), takeoverID FROM nodes WHERE name = ?" getTakeoverQuery << nameWithTakeover >> std::tie(existingHeight, existingID);
<< nameWithTakeover >> std::tie(existingHeight, existingID); getTakeoverQuery++; // reset it
auto hasBeenSetBefore = existingID != nullptr && !existingID->IsNull(); auto hasBeenSetBefore = existingID != nullptr && !existingID->IsNull();
auto takeoverHappening = needsActivate || !hasCandidate || (hasBeenSetBefore && *existingID != candidateValue.claimId); auto takeoverHappening = needsActivate || !hasCandidate || (hasBeenSetBefore && *existingID != candidateValue.claimId);
if (takeoverHappening && activateAllFor(insertUndo, insertSupportUndo, nameWithTakeover)) if (takeoverHappening && activateAllFor(insertUndo, insertSupportUndo, nameWithTakeover))
hasCandidate = getInfoForName(nameWithTakeover, candidateValue, 1); hasCandidate = getInfoForName(nameWithTakeover, candidateValue, 1);
LogPrint(BCLog::CLAIMS, "Takeover on %s at %d, happening: %d, set before: %d\n", nameWithTakeover, nNextHeight, takeoverHappening, hasBeenSetBefore);
if (takeoverHappening || !hasBeenSetBefore) { if (takeoverHappening || !hasBeenSetBefore) {
takeoverUndo.emplace_back(nameWithTakeover, std::make_pair(existingHeight, hasBeenSetBefore ? *existingID : uint160())); takeoverUndo.emplace_back(nameWithTakeover, std::make_pair(existingHeight, hasBeenSetBefore ? *existingID : uint160()));
if (hasCandidate) if (hasCandidate) {
db << "UPDATE nodes SET takeoverHeight = ?, takeoverID = ? WHERE name = ?" hasCandidateQuery << nNextHeight << candidateValue.claimId << nameWithTakeover;
<< nNextHeight << candidateValue.claimId << nameWithTakeover; hasCandidateQuery++;
else }
db << "UPDATE nodes SET takeoverHeight = NULL, takeoverID = NULL WHERE name = ?" << nameWithTakeover; else {
noCandidateQuery << nameWithTakeover;
noCandidateQuery++;
}
assert(db.rows_modified()); assert(db.rows_modified());
} }
} }
@ -988,36 +1012,38 @@ 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 = ? AND validHeight > ? AND expirationHeight > ?" auto query = db << "SELECT txID, txN, validHeight FROM claims WHERE nodeName = ?1 AND validHeight > ?2 AND expirationHeight > ?2"
<< name << nNextHeight << nNextHeight; << name << nNextHeight;
for (auto &&row: query) { for (auto &&row: query) {
uint256 hash; uint256 hash;
uint32_t n; uint32_t n;
int oldValidHeight; int oldValidHeight;
row >> hash >> n >> oldValidHeight; row >> hash >> n >> oldValidHeight;
insertUndo.emplace_back(name, COutPoint(hash, n), oldValidHeight); insertUndo.emplace_back(name, COutPoint(hash, n), oldValidHeight);
LogPrint(BCLog::CLAIMS, "Early activation of claim %s, t: %s:%d at %d\n", name, hash.GetHex().substr(0, 6), n, nNextHeight);
} }
} }
// and then update them all to activate now: // and then update them all to activate now:
db << "UPDATE claims SET validHeight = ? WHERE nodeName = ? AND validHeight > ? AND expirationHeight > ?" db << "UPDATE claims SET validHeight = ?1 WHERE nodeName = ?2 AND validHeight > ?1 AND expirationHeight > ?1"
<< nNextHeight << name << nNextHeight << nNextHeight; << 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 = ? AND validHeight > ? AND expirationHeight > ?" auto query = db << "SELECT txID, txN, validHeight FROM supports WHERE nodeName = ?1 AND validHeight > ?2 AND expirationHeight > ?2"
<< name << nNextHeight << nNextHeight; << name << nNextHeight;
for (auto &&row: query) { for (auto &&row: query) {
uint256 hash; uint256 hash;
uint32_t n; uint32_t n;
int oldValidHeight; int oldValidHeight;
row >> hash >> n >> oldValidHeight; row >> hash >> n >> oldValidHeight;
insertSupportUndo.emplace_back(name, COutPoint(hash, n), oldValidHeight); insertSupportUndo.emplace_back(name, COutPoint(hash, n), oldValidHeight);
LogPrint(BCLog::CLAIMS, "Early activation of support %s, t: %s:%d at %d\n", name, hash.GetHex().substr(0, 6), n, nNextHeight);
} }
} }
// and then update them all to activate now: // and then update them all to activate now:
db << "UPDATE supports SET validHeight = ? WHERE nodeName = ? AND validHeight > ? AND expirationHeight > ?" db << "UPDATE supports SET validHeight = ?1 WHERE nodeName = ?2 AND validHeight > ?1 AND expirationHeight > ?1"
<< nNextHeight << name << nNextHeight << nNextHeight; << nNextHeight << name;
ret |= db.rows_modified() > 0; ret |= db.rows_modified() > 0;
return ret; return ret;
} }
@ -1312,7 +1338,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 >= ?"
<< -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) {
if (hit) return false; if (hit) return false;

View file

@ -385,6 +385,8 @@ protected:
bool transacting; bool transacting;
// one greater than the height of the chain's tip // one greater than the height of the chain's tip
mutable sqlite::database_binder claimHashQuery, childHashQuery;
virtual uint256 recursiveComputeMerkleHash(const std::string& name, int takeoverHeight, bool checkOnly); virtual uint256 recursiveComputeMerkleHash(const std::string& name, int takeoverHeight, bool checkOnly);
supportEntryType getSupportsForName(const std::string& name) const; supportEntryType getSupportsForName(const std::string& name) const;

View file

@ -245,35 +245,33 @@ uint256 CClaimTrieCacheHashFork::recursiveComputeMerkleHash(const std::string& n
if (nNextHeight < Params().GetConsensus().nAllClaimsInMerkleForkHeight) if (nNextHeight < Params().GetConsensus().nAllClaimsInMerkleForkHeight)
return CClaimTrieCacheNormalizationFork::recursiveComputeMerkleHash(name, takeoverHeight, checkOnly); return CClaimTrieCacheNormalizationFork::recursiveComputeMerkleHash(name, takeoverHeight, checkOnly);
auto childQuery = db << "SELECT name, hash, IFNULL(takeoverHeight, 0) FROM nodes WHERE parent = ? ORDER BY name" << name; // it may be that using RAM for this is more expensive than preparing a new query statement in each recursive call
struct Triple { std::string name; std::unique_ptr<uint256> hash; int takeoverHeight; };
std::vector<Triple> children;
for (auto&& row : childHashQuery << name) {
children.emplace_back();
auto& b = children.back();
row >> b.name >> b.hash >> b.takeoverHeight;
}
childHashQuery++;
std::vector<uint256> childHashes; std::vector<uint256> childHashes;
for (auto&& row: childQuery) { for (auto& child: children) {
std::string key; if (child.hash == nullptr) child.hash = std::make_unique<uint256>();
std::unique_ptr<uint256> hash; if (child.hash->IsNull()) {
int childTakeoverHeight; *child.hash = recursiveComputeMerkleHash(child.name, child.takeoverHeight, checkOnly);
row >> key >> hash >> childTakeoverHeight;
if (hash == nullptr) hash = std::make_unique<uint256>();
if (hash->IsNull()) {
*hash = recursiveComputeMerkleHash(key, childTakeoverHeight, checkOnly);
} }
childHashes.push_back(*hash); childHashes.push_back(*child.hash);
} }
auto claimQuery = db << "SELECT c.txID, c.txN, "
"(SELECT TOTAL(s.amount)+c.amount FROM supports s WHERE s.supportedClaimID = c.claimID "
"AND s.validHeight < ? AND s.expirationHeight >= ?) as effectiveAmount "
"FROM claims c WHERE c.nodeName = ? AND c.validHeight < ? AND c.expirationHeight >= ? "
"ORDER BY effectiveAmount DESC, c.blockHeight, REVERSE_BYTES(c.txID), c.txN"
<< nNextHeight << nNextHeight << name << nNextHeight << nNextHeight;
std::vector<uint256> claimHashes; std::vector<uint256> claimHashes;
for (auto&& row: claimQuery) { for (auto&& row: claimHashQuery << nNextHeight << name) {
COutPoint p; COutPoint p;
row >> p.hash >> p.n; row >> p.hash >> p.n;
auto claimHash = getValueHash(p, takeoverHeight); auto claimHash = getValueHash(p, takeoverHeight);
claimHashes.push_back(claimHash); claimHashes.push_back(claimHash);
} }
claimHashQuery++;
auto left = childHashes.empty() ? leafHash : ComputeMerkleRoot(childHashes); auto left = childHashes.empty() ? leafHash : ComputeMerkleRoot(childHashes);
auto right = claimHashes.empty() ? emptyHash : ComputeMerkleRoot(claimHashes); auto right = claimHashes.empty() ? emptyHash : ComputeMerkleRoot(claimHashes);
@ -363,8 +361,7 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const uin
row >> key >> takeoverHeight; row >> key >> takeoverHeight;
std::vector<uint256> childHashes; std::vector<uint256> childHashes;
uint32_t nextCurrentIdx = 0; uint32_t nextCurrentIdx = 0;
auto childQuery = db << "SELECT name, hash FROM nodes WHERE parent = ? ORDER BY name" << key; for (auto&& child : childHashQuery << key) {
for (auto&& child : childQuery) {
std::string childKey; std::string childKey;
uint256 childHash; uint256 childHash;
child >> childKey >> childHash; child >> childKey >> childHash;
@ -372,17 +369,11 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const uin
nextCurrentIdx = uint32_t(childHashes.size()); nextCurrentIdx = uint32_t(childHashes.size());
childHashes.push_back(childHash); childHashes.push_back(childHash);
} }
childHashQuery++;
auto claimQuery = db << "SELECT c.txID, c.txN, c.claimID, "
"(SELECT TOTAL(s.amount)+c.amount FROM supports s WHERE s.supportedClaimID = c.claimID "
"AND s.validHeight < ? AND s.expirationHeight >= ?) as effectiveAmount "
"FROM claims c WHERE c.nodeName = ? AND c.validHeight < ? AND c.expirationHeight >= ? "
"ORDER BY effectiveAmount DESC, c.blockHeight, REVERSE_BYTES(c.txID), c.txN"
<< nNextHeight << nNextHeight << key << nNextHeight << nNextHeight;
std::vector<uint256> claimHashes; std::vector<uint256> claimHashes;
uint32_t finalClaimIdx = 0; uint32_t finalClaimIdx = 0;
for (auto&& child: claimQuery) { for (auto&& child: claimHashQuery << nNextHeight << key) {
COutPoint childOutPoint; COutPoint childOutPoint;
uint160 childClaimID; uint160 childClaimID;
child >> childOutPoint.hash >> childOutPoint.n >> childClaimID; child >> childOutPoint.hash >> childOutPoint.n >> childClaimID;
@ -393,6 +384,7 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const uin
} }
claimHashes.push_back(getValueHash(childOutPoint, takeoverHeight)); claimHashes.push_back(getValueHash(childOutPoint, takeoverHeight));
} }
claimHashQuery++;
// I am on a node; I need a hash(children, claims) // I am on a node; I need a hash(children, claims)
// if I am the last node on the list, it will be hash(children, x) // if I am the last node on the list, it will be hash(children, x)

View file

@ -23,6 +23,25 @@ BOOST_AUTO_TEST_CASE(claim_replace_test) {
BOOST_CHECK(fixture.is_best_claim("bassfisher", tx2)); BOOST_CHECK(fixture.is_best_claim("bassfisher", tx2));
} }
BOOST_AUTO_TEST_CASE(takeover_stability_test) {
// no competing bids
ClaimTrieChainFixture fixture;
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "@bass", "one", 1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "@bass", "two", 2);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("@bass", tx2));
uint160 id; int takeover;
BOOST_REQUIRE(fixture.getLastTakeoverForName("@bass", id, takeover));
auto height = chainActive.Tip()->nHeight;
BOOST_CHECK_EQUAL(takeover, height);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "@bass", "three", 3);
fixture.Spend(tx3);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("@bass", tx2));
BOOST_REQUIRE(fixture.getLastTakeoverForName("@bass", id, takeover));
BOOST_CHECK_EQUAL(takeover, height);
}
/* /*
claims claims
no competing bids no competing bids