Add block hash parameter to claimtrie rpc methods

Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
This commit is contained in:
Anthony Fieroni 2018-08-10 17:12:35 -06:00 committed by Brannon King
parent 24da3ac57a
commit f86eb54077
6 changed files with 650 additions and 291 deletions

View file

@ -527,39 +527,26 @@ claimsForNameType CClaimTrie::getClaimsForName(const std::string& name) const
}
//return effective amount from claim, retuns 0 if claim is not found
CAmount CClaimTrie::getEffectiveAmountForClaim(const std::string& name, uint160 claimId) const
CAmount CClaimTrie::getEffectiveAmountForClaim(const std::string& name, const uint160& claimId, std::vector<CSupportValue>* supports) const
{
std::vector<CSupportValue> supports;
return getEffectiveAmountForClaimWithSupports(name, claimId, supports);
return getEffectiveAmountForClaim(getClaimsForName(name), claimId, supports);
}
//return effective amount from claim and the supports used as inputs, retuns 0 if claim is not found
CAmount CClaimTrie::getEffectiveAmountForClaimWithSupports(const std::string& name, uint160 claimId,
std::vector<CSupportValue>& supports) const
CAmount CClaimTrie::getEffectiveAmountForClaim(const claimsForNameType& claims, const uint160& claimId, std::vector<CSupportValue>* supports) const
{
claimsForNameType claims = getClaimsForName(name);
CAmount effectiveAmount = 0;
bool claim_found = false;
for (std::vector<CClaimValue>::iterator it=claims.claims.begin(); it!=claims.claims.end(); ++it)
{
if (it->claimId == claimId && it->nValidAtHeight < nCurrentHeight)
{
for (std::vector<CClaimValue>::const_iterator it = claims.claims.begin(); it != claims.claims.end(); ++it) {
if (it->claimId == claimId && it->nValidAtHeight < nCurrentHeight) {
effectiveAmount += it->nAmount;
claim_found = true;
for (std::vector<CSupportValue>::const_iterator it = claims.supports.begin(); it != claims.supports.end(); ++it) {
if (it->supportedClaimId == claimId && it->nValidAtHeight < nCurrentHeight) {
effectiveAmount += it->nAmount;
if (supports) supports->push_back(*it);
}
}
break;
}
}
if (!claim_found)
return effectiveAmount;
for (std::vector<CSupportValue>::iterator it=claims.supports.begin(); it!=claims.supports.end(); ++it)
{
if (it->supportedClaimId == claimId && it->nValidAtHeight < nCurrentHeight)
{
effectiveAmount += it->nAmount;
supports.push_back(*it);
}
}
return effectiveAmount;
}
@ -2463,25 +2450,26 @@ bool CClaimTrieCache::getLastTakeoverForName(const std::string& name, int& nLast
int CClaimTrieCache::getNumBlocksOfContinuousOwnership(const std::string& name) const
{
const CClaimTrieNode* node = NULL;
nodeCacheType::const_iterator itCache = cache.find(name);
if (itCache != cache.end())
{
node = itCache->second;
}
if (!node)
{
node = base->getNodeForName(name);
}
if (!node || node->claims.empty())
{
return 0;
}
const CClaimTrieNode* node = getNodeForName(name);
if (!node || node->claims.empty()) return 0;
int nLastTakeoverHeight;
assert(getLastTakeoverForName(name, nLastTakeoverHeight));
return nCurrentHeight - nLastTakeoverHeight;
}
const CClaimTrieNode* CClaimTrieCache::getNodeForName(const std::string& name) const
{
const CClaimTrieNode* node = NULL;
nodeCacheType::const_iterator itCache = cache.find(name);
if (itCache != cache.end()) {
node = itCache->second;
}
if (!node) {
node = base->getNodeForName(name);
}
return node;
}
int CClaimTrieCache::getDelayForName(const std::string& name) const
{
if (!fRequireTakeoverHeights)
@ -2570,10 +2558,125 @@ uint256 CClaimTrieCache::getLeafHashForProof(const std::string& currentPosition,
}
}
CClaimTrieProof CClaimTrieCache::getProofForName(const std::string& name) const
void CClaimTrieCache::recursiveFlattenTrie(const std::string& name, const CClaimTrieNode* current, std::vector<namedNodeType>& nodes) const
{
nodes.push_back(std::make_pair(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);
if (cachedNode != cache.end())
recursiveFlattenTrie(str, cachedNode->second, nodes);
else
recursiveFlattenTrie(str, it->second, nodes);
}
}
std::vector<namedNodeType> CClaimTrieCache::flattenTrie() const
{
std::vector<namedNodeType> nodes;
recursiveFlattenTrie("", &(base->root), nodes);
return nodes;
}
claimsForNameType CClaimTrieCache::getClaimsForName(const std::string& name) const
{
int nLastTakeoverHeight = 0;
std::vector<CClaimValue> claims;
if (const CClaimTrieNode* node = getNodeForName(name)) {
claims = node->claims;
getLastTakeoverForName(name, nLastTakeoverHeight);
}
supportMapEntryType supports;
getSupportsForName(name, supports);
queueNameType::const_iterator itQueueNameCache = getQueueCacheNameRow(name, false);
if (itQueueNameCache != claimQueueNameCache.end()) {
const queueNameRowType& namedClaimRow = itQueueNameCache->second;
for (queueNameRowType::const_iterator itClaimsForName = namedClaimRow.begin(); itClaimsForName != namedClaimRow.end(); ++itClaimsForName) {
claimQueueType::const_iterator itQueueCache = getQueueCacheRow(itClaimsForName->nHeight, false);
if (itQueueCache != claimQueueCache.end()) {
const claimQueueRowType& claimRow = itQueueCache->second;
for (claimQueueRowType::const_iterator itClaimRow = claimRow.begin(); itClaimRow != claimRow.end(); ++itClaimRow) {
if (itClaimRow->first == name && itClaimRow->second.outPoint == itClaimsForName->outPoint) {
claims.push_back(itClaimRow->second);
break;
}
}
}
}
}
queueNameType::const_iterator itSupportQueueNameCache = getSupportQueueCacheNameRow(name, false);
if (itSupportQueueNameCache != supportQueueNameCache.end()) {
const queueNameRowType& namedSupportRow = itSupportQueueNameCache->second;
for (queueNameRowType::const_iterator itSupportsForName = namedSupportRow.begin(); itSupportsForName != namedSupportRow.end(); ++itSupportsForName) {
supportQueueType::const_iterator itSupportQueueCache = getSupportQueueCacheRow(itSupportsForName->nHeight, false);
if (itSupportQueueCache != supportQueueCache.end()) {
const supportQueueRowType& supportRow = itSupportQueueCache->second;
for (supportQueueRowType::const_iterator itSupportRow = supportRow.begin(); itSupportRow != supportRow.end(); ++itSupportRow) {
if (itSupportRow->first == name && itSupportRow->second.outPoint == itSupportsForName->outPoint) {
supports.push_back(itSupportRow->second);
break;
}
}
}
}
}
return claimsForNameType(claims, supports, nLastTakeoverHeight);
}
CAmount CClaimTrieCache::getEffectiveAmountForClaim(const std::string& name, const uint160& claimId, std::vector<CSupportValue>* supports) const
{
return getEffectiveAmountForClaim(getClaimsForName(name), claimId, supports);
}
CAmount CClaimTrieCache::getEffectiveAmountForClaim(const claimsForNameType& claims, const uint160& claimId, std::vector<CSupportValue>* supports) const
{
CAmount effectiveAmount = 0;
for (std::vector<CClaimValue>::const_iterator it = claims.claims.begin(); it != claims.claims.end(); ++it) {
if (it->claimId == claimId && it->nValidAtHeight < nCurrentHeight) {
effectiveAmount += it->nAmount;
for (std::vector<CSupportValue>::const_iterator it = claims.supports.begin(); it != claims.supports.end(); ++it) {
if (it->supportedClaimId == claimId && it->nValidAtHeight < nCurrentHeight) {
effectiveAmount += it->nAmount;
if (supports) supports->push_back(*it);
}
}
break;
}
}
return effectiveAmount;
}
bool CClaimTrieCache::getInfoForName(const std::string& name, CClaimValue& claim) const
{
if (dirty())
getMerkleHash();
CClaimTrieNode* current = &(base->root);
nodeCacheType::const_iterator cachedNode;
for (std::string::const_iterator itName = name.begin(); current; ++itName) {
std::string currentPosition(name.begin(), itName);
cachedNode = cache.find(currentPosition);
if (cachedNode != cache.end())
current = cachedNode->second;
if (itName == name.end())
return current->getBestClaim(claim);
nodeMapType::const_iterator itChildren = current->children.find(*itName);
if (itChildren != current->children.end()) {
current = itChildren->second;
}
}
return false;
}
bool CClaimTrieCache::getProofForName(const std::string& name, CClaimTrieProof& proof) const
{
if (dirty())
getMerkleHash();
std::vector<CClaimTrieProofNode> nodes;
CClaimTrieNode* current = &(base->root);
nodeCacheType::const_iterator cachedNode;
@ -2592,7 +2695,8 @@ CClaimTrieProof CClaimTrieCache::getProofForName(const std::string& name) const
if (fNodeHasValue)
{
int nHeightOfLastTakeover;
assert(getLastTakeoverForName(currentPosition, nHeightOfLastTakeover));
if (!getLastTakeoverForName(currentPosition, nHeightOfLastTakeover))
return false;
valueHash = getValueHash(claim.outPoint, nHeightOfLastTakeover);
}
std::vector<std::pair<unsigned char, uint256> > children;
@ -2617,7 +2721,8 @@ CClaimTrieProof CClaimTrieCache::getProofForName(const std::string& name) const
if (fNameHasValue)
{
outPoint = claim.outPoint;
assert(getLastTakeoverForName(name, nHeightOfLastTakeover));
if (!getLastTakeoverForName(name, nHeightOfLastTakeover))
return false;
}
valueHash.SetNull();
}
@ -2625,8 +2730,8 @@ CClaimTrieProof CClaimTrieCache::getProofForName(const std::string& name) const
nodes.push_back(node);
current = nextCurrent;
}
return CClaimTrieProof(nodes, fNameHasValue, outPoint,
nHeightOfLastTakeover);
proof = CClaimTrieProof(nodes, fNameHasValue, outPoint, nHeightOfLastTakeover);
return true;
}

View file

@ -323,9 +323,8 @@ public:
bool getLastTakeoverForName(const std::string& name, int& lastTakeoverHeight) const;
claimsForNameType getClaimsForName(const std::string& name) const;
CAmount getEffectiveAmountForClaim(const std::string& name, uint160 claimId) const;
CAmount getEffectiveAmountForClaimWithSupports(const std::string& name, uint160 claimId,
std::vector<CSupportValue>& supports) const;
CAmount getEffectiveAmountForClaim(const std::string& name, const uint160& claimId, std::vector<CSupportValue>* supports = NULL) const;
CAmount getEffectiveAmountForClaim(const claimsForNameType& claims, const uint160& claimId, std::vector<CSupportValue>* supports = NULL) const;
bool queueEmpty() const;
bool supportEmpty() const;
@ -519,7 +518,9 @@ public:
bool removeClaimFromTrie(const std::string& name, const COutPoint& outPoint,
CClaimValue& claim,
bool fCheckTakeover = false) const;
CClaimTrieProof getProofForName(const std::string& name) const;
bool getProofForName(const std::string& name, CClaimTrieProof& proof) const;
bool getInfoForName(const std::string& name, CClaimValue& claim) const;
bool finalizeDecrement() const;
@ -528,6 +529,12 @@ public:
bool forkForExpirationChange(bool increment) const;
std::vector<namedNodeType> flattenTrie() const;
claimsForNameType getClaimsForName(const std::string& name) const;
CAmount getEffectiveAmountForClaim(const std::string& name, const uint160& claimId, std::vector<CSupportValue>* supports = NULL) const;
CAmount getEffectiveAmountForClaim(const claimsForNameType& claims, const uint160& claimId, std::vector<CSupportValue>* supports = NULL) const;
protected:
CClaimTrie* base;
@ -625,6 +632,10 @@ protected:
bool getOriginalInfoForName(const std::string& name, CClaimValue& claim) const;
int getNumBlocksOfContinuousOwnership(const std::string& name) const;
void recursiveFlattenTrie(const std::string& name, const CClaimTrieNode* current, std::vector<namedNodeType>& nodes) const;
const CClaimTrieNode* getNodeForName(const std::string& name) const;
};
#endif // BITCOIN_CLAIMTRIE_H

