Commit ab8f1a4a authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into refactor/invariants-encoding

parents 606541f2 ebae25b4
...@@ -40,7 +40,7 @@ var ( ...@@ -40,7 +40,7 @@ var (
"Should be provided in following format: <threshold>:<label>;<threshold>:<label>;..." + "Should be provided in following format: <threshold>:<label>;<threshold>:<label>;..." +
"For example: -40:graylist;-20:restricted;0:nopx;20:friend;", "For example: -40:graylist;-20:restricted;0:nopx;20:friend;",
Required: false, Required: false,
Value: "-40:graylist;-20:restricted;0:nopx;20:friend;", Value: "-40:<=-40;-10:<=-10;-5:<=-05;-0.05:<=-00.05;0:<=0;0.05:<=00.05;5:<=05;10:<=10;20:<=20;100:>20;",
EnvVar: p2pEnv("SCORE_BANDS"), EnvVar: p2pEnv("SCORE_BANDS"),
} }
......
...@@ -143,9 +143,9 @@ func (s *scorer) SnapshotHook() pubsub.ExtendedPeerScoreInspectFn { ...@@ -143,9 +143,9 @@ func (s *scorer) SnapshotHook() pubsub.ExtendedPeerScoreInspectFn {
} }
if topSnap, ok := snap.Topics[blocksTopicName]; ok { if topSnap, ok := snap.Topics[blocksTopicName]; ok {
diff.Blocks.TimeInMesh = float64(topSnap.TimeInMesh) / float64(time.Second) diff.Blocks.TimeInMesh = float64(topSnap.TimeInMesh) / float64(time.Second)
diff.Blocks.MeshMessageDeliveries = uint64(topSnap.MeshMessageDeliveries) diff.Blocks.MeshMessageDeliveries = topSnap.MeshMessageDeliveries
diff.Blocks.FirstMessageDeliveries = uint64(topSnap.FirstMessageDeliveries) diff.Blocks.FirstMessageDeliveries = topSnap.FirstMessageDeliveries
diff.Blocks.InvalidMessageDeliveries = uint64(topSnap.InvalidMessageDeliveries) diff.Blocks.InvalidMessageDeliveries = topSnap.InvalidMessageDeliveries
} }
if err := s.peerStore.SetScore(id, &diff); err != nil { if err := s.peerStore.SetScore(id, &diff); err != nil {
s.log.Warn("Unable to update peer gossip score", "err", err) s.log.Warn("Unable to update peer gossip score", "err", err)
......
...@@ -11,9 +11,9 @@ import ( ...@@ -11,9 +11,9 @@ import (
type TopicScores struct { type TopicScores struct {
TimeInMesh float64 `json:"timeInMesh"` // in seconds TimeInMesh float64 `json:"timeInMesh"` // in seconds
FirstMessageDeliveries uint64 `json:"firstMessageDeliveries"` FirstMessageDeliveries float64 `json:"firstMessageDeliveries"`
MeshMessageDeliveries uint64 `json:"meshMessageDeliveries"` MeshMessageDeliveries float64 `json:"meshMessageDeliveries"`
InvalidMessageDeliveries uint64 `json:"invalidMessageDeliveries"` InvalidMessageDeliveries float64 `json:"invalidMessageDeliveries"`
} }
type GossipScores struct { type GossipScores struct {
......
...@@ -14,6 +14,7 @@ import ( ...@@ -14,6 +14,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/beacon"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
...@@ -379,6 +380,13 @@ func SetBalance(addr common.Address, amount *big.Int) HeadFn { ...@@ -379,6 +380,13 @@ func SetBalance(addr common.Address, amount *big.Int) HeadFn {
} }
} }
func SetCode(addr common.Address, code hexutil.Bytes) HeadFn {
return func(headState *state.StateDB) error {
headState.SetCode(addr, code)
return nil
}
}
func SetNonce(addr common.Address, nonce uint64) HeadFn { func SetNonce(addr common.Address, nonce uint64) HeadFn {
return func(headState *state.StateDB) error { return func(headState *state.StateDB) error {
headState.SetNonce(addr, nonce) headState.SetNonce(addr, nonce)
......
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
...@@ -179,6 +180,10 @@ func addrFlag(name string, usage string) cli.GenericFlag { ...@@ -179,6 +180,10 @@ func addrFlag(name string, usage string) cli.GenericFlag {
return textFlag[*common.Address](name, usage, new(common.Address)) return textFlag[*common.Address](name, usage, new(common.Address))
} }
func bytesFlag(name string, usage string) cli.GenericFlag {
return textFlag[*hexutil.Bytes](name, usage, new(hexutil.Bytes))
}
func hashFlag(name string, usage string) cli.GenericFlag { func hashFlag(name string, usage string) cli.GenericFlag {
return textFlag[*common.Hash](name, usage, new(common.Hash)) return textFlag[*common.Hash](name, usage, new(common.Hash))
} }
...@@ -191,6 +196,10 @@ func addrFlagValue(name string, ctx *cli.Context) common.Address { ...@@ -191,6 +196,10 @@ func addrFlagValue(name string, ctx *cli.Context) common.Address {
return *ctx.Generic(name).(*TextFlag[*common.Address]).Value return *ctx.Generic(name).(*TextFlag[*common.Address]).Value
} }
func bytesFlagValue(name string, ctx *cli.Context) hexutil.Bytes {
return *ctx.Generic(name).(*TextFlag[*hexutil.Bytes]).Value
}
func hashFlagValue(name string, ctx *cli.Context) common.Hash { func hashFlagValue(name string, ctx *cli.Context) common.Hash {
return *ctx.Generic(name).(*TextFlag[*common.Hash]).Value return *ctx.Generic(name).(*TextFlag[*common.Hash]).Value
} }
...@@ -271,6 +280,17 @@ var ( ...@@ -271,6 +280,17 @@ var (
return ch.RunAndClose(cheat.SetBalance(addrFlagValue("address", ctx), bigFlagValue("balance", ctx))) return ch.RunAndClose(cheat.SetBalance(addrFlagValue("address", ctx), bigFlagValue("balance", ctx)))
}), }),
} }
CheatSetCodeCmd = cli.Command{
Name: "code",
Flags: []cli.Flag{
DataDirFlag,
addrFlag("address", "Address to change code of"),
bytesFlag("code", "New code of the account"),
},
Action: CheatAction(false, func(ctx *cli.Context, ch *cheat.Cheater) error {
return ch.RunAndClose(cheat.SetCode(addrFlagValue("address", ctx), bytesFlagValue("code", ctx)))
}),
}
CheatSetNonceCmd = cli.Command{ CheatSetNonceCmd = cli.Command{
Name: "nonce", Name: "nonce",
Flags: []cli.Flag{ Flags: []cli.Flag{
...@@ -440,6 +460,7 @@ var CheatCmd = cli.Command{ ...@@ -440,6 +460,7 @@ var CheatCmd = cli.Command{
Subcommands: []cli.Command{ Subcommands: []cli.Command{
CheatStorageCmd, CheatStorageCmd,
CheatSetBalanceCmd, CheatSetBalanceCmd,
CheatSetCodeCmd,
CheatSetNonceCmd, CheatSetNonceCmd,
CheatOvmOwnersCmd, CheatOvmOwnersCmd,
CheatPrintHeadBlock, CheatPrintHeadBlock,
......
...@@ -97,3 +97,11 @@ RUN echo "downloading and verifying Codecov uploader" && \ ...@@ -97,3 +97,11 @@ RUN echo "downloading and verifying Codecov uploader" && \
cp codecov /usr/local/bin/codecov && \ cp codecov /usr/local/bin/codecov && \
chmod +x /usr/local/bin/codecov && \ chmod +x /usr/local/bin/codecov && \
rm codecov rm codecov
RUN echo "downloading mockery tool" && \
mkdir -p mockery-tmp-dir && \
curl -o mockery-tmp-dir/mockery.tar.gz -sL https://github.com/vektra/mockery/releases/download/v2.28.1/mockery_2.28.1_Linux_x86_64.tar.gz && \
tar -xzvf mockery-tmp-dir/mockery.tar.gz -C mockery-tmp-dir && \
cp mockery-tmp-dir/mockery /usr/local/bin/mockery && \
chmod +x /usr/local/bin/mockery && \
rm -rf mockery-tmp-dir
...@@ -71,6 +71,7 @@ The following request methods are rewritten: ...@@ -71,6 +71,7 @@ The following request methods are rewritten:
* `eth_getBlockByNumber` * `eth_getBlockByNumber`
* `eth_getTransactionByBlockNumberAndIndex` * `eth_getTransactionByBlockNumberAndIndex`
* `eth_getUncleByBlockNumberAndIndex` * `eth_getUncleByBlockNumberAndIndex`
* `debug_getRawReceipts`
And `eth_blockNumber` response is overridden with current block consensus. And `eth_blockNumber` response is overridden with current block consensus.
...@@ -86,7 +87,7 @@ Cache use Redis and can be enabled for the following immutable methods: ...@@ -86,7 +87,7 @@ Cache use Redis and can be enabled for the following immutable methods:
* `eth_getBlockByHash` * `eth_getBlockByHash`
* `eth_getTransactionByBlockHashAndIndex` * `eth_getTransactionByBlockHashAndIndex`
* `eth_getUncleByBlockHashAndIndex` * `eth_getUncleByBlockHashAndIndex`
* `debug_getRawReceipts` (block hash only)
## Metrics ## Metrics
......
...@@ -2,9 +2,12 @@ package proxyd ...@@ -2,9 +2,12 @@ package proxyd
import ( import (
"context" "context"
"encoding/json"
"strings" "strings"
"time" "time"
"github.com/ethereum/go-ethereum/rpc"
"github.com/go-redis/redis/v8" "github.com/go-redis/redis/v8"
"github.com/golang/snappy" "github.com/golang/snappy"
lru "github.com/hashicorp/golang-lru" lru "github.com/hashicorp/golang-lru"
...@@ -124,6 +127,21 @@ type rpcCache struct { ...@@ -124,6 +127,21 @@ type rpcCache struct {
func newRPCCache(cache Cache) RPCCache { func newRPCCache(cache Cache) RPCCache {
staticHandler := &StaticMethodHandler{cache: cache} staticHandler := &StaticMethodHandler{cache: cache}
debugGetRawReceiptsHandler := &StaticMethodHandler{cache: cache,
filter: func(req *RPCReq) bool {
// cache only if the request is for a block hash
var p []rpc.BlockNumberOrHash
err := json.Unmarshal(req.Params, &p)
if err != nil {
return false
}
if len(p) != 1 {
return false
}
return p[0].BlockHash != nil
},
}
handlers := map[string]RPCMethodHandler{ handlers := map[string]RPCMethodHandler{
"eth_chainId": staticHandler, "eth_chainId": staticHandler,
"net_version": staticHandler, "net_version": staticHandler,
...@@ -132,6 +150,7 @@ func newRPCCache(cache Cache) RPCCache { ...@@ -132,6 +150,7 @@ func newRPCCache(cache Cache) RPCCache {
"eth_getBlockByHash": staticHandler, "eth_getBlockByHash": staticHandler,
"eth_getTransactionByBlockHashAndIndex": staticHandler, "eth_getTransactionByBlockHashAndIndex": staticHandler,
"eth_getUncleByBlockHashAndIndex": staticHandler, "eth_getUncleByBlockHashAndIndex": staticHandler,
"debug_getRawReceipts": debugGetRawReceiptsHandler,
} }
return &rpcCache{ return &rpcCache{
cache: cache, cache: cache,
......
...@@ -101,6 +101,20 @@ func TestRPCCacheImmutableRPCs(t *testing.T) { ...@@ -101,6 +101,20 @@ func TestRPCCacheImmutableRPCs(t *testing.T) {
}, },
name: "eth_getUncleByBlockHashAndIndex", name: "eth_getUncleByBlockHashAndIndex",
}, },
{
req: &RPCReq{
JSONRPC: "2.0",
Method: "debug_getRawReceipts",
Params: mustMarshalJSON([]string{"0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b"}),
ID: ID,
},
res: &RPCRes{
JSONRPC: "2.0",
Result: `{"debug_getRawReceipts":"!"}`,
ID: ID,
},
name: "debug_getRawReceipts",
},
} }
for _, rpc := range rpcs { for _, rpc := range rpcs {
...@@ -173,6 +187,15 @@ func TestRPCCacheUnsupportedMethod(t *testing.T) { ...@@ -173,6 +187,15 @@ func TestRPCCacheUnsupportedMethod(t *testing.T) {
ID: ID, ID: ID,
}, },
}, },
{
req: &RPCReq{
JSONRPC: "2.0",
Method: "debug_getRawReceipts",
Params: mustMarshalJSON([]string{"0x100"}),
ID: ID,
},
name: "debug_getRawReceipts",
},
} }
for _, rpc := range rpcs { for _, rpc := range rpcs {
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"os" "os"
"path" "path"
"testing" "testing"
"time"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
...@@ -630,6 +631,55 @@ func TestConsensus(t *testing.T) { ...@@ -630,6 +631,55 @@ func TestConsensus(t *testing.T) {
require.Equal(t, len(nodes["node2"].mockBackend.Requests()), 0, msg) require.Equal(t, len(nodes["node2"].mockBackend.Requests()), 0, msg)
}) })
t.Run("load balancing should not hit if node is degraded", func(t *testing.T) {
reset()
useOnlyNode1()
// replace node1 handler with one that adds a 500ms delay
oldHandler := nodes["node1"].mockBackend.handler
defer func() { nodes["node1"].mockBackend.handler = oldHandler }()
nodes["node1"].mockBackend.SetHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(500 * time.Millisecond)
oldHandler.ServeHTTP(w, r)
}))
update()
// send 10 requests to make node1 degraded
numberReqs := 10
for numberReqs > 0 {
_, statusCode, err := client.SendRPC("eth_getBlockByNumber", []interface{}{"0x101", false})
require.NoError(t, err)
require.Equal(t, 200, statusCode)
numberReqs--
}
// bring back node2
nodes["node2"].handler.ResetOverrides()
update()
// reset request counts
nodes["node1"].mockBackend.Reset()
nodes["node2"].mockBackend.Reset()
require.Equal(t, 0, len(nodes["node1"].mockBackend.Requests()))
require.Equal(t, 0, len(nodes["node2"].mockBackend.Requests()))
numberReqs = 10
for numberReqs > 0 {
_, statusCode, err := client.SendRPC("eth_getBlockByNumber", []interface{}{"0x101", false})
require.NoError(t, err)
require.Equal(t, 200, statusCode)
numberReqs--
}
msg := fmt.Sprintf("n1 %d, n2 %d",
len(nodes["node1"].mockBackend.Requests()), len(nodes["node2"].mockBackend.Requests()))
require.Equal(t, 0, len(nodes["node1"].mockBackend.Requests()), msg)
require.Equal(t, 10, len(nodes["node2"].mockBackend.Requests()), msg)
})
t.Run("rewrite response of eth_blockNumber", func(t *testing.T) { t.Run("rewrite response of eth_blockNumber", func(t *testing.T) {
reset() reset()
update() update()
......
...@@ -3,6 +3,7 @@ rpc_port = 8545 ...@@ -3,6 +3,7 @@ rpc_port = 8545
[backend] [backend]
response_timeout_seconds = 1 response_timeout_seconds = 1
max_degraded_latency_threshold = "30ms"
[backends] [backends]
[backends.node1] [backends.node1]
......
...@@ -17,8 +17,9 @@ type RPCMethodHandler interface { ...@@ -17,8 +17,9 @@ type RPCMethodHandler interface {
} }
type StaticMethodHandler struct { type StaticMethodHandler struct {
cache Cache cache Cache
m sync.RWMutex m sync.RWMutex
filter func(*RPCReq) bool
} }
func (e *StaticMethodHandler) key(req *RPCReq) string { func (e *StaticMethodHandler) key(req *RPCReq) string {
...@@ -33,6 +34,10 @@ func (e *StaticMethodHandler) GetRPCMethod(ctx context.Context, req *RPCReq) (*R ...@@ -33,6 +34,10 @@ func (e *StaticMethodHandler) GetRPCMethod(ctx context.Context, req *RPCReq) (*R
if e.cache == nil { if e.cache == nil {
return nil, nil return nil, nil
} }
if e.filter != nil && !e.filter(req) {
return nil, nil
}
e.m.RLock() e.m.RLock()
defer e.m.RUnlock() defer e.m.RUnlock()
...@@ -62,6 +67,9 @@ func (e *StaticMethodHandler) PutRPCMethod(ctx context.Context, req *RPCReq, res ...@@ -62,6 +67,9 @@ func (e *StaticMethodHandler) PutRPCMethod(ctx context.Context, req *RPCReq, res
if e.cache == nil { if e.cache == nil {
return nil return nil
} }
if e.filter != nil && !e.filter(req) {
return nil
}
e.m.Lock() e.m.Lock()
defer e.m.Unlock() defer e.m.Unlock()
......
...@@ -358,6 +358,14 @@ var ( ...@@ -358,6 +358,14 @@ var (
"backend_name", "backend_name",
}) })
degradedBackends = promauto.NewGaugeVec(prometheus.GaugeOpts{
Namespace: MetricsNamespace,
Name: "backend_degraded",
Help: "Bool gauge for degraded backends",
}, []string{
"backend_name",
})
networkErrorRateBackend = promauto.NewGaugeVec(prometheus.GaugeOpts{ networkErrorRateBackend = promauto.NewGaugeVec(prometheus.GaugeOpts{
Namespace: MetricsNamespace, Namespace: MetricsNamespace,
Name: "backend_error_rate", Name: "backend_error_rate",
...@@ -493,6 +501,7 @@ func RecordConsensusBackendUpdateDelay(b *Backend, lastUpdate time.Time) { ...@@ -493,6 +501,7 @@ func RecordConsensusBackendUpdateDelay(b *Backend, lastUpdate time.Time) {
func RecordBackendNetworkLatencyAverageSlidingWindow(b *Backend, avgLatency time.Duration) { func RecordBackendNetworkLatencyAverageSlidingWindow(b *Backend, avgLatency time.Duration) {
avgLatencyBackend.WithLabelValues(b.Name).Set(float64(avgLatency.Milliseconds())) avgLatencyBackend.WithLabelValues(b.Name).Set(float64(avgLatency.Milliseconds()))
degradedBackends.WithLabelValues(b.Name).Set(boolToFloat64(b.IsDegraded()))
} }
func RecordBackendNetworkErrorRateSlidingWindow(b *Backend, rate float64) { func RecordBackendNetworkErrorRateSlidingWindow(b *Backend, rate float64) {
......
...@@ -63,24 +63,26 @@ func RewriteRequest(rctx RewriteContext, req *RPCReq, res *RPCRes) (RewriteResul ...@@ -63,24 +63,26 @@ func RewriteRequest(rctx RewriteContext, req *RPCReq, res *RPCRes) (RewriteResul
case "eth_getLogs", case "eth_getLogs",
"eth_newFilter": "eth_newFilter":
return rewriteRange(rctx, req, res, 0) return rewriteRange(rctx, req, res, 0)
case "debug_getRawReceipts":
return rewriteParam(rctx, req, res, 0, true)
case "eth_getBalance", case "eth_getBalance",
"eth_getCode", "eth_getCode",
"eth_getTransactionCount", "eth_getTransactionCount",
"eth_call": "eth_call":
return rewriteParam(rctx, req, res, 1) return rewriteParam(rctx, req, res, 1, false)
case "eth_getStorageAt": case "eth_getStorageAt":
return rewriteParam(rctx, req, res, 2) return rewriteParam(rctx, req, res, 2, false)
case "eth_getBlockTransactionCountByNumber", case "eth_getBlockTransactionCountByNumber",
"eth_getUncleCountByBlockNumber", "eth_getUncleCountByBlockNumber",
"eth_getBlockByNumber", "eth_getBlockByNumber",
"eth_getTransactionByBlockNumberAndIndex", "eth_getTransactionByBlockNumberAndIndex",
"eth_getUncleByBlockNumberAndIndex": "eth_getUncleByBlockNumberAndIndex":
return rewriteParam(rctx, req, res, 0) return rewriteParam(rctx, req, res, 0, false)
} }
return RewriteNone, nil return RewriteNone, nil
} }
func rewriteParam(rctx RewriteContext, req *RPCReq, res *RPCRes, pos int) (RewriteResult, error) { func rewriteParam(rctx RewriteContext, req *RPCReq, res *RPCRes, pos int, required bool) (RewriteResult, error) {
var p []interface{} var p []interface{}
err := json.Unmarshal(req.Params, &p) err := json.Unmarshal(req.Params, &p)
if err != nil { if err != nil {
...@@ -89,9 +91,9 @@ func rewriteParam(rctx RewriteContext, req *RPCReq, res *RPCRes, pos int) (Rewri ...@@ -89,9 +91,9 @@ func rewriteParam(rctx RewriteContext, req *RPCReq, res *RPCRes, pos int) (Rewri
// we assume latest if the param is missing, // we assume latest if the param is missing,
// and we don't rewrite if there is not enough params // and we don't rewrite if there is not enough params
if len(p) == pos { if len(p) == pos && !required {
p = append(p, "latest") p = append(p, "latest")
} else if len(p) < pos { } else if len(p) <= pos {
return RewriteNone, nil return RewriteNone, nil
} }
......
...@@ -148,6 +148,74 @@ func TestRewriteRequest(t *testing.T) { ...@@ -148,6 +148,74 @@ func TestRewriteRequest(t *testing.T) {
expected: RewriteOverrideError, expected: RewriteOverrideError,
expectedErr: ErrRewriteBlockOutOfRange, expectedErr: ErrRewriteBlockOutOfRange,
}, },
/* required parameter at pos 0 */
{
name: "debug_getRawReceipts latest",
args: args{
rctx: RewriteContext{latest: hexutil.Uint64(100)},
req: &RPCReq{Method: "debug_getRawReceipts", Params: mustMarshalJSON([]string{"latest"})},
res: nil,
},
expected: RewriteOverrideRequest,
check: func(t *testing.T, args args) {
var p []string
err := json.Unmarshal(args.req.Params, &p)
require.Nil(t, err)
require.Equal(t, 1, len(p))
require.Equal(t, hexutil.Uint64(100).String(), p[0])
},
},
{
name: "debug_getRawReceipts within range",
args: args{
rctx: RewriteContext{latest: hexutil.Uint64(100)},
req: &RPCReq{Method: "debug_getRawReceipts", Params: mustMarshalJSON([]string{hexutil.Uint64(55).String()})},
res: nil,
},
expected: RewriteNone,
check: func(t *testing.T, args args) {
var p []string
err := json.Unmarshal(args.req.Params, &p)
require.Nil(t, err)
require.Equal(t, 1, len(p))
require.Equal(t, hexutil.Uint64(55).String(), p[0])
},
},
{
name: "debug_getRawReceipts out of range",
args: args{
rctx: RewriteContext{latest: hexutil.Uint64(100)},
req: &RPCReq{Method: "debug_getRawReceipts", Params: mustMarshalJSON([]string{hexutil.Uint64(111).String()})},
res: nil,
},
expected: RewriteOverrideError,
expectedErr: ErrRewriteBlockOutOfRange,
},
{
name: "debug_getRawReceipts missing parameter",
args: args{
rctx: RewriteContext{latest: hexutil.Uint64(100)},
req: &RPCReq{Method: "debug_getRawReceipts", Params: mustMarshalJSON([]string{})},
res: nil,
},
expected: RewriteNone,
},
{
name: "debug_getRawReceipts with block hash",
args: args{
rctx: RewriteContext{latest: hexutil.Uint64(100)},
req: &RPCReq{Method: "debug_getRawReceipts", Params: mustMarshalJSON([]string{"0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b"})},
res: nil,
},
expected: RewriteNone,
check: func(t *testing.T, args args) {
var p []string
err := json.Unmarshal(args.req.Params, &p)
require.Nil(t, err)
require.Equal(t, 1, len(p))
require.Equal(t, "0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b", p[0])
},
},
/* default block parameter */ /* default block parameter */
{ {
name: "eth_getCode omit block, should add", name: "eth_getCode omit block, should add",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment