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

Incorporate use of ethclient in data migration compatibility test #90

Merged
merged 4 commits into from
Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
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
84 changes: 81 additions & 3 deletions compat_tests/compat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import (
"context"
"encoding/json"
"fmt"
"math/big"
"testing"
"time"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/require"
)
Expand All @@ -29,11 +32,56 @@ func TestCompatibilityOfChain(t *testing.T) {
defer cancel()
c, err := rpc.DialContext(ctx, "http://localhost:8545")
require.NoError(t, err)

ec := ethclient.NewClient(c)
ctx, cancel = context.WithTimeout(context.Background(), time.Minute*5)
defer cancel()
id, err := ec.ChainID(ctx)
require.NoError(t, err)
require.Greater(t, id.Uint64(), uint64(0))

var res json.RawMessage
startBlock := uint64(2800)
amount := uint64(1000)
incrementalLogs := make([]*types.Log, 0)
for i := startBlock; i <= startBlock+amount; i++ {
res, err := rpcCall(c, dumpOutput, "eth_getBlockByNumber", hexutil.EncodeUint64(i), true)
ctx, cancel = context.WithTimeout(context.Background(), time.Minute)
defer cancel()
b, err := ec.BlockByNumber(ctx, big.NewInt(int64(i)))
require.NoError(t, err)
h, err := ec.HeaderByNumber(ctx, big.NewInt(int64(i)))
require.NoError(t, err)

// Comparing the 2 headers directly doesn't work, they differ on unset
// and nil big ints, which represent the same thing but are technically
// not eaual. So instead we compare the marshalled output.
bhMarshalled, err := json.Marshal(b.Header())
require.NoError(t, err)
hMarshalled, err := json.Marshal(h)
require.NoError(t, err)
require.Equal(t, bhMarshalled, hMarshalled)

// Now get the header by hash and compare
h2, err := ec.HeaderByHash(ctx, h.Hash())
require.NoError(t, err)
h2Marshalled, err := json.Marshal(h2)
require.NoError(t, err)
require.Equal(t, hMarshalled, h2Marshalled)

// Now get the block by hash and compare
b2, err := ec.BlockByHash(ctx, b.Hash())
require.NoError(t, err)
b2hMarshalled, err := json.Marshal(b2.Header())
require.NoError(t, err)
require.Equal(t, bhMarshalled, b2hMarshalled)

bbMarshalled, err := json.Marshal(b.Body())
require.NoError(t, err)
b2bMarshalled, err := json.Marshal(b2.Body())
require.NoError(t, err)
require.Equal(t, bbMarshalled, b2bMarshalled)

res, err = rpcCall(c, dumpOutput, "eth_getBlockByNumber", hexutil.EncodeUint64(i), true)
require.NoError(t, err)
// Check we got a block
require.NotEqual(t, "null", string(res), "block %d should not be null", i)
Expand All @@ -43,15 +91,33 @@ func TestCompatibilityOfChain(t *testing.T) {
txs := blockTransactions{}
err = json.Unmarshal(res, &txs)
require.NoError(t, err)

incrementalBlockReceipts := types.Receipts{}
for _, tx := range txs.Transactions {
for i, tx := range txs.Transactions {
// Compare transactions decoded from rpcCall with transactions from
// the the block returned by ethclient and those directly retrieved
// by ethclient. Comparing transactions directly does not work
// because of differing private fields. The hash is calculated over
// the data of the transaction and so serves as a good proxy for
// equality.
require.Equal(t, tx.Hash(), b.Transactions()[i].Hash())
tx2, _, err := ec.TransactionByHash(ctx, tx.Hash())
require.NoError(t, err)
require.Equal(t, tx.Hash(), tx2.Hash())

_, err = rpcCall(c, dumpOutput, "eth_getTransactionByHash", tx.Hash())
require.NoError(t, err)
res, err = rpcCall(c, dumpOutput, "eth_getTransactionReceipt", tx.Hash())
require.NoError(t, err)
r := types.Receipt{}
err = json.Unmarshal(res, &r)
require.NoError(t, err)

// Check receipt decoded from RPC call matches that returned directly from ethclient.
r2, err := ec.TransactionReceipt(ctx, tx.Hash())
require.NoError(t, err)
require.Equal(t, r, *r2)

incrementalBlockReceipts = append(incrementalBlockReceipts, &r)
incrementalLogs = append(incrementalLogs, r.Logs...)
}
Expand Down Expand Up @@ -83,7 +149,7 @@ func TestCompatibilityOfChain(t *testing.T) {
// Get all logs for the range and compare with the logs extracted from receipts.
from := rpc.BlockNumber(startBlock)
to := rpc.BlockNumber(amount + startBlock)
res, err := rpcCall(c, dumpOutput, "eth_getLogs", filterQuery{
res, err = rpcCall(c, dumpOutput, "eth_getLogs", filterQuery{
FromBlock: &from,
ToBlock: &to,
})
Expand All @@ -93,6 +159,18 @@ func TestCompatibilityOfChain(t *testing.T) {
require.NoError(t, err)
require.Equal(t, len(incrementalLogs), len(logs))
require.Equal(t, incrementalLogs, logs)

// Compare logs with those retrived via ethclient
logs2, err := ec.FilterLogs(ctx, ethereum.FilterQuery{
FromBlock: big.NewInt(int64(startBlock)),
ToBlock: big.NewInt(int64(startBlock + amount)),
})
// ethclient returns non pointers to logs, convert to pointer form
logPointers := make([]*types.Log, len(logs2))
for i := range logs2 {
logPointers[i] = &logs2[i]
}
require.Equal(t, logPointers, logs)
}

type filterQuery struct {
Expand Down
3 changes: 2 additions & 1 deletion ethclient/ethclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
)

Expand Down Expand Up @@ -150,7 +151,7 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface
if head.UncleHash == types.EmptyUncleHash && len(body.UncleHashes) > 0 {
return nil, errors.New("server returned non-empty uncle list but block header indicates no uncles")
}
if head.UncleHash != types.EmptyUncleHash && len(body.UncleHashes) == 0 {
if head.Number.Uint64() >= params.CEL2StartBlock && head.UncleHash != types.EmptyUncleHash && len(body.UncleHashes) == 0 {
alecps marked this conversation as resolved.
Show resolved Hide resolved
return nil, errors.New("server returned empty uncle list but block header indicates uncles")
}
if head.TxHash == types.EmptyTxsHash && len(body.Transactions) > 0 {
Expand Down
5 changes: 5 additions & 0 deletions params/celo_extensions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package params

const (
CEL2StartBlock uint64 = 25000000
)