Replace flattenTrie by callback
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg> Use interruption point instead of boolean condition Signed-off-by: Anthony Fieroni <bvbfan@abv.bg> Add ability to earlier exit in rpc methods getclaimtrie and getclaimsintrie Signed-off-by: Anthony Fieroni <bvbfan@abv.bg> simplified early exit handling ran formatter
This commit is contained in:
parent
b5a0c962d0
commit
02986f766c
4 changed files with 181 additions and 90 deletions
|
@ -403,28 +403,6 @@ CAmount CClaimTrie::getTotalValueOfClaimsRecursive(const CClaimTrieNode* current
|
||||||
return value_in_subtrie;
|
return value_in_subtrie;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClaimTrie::recursiveFlattenTrie(const std::string& name, const CClaimTrieNode* current, std::vector<namedNodeType>& nodes) const
|
|
||||||
{
|
|
||||||
namedNodeType node(name, *current);
|
|
||||||
nodes.push_back(node);
|
|
||||||
for (nodeMapType::const_iterator it = current->children.begin(); it != current->children.end(); ++it)
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << name << it->first;
|
|
||||||
if (!recursiveFlattenTrie(ss.str(), it->second, nodes))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<namedNodeType> CClaimTrie::flattenTrie() const
|
|
||||||
{
|
|
||||||
std::vector<namedNodeType> nodes;
|
|
||||||
if (!recursiveFlattenTrie("", &root, nodes))
|
|
||||||
LogPrintf("%s: Something went wrong flattening the trie", __func__);
|
|
||||||
return nodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CClaimTrieNode* CClaimTrie::getNodeForName(const std::string& name) const
|
const CClaimTrieNode* CClaimTrie::getNodeForName(const std::string& name) const
|
||||||
{
|
{
|
||||||
const CClaimTrieNode* current = &root;
|
const CClaimTrieNode* current = &root;
|
||||||
|
@ -2548,25 +2526,32 @@ uint256 CClaimTrieCache::getLeafHashForProof(const std::string& currentPosition,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CClaimTrieCache::recursiveFlattenTrie(const std::string& name, const CClaimTrieNode* current, std::vector<namedNodeType>& nodes) const
|
void CClaimTrieCache::recursiveIterateTrie(std::string& name, const CClaimTrieNode* current, CNodeCallback& callback) const
|
||||||
{
|
{
|
||||||
nodes.push_back(std::make_pair(name, *current));
|
callback.visit(name, current);
|
||||||
|
|
||||||
nodeCacheType::const_iterator cachedNode;
|
nodeCacheType::const_iterator cachedNode;
|
||||||
for (nodeMapType::const_iterator it = current->children.begin(); it != current->children.end(); ++it) {
|
for (nodeMapType::const_iterator it = current->children.begin(); it != current->children.end(); ++it) {
|
||||||
const std::string str = name + char(it->first);
|
name.push_back(it->first);
|
||||||
cachedNode = cache.find(str);
|
cachedNode = cache.find(name);
|
||||||
if (cachedNode != cache.end())
|
if (cachedNode != cache.end())
|
||||||
recursiveFlattenTrie(str, cachedNode->second, nodes);
|
recursiveIterateTrie(name, cachedNode->second, callback);
|
||||||
else
|
else
|
||||||
recursiveFlattenTrie(str, it->second, nodes);
|
recursiveIterateTrie(name, it->second, callback);
|
||||||
|
name.erase(name.end() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<namedNodeType> CClaimTrieCache::flattenTrie() const
|
bool CClaimTrieCache::iterateTrie(CNodeCallback& callback) const
|
||||||
{
|
{
|
||||||
std::vector<namedNodeType> nodes;
|
try {
|
||||||
recursiveFlattenTrie("", getRoot(), nodes);
|
std::string name;
|
||||||
return nodes;
|
recursiveIterateTrie(name, getRoot(), callback);
|
||||||
|
assert(name.empty());
|
||||||
|
} catch (const CNodeCallback::CRecursionInterruptionException& ex) {
|
||||||
|
return ex.success;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
claimsForNameType CClaimTrieCache::getClaimsForName(const std::string& name) const
|
claimsForNameType CClaimTrieCache::getClaimsForName(const std::string& name) const
|
||||||
|
|
|
@ -132,8 +132,6 @@ typedef std::vector<CSupportValue> supportMapEntryType;
|
||||||
|
|
||||||
typedef std::map<unsigned char, CClaimTrieNode*> nodeMapType;
|
typedef std::map<unsigned char, CClaimTrieNode*> nodeMapType;
|
||||||
|
|
||||||
typedef std::pair<std::string, CClaimTrieNode> namedNodeType;
|
|
||||||
|
|
||||||
class CClaimTrieNode
|
class CClaimTrieNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -317,7 +315,6 @@ public:
|
||||||
bool WriteToDisk();
|
bool WriteToDisk();
|
||||||
bool ReadFromDisk(bool check = false);
|
bool ReadFromDisk(bool check = false);
|
||||||
|
|
||||||
std::vector<namedNodeType> flattenTrie() const;
|
|
||||||
bool getInfoForName(const std::string& name, CClaimValue& claim) const;
|
bool getInfoForName(const std::string& name, CClaimValue& claim) const;
|
||||||
bool getLastTakeoverForName(const std::string& name, int& lastTakeoverHeight) const;
|
bool getLastTakeoverForName(const std::string& name, int& lastTakeoverHeight) const;
|
||||||
|
|
||||||
|
@ -392,9 +389,6 @@ private:
|
||||||
unsigned int getTotalClaimsRecursive(const CClaimTrieNode* current) const;
|
unsigned int getTotalClaimsRecursive(const CClaimTrieNode* current) const;
|
||||||
CAmount getTotalValueOfClaimsRecursive(const CClaimTrieNode* current,
|
CAmount getTotalValueOfClaimsRecursive(const CClaimTrieNode* current,
|
||||||
bool fControllingOnly) const;
|
bool fControllingOnly) const;
|
||||||
bool recursiveFlattenTrie(const std::string& name,
|
|
||||||
const CClaimTrieNode* current,
|
|
||||||
std::vector<namedNodeType>& nodes) const;
|
|
||||||
|
|
||||||
void markNodeDirty(const std::string& name, CClaimTrieNode* node);
|
void markNodeDirty(const std::string& name, CClaimTrieNode* node);
|
||||||
void updateQueueRow(int nHeight, claimQueueRowType& row);
|
void updateQueueRow(int nHeight, claimQueueRowType& row);
|
||||||
|
@ -459,6 +453,27 @@ public:
|
||||||
int nHeightOfLastTakeover;
|
int nHeightOfLastTakeover;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CNodeCallback {
|
||||||
|
struct CRecursionInterruptionException : public std::exception {
|
||||||
|
const bool success;
|
||||||
|
explicit CRecursionInterruptionException(bool success) : success(success) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~CNodeCallback()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback to be called on every trie node
|
||||||
|
* @param[in] name full name of the node
|
||||||
|
* @param[in] node pointer to node itself
|
||||||
|
*
|
||||||
|
* To breakout early throw an exception.
|
||||||
|
* Throwing CRecursionInterruptionException will allow you to set the return value of iterateTrie.
|
||||||
|
*/
|
||||||
|
virtual void visit(const std::string& name, const CClaimTrieNode* node) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class CClaimTrieCache
|
class CClaimTrieCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -533,7 +548,7 @@ public:
|
||||||
|
|
||||||
bool forkForExpirationChange(bool increment) const;
|
bool forkForExpirationChange(bool increment) const;
|
||||||
|
|
||||||
std::vector<namedNodeType> flattenTrie() const;
|
bool iterateTrie(CNodeCallback& callback) const;
|
||||||
|
|
||||||
claimsForNameType getClaimsForName(const std::string& name) const;
|
claimsForNameType getClaimsForName(const std::string& name) const;
|
||||||
|
|
||||||
|
@ -635,7 +650,7 @@ protected:
|
||||||
|
|
||||||
int getNumBlocksOfContinuousOwnership(const std::string& name) const;
|
int getNumBlocksOfContinuousOwnership(const std::string& name) const;
|
||||||
|
|
||||||
void recursiveFlattenTrie(const std::string& name, const CClaimTrieNode* current, std::vector<namedNodeType>& nodes) const;
|
void recursiveIterateTrie(std::string& name, const CClaimTrieNode* current, CNodeCallback& callback) const;
|
||||||
|
|
||||||
const CClaimTrieNode* getNodeForName(const std::string& name) const;
|
const CClaimTrieNode* getNodeForName(const std::string& name) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -112,44 +112,65 @@ UniValue getclaimsintrie(const UniValue& params, bool fHelp)
|
||||||
RollBackTo(blockIndex, coinsCache, trieCache);
|
RollBackTo(blockIndex, coinsCache, trieCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue ret(UniValue::VARR);
|
class CClaimsCallback : public CNodeCallback
|
||||||
std::vector<namedNodeType> nodes = trieCache.flattenTrie();
|
{
|
||||||
for (std::vector<namedNodeType>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
|
public:
|
||||||
if (it->second.claims.empty()) continue;
|
CClaimsCallback(UniValue& ret, const CCoinsViewCache& coinsCache) : nodes(ret), coinsCache(coinsCache)
|
||||||
|
{
|
||||||
UniValue claims(UniValue::VARR);
|
|
||||||
for (std::vector<CClaimValue>::iterator itClaims = it->second.claims.begin(); itClaims != it->second.claims.end(); ++itClaims) {
|
|
||||||
UniValue claim(UniValue::VOBJ);
|
|
||||||
claim.push_back(Pair("claimId", itClaims->claimId.GetHex()));
|
|
||||||
claim.push_back(Pair("txid", itClaims->outPoint.hash.GetHex()));
|
|
||||||
claim.push_back(Pair("n", (int)itClaims->outPoint.n));
|
|
||||||
claim.push_back(Pair("amount", ValueFromAmount(itClaims->nAmount)));
|
|
||||||
claim.push_back(Pair("height", itClaims->nHeight));
|
|
||||||
const CCoins* coin = coinsCache.AccessCoins(itClaims->outPoint.hash);
|
|
||||||
if (!coin) {
|
|
||||||
LogPrintf("%s: %s does not exist in the coins view, despite being associated with a name\n",
|
|
||||||
__func__, itClaims->outPoint.hash.GetHex());
|
|
||||||
claim.push_back(Pair("error", "No value found for claim"));
|
|
||||||
} else if (!coin->IsAvailable(itClaims->outPoint.n)) {
|
|
||||||
LogPrintf("%s: the specified txout of %s appears to have been spent\n", __func__, itClaims->outPoint.hash.GetHex());
|
|
||||||
claim.push_back(Pair("error", "Txout spent"));
|
|
||||||
} else {
|
|
||||||
int op;
|
|
||||||
std::vector<std::vector<unsigned char> > vvchParams;
|
|
||||||
if (!DecodeClaimScript(coin->vout[itClaims->outPoint.n].scriptPubKey, op, vvchParams)) {
|
|
||||||
LogPrintf("%s: the specified txout of %s does not have an claim command\n", __func__, itClaims->outPoint.hash.GetHex());
|
|
||||||
}
|
|
||||||
std::string sValue(vvchParams[1].begin(), vvchParams[1].end());
|
|
||||||
claim.push_back(Pair("value", sValue));
|
|
||||||
}
|
|
||||||
claims.push_back(claim);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue node(UniValue::VOBJ);
|
void visit(const std::string& name, const CClaimTrieNode* node)
|
||||||
node.push_back(Pair("name", it->first));
|
{
|
||||||
node.push_back(Pair("claims", claims));
|
if (ShutdownRequested())
|
||||||
ret.push_back(node);
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Shutdown requested");
|
||||||
}
|
|
||||||
|
boost::this_thread::interruption_point();
|
||||||
|
|
||||||
|
if (node->claims.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
UniValue claims(UniValue::VARR);
|
||||||
|
for (std::vector<CClaimValue>::const_iterator itClaims = node->claims.begin(); itClaims != node->claims.end(); ++itClaims) {
|
||||||
|
UniValue claim(UniValue::VOBJ);
|
||||||
|
claim.push_back(Pair("claimId", itClaims->claimId.GetHex()));
|
||||||
|
claim.push_back(Pair("txid", itClaims->outPoint.hash.GetHex()));
|
||||||
|
claim.push_back(Pair("n", (int)itClaims->outPoint.n));
|
||||||
|
claim.push_back(Pair("amount", ::ValueFromAmount(itClaims->nAmount)));
|
||||||
|
claim.push_back(Pair("height", itClaims->nHeight));
|
||||||
|
const CCoins* coin = coinsCache.AccessCoins(itClaims->outPoint.hash);
|
||||||
|
if (!coin) {
|
||||||
|
LogPrintf("%s: %s does not exist in the coins view, despite being associated with a name\n",
|
||||||
|
__func__, itClaims->outPoint.hash.GetHex());
|
||||||
|
claim.push_back(Pair("error", "No value found for claim"));
|
||||||
|
} else if (!coin->IsAvailable(itClaims->outPoint.n)) {
|
||||||
|
LogPrintf("%s: the specified txout of %s appears to have been spent\n", __func__, itClaims->outPoint.hash.GetHex());
|
||||||
|
claim.push_back(Pair("error", "Txout spent"));
|
||||||
|
} else {
|
||||||
|
int op;
|
||||||
|
std::vector<std::vector<unsigned char> > vvchParams;
|
||||||
|
if (!DecodeClaimScript(coin->vout[itClaims->outPoint.n].scriptPubKey, op, vvchParams)) {
|
||||||
|
LogPrintf("%s: the specified txout of %s does not have an claim command\n", __func__, itClaims->outPoint.hash.GetHex());
|
||||||
|
}
|
||||||
|
std::string sValue(vvchParams[1].begin(), vvchParams[1].end());
|
||||||
|
claim.push_back(Pair("value", sValue));
|
||||||
|
}
|
||||||
|
claims.push_back(claim);
|
||||||
|
}
|
||||||
|
|
||||||
|
UniValue nodeObj(UniValue::VOBJ);
|
||||||
|
nodeObj.push_back(Pair("name", name));
|
||||||
|
nodeObj.push_back(Pair("claims", claims));
|
||||||
|
nodes.push_back(nodeObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
UniValue& nodes;
|
||||||
|
const CCoinsViewCache& coinsCache;
|
||||||
|
};
|
||||||
|
|
||||||
|
UniValue ret(UniValue::VARR);
|
||||||
|
CClaimsCallback claimsCallback(ret, coinsCache);
|
||||||
|
trieCache.iterateTrie(claimsCallback);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,23 +209,40 @@ UniValue getclaimtrie(const UniValue& params, bool fHelp)
|
||||||
RollBackTo(blockIndex, coinsCache, trieCache);
|
RollBackTo(blockIndex, coinsCache, trieCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue ret(UniValue::VARR);
|
class CClaimCallback : public CNodeCallback
|
||||||
std::vector<namedNodeType> nodes = trieCache.flattenTrie();
|
|
||||||
for (std::vector<namedNodeType>::iterator it = nodes.begin(); it != nodes.end(); ++it)
|
|
||||||
{
|
{
|
||||||
UniValue node(UniValue::VOBJ);
|
public:
|
||||||
node.push_back(Pair("name", it->first));
|
CClaimCallback(UniValue& ret) : nodes(ret)
|
||||||
node.push_back(Pair("hash", it->second.hash.GetHex()));
|
|
||||||
CClaimValue claim;
|
|
||||||
if (it->second.getBestClaim(claim))
|
|
||||||
{
|
{
|
||||||
node.push_back(Pair("txid", claim.outPoint.hash.GetHex()));
|
|
||||||
node.push_back(Pair("n", (int)claim.outPoint.n));
|
|
||||||
node.push_back(Pair("value", ValueFromAmount(claim.nAmount)));
|
|
||||||
node.push_back(Pair("height", claim.nHeight));
|
|
||||||
}
|
}
|
||||||
ret.push_back(node);
|
|
||||||
}
|
void visit(const std::string& name, const CClaimTrieNode* node)
|
||||||
|
{
|
||||||
|
if (ShutdownRequested())
|
||||||
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Shutdown requested");
|
||||||
|
|
||||||
|
boost::this_thread::interruption_point();
|
||||||
|
|
||||||
|
UniValue nodeObj(UniValue::VOBJ);
|
||||||
|
nodeObj.push_back(Pair("name", name));
|
||||||
|
nodeObj.push_back(Pair("hash", node->hash.GetHex()));
|
||||||
|
CClaimValue claim;
|
||||||
|
if (node->getBestClaim(claim)) {
|
||||||
|
nodeObj.push_back(Pair("txid", claim.outPoint.hash.GetHex()));
|
||||||
|
nodeObj.push_back(Pair("n", (int)claim.outPoint.n));
|
||||||
|
nodeObj.push_back(Pair("value", ::ValueFromAmount(claim.nAmount)));
|
||||||
|
nodeObj.push_back(Pair("height", claim.nHeight));
|
||||||
|
}
|
||||||
|
nodes.push_back(nodeObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
UniValue& nodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
UniValue ret(UniValue::VARR);
|
||||||
|
CClaimCallback claimCallback(ret);
|
||||||
|
trieCache.iterateTrie(claimCallback);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -274,5 +274,58 @@ BOOST_AUTO_TEST_CASE(recursive_prune_test)
|
||||||
BOOST_CHECK_EQUAL(0, it->second->children.size());
|
BOOST_CHECK_EQUAL(0, it->second->children.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(iteratetrie_test)
|
||||||
|
{
|
||||||
|
BOOST_CHECK(pclaimTrie->empty());
|
||||||
|
CClaimTrieCacheTest ctc(pclaimTrie);
|
||||||
|
|
||||||
|
uint256 hash0(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
|
||||||
|
CMutableTransaction tx1 = BuildTransaction(hash0);
|
||||||
|
|
||||||
|
const uint256 txhash = tx1.GetHash();
|
||||||
|
CClaimValue claimVal(COutPoint(txhash, 0), ClaimIdHash(txhash, 0), CAmount(10), 0, 0);
|
||||||
|
ctc.insertClaimIntoTrie("test", claimVal);
|
||||||
|
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
struct TestCallBack : public CNodeCallback {
|
||||||
|
TestCallBack(int& count) : count(count)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit(const std::string& name, const CClaimTrieNode* node)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
if (name == "test") {
|
||||||
|
BOOST_CHECK(node->claims.size() == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int& count;
|
||||||
|
} testCallback(count);
|
||||||
|
|
||||||
|
BOOST_CHECK(ctc.iterateTrie(testCallback));
|
||||||
|
BOOST_CHECK(count == 5);
|
||||||
|
|
||||||
|
count = 3;
|
||||||
|
|
||||||
|
struct TestCallBack2 : public CNodeCallback {
|
||||||
|
TestCallBack2(int& count) : count(count)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit(const std::string& name, const CClaimTrieNode* node)
|
||||||
|
{
|
||||||
|
if (--count <= 0)
|
||||||
|
throw CRecursionInterruptionException(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
int& count;
|
||||||
|
} testCallback2(count);
|
||||||
|
|
||||||
|
BOOST_CHECK(!ctc.iterateTrie(testCallback2));
|
||||||
|
BOOST_CHECK(count == 0);
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
Loading…
Reference in a new issue