github.com/lbryio/lbcd@v0.22.119/btcjson/chainsvrcmds_test.go (about)

     1  // Copyright (c) 2014 The btcsuite developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package btcjson_test
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/hex"
    10  	"encoding/json"
    11  	"fmt"
    12  	"reflect"
    13  	"testing"
    14  
    15  	"github.com/lbryio/lbcd/btcjson"
    16  	"github.com/lbryio/lbcd/wire"
    17  )
    18  
    19  // TestChainSvrCmds tests all of the chain server commands marshal and unmarshal
    20  // into valid results include handling of optional fields being omitted in the
    21  // marshalled command, while optional fields with defaults have the default
    22  // assigned on unmarshalled commands.
    23  func TestChainSvrCmds(t *testing.T) {
    24  	t.Parallel()
    25  
    26  	testID := int(1)
    27  	tests := []struct {
    28  		name         string
    29  		newCmd       func() (interface{}, error)
    30  		staticCmd    func() interface{}
    31  		marshalled   string
    32  		unmarshalled interface{}
    33  	}{
    34  		{
    35  			name: "addnode",
    36  			newCmd: func() (interface{}, error) {
    37  				return btcjson.NewCmd("addnode", "127.0.0.1", btcjson.ANRemove)
    38  			},
    39  			staticCmd: func() interface{} {
    40  				return btcjson.NewAddNodeCmd("127.0.0.1", btcjson.ANRemove)
    41  			},
    42  			marshalled:   `{"jsonrpc":"1.0","method":"addnode","params":["127.0.0.1","remove"],"id":1}`,
    43  			unmarshalled: &btcjson.AddNodeCmd{Addr: "127.0.0.1", SubCmd: btcjson.ANRemove},
    44  		},
    45  		{
    46  			name: "createrawtransaction",
    47  			newCmd: func() (interface{}, error) {
    48  				return btcjson.NewCmd("createrawtransaction", `[{"txid":"123","vout":1}]`,
    49  					`{"456":0.0123}`)
    50  			},
    51  			staticCmd: func() interface{} {
    52  				txInputs := []btcjson.TransactionInput{
    53  					{Txid: "123", Vout: 1},
    54  				}
    55  				txOutputs := map[string]interface{}{"456": .0123}
    56  				return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, nil)
    57  			},
    58  			marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123}],"id":1}`,
    59  			unmarshalled: &btcjson.CreateRawTransactionCmd{
    60  				Inputs:  []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
    61  				Outputs: map[string]interface{}{"456": .0123},
    62  			},
    63  		},
    64  		{
    65  			name: "createrawtransaction - no inputs",
    66  			newCmd: func() (interface{}, error) {
    67  				return btcjson.NewCmd("createrawtransaction", `[]`, `{"456":0.0123}`)
    68  			},
    69  			staticCmd: func() interface{} {
    70  				txOutputs := map[string]interface{}{"456": .0123}
    71  				return btcjson.NewCreateRawTransactionCmd(nil, txOutputs, nil)
    72  			},
    73  			marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[],{"456":0.0123}],"id":1}`,
    74  			unmarshalled: &btcjson.CreateRawTransactionCmd{
    75  				Inputs:  []btcjson.TransactionInput{},
    76  				Outputs: map[string]interface{}{"456": .0123},
    77  			},
    78  		},
    79  		{
    80  			name: "createrawtransaction optional",
    81  			newCmd: func() (interface{}, error) {
    82  				return btcjson.NewCmd("createrawtransaction", `[{"txid":"123","vout":1}]`,
    83  					`{"456":0.0123}`, int64(12312333333))
    84  			},
    85  			staticCmd: func() interface{} {
    86  				txInputs := []btcjson.TransactionInput{
    87  					{Txid: "123", Vout: 1},
    88  				}
    89  				txOutputs := map[string]interface{}{"456": .0123}
    90  				return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, btcjson.Int64(12312333333))
    91  			},
    92  			marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123},12312333333],"id":1}`,
    93  			unmarshalled: &btcjson.CreateRawTransactionCmd{
    94  				Inputs:   []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
    95  				Outputs:  map[string]interface{}{"456": .0123},
    96  				LockTime: btcjson.Int64(12312333333),
    97  			},
    98  		},
    99  		{
   100  			name: "createrawtransaction with data",
   101  			newCmd: func() (interface{}, error) {
   102  				return btcjson.NewCmd("createrawtransaction", `[{"txid":"123","vout":1}]`,
   103  					`{"data":"6a134920616d204672616374616c456e6372797074"}`)
   104  			},
   105  			staticCmd: func() interface{} {
   106  				txInputs := []btcjson.TransactionInput{
   107  					{Txid: "123", Vout: 1},
   108  				}
   109  				txOutputs := map[string]interface{}{"data": "6a134920616d204672616374616c456e6372797074"}
   110  				return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, nil)
   111  			},
   112  			marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"data":"6a134920616d204672616374616c456e6372797074"}],"id":1}`,
   113  			unmarshalled: &btcjson.CreateRawTransactionCmd{
   114  				Inputs:  []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
   115  				Outputs: map[string]interface{}{"data": "6a134920616d204672616374616c456e6372797074"},
   116  			},
   117  		},
   118  		{
   119  			name: "fundrawtransaction - empty opts",
   120  			newCmd: func() (i interface{}, e error) {
   121  				return btcjson.NewCmd("fundrawtransaction", "deadbeef", "{}")
   122  			},
   123  			staticCmd: func() interface{} {
   124  				deadbeef, err := hex.DecodeString("deadbeef")
   125  				if err != nil {
   126  					panic(err)
   127  				}
   128  				return btcjson.NewFundRawTransactionCmd(deadbeef, btcjson.FundRawTransactionOpts{}, nil)
   129  			},
   130  			marshalled: `{"jsonrpc":"1.0","method":"fundrawtransaction","params":["deadbeef",{}],"id":1}`,
   131  			unmarshalled: &btcjson.FundRawTransactionCmd{
   132  				HexTx:     "deadbeef",
   133  				Options:   btcjson.FundRawTransactionOpts{},
   134  				IsWitness: nil,
   135  			},
   136  		},
   137  		{
   138  			name: "fundrawtransaction - full opts",
   139  			newCmd: func() (i interface{}, e error) {
   140  				return btcjson.NewCmd("fundrawtransaction", "deadbeef", `{"changeAddress":"bcrt1qeeuctq9wutlcl5zatge7rjgx0k45228cxez655","changePosition":1,"change_type":"legacy","includeWatching":true,"lockUnspents":true,"feeRate":0.7,"subtractFeeFromOutputs":[0],"replaceable":true,"conf_target":8,"estimate_mode":"ECONOMICAL"}`)
   141  			},
   142  			staticCmd: func() interface{} {
   143  				deadbeef, err := hex.DecodeString("deadbeef")
   144  				if err != nil {
   145  					panic(err)
   146  				}
   147  				changeAddress := "bcrt1qeeuctq9wutlcl5zatge7rjgx0k45228cxez655"
   148  				change := 1
   149  				changeType := btcjson.ChangeTypeLegacy
   150  				watching := true
   151  				lockUnspents := true
   152  				feeRate := 0.7
   153  				replaceable := true
   154  				confTarget := 8
   155  
   156  				return btcjson.NewFundRawTransactionCmd(deadbeef, btcjson.FundRawTransactionOpts{
   157  					ChangeAddress:          &changeAddress,
   158  					ChangePosition:         &change,
   159  					ChangeType:             &changeType,
   160  					IncludeWatching:        &watching,
   161  					LockUnspents:           &lockUnspents,
   162  					FeeRate:                &feeRate,
   163  					SubtractFeeFromOutputs: []int{0},
   164  					Replaceable:            &replaceable,
   165  					ConfTarget:             &confTarget,
   166  					EstimateMode:           &btcjson.EstimateModeEconomical,
   167  				}, nil)
   168  			},
   169  			marshalled: `{"jsonrpc":"1.0","method":"fundrawtransaction","params":["deadbeef",{"changeAddress":"bcrt1qeeuctq9wutlcl5zatge7rjgx0k45228cxez655","changePosition":1,"change_type":"legacy","includeWatching":true,"lockUnspents":true,"feeRate":0.7,"subtractFeeFromOutputs":[0],"replaceable":true,"conf_target":8,"estimate_mode":"ECONOMICAL"}],"id":1}`,
   170  			unmarshalled: func() interface{} {
   171  				changeAddress := "bcrt1qeeuctq9wutlcl5zatge7rjgx0k45228cxez655"
   172  				change := 1
   173  				changeType := btcjson.ChangeTypeLegacy
   174  				watching := true
   175  				lockUnspents := true
   176  				feeRate := 0.7
   177  				replaceable := true
   178  				confTarget := 8
   179  				return &btcjson.FundRawTransactionCmd{
   180  					HexTx: "deadbeef",
   181  					Options: btcjson.FundRawTransactionOpts{
   182  						ChangeAddress:          &changeAddress,
   183  						ChangePosition:         &change,
   184  						ChangeType:             &changeType,
   185  						IncludeWatching:        &watching,
   186  						LockUnspents:           &lockUnspents,
   187  						FeeRate:                &feeRate,
   188  						SubtractFeeFromOutputs: []int{0},
   189  						Replaceable:            &replaceable,
   190  						ConfTarget:             &confTarget,
   191  						EstimateMode:           &btcjson.EstimateModeEconomical,
   192  					},
   193  					IsWitness: nil,
   194  				}
   195  			}(),
   196  		},
   197  		{
   198  			name: "fundrawtransaction - iswitness",
   199  			newCmd: func() (i interface{}, e error) {
   200  				return btcjson.NewCmd("fundrawtransaction", "deadbeef", "{}", true)
   201  			},
   202  			staticCmd: func() interface{} {
   203  				deadbeef, err := hex.DecodeString("deadbeef")
   204  				if err != nil {
   205  					panic(err)
   206  				}
   207  				t := true
   208  				return btcjson.NewFundRawTransactionCmd(deadbeef, btcjson.FundRawTransactionOpts{}, &t)
   209  			},
   210  			marshalled: `{"jsonrpc":"1.0","method":"fundrawtransaction","params":["deadbeef",{},true],"id":1}`,
   211  			unmarshalled: &btcjson.FundRawTransactionCmd{
   212  				HexTx:   "deadbeef",
   213  				Options: btcjson.FundRawTransactionOpts{},
   214  				IsWitness: func() *bool {
   215  					t := true
   216  					return &t
   217  				}(),
   218  			},
   219  		},
   220  		{
   221  			name: "decoderawtransaction",
   222  			newCmd: func() (interface{}, error) {
   223  				return btcjson.NewCmd("decoderawtransaction", "123")
   224  			},
   225  			staticCmd: func() interface{} {
   226  				return btcjson.NewDecodeRawTransactionCmd("123")
   227  			},
   228  			marshalled:   `{"jsonrpc":"1.0","method":"decoderawtransaction","params":["123"],"id":1}`,
   229  			unmarshalled: &btcjson.DecodeRawTransactionCmd{HexTx: "123"},
   230  		},
   231  		{
   232  			name: "decodescript",
   233  			newCmd: func() (interface{}, error) {
   234  				return btcjson.NewCmd("decodescript", "00")
   235  			},
   236  			staticCmd: func() interface{} {
   237  				return btcjson.NewDecodeScriptCmd("00")
   238  			},
   239  			marshalled:   `{"jsonrpc":"1.0","method":"decodescript","params":["00"],"id":1}`,
   240  			unmarshalled: &btcjson.DecodeScriptCmd{HexScript: "00"},
   241  		},
   242  		{
   243  			name: "deriveaddresses no range",
   244  			newCmd: func() (interface{}, error) {
   245  				return btcjson.NewCmd("deriveaddresses", "00")
   246  			},
   247  			staticCmd: func() interface{} {
   248  				return btcjson.NewDeriveAddressesCmd("00", nil)
   249  			},
   250  			marshalled:   `{"jsonrpc":"1.0","method":"deriveaddresses","params":["00"],"id":1}`,
   251  			unmarshalled: &btcjson.DeriveAddressesCmd{Descriptor: "00"},
   252  		},
   253  		{
   254  			name: "deriveaddresses int range",
   255  			newCmd: func() (interface{}, error) {
   256  				return btcjson.NewCmd(
   257  					"deriveaddresses", "00", btcjson.DescriptorRange{Value: 2})
   258  			},
   259  			staticCmd: func() interface{} {
   260  				return btcjson.NewDeriveAddressesCmd(
   261  					"00", &btcjson.DescriptorRange{Value: 2})
   262  			},
   263  			marshalled: `{"jsonrpc":"1.0","method":"deriveaddresses","params":["00",2],"id":1}`,
   264  			unmarshalled: &btcjson.DeriveAddressesCmd{
   265  				Descriptor: "00",
   266  				Range:      &btcjson.DescriptorRange{Value: 2},
   267  			},
   268  		},
   269  		{
   270  			name: "deriveaddresses slice range",
   271  			newCmd: func() (interface{}, error) {
   272  				return btcjson.NewCmd(
   273  					"deriveaddresses", "00",
   274  					btcjson.DescriptorRange{Value: []int{0, 2}},
   275  				)
   276  			},
   277  			staticCmd: func() interface{} {
   278  				return btcjson.NewDeriveAddressesCmd(
   279  					"00", &btcjson.DescriptorRange{Value: []int{0, 2}})
   280  			},
   281  			marshalled: `{"jsonrpc":"1.0","method":"deriveaddresses","params":["00",[0,2]],"id":1}`,
   282  			unmarshalled: &btcjson.DeriveAddressesCmd{
   283  				Descriptor: "00",
   284  				Range:      &btcjson.DescriptorRange{Value: []int{0, 2}},
   285  			},
   286  		},
   287  		{
   288  			name: "getaddednodeinfo",
   289  			newCmd: func() (interface{}, error) {
   290  				return btcjson.NewCmd("getaddednodeinfo", true)
   291  			},
   292  			staticCmd: func() interface{} {
   293  				return btcjson.NewGetAddedNodeInfoCmd(true, nil)
   294  			},
   295  			marshalled:   `{"jsonrpc":"1.0","method":"getaddednodeinfo","params":[true],"id":1}`,
   296  			unmarshalled: &btcjson.GetAddedNodeInfoCmd{DNS: true, Node: nil},
   297  		},
   298  		{
   299  			name: "getaddednodeinfo optional",
   300  			newCmd: func() (interface{}, error) {
   301  				return btcjson.NewCmd("getaddednodeinfo", true, "127.0.0.1")
   302  			},
   303  			staticCmd: func() interface{} {
   304  				return btcjson.NewGetAddedNodeInfoCmd(true, btcjson.String("127.0.0.1"))
   305  			},
   306  			marshalled: `{"jsonrpc":"1.0","method":"getaddednodeinfo","params":[true,"127.0.0.1"],"id":1}`,
   307  			unmarshalled: &btcjson.GetAddedNodeInfoCmd{
   308  				DNS:  true,
   309  				Node: btcjson.String("127.0.0.1"),
   310  			},
   311  		},
   312  		{
   313  			name: "getbestblockhash",
   314  			newCmd: func() (interface{}, error) {
   315  				return btcjson.NewCmd("getbestblockhash")
   316  			},
   317  			staticCmd: func() interface{} {
   318  				return btcjson.NewGetBestBlockHashCmd()
   319  			},
   320  			marshalled:   `{"jsonrpc":"1.0","method":"getbestblockhash","params":[],"id":1}`,
   321  			unmarshalled: &btcjson.GetBestBlockHashCmd{},
   322  		},
   323  		{
   324  			name: "getblock",
   325  			newCmd: func() (interface{}, error) {
   326  				return btcjson.NewCmd("getblock", "123", btcjson.Int(0))
   327  			},
   328  			staticCmd: func() interface{} {
   329  				return btcjson.NewGetBlockCmd("123", btcjson.Int(0))
   330  			},
   331  			marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",0],"id":1}`,
   332  			unmarshalled: &btcjson.GetBlockCmd{
   333  				Hash:      "123",
   334  				Verbosity: btcjson.Int(0),
   335  			},
   336  		},
   337  		{
   338  			name: "getblock default verbosity",
   339  			newCmd: func() (interface{}, error) {
   340  				return btcjson.NewCmd("getblock", "123")
   341  			},
   342  			staticCmd: func() interface{} {
   343  				return btcjson.NewGetBlockCmd("123", nil)
   344  			},
   345  			marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123"],"id":1}`,
   346  			unmarshalled: &btcjson.GetBlockCmd{
   347  				Hash:      "123",
   348  				Verbosity: btcjson.Int(1),
   349  			},
   350  		},
   351  		{
   352  			name: "getblock required optional1",
   353  			newCmd: func() (interface{}, error) {
   354  				return btcjson.NewCmd("getblock", "123", btcjson.Int(1))
   355  			},
   356  			staticCmd: func() interface{} {
   357  				return btcjson.NewGetBlockCmd("123", btcjson.Int(1))
   358  			},
   359  			marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",1],"id":1}`,
   360  			unmarshalled: &btcjson.GetBlockCmd{
   361  				Hash:      "123",
   362  				Verbosity: btcjson.Int(1),
   363  			},
   364  		},
   365  		{
   366  			name: "getblock required optional2",
   367  			newCmd: func() (interface{}, error) {
   368  				return btcjson.NewCmd("getblock", "123", btcjson.Int(2))
   369  			},
   370  			staticCmd: func() interface{} {
   371  				return btcjson.NewGetBlockCmd("123", btcjson.Int(2))
   372  			},
   373  			marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",2],"id":1}`,
   374  			unmarshalled: &btcjson.GetBlockCmd{
   375  				Hash:      "123",
   376  				Verbosity: btcjson.Int(2),
   377  			},
   378  		},
   379  		{
   380  			name: "getblockchaininfo",
   381  			newCmd: func() (interface{}, error) {
   382  				return btcjson.NewCmd("getblockchaininfo")
   383  			},
   384  			staticCmd: func() interface{} {
   385  				return btcjson.NewGetBlockChainInfoCmd()
   386  			},
   387  			marshalled:   `{"jsonrpc":"1.0","method":"getblockchaininfo","params":[],"id":1}`,
   388  			unmarshalled: &btcjson.GetBlockChainInfoCmd{},
   389  		},
   390  		{
   391  			name: "getblockcount",
   392  			newCmd: func() (interface{}, error) {
   393  				return btcjson.NewCmd("getblockcount")
   394  			},
   395  			staticCmd: func() interface{} {
   396  				return btcjson.NewGetBlockCountCmd()
   397  			},
   398  			marshalled:   `{"jsonrpc":"1.0","method":"getblockcount","params":[],"id":1}`,
   399  			unmarshalled: &btcjson.GetBlockCountCmd{},
   400  		},
   401  		{
   402  			name: "getblockfilter",
   403  			newCmd: func() (interface{}, error) {
   404  				return btcjson.NewCmd("getblockfilter", "0000afaf")
   405  			},
   406  			staticCmd: func() interface{} {
   407  				return btcjson.NewGetBlockFilterCmd("0000afaf", nil)
   408  			},
   409  			marshalled:   `{"jsonrpc":"1.0","method":"getblockfilter","params":["0000afaf"],"id":1}`,
   410  			unmarshalled: &btcjson.GetBlockFilterCmd{BlockHash: "0000afaf", FilterType: nil},
   411  		},
   412  		{
   413  			name: "getblockfilter optional filtertype",
   414  			newCmd: func() (interface{}, error) {
   415  				return btcjson.NewCmd("getblockfilter", "0000afaf", "basic")
   416  			},
   417  			staticCmd: func() interface{} {
   418  				return btcjson.NewGetBlockFilterCmd("0000afaf", btcjson.NewFilterTypeName(btcjson.FilterTypeBasic))
   419  			},
   420  			marshalled:   `{"jsonrpc":"1.0","method":"getblockfilter","params":["0000afaf","basic"],"id":1}`,
   421  			unmarshalled: &btcjson.GetBlockFilterCmd{BlockHash: "0000afaf", FilterType: btcjson.NewFilterTypeName(btcjson.FilterTypeBasic)},
   422  		},
   423  		{
   424  			name: "getblockhash",
   425  			newCmd: func() (interface{}, error) {
   426  				return btcjson.NewCmd("getblockhash", 123)
   427  			},
   428  			staticCmd: func() interface{} {
   429  				return btcjson.NewGetBlockHashCmd(123)
   430  			},
   431  			marshalled:   `{"jsonrpc":"1.0","method":"getblockhash","params":[123],"id":1}`,
   432  			unmarshalled: &btcjson.GetBlockHashCmd{Index: 123},
   433  		},
   434  		{
   435  			name: "getblockheader",
   436  			newCmd: func() (interface{}, error) {
   437  				return btcjson.NewCmd("getblockheader", "123")
   438  			},
   439  			staticCmd: func() interface{} {
   440  				return btcjson.NewGetBlockHeaderCmd("123", nil)
   441  			},
   442  			marshalled: `{"jsonrpc":"1.0","method":"getblockheader","params":["123"],"id":1}`,
   443  			unmarshalled: &btcjson.GetBlockHeaderCmd{
   444  				Hash:    "123",
   445  				Verbose: btcjson.Bool(true),
   446  			},
   447  		},
   448  		{
   449  			name: "getblockstats height",
   450  			newCmd: func() (interface{}, error) {
   451  				return btcjson.NewCmd("getblockstats", btcjson.HashOrHeight{Value: 123})
   452  			},
   453  			staticCmd: func() interface{} {
   454  				return btcjson.NewGetBlockStatsCmd(btcjson.HashOrHeight{Value: 123}, nil)
   455  			},
   456  			marshalled: `{"jsonrpc":"1.0","method":"getblockstats","params":[123],"id":1}`,
   457  			unmarshalled: &btcjson.GetBlockStatsCmd{
   458  				HashOrHeight: btcjson.HashOrHeight{Value: 123},
   459  			},
   460  		},
   461  		{
   462  			name: "getblockstats hash",
   463  			newCmd: func() (interface{}, error) {
   464  				return btcjson.NewCmd("getblockstats", btcjson.HashOrHeight{Value: "deadbeef"})
   465  			},
   466  			staticCmd: func() interface{} {
   467  				return btcjson.NewGetBlockStatsCmd(btcjson.HashOrHeight{Value: "deadbeef"}, nil)
   468  			},
   469  			marshalled: `{"jsonrpc":"1.0","method":"getblockstats","params":["deadbeef"],"id":1}`,
   470  			unmarshalled: &btcjson.GetBlockStatsCmd{
   471  				HashOrHeight: btcjson.HashOrHeight{Value: "deadbeef"},
   472  			},
   473  		},
   474  		{
   475  			name: "getblockstats height optional stats",
   476  			newCmd: func() (interface{}, error) {
   477  				return btcjson.NewCmd("getblockstats", btcjson.HashOrHeight{Value: 123}, []string{"avgfee", "maxfee"})
   478  			},
   479  			staticCmd: func() interface{} {
   480  				return btcjson.NewGetBlockStatsCmd(btcjson.HashOrHeight{Value: 123}, &[]string{"avgfee", "maxfee"})
   481  			},
   482  			marshalled: `{"jsonrpc":"1.0","method":"getblockstats","params":[123,["avgfee","maxfee"]],"id":1}`,
   483  			unmarshalled: &btcjson.GetBlockStatsCmd{
   484  				HashOrHeight: btcjson.HashOrHeight{Value: 123},
   485  				Stats:        &[]string{"avgfee", "maxfee"},
   486  			},
   487  		},
   488  		{
   489  			name: "getblockstats hash optional stats",
   490  			newCmd: func() (interface{}, error) {
   491  				return btcjson.NewCmd("getblockstats", btcjson.HashOrHeight{Value: "deadbeef"}, []string{"avgfee", "maxfee"})
   492  			},
   493  			staticCmd: func() interface{} {
   494  				return btcjson.NewGetBlockStatsCmd(btcjson.HashOrHeight{Value: "deadbeef"}, &[]string{"avgfee", "maxfee"})
   495  			},
   496  			marshalled: `{"jsonrpc":"1.0","method":"getblockstats","params":["deadbeef",["avgfee","maxfee"]],"id":1}`,
   497  			unmarshalled: &btcjson.GetBlockStatsCmd{
   498  				HashOrHeight: btcjson.HashOrHeight{Value: "deadbeef"},
   499  				Stats:        &[]string{"avgfee", "maxfee"},
   500  			},
   501  		},
   502  		{
   503  			name: "getblocktemplate",
   504  			newCmd: func() (interface{}, error) {
   505  				return btcjson.NewCmd("getblocktemplate")
   506  			},
   507  			staticCmd: func() interface{} {
   508  				return btcjson.NewGetBlockTemplateCmd(nil)
   509  			},
   510  			marshalled:   `{"jsonrpc":"1.0","method":"getblocktemplate","params":[],"id":1}`,
   511  			unmarshalled: &btcjson.GetBlockTemplateCmd{Request: nil},
   512  		},
   513  		{
   514  			name: "getblocktemplate optional - template request",
   515  			newCmd: func() (interface{}, error) {
   516  				return btcjson.NewCmd("getblocktemplate", `{"mode":"template","capabilities":["longpoll","coinbasetxn"]}`)
   517  			},
   518  			staticCmd: func() interface{} {
   519  				template := btcjson.TemplateRequest{
   520  					Mode:         "template",
   521  					Capabilities: []string{"longpoll", "coinbasetxn"},
   522  				}
   523  				return btcjson.NewGetBlockTemplateCmd(&template)
   524  			},
   525  			marshalled: `{"jsonrpc":"1.0","method":"getblocktemplate","params":[{"mode":"template","capabilities":["longpoll","coinbasetxn"]}],"id":1}`,
   526  			unmarshalled: &btcjson.GetBlockTemplateCmd{
   527  				Request: &btcjson.TemplateRequest{
   528  					Mode:         "template",
   529  					Capabilities: []string{"longpoll", "coinbasetxn"},
   530  				},
   531  			},
   532  		},
   533  		{
   534  			name: "getblocktemplate optional - template request with tweaks",
   535  			newCmd: func() (interface{}, error) {
   536  				return btcjson.NewCmd("getblocktemplate", `{"mode":"template","capabilities":["longpoll","coinbasetxn"],"sigoplimit":500,"sizelimit":100000000,"maxversion":2}`)
   537  			},
   538  			staticCmd: func() interface{} {
   539  				template := btcjson.TemplateRequest{
   540  					Mode:         "template",
   541  					Capabilities: []string{"longpoll", "coinbasetxn"},
   542  					SigOpLimit:   500,
   543  					SizeLimit:    100000000,
   544  					MaxVersion:   2,
   545  				}
   546  				return btcjson.NewGetBlockTemplateCmd(&template)
   547  			},
   548  			marshalled: `{"jsonrpc":"1.0","method":"getblocktemplate","params":[{"mode":"template","capabilities":["longpoll","coinbasetxn"],"sigoplimit":500,"sizelimit":100000000,"maxversion":2}],"id":1}`,
   549  			unmarshalled: &btcjson.GetBlockTemplateCmd{
   550  				Request: &btcjson.TemplateRequest{
   551  					Mode:         "template",
   552  					Capabilities: []string{"longpoll", "coinbasetxn"},
   553  					SigOpLimit:   int64(500),
   554  					SizeLimit:    int64(100000000),
   555  					MaxVersion:   2,
   556  				},
   557  			},
   558  		},
   559  		{
   560  			name: "getblocktemplate optional - template request with tweaks 2",
   561  			newCmd: func() (interface{}, error) {
   562  				return btcjson.NewCmd("getblocktemplate", `{"mode":"template","capabilities":["longpoll","coinbasetxn"],"sigoplimit":true,"sizelimit":100000000,"maxversion":2}`)
   563  			},
   564  			staticCmd: func() interface{} {
   565  				template := btcjson.TemplateRequest{
   566  					Mode:         "template",
   567  					Capabilities: []string{"longpoll", "coinbasetxn"},
   568  					SigOpLimit:   true,
   569  					SizeLimit:    100000000,
   570  					MaxVersion:   2,
   571  				}
   572  				return btcjson.NewGetBlockTemplateCmd(&template)
   573  			},
   574  			marshalled: `{"jsonrpc":"1.0","method":"getblocktemplate","params":[{"mode":"template","capabilities":["longpoll","coinbasetxn"],"sigoplimit":true,"sizelimit":100000000,"maxversion":2}],"id":1}`,
   575  			unmarshalled: &btcjson.GetBlockTemplateCmd{
   576  				Request: &btcjson.TemplateRequest{
   577  					Mode:         "template",
   578  					Capabilities: []string{"longpoll", "coinbasetxn"},
   579  					SigOpLimit:   true,
   580  					SizeLimit:    int64(100000000),
   581  					MaxVersion:   2,
   582  				},
   583  			},
   584  		},
   585  		{
   586  			name: "getcfilter",
   587  			newCmd: func() (interface{}, error) {
   588  				return btcjson.NewCmd("getcfilter", "123",
   589  					wire.GCSFilterRegular)
   590  			},
   591  			staticCmd: func() interface{} {
   592  				return btcjson.NewGetCFilterCmd("123",
   593  					wire.GCSFilterRegular)
   594  			},
   595  			marshalled: `{"jsonrpc":"1.0","method":"getcfilter","params":["123",0],"id":1}`,
   596  			unmarshalled: &btcjson.GetCFilterCmd{
   597  				Hash:       "123",
   598  				FilterType: wire.GCSFilterRegular,
   599  			},
   600  		},
   601  		{
   602  			name: "getcfilterheader",
   603  			newCmd: func() (interface{}, error) {
   604  				return btcjson.NewCmd("getcfilterheader", "123",
   605  					wire.GCSFilterRegular)
   606  			},
   607  			staticCmd: func() interface{} {
   608  				return btcjson.NewGetCFilterHeaderCmd("123",
   609  					wire.GCSFilterRegular)
   610  			},
   611  			marshalled: `{"jsonrpc":"1.0","method":"getcfilterheader","params":["123",0],"id":1}`,
   612  			unmarshalled: &btcjson.GetCFilterHeaderCmd{
   613  				Hash:       "123",
   614  				FilterType: wire.GCSFilterRegular,
   615  			},
   616  		},
   617  		{
   618  			name: "getchaintips",
   619  			newCmd: func() (interface{}, error) {
   620  				return btcjson.NewCmd("getchaintips")
   621  			},
   622  			staticCmd: func() interface{} {
   623  				return btcjson.NewGetChainTipsCmd()
   624  			},
   625  			marshalled:   `{"jsonrpc":"1.0","method":"getchaintips","params":[],"id":1}`,
   626  			unmarshalled: &btcjson.GetChainTipsCmd{},
   627  		},
   628  		{
   629  			name: "getchaintxstats",
   630  			newCmd: func() (interface{}, error) {
   631  				return btcjson.NewCmd("getchaintxstats")
   632  			},
   633  			staticCmd: func() interface{} {
   634  				return btcjson.NewGetChainTxStatsCmd(nil, nil)
   635  			},
   636  			marshalled:   `{"jsonrpc":"1.0","method":"getchaintxstats","params":[],"id":1}`,
   637  			unmarshalled: &btcjson.GetChainTxStatsCmd{},
   638  		},
   639  		{
   640  			name: "getchaintxstats optional nblocks",
   641  			newCmd: func() (interface{}, error) {
   642  				return btcjson.NewCmd("getchaintxstats", btcjson.Int32(1000))
   643  			},
   644  			staticCmd: func() interface{} {
   645  				return btcjson.NewGetChainTxStatsCmd(btcjson.Int32(1000), nil)
   646  			},
   647  			marshalled: `{"jsonrpc":"1.0","method":"getchaintxstats","params":[1000],"id":1}`,
   648  			unmarshalled: &btcjson.GetChainTxStatsCmd{
   649  				NBlocks: btcjson.Int32(1000),
   650  			},
   651  		},
   652  		{
   653  			name: "getchaintxstats optional nblocks and blockhash",
   654  			newCmd: func() (interface{}, error) {
   655  				return btcjson.NewCmd("getchaintxstats", btcjson.Int32(1000), btcjson.String("0000afaf"))
   656  			},
   657  			staticCmd: func() interface{} {
   658  				return btcjson.NewGetChainTxStatsCmd(btcjson.Int32(1000), btcjson.String("0000afaf"))
   659  			},
   660  			marshalled: `{"jsonrpc":"1.0","method":"getchaintxstats","params":[1000,"0000afaf"],"id":1}`,
   661  			unmarshalled: &btcjson.GetChainTxStatsCmd{
   662  				NBlocks:   btcjson.Int32(1000),
   663  				BlockHash: btcjson.String("0000afaf"),
   664  			},
   665  		},
   666  		{
   667  			name: "getconnectioncount",
   668  			newCmd: func() (interface{}, error) {
   669  				return btcjson.NewCmd("getconnectioncount")
   670  			},
   671  			staticCmd: func() interface{} {
   672  				return btcjson.NewGetConnectionCountCmd()
   673  			},
   674  			marshalled:   `{"jsonrpc":"1.0","method":"getconnectioncount","params":[],"id":1}`,
   675  			unmarshalled: &btcjson.GetConnectionCountCmd{},
   676  		},
   677  		{
   678  			name: "getdifficulty",
   679  			newCmd: func() (interface{}, error) {
   680  				return btcjson.NewCmd("getdifficulty")
   681  			},
   682  			staticCmd: func() interface{} {
   683  				return btcjson.NewGetDifficultyCmd()
   684  			},
   685  			marshalled:   `{"jsonrpc":"1.0","method":"getdifficulty","params":[],"id":1}`,
   686  			unmarshalled: &btcjson.GetDifficultyCmd{},
   687  		},
   688  		{
   689  			name: "getgenerate",
   690  			newCmd: func() (interface{}, error) {
   691  				return btcjson.NewCmd("getgenerate")
   692  			},
   693  			staticCmd: func() interface{} {
   694  				return btcjson.NewGetGenerateCmd()
   695  			},
   696  			marshalled:   `{"jsonrpc":"1.0","method":"getgenerate","params":[],"id":1}`,
   697  			unmarshalled: &btcjson.GetGenerateCmd{},
   698  		},
   699  		{
   700  			name: "gethashespersec",
   701  			newCmd: func() (interface{}, error) {
   702  				return btcjson.NewCmd("gethashespersec")
   703  			},
   704  			staticCmd: func() interface{} {
   705  				return btcjson.NewGetHashesPerSecCmd()
   706  			},
   707  			marshalled:   `{"jsonrpc":"1.0","method":"gethashespersec","params":[],"id":1}`,
   708  			unmarshalled: &btcjson.GetHashesPerSecCmd{},
   709  		},
   710  		{
   711  			name: "getinfo",
   712  			newCmd: func() (interface{}, error) {
   713  				return btcjson.NewCmd("getinfo")
   714  			},
   715  			staticCmd: func() interface{} {
   716  				return btcjson.NewGetInfoCmd()
   717  			},
   718  			marshalled:   `{"jsonrpc":"1.0","method":"getinfo","params":[],"id":1}`,
   719  			unmarshalled: &btcjson.GetInfoCmd{},
   720  		},
   721  		{
   722  			name: "getmempoolentry",
   723  			newCmd: func() (interface{}, error) {
   724  				return btcjson.NewCmd("getmempoolentry", "txhash")
   725  			},
   726  			staticCmd: func() interface{} {
   727  				return btcjson.NewGetMempoolEntryCmd("txhash")
   728  			},
   729  			marshalled: `{"jsonrpc":"1.0","method":"getmempoolentry","params":["txhash"],"id":1}`,
   730  			unmarshalled: &btcjson.GetMempoolEntryCmd{
   731  				TxID: "txhash",
   732  			},
   733  		},
   734  		{
   735  			name: "getmempoolinfo",
   736  			newCmd: func() (interface{}, error) {
   737  				return btcjson.NewCmd("getmempoolinfo")
   738  			},
   739  			staticCmd: func() interface{} {
   740  				return btcjson.NewGetMempoolInfoCmd()
   741  			},
   742  			marshalled:   `{"jsonrpc":"1.0","method":"getmempoolinfo","params":[],"id":1}`,
   743  			unmarshalled: &btcjson.GetMempoolInfoCmd{},
   744  		},
   745  		{
   746  			name: "getmininginfo",
   747  			newCmd: func() (interface{}, error) {
   748  				return btcjson.NewCmd("getmininginfo")
   749  			},
   750  			staticCmd: func() interface{} {
   751  				return btcjson.NewGetMiningInfoCmd()
   752  			},
   753  			marshalled:   `{"jsonrpc":"1.0","method":"getmininginfo","params":[],"id":1}`,
   754  			unmarshalled: &btcjson.GetMiningInfoCmd{},
   755  		},
   756  		{
   757  			name: "getnetworkinfo",
   758  			newCmd: func() (interface{}, error) {
   759  				return btcjson.NewCmd("getnetworkinfo")
   760  			},
   761  			staticCmd: func() interface{} {
   762  				return btcjson.NewGetNetworkInfoCmd()
   763  			},
   764  			marshalled:   `{"jsonrpc":"1.0","method":"getnetworkinfo","params":[],"id":1}`,
   765  			unmarshalled: &btcjson.GetNetworkInfoCmd{},
   766  		},
   767  		{
   768  			name: "getnettotals",
   769  			newCmd: func() (interface{}, error) {
   770  				return btcjson.NewCmd("getnettotals")
   771  			},
   772  			staticCmd: func() interface{} {
   773  				return btcjson.NewGetNetTotalsCmd()
   774  			},
   775  			marshalled:   `{"jsonrpc":"1.0","method":"getnettotals","params":[],"id":1}`,
   776  			unmarshalled: &btcjson.GetNetTotalsCmd{},
   777  		},
   778  		{
   779  			name: "getnetworkhashps",
   780  			newCmd: func() (interface{}, error) {
   781  				return btcjson.NewCmd("getnetworkhashps")
   782  			},
   783  			staticCmd: func() interface{} {
   784  				return btcjson.NewGetNetworkHashPSCmd(nil, nil)
   785  			},
   786  			marshalled: `{"jsonrpc":"1.0","method":"getnetworkhashps","params":[],"id":1}`,
   787  			unmarshalled: &btcjson.GetNetworkHashPSCmd{
   788  				Blocks: btcjson.Int(120),
   789  				Height: btcjson.Int(-1),
   790  			},
   791  		},
   792  		{
   793  			name: "getnetworkhashps optional1",
   794  			newCmd: func() (interface{}, error) {
   795  				return btcjson.NewCmd("getnetworkhashps", 200)
   796  			},
   797  			staticCmd: func() interface{} {
   798  				return btcjson.NewGetNetworkHashPSCmd(btcjson.Int(200), nil)
   799  			},
   800  			marshalled: `{"jsonrpc":"1.0","method":"getnetworkhashps","params":[200],"id":1}`,
   801  			unmarshalled: &btcjson.GetNetworkHashPSCmd{
   802  				Blocks: btcjson.Int(200),
   803  				Height: btcjson.Int(-1),
   804  			},
   805  		},
   806  		{
   807  			name: "getnetworkhashps optional2",
   808  			newCmd: func() (interface{}, error) {
   809  				return btcjson.NewCmd("getnetworkhashps", 200, 123)
   810  			},
   811  			staticCmd: func() interface{} {
   812  				return btcjson.NewGetNetworkHashPSCmd(btcjson.Int(200), btcjson.Int(123))
   813  			},
   814  			marshalled: `{"jsonrpc":"1.0","method":"getnetworkhashps","params":[200,123],"id":1}`,
   815  			unmarshalled: &btcjson.GetNetworkHashPSCmd{
   816  				Blocks: btcjson.Int(200),
   817  				Height: btcjson.Int(123),
   818  			},
   819  		},
   820  		{
   821  			name: "getnodeaddresses",
   822  			newCmd: func() (interface{}, error) {
   823  				return btcjson.NewCmd("getnodeaddresses")
   824  			},
   825  			staticCmd: func() interface{} {
   826  				return btcjson.NewGetNodeAddressesCmd(nil)
   827  			},
   828  			marshalled: `{"jsonrpc":"1.0","method":"getnodeaddresses","params":[],"id":1}`,
   829  			unmarshalled: &btcjson.GetNodeAddressesCmd{
   830  				Count: btcjson.Int32(1),
   831  			},
   832  		},
   833  		{
   834  			name: "getnodeaddresses optional",
   835  			newCmd: func() (interface{}, error) {
   836  				return btcjson.NewCmd("getnodeaddresses", 10)
   837  			},
   838  			staticCmd: func() interface{} {
   839  				return btcjson.NewGetNodeAddressesCmd(btcjson.Int32(10))
   840  			},
   841  			marshalled: `{"jsonrpc":"1.0","method":"getnodeaddresses","params":[10],"id":1}`,
   842  			unmarshalled: &btcjson.GetNodeAddressesCmd{
   843  				Count: btcjson.Int32(10),
   844  			},
   845  		},
   846  		{
   847  			name: "getpeerinfo",
   848  			newCmd: func() (interface{}, error) {
   849  				return btcjson.NewCmd("getpeerinfo")
   850  			},
   851  			staticCmd: func() interface{} {
   852  				return btcjson.NewGetPeerInfoCmd()
   853  			},
   854  			marshalled:   `{"jsonrpc":"1.0","method":"getpeerinfo","params":[],"id":1}`,
   855  			unmarshalled: &btcjson.GetPeerInfoCmd{},
   856  		},
   857  		{
   858  			name: "getrawmempool",
   859  			newCmd: func() (interface{}, error) {
   860  				return btcjson.NewCmd("getrawmempool")
   861  			},
   862  			staticCmd: func() interface{} {
   863  				return btcjson.NewGetRawMempoolCmd(nil)
   864  			},
   865  			marshalled: `{"jsonrpc":"1.0","method":"getrawmempool","params":[],"id":1}`,
   866  			unmarshalled: &btcjson.GetRawMempoolCmd{
   867  				Verbose: btcjson.Bool(false),
   868  			},
   869  		},
   870  		{
   871  			name: "getrawmempool optional",
   872  			newCmd: func() (interface{}, error) {
   873  				return btcjson.NewCmd("getrawmempool", false)
   874  			},
   875  			staticCmd: func() interface{} {
   876  				return btcjson.NewGetRawMempoolCmd(btcjson.Bool(false))
   877  			},
   878  			marshalled: `{"jsonrpc":"1.0","method":"getrawmempool","params":[false],"id":1}`,
   879  			unmarshalled: &btcjson.GetRawMempoolCmd{
   880  				Verbose: btcjson.Bool(false),
   881  			},
   882  		},
   883  		{
   884  			name: "getrawtransaction",
   885  			newCmd: func() (interface{}, error) {
   886  				return btcjson.NewCmd("getrawtransaction", "123")
   887  			},
   888  			staticCmd: func() interface{} {
   889  				return btcjson.NewGetRawTransactionCmd("123", nil)
   890  			},
   891  			marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123"],"id":1}`,
   892  			unmarshalled: &btcjson.GetRawTransactionCmd{
   893  				Txid:    "123",
   894  				Verbose: btcjson.Bool(false),
   895  			},
   896  		},
   897  		{
   898  			name: "getrawtransaction optional",
   899  			newCmd: func() (interface{}, error) {
   900  				return btcjson.NewCmd("getrawtransaction", "123", true)
   901  			},
   902  			staticCmd: func() interface{} {
   903  				return btcjson.NewGetRawTransactionCmd("123", btcjson.Bool(true))
   904  			},
   905  			marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123",true],"id":1}`,
   906  			unmarshalled: &btcjson.GetRawTransactionCmd{
   907  				Txid:    "123",
   908  				Verbose: btcjson.Bool(true),
   909  			},
   910  		},
   911  		{
   912  			name: "gettxout",
   913  			newCmd: func() (interface{}, error) {
   914  				return btcjson.NewCmd("gettxout", "123", 1)
   915  			},
   916  			staticCmd: func() interface{} {
   917  				return btcjson.NewGetTxOutCmd("123", 1, nil)
   918  			},
   919  			marshalled: `{"jsonrpc":"1.0","method":"gettxout","params":["123",1],"id":1}`,
   920  			unmarshalled: &btcjson.GetTxOutCmd{
   921  				Txid:           "123",
   922  				Vout:           1,
   923  				IncludeMempool: btcjson.Bool(true),
   924  			},
   925  		},
   926  		{
   927  			name: "gettxout optional",
   928  			newCmd: func() (interface{}, error) {
   929  				return btcjson.NewCmd("gettxout", "123", 1, true)
   930  			},
   931  			staticCmd: func() interface{} {
   932  				return btcjson.NewGetTxOutCmd("123", 1, btcjson.Bool(true))
   933  			},
   934  			marshalled: `{"jsonrpc":"1.0","method":"gettxout","params":["123",1,true],"id":1}`,
   935  			unmarshalled: &btcjson.GetTxOutCmd{
   936  				Txid:           "123",
   937  				Vout:           1,
   938  				IncludeMempool: btcjson.Bool(true),
   939  			},
   940  		},
   941  		{
   942  			name: "gettxoutproof",
   943  			newCmd: func() (interface{}, error) {
   944  				return btcjson.NewCmd("gettxoutproof", []string{"123", "456"})
   945  			},
   946  			staticCmd: func() interface{} {
   947  				return btcjson.NewGetTxOutProofCmd([]string{"123", "456"}, nil)
   948  			},
   949  			marshalled: `{"jsonrpc":"1.0","method":"gettxoutproof","params":[["123","456"]],"id":1}`,
   950  			unmarshalled: &btcjson.GetTxOutProofCmd{
   951  				TxIDs: []string{"123", "456"},
   952  			},
   953  		},
   954  		{
   955  			name: "gettxoutproof optional",
   956  			newCmd: func() (interface{}, error) {
   957  				return btcjson.NewCmd("gettxoutproof", []string{"123", "456"},
   958  					btcjson.String("000000000000034a7dedef4a161fa058a2d67a173a90155f3a2fe6fc132e0ebf"))
   959  			},
   960  			staticCmd: func() interface{} {
   961  				return btcjson.NewGetTxOutProofCmd([]string{"123", "456"},
   962  					btcjson.String("000000000000034a7dedef4a161fa058a2d67a173a90155f3a2fe6fc132e0ebf"))
   963  			},
   964  			marshalled: `{"jsonrpc":"1.0","method":"gettxoutproof","params":[["123","456"],` +
   965  				`"000000000000034a7dedef4a161fa058a2d67a173a90155f3a2fe6fc132e0ebf"],"id":1}`,
   966  			unmarshalled: &btcjson.GetTxOutProofCmd{
   967  				TxIDs:     []string{"123", "456"},
   968  				BlockHash: btcjson.String("000000000000034a7dedef4a161fa058a2d67a173a90155f3a2fe6fc132e0ebf"),
   969  			},
   970  		},
   971  		{
   972  			name: "gettxoutsetinfo",
   973  			newCmd: func() (interface{}, error) {
   974  				return btcjson.NewCmd("gettxoutsetinfo")
   975  			},
   976  			staticCmd: func() interface{} {
   977  				return btcjson.NewGetTxOutSetInfoCmd()
   978  			},
   979  			marshalled:   `{"jsonrpc":"1.0","method":"gettxoutsetinfo","params":[],"id":1}`,
   980  			unmarshalled: &btcjson.GetTxOutSetInfoCmd{},
   981  		},
   982  		{
   983  			name: "getwork",
   984  			newCmd: func() (interface{}, error) {
   985  				return btcjson.NewCmd("getwork")
   986  			},
   987  			staticCmd: func() interface{} {
   988  				return btcjson.NewGetWorkCmd(nil)
   989  			},
   990  			marshalled: `{"jsonrpc":"1.0","method":"getwork","params":[],"id":1}`,
   991  			unmarshalled: &btcjson.GetWorkCmd{
   992  				Data: nil,
   993  			},
   994  		},
   995  		{
   996  			name: "getwork optional",
   997  			newCmd: func() (interface{}, error) {
   998  				return btcjson.NewCmd("getwork", "00112233")
   999  			},
  1000  			staticCmd: func() interface{} {
  1001  				return btcjson.NewGetWorkCmd(btcjson.String("00112233"))
  1002  			},
  1003  			marshalled: `{"jsonrpc":"1.0","method":"getwork","params":["00112233"],"id":1}`,
  1004  			unmarshalled: &btcjson.GetWorkCmd{
  1005  				Data: btcjson.String("00112233"),
  1006  			},
  1007  		},
  1008  		{
  1009  			name: "help",
  1010  			newCmd: func() (interface{}, error) {
  1011  				return btcjson.NewCmd("help")
  1012  			},
  1013  			staticCmd: func() interface{} {
  1014  				return btcjson.NewHelpCmd(nil)
  1015  			},
  1016  			marshalled: `{"jsonrpc":"1.0","method":"help","params":[],"id":1}`,
  1017  			unmarshalled: &btcjson.HelpCmd{
  1018  				Command: nil,
  1019  			},
  1020  		},
  1021  		{
  1022  			name: "help optional",
  1023  			newCmd: func() (interface{}, error) {
  1024  				return btcjson.NewCmd("help", "getblock")
  1025  			},
  1026  			staticCmd: func() interface{} {
  1027  				return btcjson.NewHelpCmd(btcjson.String("getblock"))
  1028  			},
  1029  			marshalled: `{"jsonrpc":"1.0","method":"help","params":["getblock"],"id":1}`,
  1030  			unmarshalled: &btcjson.HelpCmd{
  1031  				Command: btcjson.String("getblock"),
  1032  			},
  1033  		},
  1034  		{
  1035  			name: "invalidateblock",
  1036  			newCmd: func() (interface{}, error) {
  1037  				return btcjson.NewCmd("invalidateblock", "123")
  1038  			},
  1039  			staticCmd: func() interface{} {
  1040  				return btcjson.NewInvalidateBlockCmd("123")
  1041  			},
  1042  			marshalled: `{"jsonrpc":"1.0","method":"invalidateblock","params":["123"],"id":1}`,
  1043  			unmarshalled: &btcjson.InvalidateBlockCmd{
  1044  				BlockHash: "123",
  1045  			},
  1046  		},
  1047  		{
  1048  			name: "ping",
  1049  			newCmd: func() (interface{}, error) {
  1050  				return btcjson.NewCmd("ping")
  1051  			},
  1052  			staticCmd: func() interface{} {
  1053  				return btcjson.NewPingCmd()
  1054  			},
  1055  			marshalled:   `{"jsonrpc":"1.0","method":"ping","params":[],"id":1}`,
  1056  			unmarshalled: &btcjson.PingCmd{},
  1057  		},
  1058  		{
  1059  			name: "preciousblock",
  1060  			newCmd: func() (interface{}, error) {
  1061  				return btcjson.NewCmd("preciousblock", "0123")
  1062  			},
  1063  			staticCmd: func() interface{} {
  1064  				return btcjson.NewPreciousBlockCmd("0123")
  1065  			},
  1066  			marshalled: `{"jsonrpc":"1.0","method":"preciousblock","params":["0123"],"id":1}`,
  1067  			unmarshalled: &btcjson.PreciousBlockCmd{
  1068  				BlockHash: "0123",
  1069  			},
  1070  		},
  1071  		{
  1072  			name: "reconsiderblock",
  1073  			newCmd: func() (interface{}, error) {
  1074  				return btcjson.NewCmd("reconsiderblock", "123")
  1075  			},
  1076  			staticCmd: func() interface{} {
  1077  				return btcjson.NewReconsiderBlockCmd("123")
  1078  			},
  1079  			marshalled: `{"jsonrpc":"1.0","method":"reconsiderblock","params":["123"],"id":1}`,
  1080  			unmarshalled: &btcjson.ReconsiderBlockCmd{
  1081  				BlockHash: "123",
  1082  			},
  1083  		},
  1084  		{
  1085  			name: "searchrawtransactions",
  1086  			newCmd: func() (interface{}, error) {
  1087  				return btcjson.NewCmd("searchrawtransactions", "1Address")
  1088  			},
  1089  			staticCmd: func() interface{} {
  1090  				return btcjson.NewSearchRawTransactionsCmd("1Address", nil, nil, nil, nil, nil, nil)
  1091  			},
  1092  			marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address"],"id":1}`,
  1093  			unmarshalled: &btcjson.SearchRawTransactionsCmd{
  1094  				Address:     "1Address",
  1095  				Verbose:     btcjson.Int(1),
  1096  				Skip:        btcjson.Int(0),
  1097  				Count:       btcjson.Int(100),
  1098  				VinExtra:    btcjson.Int(0),
  1099  				Reverse:     btcjson.Bool(false),
  1100  				FilterAddrs: nil,
  1101  			},
  1102  		},
  1103  		{
  1104  			name: "searchrawtransactions",
  1105  			newCmd: func() (interface{}, error) {
  1106  				return btcjson.NewCmd("searchrawtransactions", "1Address", 0)
  1107  			},
  1108  			staticCmd: func() interface{} {
  1109  				return btcjson.NewSearchRawTransactionsCmd("1Address",
  1110  					btcjson.Int(0), nil, nil, nil, nil, nil)
  1111  			},
  1112  			marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0],"id":1}`,
  1113  			unmarshalled: &btcjson.SearchRawTransactionsCmd{
  1114  				Address:     "1Address",
  1115  				Verbose:     btcjson.Int(0),
  1116  				Skip:        btcjson.Int(0),
  1117  				Count:       btcjson.Int(100),
  1118  				VinExtra:    btcjson.Int(0),
  1119  				Reverse:     btcjson.Bool(false),
  1120  				FilterAddrs: nil,
  1121  			},
  1122  		},
  1123  		{
  1124  			name: "searchrawtransactions",
  1125  			newCmd: func() (interface{}, error) {
  1126  				return btcjson.NewCmd("searchrawtransactions", "1Address", 0, 5)
  1127  			},
  1128  			staticCmd: func() interface{} {
  1129  				return btcjson.NewSearchRawTransactionsCmd("1Address",
  1130  					btcjson.Int(0), btcjson.Int(5), nil, nil, nil, nil)
  1131  			},
  1132  			marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5],"id":1}`,
  1133  			unmarshalled: &btcjson.SearchRawTransactionsCmd{
  1134  				Address:     "1Address",
  1135  				Verbose:     btcjson.Int(0),
  1136  				Skip:        btcjson.Int(5),
  1137  				Count:       btcjson.Int(100),
  1138  				VinExtra:    btcjson.Int(0),
  1139  				Reverse:     btcjson.Bool(false),
  1140  				FilterAddrs: nil,
  1141  			},
  1142  		},
  1143  		{
  1144  			name: "searchrawtransactions",
  1145  			newCmd: func() (interface{}, error) {
  1146  				return btcjson.NewCmd("searchrawtransactions", "1Address", 0, 5, 10)
  1147  			},
  1148  			staticCmd: func() interface{} {
  1149  				return btcjson.NewSearchRawTransactionsCmd("1Address",
  1150  					btcjson.Int(0), btcjson.Int(5), btcjson.Int(10), nil, nil, nil)
  1151  			},
  1152  			marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5,10],"id":1}`,
  1153  			unmarshalled: &btcjson.SearchRawTransactionsCmd{
  1154  				Address:     "1Address",
  1155  				Verbose:     btcjson.Int(0),
  1156  				Skip:        btcjson.Int(5),
  1157  				Count:       btcjson.Int(10),
  1158  				VinExtra:    btcjson.Int(0),
  1159  				Reverse:     btcjson.Bool(false),
  1160  				FilterAddrs: nil,
  1161  			},
  1162  		},
  1163  		{
  1164  			name: "searchrawtransactions",
  1165  			newCmd: func() (interface{}, error) {
  1166  				return btcjson.NewCmd("searchrawtransactions", "1Address", 0, 5, 10, 1)
  1167  			},
  1168  			staticCmd: func() interface{} {
  1169  				return btcjson.NewSearchRawTransactionsCmd("1Address",
  1170  					btcjson.Int(0), btcjson.Int(5), btcjson.Int(10), btcjson.Int(1), nil, nil)
  1171  			},
  1172  			marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5,10,1],"id":1}`,
  1173  			unmarshalled: &btcjson.SearchRawTransactionsCmd{
  1174  				Address:     "1Address",
  1175  				Verbose:     btcjson.Int(0),
  1176  				Skip:        btcjson.Int(5),
  1177  				Count:       btcjson.Int(10),
  1178  				VinExtra:    btcjson.Int(1),
  1179  				Reverse:     btcjson.Bool(false),
  1180  				FilterAddrs: nil,
  1181  			},
  1182  		},
  1183  		{
  1184  			name: "searchrawtransactions",
  1185  			newCmd: func() (interface{}, error) {
  1186  				return btcjson.NewCmd("searchrawtransactions", "1Address", 0, 5, 10, 1, true)
  1187  			},
  1188  			staticCmd: func() interface{} {
  1189  				return btcjson.NewSearchRawTransactionsCmd("1Address",
  1190  					btcjson.Int(0), btcjson.Int(5), btcjson.Int(10), btcjson.Int(1), btcjson.Bool(true), nil)
  1191  			},
  1192  			marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5,10,1,true],"id":1}`,
  1193  			unmarshalled: &btcjson.SearchRawTransactionsCmd{
  1194  				Address:     "1Address",
  1195  				Verbose:     btcjson.Int(0),
  1196  				Skip:        btcjson.Int(5),
  1197  				Count:       btcjson.Int(10),
  1198  				VinExtra:    btcjson.Int(1),
  1199  				Reverse:     btcjson.Bool(true),
  1200  				FilterAddrs: nil,
  1201  			},
  1202  		},
  1203  		{
  1204  			name: "searchrawtransactions",
  1205  			newCmd: func() (interface{}, error) {
  1206  				return btcjson.NewCmd("searchrawtransactions", "1Address", 0, 5, 10, 1, true, []string{"1Address"})
  1207  			},
  1208  			staticCmd: func() interface{} {
  1209  				return btcjson.NewSearchRawTransactionsCmd("1Address",
  1210  					btcjson.Int(0), btcjson.Int(5), btcjson.Int(10), btcjson.Int(1), btcjson.Bool(true), &[]string{"1Address"})
  1211  			},
  1212  			marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5,10,1,true,["1Address"]],"id":1}`,
  1213  			unmarshalled: &btcjson.SearchRawTransactionsCmd{
  1214  				Address:     "1Address",
  1215  				Verbose:     btcjson.Int(0),
  1216  				Skip:        btcjson.Int(5),
  1217  				Count:       btcjson.Int(10),
  1218  				VinExtra:    btcjson.Int(1),
  1219  				Reverse:     btcjson.Bool(true),
  1220  				FilterAddrs: &[]string{"1Address"},
  1221  			},
  1222  		},
  1223  		{
  1224  			name: "searchrawtransactions",
  1225  			newCmd: func() (interface{}, error) {
  1226  				return btcjson.NewCmd("searchrawtransactions", "1Address", 0, 5, 10, "null", true, []string{"1Address"})
  1227  			},
  1228  			staticCmd: func() interface{} {
  1229  				return btcjson.NewSearchRawTransactionsCmd("1Address",
  1230  					btcjson.Int(0), btcjson.Int(5), btcjson.Int(10), nil, btcjson.Bool(true), &[]string{"1Address"})
  1231  			},
  1232  			marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5,10,null,true,["1Address"]],"id":1}`,
  1233  			unmarshalled: &btcjson.SearchRawTransactionsCmd{
  1234  				Address:     "1Address",
  1235  				Verbose:     btcjson.Int(0),
  1236  				Skip:        btcjson.Int(5),
  1237  				Count:       btcjson.Int(10),
  1238  				VinExtra:    nil,
  1239  				Reverse:     btcjson.Bool(true),
  1240  				FilterAddrs: &[]string{"1Address"},
  1241  			},
  1242  		},
  1243  		{
  1244  			name: "sendrawtransaction",
  1245  			newCmd: func() (interface{}, error) {
  1246  				return btcjson.NewCmd("sendrawtransaction", "1122", &btcjson.AllowHighFeesOrMaxFeeRate{})
  1247  			},
  1248  			staticCmd: func() interface{} {
  1249  				return btcjson.NewSendRawTransactionCmd("1122", nil)
  1250  			},
  1251  			marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122",false],"id":1}`,
  1252  			unmarshalled: &btcjson.SendRawTransactionCmd{
  1253  				HexTx: "1122",
  1254  				FeeSetting: &btcjson.AllowHighFeesOrMaxFeeRate{
  1255  					Value: btcjson.Bool(false),
  1256  				},
  1257  			},
  1258  		},
  1259  		{
  1260  			name: "sendrawtransaction optional",
  1261  			newCmd: func() (interface{}, error) {
  1262  				return btcjson.NewCmd("sendrawtransaction", "1122", &btcjson.AllowHighFeesOrMaxFeeRate{Value: btcjson.Bool(false)})
  1263  			},
  1264  			staticCmd: func() interface{} {
  1265  				return btcjson.NewSendRawTransactionCmd("1122", btcjson.Bool(false))
  1266  			},
  1267  			marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122",false],"id":1}`,
  1268  			unmarshalled: &btcjson.SendRawTransactionCmd{
  1269  				HexTx: "1122",
  1270  				FeeSetting: &btcjson.AllowHighFeesOrMaxFeeRate{
  1271  					Value: btcjson.Bool(false),
  1272  				},
  1273  			},
  1274  		},
  1275  		{
  1276  			name: "sendrawtransaction optional, bitcoind >= 0.19.0",
  1277  			newCmd: func() (interface{}, error) {
  1278  				return btcjson.NewCmd("sendrawtransaction", "1122", &btcjson.AllowHighFeesOrMaxFeeRate{Value: btcjson.Int32(1234)})
  1279  			},
  1280  			staticCmd: func() interface{} {
  1281  				return btcjson.NewBitcoindSendRawTransactionCmd("1122", 1234)
  1282  			},
  1283  			marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122",1234],"id":1}`,
  1284  			unmarshalled: &btcjson.SendRawTransactionCmd{
  1285  				HexTx: "1122",
  1286  				FeeSetting: &btcjson.AllowHighFeesOrMaxFeeRate{
  1287  					Value: btcjson.Int32(1234),
  1288  				},
  1289  			},
  1290  		},
  1291  		{
  1292  			name: "setgenerate",
  1293  			newCmd: func() (interface{}, error) {
  1294  				return btcjson.NewCmd("setgenerate", true)
  1295  			},
  1296  			staticCmd: func() interface{} {
  1297  				return btcjson.NewSetGenerateCmd(true, nil)
  1298  			},
  1299  			marshalled: `{"jsonrpc":"1.0","method":"setgenerate","params":[true],"id":1}`,
  1300  			unmarshalled: &btcjson.SetGenerateCmd{
  1301  				Generate:     true,
  1302  				GenProcLimit: btcjson.Int(-1),
  1303  			},
  1304  		},
  1305  		{
  1306  			name: "setgenerate optional",
  1307  			newCmd: func() (interface{}, error) {
  1308  				return btcjson.NewCmd("setgenerate", true, 6)
  1309  			},
  1310  			staticCmd: func() interface{} {
  1311  				return btcjson.NewSetGenerateCmd(true, btcjson.Int(6))
  1312  			},
  1313  			marshalled: `{"jsonrpc":"1.0","method":"setgenerate","params":[true,6],"id":1}`,
  1314  			unmarshalled: &btcjson.SetGenerateCmd{
  1315  				Generate:     true,
  1316  				GenProcLimit: btcjson.Int(6),
  1317  			},
  1318  		},
  1319  		{
  1320  			name: "signmessagewithprivkey",
  1321  			newCmd: func() (interface{}, error) {
  1322  				return btcjson.NewCmd("signmessagewithprivkey", "5Hue", "Hey")
  1323  			},
  1324  			staticCmd: func() interface{} {
  1325  				return btcjson.NewSignMessageWithPrivKey("5Hue", "Hey")
  1326  			},
  1327  			marshalled: `{"jsonrpc":"1.0","method":"signmessagewithprivkey","params":["5Hue","Hey"],"id":1}`,
  1328  			unmarshalled: &btcjson.SignMessageWithPrivKeyCmd{
  1329  				PrivKey: "5Hue",
  1330  				Message: "Hey",
  1331  			},
  1332  		},
  1333  		{
  1334  			name: "stop",
  1335  			newCmd: func() (interface{}, error) {
  1336  				return btcjson.NewCmd("stop")
  1337  			},
  1338  			staticCmd: func() interface{} {
  1339  				return btcjson.NewStopCmd()
  1340  			},
  1341  			marshalled:   `{"jsonrpc":"1.0","method":"stop","params":[],"id":1}`,
  1342  			unmarshalled: &btcjson.StopCmd{},
  1343  		},
  1344  		{
  1345  			name: "submitblock",
  1346  			newCmd: func() (interface{}, error) {
  1347  				return btcjson.NewCmd("submitblock", "112233")
  1348  			},
  1349  			staticCmd: func() interface{} {
  1350  				return btcjson.NewSubmitBlockCmd("112233", nil)
  1351  			},
  1352  			marshalled: `{"jsonrpc":"1.0","method":"submitblock","params":["112233"],"id":1}`,
  1353  			unmarshalled: &btcjson.SubmitBlockCmd{
  1354  				HexBlock: "112233",
  1355  				Options:  nil,
  1356  			},
  1357  		},
  1358  		{
  1359  			name: "submitblock optional",
  1360  			newCmd: func() (interface{}, error) {
  1361  				return btcjson.NewCmd("submitblock", "112233", `{"workid":"12345"}`)
  1362  			},
  1363  			staticCmd: func() interface{} {
  1364  				options := btcjson.SubmitBlockOptions{
  1365  					WorkID: "12345",
  1366  				}
  1367  				return btcjson.NewSubmitBlockCmd("112233", &options)
  1368  			},
  1369  			marshalled: `{"jsonrpc":"1.0","method":"submitblock","params":["112233",{"workid":"12345"}],"id":1}`,
  1370  			unmarshalled: &btcjson.SubmitBlockCmd{
  1371  				HexBlock: "112233",
  1372  				Options: &btcjson.SubmitBlockOptions{
  1373  					WorkID: "12345",
  1374  				},
  1375  			},
  1376  		},
  1377  		{
  1378  			name: "uptime",
  1379  			newCmd: func() (interface{}, error) {
  1380  				return btcjson.NewCmd("uptime")
  1381  			},
  1382  			staticCmd: func() interface{} {
  1383  				return btcjson.NewUptimeCmd()
  1384  			},
  1385  			marshalled:   `{"jsonrpc":"1.0","method":"uptime","params":[],"id":1}`,
  1386  			unmarshalled: &btcjson.UptimeCmd{},
  1387  		},
  1388  		{
  1389  			name: "validateaddress",
  1390  			newCmd: func() (interface{}, error) {
  1391  				return btcjson.NewCmd("validateaddress", "1Address")
  1392  			},
  1393  			staticCmd: func() interface{} {
  1394  				return btcjson.NewValidateAddressCmd("1Address")
  1395  			},
  1396  			marshalled: `{"jsonrpc":"1.0","method":"validateaddress","params":["1Address"],"id":1}`,
  1397  			unmarshalled: &btcjson.ValidateAddressCmd{
  1398  				Address: "1Address",
  1399  			},
  1400  		},
  1401  		{
  1402  			name: "verifychain",
  1403  			newCmd: func() (interface{}, error) {
  1404  				return btcjson.NewCmd("verifychain")
  1405  			},
  1406  			staticCmd: func() interface{} {
  1407  				return btcjson.NewVerifyChainCmd(nil, nil)
  1408  			},
  1409  			marshalled: `{"jsonrpc":"1.0","method":"verifychain","params":[],"id":1}`,
  1410  			unmarshalled: &btcjson.VerifyChainCmd{
  1411  				CheckLevel: btcjson.Int32(3),
  1412  				CheckDepth: btcjson.Int32(288),
  1413  			},
  1414  		},
  1415  		{
  1416  			name: "verifychain optional1",
  1417  			newCmd: func() (interface{}, error) {
  1418  				return btcjson.NewCmd("verifychain", 2)
  1419  			},
  1420  			staticCmd: func() interface{} {
  1421  				return btcjson.NewVerifyChainCmd(btcjson.Int32(2), nil)
  1422  			},
  1423  			marshalled: `{"jsonrpc":"1.0","method":"verifychain","params":[2],"id":1}`,
  1424  			unmarshalled: &btcjson.VerifyChainCmd{
  1425  				CheckLevel: btcjson.Int32(2),
  1426  				CheckDepth: btcjson.Int32(288),
  1427  			},
  1428  		},
  1429  		{
  1430  			name: "verifychain optional2",
  1431  			newCmd: func() (interface{}, error) {
  1432  				return btcjson.NewCmd("verifychain", 2, 500)
  1433  			},
  1434  			staticCmd: func() interface{} {
  1435  				return btcjson.NewVerifyChainCmd(btcjson.Int32(2), btcjson.Int32(500))
  1436  			},
  1437  			marshalled: `{"jsonrpc":"1.0","method":"verifychain","params":[2,500],"id":1}`,
  1438  			unmarshalled: &btcjson.VerifyChainCmd{
  1439  				CheckLevel: btcjson.Int32(2),
  1440  				CheckDepth: btcjson.Int32(500),
  1441  			},
  1442  		},
  1443  		{
  1444  			name: "verifymessage",
  1445  			newCmd: func() (interface{}, error) {
  1446  				return btcjson.NewCmd("verifymessage", "1Address", "301234", "test")
  1447  			},
  1448  			staticCmd: func() interface{} {
  1449  				return btcjson.NewVerifyMessageCmd("1Address", "301234", "test")
  1450  			},
  1451  			marshalled: `{"jsonrpc":"1.0","method":"verifymessage","params":["1Address","301234","test"],"id":1}`,
  1452  			unmarshalled: &btcjson.VerifyMessageCmd{
  1453  				Address:   "1Address",
  1454  				Signature: "301234",
  1455  				Message:   "test",
  1456  			},
  1457  		},
  1458  		{
  1459  			name: "verifytxoutproof",
  1460  			newCmd: func() (interface{}, error) {
  1461  				return btcjson.NewCmd("verifytxoutproof", "test")
  1462  			},
  1463  			staticCmd: func() interface{} {
  1464  				return btcjson.NewVerifyTxOutProofCmd("test")
  1465  			},
  1466  			marshalled: `{"jsonrpc":"1.0","method":"verifytxoutproof","params":["test"],"id":1}`,
  1467  			unmarshalled: &btcjson.VerifyTxOutProofCmd{
  1468  				Proof: "test",
  1469  			},
  1470  		},
  1471  		{
  1472  			name: "getdescriptorinfo",
  1473  			newCmd: func() (interface{}, error) {
  1474  				return btcjson.NewCmd("getdescriptorinfo", "123")
  1475  			},
  1476  			staticCmd: func() interface{} {
  1477  				return btcjson.NewGetDescriptorInfoCmd("123")
  1478  			},
  1479  			marshalled:   `{"jsonrpc":"1.0","method":"getdescriptorinfo","params":["123"],"id":1}`,
  1480  			unmarshalled: &btcjson.GetDescriptorInfoCmd{Descriptor: "123"},
  1481  		},
  1482  	}
  1483  
  1484  	t.Logf("Running %d tests", len(tests))
  1485  	for i, test := range tests {
  1486  		// Marshal the command as created by the new static command
  1487  		// creation function.
  1488  		marshalled, err := btcjson.MarshalCmd(btcjson.RpcVersion1, testID, test.staticCmd())
  1489  		if err != nil {
  1490  			t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
  1491  				test.name, err)
  1492  			continue
  1493  		}
  1494  
  1495  		if !bytes.Equal(marshalled, []byte(test.marshalled)) {
  1496  			t.Errorf("Test #%d (%s) unexpected marshalled data - "+
  1497  				"got %s, want %s", i, test.name, marshalled,
  1498  				test.marshalled)
  1499  			t.Errorf("\n%s\n%s", marshalled, test.marshalled)
  1500  			continue
  1501  		}
  1502  
  1503  		// Ensure the command is created without error via the generic
  1504  		// new command creation function.
  1505  		cmd, err := test.newCmd()
  1506  		if err != nil {
  1507  			t.Errorf("Test #%d (%s) unexpected NewCmd error: %v ",
  1508  				i, test.name, err)
  1509  		}
  1510  
  1511  		// Marshal the command as created by the generic new command
  1512  		// creation function.
  1513  		marshalled, err = btcjson.MarshalCmd(btcjson.RpcVersion1, testID, cmd)
  1514  		if err != nil {
  1515  			t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
  1516  				test.name, err)
  1517  			continue
  1518  		}
  1519  
  1520  		if !bytes.Equal(marshalled, []byte(test.marshalled)) {
  1521  			t.Errorf("Test #%d (%s) unexpected marshalled data - "+
  1522  				"got %s, want %s", i, test.name, marshalled,
  1523  				test.marshalled)
  1524  			continue
  1525  		}
  1526  
  1527  		var request btcjson.Request
  1528  		if err := json.Unmarshal(marshalled, &request); err != nil {
  1529  			t.Errorf("Test #%d (%s) unexpected error while "+
  1530  				"unmarshalling JSON-RPC request: %v", i,
  1531  				test.name, err)
  1532  			continue
  1533  		}
  1534  
  1535  		cmd, err = btcjson.UnmarshalCmd(&request)
  1536  		if err != nil {
  1537  			t.Errorf("UnmarshalCmd #%d (%s) unexpected error: %v", i,
  1538  				test.name, err)
  1539  			continue
  1540  		}
  1541  
  1542  		if !reflect.DeepEqual(cmd, test.unmarshalled) {
  1543  			t.Errorf("Test #%d (%s) unexpected unmarshalled command "+
  1544  				"- got %s, want %s", i, test.name,
  1545  				fmt.Sprintf("(%T) %+[1]v", cmd),
  1546  				fmt.Sprintf("(%T) %+[1]v\n", test.unmarshalled))
  1547  			continue
  1548  		}
  1549  	}
  1550  }
  1551  
  1552  // TestChainSvrCmdErrors ensures any errors that occur in the command during
  1553  // custom mashal and unmarshal are as expected.
  1554  func TestChainSvrCmdErrors(t *testing.T) {
  1555  	t.Parallel()
  1556  
  1557  	tests := []struct {
  1558  		name       string
  1559  		result     interface{}
  1560  		marshalled string
  1561  		err        error
  1562  	}{
  1563  		{
  1564  			name:       "template request with invalid type",
  1565  			result:     &btcjson.TemplateRequest{},
  1566  			marshalled: `{"mode":1}`,
  1567  			err:        &json.UnmarshalTypeError{},
  1568  		},
  1569  		{
  1570  			name:       "invalid template request sigoplimit field",
  1571  			result:     &btcjson.TemplateRequest{},
  1572  			marshalled: `{"sigoplimit":"invalid"}`,
  1573  			err:        btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
  1574  		},
  1575  		{
  1576  			name:       "invalid template request sizelimit field",
  1577  			result:     &btcjson.TemplateRequest{},
  1578  			marshalled: `{"sizelimit":"invalid"}`,
  1579  			err:        btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
  1580  		},
  1581  	}
  1582  
  1583  	t.Logf("Running %d tests", len(tests))
  1584  	for i, test := range tests {
  1585  		err := json.Unmarshal([]byte(test.marshalled), &test.result)
  1586  		if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
  1587  			t.Errorf("Test #%d (%s) wrong error - got %T (%v), "+
  1588  				"want %T", i, test.name, err, err, test.err)
  1589  			continue
  1590  		}
  1591  
  1592  		if terr, ok := test.err.(btcjson.Error); ok {
  1593  			gotErrorCode := err.(btcjson.Error).ErrorCode
  1594  			if gotErrorCode != terr.ErrorCode {
  1595  				t.Errorf("Test #%d (%s) mismatched error code "+
  1596  					"- got %v (%v), want %v", i, test.name,
  1597  					gotErrorCode, terr, terr.ErrorCode)
  1598  				continue
  1599  			}
  1600  		}
  1601  	}
  1602  }