比特币 RPC 命令「listaddressgroupings」
$ bitcoin-cli help listaddressgroupings listaddressgroupings 列出一组地址,它们的共同所有权作为输入或在过去的交易中作为找零而被公开 结果: [ [ [ "bitcoinaddress",(字符串)比特币地址 amount, (数字)以 BTC 为单位的金额 "account" (字符串,可选)账户(已过时) ] ,... ] ,... ] 例子: > bitcoin-cli listaddressgroupings > curl --user myusername:mypassword --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "listaddressgroupings", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/
源码剖析
listaddressgroupings
对应的函数在文件 rpcserver.h
中被引用。
extern UniValue listaddressgroupings(const UniValue& params, bool fHelp);
实现在文件 rpcwallet.cpp
中。
UniValue listaddressgroupings(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp)) // 1. 确保钱包可用
return NullUniValue;
if (fHelp)
throw runtime_error(
"listaddressgroupings\n"
"\nLists groups of addresses which have had their common ownership\n"
"made public by common use as inputs or as the resulting change\n"
"in past transactions\n"
"\nResult:\n"
"[\n"
" [\n"
" [\n"
" \"bitcoinaddress\", (string) The bitcoin address\n"
" amount, (numeric) The amount in " + CURRENCY_UNIT + "\n"
" \"account\" (string, optional) The account (DEPRECATED)\n"
" ]\n"
" ,...\n"
" ]\n"
" ,...\n"
"]\n"
"\nExamples:\n"
+ HelpExampleCli("listaddressgroupings", "")
+ HelpExampleRpc("listaddressgroupings", "")
); // 2. 帮助内容
LOCK2(cs_main, pwalletMain->cs_wallet);
UniValue jsonGroupings(UniValue::VARR); // 3. 获取地址集合
map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances(); // 获取地址余额映射列表
BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings()) // 获取并遍历地址分组集合
{
UniValue jsonGrouping(UniValue::VARR); // 地址分组对象
BOOST_FOREACH(CTxDestination address, grouping) // 遍历一个地址分组
{
UniValue addressInfo(UniValue::VARR); // 一个地址信息(地址、余额、账户)
addressInfo.push_back(CBitcoinAddress(address).ToString()); // 获取地址
addressInfo.push_back(ValueFromAmount(balances[address])); // 获取地址余额
{
if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end()) // 若地址簿中有该地址
addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name); // 把该地址关联的账户名加入地址信息
}
jsonGrouping.push_back(addressInfo); // 加入地址分组
}
jsonGroupings.push_back(jsonGrouping); // 加入地址分组集合
}
return jsonGroupings;
}
1. 确保钱包可用
参考比特币 RPC 命令「fundrawtransaction」1. 确保钱包可用。
2. 帮助内容
参考比特币 RPC 命令「getbestblockhash」1. 帮助内容。
3. 获取地址集合
获取地址余额函数 pwalletMain->GetAddressBalances()
定义在文件 wallet.cpp
中。
std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
{
map<CTxDestination, CAmount> balances; // 地址余额映射列表
{
LOCK(cs_wallet); // 钱包上锁
BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet) // 遍历钱包交易映射列表
{ // 获取一个钱包条目(交易索引,钱包交易)
CWalletTx *pcoin = &walletEntry.second; // 获取钱包交易
if (!CheckFinalTx(*pcoin) || !pcoin->IsTrusted()) // 为最终交易 且 交易可信
continue; // 跳过
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) // 若为创币交易 且 未成熟
continue; // 跳过
int nDepth = pcoin->GetDepthInMainChain(); // 获取该交易所在区块的主链深度
if (nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? 0 : 1))
continue;
for (unsigned int i = 0; i < pcoin->vout.size(); i++) // 遍历该交易的输出列表
{
CTxDestination addr;
if (!IsMine(pcoin->vout[i])) // 若交易输出不是我的
continue; // 跳过
if(!ExtractDestination(pcoin->vout[i].scriptPubKey, addr)) // 从交易输出中抽取交易地址
continue;
CAmount n = IsSpent(walletEntry.first, i) ? 0 : pcoin->vout[i].nValue; // 若该交易未花费,获取其输出点的值
if (!balances.count(addr)) // 结果集中不含该地址
balances[addr] = 0; // 初始化
balances[addr] += n; // 累加地址余额(未花费的输出点)
}
}
}
return balances; // 返回地址余额映射列表
}
通过遍历钱包交易映射列表,获取每笔钱包交易的输入和输出列表对应的交易地址。