diff --git a/src/claimtrie/forks.cpp b/src/claimtrie/forks.cpp index d8aa15cf1..c76e25fb1 100644 --- a/src/claimtrie/forks.cpp +++ b/src/claimtrie/forks.cpp @@ -144,6 +144,7 @@ bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary(takeov // make the new nodes db << "INSERT INTO nodes(name) SELECT NORMALIZED(name) AS nn FROM claims WHERE nn != nodeName " "AND validHeight <= ?1 AND expirationHeight > ?1 ON CONFLICT(name) DO UPDATE SET hash = NULL" << nNextHeight; + db << "UPDATE nodes SET hash = NULL WHERE name IN " "(SELECT NORMALIZED(name) AS nn FROM supports WHERE nn != nodeName " "AND validHeight <= ?1 AND expirationHeight > ?1)" << nNextHeight; @@ -181,6 +182,7 @@ bool CClaimTrieCacheNormalizationFork::unnormalizeAllNamesInTrieIfNecessary() 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; + db << "UPDATE nodes SET hash = NULL WHERE name IN " "(SELECT name FROM supports WHERE name != nodeName UNION " "SELECT nodeName FROM supports WHERE name != nodeName UNION " diff --git a/src/claimtrie/log.cpp b/src/claimtrie/log.cpp index a17a97938..6df895616 100644 --- a/src/claimtrie/log.cpp +++ b/src/claimtrie/log.cpp @@ -3,6 +3,7 @@ void CLogPrint::setLogger(ClogBase* log) { + ss.str({}); logger = log; } @@ -14,10 +15,16 @@ CLogPrint& CLogPrint::global() CLogPrint& CLogPrint::operator<<(const Clog& cl) { - if (logger && cl == Clog::endl) { - ss << '\n'; - logger->LogPrintStr(ss.str()); - ss.str({}); + if (logger) { + switch(cl) { + case Clog::endl: + ss << '\n'; + // fallthrough + case Clog::flush: + logger->LogPrintStr(ss.str()); + ss.str({}); + break; + } } return *this; } diff --git a/src/claimtrie/log.h b/src/claimtrie/log.h index ac3f49f0e..a2db7e39a 100644 --- a/src/claimtrie/log.h +++ b/src/claimtrie/log.h @@ -15,6 +15,7 @@ struct ClogBase enum struct Clog { endl = 0, + flush = 1, }; struct CLogPrint diff --git a/src/claimtrie/trie.cpp b/src/claimtrie/trie.cpp index 43d6dc899..ede41b102 100644 --- a/src/claimtrie/trie.cpp +++ b/src/claimtrie/trie.cpp @@ -61,6 +61,7 @@ CClaimTrie::CClaimTrie(bool fWipe, int height, { 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_parent ON nodes (parent)"; @@ -69,6 +70,7 @@ CClaimTrie::CClaimTrie(bool fWipe, int height, "txID BLOB NOT NULL COLLATE BINARY, txN INTEGER NOT NULL, blockHeight INTEGER NOT NULL, " "validHeight INTEGER NOT NULL, expirationHeight INTEGER NOT NULL, " "amount INTEGER NOT NULL, metadata BLOB COLLATE BINARY);"; + db << "CREATE INDEX IF NOT EXISTS claims_validHeight ON claims (validHeight)"; db << "CREATE INDEX IF NOT EXISTS claims_expirationHeight ON claims (expirationHeight)"; db << "CREATE INDEX IF NOT EXISTS claims_nodeName ON claims (nodeName)"; @@ -77,6 +79,7 @@ CClaimTrie::CClaimTrie(bool fWipe, int height, "supportedClaimID BLOB NOT NULL COLLATE BINARY, name TEXT NOT NULL, nodeName TEXT NOT NULL, " "blockHeight INTEGER NOT NULL, validHeight INTEGER NOT NULL, expirationHeight INTEGER NOT NULL, " "amount INTEGER NOT NULL, metadata BLOB COLLATE BINARY, PRIMARY KEY(txID, txN));"; + db << "CREATE INDEX IF NOT EXISTS supports_supportedClaimID ON supports (supportedClaimID)"; db << "CREATE INDEX IF NOT EXISTS supports_validHeight ON supports (validHeight)"; db << "CREATE INDEX IF NOT EXISTS supports_expirationHeight ON supports (expirationHeight)"; @@ -321,11 +324,17 @@ std::size_t CClaimTrieCacheBase::getTotalClaimsInTrie() const int64_t CClaimTrieCacheBase::getTotalValueOfClaimsInTrie(bool fControllingOnly) const { int64_t ret = 0; - std::string query("SELECT SUM(SELECT IFNULL(SUM(s.amount),0)+c.amount FROM supports s " - "WHERE s.supportedClaimID = c.claimID AND s.validHeight < ?1 AND s.expirationHeight >= ?1) " - "FROM claims c WHERE c.validHeight < ?1 AND s.expirationHeight >= ?1"); - if (fControllingOnly) - throw std::runtime_error("not implemented yet"); // TODO: finish this + const std::string query = fControllingOnly ? + "SELECT SUM(amount) FROM (SELECT c.amount as amount, " + "(SELECT(SELECT IFNULL(SUM(s.amount),0)+c.amount FROM supports s " + "WHERE s.supportedClaimID = c.claimID AND c.nodeName = s.nodeName " + "AND s.validHeight < ?1 AND s.expirationHeight >= ?1) as effective " + "ORDER BY effective DESC LIMIT 1) as winner FROM claims c " + "WHERE c.validHeight < ?1 AND c.expirationHeight >= ?1 GROUP BY c.nodeName)" + : + "SELECT SUM(amount) FROM (SELECT c.amount as amount " + "FROM claims c WHERE c.validHeight < ?1 AND s.expirationHeight >= ?1)"; + db << query << nNextHeight >> ret; return ret; } @@ -448,7 +457,7 @@ bool CClaimTrieCacheBase::checkConsistency() bool CClaimTrieCacheBase::validateDb(const CUint256& rootHash) { - logPrint << "Checking claim trie consistency... "; + logPrint << "Checking claim trie consistency... " << Clog::flush; if (checkConsistency()) { logPrint << "consistent" << Clog::endl; if (rootHash != getMerkleHash()) { @@ -569,6 +578,7 @@ bool CClaimTrieCacheBase::addClaim(const std::string& name, const CTxOutPoint& o if (nValidHeight < 0) nValidHeight = nHeight + getDelayForName(name, claimId); // sets nValidHeight to the old value + auto nodeName = adjustNameForValidHeight(name, nValidHeight); auto expires = expirationTime() + nHeight; @@ -589,6 +599,7 @@ bool CClaimTrieCacheBase::addSupport(const std::string& name, const CTxOutPoint& if (nValidHeight < 0) nValidHeight = nHeight + getDelayForName(name, supportedClaimId); + auto nodeName = adjustNameForValidHeight(name, nValidHeight); auto expires = expirationTime() + nHeight; @@ -1113,6 +1124,7 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimUndoTy db << "INSERT INTO nodes(name) SELECT nodeName FROM claims " "WHERE validHeight = ?1 AND expirationHeight > ?1 " "ON CONFLICT(name) DO UPDATE SET hash = NULL" << nNextHeight; + db << "UPDATE nodes SET hash = NULL WHERE name IN " "(SELECT nodeName FROM supports WHERE validHeight = ?1 AND expirationHeight > ?1)" << nNextHeight; @@ -1269,6 +1281,7 @@ bool CClaimTrieCacheBase::finalizeDecrement(takeoverUndoType& takeoverUndo) { db << "UPDATE nodes SET hash = NULL WHERE name IN " "(SELECT nodeName FROM claims WHERE validHeight = ?1 AND expirationHeight > ?1)" << nNextHeight; + db << "UPDATE nodes SET hash = NULL WHERE name IN " "(SELECT nodeName FROM supports WHERE validHeight = ?1 AND expirationHeight > ?1)" << nNextHeight; diff --git a/src/rpc/claimtrie.cpp b/src/rpc/claimtrie.cpp index 0d88bfc4d..fa0b30222 100644 --- a/src/rpc/claimtrie.cpp +++ b/src/rpc/claimtrie.cpp @@ -742,47 +742,92 @@ UniValue getclaimproofbyseq(const JSONRPCRequest& request) return proofToJSON(proof); } -extern bool UndoReadFromDisk(CBlockUndo&, const CBlockIndex*); - -template -UniValue removedToJSON(const std::vector>& undo) -{ - UniValue ret(UniValue::VARR); - for (auto& u : undo) { - auto outPoint = COutPoint(u.second.outPoint); - ret.push_back(ClaimIdHash(outPoint.hash, outPoint.n).ToString()); - } - return ret; -} - UniValue getchangesinblock(const JSONRPCRequest& request) { validateRequest(request, GETCHANGESINBLOCK, 0, 1); - CBlockUndo undo; + CBlock block; + LOCK(cs_main); + bool allowSupportMetadata; + CCoinsViewCache coinsCache(pcoinsTip.get()); { - LOCK(cs_main); auto index = chainActive.Tip(); if (request.params.size() > 0) index = BlockHashIndex(ParseHashV(request.params[0], T_BLOCKHASH " (optional parameter)")); - if (!UndoReadFromDisk(undo, index)) + if (!ReadBlockFromDisk(block, index, Params().GetConsensus())) throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read the undo block for height " + std::to_string(index->nHeight)); + + allowSupportMetadata = index->nHeight >= Params().GetConsensus().nAllClaimsInMerkleForkHeight; } - auto addedUpdated = [](const insertUndoType& insertUndo) { - UniValue added(UniValue::VARR); - for (auto& a : insertUndo) - added.push_back(ClaimIdHash(uint256(a.outPoint.hash), a.outPoint.n).ToString()); - return added; + UniValue claimsAddUp(UniValue::VARR), + claimsRm(UniValue::VARR), + supportsAddUp(UniValue::VARR), + supportsRm(UniValue::VARR); + + int op; + std::vector > vvchParams; + + auto findScriptKey = [&block](const COutPoint& point) -> CScript { + for (auto& tx : block.vtx) + if (tx->GetHash() == point.hash && point.n < tx->vout.size()) + return tx->vout[point.n].scriptPubKey; + return CScript{}; }; + for (auto& tx : block.vtx) { + if (tx->IsCoinBase()) + continue; + + for (auto& txin : tx->vin) { + const Coin& coin = coinsCache.AccessCoin(txin.prevout); + CScript scriptPubKey = coin.out.IsNull() ? + findScriptKey(txin.prevout) : coin.out.scriptPubKey; + + if (scriptPubKey.empty()) + continue; + + if (!DecodeClaimScript(scriptPubKey, op, vvchParams, allowSupportMetadata)) + continue; + + switch (op) { + case OP_CLAIM_NAME: + claimsRm.push_back(ClaimIdHash(txin.prevout.hash, txin.prevout.n).ToString()); + break; + case OP_UPDATE_CLAIM: + claimsRm.push_back(uint160(vvchParams[1]).ToString()); + break; + case OP_SUPPORT_CLAIM: + supportsRm.push_back(uint160(vvchParams[1]).ToString()); + } + } + + for (std::size_t i = 0; i < tx->vout.size(); ++i) { + auto& txout = tx->vout[i]; + if (txout.scriptPubKey.empty()) + continue; + + if (!DecodeClaimScript(txout.scriptPubKey, op, vvchParams, allowSupportMetadata)) + continue; + + switch (op) { + case OP_CLAIM_NAME: + case OP_UPDATE_CLAIM: + claimsAddUp.push_back(ClaimIdHash(tx->GetHash(), i).ToString()); + break; + case OP_SUPPORT_CLAIM: + supportsAddUp.push_back(ClaimIdHash(tx->GetHash(), i).ToString()); + } + } + } + UniValue result(UniValue::VOBJ); - result.pushKV(T_CLAIMSADDEDORUPDATED, addedUpdated(undo.insertUndo)); - result.pushKV(T_CLAIMSREMOVED, removedToJSON(undo.expireUndo)); - result.pushKV(T_SUPPORTSADDEDORUPDATED, addedUpdated(undo.insertSupportUndo)); - result.pushKV(T_SUPPORTSREMOVED, removedToJSON(undo.expireSupportUndo)); + result.pushKV(T_CLAIMSADDEDORUPDATED, claimsAddUp); + result.pushKV(T_CLAIMSREMOVED, claimsRm); + result.pushKV(T_SUPPORTSADDEDORUPDATED, supportsAddUp); + result.pushKV(T_SUPPORTSREMOVED, supportsRm); return result; } diff --git a/src/test/claimtrierpc_tests.cpp b/src/test/claimtrierpc_tests.cpp index 644778cbb..c8d41e127 100644 --- a/src/test/claimtrierpc_tests.cpp +++ b/src/test/claimtrierpc_tests.cpp @@ -353,19 +353,16 @@ BOOST_AUTO_TEST_CASE(hash_bid_seq_claim_changes_test) claimHash = getValueHash(COutPoint(tx3.GetHash(), 0), result[T_LASTTAKEOVERHEIGHT].get_int()); ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash); - // TODO: repair this or ditch it -// auto getchangesinblock = tableRPC["getchangesinblock"]->actor; -// req.params = UniValue(UniValue::VARR); -// req.params.push_back(UniValue(blockhash.GetHex())); -// -// result = getchangesinblock(req); -// BOOST_REQUIRE_EQUAL(result[T_CLAIMSADDEDORUPDATED].size(), 3); -// BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED][0].get_str(), claimId2.GetHex()); -// BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED][1].get_str(), claimId3.GetHex()); -// BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED][2].get_str(), claimId4.GetHex()); -// BOOST_CHECK_EQUAL(result[T_CLAIMSREMOVED].size(), 0); -// BOOST_CHECK_EQUAL(result[T_SUPPORTSADDEDORUPDATED].size(), 0); -// BOOST_CHECK_EQUAL(result[T_SUPPORTSREMOVED].size(), 0); + auto getchangesinblock = tableRPC["getchangesinblock"]->actor; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(blockhash.GetHex())); + + result = getchangesinblock(req); + BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED].size(), 1); + BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED][0].get_str(), claimId4.GetHex()); + BOOST_CHECK_EQUAL(result[T_CLAIMSREMOVED].size(), 0); + BOOST_CHECK_EQUAL(result[T_SUPPORTSADDEDORUPDATED].size(), 0); + BOOST_CHECK_EQUAL(result[T_SUPPORTSREMOVED].size(), 0); } BOOST_AUTO_TEST_CASE(claim_rpc_pending_amount_test)