Skip to content

Commit

Permalink
Implement new rpc calls to get anonymity sets
Browse files Browse the repository at this point in the history
  • Loading branch information
levonpetrosyan93 committed Dec 14, 2024
1 parent 6da96d8 commit abc7a95
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 0 deletions.
137 changes: 137 additions & 0 deletions src/rpc/misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,141 @@ UniValue getsparkanonymityset(const JSONRPCRequest& request)
return ret;
}

UniValue getsparkanonymitysetmeta(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
"getsparkanonymitysetmeta\n"
"\nReturns the anonymity set and latest block hash.\n"
"\nArguments:\n"
"{\n"
" \"coinGroupId\" (int)\n"
"}\n"
"\nResult:\n"
"{\n"
" \"blockHash\" (string) Latest block hash for anonymity set\n"
" \"setHash\" (string) Anonymity set hash\n"
" \"size\" (int) set size\n"
"}\n"
+ HelpExampleCli("getsparkanonymitysetmeta", "\"1\" ")
+ HelpExampleRpc("getsparkanonymitysetmeta", "\"1\" ")
);


int coinGroupId;
try {
coinGroupId = 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());
}

if(!GetBoolArg("-mobile", false)){
throw std::runtime_error(std::string("Please rerun Firo with -mobile "));
}

uint256 blockHash;
std::vector<unsigned char> setHash;
int size;
{
LOCK(cs_main);
spark::CSparkState* sparkState = spark::CSparkState::GetState();
sparkState->GetAnonSetMetaData(
&chainActive,
chainActive.Height() - (ZC_MINT_CONFIRMATIONS - 1),
coinGroupId,
blockHash,
setHash,
size);
}

UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("blockHash", EncodeBase64(blockHash.begin(), blockHash.size())));
ret.push_back(Pair("setHash", UniValue(EncodeBase64(setHash.data(), setHash.size()))));
ret.push_back(Pair("size", size));

return ret;
}

UniValue getsparkanonymitysetsector(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 4)
throw std::runtime_error(
"getsparkanonymitysetsector\n"
"\nReturns the anonymity sector based on provided data.\n"
"\nArguments:\n"
"{\n"
" \"coinGroupId\" (int)\n"
" \"latestBlock\" (string)\n"
" \"startIndex\" (int)\n"
" \"endIndex\" (int)\n"
"}\n"
"\nResult:\n"
"{\n"
" \"mints\" (Pair<string, string>) Serialized Spark coin paired with txhash\n"
"}\n"
+ HelpExampleCli("getsparkanonymitysetsector", "\"1\" " "\"ca511f07489e35c9bc60ca62c82de225ba7aae7811ce4c090f95aa976639dc4e\"" "\"0\" " "\"1000\" ")
+ HelpExampleRpc("getsparkanonymitysetsector", "\"1\" " "\"ca511f07489e35c9bc60ca62c82de225ba7aae7811ce4c090f95aa976639dc4e\"" "\"0\" " "\"1000\" ")
);


int coinGroupId;
std::string latestBlock;
int startIndex;
int endIndex;

try {
coinGroupId = std::stol(request.params[0].get_str());
latestBlock = request.params[1].get_str();
startIndex = std::stol(request.params[2].get_str());
endIndex = std::stol(request.params[3].get_str());

} catch (std::logic_error const & e) {
throw std::runtime_error(std::string("An exception occurred while parsing parameters: ") + e.what());
}

if(!GetBoolArg("-mobile", false)) {
throw std::runtime_error(std::string("Please rerun Firo with -mobile "));
}
std::vector<std::pair<spark::Coin, std::pair<uint256, std::vector<unsigned char>>>> coins;
uint256 blockHash = uint256S(latestBlock);
{
LOCK(cs_main);
spark::CSparkState* sparkState = spark::CSparkState::GetState();
sparkState->GetCoinsForRecovery(
&chainActive,
chainActive.Height() - (ZC_MINT_CONFIRMATIONS - 1),
coinGroupId,
blockHash,
coins);
}

UniValue ret(UniValue::VOBJ);
UniValue mints(UniValue::VARR);

std::size_t counter = 0;
for (const auto& coin : coins) {
if (counter < startIndex || ++counter > endIndex)
continue;

CDataStream serializedCoin(SER_NETWORK, PROTOCOL_VERSION);
serializedCoin << coin;
std::vector<unsigned char> vch(serializedCoin.begin(), serializedCoin.end());

std::vector<UniValue> data;
data.push_back(EncodeBase64(vch.data(), size_t(vch.size()))); // coin
data.push_back(EncodeBase64(coin.second.first.begin(), coin.second.first.size())); // tx hash
data.push_back(EncodeBase64(coin.second.second.data(), coin.second.second.size())); // spark serial context

UniValue entity(UniValue::VARR);
entity.push_backV(data);
mints.push_back(entity);
}

ret.push_back(Pair("coins", mints));

return ret;
}

