Fix build for new btcws notifications.

This commit is contained in:
Josh Rickmar 2013-12-13 11:00:31 -05:00
parent d4e756bc23
commit 75d3a77106
3 changed files with 94 additions and 95 deletions

View file

@ -93,7 +93,11 @@ func (a *Account) Lock() error {
a.mtx.Lock() a.mtx.Lock()
defer a.mtx.Unlock() defer a.mtx.Unlock()
return a.Wallet.Lock() err := a.Wallet.Lock()
if err == nil {
NotifyWalletLockStateChange(a.Name(), true)
}
return err
} }
// Unlock unlocks the underlying wallet for an account. // Unlock unlocks the underlying wallet for an account.
@ -101,6 +105,10 @@ func (a *Account) Unlock(passphrase []byte, timeout int64) error {
a.mtx.Lock() a.mtx.Lock()
defer a.mtx.Unlock() defer a.mtx.Unlock()
err := a.Wallet.Unlock(passphrase)
if err == nil {
NotifyWalletLockStateChange(a.Name(), false)
}
return a.Wallet.Unlock(passphrase) return a.Wallet.Unlock(passphrase)
} }

View file

@ -1055,7 +1055,6 @@ func WalletPassphrase(frontend chan []byte, icmd btcjson.Cmd) {
case nil: case nil:
ReplySuccess(frontend, cmd.Id(), nil) ReplySuccess(frontend, cmd.Id(), nil)
NotifyWalletLockStateChange("", false)
go func(timeout int64) { go func(timeout int64) {
time.Sleep(time.Second * time.Duration(timeout)) time.Sleep(time.Second * time.Duration(timeout))
_ = a.Lock() _ = a.Lock()
@ -1083,46 +1082,25 @@ type AccountNtfn struct {
// NotifyWalletLockStateChange sends a notification to all frontends // NotifyWalletLockStateChange sends a notification to all frontends
// that the wallet has just been locked or unlocked. // that the wallet has just been locked or unlocked.
func NotifyWalletLockStateChange(account string, locked bool) { func NotifyWalletLockStateChange(account string, locked bool) {
var id interface{} = "btcwallet:newwalletlockstate" ntfn := btcws.NewWalletLockStateNtfn(account, locked)
m := btcjson.Reply{ mntfn, _ := ntfn.MarshalJSON()
Result: &AccountNtfn{ frontendNotificationMaster <- mntfn
Account: account,
Notification: locked,
},
Id: &id,
}
msg, _ := json.Marshal(&m)
frontendNotificationMaster <- msg
} }
// NotifyWalletBalance sends a confirmed account balance notification // NotifyWalletBalance sends a confirmed account balance notification
// to a frontend. // to a frontend.
func NotifyWalletBalance(frontend chan []byte, account string, balance float64) { func NotifyWalletBalance(frontend chan []byte, account string, balance float64) {
var id interface{} = "btcwallet:accountbalance" ntfn := btcws.NewAccountBalanceNtfn(account, balance, true)
m := btcjson.Reply{ mntfn, _ := ntfn.MarshalJSON()
Result: &AccountNtfn{ frontend <- mntfn
Account: account,
Notification: balance,
},
Id: &id,
}
msg, _ := json.Marshal(&m)
frontend <- msg
} }
// NotifyWalletBalanceUnconfirmed sends a confirmed account balance // NotifyWalletBalanceUnconfirmed sends a confirmed account balance
// notification to a frontend. // notification to a frontend.
func NotifyWalletBalanceUnconfirmed(frontend chan []byte, account string, balance float64) { func NotifyWalletBalanceUnconfirmed(frontend chan []byte, account string, balance float64) {
var id interface{} = "btcwallet:accountbalanceunconfirmed" ntfn := btcws.NewAccountBalanceNtfn(account, balance, false)
m := btcjson.Reply{ mntfn, _ := ntfn.MarshalJSON()
Result: &AccountNtfn{ frontend <- mntfn
Account: account,
Notification: balance,
},
Id: &id,
}
msg, _ := json.Marshal(&m)
frontend <- msg
} }
// NotifyNewTxDetails sends details of a new transaction to a frontend. // NotifyNewTxDetails sends details of a new transaction to a frontend.

View file

@ -345,7 +345,7 @@ func frontendListenerDuplicator() {
NotifyBtcdConnected(frontendNotificationMaster, NotifyBtcdConnected(frontendNotificationMaster,
btcdConnected.b) btcdConnected.b)
if bs, err := GetCurBlock(); err == nil { if bs, err := GetCurBlock(); err == nil {
NotifyNewBlockChainHeight(c, bs.Height) NotifyNewBlockChainHeight(c, bs)
NotifyBalances(c) NotifyBalances(c)
} }
@ -381,13 +381,10 @@ func frontendListenerDuplicator() {
// NotifyBtcdConnected notifies all frontends of a new btcd connection. // NotifyBtcdConnected notifies all frontends of a new btcd connection.
func NotifyBtcdConnected(reply chan []byte, conn bool) { func NotifyBtcdConnected(reply chan []byte, conn bool) {
btcdConnected.b = conn btcdConnected.b = conn
var idStr interface{} = "btcwallet:btcdconnected"
r := btcjson.Reply{ ntfn := btcws.NewBtcdConnectedNtfn(conn)
Result: conn, mntfn, _ := ntfn.MarshalJSON()
Id: &idStr, frontendNotificationMaster <- mntfn
}
ntfn, _ := json.Marshal(r)
frontendNotificationMaster <- ntfn
} }
// frontendSendRecv is the handler function for websocket connections from // frontendSendRecv is the handler function for websocket connections from
@ -481,12 +478,12 @@ func BtcdHandler(ws *websocket.Conn, done chan struct{}) {
}() }()
} }
type notificationHandler func(btcws.Notification) type notificationHandler func(btcjson.Cmd, []byte)
var notificationHandlers = map[string]notificationHandler{ var notificationHandlers = map[string]notificationHandler{
btcws.BlockConnectedNtfnId: NtfnBlockConnected, btcws.BlockConnectedNtfnMethod: NtfnBlockConnected,
btcws.BlockDisconnectedNtfnId: NtfnBlockDisconnected, btcws.BlockDisconnectedNtfnMethod: NtfnBlockDisconnected,
btcws.TxMinedNtfnId: NtfnTxMined, btcws.TxMinedNtfnMethod: NtfnTxMined,
} }
// ProcessBtcdNotificationReply unmarshalls the JSON notification or // ProcessBtcdNotificationReply unmarshalls the JSON notification or
@ -495,29 +492,63 @@ var notificationHandlers = map[string]notificationHandler{
// notifications are processed by btcwallet, and frontend notifications // notifications are processed by btcwallet, and frontend notifications
// are sent to every connected frontend. // are sent to every connected frontend.
func ProcessBtcdNotificationReply(b []byte) { func ProcessBtcdNotificationReply(b []byte) {
// Check if the json id field was set by btcwallet. // Idea: instead of reading btcd messages from just one websocket
var routeID uint64 // connection, maybe use two so the same connection isn't used
var origID string // for both notifications and responses? Should make handling
// must faster as unnecessary unmarshal attempts could be avoided.
var r btcjson.Reply // Check for notifications first.
if err := json.Unmarshal(b, &r); err != nil { if req, err := btcjson.ParseMarshaledCmd(b); err == nil {
log.Errorf("Unable to unmarshal btcd message: %v", err) // btcd should not be sending Requests except for
// notifications. Check for a nil id.
if req.Id() != nil {
// Invalid response
log.Warnf("btcd sent a non-notification JSON-RPC Request (ID: %v)",
req.Id())
return
}
// Message is a btcd notification. Check the method and dispatch
// correct handler, or if no handler, pass up to each wallet.
if ntfnHandler, ok := notificationHandlers[req.Method()]; ok {
ntfnHandler(req, b)
} else {
// No handler; send to all wallets.
frontendNotificationMaster <- b
}
return return
} }
// b is not a Request notification, so it must be a Response.
// Attempt to parse it as one and handle.
var r btcjson.Reply
if err := json.Unmarshal(b, &r); err != nil {
log.Warn("Unable to process btcd message as notification or response")
return
}
// Check for a valid ID.
//
// TODO(jrick): Remove this terrible ID overloading. Each
// passed-through request should be given a new unique ID number
// (reading from the NewJSONID channel) and a reply route with the
// frontend's incoming ID should be set.
if r.Id == nil { if r.Id == nil {
// btcd should only ever be sending JSON messages with a string in // Responses with no IDs cannot be handled.
// the id field. Log the error and drop the message. log.Warn("Unable to process btcd response without ID")
log.Error("Unable to process btcd notification or reply.")
return return
} }
idStr, ok := (*r.Id).(string) idStr, ok := (*r.Id).(string)
if !ok { if !ok {
// btcd should only ever be sending JSON messages with a string in // btcd's responses to btcwallet should (currently, see TODO above)
// the id field. Log the error and drop the message. // only ever be sending string IDs. If ID is not a string, log the
// error and drop the message.
log.Error("Incorrect btcd notification id type.") log.Error("Incorrect btcd notification id type.")
return return
} }
var routeID uint64
var origID string
n, _ := fmt.Sscanf(idStr, "btcwallet(%d)-%s", &routeID, &origID) n, _ := fmt.Sscanf(idStr, "btcwallet(%d)-%s", &routeID, &origID)
if n == 1 { if n == 1 {
// Request originated from btcwallet. Run and remove correct // Request originated from btcwallet. Run and remove correct
@ -565,34 +596,16 @@ func ProcessBtcdNotificationReply(b []byte) {
return return
} }
c <- b c <- b
} else {
// Message is a btcd notification. Check the id and dispatch
// correct handler, or if no handler, pass up to each wallet.
if ntfnHandler, ok := notificationHandlers[idStr]; ok {
n, err := btcws.ParseMarshaledNtfn(idStr, b)
if err != nil {
log.Errorf("Error unmarshaling expected "+
"notification: %v", err)
return
}
ntfnHandler(n)
return
}
frontendNotificationMaster <- b
} }
} }
// NotifyNewBlockChainHeight notifies all frontends of a new // NotifyNewBlockChainHeight notifies all frontends of a new
// blockchain height. // blockchain height. This sends the same notification as
func NotifyNewBlockChainHeight(reply chan []byte, height int32) { // btcd, so this can probably be removed.
var id interface{} = "btcwallet:newblockchainheight" func NotifyNewBlockChainHeight(reply chan []byte, bs wallet.BlockStamp) {
msgRaw := &btcjson.Reply{ ntfn := btcws.NewBlockConnectedNtfn(bs.Hash.String(), bs.Height)
Result: height, mntfn, _ := ntfn.MarshalJSON()
Id: &id, reply <- mntfn
}
msg, _ := json.Marshal(msgRaw)
reply <- msg
} }
// NtfnBlockConnected handles btcd notifications resulting from newly // NtfnBlockConnected handles btcd notifications resulting from newly
@ -602,15 +615,15 @@ func NotifyNewBlockChainHeight(reply chan []byte, height int32) {
// to mark wallet files with a possibly-better earliest block height, // to mark wallet files with a possibly-better earliest block height,
// and will greatly reduce rescan times for wallets created with an // and will greatly reduce rescan times for wallets created with an
// out of sync btcd. // out of sync btcd.
func NtfnBlockConnected(n btcws.Notification) { func NtfnBlockConnected(n btcjson.Cmd, marshaled []byte) {
bcn, ok := n.(*btcws.BlockConnectedNtfn) bcn, ok := n.(*btcws.BlockConnectedNtfn)
if !ok { if !ok {
log.Errorf("%v handler: unexpected type", n.Id()) log.Errorf("%v handler: unexpected type", n.Method())
return return
} }
hash, err := btcwire.NewShaHashFromStr(bcn.Hash) hash, err := btcwire.NewShaHashFromStr(bcn.Hash)
if err != nil { if err != nil {
log.Errorf("%v handler: invalid hash string", n.Id()) log.Errorf("%v handler: invalid hash string", n.Method())
return return
} }
@ -630,22 +643,22 @@ func NtfnBlockConnected(n btcws.Notification) {
accountstore.BlockNotify(bs) accountstore.BlockNotify(bs)
// Notify frontends of new blockchain height. // Pass notification to frontends too.
NotifyNewBlockChainHeight(frontendNotificationMaster, bcn.Height) frontendNotificationMaster <- marshaled
} }
// NtfnBlockDisconnected handles btcd notifications resulting from // NtfnBlockDisconnected handles btcd notifications resulting from
// blocks disconnected from the main chain in the event of a chain // blocks disconnected from the main chain in the event of a chain
// switch and notifies frontends of the new blockchain height. // switch and notifies frontends of the new blockchain height.
func NtfnBlockDisconnected(n btcws.Notification) { func NtfnBlockDisconnected(n btcjson.Cmd, marshaled []byte) {
bdn, ok := n.(*btcws.BlockDisconnectedNtfn) bdn, ok := n.(*btcws.BlockDisconnectedNtfn)
if !ok { if !ok {
log.Errorf("%v handler: unexpected type", n.Id()) log.Errorf("%v handler: unexpected type", n.Method())
return return
} }
hash, err := btcwire.NewShaHashFromStr(bdn.Hash) hash, err := btcwire.NewShaHashFromStr(bdn.Hash)
if err != nil { if err != nil {
log.Errorf("%v handler: invalid hash string", n.Id()) log.Errorf("%v handler: invalid hash string", n.Method())
return return
} }
@ -654,34 +667,34 @@ func NtfnBlockDisconnected(n btcws.Notification) {
accountstore.Rollback(bdn.Height, hash) accountstore.Rollback(bdn.Height, hash)
}() }()
// Notify frontends of new blockchain height. // Pass notification to frontends too.
NotifyNewBlockChainHeight(frontendNotificationMaster, bdn.Height) frontendNotificationMaster <- marshaled
} }
// NtfnTxMined handles btcd notifications resulting from newly // NtfnTxMined handles btcd notifications resulting from newly
// mined transactions that originated from this wallet. // mined transactions that originated from this wallet.
func NtfnTxMined(n btcws.Notification) { func NtfnTxMined(n btcjson.Cmd, marshaled []byte) {
tmn, ok := n.(*btcws.TxMinedNtfn) tmn, ok := n.(*btcws.TxMinedNtfn)
if !ok { if !ok {
log.Errorf("%v handler: unexpected type", n.Id()) log.Errorf("%v handler: unexpected type", n.Method())
return return
} }
txid, err := btcwire.NewShaHashFromStr(tmn.TxID) txid, err := btcwire.NewShaHashFromStr(tmn.TxID)
if err != nil { if err != nil {
log.Errorf("%v handler: invalid hash string", n.Id()) log.Errorf("%v handler: invalid hash string", n.Method())
return return
} }
blockhash, err := btcwire.NewShaHashFromStr(tmn.BlockHash) blockhash, err := btcwire.NewShaHashFromStr(tmn.BlockHash)
if err != nil { if err != nil {
log.Errorf("%v handler: invalid block hash string", n.Id()) log.Errorf("%v handler: invalid block hash string", n.Method())
return return
} }
err = accountstore.RecordMinedTx(txid, blockhash, err = accountstore.RecordMinedTx(txid, blockhash,
tmn.BlockHeight, tmn.Index, tmn.BlockTime) tmn.BlockHeight, tmn.Index, tmn.BlockTime)
if err != nil { if err != nil {
log.Errorf("%v handler: %v", n.Id(), err) log.Errorf("%v handler: %v", n.Method(), err)
return return
} }
@ -900,7 +913,7 @@ func BtcdHandshake(ws *websocket.Conn) error {
if err != nil { if err != nil {
return fmt.Errorf("cannot get best block: %v", err) return fmt.Errorf("cannot get best block: %v", err)
} }
NotifyNewBlockChainHeight(frontendNotificationMaster, bs.Height) NotifyNewBlockChainHeight(frontendNotificationMaster, bs)
NotifyBalances(frontendNotificationMaster) NotifyBalances(frontendNotificationMaster)
// Get default account. Only the default account is used to // Get default account. Only the default account is used to