Fixed data races in rpcwebsocket Notify functions

Access to connections map and associated notification maps in rpcServer
need to be protected with s.ws.Lock to prevent race with add/remove new
clients.

This closes #88.
This commit is contained in:
Francis Lam 2014-02-10 10:34:26 -05:00
parent 354cc38d2d
commit 1d60e5dba5

View file

@ -827,6 +827,9 @@ func (s *rpcServer) websocketJSONHandler(r chan *btcjson.Reply, c handlerChans,
// of a new block connected to the main chain. The notification is sent
// to each connected wallet.
func (s *rpcServer) NotifyBlockConnected(block *btcutil.Block) {
s.ws.Lock()
defer s.ws.Unlock()
hash, err := block.Sha()
if err != nil {
rpcsLog.Error("Bad block; connected block notification dropped")
@ -842,7 +845,6 @@ func (s *rpcServer) NotifyBlockConnected(block *btcutil.Block) {
}
// Inform any interested parties about txs mined in this block.
s.ws.Lock()
for _, tx := range block.Transactions() {
if clist, ok := s.ws.minedTxNotifications[*tx.Sha()]; ok {
var enext *list.Element
@ -860,13 +862,15 @@ func (s *rpcServer) NotifyBlockConnected(block *btcutil.Block) {
}
}
}
s.ws.Unlock()
}
// NotifyBlockDisconnected creates and marshals a JSON message to notify
// of a new block disconnected from the main chain. The notification is sent
// to each connected wallet.
func (s *rpcServer) NotifyBlockDisconnected(block *btcutil.Block) {
s.ws.Lock()
defer s.ws.Unlock()
hash, err := block.Sha()
if err != nil {
rpcsLog.Error("Bad block; connected block notification dropped")
@ -910,6 +914,9 @@ func notifySpentData(n ntfnChan, txhash *btcwire.ShaHash, index uint32,
// each transaction input of a new block and perform any checks and
// notify listening frontends when necessary.
func (s *rpcServer) newBlockNotifyCheckTxIn(tx *btcutil.Tx) {
s.ws.Lock()
defer s.ws.Unlock()
for _, txin := range tx.MsgTx().TxIn {
if clist, ok := s.ws.spentNotifications[txin.PreviousOutpoint]; ok {
var enext *list.Element
@ -928,6 +935,9 @@ func (s *rpcServer) newBlockNotifyCheckTxIn(tx *btcutil.Tx) {
// necessary notifications for wallets. If a non-nil block is passed,
// additional block information is passed with the notifications.
func (s *rpcServer) NotifyForTxOuts(tx *btcutil.Tx, block *btcutil.Block) {
s.ws.Lock()
defer s.ws.Unlock()
// Nothing to do if nobody is listening for transaction notifications.
if len(s.ws.txNotifications) == 0 {
return
@ -987,6 +997,9 @@ func (s *rpcServer) NotifyForTxOuts(tx *btcutil.Tx, block *btcutil.Block) {
// NotifyForNewTx sends delivers the new tx to any client that has
// registered for all new TX.
func (s *rpcServer) NotifyForNewTx(tx *btcutil.Tx) {
s.ws.Lock()
defer s.ws.Unlock()
txId := tx.Sha().String()
mtx := tx.MsgTx()