Move last seen block to RPC client structure.
Pass the RPC client to the notification handlers. Update the last seen block for blockconnected notifications in the client structure directly, protecting access with a mutex.
This commit is contained in:
parent
770384be12
commit
061a220354
6 changed files with 267 additions and 183 deletions
120
account.go
120
account.go
|
@ -104,18 +104,17 @@ func (a *Account) AddressUsed(addr btcutil.Address) bool {
|
||||||
// a UTXO must be in a block. If confirmations is 1 or greater,
|
// a UTXO must be in a block. If confirmations is 1 or greater,
|
||||||
// the balance will be calculated based on how many how many blocks
|
// the balance will be calculated based on how many how many blocks
|
||||||
// include a UTXO.
|
// include a UTXO.
|
||||||
func (a *Account) CalculateBalance(confirms int) float64 {
|
func (a *Account) CalculateBalance(confirms int) (btcutil.Amount, error) {
|
||||||
bs, err := GetCurBlock()
|
rpcc, err := accessClient()
|
||||||
if bs.Height == int32(btcutil.BlockHeightUnknown) || err != nil {
|
if err != nil {
|
||||||
return 0.
|
return 0, err
|
||||||
|
}
|
||||||
|
bs, err := rpcc.BlockStamp()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
bal, err := a.TxStore.Balance(confirms, bs.Height)
|
return a.TxStore.Balance(confirms, bs.Height)
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Cannot calculate balance: %v", err)
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return bal.ToUnit(btcutil.AmountBTC)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CalculateAddressBalance sums the amounts of all unspent transaction
|
// CalculateAddressBalance sums the amounts of all unspent transaction
|
||||||
|
@ -127,16 +126,20 @@ func (a *Account) CalculateBalance(confirms int) float64 {
|
||||||
// a UTXO must be in a block. If confirmations is 1 or greater,
|
// a UTXO must be in a block. If confirmations is 1 or greater,
|
||||||
// the balance will be calculated based on how many how many blocks
|
// the balance will be calculated based on how many how many blocks
|
||||||
// include a UTXO.
|
// include a UTXO.
|
||||||
func (a *Account) CalculateAddressBalance(addr btcutil.Address, confirms int) float64 {
|
func (a *Account) CalculateAddressBalance(addr btcutil.Address, confirms int) (btcutil.Amount, error) {
|
||||||
bs, err := GetCurBlock()
|
rpcc, err := accessClient()
|
||||||
if bs.Height == int32(btcutil.BlockHeightUnknown) || err != nil {
|
if err != nil {
|
||||||
return 0.
|
return 0, err
|
||||||
|
}
|
||||||
|
bs, err := rpcc.BlockStamp()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var bal btcutil.Amount
|
var bal btcutil.Amount
|
||||||
unspent, err := a.TxStore.UnspentOutputs()
|
unspent, err := a.TxStore.UnspentOutputs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0.
|
return 0, err
|
||||||
}
|
}
|
||||||
for _, credit := range unspent {
|
for _, credit := range unspent {
|
||||||
if credit.Confirmed(confirms, bs.Height) {
|
if credit.Confirmed(confirms, bs.Height) {
|
||||||
|
@ -151,7 +154,7 @@ func (a *Account) CalculateAddressBalance(addr btcutil.Address, confirms int) fl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bal.ToUnit(btcutil.AmountBTC)
|
return bal, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CurrentAddress gets the most recently requested Bitcoin payment address
|
// CurrentAddress gets the most recently requested Bitcoin payment address
|
||||||
|
@ -203,14 +206,18 @@ func (a *Account) ListSinceBlock(since, curBlockHeight int32,
|
||||||
// transaction. This is intended to be used for listtransactions RPC
|
// transaction. This is intended to be used for listtransactions RPC
|
||||||
// replies.
|
// replies.
|
||||||
func (a *Account) ListTransactions(from, count int) ([]btcjson.ListTransactionsResult, error) {
|
func (a *Account) ListTransactions(from, count int) ([]btcjson.ListTransactionsResult, error) {
|
||||||
|
txList := []btcjson.ListTransactionsResult{}
|
||||||
|
|
||||||
// Get current block. The block height used for calculating
|
// Get current block. The block height used for calculating
|
||||||
// the number of tx confirmations.
|
// the number of tx confirmations.
|
||||||
bs, err := GetCurBlock()
|
rpcc, err := accessClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return txList, err
|
||||||
|
}
|
||||||
|
bs, err := rpcc.BlockStamp()
|
||||||
|
if err != nil {
|
||||||
|
return txList, err
|
||||||
}
|
}
|
||||||
|
|
||||||
txList := []btcjson.ListTransactionsResult{}
|
|
||||||
|
|
||||||
records := a.TxStore.Records()
|
records := a.TxStore.Records()
|
||||||
lastLookupIdx := len(records) - count
|
lastLookupIdx := len(records) - count
|
||||||
|
@ -232,14 +239,19 @@ func (a *Account) ListTransactions(from, count int) ([]btcjson.ListTransactionsR
|
||||||
func (a *Account) ListAddressTransactions(pkHashes map[string]struct{}) (
|
func (a *Account) ListAddressTransactions(pkHashes map[string]struct{}) (
|
||||||
[]btcjson.ListTransactionsResult, error) {
|
[]btcjson.ListTransactionsResult, error) {
|
||||||
|
|
||||||
|
txList := []btcjson.ListTransactionsResult{}
|
||||||
|
|
||||||
// Get current block. The block height used for calculating
|
// Get current block. The block height used for calculating
|
||||||
// the number of tx confirmations.
|
// the number of tx confirmations.
|
||||||
bs, err := GetCurBlock()
|
rpcc, err := accessClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return txList, err
|
||||||
|
}
|
||||||
|
bs, err := rpcc.BlockStamp()
|
||||||
|
if err != nil {
|
||||||
|
return txList, err
|
||||||
}
|
}
|
||||||
|
|
||||||
txList := []btcjson.ListTransactionsResult{}
|
|
||||||
for _, r := range a.TxStore.Records() {
|
for _, r := range a.TxStore.Records() {
|
||||||
for _, c := range r.Credits() {
|
for _, c := range r.Credits() {
|
||||||
// We only care about the case where len(addrs) == 1,
|
// We only care about the case where len(addrs) == 1,
|
||||||
|
@ -271,16 +283,21 @@ func (a *Account) ListAddressTransactions(pkHashes map[string]struct{}) (
|
||||||
// transaction. This is intended to be used for listalltransactions RPC
|
// transaction. This is intended to be used for listalltransactions RPC
|
||||||
// replies.
|
// replies.
|
||||||
func (a *Account) ListAllTransactions() ([]btcjson.ListTransactionsResult, error) {
|
func (a *Account) ListAllTransactions() ([]btcjson.ListTransactionsResult, error) {
|
||||||
|
txList := []btcjson.ListTransactionsResult{}
|
||||||
|
|
||||||
// Get current block. The block height used for calculating
|
// Get current block. The block height used for calculating
|
||||||
// the number of tx confirmations.
|
// the number of tx confirmations.
|
||||||
bs, err := GetCurBlock()
|
rpcc, err := accessClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return txList, err
|
||||||
|
}
|
||||||
|
bs, err := rpcc.BlockStamp()
|
||||||
|
if err != nil {
|
||||||
|
return txList, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search in reverse order: lookup most recently-added first.
|
// Search in reverse order: lookup most recently-added first.
|
||||||
records := a.TxStore.Records()
|
records := a.TxStore.Records()
|
||||||
txList := []btcjson.ListTransactionsResult{}
|
|
||||||
for i := len(records) - 1; i >= 0; i-- {
|
for i := len(records) - 1; i >= 0; i-- {
|
||||||
jsonResults, err := records[i].ToJSON(a.name, bs.Height, a.Net())
|
jsonResults, err := records[i].ToJSON(a.name, bs.Height, a.Net())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -478,7 +495,7 @@ func (a *Account) LockedOutpoints() []btcjson.TransactionInput {
|
||||||
// Track requests btcd to send notifications of new transactions for
|
// Track requests btcd to send notifications of new transactions for
|
||||||
// each address stored in a wallet.
|
// each address stored in a wallet.
|
||||||
func (a *Account) Track() {
|
func (a *Account) Track() {
|
||||||
client, err := accessClient()
|
rpcc, err := accessClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("No chain server client to track addresses.")
|
log.Errorf("No chain server client to track addresses.")
|
||||||
return
|
return
|
||||||
|
@ -495,7 +512,7 @@ func (a *Account) Track() {
|
||||||
addrs = append(addrs, addr)
|
addrs = append(addrs, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := client.NotifyReceived(addrs); err != nil {
|
if err := rpcc.NotifyReceived(addrs); err != nil {
|
||||||
log.Error("Unable to request transaction updates for address.")
|
log.Error("Unable to request transaction updates for address.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,7 +560,7 @@ func (a *Account) RescanActiveJob() (*RescanJob, error) {
|
||||||
// credits that are not known to have been mined into a block, and attempts
|
// credits that are not known to have been mined into a block, and attempts
|
||||||
// to send each to the chain server for relay.
|
// to send each to the chain server for relay.
|
||||||
func (a *Account) ResendUnminedTxs() {
|
func (a *Account) ResendUnminedTxs() {
|
||||||
client, err := accessClient()
|
rpcc, err := accessClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("No chain server client to resend txs.")
|
log.Errorf("No chain server client to resend txs.")
|
||||||
return
|
return
|
||||||
|
@ -551,7 +568,7 @@ func (a *Account) ResendUnminedTxs() {
|
||||||
|
|
||||||
txs := a.TxStore.UnminedDebitTxs()
|
txs := a.TxStore.UnminedDebitTxs()
|
||||||
for _, tx := range txs {
|
for _, tx := range txs {
|
||||||
_, err := client.SendRawTransaction(tx.MsgTx(), false)
|
_, err := rpcc.SendRawTransaction(tx.MsgTx(), false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO(jrick): Check error for if this tx is a double spend,
|
// TODO(jrick): Check error for if this tx is a double spend,
|
||||||
// remove it if so.
|
// remove it if so.
|
||||||
|
@ -592,7 +609,11 @@ func (a *Account) ActivePaymentAddresses() map[string]struct{} {
|
||||||
// NewAddress returns a new payment address for an account.
|
// NewAddress returns a new payment address for an account.
|
||||||
func (a *Account) NewAddress() (btcutil.Address, error) {
|
func (a *Account) NewAddress() (btcutil.Address, error) {
|
||||||
// Get current block's height and hash.
|
// Get current block's height and hash.
|
||||||
bs, err := GetCurBlock()
|
rpcc, err := accessClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
bs, err := rpcc.BlockStamp()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -613,11 +634,7 @@ func (a *Account) NewAddress() (btcutil.Address, error) {
|
||||||
AcctMgr.MarkAddressForAccount(addr, a)
|
AcctMgr.MarkAddressForAccount(addr, a)
|
||||||
|
|
||||||
// Request updates from btcd for new transactions sent to this address.
|
// Request updates from btcd for new transactions sent to this address.
|
||||||
client, err := accessClient()
|
if err := rpcc.NotifyReceived([]btcutil.Address{addr}); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := client.NotifyReceived([]btcutil.Address{addr}); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -627,7 +644,11 @@ func (a *Account) NewAddress() (btcutil.Address, error) {
|
||||||
// NewChangeAddress returns a new change address for an account.
|
// NewChangeAddress returns a new change address for an account.
|
||||||
func (a *Account) NewChangeAddress() (btcutil.Address, error) {
|
func (a *Account) NewChangeAddress() (btcutil.Address, error) {
|
||||||
// Get current block's height and hash.
|
// Get current block's height and hash.
|
||||||
bs, err := GetCurBlock()
|
rpcc, err := accessClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
bs, err := rpcc.BlockStamp()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -648,11 +669,7 @@ func (a *Account) NewChangeAddress() (btcutil.Address, error) {
|
||||||
AcctMgr.MarkAddressForAccount(addr, a)
|
AcctMgr.MarkAddressForAccount(addr, a)
|
||||||
|
|
||||||
// Request updates from btcd for new transactions sent to this address.
|
// Request updates from btcd for new transactions sent to this address.
|
||||||
client, err := accessClient()
|
if err := rpcc.NotifyReceived([]btcutil.Address{addr}); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := client.NotifyReceived([]btcutil.Address{addr}); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -676,13 +693,13 @@ func (a *Account) RecoverAddresses(n int) error {
|
||||||
|
|
||||||
// Run a goroutine to rescan blockchain for recovered addresses.
|
// Run a goroutine to rescan blockchain for recovered addresses.
|
||||||
go func() {
|
go func() {
|
||||||
client, err := accessClient()
|
rpcc, err := accessClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Cannot access chain server client to " +
|
log.Errorf("Cannot access chain server client to " +
|
||||||
"rescan recovered addresses.")
|
"rescan recovered addresses.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = client.Rescan(lastInfo.FirstBlock(), addrs, nil)
|
err = rpcc.Rescan(lastInfo.FirstBlock(), addrs, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Rescanning for recovered addresses "+
|
log.Errorf("Rescanning for recovered addresses "+
|
||||||
"failed: %v", err)
|
"failed: %v", err)
|
||||||
|
@ -703,13 +720,13 @@ func ReqSpentUtxoNtfns(credits []txstore.Credit) {
|
||||||
ops = append(ops, op)
|
ops = append(ops, op)
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := accessClient()
|
rpcc, err := accessClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Cannot access chain server client to " +
|
log.Errorf("Cannot access chain server client to " +
|
||||||
"request spent output notifications.")
|
"request spent output notifications.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := client.NotifySpent(ops); err != nil {
|
if err := rpcc.NotifySpent(ops); err != nil {
|
||||||
log.Errorf("Cannot request notifications for spent outputs: %v",
|
log.Errorf("Cannot request notifications for spent outputs: %v",
|
||||||
err)
|
err)
|
||||||
}
|
}
|
||||||
|
@ -718,8 +735,12 @@ func ReqSpentUtxoNtfns(credits []txstore.Credit) {
|
||||||
// TotalReceived iterates through an account's transaction history, returning the
|
// TotalReceived iterates through an account's transaction history, returning the
|
||||||
// total amount of bitcoins received for any account address. Amounts received
|
// total amount of bitcoins received for any account address. Amounts received
|
||||||
// through multisig transactions are ignored.
|
// through multisig transactions are ignored.
|
||||||
func (a *Account) TotalReceived(confirms int) (float64, error) {
|
func (a *Account) TotalReceived(confirms int) (btcutil.Amount, error) {
|
||||||
bs, err := GetCurBlock()
|
rpcc, err := accessClient()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
bs, err := rpcc.BlockStamp()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
@ -738,6 +759,5 @@ func (a *Account) TotalReceived(confirms int) (float64, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return amount, nil
|
||||||
return amount.ToUnit(btcutil.AmountBTC), nil
|
|
||||||
}
|
}
|
||||||
|
|
69
acctmgr.go
69
acctmgr.go
|
@ -758,10 +758,16 @@ func (am *AccountManager) BlockNotify(bs *wallet.BlockStamp) {
|
||||||
// TODO: need a flag or check that the utxo store was actually
|
// TODO: need a flag or check that the utxo store was actually
|
||||||
// modified, or this will notify even if there are no balance
|
// modified, or this will notify even if there are no balance
|
||||||
// changes, or sending these notifications as the utxos are added.
|
// changes, or sending these notifications as the utxos are added.
|
||||||
confirmed := a.CalculateBalance(1)
|
confirmed, err := a.CalculateBalance(1)
|
||||||
unconfirmed := a.CalculateBalance(0) - confirmed
|
var unconfirmed btcutil.Amount
|
||||||
server.NotifyWalletBalance(a.name, confirmed)
|
if err == nil {
|
||||||
server.NotifyWalletBalanceUnconfirmed(a.name, unconfirmed)
|
unconfirmed, err = a.CalculateBalance(0)
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
unconfirmed -= confirmed
|
||||||
|
server.NotifyWalletBalance(a.name, confirmed)
|
||||||
|
server.NotifyWalletBalanceUnconfirmed(a.name, unconfirmed)
|
||||||
|
}
|
||||||
|
|
||||||
// If this is the default account, update the block all accounts
|
// If this is the default account, update the block all accounts
|
||||||
// are synced with, and schedule a wallet write.
|
// are synced with, and schedule a wallet write.
|
||||||
|
@ -797,13 +803,13 @@ func (am *AccountManager) RecordSpendingTx(tx *btcutil.Tx, block *txstore.Block)
|
||||||
|
|
||||||
// CalculateBalance returns the balance, calculated using minconf block
|
// CalculateBalance returns the balance, calculated using minconf block
|
||||||
// confirmations, of an account.
|
// confirmations, of an account.
|
||||||
func (am *AccountManager) CalculateBalance(account string, minconf int) (float64, error) {
|
func (am *AccountManager) CalculateBalance(account string, minconf int) (btcutil.Amount, error) {
|
||||||
a, err := am.Account(account)
|
a, err := am.Account(account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.CalculateBalance(minconf), nil
|
return a.CalculateBalance(minconf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateEncryptedWallet creates a new default account with a wallet file
|
// CreateEncryptedWallet creates a new default account with a wallet file
|
||||||
|
@ -814,7 +820,11 @@ func (am *AccountManager) CreateEncryptedWallet(passphrase []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current block's height and hash.
|
// Get current block's height and hash.
|
||||||
bs, err := GetCurBlock()
|
rpcc, err := accessClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
bs, err := rpcc.BlockStamp()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -918,13 +928,37 @@ func (am *AccountManager) DumpWIFPrivateKey(addr btcutil.Address) (string, error
|
||||||
|
|
||||||
// ListAccounts returns a map of account names to their current account
|
// ListAccounts returns a map of account names to their current account
|
||||||
// balances. The balances are calculated using minconf confirmations.
|
// balances. The balances are calculated using minconf confirmations.
|
||||||
func (am *AccountManager) ListAccounts(minconf int) map[string]float64 {
|
func (am *AccountManager) ListAccounts(minconf int) (map[string]btcutil.Amount, error) {
|
||||||
// Create and fill a map of account names and their balances.
|
// Create and fill a map of account names and their balances.
|
||||||
pairs := make(map[string]float64)
|
accts := am.AllAccounts()
|
||||||
for _, a := range am.AllAccounts() {
|
pairs := make(map[string]btcutil.Amount, len(accts))
|
||||||
pairs[a.name] = a.CalculateBalance(minconf)
|
for _, a := range accts {
|
||||||
|
bal, err := a.CalculateBalance(minconf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pairs[a.name] = bal
|
||||||
}
|
}
|
||||||
return pairs
|
return pairs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAccountsF64 returns a map of account names to their current account
|
||||||
|
// balances. The balances are calculated using minconf confirmations.
|
||||||
|
//
|
||||||
|
// The amounts are converted to float64 so this result may be marshaled
|
||||||
|
// as a JSON object for the listaccounts RPC.
|
||||||
|
func (am *AccountManager) ListAccountsF64(minconf int) (map[string]float64, error) {
|
||||||
|
// Create and fill a map of account names and their balances.
|
||||||
|
accts := am.AllAccounts()
|
||||||
|
pairs := make(map[string]float64, len(accts))
|
||||||
|
for _, a := range accts {
|
||||||
|
bal, err := a.CalculateBalance(minconf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pairs[a.name] = bal.ToUnit(btcutil.AmountBTC)
|
||||||
|
}
|
||||||
|
return pairs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListSinceBlock returns a slice of objects representing all transactions in
|
// ListSinceBlock returns a slice of objects representing all transactions in
|
||||||
|
@ -983,14 +1017,19 @@ func (am *AccountManager) GetTransaction(txSha *btcwire.ShaHash) []accountTx {
|
||||||
func (am *AccountManager) ListUnspent(minconf, maxconf int,
|
func (am *AccountManager) ListUnspent(minconf, maxconf int,
|
||||||
addresses map[string]bool) ([]*btcjson.ListUnspentResult, error) {
|
addresses map[string]bool) ([]*btcjson.ListUnspentResult, error) {
|
||||||
|
|
||||||
bs, err := GetCurBlock()
|
results := []*btcjson.ListUnspentResult{}
|
||||||
|
|
||||||
|
rpcc, err := accessClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return results, err
|
||||||
|
}
|
||||||
|
bs, err := rpcc.BlockStamp()
|
||||||
|
if err != nil {
|
||||||
|
return results, err
|
||||||
}
|
}
|
||||||
|
|
||||||
filter := len(addresses) != 0
|
filter := len(addresses) != 0
|
||||||
|
|
||||||
results := []*btcjson.ListUnspentResult{}
|
|
||||||
for _, a := range am.AllAccounts() {
|
for _, a := range am.AllAccounts() {
|
||||||
unspent, err := a.TxStore.SortedUnspentOutputs()
|
unspent, err := a.TxStore.SortedUnspentOutputs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
59
cmd.go
59
cmd.go
|
@ -23,67 +23,16 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
_ "net/http/pprof"
|
_ "net/http/pprof"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/conformal/btcutil"
|
|
||||||
"github.com/conformal/btcwallet/wallet"
|
|
||||||
"github.com/conformal/btcwire"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
cfg *config
|
cfg *config
|
||||||
server *rpcServer
|
server *rpcServer
|
||||||
shutdownChan = make(chan struct{})
|
shutdownChan = make(chan struct{})
|
||||||
|
clientAccessChan = make(chan *rpcClient)
|
||||||
curBlock = struct {
|
|
||||||
sync.RWMutex
|
|
||||||
wallet.BlockStamp
|
|
||||||
}{
|
|
||||||
BlockStamp: wallet.BlockStamp{
|
|
||||||
Height: int32(btcutil.BlockHeightUnknown),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetCurBlock returns the blockchain height and SHA hash of the most
|
|
||||||
// recently seen block. If no blocks have been seen since btcd has
|
|
||||||
// connected, btcd is queried for the current block height and hash.
|
|
||||||
func GetCurBlock() (wallet.BlockStamp, error) {
|
|
||||||
curBlock.RLock()
|
|
||||||
bs := curBlock.BlockStamp
|
|
||||||
curBlock.RUnlock()
|
|
||||||
if bs.Height != int32(btcutil.BlockHeightUnknown) {
|
|
||||||
return bs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var bbHash *btcwire.ShaHash
|
|
||||||
var bbHeight int32
|
|
||||||
client, err := accessClient()
|
|
||||||
if err == nil {
|
|
||||||
bbHash, bbHeight, err = client.GetBestBlock()
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
unknown := wallet.BlockStamp{
|
|
||||||
Height: int32(btcutil.BlockHeightUnknown),
|
|
||||||
}
|
|
||||||
return unknown, err
|
|
||||||
}
|
|
||||||
|
|
||||||
curBlock.Lock()
|
|
||||||
if bbHeight > curBlock.BlockStamp.Height {
|
|
||||||
bs = wallet.BlockStamp{
|
|
||||||
Height: bbHeight,
|
|
||||||
Hash: *bbHash,
|
|
||||||
}
|
|
||||||
curBlock.BlockStamp = bs
|
|
||||||
}
|
|
||||||
curBlock.Unlock()
|
|
||||||
return bs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var clientAccessChan = make(chan *rpcClient)
|
|
||||||
|
|
||||||
func clientAccess(newClient <-chan *rpcClient) {
|
func clientAccess(newClient <-chan *rpcClient) {
|
||||||
var client *rpcClient
|
var client *rpcClient
|
||||||
for {
|
for {
|
||||||
|
|
|
@ -163,7 +163,11 @@ func (a *Account) txToPairs(pairs map[string]btcutil.Amount,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current block's height and hash.
|
// Get current block's height and hash.
|
||||||
bs, err := GetCurBlock()
|
rpcc, err := accessClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
bs, err := rpcc.BlockStamp()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
72
rpcclient.go
72
rpcclient.go
|
@ -72,7 +72,7 @@ type acceptedTx struct {
|
||||||
type (
|
type (
|
||||||
// Container type for any notification.
|
// Container type for any notification.
|
||||||
notification interface {
|
notification interface {
|
||||||
handleNotification() error
|
handleNotification(*rpcClient) error
|
||||||
}
|
}
|
||||||
|
|
||||||
blockConnected blockSummary
|
blockConnected blockSummary
|
||||||
|
@ -85,18 +85,18 @@ type (
|
||||||
rescanProgress int32
|
rescanProgress int32
|
||||||
)
|
)
|
||||||
|
|
||||||
func (n blockConnected) handleNotification() error {
|
func (n blockConnected) handleNotification(c *rpcClient) error {
|
||||||
// Update the blockstamp for the newly-connected block.
|
// Update the blockstamp for the newly-connected block.
|
||||||
bs := &wallet.BlockStamp{
|
bs := wallet.BlockStamp{
|
||||||
Height: n.height,
|
Height: n.height,
|
||||||
Hash: *n.hash,
|
Hash: *n.hash,
|
||||||
}
|
}
|
||||||
curBlock.Lock()
|
c.mtx.Lock()
|
||||||
curBlock.BlockStamp = *bs
|
c.blockStamp = bs
|
||||||
curBlock.Unlock()
|
c.mtx.Unlock()
|
||||||
|
|
||||||
AcctMgr.Grab()
|
AcctMgr.Grab()
|
||||||
AcctMgr.BlockNotify(bs)
|
AcctMgr.BlockNotify(&bs)
|
||||||
AcctMgr.Release()
|
AcctMgr.Release()
|
||||||
|
|
||||||
// Pass notification to wallet clients too.
|
// Pass notification to wallet clients too.
|
||||||
|
@ -121,7 +121,7 @@ func (n blockConnected) MarshalJSON() ([]byte, error) {
|
||||||
return nn.MarshalJSON()
|
return nn.MarshalJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n blockDisconnected) handleNotification() error {
|
func (n blockDisconnected) handleNotification(c *rpcClient) error {
|
||||||
AcctMgr.Grab()
|
AcctMgr.Grab()
|
||||||
defer AcctMgr.Release()
|
defer AcctMgr.Release()
|
||||||
|
|
||||||
|
@ -170,14 +170,14 @@ func parseBlock(block *btcws.BlockDetails) (*txstore.Block, int, error) {
|
||||||
return b, block.Index, nil
|
return b, block.Index, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n recvTx) handleNotification() error {
|
func (n recvTx) handleNotification(c *rpcClient) error {
|
||||||
block, txIdx, err := parseBlock(n.block)
|
block, txIdx, err := parseBlock(n.block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return InvalidNotificationError{err}
|
return InvalidNotificationError{err}
|
||||||
}
|
}
|
||||||
n.tx.SetIndex(txIdx)
|
n.tx.SetIndex(txIdx)
|
||||||
|
|
||||||
bs, err := GetCurBlock()
|
bs, err := c.BlockStamp()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot get current block: %v", err)
|
return fmt.Errorf("cannot get current block: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -233,7 +233,7 @@ func (n recvTx) handleNotification() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n redeemingTx) handleNotification() error {
|
func (n redeemingTx) handleNotification(c *rpcClient) error {
|
||||||
block, txIdx, err := parseBlock(n.block)
|
block, txIdx, err := parseBlock(n.block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return InvalidNotificationError{err}
|
return InvalidNotificationError{err}
|
||||||
|
@ -246,26 +246,34 @@ func (n redeemingTx) handleNotification() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n rescanFinished) handleNotification() error {
|
func (n rescanFinished) handleNotification(c *rpcClient) error {
|
||||||
AcctMgr.rm.MarkFinished(n)
|
AcctMgr.rm.MarkFinished(n)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n rescanProgress) handleNotification() error {
|
func (n rescanProgress) handleNotification(c *rpcClient) error {
|
||||||
AcctMgr.rm.MarkProgress(n)
|
AcctMgr.rm.MarkProgress(n)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type rpcClient struct {
|
type rpcClient struct {
|
||||||
*btcrpcclient.Client // client to btcd
|
*btcrpcclient.Client // client to btcd
|
||||||
enqueueNotification chan notification
|
|
||||||
dequeueNotification chan notification
|
mtx sync.Mutex
|
||||||
quit chan struct{}
|
blockStamp wallet.BlockStamp
|
||||||
wg sync.WaitGroup
|
|
||||||
|
enqueueNotification chan notification
|
||||||
|
dequeueNotification chan notification
|
||||||
|
|
||||||
|
quit chan struct{}
|
||||||
|
wg sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRPCClient(certs []byte) (*rpcClient, error) {
|
func newRPCClient(certs []byte) (*rpcClient, error) {
|
||||||
client := rpcClient{
|
client := rpcClient{
|
||||||
|
blockStamp: wallet.BlockStamp{
|
||||||
|
Height: int32(btcutil.BlockHeightUnknown),
|
||||||
|
},
|
||||||
enqueueNotification: make(chan notification),
|
enqueueNotification: make(chan notification),
|
||||||
dequeueNotification: make(chan notification),
|
dequeueNotification: make(chan notification),
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
|
@ -408,7 +416,7 @@ out:
|
||||||
|
|
||||||
func (c *rpcClient) handleNotifications() {
|
func (c *rpcClient) handleNotifications() {
|
||||||
for n := range c.dequeueNotification {
|
for n := range c.dequeueNotification {
|
||||||
err := n.handleNotification()
|
err := n.handleNotification(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch e := err.(type) {
|
switch e := err.(type) {
|
||||||
case InvalidNotificationError:
|
case InvalidNotificationError:
|
||||||
|
@ -421,6 +429,30 @@ func (c *rpcClient) handleNotifications() {
|
||||||
c.wg.Done()
|
c.wg.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlockStamp returns (as a blockstamp) the height and hash of the last seen
|
||||||
|
// block from the RPC client. If no blocks have been seen (the height is -1),
|
||||||
|
// the chain server is queried for the block and the result is saved for future
|
||||||
|
// calls, or an error is returned if the RPC is unsuccessful.
|
||||||
|
func (c *rpcClient) BlockStamp() (wallet.BlockStamp, error) {
|
||||||
|
c.mtx.Lock()
|
||||||
|
defer c.mtx.Unlock()
|
||||||
|
|
||||||
|
if c.blockStamp.Height != int32(btcutil.BlockHeightUnknown) {
|
||||||
|
return c.blockStamp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
hash, height, err := c.GetBestBlock()
|
||||||
|
if err != nil {
|
||||||
|
return wallet.BlockStamp{}, err
|
||||||
|
}
|
||||||
|
bs := wallet.BlockStamp{
|
||||||
|
Hash: *hash,
|
||||||
|
Height: height,
|
||||||
|
}
|
||||||
|
c.blockStamp = bs
|
||||||
|
return bs, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Handshake first checks that the websocket connection between btcwallet and
|
// Handshake first checks that the websocket connection between btcwallet and
|
||||||
// btcd is valid, that is, that there are no mismatching settings between
|
// btcd is valid, that is, that there are no mismatching settings between
|
||||||
// the two processes (such as running on different Bitcoin networks). If the
|
// the two processes (such as running on different Bitcoin networks). If the
|
||||||
|
@ -448,9 +480,9 @@ func (c *rpcClient) Handshake() error {
|
||||||
// saved block hash, assume that this btcd instance is not yet
|
// saved block hash, assume that this btcd instance is not yet
|
||||||
// synced up to a previous btcd that was last used with this
|
// synced up to a previous btcd that was last used with this
|
||||||
// wallet.
|
// wallet.
|
||||||
bs, err := GetCurBlock()
|
bs, err := c.BlockStamp()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot get best block: %v", err)
|
return err
|
||||||
}
|
}
|
||||||
if server != nil {
|
if server != nil {
|
||||||
server.NotifyNewBlockChainHeight(&bs)
|
server.NotifyNewBlockChainHeight(&bs)
|
||||||
|
|
124
rpcserver.go
124
rpcserver.go
|
@ -398,9 +398,9 @@ func (s *rpcServer) Stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disconnect the connected chain server, if any.
|
// Disconnect the connected chain server, if any.
|
||||||
client, err := accessClient()
|
rpcc, err := accessClient()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
client.Stop()
|
rpcc.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the account manager and finish all pending account file writes.
|
// Stop the account manager and finish all pending account file writes.
|
||||||
|
@ -535,9 +535,9 @@ func (s *rpcServer) postPassthrough(w http.ResponseWriter, request rawRequest) {
|
||||||
// request's ID.
|
// request's ID.
|
||||||
func passthrough(request rawRequest) []byte {
|
func passthrough(request rawRequest) []byte {
|
||||||
var res json.RawMessage
|
var res json.RawMessage
|
||||||
client, err := accessClient()
|
rpcc, err := accessClient()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
res, err = client.RawRequest(request.Method, request.Params)
|
res, err = rpcc.RawRequest(request.Method, request.Params)
|
||||||
}
|
}
|
||||||
var jsonErr *btcjson.Error
|
var jsonErr *btcjson.Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -878,9 +878,9 @@ func (s *rpcServer) PostClientRPC(w http.ResponseWriter, r *http.Request) {
|
||||||
// current connection status of btcwallet to btcd.
|
// current connection status of btcwallet to btcd.
|
||||||
func (s *rpcServer) NotifyConnectionStatus(wsc *websocketClient) {
|
func (s *rpcServer) NotifyConnectionStatus(wsc *websocketClient) {
|
||||||
connected := false
|
connected := false
|
||||||
client, err := accessClient()
|
rpcc, err := accessClient()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
connected = !client.Disconnected()
|
connected = !rpcc.Disconnected()
|
||||||
}
|
}
|
||||||
ntfn := btcws.NewBtcdConnectedNtfn(connected)
|
ntfn := btcws.NewBtcdConnectedNtfn(connected)
|
||||||
mntfn, err := ntfn.MarshalJSON()
|
mntfn, err := ntfn.MarshalJSON()
|
||||||
|
@ -1287,7 +1287,7 @@ func GetBalance(icmd btcjson.Cmd) (interface{}, error) {
|
||||||
if err == ErrNotFound {
|
if err == ErrNotFound {
|
||||||
return nil, btcjson.ErrWalletInvalidAccountName
|
return nil, btcjson.ErrWalletInvalidAccountName
|
||||||
}
|
}
|
||||||
return balance, err
|
return balance.ToUnit(btcutil.AmountBTC), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetInfo handles a getinfo request by returning the a structure containing
|
// GetInfo handles a getinfo request by returning the a structure containing
|
||||||
|
@ -1296,22 +1296,25 @@ func GetBalance(icmd btcjson.Cmd) (interface{}, error) {
|
||||||
func GetInfo(icmd btcjson.Cmd) (interface{}, error) {
|
func GetInfo(icmd btcjson.Cmd) (interface{}, error) {
|
||||||
// Call down to btcd for all of the information in this command known
|
// Call down to btcd for all of the information in this command known
|
||||||
// by them.
|
// by them.
|
||||||
client, err := accessClient()
|
rpcc, err := accessClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
info, err := client.GetInfo()
|
info, err := rpcc.GetInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
balance := float64(0.0)
|
var balance btcutil.Amount
|
||||||
accounts := AcctMgr.ListAccounts(1)
|
accounts, err := AcctMgr.ListAccounts(1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
for _, v := range accounts {
|
for _, v := range accounts {
|
||||||
balance += v
|
balance += v
|
||||||
}
|
}
|
||||||
info.WalletVersion = int32(wallet.VersCurrent.Uint32())
|
info.WalletVersion = int32(wallet.VersCurrent.Uint32())
|
||||||
info.Balance = balance
|
info.Balance = balance.ToUnit(btcutil.AmountBTC)
|
||||||
// Keypool times are not tracked. set to current time.
|
// Keypool times are not tracked. set to current time.
|
||||||
info.KeypoolOldest = time.Now().Unix()
|
info.KeypoolOldest = time.Now().Unix()
|
||||||
info.KeypoolSize = int32(cfg.KeypoolSize)
|
info.KeypoolSize = int32(cfg.KeypoolSize)
|
||||||
|
@ -1406,7 +1409,8 @@ func GetAddressBalance(icmd btcjson.Cmd) (interface{}, error) {
|
||||||
return nil, ErrAddressNotInWallet
|
return nil, ErrAddressNotInWallet
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.CalculateAddressBalance(addr, int(cmd.Minconf)), nil
|
bal, err := a.CalculateAddressBalance(addr, int(cmd.Minconf))
|
||||||
|
return bal.ToUnit(btcutil.AmountBTC), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUnconfirmedBalance handles a getunconfirmedbalance extension request
|
// GetUnconfirmedBalance handles a getunconfirmedbalance extension request
|
||||||
|
@ -1427,7 +1431,16 @@ func GetUnconfirmedBalance(icmd btcjson.Cmd) (interface{}, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.CalculateBalance(0) - a.CalculateBalance(1), nil
|
unconfirmed, err := a.CalculateBalance(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
confirmed, err := a.CalculateBalance(1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return (unconfirmed - confirmed).ToUnit(btcutil.AmountBTC), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImportPrivKey handles an importprivkey request by parsing
|
// ImportPrivKey handles an importprivkey request by parsing
|
||||||
|
@ -1502,8 +1515,15 @@ func (s *rpcServer) NotifyNewBlockChainHeight(bs *wallet.BlockStamp) {
|
||||||
// separate notifications for each account.
|
// separate notifications for each account.
|
||||||
func (s *rpcServer) NotifyBalances() {
|
func (s *rpcServer) NotifyBalances() {
|
||||||
for _, a := range AcctMgr.AllAccounts() {
|
for _, a := range AcctMgr.AllAccounts() {
|
||||||
balance := a.CalculateBalance(1)
|
balance, err := a.CalculateBalance(1)
|
||||||
unconfirmed := a.CalculateBalance(0) - balance
|
var unconfirmed btcutil.Amount
|
||||||
|
if err == nil {
|
||||||
|
unconfirmed, err = a.CalculateBalance(0)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
unconfirmed -= balance
|
||||||
s.NotifyWalletBalance(a.name, balance)
|
s.NotifyWalletBalance(a.name, balance)
|
||||||
s.NotifyWalletBalanceUnconfirmed(a.name, unconfirmed)
|
s.NotifyWalletBalanceUnconfirmed(a.name, unconfirmed)
|
||||||
}
|
}
|
||||||
|
@ -1580,7 +1600,8 @@ func GetReceivedByAccount(icmd btcjson.Cmd) (interface{}, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.TotalReceived(cmd.MinConf)
|
bal, err := a.TotalReceived(cmd.MinConf)
|
||||||
|
return bal.ToUnit(btcutil.AmountBTC), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransaction handles a gettransaction request by returning details about
|
// GetTransaction handles a gettransaction request by returning details about
|
||||||
|
@ -1602,7 +1623,11 @@ func GetTransaction(icmd btcjson.Cmd) (interface{}, error) {
|
||||||
return nil, btcjson.ErrNoTxInfo
|
return nil, btcjson.ErrNoTxInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
bs, err := GetCurBlock()
|
rpcc, err := accessClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
bs, err := rpcc.BlockStamp()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1719,7 +1744,7 @@ func ListAccounts(icmd btcjson.Cmd) (interface{}, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the map. This will be marshaled into a JSON object.
|
// Return the map. This will be marshaled into a JSON object.
|
||||||
return AcctMgr.ListAccounts(cmd.MinConf), nil
|
return AcctMgr.ListAccounts(cmd.MinConf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListLockUnspent handles a listlockunspent request by returning an slice of
|
// ListLockUnspent handles a listlockunspent request by returning an slice of
|
||||||
|
@ -1763,14 +1788,17 @@ func ListReceivedByAddress(icmd btcjson.Cmd) (interface{}, error) {
|
||||||
confirmations int32
|
confirmations int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intermediate data for all addresses.
|
rpcc, err := accessClient()
|
||||||
allAddrData := make(map[string]AddrData)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
bs, err := GetCurBlock()
|
}
|
||||||
|
bs, err := rpcc.BlockStamp()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Intermediate data for all addresses.
|
||||||
|
allAddrData := make(map[string]AddrData)
|
||||||
for _, account := range AcctMgr.AllAccounts() {
|
for _, account := range AcctMgr.AllAccounts() {
|
||||||
if cmd.IncludeEmpty {
|
if cmd.IncludeEmpty {
|
||||||
// Create an AddrData entry for each active address in the account.
|
// Create an AddrData entry for each active address in the account.
|
||||||
|
@ -1842,7 +1870,7 @@ func ListSinceBlock(icmd btcjson.Cmd) (interface{}, error) {
|
||||||
return nil, btcjson.ErrInternal
|
return nil, btcjson.ErrInternal
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := accessClient()
|
rpcc, err := accessClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1853,14 +1881,14 @@ func ListSinceBlock(icmd btcjson.Cmd) (interface{}, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, DeserializationError{err}
|
return nil, DeserializationError{err}
|
||||||
}
|
}
|
||||||
block, err := client.GetBlock(hash)
|
block, err := rpcc.GetBlock(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
height = int32(block.Height())
|
height = int32(block.Height())
|
||||||
}
|
}
|
||||||
|
|
||||||
bs, err := GetCurBlock()
|
bs, err := rpcc.BlockStamp()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1868,7 +1896,7 @@ func ListSinceBlock(icmd btcjson.Cmd) (interface{}, error) {
|
||||||
// For the result we need the block hash for the last block counted
|
// For the result we need the block hash for the last block counted
|
||||||
// in the blockchain due to confirmations. We send this off now so that
|
// in the blockchain due to confirmations. We send this off now so that
|
||||||
// it can arrive asynchronously while we figure out the rest.
|
// it can arrive asynchronously while we figure out the rest.
|
||||||
gbh := client.GetBlockHashAsync(int64(bs.Height) + 1 - int64(cmd.TargetConfirmations))
|
gbh := rpcc.GetBlockHashAsync(int64(bs.Height) + 1 - int64(cmd.TargetConfirmations))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -2038,7 +2066,7 @@ func LockUnspent(icmd btcjson.Cmd) (interface{}, error) {
|
||||||
func sendPairs(icmd btcjson.Cmd, account string, amounts map[string]btcutil.Amount,
|
func sendPairs(icmd btcjson.Cmd, account string, amounts map[string]btcutil.Amount,
|
||||||
minconf int) (interface{}, error) {
|
minconf int) (interface{}, error) {
|
||||||
|
|
||||||
client, err := accessClient()
|
rpcc, err := accessClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -2070,13 +2098,13 @@ func sendPairs(icmd btcjson.Cmd, account string, amounts map[string]btcutil.Amou
|
||||||
if err := AcctMgr.ds.FlushAccount(a); err != nil {
|
if err := AcctMgr.ds.FlushAccount(a); err != nil {
|
||||||
return nil, fmt.Errorf("Cannot write account: %v", err)
|
return nil, fmt.Errorf("Cannot write account: %v", err)
|
||||||
}
|
}
|
||||||
err := client.NotifyReceived([]btcutil.Address{createdTx.changeAddr})
|
err := rpcc.NotifyReceived([]btcutil.Address{createdTx.changeAddr})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
txSha, err := client.SendRawTransaction(createdTx.tx.MsgTx(), false)
|
txSha, err := rpcc.SendRawTransaction(createdTx.tx.MsgTx(), false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -2179,8 +2207,11 @@ func handleSendRawTxReply(icmd btcjson.Cmd, txSha *btcwire.ShaHash, a *Account,
|
||||||
AcctMgr.ds.ScheduleTxStoreWrite(a)
|
AcctMgr.ds.ScheduleTxStoreWrite(a)
|
||||||
|
|
||||||
// Notify websocket clients of the transaction.
|
// Notify websocket clients of the transaction.
|
||||||
bs, err := GetCurBlock()
|
rpcc, err := accessClient()
|
||||||
if err == nil {
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if bs, err := rpcc.BlockStamp(); err == nil {
|
||||||
ltr, err := debits.ToJSON(a.Name(), bs.Height, a.Net())
|
ltr, err := debits.ToJSON(a.Name(), bs.Height, a.Net())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Error adding sent tx history: %v", err)
|
log.Errorf("Error adding sent tx history: %v", err)
|
||||||
|
@ -2199,8 +2230,15 @@ func handleSendRawTxReply(icmd btcjson.Cmd, txSha *btcwire.ShaHash, a *Account,
|
||||||
|
|
||||||
// Notify websocket clients of account's new unconfirmed and
|
// Notify websocket clients of account's new unconfirmed and
|
||||||
// confirmed balance.
|
// confirmed balance.
|
||||||
confirmed := a.CalculateBalance(1)
|
confirmed, err := a.CalculateBalance(1)
|
||||||
unconfirmed := a.CalculateBalance(0) - confirmed
|
var unconfirmed btcutil.Amount
|
||||||
|
if err == nil {
|
||||||
|
unconfirmed, err = a.CalculateBalance(0)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
unconfirmed -= confirmed
|
||||||
server.NotifyWalletBalance(a.name, confirmed)
|
server.NotifyWalletBalance(a.name, confirmed)
|
||||||
server.NotifyWalletBalanceUnconfirmed(a.name, unconfirmed)
|
server.NotifyWalletBalanceUnconfirmed(a.name, unconfirmed)
|
||||||
|
|
||||||
|
@ -2394,7 +2432,7 @@ func SignRawTransaction(icmd btcjson.Cmd) (interface{}, error) {
|
||||||
}] = script
|
}] = script
|
||||||
}
|
}
|
||||||
|
|
||||||
var client *rpcClient
|
var rpcc *rpcClient
|
||||||
|
|
||||||
// Now we go and look for any inputs that we were not provided by
|
// Now we go and look for any inputs that we were not provided by
|
||||||
// querying btcd with getrawtransaction. We queue up a bunch of async
|
// querying btcd with getrawtransaction. We queue up a bunch of async
|
||||||
|
@ -2419,15 +2457,15 @@ func SignRawTransaction(icmd btcjson.Cmd) (interface{}, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Never heard of this one before, request it.
|
// Never heard of this one before, request it.
|
||||||
if client == nil {
|
if rpcc == nil {
|
||||||
client, err = accessClient()
|
rpcc, err = accessClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prevHash := &txIn.PreviousOutpoint.Hash
|
prevHash := &txIn.PreviousOutpoint.Hash
|
||||||
requested[txIn.PreviousOutpoint.Hash] = &pendingTx{
|
requested[txIn.PreviousOutpoint.Hash] = &pendingTx{
|
||||||
resp: client.GetRawTransactionAsync(prevHash),
|
resp: rpcc.GetRawTransactionAsync(prevHash),
|
||||||
inputs: []uint32{txIn.PreviousOutpoint.Index},
|
inputs: []uint32{txIn.PreviousOutpoint.Index},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2814,8 +2852,9 @@ func (s *rpcServer) NotifyWalletLockStateChange(account string, locked bool) {
|
||||||
|
|
||||||
// NotifyWalletBalance sends a confirmed account balance notification
|
// NotifyWalletBalance sends a confirmed account balance notification
|
||||||
// to all websocket clients.
|
// to all websocket clients.
|
||||||
func (s *rpcServer) NotifyWalletBalance(account string, balance float64) {
|
func (s *rpcServer) NotifyWalletBalance(account string, balance btcutil.Amount) {
|
||||||
ntfn := btcws.NewAccountBalanceNtfn(account, balance, true)
|
fbal := balance.ToUnit(btcutil.AmountBTC)
|
||||||
|
ntfn := btcws.NewAccountBalanceNtfn(account, fbal, true)
|
||||||
mntfn, err := ntfn.MarshalJSON()
|
mntfn, err := ntfn.MarshalJSON()
|
||||||
// If the marshal failed, it indicates that the btcws notification
|
// If the marshal failed, it indicates that the btcws notification
|
||||||
// struct contains a field with a type that is not marshalable.
|
// struct contains a field with a type that is not marshalable.
|
||||||
|
@ -2830,8 +2869,9 @@ func (s *rpcServer) NotifyWalletBalance(account string, balance float64) {
|
||||||
|
|
||||||
// NotifyWalletBalanceUnconfirmed sends a confirmed account balance
|
// NotifyWalletBalanceUnconfirmed sends a confirmed account balance
|
||||||
// notification to all websocket clients.
|
// notification to all websocket clients.
|
||||||
func (s *rpcServer) NotifyWalletBalanceUnconfirmed(account string, balance float64) {
|
func (s *rpcServer) NotifyWalletBalanceUnconfirmed(account string, balance btcutil.Amount) {
|
||||||
ntfn := btcws.NewAccountBalanceNtfn(account, balance, false)
|
fbal := balance.ToUnit(btcutil.AmountBTC)
|
||||||
|
ntfn := btcws.NewAccountBalanceNtfn(account, fbal, false)
|
||||||
mntfn, err := ntfn.MarshalJSON()
|
mntfn, err := ntfn.MarshalJSON()
|
||||||
// If the marshal failed, it indicates that the btcws notification
|
// If the marshal failed, it indicates that the btcws notification
|
||||||
// struct contains a field with a type that is not marshalable.
|
// struct contains a field with a type that is not marshalable.
|
||||||
|
|
Loading…
Reference in a new issue