Compare commits

...

6 commits

Author SHA1 Message Date
Brannon King
eecb9f015e rolling version 2020-06-29 11:48:59 -06:00
Brannon King
33edd67d66
Merge pull request #391 from lbryio/merkle_improve_v19 2020-06-29 07:29:10 -06:00
Brannon King
701cab7df3 scaled back the dbcache change 2020-06-25 09:52:49 +03:00
Brannon King
909bb331d0 use a better index on support table 2020-06-25 09:52:07 +03:00
Anthony Fieroni
2248bfacec Increase default db cache, optimize db before sync
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
2020-06-17 15:02:47 +03:00
Anthony Fieroni
b7e26d3e75 Add claims hash to node table
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
2020-06-17 15:02:29 +03:00
7 changed files with 128 additions and 66 deletions

View file

@ -3,7 +3,7 @@ AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 0) define(_CLIENT_VERSION_MAJOR, 0)
define(_CLIENT_VERSION_MINOR, 19) define(_CLIENT_VERSION_MINOR, 19)
define(_CLIENT_VERSION_REVISION, 1) define(_CLIENT_VERSION_REVISION, 1)
define(_CLIENT_VERSION_BUILD, 2) define(_CLIENT_VERSION_BUILD, 3)
define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_RC, 0)
define(_CLIENT_VERSION_IS_RELEASE, true) define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2020) define(_COPYRIGHT_YEAR, 2020)

View file

