diff --git a/btcjson/btcws/README.md b/btcjson/btcws/README.md new file mode 100644 index 00000000..cd1bb925 --- /dev/null +++ b/btcjson/btcws/README.md @@ -0,0 +1,88 @@ +btcws +===== + +[![Build Status](https://travis-ci.org/btcsuite/btcd.png?branch=master)] +(https://travis-ci.org/btcsuite/btcws) + +Package btcws implements extensions to the standard bitcoind JSON-RPC +API for the btcd suite of programs (btcd, btcwallet, and btcgui). +Importing this package registers all implemented custom requests with +btcjson (using btcjson.RegisterCustomCmd). + +## Sample Use +```Go +// Client Side +import ( + "golang.org/x/net/websocket" + "github.com/btcsuite/btcd/btcjson/btcws" +) + +// Create rescan command. +id := 0 +addrs := map[string]struct{}{ + "17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH": struct{}, +} +cmd, err := btcws.NewRescanCmd(id, 270000, addrs) + +// Set up a handler for a reply with id 0. +AddReplyHandler(id, func(reply map[string]interface{}) { + // Deal with reply. +}) + +// JSON marshal and send rescan request to websocket connection. +websocket.JSON.Send(btcdWSConn, cmd) + + +// Server Side +import ( + "golang.org/x/net/websocket" + "github.com/btcsuite/btcd/btcjson" + "github.com/btcsuite/btcd/btcjson/btcws" +) + +// Get marshaled request. +var b []byte +err := websocket.Message.Receive(clientWSConn, &b) + +// Parse marshaled command. +cmd, err := btcjson.ParseMarshaledCmd(b) + +// If this is a rescan command, handle and reply. +rcmd, ok := cmd.(*btcws.RescanCmd) +if ok { + // Do stuff + var reply []byte + err := websocket.Message.Send(clientWSConn, reply) +} + +``` + +## Installation + +```bash +$ go get github.com/btcsuite/btcd/btcjson/btcws +``` + +## GPG Verification Key + +All official release tags are signed by Conformal so users can ensure the code +has not been tampered with and is coming from Conformal. To verify the +signature perform the following: + +- Download the public key from the Conformal website at + https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt + +- Import the public key into your GPG keyring: + ```bash + gpg --import GIT-GPG-KEY-conformal.txt + ``` + +- Verify the release tag with the following command where `TAG_NAME` is a + placeholder for the specific tag: + ```bash + git tag -v TAG_NAME + ``` + +## License + +Package btcws is licensed under the liberal ISC License. diff --git a/btcjson/btcws/cmds.go b/btcjson/btcws/cmds.go new file mode 100644 index 00000000..e79df6f3 --- /dev/null +++ b/btcjson/btcws/cmds.go @@ -0,0 +1,1664 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcws + +import ( + "encoding/json" + "errors" + + "github.com/btcsuite/btcd/btcjson" + "github.com/btcsuite/btcd/wire" +) + +// Help texts +const ( + authenticateHelp = `authenticate "username" "passphrase" +Authenticate the websocket with the RPC server. This is only required if the +credentials were not already supplied via HTTP auth headers. It must be the +first command sent or you will be disconnected.` + + createNewAccountHelp = `createnewaccount "accountname" +Create a new account with the given name.` + + renameAccountHelp = `renameaccount "oldname" "newname" +Rename an account to the given new name.` +) + +func init() { + btcjson.RegisterCustomCmd("authenticate", parseAuthenticateCmd, nil, + authenticateHelp) + btcjson.RegisterCustomCmd("createencryptedwallet", + parseCreateEncryptedWalletCmd, nil, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd("createnewaccount", + parseCreateNewAccountCmd, nil, createNewAccountHelp) + btcjson.RegisterCustomCmd("exportwatchingwallet", + parseExportWatchingWalletCmd, nil, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd("getbestblock", parseGetBestBlockCmd, + parseGetBestBlockCmdReply, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd("getcurrentnet", parseGetCurrentNetCmd, nil, + `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd("getunconfirmedbalance", + parseGetUnconfirmedBalanceCmd, nil, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd("listaddresstransactions", + parseListAddressTransactionsCmd, + parseListAddressTransactionsCmdReply, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd("listalltransactions", + parseListAllTransactionsCmd, nil, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd("notifyblocks", parseNotifyBlocksCmd, nil, + `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd("notifyreceived", parseNotifyReceivedCmd, nil, + `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd("notifynewtransactions", + parseNotifyNewTransactionsCmd, nil, `TODO(flam) fillmein`) + btcjson.RegisterCustomCmd("notifyspent", parseNotifySpentCmd, + nil, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd("recoveraddresses", parseRecoverAddressesCmd, + nil, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd("renameaccount", parseRenameAccountCmd, + nil, renameAccountHelp) + btcjson.RegisterCustomCmd("rescan", parseRescanCmd, + nil, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd("walletislocked", parseWalletIsLockedCmd, + nil, `TODO(jrick) fillmein`) +} + +// AuthenticateCmd is a type handling custom marshaling and +// unmarshaling of authenticate JSON websocket extension +// commands. +type AuthenticateCmd struct { + id interface{} + Username string + Passphrase string +} + +// Enforce that AuthenticateCmd satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &AuthenticateCmd{} + +// NewAuthenticateCmd creates a new GetCurrentNetCmd. +func NewAuthenticateCmd(id interface{}, username, passphrase string) *AuthenticateCmd { + return &AuthenticateCmd{ + id: id, + Username: username, + Passphrase: passphrase, + } +} + +// parseAuthenticateCmd parses a RawCmd into a concrete type satisifying +// the btcjson.Cmd interface. This is used when registering the custom +// command with the btcjson parser. +func parseAuthenticateCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if len(r.Params) != 2 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var username string + if err := json.Unmarshal(r.Params[0], &username); err != nil { + return nil, errors.New("first parameter 'username' must be " + + "a string: " + err.Error()) + } + + var passphrase string + if err := json.Unmarshal(r.Params[1], &passphrase); err != nil { + return nil, errors.New("second parameter 'passphrase' must " + + "be a string: " + err.Error()) + } + + return NewAuthenticateCmd(r.Id, username, passphrase), nil +} + +// Id satisifies the Cmd interface by returning the ID of the command. +func (cmd *AuthenticateCmd) Id() interface{} { + return cmd.id +} + +// Method satisfies the Cmd interface by returning the RPC method. +func (cmd *AuthenticateCmd) Method() string { + return "authenticate" +} + +// MarshalJSON returns the JSON encoding of cmd. Part of the Cmd interface. +func (cmd *AuthenticateCmd) MarshalJSON() ([]byte, error) { + params := []interface{}{ + cmd.Username, + cmd.Passphrase, + } + + raw, err := btcjson.NewRawCmd(cmd.id, cmd.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of cmd into cmd. Part of +// the Cmd interface. +func (cmd *AuthenticateCmd) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newCmd, err := parseAuthenticateCmd(&r) + if err != nil { + return err + } + + concreteCmd, ok := newCmd.(*AuthenticateCmd) + if !ok { + return btcjson.ErrInternal + } + *cmd = *concreteCmd + return nil +} + +// GetCurrentNetCmd is a type handling custom marshaling and +// unmarshaling of getcurrentnet JSON websocket extension +// commands. +type GetCurrentNetCmd struct { + id interface{} +} + +// Enforce that GetCurrentNetCmd satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &GetCurrentNetCmd{} + +// NewGetCurrentNetCmd creates a new GetCurrentNetCmd. +func NewGetCurrentNetCmd(id interface{}) *GetCurrentNetCmd { + return &GetCurrentNetCmd{id: id} +} + +// parseGetCurrentNetCmd parses a RawCmd into a concrete type satisifying +// the btcjson.Cmd interface. This is used when registering the custom +// command with the btcjson parser. +func parseGetCurrentNetCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if len(r.Params) != 0 { + return nil, btcjson.ErrWrongNumberOfParams + } + + return NewGetCurrentNetCmd(r.Id), nil +} + +// Id satisifies the Cmd interface by returning the ID of the command. +func (cmd *GetCurrentNetCmd) Id() interface{} { + return cmd.id +} + +// Method satisfies the Cmd interface by returning the RPC method. +func (cmd *GetCurrentNetCmd) Method() string { + return "getcurrentnet" +} + +// MarshalJSON returns the JSON encoding of cmd. Part of the Cmd interface. +func (cmd *GetCurrentNetCmd) MarshalJSON() ([]byte, error) { + raw, err := btcjson.NewRawCmd(cmd.id, cmd.Method(), []interface{}{}) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of cmd into cmd. Part of +// the Cmd interface. +func (cmd *GetCurrentNetCmd) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newCmd, err := parseGetCurrentNetCmd(&r) + if err != nil { + return err + } + + concreteCmd, ok := newCmd.(*GetCurrentNetCmd) + if !ok { + return btcjson.ErrInternal + } + *cmd = *concreteCmd + return nil +} + +// ExportWatchingWalletCmd is a type handling custom marshaling and +// unmarshaling of exportwatchingwallet JSON websocket extension +// commands. +type ExportWatchingWalletCmd struct { + id interface{} + Account string + Download bool +} + +// Enforce that ExportWatchingWalletCmd satisifies the btcjson.Cmd +// interface. +var _ btcjson.Cmd = &ExportWatchingWalletCmd{} + +// NewExportWatchingWalletCmd creates a new ExportWatchingWalletCmd. +func NewExportWatchingWalletCmd(id interface{}, optArgs ...interface{}) (*ExportWatchingWalletCmd, error) { + if len(optArgs) > 2 { + return nil, btcjson.ErrTooManyOptArgs + } + + // Optional parameters set to their defaults. + account := "" + dl := false + + if len(optArgs) > 0 { + a, ok := optArgs[0].(string) + if !ok { + return nil, errors.New("first optarg account must be a string") + } + account = a + } + if len(optArgs) > 1 { + b, ok := optArgs[1].(bool) + if !ok { + return nil, errors.New("second optarg zip must be a boolean") + } + dl = b + } + + return &ExportWatchingWalletCmd{ + id: id, + Account: account, + Download: dl, + }, nil +} + +// parseExportWatchingWalletCmd parses a RawCmd into a concrete type +// satisifying the btcjson.Cmd interface. This is used when registering +// the custom command with the btcjson parser. +func parseExportWatchingWalletCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if len(r.Params) > 2 { + return nil, btcjson.ErrTooManyOptArgs + } + + optArgs := make([]interface{}, 0, 2) + if len(r.Params) > 0 { + var account string + if err := json.Unmarshal(r.Params[0], &account); err != nil { + return nil, errors.New("first optional parameter " + + " 'account' must be a string: " + err.Error()) + } + optArgs = append(optArgs, account) + } + + if len(r.Params) > 1 { + var download bool + if err := json.Unmarshal(r.Params[1], &download); err != nil { + return nil, errors.New("second optional parameter " + + " 'download' must be a bool: " + err.Error()) + } + optArgs = append(optArgs, download) + } + + return NewExportWatchingWalletCmd(r.Id, optArgs...) +} + +// Id satisifies the Cmd interface by returning the ID of the command. +func (cmd *ExportWatchingWalletCmd) Id() interface{} { + return cmd.id +} + +// Method satisifies the Cmd interface by returning the RPC method. +func (cmd *ExportWatchingWalletCmd) Method() string { + return "exportwatchingwallet" +} + +// MarshalJSON returns the JSON encoding of cmd. Part of the Cmd interface. +func (cmd *ExportWatchingWalletCmd) MarshalJSON() ([]byte, error) { + params := make([]interface{}, 0, 2) + if cmd.Account != "" || cmd.Download { + params = append(params, cmd.Account) + } + if cmd.Download { + params = append(params, cmd.Download) + } + + raw, err := btcjson.NewRawCmd(cmd.id, cmd.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of cmd into cmd. Part of +// the Cmd interface. +func (cmd *ExportWatchingWalletCmd) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newCmd, err := parseExportWatchingWalletCmd(&r) + if err != nil { + return err + } + + concreteCmd, ok := newCmd.(*ExportWatchingWalletCmd) + if !ok { + return btcjson.ErrInternal + } + *cmd = *concreteCmd + return nil +} + +// GetUnconfirmedBalanceCmd is a type handling custom marshaling and +// unmarshaling of getunconfirmedbalance JSON websocket extension +// commands. +type GetUnconfirmedBalanceCmd struct { + id interface{} + Account string +} + +// Enforce that GetUnconfirmedBalanceCmd satisifies the btcjson.Cmd +// interface. +var _ btcjson.Cmd = &GetUnconfirmedBalanceCmd{} + +// NewGetUnconfirmedBalanceCmd creates a new GetUnconfirmedBalanceCmd. +func NewGetUnconfirmedBalanceCmd(id interface{}, + optArgs ...string) (*GetUnconfirmedBalanceCmd, error) { + + if len(optArgs) > 1 { + return nil, btcjson.ErrTooManyOptArgs + } + + // Optional parameters set to their defaults. + account := "" + + if len(optArgs) == 1 { + account = optArgs[0] + } + + return &GetUnconfirmedBalanceCmd{ + id: id, + Account: account, + }, nil +} + +// parseGetUnconfirmedBalanceCmd parses a RawCmd into a concrete type +// satisifying the btcjson.Cmd interface. This is used when registering +// the custom command with the btcjson parser. +func parseGetUnconfirmedBalanceCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if len(r.Params) > 1 { + return nil, btcjson.ErrWrongNumberOfParams + } + + optArgs := make([]string, 0, 1) + if len(r.Params) > 0 { + var account string + if err := json.Unmarshal(r.Params[0], &account); err != nil { + return nil, errors.New("first optional parameter " + + " 'account' must be a string: " + err.Error()) + } + optArgs = append(optArgs, account) + } + + return NewGetUnconfirmedBalanceCmd(r.Id, optArgs...) +} + +// Id satisifies the Cmd interface by returning the ID of the command. +func (cmd *GetUnconfirmedBalanceCmd) Id() interface{} { + return cmd.id +} + +// Method satisifies the Cmd interface by returning the RPC method. +func (cmd *GetUnconfirmedBalanceCmd) Method() string { + return "getunconfirmedbalance" +} + +// MarshalJSON returns the JSON encoding of cmd. Part of the Cmd interface. +func (cmd *GetUnconfirmedBalanceCmd) MarshalJSON() ([]byte, error) { + params := make([]interface{}, 0, 1) + if cmd.Account != "" { + params = append(params, cmd.Account) + } + + raw, err := btcjson.NewRawCmd(cmd.id, cmd.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of cmd into cmd. Part of +// the Cmd interface. +func (cmd *GetUnconfirmedBalanceCmd) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newCmd, err := parseGetUnconfirmedBalanceCmd(&r) + if err != nil { + return err + } + + concreteCmd, ok := newCmd.(*GetUnconfirmedBalanceCmd) + if !ok { + return btcjson.ErrInternal + } + *cmd = *concreteCmd + return nil +} + +// GetBestBlockResult holds the result of a getbestblock response. +type GetBestBlockResult struct { + Hash string `json:"hash"` + Height int32 `json:"height"` +} + +// GetBestBlockCmd is a type handling custom marshaling and +// unmarshaling of getbestblock JSON websocket extension +// commands. +type GetBestBlockCmd struct { + id interface{} +} + +// Enforce that GetBestBlockCmd satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &GetBestBlockCmd{} + +// NewGetBestBlockCmd creates a new GetBestBlock. +func NewGetBestBlockCmd(id interface{}) *GetBestBlockCmd { + return &GetBestBlockCmd{id: id} +} + +// parseGetBestBlockCmd parses a RawCmd into a concrete type satisifying +// the btcjson.Cmd interface. This is used when registering the custom +// command with the btcjson parser. +func parseGetBestBlockCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if len(r.Params) != 0 { + return nil, btcjson.ErrWrongNumberOfParams + } + + return NewGetBestBlockCmd(r.Id), nil +} + +// parseGetBestBlockCmdReply parses a the reply to a GetBestBlockCmd into a +// concrete type and returns it packed into an interface. This is used when +// registering the custom command with btcjson. +func parseGetBestBlockCmdReply(message json.RawMessage) (interface{}, error) { + var res *GetBestBlockResult + if err := json.Unmarshal(message, &res); err != nil { + return nil, err + } + return res, nil +} + +// Id satisifies the Cmd interface by returning the ID of the command. +func (cmd *GetBestBlockCmd) Id() interface{} { + return cmd.id +} + +// Method satisfies the Cmd interface by returning the RPC method. +func (cmd *GetBestBlockCmd) Method() string { + return "getbestblock" +} + +// MarshalJSON returns the JSON encoding of cmd. Part of the Cmd interface. +func (cmd *GetBestBlockCmd) MarshalJSON() ([]byte, error) { + raw, err := btcjson.NewRawCmd(cmd.id, cmd.Method(), []interface{}{}) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of cmd into cmd. Part of +// the Cmd interface. +func (cmd *GetBestBlockCmd) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newCmd, err := parseGetBestBlockCmd(&r) + if err != nil { + return err + } + + concreteCmd, ok := newCmd.(*GetBestBlockCmd) + if !ok { + return btcjson.ErrInternal + } + *cmd = *concreteCmd + return nil +} + +// RecoverAddressesCmd is a type handling custom marshaling and +// unmarshaling of recoveraddresses JSON websocket extension +// commands. +type RecoverAddressesCmd struct { + id interface{} + Account string + N int +} + +// Enforce that RecoverAddressesCmd satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &RecoverAddressesCmd{} + +// NewRecoverAddressesCmd creates a new RecoverAddressesCmd. +func NewRecoverAddressesCmd(id interface{}, account string, n int) *RecoverAddressesCmd { + return &RecoverAddressesCmd{ + id: id, + Account: account, + N: n, + } +} + +// parseRecoverAddressesCmd parses a RawCmd into a concrete type satisifying +// the btcjson.Cmd interface. This is used when registering the custom +// command with the btcjson parser. +func parseRecoverAddressesCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if len(r.Params) != 2 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var account string + if err := json.Unmarshal(r.Params[0], &account); err != nil { + return nil, errors.New("first parameter 'account' must be a " + + "string: " + err.Error()) + } + + var n int + if err := json.Unmarshal(r.Params[1], &n); err != nil { + return nil, errors.New("second parameter 'n' must be an " + + "integer: " + err.Error()) + } + + return NewRecoverAddressesCmd(r.Id, account, n), nil +} + +// Id satisifies the Cmd interface by returning the ID of the command. +func (cmd *RecoverAddressesCmd) Id() interface{} { + return cmd.id +} + +// Method satisfies the Cmd interface by returning the RPC method. +func (cmd *RecoverAddressesCmd) Method() string { + return "recoveraddresses" +} + +// MarshalJSON returns the JSON encoding of cmd. Part of the Cmd interface. +func (cmd *RecoverAddressesCmd) MarshalJSON() ([]byte, error) { + params := []interface{}{ + cmd.Account, + cmd.N, + } + + raw, err := btcjson.NewRawCmd(cmd.id, cmd.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of cmd into cmd. Part of +// the Cmd interface. +func (cmd *RecoverAddressesCmd) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newCmd, err := parseRecoverAddressesCmd(&r) + if err != nil { + return err + } + + concreteCmd, ok := newCmd.(*RecoverAddressesCmd) + if !ok { + return btcjson.ErrInternal + } + *cmd = *concreteCmd + return nil +} + +// RenameAccountCmd is a type handling custom marshaling and +// unmarshaling of renameaccount JSON websocket extension +// commands. +type RenameAccountCmd struct { + id interface{} + OldAccount string + NewAccount string +} + +// Enforce that RenameAccountCmd satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &RenameAccountCmd{} + +// NewRenameAccountCmd creates a new GetCurrentNetCmd. +func NewRenameAccountCmd(id interface{}, oldaccount, newaccount string) *RenameAccountCmd { + return &RenameAccountCmd{ + id: id, + OldAccount: oldaccount, + NewAccount: newaccount, + } +} + +// parseRenameAccountCmd parses a RawCmd into a concrete type satisifying +// the btcjson.Cmd interface. This is used when registering the custom +// command with the btcjson parser. +func parseRenameAccountCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if len(r.Params) != 2 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var oldaccount string + if err := json.Unmarshal(r.Params[0], &oldaccount); err != nil { + return nil, errors.New("first parameter 'oldaccount' must be " + + "a string: " + err.Error()) + } + + var newaccount string + if err := json.Unmarshal(r.Params[1], &newaccount); err != nil { + return nil, errors.New("second parameter 'newaccount' must " + + "be a string: " + err.Error()) + } + + return NewRenameAccountCmd(r.Id, oldaccount, newaccount), nil +} + +// Id satisifies the Cmd interface by returning the ID of the command. +func (cmd *RenameAccountCmd) Id() interface{} { + return cmd.id +} + +// Method satisfies the Cmd interface by returning the RPC method. +func (cmd *RenameAccountCmd) Method() string { + return "renameaccount" +} + +// MarshalJSON returns the JSON encoding of cmd. Part of the Cmd interface. +func (cmd *RenameAccountCmd) MarshalJSON() ([]byte, error) { + params := []interface{}{ + cmd.OldAccount, + cmd.NewAccount, + } + + raw, err := btcjson.NewRawCmd(cmd.id, cmd.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of cmd into cmd. Part of +// the Cmd interface. +func (cmd *RenameAccountCmd) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newCmd, err := parseRenameAccountCmd(&r) + if err != nil { + return err + } + + concreteCmd, ok := newCmd.(*RenameAccountCmd) + if !ok { + return btcjson.ErrInternal + } + *cmd = *concreteCmd + return nil +} + +// OutPoint describes a transaction outpoint that will be marshalled to and +// from JSON. +type OutPoint struct { + Hash string `json:"hash"` + Index uint32 `json:"index"` +} + +// NewOutPointFromWire creates a new OutPoint from the OutPoint structure +// of the wire package. +func NewOutPointFromWire(op *wire.OutPoint) *OutPoint { + return &OutPoint{ + Hash: op.Hash.String(), + Index: op.Index, + } +} + +// RescanCmd is a type handling custom marshaling and +// unmarshaling of rescan JSON websocket extension +// commands. +type RescanCmd struct { + id interface{} + BeginBlock string + Addresses []string + OutPoints []OutPoint + EndBlock string +} + +// Enforce that RescanCmd satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &RescanCmd{} + +// NewRescanCmd creates a new RescanCmd, parsing the optional +// arguments optArgs which may either be empty or a single upper +// block hash. +func NewRescanCmd(id interface{}, begin string, addresses []string, + outpoints []OutPoint, optArgs ...string) (*RescanCmd, error) { + + // Optional parameters set to their defaults. + var end string + + if len(optArgs) > 0 { + if len(optArgs) > 1 { + return nil, btcjson.ErrTooManyOptArgs + } + end = optArgs[0] + } + + return &RescanCmd{ + id: id, + BeginBlock: begin, + Addresses: addresses, + OutPoints: outpoints, + EndBlock: end, + }, nil +} + +// parseRescanCmd parses a RawCmd into a concrete type satisifying +// the btcjson.Cmd interface. This is used when registering the custom +// command with the btcjson parser. +func parseRescanCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if len(r.Params) < 3 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var begin string + if err := json.Unmarshal(r.Params[0], &begin); err != nil { + return nil, errors.New("first parameter 'begin' must be a " + + "string: " + err.Error()) + } + + var addresses []string + if err := json.Unmarshal(r.Params[1], &addresses); err != nil { + return nil, errors.New("second parameter 'addresses' must be " + + "an array of strings: " + err.Error()) + } + + var outpoints []OutPoint + if err := json.Unmarshal(r.Params[2], &outpoints); err != nil { + return nil, errors.New("third parameter 'outpoints' must be " + + "an array of transaction outpoint JSON objects: " + + err.Error()) + } + + optArgs := make([]string, 0, 1) + if len(r.Params) > 3 { + var endblock string + if err := json.Unmarshal(r.Params[3], &endblock); err != nil { + return nil, errors.New("fourth optional parameter " + + "'endblock' must be a string: " + err.Error()) + } + optArgs = append(optArgs, endblock) + } + + return NewRescanCmd(r.Id, begin, addresses, outpoints, optArgs...) +} + +// Id satisifies the Cmd interface by returning the ID of the command. +func (cmd *RescanCmd) Id() interface{} { + return cmd.id +} + +// Method satisfies the Cmd interface by returning the RPC method. +func (cmd *RescanCmd) Method() string { + return "rescan" +} + +// MarshalJSON returns the JSON encoding of cmd. Part of the Cmd interface. +func (cmd *RescanCmd) MarshalJSON() ([]byte, error) { + params := make([]interface{}, 3, 4) + params[0] = cmd.BeginBlock + params[1] = cmd.Addresses + params[2] = cmd.OutPoints + if cmd.EndBlock != "" { + params = append(params, cmd.EndBlock) + } + + raw, err := btcjson.NewRawCmd(cmd.id, cmd.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of cmd into cmd. Part of +// the Cmd interface. +func (cmd *RescanCmd) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newCmd, err := parseRescanCmd(&r) + if err != nil { + return err + } + + concreteCmd, ok := newCmd.(*RescanCmd) + if !ok { + return btcjson.ErrInternal + } + *cmd = *concreteCmd + return nil +} + +// NotifyBlocksCmd is a type handling custom marshaling and +// unmarshaling of notifyblocks JSON websocket extension +// commands. +type NotifyBlocksCmd struct { + id interface{} +} + +// Enforce that NotifyBlocksCmd satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &NotifyBlocksCmd{} + +// NewNotifyBlocksCmd creates a new NotifyBlocksCmd. +func NewNotifyBlocksCmd(id interface{}) *NotifyBlocksCmd { + return &NotifyBlocksCmd{ + id: id, + } +} + +// parseNotifyBlocksCmd parses a NotifyBlocksCmd into a concrete type +// satisifying the btcjson.Cmd interface. This is used when registering +// the custom command with the btcjson parser. +func parseNotifyBlocksCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if len(r.Params) != 0 { + return nil, btcjson.ErrWrongNumberOfParams + } + return NewNotifyBlocksCmd(r.Id), nil +} + +// Id satisifies the Cmd interface by returning the ID of the command. +func (cmd *NotifyBlocksCmd) Id() interface{} { + return cmd.id +} + +// Method satisfies the Cmd interface by returning the RPC method. +func (cmd *NotifyBlocksCmd) Method() string { + return "notifyblocks" +} + +// MarshalJSON returns the JSON encoding of cmd. Part of the Cmd interface. +func (cmd *NotifyBlocksCmd) MarshalJSON() ([]byte, error) { + raw, err := btcjson.NewRawCmd(cmd.id, cmd.Method(), []interface{}{}) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of cmd into cmd. Part of +// the Cmd interface. +func (cmd *NotifyBlocksCmd) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newCmd, err := parseNotifyBlocksCmd(&r) + if err != nil { + return err + } + + concreteCmd, ok := newCmd.(*NotifyBlocksCmd) + if !ok { + return btcjson.ErrInternal + } + *cmd = *concreteCmd + return nil +} + +// NotifyReceivedCmd is a type handling custom marshaling and +// unmarshaling of notifyreceived JSON websocket extension +// commands. +type NotifyReceivedCmd struct { + id interface{} + Addresses []string +} + +// Enforce that NotifyReceivedCmd satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &NotifyReceivedCmd{} + +// NewNotifyReceivedCmd creates a new NotifyReceivedCmd. +func NewNotifyReceivedCmd(id interface{}, addresses []string) *NotifyReceivedCmd { + return &NotifyReceivedCmd{ + id: id, + Addresses: addresses, + } +} + +// parseNotifyReceivedCmd parses a NotifyNewTXsCmd into a concrete type +// satisifying the btcjson.Cmd interface. This is used when registering +// the custom command with the btcjson parser. +func parseNotifyReceivedCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if len(r.Params) != 1 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var addresses []string + if err := json.Unmarshal(r.Params[0], &addresses); err != nil { + return nil, errors.New("first parameter 'addresses' must be " + + "an array of strings: " + err.Error()) + } + + return NewNotifyReceivedCmd(r.Id, addresses), nil +} + +// Id satisifies the Cmd interface by returning the ID of the command. +func (cmd *NotifyReceivedCmd) Id() interface{} { + return cmd.id +} + +// Method satisfies the Cmd interface by returning the RPC method. +func (cmd *NotifyReceivedCmd) Method() string { + return "notifyreceived" +} + +// MarshalJSON returns the JSON encoding of cmd. Part of the Cmd interface. +func (cmd *NotifyReceivedCmd) MarshalJSON() ([]byte, error) { + params := []interface{}{ + cmd.Addresses, + } + + raw, err := btcjson.NewRawCmd(cmd.id, cmd.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of cmd into cmd. Part of +// the Cmd interface. +func (cmd *NotifyReceivedCmd) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newCmd, err := parseNotifyReceivedCmd(&r) + if err != nil { + return err + } + + concreteCmd, ok := newCmd.(*NotifyReceivedCmd) + if !ok { + return btcjson.ErrInternal + } + *cmd = *concreteCmd + return nil +} + +// NotifyNewTransactionsCmd is a type handling custom marshaling and +// unmarshaling of notifynewtransactions JSON websocket extension +// commands. +type NotifyNewTransactionsCmd struct { + id interface{} + Verbose bool +} + +// Enforce that NotifyNewTransactionsCmd satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &NotifyNewTransactionsCmd{} + +// NewNotifyNewTransactionsCmd creates a new NotifyNewTransactionsCmd that +// optionally takes a single verbose parameter that defaults to false. +func NewNotifyNewTransactionsCmd(id interface{}, optArgs ...bool) (*NotifyNewTransactionsCmd, error) { + verbose := false + + optArgsLen := len(optArgs) + if optArgsLen > 0 { + if optArgsLen > 1 { + return nil, btcjson.ErrTooManyOptArgs + } + verbose = optArgs[0] + } + + return &NotifyNewTransactionsCmd{ + id: id, + Verbose: verbose, + }, nil +} + +// parseNotifyNewTransactionsCmd parses a NotifyNewTransactionsCmd into a +// concrete type satisifying the btcjson.Cmd interface. This is used when +// registering the custom command with the btcjson parser. +func parseNotifyNewTransactionsCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if len(r.Params) > 1 { + return nil, btcjson.ErrWrongNumberOfParams + } + + optArgs := make([]bool, 0, 1) + if len(r.Params) > 0 { + var verbose bool + if err := json.Unmarshal(r.Params[0], &verbose); err != nil { + return nil, errors.New("first optional parameter " + + "'verbose' must be a bool: " + err.Error()) + } + optArgs = append(optArgs, verbose) + } + + return NewNotifyNewTransactionsCmd(r.Id, optArgs...) +} + +// Id satisifies the Cmd interface by returning the ID of the command. +func (cmd *NotifyNewTransactionsCmd) Id() interface{} { + return cmd.id +} + +// Method satisfies the Cmd interface by returning the RPC method. +func (cmd *NotifyNewTransactionsCmd) Method() string { + return "notifynewtransactions" +} + +// MarshalJSON returns the JSON encoding of cmd. Part of the Cmd interface. +func (cmd *NotifyNewTransactionsCmd) MarshalJSON() ([]byte, error) { + params := []interface{}{ + cmd.Verbose, + } + + raw, err := btcjson.NewRawCmd(cmd.id, cmd.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of cmd into cmd. Part of +// the Cmd interface. +func (cmd *NotifyNewTransactionsCmd) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newCmd, err := parseNotifyNewTransactionsCmd(&r) + if err != nil { + return err + } + + concreteCmd, ok := newCmd.(*NotifyNewTransactionsCmd) + if !ok { + return btcjson.ErrInternal + } + *cmd = *concreteCmd + return nil +} + +// NotifySpentCmd is a type handling custom marshaling and +// unmarshaling of notifyspent JSON websocket extension +// commands. +type NotifySpentCmd struct { + id interface{} + OutPoints []OutPoint +} + +// Enforce that NotifySpentCmd satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &NotifySpentCmd{} + +// NewNotifySpentCmd creates a new NotifySpentCmd. +func NewNotifySpentCmd(id interface{}, outpoints []OutPoint) *NotifySpentCmd { + return &NotifySpentCmd{ + id: id, + OutPoints: outpoints, + } +} + +// parseNotifySpentCmd parses a NotifySpentCmd into a concrete type +// satisifying the btcjson.Cmd interface. This is used when registering +// the custom command with the btcjson parser. +func parseNotifySpentCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if len(r.Params) != 1 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var outpoints []OutPoint + if err := json.Unmarshal(r.Params[0], &outpoints); err != nil { + return nil, errors.New("first parameter 'outpoints' must be a " + + "an array of transaction outpoint JSON objects: " + + err.Error()) + } + + return NewNotifySpentCmd(r.Id, outpoints), nil +} + +// Id satisifies the Cmd interface by returning the ID of the command. +func (cmd *NotifySpentCmd) Id() interface{} { + return cmd.id +} + +// Method satisfies the Cmd interface by returning the RPC method. +func (cmd *NotifySpentCmd) Method() string { + return "notifyspent" +} + +// MarshalJSON returns the JSON encoding of cmd. Part of the Cmd interface. +func (cmd *NotifySpentCmd) MarshalJSON() ([]byte, error) { + params := []interface{}{ + cmd.OutPoints, + } + + raw, err := btcjson.NewRawCmd(cmd.id, cmd.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of cmd into cmd. Part of +// the Cmd interface. +func (cmd *NotifySpentCmd) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newCmd, err := parseNotifySpentCmd(&r) + if err != nil { + return err + } + + concreteCmd, ok := newCmd.(*NotifySpentCmd) + if !ok { + return btcjson.ErrInternal + } + *cmd = *concreteCmd + return nil +} + +// CreateEncryptedWalletCmd is a type handling custom +// marshaling and unmarshaling of createencryptedwallet +// JSON websocket extension commands. +type CreateEncryptedWalletCmd struct { + id interface{} + Passphrase string +} + +// Enforce that CreateEncryptedWalletCmd satisifies the btcjson.Cmd +// interface. +var _ btcjson.Cmd = &CreateEncryptedWalletCmd{} + +// NewCreateEncryptedWalletCmd creates a new CreateEncryptedWalletCmd. +func NewCreateEncryptedWalletCmd(id interface{}, passphrase string) *CreateEncryptedWalletCmd { + return &CreateEncryptedWalletCmd{ + id: id, + Passphrase: passphrase, + } +} + +// parseCreateEncryptedWalletCmd parses a CreateEncryptedWalletCmd +// into a concrete type satisifying the btcjson.Cmd interface. +// This is used when registering the custom command with the btcjson +// parser. +func parseCreateEncryptedWalletCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if len(r.Params) != 1 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var passphrase string + if err := json.Unmarshal(r.Params[0], &passphrase); err != nil { + return nil, errors.New("first parameter 'passphrase' must be " + + "a string: " + err.Error()) + } + + return NewCreateEncryptedWalletCmd(r.Id, passphrase), nil +} + +// Id satisifies the Cmd interface by returning the ID of the command. +func (cmd *CreateEncryptedWalletCmd) Id() interface{} { + return cmd.id +} + +// Method satisfies the Cmd interface by returning the RPC method. +func (cmd *CreateEncryptedWalletCmd) Method() string { + return "createencryptedwallet" +} + +// MarshalJSON returns the JSON encoding of cmd. Part of the Cmd interface. +func (cmd *CreateEncryptedWalletCmd) MarshalJSON() ([]byte, error) { + params := []interface{}{ + cmd.Passphrase, + } + + raw, err := btcjson.NewRawCmd(cmd.id, cmd.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of cmd into cmd. Part of +// the Cmd interface. +func (cmd *CreateEncryptedWalletCmd) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newCmd, err := parseCreateEncryptedWalletCmd(&r) + if err != nil { + return err + } + + concreteCmd, ok := newCmd.(*CreateEncryptedWalletCmd) + if !ok { + return btcjson.ErrInternal + } + *cmd = *concreteCmd + return nil +} + +// CreateNewAccountCmd is a type handling custom +// marshaling and unmarshaling of createnewaccount +// JSON websocket extension commands. +type CreateNewAccountCmd struct { + id interface{} + Account string +} + +// Enforce that CreateNewAccountCmd satisifies the btcjson.Cmd +// interface. +var _ btcjson.Cmd = &CreateNewAccountCmd{} + +// NewCreateNewAccountCmd creates a new CreateNewAccountCmd. +func NewCreateNewAccountCmd(id interface{}, account string) *CreateNewAccountCmd { + return &CreateNewAccountCmd{ + id: id, + Account: account, + } +} + +// parseCreateNewAccountCmd parses a CreateNewAccountCmd +// into a concrete type satisifying the btcjson.Cmd interface. +// This is used when registering the custom command with the btcjson +// parser. +func parseCreateNewAccountCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if len(r.Params) != 1 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var account string + if err := json.Unmarshal(r.Params[0], &account); err != nil { + return nil, errors.New("first parameter 'account' must be " + + "a string: " + err.Error()) + } + + return NewCreateNewAccountCmd(r.Id, account), nil +} + +// Id satisifies the Cmd interface by returning the ID of the command. +func (cmd *CreateNewAccountCmd) Id() interface{} { + return cmd.id +} + +// Method satisfies the Cmd interface by returning the RPC method. +func (cmd *CreateNewAccountCmd) Method() string { + return "createnewaccount" +} + +// MarshalJSON returns the JSON encoding of cmd. Part of the Cmd interface. +func (cmd *CreateNewAccountCmd) MarshalJSON() ([]byte, error) { + params := []interface{}{ + cmd.Account, + } + + raw, err := btcjson.NewRawCmd(cmd.id, cmd.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of cmd into cmd. Part of +// the Cmd interface. +func (cmd *CreateNewAccountCmd) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newCmd, err := parseCreateNewAccountCmd(&r) + if err != nil { + return err + } + + concreteCmd, ok := newCmd.(*CreateNewAccountCmd) + if !ok { + return btcjson.ErrInternal + } + *cmd = *concreteCmd + return nil +} + +// WalletIsLockedCmd is a type handling custom marshaling and +// unmarshaling of walletislocked JSON websocket extension commands. +type WalletIsLockedCmd struct { + id interface{} + Account string +} + +// Enforce that WalletIsLockedCmd satisifies the btcjson.Cmd +// interface. +var _ btcjson.Cmd = &WalletIsLockedCmd{} + +// NewWalletIsLockedCmd creates a new WalletIsLockedCmd. +func NewWalletIsLockedCmd(id interface{}, + optArgs ...string) (*WalletIsLockedCmd, error) { + + // Optional arguments set to their default values. + account := "" + + if len(optArgs) > 1 { + return nil, btcjson.ErrInvalidParams + } + + if len(optArgs) == 1 { + account = optArgs[0] + } + + return &WalletIsLockedCmd{ + id: id, + Account: account, + }, nil +} + +// parseWalletIsLockedCmd parses a WalletIsLockedCmd into a concrete +// type satisifying the btcjson.Cmd interface. This is used when +// registering the custom command with the btcjson parser. +func parseWalletIsLockedCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if len(r.Params) > 1 { + return nil, btcjson.ErrInvalidParams + } + + if len(r.Params) == 0 { + return NewWalletIsLockedCmd(r.Id) + } + + var account string + if err := json.Unmarshal(r.Params[0], &account); err != nil { + return nil, errors.New("first parameter 'account' must be a " + + "string: " + err.Error()) + } + + return NewWalletIsLockedCmd(r.Id, account) +} + +// Id satisifies the Cmd interface by returning the ID of the command. +func (cmd *WalletIsLockedCmd) Id() interface{} { + return cmd.id +} + +// Method satisfies the Cmd interface by returning the RPC method. +func (cmd *WalletIsLockedCmd) Method() string { + return "walletislocked" +} + +// MarshalJSON returns the JSON encoding of cmd. Part of the Cmd interface. +func (cmd *WalletIsLockedCmd) MarshalJSON() ([]byte, error) { + params := make([]interface{}, 0, 1) + if cmd.Account != "" { + params = append(params, cmd.Account) + } + + raw, err := btcjson.NewRawCmd(cmd.id, cmd.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of cmd into cmd. Part of +// the Cmd interface. +func (cmd *WalletIsLockedCmd) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newCmd, err := parseWalletIsLockedCmd(&r) + if err != nil { + return err + } + + concreteCmd, ok := newCmd.(*WalletIsLockedCmd) + if !ok { + return btcjson.ErrInternal + } + *cmd = *concreteCmd + return nil +} + +// ListAddressTransactionsCmd is a type handling custom marshaling and +// unmarshaling of listaddresstransactions JSON websocket extension commands. +type ListAddressTransactionsCmd struct { + id interface{} + Account string + Addresses []string +} + +// Enforce that ListAddressTransactionsCmd satisifies the btcjson.Cmd +// interface. +var _ btcjson.Cmd = &ListAddressTransactionsCmd{} + +// NewListAddressTransactionsCmd creates a new ListAddressTransactionsCmd. +func NewListAddressTransactionsCmd(id interface{}, addresses []string, + optArgs ...string) (*ListAddressTransactionsCmd, error) { + + if len(optArgs) > 1 { + return nil, btcjson.ErrTooManyOptArgs + } + + // Optional arguments set to their default values. + account := "" + + if len(optArgs) == 1 { + account = optArgs[0] + } + + return &ListAddressTransactionsCmd{ + id: id, + Account: account, + Addresses: addresses, + }, nil +} + +// parseListAddressTransactionsCmd parses a ListAddressTransactionsCmd into +// a concrete type satisifying the btcjson.Cmd interface. This is used +// when registering the custom command with the btcjson parser. +func parseListAddressTransactionsCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if len(r.Params) == 0 || len(r.Params) > 2 { + return nil, btcjson.ErrInvalidParams + } + + var addresses []string + if err := json.Unmarshal(r.Params[0], &addresses); err != nil { + return nil, errors.New("first parameter 'addresses' must be " + + "an array of strings: " + err.Error()) + } + + optArgs := make([]string, 0, 1) + if len(r.Params) > 1 { + var account string + if err := json.Unmarshal(r.Params[1], &account); err != nil { + return nil, errors.New("second optional parameter " + + "'account' must be a string: " + err.Error()) + } + optArgs = append(optArgs, account) + } + + return NewListAddressTransactionsCmd(r.Id, addresses, optArgs...) +} + +// parseListAddressTransactionsCmdReply parses a the reply to a +// ListAddressTransactionsCmd into a concrete type and returns it packed into +// an interface. This is used when registering the custom command with btcjson. +func parseListAddressTransactionsCmdReply(message json.RawMessage) (interface{}, error) { + var res []btcjson.ListTransactionsResult + if err := json.Unmarshal(message, &res); err != nil { + return nil, err + } + return res, nil +} + +// Id satisifies the Cmd interface by returning the ID of the command. +func (cmd *ListAddressTransactionsCmd) Id() interface{} { + return cmd.id +} + +// Method satisfies the Cmd interface by returning the RPC method. +func (cmd *ListAddressTransactionsCmd) Method() string { + return "listaddresstransactions" +} + +// MarshalJSON returns the JSON encoding of cmd. Part of the Cmd interface. +func (cmd *ListAddressTransactionsCmd) MarshalJSON() ([]byte, error) { + params := make([]interface{}, 1, 2) + params[0] = cmd.Addresses + if cmd.Account != "" { + params = append(params, cmd.Account) + } + + raw, err := btcjson.NewRawCmd(cmd.id, cmd.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of cmd into cmd. Part of +// the Cmd interface. +func (cmd *ListAddressTransactionsCmd) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newCmd, err := parseListAddressTransactionsCmd(&r) + if err != nil { + return err + } + + concreteCmd, ok := newCmd.(*ListAddressTransactionsCmd) + if !ok { + return btcjson.ErrInternal + } + *cmd = *concreteCmd + return nil +} + +// ListAllTransactionsCmd is a type handling custom marshaling and +// unmarshaling of listalltransactions JSON websocket extension commands. +type ListAllTransactionsCmd struct { + id interface{} + Account *string +} + +// Enforce that ListAllTransactionsCmd satisifies the btcjson.Cmd +// interface. +var _ btcjson.Cmd = &ListAllTransactionsCmd{} + +// NewListAllTransactionsCmd creates a new ListAllTransactionsCmd. +func NewListAllTransactionsCmd(id interface{}, + optArgs ...string) (*ListAllTransactionsCmd, error) { + + // Optional arguments set to their default values. + var account *string + + if len(optArgs) > 1 { + return nil, btcjson.ErrInvalidParams + } + + if len(optArgs) == 1 { + account = &optArgs[0] + } + + return &ListAllTransactionsCmd{ + id: id, + Account: account, + }, nil +} + +// parseListAllTransactionsCmd parses a ListAllTransactionsCmd into a concrete +// type satisifying the btcjson.Cmd interface. This is used when +// registering the custom command with the btcjson parser. +func parseListAllTransactionsCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if len(r.Params) > 1 { + return nil, btcjson.ErrInvalidParams + } + + optArgs := make([]string, 0, 1) + if len(r.Params) > 0 { + var account string + if err := json.Unmarshal(r.Params[0], &account); err != nil { + return nil, errors.New("first optional parameter " + + "'account' must be a string: " + err.Error()) + } + optArgs = append(optArgs, account) + } + + return NewListAllTransactionsCmd(r.Id, optArgs...) +} + +// Id satisifies the Cmd interface by returning the ID of the command. +func (cmd *ListAllTransactionsCmd) Id() interface{} { + return cmd.id +} + +// Method satisfies the Cmd interface by returning the RPC method. +func (cmd *ListAllTransactionsCmd) Method() string { + return "listalltransactions" +} + +// MarshalJSON returns the JSON encoding of cmd. Part of the Cmd interface. +func (cmd *ListAllTransactionsCmd) MarshalJSON() ([]byte, error) { + params := make([]interface{}, 0, 1) + if cmd.Account != nil { + params = append(params, cmd.Account) + } + + raw, err := btcjson.NewRawCmd(cmd.id, cmd.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of cmd into cmd. Part of +// the Cmd interface. +func (cmd *ListAllTransactionsCmd) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newCmd, err := parseListAllTransactionsCmd(&r) + if err != nil { + return err + } + + concreteCmd, ok := newCmd.(*ListAllTransactionsCmd) + if !ok { + return btcjson.ErrInternal + } + *cmd = *concreteCmd + return nil +} diff --git a/btcjson/btcws/cmds_test.go b/btcjson/btcws/cmds_test.go new file mode 100644 index 00000000..f6c8f173 --- /dev/null +++ b/btcjson/btcws/cmds_test.go @@ -0,0 +1,364 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +// this has to be in the real package so we can mock up structs +package btcws + +import ( + "reflect" + "testing" + + "github.com/btcsuite/btcd/btcjson" + "github.com/davecgh/go-spew/spew" +) + +var testAccount = "account" + +var cmdtests = []struct { + name string + f func() (btcjson.Cmd, error) + result btcjson.Cmd // after marshal and unmarshal +}{ + { + name: "createencryptedwallet", + f: func() (btcjson.Cmd, error) { + return NewCreateEncryptedWalletCmd( + float64(1), + "banana"), nil + }, + result: &CreateEncryptedWalletCmd{ + id: float64(1), + Passphrase: "banana", + }, + }, + { + name: "createnewaccount", + f: func() (btcjson.Cmd, error) { + return NewCreateNewAccountCmd( + float64(1), + "account"), nil + }, + result: &CreateNewAccountCmd{ + id: float64(1), + Account: "account", + }, + }, + { + name: "getbestblock", + f: func() (btcjson.Cmd, error) { + return NewGetBestBlockCmd(float64(1)), nil + }, + result: &GetBestBlockCmd{ + id: float64(1), + }, + }, + { + name: "getcurrentnet", + f: func() (btcjson.Cmd, error) { + return NewGetCurrentNetCmd(float64(1)), nil + }, + result: &GetCurrentNetCmd{ + id: float64(1), + }, + }, + { + name: "getunconfirmedbalance no optargs", + f: func() (btcjson.Cmd, error) { + return NewGetUnconfirmedBalanceCmd(float64(1)) + }, + result: &GetUnconfirmedBalanceCmd{ + id: float64(1), + Account: "", + }, + }, + { + name: "getunconfirmedbalance one optarg", + f: func() (btcjson.Cmd, error) { + return NewGetUnconfirmedBalanceCmd(float64(1), + testAccount) + }, + result: &GetUnconfirmedBalanceCmd{ + id: float64(1), + Account: testAccount, + }, + }, + { + name: "listaddresstransactions no optargs", + f: func() (btcjson.Cmd, error) { + addrs := []string{ + "17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH", + } + return NewListAddressTransactionsCmd( + float64(1), + addrs) + }, + result: &ListAddressTransactionsCmd{ + id: float64(1), + Account: "", + Addresses: []string{ + "17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH", + }, + }, + }, + { + name: "listaddresstransactions one optarg", + f: func() (btcjson.Cmd, error) { + addrs := []string{ + "17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH", + } + return NewListAddressTransactionsCmd( + float64(1), + addrs, + testAccount) + }, + result: &ListAddressTransactionsCmd{ + id: float64(1), + Account: testAccount, + Addresses: []string{ + "17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH", + }, + }, + }, + { + name: "listalltransactions no optargs", + f: func() (btcjson.Cmd, error) { + return NewListAllTransactionsCmd(float64(1)) + }, + result: &ListAllTransactionsCmd{ + id: float64(1), + Account: nil, + }, + }, + { + name: "listalltransactions one optarg", + f: func() (btcjson.Cmd, error) { + return NewListAllTransactionsCmd( + float64(1), + testAccount) + }, + result: &ListAllTransactionsCmd{ + id: float64(1), + Account: &testAccount, + }, + }, + { + name: "notifyreceived", + f: func() (btcjson.Cmd, error) { + addrs := []string{ + "17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH", + } + return NewNotifyReceivedCmd( + float64(1), + addrs), nil + }, + result: &NotifyReceivedCmd{ + id: float64(1), + Addresses: []string{ + "17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH", + }, + }, + }, + { + name: "notifynewtransactions", + f: func() (btcjson.Cmd, error) { + return NewNotifyNewTransactionsCmd( + float64(1), + true) + }, + result: &NotifyNewTransactionsCmd{ + id: float64(1), + Verbose: true, + }, + }, + { + name: "notifyspent", + f: func() (btcjson.Cmd, error) { + ops := []OutPoint{ + { + Hash: "000102030405060708091011121314" + + "1516171819202122232425262728" + + "293031", + Index: 1, + }, + } + return NewNotifySpentCmd(float64(1), ops), nil + }, + result: &NotifySpentCmd{ + id: float64(1), + OutPoints: []OutPoint{ + { + Hash: "000102030405060708091011121314" + + "1516171819202122232425262728" + + "293031", + Index: 1, + }, + }, + }, + }, + { + name: "renameaccount", + f: func() (btcjson.Cmd, error) { + return NewRenameAccountCmd( + float64(1), + "old", + "new"), nil + }, + result: &RenameAccountCmd{ + id: float64(1), + OldAccount: "old", + NewAccount: "new", + }, + }, + { + name: "rescan no optargs", + f: func() (btcjson.Cmd, error) { + addrs := []string{"17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH"} + ops := []OutPoint{ + { + Hash: "000102030405060708091011121314" + + "1516171819202122232425262728" + + "293031", + Index: 1, + }, + } + return NewRescanCmd( + float64(1), + "0000000000000002a775aec59dc6a9e4bb1c025cf1b8c2195dd9dc3998c827c5", + addrs, + ops) + }, + result: &RescanCmd{ + id: float64(1), + BeginBlock: "0000000000000002a775aec59dc6a9e4bb1c025cf1b8c2195dd9dc3998c827c5", + Addresses: []string{"17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH"}, + OutPoints: []OutPoint{ + { + Hash: "000102030405060708091011121314" + + "1516171819202122232425262728" + + "293031", + Index: 1, + }, + }, + EndBlock: "", + }, + }, + { + name: "rescan one optarg", + f: func() (btcjson.Cmd, error) { + addrs := []string{"17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH"} + ops := []OutPoint{ + { + Hash: "000102030405060708091011121314" + + "1516171819202122232425262728" + + "293031", + Index: 1, + }, + } + return NewRescanCmd( + float64(1), + "0000000000000002a775aec59dc6a9e4bb1c025cf1b8c2195dd9dc3998c827c5", + addrs, + ops, + "0000000000000001c091ada69f444dc0282ecaabe4808ddbb2532e5555db0c03") + }, + result: &RescanCmd{ + id: float64(1), + BeginBlock: "0000000000000002a775aec59dc6a9e4bb1c025cf1b8c2195dd9dc3998c827c5", + Addresses: []string{"17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH"}, + OutPoints: []OutPoint{ + { + Hash: "000102030405060708091011121314" + + "1516171819202122232425262728" + + "293031", + Index: 1, + }, + }, + EndBlock: "0000000000000001c091ada69f444dc0282ecaabe4808ddbb2532e5555db0c03", + }, + }, + { + name: "walletislocked no optargs", + f: func() (btcjson.Cmd, error) { + return NewWalletIsLockedCmd(float64(1)) + }, + result: &WalletIsLockedCmd{ + id: float64(1), + Account: "", + }, + }, + { + name: "walletislocked one optarg", + f: func() (btcjson.Cmd, error) { + return NewWalletIsLockedCmd( + float64(1), + testAccount) + }, + result: &WalletIsLockedCmd{ + id: float64(1), + Account: testAccount, + }, + }, +} + +func TestCmds(t *testing.T) { + for _, test := range cmdtests { + c, err := test.f() + if err != nil { + t.Errorf("%s: failed to run func: %v", + test.name, err) + continue + } + + mc, err := c.MarshalJSON() + if err != nil { + t.Errorf("%s: failed to marshal cmd: %v", + test.name, err) + continue + } + + c2, err := btcjson.ParseMarshaledCmd(mc) + if err != nil { + t.Errorf("%s: failed to ummarshal cmd: %v", + test.name, err) + continue + } + + if !reflect.DeepEqual(test.result, c2) { + t.Errorf("%s: unmarshal not as expected. "+ + "got %v wanted %v", test.name, spew.Sdump(c2), + spew.Sdump(test.result)) + } + if !reflect.DeepEqual(c, c2) { + t.Errorf("%s: unmarshal not as we started with. "+ + "got %v wanted %v", test.name, spew.Sdump(c2), + spew.Sdump(c)) + } + + // id from Id func must match result. + if c.Id() != test.result.Id() { + t.Errorf("%s: Id returned incorrect id. "+ + "got %v wanted %v", test.name, c.Id(), + test.result.Id()) + } + + // method from Method func must match result. + if c.Method() != test.result.Method() { + t.Errorf("%s: Method returned incorrect method. "+ + "got %v wanted %v", test.name, c.Method(), + test.result.Method()) + } + + // Read marshaled command back into c. Should still + // match result. + if err := c.UnmarshalJSON(mc); err != nil { + t.Errorf("%s: error while unmarshalling: %v", test.name, + err) + } + if !reflect.DeepEqual(test.result, c) { + t.Errorf("%s: unmarshal not as expected. "+ + "got %v wanted %v", test.name, spew.Sdump(c), + spew.Sdump(test.result)) + } + } +} diff --git a/btcjson/btcws/notifications.go b/btcjson/btcws/notifications.go new file mode 100644 index 00000000..d06d5410 --- /dev/null +++ b/btcjson/btcws/notifications.go @@ -0,0 +1,1249 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcws + +import ( + "encoding/json" + "errors" + + "github.com/btcsuite/btcd/btcjson" +) + +var ( + // ErrNotANtfn describes an error where a JSON-RPC Request + // object cannot be successfully parsed as a notification + // due to having an ID. + ErrNotANtfn = errors.New("notifications may not have IDs") +) + +const ( + // AccountBalanceNtfnMethod is the method of the btcwallet + // accountbalance notification. + AccountBalanceNtfnMethod = "accountbalance" + + // TxAcceptedNtfnMethod is the method of the btcd txaccepted + // notification + TxAcceptedNtfnMethod = "txaccepted" + + // TxAcceptedVerboseNtfnMethod is the method of the btcd + // txacceptedverbose notifications. + TxAcceptedVerboseNtfnMethod = "txacceptedverbose" + + // BlockConnectedNtfnMethod is the method of the btcd + // blockconnected notification. + BlockConnectedNtfnMethod = "blockconnected" + + // BlockDisconnectedNtfnMethod is the method of the btcd + // blockdisconnected notification. + BlockDisconnectedNtfnMethod = "blockdisconnected" + + // BtcdConnectedNtfnMethod is the method of the btcwallet + // btcdconnected notification. + BtcdConnectedNtfnMethod = "btcdconnected" + + // RecvTxNtfnMethod is the method of the btcd recvtx notification. + RecvTxNtfnMethod = "recvtx" + + // TxNtfnMethod is the method of the btcwallet newtx + // notification. + TxNtfnMethod = "newtx" + + // RedeemingTxNtfnMethod is the method of the btcd redeemingtx + // notification. + RedeemingTxNtfnMethod = "redeemingtx" + + // RescanFinishedNtfnMethod is the method of the btcd rescanfinished + // notification. + RescanFinishedNtfnMethod = "rescanfinished" + + // RescanProgressNtfnMethod is the method of the btcd rescanprogress + // notification. + RescanProgressNtfnMethod = "rescanprogress" + + // WalletLockStateNtfnMethod is the method of the btcwallet + // walletlockstate notification. + WalletLockStateNtfnMethod = "walletlockstate" +) + +// Register notifications with btcjson. +func init() { + btcjson.RegisterCustomCmd(AccountBalanceNtfnMethod, + parseAccountBalanceNtfn, nil, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd(BlockConnectedNtfnMethod, + parseBlockConnectedNtfn, nil, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd(BlockDisconnectedNtfnMethod, + parseBlockDisconnectedNtfn, nil, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd(BtcdConnectedNtfnMethod, + parseBtcdConnectedNtfn, nil, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd(RecvTxNtfnMethod, + parseRecvTxNtfn, nil, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd(RescanFinishedNtfnMethod, + parseRescanFinishedNtfn, nil, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd(RescanProgressNtfnMethod, + parseRescanProgressNtfn, nil, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd(RedeemingTxNtfnMethod, parseRedeemingTxNtfn, + nil, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd(TxNtfnMethod, parseTxNtfn, nil, + `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd(WalletLockStateNtfnMethod, + parseWalletLockStateNtfn, nil, `TODO(jrick) fillmein`) + btcjson.RegisterCustomCmd(TxAcceptedNtfnMethod, parseTxAcceptedNtfn, nil, + `TODO(flam) fillmein`) + btcjson.RegisterCustomCmd(TxAcceptedVerboseNtfnMethod, + parseTxAcceptedVerboseNtfn, nil, `TODO(flam) fillmein`) +} + +// BlockDetails describes details of a tx in a block. +type BlockDetails struct { + Height int32 `json:"height"` + Hash string `json:"hash"` + Index int `json:"index"` + Time int64 `json:"time"` +} + +// AccountBalanceNtfn is a type handling custom marshaling and +// unmarshaling of accountbalance JSON websocket notifications. +type AccountBalanceNtfn struct { + Account string + Balance float64 + Confirmed bool // Whether Balance is confirmed or unconfirmed. +} + +// Enforce that AccountBalanceNtfn satisifes the btcjson.Cmd interface. +var _ btcjson.Cmd = &AccountBalanceNtfn{} + +// NewAccountBalanceNtfn creates a new AccountBalanceNtfn. +func NewAccountBalanceNtfn(account string, balance float64, + confirmed bool) *AccountBalanceNtfn { + + return &AccountBalanceNtfn{ + Account: account, + Balance: balance, + Confirmed: confirmed, + } +} + +// parseAccountBalanceNtfn parses a RawCmd into a concrete type satisifying +// the btcjson.Cmd interface. This is used when registering the notification +// with the btcjson parser. +func parseAccountBalanceNtfn(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if r.Id != nil { + return nil, ErrNotANtfn + } + + if len(r.Params) != 3 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var account string + if err := json.Unmarshal(r.Params[0], &account); err != nil { + return nil, errors.New("first parameter 'account' must be a string: " + err.Error()) + } + + var balance float64 + if err := json.Unmarshal(r.Params[1], &balance); err != nil { + return nil, errors.New("second parameter 'balance' must be a number: " + err.Error()) + } + + var confirmed bool + if err := json.Unmarshal(r.Params[2], &confirmed); err != nil { + return nil, errors.New("third parameter 'confirmed' must be a bool: " + err.Error()) + } + + return NewAccountBalanceNtfn(account, balance, confirmed), nil +} + +// Id satisifies the btcjson.Cmd interface by returning nil for a +// notification ID. +func (n *AccountBalanceNtfn) Id() interface{} { + return nil +} + +// Method satisifies the btcjson.Cmd interface by returning the method +// of the notification. +func (n *AccountBalanceNtfn) Method() string { + return AccountBalanceNtfnMethod +} + +// MarshalJSON returns the JSON encoding of n. Part of the btcjson.Cmd +// interface. +func (n *AccountBalanceNtfn) MarshalJSON() ([]byte, error) { + params := []interface{}{ + n.Account, + n.Balance, + n.Confirmed, + } + + // No ID for notifications. + raw, err := btcjson.NewRawCmd(nil, n.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of n into n. Part of +// the btcjson.Cmd interface. +func (n *AccountBalanceNtfn) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newNtfn, err := parseAccountBalanceNtfn(&r) + if err != nil { + return err + } + + concreteNtfn, ok := newNtfn.(*AccountBalanceNtfn) + if !ok { + return btcjson.ErrInternal + } + *n = *concreteNtfn + return nil +} + +// BlockConnectedNtfn is a type handling custom marshaling and +// unmarshaling of blockconnected JSON websocket notifications. +type BlockConnectedNtfn struct { + Hash string + Height int32 +} + +// Enforce that BlockConnectedNtfn satisfies the btcjson.Cmd interface. +var _ btcjson.Cmd = &BlockConnectedNtfn{} + +// NewBlockConnectedNtfn creates a new BlockConnectedNtfn. +func NewBlockConnectedNtfn(hash string, height int32) *BlockConnectedNtfn { + return &BlockConnectedNtfn{ + Hash: hash, + Height: height, + } +} + +// parseBlockConnectedNtfn parses a RawCmd into a concrete type satisifying +// the btcjson.Cmd interface. This is used when registering the notification +// with the btcjson parser. +func parseBlockConnectedNtfn(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if r.Id != nil { + return nil, ErrNotANtfn + } + + if len(r.Params) != 2 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var hash string + if err := json.Unmarshal(r.Params[0], &hash); err != nil { + return nil, errors.New("first parameter 'hash' must be a string: " + err.Error()) + } + + var height int32 + if err := json.Unmarshal(r.Params[1], &height); err != nil { + return nil, errors.New("second parameter 'height' must be a 32-bit integer: " + err.Error()) + } + + return NewBlockConnectedNtfn(hash, height), nil +} + +// Id satisifies the btcjson.Cmd interface by returning nil for a +// notification ID. +func (n *BlockConnectedNtfn) Id() interface{} { + return nil +} + +// Method satisifies the btcjson.Cmd interface by returning the method +// of the notification. +func (n *BlockConnectedNtfn) Method() string { + return BlockConnectedNtfnMethod +} + +// MarshalJSON returns the JSON encoding of n. Part of the btcjson.Cmd +// interface. +func (n *BlockConnectedNtfn) MarshalJSON() ([]byte, error) { + params := []interface{}{ + n.Hash, + n.Height, + } + + // No ID for notifications. + raw, err := btcjson.NewRawCmd(nil, n.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of n into n. Part of +// the btcjson.Cmd interface. +func (n *BlockConnectedNtfn) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newNtfn, err := parseBlockConnectedNtfn(&r) + if err != nil { + return err + } + + concreteNtfn, ok := newNtfn.(*BlockConnectedNtfn) + if !ok { + return btcjson.ErrInternal + } + *n = *concreteNtfn + return nil +} + +// BlockDisconnectedNtfn is a type handling custom marshaling and +// unmarshaling of blockdisconnected JSON websocket notifications. +type BlockDisconnectedNtfn struct { + Hash string + Height int32 +} + +// Enforce that BlockDisconnectedNtfn satisfies the btcjson.Cmd interface. +var _ btcjson.Cmd = &BlockDisconnectedNtfn{} + +// NewBlockDisconnectedNtfn creates a new BlockDisconnectedNtfn. +func NewBlockDisconnectedNtfn(hash string, height int32) *BlockDisconnectedNtfn { + return &BlockDisconnectedNtfn{ + Hash: hash, + Height: height, + } +} + +// parseBlockDisconnectedNtfn parses a RawCmd into a concrete type satisifying +// the btcjson.Cmd interface. This is used when registering the notification +// with the btcjson parser. +func parseBlockDisconnectedNtfn(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if r.Id != nil { + return nil, ErrNotANtfn + } + + if len(r.Params) != 2 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var hash string + if err := json.Unmarshal(r.Params[0], &hash); err != nil { + return nil, errors.New("first parameter 'hash' must be a string: " + err.Error()) + } + + var height int32 + if err := json.Unmarshal(r.Params[1], &height); err != nil { + return nil, errors.New("second parameter 'height' must be a 32-bit integer: " + err.Error()) + } + + return NewBlockDisconnectedNtfn(hash, height), nil +} + +// Id satisifies the btcjson.Cmd interface by returning nil for a +// notification ID. +func (n *BlockDisconnectedNtfn) Id() interface{} { + return nil +} + +// Method satisifies the btcjson.Cmd interface by returning the method +// of the notification. +func (n *BlockDisconnectedNtfn) Method() string { + return BlockDisconnectedNtfnMethod +} + +// MarshalJSON returns the JSON encoding of n. Part of the btcjson.Cmd +// interface. +func (n *BlockDisconnectedNtfn) MarshalJSON() ([]byte, error) { + params := []interface{}{ + n.Hash, + n.Height, + } + + // No ID for notifications. + raw, err := btcjson.NewRawCmd(nil, n.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of n into n. Part of +// the btcjson.Cmd interface. +func (n *BlockDisconnectedNtfn) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newNtfn, err := parseBlockDisconnectedNtfn(&r) + if err != nil { + return err + } + + concreteNtfn, ok := newNtfn.(*BlockDisconnectedNtfn) + if !ok { + return btcjson.ErrInternal + } + *n = *concreteNtfn + return nil +} + +// BtcdConnectedNtfn is a type handling custom marshaling and +// unmarshaling of btcdconnected JSON websocket notifications. +type BtcdConnectedNtfn struct { + Connected bool +} + +// Enforce that BtcdConnectedNtfn satisifies the btcjson.Cmd +// interface. +var _ btcjson.Cmd = &BtcdConnectedNtfn{} + +// NewBtcdConnectedNtfn creates a new BtcdConnectedNtfn. +func NewBtcdConnectedNtfn(connected bool) *BtcdConnectedNtfn { + return &BtcdConnectedNtfn{connected} +} + +// parseBtcdConnectedNtfn parses a RawCmd into a concrete type satisifying +// the btcjson.Cmd interface. This is used when registering the notification +// with the btcjson parser. +func parseBtcdConnectedNtfn(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if r.Id != nil { + return nil, ErrNotANtfn + } + + if len(r.Params) != 1 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var connected bool + if err := json.Unmarshal(r.Params[0], &connected); err != nil { + return nil, errors.New("first parameter 'connected' must be a bool: " + err.Error()) + } + + return NewBtcdConnectedNtfn(connected), nil +} + +// Id satisifies the btcjson.Cmd interface by returning nil for a +// notification ID. +func (n *BtcdConnectedNtfn) Id() interface{} { + return nil +} + +// Method satisifies the btcjson.Cmd interface by returning the method +// of the notification. +func (n *BtcdConnectedNtfn) Method() string { + return BtcdConnectedNtfnMethod +} + +// MarshalJSON returns the JSON encoding of n. Part of the btcjson.Cmd +// interface. +func (n *BtcdConnectedNtfn) MarshalJSON() ([]byte, error) { + params := []interface{}{ + n.Connected, + } + + // No ID for notifications. + raw, err := btcjson.NewRawCmd(nil, n.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of n into n. Part of +// the btcjson.Cmd interface. +func (n *BtcdConnectedNtfn) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newNtfn, err := parseBtcdConnectedNtfn(&r) + if err != nil { + return err + } + + concreteNtfn, ok := newNtfn.(*BtcdConnectedNtfn) + if !ok { + return btcjson.ErrInternal + } + *n = *concreteNtfn + return nil +} + +// RecvTxNtfn is a type handling custom marshaling and unmarshaling +// of recvtx JSON websocket notifications. +type RecvTxNtfn struct { + HexTx string + Block *BlockDetails +} + +// Enforce that RecvTxNtfn satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &RecvTxNtfn{} + +// NewRecvTxNtfn creates a new RecvTxNtfn. +func NewRecvTxNtfn(hextx string, block *BlockDetails) *RecvTxNtfn { + return &RecvTxNtfn{ + HexTx: hextx, + Block: block, + } +} + +// parsRecvTxNtfn parses a RawCmd into a concrete type satisifying the +// btcjson.Cmd interface. This is used when registering the notification with +// the btcjson parser. +func parseRecvTxNtfn(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if r.Id != nil { + return nil, ErrNotANtfn + } + + // Must have one or two parameters. + if len(r.Params) == 0 || len(r.Params) > 2 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var hextx string + if err := json.Unmarshal(r.Params[0], &hextx); err != nil { + return nil, errors.New("first parameter 'hextx' must be a " + + "string: " + err.Error()) + } + + var blockDetails *BlockDetails + if len(r.Params) > 1 { + if err := json.Unmarshal(r.Params[1], &blockDetails); err != nil { + return nil, errors.New("second optional parameter " + + "'details' must be a JSON oject of block " + + "details: " + err.Error()) + } + } + + return NewRecvTxNtfn(hextx, blockDetails), nil +} + +// Id satisifies the btcjson.Cmd interface by returning nil for a +// notification ID. +func (n *RecvTxNtfn) Id() interface{} { + return nil +} + +// Method satisifies the btcjson.Cmd interface by returning the method +// of the notification. +func (n *RecvTxNtfn) Method() string { + return RecvTxNtfnMethod +} + +// MarshalJSON returns the JSON encoding of n. Part of the btcjson.Cmd +// interface. +func (n *RecvTxNtfn) MarshalJSON() ([]byte, error) { + params := make([]interface{}, 1, 2) + params[0] = n.HexTx + if n.Block != nil { + params = append(params, n.Block) + } + + // No ID for notifications. + raw, err := btcjson.NewRawCmd(nil, n.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of n into n. Part of +// the btcjson.Cmd interface. +func (n *RecvTxNtfn) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newNtfn, err := parseRecvTxNtfn(&r) + if err != nil { + return err + } + + concreteNtfn, ok := newNtfn.(*RecvTxNtfn) + if !ok { + return btcjson.ErrInternal + } + *n = *concreteNtfn + return nil +} + +// RedeemingTxNtfn is a type handling custom marshaling and unmarshaling +// of redeemingtx JSON websocket notifications. +type RedeemingTxNtfn struct { + HexTx string + Block *BlockDetails +} + +// Enforce that RedeemingTxNtfn satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &RedeemingTxNtfn{} + +// NewRedeemingTxNtfn creates a new RedeemingTxNtfn. +func NewRedeemingTxNtfn(hextx string, block *BlockDetails) *RedeemingTxNtfn { + return &RedeemingTxNtfn{ + HexTx: hextx, + Block: block, + } +} + +// parseRedeemingTxNtfn parses a RawCmd into a concrete type satisifying the +// btcjson.Cmd interface. This is used when registering the notification with +// the btcjson parser. +func parseRedeemingTxNtfn(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if r.Id != nil { + return nil, ErrNotANtfn + } + + // Must have one or two parameters. + if len(r.Params) == 0 || len(r.Params) > 2 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var hextx string + if err := json.Unmarshal(r.Params[0], &hextx); err != nil { + return nil, errors.New("first parameter 'hextx' must be a " + + "string: " + err.Error()) + } + + var blockDetails *BlockDetails + if len(r.Params) > 1 { + if err := json.Unmarshal(r.Params[1], &blockDetails); err != nil { + return nil, errors.New("second optional parameter " + + "'details' must be a JSON oject of block " + + "details: " + err.Error()) + } + } + + return NewRedeemingTxNtfn(hextx, blockDetails), nil +} + +// Id satisifies the btcjson.Cmd interface by returning nil for a +// notification ID. +func (n *RedeemingTxNtfn) Id() interface{} { + return nil +} + +// Method satisifies the btcjson.Cmd interface by returning the method +// of the notification. +func (n *RedeemingTxNtfn) Method() string { + return RedeemingTxNtfnMethod +} + +// MarshalJSON returns the JSON encoding of n. Part of the btcjson.Cmd +// interface. +func (n *RedeemingTxNtfn) MarshalJSON() ([]byte, error) { + params := make([]interface{}, 1, 2) + params[0] = n.HexTx + if n.Block != nil { + params = append(params, n.Block) + } + + // No ID for notifications. + raw, err := btcjson.NewRawCmd(nil, n.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of n into n. Part of +// the btcjson.Cmd interface. +func (n *RedeemingTxNtfn) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newNtfn, err := parseRedeemingTxNtfn(&r) + if err != nil { + return err + } + + concreteNtfn, ok := newNtfn.(*RedeemingTxNtfn) + if !ok { + return btcjson.ErrInternal + } + *n = *concreteNtfn + return nil +} + +// RescanFinishedNtfn is type handling custom marshaling and +// unmarshaling of rescanfinished JSON websocket notifications. +type RescanFinishedNtfn struct { + Hash string + Height int32 + Time int64 +} + +// Enforce that RescanFinishedNtfn satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &RescanFinishedNtfn{} + +// NewRescanFinishedNtfn creates a new RescanFinshedNtfn. +func NewRescanFinishedNtfn(hash string, height int32, time int64) *RescanFinishedNtfn { + return &RescanFinishedNtfn{hash, height, time} +} + +// parseRescanFinishedNtfn parses a RawCmd into a concrete type satisifying +// the btcjson.Cmd interface. This is used when registering the notification +// with the btcjson parser. +func parseRescanFinishedNtfn(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if r.Id != nil { + return nil, ErrNotANtfn + } + + if len(r.Params) != 3 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var hash string + if err := json.Unmarshal(r.Params[0], &hash); err != nil { + return nil, errors.New("first parameter 'hash' must be a " + + "string: " + err.Error()) + } + + var height int32 + if err := json.Unmarshal(r.Params[1], &height); err != nil { + return nil, errors.New("second parameter 'height' must be a " + + "32-bit integer: " + err.Error()) + } + + var time int64 + if err := json.Unmarshal(r.Params[2], &time); err != nil { + return nil, errors.New("third parameter 'time' must be a " + + "64-bit integer: " + err.Error()) + } + + return NewRescanFinishedNtfn(hash, height, time), nil +} + +// Id satisifies the btcjson.Cmd interface by returning nil for a +// notification ID. +func (n *RescanFinishedNtfn) Id() interface{} { + return nil +} + +// Method satisifies the btcjson.Cmd interface by returning the method +// of the notification. +func (n *RescanFinishedNtfn) Method() string { + return RescanFinishedNtfnMethod +} + +// MarshalJSON returns the JSON encoding of n. Part of the btcjson.Cmd +// interface. +func (n *RescanFinishedNtfn) MarshalJSON() ([]byte, error) { + params := []interface{}{ + n.Hash, + n.Height, + n.Time, + } + + // No ID for notifications. + raw, err := btcjson.NewRawCmd(nil, n.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of n into n. Part of +// the btcjson.Cmd interface. +func (n *RescanFinishedNtfn) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newNtfn, err := parseRescanFinishedNtfn(&r) + if err != nil { + return err + } + + concreteNtfn, ok := newNtfn.(*RescanFinishedNtfn) + if !ok { + return btcjson.ErrInternal + } + *n = *concreteNtfn + return nil +} + +// RescanProgressNtfn is type handling custom marshaling and +// unmarshaling of rescanprogress JSON websocket notifications. +type RescanProgressNtfn struct { + Hash string + Height int32 + Time int64 +} + +// Enforce that RescanProgressNtfn satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &RescanProgressNtfn{} + +// NewRescanProgressNtfn creates a new RescanProgressNtfn. +func NewRescanProgressNtfn(hash string, height int32, time int64) *RescanProgressNtfn { + return &RescanProgressNtfn{hash, height, time} +} + +// parseRescanProgressNtfn parses a RawCmd into a concrete type satisifying +// the btcjson.Cmd interface. This is used when registering the notification +// with the btcjson parser. +func parseRescanProgressNtfn(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if r.Id != nil { + return nil, ErrNotANtfn + } + + if len(r.Params) != 3 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var hash string + if err := json.Unmarshal(r.Params[0], &hash); err != nil { + return nil, errors.New("first parameter 'hash' must be a " + + "string: " + err.Error()) + } + + var height int32 + if err := json.Unmarshal(r.Params[1], &height); err != nil { + return nil, errors.New("second parameter 'height' must be a " + + "32-bit integer: " + err.Error()) + } + + var time int64 + if err := json.Unmarshal(r.Params[2], &time); err != nil { + return nil, errors.New("third parameter 'time' must be a " + + "64-bit integer: " + err.Error()) + } + + return NewRescanProgressNtfn(hash, height, time), nil +} + +// Id satisifies the btcjson.Cmd interface by returning nil for a +// notification ID. +func (n *RescanProgressNtfn) Id() interface{} { + return nil +} + +// Method satisifies the btcjson.Cmd interface by returning the method +// of the notification. +func (n *RescanProgressNtfn) Method() string { + return RescanProgressNtfnMethod +} + +// MarshalJSON returns the JSON encoding of n. Part of the btcjson.Cmd +// interface. +func (n *RescanProgressNtfn) MarshalJSON() ([]byte, error) { + params := []interface{}{ + n.Hash, + n.Height, + n.Time, + } + + // No ID for notifications. + raw, err := btcjson.NewRawCmd(nil, n.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of n into n. Part of +// the btcjson.Cmd interface. +func (n *RescanProgressNtfn) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newNtfn, err := parseRescanProgressNtfn(&r) + if err != nil { + return err + } + + concreteNtfn, ok := newNtfn.(*RescanProgressNtfn) + if !ok { + return btcjson.ErrInternal + } + *n = *concreteNtfn + return nil +} + +// TxNtfn is a type handling custom marshaling and +// unmarshaling of newtx JSON websocket notifications. +type TxNtfn struct { + Account string + Details *btcjson.ListTransactionsResult +} + +// Enforce that TxNtfn satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &TxNtfn{} + +// NewTxNtfn creates a new TxNtfn. +func NewTxNtfn(account string, details *btcjson.ListTransactionsResult) *TxNtfn { + return &TxNtfn{ + Account: account, + Details: details, + } +} + +// parseTxNtfn parses a RawCmd into a concrete type satisifying +// the btcjson.Cmd interface. This is used when registering the notification +// with the btcjson parser. +func parseTxNtfn(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if r.Id != nil { + return nil, ErrNotANtfn + } + + if len(r.Params) != 2 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var account string + if err := json.Unmarshal(r.Params[0], &account); err != nil { + return nil, errors.New("first parameter 'account' must be a " + + "string: " + err.Error()) + } + + var details btcjson.ListTransactionsResult + if err := json.Unmarshal(r.Params[1], &details); err != nil { + return nil, errors.New("second parameter 'details' must be a " + + "JSON object of transaction details: " + err.Error()) + } + + return NewTxNtfn(account, &details), nil +} + +// Id satisifies the btcjson.Cmd interface by returning nil for a +// notification ID. +func (n *TxNtfn) Id() interface{} { + return nil +} + +// Method satisifies the btcjson.Cmd interface by returning the method +// of the notification. +func (n *TxNtfn) Method() string { + return TxNtfnMethod +} + +// MarshalJSON returns the JSON encoding of n. Part of the btcjson.Cmd +// interface. +func (n *TxNtfn) MarshalJSON() ([]byte, error) { + params := []interface{}{ + n.Account, + n.Details, + } + + // No ID for notifications. + raw, err := btcjson.NewRawCmd(nil, n.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of n into n. Part of +// the btcjson.Cmd interface. +func (n *TxNtfn) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newNtfn, err := parseTxNtfn(&r) + if err != nil { + return err + } + + concreteNtfn, ok := newNtfn.(*TxNtfn) + if !ok { + return btcjson.ErrInternal + } + *n = *concreteNtfn + return nil +} + +// WalletLockStateNtfn is a type handling custom marshaling and +// unmarshaling of walletlockstate JSON websocket notifications. +type WalletLockStateNtfn struct { + Account string + Locked bool +} + +// Enforce that WalletLockStateNtfnMethod satisifies the btcjson.Cmd +// interface. +var _ btcjson.Cmd = &WalletLockStateNtfn{} + +// NewWalletLockStateNtfn creates a new WalletLockStateNtfn. +func NewWalletLockStateNtfn(account string, + locked bool) *WalletLockStateNtfn { + + return &WalletLockStateNtfn{ + Account: account, + Locked: locked, + } +} + +// parseWalletLockStateNtfn parses a RawCmd into a concrete type +// satisifying the btcjson.Cmd interface. This is used when registering +// the notification with the btcjson parser. +func parseWalletLockStateNtfn(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if r.Id != nil { + return nil, ErrNotANtfn + } + + if len(r.Params) != 2 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var account string + if err := json.Unmarshal(r.Params[0], &account); err != nil { + return nil, errors.New("first parameter 'account' must be a " + + "string: " + err.Error()) + } + + var locked bool + if err := json.Unmarshal(r.Params[1], &locked); err != nil { + return nil, errors.New("second parameter 'locked' must be a " + + "bool: " + err.Error()) + } + + return NewWalletLockStateNtfn(account, locked), nil +} + +// Id satisifies the btcjson.Cmd interface by returning nil for a +// notification ID. +func (n *WalletLockStateNtfn) Id() interface{} { + return nil +} + +// Method satisifies the btcjson.Cmd interface by returning the method +// of the notification. +func (n *WalletLockStateNtfn) Method() string { + return WalletLockStateNtfnMethod +} + +// MarshalJSON returns the JSON encoding of n. Part of the btcjson.Cmd +// interface. +func (n *WalletLockStateNtfn) MarshalJSON() ([]byte, error) { + params := []interface{}{ + n.Account, + n.Locked, + } + + // No ID for notifications. + raw, err := btcjson.NewRawCmd(nil, n.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of n into n. Part of +// the btcjson.Cmd interface. +func (n *WalletLockStateNtfn) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newNtfn, err := parseWalletLockStateNtfn(&r) + if err != nil { + return err + } + + concreteNtfn, ok := newNtfn.(*WalletLockStateNtfn) + if !ok { + return btcjson.ErrInternal + } + *n = *concreteNtfn + return nil +} + +// TxAcceptedNtfn is a type handling custom marshaling and +// unmarshaling of txmined JSON websocket notifications. +type TxAcceptedNtfn struct { + TxID string `json:"txid"` + Amount int64 `json:"amount"` +} + +// Enforce that TxAcceptedNtfn satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &TxAcceptedNtfn{} + +// NewTxAcceptedNtfn creates a new TxAcceptedNtfn. +func NewTxAcceptedNtfn(txid string, amount int64) *TxAcceptedNtfn { + return &TxAcceptedNtfn{ + TxID: txid, + Amount: amount, + } +} + +// parseTxAcceptedNtfn parses a RawCmd into a concrete type satisifying +// the btcjson.Cmd interface. This is used when registering the notification +// with the btcjson parser. +func parseTxAcceptedNtfn(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if r.Id != nil { + return nil, ErrNotANtfn + } + + if len(r.Params) != 2 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var txid string + if err := json.Unmarshal(r.Params[0], &txid); err != nil { + return nil, errors.New("first parameter 'txid' must be a " + + "string: " + err.Error()) + } + + var amount int64 + if err := json.Unmarshal(r.Params[1], &amount); err != nil { + return nil, errors.New("second parameter 'amount' must be an " + + "integer: " + err.Error()) + } + + return NewTxAcceptedNtfn(txid, amount), nil +} + +// Id satisifies the btcjson.Cmd interface by returning nil for a +// notification ID. +func (n *TxAcceptedNtfn) Id() interface{} { + return nil +} + +// Method satisifies the btcjson.Cmd interface by returning the method +// of the notification. +func (n *TxAcceptedNtfn) Method() string { + return TxAcceptedNtfnMethod +} + +// MarshalJSON returns the JSON encoding of n. Part of the btcjson.Cmd +// interface. +func (n *TxAcceptedNtfn) MarshalJSON() ([]byte, error) { + params := []interface{}{ + n.TxID, + n.Amount, + } + + // No ID for notifications. + raw, err := btcjson.NewRawCmd(nil, n.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of n into n. Part of +// the btcjson.Cmd interface. +func (n *TxAcceptedNtfn) UnmarshalJSON(b []byte) error { + // Unmarshal into a RawCmd. + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newNtfn, err := parseTxAcceptedNtfn(&r) + if err != nil { + return err + } + + concreteNtfn, ok := newNtfn.(*TxAcceptedNtfn) + if !ok { + return btcjson.ErrInternal + } + *n = *concreteNtfn + return nil +} + +// TxAcceptedVerboseNtfn is a type handling custom marshaling and +// unmarshaling of txmined JSON websocket notifications. +type TxAcceptedVerboseNtfn struct { + RawTx *btcjson.TxRawResult `json:"rawtx"` +} + +// Enforce that TxAcceptedNtfn satisifies the btcjson.Cmd interface. +var _ btcjson.Cmd = &TxAcceptedVerboseNtfn{} + +// NewTxAcceptedVerboseNtfn creates a new TxAcceptedVerboseNtfn. +func NewTxAcceptedVerboseNtfn(rawTx *btcjson.TxRawResult) *TxAcceptedVerboseNtfn { + return &TxAcceptedVerboseNtfn{ + RawTx: rawTx, + } +} + +// parseTxAcceptedVerboseNtfn parses a RawCmd into a concrete type satisifying +// the btcjson.Cmd interface. This is used when registering the notification +// with the btcjson parser. +func parseTxAcceptedVerboseNtfn(r *btcjson.RawCmd) (btcjson.Cmd, error) { + if r.Id != nil { + return nil, ErrNotANtfn + } + + if len(r.Params) != 1 { + return nil, btcjson.ErrWrongNumberOfParams + } + + var rawTx *btcjson.TxRawResult + if err := json.Unmarshal(r.Params[0], &rawTx); err != nil { + return nil, err + } + + return NewTxAcceptedVerboseNtfn(rawTx), nil +} + +// Id satisifies the btcjson.Cmd interface by returning nil for a +// notification ID. +func (n *TxAcceptedVerboseNtfn) Id() interface{} { + return nil +} + +// Method satisifies the btcjson.Cmd interface by returning the method +// of the notification. +func (n *TxAcceptedVerboseNtfn) Method() string { + return TxAcceptedVerboseNtfnMethod +} + +// MarshalJSON returns the JSON encoding of n. Part of the btcjson.Cmd +// interface. +func (n *TxAcceptedVerboseNtfn) MarshalJSON() ([]byte, error) { + params := []interface{}{ + n.RawTx, + } + + // No ID for notifications. + raw, err := btcjson.NewRawCmd(nil, n.Method(), params) + if err != nil { + return nil, err + } + return json.Marshal(raw) +} + +// UnmarshalJSON unmarshals the JSON encoding of n into n. Part of +// the btcjson.Cmd interface. +func (n *TxAcceptedVerboseNtfn) UnmarshalJSON(b []byte) error { + var r btcjson.RawCmd + if err := json.Unmarshal(b, &r); err != nil { + return err + } + + newNtfn, err := parseTxAcceptedVerboseNtfn(&r) + if err != nil { + return err + } + + concreteNtfn, ok := newNtfn.(*TxAcceptedVerboseNtfn) + if !ok { + return btcjson.ErrInternal + } + *n = *concreteNtfn + return nil +} diff --git a/btcjson/btcws/notifications_test.go b/btcjson/btcws/notifications_test.go new file mode 100644 index 00000000..1df4e2d6 --- /dev/null +++ b/btcjson/btcws/notifications_test.go @@ -0,0 +1,290 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcws_test + +import ( + "reflect" + "testing" + + "github.com/btcsuite/btcd/btcjson" + "github.com/btcsuite/btcd/btcjson/btcws" + "github.com/davecgh/go-spew/spew" +) + +var ntfntests = []struct { + name string + f func() btcjson.Cmd + result btcjson.Cmd // after marshal and unmarshal +}{ + { + name: "accountbalance", + f: func() btcjson.Cmd { + return btcws.NewAccountBalanceNtfn("abcde", 1.2345, true) + }, + result: &btcws.AccountBalanceNtfn{ + Account: "abcde", + Balance: 1.2345, + Confirmed: true, + }, + }, + { + name: "blockconnected", + f: func() btcjson.Cmd { + return btcws.NewBlockConnectedNtfn( + "000000004811dda1c320ad5d0ea184a20a53acd92292c5f1cb926c3ee82abf70", + 153469) + }, + result: &btcws.BlockConnectedNtfn{ + Hash: "000000004811dda1c320ad5d0ea184a20a53acd92292c5f1cb926c3ee82abf70", + Height: 153469, + }, + }, + { + name: "blockdisconnected", + f: func() btcjson.Cmd { + return btcws.NewBlockDisconnectedNtfn( + "000000004811dda1c320ad5d0ea184a20a53acd92292c5f1cb926c3ee82abf70", + 153469) + }, + result: &btcws.BlockDisconnectedNtfn{ + Hash: "000000004811dda1c320ad5d0ea184a20a53acd92292c5f1cb926c3ee82abf70", + Height: 153469, + }, + }, + { + name: "btcdconnected", + f: func() btcjson.Cmd { + return btcws.NewBtcdConnectedNtfn(true) + }, + result: &btcws.BtcdConnectedNtfn{ + Connected: true, + }, + }, + { + name: "recvtx no block", + f: func() btcjson.Cmd { + return btcws.NewRecvTxNtfn("lalala the hex tx", nil) + }, + result: &btcws.RecvTxNtfn{ + HexTx: "lalala the hex tx", + Block: nil, + }, + }, + { + name: "recvtx with block", + f: func() btcjson.Cmd { + block := &btcws.BlockDetails{ + Height: 153469, + Hash: "000000004811dda1c320ad5d0ea184a20a53acd92292c5f1cb926c3ee82abf70", + Index: 1, + Time: 1386944019, + } + return btcws.NewRecvTxNtfn("lalala the hex tx", block) + }, + result: &btcws.RecvTxNtfn{ + HexTx: "lalala the hex tx", + Block: &btcws.BlockDetails{ + Height: 153469, + Hash: "000000004811dda1c320ad5d0ea184a20a53acd92292c5f1cb926c3ee82abf70", + Index: 1, + Time: 1386944019, + }, + }, + }, + { + name: "redeemingtx", + f: func() btcjson.Cmd { + return btcws.NewRedeemingTxNtfn("lalala the hex tx", nil) + }, + result: &btcws.RedeemingTxNtfn{ + HexTx: "lalala the hex tx", + Block: nil, + }, + }, + { + name: "redeemingtx with block", + f: func() btcjson.Cmd { + block := &btcws.BlockDetails{ + Height: 153469, + Hash: "000000004811dda1c320ad5d0ea184a20a53acd92292c5f1cb926c3ee82abf70", + Index: 1, + Time: 1386944019, + } + return btcws.NewRedeemingTxNtfn("lalala the hex tx", block) + }, + result: &btcws.RedeemingTxNtfn{ + HexTx: "lalala the hex tx", + Block: &btcws.BlockDetails{ + Height: 153469, + Hash: "000000004811dda1c320ad5d0ea184a20a53acd92292c5f1cb926c3ee82abf70", + Index: 1, + Time: 1386944019, + }, + }, + }, + { + name: "rescanfinished", + f: func() btcjson.Cmd { + return btcws.NewRescanFinishedNtfn( + "00000000b8980ec1fe96bc1b4425788ddc88dd36699521a448ebca2020b38699", + 12345, 1240784732) + }, + result: &btcws.RescanFinishedNtfn{ + Hash: "00000000b8980ec1fe96bc1b4425788ddc88dd36699521a448ebca2020b38699", + Height: 12345, + Time: 1240784732, + }, + }, + { + name: "rescanprogress", + f: func() btcjson.Cmd { + return btcws.NewRescanProgressNtfn( + "00000000b8980ec1fe96bc1b4425788ddc88dd36699521a448ebca2020b38699", + 12345, 1240784732) + }, + result: &btcws.RescanProgressNtfn{ + Hash: "00000000b8980ec1fe96bc1b4425788ddc88dd36699521a448ebca2020b38699", + Height: 12345, + Time: 1240784732, + }, + }, + { + name: "newtx", + f: func() btcjson.Cmd { + details := &btcjson.ListTransactionsResult{ + Account: "original", + Address: "mnSsMBY8j4AhQzbR6XqawND7NPTECVdtLd", + Category: "receive", + Amount: 100, + Fee: 0.0, + Confirmations: 6707, + Generated: false, + BlockHash: "000000000b20bf5fe8e25b19f9ec340744cda321a17ade12af9838530a75098b", + BlockIndex: 2, + BlockTime: 1397079345, + TxID: "cb082a63b29f446551829d03fa8bac02d3825a18994d5feec564f14101fc5fad", + WalletConflicts: []string{}, + Time: 123123123, + TimeReceived: 1397079169, + Comment: "comment", + OtherAccount: "", + } + return btcws.NewTxNtfn("abcde", details) + }, + result: &btcws.TxNtfn{ + Account: "abcde", + Details: &btcjson.ListTransactionsResult{ + Account: "original", + Address: "mnSsMBY8j4AhQzbR6XqawND7NPTECVdtLd", + Category: "receive", + Amount: 100, + Fee: 0.0, + Confirmations: 6707, + Generated: false, + BlockHash: "000000000b20bf5fe8e25b19f9ec340744cda321a17ade12af9838530a75098b", + BlockIndex: 2, + BlockTime: 1397079345, + TxID: "cb082a63b29f446551829d03fa8bac02d3825a18994d5feec564f14101fc5fad", + WalletConflicts: []string{}, + Time: 123123123, + TimeReceived: 1397079169, + Comment: "comment", + OtherAccount: "", + }, + }, + }, + { + name: "walletlockstate", + f: func() btcjson.Cmd { + return btcws.NewWalletLockStateNtfn("abcde", true) + }, + result: &btcws.WalletLockStateNtfn{ + Account: "abcde", + Locked: true, + }, + }, + { + name: "txaccepted", + f: func() btcjson.Cmd { + return btcws.NewTxAcceptedNtfn( + "062f2b5f7d28c787e0f3aee382132241cd590efb7b83bd2c7f506de5aa4ef275", + 34567765) + }, + result: &btcws.TxAcceptedNtfn{ + TxID: "062f2b5f7d28c787e0f3aee382132241cd590efb7b83bd2c7f506de5aa4ef275", + Amount: 34567765, + }, + }, + { + name: "txacceptedverbose", + f: func() btcjson.Cmd { + return btcws.NewTxAcceptedVerboseNtfn(&btcjson.TxRawResult{ + Hex: "01000000010cdf900074a3622499a2f28f44a94476f27a8900a2bdd60e042754b6cab09741000000008a473044022012e11012fad1eb21ba1c82deb8da98778b08e714b72f281293064528343fae0502204294d7520f469f9673087a55395de0ce0e9074dce236db9fe7f30013b5fd00b90141047b6ff7832b4a763666e5481a0bd9eedb656d9f882d215c16fe9563d7b191cd67b2a41601a853a9f9d92773ae6f912ef451a089148e510623759cf55c408efdefffffffff02f4063f00000000001976a914b269e0ceec5d5b5e192cf580ae42341e0f79b0b588aca8c84b02000000001976a91439233c0d43a1411e547c60bad8985bae3530b6af88ac00000000", + Txid: "0cfeb968fb5d0f6b9a2a1de37c0607a1964dd3e335f203377cec90e03b20869e", + Version: 0x1, + LockTime: 0x0, + }) + }, + result: &btcws.TxAcceptedVerboseNtfn{ + RawTx: &btcjson.TxRawResult{ + Hex: "01000000010cdf900074a3622499a2f28f44a94476f27a8900a2bdd60e042754b6cab09741000000008a473044022012e11012fad1eb21ba1c82deb8da98778b08e714b72f281293064528343fae0502204294d7520f469f9673087a55395de0ce0e9074dce236db9fe7f30013b5fd00b90141047b6ff7832b4a763666e5481a0bd9eedb656d9f882d215c16fe9563d7b191cd67b2a41601a853a9f9d92773ae6f912ef451a089148e510623759cf55c408efdefffffffff02f4063f00000000001976a914b269e0ceec5d5b5e192cf580ae42341e0f79b0b588aca8c84b02000000001976a91439233c0d43a1411e547c60bad8985bae3530b6af88ac00000000", + Txid: "0cfeb968fb5d0f6b9a2a1de37c0607a1964dd3e335f203377cec90e03b20869e", + Version: 0x1, + LockTime: 0x0, + }, + }, + }, +} + +func TestNtfns(t *testing.T) { + for _, test := range ntfntests { + // create notification. + n := test.f() + + // verify that id is nil. + if n.Id() != nil { + t.Errorf("%s: notification should not have non-nil id %v", + test.name, n.Id()) + continue + } + + mn, err := n.MarshalJSON() + if err != nil { + t.Errorf("%s: failed to marshal notification: %v", + test.name, err) + continue + } + + n2, err := btcjson.ParseMarshaledCmd(mn) + if err != nil { + t.Errorf("%s: failed to ummarshal cmd: %v", + test.name, err) + continue + } + + if !reflect.DeepEqual(test.result, n2) { + t.Errorf("%s: unmarshal not as expected. "+ + "got %v wanted %v", test.name, spew.Sdump(n2), + spew.Sdump(test.result)) + } + if !reflect.DeepEqual(n, n2) { + t.Errorf("%s: unmarshal not as we started with. "+ + "got %v wanted %v", test.name, spew.Sdump(n2), + spew.Sdump(n)) + } + + // Read marshaled notification back into n. Should still + // match result. + if err := n.UnmarshalJSON(mn); err != nil { + t.Errorf("%s: unmarshal failed: %v", test.name, err) + continue + } + if !reflect.DeepEqual(test.result, n) { + t.Errorf("%s: unmarshal not as expected. "+ + "got %v wanted %v", test.name, spew.Sdump(n), + spew.Sdump(test.result)) + } + } +}