Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests to jsonrpc, to assure our jsonrpc clients behave as expected. #70

Merged
merged 5 commits into from
Jul 30, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add tests to jsonrpc, starting w/ opstack
msf committed Jul 26, 2024
commit 1e706b6b8bf49691b8c4665fde9567683f9df754
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@ test:
CGO_ENABLED=1 go test -timeout=$(TEST_TIMEOUT) -race -bench=. -benchmem -cover ./...

gen-mocks: bin/moq ./client/jsonrpc/ ./client/duneapi/
./bin/moq -pkg jsonrpc_mock -out ./mocks/jsonrpc/httpclient.go ./client/jsonrpc HTTPClient
./bin/moq -pkg jsonrpc_mock -out ./mocks/jsonrpc/rpcnode.go ./client/jsonrpc BlockchainClient
./bin/moq -pkg duneapi_mock -out ./mocks/duneapi/client.go ./client/duneapi BlockchainIngester

9 changes: 0 additions & 9 deletions client/jsonrpc/arbitrum_nitro.go
Original file line number Diff line number Diff line change
@@ -5,7 +5,6 @@ import (
"context"
"encoding/json"
"fmt"
"log/slog"
"time"

"github.com/duneanalytics/blockchain-ingester/models"
@@ -18,14 +17,6 @@ type ArbitrumNitroClient struct {

var _ BlockchainClient = &ArbitrumNitroClient{}

func NewArbitrumNitroClient(log *slog.Logger, cfg Config) (*ArbitrumNitroClient, error) {
rpcClient, err := newClient(log.With("module", "jsonrpc"), cfg)
if err != nil {
return nil, err
}
return &ArbitrumNitroClient{*rpcClient}, nil
}

// BlockByNumber returns the block with the given blockNumber.
// it uses 3 different methods to get the block:
// 1. eth_getBlockByNumber
45 changes: 18 additions & 27 deletions client/jsonrpc/client.go
Original file line number Diff line number Diff line change
@@ -29,44 +29,36 @@ const (
)

type rpcClient struct {
client *retryablehttp.Client
cfg Config
log *slog.Logger
bufPool *sync.Pool
cfg Config
client HTTPClient
httpHeaders map[string]string
log *slog.Logger
wrkPool *ants.Pool
}

func NewClient(logger *slog.Logger, cfg Config) (BlockchainClient, error) {
func NewClient(log *slog.Logger, cfg Config) (BlockchainClient, error) {
// use the production http client w/ retries
return NewRPCClient(log, NewHTTPClient(log), cfg)
}

func NewRPCClient(log *slog.Logger, client HTTPClient, cfg Config) (BlockchainClient, error) {
rpcClient, err := newClient(log.With("module", "jsonrpc"), client, cfg)
if err != nil {
return nil, err
}
switch cfg.EVMStack {
case models.OpStack:
return NewOpStackClient(logger, cfg)
return &OpStackClient{*rpcClient}, nil
case models.ArbitrumNitro:
return NewArbitrumNitroClient(logger, cfg)
return &ArbitrumNitroClient{*rpcClient}, nil
default:
return nil, fmt.Errorf("unsupported EVM stack: %s", cfg.EVMStack)
}
}

func newClient(log *slog.Logger, cfg Config) (*rpcClient, error) { // revive:disable-line:unexported-return
client := retryablehttp.NewClient()
client.RetryMax = MaxRetries
client.Logger = log
checkRetry := func(ctx context.Context, resp *http.Response, err error) (bool, error) {
yes, err2 := retryablehttp.DefaultRetryPolicy(ctx, resp, err)
if yes {
if resp == nil {
log.Warn("Retrying request to RPC client", "error", err2)
} else {
log.Warn("Retrying request to RPC client", "statusCode", resp.Status, "error", err2)
}
}
return yes, err2
}
client.CheckRetry = checkRetry
client.Backoff = retryablehttp.LinearJitterBackoff
client.HTTPClient.Timeout = DefaultRequestTimeout

func newClient(log *slog.Logger, client HTTPClient, cfg Config,
) (*rpcClient, error) { // revive:disable-line:unexported-return
if cfg.TotalRPCConcurrency == 0 {
cfg.TotalRPCConcurrency = DefaultMaxRPCConcurrency
}
@@ -98,8 +90,7 @@ func newClient(log *slog.Logger, cfg Config) (*rpcClient, error) { // revive:dis

func (c *rpcClient) LatestBlockNumber() (int64, error) {
buf := c.bufPool.Get().(*bytes.Buffer)
defer c.bufPool.Put(buf)
buf.Reset()
defer c.putBuffer(buf)

err := c.getResponseBody(context.Background(), "eth_blockNumber", []any{}, buf)
if err != nil {
34 changes: 34 additions & 0 deletions client/jsonrpc/httpclient.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package jsonrpc

import (
"context"
"log/slog"
"net/http"

"github.com/hashicorp/go-retryablehttp"
)

type HTTPClient interface {
Do(req *retryablehttp.Request) (*http.Response, error)
}

func NewHTTPClient(log *slog.Logger) *retryablehttp.Client {
client := retryablehttp.NewClient()
client.RetryMax = MaxRetries
client.Logger = log
checkRetry := func(ctx context.Context, resp *http.Response, err error) (bool, error) {
yes, err2 := retryablehttp.DefaultRetryPolicy(ctx, resp, err)
if yes {
if resp == nil {
log.Warn("Retrying request to RPC client", "error", err2)
} else {
log.Warn("Retrying request to RPC client", "statusCode", resp.Status, "error", err2)
}
}
return yes, err2
}
client.CheckRetry = checkRetry
client.Backoff = retryablehttp.LinearJitterBackoff
client.HTTPClient.Timeout = DefaultRequestTimeout
return client
}
110 changes: 110 additions & 0 deletions client/jsonrpc/httpclient_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package jsonrpc_test

import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"log/slog"
"net/http"
"os"

"github.com/davecgh/go-spew/spew"
"github.com/duneanalytics/blockchain-ingester/client/jsonrpc"
jsonrpc_mock "github.com/duneanalytics/blockchain-ingester/mocks/jsonrpc"
"github.com/duneanalytics/blockchain-ingester/models"
"github.com/hashicorp/go-retryablehttp"
)

type jsonRPCRequest struct {
Method string `json:"method"`
Params []interface{} `json:"params"`
HTTPHeaders http.Header
}

type jsonRPCResponse struct {
Body io.Reader
StatusCode int // optional, default to 200
ContentType string // optional, default to "application/json"
}

type MockedRequest struct {
Req jsonRPCRequest
Resp jsonRPCResponse
}

func MockHTTPRequests(requests []MockedRequest) *jsonrpc_mock.HTTPClientMock {
return &jsonrpc_mock.HTTPClientMock{
DoFunc: func(req *retryablehttp.Request) (*http.Response, error) {
if req.Method != http.MethodPost {
return nil, fmt.Errorf("expected POST method, got %s", req.Method)
}
// we use httpretryable.Client, so we can't use req.Body directly
// we need to read the body and then reset it

body, err := req.BodyBytes()
if err != nil {
return nil, err
}
var jsonReq jsonRPCRequest
if err := json.Unmarshal(body, &jsonReq); err != nil {
return nil, err
}
jsonReqParams := fmt.Sprintf("%+v", jsonReq.Params)
// looking for a matching request
for _, r := range requests {
if r.Req.Method == jsonReq.Method {
// we do this because reflect.DeepEquals() Comparison fails on map[string]any != map[string]string
if jsonReqParams != fmt.Sprintf("%+v", r.Req.Params) {
continue
}
// this is a match, validate registered headers
for k, v := range r.Req.HTTPHeaders {
if req.Header.Get(k) != v[0] {
return nil, fmt.Errorf("expected header %s to be %s, got %s", k, v[0], req.Header.Get(k))
}
}
// all headers match, return the response
resp := &http.Response{
StatusCode: 200,
Body: io.NopCloser(r.Resp.Body),
Header: make(http.Header),
}
if r.Resp.StatusCode != 0 {
resp.StatusCode = r.Resp.StatusCode
}
resp.Header.Set("Content-Type", "application/json")
if r.Resp.ContentType != "" {
resp.Header.Set("Content-Type", r.Resp.ContentType)
}
return resp, nil
}
}
if jsonReq.Method == "eth_blockNumber" {
resp := &http.Response{
StatusCode: 200,
Body: io.NopCloser(bytes.NewReader([]byte(`{"jsonrpc":"2.0","id":1,"result":"0x7a549b"}`))),
}
return resp, nil
}
return nil, fmt.Errorf("no matching request found, req: %+v", jsonReq)
},
}
}

func NewTestLogger() *slog.Logger {
return slog.New(slog.NewTextHandler(io.Discard, nil))
}

func NewTestRPCClient(httpClient jsonrpc.HTTPClient, stack models.EVMStack) (jsonrpc.BlockchainClient, error) {
return jsonrpc.NewRPCClient(NewTestLogger(), httpClient, jsonrpc.Config{EVMStack: stack})
}

func readFileForTest(filename string) *bytes.Buffer {
data, err := os.ReadFile(filename)
if err != nil {
log.Panicf("Failed to read file: %v", err)
}
return bytes.NewBuffer(data)
}
9 changes: 0 additions & 9 deletions client/jsonrpc/opstack.go
Original file line number Diff line number Diff line change
@@ -4,7 +4,6 @@ import (
"bytes"
"context"
"fmt"
"log/slog"
"time"

"github.com/duneanalytics/blockchain-ingester/models"
@@ -17,14 +16,6 @@ type OpStackClient struct {

var _ BlockchainClient = &OpStackClient{}

func NewOpStackClient(log *slog.Logger, cfg Config) (*OpStackClient, error) {
rpcClient, err := newClient(log.With("module", "jsonrpc"), cfg)
if err != nil {
return nil, err
}
return &OpStackClient{*rpcClient}, nil
}

// BlockByNumber returns the block with the given blockNumber.
// it uses 3 different methods to get the block:
// 1. eth_getBlockByNumber
56 changes: 56 additions & 0 deletions client/jsonrpc/opstack_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package jsonrpc_test

import (
"context"
"testing"

"github.com/duneanalytics/blockchain-ingester/models"
"github.com/stretchr/testify/require"
)

func TestOpStackBasic(t *testing.T) {
getBlockByNumberResponse := readFileForTest("testdata/opstack-eth_getBlockByNumber.json")
getBlockReceiptsResponse := readFileForTest("testdata/opstack-eth_getBlockReceipts.json")
debugtraceBlockByNumberResponse := readFileForTest("testdata/opstack-debug_traceBlockByNumber.json")
blockNumberHex := "0x7a549b"
blockNumber := int64(8017051)
httpClientMock := MockHTTPRequests(
[]MockedRequest{
{
Req: jsonRPCRequest{
Method: "eth_getBlockByNumber",
Params: []interface{}{blockNumberHex, true},
},
Resp: jsonRPCResponse{
Body: getBlockByNumberResponse,
},
},
{
Req: jsonRPCRequest{
Method: "eth_getBlockReceipts",
Params: []interface{}{blockNumberHex},
},
Resp: jsonRPCResponse{
Body: getBlockReceiptsResponse,
},
},
{
Req: jsonRPCRequest{
Method: "debug_traceBlockByNumber",
Params: []interface{}{blockNumberHex, map[string]string{"tracer": "callTracer"}},
},
Resp: jsonRPCResponse{
Body: debugtraceBlockByNumberResponse,
},
},
})

opstack, err := NewTestRPCClient(httpClientMock, models.OpStack)
require.NoError(t, err)

block, err := opstack.BlockByNumber(context.Background(), blockNumber)
require.NoError(t, err)
require.NotNil(t, block)
require.Equal(t, blockNumber, block.BlockNumber)
require.False(t, block.Errored())
}
2,667 changes: 2,667 additions & 0 deletions client/jsonrpc/testdata/opstack-debug_traceBlockByNumber.json

Large diffs are not rendered by default.

155 changes: 155 additions & 0 deletions client/jsonrpc/testdata/opstack-eth_getBlockByNumber.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
{
"jsonrpc": "2.0",
"result": {
"baseFeePerGas": "0x13a2",
"blobGasUsed": "0x0",
"difficulty": "0x0",
"excessBlobGas": "0x0",
"extraData": "0x",
"gasLimit": "0x1c9c380",
"gasUsed": "0x442974",
"hash": "0x4dc3e5326b8d6e7eb4d0a9220381d911b09431a2b27ee6ab06a6249a5195f436",
"logsBloom": "0x00000000000000000000000000000002000000000000000000008000000000000000000000000000000000004000000000000000000000000000000000000000000000000000100000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001020000000000000000000000000000000000000002000001000000000000000000100100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000",
"miner": "0x4200000000000000000000000000000000000011",
"mixHash": "0x134657ec80b014632c560af436524a999ec3e3961e9911d21fb413f050b12d2f",
"nonce": "0x0000000000000000",
"number": "0x7a549b",
"parentBeaconBlockRoot": "0xd38373593b0d5e9eb20998264fde22b642f6658f7a2975897a7ade285e4b4daf",
"parentHash": "0x98b4922cd437bbd00d09c72eaa4569de934918cb52ddfcf5c765928d86f96306",
"receiptsRoot": "0xaec6d23829974cc7f55ab728fe1e87615d195fc5d0460fd5d42febfd892ba298",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"size": "0x5fe",
"stateRoot": "0xed73bfa7d6bc0535f1b1318d1ae58983ade52d55c5005c3257fa66e5a930ce09",
"timestamp": "0x664b28d5",
"totalDifficulty": "0x0",
"transactions": [
{
"blockHash": "0x4dc3e5326b8d6e7eb4d0a9220381d911b09431a2b27ee6ab06a6249a5195f436",
"blockNumber": "0x7a549b",
"depositReceiptVersion": "0x1",
"from": "0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001",
"gas": "0xf4240",
"gasPrice": "0x0",
"hash": "0x6711626fa36243fc18c0f8bac16ab9fcf017c35ec6e340a495ec16151e453757",
"input": "0x440a5e2000004e2000095506000000000000000000000000664b289700000000012fcfc700000000000000000000000000000000000000000000000000000001d6fedf000000000000000000000000000000000000000000000000000000000000000001b7c4005bbc6eee3d76205edaacc42eca5c8fbac4b6b3e0affcd75a864b43bc8000000000000000000000000099199a22125034c808ff20f377d91187e8050f2e",
"mint": "0x0",
"nonce": "0x7a549b",
"r": "0x0",
"s": "0x0",
"sourceHash": "0x5cde6945af90e967d107d56df1c22d0f2844047a38cf655bebfb4ed38e8832a0",
"to": "0x4200000000000000000000000000000000000015",
"transactionIndex": "0x0",
"type": "0x7e",
"v": "0x0",
"value": "0x0"
},
{
"blockHash": "0x4dc3e5326b8d6e7eb4d0a9220381d911b09431a2b27ee6ab06a6249a5195f436",
"blockNumber": "0x7a549b",
"chainId": "0x868b",
"from": "0x3342ac381db93eb7768d093e2f1231a2da425d0d",
"gas": "0x5eef",
"gasPrice": "0x10de7b",
"hash": "0x9e88acd51d0f1f2244d278026376105b6b6569b5395c48aa52f2030f866734ef",
"input": "0x646174613a2c7b2270223a226d6f64652d3230222c226f70223a226d696e74222c227469636b223a226d6f646573222c22616d74223a2231227d",
"nonce": "0x24b",
"r": "0x90df8b4c39cc49b799e9eb1efaff48a3037b97cbda14553a221a02b991551c2a",
"s": "0x43abc34cce779a1affc0e9bd5a5a4f213a0361dabaac299cd0668d6c7e9b5a57",
"to": "0x3342ac381db93eb7768d093e2f1231a2da425d0d",
"transactionIndex": "0x1",
"type": "0x0",
"v": "0x10d3a",
"value": "0x0"
},
{
"accessList": [],
"blockHash": "0x4dc3e5326b8d6e7eb4d0a9220381d911b09431a2b27ee6ab06a6249a5195f436",
"blockNumber": "0x7a549b",
"chainId": "0x868b",
"from": "0x8677f549789e7981f76d4d80c7c54b2dfaa060af",
"gas": "0x22047",
"gasPrice": "0x19a42",
"hash": "0x6aef02d81df05983cbd528a7e1d57696cef3f0f3f5f7a8c5a9b1f7d4b6a6d8bd",
"input": "0x17835d1c000000000000000000000000000000000000000000000000002f61ab04005df300000000000000000000000000000000000000000000000000000000664b28cf",
"maxFeePerGas": "0x5968564a",
"maxPriorityFeePerGas": "0x186a0",
"nonce": "0x12510",
"r": "0x31ad32847e970beb40026e6f11ebcbc9eb40d0b8cf78976281400cf43c3bfb2b",
"s": "0x153b2f2741f9afceb91b9fd45915673092f52c794a39f7ccc185915d0d76ba5d",
"to": "0x3180341afdd106f14d224ec96c9a17420ab5f33d",
"transactionIndex": "0x2",
"type": "0x2",
"v": "0x0",
"value": "0x0",
"yParity": "0x0"
},
{
"accessList": [],
"blockHash": "0x4dc3e5326b8d6e7eb4d0a9220381d911b09431a2b27ee6ab06a6249a5195f436",
"blockNumber": "0x7a549b",
"chainId": "0x868b",
"from": "0x5a178ae7d1e3fc42a8425a0c455e3b6c3157ff0c",
"gas": "0x1ab3f00",
"gasPrice": "0x2710",
"hash": "0x310b151c69b810e900cd72c6b0335d8e9dafb783e793eae48b72aa3b6314a704",
"input": "0x00",
"maxFeePerGas": "0x2710",
"maxPriorityFeePerGas": "0x270f",
"nonce": "0x1e59f",
"r": "0x2a307446b54789023633695694108ff5d1c02dc37fa87dd31d7750a134353ee8",
"s": "0x1e5a395c8e0f6943ff04f4d1db127887e6961aed6d8fce80d9a677a73fb065ba",
"to": "0xe6dce473803a7fee2805f02c0140ce01bc738186",
"transactionIndex": "0x3",
"type": "0x2",
"v": "0x0",
"value": "0x0",
"yParity": "0x0"
},
{
"blockHash": "0x4dc3e5326b8d6e7eb4d0a9220381d911b09431a2b27ee6ab06a6249a5195f436",
"blockNumber": "0x7a549b",
"chainId": "0x868b",
"from": "0x93df6a148a6dd5b162ae1f49d03a981e13afc8f5",
"gas": "0x1312d00",
"gasPrice": "0x2710",
"hash": "0x27c04bd94b2404b0e9b898394c72cdf95471f2a4a57ca563be44a899d9b91a9a",
"input": "0x00000000",
"nonce": "0x29a2c",
"r": "0xd58aa4ca52e46514b9ceb18502775ac0fb1653721b8fd0fc36cf52c0031b52b",
"s": "0xdf6eea19e8925e5618509d8b1b68d58fb43c70c593a743f1ac712b2cbf9ec2c",
"to": "0x4397da4e02198b79e6934ad10e395d43816b553d",
"transactionIndex": "0x4",
"type": "0x0",
"v": "0x10d3a",
"value": "0x0"
},
{
"accessList": [],
"blockHash": "0x4dc3e5326b8d6e7eb4d0a9220381d911b09431a2b27ee6ab06a6249a5195f436",
"blockNumber": "0x7a549b",
"chainId": "0x868b",
"from": "0x1e8248888f342a4fdc91b4de3a883193dc8539bb",
"gas": "0x12e1fc0",
"gasPrice": "0x13a3",
"hash": "0x42c16a4a0d2129017f90755da9727d1a77e2d4ae3289489c0ce356b414941746",
"input": "0x4e71d92d",
"maxFeePerGas": "0x5f6084a",
"maxPriorityFeePerGas": "0x1",
"nonce": "0x27320",
"r": "0xce51449548a7d61c6db165e3d03ed629c21733971f1daae3d9f1ac9248733381",
"s": "0x1b9b2dbe8ceed702f54b3c124dfb72405f6ea26357c58a056b983aee4c00a4d0",
"to": "0x2d58e04e43411c58e781339d70f8ebe05aa17b68",
"transactionIndex": "0x5",
"type": "0x2",
"v": "0x0",
"value": "0x0",
"yParity": "0x0"
}
],
"transactionsRoot": "0xb710d62aa870d3c6b90f1ef85e285ac91e23f3bcc61f1d181d22ee884f65bd98",
"uncles": [],
"withdrawals": [],
"withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
},
"id": 1
}
172 changes: 172 additions & 0 deletions client/jsonrpc/testdata/opstack-eth_getBlockReceipts.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
{
"jsonrpc": "2.0",
"result": [
{
"blockHash": "0x4dc3e5326b8d6e7eb4d0a9220381d911b09431a2b27ee6ab06a6249a5195f436",
"blockNumber": "0x7a549b",
"contractAddress": null,
"cumulativeGasUsed": "0xcbf7",
"depositNonce": "0x7a549b",
"depositReceiptVersion": "0x1",
"effectiveGasPrice": "0x0",
"from": "0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001",
"gasUsed": "0xcbf7",
"logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1",
"to": "0x4200000000000000000000000000000000000015",
"transactionHash": "0x6711626fa36243fc18c0f8bac16ab9fcf017c35ec6e340a495ec16151e453757",
"transactionIndex": "0x0",
"type": "0x7e"
},
{
"blockHash": "0x4dc3e5326b8d6e7eb4d0a9220381d911b09431a2b27ee6ab06a6249a5195f436",
"blockNumber": "0x7a549b",
"contractAddress": null,
"cumulativeGasUsed": "0x1219f",
"effectiveGasPrice": "0x10de7b",
"from": "0x3342ac381db93eb7768d093e2f1231a2da425d0d",
"gasUsed": "0x55a8",
"l1Fee": "0x608dd93c8d",
"l1GasPrice": "0x1d6fedf00",
"l1GasUsed": "0xa40",
"logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1",
"to": "0x3342ac381db93eb7768d093e2f1231a2da425d0d",
"transactionHash": "0x9e88acd51d0f1f2244d278026376105b6b6569b5395c48aa52f2030f866734ef",
"transactionIndex": "0x1",
"type": "0x0"
},
{
"blockHash": "0x4dc3e5326b8d6e7eb4d0a9220381d911b09431a2b27ee6ab06a6249a5195f436",
"blockNumber": "0x7a549b",
"contractAddress": null,
"cumulativeGasUsed": "0x33d7b",
"effectiveGasPrice": "0x19a42",
"from": "0x8677f549789e7981f76d4d80c7c54b2dfaa060af",
"gasUsed": "0x21bdc",
"l1Fee": "0x53e5661f8a",
"l1GasPrice": "0x1d6fedf00",
"l1GasUsed": "0x8e8",
"logs": [
{
"address": "0x3180341afdd106f14d224ec96c9a17420ab5f33d",
"blockHash": "0x4dc3e5326b8d6e7eb4d0a9220381d911b09431a2b27ee6ab06a6249a5195f436",
"blockNumber": "0x7a549b",
"data": "0x000000000000000000000000cdd475325d6f564d27247d1dddbb0dac6fa0a5cf00000000000000000000000000000000000cea5044471bf5a7169dace880000000000000000000000000000000000000000ced28894f0dac2b3cb76828000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008da",
"logIndex": "0x0",
"removed": false,
"topics": [
"0x23b9387f81fca646aac1dc4487ede045c65f5f7445482906565f01e05afdb3a8"
],
"transactionHash": "0x6aef02d81df05983cbd528a7e1d57696cef3f0f3f5f7a8c5a9b1f7d4b6a6d8bd",
"transactionIndex": "0x2"
},
{
"address": "0x1d610fd6a8cb065658c7e6ce5ea268310dc8043e",
"blockHash": "0x4dc3e5326b8d6e7eb4d0a9220381d911b09431a2b27ee6ab06a6249a5195f436",
"blockNumber": "0x7a549b",
"data": "0x000000000000000000000000cdd475325d6f564d27247d1dddbb0dac6fa0a5cf00000000000000000000000000000000000cede883782b9b651fda18380000000000000000000000000000003180341afdd106f14d224ec96c9a17420ab5f33d",
"logIndex": "0x1",
"removed": false,
"topics": [
"0xc37a77b91cc3fc2d0e4b43fd2f347ec67adda10e39215de4742836cc3e42c97a"
],
"transactionHash": "0x6aef02d81df05983cbd528a7e1d57696cef3f0f3f5f7a8c5a9b1f7d4b6a6d8bd",
"transactionIndex": "0x2"
},
{
"address": "0x3180341afdd106f14d224ec96c9a17420ab5f33d",
"blockHash": "0x4dc3e5326b8d6e7eb4d0a9220381d911b09431a2b27ee6ab06a6249a5195f436",
"blockNumber": "0x7a549b",
"data": "0x000000000000000000000000420000000000000000000000000000000000000600000000000000000000000000000000000099059e68e694a21e2c04d6800000000000000000000000000000000000000000990249e930e17af3272730000000000000000000000000000000000000000000000000000000000000000000054600000000000000000000000000000000000000000000000000000000000016b8",
"logIndex": "0x2",
"removed": false,
"topics": [
"0x23b9387f81fca646aac1dc4487ede045c65f5f7445482906565f01e05afdb3a8"
],
"transactionHash": "0x6aef02d81df05983cbd528a7e1d57696cef3f0f3f5f7a8c5a9b1f7d4b6a6d8bd",
"transactionIndex": "0x2"
},
{
"address": "0x1d610fd6a8cb065658c7e6ce5ea268310dc8043e",
"blockHash": "0x4dc3e5326b8d6e7eb4d0a9220381d911b09431a2b27ee6ab06a6249a5195f436",
"blockNumber": "0x7a549b",
"data": "0x00000000000000000000000042000000000000000000000000000000000000060000000000000000000000000000000000009919122e32544c0b5496f80000000000000000000000000000003180341afdd106f14d224ec96c9a17420ab5f33d",
"logIndex": "0x3",
"removed": false,
"topics": [
"0xc37a77b91cc3fc2d0e4b43fd2f347ec67adda10e39215de4742836cc3e42c97a"
],
"transactionHash": "0x6aef02d81df05983cbd528a7e1d57696cef3f0f3f5f7a8c5a9b1f7d4b6a6d8bd",
"transactionIndex": "0x2"
}
],
"logsBloom": "0x00000000000000000000000000000002000000000000000000008000000000000000000000000000000000004000000000000000000000000000000000000000000000000000100000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001020000000000000000000000000000000000000002000001000000000000000000100100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000",
"status": "0x1",
"to": "0x3180341afdd106f14d224ec96c9a17420ab5f33d",
"transactionHash": "0x6aef02d81df05983cbd528a7e1d57696cef3f0f3f5f7a8c5a9b1f7d4b6a6d8bd",
"transactionIndex": "0x2",
"type": "0x2"
},
{
"blockHash": "0x4dc3e5326b8d6e7eb4d0a9220381d911b09431a2b27ee6ab06a6249a5195f436",
"blockNumber": "0x7a549b",
"contractAddress": null,
"cumulativeGasUsed": "0x78f1d",
"effectiveGasPrice": "0x2710",
"from": "0x5a178ae7d1e3fc42a8425a0c455e3b6c3157ff0c",
"gasUsed": "0x451a2",
"l1Fee": "0x410e677162",
"l1GasPrice": "0x1d6fedf00",
"l1GasUsed": "0x6e8",
"logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1",
"to": "0xe6dce473803a7fee2805f02c0140ce01bc738186",
"transactionHash": "0x310b151c69b810e900cd72c6b0335d8e9dafb783e793eae48b72aa3b6314a704",
"transactionIndex": "0x3",
"type": "0x2"
},
{
"blockHash": "0x4dc3e5326b8d6e7eb4d0a9220381d911b09431a2b27ee6ab06a6249a5195f436",
"blockNumber": "0x7a549b",
"contractAddress": null,
"cumulativeGasUsed": "0x2c6865",
"effectiveGasPrice": "0x2710",
"from": "0x93df6a148a6dd5b162ae1f49d03a981e13afc8f5",
"gasUsed": "0x24d948",
"l1Fee": "0x3eb3879b9d",
"l1GasPrice": "0x1d6fedf00",
"l1GasUsed": "0x6a8",
"logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1",
"to": "0x4397da4e02198b79e6934ad10e395d43816b553d",
"transactionHash": "0x27c04bd94b2404b0e9b898394c72cdf95471f2a4a57ca563be44a899d9b91a9a",
"transactionIndex": "0x4",
"type": "0x0"
},
{
"blockHash": "0x4dc3e5326b8d6e7eb4d0a9220381d911b09431a2b27ee6ab06a6249a5195f436",
"blockNumber": "0x7a549b",
"contractAddress": null,
"cumulativeGasUsed": "0x442974",
"effectiveGasPrice": "0x13a3",
"from": "0x1e8248888f342a4fdc91b4de3a883193dc8539bb",
"gasUsed": "0x17c10f",
"l1Fee": "0x43da513f3c",
"l1GasPrice": "0x1d6fedf00",
"l1GasUsed": "0x734",
"logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1",
"to": "0x2d58e04e43411c58e781339d70f8ebe05aa17b68",
"transactionHash": "0x42c16a4a0d2129017f90755da9727d1a77e2d4ae3289489c0ce356b414941746",
"transactionIndex": "0x5",
"type": "0x2"
}
],
"id": 1
}
77 changes: 77 additions & 0 deletions mocks/jsonrpc/httpclient.go