make getting a proof an rpc call
This commit is contained in:
parent
ff6459a9bb
commit
ab830e84a3
8 changed files with 215 additions and 88 deletions
36
src/main.cpp
36
src/main.cpp
|
@ -3491,6 +3491,42 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GetProofForName(const CBlockIndex* pindexProof, const std::string& name, CNCCTrieProof& proof)
|
||||||
|
{
|
||||||
|
AssertLockHeld(cs_main);
|
||||||
|
if (!chainActive.Contains(pindexProof))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CCoinsViewCache coins(pcoinsTip);
|
||||||
|
CNCCTrieCache trieCache(pnccTrie);
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
void UnloadBlockIndex()
|
void UnloadBlockIndex()
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
|
@ -167,6 +167,8 @@ FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false);
|
||||||
FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false);
|
FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false);
|
||||||
/** Translation to a filesystem path */
|
/** Translation to a filesystem path */
|
||||||
boost::filesystem::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix);
|
boost::filesystem::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix);
|
||||||
|
/** Get a cryptographic proof that a name maps to a value **/
|
||||||
|
bool GetProofForName(const CBlockIndex* pindexProof, const std::string& name, CNCCTrieProof& proof);
|
||||||
/** Import blocks from an external file */
|
/** Import blocks from an external file */
|
||||||
bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp = NULL);
|
bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp = NULL);
|
||||||
/** Initialize a new block tree database + block data on disk */
|
/** Initialize a new block tree database + block data on disk */
|
||||||
|
|
|
@ -1307,11 +1307,6 @@ CNCCTrieProof CNCCTrieCache::getProofForName(const std::string& name) const
|
||||||
if (cachedNode != cache.end())
|
if (cachedNode != cache.end())
|
||||||
current = cachedNode->second;
|
current = cachedNode->second;
|
||||||
hashMapType::const_iterator cachedHash = cacheHashes.find(currentPosition);
|
hashMapType::const_iterator cachedHash = cacheHashes.find(currentPosition);
|
||||||
uint256 nodeHash;
|
|
||||||
if (cachedHash != cacheHashes.end())
|
|
||||||
nodeHash = cachedHash->second;
|
|
||||||
else
|
|
||||||
nodeHash = current->hash;
|
|
||||||
CNodeValue val;
|
CNodeValue val;
|
||||||
bool fNodeHasValue = current->getBestValue(val);
|
bool fNodeHasValue = current->getBestValue(val);
|
||||||
uint256 valHash;
|
uint256 valHash;
|
||||||
|
@ -1332,7 +1327,7 @@ CNCCTrieProof CNCCTrieCache::getProofForName(const std::string& name) const
|
||||||
nextCurrent = itChildren->second;
|
nextCurrent = itChildren->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nodes[currentPosition] = CNCCTrieProofNode(child_chars, fNodeHasValue, valHash, nodeHash);
|
nodes[currentPosition] = CNCCTrieProofNode(child_chars, fNodeHasValue, valHash);
|
||||||
current = nextCurrent;
|
current = nextCurrent;
|
||||||
if (current == NULL)
|
if (current == NULL)
|
||||||
break;
|
break;
|
||||||
|
@ -1343,11 +1338,6 @@ CNCCTrieProof CNCCTrieCache::getProofForName(const std::string& name) const
|
||||||
if (cachedNode != cache.end())
|
if (cachedNode != cache.end())
|
||||||
current = cachedNode->second;
|
current = cachedNode->second;
|
||||||
hashMapType::const_iterator cachedHash = cacheHashes.find(name);
|
hashMapType::const_iterator cachedHash = cacheHashes.find(name);
|
||||||
uint256 nodeHash;
|
|
||||||
if (cachedHash != cacheHashes.end())
|
|
||||||
nodeHash = cachedHash->second;
|
|
||||||
else
|
|
||||||
nodeHash = current->hash;
|
|
||||||
fNameHasValue = current->getBestValue(nameVal);
|
fNameHasValue = current->getBestValue(nameVal);
|
||||||
uint256 valHash;
|
uint256 valHash;
|
||||||
if (fNameHasValue)
|
if (fNameHasValue)
|
||||||
|
@ -1365,7 +1355,7 @@ CNCCTrieProof CNCCTrieCache::getProofForName(const std::string& name) const
|
||||||
std::pair<std::string, CNCCTrieProofLeafNode> leaf = getLeafNodeForProof(name, itChildren->first, itChildren->second);
|
std::pair<std::string, CNCCTrieProofLeafNode> leaf = getLeafNodeForProof(name, itChildren->first, itChildren->second);
|
||||||
leafNodes[leaf.first] = leaf.second;
|
leafNodes[leaf.first] = leaf.second;
|
||||||
}
|
}
|
||||||
nodes[name] = CNCCTrieProofNode(child_chars, fNameHasValue, valHash, nodeHash);
|
nodes[name] = CNCCTrieProofNode(child_chars, fNameHasValue, valHash);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -205,11 +205,10 @@ class CNCCTrieProofNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CNCCTrieProofNode() {};
|
CNCCTrieProofNode() {};
|
||||||
CNCCTrieProofNode(std::vector<unsigned char> children, bool hasValue, uint256 valHash, uint256 nodeHash) : children(children), hasValue(hasValue), valHash(valHash), nodeHash(nodeHash) {};
|
CNCCTrieProofNode(std::vector<unsigned char> children, bool hasValue, uint256 valHash) : children(children), hasValue(hasValue), valHash(valHash) {};
|
||||||
std::vector<unsigned char> children;
|
std::vector<unsigned char> children;
|
||||||
bool hasValue;
|
bool hasValue;
|
||||||
uint256 valHash;
|
uint256 valHash;
|
||||||
uint256 nodeHash;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CNCCTrieProofLeafNode
|
class CNCCTrieProofLeafNode
|
||||||
|
|
|
@ -269,3 +269,121 @@ UniValue getclaimsfortx(const UniValue& params, bool fHelp)
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UniValue proofToJSON(const CNCCTrieProof& proof)
|
||||||
|
{
|
||||||
|
UniValue result(UniValue::VOBJ);
|
||||||
|
UniValue nodes(UniValue::VARR);
|
||||||
|
for (std::map<std::string, CNCCTrieProofNode>::const_iterator itNode = proof.nodes.begin(); itNode != proof.nodes.end(); ++itNode)
|
||||||
|
{
|
||||||
|
UniValue node(UniValue::VOBJ);
|
||||||
|
node.push_back(Pair("name", itNode->first));
|
||||||
|
UniValue children(UniValue::VARR);
|
||||||
|
for (std::vector<unsigned char>::const_iterator itChildren = itNode->second.children.begin(); itChildren != itNode->second.children.end(); ++itChildren)
|
||||||
|
{
|
||||||
|
children.push_back(*itChildren);
|
||||||
|
}
|
||||||
|
node.push_back(Pair("children", children));
|
||||||
|
if (itNode->second.hasValue)
|
||||||
|
{
|
||||||
|
node.push_back(Pair("valueHash", itNode->second.valHash.GetHex()));
|
||||||
|
}
|
||||||
|
nodes.push_back(node);
|
||||||
|
}
|
||||||
|
result.push_back(Pair("nodes", nodes));
|
||||||
|
UniValue leafNodes(UniValue::VARR);
|
||||||
|
for (std::map<std::string, CNCCTrieProofLeafNode>::const_iterator itLeafNode = proof.leafNodes.begin(); itLeafNode != proof.leafNodes.end(); ++itLeafNode)
|
||||||
|
{
|
||||||
|
UniValue leafNode(UniValue::VOBJ);
|
||||||
|
leafNode.push_back(Pair("name", itLeafNode->first));
|
||||||
|
leafNode.push_back(Pair("nodeHash", itLeafNode->second.nodeHash.GetHex()));
|
||||||
|
leafNodes.push_back(leafNode);
|
||||||
|
}
|
||||||
|
result.push_back(Pair("leafNodes", leafNodes));
|
||||||
|
if (proof.hasValue)
|
||||||
|
{
|
||||||
|
result.push_back(Pair("txhash", proof.txhash.GetHex()));
|
||||||
|
result.push_back(Pair("nOut", (int)proof.nOut));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
UniValue getnameproof(const UniValue& params, bool fHelp)
|
||||||
|
{
|
||||||
|
if (fHelp || (params.size() != 1 && params.size() != 2))
|
||||||
|
throw std::runtime_error(
|
||||||
|
"getnameproof\n"
|
||||||
|
"Return the cryptographic proof that a name maps to a value\n"
|
||||||
|
"or doesn't.\n"
|
||||||
|
"Arguments:\n"
|
||||||
|
"1. \"name\" (string) the name to get a proof for\n"
|
||||||
|
"2. \"blockhash\" (string, optional) the hash of the block\n"
|
||||||
|
" which is the basis\n"
|
||||||
|
" of the proof. If\n"
|
||||||
|
" none is given, \n"
|
||||||
|
" the latest block\n"
|
||||||
|
" will be used.\n"
|
||||||
|
"Result: \n"
|
||||||
|
"{\n"
|
||||||
|
" \"nodes\" : [ (array of object) full nodes (i.e.\n"
|
||||||
|
" those which lead to\n"
|
||||||
|
" the requested name)\n"
|
||||||
|
" \"name\" : \"node name\" (string) The name of the node\n"
|
||||||
|
" \"children\" : [ (array of numeric) the characters\n"
|
||||||
|
" corresponding to\n"
|
||||||
|
" the children of\n"
|
||||||
|
" this node\n"
|
||||||
|
" \"child\" (numeric) a 0-255 number referring to\n"
|
||||||
|
" a child node of this node\n"
|
||||||
|
" ]\n"
|
||||||
|
" \"valueHash\" (string, if exists) the hash of this\n"
|
||||||
|
" node's value, if\n"
|
||||||
|
" it has one\n"
|
||||||
|
" ]\n"
|
||||||
|
" \"leaf_nodes\" : [ (array of object) leaf nodes (i.e.\n"
|
||||||
|
" those which do not\n"
|
||||||
|
" lead to the requested\n"
|
||||||
|
" name but nonetheless\n"
|
||||||
|
" contribute to the proof\n"
|
||||||
|
" \"name\" : \"node name\" (string) the name of the node\n"
|
||||||
|
" \"nodeHash\" : \"hash\" (string) the hash of the node\n"
|
||||||
|
" ]\n"
|
||||||
|
" \"txhash\" : \"hash\" (string, if exists) the txid of the\n"
|
||||||
|
" claim which controls\n"
|
||||||
|
" this name, if there\n"
|
||||||
|
" is one.\n"
|
||||||
|
" \"nOut\" : n, (numeric) the nOut of the claim which\n"
|
||||||
|
" controls this name, if there\n"
|
||||||
|
" is one.\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n");
|
||||||
|
|
||||||
|
LOCK(cs_main);
|
||||||
|
std::string strName = params[0].get_str();
|
||||||
|
uint256 blockHash;
|
||||||
|
if (params.size() == 2)
|
||||||
|
{
|
||||||
|
std::string strBlockHash = params[1].get_str();
|
||||||
|
blockHash = uint256S(strBlockHash);
|
||||||
|
}
|
||||||
|
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 + 10))
|
||||||
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Block too deep to generate proof");
|
||||||
|
|
||||||
|
CNCCTrieProof proof;
|
||||||
|
if (!GetProofForName(pblockIndex, strName, proof))
|
||||||
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Failed to generate proof");
|
||||||
|
|
||||||
|
return proofToJSON(proof);
|
||||||
|
}
|
||||||
|
|
|
@ -386,6 +386,7 @@ static const CRPCCommand vRPCCommands[] =
|
||||||
{ "nametrie", "gettotalclaims", &gettotalclaims, true },
|
{ "nametrie", "gettotalclaims", &gettotalclaims, true },
|
||||||
{ "nametrie", "gettotalvalueofclaims", &gettotalvalueofclaims, true },
|
{ "nametrie", "gettotalvalueofclaims", &gettotalvalueofclaims, true },
|
||||||
{ "nametrie", "getclaimsfortx", &getclaimsfortx, true },
|
{ "nametrie", "getclaimsfortx", &getclaimsfortx, true },
|
||||||
|
{ "nametrie", "getnameproof", &getnameproof, true },
|
||||||
};
|
};
|
||||||
|
|
||||||
CRPCTable::CRPCTable()
|
CRPCTable::CRPCTable()
|
||||||
|
|
|
@ -247,6 +247,7 @@ extern UniValue gettotalclaimednames(const UniValue& params, bool fHelp);
|
||||||
extern UniValue gettotalclaims(const UniValue& params, bool fHelp);
|
extern UniValue gettotalclaims(const UniValue& params, bool fHelp);
|
||||||
extern UniValue gettotalvalueofclaims(const UniValue& params, bool fHelp);
|
extern UniValue gettotalvalueofclaims(const UniValue& params, bool fHelp);
|
||||||
extern UniValue getclaimsfortx(const UniValue& params, bool fHelp);
|
extern UniValue getclaimsfortx(const UniValue& params, bool fHelp);
|
||||||
|
extern UniValue getnameproof(const UniValue& params, bool fHelp);
|
||||||
|
|
||||||
// in rest.cpp
|
// in rest.cpp
|
||||||
extern bool HTTPReq_REST(AcceptedConnection *conn,
|
extern bool HTTPReq_REST(AcceptedConnection *conn,
|
||||||
|
|
|
@ -1418,30 +1418,33 @@ BOOST_AUTO_TEST_CASE(ncctrienode_serialize_unserialize)
|
||||||
BOOST_CHECK(n1 == n2);
|
BOOST_CHECK(n1 == n2);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool verify_proof(CNCCTrieProof proof, uint256 rootHash, const std::string& name)
|
bool get_node_hash(const std::string& name, const std::string& currentPosition, const std::string::const_iterator itName, CNCCTrieProof& proof, uint256& nodeHash)
|
||||||
{
|
{
|
||||||
for (std::string::const_iterator itName = name.begin(); itName != name.end(); ++itName)
|
|
||||||
{
|
|
||||||
std::string currentPosition(name.begin(), itName);
|
|
||||||
std::map<std::string, CNCCTrieProofNode>::const_iterator itNode = proof.nodes.find(currentPosition);
|
std::map<std::string, CNCCTrieProofNode>::const_iterator itNode = proof.nodes.find(currentPosition);
|
||||||
if (itNode == proof.nodes.end())
|
if (itNode == proof.nodes.end())
|
||||||
{
|
{
|
||||||
return currentPosition != "" && !proof.hasValue;
|
return false;
|
||||||
|
}
|
||||||
|
if (name == currentPosition && itName != name.end())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
std::vector<unsigned char> vchToHash;
|
std::vector<unsigned char> vchToHash;
|
||||||
|
bool haveNextNode = false;
|
||||||
for (std::vector<unsigned char>::const_iterator itChildren = itNode->second.children.begin(); itChildren != itNode->second.children.end(); ++itChildren)
|
for (std::vector<unsigned char>::const_iterator itChildren = itNode->second.children.begin(); itChildren != itNode->second.children.end(); ++itChildren)
|
||||||
{
|
{
|
||||||
vchToHash.push_back(*itChildren);
|
vchToHash.push_back(*itChildren);
|
||||||
std::stringstream nextPosition;
|
std::stringstream nextPosition;
|
||||||
nextPosition << currentPosition << *itChildren;
|
nextPosition << currentPosition << *itChildren;
|
||||||
if (*itChildren == *itName)
|
if (name != currentPosition && *itChildren == *itName)
|
||||||
{
|
{
|
||||||
std::map<std::string, CNCCTrieProofNode>::const_iterator itChildNode = proof.nodes.find(nextPosition.str());
|
uint256 childNodeHash;
|
||||||
if (itChildNode == proof.nodes.end())
|
if (!get_node_hash(name, nextPosition.str(), itName + 1, proof, childNodeHash))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
vchToHash.insert(vchToHash.end(), itChildNode->second.nodeHash.begin(), itChildNode->second.nodeHash.end());
|
haveNextNode = true;
|
||||||
|
vchToHash.insert(vchToHash.end(), childNodeHash.begin(), childNodeHash.end());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1453,47 +1456,24 @@ bool verify_proof(CNCCTrieProof proof, uint256 rootHash, const std::string& name
|
||||||
vchToHash.insert(vchToHash.end(), itChildNode->second.nodeHash.begin(), itChildNode->second.nodeHash.end());
|
vchToHash.insert(vchToHash.end(), itChildNode->second.nodeHash.begin(), itChildNode->second.nodeHash.end());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (name != currentPosition)
|
||||||
|
{
|
||||||
|
if (!haveNextNode && proof.hasValue)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (itNode->second.hasValue)
|
if (itNode->second.hasValue)
|
||||||
{
|
{
|
||||||
vchToHash.insert(vchToHash.end(), itNode->second.valHash.begin(), itNode->second.valHash.end());
|
vchToHash.insert(vchToHash.end(), itNode->second.valHash.begin(), itNode->second.valHash.end());
|
||||||
}
|
}
|
||||||
CHash256 hasher;
|
}
|
||||||
std::vector<unsigned char> vchHash(hasher.OUTPUT_SIZE);
|
else
|
||||||
hasher.Write(vchToHash.data(), vchToHash.size());
|
{
|
||||||
hasher.Finalize(&(vchHash[0]));
|
if (proof.hasValue != itNode->second.hasValue)
|
||||||
uint256 calculatedHash(vchHash);
|
|
||||||
if (calculatedHash != itNode->second.nodeHash)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (currentPosition == "" && calculatedHash != rootHash)
|
if (proof.hasValue)
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::map<std::string, CNCCTrieProofNode>::const_iterator itNode = proof.nodes.find(name);
|
|
||||||
if (itNode == proof.nodes.end())
|
|
||||||
{
|
|
||||||
return name != "" && !proof.hasValue;
|
|
||||||
}
|
|
||||||
std::vector<unsigned char> vchToHash;
|
|
||||||
for (std::vector<unsigned char>::const_iterator itChildren = itNode->second.children.begin(); itChildren != itNode->second.children.end(); ++itChildren)
|
|
||||||
{
|
|
||||||
vchToHash.push_back(*itChildren);
|
|
||||||
std::stringstream nextPosition;
|
|
||||||
nextPosition << name << *itChildren;
|
|
||||||
std::map<std::string, CNCCTrieProofLeafNode>::const_iterator itChildNode = proof.leafNodes.find(nextPosition.str());
|
|
||||||
if (itChildNode == proof.leafNodes.end())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
vchToHash.insert(vchToHash.end(), itChildNode->second.nodeHash.begin(), itChildNode->second.nodeHash.end());
|
|
||||||
}
|
|
||||||
if (itNode->second.hasValue != proof.hasValue)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (itNode->second.hasValue)
|
|
||||||
{
|
{
|
||||||
uint256 valHash = getOutPointHash(proof.txhash, proof.nOut);
|
uint256 valHash = getOutPointHash(proof.txhash, proof.nOut);
|
||||||
if (valHash != itNode->second.valHash)
|
if (valHash != itNode->second.valHash)
|
||||||
|
@ -1502,22 +1482,22 @@ bool verify_proof(CNCCTrieProof proof, uint256 rootHash, const std::string& name
|
||||||
}
|
}
|
||||||
vchToHash.insert(vchToHash.end(), valHash.begin(), valHash.end());
|
vchToHash.insert(vchToHash.end(), valHash.begin(), valHash.end());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
CHash256 hasher;
|
CHash256 hasher;
|
||||||
std::vector<unsigned char> vchHash(hasher.OUTPUT_SIZE);
|
std::vector<unsigned char> vchHash(hasher.OUTPUT_SIZE);
|
||||||
hasher.Write(vchToHash.data(), vchToHash.size());
|
hasher.Write(vchToHash.data(), vchToHash.size());
|
||||||
hasher.Finalize(&(vchHash[0]));
|
hasher.Finalize(&(vchHash[0]));
|
||||||
uint256 calculatedHash(vchHash);
|
uint256 calculatedHash(vchHash);
|
||||||
if (calculatedHash != itNode->second.nodeHash)
|
nodeHash = calculatedHash;
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (name == "" && calculatedHash != rootHash)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool verify_proof(CNCCTrieProof proof, uint256 rootHash, const std::string& name)
|
||||||
|
{
|
||||||
|
uint256 computedRootHash;
|
||||||
|
return get_node_hash(name, "", name.begin(), proof, computedRootHash) && rootHash == computedRootHash;
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(ncctrievalue_proof)
|
BOOST_AUTO_TEST_CASE(ncctrievalue_proof)
|
||||||
{
|
{
|
||||||
int block_counter = 0;
|
int block_counter = 0;
|
||||||
|
|
Loading…
Reference in a new issue