mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-10-14 00:59:33 +00:00
[NOD-146] Remove unnecessary dag notifications (#288)
This commit is contained in:
parent
945b3f8fbf
commit
8acc738b27
@ -80,23 +80,6 @@ func NewStopNotifyNewTransactionsCmd() *StopNotifyNewTransactionsCmd {
|
||||
return &StopNotifyNewTransactionsCmd{}
|
||||
}
|
||||
|
||||
// NotifyReceivedCmd defines the notifyReceived JSON-RPC command.
|
||||
//
|
||||
// NOTE: Deprecated. Use LoadTxFilterCmd instead.
|
||||
type NotifyReceivedCmd struct {
|
||||
Addresses []string
|
||||
}
|
||||
|
||||
// NewNotifyReceivedCmd returns a new instance which can be used to issue a
|
||||
// notifyReceived JSON-RPC command.
|
||||
//
|
||||
// NOTE: Deprecated. Use NewLoadTxFilterCmd instead.
|
||||
func NewNotifyReceivedCmd(addresses []string) *NotifyReceivedCmd {
|
||||
return &NotifyReceivedCmd{
|
||||
Addresses: addresses,
|
||||
}
|
||||
}
|
||||
|
||||
// OutPoint describes a transaction outpoint that will be marshalled to and
|
||||
// from JSON.
|
||||
type OutPoint struct {
|
||||
@ -128,57 +111,6 @@ func NewLoadTxFilterCmd(reload bool, addresses []string, outPoints []OutPoint) *
|
||||
}
|
||||
}
|
||||
|
||||
// NotifySpentCmd defines the notifySpent JSON-RPC command.
|
||||
//
|
||||
// NOTE: Deprecated. Use LoadTxFilterCmd instead.
|
||||
type NotifySpentCmd struct {
|
||||
OutPoints []OutPoint
|
||||
}
|
||||
|
||||
// NewNotifySpentCmd returns a new instance which can be used to issue a
|
||||
// notifySpent JSON-RPC command.
|
||||
//
|
||||
// NOTE: Deprecated. Use NewLoadTxFilterCmd instead.
|
||||
func NewNotifySpentCmd(outPoints []OutPoint) *NotifySpentCmd {
|
||||
return &NotifySpentCmd{
|
||||
OutPoints: outPoints,
|
||||
}
|
||||
}
|
||||
|
||||
// StopNotifyReceivedCmd defines the stopNotifyReceived JSON-RPC command.
|
||||
//
|
||||
// NOTE: Deprecated. Use LoadTxFilterCmd instead.
|
||||
type StopNotifyReceivedCmd struct {
|
||||
Addresses []string
|
||||
}
|
||||
|
||||
// NewStopNotifyReceivedCmd returns a new instance which can be used to issue a
|
||||
// stopNotifyReceived JSON-RPC command.
|
||||
//
|
||||
// NOTE: Deprecated. Use NewLoadTxFilterCmd instead.
|
||||
func NewStopNotifyReceivedCmd(addresses []string) *StopNotifyReceivedCmd {
|
||||
return &StopNotifyReceivedCmd{
|
||||
Addresses: addresses,
|
||||
}
|
||||
}
|
||||
|
||||
// StopNotifySpentCmd defines the stopNotifySpent JSON-RPC command.
|
||||
//
|
||||
// NOTE: Deprecated. Use LoadTxFilterCmd instead.
|
||||
type StopNotifySpentCmd struct {
|
||||
OutPoints []OutPoint
|
||||
}
|
||||
|
||||
// NewStopNotifySpentCmd returns a new instance which can be used to issue a
|
||||
// stopNotifySpent JSON-RPC command.
|
||||
//
|
||||
// NOTE: Deprecated. Use NewLoadTxFilterCmd instead.
|
||||
func NewStopNotifySpentCmd(outPoints []OutPoint) *StopNotifySpentCmd {
|
||||
return &StopNotifySpentCmd{
|
||||
OutPoints: outPoints,
|
||||
}
|
||||
}
|
||||
|
||||
// RescanBlocksCmd defines the rescan JSON-RPC command.
|
||||
//
|
||||
// NOTE: This is a btcd extension ported from github.com/decred/dcrd/dcrjson
|
||||
@ -205,12 +137,8 @@ func init() {
|
||||
MustRegisterCmd("loadTxFilter", (*LoadTxFilterCmd)(nil), flags)
|
||||
MustRegisterCmd("notifyBlocks", (*NotifyBlocksCmd)(nil), flags)
|
||||
MustRegisterCmd("notifyNewTransactions", (*NotifyNewTransactionsCmd)(nil), flags)
|
||||
MustRegisterCmd("notifyReceived", (*NotifyReceivedCmd)(nil), flags)
|
||||
MustRegisterCmd("notifySpent", (*NotifySpentCmd)(nil), flags)
|
||||
MustRegisterCmd("session", (*SessionCmd)(nil), flags)
|
||||
MustRegisterCmd("stopNotifyBlocks", (*StopNotifyBlocksCmd)(nil), flags)
|
||||
MustRegisterCmd("stopNotifyNewTransactions", (*StopNotifyNewTransactionsCmd)(nil), flags)
|
||||
MustRegisterCmd("stopNotifySpent", (*StopNotifySpentCmd)(nil), flags)
|
||||
MustRegisterCmd("stopNotifyReceived", (*StopNotifyReceivedCmd)(nil), flags)
|
||||
MustRegisterCmd("rescanBlocks", (*RescanBlocksCmd)(nil), flags)
|
||||
}
|
||||
|
@ -114,60 +114,6 @@ func TestDAGSvrWsCmds(t *testing.T) {
|
||||
marshalled: `{"jsonrpc":"1.0","method":"stopNotifyNewTransactions","params":[],"id":1}`,
|
||||
unmarshalled: &btcjson.StopNotifyNewTransactionsCmd{},
|
||||
},
|
||||
{
|
||||
name: "notifyReceived",
|
||||
newCmd: func() (interface{}, error) {
|
||||
return btcjson.NewCmd("notifyReceived", []string{"1Address"})
|
||||
},
|
||||
staticCmd: func() interface{} {
|
||||
return btcjson.NewNotifyReceivedCmd([]string{"1Address"})
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"notifyReceived","params":[["1Address"]],"id":1}`,
|
||||
unmarshalled: &btcjson.NotifyReceivedCmd{
|
||||
Addresses: []string{"1Address"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "stopNotifyReceived",
|
||||
newCmd: func() (interface{}, error) {
|
||||
return btcjson.NewCmd("stopNotifyReceived", []string{"1Address"})
|
||||
},
|
||||
staticCmd: func() interface{} {
|
||||
return btcjson.NewStopNotifyReceivedCmd([]string{"1Address"})
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"stopNotifyReceived","params":[["1Address"]],"id":1}`,
|
||||
unmarshalled: &btcjson.StopNotifyReceivedCmd{
|
||||
Addresses: []string{"1Address"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "notifySpent",
|
||||
newCmd: func() (interface{}, error) {
|
||||
return btcjson.NewCmd("notifySpent", `[{"txid":"123","index":0}]`)
|
||||
},
|
||||
staticCmd: func() interface{} {
|
||||
ops := []btcjson.OutPoint{{TxID: "123", Index: 0}}
|
||||
return btcjson.NewNotifySpentCmd(ops)
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"notifySpent","params":[[{"txid":"123","index":0}]],"id":1}`,
|
||||
unmarshalled: &btcjson.NotifySpentCmd{
|
||||
OutPoints: []btcjson.OutPoint{{TxID: "123", Index: 0}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "stopNotifySpent",
|
||||
newCmd: func() (interface{}, error) {
|
||||
return btcjson.NewCmd("stopNotifySpent", `[{"txid":"123","index":0}]`)
|
||||
},
|
||||
staticCmd: func() interface{} {
|
||||
ops := []btcjson.OutPoint{{TxID: "123", Index: 0}}
|
||||
return btcjson.NewStopNotifySpentCmd(ops)
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"stopNotifySpent","params":[[{"txid":"123","index":0}]],"id":1}`,
|
||||
unmarshalled: &btcjson.StopNotifySpentCmd{
|
||||
OutPoints: []btcjson.OutPoint{{TxID: "123", Index: 0}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "loadTxFilter",
|
||||
newCmd: func() (interface{}, error) {
|
||||
|
@ -13,36 +13,6 @@ const (
|
||||
// notifications from the dag server that a block has been connected.
|
||||
FilteredBlockAddedNtfnMethod = "filteredBlockAdded"
|
||||
|
||||
// RecvTxNtfnMethod is the legacy, deprecated method used for
|
||||
// notifications from the dag server that a transaction which pays to
|
||||
// a registered address has been processed.
|
||||
//
|
||||
// NOTE: Deprecated. Use RelevantTxAcceptedNtfnMethod and
|
||||
// FilteredBlockAddedNtfnMethod instead.
|
||||
RecvTxNtfnMethod = "recvTx"
|
||||
|
||||
// RedeemingTxNtfnMethod is the legacy, deprecated method used for
|
||||
// notifications from the dag server that a transaction which spends a
|
||||
// registered outpoint has been processed.
|
||||
//
|
||||
// NOTE: Deprecated. Use RelevantTxAcceptedNtfnMethod and
|
||||
// FilteredBlockAddedNtfnMethod instead.
|
||||
RedeemingTxNtfnMethod = "redeemingTx"
|
||||
|
||||
// RescanFinishedNtfnMethod is the legacy, deprecated method used for
|
||||
// notifications from the dag server that a legacy, deprecated rescan
|
||||
// operation has finished.
|
||||
//
|
||||
// NOTE: Deprecated. Not used with rescanblocks command.
|
||||
RescanFinishedNtfnMethod = "rescanFinished"
|
||||
|
||||
// RescanProgressNtfnMethod is the legacy, deprecated method used for
|
||||
// notifications from the dag server that a legacy, deprecated rescan
|
||||
// operation this is underway has made progress.
|
||||
//
|
||||
// NOTE: Deprecated. Not used with rescanblocks command.
|
||||
RescanProgressNtfnMethod = "rescanProgress"
|
||||
|
||||
// TxAcceptedNtfnMethod is the method used for notifications from the
|
||||
// dag server that a transaction has been accepted into the mempool.
|
||||
TxAcceptedNtfnMethod = "txAccepted"
|
||||
@ -85,90 +55,6 @@ type BlockDetails struct {
|
||||
Time int64 `json:"time"`
|
||||
}
|
||||
|
||||
// RecvTxNtfn defines the recvTx JSON-RPC notification.
|
||||
//
|
||||
// NOTE: Deprecated. Use RelevantTxAcceptedNtfn and FilteredBlockAddedNtfn
|
||||
// instead.
|
||||
type RecvTxNtfn struct {
|
||||
HexTx string
|
||||
Block *BlockDetails
|
||||
}
|
||||
|
||||
// NewRecvTxNtfn returns a new instance which can be used to issue a recvTx
|
||||
// JSON-RPC notification.
|
||||
//
|
||||
// NOTE: Deprecated. Use NewRelevantTxAcceptedNtfn and
|
||||
// NewFilteredBlockAddedNtfn instead.
|
||||
func NewRecvTxNtfn(hexTx string, block *BlockDetails) *RecvTxNtfn {
|
||||
return &RecvTxNtfn{
|
||||
HexTx: hexTx,
|
||||
Block: block,
|
||||
}
|
||||
}
|
||||
|
||||
// RedeemingTxNtfn defines the redeemingTx JSON-RPC notification.
|
||||
//
|
||||
// NOTE: Deprecated. Use RelevantTxAcceptedNtfn and FilteredBlockAddedNtfn
|
||||
// instead.
|
||||
type RedeemingTxNtfn struct {
|
||||
HexTx string
|
||||
Block *BlockDetails
|
||||
}
|
||||
|
||||
// NewRedeemingTxNtfn returns a new instance which can be used to issue a
|
||||
// redeemingTx JSON-RPC notification.
|
||||
//
|
||||
// NOTE: Deprecated. Use NewRelevantTxAcceptedNtfn and
|
||||
// NewFilteredBlockAddedNtfn instead.
|
||||
func NewRedeemingTxNtfn(hexTx string, block *BlockDetails) *RedeemingTxNtfn {
|
||||
return &RedeemingTxNtfn{
|
||||
HexTx: hexTx,
|
||||
Block: block,
|
||||
}
|
||||
}
|
||||
|
||||
// RescanFinishedNtfn defines the rescanFinished JSON-RPC notification.
|
||||
//
|
||||
// NOTE: Deprecated. Not used with rescanblocks command.
|
||||
type RescanFinishedNtfn struct {
|
||||
Hash string
|
||||
Height uint64
|
||||
Time int64
|
||||
}
|
||||
|
||||
// NewRescanFinishedNtfn returns a new instance which can be used to issue a
|
||||
// rescanFinished JSON-RPC notification.
|
||||
//
|
||||
// NOTE: Deprecated. Not used with rescanblocks command.
|
||||
func NewRescanFinishedNtfn(hash string, height uint64, time int64) *RescanFinishedNtfn {
|
||||
return &RescanFinishedNtfn{
|
||||
Hash: hash,
|
||||
Height: height,
|
||||
Time: time,
|
||||
}
|
||||
}
|
||||
|
||||
// RescanProgressNtfn defines the rescanProgress JSON-RPC notification.
|
||||
//
|
||||
// NOTE: Deprecated. Not used with rescanblocks command.
|
||||
type RescanProgressNtfn struct {
|
||||
Hash string
|
||||
Height uint64
|
||||
Time int64
|
||||
}
|
||||
|
||||
// NewRescanProgressNtfn returns a new instance which can be used to issue a
|
||||
// rescanProgress JSON-RPC notification.
|
||||
//
|
||||
// NOTE: Deprecated. Not used with rescanblocks command.
|
||||
func NewRescanProgressNtfn(hash string, height uint64, time int64) *RescanProgressNtfn {
|
||||
return &RescanProgressNtfn{
|
||||
Hash: hash,
|
||||
Height: height,
|
||||
Time: time,
|
||||
}
|
||||
}
|
||||
|
||||
// TxAcceptedNtfn defines the txAccepted JSON-RPC notification.
|
||||
type TxAcceptedNtfn struct {
|
||||
TxID string
|
||||
@ -215,10 +101,6 @@ func init() {
|
||||
flags := UFWebsocketOnly | UFNotification
|
||||
|
||||
MustRegisterCmd(FilteredBlockAddedNtfnMethod, (*FilteredBlockAddedNtfn)(nil), flags)
|
||||
MustRegisterCmd(RecvTxNtfnMethod, (*RecvTxNtfn)(nil), flags)
|
||||
MustRegisterCmd(RedeemingTxNtfnMethod, (*RedeemingTxNtfn)(nil), flags)
|
||||
MustRegisterCmd(RescanFinishedNtfnMethod, (*RescanFinishedNtfn)(nil), flags)
|
||||
MustRegisterCmd(RescanProgressNtfnMethod, (*RescanProgressNtfn)(nil), flags)
|
||||
MustRegisterCmd(TxAcceptedNtfnMethod, (*TxAcceptedNtfn)(nil), flags)
|
||||
MustRegisterCmd(TxAcceptedVerboseNtfnMethod, (*TxAcceptedVerboseNtfn)(nil), flags)
|
||||
MustRegisterCmd(RelevantTxAcceptedNtfnMethod, (*RelevantTxAcceptedNtfn)(nil), flags)
|
||||
|
@ -47,86 +47,6 @@ func TestDAGSvrWsNtfns(t *testing.T) {
|
||||
SubscribedTxs: []string{"tx0", "tx1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "recvTx",
|
||||
newNtfn: func() (interface{}, error) {
|
||||
return btcjson.NewCmd("recvTx", "001122", `{"height":100000,"hash":"123","index":0,"time":12345678}`)
|
||||
},
|
||||
staticNtfn: func() interface{} {
|
||||
blockDetails := btcjson.BlockDetails{
|
||||
Height: 100000,
|
||||
Hash: "123",
|
||||
Index: 0,
|
||||
Time: 12345678,
|
||||
}
|
||||
return btcjson.NewRecvTxNtfn("001122", &blockDetails)
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"recvTx","params":["001122",{"height":100000,"hash":"123","index":0,"time":12345678}],"id":null}`,
|
||||
unmarshalled: &btcjson.RecvTxNtfn{
|
||||
HexTx: "001122",
|
||||
Block: &btcjson.BlockDetails{
|
||||
Height: 100000,
|
||||
Hash: "123",
|
||||
Index: 0,
|
||||
Time: 12345678,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "redeemingTx",
|
||||
newNtfn: func() (interface{}, error) {
|
||||
return btcjson.NewCmd("redeemingTx", "001122", `{"height":100000,"hash":"123","index":0,"time":12345678}`)
|
||||
},
|
||||
staticNtfn: func() interface{} {
|
||||
blockDetails := btcjson.BlockDetails{
|
||||
Height: 100000,
|
||||
Hash: "123",
|
||||
Index: 0,
|
||||
Time: 12345678,
|
||||
}
|
||||
return btcjson.NewRedeemingTxNtfn("001122", &blockDetails)
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"redeemingTx","params":["001122",{"height":100000,"hash":"123","index":0,"time":12345678}],"id":null}`,
|
||||
unmarshalled: &btcjson.RedeemingTxNtfn{
|
||||
HexTx: "001122",
|
||||
Block: &btcjson.BlockDetails{
|
||||
Height: 100000,
|
||||
Hash: "123",
|
||||
Index: 0,
|
||||
Time: 12345678,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "rescanFinished",
|
||||
newNtfn: func() (interface{}, error) {
|
||||
return btcjson.NewCmd("rescanFinished", "123", 100000, 12345678)
|
||||
},
|
||||
staticNtfn: func() interface{} {
|
||||
return btcjson.NewRescanFinishedNtfn("123", 100000, 12345678)
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"rescanFinished","params":["123",100000,12345678],"id":null}`,
|
||||
unmarshalled: &btcjson.RescanFinishedNtfn{
|
||||
Hash: "123",
|
||||
Height: 100000,
|
||||
Time: 12345678,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "rescanProgress",
|
||||
newNtfn: func() (interface{}, error) {
|
||||
return btcjson.NewCmd("rescanProgress", "123", 100000, 12345678)
|
||||
},
|
||||
staticNtfn: func() interface{} {
|
||||
return btcjson.NewRescanProgressNtfn("123", 100000, 12345678)
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"rescanProgress","params":["123",100000,12345678],"id":null}`,
|
||||
unmarshalled: &btcjson.RescanProgressNtfn{
|
||||
Hash: "123",
|
||||
Height: 100000,
|
||||
Time: 12345678,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "txAccepted",
|
||||
newNtfn: func() (interface{}, error) {
|
||||
|
@ -261,16 +261,6 @@ func (c *Client) trackRegisteredNtfns(cmd interface{}) {
|
||||
c.ntfnState.notifyNewTx = true
|
||||
}
|
||||
c.ntfnState.notifyNewTxSubnetworkID = bcmd.Subnetwork
|
||||
|
||||
case *btcjson.NotifySpentCmd:
|
||||
for _, op := range bcmd.OutPoints {
|
||||
c.ntfnState.notifySpent[op] = struct{}{}
|
||||
}
|
||||
|
||||
case *btcjson.NotifyReceivedCmd:
|
||||
for _, addr := range bcmd.Addresses {
|
||||
c.ntfnState.notifyReceived[addr] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -536,34 +526,6 @@ func (c *Client) reregisterNtfns() error {
|
||||
}
|
||||
}
|
||||
|
||||
// Reregister the combination of all previously registered notifyspent
|
||||
// outpoints in one command if needed.
|
||||
nslen := len(stateCopy.notifySpent)
|
||||
if nslen > 0 {
|
||||
outpoints := make([]btcjson.OutPoint, 0, nslen)
|
||||
for op := range stateCopy.notifySpent {
|
||||
outpoints = append(outpoints, op)
|
||||
}
|
||||
log.Debugf("Reregistering [notifyspent] outpoints: %v", outpoints)
|
||||
if err := c.notifySpentInternal(outpoints).Receive(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Reregister the combination of all previously registered
|
||||
// notifyreceived addresses in one command if needed.
|
||||
nrlen := len(stateCopy.notifyReceived)
|
||||
if nrlen > 0 {
|
||||
addresses := make([]string, 0, nrlen)
|
||||
for addr := range stateCopy.notifyReceived {
|
||||
addresses = append(addresses, addr)
|
||||
}
|
||||
log.Debugf("Reregistering [notifyreceived] addresses: %v", addresses)
|
||||
if err := c.notifyReceivedInternal(addresses).Receive(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -36,8 +36,6 @@ type notificationState struct {
|
||||
notifyNewTx bool
|
||||
notifyNewTxVerbose bool
|
||||
notifyNewTxSubnetworkID *string
|
||||
notifyReceived map[string]struct{}
|
||||
notifySpent map[btcjson.OutPoint]struct{}
|
||||
}
|
||||
|
||||
// Copy returns a deep copy of the receiver.
|
||||
@ -47,24 +45,13 @@ func (s *notificationState) Copy() *notificationState {
|
||||
stateCopy.notifyNewTx = s.notifyNewTx
|
||||
stateCopy.notifyNewTxVerbose = s.notifyNewTxVerbose
|
||||
stateCopy.notifyNewTxSubnetworkID = s.notifyNewTxSubnetworkID
|
||||
stateCopy.notifyReceived = make(map[string]struct{})
|
||||
for addr := range s.notifyReceived {
|
||||
stateCopy.notifyReceived[addr] = struct{}{}
|
||||
}
|
||||
stateCopy.notifySpent = make(map[btcjson.OutPoint]struct{})
|
||||
for op := range s.notifySpent {
|
||||
stateCopy.notifySpent[op] = struct{}{}
|
||||
}
|
||||
|
||||
return &stateCopy
|
||||
}
|
||||
|
||||
// newNotificationState returns a new notification state ready to be populated.
|
||||
func newNotificationState() *notificationState {
|
||||
return ¬ificationState{
|
||||
notifyReceived: make(map[string]struct{}),
|
||||
notifySpent: make(map[btcjson.OutPoint]struct{}),
|
||||
}
|
||||
return ¬ificationState{}
|
||||
}
|
||||
|
||||
// newNilFutureResult returns a new future result channel that already has the
|
||||
@ -81,11 +68,6 @@ func newNilFutureResult() chan *response {
|
||||
// notifications. Since all of the functions are nil by default, all
|
||||
// notifications are effectively ignored until their handlers are set to a
|
||||
// concrete callback.
|
||||
//
|
||||
// NOTE: Unless otherwise documented, these handlers must NOT directly call any
|
||||
// blocking calls on the client instance since the input reader goroutine blocks
|
||||
// until the callback has completed. Doing so will result in a deadlock
|
||||
// situation.
|
||||
type NotificationHandlers struct {
|
||||
// OnClientConnected is invoked when the client connects or reconnects
|
||||
// to the RPC server. This callback is run async with the rest of the
|
||||
@ -107,29 +89,6 @@ type NotificationHandlers struct {
|
||||
OnFilteredBlockAdded func(height uint64, header *wire.BlockHeader,
|
||||
txs []*util.Tx)
|
||||
|
||||
// OnRecvTx is invoked when a transaction that receives funds to a
|
||||
// registered address is received into the memory pool and also
|
||||
// connected to the BlockDAG. It will only be invoked if a
|
||||
// preceding call to NotifyReceived, Rescan, or RescanEndHeight has been
|
||||
// made to register for the notification and the function is non-nil.
|
||||
//
|
||||
// NOTE: Deprecated. Use OnRelevantTxAccepted instead.
|
||||
OnRecvTx func(transaction *util.Tx, details *btcjson.BlockDetails)
|
||||
|
||||
// OnRedeemingTx is invoked when a transaction that spends a registered
|
||||
// outpoint is received into the memory pool and also connected to the
|
||||
// blockDAG. It will only be invoked if a preceding call to
|
||||
// NotifySpent, Rescan, or RescanEndHeight has been made to register for
|
||||
// the notification and the function is non-nil.
|
||||
//
|
||||
// NOTE: The NotifyReceived will automatically register notifications
|
||||
// for the outpoints that are now "owned" as a result of receiving
|
||||
// funds to the registered addresses. This means it is possible for
|
||||
// this to invoked indirectly as the result of a NotifyReceived call.
|
||||
//
|
||||
// NOTE: Deprecated. Use OnRelevantTxAccepted instead.
|
||||
OnRedeemingTx func(transaction *util.Tx, details *btcjson.BlockDetails)
|
||||
|
||||
// OnRelevantTxAccepted is invoked when an unmined transaction passes
|
||||
// the client's transaction filter.
|
||||
//
|
||||
@ -137,22 +96,6 @@ type NotificationHandlers struct {
|
||||
// github.com/decred/dcrrpcclient.
|
||||
OnRelevantTxAccepted func(transaction []byte)
|
||||
|
||||
// OnRescanFinished is invoked after a rescan finishes due to a previous
|
||||
// call to Rescan or RescanEndHeight. Finished rescans should be
|
||||
// signaled on this notification, rather than relying on the return
|
||||
// result of a rescan request, due to how btcd may send various rescan
|
||||
// notifications after the rescan request has already returned.
|
||||
//
|
||||
// NOTE: Deprecated. Not used with RescanBlocks.
|
||||
OnRescanFinished func(hash *daghash.Hash, height int32, blkTime time.Time)
|
||||
|
||||
// OnRescanProgress is invoked periodically when a rescan is underway.
|
||||
// It will only be invoked if a preceding call to Rescan or
|
||||
// RescanEndHeight has been made and the function is non-nil.
|
||||
//
|
||||
// NOTE: Deprecated. Not used with RescanBlocks.
|
||||
OnRescanProgress func(hash *daghash.Hash, height int32, blkTime time.Time)
|
||||
|
||||
// OnTxAccepted is invoked when a transaction is accepted into the
|
||||
// memory pool. It will only be invoked if a preceding call to
|
||||
// NotifyNewTransactions with the verbose flag set to false has been
|
||||
@ -224,40 +167,6 @@ func (c *Client) handleNotification(ntfn *rawNotification) {
|
||||
c.ntfnHandlers.OnFilteredBlockAdded(blockHeight,
|
||||
blockHeader, transactions)
|
||||
|
||||
// OnRecvTx
|
||||
case btcjson.RecvTxNtfnMethod:
|
||||
// Ignore the notification if the client is not interested in
|
||||
// it.
|
||||
if c.ntfnHandlers.OnRecvTx == nil {
|
||||
return
|
||||
}
|
||||
|
||||
tx, block, err := parseChainTxNtfnParams(ntfn.Params)
|
||||
if err != nil {
|
||||
log.Warnf("Received invalid recvtx notification: %s",
|
||||
err)
|
||||
return
|
||||
}
|
||||
|
||||
c.ntfnHandlers.OnRecvTx(tx, block)
|
||||
|
||||
// OnRedeemingTx
|
||||
case btcjson.RedeemingTxNtfnMethod:
|
||||
// Ignore the notification if the client is not interested in
|
||||
// it.
|
||||
if c.ntfnHandlers.OnRedeemingTx == nil {
|
||||
return
|
||||
}
|
||||
|
||||
tx, block, err := parseChainTxNtfnParams(ntfn.Params)
|
||||
if err != nil {
|
||||
log.Warnf("Received invalid redeemingtx "+
|
||||
"notification: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.ntfnHandlers.OnRedeemingTx(tx, block)
|
||||
|
||||
// OnRelevantTxAccepted
|
||||
case btcjson.RelevantTxAcceptedNtfnMethod:
|
||||
// Ignore the notification if the client is not interested in
|
||||
@ -275,40 +184,6 @@ func (c *Client) handleNotification(ntfn *rawNotification) {
|
||||
|
||||
c.ntfnHandlers.OnRelevantTxAccepted(transaction)
|
||||
|
||||
// OnRescanFinished
|
||||
case btcjson.RescanFinishedNtfnMethod:
|
||||
// Ignore the notification if the client is not interested in
|
||||
// it.
|
||||
if c.ntfnHandlers.OnRescanFinished == nil {
|
||||
return
|
||||
}
|
||||
|
||||
hash, height, blkTime, err := parseRescanProgressParams(ntfn.Params)
|
||||
if err != nil {
|
||||
log.Warnf("Received invalid rescanfinished "+
|
||||
"notification: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.ntfnHandlers.OnRescanFinished(hash, height, blkTime)
|
||||
|
||||
// OnRescanProgress
|
||||
case btcjson.RescanProgressNtfnMethod:
|
||||
// Ignore the notification if the client is not interested in
|
||||
// it.
|
||||
if c.ntfnHandlers.OnRescanProgress == nil {
|
||||
return
|
||||
}
|
||||
|
||||
hash, height, blkTime, err := parseRescanProgressParams(ntfn.Params)
|
||||
if err != nil {
|
||||
log.Warnf("Received invalid rescanprogress "+
|
||||
"notification: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.ntfnHandlers.OnRescanProgress(hash, height, blkTime)
|
||||
|
||||
// OnTxAccepted
|
||||
case btcjson.TxAcceptedNtfnMethod:
|
||||
// Ignore the notification if the client is not interested in
|
||||
@ -578,43 +453,6 @@ func parseChainTxNtfnParams(params []json.RawMessage) (*util.Tx,
|
||||
return util.NewTx(&msgTx), block, nil
|
||||
}
|
||||
|
||||
// parseRescanProgressParams parses out the height of the last rescanned block
|
||||
// from the parameters of rescanfinished and rescanprogress notifications.
|
||||
func parseRescanProgressParams(params []json.RawMessage) (*daghash.Hash, int32, time.Time, error) {
|
||||
if len(params) != 3 {
|
||||
return nil, 0, time.Time{}, wrongNumParams(len(params))
|
||||
}
|
||||
|
||||
// Unmarshal first parameter as an string.
|
||||
var hashStr string
|
||||
err := json.Unmarshal(params[0], &hashStr)
|
||||
if err != nil {
|
||||
return nil, 0, time.Time{}, err
|
||||
}
|
||||
|
||||
// Unmarshal second parameter as an integer.
|
||||
var height int32
|
||||
err = json.Unmarshal(params[1], &height)
|
||||
if err != nil {
|
||||
return nil, 0, time.Time{}, err
|
||||
}
|
||||
|
||||
// Unmarshal third parameter as an integer.
|
||||
var blkTime int64
|
||||
err = json.Unmarshal(params[2], &blkTime)
|
||||
if err != nil {
|
||||
return nil, 0, time.Time{}, err
|
||||
}
|
||||
|
||||
// Decode string encoding of block hash.
|
||||
hash, err := daghash.NewHashFromStr(hashStr)
|
||||
if err != nil {
|
||||
return nil, 0, time.Time{}, err
|
||||
}
|
||||
|
||||
return hash, height, time.Unix(blkTime, 0), nil
|
||||
}
|
||||
|
||||
// parseTxAcceptedNtfnParams parses out the transaction hash and total amount
|
||||
// from the parameters of a txaccepted notification.
|
||||
func parseTxAcceptedNtfnParams(params []json.RawMessage) (*daghash.Hash,
|
||||
@ -801,38 +639,6 @@ func (c *Client) NotifyBlocks() error {
|
||||
return c.NotifyBlocksAsync().Receive()
|
||||
}
|
||||
|
||||
// FutureNotifySpentResult is a future promise to deliver the result of a
|
||||
// NotifySpentAsync RPC invocation (or an applicable error).
|
||||
//
|
||||
// NOTE: Deprecated. Use FutureLoadTxFilterResult instead.
|
||||
type FutureNotifySpentResult chan *response
|
||||
|
||||
// Receive waits for the response promised by the future and returns an error
|
||||
// if the registration was not successful.
|
||||
func (r FutureNotifySpentResult) Receive() error {
|
||||
_, err := receiveFuture(r)
|
||||
return err
|
||||
}
|
||||
|
||||
// notifySpentInternal is the same as notifySpentAsync except it accepts
|
||||
// the converted outpoints as a parameter so the client can more efficiently
|
||||
// recreate the previous notification state on reconnect.
|
||||
func (c *Client) notifySpentInternal(outpoints []btcjson.OutPoint) FutureNotifySpentResult {
|
||||
// Not supported in HTTP POST mode.
|
||||
if c.config.HTTPPostMode {
|
||||
return newFutureError(ErrWebsocketsRequired)
|
||||
}
|
||||
|
||||
// Ignore the notification if the client is not interested in
|
||||
// notifications.
|
||||
if c.ntfnHandlers == nil {
|
||||
return newNilFutureResult()
|
||||
}
|
||||
|
||||
cmd := btcjson.NewNotifySpentCmd(outpoints)
|
||||
return c.sendCmd(cmd)
|
||||
}
|
||||
|
||||
// newOutPointFromWire constructs the btcjson representation of a transaction
|
||||
// outpoint from the wire type.
|
||||
func newOutPointFromWire(op *wire.OutPoint) btcjson.OutPoint {
|
||||
@ -842,51 +648,6 @@ func newOutPointFromWire(op *wire.OutPoint) btcjson.OutPoint {
|
||||
}
|
||||
}
|
||||
|
||||
// NotifySpentAsync returns an instance of a type that can be used to get the
|
||||
// result of the RPC at some future time by invoking the Receive function on
|
||||
// the returned instance.
|
||||
//
|
||||
// See NotifySpent for the blocking version and more details.
|
||||
//
|
||||
// NOTE: This is a btcd extension and requires a websocket connection.
|
||||
//
|
||||
// NOTE: Deprecated. Use LoadTxFilterAsync instead.
|
||||
func (c *Client) NotifySpentAsync(outpoints []*wire.OutPoint) FutureNotifySpentResult {
|
||||
// Not supported in HTTP POST mode.
|
||||
if c.config.HTTPPostMode {
|
||||
return newFutureError(ErrWebsocketsRequired)
|
||||
}
|
||||
|
||||
// Ignore the notification if the client is not interested in
|
||||
// notifications.
|
||||
if c.ntfnHandlers == nil {
|
||||
return newNilFutureResult()
|
||||
}
|
||||
|
||||
ops := make([]btcjson.OutPoint, 0, len(outpoints))
|
||||
for _, outpoint := range outpoints {
|
||||
ops = append(ops, newOutPointFromWire(outpoint))
|
||||
}
|
||||
cmd := btcjson.NewNotifySpentCmd(ops)
|
||||
return c.sendCmd(cmd)
|
||||
}
|
||||
|
||||
// NotifySpent registers the client to receive notifications when the passed
|
||||
// transaction outputs are spent. The notifications are delivered to the
|
||||
// notification handlers associated with the client. Calling this function has
|
||||
// no effect if there are no notification handlers and will result in an error
|
||||
// if the client is configured to run in HTTP POST mode.
|
||||
//
|
||||
// The notifications delivered as a result of this call will be via
|
||||
// OnRedeemingTx.
|
||||
//
|
||||
// NOTE: This is a btcd extension and requires a websocket connection.
|
||||
//
|
||||
// NOTE: Deprecated. Use LoadTxFilter instead.
|
||||
func (c *Client) NotifySpent(outpoints []*wire.OutPoint) error {
|
||||
return c.NotifySpentAsync(outpoints).Receive()
|
||||
}
|
||||
|
||||
// FutureNotifyNewTransactionsResult is a future promise to deliver the result
|
||||
// of a NotifyNewTransactionsAsync RPC invocation (or an applicable error).
|
||||
type FutureNotifyNewTransactionsResult chan *response
|
||||
@ -936,105 +697,6 @@ func (c *Client) NotifyNewTransactions(verbose bool, subnetworkID *string) error
|
||||
return c.NotifyNewTransactionsAsync(verbose, subnetworkID).Receive()
|
||||
}
|
||||
|
||||
// FutureNotifyReceivedResult is a future promise to deliver the result of a
|
||||
// NotifyReceivedAsync RPC invocation (or an applicable error).
|
||||
//
|
||||
// NOTE: Deprecated. Use FutureLoadTxFilterResult instead.
|
||||
type FutureNotifyReceivedResult chan *response
|
||||
|
||||
// Receive waits for the response promised by the future and returns an error
|
||||
// if the registration was not successful.
|
||||
func (r FutureNotifyReceivedResult) Receive() error {
|
||||
_, err := receiveFuture(r)
|
||||
return err
|
||||
}
|
||||
|
||||
// notifyReceivedInternal is the same as notifyReceivedAsync except it accepts
|
||||
// the converted addresses as a parameter so the client can more efficiently
|
||||
// recreate the previous notification state on reconnect.
|
||||
func (c *Client) notifyReceivedInternal(addresses []string) FutureNotifyReceivedResult {
|
||||
// Not supported in HTTP POST mode.
|
||||
if c.config.HTTPPostMode {
|
||||
return newFutureError(ErrWebsocketsRequired)
|
||||
}
|
||||
|
||||
// Ignore the notification if the client is not interested in
|
||||
// notifications.
|
||||
if c.ntfnHandlers == nil {
|
||||
return newNilFutureResult()
|
||||
}
|
||||
|
||||
// Convert addresses to strings.
|
||||
cmd := btcjson.NewNotifyReceivedCmd(addresses)
|
||||
return c.sendCmd(cmd)
|
||||
}
|
||||
|
||||
// NotifyReceivedAsync returns an instance of a type that can be used to get the
|
||||
// result of the RPC at some future time by invoking the Receive function on
|
||||
// the returned instance.
|
||||
//
|
||||
// See NotifyReceived for the blocking version and more details.
|
||||
//
|
||||
// NOTE: This is a btcd extension and requires a websocket connection.
|
||||
//
|
||||
// NOTE: Deprecated. Use LoadTxFilterAsync instead.
|
||||
func (c *Client) NotifyReceivedAsync(addresses []util.Address) FutureNotifyReceivedResult {
|
||||
// Not supported in HTTP POST mode.
|
||||
if c.config.HTTPPostMode {
|
||||
return newFutureError(ErrWebsocketsRequired)
|
||||
}
|
||||
|
||||
// Ignore the notification if the client is not interested in
|
||||
// notifications.
|
||||
if c.ntfnHandlers == nil {
|
||||
return newNilFutureResult()
|
||||
}
|
||||
|
||||
// Convert addresses to strings.
|
||||
addrs := make([]string, 0, len(addresses))
|
||||
for _, addr := range addresses {
|
||||
addrs = append(addrs, addr.String())
|
||||
}
|
||||
cmd := btcjson.NewNotifyReceivedCmd(addrs)
|
||||
return c.sendCmd(cmd)
|
||||
}
|
||||
|
||||
// NotifyReceived registers the client to receive notifications every time a
|
||||
// new transaction which pays to one of the passed addresses is accepted to
|
||||
// memory pool or in a block added to the block DAG. In addition, when
|
||||
// one of these transactions is detected, the client is also automatically
|
||||
// registered for notifications when the new transaction outpoints the address
|
||||
// now has available are spent (See NotifySpent). The notifications are
|
||||
// delivered to the notification handlers associated with the client. Calling
|
||||
// this function has no effect if there are no notification handlers and will
|
||||
// result in an error if the client is configured to run in HTTP POST mode.
|
||||
//
|
||||
// The notifications delivered as a result of this call will be via one of
|
||||
// *OnRecvTx (for transactions that receive funds to one of the passed
|
||||
// addresses) or OnRedeemingTx (for transactions which spend from one
|
||||
// of the outpoints which are automatically registered upon receipt of funds to
|
||||
// the address).
|
||||
//
|
||||
// NOTE: This is a btcd extension and requires a websocket connection.
|
||||
//
|
||||
// NOTE: Deprecated. Use LoadTxFilter instead.
|
||||
func (c *Client) NotifyReceived(addresses []util.Address) error {
|
||||
return c.NotifyReceivedAsync(addresses).Receive()
|
||||
}
|
||||
|
||||
// FutureRescanResult is a future promise to deliver the result of a RescanAsync
|
||||
// or RescanEndHeightAsync RPC invocation (or an applicable error).
|
||||
//
|
||||
// NOTE: Deprecated. Use FutureRescanBlocksResult instead.
|
||||
type FutureRescanResult chan *response
|
||||
|
||||
// Receive waits for the response promised by the future and returns an error
|
||||
// if the rescan was not successful.
|
||||
func (r FutureRescanResult) Receive() error {
|
||||
_, err := receiveFuture(r)
|
||||
return err
|
||||
}
|
||||
|
||||
// FutureLoadTxFilterResult is a future promise to deliver the result
|
||||
// of a LoadTxFilterAsync RPC invocation (or an applicable error).
|
||||
//
|
||||
|
@ -610,43 +610,16 @@ var helpDescsEnUS = map[string]string{
|
||||
// StopNotifyNewTransactionsCmd help.
|
||||
"stopNotifyNewTransactions--synopsis": "Stop sending either a txaccepted or a txacceptedverbose notification when a new transaction is accepted into the mempool.",
|
||||
|
||||
// NotifyReceivedCmd help.
|
||||
"notifyReceived--synopsis": "Send a recvtx notification when a transaction added to mempool or appears in a newly-attached block contains a txout pkScript sending to any of the passed addresses.\n" +
|
||||
"Matching outpoints are automatically registered for redeemingtx notifications.",
|
||||
"notifyReceived-addresses": "List of address to receive notifications about",
|
||||
|
||||
// StopNotifyReceivedCmd help.
|
||||
"stopNotifyReceived--synopsis": "Cancel registered receive notifications for each passed address.",
|
||||
"stopNotifyReceived-addresses": "List of address to cancel receive notifications for",
|
||||
|
||||
// OutPoint help.
|
||||
"outPoint-txid": "The hex-encoded bytes of the outPoint transaction ID",
|
||||
"outPoint-index": "The index of the outPoint",
|
||||
|
||||
// NotifySpentCmd help.
|
||||
"notifySpent--synopsis": "Send a redeemingtx notification when a transaction spending an outPoint appears in mempool (if relayed to this btcd instance) and when such a transaction first appears in a newly-attached block.",
|
||||
"notifySpent-outPoints": "List of transaction outpoints to monitor.",
|
||||
|
||||
// StopNotifySpentCmd help.
|
||||
"stopNotifySpent--synopsis": "Cancel registered spending notifications for each passed outPoint.",
|
||||
"stopNotifySpent-outPoints": "List of transaction outpoints to stop monitoring.",
|
||||
|
||||
// LoadTxFilterCmd help.
|
||||
"loadTxFilter--synopsis": "Load, add to, or reload a websocket client's transaction filter for mempool transactions, new blocks and rescanBlocks.",
|
||||
"loadTxFilter-reload": "Load a new filter instead of adding data to an existing one",
|
||||
"loadTxFilter-addresses": "Array of addresses to add to the transaction filter",
|
||||
"loadTxFilter-outPoints": "Array of outpoints to add to the transaction filter",
|
||||
|
||||
// Rescan help.
|
||||
"rescan--synopsis": "Rescan block chain for transactions to addresses.\n" +
|
||||
"When the endblock parameter is omitted, the rescan continues through the best block in the main chain.\n" +
|
||||
"Rescan results are sent as recvtx and redeemingtx notifications.\n" +
|
||||
"This call returns once the rescan completes.",
|
||||
"rescan-beginBlock": "Hash of the first block to begin rescanning",
|
||||
"rescan-addresses": "List of addresses to include in the rescan",
|
||||
"rescan-outPoints": "List of transaction outpoints to include in the rescan",
|
||||
"rescan-endBlock": "Hash of final block to rescan",
|
||||
|
||||
// RescanBlocks help.
|
||||
"rescanBlocks--synopsis": "Rescan blocks for transactions matching the loaded transaction filter.",
|
||||
"rescanBlocks-blockHashes": "List of hashes to rescan. Each next block must be a child of the previous.",
|
||||
@ -742,11 +715,6 @@ var rpcResultTypes = map[string][]interface{}{
|
||||
"stopNotifyBlocks": nil,
|
||||
"notifyNewTransactions": nil,
|
||||
"stopNotifyNewTransactions": nil,
|
||||
"notifyReceived": nil,
|
||||
"stopNotifyReceived": nil,
|
||||
"notifySpent": nil,
|
||||
"stopNotifySpent": nil,
|
||||
"rescan": nil,
|
||||
"rescanBlocks": {(*[]btcjson.RescannedBlock)(nil)},
|
||||
}
|
||||
|
||||
|
@ -69,13 +69,9 @@ var wsHandlersBeforeInit = map[string]wsCommandHandler{
|
||||
"help": handleWebsocketHelp,
|
||||
"notifyBlocks": handleNotifyBlocks,
|
||||
"notifyNewTransactions": handleNotifyNewTransactions,
|
||||
"notifyReceived": handleNotifyReceived,
|
||||
"notifySpent": handleNotifySpent,
|
||||
"session": handleSession,
|
||||
"stopNotifyBlocks": handleStopNotifyBlocks,
|
||||
"stopNotifyNewTransactions": handleStopNotifyNewTransactions,
|
||||
"stopNotifySpent": handleStopNotifySpent,
|
||||
"stopNotifyReceived": handleStopNotifyReceived,
|
||||
"rescanBlocks": handleRescanBlocks,
|
||||
}
|
||||
|
||||
@ -446,22 +442,6 @@ type notificationRegisterBlocks wsClient
|
||||
type notificationUnregisterBlocks wsClient
|
||||
type notificationRegisterNewMempoolTxs wsClient
|
||||
type notificationUnregisterNewMempoolTxs wsClient
|
||||
type notificationRegisterSpent struct {
|
||||
wsc *wsClient
|
||||
ops []*wire.OutPoint
|
||||
}
|
||||
type notificationUnregisterSpent struct {
|
||||
wsc *wsClient
|
||||
op *wire.OutPoint
|
||||
}
|
||||
type notificationRegisterAddr struct {
|
||||
wsc *wsClient
|
||||
addrs []string
|
||||
}
|
||||
type notificationUnregisterAddr struct {
|
||||
wsc *wsClient
|
||||
addr string
|
||||
}
|
||||
|
||||
// notificationHandler reads notifications and control messages from the queue
|
||||
// handler and processes one at a time.
|
||||
@ -478,8 +458,6 @@ func (m *wsNotificationManager) notificationHandler() {
|
||||
// since it is quite a bit more efficient than using the entire struct.
|
||||
blockNotifications := make(map[chan struct{}]*wsClient)
|
||||
txNotifications := make(map[chan struct{}]*wsClient)
|
||||
watchedOutPoints := make(map[wire.OutPoint]map[chan struct{}]*wsClient)
|
||||
watchedAddrs := make(map[string]map[chan struct{}]*wsClient)
|
||||
|
||||
out:
|
||||
for {
|
||||
@ -493,15 +471,6 @@ out:
|
||||
case *notificationBlockAdded:
|
||||
block := (*util.Block)(n)
|
||||
|
||||
// Skip iterating through all txs if no
|
||||
// tx notification requests exist.
|
||||
if len(watchedOutPoints) != 0 || len(watchedAddrs) != 0 {
|
||||
for _, tx := range block.Transactions() {
|
||||
m.notifyForTx(watchedOutPoints,
|
||||
watchedAddrs, tx, block)
|
||||
}
|
||||
}
|
||||
|
||||
if len(blockNotifications) != 0 {
|
||||
m.notifyFilteredBlockAdded(blockNotifications,
|
||||
block)
|
||||
@ -511,7 +480,6 @@ out:
|
||||
if n.isNew && len(txNotifications) != 0 {
|
||||
m.notifyForNewTx(txNotifications, n.tx)
|
||||
}
|
||||
m.notifyForTx(watchedOutPoints, watchedAddrs, n.tx, nil)
|
||||
m.notifyRelevantTxAccepted(n.tx, clients)
|
||||
|
||||
case *notificationRegisterBlocks:
|
||||
@ -532,27 +500,8 @@ out:
|
||||
// the client itself.
|
||||
delete(blockNotifications, wsc.quit)
|
||||
delete(txNotifications, wsc.quit)
|
||||
for k := range wsc.spentRequests {
|
||||
op := k
|
||||
m.removeSpentRequest(watchedOutPoints, wsc, &op)
|
||||
}
|
||||
for addr := range wsc.addrRequests {
|
||||
m.removeAddrRequest(watchedAddrs, wsc, addr)
|
||||
}
|
||||
delete(clients, wsc.quit)
|
||||
|
||||
case *notificationRegisterSpent:
|
||||
m.addSpentRequests(watchedOutPoints, n.wsc, n.ops)
|
||||
|
||||
case *notificationUnregisterSpent:
|
||||
m.removeSpentRequest(watchedOutPoints, n.wsc, n.op)
|
||||
|
||||
case *notificationRegisterAddr:
|
||||
m.addAddrRequests(watchedAddrs, n.wsc, n.addrs)
|
||||
|
||||
case *notificationUnregisterAddr:
|
||||
m.removeAddrRequest(watchedAddrs, n.wsc, n.addr)
|
||||
|
||||
case *notificationRegisterNewMempoolTxs:
|
||||
wsc := (*wsClient)(n)
|
||||
txNotifications[wsc.quit] = wsc
|
||||
@ -800,91 +749,6 @@ func (m *wsNotificationManager) notifyForNewTx(clients map[chan struct{}]*wsClie
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterSpentRequests requests a notification when each of the passed
|
||||
// outpoints is confirmed spent (contained in a block added to the blockDAG)
|
||||
// for the passed websocket client. The request is automatically
|
||||
// removed once the notification has been sent.
|
||||
func (m *wsNotificationManager) RegisterSpentRequests(wsc *wsClient, ops []*wire.OutPoint) {
|
||||
m.queueNotification <- ¬ificationRegisterSpent{
|
||||
wsc: wsc,
|
||||
ops: ops,
|
||||
}
|
||||
}
|
||||
|
||||
// addSpentRequests modifies a map of watched outpoints to sets of websocket
|
||||
// clients to add a new request watch all of the outpoints in ops and create
|
||||
// and send a notification when spent to the websocket client wsc.
|
||||
func (m *wsNotificationManager) addSpentRequests(opMap map[wire.OutPoint]map[chan struct{}]*wsClient,
|
||||
wsc *wsClient, ops []*wire.OutPoint) {
|
||||
|
||||
for _, op := range ops {
|
||||
// Track the request in the client as well so it can be quickly
|
||||
// be removed on disconnect.
|
||||
wsc.spentRequests[*op] = struct{}{}
|
||||
|
||||
// Add the client to the list to notify when the outpoint is seen.
|
||||
// Create the list as needed.
|
||||
cmap, ok := opMap[*op]
|
||||
if !ok {
|
||||
cmap = make(map[chan struct{}]*wsClient)
|
||||
opMap[*op] = cmap
|
||||
}
|
||||
cmap[wsc.quit] = wsc
|
||||
}
|
||||
|
||||
// Check if any transactions spending these outputs already exists in
|
||||
// the mempool, if so send the notification immediately.
|
||||
spends := make(map[daghash.Hash]*util.Tx)
|
||||
for _, op := range ops {
|
||||
spend := m.server.cfg.TxMemPool.CheckSpend(*op)
|
||||
if spend != nil {
|
||||
log.Debugf("Found existing mempool spend for "+
|
||||
"outpoint<%s>: %s", op, spend.Hash())
|
||||
spends[*spend.Hash()] = spend
|
||||
}
|
||||
}
|
||||
|
||||
for _, spend := range spends {
|
||||
m.notifyForTx(opMap, nil, spend, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// UnregisterSpentRequest removes a request from the passed websocket client
|
||||
// to be notified when the passed outpoint is confirmed spent (contained in a
|
||||
// block added to the blockDAG).
|
||||
func (m *wsNotificationManager) UnregisterSpentRequest(wsc *wsClient, op *wire.OutPoint) {
|
||||
m.queueNotification <- ¬ificationUnregisterSpent{
|
||||
wsc: wsc,
|
||||
op: op,
|
||||
}
|
||||
}
|
||||
|
||||
// removeSpentRequest modifies a map of watched outpoints to remove the
|
||||
// websocket client wsc from the set of clients to be notified when a
|
||||
// watched outpoint is spent. If wsc is the last client, the outpoint
|
||||
// key is removed from the map.
|
||||
func (*wsNotificationManager) removeSpentRequest(ops map[wire.OutPoint]map[chan struct{}]*wsClient,
|
||||
wsc *wsClient, op *wire.OutPoint) {
|
||||
|
||||
// Remove the request tracking from the client.
|
||||
delete(wsc.spentRequests, *op)
|
||||
|
||||
// Remove the client from the list to notify.
|
||||
notifyMap, ok := ops[*op]
|
||||
if !ok {
|
||||
log.Warnf("Attempt to remove nonexistent spent request "+
|
||||
"for websocket client %s", wsc.addr)
|
||||
return
|
||||
}
|
||||
delete(notifyMap, wsc.quit)
|
||||
|
||||
// Remove the map entry altogether if there are
|
||||
// no more clients interested in it.
|
||||
if len(notifyMap) == 0 {
|
||||
delete(ops, *op)
|
||||
}
|
||||
}
|
||||
|
||||
// txHexString returns the serialized transaction encoded in hexadecimal.
|
||||
func txHexString(tx *wire.MsgTx) string {
|
||||
buf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize()))
|
||||
@ -907,66 +771,6 @@ func blockDetails(block *util.Block, txIndex int) *btcjson.BlockDetails {
|
||||
}
|
||||
}
|
||||
|
||||
// newRedeemingTxNotification returns a new marshalled redeemingtx notification
|
||||
// with the passed parameters.
|
||||
func newRedeemingTxNotification(txHex string, index int, block *util.Block) ([]byte, error) {
|
||||
// Create and marshal the notification.
|
||||
ntfn := btcjson.NewRedeemingTxNtfn(txHex, blockDetails(block, index))
|
||||
return btcjson.MarshalCmd(nil, ntfn)
|
||||
}
|
||||
|
||||
// notifyForTxOuts examines each transaction output, notifying interested
|
||||
// websocket clients of the transaction if an output spends to a watched
|
||||
// address. A spent notification request is automatically registered for
|
||||
// the client for each matching output.
|
||||
func (m *wsNotificationManager) notifyForTxOuts(ops map[wire.OutPoint]map[chan struct{}]*wsClient,
|
||||
addrs map[string]map[chan struct{}]*wsClient, tx *util.Tx, block *util.Block) {
|
||||
|
||||
// Nothing to do if nobody is listening for address notifications.
|
||||
if len(addrs) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
txHex := ""
|
||||
wscNotified := make(map[chan struct{}]struct{})
|
||||
for i, txOut := range tx.MsgTx().TxOut {
|
||||
_, txAddrs, _, err := txscript.ExtractPkScriptAddrs(
|
||||
txOut.PkScript, m.server.cfg.DAGParams)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, txAddr := range txAddrs {
|
||||
cmap, ok := addrs[txAddr.EncodeAddress()]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if txHex == "" {
|
||||
txHex = txHexString(tx.MsgTx())
|
||||
}
|
||||
ntfn := btcjson.NewRecvTxNtfn(txHex, blockDetails(block,
|
||||
tx.Index()))
|
||||
|
||||
marshalledJSON, err := btcjson.MarshalCmd(nil, ntfn)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to marshal processedtx notification: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
op := []*wire.OutPoint{wire.NewOutPoint(tx.ID(), uint32(i))}
|
||||
for wscQuit, wsc := range cmap {
|
||||
m.addSpentRequests(ops, wsc, op)
|
||||
|
||||
if _, ok := wscNotified[wscQuit]; !ok {
|
||||
wscNotified[wscQuit] = struct{}{}
|
||||
wsc.QueueNotification(marshalledJSON)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// notifyRelevantTxAccepted examines the inputs and outputs of the passed
|
||||
// transaction, notifying websocket clients of outputs spending to a watched
|
||||
// address and inputs spending a watched outpoint. Any outputs paying to a
|
||||
@ -990,124 +794,6 @@ func (m *wsNotificationManager) notifyRelevantTxAccepted(tx *util.Tx,
|
||||
}
|
||||
}
|
||||
|
||||
// notifyForTx examines the inputs and outputs of the passed transaction,
|
||||
// notifying websocket clients of outputs spending to a watched address
|
||||
// and inputs spending a watched outpoint.
|
||||
func (m *wsNotificationManager) notifyForTx(ops map[wire.OutPoint]map[chan struct{}]*wsClient,
|
||||
addrs map[string]map[chan struct{}]*wsClient, tx *util.Tx, block *util.Block) {
|
||||
|
||||
if len(ops) != 0 {
|
||||
m.notifyForTxIns(ops, tx, block)
|
||||
}
|
||||
if len(addrs) != 0 {
|
||||
m.notifyForTxOuts(ops, addrs, tx, block)
|
||||
}
|
||||
}
|
||||
|
||||
// notifyForTxIns examines the inputs of the passed transaction and sends
|
||||
// interested websocket clients a redeemingtx notification if any inputs
|
||||
// spend a watched output. If block is non-nil, any matching spent
|
||||
// requests are removed.
|
||||
func (m *wsNotificationManager) notifyForTxIns(ops map[wire.OutPoint]map[chan struct{}]*wsClient,
|
||||
tx *util.Tx, block *util.Block) {
|
||||
|
||||
// Nothing to do if nobody is watching outpoints.
|
||||
if len(ops) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
txHex := ""
|
||||
wscNotified := make(map[chan struct{}]struct{})
|
||||
for _, txIn := range tx.MsgTx().TxIn {
|
||||
prevOut := &txIn.PreviousOutPoint
|
||||
if cmap, ok := ops[*prevOut]; ok {
|
||||
if txHex == "" {
|
||||
txHex = txHexString(tx.MsgTx())
|
||||
}
|
||||
marshalledJSON, err := newRedeemingTxNotification(txHex, tx.Index(), block)
|
||||
if err != nil {
|
||||
log.Warnf("Failed to marshal redeemingtx notification: %s", err)
|
||||
continue
|
||||
}
|
||||
for wscQuit, wsc := range cmap {
|
||||
if block != nil {
|
||||
m.removeSpentRequest(ops, wsc, prevOut)
|
||||
}
|
||||
|
||||
if _, ok := wscNotified[wscQuit]; !ok {
|
||||
wscNotified[wscQuit] = struct{}{}
|
||||
wsc.QueueNotification(marshalledJSON)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterTxOutAddressRequests requests notifications to the passed websocket
|
||||
// client when a transaction output spends to the passed address.
|
||||
func (m *wsNotificationManager) RegisterTxOutAddressRequests(wsc *wsClient, addrs []string) {
|
||||
m.queueNotification <- ¬ificationRegisterAddr{
|
||||
wsc: wsc,
|
||||
addrs: addrs,
|
||||
}
|
||||
}
|
||||
|
||||
// addAddrRequests adds the websocket client wsc to the address to client set
|
||||
// addrMap so wsc will be notified for any mempool or block transaction outputs
|
||||
// spending to any of the addresses in addrs.
|
||||
func (*wsNotificationManager) addAddrRequests(addrMap map[string]map[chan struct{}]*wsClient,
|
||||
wsc *wsClient, addrs []string) {
|
||||
|
||||
for _, addr := range addrs {
|
||||
// Track the request in the client as well so it can be quickly be
|
||||
// removed on disconnect.
|
||||
wsc.addrRequests[addr] = struct{}{}
|
||||
|
||||
// Add the client to the set of clients to notify when the
|
||||
// outpoint is seen. Create map as needed.
|
||||
cmap, ok := addrMap[addr]
|
||||
if !ok {
|
||||
cmap = make(map[chan struct{}]*wsClient)
|
||||
addrMap[addr] = cmap
|
||||
}
|
||||
cmap[wsc.quit] = wsc
|
||||
}
|
||||
}
|
||||
|
||||
// UnregisterTxOutAddressRequest removes a request from the passed websocket
|
||||
// client to be notified when a transaction spends to the passed address.
|
||||
func (m *wsNotificationManager) UnregisterTxOutAddressRequest(wsc *wsClient, addr string) {
|
||||
m.queueNotification <- ¬ificationUnregisterAddr{
|
||||
wsc: wsc,
|
||||
addr: addr,
|
||||
}
|
||||
}
|
||||
|
||||
// removeAddrRequest removes the websocket client wsc from the address to
|
||||
// client set addrs so it will no longer receive notification updates for
|
||||
// any transaction outputs send to addr.
|
||||
func (*wsNotificationManager) removeAddrRequest(addrs map[string]map[chan struct{}]*wsClient,
|
||||
wsc *wsClient, addr string) {
|
||||
|
||||
// Remove the request tracking from the client.
|
||||
delete(wsc.addrRequests, addr)
|
||||
|
||||
// Remove the client from the list to notify.
|
||||
cmap, ok := addrs[addr]
|
||||
if !ok {
|
||||
log.Warnf("Attempt to remove nonexistent addr request "+
|
||||
"<%s> for websocket client %s", addr, wsc.addr)
|
||||
return
|
||||
}
|
||||
delete(cmap, wsc.quit)
|
||||
|
||||
// Remove the map entry altogether if there are no more clients
|
||||
// interested in it.
|
||||
if len(cmap) == 0 {
|
||||
delete(addrs, addr)
|
||||
}
|
||||
}
|
||||
|
||||
// AddClient adds the passed websocket client to the notification manager.
|
||||
func (m *wsNotificationManager) AddClient(wsc *wsClient) {
|
||||
m.queueNotification <- (*notificationRegisterClient)(wsc)
|
||||
@ -1213,16 +899,6 @@ type wsClient struct {
|
||||
// new transaction information from a specific subnetwork.
|
||||
subnetworkIDForTxUpdates *subnetworkid.SubnetworkID
|
||||
|
||||
// addrRequests is a set of addresses the caller has requested to be
|
||||
// notified about. It is maintained here so all requests can be removed
|
||||
// when a wallet disconnects. Owned by the notification manager.
|
||||
addrRequests map[string]struct{}
|
||||
|
||||
// spentRequests is a set of unspent Outpoints a wallet has requested
|
||||
// notifications for when they are spent by a processed transaction.
|
||||
// Owned by the notification manager.
|
||||
spentRequests map[wire.OutPoint]struct{}
|
||||
|
||||
// filterData is the new generation transaction filter backported from
|
||||
// github.com/decred/dcrd for the new backported `loadTxFilter` and
|
||||
// `rescanBlocks` methods.
|
||||
@ -1659,8 +1335,6 @@ func newWebsocketClient(server *Server, conn *websocket.Conn,
|
||||
isAdmin: isAdmin,
|
||||
sessionID: sessionID,
|
||||
server: server,
|
||||
addrRequests: make(map[string]struct{}),
|
||||
spentRequests: make(map[wire.OutPoint]struct{}),
|
||||
serviceRequestSem: makeSemaphore(config.MainConfig().RPCMaxConcurrentReqs),
|
||||
ntfnChan: make(chan []byte, 1), // nonblocking sync
|
||||
sendChan: make(chan wsResponse, websocketSendBufferSize),
|
||||
@ -1781,23 +1455,6 @@ func handleStopNotifyBlocks(wsc *wsClient, icmd interface{}) (interface{}, error
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// handleNotifySpent implements the notifySpent command extension for
|
||||
// websocket connections.
|
||||
func handleNotifySpent(wsc *wsClient, icmd interface{}) (interface{}, error) {
|
||||
cmd, ok := icmd.(*btcjson.NotifySpentCmd)
|
||||
if !ok {
|
||||
return nil, btcjson.ErrRPCInternal
|
||||
}
|
||||
|
||||
outpoints, err := deserializeOutpoints(cmd.OutPoints)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wsc.server.ntfnMgr.RegisterSpentRequests(wsc, outpoints)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// handleNotifyNewTransations implements the notifyNewTransactions command
|
||||
// extension for websocket connections.
|
||||
func handleNotifyNewTransactions(wsc *wsClient, icmd interface{}) (interface{}, error) {
|
||||
@ -1862,85 +1519,6 @@ func handleStopNotifyNewTransactions(wsc *wsClient, icmd interface{}) (interface
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// handleNotifyReceived implements the notifyReceived command extension for
|
||||
// websocket connections.
|
||||
func handleNotifyReceived(wsc *wsClient, icmd interface{}) (interface{}, error) {
|
||||
cmd, ok := icmd.(*btcjson.NotifyReceivedCmd)
|
||||
if !ok {
|
||||
return nil, btcjson.ErrRPCInternal
|
||||
}
|
||||
|
||||
// Decode addresses to validate input, but the strings slice is used
|
||||
// directly if these are all ok.
|
||||
err := checkAddressValidity(cmd.Addresses, wsc.server.cfg.DAGParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wsc.server.ntfnMgr.RegisterTxOutAddressRequests(wsc, cmd.Addresses)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// handleStopNotifySpent implements the stopNotifySpent command extension for
|
||||
// websocket connections.
|
||||
func handleStopNotifySpent(wsc *wsClient, icmd interface{}) (interface{}, error) {
|
||||
cmd, ok := icmd.(*btcjson.StopNotifySpentCmd)
|
||||
if !ok {
|
||||
return nil, btcjson.ErrRPCInternal
|
||||
}
|
||||
|
||||
outpoints, err := deserializeOutpoints(cmd.OutPoints)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, outpoint := range outpoints {
|
||||
wsc.server.ntfnMgr.UnregisterSpentRequest(wsc, outpoint)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// handleStopNotifyReceived implements the stopNotifyReceived command extension
|
||||
// for websocket connections.
|
||||
func handleStopNotifyReceived(wsc *wsClient, icmd interface{}) (interface{}, error) {
|
||||
cmd, ok := icmd.(*btcjson.StopNotifyReceivedCmd)
|
||||
if !ok {
|
||||
return nil, btcjson.ErrRPCInternal
|
||||
}
|
||||
|
||||
// Decode addresses to validate input, but the strings slice is used
|
||||
// directly if these are all ok.
|
||||
err := checkAddressValidity(cmd.Addresses, wsc.server.cfg.DAGParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, addr := range cmd.Addresses {
|
||||
wsc.server.ntfnMgr.UnregisterTxOutAddressRequest(wsc, addr)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// checkAddressValidity checks the validity of each address in the passed
|
||||
// string slice. It does this by attempting to decode each address using the
|
||||
// current active network parameters. If any single address fails to decode
|
||||
// properly, the function returns an error. Otherwise, nil is returned.
|
||||
func checkAddressValidity(addrs []string, params *dagconfig.Params) error {
|
||||
for _, addr := range addrs {
|
||||
_, err := util.DecodeAddress(addr, params.Prefix)
|
||||
if err != nil {
|
||||
return &btcjson.RPCError{
|
||||
Code: btcjson.ErrRPCInvalidAddressOrKey,
|
||||
Message: fmt.Sprintf("Invalid address or key: %s",
|
||||
addr),
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// deserializeOutpoints deserializes each serialized outpoint.
|
||||
func deserializeOutpoints(serializedOuts []btcjson.OutPoint) ([]*wire.OutPoint, error) {
|
||||
outpoints := make([]*wire.OutPoint, 0, len(serializedOuts))
|
||||
|
Loading…
x
Reference in New Issue
Block a user