diff --git a/account.go b/account.go index a589b3b..ed0a08e 100644 --- a/account.go +++ b/account.go @@ -28,6 +28,8 @@ import ( "sync" ) +var accounts = NewAccountStore() + // Account is a structure containing all the components for a // complete wallet. It contains the Armory-style wallet (to store // addresses and keys), and tx and utxo data stores, along with locks @@ -82,16 +84,16 @@ func (s *AccountStore) Rollback(height int32, hash *btcwire.ShaHash) { // with the passed chainheight and block hash was connected to the main // chain. This is used to remove transactions and utxos for each wallet // that occured on a chain no longer considered to be the main chain. -func (w *Account) Rollback(height int32, hash *btcwire.ShaHash) { - w.UtxoStore.Lock() - w.UtxoStore.dirty = w.UtxoStore.dirty || w.UtxoStore.s.Rollback(height, hash) - w.UtxoStore.Unlock() +func (a *Account) Rollback(height int32, hash *btcwire.ShaHash) { + a.UtxoStore.Lock() + a.UtxoStore.dirty = a.UtxoStore.dirty || a.UtxoStore.s.Rollback(height, hash) + a.UtxoStore.Unlock() - w.TxStore.Lock() - w.TxStore.dirty = w.TxStore.dirty || w.TxStore.s.Rollback(height, hash) - w.TxStore.Unlock() + a.TxStore.Lock() + a.TxStore.dirty = a.TxStore.dirty || a.TxStore.s.Rollback(height, hash) + a.TxStore.Unlock() - if err := w.writeDirtyToDisk(); err != nil { + if err := a.writeDirtyToDisk(); err != nil { log.Errorf("cannot sync dirty wallet: %v", err) } } @@ -105,7 +107,7 @@ func (w *Account) Rollback(height int32, hash *btcwire.ShaHash) { // 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 // include a UTXO. -func (w *Account) CalculateBalance(confirms int) float64 { +func (a *Account) CalculateBalance(confirms int) float64 { var bal uint64 // Measured in satoshi bs, err := GetCurBlock() @@ -113,47 +115,47 @@ func (w *Account) CalculateBalance(confirms int) float64 { return 0. } - w.UtxoStore.RLock() - for _, u := range w.UtxoStore.s { + a.UtxoStore.RLock() + for _, u := range a.UtxoStore.s { // Utxos not yet in blocks (height -1) should only be // added if confirmations is 0. if confirms == 0 || (u.Height != -1 && int(bs.Height-u.Height+1) >= confirms) { bal += u.Amt } } - w.UtxoStore.RUnlock() + a.UtxoStore.RUnlock() return float64(bal) / float64(btcutil.SatoshiPerBitcoin) } // Track requests btcd to send notifications of new transactions for // each address stored in a wallet and sets up a new reply handler for // these notifications. -func (w *Account) Track() { +func (a *Account) Track() { n := <-NewJSONID - w.mtx.Lock() - w.NewBlockTxSeqN = n - w.mtx.Unlock() + a.mtx.Lock() + a.NewBlockTxSeqN = n + a.mtx.Unlock() replyHandlers.Lock() - replyHandlers.m[n] = w.newBlockTxOutHandler + replyHandlers.m[n] = a.newBlockTxOutHandler replyHandlers.Unlock() - for _, addr := range w.GetActiveAddresses() { - w.ReqNewTxsForAddress(addr.Address) + for _, addr := range a.GetActiveAddresses() { + a.ReqNewTxsForAddress(addr.Address) } n = <-NewJSONID - w.mtx.Lock() - w.SpentOutpointSeqN = n - w.mtx.Unlock() + a.mtx.Lock() + a.SpentOutpointSeqN = n + a.mtx.Unlock() replyHandlers.Lock() - replyHandlers.m[n] = w.spentUtxoHandler + replyHandlers.m[n] = a.spentUtxoHandler replyHandlers.Unlock() - w.UtxoStore.RLock() - for _, utxo := range w.UtxoStore.s { - w.ReqSpentUtxoNtfn(utxo) + a.UtxoStore.RLock() + for _, utxo := range a.UtxoStore.s { + a.ReqSpentUtxoNtfn(utxo) } - w.UtxoStore.RUnlock() + a.UtxoStore.RUnlock() } // RescanToBestBlock requests btcd to rescan the blockchain for new @@ -161,22 +163,22 @@ func (w *Account) Track() { // btcwallet catch up to a long-running btcd process, as otherwise // it would have missed notifications as blocks are attached to the // main chain. -func (w *Account) RescanToBestBlock() { +func (a *Account) RescanToBestBlock() { beginBlock := int32(0) - if w.fullRescan { + if a.fullRescan { // Need to perform a complete rescan since the wallet creation // block. - beginBlock = w.CreatedAt() + beginBlock = a.CreatedAt() log.Debugf("Rescanning account '%v' for new transactions since block height %v", - w.name, beginBlock) + a.name, beginBlock) } else { // The last synced block height should be used the starting // point for block rescanning. Grab the block stamp here. - bs := w.SyncedWith() + bs := a.SyncedWith() log.Debugf("Rescanning account '%v' for new transactions since block height %v hash %v", - w.name, bs.Height, bs.Hash) + a.name, bs.Height, bs.Hash) // If we're synced with block x, must scan the blocks x+1 to best block. beginBlock = bs.Height + 1 @@ -184,7 +186,7 @@ func (w *Account) RescanToBestBlock() { n := <-NewJSONID cmd, err := btcws.NewRescanCmd(fmt.Sprintf("btcwallet(%v)", n), - beginBlock, w.ActivePaymentAddresses()) + beginBlock, a.ActivePaymentAddresses()) if err != nil { log.Errorf("cannot create rescan request: %v", err) return @@ -199,21 +201,21 @@ func (w *Account) RescanToBestBlock() { replyHandlers.m[n] = func(result interface{}, e *btcjson.Error) bool { // Rescan is compatible with new txs from connected block // notifications, so use that handler. - _ = w.newBlockTxOutHandler(result, e) + _ = a.newBlockTxOutHandler(result, e) if result != nil { // Notify frontends of new account balance. - confirmed := w.CalculateBalance(1) - unconfirmed := w.CalculateBalance(0) - confirmed - NotifyWalletBalance(frontendNotificationMaster, w.name, confirmed) - NotifyWalletBalanceUnconfirmed(frontendNotificationMaster, w.name, unconfirmed) + confirmed := a.CalculateBalance(1) + unconfirmed := a.CalculateBalance(0) - confirmed + NotifyWalletBalance(frontendNotificationMaster, a.name, confirmed) + NotifyWalletBalanceUnconfirmed(frontendNotificationMaster, a.name, unconfirmed) return false } if bs, err := GetCurBlock(); err == nil { - w.SetSyncedWith(&bs) - w.dirty = true - if err = w.writeDirtyToDisk(); err != nil { + a.SetSyncedWith(&bs) + a.dirty = true + if err = a.writeDirtyToDisk(); err != nil { log.Errorf("cannot sync dirty wallet: %v", err) } @@ -229,11 +231,11 @@ func (w *Account) RescanToBestBlock() { // SortedActivePaymentAddresses returns a slice of all active payment // addresses in an account. -func (w *Account) SortedActivePaymentAddresses() []string { - w.mtx.RLock() - defer w.mtx.RUnlock() +func (a *Account) SortedActivePaymentAddresses() []string { + a.mtx.RLock() + defer a.mtx.RUnlock() - infos := w.GetSortedActiveAddresses() + infos := a.GetSortedActiveAddresses() addrs := make([]string, len(infos)) for i, addr := range infos { @@ -245,11 +247,11 @@ func (w *Account) SortedActivePaymentAddresses() []string { // ActivePaymentAddresses returns a set of all active pubkey hashes // in an account. -func (w *Account) ActivePaymentAddresses() map[string]struct{} { - w.mtx.RLock() - defer w.mtx.RUnlock() +func (a *Account) ActivePaymentAddresses() map[string]struct{} { + a.mtx.RLock() + defer a.mtx.RUnlock() - infos := w.GetActiveAddresses() + infos := a.GetActiveAddresses() addrs := make(map[string]struct{}, len(infos)) for _, info := range infos { @@ -261,12 +263,12 @@ func (w *Account) ActivePaymentAddresses() map[string]struct{} { // ReqNewTxsForAddress sends a message to btcd to request tx updates // for addr for each new block that is added to the blockchain. -func (w *Account) ReqNewTxsForAddress(addr string) { +func (a *Account) ReqNewTxsForAddress(addr string) { log.Debugf("Requesting notifications of TXs sending to address %v", addr) - w.mtx.RLock() - n := w.NewBlockTxSeqN - w.mtx.RUnlock() + a.mtx.RLock() + n := a.NewBlockTxSeqN + a.mtx.RUnlock() cmd := btcws.NewNotifyNewTXsCmd(fmt.Sprintf("btcwallet(%d)", n), []string{addr}) @@ -280,13 +282,13 @@ func (w *Account) ReqNewTxsForAddress(addr string) { // ReqSpentUtxoNtfn sends a message to btcd to request updates for when // a stored UTXO has been spent. -func (w *Account) ReqSpentUtxoNtfn(u *tx.Utxo) { +func (a *Account) ReqSpentUtxoNtfn(u *tx.Utxo) { log.Debugf("Requesting spent UTXO notifications for Outpoint hash %s index %d", u.Out.Hash, u.Out.Index) - w.mtx.RLock() - n := w.SpentOutpointSeqN - w.mtx.RUnlock() + a.mtx.RLock() + n := a.SpentOutpointSeqN + a.mtx.RUnlock() cmd := btcws.NewNotifySpentCmd(fmt.Sprintf("btcwallet(%d)", n), (*btcwire.OutPoint)(&u.Out)) @@ -301,7 +303,7 @@ func (w *Account) ReqSpentUtxoNtfn(u *tx.Utxo) { // spentUtxoHandler is the handler function for btcd spent UTXO notifications // resulting from transactions in newly-attached blocks. -func (w *Account) spentUtxoHandler(result interface{}, e *btcjson.Error) bool { +func (a *Account) spentUtxoHandler(result interface{}, e *btcjson.Error) bool { if e != nil { log.Errorf("Spent UTXO Handler: Error %d received from btcd: %s", e.Code, e.Message) @@ -334,7 +336,7 @@ func (w *Account) spentUtxoHandler(result interface{}, e *btcjson.Error) bool { // newBlockTxOutHandler is the handler function for btcd transaction // notifications resulting from newly-attached blocks. -func (w *Account) newBlockTxOutHandler(result interface{}, e *btcjson.Error) bool { +func (a *Account) newBlockTxOutHandler(result interface{}, e *btcjson.Error) bool { if e != nil { log.Errorf("Tx Handler: Error %d received from btcd: %s", e.Code, e.Message) @@ -425,37 +427,37 @@ func (w *Account) newBlockTxOutHandler(result interface{}, e *btcjson.Error) boo copy(t.SenderAddr[:], senderHash) copy(t.ReceiverAddr[:], receiverHash) - w.TxStore.Lock() - txs := w.TxStore.s - w.TxStore.s = append(txs, t) - w.TxStore.dirty = true - w.TxStore.Unlock() + a.TxStore.Lock() + txs := a.TxStore.s + a.TxStore.s = append(txs, t) + a.TxStore.dirty = true + a.TxStore.Unlock() // Add to UtxoStore if unspent. if !spent { // First, iterate through all stored utxos. If an unconfirmed utxo // (not present in a block) has the same outpoint as this utxo, // update the block height and hash. - w.UtxoStore.RLock() - for _, u := range w.UtxoStore.s { + a.UtxoStore.RLock() + for _, u := range a.UtxoStore.s { if bytes.Equal(u.Out.Hash[:], txhash[:]) && u.Out.Index == uint32(index) { // Found a either a duplicate, or a change UTXO. If not change, // ignore it. - w.UtxoStore.RUnlock() + a.UtxoStore.RUnlock() if u.Height != -1 { return false } - w.UtxoStore.Lock() + a.UtxoStore.Lock() copy(u.BlockHash[:], blockhash[:]) u.Height = int32(height) - w.UtxoStore.dirty = true - w.UtxoStore.Unlock() + a.UtxoStore.dirty = true + a.UtxoStore.Unlock() return false } } - w.UtxoStore.RUnlock() + a.UtxoStore.RUnlock() // After iterating through all UTXOs, it was not a duplicate or // change UTXO appearing in a block. Append a new Utxo to the end. @@ -469,10 +471,10 @@ func (w *Account) newBlockTxOutHandler(result interface{}, e *btcjson.Error) boo u.Out.Index = uint32(index) copy(u.AddrHash[:], receiverHash) copy(u.BlockHash[:], blockhash[:]) - w.UtxoStore.Lock() - w.UtxoStore.s = append(w.UtxoStore.s, u) - w.UtxoStore.dirty = true - w.UtxoStore.Unlock() + a.UtxoStore.Lock() + a.UtxoStore.s = append(a.UtxoStore.s, u) + a.UtxoStore.dirty = true + a.UtxoStore.Unlock() // If this notification came from mempool (TODO: currently // unimplemented) notify the new unconfirmed balance immediately. diff --git a/cmd.go b/cmd.go index fb485c9..b506f66 100644 --- a/cmd.go +++ b/cmd.go @@ -56,8 +56,6 @@ var ( Height: int32(btcutil.BlockHeightUnknown), }, } - - wallets = NewAccountStore() ) // walletdir returns the directory path which holds the wallet, utxo, @@ -73,13 +71,13 @@ func walletdir(cfg *config, account string) string { return filepath.Join(cfg.DataDir, wname) } -// OpenWallet opens a wallet described by account in the data +// OpenAccount opens an account described by account in the data // directory specified by cfg. If the wallet does not exist, ErrNoWallet // is returned as an error. // // Wallets opened from this function are not set to track against a // btcd connection. -func OpenWallet(cfg *config, account string) (*Account, error) { +func OpenAccount(cfg *config, account string) (*Account, error) { wdir := walletdir(cfg, account) fi, err := os.Stat(wdir) if err != nil { @@ -117,7 +115,7 @@ func OpenWallet(cfg *config, account string) (*Account, error) { return nil, fmt.Errorf("cannot read wallet: %s", err) } - w := &Account{ + a := &Account{ Wallet: wlt, name: account, } @@ -127,30 +125,30 @@ func OpenWallet(cfg *config, account string) (*Account, error) { var utxos tx.UtxoStore if utxofile, err = os.Open(utxofilepath); err != nil { log.Errorf("cannot open utxo file: %s", err) - return w, ErrNoUtxos + return a, ErrNoUtxos } defer utxofile.Close() if _, err = utxos.ReadFrom(utxofile); err != nil { log.Errorf("cannot read utxo file: %s", err) - return w, ErrNoUtxos + return a, ErrNoUtxos } - w.UtxoStore.s = utxos + a.UtxoStore.s = utxos // Read tx file. If this fails, return a ErrNoTxs error and let // the caller decide if a rescan is necessary. if txfile, err = os.Open(txfilepath); err != nil { log.Errorf("cannot open tx file: %s", err) - return w, ErrNoTxs + return a, ErrNoTxs } defer txfile.Close() var txs tx.TxStore if _, err = txs.ReadFrom(txfile); err != nil { log.Errorf("cannot read tx file: %s", err) - return w, ErrNoTxs + return a, ErrNoTxs } - w.TxStore.s = txs + a.TxStore.s = txs - return w, nil + return a, nil } // GetCurBlock returns the blockchain height and SHA hash of the most @@ -286,36 +284,36 @@ func main() { loggers = setLogLevel(cfg.DebugLevel) } - // Open default wallet - w, err := OpenWallet(cfg, "") + // Open default account + a, err := OpenAccount(cfg, "") switch err { case ErrNoTxs: // Do nothing special for now. This will be implemented when // the tx history file is properly written. - wallets.Lock() - wallets.m[""] = w - wallets.Unlock() + accounts.Lock() + accounts.m[""] = a + accounts.Unlock() case ErrNoUtxos: // Add wallet, but mark wallet as needing a full rescan since // the wallet creation block. This will take place when btcd // connects. - wallets.Lock() - wallets.m[""] = w - wallets.Unlock() - w.fullRescan = true + accounts.Lock() + accounts.m[""] = a + accounts.Unlock() + a.fullRescan = true case nil: - wallets.Lock() - wallets.m[""] = w - wallets.Unlock() + accounts.Lock() + accounts.m[""] = a + accounts.Unlock() default: log.Errorf("cannot open wallet: %v", err) } - // Start wallet disk syncer goroutine. - go DirtyWalletSyncer() + // Start account disk syncer goroutine. + go DirtyAccountSyncer() go func() { // Start HTTP server to listen and send messages to frontend and btcd diff --git a/cmdmgr.go b/cmdmgr.go index 0ea3b74..1ea9f16 100644 --- a/cmdmgr.go +++ b/cmdmgr.go @@ -168,7 +168,7 @@ func GetAddressesByAccount(frontend chan []byte, icmd btcjson.Cmd) { } // Check that the account specified in the request exists. - w, ok := wallets.m[cmd.Account] + a, ok := accounts.m[cmd.Account] if !ok { ReplyError(frontend, cmd.Id(), &btcjson.ErrWalletInvalidAccountName) @@ -176,7 +176,7 @@ func GetAddressesByAccount(frontend chan []byte, icmd btcjson.Cmd) { } // Reply with sorted active payment addresses. - ReplySuccess(frontend, cmd.Id(), w.SortedActivePaymentAddresses()) + ReplySuccess(frontend, cmd.Id(), a.SortedActivePaymentAddresses()) } // GetBalance replies to a getbalance request with the balance for an @@ -191,7 +191,7 @@ func GetBalance(frontend chan []byte, icmd btcjson.Cmd) { } // Check that the account specified in the request exists. - w, ok := wallets.m[cmd.Account] + a, ok := accounts.m[cmd.Account] if !ok { ReplyError(frontend, cmd.Id(), &btcjson.ErrWalletInvalidAccountName) @@ -199,7 +199,7 @@ func GetBalance(frontend chan []byte, icmd btcjson.Cmd) { } // Reply with calculated balance. - ReplySuccess(frontend, cmd.Id(), w.CalculateBalance(cmd.MinConf)) + ReplySuccess(frontend, cmd.Id(), a.CalculateBalance(cmd.MinConf)) } // GetBalances replies to a getbalances extension request by notifying @@ -208,17 +208,17 @@ func GetBalances(frontend chan []byte, cmd btcjson.Cmd) { NotifyBalances(frontend) } -// NotifyBalances notifies an attached wallet of the current confirmed +// NotifyBalances notifies an attached frontend of the current confirmed // and unconfirmed account balances. // // TODO(jrick): Switch this to return a JSON object (map) of all accounts // and their balances, instead of separate notifications for each account. -func NotifyBalances(reply chan []byte) { - for _, w := range wallets.m { - balance := w.CalculateBalance(1) - unconfirmed := w.CalculateBalance(0) - balance - NotifyWalletBalance(reply, w.name, balance) - NotifyWalletBalanceUnconfirmed(reply, w.name, unconfirmed) +func NotifyBalances(frontend chan []byte) { + for _, a := range accounts.m { + balance := a.CalculateBalance(1) + unconfirmed := a.CalculateBalance(0) - balance + NotifyWalletBalance(frontend, a.name, balance) + NotifyWalletBalanceUnconfirmed(frontend, a.name, unconfirmed) } } @@ -234,7 +234,7 @@ func GetNewAddress(frontend chan []byte, icmd btcjson.Cmd) { } // Check that the account specified in the request exists. - w, ok := wallets.m[cmd.Account] + a, ok := accounts.m[cmd.Account] if !ok { ReplyError(frontend, cmd.Id(), &btcjson.ErrWalletInvalidAccountName) @@ -242,7 +242,7 @@ func GetNewAddress(frontend chan []byte, icmd btcjson.Cmd) { } // Get next address from wallet. - addr, err := w.NextUnusedAddress() + addr, err := a.NextUnusedAddress() if err != nil { // TODO(jrick): generate new addresses if the address pool is // empty. @@ -253,13 +253,13 @@ func GetNewAddress(frontend chan []byte, icmd btcjson.Cmd) { } // Write updated wallet to disk. - w.dirty = true - if err = w.writeDirtyToDisk(); err != nil { + a.dirty = true + if err = a.writeDirtyToDisk(); err != nil { log.Errorf("cannot sync dirty wallet: %v", err) } // Request updates from btcd for new transactions sent to this address. - w.ReqNewTxsForAddress(addr) + a.ReqNewTxsForAddress(addr) // Reply with the new payment address string. ReplySuccess(frontend, cmd.Id(), addr) @@ -277,8 +277,8 @@ func ListAccounts(frontend chan []byte, icmd btcjson.Cmd) { // Create and fill a map of account names and their balances. pairs := make(map[string]float64) - for account, w := range wallets.m { - pairs[account] = w.CalculateBalance(cmd.MinConf) + for aname, a := range accounts.m { + pairs[aname] = a.CalculateBalance(cmd.MinConf) } // Reply with the map. This will be marshaled into a JSON object. @@ -317,7 +317,7 @@ func SendFrom(frontend chan []byte, icmd btcjson.Cmd) { } // Check that the account specified in the request exists. - w, ok := wallets.m[cmd.FromAccount] + a, ok := accounts.m[cmd.FromAccount] if !ok { ReplyError(frontend, cmd.Id(), &btcjson.ErrWalletInvalidAccountName) @@ -337,7 +337,7 @@ func SendFrom(frontend chan []byte, icmd btcjson.Cmd) { // Create transaction, replying with an error if the creation // was not successful. - createdTx, err := w.txToPairs(pairs, fee, cmd.MinConf) + createdTx, err := a.txToPairs(pairs, fee, cmd.MinConf) switch { case err == ErrNonPositiveAmount: e := &btcjson.Error{ @@ -363,11 +363,11 @@ func SendFrom(frontend chan []byte, icmd btcjson.Cmd) { // If a change address was added, mark wallet as dirty, sync to disk, // and Request updates for change address. if len(createdTx.changeAddr) != 0 { - w.dirty = true - if err := w.writeDirtyToDisk(); err != nil { + a.dirty = true + if err := a.writeDirtyToDisk(); err != nil { log.Errorf("cannot write dirty wallet: %v", err) } - w.ReqNewTxsForAddress(createdTx.changeAddr) + a.ReqNewTxsForAddress(createdTx.changeAddr) } // Create sendrawtransaction request with hexstring of the raw tx. @@ -387,7 +387,7 @@ func SendFrom(frontend chan []byte, icmd btcjson.Cmd) { // Set up a reply handler to respond to the btcd reply. replyHandlers.Lock() replyHandlers.m[n] = func(result interface{}, err *btcjson.Error) bool { - return handleSendRawTxReply(frontend, cmd, result, err, w, + return handleSendRawTxReply(frontend, cmd, result, err, a, createdTx) } replyHandlers.Unlock() @@ -420,7 +420,7 @@ func SendMany(frontend chan []byte, icmd btcjson.Cmd) { } // Check that the account specified in the request exists. - w, ok := wallets.m[cmd.FromAccount] + a, ok := accounts.m[cmd.FromAccount] if !ok { ReplyError(frontend, cmd.Id(), &btcjson.ErrWalletInvalidAccountName) @@ -435,7 +435,7 @@ func SendMany(frontend chan []byte, icmd btcjson.Cmd) { // Create transaction, replying with an error if the creation // was not successful. - createdTx, err := w.txToPairs(cmd.Amounts, fee, cmd.MinConf) + createdTx, err := a.txToPairs(cmd.Amounts, fee, cmd.MinConf) switch { case err == ErrNonPositiveAmount: e := &btcjson.Error{ @@ -461,11 +461,11 @@ func SendMany(frontend chan []byte, icmd btcjson.Cmd) { // If a change address was added, mark wallet as dirty, sync to disk, // and request updates for change address. if len(createdTx.changeAddr) != 0 { - w.dirty = true - if err := w.writeDirtyToDisk(); err != nil { + a.dirty = true + if err := a.writeDirtyToDisk(); err != nil { log.Errorf("cannot write dirty wallet: %v", err) } - w.ReqNewTxsForAddress(createdTx.changeAddr) + a.ReqNewTxsForAddress(createdTx.changeAddr) } // Create sendrawtransaction request with hexstring of the raw tx. @@ -485,7 +485,7 @@ func SendMany(frontend chan []byte, icmd btcjson.Cmd) { // Set up a reply handler to respond to the btcd reply. replyHandlers.Lock() replyHandlers.m[n] = func(result interface{}, err *btcjson.Error) bool { - return handleSendRawTxReply(frontend, cmd, result, err, w, + return handleSendRawTxReply(frontend, cmd, result, err, a, createdTx) } replyHandlers.Unlock() @@ -495,7 +495,7 @@ func SendMany(frontend chan []byte, icmd btcjson.Cmd) { } func handleSendRawTxReply(frontend chan []byte, icmd btcjson.Cmd, - result interface{}, err *btcjson.Error, w *Account, + result interface{}, err *btcjson.Error, a *Account, txInfo *CreatedTx) bool { if err != nil { @@ -504,31 +504,31 @@ func handleSendRawTxReply(frontend chan []byte, icmd btcjson.Cmd, } // Remove previous unspent outputs now spent by the tx. - w.UtxoStore.Lock() - modified := w.UtxoStore.s.Remove(txInfo.inputs) + a.UtxoStore.Lock() + modified := a.UtxoStore.s.Remove(txInfo.inputs) // Add unconfirmed change utxo (if any) to UtxoStore. if txInfo.changeUtxo != nil { - w.UtxoStore.s = append(w.UtxoStore.s, txInfo.changeUtxo) - w.ReqSpentUtxoNtfn(txInfo.changeUtxo) + a.UtxoStore.s = append(a.UtxoStore.s, txInfo.changeUtxo) + a.ReqSpentUtxoNtfn(txInfo.changeUtxo) modified = true } if modified { - w.UtxoStore.dirty = true - w.UtxoStore.Unlock() - if err := w.writeDirtyToDisk(); err != nil { + a.UtxoStore.dirty = true + a.UtxoStore.Unlock() + if err := a.writeDirtyToDisk(); err != nil { log.Errorf("cannot sync dirty wallet: %v", err) } // Notify all frontends of account's new unconfirmed and // confirmed balance. - confirmed := w.CalculateBalance(1) - unconfirmed := w.CalculateBalance(0) - confirmed - NotifyWalletBalance(frontendNotificationMaster, w.name, confirmed) - NotifyWalletBalanceUnconfirmed(frontendNotificationMaster, w.name, unconfirmed) + confirmed := a.CalculateBalance(1) + unconfirmed := a.CalculateBalance(0) - confirmed + NotifyWalletBalance(frontendNotificationMaster, a.name, confirmed) + NotifyWalletBalanceUnconfirmed(frontendNotificationMaster, a.name, unconfirmed) } else { - w.UtxoStore.Unlock() + a.UtxoStore.Unlock() } // btcd cannot be trusted to successfully relay the tx to the @@ -613,11 +613,11 @@ func CreateEncryptedWallet(frontend chan []byte, icmd btcjson.Cmd) { // Grab the account map lock and defer the unlock. If an // account is successfully created, it will be added to the // map while the lock is held. - wallets.Lock() - defer wallets.Unlock() + accounts.Lock() + defer accounts.Unlock() // Does this wallet already exist? - if _, ok = wallets.m[cmd.Account]; ok { + if _, ok = accounts.m[cmd.Account]; ok { ReplyError(frontend, cmd.Id(), &btcjson.ErrWalletInvalidAccountName) return @@ -653,7 +653,7 @@ func CreateEncryptedWallet(frontend chan []byte, icmd btcjson.Cmd) { // Create new account with the wallet. A new JSON ID is set for // transaction notifications. - bw := &Account{ + a := &Account{ Wallet: wlt, name: cmd.Account, dirty: true, @@ -663,15 +663,15 @@ func CreateEncryptedWallet(frontend chan []byte, icmd btcjson.Cmd) { // Begin tracking account against a connected btcd. // // TODO(jrick): this should *only* happen if btcd is connected. - bw.Track() + a.Track() // Save the account in the global account map. The mutex is // already held at this point, and will be unlocked when this // func returns. - wallets.m[cmd.Account] = bw + accounts.m[cmd.Account] = a // Write new wallet to disk. - if err := bw.writeDirtyToDisk(); err != nil { + if err := a.writeDirtyToDisk(); err != nil { log.Errorf("cannot sync dirty wallet: %v", err) } @@ -695,7 +695,7 @@ func WalletIsLocked(frontend chan []byte, icmd btcjson.Cmd) { } // Check that the account specified in the request exists. - w, ok := wallets.m[cmd.Account] + a, ok := accounts.m[cmd.Account] if !ok { ReplyError(frontend, cmd.Id(), &btcjson.ErrWalletInvalidAccountName) @@ -703,7 +703,7 @@ func WalletIsLocked(frontend chan []byte, icmd btcjson.Cmd) { } // Reply with true for a locked wallet, and false for unlocked. - ReplySuccess(frontend, cmd.Id(), w.IsLocked()) + ReplySuccess(frontend, cmd.Id(), a.IsLocked()) } // WalletLock responds to walletlock request by locking the wallet, @@ -713,8 +713,8 @@ func WalletIsLocked(frontend chan []byte, icmd btcjson.Cmd) { // with this. Lock all the wallets, like if all accounts are locked // for one bitcoind wallet? func WalletLock(frontend chan []byte, icmd btcjson.Cmd) { - if w, ok := wallets.m[""]; ok { - if err := w.Lock(); err != nil { + if a, ok := accounts.m[""]; ok { + if err := a.Lock(); err != nil { ReplyError(frontend, icmd.Id(), &btcjson.ErrWalletWrongEncState) return @@ -737,8 +737,8 @@ func WalletPassphrase(frontend chan []byte, icmd btcjson.Cmd) { return } - if w, ok := wallets.m[""]; ok { - if err := w.Unlock([]byte(cmd.Passphrase)); err != nil { + if a, ok := accounts.m[""]; ok { + if err := a.Unlock([]byte(cmd.Passphrase)); err != nil { ReplyError(frontend, cmd.Id(), &btcjson.ErrWalletPassphraseIncorrect) return @@ -747,7 +747,7 @@ func WalletPassphrase(frontend chan []byte, icmd btcjson.Cmd) { NotifyWalletLockStateChange("", false) go func() { time.Sleep(time.Second * time.Duration(int64(cmd.Timeout))) - w.Lock() + a.Lock() NotifyWalletLockStateChange("", true) }() } diff --git a/disksync.go b/disksync.go index 9171ae3..186f37e 100644 --- a/disksync.go +++ b/disksync.go @@ -25,8 +25,8 @@ import ( ) var ( - // dirtyWallets holds a set of wallets that include dirty components. - dirtyWallets = struct { + // dirtyAccounts holds a set of accounts that include dirty components. + dirtyAccounts = struct { sync.Mutex m map[*Account]bool }{ @@ -34,29 +34,29 @@ var ( } ) -// DirtyWalletSyncer synces dirty wallets for cases where the updated -// information was not required to be immediately written to disk. Wallets -// may be added to dirtyWallets and will be checked and processed every 10 +// DirtyAccountSyncer synces dirty accounts for cases where the updated +// information was not required to be immediately written to disk. Accounts +// may be added to dirtyAccounts and will be checked and processed every 10 // seconds by this function. // // This never returns and is meant to be called from a goroutine. -func DirtyWalletSyncer() { +func DirtyAccountSyncer() { ticker := time.Tick(10 * time.Second) for { select { case <-ticker: - dirtyWallets.Lock() - for w := range dirtyWallets.m { - log.Debugf("Syncing wallet '%v' to disk", - w.Wallet.Name()) - if err := w.writeDirtyToDisk(); err != nil { + dirtyAccounts.Lock() + for a := range dirtyAccounts.m { + log.Debugf("Syncing account '%v' to disk", + a.Wallet.Name()) + if err := a.writeDirtyToDisk(); err != nil { log.Errorf("cannot sync dirty wallet: %v", err) } else { - delete(dirtyWallets.m, w) + delete(dirtyAccounts.m, a) } } - dirtyWallets.Unlock() + dirtyAccounts.Unlock() } } } diff --git a/sockets.go b/sockets.go index ed50f6f..cca99a6 100644 --- a/sockets.go +++ b/sockets.go @@ -397,23 +397,23 @@ func NtfnBlockConnected(n btcws.Notification) { // // TODO(jrick): send frontend tx notifications once that's // implemented. - for _, w := range wallets.m { + for _, a := range accounts.m { // Mark wallet as being synced with the new blockstamp. - w.mtx.Lock() - w.Wallet.SetSyncedWith(bs) - w.mtx.Unlock() + a.mtx.Lock() + a.Wallet.SetSyncedWith(bs) + a.mtx.Unlock() // The UTXO store will be dirty if it was modified // from a tx notification. - if w.UtxoStore.dirty { + if a.UtxoStore.dirty { // Notify all frontends of account's new unconfirmed // and confirmed balance. - confirmed := w.CalculateBalance(1) - unconfirmed := w.CalculateBalance(0) - confirmed + confirmed := a.CalculateBalance(1) + unconfirmed := a.CalculateBalance(0) - confirmed NotifyWalletBalance(frontendNotificationMaster, - w.name, confirmed) + a.name, confirmed) NotifyWalletBalanceUnconfirmed(frontendNotificationMaster, - w.name, unconfirmed) + a.name, unconfirmed) } // The account is intentionaly not immediately synced to disk. @@ -426,10 +426,10 @@ func NtfnBlockConnected(n btcws.Notification) { // // Instead, the wallet is queued to be written to disk at the // next scheduled disk sync. - w.dirty = true - dirtyWallets.Lock() - dirtyWallets.m[w] = true - dirtyWallets.Unlock() + a.dirty = true + dirtyAccounts.Lock() + dirtyAccounts.m[a] = true + dirtyAccounts.Unlock() } // Notify frontends of new blockchain height. @@ -455,7 +455,7 @@ func NtfnBlockDisconnected(n btcws.Notification) { // Rollback Utxo and Tx data stores. go func() { - wallets.Rollback(bdn.Height, hash) + accounts.Rollback(bdn.Height, hash) }() // Notify frontends of new blockchain height. @@ -619,13 +619,13 @@ func BtcdHandshake(ws *websocket.Conn) { // since last connection. If so, rollback and rescan to // catch up. - for _, w := range wallets.m { - w.RescanToBestBlock() + for _, a := range accounts.m { + a.RescanToBestBlock() } // Begin tracking wallets against this btcd instance. - for _, w := range wallets.m { - w.Track() + for _, a := range accounts.m { + a.Track() } // (Re)send any unmined transactions to btcd in case of a btcd restart.