UniValue getsparkmintmetadata(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
Expand Down Expand Up @@ -1921,6 +2056,8 @@ static const CRPCCommand commands[] =

/* Mobile Spark */
{ "mobile", "getsparkanonymityset", &getsparkanonymityset, false },
{ "mobile", "getsparkanonymitysetmeta", &getsparkanonymitysetmeta, false },
{ "mobile", "getsparkanonymitysetsector", &getsparkanonymitysetsector, false },
{ "mobile", "getsparkmintmetadata", &getsparkmintmetadata, true },
{ "mobile", "getusedcoinstags", &getusedcoinstags, false },
{ "mobile", "getusedcoinstagstxhashes", &getusedcoinstagstxhashes, false },
Expand Down
2 changes: 2 additions & 0 deletions src/rpc/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,8 @@ static const CRPCCommand vRPCCommands[] =

/* Mobile Spark */
{ "mobile", "getsparkanonymityset", &getsparkanonymityset, false },
{ "mobile", "getsparkanonymitysetmeta", &getsparkanonymitysetmeta, false },
{ "mobile", "getsparkanonymitysetsector", &getsparkanonymitysetsector, false },
{ "mobile", "getsparkmintmetadata", &getsparkmintmetadata, true },
{ "mobile", "getusedcoinstags", &getusedcoinstags, false },
{ "mobile", "getusedcoinstagstxhashes", &getusedcoinstagstxhashes, false },
Expand Down
2 changes: 2 additions & 0 deletions src/rpc/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@ extern UniValue getfeerate(const JSONRPCRequest& params);
extern UniValue getlatestcoinid(const JSONRPCRequest& params);

extern UniValue getsparkanonymityset(const JSONRPCRequest& params);
extern UniValue getsparkanonymitysetmeta(const JSONRPCRequest& params);
extern UniValue getsparkanonymitysetsector(const JSONRPCRequest& params);
extern UniValue getsparkmintmetadata(const JSONRPCRequest& params);
extern UniValue getusedcoinstags(const JSONRPCRequest& params);
extern UniValue getusedcoinstagstxhashes(const JSONRPCRequest& params);
Expand Down
79 changes: 79 additions & 0 deletions src/spark/state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,85 @@ void CSparkState::GetCoinsForRecovery(
}
}

void CSparkState::GetAnonSetMetaData(
CChain *chain,
int maxHeight,
int coinGroupID,
uint256& blockHash_out,
std::vector<unsigned char>& setHash_out,
int& size) {
if (coinGroups.count(coinGroupID) == 0) {
return;
}
SparkCoinGroupInfo &coinGroup = coinGroups[coinGroupID];
size = 0;
for (CBlockIndex *block = coinGroup.lastBlock;; block = block->pprev) {
// check coins in group coinGroupID - 1 in the case that using coins from prev group.
int id = 0;
if (CountCoinInBlock(block, coinGroupID)) {
id = coinGroupID;
} else if (CountCoinInBlock(block, coinGroupID - 1)) {
id = coinGroupID - 1;
}
if (id) {
if (size == 0) {
// latest block satisfying given conditions
// remember block hash and set hash
blockHash_out = block->GetBlockHash();
setHash_out = GetAnonymitySetHash(block, id);
}
size += block->sparkMintedCoins[id].size();
}
if (block == coinGroup.firstBlock) {
break ;
}
}
}

void CSparkState::GetCoinsForRecovery(
CChain *chain,
int maxHeight,
int coinGroupID,
uint256& blockHash,
std::vector<std::pair<spark::Coin, std::pair<uint256, std::vector<unsigned char>>>>& coins) {
coins.clear();
if (coinGroups.count(coinGroupID) == 0) {
return;
}
SparkCoinGroupInfo &coinGroup = coinGroups[coinGroupID];
CBlockIndex *index = coinGroup.lastBlock;
// find index for block with hash of accumulatorBlockHash or set index to the coinGroup.firstBlock if not found
while (index != coinGroup.firstBlock && index->GetBlockHash() != blockHash)
index = index->pprev;

for (CBlockIndex *block = index;; block = block->pprev) {
// ignore block heigher than max height
if (block->nHeight > maxHeight) {
continue;
}

// check coins in group coinGroupID - 1 in the case that using coins from prev group.
int id = 0;
if (CountCoinInBlock(block, coinGroupID)) {
id = coinGroupID;
} else if (CountCoinInBlock(block, coinGroupID - 1)) {
id = coinGroupID - 1;
}
if (id) {
if (block->sparkMintedCoins.count(id) > 0) {
for (const auto &coin : block->sparkMintedCoins[id]) {
std::pair<uint256, std::vector<unsigned char>> txHashContext;
if (block->sparkTxHashContext.count(coin.S))
txHashContext = block->sparkTxHashContext[coin.S];
coins.push_back({coin, txHashContext});
}
}
}
if (block == coinGroup.firstBlock) {
break ;
}
}
}

std::unordered_map<spark::Coin, CMintedCoinInfo, spark::CoinHash> const & CSparkState::GetMints() const {
return mintedCoins;
Expand Down
15 changes: 15 additions & 0 deletions src/spark/state.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,21 @@ class CSparkState {
std::vector<std::pair<spark::Coin, std::pair<uint256, std::vector<unsigned char>>>>& coins,
std::vector<unsigned char>& setHash_out);

void GetAnonSetMetaData(
CChain *chain,
int maxHeight,
int coinGroupID,
uint256& blockHash_out,
std::vector<unsigned char>& setHash_out,
int& size);

void GetCoinsForRecovery(
CChain *chain,
int maxHeight,
int coinGroupID,
uint256& blockHash,
std::vector<std::pair<spark::Coin, std::pair<uint256, std::vector<unsigned char>>>>& coins);

std::unordered_map<spark::Coin, CMintedCoinInfo, spark::CoinHash> const & GetMints() const;
std::unordered_map<GroupElement, int, spark::CLTagHash> const & GetSpends() const;
std::unordered_map<uint256, uint256> const& GetSpendTxIds() const;
Expand Down

0 comments on commit abc7a95

Please sign in to comment.