ethereum / go-ethereum

Go implementation of the Ethereum protocol
https://geth.ethereum.org
GNU Lesser General Public License v3.0
47.74k stars 20.21k forks source link

rpc.Client.CallContext incorrectly unmarshalling null results #26700

Closed JasonYuan869 closed 1 year ago

JasonYuan869 commented 1 year ago

System information

Geth version: v1.10.26 (but also in master branch)

Expected behaviour

When {"result": null} is returned from a JSON RPC call in rpc.CallContext, it should unmarshal into a json.RawMessage as json.RawMessage("null").

Actual behaviour

It actually gets unmarshalled as nil.

Steps to reproduce the behaviour

  1. Create a local blockchain private network and expose it with --http or --ws
  2. Set RPC_ENDPOINT environment variable to the URL of the network
  3. The following code attempts to retrieve a transaction receipt for an invalid hash, which should set result to json.RawMessage("null")
    
    package main

import ( "encoding/json" "fmt" "os"

"github.com/ethereum/go-ethereum/rpc"

)

func main() { client, err := rpc.Dial(os.Getenv("RPC_ENDPOINT")) if err != nil { panic(err) } defer client.Close()

var result json.RawMessage
invalidHash := "0x1234567890123456789012345678901234567890123456789012345678901234"

err = client.Call(&result, "eth_getTransactionReceipt", invalidHash)
if err != nil {
    panic(err)
}

if result == nil {
    panic("result should not be nil")
} else {
    fmt.Printf("result: %s", result)
}

}


3. The go code panics since `result` is `nil`
4. Observe that running curl against the endpoint with the same RPC call properly returns the JSON field `"result": null`.

#### Fix
The error seems to be caused by a redundant reference operator in `rpc.Client.CallContext()`, when the JSON unmarshaller is called.

https://github.com/ethereum/go-ethereum/blob/dbd6c1324dda8bb93c7a8297446fce7998cab4e1/rpc/client.go#L348

Line 321 already checks that `result` is a pointer, so there shouldn’t be any need to reference it again.

https://github.com/ethereum/go-ethereum/blob/dbd6c1324dda8bb93c7a8297446fce7998cab4e1/rpc/client.go#L321-L323

Upon further investigation, it seems that nested pointers will be set to `nil` specifically when decoding `null` values (https://go.dev/src/encoding/json/decode.go#L424). 
JasonYuan869 commented 1 year ago

Closed in https://github.com/ethereum/go-ethereum/pull/26723