chainsvrcmds_test.go raw

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