Skip to content

Commit

Permalink
[RPC] Refactor spendzerocoin/spendzcoinmints, fix createrawzerocoinstake
Browse files Browse the repository at this point in the history
- reorg parameters check and mints fetch
- add isPublicSpend argument to spendzerocoinmints for regtest
- us v2 spends in createrawzerocoinstake and lock it for regtest
- uniform naming for public spend flag to isPublicSpend
Github-Pull: #1218
Rebased-From: 904ecec
  • Loading branch information
random-zebra authored and Fuzzbawls committed Jan 11, 2020
1 parent 9134f40 commit e8b7ce3
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 64 deletions.
9 changes: 6 additions & 3 deletions src/rpc/rawtransaction.cpp
Expand Up @@ -922,7 +922,7 @@ UniValue createrawzerocoinstake(const UniValue& params, bool fHelp)
if (fHelp || params.size() != 1)
throw std::runtime_error(
"createrawzerocoinstake mint_input \n"
"\nCreates raw zPIV coinstakes (without MN output).\n" +
"\nCreates raw zPIV coinstakes (without MN output). Only for regtest\n" +
HelpRequiringPassphrase() + "\n"

"\nArguments:\n"
Expand All @@ -939,6 +939,9 @@ UniValue createrawzerocoinstake(const UniValue& params, bool fHelp)
HelpExampleRpc("createrawzerocoinstake", "0d8c16eee7737e3cc1e4e70dc006634182b175e039700931283b202715a0818f"));


if (Params().NetworkID() != CBaseChainParams::REGTEST)
throw JSONRPCError(RPC_WALLET_ERROR, "createrawzerocoinstake is available only on regtest net");

assert(pwalletMain != NULL);
LOCK2(cs_main, pwalletMain->cs_wallet);

Expand Down Expand Up @@ -983,8 +986,8 @@ UniValue createrawzerocoinstake(const UniValue& params, bool fHelp)

// create the zerocoinspend input
CTxIn newTxIn;
// !TODO: mint checks
if (!pwalletMain->MintToTxIn(input_mint, hashTxOut, newTxIn, receipt, libzerocoin::SpendType::STAKE))
// Use v2 spends for input (with v3 zpiv staking is disabled)
if (!pwalletMain->MintToTxIn(input_mint, hashTxOut, newTxIn, receipt, libzerocoin::SpendType::STAKE, nullptr, false))
throw JSONRPCError(RPC_WALLET_ERROR, "failed to create zc-spend stake input");

coinstake_tx.vin.push_back(newTxIn);
Expand Down
111 changes: 53 additions & 58 deletions src/wallet/rpcwallet.cpp
Expand Up @@ -3182,7 +3182,8 @@ UniValue listmintedzerocoins(const UniValue& params, bool fHelp)

"\nArguments:\n"
"1. fVerbose (boolean, optional, default=false) Output mints metadata.\n"
"2. fMatureOnly (boolean, optional, default=false) List only mature mints. (Set only if fVerbose is specified)\n"
"2. fMatureOnly (boolean, optional, default=false) List only mature mints.\n"
" Set only if fVerbose is specified\n"

