feat_: Add timeout to callprivaterpc endpoint

This commit is contained in:
Andrea Maria Piana 2024-06-04 14:21:04 +01:00
parent dfdc1652a2
commit c592bef3d1
2 changed files with 63 additions and 11 deletions

View File

@ -3,6 +3,7 @@ package rpc
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"time"
gethrpc "github.com/ethereum/go-ethereum/rpc" gethrpc "github.com/ethereum/go-ethereum/rpc"
) )
@ -38,6 +39,7 @@ type jsonrpcRequest struct {
ChainID uint64 `json:"chainId"` ChainID uint64 `json:"chainId"`
Method string `json:"method"` Method string `json:"method"`
Params json.RawMessage `json:"params,omitempty"` Params json.RawMessage `json:"params,omitempty"`
Timeout uint64 `json:"timeout,omitempty"`
} }
type jsonrpcSuccessfulResponse struct { type jsonrpcSuccessfulResponse struct {
@ -111,11 +113,28 @@ func (c *Client) callBatchMethods(ctx context.Context, msgs json.RawMessage) str
// callSingleMethod executes single JSON-RPC message and constructs proper response. // callSingleMethod executes single JSON-RPC message and constructs proper response.
func (c *Client) callSingleMethod(ctx context.Context, msg json.RawMessage) string { func (c *Client) callSingleMethod(ctx context.Context, msg json.RawMessage) string {
// unmarshal JSON body into json-rpc request // unmarshal JSON body into json-rpc request
chainID, method, params, id, err := methodAndParamsFromBody(msg) jsonrpcParams, err := methodAndParamsFromBody(msg)
if err != nil { if err != nil {
return newErrorResponse(errInvalidMessageCode, err, id) return newErrorResponse(errInvalidMessageCode, err, nil)
} }
chainID := jsonrpcParams.ChainID
method := jsonrpcParams.Method
params := jsonrpcParams.Params
timeout := jsonrpcParams.Timeout
id := jsonrpcParams.ID
if timeout != 0 {
// TODO: remove me
c.log.Info("setting 50ms timeout", "method", method)
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, time.Duration(timeout)*time.Millisecond)
defer cancel()
}
// TODO: remove me
c.log.Info("calling method", "method", method)
if chainID == 0 { if chainID == 0 {
chainID = c.UpstreamChainID chainID = c.UpstreamChainID
} }
@ -139,24 +158,38 @@ func (c *Client) callSingleMethod(ctx context.Context, msg json.RawMessage) stri
return newSuccessResponse(result, id) return newSuccessResponse(result, id)
} }
type jsonrpcParameters struct {
ChainID uint64
Method string
Params []interface{}
Timeout uint64
ID json.RawMessage
}
// methodAndParamsFromBody extracts Method and Params of // methodAndParamsFromBody extracts Method and Params of
// JSON-RPC body into values ready to use with ethereum-go's // JSON-RPC body into values ready to use with ethereum-go's
// RPC client Call() function. A lot of empty interface usage is // RPC client Call() function. A lot of empty interface usage is
// due to the underlying code design :/ // due to the underlying code design :/
func methodAndParamsFromBody(body json.RawMessage) (uint64, string, []interface{}, json.RawMessage, error) { func methodAndParamsFromBody(body json.RawMessage) (*jsonrpcParameters, error) {
msg, err := unmarshalMessage(body) msg, err := unmarshalMessage(body)
if err != nil { if err != nil {
return 0, "", nil, nil, err return nil, err
} }
params := []interface{}{} params := []interface{}{}
if msg.Params != nil { if msg.Params != nil {
err = json.Unmarshal(msg.Params, &params) err = json.Unmarshal(msg.Params, &params)
if err != nil { if err != nil {
return 0, "", nil, nil, err return nil, err
} }
} }
return msg.ChainID, msg.Method, params, msg.ID, nil return &jsonrpcParameters{
ChainID: msg.ChainID,
Method: msg.Method,
Params: params,
Timeout: msg.Timeout,
ID: msg.ID,
}, nil
} }
// unmarshalMessage tries to unmarshal JSON-RPC message. // unmarshalMessage tries to unmarshal JSON-RPC message.

View File

@ -59,6 +59,7 @@ func TestMethodAndParamsFromBody(t *testing.T) {
id json.RawMessage id json.RawMessage
chainID uint64 chainID uint64
shouldFail bool shouldFail bool
timeout uint64
}{ }{
{ {
"params_array", "params_array",
@ -73,6 +74,7 @@ func TestMethodAndParamsFromBody(t *testing.T) {
json.RawMessage(`42`), json.RawMessage(`42`),
0, 0,
false, false,
0,
}, },
{ {
"params_empty_array", "params_empty_array",
@ -82,6 +84,7 @@ func TestMethodAndParamsFromBody(t *testing.T) {
nil, nil,
0, 0,
false, false,
0,
}, },
{ {
"params_none", "params_none",
@ -91,6 +94,7 @@ func TestMethodAndParamsFromBody(t *testing.T) {
nil, nil,
0, 0,
false, false,
0,
}, },
{ {
"params_chain_id", "params_chain_id",
@ -100,6 +104,7 @@ func TestMethodAndParamsFromBody(t *testing.T) {
nil, nil,
2, 2,
false, false,
0,
}, },
{ {
"getFilterMessage", "getFilterMessage",
@ -109,6 +114,7 @@ func TestMethodAndParamsFromBody(t *testing.T) {
json.RawMessage(`44`), json.RawMessage(`44`),
0, 0,
false, false,
0,
}, },
{ {
"getFilterMessage_array", "getFilterMessage_array",
@ -118,6 +124,7 @@ func TestMethodAndParamsFromBody(t *testing.T) {
nil, nil,
0, 0,
true, true,
0,
}, },
{ {
"empty_array", "empty_array",
@ -127,21 +134,33 @@ func TestMethodAndParamsFromBody(t *testing.T) {
nil, nil,
0, 0,
true, true,
0,
},
{
"timeout",
json.RawMessage(`{"jsonrpc": "2.0", "timeout": 2000, "method": "test"}`),
[]interface{}{},
"test",
nil,
0,
false,
2000,
}, },
} }
for _, test := range cases { for _, test := range cases {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
chainID, method, params, id, err := methodAndParamsFromBody(test.body) response, err := methodAndParamsFromBody(test.body)
if test.shouldFail { if test.shouldFail {
require.Error(t, err) require.Error(t, err)
return return
} }
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, test.chainID, chainID) require.Equal(t, test.timeout, response.Timeout)
require.Equal(t, test.method, method) require.Equal(t, test.chainID, response.ChainID)
require.Equal(t, test.params, params) require.Equal(t, test.method, response.Method)
require.EqualValues(t, test.id, id) require.Equal(t, test.params, response.Params)
require.EqualValues(t, test.id, response.ID)
}) })
} }
} }