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:
Brannon King 2018-12-13 15:48:17 +01:00
parent b5a0c962d0
commit 02986f766c
4 changed files with 181 additions and 90 deletions

View file

@ -403,28 +403,6 @@ CAmount CClaimTrie::getTotalValueOfClaimsRecursive(const CClaimTrieNode* current
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* 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;
for (nodeMapType::const_iterator it = current->children.begin(); it != current->children.end(); ++it) {
const std::string str = name + char(it->first);
cachedNode = cache.find(str);
name.push_back(it->first);
cachedNode = cache.find(name);
if (cachedNode != cache.end())
recursiveFlattenTrie(str, cachedNode->second, nodes);
recursiveIterateTrie(name, cachedNode->second, callback);
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;
recursiveFlattenTrie("", getRoot(), nodes);
return nodes;
try {
std::string name;
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

View file

@ -132,8 +132,6 @@ typedef std::vector<CSupportValue> supportMapEntryType;
typedef std::map<unsigned char, CClaimTrieNode*> nodeMapType;
typedef std::pair<std::string, CClaimTrieNode> namedNodeType;
class CClaimTrieNode
{
public:
@ -317,7 +315,6 @@ public:
bool WriteToDisk();
bool ReadFromDisk(bool check = false);
std::vector<namedNodeType> flattenTrie() const;
bool getInfoForName(const std::string& name, CClaimValue& claim) const;
bool getLastTakeoverForName(const std::string& name, int& lastTakeoverHeight) const;
@ -392,9 +389,6 @@ private:
unsigned int getTotalClaimsRecursive(const CClaimTrieNode* current) const;
CAmount getTotalValueOfClaimsRecursive(const CClaimTrieNode* current,
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 updateQueueRow(int nHeight, claimQueueRowType& row);
@ -459,6 +453,27 @@ public:
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
{
public:
@ -533,7 +548,7 @@ public:
bool forkForExpirationChange(bool increment) const;
std::vector<namedNodeType> flattenTrie() const;
bool iterateTrie(CNodeCallback& callback) const;
claimsForNameType getClaimsForName(const std::string& name) const;
@ -635,7 +650,7 @@ protected:
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;
};

View file

@ -112,44 +112,65 @@ UniValue getclaimsintrie(const UniValue& params, bool fHelp)
RollBackTo(blockIndex, coinsCache, trieCache);
}
UniValue ret(UniValue::VARR);
std::vector<namedNodeType> nodes = trieCache.flattenTrie();
for (std::vector<namedNodeType>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
if (it->second.claims.empty()) continue;
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);
class CClaimsCallback : public CNodeCallback
{
public:
CClaimsCallback(UniValue& ret, const CCoinsViewCache& coinsCache) : nodes(ret), coinsCache(coinsCache)
{
}
UniValue node(UniValue::VOBJ);
node.push_back(Pair("name", it->first));
node.push_back(Pair("claims", claims));
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();
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;
}
@ -188,23 +209,40 @@ UniValue getclaimtrie(const UniValue& params, bool fHelp)
RollBackTo(blockIndex, coinsCache, trieCache);
}
UniValue ret(UniValue::VARR);
std::vector<namedNodeType> nodes = trieCache.flattenTrie();
for (std::vector<namedNodeType>::iterator it = nodes.begin(); it != nodes.end(); ++it)
class CClaimCallback : public CNodeCallback
{
UniValue node(UniValue::VOBJ);
node.push_back(Pair("name", it->first));
node.push_back(Pair("hash", it->second.hash.GetHex()));
CClaimValue claim;
if (it->second.getBestClaim(claim))
public:
CClaimCallback(UniValue& ret) : nodes(ret)
{
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;
}

View file

@ -274,5 +274,58 @@ BOOST_AUTO_TEST_CASE(recursive_prune_test)
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()