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 := ð.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 }