From eecc55d94ce422ceddb668ce5d1c0946ebc1ff34 Mon Sep 17 00:00:00 2001 From: Roy Lee Date: Thu, 10 Feb 2022 14:47:25 -0800 Subject: [PATCH] rpc: take integers for boolean parameters. This is for backward compatibility with lbrycrd/bitcoind where some clients use intger values (0/1) for boolean. --- btcjson/cmdparse.go | 10 +++++ btcjson/cmdparse_test.go | 83 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/btcjson/cmdparse.go b/btcjson/cmdparse.go index 4fb8dd62..c0190bf3 100644 --- a/btcjson/cmdparse.go +++ b/btcjson/cmdparse.go @@ -134,6 +134,16 @@ func UnmarshalCmd(r *Request) (interface{}, error) { // Unmarshal the parameter into the struct field. concreteVal := rvf.Addr().Interface() if err := json.Unmarshal(r.Params[i], &concreteVal); err != nil { + // Parse Integer into Bool for compatibility with lbrycrd. + if rvf.Kind() == reflect.Ptr && + rvf.Elem().Type().Kind() == reflect.Bool { + boolInt, errBoolInt := strconv.Atoi(string(r.Params[i])) + if errBoolInt == nil { + rvf.Elem().SetBool(boolInt != 0) + continue + } + } + // The most common error is the wrong type, so // explicitly detect that error and make it nicer. fieldName := strings.ToLower(rt.Field(i).Name) diff --git a/btcjson/cmdparse_test.go b/btcjson/cmdparse_test.go index c1414c64..0da6442c 100644 --- a/btcjson/cmdparse_test.go +++ b/btcjson/cmdparse_test.go @@ -557,7 +557,7 @@ func TestUnmarshalCmdErrors(t *testing.T) { request: btcjson.Request{ Jsonrpc: btcjson.RpcVersion1, Method: "getblock", - Params: []json.RawMessage{[]byte("1")}, + Params: []json.RawMessage{[]byte("1.0")}, ID: nil, }, err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType}, @@ -591,3 +591,84 @@ func TestUnmarshalCmdErrors(t *testing.T) { } } } + +// TestUnmarshalCmdBoolParams tests the parsing of boolean paramers of the UnmarshalCmd function. +func TestUnmarshalCmdBoolParams(t *testing.T) { + t.Parallel() + + txid := []byte(`"ab91c149aff2b37a4a1856e9935ea623c973f47886d032ed7511ad8ca37855bb"`) + tests := []struct { + name string + request btcjson.Request + expect bool + }{ + { + name: "parse true", + request: btcjson.Request{ + Jsonrpc: btcjson.RpcVersion1, + Method: "getrawtransaction", + Params: []json.RawMessage{txid, []byte("true")}, + ID: nil, + }, + expect: true, + }, + { + name: "parse false", + request: btcjson.Request{ + Jsonrpc: btcjson.RpcVersion1, + Method: "getrawtransaction", + Params: []json.RawMessage{txid, []byte("false")}, + ID: nil, + }, + expect: false, + }, + { + name: "parse integer 0 to false", + request: btcjson.Request{ + Jsonrpc: btcjson.RpcVersion1, + Method: "getrawtransaction", + Params: []json.RawMessage{txid, []byte("0")}, + ID: nil, + }, + expect: false, + }, + { + name: "parse integer 1 to true", + request: btcjson.Request{ + Jsonrpc: btcjson.RpcVersion1, + Method: "getrawtransaction", + Params: []json.RawMessage{txid, []byte("1")}, + ID: nil, + }, + expect: true, + }, + { + name: "parse integer 100 to true", + request: btcjson.Request{ + Jsonrpc: btcjson.RpcVersion1, + Method: "getrawtransaction", + Params: []json.RawMessage{txid, []byte("100")}, + ID: nil, + }, + expect: true, + }, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + cmd, err := btcjson.UnmarshalCmd(&test.request) + if err != nil { + t.Errorf("Test #%d (%s) error - got %T (%v)", i, test.name, + err, err) + continue + } + cc := cmd.(*btcjson.GetRawTransactionCmd) + verbose := *cc.Verbose + if verbose != test.expect { + t.Errorf("Test #%d (%s) got %t, want %v", i, test.name, + verbose, test.expect) + continue + } + + } +}