Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/rpcwallet.cpp
Show First 20 Lines • Show All 1,464 Lines • ▼ Show 20 Lines | static void MaybePushAddress(UniValue &entry, const CTxDestination &dest) { | ||||
if (IsValidDestination(dest)) { | if (IsValidDestination(dest)) { | ||||
entry.pushKV("address", EncodeDestination(dest, GetConfig())); | entry.pushKV("address", EncodeDestination(dest, GetConfig())); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* List transactions based on the given criteria. | * List transactions based on the given criteria. | ||||
* | * | ||||
* @param pwallet The wallet. | * @param pwallet The wallet. | ||||
* @param wtx The wallet transaction. | * @param wtx The wallet transaction. | ||||
* @param nMinDepth The minimum confirmation depth. | * @param nMinDepth The minimum confirmation depth. | ||||
* @param fLong Whether to include the JSON version of the transaction. | * @param fLong Whether to include the JSON version of the | ||||
* transaction. | |||||
* @param ret The UniValue into which the result is stored. | * @param ret The UniValue into which the result is stored. | ||||
* @param filter The "is mine" filter bool. | * @param filter_ismine The "is mine" filter flags. | ||||
* @param filter_label Optional label string to filter incoming transactions. | |||||
*/ | */ | ||||
static void ListTransactions(interfaces::Chain::Lock &locked_chain, | static void ListTransactions(interfaces::Chain::Lock &locked_chain, | ||||
CWallet *const pwallet, const CWalletTx &wtx, | CWallet *const pwallet, const CWalletTx &wtx, | ||||
int nMinDepth, bool fLong, UniValue &ret, | int nMinDepth, bool fLong, UniValue &ret, | ||||
const isminefilter &filter) { | const isminefilter &filter_ismine, | ||||
const std::string *filter_label) { | |||||
Amount nFee; | Amount nFee; | ||||
std::list<COutputEntry> listReceived; | std::list<COutputEntry> listReceived; | ||||
std::list<COutputEntry> listSent; | std::list<COutputEntry> listSent; | ||||
wtx.GetAmounts(listReceived, listSent, nFee, filter); | wtx.GetAmounts(listReceived, listSent, nFee, filter_ismine); | ||||
bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY); | bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY); | ||||
// Sent | // Sent | ||||
if (!listSent.empty() || nFee != Amount::zero()) { | if (!filter_label) { | ||||
for (const COutputEntry &s : listSent) { | for (const COutputEntry &s : listSent) { | ||||
UniValue entry(UniValue::VOBJ); | UniValue entry(UniValue::VOBJ); | ||||
if (involvesWatchonly || | if (involvesWatchonly || | ||||
(::IsMine(*pwallet, s.destination) & ISMINE_WATCH_ONLY)) { | (::IsMine(*pwallet, s.destination) & ISMINE_WATCH_ONLY)) { | ||||
entry.pushKV("involvesWatchonly", true); | entry.pushKV("involvesWatchonly", true); | ||||
} | } | ||||
MaybePushAddress(entry, s.destination); | MaybePushAddress(entry, s.destination); | ||||
entry.pushKV("category", "send"); | entry.pushKV("category", "send"); | ||||
Show All 15 Lines | static void ListTransactions(interfaces::Chain::Lock &locked_chain, | ||||
// Received | // Received | ||||
if (listReceived.size() > 0 && | if (listReceived.size() > 0 && | ||||
wtx.GetDepthInMainChain(locked_chain) >= nMinDepth) { | wtx.GetDepthInMainChain(locked_chain) >= nMinDepth) { | ||||
for (const COutputEntry &r : listReceived) { | for (const COutputEntry &r : listReceived) { | ||||
std::string label; | std::string label; | ||||
if (pwallet->mapAddressBook.count(r.destination)) { | if (pwallet->mapAddressBook.count(r.destination)) { | ||||
label = pwallet->mapAddressBook[r.destination].name; | label = pwallet->mapAddressBook[r.destination].name; | ||||
} | } | ||||
if (filter_label && label != *filter_label) { | |||||
continue; | |||||
} | |||||
UniValue entry(UniValue::VOBJ); | UniValue entry(UniValue::VOBJ); | ||||
if (involvesWatchonly || | if (involvesWatchonly || | ||||
(::IsMine(*pwallet, r.destination) & ISMINE_WATCH_ONLY)) { | (::IsMine(*pwallet, r.destination) & ISMINE_WATCH_ONLY)) { | ||||
entry.pushKV("involvesWatchonly", true); | entry.pushKV("involvesWatchonly", true); | ||||
} | } | ||||
MaybePushAddress(entry, r.destination); | MaybePushAddress(entry, r.destination); | ||||
if (wtx.IsCoinBase()) { | if (wtx.IsCoinBase()) { | ||||
if (wtx.GetDepthInMainChain(locked_chain) < 1) { | if (wtx.GetDepthInMainChain(locked_chain) < 1) { | ||||
Show All 24 Lines | UniValue listtransactions(const Config &config, const JSONRPCRequest &request) { | ||||
CWallet *const pwallet = wallet.get(); | CWallet *const pwallet = wallet.get(); | ||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | ||||
return NullUniValue; | return NullUniValue; | ||||
} | } | ||||
if (request.fHelp || request.params.size() > 4) { | if (request.fHelp || request.params.size() > 4) { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
"listtransactions ( \"dummy\" count skip include_watchonly)\n" | "listtransactions ( \"label\" count skip include_watchonly )\n" | ||||
"\nIf a label name is provided, this will return only incoming " | |||||
"transactions paying to addresses with the specified label.\n" | |||||
"\nReturns up to 'count' most recent transactions skipping the " | "\nReturns up to 'count' most recent transactions skipping the " | ||||
"first 'from' transactions.\n" | "first 'from' transactions.\n" | ||||
"\nArguments:\n" | "\nArguments:\n" | ||||
"1. \"dummy\" (string, optional) If set, should be \"*\" for " | "1. \"label\" (string, optional) If set, should be a valid " | ||||
"backwards compatibility.\n" | "label name to return only incoming transactions with the " | ||||
"specified label, or \"*\" to disable filtering and return all " | |||||
"transactions.\n" | |||||
"2. count (numeric, optional, default=10) The number of " | "2. count (numeric, optional, default=10) The number of " | ||||
"transactions to return\n" | "transactions to return\n" | ||||
"3. skip (numeric, optional, default=0) The number of " | "3. skip (numeric, optional, default=0) The number of " | ||||
"transactions to skip\n" | "transactions to skip\n" | ||||
"4. include_watchonly (bool, optional, default=false) Include " | "4. include_watchonly (bool, optional, default=false) Include " | ||||
"transactions to watch-only addresses (see 'importaddress')\n" | "transactions to watch-only addresses (see 'importaddress')\n" | ||||
"\nResult:\n" | "\nResult:\n" | ||||
"[\n" | "[\n" | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | UniValue listtransactions(const Config &config, const JSONRPCRequest &request) { | ||||
// Make sure the results are valid at least up to the most recent block | // Make sure the results are valid at least up to the most recent block | ||||
// the user could have gotten from another RPC command prior to now | // the user could have gotten from another RPC command prior to now | ||||
pwallet->BlockUntilSyncedToCurrentChain(); | pwallet->BlockUntilSyncedToCurrentChain(); | ||||
auto locked_chain = pwallet->chain().lock(); | auto locked_chain = pwallet->chain().lock(); | ||||
LOCK(pwallet->cs_wallet); | LOCK(pwallet->cs_wallet); | ||||
const std::string *filter_label = nullptr; | |||||
if (!request.params[0].isNull() && request.params[0].get_str() != "*") { | if (!request.params[0].isNull() && request.params[0].get_str() != "*") { | ||||
throw JSONRPCError(RPC_INVALID_PARAMETER, | filter_label = &request.params[0].get_str(); | ||||
"Dummy value must be set to \"*\""); | if (filter_label->empty()) { | ||||
throw JSONRPCError( | |||||
RPC_INVALID_PARAMETER, | |||||
"Label argument must be a valid label name or \"*\"."); | |||||
} | |||||
} | } | ||||
int nCount = 10; | int nCount = 10; | ||||
if (!request.params[1].isNull()) { | if (!request.params[1].isNull()) { | ||||
nCount = request.params[1].get_int(); | nCount = request.params[1].get_int(); | ||||
} | } | ||||
int nFrom = 0; | int nFrom = 0; | ||||
if (!request.params[2].isNull()) { | if (!request.params[2].isNull()) { | ||||
Show All 14 Lines | UniValue listtransactions(const Config &config, const JSONRPCRequest &request) { | ||||
UniValue ret(UniValue::VARR); | UniValue ret(UniValue::VARR); | ||||
const CWallet::TxItems &txOrdered = pwallet->wtxOrdered; | const CWallet::TxItems &txOrdered = pwallet->wtxOrdered; | ||||
// iterate backwards until we have nCount items to return: | // iterate backwards until we have nCount items to return: | ||||
for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); | for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); | ||||
it != txOrdered.rend(); ++it) { | it != txOrdered.rend(); ++it) { | ||||
CWalletTx *const pwtx = (*it).second; | CWalletTx *const pwtx = (*it).second; | ||||
ListTransactions(*locked_chain, pwallet, *pwtx, 0, true, ret, filter); | ListTransactions(*locked_chain, pwallet, *pwtx, 0, true, ret, filter, | ||||
filter_label); | |||||
if ((int)ret.size() >= (nCount + nFrom)) { | if ((int)ret.size() >= (nCount + nFrom)) { | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
// ret is newest to oldest | // ret is newest to oldest | ||||
if (nFrom > (int)ret.size()) { | if (nFrom > (int)ret.size()) { | ||||
▲ Show 20 Lines • Show All 188 Lines • ▼ Show 20 Lines | static UniValue listsinceblock(const Config &config, | ||||
UniValue transactions(UniValue::VARR); | UniValue transactions(UniValue::VARR); | ||||
for (const std::pair<const TxId, CWalletTx> &pairWtx : pwallet->mapWallet) { | for (const std::pair<const TxId, CWalletTx> &pairWtx : pwallet->mapWallet) { | ||||
CWalletTx tx = pairWtx.second; | CWalletTx tx = pairWtx.second; | ||||
if (depth == -1 || tx.GetDepthInMainChain(*locked_chain) < depth) { | if (depth == -1 || tx.GetDepthInMainChain(*locked_chain) < depth) { | ||||
ListTransactions(*locked_chain, pwallet, tx, 0, true, transactions, | ListTransactions(*locked_chain, pwallet, tx, 0, true, transactions, | ||||
filter); | filter, nullptr /* filter_label */); | ||||
} | } | ||||
} | } | ||||
const Consensus::Params ¶ms = config.GetChainParams().GetConsensus(); | const Consensus::Params ¶ms = config.GetChainParams().GetConsensus(); | ||||
// when a reorg'd block is requested, we also list any relevant transactions | // when a reorg'd block is requested, we also list any relevant transactions | ||||
// in the blocks of the chain that was detached | // in the blocks of the chain that was detached | ||||
UniValue removed(UniValue::VARR); | UniValue removed(UniValue::VARR); | ||||
while (include_removed && paltindex && paltindex != pindex) { | while (include_removed && paltindex && paltindex != pindex) { | ||||
CBlock block; | CBlock block; | ||||
if (!ReadBlockFromDisk(block, paltindex, params)) { | if (!ReadBlockFromDisk(block, paltindex, params)) { | ||||
throw JSONRPCError(RPC_INTERNAL_ERROR, | throw JSONRPCError(RPC_INTERNAL_ERROR, | ||||
"Can't read block from disk"); | "Can't read block from disk"); | ||||
} | } | ||||
for (const CTransactionRef &tx : block.vtx) { | for (const CTransactionRef &tx : block.vtx) { | ||||
auto it = pwallet->mapWallet.find(tx->GetId()); | auto it = pwallet->mapWallet.find(tx->GetId()); | ||||
if (it != pwallet->mapWallet.end()) { | if (it != pwallet->mapWallet.end()) { | ||||
// We want all transactions regardless of confirmation count to | // We want all transactions regardless of confirmation count to | ||||
// appear here, even negative confirmation ones, hence the big | // appear here, even negative confirmation ones, hence the big | ||||
// negative. | // negative. | ||||
ListTransactions(*locked_chain, pwallet, it->second, -100000000, | ListTransactions(*locked_chain, pwallet, it->second, -100000000, | ||||
true, removed, filter); | true, removed, filter, | ||||
nullptr /* filter_label */); | |||||
} | } | ||||
} | } | ||||
paltindex = paltindex->pprev; | paltindex = paltindex->pprev; | ||||
} | } | ||||
CBlockIndex *pblockLast = | CBlockIndex *pblockLast = | ||||
::ChainActive()[::ChainActive().Height() + 1 - target_confirms]; | ::ChainActive()[::ChainActive().Height() + 1 - target_confirms]; | ||||
uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256(); | uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256(); | ||||
▲ Show 20 Lines • Show All 130 Lines • ▼ Show 20 Lines | static UniValue gettransaction(const Config &config, | ||||
entry.pushKV("amount", ValueFromAmount(nNet - nFee)); | entry.pushKV("amount", ValueFromAmount(nNet - nFee)); | ||||
if (wtx.IsFromMe(filter)) { | if (wtx.IsFromMe(filter)) { | ||||
entry.pushKV("fee", ValueFromAmount(nFee)); | entry.pushKV("fee", ValueFromAmount(nFee)); | ||||
} | } | ||||
WalletTxToJSON(pwallet->chain(), *locked_chain, wtx, entry); | WalletTxToJSON(pwallet->chain(), *locked_chain, wtx, entry); | ||||
UniValue details(UniValue::VARR); | UniValue details(UniValue::VARR); | ||||
ListTransactions(*locked_chain, pwallet, wtx, 0, false, details, filter); | ListTransactions(*locked_chain, pwallet, wtx, 0, false, details, filter, | ||||
nullptr /* filter_label */); | |||||
entry.pushKV("details", details); | entry.pushKV("details", details); | ||||
std::string strHex = EncodeHexTx(*wtx.tx, RPCSerializationFlags()); | std::string strHex = EncodeHexTx(*wtx.tx, RPCSerializationFlags()); | ||||
entry.pushKV("hex", strHex); | entry.pushKV("hex", strHex); | ||||
return entry; | return entry; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 2,623 Lines • ▼ Show 20 Lines | static const ContextFreeRPCCommand commands[] = { | ||||
{ "wallet", "getwalletinfo", getwalletinfo, {} }, | { "wallet", "getwalletinfo", getwalletinfo, {} }, | ||||
{ "wallet", "keypoolrefill", keypoolrefill, {"newsize"} }, | { "wallet", "keypoolrefill", keypoolrefill, {"newsize"} }, | ||||
{ "wallet", "listaddressgroupings", listaddressgroupings, {} }, | { "wallet", "listaddressgroupings", listaddressgroupings, {} }, | ||||
{ "wallet", "listlabels", listlabels, {"purpose"} }, | { "wallet", "listlabels", listlabels, {"purpose"} }, | ||||
{ "wallet", "listlockunspent", listlockunspent, {} }, | { "wallet", "listlockunspent", listlockunspent, {} }, | ||||
{ "wallet", "listreceivedbyaddress", listreceivedbyaddress, {"minconf","include_empty","include_watchonly","address_filter"} }, | { "wallet", "listreceivedbyaddress", listreceivedbyaddress, {"minconf","include_empty","include_watchonly","address_filter"} }, | ||||
{ "wallet", "listreceivedbylabel", listreceivedbylabel, {"minconf","include_empty","include_watchonly"} }, | { "wallet", "listreceivedbylabel", listreceivedbylabel, {"minconf","include_empty","include_watchonly"} }, | ||||
{ "wallet", "listsinceblock", listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} }, | { "wallet", "listsinceblock", listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} }, | ||||
{ "wallet", "listtransactions", listtransactions, {"dummy","count","skip","include_watchonly"} }, | { "wallet", "listtransactions", listtransactions, {"label|dummy","count","skip","include_watchonly"} }, | ||||
{ "wallet", "listunspent", listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} }, | { "wallet", "listunspent", listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} }, | ||||
{ "wallet", "listwallets", listwallets, {} }, | { "wallet", "listwallets", listwallets, {} }, | ||||
{ "wallet", "loadwallet", loadwallet, {"filename"} }, | { "wallet", "loadwallet", loadwallet, {"filename"} }, | ||||
{ "wallet", "lockunspent", lockunspent, {"unlock","transactions"} }, | { "wallet", "lockunspent", lockunspent, {"unlock","transactions"} }, | ||||
{ "wallet", "rescanblockchain", rescanblockchain, {"start_height", "stop_height"} }, | { "wallet", "rescanblockchain", rescanblockchain, {"start_height", "stop_height"} }, | ||||
{ "wallet", "sendmany", sendmany, {"dummy","amounts","minconf","comment","subtractfeefrom"} }, | { "wallet", "sendmany", sendmany, {"dummy","amounts","minconf","comment","subtractfeefrom"} }, | ||||
{ "wallet", "sendtoaddress", sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount"} }, | { "wallet", "sendtoaddress", sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount"} }, | ||||
{ "wallet", "sethdseed", sethdseed, {"newkeypool","seed"} }, | { "wallet", "sethdseed", sethdseed, {"newkeypool","seed"} }, | ||||
Show All 18 Lines |