Implement getreceivedbyaccount.

Closes #42.
This commit is contained in:
Josh Rickmar 2014-02-03 13:00:28 -05:00
parent 72d7dda583
commit d7a4e5e816
2 changed files with 89 additions and 3 deletions

View file

@ -140,7 +140,7 @@ func (a *Account) CalculateBalance(confirms int) float64 {
for _, u := range a.UtxoStore { for _, u := range a.UtxoStore {
// Utxos not yet in blocks (height -1) should only be // Utxos not yet in blocks (height -1) should only be
// added if confirmations is 0. // added if confirmations is 0.
if confirms == 0 || (u.Height != -1 && int(bs.Height-u.Height+1) >= confirms) { if confirmed(confirms, u.Height, bs.Height) {
bal += u.Amt bal += u.Amt
} }
} }
@ -166,7 +166,7 @@ func (a *Account) CalculateAddressBalance(addr *btcutil.AddressPubKeyHash, confi
for _, u := range a.UtxoStore { for _, u := range a.UtxoStore {
// Utxos not yet in blocks (height -1) should only be // Utxos not yet in blocks (height -1) should only be
// added if confirmations is 0. // added if confirmations is 0.
if confirms == 0 || (u.Height != -1 && int(bs.Height-u.Height+1) >= confirms) { if confirmed(confirms, u.Height, bs.Height) {
if bytes.Equal(addr.ScriptAddress(), u.AddrHash[:]) { if bytes.Equal(addr.ScriptAddress(), u.AddrHash[:]) {
bal += u.Amt bal += u.Amt
} }
@ -598,3 +598,53 @@ func ReqSpentUtxoNtfn(u *tx.Utxo) {
NotifySpent(CurrentServerConn(), (*btcwire.OutPoint)(&u.Out)) NotifySpent(CurrentServerConn(), (*btcwire.OutPoint)(&u.Out))
} }
// TotalReceived iterates through an account's transaction history, returning the
// total amount of bitcoins received for any account address. Amounts received
// through multisig transactions are ignored.
func (a *Account) TotalReceived(confirms int) (float64, error) {
bs, err := GetCurBlock()
if err != nil {
return 0, err
}
var totalSatoshis int64
for _, e := range a.TxStore {
recvtx, ok := e.(*tx.RecvTx)
if !ok {
continue
}
// Ignore change.
addr, err := btcutil.NewAddressPubKeyHash(recvtx.ReceiverHash, cfg.Net())
if err != nil {
continue
}
info, err := a.Wallet.AddressInfo(addr)
if err != nil {
continue
}
if info.Change {
continue
}
// Tally if the appropiate number of block confirmations have passed.
if confirmed(confirms, recvtx.Height(), bs.Height) {
totalSatoshis += recvtx.Amount
}
}
return float64(totalSatoshis) / float64(btcutil.SatoshiPerBitcoin), nil
}
// confirmed checks whether a transaction at height txHeight has met
// minconf confirmations for a blockchain at height curHeight.
func confirmed(minconf int, txHeight, curHeight int32) bool {
if minconf == 0 {
return true
}
if txHeight != -1 && int(curHeight-txHeight+1) >= minconf {
return true
}
return false
}

View file

@ -40,6 +40,7 @@ var rpcHandlers = map[string]cmdHandler{
"getinfo": GetInfo, "getinfo": GetInfo,
"getnewaddress": GetNewAddress, "getnewaddress": GetNewAddress,
"getrawchangeaddress": GetRawChangeAddress, "getrawchangeaddress": GetRawChangeAddress,
"getreceivedbyaccount": GetReceivedByAccount,
"importprivkey": ImportPrivKey, "importprivkey": ImportPrivKey,
"keypoolrefill": KeypoolRefill, "keypoolrefill": KeypoolRefill,
"listaccounts": ListAccounts, "listaccounts": ListAccounts,
@ -58,7 +59,6 @@ var rpcHandlers = map[string]cmdHandler{
"createmultisig": Unimplemented, "createmultisig": Unimplemented,
"dumpwallet": Unimplemented, "dumpwallet": Unimplemented,
"getblocktemplate": Unimplemented, "getblocktemplate": Unimplemented,
"getreceivedbyaccount": Unimplemented,
"getreceivedbyaddress": Unimplemented, "getreceivedbyaddress": Unimplemented,
"gettransaction": Unimplemented, "gettransaction": Unimplemented,
"gettxout": Unimplemented, "gettxout": Unimplemented,
@ -745,6 +745,42 @@ func GetRawChangeAddress(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
return addr.EncodeAddress(), nil return addr.EncodeAddress(), nil
} }
// GetReceivedByAccount handles a getreceivedbyaccount request by returning
// the total amount received by addresses of an account.
func GetReceivedByAccount(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
cmd, ok := icmd.(*btcjson.GetReceivedByAccountCmd)
if !ok {
return nil, &btcjson.ErrInternal
}
a, err := AcctMgr.Account(cmd.Account)
switch err {
case nil:
break
case ErrNotFound:
return nil, &btcjson.ErrWalletInvalidAccountName
default: // all other non-nil errors
e := btcjson.Error{
Code: btcjson.ErrWallet.Code,
Message: err.Error(),
}
return nil, &e
}
amt, err := a.TotalReceived(cmd.MinConf)
if err != nil {
e := btcjson.Error{
Code: btcjson.ErrWallet.Code,
Message: err.Error(),
}
return nil, &e
}
return amt, nil
}
// ListAccounts handles a listaccounts request by returning a map of account // ListAccounts handles a listaccounts request by returning a map of account
// names to their balances. // names to their balances.
func ListAccounts(icmd btcjson.Cmd) (interface{}, *btcjson.Error) { func ListAccounts(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {