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 all 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
146 changes: 146 additions & 0 deletions src/rpc/misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,150 @@ 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,
startIndex,
endIndex,
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);


for (const auto& coin : coins) {
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 +2065,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
93 changes: 93 additions & 0 deletions src/spark/state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,99 @@ 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,
int startIndex,
int endIndex,
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()));

std::size_t counter = 0;
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]) {
if (counter < startIndex) {
++counter;
continue;
}
if (counter >= endIndex) {
break;
}
std::pair<uint256, std::vector<unsigned char>> txHashContext;
if (block->sparkTxHashContext.count(coin.S))
txHashContext = block->sparkTxHashContext[coin.S];
coins.push_back({coin, txHashContext});
++counter;
}
}
}
if (block == coinGroup.firstBlock || counter >= endIndex) {
break ;
}
}
}

std::unordered_map<spark::Coin, CMintedCoinInfo, spark::CoinHash> const & CSparkState::GetMints() const {
return mintedCoins;
Expand Down
17 changes: 17 additions & 0 deletions src/spark/state.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,23 @@ 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,
int startIndex,
int endIndex,
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
Loading