View file

@ -4267,40 +4267,43 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
return true;
}
bool RollBackTo(const CBlockIndex* targetIndex, CCoinsViewCache& coinsCache, CClaimTrieCache& trieCache)
{
AssertLockHeld(cs_main);
for (CBlockIndex* index = chainActive.Tip(); index && index != targetIndex; index = index->pprev) {
boost::this_thread::interruption_point();
CBlock block;
if (!ReadBlockFromDisk(block, index, Params().GetConsensus()))
return false; // return error() instead?
if (coinsCache.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage() > nCoinCacheUsage)
return false; // don't allow a single query to chew up all our memory?
if (ShutdownRequested())
return false;
CValidationState state;
if (!DisconnectBlock(block, state, index, coinsCache, trieCache))
return false;
if (state.IsError())
return false;
}
return true;
}
bool GetProofForName(const CBlockIndex* pindexProof, const std::string& name, CClaimTrieProof& proof)
{
AssertLockHeld(cs_main);
if (!chainActive.Contains(pindexProof))
{
return false;
}
CCoinsViewCache coins(pcoinsTip);
CCoinsViewCache coinsCache(pcoinsTip);
CClaimTrieCache trieCache(pclaimTrie);
CBlockIndex* pindexState = chainActive.Tip();
CValidationState state;
for (CBlockIndex *pindex = chainActive.Tip(); pindex && pindex->pprev && pindexState != pindexProof; pindex=pindex->pprev)
{
boost::this_thread::interruption_point();
CBlock block;
if (!ReadBlockFromDisk(block, pindex, Params().GetConsensus()))
{
return false;
}
if (pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage)
{
bool fClean = true;
if (!DisconnectBlock(block, state, pindex, coins, trieCache, &fClean))
{
return false;
}
pindexState = pindex->pprev;
}
if (ShutdownRequested())
return false;
}
assert(pindexState == pindexProof);
proof = trieCache.getProofForName(name);
return true;
if (RollBackTo(pindexProof, coinsCache, trieCache))
return trieCache.getProofForName(name, proof);
return false;
}
void UnloadBlockIndex()

