From f2bb96c9cbbd4a3360d887edaea160e26d31e73b Mon Sep 17 00:00:00 2001 From: Anthony Fieroni Date: Wed, 14 Aug 2019 19:56:21 +0300 Subject: [PATCH] Logic fixes, unit test Signed-off-by: Anthony Fieroni --- src/rpc/claimrpchelp.h | 4 +- src/rpc/claimtrie.cpp | 142 ++++++++++--------- src/test/claimtriebranching_tests.cpp | 189 +++++++++++++++++++++++++- 3 files changed, 254 insertions(+), 81 deletions(-) diff --git a/src/rpc/claimrpchelp.h b/src/rpc/claimrpchelp.h index 69abc2cac..f7fd91f3a 100644 --- a/src/rpc/claimrpchelp.h +++ b/src/rpc/claimrpchelp.h @@ -100,7 +100,7 @@ S3(" ", T_AMOUNT, " (numeric) the amount of the support") \ S1(" ]") \ S3(" ", T_LASTTAKEOVERHEIGHT, " (numeric) the last height at which ownership of the name changed") \ S3(" ", T_BID, " (numeric) lower value means a higher bid rate, ordered by effective amount") \ -S3(" ", T_SEQUENCE, " (numeric) lower value means latest in sequence, ordered by height of insertion") +S3(" ", T_SEQUENCE, " (numeric) lower value means an older one in sequence, ordered by height of insertion") #define PROOF_OUTPUT \ S3(" ", T_NODES, ": [ (array of object, pre-fork) full nodes\n" \ @@ -194,7 +194,7 @@ S3(" ", T_VALIDATHEIGHT, " (numeric) the height at which the support S3(" ", T_AMOUNT, " (numeric) the amount of the support") S1(" ]") S3(" ", T_BID, " (numeric) lower value means a higher bid rate, ordered by effective amount") -S3(" ", T_SEQUENCE, " (numeric) lower value means latest in sequence, ordered by height of insertion") +S3(" ", T_SEQUENCE, " (numeric) lower value means an older one in sequence, ordered by height of insertion") S1(" ]") S3(" ", T_LASTTAKEOVERHEIGHT, " (numeric) the last height at which ownership of the name changed") S3(" ", T_SUPPORTSWITHOUTCLAIM, ": [") diff --git a/src/rpc/claimtrie.cpp b/src/rpc/claimtrie.cpp index 70c49fa4b..af940a790 100644 --- a/src/rpc/claimtrie.cpp +++ b/src/rpc/claimtrie.cpp @@ -19,21 +19,22 @@ #include #include -void ParseClaimtrieId(const UniValue& v, std::string& partialId, uint160& claimId, const std::string& strName) -{ - static constexpr size_t claimIdHexLength = 40; +static constexpr size_t claimIdHexLength = 40; - std::string strHex; - if (v.isStr()) - strHex = v.get_str(); - if (!IsHex(strHex)) +uint160 uint160S(const std::string& str) +{ + uint160 s; + s.SetHex(str); + return s; +} + +void ParseClaimtrieId(const UniValue& v, std::string& claimId, const std::string& strName) +{ + // use IsHexNumber which verify odd strings size + if (!v.isStr() || !IsHexNumber(claimId = v.get_str())) throw JSONRPCError(RPC_INVALID_PARAMETER, strName + " must be a hexadecimal string"); - if (strHex.length() > claimIdHexLength) + if (claimId.length() > claimIdHexLength) throw JSONRPCError(RPC_INVALID_PARAMETER, strName + " must be max 20-character hexadecimal string"); - if (strHex.length() == claimIdHexLength) - claimId.SetHex(strHex); - else - partialId = strHex; } static CBlockIndex* BlockHashIndex(const uint256& blockHash) @@ -107,7 +108,7 @@ std::string escapeNonUtf8(const std::string& name) } } -static bool getValueForOutPoint(const CScript& scriptPubKey, std::string& sValue) +static bool extractValue(const CScript& scriptPubKey, std::string& sValue) { int op; std::vector > vvchParams; @@ -174,11 +175,9 @@ std::vector seqSort(const std::vector& source) auto claimsNsupports = source; std::sort(claimsNsupports.begin(), claimsNsupports.end(), [](const CClaimNsupports& lhs, const CClaimNsupports& rhs) { - if (lhs.claim.nHeight > rhs.claim.nHeight) - return true; - if (lhs.claim.nHeight != rhs.claim.nHeight) - return false; - return lhs.claim.outPoint.n > rhs.claim.outPoint.n; + auto& lc = lhs.claim; + auto& rc = rhs.claim; + return lc.nHeight < rc.nHeight || (lc.nHeight == rc.nHeight && lc.outPoint.n < rc.outPoint.n); }); return claimsNsupports; @@ -204,7 +203,7 @@ UniValue claimToJSON(const CCoinsViewCache& coinsCache, const CClaimValue& claim auto& coin = coinsCache.AccessCoin(claim.outPoint); if (!coin.IsSpent()) { std::string value; - if (getValueForOutPoint(coin.out.scriptPubKey, value)) + if (extractValue(coin.out.scriptPubKey, value)) result.pushKV(T_VALUE, value); CTxDestination address; @@ -229,7 +228,7 @@ UniValue supportToJSON(const CCoinsViewCache& coinsCache, const CSupportValue& s auto& coin = coinsCache.AccessCoin(support.outPoint); if (!coin.IsSpent()) { std::string value; - if (getValueForOutPoint(coin.out.scriptPubKey, value)) + if (extractValue(coin.out.scriptPubKey, value)) ret.pushKV(T_VALUE, value); CTxDestination address; @@ -286,7 +285,6 @@ static UniValue getclaimsintrie(const JSONRPCRequest& request) throw JSONRPCError(RPC_METHOD_DEPRECATED, msg); } - UniValue ret(UniValue::VARR); LOCK(cs_main); CCoinsViewCache coinsCache(pcoinsTip.get()); CClaimTrieCache trieCache(pclaimTrie); @@ -296,6 +294,7 @@ static UniValue getclaimsintrie(const JSONRPCRequest& request) RollBackTo(blockIndex, coinsCache, trieCache); } + UniValue ret(UniValue::VARR); trieCache.recurseNodes({}, [&ret, &trieCache, &coinsCache] (const std::string& name, const CClaimTrieData& data) { if (ShutdownRequested()) throw JSONRPCError(RPC_INTERNAL_ERROR, "Shutdown requested"); @@ -335,8 +334,8 @@ static UniValue getnamesintrie(const JSONRPCRequest& request) CBlockIndex* blockIndex = BlockHashIndex(ParseHashV(request.params[0], T_BLOCKHASH " (optional parameter 1)")); RollBackTo(blockIndex, coinsCache, trieCache); } - UniValue ret(UniValue::VARR); + UniValue ret(UniValue::VARR); trieCache.recurseNodes({}, [&ret](const std::string &name, const CClaimTrieData &data) { if (!data.empty()) ret.push_back(escapeNonUtf8(name)); @@ -362,10 +361,9 @@ static UniValue getvalueforname(const JSONRPCRequest& request) RollBackTo(blockIndex, coinsCache, trieCache); } - uint160 claimId; - std::string partialId; + std::string claimId; if (request.params.size() > 2) - ParseClaimtrieId(request.params[2], partialId, claimId, T_CLAIMID " (optional parameter 3)"); + ParseClaimtrieId(request.params[2], claimId, T_CLAIMID " (optional parameter 3)"); const auto name = request.params[0].get_str(); UniValue ret(UniValue::VOBJ); @@ -375,8 +373,8 @@ static UniValue getvalueforname(const JSONRPCRequest& request) return ret; auto& claimNsupports = - !claimId.IsNull() ? csToName.find(claimId) : - !partialId.empty() ? csToName.find(partialId) : csToName.claimsNsupports[0]; + claimId.length() == claimIdHexLength ? csToName.find(uint160S(claimId)) : + !claimId.empty() ? csToName.find(claimId) : csToName.claimsNsupports[0]; if (claimNsupports.IsNull()) return ret; @@ -451,7 +449,7 @@ UniValue getclaimbybid(const JSONRPCRequest& request) bid = request.params[1].get_int(); if (bid < 0) - throw JSONRPCError(RPC_INVALID_PARAMETER, T_BID " (parameter 2) should be greater than 0"); + throw JSONRPCError(RPC_INVALID_PARAMETER, T_BID " (parameter 2) should not be a negative value"); if (request.params.size() > 2) { CBlockIndex* blockIndex = BlockHashIndex(ParseHashV(request.params[2], T_BLOCKHASH " (optional parameter 3)")); @@ -494,7 +492,7 @@ UniValue getclaimbyseq(const JSONRPCRequest& request) seq = request.params[1].get_int(); if (seq < 0) - throw JSONRPCError(RPC_INVALID_PARAMETER, T_SEQUENCE " (parameter 2) should be greater than 0"); + throw JSONRPCError(RPC_INVALID_PARAMETER, T_SEQUENCE " (parameter 2) should not be a negative value"); if (request.params.size() > 2) { CBlockIndex* blockIndex = BlockHashIndex(ParseHashV(request.params[2], T_BLOCKHASH " (optional parameter 3)")); @@ -534,34 +532,34 @@ UniValue getclaimbyid(const JSONRPCRequest& request) CClaimTrieCache trieCache(pclaimTrie); CCoinsViewCache coinsCache(pcoinsTip.get()); - uint160 claimId; - std::string partialId; - ParseClaimtrieId(request.params[0], partialId, claimId, T_CLAIMID " (parameter 1)"); + std::string claimId; + ParseClaimtrieId(request.params[0], claimId, T_CLAIMID " (parameter 1)"); - if (claimId.IsNull() && partialId.length() < 3) + if (claimId.length() < 3) throw JSONRPCError(RPC_INVALID_PARAMETER, T_CLAIMID " (parameter 1) should be at least 3 chars"); - UniValue claim(UniValue::VOBJ); std::string name; - CClaimValue claimValue; - if (getClaimById(claimId, name, &claimValue) || getClaimById(partialId, name, &claimValue)) { + CClaimValue claim; + UniValue ret(UniValue::VOBJ); + bool found = claimId.length() == claimIdHexLength && getClaimById(uint160S(claimId), name, &claim); + if (found || getClaimById(claimId, name, &claim)) { auto csToName = trieCache.getClaimsForName(name); - auto& claimNsupports = !claimId.IsNull() ? csToName.find(claimId) : csToName.find(partialId); + auto& claimNsupports = csToName.find(claim.claimId); if (!claimNsupports.IsNull()) { std::size_t seq = 0, bid = 0; if (csToName.claimsNsupports.size() > 1) { auto seqOrder = seqSort(csToName.claimsNsupports); - seq = indexOf(seqOrder, claimNsupports.claim.claimId); - bid = indexOf(csToName.claimsNsupports, claimNsupports.claim.claimId); + seq = indexOf(seqOrder, claim.claimId); + bid = indexOf(csToName.claimsNsupports, claim.claimId); } - claim.pushKV(T_NORMALIZEDNAME, escapeNonUtf8(csToName.name)); - claim.pushKVs(claimAndSupportsToJSON(coinsCache, claimNsupports)); - claim.pushKV(T_LASTTAKEOVERHEIGHT, csToName.nLastTakeoverHeight); - claim.pushKV(T_BID, (int)bid); - claim.pushKV(T_SEQUENCE, (int)seq); + ret.pushKV(T_NORMALIZEDNAME, escapeNonUtf8(csToName.name)); + ret.pushKVs(claimAndSupportsToJSON(coinsCache, claimNsupports)); + ret.pushKV(T_LASTTAKEOVERHEIGHT, csToName.nLastTakeoverHeight); + ret.pushKV(T_BID, (int)bid); + ret.pushKV(T_SEQUENCE, (int)seq); } } - return claim; + return ret; } UniValue gettotalclaimednames(const JSONRPCRequest& request) @@ -734,20 +732,21 @@ UniValue getnameproof(const JSONRPCRequest& request) RollBackTo(pblockIndex, coinsCache, trieCache); } - uint160 claimId; - std::string partialId; + std::string claimId; if (request.params.size() > 2) - ParseClaimtrieId(request.params[2], partialId, claimId, T_CLAIMID " (optional parameter 3)"); + ParseClaimtrieId(request.params[2], claimId, T_CLAIMID " (optional parameter 3)"); std::function comp; - if (!claimId.IsNull()) + if (claimId.length() == claimIdHexLength) { + auto claimIdx = uint160S(claimId); + comp = [claimIdx](const CClaimValue& claim) { + return claim.claimId == claimIdx; + }; + } else if (!claimId.empty()) { comp = [&claimId](const CClaimValue& claim) { - return claim.claimId == claimId; - }; - else - comp = [&partialId](const CClaimValue& claim) { - return claim.claimId.GetHex().find(partialId) == 0; + return claim.claimId.GetHex().find(claimId) == 0; }; + } CClaimTrieProof proof; std::string name = request.params[0].get_str(); @@ -770,7 +769,7 @@ UniValue getclaimproofbybid(const JSONRPCRequest& request) bid = request.params[1].get_int(); if (bid < 0) - throw JSONRPCError(RPC_INVALID_PARAMETER, T_BID " (parameter 2) should be greater than 0"); + throw JSONRPCError(RPC_INVALID_PARAMETER, T_BID " (parameter 2) should not be a negative value"); if (request.params.size() > 2) { CBlockIndex* pblockIndex = BlockHashIndex(ParseHashV(request.params[2], T_BLOCKHASH " (optional parameter 3)")); @@ -810,7 +809,7 @@ UniValue getclaimproofbyseq(const JSONRPCRequest& request) seq = request.params[1].get_int(); if (seq < 0) - throw JSONRPCError(RPC_INVALID_PARAMETER, T_SEQUENCE " (parameter 2) should be greater than 0"); + throw JSONRPCError(RPC_INVALID_PARAMETER, T_SEQUENCE " (parameter 2) should not be a negative value"); if (request.params.size() > 2) { CBlockIndex* pblockIndex = BlockHashIndex(ParseHashV(request.params[2], T_BLOCKHASH " (optional parameter 3")); @@ -838,9 +837,20 @@ UniValue getclaimproofbyseq(const JSONRPCRequest& request) extern bool UndoReadFromDisk(CBlockUndo&, const CBlockIndex*); +template +UniValue removedToJSON(const std::vector>& undo) +{ + UniValue ret(UniValue::VARR); + for (auto& u : undo) { + auto& outPoint = u.second.outPoint; + ret.push_back(ClaimIdHash(outPoint.hash, outPoint.n).ToString()); + } + return ret; +} + UniValue getchangesinblock(const JSONRPCRequest& request) { - validateRequest(request, GETCHANGESINBLOCK, 1, 0); + validateRequest(request, GETCHANGESINBLOCK, 0, 1); CBlockUndo undo; { @@ -861,25 +871,11 @@ UniValue getchangesinblock(const JSONRPCRequest& request) return added; }; - auto removedClaims = [](const claimQueueRowType& expireUndo) { - UniValue removed(UniValue::VARR); - for (auto& r : expireUndo) - removed.push_back(r.second.claimId.ToString()); - return removed; - }; - - auto removedSupports = [](const supportQueueRowType& expireUndo) { - UniValue removed(UniValue::VARR); - for (auto& r : expireUndo) - removed.push_back(r.second.supportedClaimId.ToString()); - return removed; - }; - UniValue result(UniValue::VOBJ); result.pushKV(T_CLAIMSADDEDORUPDATED, addedUpdated(undo.insertUndo)); - result.pushKV(T_CLAIMSREMOVED, removedClaims(undo.expireUndo)); + result.pushKV(T_CLAIMSREMOVED, removedToJSON(undo.expireUndo)); result.pushKV(T_SUPPORTSADDEDORUPDATED, addedUpdated(undo.insertSupportUndo)); - result.pushKV(T_SUPPORTSREMOVED, removedSupports(undo.expireSupportUndo)); + result.pushKV(T_SUPPORTSREMOVED, removedToJSON(undo.expireSupportUndo)); return result; } diff --git a/src/test/claimtriebranching_tests.cpp b/src/test/claimtriebranching_tests.cpp index 454162d0a..2d7f5d04c 100644 --- a/src/test/claimtriebranching_tests.cpp +++ b/src/test/claimtriebranching_tests.cpp @@ -4135,9 +4135,9 @@ BOOST_AUTO_TEST_CASE(update_on_support2_test) BOOST_CHECK_EQUAL(node.nHeightOfLastTakeover, height + 1); } -void ValidatePairs(CClaimTrieCache& cache, const CClaimTrieProof& proof, uint256 claimHash) +void ValidatePairs(CClaimTrieCache& cache, const std::vector>& pairs, uint256 claimHash) { - for (auto& pair : proof.pairs) + for (auto& pair : pairs) if (pair.first) // we're on the right because we were an odd index number claimHash = Hash(pair.second.begin(), pair.second.end(), claimHash.begin(), claimHash.end()); else @@ -4182,7 +4182,7 @@ BOOST_AUTO_TEST_CASE(hash_includes_all_claims_single_test) BOOST_CHECK(proof.hasValue); BOOST_CHECK_EQUAL(proof.outPoint, outPoint); auto claimHash = getValueHash(outPoint, proof.nHeightOfLastTakeover); - ValidatePairs(fixture, proof, claimHash); + ValidatePairs(fixture, proof.pairs, claimHash); } BOOST_AUTO_TEST_CASE(hash_includes_all_claims_triple_test) @@ -4212,7 +4212,7 @@ BOOST_AUTO_TEST_CASE(hash_includes_all_claims_triple_test) BOOST_CHECK(proof.hasValue); BOOST_CHECK_EQUAL(proof.outPoint, claim.outPoint); uint256 claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover); - ValidatePairs(fixture, proof, claimHash); + ValidatePairs(fixture, proof.pairs, claimHash); } } } @@ -4243,7 +4243,7 @@ BOOST_AUTO_TEST_CASE(hash_includes_all_claims_branched_test) BOOST_CHECK(proof.hasValue); BOOST_CHECK_EQUAL(proof.outPoint, claim.outPoint); uint256 claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover); - ValidatePairs(fixture, proof, claimHash); + ValidatePairs(fixture, proof.pairs, claimHash); } } } @@ -4278,9 +4278,186 @@ BOOST_AUTO_TEST_CASE(hash_claims_children_fuzzer_test) BOOST_CHECK(proof.hasValue); BOOST_CHECK_EQUAL(proof.outPoint, claim.outPoint); uint256 claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover); - ValidatePairs(fixture, proof, claimHash); + ValidatePairs(fixture, proof.pairs, claimHash); } } } +std::vector> jsonToPairs(const UniValue& jsonPair) +{ + std::vector> pairs; + for (std::size_t i = 0; i < jsonPair.size(); ++i) { + auto& jpair = jsonPair[i]; + pairs.emplace_back(jpair[T_ODD].get_bool(), uint256S(jpair[T_HASH].get_str())); + } + return pairs; +} + +BOOST_AUTO_TEST_CASE(hash_bid_seq_claim_changes_test) +{ + ClaimTrieChainFixture fixture; + fixture.setHashForkHeight(2); + fixture.IncrementBlocks(4); + + std::string name = "toa"; + std::string value1 = "one", value2 = "two", value3 = "tre", value4 = "for"; + + auto tx1 = fixture.MakeClaim(fixture.GetCoinbase(), name, value1, 1); + fixture.IncrementBlocks(1); + + CMutableTransaction tx2 = BuildTransaction(fixture.GetCoinbase(), 0, 2); + tx2.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME + << std::vector(name.begin(), name.end()) + << std::vector(value2.begin(), value2.end()) << OP_2DROP << OP_DROP << OP_TRUE; + tx2.vout[0].nValue = 3; + tx2.vout[1].scriptPubKey = CScript() << OP_CLAIM_NAME + << std::vector(name.begin(), name.end()) + << std::vector(value3.begin(), value3.end()) << OP_2DROP << OP_DROP << OP_TRUE; + tx2.vout[1].nValue = 2; + + fixture.CommitTx(tx2); + fixture.IncrementBlocks(1); + + auto tx3 = fixture.MakeClaim(fixture.GetCoinbase(), name, value4, 4); + fixture.IncrementBlocks(1); + + int height = chainActive.Height(); + + auto claimId1 = ClaimIdHash(tx1.GetHash(), 0); + auto claimId2 = ClaimIdHash(tx2.GetHash(), 0); + auto claimId3 = ClaimIdHash(tx2.GetHash(), 1); + auto claimId4 = ClaimIdHash(tx3.GetHash(), 0); + + int claim1bid = 3, claim1seq = 0; + int claim2bid = 1, claim2seq = 1; + int claim3bid = 2, claim3seq = 2; + int claim4bid = 0, claim4seq = 3; + + auto getclaimsforname = tableRPC["getclaimsforname"]->actor; + + JSONRPCRequest req; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(name)); + + auto result = getclaimsforname(req); + auto claims = result[T_CLAIMS]; + BOOST_CHECK_EQUAL(claims.size(), 4U); + BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height); + BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 4); + BOOST_CHECK_EQUAL(claims[0][T_BID].get_int(), claim4bid); + BOOST_CHECK_EQUAL(claims[0][T_SEQUENCE].get_int(), claim4seq); + BOOST_CHECK_EQUAL(claims[0][T_CLAIMID].get_str(), claimId4.GetHex()); + BOOST_CHECK_EQUAL(claims[1][T_EFFECTIVEAMOUNT].get_int(), 3); + BOOST_CHECK_EQUAL(claims[1][T_BID].get_int(), claim2bid); + BOOST_CHECK_EQUAL(claims[1][T_SEQUENCE].get_int(), claim2seq); + BOOST_CHECK_EQUAL(claims[1][T_CLAIMID].get_str(), claimId2.GetHex()); + BOOST_CHECK_EQUAL(claims[2][T_EFFECTIVEAMOUNT].get_int(), 2); + BOOST_CHECK_EQUAL(claims[2][T_BID].get_int(), claim3bid); + BOOST_CHECK_EQUAL(claims[2][T_SEQUENCE].get_int(), claim3seq); + BOOST_CHECK_EQUAL(claims[2][T_CLAIMID].get_str(), claimId3.GetHex()); + BOOST_CHECK_EQUAL(claims[3][T_EFFECTIVEAMOUNT].get_int(), 1); + BOOST_CHECK_EQUAL(claims[3][T_BID].get_int(), claim1bid); + BOOST_CHECK_EQUAL(claims[3][T_SEQUENCE].get_int(), claim1seq); + BOOST_CHECK_EQUAL(claims[3][T_CLAIMID].get_str(), claimId1.GetHex()); + + auto getclaimbybid = tableRPC["getclaimbybid"]->actor; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(name)); + req.params.push_back(UniValue(claim3bid)); + + result = getclaimbybid(req); + BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height); + BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 2); + BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim3bid); + BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim3seq); + BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId3.GetHex()); + + auto getclaimbyseq = tableRPC["getclaimbyseq"]->actor; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(name)); + req.params.push_back(UniValue(claim2seq)); + + result = getclaimbyseq(req); + BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height); + BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 3); + BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim2bid); + BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim2seq); + BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId2.GetHex()); + + auto getclaimbyid = tableRPC["getclaimbyid"]->actor; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(claimId1.GetHex())); + + result = getclaimbyid(req); + BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height); + BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 1); + BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim1bid); + BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim1seq); + BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId1.GetHex()); + + // check by partial id (at least 3 chars) + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(claimId3.GetHex().substr(0, 3))); + + result = getclaimbyid(req); + BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height); + BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 2); + BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim3bid); + BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim3seq); + BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId3.GetHex()); + + auto blockhash = chainActive.Tip()->GetBlockHash(); + + auto getnameproof = tableRPC["getnameproof"]->actor; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(name)); + req.params.push_back(UniValue(blockhash.GetHex())); + req.params.push_back(UniValue(claimId3.GetHex())); + + result = getnameproof(req); + auto claimHash = getValueHash(COutPoint(tx2.GetHash(), 1), result[T_LASTTAKEOVERHEIGHT].get_int()); + ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash); + + // check by partial id (can be even 1 char) + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(name)); + req.params.push_back(UniValue(blockhash.GetHex())); + req.params.push_back(UniValue(claimId2.GetHex().substr(0, 2))); + + result = getnameproof(req); + claimHash = getValueHash(COutPoint(tx2.GetHash(), 0), result[T_LASTTAKEOVERHEIGHT].get_int()); + ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash); + + auto getclaimproofbybid = tableRPC["getclaimproofbybid"]->actor; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(name)); + req.params.push_back(UniValue(claim1bid)); + + result = getclaimproofbybid(req); + claimHash = getValueHash(COutPoint(tx1.GetHash(), 0), result[T_LASTTAKEOVERHEIGHT].get_int()); + ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash); + + auto getclaimproofbyseq = tableRPC["getclaimproofbyseq"]->actor; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(name)); + req.params.push_back(UniValue(claim4seq)); + + result = getclaimproofbyseq(req); + claimHash = getValueHash(COutPoint(tx3.GetHash(), 0), result[T_LASTTAKEOVERHEIGHT].get_int()); + ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash); + + auto getchangesinblock = tableRPC["getchangesinblock"]->actor; + req.params = UniValue(UniValue::VARR); + req.params.push_back(UniValue(blockhash.GetHex())); + + result = getchangesinblock(req); + BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED].size(), 3); + BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED][0].get_str(), claimId2.GetHex()); + BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED][1].get_str(), claimId3.GetHex()); + BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED][2].get_str(), claimId4.GetHex()); + BOOST_CHECK_EQUAL(result[T_CLAIMSREMOVED].size(), 0); + BOOST_CHECK_EQUAL(result[T_SUPPORTSADDEDORUPDATED].size(), 0); + BOOST_CHECK_EQUAL(result[T_SUPPORTSREMOVED].size(), 0); +} + BOOST_AUTO_TEST_SUITE_END()