translate only methods with block params
This commit is contained in:
parent
924030dd70
commit
a3cf38f8b2
@ -95,43 +95,36 @@ To support backends with different specifications in the same backend group,
|
|||||||
proxyd exposes a convenient method to fetch receipts abstracting away
|
proxyd exposes a convenient method to fetch receipts abstracting away
|
||||||
what specific backend will serve the request.
|
what specific backend will serve the request.
|
||||||
|
|
||||||
Each backend can specify their preferred method to fetch receipts with `consensus_receipts_target`.
|
Each backend specifies their preferred method to fetch receipts with `consensus_receipts_target` config,
|
||||||
|
which will be translated from `consensus_getReceipts`.
|
||||||
|
|
||||||
This method takes **both** the blockNumberOrHash **and** list of transaction hashes to fetch the receipts,
|
This method takes a `blockNumberOrHash` (i.e. `tag|qty|hash`)
|
||||||
and then after selecting the backend to serve the request,
|
and returns the receipts for all transactions in the block.
|
||||||
it translates to the correct target with the appropriate parameters.
|
|
||||||
|
|
||||||
Note that only one of the parameters will be actually used depending on the target.
|
Request example
|
||||||
|
|
||||||
Request params
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"jsonrpc":"2.0",
|
"jsonrpc":"2.0",
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"params": {
|
"params": ["0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b"]
|
||||||
"blockNumberOrHash": "0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b",
|
|
||||||
"transactions": [
|
|
||||||
"0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
|
|
||||||
"0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
It currently supports translation to the following targets:
|
It currently supports translation to the following targets:
|
||||||
* `debug_getRawReceipts(blockOrHash)` (default)
|
* `debug_getRawReceipts(blockOrHash)` (default)
|
||||||
* `alchemy_getTransactionReceipts(blockOrHash)`
|
* `alchemy_getTransactionReceipts(blockOrHash)`
|
||||||
* `eth_getTransactionReceipt(txHash)` batched
|
* `parity_getBlockReceipts(blockOrHash)`
|
||||||
|
* `eth_getBlockReceipts(blockOrHash)`
|
||||||
|
|
||||||
The selected target is returned in the response, in a wrapped result.
|
The selected target is returned in the response, in a wrapped result.
|
||||||
|
|
||||||
Response
|
Response example
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"result": {
|
"result": {
|
||||||
"method": "eth_getTransactionReceipt",
|
"method": "debug_getRawReceipts",
|
||||||
"result": {
|
"result": {
|
||||||
// the actual raw result from backend
|
// the actual raw result from backend
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
sw "github.com/ethereum-optimism/optimism/proxyd/pkg/avg-sliding-window"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/google/uuid"
|
|
||||||
|
|
||||||
sw "github.com/ethereum-optimism/optimism/proxyd/pkg/avg-sliding-window"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
@ -103,6 +101,7 @@ var (
|
|||||||
ErrBackendUnexpectedJSONRPC = errors.New("backend returned an unexpected JSON-RPC response")
|
ErrBackendUnexpectedJSONRPC = errors.New("backend returned an unexpected JSON-RPC response")
|
||||||
|
|
||||||
ErrConsensusGetReceiptsCantBeBatched = errors.New("consensus_getReceipts cannot be batched")
|
ErrConsensusGetReceiptsCantBeBatched = errors.New("consensus_getReceipts cannot be batched")
|
||||||
|
ErrConsensusGetReceiptsInvalidTarget = errors.New("unsupported consensus_receipts_target")
|
||||||
)
|
)
|
||||||
|
|
||||||
func ErrInvalidRequest(msg string) *RPCErr {
|
func ErrInvalidRequest(msg string) *RPCErr {
|
||||||
@ -252,20 +251,28 @@ type indexedReqRes struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ConsensusGetReceiptsMethod = "consensus_getReceipts"
|
const ConsensusGetReceiptsMethod = "consensus_getReceipts"
|
||||||
const ReceiptsTargetEthTransactionReceipt = "eth_getTransactionReceipt"
|
|
||||||
const ReceiptsTargetDebugGetRawReceipts = "debug_getRawReceipts"
|
|
||||||
const ReceiptsTargetGetTransactionReceipts = "alchemy_getTransactionReceipts"
|
|
||||||
|
|
||||||
type ConsensusGetReceiptsReq struct {
|
const ReceiptsTargetDebugGetRawReceipts = "debug_getRawReceipts"
|
||||||
|
const ReceiptsTargetAlchemyGetTransactionReceipts = "alchemy_getTransactionReceipts"
|
||||||
|
const ReceiptsTargetParityGetTransactionReceipts = "parity_getBlockReceipts"
|
||||||
|
const ReceiptsTargetEthGetTransactionReceipts = "eth_getBlockReceipts"
|
||||||
|
|
||||||
|
type ConsensusGetReceiptsRequest struct {
|
||||||
BlockOrHash *rpc.BlockNumberOrHash `json:"blockOrHash"`
|
BlockOrHash *rpc.BlockNumberOrHash `json:"blockOrHash"`
|
||||||
Transactions []common.Hash `json:"transactions"`
|
Transactions []common.Hash `json:"transactions"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConsensusGetReceiptsRes struct {
|
type ConsensusGetReceiptsResult struct {
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
Result interface{} `json:"result"`
|
Result interface{} `json:"result"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlockHashOrNumberParameter is a non-conventional wrapper used by alchemy_getTransactionReceipts
|
||||||
|
type BlockHashOrNumberParameter struct {
|
||||||
|
BlockHash *common.Hash `json:"blockHash"`
|
||||||
|
BlockNumber *rpc.BlockNumber `json:"blockNumber"`
|
||||||
|
}
|
||||||
|
|
||||||
func NewBackend(
|
func NewBackend(
|
||||||
name string,
|
name string,
|
||||||
rpcURL string,
|
rpcURL string,
|
||||||
@ -331,12 +338,19 @@ func (b *Backend) Forward(ctx context.Context, reqs []*RPCReq, isBatch bool) ([]
|
|||||||
switch err {
|
switch err {
|
||||||
case nil: // do nothing
|
case nil: // do nothing
|
||||||
case ErrConsensusGetReceiptsCantBeBatched:
|
case ErrConsensusGetReceiptsCantBeBatched:
|
||||||
log.Debug(
|
log.Warn(
|
||||||
"Received unsupported batch request for consensus_getReceipts",
|
"Received unsupported batch request for consensus_getReceipts",
|
||||||
"name", b.Name,
|
"name", b.Name,
|
||||||
"req_id", GetReqID(ctx),
|
"req_id", GetReqID(ctx),
|
||||||
"err", err,
|
"err", err,
|
||||||
)
|
)
|
||||||
|
case ErrConsensusGetReceiptsInvalidTarget:
|
||||||
|
log.Error(
|
||||||
|
"Unsupported consensus_receipts_target for consensus_getReceipts",
|
||||||
|
"name", b.Name,
|
||||||
|
"req_id", GetReqID(ctx),
|
||||||
|
"err", err,
|
||||||
|
)
|
||||||
// ErrBackendUnexpectedJSONRPC occurs because infura responds with a single JSON-RPC object
|
// ErrBackendUnexpectedJSONRPC occurs because infura responds with a single JSON-RPC object
|
||||||
// to a batch request whenever any Request Object in the batch would induce a partial error.
|
// to a batch request whenever any Request Object in the batch would induce a partial error.
|
||||||
// We don't label the backend offline in this case. But the error is still returned to
|
// We don't label the backend offline in this case. But the error is still returned to
|
||||||
@ -414,58 +428,56 @@ func (b *Backend) doForward(ctx context.Context, rpcReqs []*RPCReq, isBatch bool
|
|||||||
// we are concerned about network error rates, so we record 1 request independently of how many are in the batch
|
// we are concerned about network error rates, so we record 1 request independently of how many are in the batch
|
||||||
b.networkRequestsSlidingWindow.Incr()
|
b.networkRequestsSlidingWindow.Incr()
|
||||||
|
|
||||||
originalRequests := rpcReqs
|
|
||||||
translatedReqs := make(map[string]*RPCReq, len(rpcReqs))
|
translatedReqs := make(map[string]*RPCReq, len(rpcReqs))
|
||||||
derivedRequests := make([]*RPCReq, 0)
|
|
||||||
// translate consensus_getReceipts to receipts target
|
// translate consensus_getReceipts to receipts target
|
||||||
// right now we only support non-batched
|
// right now we only support non-batched
|
||||||
if !isBatch {
|
if isBatch {
|
||||||
|
for _, rpcReq := range rpcReqs {
|
||||||
|
if rpcReq.Method == ConsensusGetReceiptsMethod {
|
||||||
|
return nil, ErrConsensusGetReceiptsCantBeBatched
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
for _, rpcReq := range rpcReqs {
|
for _, rpcReq := range rpcReqs {
|
||||||
if rpcReq.Method == ConsensusGetReceiptsMethod {
|
if rpcReq.Method == ConsensusGetReceiptsMethod {
|
||||||
translatedReqs[string(rpcReq.ID)] = rpcReq
|
translatedReqs[string(rpcReq.ID)] = rpcReq
|
||||||
rpcReq.Method = b.receiptsTarget
|
rpcReq.Method = b.receiptsTarget
|
||||||
var reqParams []ConsensusGetReceiptsReq
|
var reqParams []ConsensusGetReceiptsRequest
|
||||||
err := json.Unmarshal(rpcReq.Params, &reqParams)
|
err := json.Unmarshal(rpcReq.Params, &reqParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrInvalidRequest("invalid request")
|
return nil, ErrInvalidRequest("invalid request")
|
||||||
}
|
}
|
||||||
bnh := reqParams[0].BlockOrHash
|
bnh := reqParams[0].BlockOrHash
|
||||||
switch b.receiptsTarget {
|
|
||||||
|
var translatedParams []byte
|
||||||
|
switch rpcReq.Method {
|
||||||
case ReceiptsTargetDebugGetRawReceipts,
|
case ReceiptsTargetDebugGetRawReceipts,
|
||||||
ReceiptsTargetGetTransactionReceipts: // block or hash
|
ReceiptsTargetEthGetTransactionReceipts,
|
||||||
|
ReceiptsTargetParityGetTransactionReceipts:
|
||||||
|
// conventional methods use an array of strings having either block number or block hash
|
||||||
|
// i.e. ["0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b"]
|
||||||
params := make([]string, 1)
|
params := make([]string, 1)
|
||||||
if bnh.BlockNumber != nil {
|
if bnh.BlockNumber != nil {
|
||||||
params[0] = bnh.BlockNumber.String()
|
params[0] = bnh.BlockNumber.String()
|
||||||
} else {
|
} else {
|
||||||
params[0] = bnh.BlockHash.Hex()
|
params[0] = bnh.BlockHash.Hex()
|
||||||
}
|
}
|
||||||
rawParams := mustMarshalJSON(params)
|
translatedParams = mustMarshalJSON(params)
|
||||||
rpcReq.Params = rawParams
|
case ReceiptsTargetAlchemyGetTransactionReceipts:
|
||||||
case ReceiptsTargetEthTransactionReceipt: // list of tx hashes
|
// alchemy uses an array of object with either block number or block hash
|
||||||
for _, txHash := range reqParams[0].Transactions {
|
// i.e. [{ blockHash: "0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b" }]
|
||||||
params := make([]common.Hash, 1)
|
params := make([]BlockHashOrNumberParameter, 1)
|
||||||
params[0] = txHash
|
if bnh.BlockNumber != nil {
|
||||||
rawParams := mustMarshalJSON(params)
|
params[0].BlockNumber = bnh.BlockNumber
|
||||||
randomID := mustMarshalJSON(uuid.New().String())
|
} else {
|
||||||
dReq := &RPCReq{
|
params[0].BlockHash = bnh.BlockHash
|
||||||
JSONRPC: rpcReq.JSONRPC,
|
|
||||||
Method: ReceiptsTargetEthTransactionReceipt,
|
|
||||||
Params: rawParams,
|
|
||||||
ID: randomID,
|
|
||||||
}
|
|
||||||
derivedRequests = append(derivedRequests, dReq)
|
|
||||||
}
|
}
|
||||||
|
translatedParams = mustMarshalJSON(params)
|
||||||
|
default:
|
||||||
|
return nil, ErrConsensusGetReceiptsInvalidTarget
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
rpcReq.Params = translatedParams
|
||||||
// replace the original request with the derived requests
|
|
||||||
if len(derivedRequests) > 0 {
|
|
||||||
rpcReqs = derivedRequests
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for _, rpcReq := range rpcReqs {
|
|
||||||
if rpcReq.Method == ConsensusGetReceiptsMethod {
|
|
||||||
return nil, ErrConsensusGetReceiptsCantBeBatched
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -582,33 +594,15 @@ func (b *Backend) doForward(ctx context.Context, rpcReqs []*RPCReq, isBatch bool
|
|||||||
for _, res := range rpcRes {
|
for _, res := range rpcRes {
|
||||||
translatedReq, exist := translatedReqs[string(res.ID)]
|
translatedReq, exist := translatedReqs[string(res.ID)]
|
||||||
if exist {
|
if exist {
|
||||||
res.Result = ConsensusGetReceiptsRes{
|
res.Result = ConsensusGetReceiptsResult{
|
||||||
Method: translatedReq.Method,
|
Method: translatedReq.Method,
|
||||||
Result: res.Result,
|
Result: res.Result,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sortBatchRPCResponse(rpcReqs, rpcRes)
|
sortBatchRPCResponse(rpcReqs, rpcRes)
|
||||||
|
|
||||||
// if the translated requests originated derived requests, wrap their results
|
|
||||||
if len(derivedRequests) > 0 {
|
|
||||||
results := make([]interface{}, 0, len(rpcRes))
|
|
||||||
for _, res := range rpcRes {
|
|
||||||
results = append(results, res.Result)
|
|
||||||
}
|
|
||||||
|
|
||||||
wrappedRes := &RPCRes{
|
|
||||||
JSONRPC: originalRequests[0].JSONRPC,
|
|
||||||
Result: ConsensusGetReceiptsRes{
|
|
||||||
Method: rpcReqs[0].Method,
|
|
||||||
Result: results,
|
|
||||||
},
|
|
||||||
ID: originalRequests[0].ID,
|
|
||||||
}
|
|
||||||
|
|
||||||
rpcRes = []*RPCRes{wrappedRes}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rpcRes, nil
|
return rpcRes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -728,10 +722,9 @@ func (bg *BackendGroup) Forward(ctx context.Context, rpcReqs []*RPCReq, isBatch
|
|||||||
|
|
||||||
if len(rpcReqs) > 0 {
|
if len(rpcReqs) > 0 {
|
||||||
res, err = back.Forward(ctx, rpcReqs, isBatch)
|
res, err = back.Forward(ctx, rpcReqs, isBatch)
|
||||||
if errors.Is(err, ErrConsensusGetReceiptsCantBeBatched) {
|
if errors.Is(err, ErrConsensusGetReceiptsCantBeBatched) ||
|
||||||
return nil, err
|
errors.Is(err, ErrConsensusGetReceiptsInvalidTarget) ||
|
||||||
}
|
errors.Is(err, ErrMethodNotWhitelisted) {
|
||||||
if errors.Is(err, ErrMethodNotWhitelisted) {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if errors.Is(err, ErrBackendOffline) {
|
if errors.Is(err, ErrBackendOffline) {
|
||||||
|
@ -788,6 +788,10 @@ func TestConsensus(t *testing.T) {
|
|||||||
t.Run("translate consensus_getReceipts to debug_getRawReceipts", func(t *testing.T) {
|
t.Run("translate consensus_getReceipts to debug_getRawReceipts", func(t *testing.T) {
|
||||||
reset()
|
reset()
|
||||||
useOnlyNode1()
|
useOnlyNode1()
|
||||||
|
update()
|
||||||
|
|
||||||
|
// reset request counts
|
||||||
|
nodes["node1"].mockBackend.Reset()
|
||||||
|
|
||||||
resRaw, statusCode, err := client.SendRPC("consensus_getReceipts", []interface{}{map[string]interface{}{
|
resRaw, statusCode, err := client.SendRPC("consensus_getReceipts", []interface{}{map[string]interface{}{
|
||||||
"blockOrHash": "0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b"}})
|
"blockOrHash": "0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b"}})
|
||||||
@ -811,6 +815,10 @@ func TestConsensus(t *testing.T) {
|
|||||||
t.Run("translate consensus_getReceipts to debug_getRawReceipts with latest block tag", func(t *testing.T) {
|
t.Run("translate consensus_getReceipts to debug_getRawReceipts with latest block tag", func(t *testing.T) {
|
||||||
reset()
|
reset()
|
||||||
useOnlyNode1()
|
useOnlyNode1()
|
||||||
|
update()
|
||||||
|
|
||||||
|
// reset request counts
|
||||||
|
nodes["node1"].mockBackend.Reset()
|
||||||
|
|
||||||
resRaw, statusCode, err := client.SendRPC("consensus_getReceipts", []interface{}{map[string]interface{}{
|
resRaw, statusCode, err := client.SendRPC("consensus_getReceipts", []interface{}{map[string]interface{}{
|
||||||
"blockOrHash": "latest"}})
|
"blockOrHash": "latest"}})
|
||||||
@ -834,6 +842,10 @@ func TestConsensus(t *testing.T) {
|
|||||||
t.Run("translate consensus_getReceipts to debug_getRawReceipts with block number", func(t *testing.T) {
|
t.Run("translate consensus_getReceipts to debug_getRawReceipts with block number", func(t *testing.T) {
|
||||||
reset()
|
reset()
|
||||||
useOnlyNode1()
|
useOnlyNode1()
|
||||||
|
update()
|
||||||
|
|
||||||
|
// reset request counts
|
||||||
|
nodes["node1"].mockBackend.Reset()
|
||||||
|
|
||||||
resRaw, statusCode, err := client.SendRPC("consensus_getReceipts", []interface{}{map[string]interface{}{
|
resRaw, statusCode, err := client.SendRPC("consensus_getReceipts", []interface{}{map[string]interface{}{
|
||||||
"blockOrHash": "0x55"}})
|
"blockOrHash": "0x55"}})
|
||||||
@ -854,9 +866,13 @@ func TestConsensus(t *testing.T) {
|
|||||||
require.Equal(t, "debug_getRawReceipts", resJsonMap["result"].(map[string]interface{})["result"].(map[string]interface{})["_"])
|
require.Equal(t, "debug_getRawReceipts", resJsonMap["result"].(map[string]interface{})["result"].(map[string]interface{})["_"])
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("translate consensus_getReceipts to alchemy_getTransactionReceipts", func(t *testing.T) {
|
t.Run("translate consensus_getReceipts to alchemy_getTransactionReceipts with block hash", func(t *testing.T) {
|
||||||
reset()
|
reset()
|
||||||
useOnlyNode1()
|
useOnlyNode1()
|
||||||
|
update()
|
||||||
|
|
||||||
|
// reset request counts
|
||||||
|
nodes["node1"].mockBackend.Reset()
|
||||||
|
|
||||||
nodes["node1"].backend.Override(proxyd.WithConsensusReceiptTarget("alchemy_getTransactionReceipts"))
|
nodes["node1"].backend.Override(proxyd.WithConsensusReceiptTarget("alchemy_getTransactionReceipts"))
|
||||||
defer nodes["node1"].backend.Override(proxyd.WithConsensusReceiptTarget("debug_getRawReceipts"))
|
defer nodes["node1"].backend.Override(proxyd.WithConsensusReceiptTarget("debug_getRawReceipts"))
|
||||||
@ -871,7 +887,7 @@ func TestConsensus(t *testing.T) {
|
|||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, "alchemy_getTransactionReceipts", reqJsonMap["method"])
|
require.Equal(t, "alchemy_getTransactionReceipts", reqJsonMap["method"])
|
||||||
require.Equal(t, "0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b", reqJsonMap["params"].([]interface{})[0])
|
require.Equal(t, "0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b", reqJsonMap["params"].([]interface{})[0].(map[string]interface{})["blockHash"])
|
||||||
|
|
||||||
var resJsonMap map[string]interface{}
|
var resJsonMap map[string]interface{}
|
||||||
err = json.Unmarshal(resRaw, &resJsonMap)
|
err = json.Unmarshal(resRaw, &resJsonMap)
|
||||||
@ -881,47 +897,79 @@ func TestConsensus(t *testing.T) {
|
|||||||
require.Equal(t, "alchemy_getTransactionReceipts", resJsonMap["result"].(map[string]interface{})["result"].(map[string]interface{})["_"])
|
require.Equal(t, "alchemy_getTransactionReceipts", resJsonMap["result"].(map[string]interface{})["result"].(map[string]interface{})["_"])
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("translate consensus_getReceipts to eth_getTransactionReceipt batched", func(t *testing.T) {
|
t.Run("translate consensus_getReceipts to alchemy_getTransactionReceipts with block number", func(t *testing.T) {
|
||||||
reset()
|
reset()
|
||||||
useOnlyNode1()
|
useOnlyNode1()
|
||||||
|
update()
|
||||||
|
|
||||||
nodes["node1"].backend.Override(proxyd.WithConsensusReceiptTarget("eth_getTransactionReceipt"))
|
// reset request counts
|
||||||
|
nodes["node1"].mockBackend.Reset()
|
||||||
|
|
||||||
|
nodes["node1"].backend.Override(proxyd.WithConsensusReceiptTarget("alchemy_getTransactionReceipts"))
|
||||||
defer nodes["node1"].backend.Override(proxyd.WithConsensusReceiptTarget("debug_getRawReceipts"))
|
defer nodes["node1"].backend.Override(proxyd.WithConsensusReceiptTarget("debug_getRawReceipts"))
|
||||||
|
|
||||||
resRaw, statusCode, err := client.SendRPC("consensus_getReceipts", []interface{}{map[string]interface{}{
|
resRaw, statusCode, err := client.SendRPC("consensus_getReceipts", []interface{}{map[string]interface{}{
|
||||||
"blockOrHash": "0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b",
|
"blockOrHash": "0x55"}})
|
||||||
"transactions": []string{
|
|
||||||
"0x85d995eba9763907fdf35cd2034144dd9d53ce32cbec21349d4b12823c6860c5",
|
|
||||||
"0x85d995eba9763907fdf35cd2034144dd9d53ce32cbec21349d4b12823c6860c6",
|
|
||||||
"0x85d995eba9763907fdf35cd2034144dd9d53ce32cbec21349d4b12823c6860c7",
|
|
||||||
"0x85d995eba9763907fdf35cd2034144dd9d53ce32cbec21349d4b12823c6860c8",
|
|
||||||
}}})
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 200, statusCode)
|
require.Equal(t, 200, statusCode)
|
||||||
|
|
||||||
var reqJsonMap []map[string]interface{}
|
var reqJsonMap map[string]interface{}
|
||||||
err = json.Unmarshal(nodes["node1"].mockBackend.Requests()[0].Body, &reqJsonMap)
|
err = json.Unmarshal(nodes["node1"].mockBackend.Requests()[0].Body, &reqJsonMap)
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 4, len(reqJsonMap))
|
require.Equal(t, "alchemy_getTransactionReceipts", reqJsonMap["method"])
|
||||||
for _, req := range reqJsonMap {
|
require.Equal(t, "0x55", reqJsonMap["params"].([]interface{})[0].(map[string]interface{})["blockNumber"])
|
||||||
require.Equal(t, "eth_getTransactionReceipt", req["method"])
|
|
||||||
}
|
|
||||||
require.Equal(t, "0x85d995eba9763907fdf35cd2034144dd9d53ce32cbec21349d4b12823c6860c5", reqJsonMap[0]["params"].([]interface{})[0])
|
|
||||||
require.Equal(t, "0x85d995eba9763907fdf35cd2034144dd9d53ce32cbec21349d4b12823c6860c6", reqJsonMap[1]["params"].([]interface{})[0])
|
|
||||||
require.Equal(t, "0x85d995eba9763907fdf35cd2034144dd9d53ce32cbec21349d4b12823c6860c7", reqJsonMap[2]["params"].([]interface{})[0])
|
|
||||||
require.Equal(t, "0x85d995eba9763907fdf35cd2034144dd9d53ce32cbec21349d4b12823c6860c8", reqJsonMap[3]["params"].([]interface{})[0])
|
|
||||||
|
|
||||||
var resJsonMap map[string]interface{}
|
var resJsonMap map[string]interface{}
|
||||||
err = json.Unmarshal(resRaw, &resJsonMap)
|
err = json.Unmarshal(resRaw, &resJsonMap)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Equal(t, "eth_getTransactionReceipt", resJsonMap["result"].(map[string]interface{})["method"].(string))
|
require.Equal(t, "alchemy_getTransactionReceipts", resJsonMap["result"].(map[string]interface{})["method"].(string))
|
||||||
require.Equal(t, 4, len(resJsonMap["result"].(map[string]interface{})["result"].([]interface{})))
|
require.Equal(t, "alchemy_getTransactionReceipts", resJsonMap["result"].(map[string]interface{})["result"].(map[string]interface{})["_"])
|
||||||
for _, res := range resJsonMap["result"].(map[string]interface{})["result"].([]interface{}) {
|
})
|
||||||
require.Equal(t, "eth_getTransactionReceipt", res.(map[string]interface{})["_"])
|
|
||||||
}
|
|
||||||
|
|
||||||
|
t.Run("translate consensus_getReceipts to alchemy_getTransactionReceipts with latest block tag", func(t *testing.T) {
|
||||||
|
reset()
|
||||||
|
useOnlyNode1()
|
||||||
|
update()
|
||||||
|
|
||||||
|
// reset request counts
|
||||||
|
nodes["node1"].mockBackend.Reset()
|
||||||
|
|
||||||
|
nodes["node1"].backend.Override(proxyd.WithConsensusReceiptTarget("alchemy_getTransactionReceipts"))
|
||||||
|
defer nodes["node1"].backend.Override(proxyd.WithConsensusReceiptTarget("debug_getRawReceipts"))
|
||||||
|
|
||||||
|
resRaw, statusCode, err := client.SendRPC("consensus_getReceipts", []interface{}{map[string]interface{}{
|
||||||
|
"blockOrHash": "latest"}})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 200, statusCode)
|
||||||
|
|
||||||
|
var reqJsonMap map[string]interface{}
|
||||||
|
err = json.Unmarshal(nodes["node1"].mockBackend.Requests()[0].Body, &reqJsonMap)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "alchemy_getTransactionReceipts", reqJsonMap["method"])
|
||||||
|
require.Equal(t, "0x101", reqJsonMap["params"].([]interface{})[0].(map[string]interface{})["blockNumber"])
|
||||||
|
|
||||||
|
var resJsonMap map[string]interface{}
|
||||||
|
err = json.Unmarshal(resRaw, &resJsonMap)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, "alchemy_getTransactionReceipts", resJsonMap["result"].(map[string]interface{})["method"].(string))
|
||||||
|
require.Equal(t, "alchemy_getTransactionReceipts", resJsonMap["result"].(map[string]interface{})["result"].(map[string]interface{})["_"])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("translate consensus_getReceipts to unsupported consensus_receipts_target", func(t *testing.T) {
|
||||||
|
reset()
|
||||||
|
useOnlyNode1()
|
||||||
|
|
||||||
|
nodes["node1"].backend.Override(proxyd.WithConsensusReceiptTarget("unsupported_consensus_receipts_target"))
|
||||||
|
defer nodes["node1"].backend.Override(proxyd.WithConsensusReceiptTarget("debug_getRawReceipts"))
|
||||||
|
|
||||||
|
_, statusCode, err := client.SendRPC("consensus_getReceipts", []interface{}{map[string]interface{}{
|
||||||
|
"blockOrHash": "latest"}})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 400, statusCode)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("consensus_getReceipts should not be used in a batch", func(t *testing.T) {
|
t.Run("consensus_getReceipts should not be used in a batch", func(t *testing.T) {
|
||||||
|
@ -347,7 +347,8 @@ func (s *Server) HandleRPC(w http.ResponseWriter, r *http.Request) {
|
|||||||
writeRPCError(ctx, w, nil, ErrGatewayTimeout)
|
writeRPCError(ctx, w, nil, ErrGatewayTimeout)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if errors.Is(err, ErrConsensusGetReceiptsCantBeBatched) {
|
if errors.Is(err, ErrConsensusGetReceiptsCantBeBatched) ||
|
||||||
|
errors.Is(err, ErrConsensusGetReceiptsInvalidTarget) {
|
||||||
writeRPCError(ctx, w, nil, ErrInvalidRequest(err.Error()))
|
writeRPCError(ctx, w, nil, ErrInvalidRequest(err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -364,6 +365,11 @@ func (s *Server) HandleRPC(w http.ResponseWriter, r *http.Request) {
|
|||||||
rawBody := json.RawMessage(body)
|
rawBody := json.RawMessage(body)
|
||||||
backendRes, cached, err := s.handleBatchRPC(ctx, []json.RawMessage{rawBody}, isLimited, false)
|
backendRes, cached, err := s.handleBatchRPC(ctx, []json.RawMessage{rawBody}, isLimited, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, ErrConsensusGetReceiptsCantBeBatched) ||
|
||||||
|
errors.Is(err, ErrConsensusGetReceiptsInvalidTarget) {
|
||||||
|
writeRPCError(ctx, w, nil, ErrInvalidRequest(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
writeRPCError(ctx, w, nil, ErrInternal)
|
writeRPCError(ctx, w, nil, ErrInternal)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -489,7 +495,8 @@ func (s *Server) handleBatchRPC(ctx context.Context, reqs []json.RawMessage, isL
|
|||||||
elems := cacheMisses[start:end]
|
elems := cacheMisses[start:end]
|
||||||
res, err := s.BackendGroups[group.backendGroup].Forward(ctx, createBatchRequest(elems), isBatch)
|
res, err := s.BackendGroups[group.backendGroup].Forward(ctx, createBatchRequest(elems), isBatch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, ErrConsensusGetReceiptsCantBeBatched) {
|
if errors.Is(err, ErrConsensusGetReceiptsCantBeBatched) ||
|
||||||
|
errors.Is(err, ErrConsensusGetReceiptsInvalidTarget) {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
log.Error(
|
log.Error(
|
||||||
|
Loading…
Reference in New Issue
Block a user