| 
									
										
										
										
											2016-11-09 02:01:56 +01:00
										 |  |  | // Copyright 2016 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-10 00:01:13 +02:00
										 |  |  | package ethclient | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 13:26:47 +01:00
										 |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-01-08 21:29:25 +01:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2019-05-02 14:50:23 +02:00
										 |  |  | 	"context" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2018-11-08 13:26:47 +01:00
										 |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"math/big" | 
					
						
							|  |  |  | 	"reflect" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2019-05-02 14:50:23 +02:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2018-11-08 13:26:47 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2019-05-02 14:50:23 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/consensus/ethash" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/core" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/core/rawdb" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/core/types" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/eth" | 
					
						
							| 
									
										
										
										
											2021-02-05 20:51:15 +08:00
										 |  |  | 	"github.com/ethereum/go-ethereum/eth/ethconfig" | 
					
						
							| 
									
										
										
										
											2019-05-02 14:50:23 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/node" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/params" | 
					
						
							| 
									
										
										
										
											2021-01-08 21:29:25 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/rpc" | 
					
						
							| 
									
										
										
										
											2018-11-08 13:26:47 +01:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2016-08-10 00:01:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Verify that Client implements the ethereum interfaces. | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	_ = ethereum.ChainReader(&Client{}) | 
					
						
							| 
									
										
										
										
											2016-11-29 15:54:06 +01:00
										 |  |  | 	_ = ethereum.TransactionReader(&Client{}) | 
					
						
							| 
									
										
										
										
											2016-08-10 00:01:13 +02:00
										 |  |  | 	_ = ethereum.ChainStateReader(&Client{}) | 
					
						
							| 
									
										
										
										
											2016-09-06 12:39:14 +03:00
										 |  |  | 	_ = ethereum.ChainSyncReader(&Client{}) | 
					
						
							| 
									
										
										
										
											2016-08-10 00:01:13 +02:00
										 |  |  | 	_ = ethereum.ContractCaller(&Client{}) | 
					
						
							|  |  |  | 	_ = ethereum.GasEstimator(&Client{}) | 
					
						
							|  |  |  | 	_ = ethereum.GasPricer(&Client{}) | 
					
						
							|  |  |  | 	_ = ethereum.LogFilterer(&Client{}) | 
					
						
							|  |  |  | 	_ = ethereum.PendingStateReader(&Client{}) | 
					
						
							|  |  |  | 	// _ = ethereum.PendingStateEventer(&Client{}) | 
					
						
							|  |  |  | 	_ = ethereum.PendingContractCaller(&Client{}) | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2018-11-08 13:26:47 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestToFilterArg(t *testing.T) { | 
					
						
							|  |  |  | 	blockHashErr := fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock") | 
					
						
							|  |  |  | 	addresses := []common.Address{ | 
					
						
							|  |  |  | 		common.HexToAddress("0xD36722ADeC3EdCB29c8e7b5a47f352D701393462"), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	blockHash := common.HexToHash( | 
					
						
							|  |  |  | 		"0xeb94bb7d78b73657a9d7a99792413f50c0a45c51fc62bdcb08a53f18e9a2b4eb", | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, testCase := range []struct { | 
					
						
							|  |  |  | 		name   string | 
					
						
							|  |  |  | 		input  ethereum.FilterQuery | 
					
						
							|  |  |  | 		output interface{} | 
					
						
							|  |  |  | 		err    error | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			"without BlockHash", | 
					
						
							|  |  |  | 			ethereum.FilterQuery{ | 
					
						
							|  |  |  | 				Addresses: addresses, | 
					
						
							|  |  |  | 				FromBlock: big.NewInt(1), | 
					
						
							|  |  |  | 				ToBlock:   big.NewInt(2), | 
					
						
							|  |  |  | 				Topics:    [][]common.Hash{}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			map[string]interface{}{ | 
					
						
							|  |  |  | 				"address":   addresses, | 
					
						
							|  |  |  | 				"fromBlock": "0x1", | 
					
						
							|  |  |  | 				"toBlock":   "0x2", | 
					
						
							|  |  |  | 				"topics":    [][]common.Hash{}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			nil, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			"with nil fromBlock and nil toBlock", | 
					
						
							|  |  |  | 			ethereum.FilterQuery{ | 
					
						
							|  |  |  | 				Addresses: addresses, | 
					
						
							|  |  |  | 				Topics:    [][]common.Hash{}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			map[string]interface{}{ | 
					
						
							|  |  |  | 				"address":   addresses, | 
					
						
							|  |  |  | 				"fromBlock": "0x0", | 
					
						
							|  |  |  | 				"toBlock":   "latest", | 
					
						
							|  |  |  | 				"topics":    [][]common.Hash{}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			nil, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2020-07-21 13:51:15 +05:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			"with negative fromBlock and negative toBlock", | 
					
						
							|  |  |  | 			ethereum.FilterQuery{ | 
					
						
							|  |  |  | 				Addresses: addresses, | 
					
						
							|  |  |  | 				FromBlock: big.NewInt(-1), | 
					
						
							|  |  |  | 				ToBlock:   big.NewInt(-1), | 
					
						
							|  |  |  | 				Topics:    [][]common.Hash{}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			map[string]interface{}{ | 
					
						
							|  |  |  | 				"address":   addresses, | 
					
						
							|  |  |  | 				"fromBlock": "pending", | 
					
						
							|  |  |  | 				"toBlock":   "pending", | 
					
						
							|  |  |  | 				"topics":    [][]common.Hash{}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			nil, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2018-11-08 13:26:47 +01:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			"with blockhash", | 
					
						
							|  |  |  | 			ethereum.FilterQuery{ | 
					
						
							|  |  |  | 				Addresses: addresses, | 
					
						
							|  |  |  | 				BlockHash: &blockHash, | 
					
						
							|  |  |  | 				Topics:    [][]common.Hash{}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			map[string]interface{}{ | 
					
						
							|  |  |  | 				"address":   addresses, | 
					
						
							|  |  |  | 				"blockHash": blockHash, | 
					
						
							|  |  |  | 				"topics":    [][]common.Hash{}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			nil, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			"with blockhash and from block", | 
					
						
							|  |  |  | 			ethereum.FilterQuery{ | 
					
						
							|  |  |  | 				Addresses: addresses, | 
					
						
							|  |  |  | 				BlockHash: &blockHash, | 
					
						
							|  |  |  | 				FromBlock: big.NewInt(1), | 
					
						
							|  |  |  | 				Topics:    [][]common.Hash{}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			nil, | 
					
						
							|  |  |  | 			blockHashErr, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			"with blockhash and to block", | 
					
						
							|  |  |  | 			ethereum.FilterQuery{ | 
					
						
							|  |  |  | 				Addresses: addresses, | 
					
						
							|  |  |  | 				BlockHash: &blockHash, | 
					
						
							|  |  |  | 				ToBlock:   big.NewInt(1), | 
					
						
							|  |  |  | 				Topics:    [][]common.Hash{}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			nil, | 
					
						
							|  |  |  | 			blockHashErr, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			"with blockhash and both from / to block", | 
					
						
							|  |  |  | 			ethereum.FilterQuery{ | 
					
						
							|  |  |  | 				Addresses: addresses, | 
					
						
							|  |  |  | 				BlockHash: &blockHash, | 
					
						
							|  |  |  | 				FromBlock: big.NewInt(1), | 
					
						
							|  |  |  | 				ToBlock:   big.NewInt(2), | 
					
						
							|  |  |  | 				Topics:    [][]common.Hash{}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			nil, | 
					
						
							|  |  |  | 			blockHashErr, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} { | 
					
						
							|  |  |  | 		t.Run(testCase.name, func(t *testing.T) { | 
					
						
							|  |  |  | 			output, err := toFilterArg(testCase.input) | 
					
						
							|  |  |  | 			if (testCase.err == nil) != (err == nil) { | 
					
						
							|  |  |  | 				t.Fatalf("expected error %v but got %v", testCase.err, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if testCase.err != nil { | 
					
						
							|  |  |  | 				if testCase.err.Error() != err.Error() { | 
					
						
							|  |  |  | 					t.Fatalf("expected error %v but got %v", testCase.err, err) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else if !reflect.DeepEqual(testCase.output, output) { | 
					
						
							|  |  |  | 				t.Fatalf("expected filter arg %v but got %v", testCase.output, output) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-05-02 14:50:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	testKey, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 
					
						
							|  |  |  | 	testAddr    = crypto.PubkeyToAddress(testKey.PublicKey) | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	testBalance = big.NewInt(2e15) | 
					
						
							| 
									
										
										
										
											2019-05-02 14:50:23 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { | 
					
						
							|  |  |  | 	// Generate test chain. | 
					
						
							|  |  |  | 	genesis, blocks := generateTestChain() | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	// Create node | 
					
						
							| 
									
										
										
										
											2019-05-02 14:50:23 +02:00
										 |  |  | 	n, err := node.New(&node.Config{}) | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("can't create new node: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Create Ethereum Service | 
					
						
							| 
									
										
										
										
											2021-02-05 20:51:15 +08:00
										 |  |  | 	config := ðconfig.Config{Genesis: genesis} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	config.Ethash.PowMode = ethash.ModeFake | 
					
						
							|  |  |  | 	ethservice, err := eth.New(n, config) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("can't create new ethereum service: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-05-02 14:50:23 +02:00
										 |  |  | 	// Import the test chain. | 
					
						
							|  |  |  | 	if err := n.Start(); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("can't start test node: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if _, err := ethservice.BlockChain().InsertChain(blocks[1:]); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("can't import test blocks: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return n, blocks | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func generateTestChain() (*core.Genesis, []*types.Block) { | 
					
						
							|  |  |  | 	db := rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 	config := params.AllEthashProtocolChanges | 
					
						
							|  |  |  | 	genesis := &core.Genesis{ | 
					
						
							|  |  |  | 		Config:    config, | 
					
						
							|  |  |  | 		Alloc:     core.GenesisAlloc{testAddr: {Balance: testBalance}}, | 
					
						
							|  |  |  | 		ExtraData: []byte("test genesis"), | 
					
						
							|  |  |  | 		Timestamp: 9000, | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		BaseFee:   big.NewInt(params.InitialBaseFee), | 
					
						
							| 
									
										
										
										
											2019-05-02 14:50:23 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	generate := func(i int, g *core.BlockGen) { | 
					
						
							|  |  |  | 		g.OffsetTime(5) | 
					
						
							|  |  |  | 		g.SetExtra([]byte("test")) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	gblock := genesis.ToBlock(db) | 
					
						
							|  |  |  | 	engine := ethash.NewFaker() | 
					
						
							|  |  |  | 	blocks, _ := core.GenerateChain(config, gblock, engine, db, 1, generate) | 
					
						
							|  |  |  | 	blocks = append([]*types.Block{gblock}, blocks...) | 
					
						
							|  |  |  | 	return genesis, blocks | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-08 21:29:25 +01:00
										 |  |  | func TestEthClient(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2019-05-02 14:50:23 +02:00
										 |  |  | 	backend, chain := newTestBackend(t) | 
					
						
							|  |  |  | 	client, _ := backend.Attach() | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	defer backend.Close() | 
					
						
							| 
									
										
										
										
											2019-05-02 14:50:23 +02:00
										 |  |  | 	defer client.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-08 21:29:25 +01:00
										 |  |  | 	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) { | 
					
						
							| 
									
										
										
										
											2019-05-02 14:50:23 +02:00
										 |  |  | 	tests := map[string]struct { | 
					
						
							|  |  |  | 		block   *big.Int | 
					
						
							|  |  |  | 		want    *types.Header | 
					
						
							|  |  |  | 		wantErr error | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		"genesis": { | 
					
						
							|  |  |  | 			block: big.NewInt(0), | 
					
						
							|  |  |  | 			want:  chain[0].Header(), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"first_block": { | 
					
						
							|  |  |  | 			block: big.NewInt(1), | 
					
						
							|  |  |  | 			want:  chain[1].Header(), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"future_block": { | 
					
						
							| 
									
										
										
										
											2021-03-19 05:14:23 -05:00
										 |  |  | 			block:   big.NewInt(1000000000), | 
					
						
							|  |  |  | 			want:    nil, | 
					
						
							|  |  |  | 			wantErr: ethereum.NotFound, | 
					
						
							| 
									
										
										
										
											2019-05-02 14:50:23 +02:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for name, tt := range tests { | 
					
						
							|  |  |  | 		t.Run(name, func(t *testing.T) { | 
					
						
							|  |  |  | 			ec := NewClient(client) | 
					
						
							|  |  |  | 			ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) | 
					
						
							|  |  |  | 			defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			got, err := ec.HeaderByNumber(ctx, tt.block) | 
					
						
							| 
									
										
										
										
											2021-03-19 05:14:23 -05:00
										 |  |  | 			if !errors.Is(err, tt.wantErr) { | 
					
						
							| 
									
										
										
										
											2019-05-02 14:50:23 +02:00
										 |  |  | 				t.Fatalf("HeaderByNumber(%v) error = %q, want %q", tt.block, err, tt.wantErr) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-03-19 05:14:23 -05:00
										 |  |  | 			if got != nil && got.Number != nil && got.Number.Sign() == 0 { | 
					
						
							| 
									
										
										
										
											2019-05-02 14:50:23 +02:00
										 |  |  | 				got.Number = big.NewInt(0) // hack to make DeepEqual work | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if !reflect.DeepEqual(got, tt.want) { | 
					
						
							|  |  |  | 				t.Fatalf("HeaderByNumber(%v)\n   = %v\nwant %v", tt.block, got, tt.want) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-08 21:29:25 +01:00
										 |  |  | func testBalanceAt(t *testing.T, client *rpc.Client) { | 
					
						
							| 
									
										
										
										
											2019-05-02 14:50:23 +02:00
										 |  |  | 	tests := map[string]struct { | 
					
						
							|  |  |  | 		account common.Address | 
					
						
							|  |  |  | 		block   *big.Int | 
					
						
							|  |  |  | 		want    *big.Int | 
					
						
							|  |  |  | 		wantErr error | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		"valid_account": { | 
					
						
							|  |  |  | 			account: testAddr, | 
					
						
							|  |  |  | 			block:   big.NewInt(1), | 
					
						
							|  |  |  | 			want:    testBalance, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"non_existent_account": { | 
					
						
							|  |  |  | 			account: common.Address{1}, | 
					
						
							|  |  |  | 			block:   big.NewInt(1), | 
					
						
							|  |  |  | 			want:    big.NewInt(0), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"future_block": { | 
					
						
							|  |  |  | 			account: testAddr, | 
					
						
							|  |  |  | 			block:   big.NewInt(1000000000), | 
					
						
							|  |  |  | 			want:    big.NewInt(0), | 
					
						
							|  |  |  | 			wantErr: errors.New("header not found"), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for name, tt := range tests { | 
					
						
							|  |  |  | 		t.Run(name, func(t *testing.T) { | 
					
						
							|  |  |  | 			ec := NewClient(client) | 
					
						
							|  |  |  | 			ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) | 
					
						
							|  |  |  | 			defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			got, err := ec.BalanceAt(ctx, tt.account, tt.block) | 
					
						
							|  |  |  | 			if tt.wantErr != nil && (err == nil || err.Error() != tt.wantErr.Error()) { | 
					
						
							|  |  |  | 				t.Fatalf("BalanceAt(%x, %v) error = %q, want %q", tt.account, tt.block, err, tt.wantErr) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if got.Cmp(tt.want) != 0 { | 
					
						
							|  |  |  | 				t.Fatalf("BalanceAt(%x, %v) = %v, want %v", tt.account, tt.block, got, tt.want) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-06-03 18:52:02 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-08 21:29:25 +01:00
										 |  |  | func testTransactionInBlockInterrupted(t *testing.T, client *rpc.Client) { | 
					
						
							| 
									
										
										
										
											2019-06-03 18:52:02 +03:00
										 |  |  | 	ec := NewClient(client) | 
					
						
							| 
									
										
										
										
											2021-01-08 21:29:25 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// 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 | 
					
						
							| 
									
										
										
										
											2019-06-03 18:52:02 +03:00
										 |  |  | 	ctx, cancel := context.WithCancel(context.Background()) | 
					
						
							|  |  |  | 	cancel() | 
					
						
							| 
									
										
										
										
											2021-01-08 21:29:25 +01:00
										 |  |  | 	tx, err := ec.TransactionInBlock(ctx, block.Hash(), 1) | 
					
						
							| 
									
										
										
										
											2019-06-03 18:52:02 +03:00
										 |  |  | 	if tx != nil { | 
					
						
							|  |  |  | 		t.Fatal("transaction should be nil") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-01-08 21:29:25 +01:00
										 |  |  | 	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") | 
					
						
							| 
									
										
										
										
											2019-06-03 18:52:02 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-06-11 13:12:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-08 21:29:25 +01:00
										 |  |  | func testChainID(t *testing.T, client *rpc.Client) { | 
					
						
							| 
									
										
										
										
											2019-06-11 13:12:33 +02:00
										 |  |  | 	ec := NewClient(client) | 
					
						
							|  |  |  | 	id, err := ec.ChainID(context.Background()) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("unexpected error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if id == nil || id.Cmp(params.AllEthashProtocolChanges.ChainID) != 0 { | 
					
						
							|  |  |  | 		t.Fatalf("ChainID returned wrong number: %+v", id) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-09-15 05:29:51 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-08 21:29:25 +01:00
										 |  |  | func testGetBlock(t *testing.T, client *rpc.Client) { | 
					
						
							| 
									
										
										
										
											2020-09-15 05:29:51 -04:00
										 |  |  | 	ec := NewClient(client) | 
					
						
							| 
									
										
										
										
											2021-01-08 21:29:25 +01:00
										 |  |  | 	// Get current block number | 
					
						
							| 
									
										
										
										
											2020-09-15 05:29:51 -04:00
										 |  |  | 	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) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-01-08 21:29:25 +01:00
										 |  |  | 	// 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) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	if gasPrice.Cmp(big.NewInt(1875000000)) != 0 { // 1 gwei tip + 0.875 basefee after a 1 gwei fee empty block | 
					
						
							| 
									
										
										
										
											2021-01-08 21:29:25 +01:00
										 |  |  | 		t.Fatalf("unexpected gas price: %v", gasPrice) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	// SuggestGasTipCap (should suggest 1 Gwei) | 
					
						
							|  |  |  | 	gasTipCap, err := ec.SuggestGasTipCap(context.Background()) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("unexpected error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if gasTipCap.Cmp(big.NewInt(1000000000)) != 0 { | 
					
						
							|  |  |  | 		t.Fatalf("unexpected gas tip cap: %v", gasTipCap) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-01-08 21:29:25 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testCallContract(t *testing.T, client *rpc.Client) { | 
					
						
							|  |  |  | 	ec := NewClient(client) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// EstimateGas | 
					
						
							|  |  |  | 	msg := ethereum.CallMsg{ | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		From:  testAddr, | 
					
						
							|  |  |  | 		To:    &common.Address{}, | 
					
						
							|  |  |  | 		Gas:   21000, | 
					
						
							|  |  |  | 		Value: big.NewInt(1), | 
					
						
							| 
									
										
										
										
											2021-01-08 21:29:25 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	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 | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 	tx := types.NewTransaction(0, common.Address{1}, big.NewInt(1), 22000, big.NewInt(params.InitialBaseFee), nil) | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 	signer := types.LatestSignerForChainID(chainID) | 
					
						
							| 
									
										
										
										
											2021-01-08 21:29:25 +01:00
										 |  |  | 	signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	signedTx, err := tx.WithSignature(signer, signature) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Send transaction | 
					
						
							|  |  |  | 	return ec.SendTransaction(context.Background(), signedTx) | 
					
						
							| 
									
										
										
										
											2020-09-15 05:29:51 -04:00
										 |  |  | } |