feat(proxyd): support eip-1898 in tag rewritting
This commit is contained in:
parent
92058943d8
commit
22b7237389
@ -66,25 +66,26 @@ func RewriteRequest(rctx RewriteContext, req *RPCReq, res *RPCRes) (RewriteResul
|
||||
"eth_newFilter":
|
||||
return rewriteRange(rctx, req, res, 0)
|
||||
case "debug_getRawReceipts", "consensus_getReceipts":
|
||||
return rewriteParam(rctx, req, res, 0, true)
|
||||
return rewriteParam(rctx, req, res, 0, true, false)
|
||||
case "eth_getBalance",
|
||||
"eth_getCode",
|
||||
"eth_getTransactionCount",
|
||||
"eth_call":
|
||||
return rewriteParam(rctx, req, res, 1, false)
|
||||
case "eth_getStorageAt":
|
||||
return rewriteParam(rctx, req, res, 2, false)
|
||||
return rewriteParam(rctx, req, res, 1, false, true)
|
||||
case "eth_getStorageAt",
|
||||
"eth_getProof":
|
||||
return rewriteParam(rctx, req, res, 2, false, true)
|
||||
case "eth_getBlockTransactionCountByNumber",
|
||||
"eth_getUncleCountByBlockNumber",
|
||||
"eth_getBlockByNumber",
|
||||
"eth_getTransactionByBlockNumberAndIndex",
|
||||
"eth_getUncleByBlockNumberAndIndex":
|
||||
return rewriteParam(rctx, req, res, 0, false)
|
||||
return rewriteParam(rctx, req, res, 0, false, false)
|
||||
}
|
||||
return RewriteNone, nil
|
||||
}
|
||||
|
||||
func rewriteParam(rctx RewriteContext, req *RPCReq, res *RPCRes, pos int, required bool) (RewriteResult, error) {
|
||||
func rewriteParam(rctx RewriteContext, req *RPCReq, res *RPCRes, pos int, required bool, blockNrOrHash bool) (RewriteResult, error) {
|
||||
var p []interface{}
|
||||
err := json.Unmarshal(req.Params, &p)
|
||||
if err != nil {
|
||||
@ -99,13 +100,38 @@ func rewriteParam(rctx RewriteContext, req *RPCReq, res *RPCRes, pos int, requir
|
||||
return RewriteNone, nil
|
||||
}
|
||||
|
||||
s, ok := p[pos].(string)
|
||||
if !ok {
|
||||
return RewriteOverrideError, errors.New("expected string")
|
||||
}
|
||||
val, rw, err := rewriteTag(rctx, s)
|
||||
if err != nil {
|
||||
return RewriteOverrideError, err
|
||||
// support for https://eips.ethereum.org/EIPS/eip-1898
|
||||
var val interface{}
|
||||
var rw bool
|
||||
if blockNrOrHash {
|
||||
bnh, err := remarshalBlockNumberOrHash(p[pos])
|
||||
if err != nil {
|
||||
// fallback to string
|
||||
s, ok := p[pos].(string)
|
||||
if ok {
|
||||
val, rw, err = rewriteTag(rctx, s)
|
||||
if err != nil {
|
||||
return RewriteOverrideError, err
|
||||
}
|
||||
} else {
|
||||
return RewriteOverrideError, errors.New("expected BlockNumberOrHash or string")
|
||||
}
|
||||
} else {
|
||||
val, rw, err = rewriteTagBlockNumberOrHash(rctx, bnh)
|
||||
if err != nil {
|
||||
return RewriteOverrideError, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
s, ok := p[pos].(string)
|
||||
if !ok {
|
||||
return RewriteOverrideError, errors.New("expected string")
|
||||
}
|
||||
|
||||
val, rw, err = rewriteTag(rctx, s)
|
||||
if err != nil {
|
||||
return RewriteOverrideError, err
|
||||
}
|
||||
}
|
||||
|
||||
if rw {
|
||||
@ -210,14 +236,23 @@ func rewriteTagMap(rctx RewriteContext, m map[string]interface{}, key string) (b
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func rewriteTag(rctx RewriteContext, current string) (string, bool, error) {
|
||||
func remarshalBlockNumberOrHash(current interface{}) (*rpc.BlockNumberOrHash, error) {
|
||||
jv, err := json.Marshal(current)
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var bnh rpc.BlockNumberOrHash
|
||||
err = bnh.UnmarshalJSON(jv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &bnh, nil
|
||||
}
|
||||
|
||||
func rewriteTag(rctx RewriteContext, current string) (string, bool, error) {
|
||||
bnh, err := remarshalBlockNumberOrHash(current)
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
@ -245,3 +280,31 @@ func rewriteTag(rctx RewriteContext, current string) (string, bool, error) {
|
||||
|
||||
return current, false, nil
|
||||
}
|
||||
|
||||
func rewriteTagBlockNumberOrHash(rctx RewriteContext, current *rpc.BlockNumberOrHash) (*rpc.BlockNumberOrHash, bool, error) {
|
||||
// this is a hash, not a block number
|
||||
if current.BlockNumber == nil {
|
||||
return current, false, nil
|
||||
}
|
||||
|
||||
switch *current.BlockNumber {
|
||||
case rpc.PendingBlockNumber,
|
||||
rpc.EarliestBlockNumber:
|
||||
return current, false, nil
|
||||
case rpc.FinalizedBlockNumber:
|
||||
bn := rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(rctx.finalized))
|
||||
return &bn, true, nil
|
||||
case rpc.SafeBlockNumber:
|
||||
bn := rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(rctx.safe))
|
||||
return &bn, true, nil
|
||||
case rpc.LatestBlockNumber:
|
||||
bn := rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(rctx.latest))
|
||||
return &bn, true, nil
|
||||
default:
|
||||
if current.BlockNumber.Int64() > int64(rctx.latest) {
|
||||
return nil, false, ErrRewriteBlockOutOfRange
|
||||
}
|
||||
}
|
||||
|
||||
return current, false, nil
|
||||
}
|
||||
|
@ -5,7 +5,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@ -282,12 +284,14 @@ func TestRewriteRequest(t *testing.T) {
|
||||
},
|
||||
expected: RewriteOverrideRequest,
|
||||
check: func(t *testing.T, args args) {
|
||||
var p []string
|
||||
var p []interface{}
|
||||
err := json.Unmarshal(args.req.Params, &p)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, 2, len(p))
|
||||
require.Equal(t, "0x123", p[0])
|
||||
require.Equal(t, hexutil.Uint64(100).String(), p[1])
|
||||
bnh, err := remarshalBlockNumberOrHash(p[1])
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, rpc.BlockNumberOrHashWithNumber(100), *bnh)
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -314,12 +318,14 @@ func TestRewriteRequest(t *testing.T) {
|
||||
},
|
||||
expected: RewriteOverrideRequest,
|
||||
check: func(t *testing.T, args args) {
|
||||
var p []string
|
||||
var p []interface{}
|
||||
err := json.Unmarshal(args.req.Params, &p)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, 2, len(p))
|
||||
require.Equal(t, "0x123", p[0])
|
||||
require.Equal(t, hexutil.Uint64(100).String(), p[1])
|
||||
bnh, err := remarshalBlockNumberOrHash(p[1])
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, rpc.BlockNumberOrHashWithNumber(100), *bnh)
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -359,13 +365,15 @@ func TestRewriteRequest(t *testing.T) {
|
||||
},
|
||||
expected: RewriteOverrideRequest,
|
||||
check: func(t *testing.T, args args) {
|
||||
var p []string
|
||||
var p []interface{}
|
||||
err := json.Unmarshal(args.req.Params, &p)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, 3, len(p))
|
||||
require.Equal(t, "0x123", p[0])
|
||||
require.Equal(t, "5", p[1])
|
||||
require.Equal(t, hexutil.Uint64(100).String(), p[2])
|
||||
bnh, err := remarshalBlockNumberOrHash(p[2])
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, rpc.BlockNumberOrHashWithNumber(100), *bnh)
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -377,13 +385,15 @@ func TestRewriteRequest(t *testing.T) {
|
||||
},
|
||||
expected: RewriteOverrideRequest,
|
||||
check: func(t *testing.T, args args) {
|
||||
var p []string
|
||||
var p []interface{}
|
||||
err := json.Unmarshal(args.req.Params, &p)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, 3, len(p))
|
||||
require.Equal(t, "0x123", p[0])
|
||||
require.Equal(t, "5", p[1])
|
||||
require.Equal(t, hexutil.Uint64(100).String(), p[2])
|
||||
bnh, err := remarshalBlockNumberOrHash(p[2])
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, rpc.BlockNumberOrHashWithNumber(100), *bnh)
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -517,6 +527,88 @@ func TestRewriteRequest(t *testing.T) {
|
||||
},
|
||||
expected: RewriteNone,
|
||||
},
|
||||
// eip1898
|
||||
{
|
||||
name: "eth_getStorageAt using rpc.BlockNumberOrHash at genesis (blockNumber)",
|
||||
args: args{
|
||||
rctx: RewriteContext{latest: hexutil.Uint64(100)},
|
||||
req: &RPCReq{Method: "eth_getStorageAt", Params: mustMarshalJSON([]interface{}{
|
||||
"0xae851f927ee40de99aabb7461c00f9622ab91d60",
|
||||
"10",
|
||||
map[string]interface{}{
|
||||
"blockNumber": "0x0",
|
||||
}})},
|
||||
res: nil,
|
||||
},
|
||||
expected: RewriteNone,
|
||||
},
|
||||
{
|
||||
name: "eth_getStorageAt using rpc.BlockNumberOrHash at genesis (hash)",
|
||||
args: args{
|
||||
rctx: RewriteContext{latest: hexutil.Uint64(100)},
|
||||
req: &RPCReq{Method: "eth_getStorageAt", Params: mustMarshalJSON([]interface{}{
|
||||
"0xae851f927ee40de99aabb7461c00f9622ab91d60",
|
||||
"10",
|
||||
map[string]interface{}{
|
||||
"blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3",
|
||||
"requireCanonical": true,
|
||||
}})},
|
||||
res: nil,
|
||||
},
|
||||
expected: RewriteNone,
|
||||
check: func(t *testing.T, args args) {
|
||||
var p []interface{}
|
||||
err := json.Unmarshal(args.req.Params, &p)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, 3, len(p))
|
||||
require.Equal(t, "0xae851f927ee40de99aabb7461c00f9622ab91d60", p[0])
|
||||
require.Equal(t, "10", p[1])
|
||||
bnh, err := remarshalBlockNumberOrHash(p[2])
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, rpc.BlockNumberOrHashWithHash(common.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"), true), *bnh)
|
||||
require.True(t, bnh.RequireCanonical)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "eth_getStorageAt using rpc.BlockNumberOrHash at latest (blockNumber)",
|
||||
args: args{
|
||||
rctx: RewriteContext{latest: hexutil.Uint64(100)},
|
||||
req: &RPCReq{Method: "eth_getStorageAt", Params: mustMarshalJSON([]interface{}{
|
||||
"0xae851f927ee40de99aabb7461c00f9622ab91d60",
|
||||
"10",
|
||||
map[string]interface{}{
|
||||
"blockNumber": "latest",
|
||||
}})},
|
||||
res: nil,
|
||||
},
|
||||
expected: RewriteOverrideRequest,
|
||||
check: func(t *testing.T, args args) {
|
||||
var p []interface{}
|
||||
err := json.Unmarshal(args.req.Params, &p)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, 3, len(p))
|
||||
require.Equal(t, "0xae851f927ee40de99aabb7461c00f9622ab91d60", p[0])
|
||||
require.Equal(t, "10", p[1])
|
||||
bnh, err := remarshalBlockNumberOrHash(p[2])
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, rpc.BlockNumberOrHashWithNumber(100), *bnh)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "eth_getStorageAt using rpc.BlockNumberOrHash out of range",
|
||||
args: args{
|
||||
rctx: RewriteContext{latest: hexutil.Uint64(100)},
|
||||
req: &RPCReq{Method: "eth_getStorageAt", Params: mustMarshalJSON([]interface{}{
|
||||
"0xae851f927ee40de99aabb7461c00f9622ab91d60",
|
||||
"10",
|
||||
map[string]interface{}{
|
||||
"blockNumber": "0x111",
|
||||
}})},
|
||||
res: nil,
|
||||
},
|
||||
expected: RewriteOverrideError,
|
||||
expectedErr: ErrRewriteBlockOutOfRange,
|
||||
},
|
||||
}
|
||||
|
||||
// generalize tests for other methods with same interface and behavior
|
||||
@ -528,6 +620,7 @@ func TestRewriteRequest(t *testing.T) {
|
||||
tests = generalize(tests, "eth_getBlockByNumber", "eth_getUncleCountByBlockNumber")
|
||||
tests = generalize(tests, "eth_getBlockByNumber", "eth_getTransactionByBlockNumberAndIndex")
|
||||
tests = generalize(tests, "eth_getBlockByNumber", "eth_getUncleByBlockNumberAndIndex")
|
||||
tests = generalize(tests, "eth_getStorageSlotAt", "eth_getProof")
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
Loading…
Reference in New Issue
Block a user