github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/rpcwebsocket.go (about) 1 // Copyright (c) 2013-2016 The btcsuite developers 2 // Copyright (c) 2016 The Dash developers 3 // Use of this source code is governed by an ISC 4 // license that can be found in the LICENSE file. 5 6 package main 7 8 import ( 9 "bytes" 10 "container/list" 11 "crypto/subtle" 12 "encoding/base64" 13 "encoding/hex" 14 "encoding/json" 15 "errors" 16 "fmt" 17 "io" 18 "math" 19 "sync" 20 "time" 21 22 "github.com/btcsuite/fastsha256" 23 "github.com/btcsuite/golangcrypto/ripemd160" 24 "github.com/btcsuite/websocket" 25 "github.com/BlockABC/godash/blockchain" 26 "github.com/BlockABC/godash/btcjson" 27 "github.com/BlockABC/godash/database" 28 "github.com/BlockABC/godash/txscript" 29 "github.com/BlockABC/godash/wire" 30 "github.com/BlockABC/godashutil" 31 ) 32 33 const ( 34 // websocketSendBufferSize is the number of elements the send channel 35 // can queue before blocking. Note that this only applies to requests 36 // handled directly in the websocket client input handler or the async 37 // handler since notifications have their own queuing mechanism 38 // independent of the send channel buffer. 39 websocketSendBufferSize = 50 40 ) 41 42 // timeZeroVal is simply the zero value for a time.Time and is used to avoid 43 // creating multiple instances. 44 var timeZeroVal time.Time 45 46 // wsCommandHandler describes a callback function used to handle a specific 47 // command. 48 type wsCommandHandler func(*wsClient, interface{}) (interface{}, error) 49 50 // wsHandlers maps RPC command strings to appropriate websocket handler 51 // functions. This is set by init because help references wsHandlers and thus 52 // causes a dependency loop. 53 var wsHandlers map[string]wsCommandHandler 54 var wsHandlersBeforeInit = map[string]wsCommandHandler{ 55 "help": handleWebsocketHelp, 56 "notifyblocks": handleNotifyBlocks, 57 "notifynewtransactions": handleNotifyNewTransactions, 58 "notifyreceived": handleNotifyReceived, 59 "notifyspent": handleNotifySpent, 60 "session": handleSession, 61 "stopnotifyblocks": handleStopNotifyBlocks, 62 "stopnotifynewtransactions": handleStopNotifyNewTransactions, 63 "stopnotifyspent": handleStopNotifySpent, 64 "stopnotifyreceived": handleStopNotifyReceived, 65 "rescan": handleRescan, 66 } 67 68 // wsAsyncHandlers holds the websocket commands which should be run 69 // asynchronously to the main input handler goroutine. This allows long-running 70 // operations to run concurrently (and one at a time) while still responding 71 // to the majority of normal requests which can be answered quickly. 72 var wsAsyncHandlers = map[string]struct{}{ 73 "rescan": {}, 74 } 75 76 // WebsocketHandler handles a new websocket client by creating a new wsClient, 77 // starting it, and blocking until the connection closes. Since it blocks, it 78 // must be run in a separate goroutine. It should be invoked from the websocket 79 // server handler which runs each new connection in a new goroutine thereby 80 // satisfying the requirement. 81 func (s *rpcServer) WebsocketHandler(conn *websocket.Conn, remoteAddr string, 82 authenticated bool, isAdmin bool) { 83 84 // Clear the read deadline that was set before the websocket hijacked 85 // the connection. 86 conn.SetReadDeadline(timeZeroVal) 87 88 // Limit max number of websocket clients. 89 rpcsLog.Infof("New websocket client %s", remoteAddr) 90 if s.ntfnMgr.NumClients()+1 > cfg.RPCMaxWebsockets { 91 rpcsLog.Infof("Max websocket clients exceeded [%d] - "+ 92 "disconnecting client %s", cfg.RPCMaxWebsockets, 93 remoteAddr) 94 conn.Close() 95 return 96 } 97 98 // Create a new websocket client to handle the new websocket connection 99 // and wait for it to shutdown. Once it has shutdown (and hence 100 // disconnected), remove it and any notifications it registered for. 101 client, err := newWebsocketClient(s, conn, remoteAddr, authenticated, isAdmin) 102 if err != nil { 103 rpcsLog.Errorf("Failed to serve client %s: %v", remoteAddr, err) 104 conn.Close() 105 return 106 } 107 s.ntfnMgr.AddClient(client) 108 client.Start() 109 client.WaitForShutdown() 110 s.ntfnMgr.RemoveClient(client) 111 rpcsLog.Infof("Disconnected websocket client %s", remoteAddr) 112 } 113 114 // wsNotificationManager is a connection and notification manager used for 115 // websockets. It allows websocket clients to register for notifications they 116 // are interested in. When an event happens elsewhere in the code such as 117 // transactions being added to the memory pool or block connects/disconnects, 118 // the notification manager is provided with the relevant details needed to 119 // figure out which websocket clients need to be notified based on what they 120 // have registered for and notifies them accordingly. It is also used to keep 121 // track of all connected websocket clients. 122 type wsNotificationManager struct { 123 // server is the RPC server the notification manager is associated with. 124 server *rpcServer 125 126 // queueNotification queues a notification for handling. 127 queueNotification chan interface{} 128 129 // notificationMsgs feeds notificationHandler with notifications 130 // and client (un)registeration requests from a queue as well as 131 // registeration and unregisteration requests from clients. 132 notificationMsgs chan interface{} 133 134 // Access channel for current number of connected clients. 135 numClients chan int 136 137 // Shutdown handling 138 wg sync.WaitGroup 139 quit chan struct{} 140 } 141 142 // queueHandler manages a queue of empty interfaces, reading from in and 143 // sending the oldest unsent to out. This handler stops when either of the 144 // in or quit channels are closed, and closes out before returning, without 145 // waiting to send any variables still remaining in the queue. 146 func queueHandler(in <-chan interface{}, out chan<- interface{}, quit <-chan struct{}) { 147 var q []interface{} 148 var dequeue chan<- interface{} 149 skipQueue := out 150 var next interface{} 151 out: 152 for { 153 select { 154 case n, ok := <-in: 155 if !ok { 156 // Sender closed input channel. 157 break out 158 } 159 160 // Either send to out immediately if skipQueue is 161 // non-nil (queue is empty) and reader is ready, 162 // or append to the queue and send later. 163 select { 164 case skipQueue <- n: 165 default: 166 q = append(q, n) 167 dequeue = out 168 skipQueue = nil 169 next = q[0] 170 } 171 172 case dequeue <- next: 173 copy(q, q[1:]) 174 q[len(q)-1] = nil // avoid leak 175 q = q[:len(q)-1] 176 if len(q) == 0 { 177 dequeue = nil 178 skipQueue = out 179 } else { 180 next = q[0] 181 } 182 183 case <-quit: 184 break out 185 } 186 } 187 close(out) 188 } 189 190 // queueHandler maintains a queue of notifications and notification handler 191 // control messages. 192 func (m *wsNotificationManager) queueHandler() { 193 queueHandler(m.queueNotification, m.notificationMsgs, m.quit) 194 m.wg.Done() 195 } 196 197 // NotifyBlockConnected passes a block newly-connected to the best chain 198 // to the notification manager for block and transaction notification 199 // processing. 200 func (m *wsNotificationManager) NotifyBlockConnected(block *godashutil.Block) { 201 // As NotifyBlockConnected will be called by the block manager 202 // and the RPC server may no longer be running, use a select 203 // statement to unblock enqueuing the notification once the RPC 204 // server has begun shutting down. 205 select { 206 case m.queueNotification <- (*notificationBlockConnected)(block): 207 case <-m.quit: 208 } 209 } 210 211 // NotifyBlockDisconnected passes a block disconnected from the best chain 212 // to the notification manager for block notification processing. 213 func (m *wsNotificationManager) NotifyBlockDisconnected(block *godashutil.Block) { 214 // As NotifyBlockDisconnected will be called by the block manager 215 // and the RPC server may no longer be running, use a select 216 // statement to unblock enqueuing the notification once the RPC 217 // server has begun shutting down. 218 select { 219 case m.queueNotification <- (*notificationBlockDisconnected)(block): 220 case <-m.quit: 221 } 222 } 223 224 // NotifyMempoolTx passes a transaction accepted by mempool to the 225 // notification manager for transaction notification processing. If 226 // isNew is true, the tx is is a new transaction, rather than one 227 // added to the mempool during a reorg. 228 func (m *wsNotificationManager) NotifyMempoolTx(tx *godashutil.Tx, isNew bool) { 229 n := ¬ificationTxAcceptedByMempool{ 230 isNew: isNew, 231 tx: tx, 232 } 233 234 // As NotifyMempoolTx will be called by mempool and the RPC server 235 // may no longer be running, use a select statement to unblock 236 // enqueuing the notification once the RPC server has begun 237 // shutting down. 238 select { 239 case m.queueNotification <- n: 240 case <-m.quit: 241 } 242 } 243 244 // Notification types 245 type notificationBlockConnected godashutil.Block 246 type notificationBlockDisconnected godashutil.Block 247 type notificationTxAcceptedByMempool struct { 248 isNew bool 249 tx *godashutil.Tx 250 } 251 252 // Notification control requests 253 type notificationRegisterClient wsClient 254 type notificationUnregisterClient wsClient 255 type notificationRegisterBlocks wsClient 256 type notificationUnregisterBlocks wsClient 257 type notificationRegisterNewMempoolTxs wsClient 258 type notificationUnregisterNewMempoolTxs wsClient 259 type notificationRegisterSpent struct { 260 wsc *wsClient 261 ops []*wire.OutPoint 262 } 263 type notificationUnregisterSpent struct { 264 wsc *wsClient 265 op *wire.OutPoint 266 } 267 type notificationRegisterAddr struct { 268 wsc *wsClient 269 addrs []string 270 } 271 type notificationUnregisterAddr struct { 272 wsc *wsClient 273 addr string 274 } 275 276 // notificationHandler reads notifications and control messages from the queue 277 // handler and processes one at a time. 278 func (m *wsNotificationManager) notificationHandler() { 279 // clients is a map of all currently connected websocket clients. 280 clients := make(map[chan struct{}]*wsClient) 281 282 // Maps used to hold lists of websocket clients to be notified on 283 // certain events. Each websocket client also keeps maps for the events 284 // which have multiple triggers to make removal from these lists on 285 // connection close less horrendously expensive. 286 // 287 // Where possible, the quit channel is used as the unique id for a client 288 // since it is quite a bit more efficient than using the entire struct. 289 blockNotifications := make(map[chan struct{}]*wsClient) 290 txNotifications := make(map[chan struct{}]*wsClient) 291 watchedOutPoints := make(map[wire.OutPoint]map[chan struct{}]*wsClient) 292 watchedAddrs := make(map[string]map[chan struct{}]*wsClient) 293 294 out: 295 for { 296 select { 297 case n, ok := <-m.notificationMsgs: 298 if !ok { 299 // queueHandler quit. 300 break out 301 } 302 switch n := n.(type) { 303 case *notificationBlockConnected: 304 block := (*godashutil.Block)(n) 305 306 // Skip iterating through all txs if no 307 // tx notification requests exist. 308 if len(watchedOutPoints) != 0 || len(watchedAddrs) != 0 { 309 for _, tx := range block.Transactions() { 310 m.notifyForTx(watchedOutPoints, 311 watchedAddrs, tx, block) 312 } 313 } 314 315 if len(blockNotifications) != 0 { 316 m.notifyBlockConnected(blockNotifications, 317 block) 318 } 319 320 case *notificationBlockDisconnected: 321 m.notifyBlockDisconnected(blockNotifications, 322 (*godashutil.Block)(n)) 323 324 case *notificationTxAcceptedByMempool: 325 if n.isNew && len(txNotifications) != 0 { 326 m.notifyForNewTx(txNotifications, n.tx) 327 } 328 m.notifyForTx(watchedOutPoints, watchedAddrs, n.tx, nil) 329 330 case *notificationRegisterBlocks: 331 wsc := (*wsClient)(n) 332 blockNotifications[wsc.quit] = wsc 333 334 case *notificationUnregisterBlocks: 335 wsc := (*wsClient)(n) 336 delete(blockNotifications, wsc.quit) 337 338 case *notificationRegisterClient: 339 wsc := (*wsClient)(n) 340 clients[wsc.quit] = wsc 341 342 case *notificationUnregisterClient: 343 wsc := (*wsClient)(n) 344 // Remove any requests made by the client as well as 345 // the client itself. 346 delete(blockNotifications, wsc.quit) 347 delete(txNotifications, wsc.quit) 348 for k := range wsc.spentRequests { 349 op := k 350 m.removeSpentRequest(watchedOutPoints, wsc, &op) 351 } 352 for addr := range wsc.addrRequests { 353 m.removeAddrRequest(watchedAddrs, wsc, addr) 354 } 355 delete(clients, wsc.quit) 356 357 case *notificationRegisterSpent: 358 m.addSpentRequests(watchedOutPoints, n.wsc, n.ops) 359 360 case *notificationUnregisterSpent: 361 m.removeSpentRequest(watchedOutPoints, n.wsc, n.op) 362 363 case *notificationRegisterAddr: 364 m.addAddrRequests(watchedAddrs, n.wsc, n.addrs) 365 366 case *notificationUnregisterAddr: 367 m.removeAddrRequest(watchedAddrs, n.wsc, n.addr) 368 369 case *notificationRegisterNewMempoolTxs: 370 wsc := (*wsClient)(n) 371 txNotifications[wsc.quit] = wsc 372 373 case *notificationUnregisterNewMempoolTxs: 374 wsc := (*wsClient)(n) 375 delete(txNotifications, wsc.quit) 376 377 default: 378 rpcsLog.Warn("Unhandled notification type") 379 } 380 381 case m.numClients <- len(clients): 382 383 case <-m.quit: 384 // RPC server shutting down. 385 break out 386 } 387 } 388 389 for _, c := range clients { 390 c.Disconnect() 391 } 392 m.wg.Done() 393 } 394 395 // NumClients returns the number of clients actively being served. 396 func (m *wsNotificationManager) NumClients() (n int) { 397 select { 398 case n = <-m.numClients: 399 case <-m.quit: // Use default n (0) if server has shut down. 400 } 401 return 402 } 403 404 // RegisterBlockUpdates requests block update notifications to the passed 405 // websocket client. 406 func (m *wsNotificationManager) RegisterBlockUpdates(wsc *wsClient) { 407 m.queueNotification <- (*notificationRegisterBlocks)(wsc) 408 } 409 410 // UnregisterBlockUpdates removes block update notifications for the passed 411 // websocket client. 412 func (m *wsNotificationManager) UnregisterBlockUpdates(wsc *wsClient) { 413 m.queueNotification <- (*notificationUnregisterBlocks)(wsc) 414 } 415 416 // notifyBlockConnected notifies websocket clients that have registered for 417 // block updates when a block is connected to the main chain. 418 func (*wsNotificationManager) notifyBlockConnected(clients map[chan struct{}]*wsClient, 419 block *godashutil.Block) { 420 421 // Notify interested websocket clients about the connected block. 422 ntfn := btcjson.NewBlockConnectedNtfn(block.Sha().String(), 423 int32(block.Height()), block.MsgBlock().Header.Timestamp.Unix()) 424 marshalledJSON, err := btcjson.MarshalCmd(nil, ntfn) 425 if err != nil { 426 rpcsLog.Error("Failed to marshal block connected notification: "+ 427 "%v", err) 428 return 429 } 430 for _, wsc := range clients { 431 wsc.QueueNotification(marshalledJSON) 432 } 433 } 434 435 // notifyBlockDisconnected notifies websocket clients that have registered for 436 // block updates when a block is disconnected from the main chain (due to a 437 // reorganize). 438 func (*wsNotificationManager) notifyBlockDisconnected(clients map[chan struct{}]*wsClient, block *godashutil.Block) { 439 // Skip notification creation if no clients have requested block 440 // connected/disconnected notifications. 441 if len(clients) == 0 { 442 return 443 } 444 445 // Notify interested websocket clients about the disconnected block. 446 ntfn := btcjson.NewBlockDisconnectedNtfn(block.Sha().String(), 447 int32(block.Height()), block.MsgBlock().Header.Timestamp.Unix()) 448 marshalledJSON, err := btcjson.MarshalCmd(nil, ntfn) 449 if err != nil { 450 rpcsLog.Error("Failed to marshal block disconnected "+ 451 "notification: %v", err) 452 return 453 } 454 for _, wsc := range clients { 455 wsc.QueueNotification(marshalledJSON) 456 } 457 } 458 459 // RegisterNewMempoolTxsUpdates requests notifications to the passed websocket 460 // client when new transactions are added to the memory pool. 461 func (m *wsNotificationManager) RegisterNewMempoolTxsUpdates(wsc *wsClient) { 462 m.queueNotification <- (*notificationRegisterNewMempoolTxs)(wsc) 463 } 464 465 // UnregisterNewMempoolTxsUpdates removes notifications to the passed websocket 466 // client when new transaction are added to the memory pool. 467 func (m *wsNotificationManager) UnregisterNewMempoolTxsUpdates(wsc *wsClient) { 468 m.queueNotification <- (*notificationUnregisterNewMempoolTxs)(wsc) 469 } 470 471 // notifyForNewTx notifies websocket clients that have registered for updates 472 // when a new transaction is added to the memory pool. 473 func (m *wsNotificationManager) notifyForNewTx(clients map[chan struct{}]*wsClient, tx *godashutil.Tx) { 474 txShaStr := tx.Sha().String() 475 mtx := tx.MsgTx() 476 477 var amount int64 478 for _, txOut := range mtx.TxOut { 479 amount += txOut.Value 480 } 481 482 ntfn := btcjson.NewTxAcceptedNtfn(txShaStr, godashutil.Amount(amount).ToBTC()) 483 marshalledJSON, err := btcjson.MarshalCmd(nil, ntfn) 484 if err != nil { 485 rpcsLog.Errorf("Failed to marshal tx notification: %s", err.Error()) 486 return 487 } 488 489 var verboseNtfn *btcjson.TxAcceptedVerboseNtfn 490 var marshalledJSONVerbose []byte 491 for _, wsc := range clients { 492 if wsc.verboseTxUpdates { 493 if marshalledJSONVerbose != nil { 494 wsc.QueueNotification(marshalledJSONVerbose) 495 continue 496 } 497 498 net := m.server.server.chainParams 499 rawTx, err := createTxRawResult(net, mtx, txShaStr, nil, 500 "", 0, 0) 501 if err != nil { 502 return 503 } 504 505 verboseNtfn = btcjson.NewTxAcceptedVerboseNtfn(*rawTx) 506 marshalledJSONVerbose, err = btcjson.MarshalCmd(nil, 507 verboseNtfn) 508 if err != nil { 509 rpcsLog.Errorf("Failed to marshal verbose tx "+ 510 "notification: %s", err.Error()) 511 return 512 } 513 wsc.QueueNotification(marshalledJSONVerbose) 514 } else { 515 wsc.QueueNotification(marshalledJSON) 516 } 517 } 518 } 519 520 // RegisterSpentRequests requests a notification when each of the passed 521 // outpoints is confirmed spent (contained in a block connected to the main 522 // chain) for the passed websocket client. The request is automatically 523 // removed once the notification has been sent. 524 func (m *wsNotificationManager) RegisterSpentRequests(wsc *wsClient, ops []*wire.OutPoint) { 525 m.queueNotification <- ¬ificationRegisterSpent{ 526 wsc: wsc, 527 ops: ops, 528 } 529 } 530 531 // addSpentRequests modifies a map of watched outpoints to sets of websocket 532 // clients to add a new request watch all of the outpoints in ops and create 533 // and send a notification when spent to the websocket client wsc. 534 func (*wsNotificationManager) addSpentRequests(opMap map[wire.OutPoint]map[chan struct{}]*wsClient, 535 wsc *wsClient, ops []*wire.OutPoint) { 536 537 for _, op := range ops { 538 // Track the request in the client as well so it can be quickly 539 // be removed on disconnect. 540 wsc.spentRequests[*op] = struct{}{} 541 542 // Add the client to the list to notify when the outpoint is seen. 543 // Create the list as needed. 544 cmap, ok := opMap[*op] 545 if !ok { 546 cmap = make(map[chan struct{}]*wsClient) 547 opMap[*op] = cmap 548 } 549 cmap[wsc.quit] = wsc 550 } 551 } 552 553 // UnregisterSpentRequest removes a request from the passed websocket client 554 // to be notified when the passed outpoint is confirmed spent (contained in a 555 // block connected to the main chain). 556 func (m *wsNotificationManager) UnregisterSpentRequest(wsc *wsClient, op *wire.OutPoint) { 557 m.queueNotification <- ¬ificationUnregisterSpent{ 558 wsc: wsc, 559 op: op, 560 } 561 } 562 563 // removeSpentRequest modifies a map of watched outpoints to remove the 564 // websocket client wsc from the set of clients to be notified when a 565 // watched outpoint is spent. If wsc is the last client, the outpoint 566 // key is removed from the map. 567 func (*wsNotificationManager) removeSpentRequest(ops map[wire.OutPoint]map[chan struct{}]*wsClient, 568 wsc *wsClient, op *wire.OutPoint) { 569 570 // Remove the request tracking from the client. 571 delete(wsc.spentRequests, *op) 572 573 // Remove the client from the list to notify. 574 notifyMap, ok := ops[*op] 575 if !ok { 576 rpcsLog.Warnf("Attempt to remove nonexistent spent request "+ 577 "for websocket client %s", wsc.addr) 578 return 579 } 580 delete(notifyMap, wsc.quit) 581 582 // Remove the map entry altogether if there are 583 // no more clients interested in it. 584 if len(notifyMap) == 0 { 585 delete(ops, *op) 586 } 587 } 588 589 // txHexString returns the serialized transaction encoded in hexadecimal. 590 func txHexString(tx *godashutil.Tx) string { 591 buf := bytes.NewBuffer(make([]byte, 0, tx.MsgTx().SerializeSize())) 592 // Ignore Serialize's error, as writing to a bytes.buffer cannot fail. 593 tx.MsgTx().Serialize(buf) 594 return hex.EncodeToString(buf.Bytes()) 595 } 596 597 // blockDetails creates a BlockDetails struct to include in btcws notifications 598 // from a block and a transaction's block index. 599 func blockDetails(block *godashutil.Block, txIndex int) *btcjson.BlockDetails { 600 if block == nil { 601 return nil 602 } 603 return &btcjson.BlockDetails{ 604 Height: int32(block.Height()), 605 Hash: block.Sha().String(), 606 Index: txIndex, 607 Time: block.MsgBlock().Header.Timestamp.Unix(), 608 } 609 } 610 611 // newRedeemingTxNotification returns a new marshalled redeemingtx notification 612 // with the passed parameters. 613 func newRedeemingTxNotification(txHex string, index int, block *godashutil.Block) ([]byte, error) { 614 // Create and marshal the notification. 615 ntfn := btcjson.NewRedeemingTxNtfn(txHex, blockDetails(block, index)) 616 return btcjson.MarshalCmd(nil, ntfn) 617 } 618 619 // notifyForTxOuts examines each transaction output, notifying interested 620 // websocket clients of the transaction if an output spends to a watched 621 // address. A spent notification request is automatically registered for 622 // the client for each matching output. 623 func (m *wsNotificationManager) notifyForTxOuts(ops map[wire.OutPoint]map[chan struct{}]*wsClient, 624 addrs map[string]map[chan struct{}]*wsClient, tx *godashutil.Tx, block *godashutil.Block) { 625 626 // Nothing to do if nobody is listening for address notifications. 627 if len(addrs) == 0 { 628 return 629 } 630 631 txHex := "" 632 wscNotified := make(map[chan struct{}]struct{}) 633 for i, txOut := range tx.MsgTx().TxOut { 634 _, txAddrs, _, err := txscript.ExtractPkScriptAddrs( 635 txOut.PkScript, m.server.server.chainParams) 636 if err != nil { 637 continue 638 } 639 640 for _, txAddr := range txAddrs { 641 cmap, ok := addrs[txAddr.EncodeAddress()] 642 if !ok { 643 continue 644 } 645 646 if txHex == "" { 647 txHex = txHexString(tx) 648 } 649 ntfn := btcjson.NewRecvTxNtfn(txHex, blockDetails(block, 650 tx.Index())) 651 652 marshalledJSON, err := btcjson.MarshalCmd(nil, ntfn) 653 if err != nil { 654 rpcsLog.Errorf("Failed to marshal processedtx notification: %v", err) 655 continue 656 } 657 658 op := []*wire.OutPoint{wire.NewOutPoint(tx.Sha(), uint32(i))} 659 for wscQuit, wsc := range cmap { 660 m.addSpentRequests(ops, wsc, op) 661 662 if _, ok := wscNotified[wscQuit]; !ok { 663 wscNotified[wscQuit] = struct{}{} 664 wsc.QueueNotification(marshalledJSON) 665 } 666 } 667 } 668 } 669 } 670 671 // notifyForTx examines the inputs and outputs of the passed transaction, 672 // notifying websocket clients of outputs spending to a watched address 673 // and inputs spending a watched outpoint. 674 func (m *wsNotificationManager) notifyForTx(ops map[wire.OutPoint]map[chan struct{}]*wsClient, 675 addrs map[string]map[chan struct{}]*wsClient, tx *godashutil.Tx, block *godashutil.Block) { 676 677 if len(ops) != 0 { 678 m.notifyForTxIns(ops, tx, block) 679 } 680 if len(addrs) != 0 { 681 m.notifyForTxOuts(ops, addrs, tx, block) 682 } 683 } 684 685 // notifyForTxIns examines the inputs of the passed transaction and sends 686 // interested websocket clients a redeemingtx notification if any inputs 687 // spend a watched output. If block is non-nil, any matching spent 688 // requests are removed. 689 func (m *wsNotificationManager) notifyForTxIns(ops map[wire.OutPoint]map[chan struct{}]*wsClient, 690 tx *godashutil.Tx, block *godashutil.Block) { 691 692 // Nothing to do if nobody is watching outpoints. 693 if len(ops) == 0 { 694 return 695 } 696 697 txHex := "" 698 wscNotified := make(map[chan struct{}]struct{}) 699 for _, txIn := range tx.MsgTx().TxIn { 700 prevOut := &txIn.PreviousOutPoint 701 if cmap, ok := ops[*prevOut]; ok { 702 if txHex == "" { 703 txHex = txHexString(tx) 704 } 705 marshalledJSON, err := newRedeemingTxNotification(txHex, tx.Index(), block) 706 if err != nil { 707 rpcsLog.Warnf("Failed to marshal redeemingtx notification: %v", err) 708 continue 709 } 710 for wscQuit, wsc := range cmap { 711 if block != nil { 712 m.removeSpentRequest(ops, wsc, prevOut) 713 } 714 715 if _, ok := wscNotified[wscQuit]; !ok { 716 wscNotified[wscQuit] = struct{}{} 717 wsc.QueueNotification(marshalledJSON) 718 } 719 } 720 } 721 } 722 } 723 724 // RegisterTxOutAddressRequests requests notifications to the passed websocket 725 // client when a transaction output spends to the passed address. 726 func (m *wsNotificationManager) RegisterTxOutAddressRequests(wsc *wsClient, addrs []string) { 727 m.queueNotification <- ¬ificationRegisterAddr{ 728 wsc: wsc, 729 addrs: addrs, 730 } 731 } 732 733 // addAddrRequests adds the websocket client wsc to the address to client set 734 // addrMap so wsc will be notified for any mempool or block transaction outputs 735 // spending to any of the addresses in addrs. 736 func (*wsNotificationManager) addAddrRequests(addrMap map[string]map[chan struct{}]*wsClient, 737 wsc *wsClient, addrs []string) { 738 739 for _, addr := range addrs { 740 // Track the request in the client as well so it can be quickly be 741 // removed on disconnect. 742 wsc.addrRequests[addr] = struct{}{} 743 744 // Add the client to the set of clients to notify when the 745 // outpoint is seen. Create map as needed. 746 cmap, ok := addrMap[addr] 747 if !ok { 748 cmap = make(map[chan struct{}]*wsClient) 749 addrMap[addr] = cmap 750 } 751 cmap[wsc.quit] = wsc 752 } 753 } 754 755 // UnregisterTxOutAddressRequest removes a request from the passed websocket 756 // client to be notified when a transaction spends to the passed address. 757 func (m *wsNotificationManager) UnregisterTxOutAddressRequest(wsc *wsClient, addr string) { 758 m.queueNotification <- ¬ificationUnregisterAddr{ 759 wsc: wsc, 760 addr: addr, 761 } 762 } 763 764 // removeAddrRequest removes the websocket client wsc from the address to 765 // client set addrs so it will no longer receive notification updates for 766 // any transaction outputs send to addr. 767 func (*wsNotificationManager) removeAddrRequest(addrs map[string]map[chan struct{}]*wsClient, 768 wsc *wsClient, addr string) { 769 770 // Remove the request tracking from the client. 771 delete(wsc.addrRequests, addr) 772 773 // Remove the client from the list to notify. 774 cmap, ok := addrs[addr] 775 if !ok { 776 rpcsLog.Warnf("Attempt to remove nonexistent addr request "+ 777 "<%s> for websocket client %s", addr, wsc.addr) 778 return 779 } 780 delete(cmap, wsc.quit) 781 782 // Remove the map entry altogether if there are no more clients 783 // interested in it. 784 if len(cmap) == 0 { 785 delete(addrs, addr) 786 } 787 } 788 789 // AddClient adds the passed websocket client to the notification manager. 790 func (m *wsNotificationManager) AddClient(wsc *wsClient) { 791 m.queueNotification <- (*notificationRegisterClient)(wsc) 792 } 793 794 // RemoveClient removes the passed websocket client and all notifications 795 // registered for it. 796 func (m *wsNotificationManager) RemoveClient(wsc *wsClient) { 797 select { 798 case m.queueNotification <- (*notificationUnregisterClient)(wsc): 799 case <-m.quit: 800 } 801 } 802 803 // Start starts the goroutines required for the manager to queue and process 804 // websocket client notifications. 805 func (m *wsNotificationManager) Start() { 806 m.wg.Add(2) 807 go m.queueHandler() 808 go m.notificationHandler() 809 } 810 811 // WaitForShutdown blocks until all notification manager goroutines have 812 // finished. 813 func (m *wsNotificationManager) WaitForShutdown() { 814 m.wg.Wait() 815 } 816 817 // Shutdown shuts down the manager, stopping the notification queue and 818 // notification handler goroutines. 819 func (m *wsNotificationManager) Shutdown() { 820 close(m.quit) 821 } 822 823 // newWsNotificationManager returns a new notification manager ready for use. 824 // See wsNotificationManager for more details. 825 func newWsNotificationManager(server *rpcServer) *wsNotificationManager { 826 return &wsNotificationManager{ 827 server: server, 828 queueNotification: make(chan interface{}), 829 notificationMsgs: make(chan interface{}), 830 numClients: make(chan int), 831 quit: make(chan struct{}), 832 } 833 } 834 835 // wsResponse houses a message to send to a connected websocket client as 836 // well as a channel to reply on when the message is sent. 837 type wsResponse struct { 838 msg []byte 839 doneChan chan bool 840 } 841 842 // wsClient provides an abstraction for handling a websocket client. The 843 // overall data flow is split into 3 main goroutines, a possible 4th goroutine 844 // for long-running operations (only started if request is made), and a 845 // websocket manager which is used to allow things such as broadcasting 846 // requested notifications to all connected websocket clients. Inbound 847 // messages are read via the inHandler goroutine and generally dispatched to 848 // their own handler. However, certain potentially long-running operations such 849 // as rescans, are sent to the asyncHander goroutine and are limited to one at a 850 // time. There are two outbound message types - one for responding to client 851 // requests and another for async notifications. Responses to client requests 852 // use SendMessage which employs a buffered channel thereby limiting the number 853 // of outstanding requests that can be made. Notifications are sent via 854 // QueueNotification which implements a queue via notificationQueueHandler to 855 // ensure sending notifications from other subsystems can't block. Ultimately, 856 // all messages are sent via the outHandler. 857 type wsClient struct { 858 sync.Mutex 859 860 // server is the RPC server that is servicing the client. 861 server *rpcServer 862 863 // conn is the underlying websocket connection. 864 conn *websocket.Conn 865 866 // disconnected indicated whether or not the websocket client is 867 // disconnected. 868 disconnected bool 869 870 // addr is the remote address of the client. 871 addr string 872 873 // authenticated specifies whether a client has been authenticated 874 // and therefore is allowed to communicated over the websocket. 875 authenticated bool 876 877 // isAdmin specifies whether a client may change the state of the server; 878 // false means its access is only to the limited set of RPC calls. 879 isAdmin bool 880 881 // sessionID is a random ID generated for each client when connected. 882 // These IDs may be queried by a client using the session RPC. A change 883 // to the session ID indicates that the client reconnected. 884 sessionID uint64 885 886 // verboseTxUpdates specifies whether a client has requested verbose 887 // information about all new transactions. 888 verboseTxUpdates bool 889 890 // addrRequests is a set of addresses the caller has requested to be 891 // notified about. It is maintained here so all requests can be removed 892 // when a wallet disconnects. Owned by the notification manager. 893 addrRequests map[string]struct{} 894 895 // spentRequests is a set of unspent Outpoints a wallet has requested 896 // notifications for when they are spent by a processed transaction. 897 // Owned by the notification manager. 898 spentRequests map[wire.OutPoint]struct{} 899 900 // Networking infrastructure. 901 asyncStarted bool 902 asyncChan chan *parsedRPCCmd 903 ntfnChan chan []byte 904 sendChan chan wsResponse 905 quit chan struct{} 906 wg sync.WaitGroup 907 } 908 909 // handleMessage is the main handler for incoming requests. It enforces 910 // authentication, parses the incoming json, looks up and executes handlers 911 // (including pass through for standard RPC commands), and sends the appropriate 912 // response. It also detects commands which are marked as long-running and 913 // sends them off to the asyncHander for processing. 914 func (c *wsClient) handleMessage(msg []byte) { 915 if !c.authenticated { 916 // Disconnect immediately if the provided command fails to 917 // parse when the client is not already authenticated. 918 var request btcjson.Request 919 if err := json.Unmarshal(msg, &request); err != nil { 920 c.Disconnect() 921 return 922 } 923 parsedCmd := parseCmd(&request) 924 if parsedCmd.err != nil { 925 c.Disconnect() 926 return 927 } 928 929 // Disconnect immediately if the first command is not 930 // authenticate when not already authenticated. 931 authCmd, ok := parsedCmd.cmd.(*btcjson.AuthenticateCmd) 932 if !ok { 933 rpcsLog.Warnf("Unauthenticated websocket message " + 934 "received") 935 c.Disconnect() 936 return 937 } 938 939 // Check credentials. 940 login := authCmd.Username + ":" + authCmd.Passphrase 941 auth := "Basic " + base64.StdEncoding.EncodeToString([]byte(login)) 942 authSha := fastsha256.Sum256([]byte(auth)) 943 cmp := subtle.ConstantTimeCompare(authSha[:], c.server.authsha[:]) 944 limitcmp := subtle.ConstantTimeCompare(authSha[:], c.server.limitauthsha[:]) 945 if cmp != 1 && limitcmp != 1 { 946 rpcsLog.Warnf("Auth failure.") 947 c.Disconnect() 948 return 949 } 950 c.authenticated = true 951 c.isAdmin = cmp == 1 952 953 // Marshal and send response. 954 reply, err := createMarshalledReply(parsedCmd.id, nil, nil) 955 if err != nil { 956 rpcsLog.Errorf("Failed to marshal authenticate reply: "+ 957 "%v", err.Error()) 958 return 959 } 960 c.SendMessage(reply, nil) 961 return 962 } 963 964 // Attempt to parse the raw message into a JSON-RPC request. 965 var request btcjson.Request 966 if err := json.Unmarshal(msg, &request); err != nil { 967 jsonErr := &btcjson.RPCError{ 968 Code: btcjson.ErrRPCParse.Code, 969 Message: "Failed to parse request: " + err.Error(), 970 } 971 972 // Marshal and send response. 973 reply, err := createMarshalledReply(nil, nil, jsonErr) 974 if err != nil { 975 rpcsLog.Errorf("Failed to marshal parse failure "+ 976 "reply: %v", err) 977 return 978 } 979 c.SendMessage(reply, nil) 980 return 981 } 982 // Requests with no ID (notifications) must not have a response per the 983 // JSON-RPC spec. 984 if request.ID == nil { 985 return 986 } 987 988 // Check if the user is limited and disconnect client if unauthorized 989 if !c.isAdmin { 990 if _, ok := rpcLimited[request.Method]; !ok { 991 jsonErr := &btcjson.RPCError{ 992 Code: btcjson.ErrRPCInvalidParams.Code, 993 Message: "limited user not authorized for this method", 994 } 995 // Marshal and send response. 996 reply, err := createMarshalledReply(request.ID, nil, jsonErr) 997 if err != nil { 998 rpcsLog.Errorf("Failed to marshal parse failure "+ 999 "reply: %v", err) 1000 return 1001 } 1002 c.SendMessage(reply, nil) 1003 return 1004 } 1005 } 1006 1007 // Attempt to parse the JSON-RPC request into a known concrete command. 1008 cmd := parseCmd(&request) 1009 if cmd.err != nil { 1010 // Marshal and send response. 1011 reply, err := createMarshalledReply(cmd.id, nil, cmd.err) 1012 if err != nil { 1013 rpcsLog.Errorf("Failed to marshal parse failure "+ 1014 "reply: %v", err) 1015 return 1016 } 1017 c.SendMessage(reply, nil) 1018 return 1019 } 1020 rpcsLog.Debugf("Received command <%s> from %s", cmd.method, c.addr) 1021 1022 // Disconnect if already authenticated and another authenticate command 1023 // is received. 1024 if _, ok := cmd.cmd.(*btcjson.AuthenticateCmd); ok { 1025 rpcsLog.Warnf("Websocket client %s is already authenticated", 1026 c.addr) 1027 c.Disconnect() 1028 return 1029 } 1030 1031 // When the command is marked as a long-running command, send it off 1032 // to the asyncHander goroutine for processing. 1033 if _, ok := wsAsyncHandlers[cmd.method]; ok { 1034 // Start up the async goroutine for handling long-running 1035 // requests asynchonrously if needed. 1036 if !c.asyncStarted { 1037 rpcsLog.Tracef("Starting async handler for %s", c.addr) 1038 c.wg.Add(1) 1039 go c.asyncHandler() 1040 c.asyncStarted = true 1041 } 1042 c.asyncChan <- cmd 1043 return 1044 } 1045 1046 // Lookup the websocket extension for the command and if it doesn't 1047 // exist fallback to handling the command as a standard command. 1048 wsHandler, ok := wsHandlers[cmd.method] 1049 if !ok { 1050 // No websocket-specific handler so handle like a legacy 1051 // RPC connection. 1052 result, jsonErr := c.server.standardCmdResult(cmd, nil) 1053 reply, err := createMarshalledReply(cmd.id, result, jsonErr) 1054 if err != nil { 1055 rpcsLog.Errorf("Failed to marshal reply for <%s> "+ 1056 "command: %v", cmd.method, err) 1057 return 1058 } 1059 1060 c.SendMessage(reply, nil) 1061 return 1062 } 1063 1064 // Invoke the handler and marshal and send response. 1065 result, jsonErr := wsHandler(c, cmd.cmd) 1066 reply, err := createMarshalledReply(cmd.id, result, jsonErr) 1067 if err != nil { 1068 rpcsLog.Errorf("Failed to marshal reply for <%s> command: %v", 1069 cmd.method, err) 1070 return 1071 } 1072 c.SendMessage(reply, nil) 1073 } 1074 1075 // inHandler handles all incoming messages for the websocket connection. It 1076 // must be run as a goroutine. 1077 func (c *wsClient) inHandler() { 1078 out: 1079 for { 1080 // Break out of the loop once the quit channel has been closed. 1081 // Use a non-blocking select here so we fall through otherwise. 1082 select { 1083 case <-c.quit: 1084 break out 1085 default: 1086 } 1087 1088 _, msg, err := c.conn.ReadMessage() 1089 if err != nil { 1090 // Log the error if it's not due to disconnecting. 1091 if err != io.EOF { 1092 rpcsLog.Errorf("Websocket receive error from "+ 1093 "%s: %v", c.addr, err) 1094 } 1095 break out 1096 } 1097 c.handleMessage(msg) 1098 } 1099 1100 // Ensure the connection is closed. 1101 c.Disconnect() 1102 c.wg.Done() 1103 rpcsLog.Tracef("Websocket client input handler done for %s", c.addr) 1104 } 1105 1106 // notificationQueueHandler handles the queuing of outgoing notifications for 1107 // the websocket client. This runs as a muxer for various sources of input to 1108 // ensure that queuing up notifications to be sent will not block. Otherwise, 1109 // slow clients could bog down the other systems (such as the mempool or block 1110 // manager) which are queuing the data. The data is passed on to outHandler to 1111 // actually be written. It must be run as a goroutine. 1112 func (c *wsClient) notificationQueueHandler() { 1113 ntfnSentChan := make(chan bool, 1) // nonblocking sync 1114 1115 // pendingNtfns is used as a queue for notifications that are ready to 1116 // be sent once there are no outstanding notifications currently being 1117 // sent. The waiting flag is used over simply checking for items in the 1118 // pending list to ensure cleanup knows what has and hasn't been sent 1119 // to the outHandler. Currently no special cleanup is needed, however 1120 // if something like a done channel is added to notifications in the 1121 // future, not knowing what has and hasn't been sent to the outHandler 1122 // (and thus who should respond to the done channel) would be 1123 // problematic without using this approach. 1124 pendingNtfns := list.New() 1125 waiting := false 1126 out: 1127 for { 1128 select { 1129 // This channel is notified when a message is being queued to 1130 // be sent across the network socket. It will either send the 1131 // message immediately if a send is not already in progress, or 1132 // queue the message to be sent once the other pending messages 1133 // are sent. 1134 case msg := <-c.ntfnChan: 1135 if !waiting { 1136 c.SendMessage(msg, ntfnSentChan) 1137 } else { 1138 pendingNtfns.PushBack(msg) 1139 } 1140 waiting = true 1141 1142 // This channel is notified when a notification has been sent 1143 // across the network socket. 1144 case <-ntfnSentChan: 1145 // No longer waiting if there are no more messages in 1146 // the pending messages queue. 1147 next := pendingNtfns.Front() 1148 if next == nil { 1149 waiting = false 1150 continue 1151 } 1152 1153 // Notify the outHandler about the next item to 1154 // asynchronously send. 1155 msg := pendingNtfns.Remove(next).([]byte) 1156 c.SendMessage(msg, ntfnSentChan) 1157 1158 case <-c.quit: 1159 break out 1160 } 1161 } 1162 1163 // Drain any wait channels before exiting so nothing is left waiting 1164 // around to send. 1165 cleanup: 1166 for { 1167 select { 1168 case <-c.ntfnChan: 1169 case <-ntfnSentChan: 1170 default: 1171 break cleanup 1172 } 1173 } 1174 c.wg.Done() 1175 rpcsLog.Tracef("Websocket client notification queue handler done "+ 1176 "for %s", c.addr) 1177 } 1178 1179 // outHandler handles all outgoing messages for the websocket connection. It 1180 // must be run as a goroutine. It uses a buffered channel to serialize output 1181 // messages while allowing the sender to continue running asynchronously. It 1182 // must be run as a goroutine. 1183 func (c *wsClient) outHandler() { 1184 out: 1185 for { 1186 // Send any messages ready for send until the quit channel is 1187 // closed. 1188 select { 1189 case r := <-c.sendChan: 1190 err := c.conn.WriteMessage(websocket.TextMessage, r.msg) 1191 if err != nil { 1192 c.Disconnect() 1193 break out 1194 } 1195 if r.doneChan != nil { 1196 r.doneChan <- true 1197 } 1198 1199 case <-c.quit: 1200 break out 1201 } 1202 } 1203 1204 // Drain any wait channels before exiting so nothing is left waiting 1205 // around to send. 1206 cleanup: 1207 for { 1208 select { 1209 case r := <-c.sendChan: 1210 if r.doneChan != nil { 1211 r.doneChan <- false 1212 } 1213 default: 1214 break cleanup 1215 } 1216 } 1217 c.wg.Done() 1218 rpcsLog.Tracef("Websocket client output handler done for %s", c.addr) 1219 } 1220 1221 // asyncHandler handles all long-running requests such as rescans which are 1222 // not run directly in the inHandler routine unlike most requests. This allows 1223 // normal quick requests to continue to be processed and responded to even while 1224 // lengthy operations are underway. Only one long-running operation is 1225 // permitted at a time, so multiple long-running requests are queued and 1226 // serialized. It must be run as a goroutine. Also, this goroutine is not 1227 // started until/if the first long-running request is made. 1228 func (c *wsClient) asyncHandler() { 1229 asyncHandlerDoneChan := make(chan struct{}, 1) // nonblocking sync 1230 pendingCmds := list.New() 1231 waiting := false 1232 1233 // runHandler runs the handler for the passed command and sends the 1234 // reply. 1235 runHandler := func(parsedCmd *parsedRPCCmd) { 1236 wsHandler, ok := wsHandlers[parsedCmd.method] 1237 if !ok { 1238 rpcsLog.Warnf("No handler for command <%s>", 1239 parsedCmd.method) 1240 return 1241 } 1242 1243 // Invoke the handler and marshal and send response. 1244 result, jsonErr := wsHandler(c, parsedCmd.cmd) 1245 reply, err := createMarshalledReply(parsedCmd.id, result, 1246 jsonErr) 1247 if err != nil { 1248 rpcsLog.Errorf("Failed to marshal reply for <%s> "+ 1249 "command: %v", parsedCmd.method, err) 1250 return 1251 } 1252 c.SendMessage(reply, nil) 1253 } 1254 1255 out: 1256 for { 1257 select { 1258 case cmd := <-c.asyncChan: 1259 if !waiting { 1260 c.wg.Add(1) 1261 go func(cmd *parsedRPCCmd) { 1262 runHandler(cmd) 1263 asyncHandlerDoneChan <- struct{}{} 1264 c.wg.Done() 1265 }(cmd) 1266 } else { 1267 pendingCmds.PushBack(cmd) 1268 } 1269 waiting = true 1270 1271 case <-asyncHandlerDoneChan: 1272 // No longer waiting if there are no more messages in 1273 // the pending messages queue. 1274 next := pendingCmds.Front() 1275 if next == nil { 1276 waiting = false 1277 continue 1278 } 1279 1280 // Notify the outHandler about the next item to 1281 // asynchronously send. 1282 element := pendingCmds.Remove(next) 1283 c.wg.Add(1) 1284 go func(cmd *parsedRPCCmd) { 1285 runHandler(cmd) 1286 asyncHandlerDoneChan <- struct{}{} 1287 c.wg.Done() 1288 }(element.(*parsedRPCCmd)) 1289 1290 case <-c.quit: 1291 break out 1292 } 1293 } 1294 1295 // Drain any wait channels before exiting so nothing is left waiting 1296 // around to send. 1297 cleanup: 1298 for { 1299 select { 1300 case <-c.asyncChan: 1301 case <-asyncHandlerDoneChan: 1302 default: 1303 break cleanup 1304 } 1305 } 1306 1307 c.wg.Done() 1308 rpcsLog.Tracef("Websocket client async handler done for %s", c.addr) 1309 } 1310 1311 // SendMessage sends the passed json to the websocket client. It is backed 1312 // by a buffered channel, so it will not block until the send channel is full. 1313 // Note however that QueueNotification must be used for sending async 1314 // notifications instead of the this function. This approach allows a limit to 1315 // the number of outstanding requests a client can make without preventing or 1316 // blocking on async notifications. 1317 func (c *wsClient) SendMessage(marshalledJSON []byte, doneChan chan bool) { 1318 // Don't send the message if disconnected. 1319 if c.Disconnected() { 1320 if doneChan != nil { 1321 doneChan <- false 1322 } 1323 return 1324 } 1325 1326 c.sendChan <- wsResponse{msg: marshalledJSON, doneChan: doneChan} 1327 } 1328 1329 // ErrClientQuit describes the error where a client send is not processed due 1330 // to the client having already been disconnected or dropped. 1331 var ErrClientQuit = errors.New("client quit") 1332 1333 // QueueNotification queues the passed notification to be sent to the websocket 1334 // client. This function, as the name implies, is only intended for 1335 // notifications since it has additional logic to prevent other subsystems, such 1336 // as the memory pool and block manager, from blocking even when the send 1337 // channel is full. 1338 // 1339 // If the client is in the process of shutting down, this function returns 1340 // ErrClientQuit. This is intended to be checked by long-running notification 1341 // handlers to stop processing if there is no more work needed to be done. 1342 func (c *wsClient) QueueNotification(marshalledJSON []byte) error { 1343 // Don't queue the message if disconnected. 1344 if c.Disconnected() { 1345 return ErrClientQuit 1346 } 1347 1348 c.ntfnChan <- marshalledJSON 1349 return nil 1350 } 1351 1352 // Disconnected returns whether or not the websocket client is disconnected. 1353 func (c *wsClient) Disconnected() bool { 1354 c.Lock() 1355 defer c.Unlock() 1356 1357 return c.disconnected 1358 } 1359 1360 // Disconnect disconnects the websocket client. 1361 func (c *wsClient) Disconnect() { 1362 c.Lock() 1363 defer c.Unlock() 1364 1365 // Nothing to do if already disconnected. 1366 if c.disconnected { 1367 return 1368 } 1369 1370 rpcsLog.Tracef("Disconnecting websocket client %s", c.addr) 1371 close(c.quit) 1372 c.conn.Close() 1373 c.disconnected = true 1374 } 1375 1376 // Start begins processing input and output messages. 1377 func (c *wsClient) Start() { 1378 rpcsLog.Tracef("Starting websocket client %s", c.addr) 1379 1380 // Start processing input and output. 1381 c.wg.Add(3) 1382 go c.inHandler() 1383 go c.notificationQueueHandler() 1384 go c.outHandler() 1385 } 1386 1387 // WaitForShutdown blocks until the websocket client goroutines are stopped 1388 // and the connection is closed. 1389 func (c *wsClient) WaitForShutdown() { 1390 c.wg.Wait() 1391 } 1392 1393 // newWebsocketClient returns a new websocket client given the notification 1394 // manager, websocket connection, remote address, and whether or not the client 1395 // has already been authenticated (via HTTP Basic access authentication). The 1396 // returned client is ready to start. Once started, the client will process 1397 // incoming and outgoing messages in separate goroutines complete with queuing 1398 // and asynchrous handling for long-running operations. 1399 func newWebsocketClient(server *rpcServer, conn *websocket.Conn, 1400 remoteAddr string, authenticated bool, isAdmin bool) (*wsClient, error) { 1401 1402 sessionID, err := wire.RandomUint64() 1403 if err != nil { 1404 return nil, err 1405 } 1406 1407 client := &wsClient{ 1408 conn: conn, 1409 addr: remoteAddr, 1410 authenticated: authenticated, 1411 isAdmin: isAdmin, 1412 sessionID: sessionID, 1413 server: server, 1414 addrRequests: make(map[string]struct{}), 1415 spentRequests: make(map[wire.OutPoint]struct{}), 1416 ntfnChan: make(chan []byte, 1), // nonblocking sync 1417 asyncChan: make(chan *parsedRPCCmd, 1), // nonblocking sync 1418 sendChan: make(chan wsResponse, websocketSendBufferSize), 1419 quit: make(chan struct{}), 1420 } 1421 return client, nil 1422 } 1423 1424 // handleWebsocketHelp implements the help command for websocket connections. 1425 func handleWebsocketHelp(wsc *wsClient, icmd interface{}) (interface{}, error) { 1426 cmd, ok := icmd.(*btcjson.HelpCmd) 1427 if !ok { 1428 return nil, btcjson.ErrRPCInternal 1429 } 1430 1431 // Provide a usage overview of all commands when no specific command 1432 // was specified. 1433 var command string 1434 if cmd.Command != nil { 1435 command = *cmd.Command 1436 } 1437 if command == "" { 1438 usage, err := wsc.server.helpCacher.rpcUsage(true) 1439 if err != nil { 1440 context := "Failed to generate RPC usage" 1441 return nil, internalRPCError(err.Error(), context) 1442 } 1443 return usage, nil 1444 } 1445 1446 // Check that the command asked for is supported and implemented. 1447 // Search the list of websocket handlers as well as the main list of 1448 // handlers since help should only be provided for those cases. 1449 valid := true 1450 if _, ok := rpcHandlers[command]; !ok { 1451 if _, ok := wsHandlers[command]; !ok { 1452 valid = false 1453 } 1454 } 1455 if !valid { 1456 return nil, &btcjson.RPCError{ 1457 Code: btcjson.ErrRPCInvalidParameter, 1458 Message: "Unknown command: " + command, 1459 } 1460 } 1461 1462 // Get the help for the command. 1463 help, err := wsc.server.helpCacher.rpcMethodHelp(command) 1464 if err != nil { 1465 context := "Failed to generate help" 1466 return nil, internalRPCError(err.Error(), context) 1467 } 1468 return help, nil 1469 } 1470 1471 // handleNotifyBlocks implements the notifyblocks command extension for 1472 // websocket connections. 1473 func handleNotifyBlocks(wsc *wsClient, icmd interface{}) (interface{}, error) { 1474 wsc.server.ntfnMgr.RegisterBlockUpdates(wsc) 1475 return nil, nil 1476 } 1477 1478 // handleSession implements the session command extension for websocket 1479 // connections. 1480 func handleSession(wsc *wsClient, icmd interface{}) (interface{}, error) { 1481 return &btcjson.SessionResult{SessionID: wsc.sessionID}, nil 1482 } 1483 1484 // handleStopNotifyBlocks implements the stopnotifyblocks command extension for 1485 // websocket connections. 1486 func handleStopNotifyBlocks(wsc *wsClient, icmd interface{}) (interface{}, error) { 1487 wsc.server.ntfnMgr.UnregisterBlockUpdates(wsc) 1488 return nil, nil 1489 } 1490 1491 // handleNotifySpent implements the notifyspent command extension for 1492 // websocket connections. 1493 func handleNotifySpent(wsc *wsClient, icmd interface{}) (interface{}, error) { 1494 cmd, ok := icmd.(*btcjson.NotifySpentCmd) 1495 if !ok { 1496 return nil, btcjson.ErrRPCInternal 1497 } 1498 1499 outpoints, err := deserializeOutpoints(cmd.OutPoints) 1500 if err != nil { 1501 return nil, err 1502 } 1503 1504 wsc.server.ntfnMgr.RegisterSpentRequests(wsc, outpoints) 1505 return nil, nil 1506 } 1507 1508 // handleNotifyNewTransations implements the notifynewtransactions command 1509 // extension for websocket connections. 1510 func handleNotifyNewTransactions(wsc *wsClient, icmd interface{}) (interface{}, error) { 1511 cmd, ok := icmd.(*btcjson.NotifyNewTransactionsCmd) 1512 if !ok { 1513 return nil, btcjson.ErrRPCInternal 1514 } 1515 1516 wsc.verboseTxUpdates = cmd.Verbose != nil && *cmd.Verbose 1517 wsc.server.ntfnMgr.RegisterNewMempoolTxsUpdates(wsc) 1518 return nil, nil 1519 } 1520 1521 // handleStopNotifyNewTransations implements the stopnotifynewtransactions 1522 // command extension for websocket connections. 1523 func handleStopNotifyNewTransactions(wsc *wsClient, icmd interface{}) (interface{}, error) { 1524 wsc.server.ntfnMgr.UnregisterNewMempoolTxsUpdates(wsc) 1525 return nil, nil 1526 } 1527 1528 // handleNotifyReceived implements the notifyreceived command extension for 1529 // websocket connections. 1530 func handleNotifyReceived(wsc *wsClient, icmd interface{}) (interface{}, error) { 1531 cmd, ok := icmd.(*btcjson.NotifyReceivedCmd) 1532 if !ok { 1533 return nil, btcjson.ErrRPCInternal 1534 } 1535 1536 // Decode addresses to validate input, but the strings slice is used 1537 // directly if these are all ok. 1538 err := checkAddressValidity(cmd.Addresses) 1539 if err != nil { 1540 return nil, err 1541 } 1542 1543 wsc.server.ntfnMgr.RegisterTxOutAddressRequests(wsc, cmd.Addresses) 1544 return nil, nil 1545 } 1546 1547 // handleStopNotifySpent implements the stopnotifyspent command extension for 1548 // websocket connections. 1549 func handleStopNotifySpent(wsc *wsClient, icmd interface{}) (interface{}, error) { 1550 cmd, ok := icmd.(*btcjson.StopNotifySpentCmd) 1551 if !ok { 1552 return nil, btcjson.ErrRPCInternal 1553 } 1554 1555 outpoints, err := deserializeOutpoints(cmd.OutPoints) 1556 if err != nil { 1557 return nil, err 1558 } 1559 1560 for _, outpoint := range outpoints { 1561 wsc.server.ntfnMgr.UnregisterSpentRequest(wsc, outpoint) 1562 } 1563 1564 return nil, nil 1565 } 1566 1567 // handleStopNotifyReceived implements the stopnotifyreceived command extension 1568 // for websocket connections. 1569 func handleStopNotifyReceived(wsc *wsClient, icmd interface{}) (interface{}, error) { 1570 cmd, ok := icmd.(*btcjson.StopNotifyReceivedCmd) 1571 if !ok { 1572 return nil, btcjson.ErrRPCInternal 1573 } 1574 1575 // Decode addresses to validate input, but the strings slice is used 1576 // directly if these are all ok. 1577 err := checkAddressValidity(cmd.Addresses) 1578 if err != nil { 1579 return nil, err 1580 } 1581 1582 for _, addr := range cmd.Addresses { 1583 wsc.server.ntfnMgr.UnregisterTxOutAddressRequest(wsc, addr) 1584 } 1585 1586 return nil, nil 1587 } 1588 1589 // checkAddressValidity checks the validity of each address in the passed 1590 // string slice. It does this by attempting to decode each address using the 1591 // current active network parameters. If any single address fails to decode 1592 // properly, the function returns an error. Otherwise, nil is returned. 1593 func checkAddressValidity(addrs []string) error { 1594 for _, addr := range addrs { 1595 _, err := godashutil.DecodeAddress(addr, activeNetParams.Params) 1596 if err != nil { 1597 return &btcjson.RPCError{ 1598 Code: btcjson.ErrRPCInvalidAddressOrKey, 1599 Message: fmt.Sprintf("Invalid address or key: %v", 1600 addr), 1601 } 1602 } 1603 } 1604 return nil 1605 } 1606 1607 // deserializeOutpoints deserializes each serialized outpoint. 1608 func deserializeOutpoints(serializedOuts []btcjson.OutPoint) ([]*wire.OutPoint, error) { 1609 outpoints := make([]*wire.OutPoint, 0, len(serializedOuts)) 1610 for i := range serializedOuts { 1611 blockHash, err := wire.NewShaHashFromStr(serializedOuts[i].Hash) 1612 if err != nil { 1613 return nil, rpcDecodeHexError(serializedOuts[i].Hash) 1614 } 1615 index := serializedOuts[i].Index 1616 outpoints = append(outpoints, wire.NewOutPoint(blockHash, index)) 1617 } 1618 1619 return outpoints, nil 1620 } 1621 1622 type rescanKeys struct { 1623 fallbacks map[string]struct{} 1624 pubKeyHashes map[[ripemd160.Size]byte]struct{} 1625 scriptHashes map[[ripemd160.Size]byte]struct{} 1626 compressedPubKeys map[[33]byte]struct{} 1627 uncompressedPubKeys map[[65]byte]struct{} 1628 unspent map[wire.OutPoint]struct{} 1629 } 1630 1631 // unspentSlice returns a slice of currently-unspent outpoints for the rescan 1632 // lookup keys. This is primarily intended to be used to register outpoints 1633 // for continuous notifications after a rescan has completed. 1634 func (r *rescanKeys) unspentSlice() []*wire.OutPoint { 1635 ops := make([]*wire.OutPoint, 0, len(r.unspent)) 1636 for op := range r.unspent { 1637 opCopy := op 1638 ops = append(ops, &opCopy) 1639 } 1640 return ops 1641 } 1642 1643 // ErrRescanReorg defines the error that is returned when an unrecoverable 1644 // reorganize is detected during a rescan. 1645 var ErrRescanReorg = btcjson.RPCError{ 1646 Code: btcjson.ErrRPCDatabase, 1647 Message: "Reorganize", 1648 } 1649 1650 // rescanBlock rescans all transactions in a single block. This is a helper 1651 // function for handleRescan. 1652 func rescanBlock(wsc *wsClient, lookups *rescanKeys, blk *godashutil.Block) { 1653 for _, tx := range blk.Transactions() { 1654 // Hexadecimal representation of this tx. Only created if 1655 // needed, and reused for later notifications if already made. 1656 var txHex string 1657 1658 // All inputs and outputs must be iterated through to correctly 1659 // modify the unspent map, however, just a single notification 1660 // for any matching transaction inputs or outputs should be 1661 // created and sent. 1662 spentNotified := false 1663 recvNotified := false 1664 1665 for _, txin := range tx.MsgTx().TxIn { 1666 if _, ok := lookups.unspent[txin.PreviousOutPoint]; ok { 1667 delete(lookups.unspent, txin.PreviousOutPoint) 1668 1669 if spentNotified { 1670 continue 1671 } 1672 1673 if txHex == "" { 1674 txHex = txHexString(tx) 1675 } 1676 marshalledJSON, err := newRedeemingTxNotification(txHex, tx.Index(), blk) 1677 if err != nil { 1678 rpcsLog.Errorf("Failed to marshal redeemingtx notification: %v", err) 1679 continue 1680 } 1681 1682 err = wsc.QueueNotification(marshalledJSON) 1683 // Stop the rescan early if the websocket client 1684 // disconnected. 1685 if err == ErrClientQuit { 1686 return 1687 } 1688 spentNotified = true 1689 } 1690 } 1691 1692 for txOutIdx, txout := range tx.MsgTx().TxOut { 1693 _, addrs, _, _ := txscript.ExtractPkScriptAddrs( 1694 txout.PkScript, wsc.server.server.chainParams) 1695 1696 for _, addr := range addrs { 1697 switch a := addr.(type) { 1698 case *godashutil.AddressPubKeyHash: 1699 if _, ok := lookups.pubKeyHashes[*a.Hash160()]; !ok { 1700 continue 1701 } 1702 1703 case *godashutil.AddressScriptHash: 1704 if _, ok := lookups.scriptHashes[*a.Hash160()]; !ok { 1705 continue 1706 } 1707 1708 case *godashutil.AddressPubKey: 1709 found := false 1710 switch sa := a.ScriptAddress(); len(sa) { 1711 case 33: // Compressed 1712 var key [33]byte 1713 copy(key[:], sa) 1714 if _, ok := lookups.compressedPubKeys[key]; ok { 1715 found = true 1716 } 1717 1718 case 65: // Uncompressed 1719 var key [65]byte 1720 copy(key[:], sa) 1721 if _, ok := lookups.uncompressedPubKeys[key]; ok { 1722 found = true 1723 } 1724 1725 default: 1726 rpcsLog.Warnf("Skipping rescanned pubkey of unknown "+ 1727 "serialized length %d", len(sa)) 1728 continue 1729 } 1730 1731 // If the transaction output pays to the pubkey of 1732 // a rescanned P2PKH address, include it as well. 1733 if !found { 1734 pkh := a.AddressPubKeyHash() 1735 if _, ok := lookups.pubKeyHashes[*pkh.Hash160()]; !ok { 1736 continue 1737 } 1738 } 1739 1740 default: 1741 // A new address type must have been added. Encode as a 1742 // payment address string and check the fallback map. 1743 addrStr := addr.EncodeAddress() 1744 _, ok := lookups.fallbacks[addrStr] 1745 if !ok { 1746 continue 1747 } 1748 } 1749 1750 outpoint := wire.OutPoint{ 1751 Hash: *tx.Sha(), 1752 Index: uint32(txOutIdx), 1753 } 1754 lookups.unspent[outpoint] = struct{}{} 1755 1756 if recvNotified { 1757 continue 1758 } 1759 1760 if txHex == "" { 1761 txHex = txHexString(tx) 1762 } 1763 ntfn := btcjson.NewRecvTxNtfn(txHex, 1764 blockDetails(blk, tx.Index())) 1765 1766 marshalledJSON, err := btcjson.MarshalCmd(nil, ntfn) 1767 if err != nil { 1768 rpcsLog.Errorf("Failed to marshal recvtx notification: %v", err) 1769 return 1770 } 1771 1772 err = wsc.QueueNotification(marshalledJSON) 1773 // Stop the rescan early if the websocket client 1774 // disconnected. 1775 if err == ErrClientQuit { 1776 return 1777 } 1778 recvNotified = true 1779 } 1780 } 1781 } 1782 } 1783 1784 // recoverFromReorg attempts to recover from a detected reorganize during a 1785 // rescan. It fetches a new range of block shas from the database and 1786 // verifies that the new range of blocks is on the same fork as a previous 1787 // range of blocks. If this condition does not hold true, the JSON-RPC error 1788 // for an unrecoverable reorganize is returned. 1789 func recoverFromReorg(chain *blockchain.BlockChain, minBlock, maxBlock int32, 1790 lastBlock *wire.ShaHash) ([]wire.ShaHash, error) { 1791 1792 hashList, err := chain.HeightRange(minBlock, maxBlock) 1793 if err != nil { 1794 rpcsLog.Errorf("Error looking up block range: %v", err) 1795 return nil, &btcjson.RPCError{ 1796 Code: btcjson.ErrRPCDatabase, 1797 Message: "Database error: " + err.Error(), 1798 } 1799 } 1800 if lastBlock == nil || len(hashList) == 0 { 1801 return hashList, nil 1802 } 1803 1804 blk, err := chain.BlockByHash(&hashList[0]) 1805 if err != nil { 1806 rpcsLog.Errorf("Error looking up possibly reorged block: %v", 1807 err) 1808 return nil, &btcjson.RPCError{ 1809 Code: btcjson.ErrRPCDatabase, 1810 Message: "Database error: " + err.Error(), 1811 } 1812 } 1813 jsonErr := descendantBlock(lastBlock, blk) 1814 if jsonErr != nil { 1815 return nil, jsonErr 1816 } 1817 return hashList, nil 1818 } 1819 1820 // descendantBlock returns the appropriate JSON-RPC error if a current block 1821 // fetched during a reorganize is not a direct child of the parent block hash. 1822 func descendantBlock(prevHash *wire.ShaHash, curBlock *godashutil.Block) error { 1823 curHash := &curBlock.MsgBlock().Header.PrevBlock 1824 if !prevHash.IsEqual(curHash) { 1825 rpcsLog.Errorf("Stopping rescan for reorged block %v "+ 1826 "(replaced by block %v)", prevHash, curHash) 1827 return &ErrRescanReorg 1828 } 1829 return nil 1830 } 1831 1832 // handleRescan implements the rescan command extension for websocket 1833 // connections. 1834 // 1835 // NOTE: This does not smartly handle reorgs, and fixing requires database 1836 // changes (for safe, concurrent access to full block ranges, and support 1837 // for other chains than the best chain). It will, however, detect whether 1838 // a reorg removed a block that was previously processed, and result in the 1839 // handler erroring. Clients must handle this by finding a block still in 1840 // the chain (perhaps from a rescanprogress notification) to resume their 1841 // rescan. 1842 func handleRescan(wsc *wsClient, icmd interface{}) (interface{}, error) { 1843 cmd, ok := icmd.(*btcjson.RescanCmd) 1844 if !ok { 1845 return nil, btcjson.ErrRPCInternal 1846 } 1847 1848 outpoints := make([]*wire.OutPoint, 0, len(cmd.OutPoints)) 1849 for i := range cmd.OutPoints { 1850 cmdOutpoint := &cmd.OutPoints[i] 1851 blockHash, err := wire.NewShaHashFromStr(cmdOutpoint.Hash) 1852 if err != nil { 1853 return nil, rpcDecodeHexError(cmdOutpoint.Hash) 1854 } 1855 outpoint := wire.NewOutPoint(blockHash, cmdOutpoint.Index) 1856 outpoints = append(outpoints, outpoint) 1857 } 1858 1859 numAddrs := len(cmd.Addresses) 1860 if numAddrs == 1 { 1861 rpcsLog.Info("Beginning rescan for 1 address") 1862 } else { 1863 rpcsLog.Infof("Beginning rescan for %d addresses", numAddrs) 1864 } 1865 1866 // Build lookup maps. 1867 lookups := rescanKeys{ 1868 fallbacks: map[string]struct{}{}, 1869 pubKeyHashes: map[[ripemd160.Size]byte]struct{}{}, 1870 scriptHashes: map[[ripemd160.Size]byte]struct{}{}, 1871 compressedPubKeys: map[[33]byte]struct{}{}, 1872 uncompressedPubKeys: map[[65]byte]struct{}{}, 1873 unspent: map[wire.OutPoint]struct{}{}, 1874 } 1875 var compressedPubkey [33]byte 1876 var uncompressedPubkey [65]byte 1877 for _, addrStr := range cmd.Addresses { 1878 addr, err := godashutil.DecodeAddress(addrStr, activeNetParams.Params) 1879 if err != nil { 1880 jsonErr := btcjson.RPCError{ 1881 Code: btcjson.ErrRPCInvalidAddressOrKey, 1882 Message: "Rescan address " + addrStr + ": " + 1883 err.Error(), 1884 } 1885 return nil, &jsonErr 1886 } 1887 switch a := addr.(type) { 1888 case *godashutil.AddressPubKeyHash: 1889 lookups.pubKeyHashes[*a.Hash160()] = struct{}{} 1890 1891 case *godashutil.AddressScriptHash: 1892 lookups.scriptHashes[*a.Hash160()] = struct{}{} 1893 1894 case *godashutil.AddressPubKey: 1895 pubkeyBytes := a.ScriptAddress() 1896 switch len(pubkeyBytes) { 1897 case 33: // Compressed 1898 copy(compressedPubkey[:], pubkeyBytes) 1899 lookups.compressedPubKeys[compressedPubkey] = struct{}{} 1900 1901 case 65: // Uncompressed 1902 copy(uncompressedPubkey[:], pubkeyBytes) 1903 lookups.uncompressedPubKeys[uncompressedPubkey] = struct{}{} 1904 1905 default: 1906 jsonErr := btcjson.RPCError{ 1907 Code: btcjson.ErrRPCInvalidAddressOrKey, 1908 Message: "Pubkey " + addrStr + " is of unknown length", 1909 } 1910 return nil, &jsonErr 1911 } 1912 1913 default: 1914 // A new address type must have been added. Use encoded 1915 // payment address string as a fallback until a fast path 1916 // is added. 1917 lookups.fallbacks[addrStr] = struct{}{} 1918 } 1919 } 1920 for _, outpoint := range outpoints { 1921 lookups.unspent[*outpoint] = struct{}{} 1922 } 1923 1924 chain := wsc.server.chain 1925 1926 minBlockHash, err := wire.NewShaHashFromStr(cmd.BeginBlock) 1927 if err != nil { 1928 return nil, rpcDecodeHexError(cmd.BeginBlock) 1929 } 1930 minBlock, err := chain.BlockHeightByHash(minBlockHash) 1931 if err != nil { 1932 return nil, &btcjson.RPCError{ 1933 Code: btcjson.ErrRPCBlockNotFound, 1934 Message: "Error getting block: " + err.Error(), 1935 } 1936 } 1937 1938 maxBlock := int32(math.MaxInt32) 1939 if cmd.EndBlock != nil { 1940 maxBlockHash, err := wire.NewShaHashFromStr(*cmd.EndBlock) 1941 if err != nil { 1942 return nil, rpcDecodeHexError(*cmd.EndBlock) 1943 } 1944 maxBlock, err = chain.BlockHeightByHash(maxBlockHash) 1945 if err != nil { 1946 return nil, &btcjson.RPCError{ 1947 Code: btcjson.ErrRPCBlockNotFound, 1948 Message: "Error getting block: " + err.Error(), 1949 } 1950 } 1951 } 1952 1953 // lastBlock and lastBlockHash track the previously-rescanned block. 1954 // They equal nil when no previous blocks have been rescanned. 1955 var lastBlock *godashutil.Block 1956 var lastBlockHash *wire.ShaHash 1957 1958 // A ticker is created to wait at least 10 seconds before notifying the 1959 // websocket client of the current progress completed by the rescan. 1960 ticker := time.NewTicker(10 * time.Second) 1961 defer ticker.Stop() 1962 1963 // Instead of fetching all block shas at once, fetch in smaller chunks 1964 // to ensure large rescans consume a limited amount of memory. 1965 fetchRange: 1966 for minBlock < maxBlock { 1967 // Limit the max number of hashes to fetch at once to the 1968 // maximum number of items allowed in a single inventory. 1969 // This value could be higher since it's not creating inventory 1970 // messages, but this mirrors the limiting logic used in the 1971 // peer-to-peer protocol. 1972 maxLoopBlock := maxBlock 1973 if maxLoopBlock-minBlock > wire.MaxInvPerMsg { 1974 maxLoopBlock = minBlock + wire.MaxInvPerMsg 1975 } 1976 hashList, err := chain.HeightRange(minBlock, maxLoopBlock) 1977 if err != nil { 1978 rpcsLog.Errorf("Error looking up block range: %v", err) 1979 return nil, &btcjson.RPCError{ 1980 Code: btcjson.ErrRPCDatabase, 1981 Message: "Database error: " + err.Error(), 1982 } 1983 } 1984 if len(hashList) == 0 { 1985 // The rescan is finished if no blocks hashes for this 1986 // range were successfully fetched and a stop block 1987 // was provided. 1988 if maxBlock != math.MaxInt32 { 1989 break 1990 } 1991 1992 // If the rescan is through the current block, set up 1993 // the client to continue to receive notifications 1994 // regarding all rescanned addresses and the current set 1995 // of unspent outputs. 1996 // 1997 // This is done safely by temporarily grabbing exclusive 1998 // access of the block manager. If no more blocks have 1999 // been attached between this pause and the fetch above, 2000 // then it is safe to register the websocket client for 2001 // continuous notifications if necessary. Otherwise, 2002 // continue the fetch loop again to rescan the new 2003 // blocks (or error due to an irrecoverable reorganize). 2004 blockManager := wsc.server.server.blockManager 2005 pauseGuard := blockManager.Pause() 2006 best := blockManager.chain.BestSnapshot() 2007 curHash := best.Hash 2008 again := true 2009 if lastBlockHash == nil || *lastBlockHash == *curHash { 2010 again = false 2011 n := wsc.server.ntfnMgr 2012 n.RegisterSpentRequests(wsc, lookups.unspentSlice()) 2013 n.RegisterTxOutAddressRequests(wsc, cmd.Addresses) 2014 } 2015 close(pauseGuard) 2016 if err != nil { 2017 rpcsLog.Errorf("Error fetching best block "+ 2018 "hash: %v", err) 2019 return nil, &btcjson.RPCError{ 2020 Code: btcjson.ErrRPCDatabase, 2021 Message: "Database error: " + 2022 err.Error(), 2023 } 2024 } 2025 if again { 2026 continue 2027 } 2028 break 2029 } 2030 2031 loopHashList: 2032 for i := range hashList { 2033 blk, err := chain.BlockByHash(&hashList[i]) 2034 if err != nil { 2035 // Only handle reorgs if a block could not be 2036 // found for the hash. 2037 if dbErr, ok := err.(database.Error); !ok || 2038 dbErr.ErrorCode != database.ErrBlockNotFound { 2039 2040 rpcsLog.Errorf("Error looking up "+ 2041 "block: %v", err) 2042 return nil, &btcjson.RPCError{ 2043 Code: btcjson.ErrRPCDatabase, 2044 Message: "Database error: " + 2045 err.Error(), 2046 } 2047 } 2048 2049 // If an absolute max block was specified, don't 2050 // attempt to handle the reorg. 2051 if maxBlock != math.MaxInt32 { 2052 rpcsLog.Errorf("Stopping rescan for "+ 2053 "reorged block %v", 2054 cmd.EndBlock) 2055 return nil, &ErrRescanReorg 2056 } 2057 2058 // If the lookup for the previously valid block 2059 // hash failed, there may have been a reorg. 2060 // Fetch a new range of block hashes and verify 2061 // that the previously processed block (if there 2062 // was any) still exists in the database. If it 2063 // doesn't, we error. 2064 // 2065 // A goto is used to branch executation back to 2066 // before the range was evaluated, as it must be 2067 // reevaluated for the new hashList. 2068 minBlock += int32(i) 2069 hashList, err = recoverFromReorg(chain, 2070 minBlock, maxBlock, lastBlockHash) 2071 if err != nil { 2072 return nil, err 2073 } 2074 if len(hashList) == 0 { 2075 break fetchRange 2076 } 2077 goto loopHashList 2078 } 2079 if i == 0 && lastBlockHash != nil { 2080 // Ensure the new hashList is on the same fork 2081 // as the last block from the old hashList. 2082 jsonErr := descendantBlock(lastBlockHash, blk) 2083 if jsonErr != nil { 2084 return nil, jsonErr 2085 } 2086 } 2087 2088 // A select statement is used to stop rescans if the 2089 // client requesting the rescan has disconnected. 2090 select { 2091 case <-wsc.quit: 2092 rpcsLog.Debugf("Stopped rescan at height %v "+ 2093 "for disconnected client", blk.Height()) 2094 return nil, nil 2095 default: 2096 rescanBlock(wsc, &lookups, blk) 2097 lastBlock = blk 2098 lastBlockHash = blk.Sha() 2099 } 2100 2101 // Periodically notify the client of the progress 2102 // completed. Continue with next block if no progress 2103 // notification is needed yet. 2104 select { 2105 case <-ticker.C: // fallthrough 2106 default: 2107 continue 2108 } 2109 2110 n := btcjson.NewRescanProgressNtfn(hashList[i].String(), 2111 int32(blk.Height()), 2112 blk.MsgBlock().Header.Timestamp.Unix()) 2113 mn, err := btcjson.MarshalCmd(nil, n) 2114 if err != nil { 2115 rpcsLog.Errorf("Failed to marshal rescan "+ 2116 "progress notification: %v", err) 2117 continue 2118 } 2119 2120 if err = wsc.QueueNotification(mn); err == ErrClientQuit { 2121 // Finished if the client disconnected. 2122 rpcsLog.Debugf("Stopped rescan at height %v "+ 2123 "for disconnected client", blk.Height()) 2124 return nil, nil 2125 } 2126 } 2127 2128 minBlock += int32(len(hashList)) 2129 } 2130 2131 // Notify websocket client of the finished rescan. Due to how btcd 2132 // asynchronously queues notifications to not block calling code, 2133 // there is no guarantee that any of the notifications created during 2134 // rescan (such as rescanprogress, recvtx and redeemingtx) will be 2135 // received before the rescan RPC returns. Therefore, another method 2136 // is needed to safely inform clients that all rescan notifications have 2137 // been sent. 2138 n := btcjson.NewRescanFinishedNtfn(lastBlockHash.String(), 2139 lastBlock.Height(), 2140 lastBlock.MsgBlock().Header.Timestamp.Unix()) 2141 if mn, err := btcjson.MarshalCmd(nil, n); err != nil { 2142 rpcsLog.Errorf("Failed to marshal rescan finished "+ 2143 "notification: %v", err) 2144 } else { 2145 // The rescan is finished, so we don't care whether the client 2146 // has disconnected at this point, so discard error. 2147 _ = wsc.QueueNotification(mn) 2148 } 2149 2150 rpcsLog.Info("Finished rescan") 2151 return nil, nil 2152 } 2153 2154 func init() { 2155 wsHandlers = wsHandlersBeforeInit 2156 }