From e491e5bdffd59878a96a1ec7c286d50b2b1125e6 Mon Sep 17 00:00:00 2001 From: Akio Nakamura Date: Tue, 18 Jul 2017 16:48:11 +0900 Subject: [PATCH 1/2] fix listreceivedbyaddress to sum amounts for each asset. --- src/wallet/rpcwallet.cpp | 45 ++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 8e3ee165ee..f7617423c4 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -839,7 +839,7 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request) set setAddress = pwalletMain->GetAccountAddresses(strAccount); // Tally - CAmount nAmount = 0; + CAmountMap mapAmount; for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; @@ -849,13 +849,17 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request) for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) { CTxDestination address; - if (ExtractDestination(wtx.tx->vout[i].scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address)) - if (wtx.GetDepthInMainChain() >= nMinDepth && wtx.GetOutputValueOut(i) >= 0) - nAmount += wtx.GetOutputValueOut(i); + if (ExtractDestination(wtx.tx->vout[i].scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address)) { + if (wtx.GetDepthInMainChain() >= nMinDepth && wtx.GetOutputValueOut(i) >= 0) { + CAmountMap wtxValue; + wtxValue[wtx.GetOutputAsset(i)] = wtx.GetOutputValueOut(i); + mapAmount += wtxValue; + } + } } } - return ValueFromAmount(nAmount); + return PushAssetBalance(mapAmount, pwalletMain, ""); } @@ -1380,12 +1384,12 @@ struct tallyitem { CBitcoinAddress address; CAmount nAmount; + CAmountMap mapAmount; int nConf; vector txids; bool fIsWatchonly; tallyitem() { - nAmount = 0; nConf = std::numeric_limits::max(); fIsWatchonly = false; } @@ -1408,14 +1412,14 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) if(params[2].get_bool()) filter = filter | ISMINE_WATCH_ONLY; - std::string strasset = "bitcoin"; + std::string strasset = ""; if (params.size() > 3 && params[3].isStr()) { if (fByAccounts) throw JSONRPCError(RPC_WALLET_ERROR, "Accounts are completely disabled for assets."); strasset = params[3].get_str(); } CAsset asset; - if (strasset != "*") + if (strasset != "") asset = GetAssetFromString(strasset); // Tally @@ -1444,14 +1448,16 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) if (wtx.GetOutputValueOut(i) < 0) continue; - if (strasset != "*" && wtx.GetOutputAsset(i) != asset) + if (strasset != "" && wtx.GetOutputAsset(i) != asset) continue; CBitcoinAddress bitcoinaddress(address); tallyitem& item = mapTally[address]; item.address = bitcoinaddress; - item.nAmount += wtx.GetOutputValueOut(i); + CAmountMap wtxValue; + wtxValue[wtx.GetOutputAsset(i)] = wtx.GetOutputValueOut(i); + item.mapAmount += wtxValue; item.nConf = min(item.nConf, nDepth); item.txids.push_back(wtx.GetHash()); if (mine & ISMINE_WATCH_ONLY) @@ -1471,13 +1477,13 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) continue; CBitcoinAddress fulladdress = address; - CAmount nAmount = 0; + CAmountMap mapAmount; int nConf = std::numeric_limits::max(); bool fIsWatchonly = false; if (it != mapTally.end()) { fulladdress = (*it).second.address; - nAmount = (*it).second.nAmount; + mapAmount = (*it).second.mapAmount; nConf = (*it).second.nConf; fIsWatchonly = (*it).second.fIsWatchonly; } @@ -1485,7 +1491,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) if (fByAccounts) { tallyitem& _item = mapAccountTally[strAccount]; - _item.nAmount += nAmount; + _item.mapAmount += mapAmount; _item.nConf = min(_item.nConf, nConf); _item.fIsWatchonly = fIsWatchonly; } @@ -1498,10 +1504,9 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) fulladdress = fulladdress.GetUnblinded(); obj.push_back(Pair("address", fulladdress.ToString())); obj.push_back(Pair("account", strAccount)); - obj.push_back(Pair("amount", ValueFromAmount(nAmount))); + obj.push_back(Pair("amount", PushAssetBalance(mapAmount, pwalletMain, strasset))); obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); - if (!fByAccounts) - obj.push_back(Pair("label", strAccount)); + obj.push_back(Pair("label", strAccount)); UniValue transactions(UniValue::VARR); if (it != mapTally.end()) { @@ -1519,13 +1524,13 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) { for (map::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it) { - CAmount nAmount = (*it).second.nAmount; + CAmountMap mapAmount = (*it).second.mapAmount; int nConf = (*it).second.nConf; UniValue obj(UniValue::VOBJ); if((*it).second.fIsWatchonly) obj.push_back(Pair("involvesWatchonly", true)); obj.push_back(Pair("account", (*it).first)); - obj.push_back(Pair("amount", ValueFromAmount(nAmount))); + obj.push_back(Pair("amount", PushAssetBalance(mapAmount, pwalletMain, strasset))); obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); ret.push_back(obj); } @@ -1541,13 +1546,13 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 4) throw runtime_error( - "listreceivedbyaddress ( minconf include_empty include_watchonly, asset)\n" + "listreceivedbyaddress ( minconf include_empty include_watchonly, \"assetlabel\" )\n" "\nList balances by receiving address.\n" "\nArguments:\n" "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n" "2. include_empty (bool, optional, default=false) Whether to include addresses that haven't received any payments.\n" "3. include_watchonly (bool, optional, default=false) Whether to include watch-only addresses (see 'importaddress').\n" - "4. \"asset\" (string, optional, default=bitcoin) The hex asset id or label to filter for. \"*\" is used to list all results.\n" + "4. \"assetlabel\" (string, optional) The hex asset id or asset label to filter for.\n" "\nResult:\n" "[\n" " {\n" From 7485b364e7fd08f3a9d40d6c455f50b81668261d Mon Sep 17 00:00:00 2001 From: Akio Nakamura Date: Wed, 19 Jul 2017 20:43:07 +0900 Subject: [PATCH 2/2] add/fix some tests for {list,get}receivedby{address,account} --- qa/rpc-tests/confidential_transactions.py | 14 ++++++++++++-- qa/rpc-tests/receivedby.py | 18 +++++++++--------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/qa/rpc-tests/confidential_transactions.py b/qa/rpc-tests/confidential_transactions.py index fbfed65f76..57517111e5 100755 --- a/qa/rpc-tests/confidential_transactions.py +++ b/qa/rpc-tests/confidential_transactions.py @@ -107,7 +107,7 @@ def run_test(self): assert_equal(self.nodes[2].getbalance()["bitcoin"], node2) # Check 2's listreceivedbyaddress - received_by_address = self.nodes[2].listreceivedbyaddress() + received_by_address = self.nodes[2].listreceivedbyaddress(0, False, False, "bitcoin") validate_by_address = [(unconfidential_address2, value1 + value3), (unconfidential_address, value0 + value2)] assert_equal(sorted([(ele['address'], ele['amount']) for ele in received_by_address], key=lambda t: t[0]), sorted(validate_by_address, key = lambda t: t[0])) @@ -131,7 +131,7 @@ def run_test(self): assert_equal(list_unspent[0]['amount']+list_unspent[1]['amount'], value1+value3) received_by_address = self.nodes[1].listreceivedbyaddress(1, False, True) assert_equal(len(received_by_address), 1) - assert_equal((received_by_address[0]['address'], received_by_address[0]['amount']), + assert_equal((received_by_address[0]['address'], received_by_address[0]['amount']['bitcoin']), (unconfidential_address2, value1 + value3)) # Spending a single confidential output and sending it to a @@ -365,6 +365,16 @@ def run_test(self): assert_equal(self.nodes[0].getwalletinfo()["balance"][issued["token"]], 1) + # Check for value when receiving defferent assets by same address. + self.nodes[0].sendtoaddress(unconfidential_address2, Decimal('0.00000001'), "", "", False, test_asset) + self.nodes[0].sendtoaddress(unconfidential_address2, Decimal('0.00000002'), "", "", False, test_asset) + self.nodes[0].generate(1) + self.sync_all() + received_by_address = self.nodes[1].listreceivedbyaddress(0, False, True) + multi_asset_amount = [x for x in received_by_address if x['address'] == unconfidential_address2][0]['amount'] + assert_equal(multi_asset_amount['bitcoin'], value1 + value3 ) + assert_equal(multi_asset_amount[test_asset], Decimal('0.00000003')) + # Check blinded multisig functionality # Get two pubkeys blinded_addr = self.nodes[0].getnewaddress() diff --git a/qa/rpc-tests/receivedby.py b/qa/rpc-tests/receivedby.py index 7cd58f8488..9859b867ab 100755 --- a/qa/rpc-tests/receivedby.py +++ b/qa/rpc-tests/receivedby.py @@ -56,11 +56,11 @@ def run_test(self): self.sync_all() assert_array_result(self.nodes[1].listreceivedbyaddress(), {"address":unblinded}, - {"address":unblinded, "account":"", "amount":Decimal("0.1"), "confirmations":10, "txids":[txid,]}) + {"address":unblinded, "account":"", "amount":{"bitcoin":Decimal("0.1")}, "confirmations":10, "txids":[txid,]}) #With min confidence < 10 assert_array_result(self.nodes[1].listreceivedbyaddress(5), {"address":unblinded}, - {"address":unblinded, "account":"", "amount":Decimal("0.1"), "confirmations":10, "txids":[txid,]}) + {"address":unblinded, "account":"", "amount":{"bitcoin":Decimal("0.1")}, "confirmations":10, "txids":[txid,]}) #With min confidence > 10, should not find Tx assert_array_result(self.nodes[1].listreceivedbyaddress(11),{"blindedaddress":addr},{ },True) @@ -69,7 +69,7 @@ def run_test(self): unblinded = self.nodes[1].validateaddress(addr)['unconfidential'] assert_array_result(self.nodes[1].listreceivedbyaddress(0,True), {"address":unblinded}, - {"address":unblinded, "account":"", "amount":0, "confirmations":0, "txids":[]}) + {"address":unblinded, "account":"", "amount":{}, "confirmations":0, "txids":[]}) ''' getreceivedbyaddress Test @@ -106,7 +106,7 @@ def run_test(self): received_by_account_json = get_sub_array_from_array(self.nodes[1].listreceivedbyaccount(),{"account":account}) if len(received_by_account_json) == 0: raise AssertionError("No accounts found in node") - balance_by_account = self.nodes[1].getreceivedbyaccount(account) + balance_by_account = self.nodes[1].getreceivedbyaccount(account)["bitcoin"] txid = self.nodes[0].sendtoaddress(addr, 0.1) self.sync_all() @@ -117,7 +117,7 @@ def run_test(self): received_by_account_json) # getreceivedbyaddress should return same balance because of 0 confirmations - balance = self.nodes[1].getreceivedbyaccount(account) + balance = self.nodes[1].getreceivedbyaccount(account)["bitcoin"] if balance != balance_by_account: raise AssertionError("Wrong balance returned by getreceivedbyaccount, %0.2f"%(balance)) @@ -126,10 +126,10 @@ def run_test(self): # listreceivedbyaccount should return updated account balance assert_array_result(self.nodes[1].listreceivedbyaccount(), {"account":account}, - {"account":received_by_account_json["account"], "amount":(received_by_account_json["amount"] + Decimal("0.1"))}) + {"account":received_by_account_json["account"], "amount":{"bitcoin":(received_by_account_json["amount"]["bitcoin"] + Decimal("0.1"))}}) # getreceivedbyaddress should return updates balance - balance = self.nodes[1].getreceivedbyaccount(account) + balance = self.nodes[1].getreceivedbyaccount(account)["bitcoin"] if balance != balance_by_account + Decimal("0.1"): raise AssertionError("Wrong balance returned by getreceivedbyaccount, %0.2f"%(balance)) @@ -140,12 +140,12 @@ def run_test(self): raise AssertionError("No accounts found in node") # Test includeempty of listreceivedbyaccount - if received_by_account_json["amount"] != Decimal("0.0"): + if received_by_account_json["amount"] != {}: raise AssertionError("Wrong balance returned by listreceivedbyaccount, %0.2f"%(received_by_account_json["amount"])) # Test getreceivedbyaccount for 0 amount accounts balance = self.nodes[1].getreceivedbyaccount("mynewaccount") - if balance != Decimal("0.0"): + if balance != {}: raise AssertionError("Wrong balance returned by getreceivedbyaccount, %0.2f"%(balance)) if __name__ == '__main__':