Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/rpcwallet.cpp
Show First 20 Lines • Show All 1,704 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static void MaybePushAddress(UniValue &entry, const CTxDestination &dest) { | static void MaybePushAddress(UniValue &entry, const CTxDestination &dest) { | ||||
if (IsValidDestination(dest)) { | if (IsValidDestination(dest)) { | ||||
entry.pushKV("address", EncodeDestination(dest)); | entry.pushKV("address", EncodeDestination(dest)); | ||||
} | } | ||||
} | } | ||||
/** | |||||
* List transactions based on the given criteria. | |||||
* | |||||
* @param pwallet The wallet. | |||||
* @param wtx The wallet transaction. | |||||
* @param strAccount The account, if any, or "*" for all. | |||||
* @param nMinDepth The minimum confirmation depth. | |||||
* @param fLong Whether to include the JSON version of the transaction. | |||||
* @param ret The UniValue into which the result is stored. | |||||
* @param filter The "is mine" filter bool. | |||||
*/ | |||||
void ListTransactions(CWallet *const pwallet, const CWalletTx &wtx, | void ListTransactions(CWallet *const pwallet, const CWalletTx &wtx, | ||||
const std::string &strAccount, int nMinDepth, bool fLong, | const std::string &strAccount, int nMinDepth, bool fLong, | ||||
UniValue &ret, const isminefilter &filter) { | UniValue &ret, const isminefilter &filter) { | ||||
Amount nFee; | Amount nFee; | ||||
std::string strSentAccount; | std::string strSentAccount; | ||||
std::list<COutputEntry> listReceived; | std::list<COutputEntry> listReceived; | ||||
std::list<COutputEntry> listSent; | std::list<COutputEntry> listSent; | ||||
▲ Show 20 Lines • Show All 386 Lines • ▼ Show 20 Lines | |||||
static UniValue listsinceblock(const Config &config, | static UniValue listsinceblock(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
CWallet *const pwallet = GetWalletForJSONRPCRequest(request); | CWallet *const pwallet = GetWalletForJSONRPCRequest(request); | ||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | ||||
return NullUniValue; | return NullUniValue; | ||||
} | } | ||||
if (request.fHelp || request.params.size() > 3) { | if (request.fHelp || request.params.size() > 4) { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
"listsinceblock ( \"blockhash\" target_confirmations " | "listsinceblock ( \"blockhash\" target_confirmations " | ||||
"include_watchonly)\n" | "include_watchonly include_removed )\n" | ||||
"\nGet all transactions in blocks since block [blockhash], or all " | "\nGet all transactions in blocks since block [blockhash], or all " | ||||
"transactions if omitted\n" | "transactions if omitted.\n" | ||||
"If \"blockhash\" is no longer a part of the main chain, " | |||||
"transactions from the fork point onward are included.\n" | |||||
"Additionally, if include_removed is set, transactions affecting " | |||||
"the wallet which were removed are returned in the \"removed\" " | |||||
"array.\n" | |||||
"\nArguments:\n" | "\nArguments:\n" | ||||
"1. \"blockhash\" (string, optional) The block hash to " | "1. \"blockhash\" (string, optional) The block hash to " | ||||
"list transactions since\n" | "list transactions since\n" | ||||
"2. target_confirmations: (numeric, optional) The confirmations " | "2. target_confirmations: (numeric, optional, default=1) The " | ||||
"required, must be 1 or more\n" | "confirmations required, must be 1 or more\n" | ||||
"3. include_watchonly: (bool, optional, default=false) " | "3. include_watchonly: (bool, optional, default=false) " | ||||
"Include transactions to watch-only addresses (see 'importaddress')" | "Include transactions to watch-only addresses (see " | ||||
"'importaddress')\n" | |||||
"4. include_removed: (bool, optional, default=true) Show " | |||||
"transactions that were removed due to a reorg in the \"removed\" " | |||||
"array\n" | |||||
" (not " | |||||
"guaranteed to work on pruned nodes)\n" | |||||
"\nResult:\n" | "\nResult:\n" | ||||
"{\n" | "{\n" | ||||
" \"transactions\": [\n" | " \"transactions\": [\n" | ||||
" \"account\":\"accountname\", (string) DEPRECATED. The " | " \"account\":\"accountname\", (string) DEPRECATED. The " | ||||
"account name associated with the transaction. Will be \"\" for " | "account name associated with the transaction. Will be \"\" for " | ||||
"the default account.\n" | "the default account.\n" | ||||
" \"address\":\"address\", (string) The bitcoin address of " | " \"address\":\"address\", (string) The bitcoin address of " | ||||
"the transaction. Not present for move transactions (category = " | "the transaction. Not present for move transactions (category = " | ||||
Show All 39 Lines | if (request.fHelp || request.params.size() > 4) { | ||||
"the 'send' category of transactions.\n" | "the 'send' category of transactions.\n" | ||||
" \"comment\": \"...\", (string) If a comment is " | " \"comment\": \"...\", (string) If a comment is " | ||||
"associated with the transaction.\n" | "associated with the transaction.\n" | ||||
" \"label\" : \"label\" (string) A comment for the " | " \"label\" : \"label\" (string) A comment for the " | ||||
"address/transaction, if any\n" | "address/transaction, if any\n" | ||||
" \"to\": \"...\", (string) If a comment to is " | " \"to\": \"...\", (string) If a comment to is " | ||||
"associated with the transaction.\n" | "associated with the transaction.\n" | ||||
" ],\n" | " ],\n" | ||||
" \"removed\": [\n" | |||||
" <structure is the same as \"transactions\" above, only " | |||||
"present if include_removed=true>\n" | |||||
" Note: transactions that were readded in the active chain will " | |||||
"appear as-is in this array, and may thus have a positive " | |||||
"confirmation count.\n" | |||||
" ],\n" | |||||
" \"lastblock\": \"lastblockhash\" (string) The hash of the " | " \"lastblock\": \"lastblockhash\" (string) The hash of the " | ||||
"last block\n" | "last block\n" | ||||
"}\n" | "}\n" | ||||
"\nExamples:\n" + | "\nExamples:\n" + | ||||
HelpExampleCli("listsinceblock", "") + | HelpExampleCli("listsinceblock", "") + | ||||
HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc4" | HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc4" | ||||
"5ef753ee9a7d38571037cdb1a57f663ad" | "5ef753ee9a7d38571037cdb1a57f663ad" | ||||
"\" 6") + | "\" 6") + | ||||
HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc4" | HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc4" | ||||
"5ef753ee9a7d38571037cdb1a57f663ad" | "5ef753ee9a7d38571037cdb1a57f663ad" | ||||
"\", 6")); | "\", 6")); | ||||
} | } | ||||
ObserveSafeMode(); | ObserveSafeMode(); | ||||
// 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(); | ||||
LOCK2(cs_main, pwallet->cs_wallet); | LOCK2(cs_main, pwallet->cs_wallet); | ||||
// Block index of the specified block or the common ancestor, if the block | |||||
// provided was in a deactivated chain. | |||||
const CBlockIndex *pindex = nullptr; | const CBlockIndex *pindex = nullptr; | ||||
// Block index of the specified block, even if it's in a deactivated chain. | |||||
const CBlockIndex *paltindex = nullptr; | |||||
int target_confirms = 1; | int target_confirms = 1; | ||||
isminefilter filter = ISMINE_SPENDABLE; | isminefilter filter = ISMINE_SPENDABLE; | ||||
if (!request.params[0].isNull()) { | if (!request.params[0].isNull()) { | ||||
uint256 blockId; | uint256 blockId; | ||||
blockId.SetHex(request.params[0].get_str()); | blockId.SetHex(request.params[0].get_str()); | ||||
BlockMap::iterator it = mapBlockIndex.find(blockId); | BlockMap::iterator it = mapBlockIndex.find(blockId); | ||||
if (it != mapBlockIndex.end()) { | if (it != mapBlockIndex.end()) { | ||||
pindex = it->second; | paltindex = pindex = it->second; | ||||
if (chainActive[pindex->nHeight] != pindex) { | if (chainActive[pindex->nHeight] != pindex) { | ||||
// the block being asked for is a part of a deactivated chain; | // the block being asked for is a part of a deactivated chain; | ||||
// we don't want to depend on its perceived height in the block | // we don't want to depend on its perceived height in the block | ||||
// chain, we want to instead use the last common ancestor | // chain, we want to instead use the last common ancestor | ||||
pindex = chainActive.FindFork(pindex); | pindex = chainActive.FindFork(pindex); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (!request.params[1].isNull()) { | if (!request.params[1].isNull()) { | ||||
target_confirms = request.params[1].get_int(); | target_confirms = request.params[1].get_int(); | ||||
if (target_confirms < 1) { | if (target_confirms < 1) { | ||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter"); | throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter"); | ||||
} | } | ||||
} | } | ||||
if (request.params.size() > 2 && request.params[2].get_bool()) { | if (!request.params[2].isNull() && request.params[2].get_bool()) { | ||||
filter = filter | ISMINE_WATCH_ONLY; | filter = filter | ISMINE_WATCH_ONLY; | ||||
} | } | ||||
bool include_removed = | |||||
(request.params[3].isNull() || request.params[3].get_bool()); | |||||
int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1; | int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1; | ||||
UniValue transactions(UniValue::VARR); | UniValue transactions(UniValue::VARR); | ||||
for (const std::pair<uint256, CWalletTx> &pairWtx : pwallet->mapWallet) { | for (const std::pair<uint256, CWalletTx> &pairWtx : pwallet->mapWallet) { | ||||
CWalletTx tx = pairWtx.second; | CWalletTx tx = pairWtx.second; | ||||
if (depth == -1 || tx.GetDepthInMainChain() < depth) { | if (depth == -1 || tx.GetDepthInMainChain() < depth) { | ||||
ListTransactions(pwallet, tx, "*", 0, true, transactions, filter); | ListTransactions(pwallet, tx, "*", 0, true, transactions, filter); | ||||
} | } | ||||
} | } | ||||
// when a reorg'd block is requested, we also list any relevant transactions | |||||
// in the blocks of the chain that was detached | |||||
UniValue removed(UniValue::VARR); | |||||
while (include_removed && paltindex && paltindex != pindex) { | |||||
CBlock block; | |||||
if (!ReadBlockFromDisk(block, paltindex, config)) { | |||||
throw JSONRPCError(RPC_INTERNAL_ERROR, | |||||
"Can't read block from disk"); | |||||
} | |||||
for (const CTransactionRef &tx : block.vtx) { | |||||
if (pwallet->mapWallet.count(tx->GetId()) > 0) { | |||||
// We want all transactions regardless of confirmation count to | |||||
// appear here, even negative confirmation ones, hence the big | |||||
// negative. | |||||
ListTransactions(pwallet, pwallet->mapWallet.at(tx->GetId()), | |||||
"*", -100000000, true, removed, filter); | |||||
} | |||||
} | |||||
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(); | ||||
UniValue ret(UniValue::VOBJ); | UniValue ret(UniValue::VOBJ); | ||||
ret.pushKV("transactions", transactions); | ret.pushKV("transactions", transactions); | ||||
if (include_removed) { | |||||
ret.pushKV("removed", removed); | |||||
} | |||||
ret.pushKV("lastblock", lastblock.GetHex()); | ret.pushKV("lastblock", lastblock.GetHex()); | ||||
return ret; | return ret; | ||||
} | } | ||||
static UniValue gettransaction(const Config &config, | static UniValue gettransaction(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
CWallet *const pwallet = GetWalletForJSONRPCRequest(request); | CWallet *const pwallet = GetWalletForJSONRPCRequest(request); | ||||
▲ Show 20 Lines • Show All 1,608 Lines • ▼ Show 20 Lines | static const ContextFreeRPCCommand commands[] = { | ||||
{ "wallet", "getwalletinfo", getwalletinfo, {} }, | { "wallet", "getwalletinfo", getwalletinfo, {} }, | ||||
{ "wallet", "keypoolrefill", keypoolrefill, {"newsize"} }, | { "wallet", "keypoolrefill", keypoolrefill, {"newsize"} }, | ||||
{ "wallet", "listaccounts", listaccounts, {"minconf","include_watchonly"} }, | { "wallet", "listaccounts", listaccounts, {"minconf","include_watchonly"} }, | ||||
{ "wallet", "listaddressgroupings", listaddressgroupings, {} }, | { "wallet", "listaddressgroupings", listaddressgroupings, {} }, | ||||
{ "wallet", "listlockunspent", listlockunspent, {} }, | { "wallet", "listlockunspent", listlockunspent, {} }, | ||||
{ "wallet", "listreceivedbylabel", listreceivedbylabel, {"minconf","include_empty","include_watchonly"} }, | { "wallet", "listreceivedbylabel", listreceivedbylabel, {"minconf","include_empty","include_watchonly"} }, | ||||
{ "wallet", "listreceivedbyaccount", listreceivedbylabel, {"minconf","include_empty","include_watchonly"} }, | { "wallet", "listreceivedbyaccount", listreceivedbylabel, {"minconf","include_empty","include_watchonly"} }, | ||||
{ "wallet", "listreceivedbyaddress", listreceivedbyaddress, {"minconf","include_empty","include_watchonly","address_filter"} }, | { "wallet", "listreceivedbyaddress", listreceivedbyaddress, {"minconf","include_empty","include_watchonly","address_filter"} }, | ||||
{ "wallet", "listsinceblock", listsinceblock, {"blockhash","target_confirmations","include_watchonly"} }, | { "wallet", "listsinceblock", listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} }, | ||||
{ "wallet", "listtransactions", listtransactions, {"account","count","skip","include_watchonly"} }, | { "wallet", "listtransactions", listtransactions, {"account","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", "lockunspent", lockunspent, {"unlock","transactions"} }, | { "wallet", "lockunspent", lockunspent, {"unlock","transactions"} }, | ||||
{ "wallet", "move", movecmd, {"fromaccount","toaccount","amount","minconf","comment"} }, | { "wallet", "move", movecmd, {"fromaccount","toaccount","amount","minconf","comment"} }, | ||||
{ "wallet", "rescanblockchain", rescanblockchain, {"start_height", "stop_height"} }, | { "wallet", "rescanblockchain", rescanblockchain, {"start_height", "stop_height"} }, | ||||
{ "wallet", "sendfrom", sendfrom, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} }, | { "wallet", "sendfrom", sendfrom, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} }, | ||||
{ "wallet", "sendmany", sendmany, {"fromaccount","amounts","minconf","comment","subtractfeefrom"} }, | { "wallet", "sendmany", sendmany, {"fromaccount","amounts","minconf","comment","subtractfeefrom"} }, | ||||
Show All 18 Lines |