diff --git a/rpcserver.go b/rpcserver.go index 4cad56d..01d491f 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -1343,6 +1343,7 @@ var rpcHandlers = map[string]requestHandler{ "getnewaddress": GetNewAddress, "getrawchangeaddress": GetRawChangeAddress, "getreceivedbyaccount": GetReceivedByAccount, + "getreceivedbyaddress": GetReceivedByAddress, "gettransaction": GetTransaction, "importprivkey": ImportPrivKey, "keypoolrefill": KeypoolRefill, @@ -1368,7 +1369,6 @@ var rpcHandlers = map[string]requestHandler{ // Reference implementation methods (still unimplemented) "backupwallet": Unimplemented, "dumpwallet": Unimplemented, - "getreceivedbyaddress": Unimplemented, "getwalletinfo": Unimplemented, "importwallet": Unimplemented, "listaddressgroupings": Unimplemented, @@ -1881,6 +1881,23 @@ func GetReceivedByAccount(w *Wallet, chainSvr *chain.Client, icmd btcjson.Cmd) ( return bal.ToUnit(btcutil.AmountBTC), nil } +// GetReceivedByAddress handles a getreceivedbyaddress request by returning +// the total amount received by a single address. +func GetReceivedByAddress(w *Wallet, chainSvr *chain.Client, icmd btcjson.Cmd) (interface{}, error) { + cmd := icmd.(*btcjson.GetReceivedByAddressCmd) + + addr, err := btcutil.DecodeAddress(cmd.Address, activeNet.Params) + if err != nil { + return nil, InvalidAddressOrKeyError{err} + } + total, err := w.TotalReceivedForAddr(addr, cmd.MinConf) + if err != nil { + return nil, err + } + + return total.ToUnit(btcutil.AmountBTC), nil +} + // GetTransaction handles a gettransaction request by returning details about // a single transaction saved by wallet. func GetTransaction(w *Wallet, chainSvr *chain.Client, icmd btcjson.Cmd) (interface{}, error) { diff --git a/wallet.go b/wallet.go index 1ac1160..cba15ac 100644 --- a/wallet.go +++ b/wallet.go @@ -1350,6 +1350,41 @@ func (w *Wallet) TotalReceived(confirms int) (btcutil.Amount, error) { return amount, nil } +// TotalReceivedForAddr iterates through a wallet's transaction history, +// returning the total amount of bitcoins received for a single wallet +// address. +func (w *Wallet) TotalReceivedForAddr(addr btcutil.Address, confirms int) (btcutil.Amount, error) { + bs, err := w.SyncedChainTip() + if err != nil { + return 0, err + } + + addrStr := addr.EncodeAddress() + var amount btcutil.Amount + for _, r := range w.TxStore.Records() { + for _, c := range r.Credits() { + if !c.Confirmed(confirms, bs.Height) { + continue + } + + _, addrs, _, err := c.Addresses(activeNet.Params) + // An error creating addresses from the output script only + // indicates a non-standard script, so ignore this credit. + if err != nil { + continue + } + for _, a := range addrs { + if addrStr == a.EncodeAddress() { + amount += c.Amount() + break + } + } + } + } + + return amount, nil +} + // TxRecord iterates through all transaction records saved in the store, // returning the first with an equivalent transaction hash. func (w *Wallet) TxRecord(txSha *btcwire.ShaHash) (r *txstore.TxRecord, ok bool) {