Skip to content

Commit bce20c3

Browse files
committed
Include coinbase transactions in receivedby wallet rpcs
1 parent dca9ab4 commit bce20c3

File tree

2 files changed

+56
-13
lines changed

2 files changed

+56
-13
lines changed

src/rpc/client.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,17 @@ static const CRPCConvertParam vRPCConvertParams[] =
4646
{ "settxfee", 0, "amount" },
4747
{ "sethdseed", 0, "newkeypool" },
4848
{ "getreceivedbyaddress", 1, "minconf" },
49+
{ "getreceivedbyaddress", 2, "include_immature_coinbase" },
4950
{ "getreceivedbylabel", 1, "minconf" },
51+
{ "getreceivedbylabel", 2, "include_immature_coinbase" },
5052
{ "listreceivedbyaddress", 0, "minconf" },
5153
{ "listreceivedbyaddress", 1, "include_empty" },
5254
{ "listreceivedbyaddress", 2, "include_watchonly" },
55+
{ "listreceivedbyaddress", 4, "include_immature_coinbase" },
5356
{ "listreceivedbylabel", 0, "minconf" },
5457
{ "listreceivedbylabel", 1, "include_empty" },
5558
{ "listreceivedbylabel", 2, "include_watchonly" },
59+
{ "listreceivedbylabel", 3, "include_immature_coinbase" },
5660
{ "getbalance", 1, "minconf" },
5761
{ "getbalance", 2, "include_watchonly" },
5862
{ "getbalance", 3, "avoid_reuse" },