@ -139,10 +139,10 @@ bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary()
// make the new nodes // make the new nodes
db << "INSERT INTO node(name) SELECT NORMALIZED(name) AS nn FROM claim WHERE nn != nodeName " db << "INSERT INTO node(name) SELECT NORMALIZED(name) AS nn FROM claim WHERE nn != nodeName "
"AND activationHeight <= ?1 AND expirationHeight > ?1 ON CONFLICT(name) DO UPDATE SET hash = NULL" << nNextHeight; "AND activationHeight <= ?1 AND expirationHeight > ?1 ON CONFLICT(name) DO UPDATE SET hash = NULL, claimsHash = NULL" << nNextHeight;
// there's a subtlety here: names in supports don't make new nodes // there's a subtlety here: names in supports don't make new nodes
db << "UPDATE node SET hash = NULL WHERE name IN " db << "UPDATE node SET hash = NULL, claimsHash = NULL WHERE name IN "
"(SELECT NORMALIZED(name) AS nn FROM support WHERE nn != nodeName " "(SELECT NORMALIZED(name) AS nn FROM support WHERE nn != nodeName "
"AND activationHeight <= ?1 AND expirationHeight > ?1)" << nNextHeight; "AND activationHeight <= ?1 AND expirationHeight > ?1)" << nNextHeight;
@ -151,7 +151,7 @@ bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary()
db << "UPDATE support SET nodeName = NORMALIZED(name) WHERE activationHeight <= ?1 AND expirationHeight > ?1" << nNextHeight; db << "UPDATE support SET nodeName = NORMALIZED(name) WHERE activationHeight <= ?1 AND expirationHeight > ?1" << nNextHeight;
// remove the old nodes // remove the old nodes
db << "UPDATE node SET hash = NULL WHERE name NOT IN " db << "UPDATE node SET hash = NULL, claimsHash = NULL WHERE name NOT IN "
"(SELECT nodeName FROM claim WHERE activationHeight <= ?1 AND expirationHeight > ?1 " "(SELECT nodeName FROM claim WHERE activationHeight <= ?1 AND expirationHeight > ?1 "
"UNION SELECT nodeName FROM support WHERE activationHeight <= ?1 AND expirationHeight > ?1)" << nNextHeight; "UNION SELECT nodeName FROM support WHERE activationHeight <= ?1 AND expirationHeight > ?1)" << nNextHeight;
@ -167,9 +167,9 @@ bool CClaimTrieCacheNormalizationFork::unnormalizeAllNamesInTrieIfNecessary()
ensureTransacting(); ensureTransacting();
db << "INSERT INTO node(name) SELECT name FROM claim WHERE name != nodeName " db << "INSERT INTO node(name) SELECT name FROM claim WHERE name != nodeName "
"AND activationHeight < ?1 AND expirationHeight > ?1 ON CONFLICT(name) DO UPDATE SET hash = NULL" << nNextHeight; "AND activationHeight < ?1 AND expirationHeight > ?1 ON CONFLICT(name) DO UPDATE SET hash = NULL, claimsHash = NULL" << nNextHeight;
db << "UPDATE node SET hash = NULL WHERE name IN " db << "UPDATE node SET hash = NULL, claimsHash = NULL WHERE name IN "
"(SELECT nodeName FROM support WHERE name != nodeName " "(SELECT nodeName FROM support WHERE name != nodeName "
"UNION SELECT nodeName FROM claim WHERE name != nodeName)"; "UNION SELECT nodeName FROM claim WHERE name != nodeName)";
@ -177,7 +177,7 @@ bool CClaimTrieCacheNormalizationFork::unnormalizeAllNamesInTrieIfNecessary()
db << "UPDATE support SET nodeName = name"; db << "UPDATE support SET nodeName = name";
// we need to let the tree structure method do the actual node delete // we need to let the tree structure method do the actual node delete
db << "UPDATE node SET hash = NULL WHERE name NOT IN " db << "UPDATE node SET hash = NULL, claimsHash = NULL WHERE name NOT IN "
"(SELECT DISTINCT name FROM claim)"; "(SELECT DISTINCT name FROM claim)";
return true; return true;
@ -243,10 +243,10 @@ uint256 ComputeMerkleRoot(std::vector<uint256> hashes)
return hashes.empty() ? uint256{} : hashes[0]; return hashes.empty() ? uint256{} : hashes[0];
} }
uint256 CClaimTrieCacheHashFork::computeNodeHash(const std::string& name, int takeoverHeight) uint256 CClaimTrieCacheHashFork::computeNodeHash(const std::string& name, uint256& claimsHash, int takeoverHeight)
{ {
if (nNextHeight < base->nAllClaimsInMerkleForkHeight) if (nNextHeight < base->nAllClaimsInMerkleForkHeight)
return CClaimTrieCacheNormalizationFork::computeNodeHash(name, takeoverHeight); return CClaimTrieCacheNormalizationFork::computeNodeHash(name, claimsHash, takeoverHeight);
std::vector<uint256> childHashes; std::vector<uint256> childHashes;
childHashQuery << name >> [&childHashes](std::string, uint256 hash) { childHashQuery << name >> [&childHashes](std::string, uint256 hash) {
@ -254,24 +254,28 @@ uint256 CClaimTrieCacheHashFork::computeNodeHash(const std::string& name, int ta
}; };
childHashQuery++; childHashQuery++;
std::vector<uint256> claimHashes;
if (takeoverHeight > 0) { if (takeoverHeight > 0) {
if (claimsHash.IsNull()) {
COutPoint p; COutPoint p;
std::vector<uint256> hashes;
for (auto&& row: claimHashQuery << nNextHeight << name) { for (auto&& row: claimHashQuery << nNextHeight << name) {
row >> p.hash >> p.n; row >> p.hash >> p.n;
claimHashes.push_back(getValueHash(p, takeoverHeight)); hashes.push_back(getValueHash(p, takeoverHeight));
} }
claimHashQuery++; claimHashQuery++;
claimsHash = hashes.empty() ? emptyHash : ComputeMerkleRoot(std::move(hashes));
}
} else {
claimsHash = emptyHash;
} }
if (name.empty() && childHashes.empty() && claimHashes.empty() if (name.empty() && childHashes.empty() && claimsHash == emptyHash
&& base->nMaxRemovalWorkaroundHeight < 0) // detecting regtest, but maybe all on next hard-fork? && base->nMaxRemovalWorkaroundHeight < 0) // detecting regtest, but maybe all on next hard-fork?
return emptyTrieHash; // here for compatibility with the functional tests return emptyTrieHash; // here for compatibility with the functional tests
auto left = childHashes.empty() ? leafHash : ComputeMerkleRoot(std::move(childHashes)); const auto& childrenHash = childHashes.empty() ? leafHash : ComputeMerkleRoot(std::move(childHashes));
auto right = claimHashes.empty() ? emptyHash : ComputeMerkleRoot(std::move(claimHashes));
return Hash(left.begin(), left.end(), right.begin(), right.end()); return Hash(childrenHash.begin(), childrenHash.end(), claimsHash.begin(), claimsHash.end());
} }
std::vector<uint256> ComputeMerklePath(const std::vector<uint256>& hashes, uint32_t idx) std::vector<uint256> ComputeMerklePath(const std::vector<uint256>& hashes, uint32_t idx)
@ -402,7 +406,7 @@ void CClaimTrieCacheHashFork::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) {
ensureTransacting(); ensureTransacting();
db << "UPDATE node SET hash = NULL"; db << "UPDATE node SET hash = NULL, claimsHash = NULL";
} }
} }
@ -411,7 +415,7 @@ bool CClaimTrieCacheHashFork::finalizeDecrement()
auto ret = CClaimTrieCacheNormalizationFork::finalizeDecrement(); auto ret = CClaimTrieCacheNormalizationFork::finalizeDecrement();
if (ret && nNextHeight == base->nAllClaimsInMerkleForkHeight - 1) { if (ret && nNextHeight == base->nAllClaimsInMerkleForkHeight - 1) {
ensureTransacting(); ensureTransacting();
db << "UPDATE node SET hash = NULL"; db << "UPDATE node SET hash = NULL, claimsHash = NULL";
} }
return ret; return ret;
} }

