Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement new rpc calls to get anonymity sets #1507

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 153 additions & 0 deletions src/rpc/misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,157 @@ 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) it should be encoded in base64 format\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\" " "\"Gy3sLu3zrVdJwaK6ZzM/1zdJy7hji9xT6l4FSrWgFUM=\" " "\"0\" " "\"1000\" ")
+ HelpExampleRpc("getsparkanonymitysetsector", "\"1\" " "\"Gy3sLu3zrVdJwaK6ZzM/1zdJy7hji9xT6l4FSrWgFUM=\" " "\"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;

std::string strHash = DecodeBase64(latestBlock);
std::vector<unsigned char> vec(strHash.begin(), strHash.end());
if (vec.size() != 32)
throw std::runtime_error(std::string("Provided blockHash data is not correct."));

uint256 blockHash(vec);
{
LOCK(cs_main);
spark::CSparkState* sparkState = spark::CSparkState::GetState();
try {
sparkState->GetCoinsForRecovery(
&chainActive,
chainActive.Height() - (ZC_MINT_CONFIRMATIONS - 1),
coinGroupId,
blockHash,
coins);
} catch (std::exception & e) {
throw std::runtime_error(std::string("Unable to get anonymity set by provided parameters: ") + e.what());
}
}

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

std::size_t counter = 0;
for (const auto& coin : coins) {
if (counter < startIndex) {
++counter;
continue;
}
if (counter >= endIndex) {
break;
}
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);

++counter;
}

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 +2072,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
83 changes: 83 additions & 0 deletions src/spark/state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,89 @@ 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) {
throw std::runtime_error(std::string("There is no anonymity set with this id: " + coinGroupID));
}
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;

if (index == coinGroup.firstBlock && coinGroup.firstBlock != coinGroup.lastBlock)
throw std::runtime_error(std::string("Incorrect blockHash provided: " + blockHash.GetHex()));


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);

levonpetrosyan93 marked this conversation as resolved.
Show resolved Hide resolved
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
Loading