"\nResult (with fVerbose=false):\n"
"[\n"
Expand Down Expand Up @@ -3234,7 +3235,6 @@ UniValue listmintedzerocoins(const UniValue& params, bool fHelp)
objMint.push_back(Pair("mint height", m.nHeight)); // Mint Height
int nConfirmations = (m.nHeight && nBestHeight > m.nHeight) ? nBestHeight - m.nHeight : 0;
objMint.push_back(Pair("confirmations", nConfirmations)); // Confirmations
// hashStake
if (m.hashStake == 0) {
CZerocoinMint mint;
if (pwalletMain->GetMint(m.hashSerial, mint)) {
Expand All @@ -3244,7 +3244,7 @@ UniValue listmintedzerocoins(const UniValue& params, bool fHelp)
pwalletMain->zpivTracker->UpdateState(m);
}
}
objMint.push_back(Pair("hash stake", m.hashStake.GetHex())); // Confirmations
objMint.push_back(Pair("hash stake", m.hashStake.GetHex())); // hashStake
// Push back mint object
jsonList.push_back(objMint);
}
Expand Down Expand Up @@ -3452,7 +3452,7 @@ UniValue spendzerocoin(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 5 || params.size() < 3)
throw std::runtime_error(
"spendzerocoin amount mintchange minimizechange ( \"address\" ispublicspend)\n"
"spendzerocoin amount mintchange minimizechange ( \"address\" isPublicSpend)\n"
"\nSpend zPIV to a PIV address.\n" +
HelpRequiringPassphrase() + "\n"

Expand All @@ -3462,7 +3462,8 @@ UniValue spendzerocoin(const UniValue& params, bool fHelp)
"3. minimizechange (boolean, required) Try to minimize the returning change [false]\n"
"4. \"address\" (string, optional, default=change) Send to specified address or to a new change address.\n"
" If there is change then an address is required\n"
"5. ispublicspend (boolean, optional, default=true) create a public zc spend instead of use the old code (only for regression tests)"
"5. isPublicSpend (boolean, optional, default=true) create a public zc spend."
" If false, instead create spend version 2 (only for regression tests)"

"\nResult:\n"
"{\n"
Expand Down Expand Up @@ -3496,37 +3497,38 @@ UniValue spendzerocoin(const UniValue& params, bool fHelp)
if(sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE))
throw JSONRPCError(RPC_WALLET_ERROR, "zPIV is currently disabled due to maintenance.");

EnsureWalletIsUnlocked();

CAmount nAmount = AmountFromValue(params[0]); // Spending amount
bool fMintChange = params[1].get_bool(); // Mint change to zPIV
if (fMintChange && Params().NetworkID() != CBaseChainParams::REGTEST)
throw JSONRPCError(RPC_WALLET_ERROR, "zPIV minting is DISABLED, cannot mint change");
bool fMinimizeChange = params[2].get_bool(); // Minimize change
std::string address_str = params.size() > 3 ? params[3].get_str() : "";
bool ispublicspend = params.size() > 4 ? params[4].get_bool() : true;
CAmount nAmount = AmountFromValue(params[0]); // Spending amount
const bool fMintChange = params[1].get_bool(); // Mint change to zPIV
const bool fMinimizeChange = params[2].get_bool(); // Minimize change
const std::string address_str = (params.size() > 3 ? params[3].get_str() : "");
const bool isPublicSpend = (params.size() > 4 ? params[4].get_bool() : true);

std::vector<CZerocoinMint> vMintsSelected;
if (Params().NetworkID() != CBaseChainParams::REGTEST) {
if (fMintChange)
throw JSONRPCError(RPC_WALLET_ERROR, "zPIV minting is DISABLED (except for regtest), cannot mint change");

if (!ispublicspend && Params().NetworkID() != CBaseChainParams::REGTEST) {
throw JSONRPCError(RPC_WALLET_ERROR, "zPIV old spend only available in regtest for tests purposes");
if (!isPublicSpend)
throw JSONRPCError(RPC_WALLET_ERROR, "zPIV old spend only available in regtest for tests purposes");
}

return DoZpivSpend(nAmount, fMintChange, fMinimizeChange, vMintsSelected, address_str, ispublicspend);
std::vector<CZerocoinMint> vMintsSelected;
return DoZpivSpend(nAmount, fMintChange, fMinimizeChange, vMintsSelected, address_str, isPublicSpend);
}


