diff --git a/src/chain.h b/src/chain.h index c6fc34832c..a62f14cb41 100644 --- a/src/chain.h +++ b/src/chain.h @@ -261,6 +261,8 @@ class CBlockIndex sigma::spend_info_container sigmaSpentSerials; std::unordered_map lelantusSpentSerials; std::unordered_map spentLTags; + // linking tag hash mapped to tx hash + std::unordered_map ltagTxhash; //! list of disabling sporks active at this block height //! std::map {feature name} -> {block number when feature is re-enabled again, parameter} @@ -303,6 +305,7 @@ class CBlockIndex sparkMintedCoins.clear(); sparkSetHash.clear(); spentLTags.clear(); + ltagTxhash.clear(); sparkTxHashContext.clear(); sigmaSpentSerials.clear(); lelantusSpentSerials.clear(); @@ -563,6 +566,7 @@ class CDiskBlockIndex : public CBlockIndex if (GetBoolArg("-mobile", false)) { READWRITE(sparkTxHashContext); + READWRITE(ltagTxhash); } } diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index bfbdf2f22f..629dde9a14 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -194,6 +194,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getusedcoinserials", 0 }, { "getlatestcoinids", 0 }, { "getsparkmintmetadata", 0 }, + { "getmempooltxs", 0 }, //Lelantus { "mintspark", 0 }, diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index ad96886540..8f73698fa0 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -1404,6 +1404,63 @@ UniValue getusedcoinstags(const JSONRPCRequest& request) return ret; } +UniValue getusedcoinstagstxhashes(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() != 1) + throw std::runtime_error( + "getusedcoinstagstxhashes\n" + "\nReturns the set of used coin tags paired with tx ids in which it was spent, this rpc required -mobile argument, \n" + "\nArguments:\n" + "{\n" + " \"startNumber \" (int) Number of elements already existing on user side\n" + "}\n" + "\nResult:\n" + "{\n" + " \"tags\" (std::string[]) array of Serialized GroupElements paired with unit256 (tx ids) \n" + "}\n" + ); + + int startNumber; + try { + startNumber = std::stol(request.params[0].get_str()); + } catch (std::logic_error const & e) { + throw std::runtime_error(std::string("An exception occurred while parsing parameters: ") + e.what()); + } + + spark::CSparkState* sparkState = spark::CSparkState::GetState(); + std::unordered_map tags; + std::unordered_map ltagTxhash; + { + LOCK(cs_main); + tags = sparkState->GetSpends(); + ltagTxhash = sparkState->GetSpendTxIds(); + } + UniValue serializedTagsTxIds(UniValue::VARR); + int i = 0; + for ( auto it = tags.begin(); it != tags.end(); ++it, ++i) { + if ((tags.size() - i - 1) < startNumber) + continue; + std::vector serialized; + serialized.resize(34); + it->first.serialize(serialized.data()); + std::vector data; + data.push_back(EncodeBase64(serialized.data(), 34)); + uint256 txid; + uint256 ltagHash = primitives::GetLTagHash(it->first); + if (ltagTxhash.count(ltagHash) > 0) + txid = ltagTxhash[ltagHash]; + data.push_back(EncodeBase64(txid.begin(), txid.size())); + UniValue entity(UniValue::VARR); + entity.push_backV(data); + serializedTagsTxIds.push_back(entity); + } + + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("tagsandtxids", serializedTagsTxIds)); + + return ret; +} + UniValue getsparklatestcoinid(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) @@ -1431,6 +1488,107 @@ UniValue getsparklatestcoinid(const JSONRPCRequest& request) return UniValue(latestCoinId); } +UniValue getmempoolsparktxids(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() != 0) + throw std::runtime_error( + "getmempoolsparktxids\n" + "\nReturns spark transaction ids existing in the mempool.\n" + ); + + UniValue result(UniValue::VARR); + std::vector txs = mempool.infoAll(); + for (auto it = txs.begin(); it != txs.end(); it++) { + if (!it->tx->IsSparkTransaction()) + continue; + result.push_back(EncodeBase64(it->tx->GetHash().begin(), it->tx->GetHash().size())); + } + + return result; +} + +UniValue getmempoolsparktxs(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() != 1) + throw std::runtime_error( + "getmempoolsparktxs\n" + "\nReturns spark metadata for each transaction id, in case tx already was removed from mempool, nothing will be returned for specific id.\n" + "\nArguments:\n" + " \"txids\"\n" + " [\n" + " {\n" + " \"txid\" (string) The transaction hash\n" + " }\n" + " ,...\n" + " ]\n" + "\nResult:\n" + "txid , {\n" + " \"lTags\" Array of GroupElements, or a string 'MintTX' in case it is mint tx\n" + " \"serial_context\" byte array which is used to identify the output spark coins, it is unique for each ix\n" + " \"coins\" Array of serialized spar::Coin elements, the output coins of the tx\n" + "}\n" + + HelpExampleCli("getmempoolsparktxs", "'{\"txids\": [\"b476ed2b374bb081ea51d111f68f0136252521214e213d119b8dc67b92f5a390\",\"b476ed2b374bb081ea51d111f68f0136252521214e213d119b8dc67b92f5a390\"]}'") + + HelpExampleRpc("getmempoolsparktxs", "{\"txids\": [\"b476ed2b374bb081ea51d111f68f0136252521214e213d119b8dc67b92f5a390\",\"b476ed2b374bb081ea51d111f68f0136252521214e213d119b8dc67b92f5a390\"]}") + + ); + + UniValue txids = find_value(request.params[0].get_obj(), "txids"); + + UniValue result(UniValue::VOBJ); + for(UniValue const & element : txids.getValues()){ + uint256 txid; + txid.SetHex(element.get_str()); + CTransactionRef tx = mempool.get(txid); + if (tx == nullptr || !tx->IsSparkTransaction()) + continue; + + UniValue data(UniValue::VOBJ); + std::vector lTags_; + UniValue lTags_json(UniValue::VARR); + if (tx->IsSparkSpend()) + { + try { + spark::SpendTransaction spend = spark::ParseSparkSpend(*tx); + auto lTags = spend.getUsedLTags(); + for ( auto it = lTags.begin(); it != lTags.end(); ++it) { + std::vector serialized; + serialized.resize(34); + it->serialize(serialized.data()); + lTags_.push_back(EncodeBase64(serialized.data(), 34)); + } + } catch (const std::exception &) { + continue; + } + } else { + lTags_.push_back("MintTX"); + } + lTags_json.push_backV(lTags_); + + data.push_back(Pair("lTags ", lTags_json)); // Spend lTags for corresponding tx, + + std::vector serial_context = spark::getSerialContext(*tx); + UniValue serial_context_json(UniValue::VARR); + serial_context_json.push_back(EncodeBase64(serial_context.data(), serial_context.size())); + data.push_back(Pair("serial_context", serial_context_json)); // spark serial context + + std::vector coins = spark::GetSparkMintCoins(*tx); + std::vector serialized_coins; + UniValue serialized_json(UniValue::VARR); + for (auto& coin: coins) { + CDataStream serializedCoin(SER_NETWORK, PROTOCOL_VERSION); + serializedCoin << coin; + std::vector vch(serializedCoin.begin(), serializedCoin.end()); + serialized_coins.push_back(EncodeBase64(vch.data(), size_t(vch.size()))); // coi + } + serialized_json.push_backV(serialized_coins); + data.push_back(Pair("coins", serialized_json)); + + result.push_back(Pair(EncodeBase64(txid.begin(), txid.size()), data)); + } + + return result; +} + UniValue checkifmncollateral(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 2) @@ -1762,7 +1920,10 @@ static const CRPCCommand commands[] = { "mobile", "getsparkanonymityset", &getsparkanonymityset, false }, { "mobile", "getsparkmintmetadata", &getsparkmintmetadata, true }, { "mobile", "getusedcoinstags", &getusedcoinstags, false }, + { "mobile", "getusedcoinstagstxhashes", &getusedcoinstagstxhashes, false }, { "mobile", "getsparklatestcoinid", &getsparklatestcoinid, true }, + { "mobile", "getmempoolsparktxids", &getmempoolsparktxids, true }, + { "mobile", "getmempoolsparktxs", &getmempoolsparktxs, true }, { "mobile", "checkifmncollateral", &checkifmncollateral, false }, diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 04870a06bc..0f07787f1b 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -342,7 +342,11 @@ static const CRPCCommand vRPCCommands[] = { "mobile", "getsparkanonymityset", &getsparkanonymityset, false }, { "mobile", "getsparkmintmetadata", &getsparkmintmetadata, true }, { "mobile", "getusedcoinstags", &getusedcoinstags, false }, + { "mobile", "getusedcoinstagstxhashes", &getusedcoinstagstxhashes, false }, { "mobile", "getsparklatestcoinid", &getsparklatestcoinid, true }, + { "mobile", "getmempoolsparktxids", &getmempoolsparktxids, true }, + { "mobile", "getmempoolsparktxs", &getmempoolsparktxs, true }, + { "mobile", "checkifmncollateral", &checkifmncollateral, false }, diff --git a/src/rpc/server.h b/src/rpc/server.h index b16f0f4e95..dbf98839b9 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -216,7 +216,10 @@ extern UniValue getlatestcoinid(const JSONRPCRequest& params); extern UniValue getsparkanonymityset(const JSONRPCRequest& params); extern UniValue getsparkmintmetadata(const JSONRPCRequest& params); extern UniValue getusedcoinstags(const JSONRPCRequest& params); +extern UniValue getusedcoinstagstxhashes(const JSONRPCRequest& params); extern UniValue getsparklatestcoinid(const JSONRPCRequest& params); +extern UniValue getmempoolsparktxids(const JSONRPCRequest& params); +extern UniValue getmempoolsparktxs(const JSONRPCRequest& params); extern UniValue checkifmncollateral(const JSONRPCRequest& params); diff --git a/src/spark/state.cpp b/src/spark/state.cpp index 5359a7a9a0..4eebb613e4 100644 --- a/src/spark/state.cpp +++ b/src/spark/state.cpp @@ -265,10 +265,16 @@ bool ConnectBlockSpark( } if (!fJustCheck) { - BOOST_FOREACH(auto& lTag, pblock->sparkTxInfo->spentLTags) { + BOOST_FOREACH (auto& lTag, pblock->sparkTxInfo->spentLTags) { pindexNew->spentLTags.insert(lTag); sparkState.AddSpend(lTag.first, lTag.second); } + if (GetBoolArg("-mobile", false)) { + BOOST_FOREACH (auto& lTag, pblock->sparkTxInfo->ltagTxhash) { + pindexNew->ltagTxhash.insert(lTag); + sparkState.AddLTagTxHash(lTag.first, lTag.second); + } + } } else { return true; @@ -693,6 +699,9 @@ bool CheckSparkSpendTransaction( if (sparkTxInfo && !sparkTxInfo->fInfoIsComplete) { for (size_t i = 0; i < lTags.size(); i++) { sparkTxInfo->spentLTags.insert(std::make_pair(lTags[i], ids[i])); + if (GetBoolArg("-mobile", false)) { + sparkTxInfo->ltagTxhash.insert(std::make_pair(primitives::GetLTagHash(lTags[i]), hashTx)); + } } } } @@ -1038,6 +1047,10 @@ void CSparkState::AddSpend(const GroupElement& lTag, int coinGroupId) { } } +void CSparkState::AddLTagTxHash(const uint256& lTagHash, const uint256& txHash) { + ltagTxhash[lTagHash] = txHash; +} + void CSparkState::RemoveSpend(const GroupElement& lTag) { auto iter = usedLTags.find(lTag); if (iter != usedLTags.end()) { @@ -1074,6 +1087,11 @@ void CSparkState::AddBlock(CBlockIndex *index) { for (auto const &lTags : index->spentLTags) { AddSpend(lTags.first, lTags.second); } + if (GetBoolArg("-mobile", false)) { + for (auto const &elem : index->ltagTxhash) { + AddLTagTxHash(elem.first, elem.second); + } + } } void CSparkState::RemoveBlock(CBlockIndex *index) { @@ -1320,6 +1338,10 @@ std::unordered_map const & CSparkState::Get return usedLTags; } +std::unordered_map const& CSparkState::GetSpendTxIds() const { + return ltagTxhash; +} + std::unordered_map const& CSparkState::GetCoinGroups() const { return coinGroups; } diff --git a/src/spark/state.h b/src/spark/state.h index 3820cb1a1d..c8883875ef 100644 --- a/src/spark/state.h +++ b/src/spark/state.h @@ -26,6 +26,7 @@ class CSparkTxInfo { // linking tag for every spend (map from lTag to coin group id) std::unordered_map spentLTags; + std::unordered_map ltagTxhash; // information about transactions in the block is complete bool fInfoIsComplete; @@ -168,6 +169,7 @@ class CSparkState { void AddMintsToStateAndBlockIndex(CBlockIndex *index, const CBlock* pblock); void AddSpend(const GroupElement& lTag, int coinGroupId); + void AddLTagTxHash(const uint256& lTagHash, const uint256& txHash); void RemoveSpend(const GroupElement& lTag); // Add everything from the block to the state void AddBlock(CBlockIndex *index); @@ -213,6 +215,7 @@ class CSparkState { std::unordered_map const & GetMints() const; std::unordered_map const & GetSpends() const; + std::unordered_map const& GetSpendTxIds() const; std::unordered_map const & GetCoinGroups() const; std::unordered_map const & GetMempoolLTags() const; @@ -238,6 +241,8 @@ class CSparkState { std::unordered_map mintedCoins; // Set of all used coin linking tags. std::unordered_map usedLTags; + // linking tag hash mapped to tx hash + std::unordered_map ltagTxhash; typedef std::map metainfo_container_t; metainfo_container_t extendedMintMetaInfo, mintMetaInfo, spendMetaInfo; diff --git a/src/txdb.cpp b/src/txdb.cpp index acb6463381..2ba448dffa 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -425,6 +425,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts(boost::functionsparkSetHash = diskindex.sparkSetHash; pindexNew->spentLTags = diskindex.spentLTags; pindexNew->sparkTxHashContext = diskindex.sparkTxHashContext; + pindexNew->ltagTxhash = diskindex.ltagTxhash; pindexNew->activeDisablingSporks = diskindex.activeDisablingSporks;