diff --git a/src/claimtrie/forks.cpp b/src/claimtrie/forks.cpp index e460bf30d..87f83ccdf 100644 --- a/src/claimtrie/forks.cpp +++ b/src/claimtrie/forks.cpp @@ -254,14 +254,14 @@ uint256 CClaimTrieCacheHashFork::computeNodeHash(const std::string& name, int ta childHashQuery++; std::vector claimHashes; - //if (takeoverHeight > 0) { + if (takeoverHeight > 0) { COutPoint p; for (auto &&row: claimHashQuery << nNextHeight << name) { row >> p.hash >> p.n; claimHashes.push_back(getValueHash(p, takeoverHeight)); } claimHashQuery++; - //} + } auto left = childHashes.empty() ? leafHash : ComputeMerkleRoot(std::move(childHashes)); auto right = claimHashes.empty() ? emptyHash : ComputeMerkleRoot(std::move(claimHashes)); diff --git a/src/claimtrie/trie.cpp b/src/claimtrie/trie.cpp index 88415ca80..64cff61bb 100644 --- a/src/claimtrie/trie.cpp +++ b/src/claimtrie/trie.cpp @@ -40,10 +40,11 @@ static const sqlite::sqlite_config sharedConfig { void applyPragmas(sqlite::database& db, std::size_t cache) { db << "PRAGMA cache_size=-" + std::to_string(cache); // in -KB - db << "PRAGMA synchronous=OFF"; // don't disk sync after transaction commit - db << "PRAGMA journal_mode=WAL"; db << "PRAGMA temp_store=MEMORY"; db << "PRAGMA case_sensitive_like=true"; + db << "PRAGMA journal_mode=WAL"; + db << "PRAGMA synchronous=OFF"; // don't disk sync after transaction commit; we handle that elsewhere + db << "PRAGMA wal_autocheckpoint=4000"; // 4k page size * 4000 = 16MB } CClaimTrie::CClaimTrie(std::size_t cacheBytes, bool fWipe, int height, @@ -68,7 +69,7 @@ CClaimTrie::CClaimTrie(std::size_t cacheBytes, bool fWipe, int height, nExtendedClaimExpirationForkHeight(nExtendedClaimExpirationForkHeight), nAllClaimsInMerkleForkHeight(nAllClaimsInMerkleForkHeight) { - applyPragmas(db, 5U * 1024U); // in KB + applyPragmas(db, cacheBytes >> 10U); // in KB db << "CREATE TABLE IF NOT EXISTS node (name BLOB NOT NULL PRIMARY KEY, " "parent BLOB REFERENCES node(name) DEFERRABLE INITIALLY DEFERRED, " @@ -136,10 +137,12 @@ bool CClaimTrie::SyncToDisk() return rc == SQLITE_OK; } -bool CClaimTrie::empty() +bool CClaimTrie::empty() // only used for testing { + sqlite::database local(dbFile, sharedConfig); + applyPragmas(local, 100); int64_t count; - db << "SELECT COUNT(*) FROM (SELECT 1 FROM claim WHERE activationHeight < ?1 AND expirationHeight >= ?1 LIMIT 1)" << nNextHeight >> count; + local << "SELECT COUNT(*) FROM (SELECT 1 FROM claim WHERE activationHeight < ?1 AND expirationHeight >= ?1 LIMIT 1)" << nNextHeight >> count; return count == 0; } @@ -427,10 +430,12 @@ uint256 CClaimTrieCacheBase::computeNodeHash(const std::string& name, int takeov }; childHashQuery++; - CClaimValue claim; - if (getInfoForName(name, claim)) { - auto valueHash = getValueHash(claim.outPoint, takeoverHeight); - vchToHash.insert(vchToHash.end(), valueHash.begin(), valueHash.end()); + if (takeoverHeight > 0) { + CClaimValue claim; + if (getInfoForName(name, claim)) { + auto valueHash = getValueHash(claim.outPoint, takeoverHeight); + vchToHash.insert(vchToHash.end(), valueHash.begin(), valueHash.end()); + } } return vchToHash.empty() ? one : Hash(vchToHash.begin(), vchToHash.end()); @@ -452,7 +457,7 @@ bool CClaimTrieCacheBase::checkConsistency() auto query = db << "SELECT n.name, n.hash, " "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 56789) OR LENGTH(n.parent) < 2"; + "WHERE n.name IN (SELECT r.name FROM node r ORDER BY RANDOM() LIMIT 100000) OR LENGTH(n.parent) < 2"; for (auto&& row: query) { std::string name; uint256 hash; @@ -519,7 +524,7 @@ extern const std::string proofClaimQuery_s = "ORDER BY n.name"; CClaimTrieCacheBase::CClaimTrieCacheBase(CClaimTrie* base) - : base(base), db(base->dbFile, sharedConfig), + : base(base), db(base->db.connection()), childHashQuery(db << childHashQuery_s), claimHashQuery(db << claimHashQuery_s), claimHashQueryLimit(db << claimHashQueryLimit_s), @@ -550,7 +555,9 @@ void CClaimTrieCacheBase::ensureTransacting() { if (!transacting) { transacting = true; - db << "begin"; + int isNotInTransaction = sqlite3_get_autocommit(db.connection().get()); + assert(isNotInTransaction); + db << "BEGIN"; } } @@ -744,11 +751,20 @@ bool CClaimTrieCacheBase::incrementBlock() "UNION SELECT nodeName FROM support WHERE expirationHeight = ?1 OR activationHeight = ?1)" << nNextHeight; - auto insertTakeoverQuery = db << "INSERT INTO takeover(name, height, claimID) VALUES(?, ?, ?)"; + insertTakeovers(); + + nNextHeight++; + return true; +} + +void CClaimTrieCacheBase::insertTakeovers(bool allowReplace) { + auto insertTakeoverQuery = allowReplace ? + db << "INSERT OR REPLACE INTO takeover(name, height, claimID) VALUES(?, ?, ?)" : + db << "INSERT INTO takeover(name, height, claimID) VALUES(?, ?, ?)"; // takeover handling: - db << "SELECT name FROM node WHERE hash IS NULL" - >> [this, &insertTakeoverQuery](const std::string& nameWithTakeover) { + db << "SELECT name FROM node WHERE hash IS NULL" + >> [this, &insertTakeoverQuery](const std::string& nameWithTakeover) { // if somebody activates on this block and they are the new best, then everybody activates on this block CClaimValue candidateValue; auto hasCandidate = getInfoForName(nameWithTakeover, candidateValue, 1); @@ -782,9 +798,6 @@ bool CClaimTrieCacheBase::incrementBlock() }; insertTakeoverQuery.used(true); - - nNextHeight++; - return true; } bool CClaimTrieCacheBase::activateAllFor(const std::string& name) diff --git a/src/claimtrie/trie.h b/src/claimtrie/trie.h index dfb6b8e25..b8e87a73f 100644 --- a/src/claimtrie/trie.h +++ b/src/claimtrie/trie.h @@ -132,6 +132,7 @@ protected: bool deleteNodeIfPossible(const std::string& name, std::string& parent, int64_t& claims); void ensureTreeStructureIsUpToDate(); void ensureTransacting(); + void insertTakeovers(bool allowReplace=false); private: bool transacting; diff --git a/src/test/claimtriecache_tests.cpp b/src/test/claimtriecache_tests.cpp index 15f2db96a..232699e5e 100644 --- a/src/test/claimtriecache_tests.cpp +++ b/src/test/claimtriecache_tests.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include @@ -14,7 +15,7 @@ class CClaimTrieCacheTest : public CClaimTrieCacheBase public: explicit CClaimTrieCacheTest(CClaimTrie* base): CClaimTrieCacheBase(base) { - nNextHeight = 2; + nNextHeight = std::max(2, nNextHeight); } bool insertClaimIntoTrie(const std::string& key, const CClaimValue& value) @@ -62,6 +63,10 @@ public: assert(!ret || nodeName == key); return ret; } + + void processTakeovers() { + insertTakeovers(true); + } }; BOOST_FIXTURE_TEST_SUITE(claimtriecache_tests, RegTestingSetup) @@ -96,110 +101,122 @@ BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test) COutPoint tx6OutPoint(tx6.GetHash(), 0); uint256 hash1; - hash1.SetHex("71c7b8d35b9a3d7ad9a1272b68972979bbd18589f1efe6f27b0bf260a6ba78fa"); + hash1.SetHex("917106c2e4a5d454c6463e366ec2c70fde57a3deacb36f566fc0c8568e4523d5"); uint256 hash2; - hash2.SetHex("c4fc0e2ad56562a636a0a237a96a5f250ef53495c2cb5edd531f087a8de83722"); + hash2.SetHex("79d0482510cb3da12b31096d459f8221cd094d268c03d96d897c932716e130e5"); uint256 hash3; - hash3.SetHex("baf52472bd7da19fe1e35116cfb3bd180d8770ffbe3ae9243df1fb58a14b0975"); + hash3.SetHex("14ba954095acc42e8a5c1c3c1ca1203a1f1fb44d66b4141272cbb5a16837e3e6"); uint256 hash4; - hash4.SetHex("c73232a755bf015f22eaa611b283ff38100f2a23fb6222e86eca363452ba0c51"); + hash4.SetHex("446b9dd04a1ff062c984cbbf0d5ab5aaea4ee3db1a9b65c5d06be0cb2090dbcf"); + auto dataDir = GetDataDir() / "merkle_test"; + fs::create_directories(dataDir); + CClaimTrie trie(10*1024*1024, true, 3, dataDir.string(), 1000, 1000, -1, 1000, 1000, 1000, 1000, 1); { - CClaimTrieCacheTest ntState(&::Claimtrie()); - ntState.insertClaimIntoTrie(std::string("test"), CClaimValue(tx1OutPoint, {}, 50, 0, 0)); - ntState.insertClaimIntoTrie(std::string("test2"), CClaimValue(tx2OutPoint, {}, 50, 0, 0)); + CClaimTrieCacheTest ntState(&trie); + ntState.insertClaimIntoTrie(std::string("test"), CClaimValue(tx1OutPoint, {}, 50, 2, 2)); + ntState.insertClaimIntoTrie(std::string("test2"), CClaimValue(tx2OutPoint, {}, 50, 2, 2)); - BOOST_CHECK(::Claimtrie().empty()); + BOOST_CHECK(trie.empty()); BOOST_CHECK_EQUAL(ntState.getTotalClaimsInTrie(), 2U); + ntState.processTakeovers(); BOOST_CHECK_EQUAL(ntState.getMerkleHash(), hash1); - ntState.insertClaimIntoTrie(std::string("test"), CClaimValue(tx3OutPoint, {}, 50, 1, 1)); + ntState.insertClaimIntoTrie(std::string("test"), CClaimValue(tx3OutPoint, {}, 50, 3, 3)); + ntState.processTakeovers(); BOOST_CHECK_EQUAL(ntState.getMerkleHash(), hash1); - ntState.insertClaimIntoTrie(std::string("tes"), CClaimValue(tx4OutPoint, {}, 50, 0, 0)); + ntState.insertClaimIntoTrie(std::string("tes"), CClaimValue(tx4OutPoint, {}, 50, 2, 2)); + ntState.processTakeovers(); BOOST_CHECK_EQUAL(ntState.getMerkleHash(), hash2); ntState.insertClaimIntoTrie(std::string("testtesttesttest"), - CClaimValue(tx5OutPoint, {}, 50, 0, 0)); + CClaimValue(tx5OutPoint, {}, 50, 2, 2)); ntState.removeClaimFromTrie(std::string("testtesttesttest"), tx5OutPoint); + ntState.processTakeovers(); BOOST_CHECK_EQUAL(ntState.getMerkleHash(), hash2); ntState.flush(); - BOOST_CHECK(!::Claimtrie().empty()); + BOOST_CHECK(!trie.empty()); BOOST_CHECK_EQUAL(ntState.getMerkleHash(), hash2); BOOST_CHECK(ntState.checkConsistency()); } { - CClaimTrieCacheTest ntState1(&::Claimtrie()); + CClaimTrieCacheTest ntState1(&trie); ntState1.removeClaimFromTrie(std::string("test"), tx1OutPoint); ntState1.removeClaimFromTrie(std::string("test2"), tx2OutPoint); ntState1.removeClaimFromTrie(std::string("test"), tx3OutPoint); ntState1.removeClaimFromTrie(std::string("tes"), tx4OutPoint); + ntState1.processTakeovers(); BOOST_CHECK_EQUAL(ntState1.getMerkleHash(), hash0); } { - CClaimTrieCacheTest ntState2(&::Claimtrie()); - ntState2.insertClaimIntoTrie(std::string("abab"), CClaimValue(tx6OutPoint, {}, 50, 0, 200)); + CClaimTrieCacheTest ntState2(&trie); + ntState2.insertClaimIntoTrie(std::string("abab"), CClaimValue(tx6OutPoint, {}, 50, 2, 200)); ntState2.removeClaimFromTrie(std::string("test"), tx1OutPoint); + ntState2.processTakeovers(); BOOST_CHECK_EQUAL(ntState2.getMerkleHash(), hash3); ntState2.flush(); - BOOST_CHECK(!::Claimtrie().empty()); + BOOST_CHECK(!trie.empty()); BOOST_CHECK_EQUAL(ntState2.getMerkleHash(), hash3); BOOST_CHECK(ntState2.checkConsistency()); } { - CClaimTrieCacheTest ntState3(&::Claimtrie()); - ntState3.insertClaimIntoTrie(std::string("test"), CClaimValue(tx1OutPoint, {}, 50, 0, 0)); + CClaimTrieCacheTest ntState3(&trie); + ntState3.insertClaimIntoTrie(std::string("test"), CClaimValue(tx1OutPoint, {}, 50, 2, 2)); + ntState3.processTakeovers(); BOOST_CHECK_EQUAL(ntState3.getMerkleHash(), hash4); ntState3.flush(); - BOOST_CHECK(!::Claimtrie().empty()); + BOOST_CHECK(!trie.empty()); BOOST_CHECK_EQUAL(ntState3.getMerkleHash(), hash4); BOOST_CHECK(ntState3.checkConsistency()); } { - CClaimTrieCacheTest ntState4(&::Claimtrie()); + CClaimTrieCacheTest ntState4(&trie); ntState4.removeClaimFromTrie(std::string("abab"), tx6OutPoint); + ntState4.processTakeovers(); BOOST_CHECK_EQUAL(ntState4.getMerkleHash(), hash2); ntState4.flush(); - BOOST_CHECK(!::Claimtrie().empty()); + BOOST_CHECK(!trie.empty()); BOOST_CHECK_EQUAL(ntState4.getMerkleHash(), hash2); BOOST_CHECK(ntState4.checkConsistency()); } { - CClaimTrieCacheTest ntState5(&::Claimtrie()); + CClaimTrieCacheTest ntState5(&trie); ntState5.removeClaimFromTrie(std::string("test"), tx3OutPoint); - + ntState5.processTakeovers(); BOOST_CHECK_EQUAL(ntState5.getMerkleHash(), hash2); ntState5.flush(); - BOOST_CHECK(!::Claimtrie().empty()); + BOOST_CHECK(!trie.empty()); BOOST_CHECK_EQUAL(ntState5.getMerkleHash(), hash2); BOOST_CHECK(ntState5.checkConsistency()); } { - CClaimTrieCacheTest ntState6(&::Claimtrie()); - ntState6.insertClaimIntoTrie(std::string("test"), CClaimValue(tx3OutPoint, {}, 50, 1, 1)); - + CClaimTrieCacheTest ntState6(&trie); + ntState6.insertClaimIntoTrie(std::string("test"), CClaimValue(tx3OutPoint, {}, 50, 3, 3)); + ntState6.processTakeovers(); BOOST_CHECK_EQUAL(ntState6.getMerkleHash(), hash2); ntState6.flush(); - BOOST_CHECK(!::Claimtrie().empty()); + BOOST_CHECK(!trie.empty()); BOOST_CHECK_EQUAL(ntState6.getMerkleHash(), hash2); BOOST_CHECK(ntState6.checkConsistency()); } { - CClaimTrieCacheTest ntState7(&::Claimtrie()); + CClaimTrieCacheTest ntState7(&trie); ntState7.removeClaimFromTrie(std::string("test"), tx3OutPoint); ntState7.removeClaimFromTrie(std::string("test"), tx1OutPoint); ntState7.removeClaimFromTrie(std::string("tes"), tx4OutPoint); ntState7.removeClaimFromTrie(std::string("test2"), tx2OutPoint); + ntState7.processTakeovers(); BOOST_CHECK_EQUAL(ntState7.getMerkleHash(), hash0); ntState7.flush(); - BOOST_CHECK(::Claimtrie().empty()); + BOOST_CHECK(trie.empty()); BOOST_CHECK_EQUAL(ntState7.getMerkleHash(), hash0); BOOST_CHECK(ntState7.checkConsistency()); } diff --git a/src/txdb.cpp b/src/txdb.cpp index 81d0f5bdd..4e986aa27 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -375,13 +375,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, >> pindexNew->nNonce >> pindexNew->nStatus; - if ((pindexNew->nHeight & 0x3ff) == 0x3ff) { // don't check for shutdown on every single block - boost::this_thread::interruption_point(); - if (ShutdownRequested()) - return false; - } - - pindexNew->nChainTx = pindexNew->pprev ? pindexNew->pprev->nChainTx + pindexNew->nTx : pindexNew->nTx; + // nChainTx gets set later; don't set it here or you'll mess up the Unlinked list if (!CheckProofOfWork(pindexNew->GetBlockPoWHash(), pindexNew->nBits, consensusParams)) { @@ -389,6 +383,12 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, LogPrintf("%s: CheckProofOfWorkFailed: %s (hash %s, nBits=%x, nTime=%d)\n", __func__, pindexNew->GetBlockPoWHash().GetHex(), pindexNew->GetBlockHash().GetHex(), pindexNew->nBits, pindexNew->nTime); return error("%s: CheckProofOfWork failed: %s", __func__, pindexNew->ToString()); } + + if ((pindexNew->nHeight & 0x3ff) == 0x3ff) { // don't check for shutdown on every single block + boost::this_thread::interruption_point(); + if (ShutdownRequested()) + return false; + } } return true; diff --git a/src/validation.cpp b/src/validation.cpp index 0b8c7cac7..50266bb76 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2814,7 +2814,7 @@ CBlockIndex* CChainState::FindMostWorkChain() { // Find the best candidate header. { - std::set::reverse_iterator it = setBlockIndexCandidates.rbegin(); + auto it = setBlockIndexCandidates.rbegin(); if (it == setBlockIndexCandidates.rend()) return nullptr; pindexNew = *it;