src/wallet/rpcwallet.cpp

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -528,11 +528,26 @@ static CAmount GetReceived(const CWallet& wallet, const UniValue& params, bool b
528528
if (!params[1].isNull())
529529
min_depth = params[1].get_int();
530530

531+
const bool include_immature_coinbase{params[2].isNull() ? false : params[2].get_bool()};
532+
533+
// Excluding coinbase outputs is deprecated
534+
// It can be enabled by setting deprecatedrpc=exclude_coinbase
535+
const bool include_coinbase{!wallet.chain().rpcEnableDeprecated("exclude_coinbase")};
536+
537+
if (include_immature_coinbase && !include_coinbase) {
538+
throw JSONRPCError(RPC_INVALID_PARAMETER, "include_immature_coinbase is incompatible with deprecated exclude_coinbase");
539+
}
540+
531541
// Tally
532542
CAmount amount = 0;
533543
for (const std::pair<const uint256, CWalletTx>& wtx_pair : wallet.mapWallet) {
534544
const CWalletTx& wtx = wtx_pair.second;
535-
if (wtx.IsCoinBase() || !wallet.chain().checkFinalTx(*wtx.tx) || wallet.GetTxDepthInMainChain(wtx) < min_depth) {
545+
int depth{wallet.GetTxDepthInMainChain(wtx)};
546+
if (depth < min_depth
547+
// Coinbase with less than 1 confirmation is no longer in the main chain
548+
|| (wtx.IsCoinBase() && (depth < 1 || !include_coinbase))
549+
|| (wallet.IsTxImmatureCoinBase(wtx) && !include_immature_coinbase)
550+
|| !wallet.chain().checkFinalTx(*wtx.tx)) {
536551
continue;
537552
}
538553

@@ -555,6 +570,7 @@ static RPCHelpMan getreceivedbyaddress()
555570
{
556571
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address for transactions."},
557572
{"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "Only include transactions confirmed at least this many times."},
573+
{"include_immature_coinbase", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include immature coinbase transactions."},
558574
},
559575
RPCResult{
560576
RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received at this address."
@@ -566,6 +582,8 @@ static RPCHelpMan getreceivedbyaddress()
566582
+ HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0") +
567583
"\nThe amount with at least 6 confirmations\n"
568584
+ HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 6") +
585+
"\nThe amount with at least 6 confirmations including immature coinbase outputs\n"
586+
+ HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 6 true") +
569587
"\nAs a JSON-RPC call\n"
570588
+ HelpExampleRpc("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\", 6")
571589
},
@@ -593,6 +611,7 @@ static RPCHelpMan getreceivedbylabel()
593611
{
594612
{"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The selected label, may be the default label using \"\"."},
595613
{"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "Only include transactions confirmed at least this many times."},
614+
{"include_immature_coinbase", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include immature coinbase transactions."},
596615
},
597616
RPCResult{
598617
RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received for this label."
@@ -604,8 +623,10 @@ static RPCHelpMan getreceivedbylabel()
604623
+ HelpExampleCli("getreceivedbylabel", "\"tabby\" 0") +
605624
"\nThe amount with at least 6 confirmations\n"
606625
+ HelpExampleCli("getreceivedbylabel", "\"tabby\" 6") +
626+
"\nThe amount with at least 6 confirmations including immature coinbase outputs\n"
627+
+ HelpExampleCli("getreceivedbylabel", "\"tabby\" 6 true") +
607628
"\nAs a JSON-RPC call\n"
608-
+ HelpExampleRpc("getreceivedbylabel", "\"tabby\", 6")
629+
+ HelpExampleRpc("getreceivedbylabel", "\"tabby\", 6, true")
609630
},
610631
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
611632
{
@@ -894,7 +915,7 @@ struct tallyitem
894915
}
895916
};
896917

897-
static UniValue ListReceived(const CWallet& wallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
918+
static UniValue ListReceived(const CWallet& wallet, const UniValue& params, const bool by_label, const bool include_immature_coinbase) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
898919
{
899920
// Minimum confirmations
900921
int nMinDepth = 1;
@@ -914,27 +935,38 @@ static UniValue ListReceived(const CWallet& wallet, const UniValue& params, bool
914935

915936
bool has_filtered_address = false;
916937
CTxDestination filtered_address = CNoDestination();
917-
if (!by_label && params.size() > 3) {
938+
if (!by_label && !params[3].isNull() && !params[3].get_str().empty()) {
918939
if (!IsValidDestinationString(params[3].get_str())) {
919940
throw JSONRPCError(RPC_WALLET_ERROR, "address_filter parameter was invalid");
920941
}
921942
filtered_address = DecodeDestination(params[3].get_str());
922943
has_filtered_address = true;
923944
}
924945

946+
// Excluding coinbase outputs is deprecated
947+
// It can be enabled by setting deprecatedrpc=exclude_coinbase
948+
const bool include_coinbase{!wallet.chain().rpcEnableDeprecated("exclude_coinbase")};
949+
950+
if (include_immature_coinbase && !include_coinbase) {
951+
throw JSONRPCError(RPC_INVALID_PARAMETER, "include_immature_coinbase is incompatible with deprecated exclude_coinbase");
952+
}
953+
925954
// Tally
926955
std::map<CTxDestination, tallyitem> mapTally;
927956
for (const std::pair<const uint256, CWalletTx>& pairWtx : wallet.mapWallet) {
928957
const CWalletTx& wtx = pairWtx.second;
929958

930-
if (wtx.IsCoinBase() || !wallet.chain().checkFinalTx(*wtx.tx)) {
931-
continue;
932-
}
933-
934959
int nDepth = wallet.GetTxDepthInMainChain(wtx);
935960
if (nDepth < nMinDepth)
936961
continue;
937962

963+
// Coinbase with less than 1 confirmation is no longer in the main chain
964+
if ((wtx.IsCoinBase() && (nDepth < 1 || !include_coinbase))
965+
|| (wallet.IsTxImmatureCoinBase(wtx) && !include_immature_coinbase)
966+
|| !wallet.chain().checkFinalTx(*wtx.tx)) {
967+
continue;
968+
}
969+
938970
for (const CTxOut& txout : wtx.tx->vout)
939971
{
940972
CTxDestination address;
@@ -1049,7 +1081,8 @@ static RPCHelpMan listreceivedbyaddress()
10491081
{"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum number of confirmations before payments are included."},
10501082
{"include_empty", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to include addresses that haven't received any payments."},
10511083
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see 'importaddress')"},
1052-
{"address_filter", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If present, only return information on this address."},
1084+
{"address_filter", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If present and non-empty, only return information on this address."},
1085+
{"include_immature_coinbase", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include immature coinbase transactions."},
10531086
},
10541087
RPCResult{
10551088
RPCResult::Type::ARR, "", "",
@@ -1071,8 +1104,9 @@ static RPCHelpMan listreceivedbyaddress()
10711104
RPCExamples{
10721105
HelpExampleCli("listreceivedbyaddress", "")
10731106
+ HelpExampleCli("listreceivedbyaddress", "6 true")
1107+
+ HelpExampleCli("listreceivedbyaddress", "6 true true \"\" true")
10741108
+ HelpExampleRpc("listreceivedbyaddress", "6, true, true")
1075-
+ HelpExampleRpc("listreceivedbyaddress", "6, true, true, \"" + EXAMPLE_ADDRESS[0] + "\"")
1109+
+ HelpExampleRpc("listreceivedbyaddress", "6, true, true, \"" + EXAMPLE_ADDRESS[0] + "\", true")
10761110
},
10771111
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
10781112
{
@@ -1083,9 +1117,11 @@ static RPCHelpMan listreceivedbyaddress()
10831117
// the user could have gotten from another RPC command prior to now
10841118
pwallet->BlockUntilSyncedToCurrentChain();
10851119

1120+
const bool include_immature_coinbase{request.params[4].isNull() ? false : request.params[4].get_bool()};
1121+
10861122
LOCK(pwallet->cs_wallet);
10871123

1088-
return ListReceived(*pwallet, request.params, false);
1124+
return ListReceived(*pwallet, request.params, false, include_immature_coinbase);
10891125
},
10901126
};
10911127
}
@@ -1098,6 +1134,7 @@ static RPCHelpMan listreceivedbylabel()
10981134
{"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum number of confirmations before payments are included."},
10991135
{"include_empty", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to include labels that haven't received any payments."},
11001136
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see 'importaddress')"},
1137+
{"include_immature_coinbase", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include immature coinbase transactions."},
11011138
},
11021139
RPCResult{
11031140
RPCResult::Type::ARR, "", "",
@@ -1114,7 +1151,7 @@ static RPCHelpMan listreceivedbylabel()
11141151
RPCExamples{
11151152
HelpExampleCli("listreceivedbylabel", "")
11161153
+ HelpExampleCli("listreceivedbylabel", "6 true")
1117-
+ HelpExampleRpc("listreceivedbylabel", "6, true, true")
1154+
+ HelpExampleRpc("listreceivedbylabel", "6, true, true, true")
11181155
},
11191156
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
11201157
{
@@ -1125,9 +1162,11 @@ static RPCHelpMan listreceivedbylabel()
11251162
// the user could have gotten from another RPC command prior to now
11261163
pwallet->BlockUntilSyncedToCurrentChain();
11271164

1165+
const bool include_immature_coinbase{request.params[3].isNull() ? false : request.params[3].get_bool()};
1166+
11281167
LOCK(pwallet->cs_wallet);
11291168

1130-
return ListReceived(*pwallet, request.params, true);
1169+
return ListReceived(*pwallet, request.params, true, include_immature_coinbase);
11311170
},
11321171
};
11331172
}

0 commit comments

Comments
 (0)