From c0c5f33ea8ff4257ad517b552c1c095b4b65bffe Mon Sep 17 00:00:00 2001 From: Kewde Date: Tue, 15 Nov 2016 05:18:25 +0100 Subject: [PATCH 1/7] Modified EstimateAnonFee Created EstimateAnonFeeIncluded EstimateAnonFeeIncluded calculates how much you can spend such that nValue + nFees < nMaxAmount. Searches for nValue (while loop) until value found that equation makes sense. while loop reduces nMaxAmount with nTransactionFee (lowest steps I could imagine) until an acceptable value is found. TODO: spend dust as fee so wallet shows a zero balance. --- src/rpcwallet.cpp | 4 +++- src/wallet.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++++-- src/wallet.h | 3 ++- 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index ef5f9e67c4..d039fba9b8 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -2689,7 +2689,9 @@ Value estimateanonfee(const Array& params, bool fHelp) CWalletTx wtx; int64_t nFee = 0; std::string sError; - if (!pwalletMain->EstimateAnonFee(nAmount, nRingSize, sNarr, wtx, nFee, sError)) + int64_t nMaxAmount = pwalletMain->GetShadowBalance(); + + if (!pwalletMain->EstimateAnonFee(nAmount, nMaxAmount, nRingSize, sNarr, wtx, nFee, sError)) { LogPrintf("EstimateAnonFee failed %s\n", sError.c_str()); throw JSONRPCError(RPC_WALLET_ERROR, sError); diff --git a/src/wallet.cpp b/src/wallet.cpp index f70f5085ca..eaee02260c 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -5148,7 +5148,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 +5168,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 +5203,43 @@ bool CWallet::EstimateAnonFee(int64_t nValue, int nRingSize, std::string& sNarr, return true; }; +int64_t EstimateAnonFeeIncluded(int64_t nMaxAmount, int nRingSize, std::string& sNarr) +{ + if (fDebugRingSig) + LogPrintf("EstimateAnonFeeIncluded()\n"); + + if (nNodeMode != NT_FULL) + { + sError = _("Error: Must be in full mode."); + return 0; + }; + + if (nMaxAmount <= 0) + { + sError = "Invalid amount"; + return 0; + }; + + if (nMaxAmount > GetShadowBalance()) + { + sError = "Insufficient funds"; + return 0; + }; + + CWalletTx wtx; + std::string sError; + int64_t nFeeRet = 0; + int64_t nValue = nMaxAmount - nTransactionFee; + + while(!EstimateAnonFee(nValue, MaxAmount, nRingSize,sNarr, wtx, nFeeRet, sError) && nValue > 0){ + nValue = nValue - nTransactionFee; + + } + + + 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..9739b04d6b 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); int ListUnspentAnonOutputs(std::list& lUAnonOutputs, bool fMatureOnly); int CountAnonOutputs(std::map& mOutputCounts, bool fMatureOnly); From 44f72fb452bb62293e2952a2d4cc5c943439ed86 Mon Sep 17 00:00:00 2001 From: Kewde Date: Tue, 15 Nov 2016 05:46:53 +0100 Subject: [PATCH 2/7] Fix small typos --- src/wallet.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/wallet.cpp b/src/wallet.cpp index eaee02260c..5dcfaa8556 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -5203,8 +5203,9 @@ bool CWallet::EstimateAnonFee(int64_t nValue, int64_t nMaxAmount, int nRingSize, return true; }; -int64_t EstimateAnonFeeIncluded(int64_t nMaxAmount, int nRingSize, std::string& sNarr) +int64_t CWallet::EstimateAnonFeeIncluded(int64_t nMaxAmount, int nRingSize, std::string& sNarr) { + std::string sError; if (fDebugRingSig) LogPrintf("EstimateAnonFeeIncluded()\n"); @@ -5227,15 +5228,17 @@ int64_t EstimateAnonFeeIncluded(int64_t nMaxAmount, int nRingSize, std::string& }; CWalletTx wtx; - std::string sError; + int64_t nFeeRet = 0; int64_t nValue = nMaxAmount - nTransactionFee; - while(!EstimateAnonFee(nValue, MaxAmount, nRingSize,sNarr, wtx, nFeeRet, sError) && nValue > 0){ + while(!EstimateAnonFee(nValue, nMaxAmount, nRingSize,sNarr, wtx, nFeeRet, sError) && nValue > 0){ nValue = nValue - nTransactionFee; } +/* if (fDebugRingSig) + LogPrintf("EstimateAnonFeeIncluded(): nFeeRet = %" PRId64 "\n", nFeeRet);*/ return nFeeRet; }; From 03d112c68722d63fdb56f6b404fe0a02a343ba66 Mon Sep 17 00:00:00 2001 From: Kewde Date: Tue, 15 Nov 2016 23:19:38 +0100 Subject: [PATCH 3/7] Add JSON RPC command options (ability for testing options) --- src/rpcwallet.cpp | 31 ++++++++++++++++++++++++------- src/wallet.cpp | 12 ++++++++---- src/wallet.h | 2 +- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index d039fba9b8..9b3fdfb37e 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]); @@ -2679,19 +2680,35 @@ Value estimateanonfee(const Array& params, bool fHelp) 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(); 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; int64_t nMaxAmount = pwalletMain->GetShadowBalance(); - if (!pwalletMain->EstimateAnonFee(nAmount, nMaxAmount, nRingSize, sNarr, wtx, nFee, sError)) + if(included){ + uint64_t nFeeRequired = pwalletMain->EstimateAnonFeeIncluded(nAmount, nRingSize, sNarr, sError); + result.push_back(Pair("Required 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); @@ -2699,7 +2716,7 @@ 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())); diff --git a/src/wallet.cpp b/src/wallet.cpp index 5dcfaa8556..5b5f1de878 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -5203,9 +5203,9 @@ bool CWallet::EstimateAnonFee(int64_t nValue, int64_t nMaxAmount, int nRingSize, return true; }; -int64_t CWallet::EstimateAnonFeeIncluded(int64_t nMaxAmount, int nRingSize, std::string& sNarr) +int64_t CWallet::EstimateAnonFeeIncluded(int64_t nMaxAmount, int nRingSize, std::string& sNarr, std::string& sError) { - std::string sError; + if (fDebugRingSig) LogPrintf("EstimateAnonFeeIncluded()\n"); @@ -5231,12 +5231,16 @@ int64_t CWallet::EstimateAnonFeeIncluded(int64_t nMaxAmount, int nRingSize, std: int64_t nFeeRet = 0; int64_t nValue = nMaxAmount - nTransactionFee; + int nFailSafe = 10000; - while(!EstimateAnonFee(nValue, nMaxAmount, nRingSize,sNarr, wtx, nFeeRet, sError) && nValue > 0){ - nValue = nValue - nTransactionFee; + while(!EstimateAnonFee(nValue, nMaxAmount, nRingSize,sNarr, wtx, nFeeRet, sError) && nFailSafe > 0){ + nValue = nValue - 10000; + LogPrintf("EstimateAnonFeeIncluded(): nValue = %" PRId64 "\n", nValue); + nFailSafe--; } + LogPrintf("EstimateAnonFeeIncluded(): Dust = %" PRId64 "\n", GetShadowBalance() - nValue - nFeeRet); /* if (fDebugRingSig) LogPrintf("EstimateAnonFeeIncluded(): nFeeRet = %" PRId64 "\n", nFeeRet);*/ diff --git a/src/wallet.h b/src/wallet.h index 9739b04d6b..aee0a1add9 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -280,7 +280,7 @@ class CWallet : public CCryptoKeyStore bool ProcessLockedAnonOutputs(); 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); + int64_t EstimateAnonFeeIncluded(int64_t nMaxAmount, int nRingSize, std::string& sNarr, std::string& sError); int ListUnspentAnonOutputs(std::list& lUAnonOutputs, bool fMatureOnly); int CountAnonOutputs(std::map& mOutputCounts, bool fMatureOnly); From 238707254742867051b423e4376ec0e4e524aaf2 Mon Sep 17 00:00:00 2001 From: Kewde Date: Wed, 16 Nov 2016 01:24:34 +0100 Subject: [PATCH 4/7] Changed step size to MIN_TX_FEE_ANON Added and cleaned up debugging Improved JSON RPC estimateanonfee output Found segmentation fault on narration --- src/rpcwallet.cpp | 7 +++++-- src/wallet.cpp | 38 +++++++++++++++++++++++++++++--------- src/wallet.h | 2 +- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 9b3fdfb37e..bc3b6bb56a 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -2678,11 +2678,13 @@ 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() > 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."); @@ -2701,7 +2703,8 @@ Value estimateanonfee(const Array& params, bool fHelp) int64_t nMaxAmount = pwalletMain->GetShadowBalance(); if(included){ - uint64_t nFeeRequired = pwalletMain->EstimateAnonFeeIncluded(nAmount, nRingSize, sNarr, sError); + uint64_t nFeeRequired = pwalletMain->EstimateAnonFeeIncluded(nAmount, nRingSize, sNarr, wtx, sError); + result.push_back(Pair("Amount", ValueFromAmount(nAmount - nFeeRequired))); result.push_back(Pair("Required fee", ValueFromAmount(nFeeRequired))); if(nFeeRequired == 0){ LogPrintf("EstimateAnonFeeIncluded failed %s\n", sError.c_str()); diff --git a/src/wallet.cpp b/src/wallet.cpp index 5b5f1de878..155a2a74f0 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; @@ -5203,7 +5204,7 @@ bool CWallet::EstimateAnonFee(int64_t nValue, int64_t nMaxAmount, int nRingSize, return true; }; -int64_t CWallet::EstimateAnonFeeIncluded(int64_t nMaxAmount, int nRingSize, std::string& sNarr, std::string& sError) +int64_t CWallet::EstimateAnonFeeIncluded(int64_t nMaxAmount, int nRingSize, std::string& sNarr, CWalletTx& wtx, std::string& sError) { if (fDebugRingSig) @@ -5212,37 +5213,56 @@ int64_t CWallet::EstimateAnonFeeIncluded(int64_t nMaxAmount, int nRingSize, std: 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; }; - CWalletTx wtx; int64_t nFeeRet = 0; int64_t nValue = nMaxAmount - nTransactionFee; - int nFailSafe = 10000; + int nFailSafe = 5000; - while(!EstimateAnonFee(nValue, nMaxAmount, nRingSize,sNarr, wtx, nFeeRet, sError) && nFailSafe > 0){ - nValue = nValue - 10000; - LogPrintf("EstimateAnonFeeIncluded(): nValue = %" PRId64 "\n", nValue); + while(!EstimateAnonFee(nValue, nMaxAmount, nRingSize, sNarr, wtx, nFeeRet, sError) && nFailSafe > 0){ + nValue = nValue - (MIN_TX_FEE_ANON); nFailSafe--; } - LogPrintf("EstimateAnonFeeIncluded(): Dust = %" PRId64 "\n", GetShadowBalance() - nValue - nFeeRet); -/* if (fDebugRingSig) - LogPrintf("EstimateAnonFeeIncluded(): nFeeRet = %" PRId64 "\n", nFeeRet);*/ + //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 = %" PRId64 "\n", nValue); + LogPrintf("EstimateAnonFeeIncluded: Fee = %" PRId64 "\n", nFeeRet); + LogPrintf("EstimateAnonFeeIncluded: Dust = %" PRId64 "\n", GetShadowBalance() - nValue - nFeeRet); + } + return nFeeRet; }; diff --git a/src/wallet.h b/src/wallet.h index aee0a1add9..23a5e46556 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -280,7 +280,7 @@ class CWallet : public CCryptoKeyStore bool ProcessLockedAnonOutputs(); 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, 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); From 48e1ed551f67dc5104b6b1ba058aa0959ec37606 Mon Sep 17 00:00:00 2001 From: Kewde Date: Wed, 16 Nov 2016 01:51:35 +0100 Subject: [PATCH 5/7] Remove PRId64 (fails on windows builds), now casts int64_t to int Improved RPC logic --- src/rpcwallet.cpp | 6 ++++-- src/wallet.cpp | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index bc3b6bb56a..5e0bb1fd9f 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -2705,7 +2705,7 @@ Value estimateanonfee(const Array& params, bool fHelp) if(included){ uint64_t nFeeRequired = pwalletMain->EstimateAnonFeeIncluded(nAmount, nRingSize, sNarr, wtx, sError); result.push_back(Pair("Amount", ValueFromAmount(nAmount - nFeeRequired))); - result.push_back(Pair("Required fee", ValueFromAmount(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); @@ -2724,7 +2724,9 @@ Value estimateanonfee(const Array& params, bool fHelp) 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 155a2a74f0..3d2ce6da87 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -5258,9 +5258,9 @@ int64_t CWallet::EstimateAnonFeeIncluded(int64_t nMaxAmount, int nRingSize, std: } if (fDebugRingSig){ - LogPrintf("EstimateAnonFeeIncluded: Found value = %" PRId64 "\n", nValue); - LogPrintf("EstimateAnonFeeIncluded: Fee = %" PRId64 "\n", nFeeRet); - LogPrintf("EstimateAnonFeeIncluded: Dust = %" PRId64 "\n", GetShadowBalance() - nValue - nFeeRet); + LogPrintf("EstimateAnonFeeIncluded: Found value = %i\n", (int) nValue); + LogPrintf("EstimateAnonFeeIncluded: Fee = %i\n", (int) nFeeRet); + LogPrintf("EstimateAnonFeeIncluded: Dust = %i\n", (int) (GetShadowBalance() - nValue - nFeeRet)); } From ba208a5a64ffa3100015c0b4f51408e78ea056a2 Mon Sep 17 00:00:00 2001 From: Kewde Date: Wed, 16 Nov 2016 22:29:12 +0100 Subject: [PATCH 6/7] Trigger TravisCI rebuild --- src/rpcwallet.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 5e0bb1fd9f..30a11d5362 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -2696,6 +2696,7 @@ Value estimateanonfee(const Array& params, bool fHelp) included = true; } } + Object result; CWalletTx wtx; int64_t nFee = 0; From 8fe4ee4ce3bf7658210271ae8868855364faf9d4 Mon Sep 17 00:00:00 2001 From: Kewde Date: Wed, 16 Nov 2016 22:32:45 +0100 Subject: [PATCH 7/7] Use %d and uncasted values instead --- src/wallet.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wallet.cpp b/src/wallet.cpp index 3d2ce6da87..bfed8ef38c 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -5258,9 +5258,9 @@ int64_t CWallet::EstimateAnonFeeIncluded(int64_t nMaxAmount, int nRingSize, std: } if (fDebugRingSig){ - LogPrintf("EstimateAnonFeeIncluded: Found value = %i\n", (int) nValue); - LogPrintf("EstimateAnonFeeIncluded: Fee = %i\n", (int) nFeeRet); - LogPrintf("EstimateAnonFeeIncluded: Dust = %i\n", (int) (GetShadowBalance() - nValue - nFeeRet)); + LogPrintf("EstimateAnonFeeIncluded: Found value = %d\n", nValue); + LogPrintf("EstimateAnonFeeIncluded: Fee = %d\n", nFeeRet); + LogPrintf("EstimateAnonFeeIncluded: Dust = %d\n", (GetShadowBalance() - nValue - nFeeRet)); }