btcjson: accept null in StringOrArray.UnmarshalJSON

StringOrArray.MarshalJSON emits JSON null for a nil slice (see existing
test "nil slice marshals as null" in TestStringOrArrayMarshalJSON), but
UnmarshalJSON did not have a matching case for null and fell to the
default branch, returning "invalid string_or_array value: <nil>". A
round trip of a nil slice therefore failed.

This bit the rpcclient against btcd's own getblockchaininfo, whose
Warnings field is a StringOrArray that the server leaves as a nil slice
when there are no warnings. Every rpctest integration test that touches
GetBlockChainInfo (TestBIP0009, TestBIP0068AndBIP0112Activation,
TestBIP0113Activation, TestPrune) failed to decode the response.

Handle the nil case explicitly so null decodes back to a nil slice, and
add regression cases for "warnings: null" and an omitted warnings field
to TestGetBlockChainInfoWarnings.
This commit is contained in:
Calvin Kim 2026-05-30 13:53:12 +09:00
parent 221178501c
commit 79752a8880
2 changed files with 13 additions and 0 deletions

View file

@ -385,6 +385,9 @@ func (h *StringOrArray) UnmarshalJSON(data []byte) error {
}
switch v := unmarshalled.(type) {
case nil:
*h = nil
case string:
*h = []string{v}

View file

@ -350,6 +350,16 @@ func TestGetBlockChainInfoWarnings(t *testing.T) {
result: `{"warnings": []}`,
expected: btcjson.StringOrArray{},
},
{
name: "blockchain info with null warnings",
result: `{"warnings": null}`,
expected: nil,
},
{
name: "blockchain info with warnings field omitted",
result: `{}`,
expected: nil,
},
}
for _, test := range tests {