Implement listreceivedbyaddress.

Closes #53.
This commit is contained in:
Nicola 'tekNico' Larosa 2014-06-06 18:10:29 +02:00 committed by Josh Rickmar
parent 99c986e21f
commit 7ec4e96c6b

View file

@ -104,6 +104,7 @@ var rpcHandlers = map[string]cmdHandler{
"importprivkey": ImportPrivKey,
"keypoolrefill": KeypoolRefill,
"listaccounts": ListAccounts,
"listreceivedbyaddress": ListReceivedByAddress,
"listsinceblock": ListSinceBlock,
"listtransactions": ListTransactions,
"listunspent": ListUnspent,
@ -131,7 +132,6 @@ var rpcHandlers = map[string]cmdHandler{
"listaddressgroupings": Unimplemented,
"listlockunspent": Unimplemented,
"listreceivedbyaccount": Unimplemented,
"listreceivedbyaddress": Unimplemented,
"lockunspent": Unimplemented,
"move": Unimplemented,
"setaccount": Unimplemented,
@ -972,6 +972,104 @@ func ListAccounts(icmd btcjson.Cmd) (interface{}, error) {
return AcctMgr.ListAccounts(cmd.MinConf), nil
}
// ListReceivedByAddress handles a listreceivedbyaddress request by returning
// a slice of objects, each one containing:
// "account": the account of the receiving address;
// "address": the receiving address;
// "amount": total amount received by the address;
// "confirmations": number of confirmations of the most recent transaction.
// It takes two parameters:
// "minconf": minimum number of confirmations to consider a transaction -
// default: one;
// "includeempty": whether or not to include addresses that have no transactions -
// default: false.
func ListReceivedByAddress(icmd btcjson.Cmd) (interface{}, error) {
cmd, ok := icmd.(*btcjson.ListReceivedByAddressCmd)
if !ok {
return nil, btcjson.ErrInternal
}
// Intermediate data for each address.
type AddrData struct {
// Associated account.
account *Account
// Total amount received.
amount btcutil.Amount
// Number of confirmations of the last transaction.
confirmations int32
}
// Intermediate data for all addresses.
allAddrData := make(map[string]AddrData)
bs, err := GetCurBlock()
if err != nil {
return nil, err
}
for _, account := range AcctMgr.AllAccounts() {
if cmd.IncludeEmpty {
// Create an AddrData entry for each active address in the account.
// Otherwise we'll just get addresses from transactions later.
for _, address := range account.SortedActivePaymentAddresses() {
// There might be duplicates, just overwrite them.
allAddrData[address] = AddrData{account: account}
}
}
for _, record := range account.TxStore.Records() {
for _, credit := range record.Credits() {
confirmations := credit.Confirmations(bs.Height)
if !credit.Confirmed(cmd.MinConf, bs.Height) {
// Not enough confirmations, skip the current block.
continue
}
_, addresses, _, err := credit.Addresses(activeNet.Params)
if err != nil {
// Unusable address, skip it.
continue
}
for _, address := range addresses {
addrStr := address.EncodeAddress()
addrData, ok := allAddrData[addrStr]
if ok {
// Address already present, check account consistency.
if addrData.account != account {
return nil, fmt.Errorf(
"Address %v in both account %v and account %v",
addrStr, addrData.account.name, account.name)
}
addrData.amount += credit.Amount()
// Always overwrite confirmations with newer ones.
addrData.confirmations = confirmations
} else {
addrData = AddrData{
account: account,
amount: credit.Amount(),
confirmations: confirmations,
}
}
allAddrData[addrStr] = addrData
}
}
}
}
// Massage address data into output format.
numAddresses := len(allAddrData)
ret := make([]btcjson.ListReceivedByAddressResult, numAddresses, numAddresses)
idx := 0
for address, addrData := range allAddrData {
ret[idx] = btcjson.ListReceivedByAddressResult{
Account: addrData.account.name,
Address: address,
Amount: addrData.amount.ToUnit(btcutil.AmountBTC),
Confirmations: uint64(addrData.confirmations),
}
idx++
}
return ret, nil
}
// ListSinceBlock handles a listsinceblock request by returning an array of maps
// with details of sent and received wallet transactions since the given block.
func ListSinceBlock(icmd btcjson.Cmd) (interface{}, error) {