View file

@ -225,6 +225,8 @@ FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false);
FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false);
/** Translation to a filesystem path */
boost::filesystem::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix);
/** Utility method for going back to a previous state **/
bool RollBackTo(const CBlockIndex* targetIndex, CCoinsViewCache& coinsCache, CClaimTrieCache& trieCache);
/** Get a cryptographic proof that a name maps to a value **/
bool GetProofForName(const CBlockIndex* pindexProof, const std::string& name, CClaimTrieProof& proof);
/** Import blocks from an external file */

View file

@ -1,8 +1,10 @@
#include "boost/scope_exit.hpp"
#include "consensus/validation.h"
#include "main.h"
#include "nameclaim.h"
#include "rpc/server.h"
#include "univalue.h"
#include "txmempool.h"
#include "univalue.h"
// Maximum block decrement that is allowed from rpc calls
const int MAX_RPC_BLOCK_DECREMENTS = 50;
@ -22,143 +24,177 @@ uint160 ParseClaimtrieId(const UniValue& v, const std::string& strName)
return result;
}
static CBlockIndex* BlockHashIndex(const uint256& blockHash)
{
AssertLockHeld(cs_main);
if (mapBlockIndex.count(blockHash) == 0)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
CBlockIndex* pblockIndex = mapBlockIndex[blockHash];
if (!chainActive.Contains(pblockIndex))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not in main chain");
if (chainActive.Tip()->nHeight > (pblockIndex->nHeight + MAX_RPC_BLOCK_DECREMENTS))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Block too deep to regenerate it");
return pblockIndex;
}
UniValue getclaimsintrie(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 0)
if (fHelp || params.size() > 1)
throw std::runtime_error(
"getclaimsintrie\n"
"Return all claims in the name trie.\n"
"Arguments:\n"
"None\n"
"1. \"blockhash\" (string, optional) get claims in the trie\n"
" at the block specified\n"
" by this block hash.\n"
" If none is given,\n"
" the latest active\n"
" block will be used.\n"
"Result: \n"
"[\n"
" {\n"
" \"name\" (string) the name claimed\n"
" \"claims\": [ (array of object) the claims for this name\n"
" \"name\" (string) the name claimed\n"
" \"claims\": [ (array of object) the claims for this name\n"
" {\n"
" \"claimId\" (string) the claimId of the claim\n"
" \"txid\" (string) the txid of the claim\n"
" \"n\" (numeric) the vout value of the claim\n"
" \"amount\" (numeric) txout amount\n"
" \"height\" (numeric) the height of the block in which this transaction is located\n"
" \"value\" (string) the value of this claim\n"
" \"claimId\" (string) the claimId of the claim\n"
" \"txid\" (string) the txid of the claim\n"
" \"n\" (numeric) the vout value of the claim\n"
" \"amount\" (numeric) txout amount\n"
" \"height\" (numeric) the height of the block in which this transaction is located\n"
" \"value\" (string) the value of this claim\n"
" }\n"
" ]\n"
" }\n"
"]\n"
);
"]\n");
LOCK(cs_main);
CCoinsViewCache coinsCache(pcoinsTip);
CClaimTrieCache trieCache(pclaimTrie);
if (!params.empty()) {
CBlockIndex* blockIndex = BlockHashIndex(ParseHashV(params[0], "blockhash (optional parameter 1)"));
if (!RollBackTo(blockIndex, coinsCache, trieCache))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Rollback failure");
}
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;
CCoinsViewCache view(pcoinsTip);
std::vector<namedNodeType> nodes = pclaimTrie->flattenTrie();
for (std::vector<namedNodeType>::iterator it = nodes.begin(); it != nodes.end(); ++it)
{
if (!it->second.claims.empty())
{
UniValue node(UniValue::VOBJ);
node.push_back(Pair("name", it->first));
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 = view.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"));
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());
}
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);
std::string sValue(vvchParams[1].begin(), vvchParams[1].end());
claim.push_back(Pair("value", sValue));
}
node.push_back(Pair("claims", claims));
ret.push_back(node);
claims.push_back(claim);
}
UniValue node(UniValue::VOBJ);
node.push_back(Pair("name", it->first));
node.push_back(Pair("claims", claims));
ret.push_back(node);
}
return ret;
}
UniValue getclaimtrie(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 0)
if (fHelp || params.size() > 1)
throw std::runtime_error(
"getclaimtrie\n"
"Return the entire name trie.\n"
"Arguments:\n"
"None\n"
"1. \"blockhash\" (string, optional) get claim in the trie\n"
" at the block specified\n"
" by this block hash.\n"
" If none is given,\n"
" the latest active\n"
" block will be used.\n"
"Result: \n"
"{\n"
"[\n"
" {\n"
" \"name\" (string) the name of the node\n"
" \"hash\" (string) the hash of the node\n"
" \"txid\" (string) (if value exists) the hash of the transaction which has successfully claimed this name\n"
" \"n\" (numeric) (if value exists) vout value\n"
" \"value\" (numeric) (if value exists) txout value\n"
" \"height\" (numeric) (if value exists) the height of the block in which this transaction is located\n"
"}\n"
);
" }\n"
"]\n");
LOCK(cs_main);
UniValue ret(UniValue::VARR);
std::vector<namedNodeType> nodes = pclaimTrie->flattenTrie();
CCoinsViewCache coinsCache(pcoinsTip);
CClaimTrieCache trieCache(pclaimTrie);
if (!params.empty()) {
CBlockIndex* blockIndex = BlockHashIndex(ParseHashV(params[0], "blockhash (optional parameter 1)"));
if (!RollBackTo(blockIndex, coinsCache, trieCache))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Rollback failure");
}
UniValue ret(UniValue::VARR);
std::vector<namedNodeType> nodes = trieCache.flattenTrie();
for (std::vector<namedNodeType>::iterator it = nodes.begin(); it != nodes.end(); ++it)
{
UniValue node(UniValue::VOBJ);
node.push_back(Pair("name", it->first));
node.push_back(Pair("name", it->first));
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));
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);
}
return ret;
}
bool getValueForClaim(const COutPoint& out, std::string& sValue)
bool getValueForClaim(const CCoinsViewCache& coinsCache, const COutPoint& out, std::string& sValue)
{
CCoinsViewCache view(pcoinsTip);
const CCoins* coin = view.AccessCoins(out.hash);
const CCoins* coin = coinsCache.AccessCoins(out.hash);
if (!coin)
{
LogPrintf("%s: %s does not exist in the coins view, despite being associated with a name\n",
__func__, out.hash.GetHex());
return true;
}
if(!coin->IsAvailable(out.n))
{
LogPrintf("%s: the specified txout of %s appears to have been spent\n", __func__, out.hash.GetHex());
return true;
}
int op;
std::vector<std::vector<unsigned char> > vvchParams;
if (!DecodeClaimScript(coin->vout[out.n].scriptPubKey, op, vvchParams))
@ -180,118 +216,113 @@ bool getValueForClaim(const COutPoint& out, std::string& sValue)
UniValue getvalueforname(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
if (fHelp || params.size() > 2)
throw std::runtime_error(
"getvalueforname \"name\"\n"
"Return the value associated with a name, if one exists\n"
"Arguments:\n"
"1. \"name\" (string) the name to look up\n"
"1. \"name\" (string) the name to look up\n"
"2. \"blockhash\" (string, optional) get the value\n"
" associated with the name\n"
" at the block specified\n"
" by this block hash.\n"
" If none is given,\n"
" the latest active\n"
" block will be used.\n"
"Result: \n"
"\"value\" (string) the value of the name, if it exists\n"
"\"claimId\" (string) the claimId for this name claim\n"
"\"txid\" (string) the hash of the transaction which successfully claimed the name\n"
"\"n\" (numeric) vout value\n"
"\"amount\" (numeric) txout amount\n"
"\"effective amount\" (numeric) txout amount plus amount from all supports associated with the claim\n"
"\"height\" (numeric) the height of the block in which this transaction is located\n"
);
"\"value\" (string) the value of the name, if it exists\n"
"\"claimId\" (string) the claimId for this name claim\n"
"\"txid\" (string) the hash of the transaction which successfully claimed the name\n"
"\"n\" (numeric) vout value\n"
"\"amount\" (numeric) txout amount\n"
"\"effective amount\" (numeric) txout amount plus amount from all supports associated with the claim\n"
"\"height\" (numeric) the height of the block in which this transaction is located\n");
LOCK(cs_main);
std::string name = params[0].get_str();
CCoinsViewCache coinsCache(pcoinsTip);
CClaimTrieCache trieCache(pclaimTrie);
if (params.size() > 1) {
CBlockIndex* blockIndex = BlockHashIndex(ParseHashV(params[1], "blockhash (optional parameter 2)"));
if (!RollBackTo(blockIndex, coinsCache, trieCache))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Rollback failure");
}
CClaimValue claim;
UniValue ret(UniValue::VOBJ);
if (!pclaimTrie->getInfoForName(name, claim))
return ret;
std::string name = params[0].get_str();
if (!trieCache.getInfoForName(name, claim))
return ret; // they may have asked for a name that doesn't exist (which is not an error)
std::string sValue;
if (!getValueForClaim(claim.outPoint, sValue))
if (!getValueForClaim(coinsCache, claim.outPoint, sValue))
return ret;
CAmount nEffectiveAmount = trieCache.getEffectiveAmountForClaim(name, claim.claimId);
ret.push_back(Pair("value", sValue));
ret.push_back(Pair("claimId", claim.claimId.GetHex()));
ret.push_back(Pair("txid", claim.outPoint.hash.GetHex()));
ret.push_back(Pair("n", (int)claim.outPoint.n));
ret.push_back(Pair("amount", claim.nAmount));
ret.push_back(Pair("effective amount", pclaimTrie->getEffectiveAmountForClaim(name, claim.claimId)));
ret.push_back(Pair("effective amount", nEffectiveAmount));
ret.push_back(Pair("height", claim.nHeight));
return ret;
}
typedef std::pair<CClaimValue, std::vector<CSupportValue> > claimAndSupportsType;
typedef std::map<uint160, claimAndSupportsType> claimSupportMapType;
typedef std::map<uint160, std::vector<CSupportValue> > supportsWithoutClaimsMapType;
UniValue claimsAndSupportsToJSON(claimSupportMapType::const_iterator itClaimsAndSupports, int nCurrentHeight)
UniValue supportToJSON(const CSupportValue& support)
{
UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("txid", support.outPoint.hash.GetHex()));
ret.push_back(Pair("n", (int)support.outPoint.n));
ret.push_back(Pair("nHeight", support.nHeight));
ret.push_back(Pair("nValidAtHeight", support.nValidAtHeight));
ret.push_back(Pair("nAmount", support.nAmount));
return ret;
}
UniValue claimAndSupportsToJSON(CAmount nEffectiveAmount, claimSupportMapType::const_iterator itClaimsAndSupports)
{
UniValue ret(UniValue::VOBJ);
const CClaimValue& claim = itClaimsAndSupports->second.first;
const std::vector<CSupportValue>& supports = itClaimsAndSupports->second.second;
CAmount nEffectiveAmount = 0;
UniValue supportObjs(UniValue::VARR);
for (std::vector<CSupportValue>::const_iterator itSupports = supports.begin(); itSupports != supports.end(); ++itSupports)
{
UniValue supportObj(UniValue::VOBJ);
supportObj.push_back(Pair("txid", itSupports->outPoint.hash.GetHex()));
supportObj.push_back(Pair("n", (int)itSupports->outPoint.n));
supportObj.push_back(Pair("nHeight", itSupports->nHeight));
supportObj.push_back(Pair("nValidAtHeight", itSupports->nValidAtHeight));
if (itSupports->nValidAtHeight < nCurrentHeight)
{
nEffectiveAmount += itSupports->nAmount;
}
supportObj.push_back(Pair("nAmount", itSupports->nAmount));
supportObjs.push_back(supportObj);
for (std::vector<CSupportValue>::const_iterator itSupports = supports.begin(); itSupports != supports.end(); ++itSupports) {
supportObjs.push_back(supportToJSON(*itSupports));
}
ret.push_back(Pair("claimId", itClaimsAndSupports->first.GetHex()));
ret.push_back(Pair("txid", claim.outPoint.hash.GetHex()));
ret.push_back(Pair("n", (int)claim.outPoint.n));
ret.push_back(Pair("nHeight", claim.nHeight));
ret.push_back(Pair("nValidAtHeight", claim.nValidAtHeight));
if (claim.nValidAtHeight < nCurrentHeight)
{
nEffectiveAmount += claim.nAmount;
}
ret.push_back(Pair("nAmount", claim.nAmount));
std::string sValue;
if (getValueForClaim(claim.outPoint, sValue))
{
ret.push_back(Pair("value", sValue));
}
ret.push_back(Pair("nEffectiveAmount", nEffectiveAmount));
ret.push_back(Pair("supports", supportObjs));
return ret;
}
UniValue supportsWithoutClaimsToJSON(supportsWithoutClaimsMapType::const_iterator itSupportsWithoutClaims, int nCurrentHeight)
{
const std::vector<CSupportValue>& supports = itSupportsWithoutClaims->second;
UniValue ret(UniValue::VOBJ);
UniValue supportObjs(UniValue::VARR);
ret.push_back(Pair("claimId (no matching claim)", itSupportsWithoutClaims->first.GetHex()));
for (std::vector<CSupportValue>::const_iterator itSupports = supports.begin(); itSupports != supports.end(); ++itSupports)
{
UniValue supportObj(UniValue::VOBJ);
supportObj.push_back(Pair("txid", itSupports->outPoint.hash.GetHex()));
supportObj.push_back(Pair("n", (int)itSupports->outPoint.n));
supportObj.push_back(Pair("nHeight", itSupports->nHeight));
supportObj.push_back(Pair("nValidAtHeight", itSupports->nValidAtHeight));
supportObj.push_back(Pair("nAmount", itSupports->nAmount));
supportObjs.push_back(supportObj);
}
ret.push_back(Pair("supports", supportObjs));
return ret;
}
UniValue getclaimsforname(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
if (fHelp || params.size() > 2)
throw std::runtime_error(
"getclaimsforname\n"
"Return all claims and supports for a name\n"
"Arguments: \n"
"1. \"name\" (string) the name for which to get claims and supports\n"
"1. \"name\" (string) the name for which to get claims and supports\n"
"2. \"blockhash\" (string, optional) get claims for name\n"
" at the block specified\n"
" by this block hash.\n"
" If none is given,\n"
" the latest active\n"
" block will be used.\n"
"Result:\n"
"{\n"
" \"nLastTakeoverheight\" (numeric) the last height at which ownership of the name changed\n"
" \"claims\": [ (array of object) claims for this name\n"
" \"nLastTakeoverHeight\" (numeric) the last height at which ownership of the name changed\n"
" \"claims\": [ (array of object) claims for this name\n"
" {\n"
" \"claimId\" (string) the claimId of this claim\n"
" \"txid\" (string) the txid of this claim\n"
@ -318,50 +349,51 @@ UniValue getclaimsforname(const UniValue& params, bool fHelp)
" \"nAmount\" (numeric) the amount of the support\n"
" }\n"
" ]\n"
"}\n"
);
"}\n");
LOCK(cs_main);
std::string name = params[0].get_str();
claimsForNameType claimsForName = pclaimTrie->getClaimsForName(name);
int nCurrentHeight = chainActive.Height();
CCoinsViewCache coinsCache(pcoinsTip);
CClaimTrieCache trieCache(pclaimTrie);
if (params.size() > 1) {
CBlockIndex* blockIndex = BlockHashIndex(ParseHashV(params[1], "blockhash (optional parameter 2)"));
if (!RollBackTo(blockIndex, coinsCache, trieCache))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Rollback failure");
}
std::string name = params[0].get_str();
claimsForNameType claimsForName = trieCache.getClaimsForName(name);
UniValue claimObjs(UniValue::VARR);
claimSupportMapType claimSupportMap;
supportsWithoutClaimsMapType supportsWithoutClaims;
for (std::vector<CClaimValue>::const_iterator itClaims = claimsForName.claims.begin(); itClaims != claimsForName.claims.end(); ++itClaims)
{
UniValue unmatchedSupports(UniValue::VARR);
for (std::vector<CClaimValue>::const_iterator itClaims = claimsForName.claims.begin(); itClaims != claimsForName.claims.end(); ++itClaims) {
claimAndSupportsType claimAndSupports = std::make_pair(*itClaims, std::vector<CSupportValue>());
claimSupportMap.insert(std::pair<uint160, claimAndSupportsType>(itClaims->claimId, claimAndSupports));
}
for (std::vector<CSupportValue>::const_iterator itSupports = claimsForName.supports.begin(); itSupports != claimsForName.supports.end(); ++itSupports)
{
for (std::vector<CSupportValue>::const_iterator itSupports = claimsForName.supports.begin(); itSupports != claimsForName.supports.end(); ++itSupports) {
claimSupportMapType::iterator itClaimAndSupports = claimSupportMap.find(itSupports->supportedClaimId);
if (itClaimAndSupports == claimSupportMap.end())
{
std::pair<supportsWithoutClaimsMapType::iterator, bool> ret = supportsWithoutClaims.insert(std::pair<uint160, std::vector<CSupportValue> >(itSupports->supportedClaimId, std::vector<CSupportValue>()));
ret.first->second.push_back(*itSupports);
}
else
{
if (itClaimAndSupports == claimSupportMap.end()) {
unmatchedSupports.push_back(supportToJSON(*itSupports));
} else {
itClaimAndSupports->second.second.push_back(*itSupports);
}
}
UniValue ret(UniValue::VOBJ);
UniValue claimObjs(UniValue::VARR);
ret.push_back(Pair("nLastTakeoverHeight", claimsForName.nLastTakeoverHeight));
for (claimSupportMapType::const_iterator itClaimsAndSupports = claimSupportMap.begin(); itClaimsAndSupports != claimSupportMap.end(); ++itClaimsAndSupports)
{
UniValue claimAndSupportsObj = claimsAndSupportsToJSON(itClaimsAndSupports, nCurrentHeight);
claimObjs.push_back(claimAndSupportsObj);
for (claimSupportMapType::const_iterator itClaimsAndSupports = claimSupportMap.begin(); itClaimsAndSupports != claimSupportMap.end(); ++itClaimsAndSupports) {
CAmount nEffectiveAmount = trieCache.getEffectiveAmountForClaim(claimsForName, itClaimsAndSupports->first);
UniValue claimObj = claimAndSupportsToJSON(nEffectiveAmount, itClaimsAndSupports);
claimObjs.push_back(claimObj);
}
ret.push_back(Pair("claims", claimObjs));
UniValue unmatchedSupports(UniValue::VARR);
for (supportsWithoutClaimsMapType::const_iterator itSupportsWithoutClaims = supportsWithoutClaims.begin(); itSupportsWithoutClaims != supportsWithoutClaims.end(); ++itSupportsWithoutClaims)
{
UniValue supportsObj = supportsWithoutClaimsToJSON(itSupportsWithoutClaims, nCurrentHeight);
unmatchedSupports.push_back(supportsObj);
}
ret.push_back(Pair("supports without claims", unmatchedSupports));
ret.push_back(Pair("unmatched supports", unmatchedSupports));
return ret;
}
@ -403,11 +435,11 @@ UniValue getclaimbyid(const UniValue& params, bool fHelp)
if (claimValue.claimId == claimId)
{
std::vector<CSupportValue> supports;
CAmount effectiveAmount = pclaimTrie->getEffectiveAmountForClaimWithSupports(
name, claimValue.claimId, supports);
CAmount effectiveAmount = pclaimTrie->getEffectiveAmountForClaim(name, claimValue.claimId, &supports);
std::string sValue;
getValueForClaim(claimValue.outPoint, sValue);
CCoinsViewCache coins(pcoinsTip);
getValueForClaim(coins, claimValue.outPoint, sValue);
claim.push_back(Pair("name", name));
claim.push_back(Pair("value", sValue));
claim.push_back(Pair("claimId", claimValue.claimId.GetHex()));
@ -448,7 +480,7 @@ UniValue gettotalclaimednames(const UniValue& params, bool fHelp)
if (!pclaimTrie)
{
return -1;
}
}
unsigned int num_names = pclaimTrie->getTotalNamesInTrie();
return int(num_names);
}
@ -531,7 +563,7 @@ UniValue getclaimsfortx(const UniValue& params, bool fHelp)
int op;
std::vector<std::vector<unsigned char> > vvchParams;
CCoinsViewCache view(pcoinsTip);
const CCoins* coin = view.AccessCoins(hash);
std::vector<CTxOut> txouts;
@ -730,7 +762,7 @@ UniValue getnameproof(const UniValue& params, bool fHelp)
" this will not\n"
" exist whether\n"
" the node has a\n"
" value or not\n"
" value or not\n"
" ]\n"
" \"txhash\" : \"hash\" (string, if exists) the txid of the\n"
" claim which controls\n"
@ -749,25 +781,12 @@ UniValue getnameproof(const UniValue& params, bool fHelp)
LOCK(cs_main);
std::string strName = params[0].get_str();
uint256 blockHash;
if (params.size() == 2)
{
blockHash = ParseHashV(params[1], "blockhash (optional parameter 2)");
CBlockIndex* pblockIndex;
if (params.size() == 2) {
pblockIndex = BlockHashIndex(ParseHashV(params[1], "blockhash (optional parameter 2)"));
} else {
pblockIndex = mapBlockIndex[chainActive.Tip()->GetBlockHash()];
}
else
{
blockHash = chainActive.Tip()->GetBlockHash();
}
if (mapBlockIndex.count(blockHash) == 0)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
CBlockIndex* pblockIndex = mapBlockIndex[blockHash];
if (!chainActive.Contains(pblockIndex))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not in main chain");
if (chainActive.Tip()->nHeight > (pblockIndex->nHeight + MAX_RPC_BLOCK_DECREMENTS))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Block too deep to generate proof");
CClaimTrieProof proof;
if (!GetProofForName(pblockIndex, strName, proof))

View file

@ -2,21 +2,22 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://opensource.org/licenses/mit-license.php
#include "main.h"
#include "consensus/validation.h"
#include "consensus/merkle.h"
#include "primitives/transaction.h"
#include "miner.h"
#include "txmempool.h"
#include "claimtrie.h"
#include "nameclaim.h"
#include "coins.h"
#include "streams.h"
#include "chainparams.h"
#include "claimtrie.h"
#include "coins.h"
#include "consensus/merkle.h"
#include "consensus/validation.h"
#include "main.h"
#include "miner.h"
#include "nameclaim.h"
#include "policy/policy.h"
#include "primitives/transaction.h"
#include "rpc/server.h"
#include "streams.h"
#include "test/test_bitcoin.h"
#include "txmempool.h"
#include <boost/test/unit_test.hpp>
#include <iostream>
#include "test/test_bitcoin.h"
using namespace std;
@ -2931,31 +2932,31 @@ BOOST_AUTO_TEST_CASE(value_proof_test)
CClaimTrieProof proof;
proof = cache.getProofForName(sName1);
BOOST_CHECK(cache.getProofForName(sName1, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName1));
BOOST_CHECK(proof.outPoint == tx1OutPoint);
proof = cache.getProofForName(sName2);
BOOST_CHECK(cache.getProofForName(sName2, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName2));
BOOST_CHECK(proof.outPoint == tx2OutPoint);
proof = cache.getProofForName(sName3);
BOOST_CHECK(cache.getProofForName(sName3, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName3));
BOOST_CHECK(proof.outPoint == tx3OutPoint);
proof = cache.getProofForName(sName4);
BOOST_CHECK(cache.getProofForName(sName4, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName4));
BOOST_CHECK(proof.outPoint == tx4OutPoint);
proof = cache.getProofForName(sName5);
BOOST_CHECK(cache.getProofForName(sName5, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName5));
BOOST_CHECK(proof.hasValue == false);
proof = cache.getProofForName(sName6);
BOOST_CHECK(cache.getProofForName(sName6, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName6));
BOOST_CHECK(proof.hasValue == false);
proof = cache.getProofForName(sName7);
BOOST_CHECK(cache.getProofForName(sName7, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName7));
BOOST_CHECK(proof.hasValue == false);
@ -2969,31 +2970,31 @@ BOOST_AUTO_TEST_CASE(value_proof_test)
cache = CClaimTrieCache(pclaimTrie);
proof = cache.getProofForName(sName1);
BOOST_CHECK(cache.getProofForName(sName1, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName1));
BOOST_CHECK(proof.outPoint == tx1OutPoint);
proof = cache.getProofForName(sName2);
BOOST_CHECK(cache.getProofForName(sName2, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName2));
BOOST_CHECK(proof.outPoint == tx2OutPoint);
proof = cache.getProofForName(sName3);
BOOST_CHECK(cache.getProofForName(sName3, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName3));
BOOST_CHECK(proof.outPoint == tx3OutPoint);
proof = cache.getProofForName(sName4);
BOOST_CHECK(cache.getProofForName(sName4, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName4));
BOOST_CHECK(proof.outPoint == tx4OutPoint);
proof = cache.getProofForName(sName5);
BOOST_CHECK(cache.getProofForName(sName5, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName5));
BOOST_CHECK(proof.hasValue == false);
proof = cache.getProofForName(sName6);
BOOST_CHECK(cache.getProofForName(sName6, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName6));
BOOST_CHECK(proof.hasValue == false);
proof = cache.getProofForName(sName7);
BOOST_CHECK(cache.getProofForName(sName7, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName7));
BOOST_CHECK(proof.outPoint == tx5OutPoint);
@ -3133,4 +3134,222 @@ BOOST_AUTO_TEST_CASE(get_claim_by_id_test_3)
BOOST_CHECK(claimValue.claimId == claimId2);
}
BOOST_AUTO_TEST_CASE(getclaimsintrie_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("test");
std::string sValue1("test");
std::string sName2("test2");
std::string sValue2("test2");
fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 42);
fixture.IncrementBlocks(1);
uint256 blockHash = chainActive.Tip()->GetBlockHash();
fixture.MakeClaim(fixture.GetCoinbase(), sName2, sValue2, 43);
fixture.IncrementBlocks(1);
rpcfn_type getclaimsintrie = tableRPC["getclaimsintrie"]->actor;
UniValue params(UniValue::VARR);
UniValue results = getclaimsintrie(params, false);
BOOST_CHECK(results.size() == 2U);
BOOST_CHECK(results[0]["name"].get_str() == sName1);
BOOST_CHECK(results[1]["name"].get_str() == sName2);
params.push_back(blockHash.GetHex());
results = getclaimsintrie(params, false);
BOOST_CHECK(results.size() == 1U);
BOOST_CHECK(results[0]["name"].get_str() == sName1);
}
BOOST_AUTO_TEST_CASE(getclaimtrie_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("test");
std::string sValue1("test");
std::string sName2("test2");
std::string sValue2("test2");
int height = chainActive.Height();
fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 42);
fixture.IncrementBlocks(1);
uint256 blockHash = chainActive.Tip()->GetBlockHash();
fixture.MakeClaim(fixture.GetCoinbase(), sName2, sValue2, 43);
fixture.IncrementBlocks(1);
rpcfn_type getclaimtrie = tableRPC["getclaimtrie"]->actor;
UniValue params(UniValue::VARR);
UniValue results = getclaimtrie(params, false);
BOOST_CHECK(results.size() == 6U);
BOOST_CHECK(results[4]["name"].get_str() == sName1);
BOOST_CHECK(results[5]["name"].get_str() == sName2);
BOOST_CHECK(results[4]["height"].get_int() == height + 1);
BOOST_CHECK(results[5]["height"].get_int() == height + 2);
params.push_back(blockHash.GetHex());
results = getclaimtrie(params, false);
BOOST_CHECK(results.size() == 5U);
BOOST_CHECK(results[4]["name"].get_str() == sName1);
BOOST_CHECK(results[4]["height"].get_int() == height + 1);
}
BOOST_AUTO_TEST_CASE(getvalueforname_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("testN");
std::string sValue1("testV");
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 2);
fixture.IncrementBlocks(1);
uint256 blockHash = chainActive.Tip()->GetBlockHash();
fixture.MakeSupport(fixture.GetCoinbase(), tx1, sName1, 3);
fixture.IncrementBlocks(10);
rpcfn_type getvalueforname = tableRPC["getvalueforname"]->actor;
UniValue params(UniValue::VARR);
params.push_back(UniValue(sName1));
UniValue results = getvalueforname(params, false);
BOOST_CHECK(results["value"].get_str() == sValue1);
BOOST_CHECK(results["amount"].get_int() == 2);
BOOST_CHECK(results["effective amount"].get_int() == 5);
params.push_back(blockHash.GetHex());
results = getvalueforname(params, false);
BOOST_CHECK(results["amount"].get_int() == 2);
BOOST_CHECK(results["effective amount"].get_int() == 2);
}
BOOST_AUTO_TEST_CASE(getclaimsforname_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("testN");
std::string sValue1("test1");
std::string sValue2("test2");
int height = chainActive.Height();
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 2);
fixture.IncrementBlocks(1);
uint256 blockHash = chainActive.Tip()->GetBlockHash();
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, 3);
fixture.IncrementBlocks(1);
rpcfn_type getclaimsforname = tableRPC["getclaimsforname"]->actor;
UniValue params(UniValue::VARR);
params.push_back(UniValue(sName1));
UniValue results = getclaimsforname(params, false);
UniValue claims = results["claims"];
BOOST_CHECK(claims.size() == 2U);
BOOST_CHECK(results["nLastTakeoverHeight"].get_int() == height + 1);
BOOST_CHECK(claims[0]["nEffectiveAmount"].get_int() == 0);
BOOST_CHECK(claims[1]["nEffectiveAmount"].get_int() == 2);
BOOST_CHECK(claims[0]["supports"].size() == 0U);
BOOST_CHECK(claims[1]["supports"].size() == 0U);
fixture.IncrementBlocks(1);
results = getclaimsforname(params, false);
claims = results["claims"];
BOOST_CHECK(claims.size() == 2U);
BOOST_CHECK(results["nLastTakeoverHeight"].get_int() == height + 3);
BOOST_CHECK(claims[0]["nEffectiveAmount"].get_int() == 3);
BOOST_CHECK(claims[1]["nEffectiveAmount"].get_int() == 2);
BOOST_CHECK(claims[0]["supports"].size() == 0U);
BOOST_CHECK(claims[1]["supports"].size() == 0U);
params.push_back(blockHash.GetHex());
results = getclaimsforname(params, false);
claims = results["claims"];
BOOST_CHECK(claims.size() == 1U);
BOOST_CHECK(results["nLastTakeoverHeight"].get_int() == height + 1);
BOOST_CHECK(claims[0]["nEffectiveAmount"].get_int() == 2);
BOOST_CHECK(claims[0]["supports"].size() == 0U);
}
BOOST_AUTO_TEST_CASE(claim_rpcs_rollback2_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("testN");
std::string sValue1("test1");
std::string sValue2("test2");
int height = chainActive.Height();
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 1);
fixture.IncrementBlocks(2);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, 2);
fixture.IncrementBlocks(3);
uint256 blockHash = chainActive.Tip()->GetBlockHash();
CMutableTransaction tx3 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, sValue1, 3);
fixture.IncrementBlocks(1);
rpcfn_type getclaimsforname = tableRPC["getclaimsforname"]->actor;
rpcfn_type getvalueforname = tableRPC["getvalueforname"]->actor;
UniValue params(UniValue::VARR);
params.push_back(UniValue(sName1));
params.push_back(blockHash.GetHex());
UniValue claimsResults = getclaimsforname(params, false);
BOOST_CHECK(claimsResults["nLastTakeoverHeight"].get_int() == height + 5);
BOOST_CHECK(claimsResults["claims"][0]["supports"].size() == 0U);
BOOST_CHECK(claimsResults["claims"][1]["supports"].size() == 0U);
UniValue valueResults = getvalueforname(params, false);
BOOST_CHECK(valueResults["value"].get_str() == sValue2);
BOOST_CHECK(valueResults["amount"].get_int() == 2);
}
BOOST_AUTO_TEST_CASE(claim_rpcs_rollback3_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("testN");
std::string sValue1("test1");
std::string sValue2("test2");
int height = chainActive.Height();
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 3);
fixture.IncrementBlocks(1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, 2);
fixture.IncrementBlocks(2);
uint256 blockHash = chainActive.Tip()->GetBlockHash();
CMutableTransaction tx3 = fixture.Spend(tx1); // abandon the claim
fixture.IncrementBlocks(1);
rpcfn_type getclaimsforname = tableRPC["getclaimsforname"]->actor;
rpcfn_type getvalueforname = tableRPC["getvalueforname"]->actor;
UniValue params(UniValue::VARR);
params.push_back(UniValue(sName1));
params.push_back(blockHash.GetHex());
UniValue claimsResults = getclaimsforname(params, false);
BOOST_CHECK(claimsResults["nLastTakeoverHeight"].get_int() == height + 1);
UniValue valueResults = getvalueforname(params, false);
BOOST_CHECK(valueResults["value"].get_str() == sValue1);
BOOST_CHECK(valueResults["amount"].get_int() == 3);
}
BOOST_AUTO_TEST_SUITE_END()