diff --git a/cmds.go b/cmds.go index f08fe839..668ed677 100644 --- a/cmds.go +++ b/cmds.go @@ -43,6 +43,8 @@ func init() { `TODO(jrick) fillmein`) btcjson.RegisterCustomCmd("notifynewtxs", parseNotifyNewTXsCmd, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd("notifyallnewtxs", parseNotifyAllNewTXsCmd, + `TODO(flam) fillmein`) btcjson.RegisterCustomCmd("notifyspent", parseNotifySpentCmd, `TODO(jrick) fillmein`) btcjson.RegisterCustomCmd("recoveraddresses", parseRecoverAddressesCmd, @@ -902,6 +904,90 @@ func (cmd *NotifyNewTXsCmd) UnmarshalJSON(b []byte) error { return nil } +// NotifyAllNewTXsCmd is a type handling custom marshaling and +// unmarshaling of notifynewtxs JSON websocket extension +// commands. +type NotifyAllNewTXsCmd struct { + id interface{} + Verbose bool +} + +// Enforce that NotifyAllNewTXsCmd satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &NotifyAllNewTXsCmd{} + +// NewNotifyAllNewTXsCmd creates a new NotifyAllNewTXsCmd. +func NewNotifyAllNewTXsCmd(id interface{}, verbose bool) *NotifyAllNewTXsCmd { + return &NotifyAllNewTXsCmd{ + id: id, + Verbose: verbose, + } +} + +// parseNotifyAllNewTXsCmd parses a NotifyAllNewTXsCmd into a concrete type +// satisifying the btcjson.Cmd interface. This is used when registering +// the custom command with the btcjson parser. +func parseNotifyAllNewTXsCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if len(r.Params) != 1 { + return nil, btcjson.ErrWrongNumberOfParams + } + + verbose := r.Params[0].(bool) + + return NewNotifyAllNewTXsCmd(r.Id, verbose), nil +} + +// Id satisifies the Cmd interface by returning the ID of the command. +func (cmd *NotifyAllNewTXsCmd) Id() interface{} { + return cmd.id +} + +// SetId satisifies the Cmd interface by setting the ID of the command. +func (cmd *NotifyAllNewTXsCmd) SetId(id interface{}) { + cmd.id = id +} + +// Method satisfies the Cmd interface by returning the RPC method. +func (cmd *NotifyAllNewTXsCmd) Method() string { + return "notifyallnewtxs" +} + +// MarshalJSON returns the JSON encoding of cmd. Part of the Cmd interface. +func (cmd *NotifyAllNewTXsCmd) MarshalJSON() ([]byte, error) { + // Fill a RawCmd and marshal. + raw := btcjson.RawCmd{ + Jsonrpc: "1.0", + Method: "notifyallnewtxs", + Id: cmd.id, + Params: []interface{}{ + cmd.Verbose, + }, + } + + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of cmd into cmd. Part of +// the Cmd interface. +func (cmd *NotifyAllNewTXsCmd) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newCmd, err := parseNotifyAllNewTXsCmd(&r) + if err != nil { + return err + } + + concreteCmd, ok := newCmd.(*NotifyAllNewTXsCmd) + if !ok { + return btcjson.ErrInternal + } + *cmd = *concreteCmd + return nil +} + // NotifySpentCmd is a type handling custom marshaling and // unmarshaling of notifyspent JSON websocket extension // commands. diff --git a/cmds_test.go b/cmds_test.go index 49fffebe..0a2375c6 100644 --- a/cmds_test.go +++ b/cmds_test.go @@ -173,6 +173,18 @@ var cmdtests = []struct { }, }, }, + { + name: "notifyallnewtxs", + f: func() (btcjson.Cmd, error) { + return NewNotifyAllNewTXsCmd( + float64(1), + true), nil + }, + result: &NotifyAllNewTXsCmd{ + id: float64(1), + Verbose: true, + }, + }, { name: "notifyspent", f: func() (btcjson.Cmd, error) { diff --git a/notifications.go b/notifications.go index 59b0c2bb..2d5fa72c 100644 --- a/notifications.go +++ b/notifications.go @@ -38,6 +38,14 @@ const ( // processedtx notification. ProcessedTxNtfnMethod = "processedtx" + // AllTxNtfnMethod is the method of the btcd alltx + // notification + AllTxNtfnMethod = "alltx" + + // AllVerboseTxNtfnMethod is the method of the btcd + // allverbosetx notifications. + AllVerboseTxNtfnMethod = "allverbosetx" + // TxMinedNtfnMethod is the method of the btcd txmined // notification. TxMinedNtfnMethod = "txmined" @@ -75,6 +83,10 @@ func init() { `TODO(jrick) fillmein`) btcjson.RegisterCustomCmd(WalletLockStateNtfnMethod, parseWalletLockStateNtfn, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd(AllTxNtfnMethod, + parseAllTxNtfn, `TODO(flam) fillmein`) + btcjson.RegisterCustomCmdGenerator(AllVerboseTxNtfnMethod, + generateAllVerboseTxNtfn) } // AccountBalanceNtfn is a type handling custom marshaling and @@ -1015,3 +1027,175 @@ func (n *WalletLockStateNtfn) UnmarshalJSON(b []byte) error { *n = *concreteNtfn return nil } + +// AllTxNtfn is a type handling custom marshaling and +// unmarshaling of txmined JSON websocket notifications. +type AllTxNtfn struct { + TxID string + Amount int64 +} + +// Enforce that AllTxNtfn satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &AllTxNtfn{} + +// NewAllTxNtfn creates a new AllTxNtfn. +func NewAllTxNtfn(txid string, amount int64) *AllTxNtfn { + return &AllTxNtfn{ + TxID: txid, + Amount: amount, + } +} + +// parseAllTxNtfn parses a RawCmd into a concrete type satisifying +// the btcjson.Cmd interface. This is used when registering the notification +// with the btcjson parser. +func parseAllTxNtfn(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if r.Id != nil { + return nil, ErrNotANtfn + } + + if len(r.Params) != 2 { + return nil, btcjson.ErrWrongNumberOfParams + } + + txid, ok := r.Params[0].(string) + if !ok { + return nil, errors.New("first parameter txid must be a string") + } + famount, ok := r.Params[1].(float64) + if !ok { + return nil, errors.New("second parameter amount must be a number") + } + + return NewAllTxNtfn(txid, int64(famount)), nil +} + +// Id satisifies the btcjson.Cmd interface by returning nil for a +// notification ID. +func (n *AllTxNtfn) Id() interface{} { + return nil +} + +// SetId is implemented to satisify the btcjson.Cmd interface. The +// notification id is not modified. +func (n *AllTxNtfn) SetId(id interface{}) {} + +// Method satisifies the btcjson.Cmd interface by returning the method +// of the notification. +func (n *AllTxNtfn) Method() string { + return AllTxNtfnMethod +} + +// MarshalJSON returns the JSON encoding of n. Part of the btcjson.Cmd +// interface. +func (n *AllTxNtfn) MarshalJSON() ([]byte, error) { + ntfn := btcjson.Message{ + Jsonrpc: "1.0", + Method: n.Method(), + Params: []interface{}{ + n.TxID, + n.Amount, + }, + } + return json.Marshal(ntfn) +} + +// UnmarshalJSON unmarshals the JSON encoding of n into n. Part of +// the btcjson.Cmd interface. +func (n *AllTxNtfn) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newNtfn, err := parseAllTxNtfn(&r) + if err != nil { + return err + } + + concreteNtfn, ok := newNtfn.(*AllTxNtfn) + if !ok { + return btcjson.ErrInternal + } + *n = *concreteNtfn + return nil +} + +// AllVerboseTxNtfn is a type handling custom marshaling and +// unmarshaling of txmined JSON websocket notifications. +type AllVerboseTxNtfn struct { + RawTx *btcjson.TxRawResult +} + +// Enforce that AllTxNtfn satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &AllVerboseTxNtfn{} + +// NewAllVerboseTxNtfn creates a new AllVerboseTxNtfn. +func NewAllVerboseTxNtfn(rawTx *btcjson.TxRawResult) *AllVerboseTxNtfn { + return &AllVerboseTxNtfn{ + RawTx: rawTx, + } +} + +// Id satisifies the btcjson.Cmd interface by returning nil for a +// notification ID. +func (n *AllVerboseTxNtfn) Id() interface{} { + return nil +} + +// SetId is implemented to satisify the btcjson.Cmd interface. The +// notification id is not modified. +func (n *AllVerboseTxNtfn) SetId(id interface{}) {} + +// Method satisifies the btcjson.Cmd interface by returning the method +// of the notification. +func (n *AllVerboseTxNtfn) Method() string { + return AllVerboseTxNtfnMethod +} + +// MarshalJSON returns the JSON encoding of n. Part of the btcjson.Cmd +// interface. +func (n *AllVerboseTxNtfn) MarshalJSON() ([]byte, error) { + ntfn := btcjson.Message{ + Jsonrpc: "1.0", + Method: n.Method(), + Params: []interface{}{ + n.RawTx, + }, + } + return json.Marshal(ntfn) +} + +func generateAllVerboseTxNtfn() btcjson.Cmd { + return new(AllVerboseTxNtfn) +} + +type rawParamsCmd struct { + Jsonrpc string `json:"jsonrpc"` + Id interface{} `json:"id"` + Method string `json:"method"` + Params []*json.RawMessage `json:"params"` +} + +// UnmarshalJSON unmarshals the JSON encoding of n into n. Part of +// the btcjson.Cmd interface. +func (n *AllVerboseTxNtfn) UnmarshalJSON(b []byte) error { + // Unmarshal into a custom rawParamsCmd + var r rawParamsCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + if len(r.Params) != 1 { + return btcjson.ErrWrongNumberOfParams + } + + var rawTx *btcjson.TxRawResult + if err := json.Unmarshal(*r.Params[0], &rawTx); err != nil { + return err + } + + *n = *NewAllVerboseTxNtfn(rawTx) + return nil +} diff --git a/notifications_test.go b/notifications_test.go index a06f72dc..d70abee3 100644 --- a/notifications_test.go +++ b/notifications_test.go @@ -154,6 +154,37 @@ var ntfntests = []struct { Locked: true, }, }, + { + name: "alltx", + f: func() btcjson.Cmd { + return btcws.NewAllTxNtfn( + "062f2b5f7d28c787e0f3aee382132241cd590efb7b83bd2c7f506de5aa4ef275", + 34567765) + }, + result: &btcws.AllTxNtfn{ + TxID: "062f2b5f7d28c787e0f3aee382132241cd590efb7b83bd2c7f506de5aa4ef275", + Amount: 34567765, + }, + }, + { + name: "allverbosetx", + f: func() btcjson.Cmd { + return btcws.NewAllVerboseTxNtfn(&btcjson.TxRawResult{ + Hex: "01000000010cdf900074a3622499a2f28f44a94476f27a8900a2bdd60e042754b6cab09741000000008a473044022012e11012fad1eb21ba1c82deb8da98778b08e714b72f281293064528343fae0502204294d7520f469f9673087a55395de0ce0e9074dce236db9fe7f30013b5fd00b90141047b6ff7832b4a763666e5481a0bd9eedb656d9f882d215c16fe9563d7b191cd67b2a41601a853a9f9d92773ae6f912ef451a089148e510623759cf55c408efdefffffffff02f4063f00000000001976a914b269e0ceec5d5b5e192cf580ae42341e0f79b0b588aca8c84b02000000001976a91439233c0d43a1411e547c60bad8985bae3530b6af88ac00000000", + Txid: "0cfeb968fb5d0f6b9a2a1de37c0607a1964dd3e335f203377cec90e03b20869e", + Version: 0x1, + LockTime: 0x0, + }) + }, + result: &btcws.AllVerboseTxNtfn{ + RawTx: &btcjson.TxRawResult{ + Hex: "01000000010cdf900074a3622499a2f28f44a94476f27a8900a2bdd60e042754b6cab09741000000008a473044022012e11012fad1eb21ba1c82deb8da98778b08e714b72f281293064528343fae0502204294d7520f469f9673087a55395de0ce0e9074dce236db9fe7f30013b5fd00b90141047b6ff7832b4a763666e5481a0bd9eedb656d9f882d215c16fe9563d7b191cd67b2a41601a853a9f9d92773ae6f912ef451a089148e510623759cf55c408efdefffffffff02f4063f00000000001976a914b269e0ceec5d5b5e192cf580ae42341e0f79b0b588aca8c84b02000000001976a91439233c0d43a1411e547c60bad8985bae3530b6af88ac00000000", + Txid: "0cfeb968fb5d0f6b9a2a1de37c0607a1964dd3e335f203377cec90e03b20869e", + Version: 0x1, + LockTime: 0x0, + }, + }, + }, } func TestNtfns(t *testing.T) {