diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index ef5f9e67c4..30a11d5362 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -2663,11 +2663,12 @@ Value sendanontosdc(const Array& params, bool fHelp) Value estimateanonfee(const Array& params, bool fHelp) { - if (fHelp || params.size() < 2 || params.size() > 3) + if (fHelp || params.size() < 2 || params.size() > 4) throw std::runtime_error( - "estimateanonfee [narration]\n" + "estimateanonfee [included] [narration]\n" "is a real number and is rounded to the nearest 0.000001\n" - " is a number of outputs of the same amount to include in the signature"); + " is a number of outputs of the same amount to include in the signature\n" + "[included] if set to 1 then also includes the fee"); int64_t nAmount = AmountFromValue(params[0]); @@ -2677,19 +2678,41 @@ Value estimateanonfee(const Array& params, bool fHelp) if (nRingSize < MIN_RING_SIZE || nRingSize > MAX_RING_SIZE) ssThrow << "Ring size must be >= " << MIN_RING_SIZE << " and <= " << MAX_RING_SIZE << ".", throw std::runtime_error(ssThrow.str()); - + LogPrintf("EstimateAnonFee before narration\n"); std::string sNarr; - if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty()) - sNarr = params[2].get_str(); + if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty()) + sNarr = params[3].get_str(); + + LogPrintf("EstimateAnonFee after narration\n"); if (sNarr.length() > 24) throw std::runtime_error("Narration must be 24 characters or less."); + bool included = false; + if(params.size() > 2){ + std::string value = params[2].get_str(); + if (IsStringBoolPositive(value)){ + included = true; + } + } + + Object result; CWalletTx wtx; int64_t nFee = 0; std::string sError; - if (!pwalletMain->EstimateAnonFee(nAmount, nRingSize, sNarr, wtx, nFee, sError)) + int64_t nMaxAmount = pwalletMain->GetShadowBalance(); + + if(included){ + uint64_t nFeeRequired = pwalletMain->EstimateAnonFeeIncluded(nAmount, nRingSize, sNarr, wtx, sError); + result.push_back(Pair("Amount", ValueFromAmount(nAmount - nFeeRequired))); + result.push_back(Pair("Estimated fee", ValueFromAmount(nFeeRequired))); + if(nFeeRequired == 0){ + LogPrintf("EstimateAnonFeeIncluded failed %s\n", sError.c_str()); + throw JSONRPCError(RPC_WALLET_ERROR, sError); + } + } + else if(!pwalletMain->EstimateAnonFee(nAmount, nMaxAmount, nRingSize, sNarr, wtx, nFee, sError)) { LogPrintf("EstimateAnonFee failed %s\n", sError.c_str()); throw JSONRPCError(RPC_WALLET_ERROR, sError); @@ -2697,12 +2720,14 @@ Value estimateanonfee(const Array& params, bool fHelp) uint32_t nBytes = ::GetSerializeSize(*(CTransaction*)&wtx, SER_NETWORK, PROTOCOL_VERSION); - Object result; + result.push_back(Pair("Estimated bytes", (int)nBytes)); result.push_back(Pair("Estimated inputs", (int)wtx.vin.size())); result.push_back(Pair("Estimated outputs", (int)wtx.vout.size())); - result.push_back(Pair("Estimated fee", ValueFromAmount(nFee))); + + if(!included) + result.push_back(Pair("Estimated fee", ValueFromAmount(nFee))); return result; } diff --git a/src/wallet.cpp b/src/wallet.cpp index f70f5085ca..bfed8ef38c 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -3799,6 +3799,7 @@ bool CWallet::CreateAnonOutputs(CStealthAddress* sxAddress, int64_t nValue, std: scriptSendTo << cpkTo; scriptSendTo << pkEphem; + //segmentation fault occurs here when calling estimateanonfee if (i == 0 && sNarr.length() > 0) { std::vector vchNarr; @@ -5148,7 +5149,7 @@ bool CWallet::ProcessLockedAnonOutputs() return true; }; -bool CWallet::EstimateAnonFee(int64_t nValue, int nRingSize, std::string& sNarr, CWalletTx& wtxNew, int64_t& nFeeRet, std::string& sError) +bool CWallet::EstimateAnonFee(int64_t nValue, int64_t nMaxAmount, int nRingSize, std::string& sNarr, CWalletTx& wtxNew, int64_t& nFeeRet, std::string& sError) { if (fDebugRingSig) LogPrintf("EstimateAnonFee()\n"); @@ -5168,7 +5169,13 @@ bool CWallet::EstimateAnonFee(int64_t nValue, int nRingSize, std::string& sNarr, return false; }; - if (nValue + nTransactionFee > GetShadowBalance()) + if (nMaxAmount <= 0) + { + sError = "Invalid max amount"; + return false; + }; + + if (nValue + nTransactionFee > nMaxAmount) { sError = "Insufficient shadow funds"; return false; @@ -5197,6 +5204,69 @@ bool CWallet::EstimateAnonFee(int64_t nValue, int nRingSize, std::string& sNarr, return true; }; +int64_t CWallet::EstimateAnonFeeIncluded(int64_t nMaxAmount, int nRingSize, std::string& sNarr, CWalletTx& wtx, std::string& sError) +{ + + if (fDebugRingSig) + LogPrintf("EstimateAnonFeeIncluded()\n"); + + if (nNodeMode != NT_FULL) + { + sError = _("Error: Must be in full mode."); + + if(fDebugRingSig) + LogPrintf("EstimateAnonFeeIncluded: must be full node"); + + return 0; + }; + + if (nMaxAmount <= 0) + { + sError = "Invalid amount"; + + if(fDebugRingSig) + LogPrintf("EstimateAnonFeeIncluded: Invalid amount"); + + return 0; + }; + + if (nMaxAmount > GetShadowBalance()) + { + sError = "Insufficient funds"; + + if(fDebugRingSig) + LogPrintf("EstimateAnonFeeIncluded: Insufficient balance"); + + return 0; + }; + + + int64_t nFeeRet = 0; + int64_t nValue = nMaxAmount - nTransactionFee; + int nFailSafe = 5000; + + while(!EstimateAnonFee(nValue, nMaxAmount, nRingSize, sNarr, wtx, nFeeRet, sError) && nFailSafe > 0){ + nValue = nValue - (MIN_TX_FEE_ANON); + nFailSafe--; + + } + + //at least 50 SDT as fee, something obviously went wrong + if(nFailSafe == 0){ + LogPrintf("EstimateAnonFeeIncluded: nFaileSafe = 0"); + return 0; + } + + if (fDebugRingSig){ + LogPrintf("EstimateAnonFeeIncluded: Found value = %d\n", nValue); + LogPrintf("EstimateAnonFeeIncluded: Fee = %d\n", nFeeRet); + LogPrintf("EstimateAnonFeeIncluded: Dust = %d\n", (GetShadowBalance() - nValue - nFeeRet)); + } + + + return nFeeRet; +}; + int CWallet::ListUnspentAnonOutputs(std::list& lUAnonOutputs, bool fMatureOnly) { CWalletDB walletdb(strWalletFile, "r"); diff --git a/src/wallet.h b/src/wallet.h index 1f38786929..23a5e46556 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -279,7 +279,8 @@ class CWallet : public CCryptoKeyStore bool ExpandLockedAnonOutput(CWalletDB *pdb, CKeyID &ckeyId, CLockedAnonOutput &lao, std::set &setUpdated); bool ProcessLockedAnonOutputs(); - bool EstimateAnonFee(int64_t nValue, int nRingSize, std::string& sNarr, CWalletTx& wtxNew, int64_t& nFeeRet, std::string& sError); + bool EstimateAnonFee(int64_t nValue, int64_t nMaxAmount, int nRingSize, std::string& sNarr, CWalletTx& wtxNew, int64_t& nFeeRet, std::string& sError); + int64_t EstimateAnonFeeIncluded(int64_t nMaxAmount, int nRingSize, std::string& sNarr, CWalletTx& wtx, std::string& sError); int ListUnspentAnonOutputs(std::list& lUAnonOutputs, bool fMatureOnly); int CountAnonOutputs(std::map& mOutputCounts, bool fMatureOnly);