Change CWallet addressgrouping to use CTxDestination instead of strings.

This is cleanup for the listaddressgroupings code. Also add some
real help text.
This commit is contained in:
Gregory Maxwell 2012-08-20 13:43:33 -04:00
parent 92735bca31
commit b1093efa83
4 changed files with 57 additions and 54 deletions

View File

@ -140,7 +140,7 @@ Value listunspent(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() > 3) if (fHelp || params.size() > 3)
throw runtime_error( throw runtime_error(
"listunspent [minconf=1] [maxconf=9999999] ['addr1','addr2',...]\n" "listunspent [minconf=1] [maxconf=9999999] [\"address\",...]\n"
"Returns array of unspent transaction outputs\n" "Returns array of unspent transaction outputs\n"
"with between minconf and maxconf (inclusive) confirmations.\n" "with between minconf and maxconf (inclusive) confirmations.\n"
"Optionally filtered to only include txouts paid to specified addresses.\n" "Optionally filtered to only include txouts paid to specified addresses.\n"
@ -165,7 +165,7 @@ Value listunspent(const Array& params, bool fHelp)
{ {
CBitcoinAddress address(input.get_str()); CBitcoinAddress address(input.get_str());
if (!address.IsValid()) if (!address.IsValid())
throw JSONRPCError(-5, string("Invalid Bitcoin address:")+input.get_str()); throw JSONRPCError(-5, string("Invalid Bitcoin address: ")+input.get_str());
if (setAddress.count(address)) if (setAddress.count(address))
throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+input.get_str()); throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+input.get_str());
setAddress.insert(address); setAddress.insert(address);
@ -180,8 +180,15 @@ Value listunspent(const Array& params, bool fHelp)
if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth) if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
continue; continue;
if (setAddress.size() && !setAddress.count(out.tx->GetAddressOfTxOut(out.i))) if(setAddress.size())
continue; {
CTxDestination address;
if(!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
continue;
if (!setAddress.count(address))
continue;
}
int64 nValue = out.tx->vout[out.i].nValue; int64 nValue = out.tx->vout[out.i].nValue;
const CScript& pk = out.tx->vout[out.i].scriptPubKey; const CScript& pk = out.tx->vout[out.i].scriptPubKey;
@ -243,7 +250,7 @@ Value createrawtransaction(const Array& params, bool fHelp)
{ {
CBitcoinAddress address(s.name_); CBitcoinAddress address(s.name_);
if (!address.IsValid()) if (!address.IsValid())
throw JSONRPCError(-5, string("Invalid Bitcoin address:")+s.name_); throw JSONRPCError(-5, string("Invalid Bitcoin address: ")+s.name_);
if (setAddress.count(address)) if (setAddress.count(address))
throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_); throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);

View File

@ -277,17 +277,21 @@ Value sendtoaddress(const Array& params, bool fHelp)
Value listaddressgroupings(const Array& params, bool fHelp) Value listaddressgroupings(const Array& params, bool fHelp)
{ {
if (fHelp) if (fHelp)
throw runtime_error("listaddressgroupings"); throw runtime_error(
"listaddressgroupings\n"
"Lists 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");
Array jsonGroupings; Array jsonGroupings;
map<string, int64> balances = pwalletMain->GetAddressBalances(); map<CTxDestination, int64> balances = pwalletMain->GetAddressBalances();
BOOST_FOREACH(set<string> grouping, pwalletMain->GetAddressGroupings()) BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
{ {
Array jsonGrouping; Array jsonGrouping;
BOOST_FOREACH(string address, grouping) BOOST_FOREACH(CTxDestination address, grouping)
{ {
Array addressInfo; Array addressInfo;
addressInfo.push_back(address); addressInfo.push_back(CBitcoinAddress(address).ToString());
addressInfo.push_back(ValueFromAmount(balances[address])); addressInfo.push_back(ValueFromAmount(balances[address]));
{ {
LOCK(pwalletMain->cs_wallet); LOCK(pwalletMain->cs_wallet);

View File

@ -1620,9 +1620,9 @@ int64 CWallet::GetOldestKeyPoolTime()
return keypool.nTime; return keypool.nTime;
} }
std::map<std::string, int64> CWallet::GetAddressBalances() std::map<CTxDestination, int64> CWallet::GetAddressBalances()
{ {
map<string, int64> balances; map<CTxDestination, int64> balances;
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
@ -1640,14 +1640,16 @@ std::map<std::string, int64> CWallet::GetAddressBalances()
if (nDepth < (pcoin->IsFromMe() ? 0 : 1)) if (nDepth < (pcoin->IsFromMe() ? 0 : 1))
continue; continue;
for (int i = 0; i < pcoin->vout.size(); i++) for (unsigned int i = 0; i < pcoin->vout.size(); i++)
{ {
CTxDestination addr;
if (!IsMine(pcoin->vout[i])) if (!IsMine(pcoin->vout[i]))
continue; continue;
if(!ExtractDestination(pcoin->vout[i].scriptPubKey, addr))
continue;
int64 n = pcoin->IsSpent(i) ? 0 : pcoin->vout[i].nValue; int64 n = pcoin->IsSpent(i) ? 0 : pcoin->vout[i].nValue;
string addr = pcoin->GetAddressOfTxOut(i);
if (!balances.count(addr)) if (!balances.count(addr))
balances[addr] = 0; balances[addr] = 0;
balances[addr] += n; balances[addr] += n;
@ -1658,69 +1660,67 @@ std::map<std::string, int64> CWallet::GetAddressBalances()
return balances; return balances;
} }
set< set<string> > CWallet::GetAddressGroupings() set< set<CTxDestination> > CWallet::GetAddressGroupings()
{ {
set< set<string> > groupings; set< set<CTxDestination> > groupings;
set<string> grouping; set<CTxDestination> grouping;
BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet) BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
{ {
CWalletTx *pcoin = &walletEntry.second; CWalletTx *pcoin = &walletEntry.second;
if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
continue;
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
continue;
int nDepth = pcoin->GetDepthInMainChain();
if (nDepth < (pcoin->IsFromMe() ? 0 : 1))
continue;
if (pcoin->vin.size() > 0 && IsMine(pcoin->vin[0])) if (pcoin->vin.size() > 0 && IsMine(pcoin->vin[0]))
{ {
// group all input addresses with each other // group all input addresses with each other
BOOST_FOREACH(CTxIn txin, pcoin->vin) BOOST_FOREACH(CTxIn txin, pcoin->vin)
grouping.insert(mapWallet[txin.prevout.hash].GetAddressOfTxOut(txin.prevout.n)); {
CTxDestination address;
if(!ExtractDestination(mapWallet[txin.prevout.hash].vout[txin.prevout.n].scriptPubKey, address))
continue;
grouping.insert(address);
}
// group change with input addresses // group change with input addresses
BOOST_FOREACH(CTxOut txout, pcoin->vout) BOOST_FOREACH(CTxOut txout, pcoin->vout)
if (IsChange(txout)) if (IsChange(txout))
{ {
CWalletTx tx = mapWallet[pcoin->vin[0].prevout.hash]; CWalletTx tx = mapWallet[pcoin->vin[0].prevout.hash];
string addr = tx.GetAddressOfTxOut(pcoin->vin[0].prevout.n);
CTxDestination txoutAddr; CTxDestination txoutAddr;
ExtractDestination(txout.scriptPubKey, txoutAddr); if(!ExtractDestination(txout.scriptPubKey, txoutAddr))
grouping.insert(CBitcoinAddress(txoutAddr).ToString()); continue;
grouping.insert(txoutAddr);
} }
groupings.insert(grouping); groupings.insert(grouping);
grouping.clear(); grouping.clear();
} }
// group lone addrs by themselves // group lone addrs by themselves
for (int i = 0; i < pcoin->vout.size(); i++) for (unsigned int i = 0; i < pcoin->vout.size(); i++)
if (IsMine(pcoin->vout[i])) if (IsMine(pcoin->vout[i]))
{ {
grouping.insert(pcoin->GetAddressOfTxOut(i)); CTxDestination address;
if(!ExtractDestination(pcoin->vout[i].scriptPubKey, address))
continue;
grouping.insert(address);
groupings.insert(grouping); groupings.insert(grouping);
grouping.clear(); grouping.clear();
} }
} }
set< set<string>* > uniqueGroupings; // a set of pointers to groups of addresses set< set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses
map< string, set<string>* > setmap; // map addresses to the unique group containing it map< CTxDestination, set<CTxDestination>* > setmap; // map addresses to the unique group containing it
BOOST_FOREACH(set<string> grouping, groupings) BOOST_FOREACH(set<CTxDestination> grouping, groupings)
{ {
// make a set of all the groups hit by this new group // make a set of all the groups hit by this new group
set< set<string>* > hits; set< set<CTxDestination>* > hits;
map< string, set<string>* >::iterator it; map< CTxDestination, set<CTxDestination>* >::iterator it;
BOOST_FOREACH(string address, grouping) BOOST_FOREACH(CTxDestination address, grouping)
if ((it = setmap.find(address)) != setmap.end()) if ((it = setmap.find(address)) != setmap.end())
hits.insert((*it).second); hits.insert((*it).second);
// merge all hit groups into a new single group and delete old groups // merge all hit groups into a new single group and delete old groups
set<string>* merged = new set<string>(grouping); set<CTxDestination>* merged = new set<CTxDestination>(grouping);
BOOST_FOREACH(set<string>* hit, hits) BOOST_FOREACH(set<CTxDestination>* hit, hits)
{ {
merged->insert(hit->begin(), hit->end()); merged->insert(hit->begin(), hit->end());
uniqueGroupings.erase(hit); uniqueGroupings.erase(hit);
@ -1729,12 +1729,12 @@ set< set<string> > CWallet::GetAddressGroupings()
uniqueGroupings.insert(merged); uniqueGroupings.insert(merged);
// update setmap // update setmap
BOOST_FOREACH(string element, *merged) BOOST_FOREACH(CTxDestination element, *merged)
setmap[element] = merged; setmap[element] = merged;
} }
set< set<string> > ret; set< set<CTxDestination> > ret;
BOOST_FOREACH(set<string>* uniqueGrouping, uniqueGroupings) BOOST_FOREACH(set<CTxDestination>* uniqueGrouping, uniqueGroupings)
{ {
ret.insert(*uniqueGrouping); ret.insert(*uniqueGrouping);
delete uniqueGrouping; delete uniqueGrouping;

View File

@ -10,7 +10,6 @@
#include <stdlib.h> #include <stdlib.h>
#include "base58.h"
#include "main.h" #include "main.h"
#include "key.h" #include "key.h"
#include "keystore.h" #include "keystore.h"
@ -177,8 +176,8 @@ public:
int64 GetOldestKeyPoolTime(); int64 GetOldestKeyPoolTime();
void GetAllReserveKeys(std::set<CKeyID>& setAddress); void GetAllReserveKeys(std::set<CKeyID>& setAddress);
std::set< std::set<std::string> > GetAddressGroupings(); std::set< std::set<CTxDestination> > GetAddressGroupings();
std::map<std::string, int64> GetAddressBalances(); std::map<CTxDestination, int64> GetAddressBalances();
bool IsMine(const CTxIn& txin) const; bool IsMine(const CTxIn& txin) const;
int64 GetDebit(const CTxIn& txin) const; int64 GetDebit(const CTxIn& txin) const;
@ -647,13 +646,6 @@ public:
return true; return true;
} }
std::string GetAddressOfTxOut(int n) const
{
CTxDestination addr;
ExtractDestination(vout[n].scriptPubKey, addr);
return CBitcoinAddress(addr).ToString();
}
bool WriteToDisk(); bool WriteToDisk();
int64 GetTxTime() const; int64 GetTxTime() const;