View file

@ -66,7 +66,7 @@ public:
bool allowSupportMetadata() const; bool allowSupportMetadata() const;
protected: protected:
uint256 computeNodeHash(const std::string& name, int takeoverHeight) override; uint256 computeNodeHash(const std::string& name, uint256& claimsHash, int takeoverHeight) override;
}; };
typedef CClaimTrieCacheHashFork CClaimTrieCache; typedef CClaimTrieCacheHashFork CClaimTrieCache;

View file

@ -73,7 +73,7 @@ CClaimTrie::CClaimTrie(std::size_t cacheBytes, bool fWipe, int height,
db << "CREATE TABLE IF NOT EXISTS node (name BLOB NOT NULL PRIMARY KEY, " db << "CREATE TABLE IF NOT EXISTS node (name BLOB NOT NULL PRIMARY KEY, "
"parent BLOB REFERENCES node(name) DEFERRABLE INITIALLY DEFERRED, " "parent BLOB REFERENCES node(name) DEFERRABLE INITIALLY DEFERRED, "
"hash BLOB)"; "hash BLOB, claimsHash BLOB)";
db << "CREATE TABLE IF NOT EXISTS claim (claimID BLOB NOT NULL PRIMARY KEY, name BLOB NOT NULL, " db << "CREATE TABLE IF NOT EXISTS claim (claimID BLOB NOT NULL PRIMARY KEY, name BLOB NOT NULL, "
"nodeName BLOB NOT NULL REFERENCES node(name) DEFERRABLE INITIALLY DEFERRED, " "nodeName BLOB NOT NULL REFERENCES node(name) DEFERRABLE INITIALLY DEFERRED, "
@ -96,6 +96,8 @@ CClaimTrie::CClaimTrie(std::size_t cacheBytes, bool fWipe, int height,
db << "DELETE FROM takeover"; db << "DELETE FROM takeover";
} }
doNodeTableMigration();
db << "CREATE INDEX IF NOT EXISTS node_hash_len_name ON node (hash, LENGTH(name) DESC)"; db << "CREATE INDEX IF NOT EXISTS node_hash_len_name ON node (hash, LENGTH(name) DESC)";
// db << "CREATE UNIQUE INDEX IF NOT EXISTS node_parent_name ON node (parent, name)"; // no apparent gain // db << "CREATE UNIQUE INDEX IF NOT EXISTS node_parent_name ON node (parent, name)"; // no apparent gain
db << "CREATE INDEX IF NOT EXISTS node_parent ON node (parent)"; db << "CREATE INDEX IF NOT EXISTS node_parent ON node (parent)";
@ -114,6 +116,29 @@ CClaimTrie::CClaimTrie(std::size_t cacheBytes, bool fWipe, int height,
db << "INSERT OR IGNORE INTO node(name, hash) VALUES(x'', ?)" << emptyTrieHash; // ensure that we always have our root node db << "INSERT OR IGNORE INTO node(name, hash) VALUES(x'', ?)" << emptyTrieHash; // ensure that we always have our root node
} }
void CClaimTrie::doNodeTableMigration()
{
try {
isNodeMigrationStart = false;
for (auto&& row : db << "SELECT claimsHash FROM node WHERE name = x''")
break;
} catch (const sqlite::sqlite_exception&) {
logPrint << "Running one-time upgrade of node table to cache the hash of claims..." << Clog::endl;
isNodeMigrationStart = true;
// new node schema
db << "CREATE TABLE node_new (name BLOB NOT NULL PRIMARY KEY, "
"parent BLOB REFERENCES node(name) DEFERRABLE INITIALLY DEFERRED, "
"hash BLOB, claimsHash BLOB)";
db << "INSERT OR REPLACE INTO node_new(name, parent, hash) "
"SELECT name, parent, hash FROM node";
db << "DROP TABLE node";
db << "ALTER TABLE node_new RENAME TO node";
}
}
CClaimTrieCacheBase::~CClaimTrieCacheBase() CClaimTrieCacheBase::~CClaimTrieCacheBase()
{ {
if (transacting) { if (transacting) {
@ -132,6 +157,7 @@ std::size_t CClaimTrie::cache()
bool CClaimTrie::SyncToDisk() bool CClaimTrie::SyncToDisk()
{ {
db << "PRAGMA optimize";
// alternatively, switch to full sync after we are caught up on the chain // alternatively, switch to full sync after we are caught up on the chain
return sqlite::sync(db) == SQLITE_OK; return sqlite::sync(db) == SQLITE_OK;
} }
@ -279,7 +305,7 @@ void CClaimTrieCacheBase::ensureTreeStructureIsUpToDate()
"name IN (WITH RECURSIVE prefix(p) AS (VALUES(?) UNION ALL " "name IN (WITH RECURSIVE prefix(p) AS (VALUES(?) UNION ALL "
"SELECT POPS(p) FROM prefix WHERE p != x'') SELECT p FROM prefix)"; "SELECT POPS(p) FROM prefix WHERE p != x'') SELECT p FROM prefix)";
auto insertQuery = db << "INSERT INTO node(name, parent, hash) VALUES(?, ?, NULL) " auto insertQuery = db << "INSERT INTO node(name, parent, hash, claimsHash) VALUES(?, ?, NULL, NULL) "
"ON CONFLICT(name) DO UPDATE SET parent = excluded.parent, hash = NULL"; "ON CONFLICT(name) DO UPDATE SET parent = excluded.parent, hash = NULL";
auto nodeQuery = db << "SELECT name FROM node WHERE parent = ?"; auto nodeQuery = db << "SELECT name FROM node WHERE parent = ?";
@ -367,7 +393,7 @@ int64_t CClaimTrieCacheBase::getTotalValueOfClaimsInTrie(bool fControllingOnly)
int64_t ret = 0; int64_t ret = 0;
const std::string query = fControllingOnly ? const std::string query = fControllingOnly ?
"SELECT SUM(amount) FROM (SELECT c.amount as amount, " "SELECT SUM(amount) FROM (SELECT c.amount as amount, "
"(SELECT(SELECT IFNULL(SUM(s.amount),0)+c.amount FROM support s " "(SELECT(SELECT IFNULL(SUM(s.amount),0)+c.amount FROM support s INDEXED BY support_supportedClaimID "
"WHERE s.supportedClaimID = c.claimID AND c.nodeName = s.nodeName " "WHERE s.supportedClaimID = c.claimID AND c.nodeName = s.nodeName "
"AND s.activationHeight < ?1 AND s.expirationHeight >= ?1) as effective " "AND s.activationHeight < ?1 AND s.expirationHeight >= ?1) as effective "
"ORDER BY effective DESC LIMIT 1) as winner FROM claim c " "ORDER BY effective DESC LIMIT 1) as winner FROM claim c "
@ -438,7 +464,7 @@ void completeHash(uint256& partialHash, const std::string& key, int to)
partialHash = Hash(it, it + 1, partialHash.begin(), partialHash.end()); partialHash = Hash(it, it + 1, partialHash.begin(), partialHash.end());
} }
uint256 CClaimTrieCacheBase::computeNodeHash(const std::string& name, int takeoverHeight) uint256 CClaimTrieCacheBase::computeNodeHash(const std::string& name, uint256& claimsHash, int takeoverHeight)
{ {
const auto pos = name.size(); const auto pos = name.size();
std::vector<uint8_t> vchToHash; std::vector<uint8_t> vchToHash;
@ -451,11 +477,13 @@ uint256 CClaimTrieCacheBase::computeNodeHash(const std::string& name, int takeov
childHashQuery++; childHashQuery++;
if (takeoverHeight > 0) { if (takeoverHeight > 0) {
if (claimsHash.IsNull()) {
CClaimValue claim; CClaimValue claim;
if (getInfoForName(name, claim)) { if (getInfoForName(name, claim))
auto valueHash = getValueHash(claim.outPoint, takeoverHeight); claimsHash = getValueHash(claim.outPoint, takeoverHeight);
vchToHash.insert(vchToHash.end(), valueHash.begin(), valueHash.end());
} }
if (!claimsHash.IsNull())
vchToHash.insert(vchToHash.end(), claimsHash.begin(), claimsHash.end());
} }
return vchToHash.empty() ? emptyTrieHash : Hash(vchToHash.begin(), vchToHash.end()); return vchToHash.empty() ? emptyTrieHash : Hash(vchToHash.begin(), vchToHash.end());
@ -473,22 +501,47 @@ bool CClaimTrieCacheBase::checkConsistency()
} }
} }
if (base->isNodeMigrationStart)
ensureTransacting();
auto updateQuery = db << "UPDATE node SET claimsHash = ? WHERE name = ?";
// not checking everything as it takes too long // not checking everything as it takes too long
auto query = db << "SELECT n.name, n.hash, " auto query = db << (base->isNodeMigrationStart ?
"SELECT n.name, n.hash, n.claimsHash, "
"IFNULL((SELECT CASE WHEN t.claimID IS NULL THEN 0 ELSE t.height END " "IFNULL((SELECT CASE WHEN t.claimID IS NULL THEN 0 ELSE t.height END "
"FROM takeover t WHERE t.name = n.name ORDER BY t.height DESC LIMIT 1), 0) FROM node n " "FROM takeover t WHERE t.name = n.name ORDER BY t.height DESC LIMIT 1), 0) "
"WHERE n.name IN (SELECT r.name FROM node r ORDER BY RANDOM() LIMIT 100000) OR n.parent = x''"; "FROM node n ORDER BY LENGTH(n.name) DESC"
:
"SELECT n.name, n.hash, n.claimsHash, "
"IFNULL((SELECT CASE WHEN t.claimID IS NULL THEN 0 ELSE t.height END "
"FROM takeover t WHERE t.name = n.name ORDER BY t.height DESC LIMIT 1), 0) "
"FROM node n WHERE n.name IN "
"(SELECT r.name FROM node r ORDER BY RANDOM() LIMIT 100000) OR n.parent = x''");
for (auto&& row: query) { for (auto&& row: query) {
std::string name; std::string name;
uint256 hash;
int takeoverHeight; int takeoverHeight;
row >> name >> hash >> takeoverHeight; uint256 hash, claimsHash, computedClaimsHash;
auto computedHash = computeNodeHash(name, takeoverHeight); row >> name >> hash >> claimsHash >> takeoverHeight;
auto computedHash = computeNodeHash(name, computedClaimsHash, takeoverHeight);
if (computedHash != hash) { if (computedHash != hash) {
logPrint << "Invalid hash at " << name << Clog::endl; logPrint << "Invalid hash at " << name << Clog::endl;
return false; return false;
} }
if (base->isNodeMigrationStart) {
assert(!computedClaimsHash.IsNull());
updateQuery << computedClaimsHash << name;
updateQuery++;
} else if (computedClaimsHash != claimsHash) {
logPrint << "Invalid claimsHash at " << name << Clog::endl;
return false;
} }
}
updateQuery.used(true);
if (base->isNodeMigrationStart)
return flush();
return true; return true;
} }
@ -530,7 +583,7 @@ const std::string childHashQuery_s = "SELECT name, hash FROM node WHERE parent =
const std::string claimHashQuery_s = const std::string claimHashQuery_s =
"SELECT c.txID, c.txN, c.claimID, c.updateHeight, c.activationHeight, c.amount, " "SELECT c.txID, c.txN, c.claimID, c.updateHeight, c.activationHeight, c.amount, "
"(SELECT IFNULL(SUM(s.amount),0)+c.amount FROM support s " "(SELECT IFNULL(SUM(s.amount),0)+c.amount FROM support s INDEXED BY support_supportedClaimID "
"WHERE s.supportedClaimID = c.claimID AND s.nodeName = c.nodeName " "WHERE s.supportedClaimID = c.claimID AND s.nodeName = c.nodeName "
"AND s.activationHeight < ?1 AND s.expirationHeight >= ?1) as effectiveAmount " "AND s.activationHeight < ?1 AND s.expirationHeight >= ?1) as effectiveAmount "
"FROM claim c WHERE c.nodeName = ?2 AND c.activationHeight < ?1 AND c.expirationHeight >= ?1 " "FROM claim c WHERE c.nodeName = ?2 AND c.activationHeight < ?1 AND c.expirationHeight >= ?1 "
@ -592,20 +645,20 @@ uint256 CClaimTrieCacheBase::getMerkleHash()
{ {
ensureTreeStructureIsUpToDate(); ensureTreeStructureIsUpToDate();
uint256 hash; uint256 hash;
db << "SELECT hash FROM node WHERE name = x''" for (auto&& row : db << "SELECT hash FROM node WHERE name = x''") {
>> [&hash](std::unique_ptr<uint256> rootHash) { row >> hash;
if (rootHash)
hash = std::move(*rootHash);
};
if (!hash.IsNull()) if (!hash.IsNull())
return hash; return hash;
}
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?
auto updateQuery = db << "UPDATE node SET hash = ? WHERE name = ?"; auto updateQuery = db << "UPDATE node SET hash = ?, claimsHash = ? WHERE name = ?";
db << "SELECT n.name, IFNULL((SELECT CASE WHEN t.claimID IS NULL THEN 0 ELSE t.height END FROM takeover t WHERE t.name = n.name " db << "SELECT n.name, n.claimsHash, "
"ORDER BY t.height DESC LIMIT 1), 0) FROM node n WHERE n.hash IS NULL ORDER BY LENGTH(n.name) DESC" // assumes n.name is blob "IFNULL((SELECT CASE WHEN t.claimID IS NULL THEN 0 ELSE t.height END "
>> [this, &hash, &updateQuery](const std::string& name, int takeoverHeight) { "FROM takeover t WHERE t.name = n.name ORDER BY t.height DESC LIMIT 1), 0) "
hash = computeNodeHash(name, takeoverHeight); "FROM node n WHERE n.hash IS NULL ORDER BY LENGTH(n.name) DESC" // assumes n.name is blob
updateQuery << hash << name; >> [&](const std::string& name, uint256 claimsHash, int takeoverHeight) {
hash = computeNodeHash(name, claimsHash, takeoverHeight);
updateQuery << hash << claimsHash << name;
updateQuery++; updateQuery++;
}; };
updateQuery.used(true); updateQuery.used(true);
@ -659,7 +712,7 @@ bool CClaimTrieCacheBase::addClaim(const std::string& name, const COutPoint& out
<< originalHeight << nHeight << nValidHeight << nValidHeight << expires; << originalHeight << nHeight << nValidHeight << nValidHeight << expires;
if (nValidHeight < nNextHeight) if (nValidHeight < nNextHeight)
db << "INSERT INTO node(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET hash = NULL" << nodeName; db << "INSERT INTO node(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET hash = NULL, claimsHash = NULL" << nodeName;
return true; return true;
} }
@ -680,7 +733,7 @@ bool CClaimTrieCacheBase::addSupport(const std::string& name, const COutPoint& o
<< supportedClaimId << name << nodeName << outPoint.hash << outPoint.n << nAmount << nHeight << nValidHeight << nValidHeight << expires; << supportedClaimId << name << nodeName << outPoint.hash << outPoint.n << nAmount << nHeight << nValidHeight << nValidHeight << expires;
if (nValidHeight < nNextHeight) if (nValidHeight < nNextHeight)
db << "UPDATE node SET hash = NULL WHERE name = ?" << nodeName; db << "UPDATE node SET hash = NULL, claimsHash = NULL WHERE name = ?" << nodeName;
return true; return true;
} }
@ -709,7 +762,7 @@ bool CClaimTrieCacheBase::removeClaim(const uint160& claimId, const COutPoint& o
if (!db.rows_modified()) if (!db.rows_modified())
return false; return false;
db << "UPDATE node SET hash = NULL WHERE name = ?" << nodeName; db << "UPDATE node SET hash = NULL, claimsHash = NULL WHERE name = ?" << nodeName;
// when node should be deleted from cache but instead it's kept // when node should be deleted from cache but instead it's kept
// because it's a parent one and should not be effectively erased // because it's a parent one and should not be effectively erased
@ -740,7 +793,8 @@ bool CClaimTrieCacheBase::removeSupport(const COutPoint& outPoint, std::string&
db << "DELETE FROM support WHERE txID = ? AND txN = ?" << outPoint.hash << outPoint.n; db << "DELETE FROM support WHERE txID = ? AND txN = ?" << outPoint.hash << outPoint.n;
if (!db.rows_modified()) if (!db.rows_modified())
return false; return false;
db << "UPDATE node SET hash = NULL WHERE name = ?" << nodeName;
db << "UPDATE node SET hash = NULL, claimsHash = NULL WHERE name = ?" << nodeName;
return true; return true;
} }
@ -757,11 +811,11 @@ bool CClaimTrieCacheBase::incrementBlock()
db << "INSERT INTO node(name) SELECT nodeName FROM claim INDEXED BY claim_activationHeight " db << "INSERT INTO node(name) SELECT nodeName FROM claim INDEXED BY claim_activationHeight "
"WHERE activationHeight = ?1 AND expirationHeight > ?1 " "WHERE activationHeight = ?1 AND expirationHeight > ?1 "
"ON CONFLICT(name) DO UPDATE SET hash = NULL" "ON CONFLICT(name) DO UPDATE SET hash = NULL, claimsHash = NULL"
<< nNextHeight; << nNextHeight;
// don't make new nodes for items in supports or items that expire this block that don't exist in claims // don't make new nodes for items in supports or items that expire this block that don't exist in claims
db << "UPDATE node SET hash = NULL WHERE name IN " db << "UPDATE node SET hash = NULL, claimsHash = NULL WHERE name IN "
"(SELECT nodeName FROM claim WHERE expirationHeight = ?1 " "(SELECT nodeName FROM claim WHERE expirationHeight = ?1 "
"UNION SELECT nodeName FROM support WHERE expirationHeight = ?1 OR activationHeight = ?1)" "UNION SELECT nodeName FROM support WHERE expirationHeight = ?1 OR activationHeight = ?1)"
<< nNextHeight; << nNextHeight;
@ -836,10 +890,10 @@ bool CClaimTrieCacheBase::decrementBlock()
nNextHeight--; nNextHeight--;
db << "INSERT INTO node(name) SELECT nodeName FROM claim " db << "INSERT INTO node(name) SELECT nodeName FROM claim "
"WHERE expirationHeight = ? ON CONFLICT(name) DO UPDATE SET hash = NULL" "WHERE expirationHeight = ? ON CONFLICT(name) DO UPDATE SET hash = NULL, claimsHash = NULL"
<< nNextHeight; << nNextHeight;
db << "UPDATE node SET hash = NULL WHERE name IN(" db << "UPDATE node SET hash = NULL, claimsHash = NULL WHERE name IN("
"SELECT nodeName FROM support WHERE expirationHeight = ?1 OR activationHeight = ?1 " "SELECT nodeName FROM support WHERE expirationHeight = ?1 OR activationHeight = ?1 "
"UNION SELECT nodeName FROM claim WHERE activationHeight = ?1)" "UNION SELECT nodeName FROM claim WHERE activationHeight = ?1)"
<< nNextHeight; << nNextHeight;
@ -855,7 +909,7 @@ bool CClaimTrieCacheBase::decrementBlock()
bool CClaimTrieCacheBase::finalizeDecrement() bool CClaimTrieCacheBase::finalizeDecrement()
{ {
db << "UPDATE node SET hash = NULL WHERE name IN " db << "UPDATE node SET hash = NULL, claimsHash = NULL WHERE name IN "
"(SELECT nodeName FROM claim WHERE activationHeight = ?1 AND expirationHeight > ?1 " "(SELECT nodeName FROM claim WHERE activationHeight = ?1 AND expirationHeight > ?1 "
"UNION SELECT nodeName FROM support WHERE activationHeight = ?1 AND expirationHeight > ?1 " "UNION SELECT nodeName FROM support WHERE activationHeight = ?1 AND expirationHeight > ?1 "
"UNION SELECT name FROM takeover WHERE height = ?1)" << nNextHeight; "UNION SELECT name FROM takeover WHERE height = ?1)" << nNextHeight;

View file

@ -52,6 +52,7 @@ protected:
const std::size_t dbCacheBytes; const std::size_t dbCacheBytes;
const std::string dbFile; const std::string dbFile;
sqlite::database db; sqlite::database db;
bool isNodeMigrationStart;
const int nProportionalDelayFactor; const int nProportionalDelayFactor;
const int nNormalizedNameForkHeight; const int nNormalizedNameForkHeight;
@ -61,6 +62,9 @@ protected:
const int64_t nExtendedClaimExpirationTime; const int64_t nExtendedClaimExpirationTime;
const int64_t nExtendedClaimExpirationForkHeight; const int64_t nExtendedClaimExpirationForkHeight;
const int64_t nAllClaimsInMerkleForkHeight; const int64_t nAllClaimsInMerkleForkHeight;
private:
void doNodeTableMigration();
}; };
class CClaimTrieCacheBase class CClaimTrieCacheBase
@ -124,7 +128,7 @@ protected:
mutable std::unordered_set<std::string> removalWorkaround; mutable std::unordered_set<std::string> removalWorkaround;
sqlite::database_binder childHashQuery, claimHashQuery, claimHashQueryLimit; sqlite::database_binder childHashQuery, claimHashQuery, claimHashQueryLimit;
virtual uint256 computeNodeHash(const std::string& name, int takeoverHeight); virtual uint256 computeNodeHash(const std::string& name, uint256& claimsHash, int takeoverHeight);
supportEntryType getSupportsForName(const std::string& name) const; supportEntryType getSupportsForName(const std::string& name) const;
virtual int getDelayForName(const std::string& name, const uint160& claimId) const; virtual int getDelayForName(const std::string& name, const uint160& claimId) const;