UniValue spendzerocoinmints(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
if (fHelp || params.size() < 1 || params.size() > 3)
throw std::runtime_error(
"spendzerocoinmints mints_list (\"address\") \n"
"spendzerocoinmints mints_list (\"address\" isPublicSpend) \n"
"\nSpend zPIV mints to a PIV address.\n" +
HelpRequiringPassphrase() + "\n"

"\nArguments:\n"
"1. mints_list (string, required) A json array of zerocoin mints serial hashes\n"
"2. \"address\" (string, optional, default=change) Send to specified address or to a new change address.\n"
"3. isPublicSpend (boolean, optional, default=true) create a public zc spend."
" If false, instead create spend version 2 (only for regression tests)"

"\nResult:\n"
"{\n"
Expand Down Expand Up @@ -3560,61 +3562,53 @@ UniValue spendzerocoinmints(const UniValue& params, bool fHelp)
if(sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE))
throw JSONRPCError(RPC_WALLET_ERROR, "zPIV is currently disabled due to maintenance.");

std::string address_str = "";
if (params.size() > 1) {
RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VSTR));
address_str = params[1].get_str();
} else
RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR));

EnsureWalletIsUnlocked();

UniValue arrMints = params[0].get_array();
const std::string address_str = (params.size() > 1 ? params[1].get_str() : "");
const bool isPublicSpend = (params.size() > 2 ? params[2].get_bool() : true);

if (arrMints.size() == 0)
throw JSONRPCError(RPC_WALLET_ERROR, "No zerocoin selected");
if (arrMints.size() > 7)
throw JSONRPCError(RPC_WALLET_ERROR, "Too many mints included. Maximum zerocoins per spend: 7");

CAmount nAmount(0); // Spending amount
if (!isPublicSpend && Params().NetworkID() != CBaseChainParams::REGTEST) {
throw JSONRPCError(RPC_WALLET_ERROR, "zPIV old spend only available in regtest for tests purposes");
}

// check mints supplied and save serial hash (do this here so we don't fetch if any is wrong)
std::vector<uint256> vSerialHashes;
for(unsigned int i = 0; i < arrMints.size(); i++) {
std::string serialHashStr = arrMints[i].get_str();
if (!IsHex(serialHashStr))
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex serial hash");
vSerialHashes.push_back(uint256(serialHashStr));
}

