github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/ethclient/ethclient_test.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package ethclient
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  	"math/big"
    24  	"reflect"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/kisexp/xdchain"
    29  	"github.com/kisexp/xdchain/common"
    30  	"github.com/kisexp/xdchain/consensus/ethash"
    31  	"github.com/kisexp/xdchain/core"
    32  	"github.com/kisexp/xdchain/core/rawdb"
    33  	"github.com/kisexp/xdchain/core/types"
    34  	"github.com/kisexp/xdchain/crypto"
    35  	"github.com/kisexp/xdchain/eth"
    36  	"github.com/kisexp/xdchain/node"
    37  	"github.com/kisexp/xdchain/params"
    38  	"github.com/stretchr/testify/assert"
    39  )
    40  
    41  // Verify that Client implements the ethereum interfaces.
    42  var (
    43  	_ = ethereum.ChainReader(&Client{})
    44  	_ = ethereum.TransactionReader(&Client{})
    45  	_ = ethereum.ChainStateReader(&Client{})
    46  	_ = ethereum.ChainSyncReader(&Client{})
    47  	_ = ethereum.ContractCaller(&Client{})
    48  	_ = ethereum.GasEstimator(&Client{})
    49  	_ = ethereum.GasPricer(&Client{})
    50  	_ = ethereum.LogFilterer(&Client{})
    51  	_ = ethereum.PendingStateReader(&Client{})
    52  	// _ = ethereum.PendingStateEventer(&Client{})
    53  	_ = ethereum.PendingContractCaller(&Client{})
    54  )
    55  
    56  func TestToFilterArg(t *testing.T) {
    57  	blockHashErr := fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock")
    58  	addresses := []common.Address{
    59  		common.HexToAddress("0xD36722ADeC3EdCB29c8e7b5a47f352D701393462"),
    60  	}
    61  	blockHash := common.HexToHash(
    62  		"0xeb94bb7d78b73657a9d7a99792413f50c0a45c51fc62bdcb08a53f18e9a2b4eb",
    63  	)
    64  
    65  	for _, testCase := range []struct {
    66  		name   string
    67  		input  ethereum.FilterQuery
    68  		output interface{}
    69  		err    error
    70  	}{
    71  		{
    72  			"without BlockHash",
    73  			ethereum.FilterQuery{
    74  				Addresses: addresses,
    75  				FromBlock: big.NewInt(1),
    76  				ToBlock:   big.NewInt(2),
    77  				Topics:    [][]common.Hash{},
    78  			},
    79  			map[string]interface{}{
    80  				"address":   addresses,
    81  				"fromBlock": "0x1",
    82  				"toBlock":   "0x2",
    83  				"topics":    [][]common.Hash{},
    84  			},
    85  			nil,
    86  		},
    87  		{
    88  			"with nil fromBlock and nil toBlock",
    89  			ethereum.FilterQuery{
    90  				Addresses: addresses,
    91  				Topics:    [][]common.Hash{},
    92  			},
    93  			map[string]interface{}{
    94  				"address":   addresses,
    95  				"fromBlock": "0x0",
    96  				"toBlock":   "latest",
    97  				"topics":    [][]common.Hash{},
    98  			},
    99  			nil,
   100  		},
   101  		{
   102  			"with negative fromBlock and negative toBlock",
   103  			ethereum.FilterQuery{
   104  				Addresses: addresses,
   105  				FromBlock: big.NewInt(-1),
   106  				ToBlock:   big.NewInt(-1),
   107  				Topics:    [][]common.Hash{},
   108  			},
   109  			map[string]interface{}{
   110  				"address":   addresses,
   111  				"fromBlock": "pending",
   112  				"toBlock":   "pending",
   113  				"topics":    [][]common.Hash{},
   114  			},
   115  			nil,
   116  		},
   117  		{
   118  			"with blockhash",
   119  			ethereum.FilterQuery{
   120  				Addresses: addresses,
   121  				BlockHash: &blockHash,
   122  				Topics:    [][]common.Hash{},
   123  			},
   124  			map[string]interface{}{
   125  				"address":   addresses,
   126  				"blockHash": blockHash,
   127  				"topics":    [][]common.Hash{},
   128  			},
   129  			nil,
   130  		},
   131  		{
   132  			"with blockhash and from block",
   133  			ethereum.FilterQuery{
   134  				Addresses: addresses,
   135  				BlockHash: &blockHash,
   136  				FromBlock: big.NewInt(1),
   137  				Topics:    [][]common.Hash{},
   138  			},
   139  			nil,
   140  			blockHashErr,
   141  		},
   142  		{
   143  			"with blockhash and to block",
   144  			ethereum.FilterQuery{
   145  				Addresses: addresses,
   146  				BlockHash: &blockHash,
   147  				ToBlock:   big.NewInt(1),
   148  				Topics:    [][]common.Hash{},
   149  			},
   150  			nil,
   151  			blockHashErr,
   152  		},
   153  		{
   154  			"with blockhash and both from / to block",
   155  			ethereum.FilterQuery{
   156  				Addresses: addresses,
   157  				BlockHash: &blockHash,
   158  				FromBlock: big.NewInt(1),
   159  				ToBlock:   big.NewInt(2),
   160  				Topics:    [][]common.Hash{},
   161  			},
   162  			nil,
   163  			blockHashErr,
   164  		},
   165  	} {
   166  		t.Run(testCase.name, func(t *testing.T) {
   167  			output, err := toFilterArg(testCase.input)
   168  			if (testCase.err == nil) != (err == nil) {
   169  				t.Fatalf("expected error %v but got %v", testCase.err, err)
   170  			}
   171  			if testCase.err != nil {
   172  				if testCase.err.Error() != err.Error() {
   173  					t.Fatalf("expected error %v but got %v", testCase.err, err)
   174  				}
   175  			} else if !reflect.DeepEqual(testCase.output, output) {
   176  				t.Fatalf("expected filter arg %v but got %v", testCase.output, output)
   177  			}
   178  		})
   179  	}
   180  }
   181  
   182  var (
   183  	testKey, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
   184  	testAddr    = crypto.PubkeyToAddress(testKey.PublicKey)
   185  	testBalance = big.NewInt(2e10)
   186  )
   187  
   188  func newTestBackend(t *testing.T) (*node.Node, []*types.Block) {
   189  	// Generate test chain.
   190  	genesis, blocks := generateTestChain()
   191  	// Create node
   192  	n, err := node.New(&node.Config{})
   193  	if err != nil {
   194  		t.Fatalf("can't create new node: %v", err)
   195  	}
   196  	// Create Ethereum Service
   197  	config := &eth.Config{Genesis: genesis}
   198  	config.Ethash.PowMode = ethash.ModeFake
   199  	ethservice, err := eth.New(n, config)
   200  	if err != nil {
   201  		t.Fatalf("can't create new ethereum service: %v", err)
   202  	}
   203  	// Import the test chain.
   204  	if err := n.Start(); err != nil {
   205  		t.Fatalf("can't start test node: %v", err)
   206  	}
   207  	if _, err := ethservice.BlockChain().InsertChain(blocks[1:]); err != nil {
   208  		t.Fatalf("can't import test blocks: %v", err)
   209  	}
   210  	return n, blocks
   211  }
   212  
   213  func generateTestChain() (*core.Genesis, []*types.Block) {
   214  	db := rawdb.NewMemoryDatabase()
   215  	config := params.AllEthashProtocolChanges
   216  	genesis := &core.Genesis{
   217  		Config:    config,
   218  		Alloc:     core.GenesisAlloc{testAddr: {Balance: testBalance}},
   219  		ExtraData: []byte("test genesis"),
   220  		Timestamp: 9000,
   221  	}
   222  	generate := func(i int, g *core.BlockGen) {
   223  		g.OffsetTime(5)
   224  		g.SetExtra([]byte("test"))
   225  	}
   226  	gblock := genesis.ToBlock(db)
   227  	engine := ethash.NewFaker()
   228  	blocks, _ := core.GenerateChain(config, gblock, engine, db, 1, generate)
   229  	blocks = append([]*types.Block{gblock}, blocks...)
   230  	return genesis, blocks
   231  }
   232  
   233  func TestHeader(t *testing.T) {
   234  	backend, chain := newTestBackend(t)
   235  	client, _ := backend.Attach()
   236  	defer backend.Close()
   237  	defer client.Close()
   238  
   239  	tests := map[string]struct {
   240  		block   *big.Int
   241  		want    *types.Header
   242  		wantErr error
   243  	}{
   244  		"genesis": {
   245  			block: big.NewInt(0),
   246  			want:  chain[0].Header(),
   247  		},
   248  		"first_block": {
   249  			block: big.NewInt(1),
   250  			want:  chain[1].Header(),
   251  		},
   252  		"future_block": {
   253  			block: big.NewInt(1000000000),
   254  			want:  nil,
   255  		},
   256  	}
   257  	for name, tt := range tests {
   258  		t.Run(name, func(t *testing.T) {
   259  			ec := NewClient(client)
   260  			ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
   261  			defer cancel()
   262  
   263  			got, err := ec.HeaderByNumber(ctx, tt.block)
   264  			if tt.wantErr != nil && (err == nil || err.Error() != tt.wantErr.Error()) {
   265  				t.Fatalf("HeaderByNumber(%v) error = %q, want %q", tt.block, err, tt.wantErr)
   266  			}
   267  			if got != nil && got.Number.Sign() == 0 {
   268  				got.Number = big.NewInt(0) // hack to make DeepEqual work
   269  			}
   270  			if !reflect.DeepEqual(got, tt.want) {
   271  				t.Fatalf("HeaderByNumber(%v)\n   = %v\nwant %v", tt.block, got, tt.want)
   272  			}
   273  		})
   274  	}
   275  }
   276  
   277  func TestBalanceAt(t *testing.T) {
   278  	backend, _ := newTestBackend(t)
   279  	client, _ := backend.Attach()
   280  	defer backend.Close()
   281  	defer client.Close()
   282  
   283  	tests := map[string]struct {
   284  		account common.Address
   285  		block   *big.Int
   286  		want    *big.Int
   287  		wantErr error
   288  	}{
   289  		"valid_account": {
   290  			account: testAddr,
   291  			block:   big.NewInt(1),
   292  			want:    testBalance,
   293  		},
   294  		"non_existent_account": {
   295  			account: common.Address{1},
   296  			block:   big.NewInt(1),
   297  			want:    big.NewInt(0),
   298  		},
   299  		"future_block": {
   300  			account: testAddr,
   301  			block:   big.NewInt(1000000000),
   302  			want:    big.NewInt(0),
   303  			wantErr: errors.New("header not found"),
   304  		},
   305  	}
   306  	for name, tt := range tests {
   307  		t.Run(name, func(t *testing.T) {
   308  			ec := NewClient(client)
   309  			ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
   310  			defer cancel()
   311  
   312  			got, err := ec.BalanceAt(ctx, tt.account, tt.block)
   313  			if tt.wantErr != nil && (err == nil || err.Error() != tt.wantErr.Error()) {
   314  				t.Fatalf("BalanceAt(%x, %v) error = %q, want %q", tt.account, tt.block, err, tt.wantErr)
   315  			}
   316  			if got.Cmp(tt.want) != 0 {
   317  				t.Fatalf("BalanceAt(%x, %v) = %v, want %v", tt.account, tt.block, got, tt.want)
   318  			}
   319  		})
   320  	}
   321  }
   322  
   323  func TestTransactionInBlockInterrupted(t *testing.T) {
   324  	backend, _ := newTestBackend(t)
   325  	client, _ := backend.Attach()
   326  	defer backend.Close()
   327  	defer client.Close()
   328  
   329  	ec := NewClient(client)
   330  	ctx, cancel := context.WithCancel(context.Background())
   331  	cancel()
   332  	tx, err := ec.TransactionInBlock(ctx, common.Hash{1}, 1)
   333  	if tx != nil {
   334  		t.Fatal("transaction should be nil")
   335  	}
   336  	if err == nil {
   337  		t.Fatal("error should not be nil")
   338  	}
   339  }
   340  
   341  func TestChainID(t *testing.T) {
   342  	backend, _ := newTestBackend(t)
   343  	client, _ := backend.Attach()
   344  	defer backend.Close()
   345  	defer client.Close()
   346  	ec := NewClient(client)
   347  
   348  	id, err := ec.ChainID(context.Background())
   349  	if err != nil {
   350  		t.Fatalf("unexpected error: %v", err)
   351  	}
   352  	if id == nil || id.Cmp(params.AllEthashProtocolChanges.ChainID) != 0 {
   353  		t.Fatalf("ChainID returned wrong number: %+v", id)
   354  	}
   355  }
   356  
   357  func TestBlockNumber(t *testing.T) {
   358  	backend, _ := newTestBackend(t)
   359  	client, _ := backend.Attach()
   360  	defer backend.Close()
   361  	defer client.Close()
   362  	ec := NewClient(client)
   363  
   364  	blockNumber, err := ec.BlockNumber(context.Background())
   365  	if err != nil {
   366  		t.Fatalf("unexpected error: %v", err)
   367  	}
   368  	if blockNumber != 1 {
   369  		t.Fatalf("BlockNumber returned wrong number: %d", blockNumber)
   370  	}
   371  }
   372  
   373  func TestClient_PreparePrivateTransaction_whenTypical(t *testing.T) {
   374  	testObject := NewClient(nil)
   375  
   376  	_, err := testObject.PreparePrivateTransaction([]byte("arbitrary payload"), "arbitrary private from")
   377  
   378  	assert.Error(t, err)
   379  }
   380  
   381  func TestClient_PreparePrivateTransaction_whenClientIsConfigured(t *testing.T) {
   382  	expectedData := []byte("arbitrary payload")
   383  	expectedDataEPH := common.BytesToEncryptedPayloadHash(expectedData)
   384  	testObject := NewClient(nil)
   385  	testObject.pc = &privateTransactionManagerStubClient{expectedData}
   386  
   387  	actualData, err := testObject.PreparePrivateTransaction([]byte("arbitrary payload"), "arbitrary private from")
   388  
   389  	assert.NoError(t, err)
   390  	assert.Equal(t, expectedDataEPH, actualData)
   391  }
   392  
   393  type privateTransactionManagerStubClient struct {
   394  	expectedData []byte
   395  }
   396  
   397  func (s *privateTransactionManagerStubClient) StoreRaw(data []byte, from string) (common.EncryptedPayloadHash, error) {
   398  	return common.BytesToEncryptedPayloadHash(data), nil
   399  }