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

ethclient: better test suite for ethclient package #22127

Merged
merged 3 commits into from
Jan 8, 2021
Merged
Changes from 2 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
256 changes: 228 additions & 28 deletions ethclient/ethclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package ethclient

import (
"bytes"
"context"
"errors"
"fmt"
Expand All @@ -35,6 +36,7 @@ import (
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
)

// Verify that Client implements the ethereum interfaces.
Expand Down Expand Up @@ -229,12 +231,48 @@ func generateTestChain() (*core.Genesis, []*types.Block) {
return genesis, blocks
}

func TestHeader(t *testing.T) {
func TestEthClient(t *testing.T) {
backend, chain := newTestBackend(t)
client, _ := backend.Attach()
defer backend.Close()
defer client.Close()

tests := map[string]struct {
test func(t *testing.T)
}{
"TestHeader": {
func(t *testing.T) { testHeader(t, chain, client) },
},
"TestBalanceAt": {
func(t *testing.T) { testBalanceAt(t, client) },
},
"TestTxInBlockInterrupted": {
func(t *testing.T) { testTransactionInBlockInterrupted(t, client) },
},
"TestChainID": {
func(t *testing.T) { testChainID(t, client) },
},
"TestGetBlock": {
func(t *testing.T) { testGetBlock(t, client) },
},
"TestStatusFunctions": {
func(t *testing.T) { testStatusFunctions(t, client) },
},
"TestCallContract": {
func(t *testing.T) { testCallContract(t, client) },
},
"TestAtFunctions": {
func(t *testing.T) { testAtFunctions(t, client) },
},
}

t.Parallel()
for name, tt := range tests {
t.Run(name, tt.test)
}
}

func testHeader(t *testing.T, chain []*types.Block, client *rpc.Client) {
tests := map[string]struct {
block *big.Int
want *types.Header
Expand Down Expand Up @@ -273,12 +311,7 @@ func TestHeader(t *testing.T) {
}
}

func TestBalanceAt(t *testing.T) {
backend, _ := newTestBackend(t)
client, _ := backend.Attach()
defer backend.Close()
defer client.Close()

func testBalanceAt(t *testing.T, client *rpc.Client) {
tests := map[string]struct {
account common.Address
block *big.Int
Expand Down Expand Up @@ -319,31 +352,32 @@ func TestBalanceAt(t *testing.T) {
}
}

func TestTransactionInBlockInterrupted(t *testing.T) {
backend, _ := newTestBackend(t)
client, _ := backend.Attach()
defer backend.Close()
defer client.Close()

func testTransactionInBlockInterrupted(t *testing.T, client *rpc.Client) {
ec := NewClient(client)

// Get current block by number
block, err := ec.BlockByNumber(context.Background(), nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
// Test tx in block interupted
ctx, cancel := context.WithCancel(context.Background())
cancel()
tx, err := ec.TransactionInBlock(ctx, common.Hash{1}, 1)
tx, err := ec.TransactionInBlock(ctx, block.Hash(), 1)
if tx != nil {
t.Fatal("transaction should be nil")
}
if err == nil {
t.Fatal("error should not be nil")
if err == nil || err == ethereum.NotFound {
t.Fatal("error should not be nil/notfound")
}
// Test tx in block not found
if _, err := ec.TransactionInBlock(context.Background(), block.Hash(), 1); err != ethereum.NotFound {
t.Fatal("error should be ethereum.NotFound")
}
}

func TestChainID(t *testing.T) {
backend, _ := newTestBackend(t)
client, _ := backend.Attach()
defer backend.Close()
defer client.Close()
func testChainID(t *testing.T, client *rpc.Client) {
ec := NewClient(client)

id, err := ec.ChainID(context.Background())
if err != nil {
t.Fatalf("unexpected error: %v", err)
Expand All @@ -353,18 +387,184 @@ func TestChainID(t *testing.T) {
}
}

func TestBlockNumber(t *testing.T) {
backend, _ := newTestBackend(t)
client, _ := backend.Attach()
defer backend.Close()
defer client.Close()
func testGetBlock(t *testing.T, client *rpc.Client) {
ec := NewClient(client)

// Get current block number
blockNumber, err := ec.BlockNumber(context.Background())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if blockNumber != 1 {
t.Fatalf("BlockNumber returned wrong number: %d", blockNumber)
}
// Get current block by number
block, err := ec.BlockByNumber(context.Background(), new(big.Int).SetUint64(blockNumber))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if block.NumberU64() != blockNumber {
t.Fatalf("BlockByNumber returned wrong block: want %d got %d", blockNumber, block.NumberU64())
}
// Get current block by hash
blockH, err := ec.BlockByHash(context.Background(), block.Hash())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if block.Hash() != blockH.Hash() {
t.Fatalf("BlockByHash returned wrong block: want %v got %v", block.Hash().Hex(), blockH.Hash().Hex())
}
// Get header by number
header, err := ec.HeaderByNumber(context.Background(), new(big.Int).SetUint64(blockNumber))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if block.Header().Hash() != header.Hash() {
t.Fatalf("HeaderByNumber returned wrong header: want %v got %v", block.Header().Hash().Hex(), header.Hash().Hex())
}
// Get header by hash
headerH, err := ec.HeaderByHash(context.Background(), block.Hash())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if block.Header().Hash() != headerH.Hash() {
t.Fatalf("HeaderByHash returned wrong header: want %v got %v", block.Header().Hash().Hex(), headerH.Hash().Hex())
}
}

func testStatusFunctions(t *testing.T, client *rpc.Client) {
ec := NewClient(client)

// Sync progress
progress, err := ec.SyncProgress(context.Background())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if progress != nil {
t.Fatalf("unexpected progress: %v", progress)
}
// NetworkID
networkID, err := ec.NetworkID(context.Background())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if networkID.Cmp(big.NewInt(0)) != 0 {
t.Fatalf("unexpected networkID: %v", networkID)
}
// SuggestGasPrice (should suggest 1 Gwei)
gasPrice, err := ec.SuggestGasPrice(context.Background())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if gasPrice.Cmp(big.NewInt(1000000000)) != 0 {
t.Fatalf("unexpected gas price: %v", gasPrice)
}
}

func testCallContract(t *testing.T, client *rpc.Client) {
ec := NewClient(client)

// EstimateGas
msg := ethereum.CallMsg{
From: testAddr,
To: &common.Address{},
Gas: 21000,
GasPrice: big.NewInt(1),
Value: big.NewInt(1),
}
gas, err := ec.EstimateGas(context.Background(), msg)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if gas != 21000 {
t.Fatalf("unexpected gas price: %v", gas)
}
// CallContract
if _, err := ec.CallContract(context.Background(), msg, big.NewInt(1)); err != nil {
t.Fatalf("unexpected error: %v", err)
}
// PendingCallCOntract
if _, err := ec.PendingCallContract(context.Background(), msg); err != nil {
t.Fatalf("unexpected error: %v", err)
}
}

func testAtFunctions(t *testing.T, client *rpc.Client) {
ec := NewClient(client)
// send a transaction for some interesting pending status
sendTransaction(ec)
time.Sleep(100 * time.Millisecond)
// Check pending transaction count
pending, err := ec.PendingTransactionCount(context.Background())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if pending != 1 {
t.Fatalf("unexpected pending, wanted 1 got: %v", pending)
}
// Query balance
balance, err := ec.BalanceAt(context.Background(), testAddr, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
penBalance, err := ec.PendingBalanceAt(context.Background(), testAddr)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if balance.Cmp(penBalance) == 0 {
t.Fatalf("unexpected balance: %v %v", balance, penBalance)
}
// NonceAt
nonce, err := ec.NonceAt(context.Background(), testAddr, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
penNonce, err := ec.PendingNonceAt(context.Background(), testAddr)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if penNonce != nonce+1 {
t.Fatalf("unexpected nonce: %v %v", nonce, penNonce)
}
// StorageAt
storage, err := ec.StorageAt(context.Background(), testAddr, common.Hash{}, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
penStorage, err := ec.PendingStorageAt(context.Background(), testAddr, common.Hash{})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !bytes.Equal(storage, penStorage) {
t.Fatalf("unexpected storage: %v %v", storage, penStorage)
}
// CodeAt
code, err := ec.CodeAt(context.Background(), testAddr, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
penCode, err := ec.PendingCodeAt(context.Background(), testAddr)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !bytes.Equal(code, penCode) {
t.Fatalf("unexpected code: %v %v", code, penCode)
}
}

func sendTransaction(ec *Client) error {
// Retrieve chainID
chainID, err := ec.ChainID(context.Background())
if err != nil {
return err
}
// Create transaction
tx := types.NewTransaction(0, common.Address{1}, big.NewInt(1), 22000, big.NewInt(1), nil)
signer := types.NewEIP155Signer(chainID)
signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey)
if err != nil {
return err
}
signedTx, err := tx.WithSignature(signer, signature)
MariusVanDerWijden marked this conversation as resolved.
Show resolved Hide resolved
// Send transaction
return ec.SendTransaction(context.Background(), signedTx)
}