// fetch mints and update nAmount
CAmount nAmount(0);
std::vector<CZerocoinMint> vMintsSelected;
for(unsigned int i=0; i < arrMints.size(); i++) {

for(const uint256& serialHash : vSerialHashes) {
CZerocoinMint mint;
std::string serialHash = arrMints[i].get_str();

if (!IsHex(serialHash))
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex serial hash");

uint256 hashSerial(serialHash);
if (!pwalletMain->GetMint(hashSerial, mint)) {
std::string strErr = "Failed to fetch mint associated with serial hash " + serialHash;
if (!pwalletMain->GetMint(serialHash, mint)) {
std::string strErr = "Failed to fetch mint associated with serial hash " + serialHash.GetHex();
throw JSONRPCError(RPC_WALLET_ERROR, strErr);
}

vMintsSelected.emplace_back(mint);
nAmount += mint.GetDenominationAsAmount();
}

CBitcoinAddress address = CBitcoinAddress(); // Optional sending address. Dummy initialization here.
if (params.size() == 4) {
// Destination address was supplied as params[4]. Optional parameters MUST be at the end
// to avoid type confusion from the JSON interpreter
address = CBitcoinAddress(params[3].get_str());
if(!address.IsValid() || address.IsStakingAddress())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid PIVX address");
}

return DoZpivSpend(nAmount, false, true, vMintsSelected, address_str);
return DoZpivSpend(nAmount, false, true, vMintsSelected, address_str, isPublicSpend);
}


extern UniValue DoZpivSpend(const CAmount nAmount, bool fMintChange, bool fMinimizeChange, std::vector<CZerocoinMint>& vMintsSelected, std::string address_str, bool ispublicspend)
extern UniValue DoZpivSpend(const CAmount nAmount, bool fMintChange, bool fMinimizeChange, std::vector<CZerocoinMint>& vMintsSelected, std::string address_str, bool isPublicSpend)
{
// zerocoin MINT is disabled. fMintChange should be false here. Double check
if (fMintChange && Params().NetworkID() != CBaseChainParams::REGTEST)
throw JSONRPCError(RPC_WALLET_ERROR, "zPIV minting is DISABLED, cannot mint change");
// zerocoin mint / v2 spend is disabled. fMintChange/isPublicSpend should be false here. Double check
if (Params().NetworkID() != CBaseChainParams::REGTEST) {
if (fMintChange)
throw JSONRPCError(RPC_WALLET_ERROR, "zPIV minting is DISABLED (except for regtest), cannot mint change");

if (!isPublicSpend)
throw JSONRPCError(RPC_WALLET_ERROR, "zPIV old spend only available in regtest for tests purposes");
}

int64_t nTimeStart = GetTimeMillis();
CBitcoinAddress address = CBitcoinAddress(); // Optional sending address. Dummy initialization here.
Expand All @@ -3630,7 +3624,8 @@ extern UniValue DoZpivSpend(const CAmount nAmount, bool fMintChange, bool fMinim
outputs.push_back(std::pair<CBitcoinAddress*, CAmount>(&address, nAmount));
}

fSuccess = pwalletMain->SpendZerocoin(nAmount, wtx, receipt, vMintsSelected, fMintChange, fMinimizeChange, outputs, nullptr, ispublicspend);
EnsureWalletIsUnlocked();
fSuccess = pwalletMain->SpendZerocoin(nAmount, wtx, receipt, vMintsSelected, fMintChange, fMinimizeChange, outputs, nullptr, isPublicSpend);

if (!fSuccess)
throw JSONRPCError(RPC_WALLET_ERROR, receipt.GetStatusMessage());
Expand Down
4 changes: 2 additions & 2 deletions src/wallet/wallet.cpp
Expand Up @@ -4285,12 +4285,12 @@ bool CWallet::MintToTxIn(
CZerocoinSpendReceipt& receipt,
libzerocoin::SpendType spendType,
CBlockIndex* pindexCheckpoint,
bool publicCoinSpend)
bool isPublicSpend)
{
std::map<CBigNum, CZerocoinMint> mapMints;
mapMints.insert(std::make_pair(mint.GetValue(), mint));
std::vector<CTxIn> vin;
if (publicCoinSpend) {
if (isPublicSpend) {
if (MintsToInputVectorPublicSpend(mapMints, hashTxOut, vin, receipt, spendType, pindexCheckpoint)) {
newTxIn = vin[0];
return true;
Expand Down
2 changes: 1 addition & 1 deletion src/wallet/wallet.h
Expand Up @@ -209,7 +209,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
bool isPublicSpend = true);

bool CheckCoinSpend(libzerocoin::CoinSpend& spend, libzerocoin::Accumulator& accumulator, CZerocoinSpendReceipt& receipt);
bool MintToTxIn(CZerocoinMint zerocoinSelected, const uint256& hashTxOut, CTxIn& newTxIn, CZerocoinSpendReceipt& receipt, libzerocoin::SpendType spendType, CBlockIndex* pindexCheckpoint = nullptr, bool publicCoinSpend = true);
bool MintToTxIn(CZerocoinMint zerocoinSelected, const uint256& hashTxOut, CTxIn& newTxIn, CZerocoinSpendReceipt& receipt, libzerocoin::SpendType spendType, CBlockIndex* pindexCheckpoint = nullptr, bool isPublicSpend = true);
bool MintsToInputVector(std::map<CBigNum, CZerocoinMint>& mapMintsSelected, const uint256& hashTxOut, std::vector<CTxIn>& vin,
CZerocoinSpendReceipt& receipt, libzerocoin::SpendType spendType, CBlockIndex* pindexCheckpoint = nullptr);
// Public coin spend input creation
Expand Down

0 comments on commit e8b7ce3

Please sign in to comment.