From 62ae624835cab25ea9f055aeaa7e6d6084c05494 Mon Sep 17 00:00:00 2001 From: presstab Date: Wed, 15 Nov 2017 10:52:03 -0700 Subject: [PATCH] Double check tx size when creating zPIV tx's. It is possible for a spend of 7 to be larger than the max transaction size. Catch these cases and send a correct error report up the chain to the GUI. Github-Merge: #412 Rebased-From: 0983755 --- src/wallet.cpp | 63 +++++++++++++++++++++++++++++++------------------- src/wallet.h | 3 ++- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/src/wallet.cpp b/src/wallet.cpp index 788719ab4d21e..687e1f68a2ea2 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -4065,14 +4065,14 @@ bool CWallet::CreateZerocoinMintTransaction(const CAmount nValue, CMutableTransa bool CWallet::MintToTxIn(CZerocoinMint zerocoinSelected, int nSecurityLevel, const uint256& hashTxOut, CTxIn& newTxIn, CZerocoinSpendReceipt& receipt) { // Default error status if not changed below - receipt.SetStatus("Transaction Mint Started", ZPIV_TXMINT_GENERAL); + receipt.SetStatus(_("Transaction Mint Started"), ZPIV_TXMINT_GENERAL); libzerocoin::CoinDenomination denomination = zerocoinSelected.GetDenomination(); // 2. Get pubcoin from the private coin libzerocoin::PublicCoin pubCoinSelected(Params().Zerocoin_Params(), zerocoinSelected.GetValue(), denomination); LogPrintf("%s : pubCoinSelected:\n denom=%d\n value%s\n", __func__, denomination, pubCoinSelected.getValue().GetHex()); if (!pubCoinSelected.validate()) { - receipt.SetStatus("the selected mint coin is an invalid coin", ZPIV_INVALID_COIN); + receipt.SetStatus(_("The selected mint coin is an invalid coin"), ZPIV_INVALID_COIN); return false; } @@ -4082,7 +4082,7 @@ bool CWallet::MintToTxIn(CZerocoinMint zerocoinSelected, int nSecurityLevel, con string strFailReason = ""; int nMintsAdded = 0; if (!GenerateAccumulatorWitness(pubCoinSelected, accumulator, witness, nSecurityLevel, nMintsAdded, strFailReason)) { - receipt.SetStatus("Try to spend with a higher security level to include more coins", ZPIV_FAILED_ACCUMULATOR_INITIALIZATION); + receipt.SetStatus(_("Try to spend with a higher security level to include more coins"), ZPIV_FAILED_ACCUMULATOR_INITIALIZATION); LogPrintf("%s : %s \n", __func__, receipt.GetStatusMessage()); return false; } @@ -4098,7 +4098,7 @@ bool CWallet::MintToTxIn(CZerocoinMint zerocoinSelected, int nSecurityLevel, con libzerocoin::CoinSpend spend(Params().Zerocoin_Params(), privateCoin, accumulator, nChecksum, witness, hashTxOut); if (!spend.Verify(accumulator)) { - receipt.SetStatus("the new spend coin transaction did not verify", ZPIV_INVALID_WITNESS); + receipt.SetStatus(_("The new spend coin transaction did not verify"), ZPIV_INVALID_WITNESS); return false; } @@ -4122,13 +4122,13 @@ bool CWallet::MintToTxIn(CZerocoinMint zerocoinSelected, int nSecurityLevel, con serializedCoinSpendChecking << spend; } catch (...) { - receipt.SetStatus("failed to deserialize", ZPIV_BAD_SERIALIZATION); + receipt.SetStatus(_("Failed to deserialize"), ZPIV_BAD_SERIALIZATION); return false; } libzerocoin::CoinSpend newSpendChecking(Params().Zerocoin_Params(), serializedCoinSpendChecking); if (!newSpendChecking.Verify(accumulator)) { - receipt.SetStatus("the transaction did not verify", ZPIV_BAD_SERIALIZATION); + receipt.SetStatus(_("The transaction did not verify"), ZPIV_BAD_SERIALIZATION); return false; } @@ -4141,7 +4141,7 @@ bool CWallet::MintToTxIn(CZerocoinMint zerocoinSelected, int nSecurityLevel, con LogPrintf("%s failed to write zerocoinmint\n", __func__); pwalletMain->NotifyZerocoinChanged(pwalletMain, zerocoinSelected.GetValue().GetHex(), "Used", CT_UPDATED); - receipt.SetStatus("the coin spend has been used", ZPIV_SPENT_USED_ZPIV); + receipt.SetStatus(_("The coin spend has been used"), ZPIV_SPENT_USED_ZPIV); return false; } } @@ -4152,11 +4152,11 @@ bool CWallet::MintToTxIn(CZerocoinMint zerocoinSelected, int nSecurityLevel, con receipt.AddSpend(zcSpend); } catch (const std::exception&) { - receipt.SetStatus("CoinSpend: Accumulator witness does not verify", ZPIV_INVALID_WITNESS); + receipt.SetStatus(_("CoinSpend: Accumulator witness does not verify"), ZPIV_INVALID_WITNESS); return false; } - receipt.SetStatus("Spend Valid", ZPIV_SPEND_OKAY); // Everything okay + receipt.SetStatus(_("Spend Valid"), ZPIV_SPEND_OKAY); // Everything okay return true; } @@ -4166,12 +4166,12 @@ bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, int nSecurityLevel, // Check available funds int nStatus = ZPIV_TRX_FUNDS_PROBLEMS; if (nValue > GetZerocoinBalance(true)) { - receipt.SetStatus("You don't have enough Zerocoins in your wallet", nStatus); + receipt.SetStatus(_("You don't have enough Zerocoins in your wallet"), nStatus); return false; } if (nValue < 1) { - receipt.SetStatus("Value is below the the smallest available denomination (= 1) of zPiv", nStatus); + receipt.SetStatus(_("Value is below the the smallest available denomination (= 1) of zPiv"), nStatus); return false; } @@ -4188,7 +4188,7 @@ bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, int nSecurityLevel, if (vSelectedMints.empty()) { listMints = walletdb.ListMintedCoins(true, true, true); // need to find mints to spend if(listMints.empty()) { - receipt.SetStatus("failed to find Zerocoins in in wallet.dat", nStatus); + receipt.SetStatus(_("Failed to find Zerocoins in in wallet.dat"), nStatus); return false; } @@ -4214,7 +4214,7 @@ bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, int nSecurityLevel, for (CZerocoinMint mint : vSelectedMints) { // see if this serial has already been spent if (IsSerialKnown(mint.GetSerialNumber())) { - receipt.SetStatus("trying to spend an already spent serial #, try again.", nStatus); + receipt.SetStatus(_("Trying to spend an already spent serial #, try again."), nStatus); mint.SetUsed(true); walletdb.WriteZerocoinMint(mint); @@ -4227,10 +4227,10 @@ bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, int nSecurityLevel, uint256 hashBlock; bool fArchive = false; if (!GetTransaction(mint.GetTxHash(), txMint, hashBlock)) { - receipt.SetStatus("unable to find transaction containing mint", nStatus); + receipt.SetStatus(_("Unable to find transaction containing mint"), nStatus); fArchive = true; } else if (mapBlockIndex.count(hashBlock) < 1) { - receipt.SetStatus("mint did not make it into blockchain", nStatus); + receipt.SetStatus(_("Mint did not make it into blockchain"), nStatus); fArchive = true; } @@ -4246,16 +4246,16 @@ bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, int nSecurityLevel, if (vSelectedMints.empty()) { if(nNeededSpends > 0){ // Too much spends needed, so abuse nStatus to report back the number of needed spends - receipt.SetStatus("Too much spends needed", nStatus, nNeededSpends); + receipt.SetStatus(_("Too many spends needed"), nStatus, nNeededSpends); } else { - receipt.SetStatus("failed to select a zerocoin", nStatus); + receipt.SetStatus(_("Failed to select a zerocoin"), nStatus); } return false; } if ((static_cast(vSelectedMints.size()) > Params().Zerocoin_MaxSpendsPerTransaction())) { - receipt.SetStatus("Failed to find coin set amongst held coins with less than maxNumber of Spends", nStatus); + receipt.SetStatus(_("Failed to find coin set amongst held coins with less than maxNumber of Spends"), nStatus); return false; } @@ -4275,9 +4275,11 @@ bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, int nSecurityLevel, CScript scriptChange; CAmount nChange = nValueSelected - nValue; if (nChange && !address) { - receipt.SetStatus("Need address because change is not exact", nStatus); + receipt.SetStatus(_("Need address because change is not exact"), nStatus); return false; - } else if (address) { + } + + if (address) { scriptZerocoinSpend = GetScriptForDestination(address->Get()); if (nChange) { // Reserve a new key pair from key pool @@ -4299,7 +4301,7 @@ bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, int nSecurityLevel, CAmount nFeeRet = 0; string strFailReason = ""; if (!CreateZerocoinMintTransaction(nChange, txNew, vNewMints, &reserveKey, nFeeRet, strFailReason, NULL, true)) { - receipt.SetStatus("Failed to create mint", nStatus); + receipt.SetStatus(_("Failed to create mint"), nStatus); return false; } } else { @@ -4324,13 +4326,20 @@ bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, int nSecurityLevel, txNew.vin.push_back(newTxIn); } + // Limit size + unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION); + if (nBytes >= MAX_ZEROCOIN_TX_SIZE) { + receipt.SetStatus(_("In rare cases, a spend with 7 coins exceeds our maximum allowable transaction size, please retry spend using 6 or less coins"), ZPIV_TX_TOO_LARGE); + return false; + } + //now that all inputs have been added, add full tx hash to zerocoinspend records and write to db uint256 txHash = txNew.GetHash(); for (CZerocoinSpend spend : receipt.GetSpends()) { spend.SetTxHash(txHash); if (!CWalletDB(strWalletFile).WriteZerocoinSpendSerialEntry(spend)) { - receipt.SetStatus("failed to write coin serial number into wallet", nStatus); + receipt.SetStatus(_("Failed to write coin serial number into wallet"), nStatus); } } @@ -4342,7 +4351,7 @@ bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, int nSecurityLevel, } } - receipt.SetStatus("Transaction Created", ZPIV_SPEND_OKAY); // Everything okay + receipt.SetStatus(_("Transaction Created"), ZPIV_SPEND_OKAY); // Everything okay return true; } @@ -4501,7 +4510,7 @@ string CWallet::MintZerocoin(CAmount nValue, CWalletTx& wtxNew, vector= MAX_ZEROCOIN_TX_SIZE) { + return _("Error: The transaction is larger than the maximum allowed transaction size!"); + } + //commit the transaction to the network if (!CommitTransaction(wtxNew, reservekey)) { return _("Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); diff --git a/src/wallet.h b/src/wallet.h index c1e9fba2b2da7..c89fcbd4f5849 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -101,7 +101,8 @@ enum ZerocoinSpendStatus { ZPIV_FAILED_ACCUMULATOR_INITIALIZATION = 11, // Failed to initialize witness ZPIV_INVALID_WITNESS = 12, // Spend coin transaction did not verify ZPIV_BAD_SERIALIZATION = 13, // Transaction verification failed - ZPIV_SPENT_USED_ZPIV = 14 // Coin has already been spend + ZPIV_SPENT_USED_ZPIV = 14, // Coin has already been spend + ZPIV_TX_TOO_LARGE = 15 // The transaction is larger than the max tx size }; struct CompactTallyItem {