github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/btcjson/chainsvrcmds_test.go (about)

     1  // Copyright (c) 2014 The btcsuite developers
     2  // Copyright (c) 2016 The Dash developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package btcjson_test
     7  
     8  import (
     9  	"bytes"
    10  	"encoding/json"
    11  	"fmt"
    12  	"reflect"
    13  	"testing"
    14  
    15  	"github.com/BlockABC/godash/btcjson"
    16  )
    17  
    18  // TestChainSvrCmds tests all of the chain server commands marshal and unmarshal
    19  // into valid results include handling of optional fields being omitted in the
    20  // marshalled command, while optional fields with defaults have the default
    21  // assigned on unmarshalled commands.
    22  func TestChainSvrCmds(t *testing.T) {
    23  	t.Parallel()
    24  
    25  	testID := int(1)
    26  	tests := []struct {
    27  		name         string
    28  		newCmd       func() (interface{}, error)
    29  		staticCmd    func() interface{}
    30  		marshalled   string
    31  		unmarshalled interface{}
    32  	}{
    33  		{
    34  			name: "addnode",
    35  			newCmd: func() (interface{}, error) {
    36  				return btcjson.NewCmd("addnode", "127.0.0.1", btcjson.ANRemove)
    37  			},
    38  			staticCmd: func() interface{} {
    39  				return btcjson.NewAddNodeCmd("127.0.0.1", btcjson.ANRemove)
    40  			},
    41  			marshalled:   `{"jsonrpc":"1.0","method":"addnode","params":["127.0.0.1","remove"],"id":1}`,
    42  			unmarshalled: &btcjson.AddNodeCmd{Addr: "127.0.0.1", SubCmd: btcjson.ANRemove},
    43  		},
    44  		{
    45  			name: "createrawtransaction",
    46  			newCmd: func() (interface{}, error) {
    47  				return btcjson.NewCmd("createrawtransaction", `[{"txid":"123","vout":1}]`,
    48  					`{"456":0.0123}`)
    49  			},
    50  			staticCmd: func() interface{} {
    51  				txInputs := []btcjson.TransactionInput{
    52  					{Txid: "123", Vout: 1},
    53  				}
    54  				amounts := map[string]float64{"456": .0123}
    55  				return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, nil)
    56  			},
    57  			marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123}],"id":1}`,
    58  			unmarshalled: &btcjson.CreateRawTransactionCmd{
    59  				Inputs:  []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
    60  				Amounts: map[string]float64{"456": .0123},
    61  			},
    62  		},
    63  		{
    64  			name: "createrawtransaction optional",
    65  			newCmd: func() (interface{}, error) {
    66  				return btcjson.NewCmd("createrawtransaction", `[{"txid":"123","vout":1}]`,
    67  					`{"456":0.0123}`, int64(12312333333))
    68  			},
    69  			staticCmd: func() interface{} {
    70  				txInputs := []btcjson.TransactionInput{
    71  					{Txid: "123", Vout: 1},
    72  				}
    73  				amounts := map[string]float64{"456": .0123}
    74  				return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, btcjson.Int64(12312333333))
    75  			},
    76  			marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123},12312333333],"id":1}`,
    77  			unmarshalled: &btcjson.CreateRawTransactionCmd{
    78  				Inputs:   []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
    79  				Amounts:  map[string]float64{"456": .0123},
    80  				LockTime: btcjson.Int64(12312333333),
    81  			},
    82  		},
    83  
    84  		{
    85  			name: "decoderawtransaction",
    86  			newCmd: func() (interface{}, error) {
    87  				return btcjson.NewCmd("decoderawtransaction", "123")
    88  			},
    89  			staticCmd: func() interface{} {
    90  				return btcjson.NewDecodeRawTransactionCmd("123")
    91  			},
    92  			marshalled:   `{"jsonrpc":"1.0","method":"decoderawtransaction","params":["123"],"id":1}`,
    93  			unmarshalled: &btcjson.DecodeRawTransactionCmd{HexTx: "123"},
    94  		},
    95  		{
    96  			name: "decodescript",
    97  			newCmd: func() (interface{}, error) {
    98  				return btcjson.NewCmd("decodescript", "00")
    99  			},
   100  			staticCmd: func() interface{} {
   101  				return btcjson.NewDecodeScriptCmd("00")
   102  			},
   103  			marshalled:   `{"jsonrpc":"1.0","method":"decodescript","params":["00"],"id":1}`,
   104  			unmarshalled: &btcjson.DecodeScriptCmd{HexScript: "00"},
   105  		},
   106  		{
   107  			name: "getaddednodeinfo",
   108  			newCmd: func() (interface{}, error) {
   109  				return btcjson.NewCmd("getaddednodeinfo", true)
   110  			},
   111  			staticCmd: func() interface{} {
   112  				return btcjson.NewGetAddedNodeInfoCmd(true, nil)
   113  			},
   114  			marshalled:   `{"jsonrpc":"1.0","method":"getaddednodeinfo","params":[true],"id":1}`,
   115  			unmarshalled: &btcjson.GetAddedNodeInfoCmd{DNS: true, Node: nil},
   116  		},
   117  		{
   118  			name: "getaddednodeinfo optional",
   119  			newCmd: func() (interface{}, error) {
   120  				return btcjson.NewCmd("getaddednodeinfo", true, "127.0.0.1")
   121  			},
   122  			staticCmd: func() interface{} {
   123  				return btcjson.NewGetAddedNodeInfoCmd(true, btcjson.String("127.0.0.1"))
   124  			},
   125  			marshalled: `{"jsonrpc":"1.0","method":"getaddednodeinfo","params":[true,"127.0.0.1"],"id":1}`,
   126  			unmarshalled: &btcjson.GetAddedNodeInfoCmd{
   127  				DNS:  true,
   128  				Node: btcjson.String("127.0.0.1"),
   129  			},
   130  		},
   131  		{
   132  			name: "getbestblockhash",
   133  			newCmd: func() (interface{}, error) {
   134  				return btcjson.NewCmd("getbestblockhash")
   135  			},
   136  			staticCmd: func() interface{} {
   137  				return btcjson.NewGetBestBlockHashCmd()
   138  			},
   139  			marshalled:   `{"jsonrpc":"1.0","method":"getbestblockhash","params":[],"id":1}`,
   140  			unmarshalled: &btcjson.GetBestBlockHashCmd{},
   141  		},
   142  		{
   143  			name: "getblock",
   144  			newCmd: func() (interface{}, error) {
   145  				return btcjson.NewCmd("getblock", "123")
   146  			},
   147  			staticCmd: func() interface{} {
   148  				return btcjson.NewGetBlockCmd("123", nil, nil)
   149  			},
   150  			marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123"],"id":1}`,
   151  			unmarshalled: &btcjson.GetBlockCmd{
   152  				Hash:      "123",
   153  				Verbose:   btcjson.Bool(true),
   154  				VerboseTx: btcjson.Bool(false),
   155  			},
   156  		},
   157  		{
   158  			name: "getblock required optional1",
   159  			newCmd: func() (interface{}, error) {
   160  				// Intentionally use a source param that is
   161  				// more pointers than the destination to
   162  				// exercise that path.
   163  				verbosePtr := btcjson.Bool(true)
   164  				return btcjson.NewCmd("getblock", "123", &verbosePtr)
   165  			},
   166  			staticCmd: func() interface{} {
   167  				return btcjson.NewGetBlockCmd("123", btcjson.Bool(true), nil)
   168  			},
   169  			marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",true],"id":1}`,
   170  			unmarshalled: &btcjson.GetBlockCmd{
   171  				Hash:      "123",
   172  				Verbose:   btcjson.Bool(true),
   173  				VerboseTx: btcjson.Bool(false),
   174  			},
   175  		},
   176  		{
   177  			name: "getblock required optional2",
   178  			newCmd: func() (interface{}, error) {
   179  				return btcjson.NewCmd("getblock", "123", true, true)
   180  			},
   181  			staticCmd: func() interface{} {
   182  				return btcjson.NewGetBlockCmd("123", btcjson.Bool(true), btcjson.Bool(true))
   183  			},
   184  			marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",true,true],"id":1}`,
   185  			unmarshalled: &btcjson.GetBlockCmd{
   186  				Hash:      "123",
   187  				Verbose:   btcjson.Bool(true),
   188  				VerboseTx: btcjson.Bool(true),
   189  			},
   190  		},
   191  		{
   192  			name: "getblockchaininfo",
   193  			newCmd: func() (interface{}, error) {
   194  				return btcjson.NewCmd("getblockchaininfo")
   195  			},
   196  			staticCmd: func() interface{} {
   197  				return btcjson.NewGetBlockChainInfoCmd()
   198  			},
   199  			marshalled:   `{"jsonrpc":"1.0","method":"getblockchaininfo","params":[],"id":1}`,
   200  			unmarshalled: &btcjson.GetBlockChainInfoCmd{},
   201  		},
   202  		{
   203  			name: "getblockcount",
   204  			newCmd: func() (interface{}, error) {
   205  				return btcjson.NewCmd("getblockcount")
   206  			},
   207  			staticCmd: func() interface{} {
   208  				return btcjson.NewGetBlockCountCmd()
   209  			},
   210  			marshalled:   `{"jsonrpc":"1.0","method":"getblockcount","params":[],"id":1}`,
   211  			unmarshalled: &btcjson.GetBlockCountCmd{},
   212  		},
   213  		{
   214  			name: "getblockhash",
   215  			newCmd: func() (interface{}, error) {
   216  				return btcjson.NewCmd("getblockhash", 123)
   217  			},
   218  			staticCmd: func() interface{} {
   219  				return btcjson.NewGetBlockHashCmd(123)
   220  			},
   221  			marshalled:   `{"jsonrpc":"1.0","method":"getblockhash","params":[123],"id":1}`,
   222  			unmarshalled: &btcjson.GetBlockHashCmd{Index: 123},
   223  		},
   224  		{
   225  			name: "getblockheader",
   226  			newCmd: func() (interface{}, error) {
   227  				return btcjson.NewCmd("getblockheader", "123")
   228  			},
   229  			staticCmd: func() interface{} {
   230  				return btcjson.NewGetBlockHeaderCmd("123", nil)
   231  			},
   232  			marshalled: `{"jsonrpc":"1.0","method":"getblockheader","params":["123"],"id":1}`,
   233  			unmarshalled: &btcjson.GetBlockHeaderCmd{
   234  				Hash:    "123",
   235  				Verbose: btcjson.Bool(true),
   236  			},
   237  		},
   238  		{
   239  			name: "getblocktemplate",
   240  			newCmd: func() (interface{}, error) {
   241  				return btcjson.NewCmd("getblocktemplate")
   242  			},
   243  			staticCmd: func() interface{} {
   244  				return btcjson.NewGetBlockTemplateCmd(nil)
   245  			},
   246  			marshalled:   `{"jsonrpc":"1.0","method":"getblocktemplate","params":[],"id":1}`,
   247  			unmarshalled: &btcjson.GetBlockTemplateCmd{Request: nil},
   248  		},
   249  		{
   250  			name: "getblocktemplate optional - template request",
   251  			newCmd: func() (interface{}, error) {
   252  				return btcjson.NewCmd("getblocktemplate", `{"mode":"template","capabilities":["longpoll","coinbasetxn"]}`)
   253  			},
   254  			staticCmd: func() interface{} {
   255  				template := btcjson.TemplateRequest{
   256  					Mode:         "template",
   257  					Capabilities: []string{"longpoll", "coinbasetxn"},
   258  				}
   259  				return btcjson.NewGetBlockTemplateCmd(&template)
   260  			},
   261  			marshalled: `{"jsonrpc":"1.0","method":"getblocktemplate","params":[{"mode":"template","capabilities":["longpoll","coinbasetxn"]}],"id":1}`,
   262  			unmarshalled: &btcjson.GetBlockTemplateCmd{
   263  				Request: &btcjson.TemplateRequest{
   264  					Mode:         "template",
   265  					Capabilities: []string{"longpoll", "coinbasetxn"},
   266  				},
   267  			},
   268  		},
   269  		{
   270  			name: "getblocktemplate optional - template request with tweaks",
   271  			newCmd: func() (interface{}, error) {
   272  				return btcjson.NewCmd("getblocktemplate", `{"mode":"template","capabilities":["longpoll","coinbasetxn"],"sigoplimit":500,"sizelimit":100000000,"maxversion":2}`)
   273  			},
   274  			staticCmd: func() interface{} {
   275  				template := btcjson.TemplateRequest{
   276  					Mode:         "template",
   277  					Capabilities: []string{"longpoll", "coinbasetxn"},
   278  					SigOpLimit:   500,
   279  					SizeLimit:    100000000,
   280  					MaxVersion:   2,
   281  				}
   282  				return btcjson.NewGetBlockTemplateCmd(&template)
   283  			},
   284  			marshalled: `{"jsonrpc":"1.0","method":"getblocktemplate","params":[{"mode":"template","capabilities":["longpoll","coinbasetxn"],"sigoplimit":500,"sizelimit":100000000,"maxversion":2}],"id":1}`,
   285  			unmarshalled: &btcjson.GetBlockTemplateCmd{
   286  				Request: &btcjson.TemplateRequest{
   287  					Mode:         "template",
   288  					Capabilities: []string{"longpoll", "coinbasetxn"},
   289  					SigOpLimit:   int64(500),
   290  					SizeLimit:    int64(100000000),
   291  					MaxVersion:   2,
   292  				},
   293  			},
   294  		},
   295  		{
   296  			name: "getblocktemplate optional - template request with tweaks 2",
   297  			newCmd: func() (interface{}, error) {
   298  				return btcjson.NewCmd("getblocktemplate", `{"mode":"template","capabilities":["longpoll","coinbasetxn"],"sigoplimit":true,"sizelimit":100000000,"maxversion":2}`)
   299  			},
   300  			staticCmd: func() interface{} {
   301  				template := btcjson.TemplateRequest{
   302  					Mode:         "template",
   303  					Capabilities: []string{"longpoll", "coinbasetxn"},
   304  					SigOpLimit:   true,
   305  					SizeLimit:    100000000,
   306  					MaxVersion:   2,
   307  				}
   308  				return btcjson.NewGetBlockTemplateCmd(&template)
   309  			},
   310  			marshalled: `{"jsonrpc":"1.0","method":"getblocktemplate","params":[{"mode":"template","capabilities":["longpoll","coinbasetxn"],"sigoplimit":true,"sizelimit":100000000,"maxversion":2}],"id":1}`,
   311  			unmarshalled: &btcjson.GetBlockTemplateCmd{
   312  				Request: &btcjson.TemplateRequest{
   313  					Mode:         "template",
   314  					Capabilities: []string{"longpoll", "coinbasetxn"},
   315  					SigOpLimit:   true,
   316  					SizeLimit:    int64(100000000),
   317  					MaxVersion:   2,
   318  				},
   319  			},
   320  		},
   321  		{
   322  			name: "getchaintips",
   323  			newCmd: func() (interface{}, error) {
   324  				return btcjson.NewCmd("getchaintips")
   325  			},
   326  			staticCmd: func() interface{} {
   327  				return btcjson.NewGetChainTipsCmd()
   328  			},
   329  			marshalled:   `{"jsonrpc":"1.0","method":"getchaintips","params":[],"id":1}`,
   330  			unmarshalled: &btcjson.GetChainTipsCmd{},
   331  		},
   332  		{
   333  			name: "getconnectioncount",
   334  			newCmd: func() (interface{}, error) {
   335  				return btcjson.NewCmd("getconnectioncount")
   336  			},
   337  			staticCmd: func() interface{} {
   338  				return btcjson.NewGetConnectionCountCmd()
   339  			},
   340  			marshalled:   `{"jsonrpc":"1.0","method":"getconnectioncount","params":[],"id":1}`,
   341  			unmarshalled: &btcjson.GetConnectionCountCmd{},
   342  		},
   343  		{
   344  			name: "getdifficulty",
   345  			newCmd: func() (interface{}, error) {
   346  				return btcjson.NewCmd("getdifficulty")
   347  			},
   348  			staticCmd: func() interface{} {
   349  				return btcjson.NewGetDifficultyCmd()
   350  			},
   351  			marshalled:   `{"jsonrpc":"1.0","method":"getdifficulty","params":[],"id":1}`,
   352  			unmarshalled: &btcjson.GetDifficultyCmd{},
   353  		},
   354  		{
   355  			name: "getgenerate",
   356  			newCmd: func() (interface{}, error) {
   357  				return btcjson.NewCmd("getgenerate")
   358  			},
   359  			staticCmd: func() interface{} {
   360  				return btcjson.NewGetGenerateCmd()
   361  			},
   362  			marshalled:   `{"jsonrpc":"1.0","method":"getgenerate","params":[],"id":1}`,
   363  			unmarshalled: &btcjson.GetGenerateCmd{},
   364  		},
   365  		{
   366  			name: "gethashespersec",
   367  			newCmd: func() (interface{}, error) {
   368  				return btcjson.NewCmd("gethashespersec")
   369  			},
   370  			staticCmd: func() interface{} {
   371  				return btcjson.NewGetHashesPerSecCmd()
   372  			},
   373  			marshalled:   `{"jsonrpc":"1.0","method":"gethashespersec","params":[],"id":1}`,
   374  			unmarshalled: &btcjson.GetHashesPerSecCmd{},
   375  		},
   376  		{
   377  			name: "getinfo",
   378  			newCmd: func() (interface{}, error) {
   379  				return btcjson.NewCmd("getinfo")
   380  			},
   381  			staticCmd: func() interface{} {
   382  				return btcjson.NewGetInfoCmd()
   383  			},
   384  			marshalled:   `{"jsonrpc":"1.0","method":"getinfo","params":[],"id":1}`,
   385  			unmarshalled: &btcjson.GetInfoCmd{},
   386  		},
   387  		{
   388  			name: "getmempoolinfo",
   389  			newCmd: func() (interface{}, error) {
   390  				return btcjson.NewCmd("getmempoolinfo")
   391  			},
   392  			staticCmd: func() interface{} {
   393  				return btcjson.NewGetMempoolInfoCmd()
   394  			},
   395  			marshalled:   `{"jsonrpc":"1.0","method":"getmempoolinfo","params":[],"id":1}`,
   396  			unmarshalled: &btcjson.GetMempoolInfoCmd{},
   397  		},
   398  		{
   399  			name: "getmininginfo",
   400  			newCmd: func() (interface{}, error) {
   401  				return btcjson.NewCmd("getmininginfo")
   402  			},
   403  			staticCmd: func() interface{} {
   404  				return btcjson.NewGetMiningInfoCmd()
   405  			},
   406  			marshalled:   `{"jsonrpc":"1.0","method":"getmininginfo","params":[],"id":1}`,
   407  			unmarshalled: &btcjson.GetMiningInfoCmd{},
   408  		},
   409  		{
   410  			name: "getnetworkinfo",
   411  			newCmd: func() (interface{}, error) {
   412  				return btcjson.NewCmd("getnetworkinfo")
   413  			},
   414  			staticCmd: func() interface{} {
   415  				return btcjson.NewGetNetworkInfoCmd()
   416  			},
   417  			marshalled:   `{"jsonrpc":"1.0","method":"getnetworkinfo","params":[],"id":1}`,
   418  			unmarshalled: &btcjson.GetNetworkInfoCmd{},
   419  		},
   420  		{
   421  			name: "getnettotals",
   422  			newCmd: func() (interface{}, error) {
   423  				return btcjson.NewCmd("getnettotals")
   424  			},
   425  			staticCmd: func() interface{} {
   426  				return btcjson.NewGetNetTotalsCmd()
   427  			},
   428  			marshalled:   `{"jsonrpc":"1.0","method":"getnettotals","params":[],"id":1}`,
   429  			unmarshalled: &btcjson.GetNetTotalsCmd{},
   430  		},
   431  		{
   432  			name: "getnetworkhashps",
   433  			newCmd: func() (interface{}, error) {
   434  				return btcjson.NewCmd("getnetworkhashps")
   435  			},
   436  			staticCmd: func() interface{} {
   437  				return btcjson.NewGetNetworkHashPSCmd(nil, nil)
   438  			},
   439  			marshalled: `{"jsonrpc":"1.0","method":"getnetworkhashps","params":[],"id":1}`,
   440  			unmarshalled: &btcjson.GetNetworkHashPSCmd{
   441  				Blocks: btcjson.Int(120),
   442  				Height: btcjson.Int(-1),
   443  			},
   444  		},
   445  		{
   446  			name: "getnetworkhashps optional1",
   447  			newCmd: func() (interface{}, error) {
   448  				return btcjson.NewCmd("getnetworkhashps", 200)
   449  			},
   450  			staticCmd: func() interface{} {
   451  				return btcjson.NewGetNetworkHashPSCmd(btcjson.Int(200), nil)
   452  			},
   453  			marshalled: `{"jsonrpc":"1.0","method":"getnetworkhashps","params":[200],"id":1}`,
   454  			unmarshalled: &btcjson.GetNetworkHashPSCmd{
   455  				Blocks: btcjson.Int(200),
   456  				Height: btcjson.Int(-1),
   457  			},
   458  		},
   459  		{
   460  			name: "getnetworkhashps optional2",
   461  			newCmd: func() (interface{}, error) {
   462  				return btcjson.NewCmd("getnetworkhashps", 200, 123)
   463  			},
   464  			staticCmd: func() interface{} {
   465  				return btcjson.NewGetNetworkHashPSCmd(btcjson.Int(200), btcjson.Int(123))
   466  			},
   467  			marshalled: `{"jsonrpc":"1.0","method":"getnetworkhashps","params":[200,123],"id":1}`,
   468  			unmarshalled: &btcjson.GetNetworkHashPSCmd{
   469  				Blocks: btcjson.Int(200),
   470  				Height: btcjson.Int(123),
   471  			},
   472  		},
   473  		{
   474  			name: "getpeerinfo",
   475  			newCmd: func() (interface{}, error) {
   476  				return btcjson.NewCmd("getpeerinfo")
   477  			},
   478  			staticCmd: func() interface{} {
   479  				return btcjson.NewGetPeerInfoCmd()
   480  			},
   481  			marshalled:   `{"jsonrpc":"1.0","method":"getpeerinfo","params":[],"id":1}`,
   482  			unmarshalled: &btcjson.GetPeerInfoCmd{},
   483  		},
   484  		{
   485  			name: "getrawmempool",
   486  			newCmd: func() (interface{}, error) {
   487  				return btcjson.NewCmd("getrawmempool")
   488  			},
   489  			staticCmd: func() interface{} {
   490  				return btcjson.NewGetRawMempoolCmd(nil)
   491  			},
   492  			marshalled: `{"jsonrpc":"1.0","method":"getrawmempool","params":[],"id":1}`,
   493  			unmarshalled: &btcjson.GetRawMempoolCmd{
   494  				Verbose: btcjson.Bool(false),
   495  			},
   496  		},
   497  		{
   498  			name: "getrawmempool optional",
   499  			newCmd: func() (interface{}, error) {
   500  				return btcjson.NewCmd("getrawmempool", false)
   501  			},
   502  			staticCmd: func() interface{} {
   503  				return btcjson.NewGetRawMempoolCmd(btcjson.Bool(false))
   504  			},
   505  			marshalled: `{"jsonrpc":"1.0","method":"getrawmempool","params":[false],"id":1}`,
   506  			unmarshalled: &btcjson.GetRawMempoolCmd{
   507  				Verbose: btcjson.Bool(false),
   508  			},
   509  		},
   510  		{
   511  			name: "getrawtransaction",
   512  			newCmd: func() (interface{}, error) {
   513  				return btcjson.NewCmd("getrawtransaction", "123")
   514  			},
   515  			staticCmd: func() interface{} {
   516  				return btcjson.NewGetRawTransactionCmd("123", nil)
   517  			},
   518  			marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123"],"id":1}`,
   519  			unmarshalled: &btcjson.GetRawTransactionCmd{
   520  				Txid:    "123",
   521  				Verbose: btcjson.Int(0),
   522  			},
   523  		},
   524  		{
   525  			name: "getrawtransaction optional",
   526  			newCmd: func() (interface{}, error) {
   527  				return btcjson.NewCmd("getrawtransaction", "123", 1)
   528  			},
   529  			staticCmd: func() interface{} {
   530  				return btcjson.NewGetRawTransactionCmd("123", btcjson.Int(1))
   531  			},
   532  			marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123",1],"id":1}`,
   533  			unmarshalled: &btcjson.GetRawTransactionCmd{
   534  				Txid:    "123",
   535  				Verbose: btcjson.Int(1),
   536  			},
   537  		},
   538  		{
   539  			name: "gettxout",
   540  			newCmd: func() (interface{}, error) {
   541  				return btcjson.NewCmd("gettxout", "123", 1)
   542  			},
   543  			staticCmd: func() interface{} {
   544  				return btcjson.NewGetTxOutCmd("123", 1, nil)
   545  			},
   546  			marshalled: `{"jsonrpc":"1.0","method":"gettxout","params":["123",1],"id":1}`,
   547  			unmarshalled: &btcjson.GetTxOutCmd{
   548  				Txid:           "123",
   549  				Vout:           1,
   550  				IncludeMempool: btcjson.Bool(true),
   551  			},
   552  		},
   553  		{
   554  			name: "gettxout optional",
   555  			newCmd: func() (interface{}, error) {
   556  				return btcjson.NewCmd("gettxout", "123", 1, true)
   557  			},
   558  			staticCmd: func() interface{} {
   559  				return btcjson.NewGetTxOutCmd("123", 1, btcjson.Bool(true))
   560  			},
   561  			marshalled: `{"jsonrpc":"1.0","method":"gettxout","params":["123",1,true],"id":1}`,
   562  			unmarshalled: &btcjson.GetTxOutCmd{
   563  				Txid:           "123",
   564  				Vout:           1,
   565  				IncludeMempool: btcjson.Bool(true),
   566  			},
   567  		},
   568  		{
   569  			name: "gettxoutproof",
   570  			newCmd: func() (interface{}, error) {
   571  				return btcjson.NewCmd("gettxoutproof", []string{"123", "456"})
   572  			},
   573  			staticCmd: func() interface{} {
   574  				return btcjson.NewGetTxOutProofCmd([]string{"123", "456"}, nil)
   575  			},
   576  			marshalled: `{"jsonrpc":"1.0","method":"gettxoutproof","params":[["123","456"]],"id":1}`,
   577  			unmarshalled: &btcjson.GetTxOutProofCmd{
   578  				TxIDs: []string{"123", "456"},
   579  			},
   580  		},
   581  		{
   582  			name: "gettxoutproof optional",
   583  			newCmd: func() (interface{}, error) {
   584  				return btcjson.NewCmd("gettxoutproof", []string{"123", "456"},
   585  					btcjson.String("000000000000034a7dedef4a161fa058a2d67a173a90155f3a2fe6fc132e0ebf"))
   586  			},
   587  			staticCmd: func() interface{} {
   588  				return btcjson.NewGetTxOutProofCmd([]string{"123", "456"},
   589  					btcjson.String("000000000000034a7dedef4a161fa058a2d67a173a90155f3a2fe6fc132e0ebf"))
   590  			},
   591  			marshalled: `{"jsonrpc":"1.0","method":"gettxoutproof","params":[["123","456"],` +
   592  				`"000000000000034a7dedef4a161fa058a2d67a173a90155f3a2fe6fc132e0ebf"],"id":1}`,
   593  			unmarshalled: &btcjson.GetTxOutProofCmd{
   594  				TxIDs:     []string{"123", "456"},
   595  				BlockHash: btcjson.String("000000000000034a7dedef4a161fa058a2d67a173a90155f3a2fe6fc132e0ebf"),
   596  			},
   597  		},
   598  		{
   599  			name: "gettxoutsetinfo",
   600  			newCmd: func() (interface{}, error) {
   601  				return btcjson.NewCmd("gettxoutsetinfo")
   602  			},
   603  			staticCmd: func() interface{} {
   604  				return btcjson.NewGetTxOutSetInfoCmd()
   605  			},
   606  			marshalled:   `{"jsonrpc":"1.0","method":"gettxoutsetinfo","params":[],"id":1}`,
   607  			unmarshalled: &btcjson.GetTxOutSetInfoCmd{},
   608  		},
   609  		{
   610  			name: "getwork",
   611  			newCmd: func() (interface{}, error) {
   612  				return btcjson.NewCmd("getwork")
   613  			},
   614  			staticCmd: func() interface{} {
   615  				return btcjson.NewGetWorkCmd(nil)
   616  			},
   617  			marshalled: `{"jsonrpc":"1.0","method":"getwork","params":[],"id":1}`,
   618  			unmarshalled: &btcjson.GetWorkCmd{
   619  				Data: nil,
   620  			},
   621  		},
   622  		{
   623  			name: "getwork optional",
   624  			newCmd: func() (interface{}, error) {
   625  				return btcjson.NewCmd("getwork", "00112233")
   626  			},
   627  			staticCmd: func() interface{} {
   628  				return btcjson.NewGetWorkCmd(btcjson.String("00112233"))
   629  			},
   630  			marshalled: `{"jsonrpc":"1.0","method":"getwork","params":["00112233"],"id":1}`,
   631  			unmarshalled: &btcjson.GetWorkCmd{
   632  				Data: btcjson.String("00112233"),
   633  			},
   634  		},
   635  		{
   636  			name: "help",
   637  			newCmd: func() (interface{}, error) {
   638  				return btcjson.NewCmd("help")
   639  			},
   640  			staticCmd: func() interface{} {
   641  				return btcjson.NewHelpCmd(nil)
   642  			},
   643  			marshalled: `{"jsonrpc":"1.0","method":"help","params":[],"id":1}`,
   644  			unmarshalled: &btcjson.HelpCmd{
   645  				Command: nil,
   646  			},
   647  		},
   648  		{
   649  			name: "help optional",
   650  			newCmd: func() (interface{}, error) {
   651  				return btcjson.NewCmd("help", "getblock")
   652  			},
   653  			staticCmd: func() interface{} {
   654  				return btcjson.NewHelpCmd(btcjson.String("getblock"))
   655  			},
   656  			marshalled: `{"jsonrpc":"1.0","method":"help","params":["getblock"],"id":1}`,
   657  			unmarshalled: &btcjson.HelpCmd{
   658  				Command: btcjson.String("getblock"),
   659  			},
   660  		},
   661  		{
   662  			name: "invalidateblock",
   663  			newCmd: func() (interface{}, error) {
   664  				return btcjson.NewCmd("invalidateblock", "123")
   665  			},
   666  			staticCmd: func() interface{} {
   667  				return btcjson.NewInvalidateBlockCmd("123")
   668  			},
   669  			marshalled: `{"jsonrpc":"1.0","method":"invalidateblock","params":["123"],"id":1}`,
   670  			unmarshalled: &btcjson.InvalidateBlockCmd{
   671  				BlockHash: "123",
   672  			},
   673  		},
   674  		{
   675  			name: "ping",
   676  			newCmd: func() (interface{}, error) {
   677  				return btcjson.NewCmd("ping")
   678  			},
   679  			staticCmd: func() interface{} {
   680  				return btcjson.NewPingCmd()
   681  			},
   682  			marshalled:   `{"jsonrpc":"1.0","method":"ping","params":[],"id":1}`,
   683  			unmarshalled: &btcjson.PingCmd{},
   684  		},
   685  		{
   686  			name: "reconsiderblock",
   687  			newCmd: func() (interface{}, error) {
   688  				return btcjson.NewCmd("reconsiderblock", "123")
   689  			},
   690  			staticCmd: func() interface{} {
   691  				return btcjson.NewReconsiderBlockCmd("123")
   692  			},
   693  			marshalled: `{"jsonrpc":"1.0","method":"reconsiderblock","params":["123"],"id":1}`,
   694  			unmarshalled: &btcjson.ReconsiderBlockCmd{
   695  				BlockHash: "123",
   696  			},
   697  		},
   698  		{
   699  			name: "searchrawtransactions",
   700  			newCmd: func() (interface{}, error) {
   701  				return btcjson.NewCmd("searchrawtransactions", "1Address")
   702  			},
   703  			staticCmd: func() interface{} {
   704  				return btcjson.NewSearchRawTransactionsCmd("1Address", nil, nil, nil, nil, nil, nil)
   705  			},
   706  			marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address"],"id":1}`,
   707  			unmarshalled: &btcjson.SearchRawTransactionsCmd{
   708  				Address:     "1Address",
   709  				Verbose:     btcjson.Int(1),
   710  				Skip:        btcjson.Int(0),
   711  				Count:       btcjson.Int(100),
   712  				VinExtra:    btcjson.Int(0),
   713  				Reverse:     btcjson.Bool(false),
   714  				FilterAddrs: nil,
   715  			},
   716  		},
   717  		{
   718  			name: "searchrawtransactions",
   719  			newCmd: func() (interface{}, error) {
   720  				return btcjson.NewCmd("searchrawtransactions", "1Address", 0)
   721  			},
   722  			staticCmd: func() interface{} {
   723  				return btcjson.NewSearchRawTransactionsCmd("1Address",
   724  					btcjson.Int(0), nil, nil, nil, nil, nil)
   725  			},
   726  			marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0],"id":1}`,
   727  			unmarshalled: &btcjson.SearchRawTransactionsCmd{
   728  				Address:     "1Address",
   729  				Verbose:     btcjson.Int(0),
   730  				Skip:        btcjson.Int(0),
   731  				Count:       btcjson.Int(100),
   732  				VinExtra:    btcjson.Int(0),
   733  				Reverse:     btcjson.Bool(false),
   734  				FilterAddrs: nil,
   735  			},
   736  		},
   737  		{
   738  			name: "searchrawtransactions",
   739  			newCmd: func() (interface{}, error) {
   740  				return btcjson.NewCmd("searchrawtransactions", "1Address", 0, 5)
   741  			},
   742  			staticCmd: func() interface{} {
   743  				return btcjson.NewSearchRawTransactionsCmd("1Address",
   744  					btcjson.Int(0), btcjson.Int(5), nil, nil, nil, nil)
   745  			},
   746  			marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5],"id":1}`,
   747  			unmarshalled: &btcjson.SearchRawTransactionsCmd{
   748  				Address:     "1Address",
   749  				Verbose:     btcjson.Int(0),
   750  				Skip:        btcjson.Int(5),
   751  				Count:       btcjson.Int(100),
   752  				VinExtra:    btcjson.Int(0),
   753  				Reverse:     btcjson.Bool(false),
   754  				FilterAddrs: nil,
   755  			},
   756  		},
   757  		{
   758  			name: "searchrawtransactions",
   759  			newCmd: func() (interface{}, error) {
   760  				return btcjson.NewCmd("searchrawtransactions", "1Address", 0, 5, 10)
   761  			},
   762  			staticCmd: func() interface{} {
   763  				return btcjson.NewSearchRawTransactionsCmd("1Address",
   764  					btcjson.Int(0), btcjson.Int(5), btcjson.Int(10), nil, nil, nil)
   765  			},
   766  			marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5,10],"id":1}`,
   767  			unmarshalled: &btcjson.SearchRawTransactionsCmd{
   768  				Address:     "1Address",
   769  				Verbose:     btcjson.Int(0),
   770  				Skip:        btcjson.Int(5),
   771  				Count:       btcjson.Int(10),
   772  				VinExtra:    btcjson.Int(0),
   773  				Reverse:     btcjson.Bool(false),
   774  				FilterAddrs: nil,
   775  			},
   776  		},
   777  		{
   778  			name: "searchrawtransactions",
   779  			newCmd: func() (interface{}, error) {
   780  				return btcjson.NewCmd("searchrawtransactions", "1Address", 0, 5, 10, 1)
   781  			},
   782  			staticCmd: func() interface{} {
   783  				return btcjson.NewSearchRawTransactionsCmd("1Address",
   784  					btcjson.Int(0), btcjson.Int(5), btcjson.Int(10), btcjson.Int(1), nil, nil)
   785  			},
   786  			marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5,10,1],"id":1}`,
   787  			unmarshalled: &btcjson.SearchRawTransactionsCmd{
   788  				Address:     "1Address",
   789  				Verbose:     btcjson.Int(0),
   790  				Skip:        btcjson.Int(5),
   791  				Count:       btcjson.Int(10),
   792  				VinExtra:    btcjson.Int(1),
   793  				Reverse:     btcjson.Bool(false),
   794  				FilterAddrs: nil,
   795  			},
   796  		},
   797  		{
   798  			name: "searchrawtransactions",
   799  			newCmd: func() (interface{}, error) {
   800  				return btcjson.NewCmd("searchrawtransactions", "1Address", 0, 5, 10, 1, true)
   801  			},
   802  			staticCmd: func() interface{} {
   803  				return btcjson.NewSearchRawTransactionsCmd("1Address",
   804  					btcjson.Int(0), btcjson.Int(5), btcjson.Int(10), btcjson.Int(1), btcjson.Bool(true), nil)
   805  			},
   806  			marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5,10,1,true],"id":1}`,
   807  			unmarshalled: &btcjson.SearchRawTransactionsCmd{
   808  				Address:     "1Address",
   809  				Verbose:     btcjson.Int(0),
   810  				Skip:        btcjson.Int(5),
   811  				Count:       btcjson.Int(10),
   812  				VinExtra:    btcjson.Int(1),
   813  				Reverse:     btcjson.Bool(true),
   814  				FilterAddrs: nil,
   815  			},
   816  		},
   817  		{
   818  			name: "searchrawtransactions",
   819  			newCmd: func() (interface{}, error) {
   820  				return btcjson.NewCmd("searchrawtransactions", "1Address", 0, 5, 10, 1, true, []string{"1Address"})
   821  			},
   822  			staticCmd: func() interface{} {
   823  				return btcjson.NewSearchRawTransactionsCmd("1Address",
   824  					btcjson.Int(0), btcjson.Int(5), btcjson.Int(10), btcjson.Int(1), btcjson.Bool(true), &[]string{"1Address"})
   825  			},
   826  			marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5,10,1,true,["1Address"]],"id":1}`,
   827  			unmarshalled: &btcjson.SearchRawTransactionsCmd{
   828  				Address:     "1Address",
   829  				Verbose:     btcjson.Int(0),
   830  				Skip:        btcjson.Int(5),
   831  				Count:       btcjson.Int(10),
   832  				VinExtra:    btcjson.Int(1),
   833  				Reverse:     btcjson.Bool(true),
   834  				FilterAddrs: &[]string{"1Address"},
   835  			},
   836  		},
   837  		{
   838  			name: "sendrawtransaction",
   839  			newCmd: func() (interface{}, error) {
   840  				return btcjson.NewCmd("sendrawtransaction", "1122")
   841  			},
   842  			staticCmd: func() interface{} {
   843  				return btcjson.NewSendRawTransactionCmd("1122", nil)
   844  			},
   845  			marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122"],"id":1}`,
   846  			unmarshalled: &btcjson.SendRawTransactionCmd{
   847  				HexTx:         "1122",
   848  				AllowHighFees: btcjson.Bool(false),
   849  			},
   850  		},
   851  		{
   852  			name: "sendrawtransaction optional",
   853  			newCmd: func() (interface{}, error) {
   854  				return btcjson.NewCmd("sendrawtransaction", "1122", false)
   855  			},
   856  			staticCmd: func() interface{} {
   857  				return btcjson.NewSendRawTransactionCmd("1122", btcjson.Bool(false))
   858  			},
   859  			marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122",false],"id":1}`,
   860  			unmarshalled: &btcjson.SendRawTransactionCmd{
   861  				HexTx:         "1122",
   862  				AllowHighFees: btcjson.Bool(false),
   863  			},
   864  		},
   865  		{
   866  			name: "setgenerate",
   867  			newCmd: func() (interface{}, error) {
   868  				return btcjson.NewCmd("setgenerate", true)
   869  			},
   870  			staticCmd: func() interface{} {
   871  				return btcjson.NewSetGenerateCmd(true, nil)
   872  			},
   873  			marshalled: `{"jsonrpc":"1.0","method":"setgenerate","params":[true],"id":1}`,
   874  			unmarshalled: &btcjson.SetGenerateCmd{
   875  				Generate:     true,
   876  				GenProcLimit: btcjson.Int(-1),
   877  			},
   878  		},
   879  		{
   880  			name: "setgenerate optional",
   881  			newCmd: func() (interface{}, error) {
   882  				return btcjson.NewCmd("setgenerate", true, 6)
   883  			},
   884  			staticCmd: func() interface{} {
   885  				return btcjson.NewSetGenerateCmd(true, btcjson.Int(6))
   886  			},
   887  			marshalled: `{"jsonrpc":"1.0","method":"setgenerate","params":[true,6],"id":1}`,
   888  			unmarshalled: &btcjson.SetGenerateCmd{
   889  				Generate:     true,
   890  				GenProcLimit: btcjson.Int(6),
   891  			},
   892  		},
   893  		{
   894  			name: "stop",
   895  			newCmd: func() (interface{}, error) {
   896  				return btcjson.NewCmd("stop")
   897  			},
   898  			staticCmd: func() interface{} {
   899  				return btcjson.NewStopCmd()
   900  			},
   901  			marshalled:   `{"jsonrpc":"1.0","method":"stop","params":[],"id":1}`,
   902  			unmarshalled: &btcjson.StopCmd{},
   903  		},
   904  		{
   905  			name: "submitblock",
   906  			newCmd: func() (interface{}, error) {
   907  				return btcjson.NewCmd("submitblock", "112233")
   908  			},
   909  			staticCmd: func() interface{} {
   910  				return btcjson.NewSubmitBlockCmd("112233", nil)
   911  			},
   912  			marshalled: `{"jsonrpc":"1.0","method":"submitblock","params":["112233"],"id":1}`,
   913  			unmarshalled: &btcjson.SubmitBlockCmd{
   914  				HexBlock: "112233",
   915  				Options:  nil,
   916  			},
   917  		},
   918  		{
   919  			name: "submitblock optional",
   920  			newCmd: func() (interface{}, error) {
   921  				return btcjson.NewCmd("submitblock", "112233", `{"workid":"12345"}`)
   922  			},
   923  			staticCmd: func() interface{} {
   924  				options := btcjson.SubmitBlockOptions{
   925  					WorkID: "12345",
   926  				}
   927  				return btcjson.NewSubmitBlockCmd("112233", &options)
   928  			},
   929  			marshalled: `{"jsonrpc":"1.0","method":"submitblock","params":["112233",{"workid":"12345"}],"id":1}`,
   930  			unmarshalled: &btcjson.SubmitBlockCmd{
   931  				HexBlock: "112233",
   932  				Options: &btcjson.SubmitBlockOptions{
   933  					WorkID: "12345",
   934  				},
   935  			},
   936  		},
   937  		{
   938  			name: "validateaddress",
   939  			newCmd: func() (interface{}, error) {
   940  				return btcjson.NewCmd("validateaddress", "1Address")
   941  			},
   942  			staticCmd: func() interface{} {
   943  				return btcjson.NewValidateAddressCmd("1Address")
   944  			},
   945  			marshalled: `{"jsonrpc":"1.0","method":"validateaddress","params":["1Address"],"id":1}`,
   946  			unmarshalled: &btcjson.ValidateAddressCmd{
   947  				Address: "1Address",
   948  			},
   949  		},
   950  		{
   951  			name: "verifychain",
   952  			newCmd: func() (interface{}, error) {
   953  				return btcjson.NewCmd("verifychain")
   954  			},
   955  			staticCmd: func() interface{} {
   956  				return btcjson.NewVerifyChainCmd(nil, nil)
   957  			},
   958  			marshalled: `{"jsonrpc":"1.0","method":"verifychain","params":[],"id":1}`,
   959  			unmarshalled: &btcjson.VerifyChainCmd{
   960  				CheckLevel: btcjson.Int32(3),
   961  				CheckDepth: btcjson.Int32(288),
   962  			},
   963  		},
   964  		{
   965  			name: "verifychain optional1",
   966  			newCmd: func() (interface{}, error) {
   967  				return btcjson.NewCmd("verifychain", 2)
   968  			},
   969  			staticCmd: func() interface{} {
   970  				return btcjson.NewVerifyChainCmd(btcjson.Int32(2), nil)
   971  			},
   972  			marshalled: `{"jsonrpc":"1.0","method":"verifychain","params":[2],"id":1}`,
   973  			unmarshalled: &btcjson.VerifyChainCmd{
   974  				CheckLevel: btcjson.Int32(2),
   975  				CheckDepth: btcjson.Int32(288),
   976  			},
   977  		},
   978  		{
   979  			name: "verifychain optional2",
   980  			newCmd: func() (interface{}, error) {
   981  				return btcjson.NewCmd("verifychain", 2, 500)
   982  			},
   983  			staticCmd: func() interface{} {
   984  				return btcjson.NewVerifyChainCmd(btcjson.Int32(2), btcjson.Int32(500))
   985  			},
   986  			marshalled: `{"jsonrpc":"1.0","method":"verifychain","params":[2,500],"id":1}`,
   987  			unmarshalled: &btcjson.VerifyChainCmd{
   988  				CheckLevel: btcjson.Int32(2),
   989  				CheckDepth: btcjson.Int32(500),
   990  			},
   991  		},
   992  		{
   993  			name: "verifymessage",
   994  			newCmd: func() (interface{}, error) {
   995  				return btcjson.NewCmd("verifymessage", "1Address", "301234", "test")
   996  			},
   997  			staticCmd: func() interface{} {
   998  				return btcjson.NewVerifyMessageCmd("1Address", "301234", "test")
   999  			},
  1000  			marshalled: `{"jsonrpc":"1.0","method":"verifymessage","params":["1Address","301234","test"],"id":1}`,
  1001  			unmarshalled: &btcjson.VerifyMessageCmd{
  1002  				Address:   "1Address",
  1003  				Signature: "301234",
  1004  				Message:   "test",
  1005  			},
  1006  		},
  1007  		{
  1008  			name: "verifytxoutproof",
  1009  			newCmd: func() (interface{}, error) {
  1010  				return btcjson.NewCmd("verifytxoutproof", "test")
  1011  			},
  1012  			staticCmd: func() interface{} {
  1013  				return btcjson.NewVerifyTxOutProofCmd("test")
  1014  			},
  1015  			marshalled: `{"jsonrpc":"1.0","method":"verifytxoutproof","params":["test"],"id":1}`,
  1016  			unmarshalled: &btcjson.VerifyTxOutProofCmd{
  1017  				Proof: "test",
  1018  			},
  1019  		},
  1020  	}
  1021  
  1022  	t.Logf("Running %d tests", len(tests))
  1023  	for i, test := range tests {
  1024  		// Marshal the command as created by the new static command
  1025  		// creation function.
  1026  		marshalled, err := btcjson.MarshalCmd(testID, test.staticCmd())
  1027  		if err != nil {
  1028  			t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
  1029  				test.name, err)
  1030  			continue
  1031  		}
  1032  
  1033  		if !bytes.Equal(marshalled, []byte(test.marshalled)) {
  1034  			t.Errorf("Test #%d (%s) unexpected marshalled data - "+
  1035  				"got %s, want %s", i, test.name, marshalled,
  1036  				test.marshalled)
  1037  			t.Errorf("\n%s\n%s", marshalled, test.marshalled)
  1038  			continue
  1039  		}
  1040  
  1041  		// Ensure the command is created without error via the generic
  1042  		// new command creation function.
  1043  		cmd, err := test.newCmd()
  1044  		if err != nil {
  1045  			t.Errorf("Test #%d (%s) unexpected NewCmd error: %v ",
  1046  				i, test.name, err)
  1047  		}
  1048  
  1049  		// Marshal the command as created by the generic new command
  1050  		// creation function.
  1051  		marshalled, err = btcjson.MarshalCmd(testID, cmd)
  1052  		if err != nil {
  1053  			t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
  1054  				test.name, err)
  1055  			continue
  1056  		}
  1057  
  1058  		if !bytes.Equal(marshalled, []byte(test.marshalled)) {
  1059  			t.Errorf("Test #%d (%s) unexpected marshalled data - "+
  1060  				"got %s, want %s", i, test.name, marshalled,
  1061  				test.marshalled)
  1062  			continue
  1063  		}
  1064  
  1065  		var request btcjson.Request
  1066  		if err := json.Unmarshal(marshalled, &request); err != nil {
  1067  			t.Errorf("Test #%d (%s) unexpected error while "+
  1068  				"unmarshalling JSON-RPC request: %v", i,
  1069  				test.name, err)
  1070  			continue
  1071  		}
  1072  
  1073  		cmd, err = btcjson.UnmarshalCmd(&request)
  1074  		if err != nil {
  1075  			t.Errorf("UnmarshalCmd #%d (%s) unexpected error: %v", i,
  1076  				test.name, err)
  1077  			continue
  1078  		}
  1079  
  1080  		if !reflect.DeepEqual(cmd, test.unmarshalled) {
  1081  			t.Errorf("Test #%d (%s) unexpected unmarshalled command "+
  1082  				"- got %s, want %s", i, test.name,
  1083  				fmt.Sprintf("(%T) %+[1]v", cmd),
  1084  				fmt.Sprintf("(%T) %+[1]v\n", test.unmarshalled))
  1085  			continue
  1086  		}
  1087  	}
  1088  }
  1089  
  1090  // TestChainSvrCmdErrors ensures any errors that occur in the command during
  1091  // custom mashal and unmarshal are as expected.
  1092  func TestChainSvrCmdErrors(t *testing.T) {
  1093  	t.Parallel()
  1094  
  1095  	tests := []struct {
  1096  		name       string
  1097  		result     interface{}
  1098  		marshalled string
  1099  		err        error
  1100  	}{
  1101  		{
  1102  			name:       "template request with invalid type",
  1103  			result:     &btcjson.TemplateRequest{},
  1104  			marshalled: `{"mode":1}`,
  1105  			err:        &json.UnmarshalTypeError{},
  1106  		},
  1107  		{
  1108  			name:       "invalid template request sigoplimit field",
  1109  			result:     &btcjson.TemplateRequest{},
  1110  			marshalled: `{"sigoplimit":"invalid"}`,
  1111  			err:        btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
  1112  		},
  1113  		{
  1114  			name:       "invalid template request sizelimit field",
  1115  			result:     &btcjson.TemplateRequest{},
  1116  			marshalled: `{"sizelimit":"invalid"}`,
  1117  			err:        btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
  1118  		},
  1119  	}
  1120  
  1121  	t.Logf("Running %d tests", len(tests))
  1122  	for i, test := range tests {
  1123  		err := json.Unmarshal([]byte(test.marshalled), &test.result)
  1124  		if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
  1125  			t.Errorf("Test #%d (%s) wrong error - got %T (%[2]v), "+
  1126  				"want %T", i, test.name, err, test.err)
  1127  			continue
  1128  		}
  1129  
  1130  		if terr, ok := test.err.(btcjson.Error); ok {
  1131  			gotErrorCode := err.(btcjson.Error).ErrorCode
  1132  			if gotErrorCode != terr.ErrorCode {
  1133  				t.Errorf("Test #%d (%s) mismatched error code "+
  1134  					"- got %v (%v), want %v", i, test.name,
  1135  					gotErrorCode, terr, terr.ErrorCode)
  1136  				continue
  1137  			}
  1138  		}
  1139  	}
  1140  }