Added commands to support notifyallnewtxs

Sending NotifyAllNewTXsCmd will register websocket client to receive
notifications on all new transactions.

Once registered the client will receive either AllTxNtfn or
AllVerboseTxNtfn based on the required verbose field in the
NotifyAllNewTXsCmd.
This commit is contained in:
Francis Lam 2014-02-08 17:03:22 -05:00
parent 3cba42282e
commit 07c403efd0
4 changed files with 313 additions and 0 deletions

86
cmds.go
View file

@ -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.

View file

@ -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) {

View file

@ -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
}

View file

@ -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) {