github.com/lbryio/lbcd@v0.22.119/rpcclient/notify.go (about) 1 // Copyright (c) 2014-2017 The btcsuite developers 2 // Copyright (c) 2015-2017 The Decred 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 rpcclient 7 8 import ( 9 "bytes" 10 "encoding/hex" 11 "encoding/json" 12 "errors" 13 "fmt" 14 "time" 15 16 "github.com/lbryio/lbcd/btcjson" 17 "github.com/lbryio/lbcd/chaincfg/chainhash" 18 "github.com/lbryio/lbcd/wire" 19 btcutil "github.com/lbryio/lbcutil" 20 ) 21 22 var ( 23 // ErrWebsocketsRequired is an error to describe the condition where the 24 // caller is trying to use a websocket-only feature, such as requesting 25 // notifications or other websocket requests when the client is 26 // configured to run in HTTP POST mode. 27 ErrWebsocketsRequired = errors.New("a websocket connection is required " + 28 "to use this feature") 29 ) 30 31 // notificationState is used to track the current state of successfully 32 // registered notification so the state can be automatically re-established on 33 // reconnect. 34 type notificationState struct { 35 notifyBlocks bool 36 notifyNewTx bool 37 notifyNewTxVerbose bool 38 notifyReceived map[string]struct{} 39 notifySpent map[btcjson.OutPoint]struct{} 40 } 41 42 // Copy returns a deep copy of the receiver. 43 func (s *notificationState) Copy() *notificationState { 44 var stateCopy notificationState 45 stateCopy.notifyBlocks = s.notifyBlocks 46 stateCopy.notifyNewTx = s.notifyNewTx 47 stateCopy.notifyNewTxVerbose = s.notifyNewTxVerbose 48 stateCopy.notifyReceived = make(map[string]struct{}) 49 for addr := range s.notifyReceived { 50 stateCopy.notifyReceived[addr] = struct{}{} 51 } 52 stateCopy.notifySpent = make(map[btcjson.OutPoint]struct{}) 53 for op := range s.notifySpent { 54 stateCopy.notifySpent[op] = struct{}{} 55 } 56 57 return &stateCopy 58 } 59 60 // newNotificationState returns a new notification state ready to be populated. 61 func newNotificationState() *notificationState { 62 return ¬ificationState{ 63 notifyReceived: make(map[string]struct{}), 64 notifySpent: make(map[btcjson.OutPoint]struct{}), 65 } 66 } 67 68 // newNilFutureResult returns a new future result channel that already has the 69 // result waiting on the channel with the reply set to nil. This is useful 70 // to ignore things such as notifications when the caller didn't specify any 71 // notification handlers. 72 func newNilFutureResult() chan *Response { 73 responseChan := make(chan *Response, 1) 74 responseChan <- &Response{result: nil, err: nil} 75 return responseChan 76 } 77 78 // NotificationHandlers defines callback function pointers to invoke with 79 // notifications. Since all of the functions are nil by default, all 80 // notifications are effectively ignored until their handlers are set to a 81 // concrete callback. 82 // 83 // NOTE: Unless otherwise documented, these handlers must NOT directly call any 84 // blocking calls on the client instance since the input reader goroutine blocks 85 // until the callback has completed. Doing so will result in a deadlock 86 // situation. 87 type NotificationHandlers struct { 88 // OnClientConnected is invoked when the client connects or reconnects 89 // to the RPC server. This callback is run async with the rest of the 90 // notification handlers, and is safe for blocking client requests. 91 OnClientConnected func() 92 93 // OnBlockConnected is invoked when a block is connected to the longest 94 // (best) chain. It will only be invoked if a preceding call to 95 // NotifyBlocks has been made to register for the notification and the 96 // function is non-nil. 97 // 98 // Deprecated: Use OnFilteredBlockConnected instead. 99 OnBlockConnected func(hash *chainhash.Hash, height int32, t time.Time) 100 101 // OnFilteredBlockConnected is invoked when a block is connected to the 102 // longest (best) chain. It will only be invoked if a preceding call to 103 // NotifyBlocks has been made to register for the notification and the 104 // function is non-nil. Its parameters differ from OnBlockConnected: it 105 // receives the block's height, header, and relevant transactions. 106 OnFilteredBlockConnected func(height int32, header *wire.BlockHeader, 107 txs []*btcutil.Tx) 108 109 // OnBlockDisconnected is invoked when a block is disconnected from the 110 // longest (best) chain. It will only be invoked if a preceding call to 111 // NotifyBlocks has been made to register for the notification and the 112 // function is non-nil. 113 // 114 // Deprecated: Use OnFilteredBlockDisconnected instead. 115 OnBlockDisconnected func(hash *chainhash.Hash, height int32, t time.Time) 116 117 // OnFilteredBlockDisconnected is invoked when a block is disconnected 118 // from the longest (best) chain. It will only be invoked if a 119 // preceding NotifyBlocks has been made to register for the notification 120 // and the call to function is non-nil. Its parameters differ from 121 // OnBlockDisconnected: it receives the block's height and header. 122 OnFilteredBlockDisconnected func(height int32, header *wire.BlockHeader) 123 124 // OnRecvTx is invoked when a transaction that receives funds to a 125 // registered address is received into the memory pool and also 126 // connected to the longest (best) chain. It will only be invoked if a 127 // preceding call to NotifyReceived, Rescan, or RescanEndHeight has been 128 // made to register for the notification and the function is non-nil. 129 // 130 // Deprecated: Use OnRelevantTxAccepted instead. 131 OnRecvTx func(transaction *btcutil.Tx, details *btcjson.BlockDetails) 132 133 // OnRedeemingTx is invoked when a transaction that spends a registered 134 // outpoint is received into the memory pool and also connected to the 135 // longest (best) chain. It will only be invoked if a preceding call to 136 // NotifySpent, Rescan, or RescanEndHeight has been made to register for 137 // the notification and the function is non-nil. 138 // 139 // NOTE: The NotifyReceived will automatically register notifications 140 // for the outpoints that are now "owned" as a result of receiving 141 // funds to the registered addresses. This means it is possible for 142 // this to invoked indirectly as the result of a NotifyReceived call. 143 // 144 // Deprecated: Use OnRelevantTxAccepted instead. 145 OnRedeemingTx func(transaction *btcutil.Tx, details *btcjson.BlockDetails) 146 147 // OnRelevantTxAccepted is invoked when an unmined transaction passes 148 // the client's transaction filter. 149 // 150 // NOTE: This is a btcsuite extension ported from 151 // github.com/decred/dcrrpcclient. 152 OnRelevantTxAccepted func(transaction []byte) 153 154 // OnRescanFinished is invoked after a rescan finishes due to a previous 155 // call to Rescan or RescanEndHeight. Finished rescans should be 156 // signaled on this notification, rather than relying on the return 157 // result of a rescan request, due to how btcd may send various rescan 158 // notifications after the rescan request has already returned. 159 // 160 // Deprecated: Not used with RescanBlocks. 161 OnRescanFinished func(hash *chainhash.Hash, height int32, blkTime time.Time) 162 163 // OnRescanProgress is invoked periodically when a rescan is underway. 164 // It will only be invoked if a preceding call to Rescan or 165 // RescanEndHeight has been made and the function is non-nil. 166 // 167 // Deprecated: Not used with RescanBlocks. 168 OnRescanProgress func(hash *chainhash.Hash, height int32, blkTime time.Time) 169 170 // OnTxAccepted is invoked when a transaction is accepted into the 171 // memory pool. It will only be invoked if a preceding call to 172 // NotifyNewTransactions with the verbose flag set to false has been 173 // made to register for the notification and the function is non-nil. 174 OnTxAccepted func(hash *chainhash.Hash, amount btcutil.Amount) 175 176 // OnTxAccepted is invoked when a transaction is accepted into the 177 // memory pool. It will only be invoked if a preceding call to 178 // NotifyNewTransactions with the verbose flag set to true has been 179 // made to register for the notification and the function is non-nil. 180 OnTxAcceptedVerbose func(txDetails *btcjson.TxRawResult) 181 182 // OnBtcdConnected is invoked when a wallet connects or disconnects from 183 // btcd. 184 // 185 // This will only be available when client is connected to a wallet 186 // server such as btcwallet. 187 OnBtcdConnected func(connected bool) 188 189 // OnAccountBalance is invoked with account balance updates. 190 // 191 // This will only be available when speaking to a wallet server 192 // such as btcwallet. 193 OnAccountBalance func(account string, balance btcutil.Amount, confirmed bool) 194 195 // OnWalletLockState is invoked when a wallet is locked or unlocked. 196 // 197 // This will only be available when client is connected to a wallet 198 // server such as btcwallet. 199 OnWalletLockState func(locked bool) 200 201 // OnUnknownNotification is invoked when an unrecognized notification 202 // is received. This typically means the notification handling code 203 // for this package needs to be updated for a new notification type or 204 // the caller is using a custom notification this package does not know 205 // about. 206 OnUnknownNotification func(method string, params []json.RawMessage) 207 } 208 209 // handleNotification examines the passed notification type, performs 210 // conversions to get the raw notification types into higher level types and 211 // delivers the notification to the appropriate On<X> handler registered with 212 // the client. 213 func (c *Client) handleNotification(ntfn *rawNotification) { 214 // Ignore the notification if the client is not interested in any 215 // notifications. 216 if c.ntfnHandlers == nil { 217 return 218 } 219 220 switch ntfn.Method { 221 // OnBlockConnected 222 case btcjson.BlockConnectedNtfnMethod: 223 // Ignore the notification if the client is not interested in 224 // it. 225 if c.ntfnHandlers.OnBlockConnected == nil { 226 return 227 } 228 229 blockHash, blockHeight, blockTime, err := parseChainNtfnParams(ntfn.Params) 230 if err != nil { 231 log.Warnf("Received invalid block connected "+ 232 "notification: %v", err) 233 return 234 } 235 236 c.ntfnHandlers.OnBlockConnected(blockHash, blockHeight, blockTime) 237 238 // OnFilteredBlockConnected 239 case btcjson.FilteredBlockConnectedNtfnMethod: 240 // Ignore the notification if the client is not interested in 241 // it. 242 if c.ntfnHandlers.OnFilteredBlockConnected == nil { 243 return 244 } 245 246 blockHeight, blockHeader, transactions, err := 247 parseFilteredBlockConnectedParams(ntfn.Params) 248 if err != nil { 249 log.Warnf("Received invalid filtered block "+ 250 "connected notification: %v", err) 251 return 252 } 253 254 c.ntfnHandlers.OnFilteredBlockConnected(blockHeight, 255 blockHeader, transactions) 256 257 // OnBlockDisconnected 258 case btcjson.BlockDisconnectedNtfnMethod: 259 // Ignore the notification if the client is not interested in 260 // it. 261 if c.ntfnHandlers.OnBlockDisconnected == nil { 262 return 263 } 264 265 blockHash, blockHeight, blockTime, err := parseChainNtfnParams(ntfn.Params) 266 if err != nil { 267 log.Warnf("Received invalid block connected "+ 268 "notification: %v", err) 269 return 270 } 271 272 c.ntfnHandlers.OnBlockDisconnected(blockHash, blockHeight, blockTime) 273 274 // OnFilteredBlockDisconnected 275 case btcjson.FilteredBlockDisconnectedNtfnMethod: 276 // Ignore the notification if the client is not interested in 277 // it. 278 if c.ntfnHandlers.OnFilteredBlockDisconnected == nil { 279 return 280 } 281 282 blockHeight, blockHeader, err := 283 parseFilteredBlockDisconnectedParams(ntfn.Params) 284 if err != nil { 285 log.Warnf("Received invalid filtered block "+ 286 "disconnected notification: %v", err) 287 return 288 } 289 290 c.ntfnHandlers.OnFilteredBlockDisconnected(blockHeight, 291 blockHeader) 292 293 // OnRecvTx 294 case btcjson.RecvTxNtfnMethod: 295 // Ignore the notification if the client is not interested in 296 // it. 297 if c.ntfnHandlers.OnRecvTx == nil { 298 return 299 } 300 301 tx, block, err := parseChainTxNtfnParams(ntfn.Params) 302 if err != nil { 303 log.Warnf("Received invalid recvtx notification: %v", 304 err) 305 return 306 } 307 308 c.ntfnHandlers.OnRecvTx(tx, block) 309 310 // OnRedeemingTx 311 case btcjson.RedeemingTxNtfnMethod: 312 // Ignore the notification if the client is not interested in 313 // it. 314 if c.ntfnHandlers.OnRedeemingTx == nil { 315 return 316 } 317 318 tx, block, err := parseChainTxNtfnParams(ntfn.Params) 319 if err != nil { 320 log.Warnf("Received invalid redeemingtx "+ 321 "notification: %v", err) 322 return 323 } 324 325 c.ntfnHandlers.OnRedeemingTx(tx, block) 326 327 // OnRelevantTxAccepted 328 case btcjson.RelevantTxAcceptedNtfnMethod: 329 // Ignore the notification if the client is not interested in 330 // it. 331 if c.ntfnHandlers.OnRelevantTxAccepted == nil { 332 return 333 } 334 335 transaction, err := parseRelevantTxAcceptedParams(ntfn.Params) 336 if err != nil { 337 log.Warnf("Received invalid relevanttxaccepted "+ 338 "notification: %v", err) 339 return 340 } 341 342 c.ntfnHandlers.OnRelevantTxAccepted(transaction) 343 344 // OnRescanFinished 345 case btcjson.RescanFinishedNtfnMethod: 346 // Ignore the notification if the client is not interested in 347 // it. 348 if c.ntfnHandlers.OnRescanFinished == nil { 349 return 350 } 351 352 hash, height, blkTime, err := parseRescanProgressParams(ntfn.Params) 353 if err != nil { 354 log.Warnf("Received invalid rescanfinished "+ 355 "notification: %v", err) 356 return 357 } 358 359 c.ntfnHandlers.OnRescanFinished(hash, height, blkTime) 360 361 // OnRescanProgress 362 case btcjson.RescanProgressNtfnMethod: 363 // Ignore the notification if the client is not interested in 364 // it. 365 if c.ntfnHandlers.OnRescanProgress == nil { 366 return 367 } 368 369 hash, height, blkTime, err := parseRescanProgressParams(ntfn.Params) 370 if err != nil { 371 log.Warnf("Received invalid rescanprogress "+ 372 "notification: %v", err) 373 return 374 } 375 376 c.ntfnHandlers.OnRescanProgress(hash, height, blkTime) 377 378 // OnTxAccepted 379 case btcjson.TxAcceptedNtfnMethod: 380 // Ignore the notification if the client is not interested in 381 // it. 382 if c.ntfnHandlers.OnTxAccepted == nil { 383 return 384 } 385 386 hash, amt, err := parseTxAcceptedNtfnParams(ntfn.Params) 387 if err != nil { 388 log.Warnf("Received invalid tx accepted "+ 389 "notification: %v", err) 390 return 391 } 392 393 c.ntfnHandlers.OnTxAccepted(hash, amt) 394 395 // OnTxAcceptedVerbose 396 case btcjson.TxAcceptedVerboseNtfnMethod: 397 // Ignore the notification if the client is not interested in 398 // it. 399 if c.ntfnHandlers.OnTxAcceptedVerbose == nil { 400 return 401 } 402 403 rawTx, err := parseTxAcceptedVerboseNtfnParams(ntfn.Params) 404 if err != nil { 405 log.Warnf("Received invalid tx accepted verbose "+ 406 "notification: %v", err) 407 return 408 } 409 410 c.ntfnHandlers.OnTxAcceptedVerbose(rawTx) 411 412 // OnBtcdConnected 413 case btcjson.BtcdConnectedNtfnMethod: 414 // Ignore the notification if the client is not interested in 415 // it. 416 if c.ntfnHandlers.OnBtcdConnected == nil { 417 return 418 } 419 420 connected, err := parseBtcdConnectedNtfnParams(ntfn.Params) 421 if err != nil { 422 log.Warnf("Received invalid lbcd connected "+ 423 "notification: %v", err) 424 return 425 } 426 427 c.ntfnHandlers.OnBtcdConnected(connected) 428 429 // OnAccountBalance 430 case btcjson.AccountBalanceNtfnMethod: 431 // Ignore the notification if the client is not interested in 432 // it. 433 if c.ntfnHandlers.OnAccountBalance == nil { 434 return 435 } 436 437 account, bal, conf, err := parseAccountBalanceNtfnParams(ntfn.Params) 438 if err != nil { 439 log.Warnf("Received invalid account balance "+ 440 "notification: %v", err) 441 return 442 } 443 444 c.ntfnHandlers.OnAccountBalance(account, bal, conf) 445 446 // OnWalletLockState 447 case btcjson.WalletLockStateNtfnMethod: 448 // Ignore the notification if the client is not interested in 449 // it. 450 if c.ntfnHandlers.OnWalletLockState == nil { 451 return 452 } 453 454 // The account name is not notified, so the return value is 455 // discarded. 456 _, locked, err := parseWalletLockStateNtfnParams(ntfn.Params) 457 if err != nil { 458 log.Warnf("Received invalid wallet lock state "+ 459 "notification: %v", err) 460 return 461 } 462 463 c.ntfnHandlers.OnWalletLockState(locked) 464 465 // OnUnknownNotification 466 default: 467 if c.ntfnHandlers.OnUnknownNotification == nil { 468 return 469 } 470 471 c.ntfnHandlers.OnUnknownNotification(ntfn.Method, ntfn.Params) 472 } 473 } 474 475 // wrongNumParams is an error type describing an unparseable JSON-RPC 476 // notificiation due to an incorrect number of parameters for the 477 // expected notification type. The value is the number of parameters 478 // of the invalid notification. 479 type wrongNumParams int 480 481 // Error satisifies the builtin error interface. 482 func (e wrongNumParams) Error() string { 483 return fmt.Sprintf("wrong number of parameters (%d)", e) 484 } 485 486 // parseChainNtfnParams parses out the block hash and height from the parameters 487 // of blockconnected and blockdisconnected notifications. 488 func parseChainNtfnParams(params []json.RawMessage) (*chainhash.Hash, 489 int32, time.Time, error) { 490 491 if len(params) != 3 { 492 return nil, 0, time.Time{}, wrongNumParams(len(params)) 493 } 494 495 // Unmarshal first parameter as a string. 496 var blockHashStr string 497 err := json.Unmarshal(params[0], &blockHashStr) 498 if err != nil { 499 return nil, 0, time.Time{}, err 500 } 501 502 // Unmarshal second parameter as an integer. 503 var blockHeight int32 504 err = json.Unmarshal(params[1], &blockHeight) 505 if err != nil { 506 return nil, 0, time.Time{}, err 507 } 508 509 // Unmarshal third parameter as unix time. 510 var blockTimeUnix int64 511 err = json.Unmarshal(params[2], &blockTimeUnix) 512 if err != nil { 513 return nil, 0, time.Time{}, err 514 } 515 516 // Create hash from block hash string. 517 blockHash, err := chainhash.NewHashFromStr(blockHashStr) 518 if err != nil { 519 return nil, 0, time.Time{}, err 520 } 521 522 // Create time.Time from unix time. 523 blockTime := time.Unix(blockTimeUnix, 0) 524 525 return blockHash, blockHeight, blockTime, nil 526 } 527 528 // parseFilteredBlockConnectedParams parses out the parameters included in a 529 // filteredblockconnected notification. 530 // 531 // NOTE: This is a btcd extension ported from github.com/decred/dcrrpcclient 532 // and requires a websocket connection. 533 func parseFilteredBlockConnectedParams(params []json.RawMessage) (int32, 534 *wire.BlockHeader, []*btcutil.Tx, error) { 535 536 if len(params) < 3 { 537 return 0, nil, nil, wrongNumParams(len(params)) 538 } 539 540 // Unmarshal first parameter as an integer. 541 var blockHeight int32 542 err := json.Unmarshal(params[0], &blockHeight) 543 if err != nil { 544 return 0, nil, nil, err 545 } 546 547 // Unmarshal second parameter as a slice of bytes. 548 blockHeaderBytes, err := parseHexParam(params[1]) 549 if err != nil { 550 return 0, nil, nil, err 551 } 552 553 // Deserialize block header from slice of bytes. 554 var blockHeader wire.BlockHeader 555 err = blockHeader.Deserialize(bytes.NewReader(blockHeaderBytes)) 556 if err != nil { 557 return 0, nil, nil, err 558 } 559 560 // Unmarshal third parameter as a slice of hex-encoded strings. 561 var hexTransactions []string 562 err = json.Unmarshal(params[2], &hexTransactions) 563 if err != nil { 564 return 0, nil, nil, err 565 } 566 567 // Create slice of transactions from slice of strings by hex-decoding. 568 transactions := make([]*btcutil.Tx, len(hexTransactions)) 569 for i, hexTx := range hexTransactions { 570 transaction, err := hex.DecodeString(hexTx) 571 if err != nil { 572 return 0, nil, nil, err 573 } 574 575 transactions[i], err = btcutil.NewTxFromBytes(transaction) 576 if err != nil { 577 return 0, nil, nil, err 578 } 579 } 580 581 return blockHeight, &blockHeader, transactions, nil 582 } 583 584 // parseFilteredBlockDisconnectedParams parses out the parameters included in a 585 // filteredblockdisconnected notification. 586 // 587 // NOTE: This is a btcd extension ported from github.com/decred/dcrrpcclient 588 // and requires a websocket connection. 589 func parseFilteredBlockDisconnectedParams(params []json.RawMessage) (int32, 590 *wire.BlockHeader, error) { 591 if len(params) < 2 { 592 return 0, nil, wrongNumParams(len(params)) 593 } 594 595 // Unmarshal first parameter as an integer. 596 var blockHeight int32 597 err := json.Unmarshal(params[0], &blockHeight) 598 if err != nil { 599 return 0, nil, err 600 } 601 602 // Unmarshal second parmeter as a slice of bytes. 603 blockHeaderBytes, err := parseHexParam(params[1]) 604 if err != nil { 605 return 0, nil, err 606 } 607 608 // Deserialize block header from slice of bytes. 609 var blockHeader wire.BlockHeader 610 err = blockHeader.Deserialize(bytes.NewReader(blockHeaderBytes)) 611 if err != nil { 612 return 0, nil, err 613 } 614 615 return blockHeight, &blockHeader, nil 616 } 617 618 func parseHexParam(param json.RawMessage) ([]byte, error) { 619 var s string 620 err := json.Unmarshal(param, &s) 621 if err != nil { 622 return nil, err 623 } 624 return hex.DecodeString(s) 625 } 626 627 // parseRelevantTxAcceptedParams parses out the parameter included in a 628 // relevanttxaccepted notification. 629 func parseRelevantTxAcceptedParams(params []json.RawMessage) (transaction []byte, err error) { 630 if len(params) < 1 { 631 return nil, wrongNumParams(len(params)) 632 } 633 634 return parseHexParam(params[0]) 635 } 636 637 // parseChainTxNtfnParams parses out the transaction and optional details about 638 // the block it's mined in from the parameters of recvtx and redeemingtx 639 // notifications. 640 func parseChainTxNtfnParams(params []json.RawMessage) (*btcutil.Tx, 641 *btcjson.BlockDetails, error) { 642 643 if len(params) == 0 || len(params) > 2 { 644 return nil, nil, wrongNumParams(len(params)) 645 } 646 647 // Unmarshal first parameter as a string. 648 var txHex string 649 err := json.Unmarshal(params[0], &txHex) 650 if err != nil { 651 return nil, nil, err 652 } 653 654 // If present, unmarshal second optional parameter as the block details 655 // JSON object. 656 var block *btcjson.BlockDetails 657 if len(params) > 1 { 658 err = json.Unmarshal(params[1], &block) 659 if err != nil { 660 return nil, nil, err 661 } 662 } 663 664 // Hex decode and deserialize the transaction. 665 serializedTx, err := hex.DecodeString(txHex) 666 if err != nil { 667 return nil, nil, err 668 } 669 var msgTx wire.MsgTx 670 err = msgTx.Deserialize(bytes.NewReader(serializedTx)) 671 if err != nil { 672 return nil, nil, err 673 } 674 675 // TODO: Change recvtx and redeemingtx callback signatures to use 676 // nicer types for details about the block (block hash as a 677 // chainhash.Hash, block time as a time.Time, etc.). 678 return btcutil.NewTx(&msgTx), block, nil 679 } 680 681 // parseRescanProgressParams parses out the height of the last rescanned block 682 // from the parameters of rescanfinished and rescanprogress notifications. 683 func parseRescanProgressParams(params []json.RawMessage) (*chainhash.Hash, int32, time.Time, error) { 684 if len(params) != 3 { 685 return nil, 0, time.Time{}, wrongNumParams(len(params)) 686 } 687 688 // Unmarshal first parameter as an string. 689 var hashStr string 690 err := json.Unmarshal(params[0], &hashStr) 691 if err != nil { 692 return nil, 0, time.Time{}, err 693 } 694 695 // Unmarshal second parameter as an integer. 696 var height int32 697 err = json.Unmarshal(params[1], &height) 698 if err != nil { 699 return nil, 0, time.Time{}, err 700 } 701 702 // Unmarshal third parameter as an integer. 703 var blkTime int64 704 err = json.Unmarshal(params[2], &blkTime) 705 if err != nil { 706 return nil, 0, time.Time{}, err 707 } 708 709 // Decode string encoding of block hash. 710 hash, err := chainhash.NewHashFromStr(hashStr) 711 if err != nil { 712 return nil, 0, time.Time{}, err 713 } 714 715 return hash, height, time.Unix(blkTime, 0), nil 716 } 717 718 // parseTxAcceptedNtfnParams parses out the transaction hash and total amount 719 // from the parameters of a txaccepted notification. 720 func parseTxAcceptedNtfnParams(params []json.RawMessage) (*chainhash.Hash, 721 btcutil.Amount, error) { 722 723 if len(params) != 2 { 724 return nil, 0, wrongNumParams(len(params)) 725 } 726 727 // Unmarshal first parameter as a string. 728 var txHashStr string 729 err := json.Unmarshal(params[0], &txHashStr) 730 if err != nil { 731 return nil, 0, err 732 } 733 734 // Unmarshal second parameter as a floating point number. 735 var famt float64 736 err = json.Unmarshal(params[1], &famt) 737 if err != nil { 738 return nil, 0, err 739 } 740 741 // Bounds check amount. 742 amt, err := btcutil.NewAmount(famt) 743 if err != nil { 744 return nil, 0, err 745 } 746 747 // Decode string encoding of transaction sha. 748 txHash, err := chainhash.NewHashFromStr(txHashStr) 749 if err != nil { 750 return nil, 0, err 751 } 752 753 return txHash, amt, nil 754 } 755 756 // parseTxAcceptedVerboseNtfnParams parses out details about a raw transaction 757 // from the parameters of a txacceptedverbose notification. 758 func parseTxAcceptedVerboseNtfnParams(params []json.RawMessage) (*btcjson.TxRawResult, 759 error) { 760 761 if len(params) != 1 { 762 return nil, wrongNumParams(len(params)) 763 } 764 765 // Unmarshal first parameter as a raw transaction result object. 766 var rawTx btcjson.TxRawResult 767 err := json.Unmarshal(params[0], &rawTx) 768 if err != nil { 769 return nil, err 770 } 771 772 // TODO: change txacceptedverbose notification callbacks to use nicer 773 // types for all details about the transaction (i.e. decoding hashes 774 // from their string encoding). 775 return &rawTx, nil 776 } 777 778 // parseBtcdConnectedNtfnParams parses out the connection status of btcd 779 // and btcwallet from the parameters of a btcdconnected notification. 780 func parseBtcdConnectedNtfnParams(params []json.RawMessage) (bool, error) { 781 if len(params) != 1 { 782 return false, wrongNumParams(len(params)) 783 } 784 785 // Unmarshal first parameter as a boolean. 786 var connected bool 787 err := json.Unmarshal(params[0], &connected) 788 if err != nil { 789 return false, err 790 } 791 792 return connected, nil 793 } 794 795 // parseAccountBalanceNtfnParams parses out the account name, total balance, 796 // and whether or not the balance is confirmed or unconfirmed from the 797 // parameters of an accountbalance notification. 798 func parseAccountBalanceNtfnParams(params []json.RawMessage) (account string, 799 balance btcutil.Amount, confirmed bool, err error) { 800 801 if len(params) != 3 { 802 return "", 0, false, wrongNumParams(len(params)) 803 } 804 805 // Unmarshal first parameter as a string. 806 err = json.Unmarshal(params[0], &account) 807 if err != nil { 808 return "", 0, false, err 809 } 810 811 // Unmarshal second parameter as a floating point number. 812 var fbal float64 813 err = json.Unmarshal(params[1], &fbal) 814 if err != nil { 815 return "", 0, false, err 816 } 817 818 // Unmarshal third parameter as a boolean. 819 err = json.Unmarshal(params[2], &confirmed) 820 if err != nil { 821 return "", 0, false, err 822 } 823 824 // Bounds check amount. 825 bal, err := btcutil.NewAmount(fbal) 826 if err != nil { 827 return "", 0, false, err 828 } 829 830 return account, bal, confirmed, nil 831 } 832 833 // parseWalletLockStateNtfnParams parses out the account name and locked 834 // state of an account from the parameters of a walletlockstate notification. 835 func parseWalletLockStateNtfnParams(params []json.RawMessage) (account string, 836 locked bool, err error) { 837 838 if len(params) != 2 { 839 return "", false, wrongNumParams(len(params)) 840 } 841 842 // Unmarshal first parameter as a string. 843 err = json.Unmarshal(params[0], &account) 844 if err != nil { 845 return "", false, err 846 } 847 848 // Unmarshal second parameter as a boolean. 849 err = json.Unmarshal(params[1], &locked) 850 if err != nil { 851 return "", false, err 852 } 853 854 return account, locked, nil 855 } 856 857 // FutureNotifyBlocksResult is a future promise to deliver the result of a 858 // NotifyBlocksAsync RPC invocation (or an applicable error). 859 type FutureNotifyBlocksResult chan *Response 860 861 // Receive waits for the Response promised by the future and returns an error 862 // if the registration was not successful. 863 func (r FutureNotifyBlocksResult) Receive() error { 864 _, err := ReceiveFuture(r) 865 return err 866 } 867 868 // NotifyBlocksAsync returns an instance of a type that can be used to get the 869 // result of the RPC at some future time by invoking the Receive function on 870 // the returned instance. 871 // 872 // See NotifyBlocks for the blocking version and more details. 873 // 874 // NOTE: This is a btcd extension and requires a websocket connection. 875 func (c *Client) NotifyBlocksAsync() FutureNotifyBlocksResult { 876 // Not supported in HTTP POST mode. 877 if c.config.HTTPPostMode { 878 return newFutureError(ErrWebsocketsRequired) 879 } 880 881 // Ignore the notification if the client is not interested in 882 // notifications. 883 if c.ntfnHandlers == nil { 884 return newNilFutureResult() 885 } 886 887 cmd := btcjson.NewNotifyBlocksCmd() 888 return c.SendCmd(cmd) 889 } 890 891 // NotifyBlocks registers the client to receive notifications when blocks are 892 // connected and disconnected from the main chain. The notifications are 893 // delivered to the notification handlers associated with the client. Calling 894 // this function has no effect if there are no notification handlers and will 895 // result in an error if the client is configured to run in HTTP POST mode. 896 // 897 // The notifications delivered as a result of this call will be via one of 898 // OnBlockConnected or OnBlockDisconnected. 899 // 900 // NOTE: This is a btcd extension and requires a websocket connection. 901 func (c *Client) NotifyBlocks() error { 902 return c.NotifyBlocksAsync().Receive() 903 } 904 905 // FutureNotifySpentResult is a future promise to deliver the result of a 906 // NotifySpentAsync RPC invocation (or an applicable error). 907 // 908 // Deprecated: Use FutureLoadTxFilterResult instead. 909 type FutureNotifySpentResult chan *Response 910 911 // Receive waits for the Response promised by the future and returns an error 912 // if the registration was not successful. 913 func (r FutureNotifySpentResult) Receive() error { 914 _, err := ReceiveFuture(r) 915 return err 916 } 917 918 // notifySpentInternal is the same as notifySpentAsync except it accepts 919 // the converted outpoints as a parameter so the client can more efficiently 920 // recreate the previous notification state on reconnect. 921 func (c *Client) notifySpentInternal(outpoints []btcjson.OutPoint) FutureNotifySpentResult { 922 // Not supported in HTTP POST mode. 923 if c.config.HTTPPostMode { 924 return newFutureError(ErrWebsocketsRequired) 925 } 926 927 // Ignore the notification if the client is not interested in 928 // notifications. 929 if c.ntfnHandlers == nil { 930 return newNilFutureResult() 931 } 932 933 cmd := btcjson.NewNotifySpentCmd(outpoints) 934 return c.SendCmd(cmd) 935 } 936 937 // newOutPointFromWire constructs the btcjson representation of a transaction 938 // outpoint from the wire type. 939 func newOutPointFromWire(op *wire.OutPoint) btcjson.OutPoint { 940 return btcjson.OutPoint{ 941 Hash: op.Hash.String(), 942 Index: op.Index, 943 } 944 } 945 946 // NotifySpentAsync returns an instance of a type that can be used to get the 947 // result of the RPC at some future time by invoking the Receive function on 948 // the returned instance. 949 // 950 // See NotifySpent for the blocking version and more details. 951 // 952 // NOTE: This is a btcd extension and requires a websocket connection. 953 // 954 // Deprecated: Use LoadTxFilterAsync instead. 955 func (c *Client) NotifySpentAsync(outpoints []*wire.OutPoint) FutureNotifySpentResult { 956 // Not supported in HTTP POST mode. 957 if c.config.HTTPPostMode { 958 return newFutureError(ErrWebsocketsRequired) 959 } 960 961 // Ignore the notification if the client is not interested in 962 // notifications. 963 if c.ntfnHandlers == nil { 964 return newNilFutureResult() 965 } 966 967 ops := make([]btcjson.OutPoint, 0, len(outpoints)) 968 for _, outpoint := range outpoints { 969 ops = append(ops, newOutPointFromWire(outpoint)) 970 } 971 cmd := btcjson.NewNotifySpentCmd(ops) 972 return c.SendCmd(cmd) 973 } 974 975 // NotifySpent registers the client to receive notifications when the passed 976 // transaction outputs are spent. The notifications are delivered to the 977 // notification handlers associated with the client. Calling this function has 978 // no effect if there are no notification handlers and will result in an error 979 // if the client is configured to run in HTTP POST mode. 980 // 981 // The notifications delivered as a result of this call will be via 982 // OnRedeemingTx. 983 // 984 // NOTE: This is a btcd extension and requires a websocket connection. 985 // 986 // Deprecated: Use LoadTxFilter instead. 987 func (c *Client) NotifySpent(outpoints []*wire.OutPoint) error { 988 return c.NotifySpentAsync(outpoints).Receive() 989 } 990 991 // FutureNotifyNewTransactionsResult is a future promise to deliver the result 992 // of a NotifyNewTransactionsAsync RPC invocation (or an applicable error). 993 type FutureNotifyNewTransactionsResult chan *Response 994 995 // Receive waits for the Response promised by the future and returns an error 996 // if the registration was not successful. 997 func (r FutureNotifyNewTransactionsResult) Receive() error { 998 _, err := ReceiveFuture(r) 999 return err 1000 } 1001 1002 // NotifyNewTransactionsAsync returns an instance of a type that can be used to 1003 // get the result of the RPC at some future time by invoking the Receive 1004 // function on the returned instance. 1005 // 1006 // See NotifyNewTransactionsAsync for the blocking version and more details. 1007 // 1008 // NOTE: This is a btcd extension and requires a websocket connection. 1009 func (c *Client) NotifyNewTransactionsAsync(verbose bool) FutureNotifyNewTransactionsResult { 1010 // Not supported in HTTP POST mode. 1011 if c.config.HTTPPostMode { 1012 return newFutureError(ErrWebsocketsRequired) 1013 } 1014 1015 // Ignore the notification if the client is not interested in 1016 // notifications. 1017 if c.ntfnHandlers == nil { 1018 return newNilFutureResult() 1019 } 1020 1021 cmd := btcjson.NewNotifyNewTransactionsCmd(&verbose) 1022 return c.SendCmd(cmd) 1023 } 1024 1025 // NotifyNewTransactions registers the client to receive notifications every 1026 // time a new transaction is accepted to the memory pool. The notifications are 1027 // delivered to the notification handlers associated with the client. Calling 1028 // this function has no effect if there are no notification handlers and will 1029 // result in an error if the client is configured to run in HTTP POST mode. 1030 // 1031 // The notifications delivered as a result of this call will be via one of 1032 // OnTxAccepted (when verbose is false) or OnTxAcceptedVerbose (when verbose is 1033 // true). 1034 // 1035 // NOTE: This is a btcd extension and requires a websocket connection. 1036 func (c *Client) NotifyNewTransactions(verbose bool) error { 1037 return c.NotifyNewTransactionsAsync(verbose).Receive() 1038 } 1039 1040 // FutureNotifyReceivedResult is a future promise to deliver the result of a 1041 // NotifyReceivedAsync RPC invocation (or an applicable error). 1042 // 1043 // Deprecated: Use FutureLoadTxFilterResult instead. 1044 type FutureNotifyReceivedResult chan *Response 1045 1046 // Receive waits for the Response promised by the future and returns an error 1047 // if the registration was not successful. 1048 func (r FutureNotifyReceivedResult) Receive() error { 1049 _, err := ReceiveFuture(r) 1050 return err 1051 } 1052 1053 // notifyReceivedInternal is the same as notifyReceivedAsync except it accepts 1054 // the converted addresses as a parameter so the client can more efficiently 1055 // recreate the previous notification state on reconnect. 1056 func (c *Client) notifyReceivedInternal(addresses []string) FutureNotifyReceivedResult { 1057 // Not supported in HTTP POST mode. 1058 if c.config.HTTPPostMode { 1059 return newFutureError(ErrWebsocketsRequired) 1060 } 1061 1062 // Ignore the notification if the client is not interested in 1063 // notifications. 1064 if c.ntfnHandlers == nil { 1065 return newNilFutureResult() 1066 } 1067 1068 // Convert addresses to strings. 1069 cmd := btcjson.NewNotifyReceivedCmd(addresses) 1070 return c.SendCmd(cmd) 1071 } 1072 1073 // NotifyReceivedAsync returns an instance of a type that can be used to get the 1074 // result of the RPC at some future time by invoking the Receive function on 1075 // the returned instance. 1076 // 1077 // See NotifyReceived for the blocking version and more details. 1078 // 1079 // NOTE: This is a btcd extension and requires a websocket connection. 1080 // 1081 // Deprecated: Use LoadTxFilterAsync instead. 1082 func (c *Client) NotifyReceivedAsync(addresses []btcutil.Address) FutureNotifyReceivedResult { 1083 // Not supported in HTTP POST mode. 1084 if c.config.HTTPPostMode { 1085 return newFutureError(ErrWebsocketsRequired) 1086 } 1087 1088 // Ignore the notification if the client is not interested in 1089 // notifications. 1090 if c.ntfnHandlers == nil { 1091 return newNilFutureResult() 1092 } 1093 1094 // Convert addresses to strings. 1095 addrs := make([]string, 0, len(addresses)) 1096 for _, addr := range addresses { 1097 addrs = append(addrs, addr.String()) 1098 } 1099 cmd := btcjson.NewNotifyReceivedCmd(addrs) 1100 return c.SendCmd(cmd) 1101 } 1102 1103 // NotifyReceived registers the client to receive notifications every time a 1104 // new transaction which pays to one of the passed addresses is accepted to 1105 // memory pool or in a block connected to the block chain. In addition, when 1106 // one of these transactions is detected, the client is also automatically 1107 // registered for notifications when the new transaction outpoints the address 1108 // now has available are spent (See NotifySpent). The notifications are 1109 // delivered to the notification handlers associated with the client. Calling 1110 // this function has no effect if there are no notification handlers and will 1111 // result in an error if the client is configured to run in HTTP POST mode. 1112 // 1113 // The notifications delivered as a result of this call will be via one of 1114 // *OnRecvTx (for transactions that receive funds to one of the passed 1115 // addresses) or OnRedeemingTx (for transactions which spend from one 1116 // of the outpoints which are automatically registered upon receipt of funds to 1117 // the address). 1118 // 1119 // NOTE: This is a btcd extension and requires a websocket connection. 1120 // 1121 // Deprecated: Use LoadTxFilter instead. 1122 func (c *Client) NotifyReceived(addresses []btcutil.Address) error { 1123 return c.NotifyReceivedAsync(addresses).Receive() 1124 } 1125 1126 // FutureRescanResult is a future promise to deliver the result of a RescanAsync 1127 // or RescanEndHeightAsync RPC invocation (or an applicable error). 1128 // 1129 // Deprecated: Use FutureRescanBlocksResult instead. 1130 type FutureRescanResult chan *Response 1131 1132 // Receive waits for the Response promised by the future and returns an error 1133 // if the rescan was not successful. 1134 func (r FutureRescanResult) Receive() error { 1135 _, err := ReceiveFuture(r) 1136 return err 1137 } 1138 1139 // RescanAsync returns an instance of a type that can be used to get the result 1140 // of the RPC at some future time by invoking the Receive function on the 1141 // returned instance. 1142 // 1143 // See Rescan for the blocking version and more details. 1144 // 1145 // NOTE: Rescan requests are not issued on client reconnect and must be 1146 // performed manually (ideally with a new start height based on the last 1147 // rescan progress notification). See the OnClientConnected notification 1148 // callback for a good callsite to reissue rescan requests on connect and 1149 // reconnect. 1150 // 1151 // NOTE: This is a btcd extension and requires a websocket connection. 1152 // 1153 // Deprecated: Use RescanBlocksAsync instead. 1154 func (c *Client) RescanAsync(startBlock *chainhash.Hash, 1155 addresses []btcutil.Address, 1156 outpoints []*wire.OutPoint) FutureRescanResult { 1157 1158 // Not supported in HTTP POST mode. 1159 if c.config.HTTPPostMode { 1160 return newFutureError(ErrWebsocketsRequired) 1161 } 1162 1163 // Ignore the notification if the client is not interested in 1164 // notifications. 1165 if c.ntfnHandlers == nil { 1166 return newNilFutureResult() 1167 } 1168 1169 // Convert block hashes to strings. 1170 var startBlockHashStr string 1171 if startBlock != nil { 1172 startBlockHashStr = startBlock.String() 1173 } 1174 1175 // Convert addresses to strings. 1176 addrs := make([]string, 0, len(addresses)) 1177 for _, addr := range addresses { 1178 addrs = append(addrs, addr.String()) 1179 } 1180 1181 // Convert outpoints. 1182 ops := make([]btcjson.OutPoint, 0, len(outpoints)) 1183 for _, op := range outpoints { 1184 ops = append(ops, newOutPointFromWire(op)) 1185 } 1186 1187 cmd := btcjson.NewRescanCmd(startBlockHashStr, addrs, ops, nil) 1188 return c.SendCmd(cmd) 1189 } 1190 1191 // Rescan rescans the block chain starting from the provided starting block to 1192 // the end of the longest chain for transactions that pay to the passed 1193 // addresses and transactions which spend the passed outpoints. 1194 // 1195 // The notifications of found transactions are delivered to the notification 1196 // handlers associated with client and this call will not return until the 1197 // rescan has completed. Calling this function has no effect if there are no 1198 // notification handlers and will result in an error if the client is configured 1199 // to run in HTTP POST mode. 1200 // 1201 // The notifications delivered as a result of this call will be via one of 1202 // OnRedeemingTx (for transactions which spend from the one of the 1203 // passed outpoints), OnRecvTx (for transactions that receive funds 1204 // to one of the passed addresses), and OnRescanProgress (for rescan progress 1205 // updates). 1206 // 1207 // See RescanEndBlock to also specify an ending block to finish the rescan 1208 // without continuing through the best block on the main chain. 1209 // 1210 // NOTE: Rescan requests are not issued on client reconnect and must be 1211 // performed manually (ideally with a new start height based on the last 1212 // rescan progress notification). See the OnClientConnected notification 1213 // callback for a good callsite to reissue rescan requests on connect and 1214 // reconnect. 1215 // 1216 // NOTE: This is a btcd extension and requires a websocket connection. 1217 // 1218 // Deprecated: Use RescanBlocks instead. 1219 func (c *Client) Rescan(startBlock *chainhash.Hash, 1220 addresses []btcutil.Address, 1221 outpoints []*wire.OutPoint) error { 1222 1223 return c.RescanAsync(startBlock, addresses, outpoints).Receive() 1224 } 1225 1226 // RescanEndBlockAsync returns an instance of a type that can be used to get 1227 // the result of the RPC at some future time by invoking the Receive function on 1228 // the returned instance. 1229 // 1230 // See RescanEndBlock for the blocking version and more details. 1231 // 1232 // NOTE: This is a btcd extension and requires a websocket connection. 1233 // 1234 // Deprecated: Use RescanBlocksAsync instead. 1235 func (c *Client) RescanEndBlockAsync(startBlock *chainhash.Hash, 1236 addresses []btcutil.Address, outpoints []*wire.OutPoint, 1237 endBlock *chainhash.Hash) FutureRescanResult { 1238 1239 // Not supported in HTTP POST mode. 1240 if c.config.HTTPPostMode { 1241 return newFutureError(ErrWebsocketsRequired) 1242 } 1243 1244 // Ignore the notification if the client is not interested in 1245 // notifications. 1246 if c.ntfnHandlers == nil { 1247 return newNilFutureResult() 1248 } 1249 1250 // Convert block hashes to strings. 1251 var startBlockHashStr, endBlockHashStr string 1252 if startBlock != nil { 1253 startBlockHashStr = startBlock.String() 1254 } 1255 if endBlock != nil { 1256 endBlockHashStr = endBlock.String() 1257 } 1258 1259 // Convert addresses to strings. 1260 addrs := make([]string, 0, len(addresses)) 1261 for _, addr := range addresses { 1262 addrs = append(addrs, addr.String()) 1263 } 1264 1265 // Convert outpoints. 1266 ops := make([]btcjson.OutPoint, 0, len(outpoints)) 1267 for _, op := range outpoints { 1268 ops = append(ops, newOutPointFromWire(op)) 1269 } 1270 1271 cmd := btcjson.NewRescanCmd(startBlockHashStr, addrs, ops, 1272 &endBlockHashStr) 1273 return c.SendCmd(cmd) 1274 } 1275 1276 // RescanEndHeight rescans the block chain starting from the provided starting 1277 // block up to the provided ending block for transactions that pay to the 1278 // passed addresses and transactions which spend the passed outpoints. 1279 // 1280 // The notifications of found transactions are delivered to the notification 1281 // handlers associated with client and this call will not return until the 1282 // rescan has completed. Calling this function has no effect if there are no 1283 // notification handlers and will result in an error if the client is configured 1284 // to run in HTTP POST mode. 1285 // 1286 // The notifications delivered as a result of this call will be via one of 1287 // OnRedeemingTx (for transactions which spend from the one of the 1288 // passed outpoints), OnRecvTx (for transactions that receive funds 1289 // to one of the passed addresses), and OnRescanProgress (for rescan progress 1290 // updates). 1291 // 1292 // See Rescan to also perform a rescan through current end of the longest chain. 1293 // 1294 // NOTE: This is a btcd extension and requires a websocket connection. 1295 // 1296 // Deprecated: Use RescanBlocks instead. 1297 func (c *Client) RescanEndHeight(startBlock *chainhash.Hash, 1298 addresses []btcutil.Address, outpoints []*wire.OutPoint, 1299 endBlock *chainhash.Hash) error { 1300 1301 return c.RescanEndBlockAsync(startBlock, addresses, outpoints, 1302 endBlock).Receive() 1303 } 1304 1305 // FutureLoadTxFilterResult is a future promise to deliver the result 1306 // of a LoadTxFilterAsync RPC invocation (or an applicable error). 1307 // 1308 // NOTE: This is a btcd extension ported from github.com/decred/dcrrpcclient 1309 // and requires a websocket connection. 1310 type FutureLoadTxFilterResult chan *Response 1311 1312 // Receive waits for the Response promised by the future and returns an error 1313 // if the registration was not successful. 1314 // 1315 // NOTE: This is a btcd extension ported from github.com/decred/dcrrpcclient 1316 // and requires a websocket connection. 1317 func (r FutureLoadTxFilterResult) Receive() error { 1318 _, err := ReceiveFuture(r) 1319 return err 1320 } 1321 1322 // LoadTxFilterAsync returns an instance of a type that can be used to 1323 // get the result of the RPC at some future time by invoking the Receive 1324 // function on the returned instance. 1325 // 1326 // See LoadTxFilter for the blocking version and more details. 1327 // 1328 // NOTE: This is a btcd extension ported from github.com/decred/dcrrpcclient 1329 // and requires a websocket connection. 1330 func (c *Client) LoadTxFilterAsync(reload bool, addresses []btcutil.Address, 1331 outPoints []wire.OutPoint) FutureLoadTxFilterResult { 1332 1333 addrStrs := make([]string, len(addresses)) 1334 for i, a := range addresses { 1335 addrStrs[i] = a.EncodeAddress() 1336 } 1337 outPointObjects := make([]btcjson.OutPoint, len(outPoints)) 1338 for i := range outPoints { 1339 outPointObjects[i] = btcjson.OutPoint{ 1340 Hash: outPoints[i].Hash.String(), 1341 Index: outPoints[i].Index, 1342 } 1343 } 1344 1345 cmd := btcjson.NewLoadTxFilterCmd(reload, addrStrs, outPointObjects) 1346 return c.SendCmd(cmd) 1347 } 1348 1349 // LoadTxFilter loads, reloads, or adds data to a websocket client's transaction 1350 // filter. The filter is consistently updated based on inspected transactions 1351 // during mempool acceptance, block acceptance, and for all rescanned blocks. 1352 // 1353 // NOTE: This is a btcd extension ported from github.com/decred/dcrrpcclient 1354 // and requires a websocket connection. 1355 func (c *Client) LoadTxFilter(reload bool, addresses []btcutil.Address, outPoints []wire.OutPoint) error { 1356 return c.LoadTxFilterAsync(reload, addresses, outPoints).Receive() 1357 }