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