View file

@ -59,7 +59,7 @@ class uint256;
//! No need to periodic flush if at least this much space still available. //! No need to periodic flush if at least this much space still available.
static constexpr int MAX_BLOCK_COINSDB_USAGE = 10; static constexpr int MAX_BLOCK_COINSDB_USAGE = 10;
//! -dbcache default (MiB) //! -dbcache default (MiB)
static const int64_t nDefaultDbCache = 480; static const int64_t nDefaultDbCache = 800;
//! -dbbatchsize default (bytes) //! -dbbatchsize default (bytes)
static const int64_t nDefaultDbBatchSize = 16 << 20; static const int64_t nDefaultDbBatchSize = 16 << 20;
//! max. -dbcache (MiB) //! max. -dbcache (MiB)

View file

@ -2347,6 +2347,9 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
// TODO: if the "just check" flag is set, we should reduce the work done here. Incrementing blocks twice per mine is not efficient. // TODO: if the "just check" flag is set, we should reduce the work done here. Incrementing blocks twice per mine is not efficient.
assert(trieCache.incrementBlock()); assert(trieCache.incrementBlock());
int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2;
LogPrint(BCLog::BENCH, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), MILLI * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : MILLI * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * MICRO, nTimeConnect * MILLI / nBlocksTotal);
if (trieCache.getMerkleHash() != block.hashClaimTrie) { if (trieCache.getMerkleHash() != block.hashClaimTrie) {
return state.Invalid(ValidationInvalidReason::CLAIMTRIE_HASH, return state.Invalid(ValidationInvalidReason::CLAIMTRIE_HASH,
error("ConnectBlock() : the merkle root of the claim trie does not match " error("ConnectBlock() : the merkle root of the claim trie does not match "
@ -2354,9 +2357,6 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
block.hashClaimTrie.GetHex(), pindex->nHeight), REJECT_INVALID, "bad-claim-merkle-hash"); block.hashClaimTrie.GetHex(), pindex->nHeight), REJECT_INVALID, "bad-claim-merkle-hash");
} }
int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2;
LogPrint(BCLog::BENCH, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), MILLI * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : MILLI * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * MICRO, nTimeConnect * MILLI / nBlocksTotal);
CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()); CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus());
if (block.vtx[0]->GetValueOut() > blockReward) if (block.vtx[0]->GetValueOut() > blockReward)
return state.Invalid(ValidationInvalidReason::CONSENSUS, return state.Invalid(ValidationInvalidReason::CONSENSUS,
@ -2366,8 +2366,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
if (!control.Wait()) if (!control.Wait())
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: CheckQueue failed", __func__), REJECT_INVALID, "block-validation-failed"); return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: CheckQueue failed", __func__), REJECT_INVALID, "block-validation-failed");
int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2; int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime3;
LogPrint(BCLog::BENCH, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1, MILLI * (nTime4 - nTime2), nInputs <= 1 ? 0 : MILLI * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * MICRO, nTimeVerify * MILLI / nBlocksTotal); LogPrint(BCLog::BENCH, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1, MILLI * (nTime4 - nTime3), nInputs <= 1 ? 0 : MILLI * (nTime4 - nTime3) / (nInputs-1), nTimeVerify * MICRO, nTimeVerify * MILLI / nBlocksTotal);
if (fJustCheck) if (fJustCheck)
return true; return true;