github.com/theQRL/go-zond@v0.1.1/les/odr_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 les 18 19 // Note: these tests are disabled now because they cannot work with the old sync 20 // mechanism removed but will be useful again once the PoS ultralight mode is implemented 21 22 /* 23 import ( 24 "bytes" 25 "context" 26 "crypto/rand" 27 "fmt" 28 "math/big" 29 "reflect" 30 "testing" 31 "time" 32 33 "github.com/theQRL/go-zond/common" 34 "github.com/theQRL/go-zond/common/math" 35 "github.com/theQRL/go-zond/core" 36 "github.com/theQRL/go-zond/core/rawdb" 37 "github.com/theQRL/go-zond/core/state" 38 "github.com/theQRL/go-zond/core/txpool" 39 "github.com/theQRL/go-zond/core/types" 40 "github.com/theQRL/go-zond/core/vm" 41 "github.com/theQRL/go-zond/zonddb" 42 "github.com/theQRL/go-zond/light" 43 "github.com/theQRL/go-zond/params" 44 "github.com/theQRL/go-zond/rlp" 45 ) 46 47 type odrTestFn func(ctx context.Context, db zonddb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte 48 49 func TestOdrGetBlockLes2(t *testing.T) { testOdr(t, 2, 1, true, odrGetBlock) } 50 func TestOdrGetBlockLes3(t *testing.T) { testOdr(t, 3, 1, true, odrGetBlock) } 51 func TestOdrGetBlockLes4(t *testing.T) { testOdr(t, 4, 1, true, odrGetBlock) } 52 53 func odrGetBlock(ctx context.Context, db zonddb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte { 54 var block *types.Block 55 if bc != nil { 56 block = bc.GetBlockByHash(bhash) 57 } else { 58 block, _ = lc.GetBlockByHash(ctx, bhash) 59 } 60 if block == nil { 61 return nil 62 } 63 rlp, _ := rlp.EncodeToBytes(block) 64 return rlp 65 } 66 67 func TestOdrGetReceiptsLes2(t *testing.T) { testOdr(t, 2, 1, true, odrGetReceipts) } 68 func TestOdrGetReceiptsLes3(t *testing.T) { testOdr(t, 3, 1, true, odrGetReceipts) } 69 func TestOdrGetReceiptsLes4(t *testing.T) { testOdr(t, 4, 1, true, odrGetReceipts) } 70 71 func odrGetReceipts(ctx context.Context, db zonddb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte { 72 var receipts types.Receipts 73 if bc != nil { 74 if number := rawdb.ReadHeaderNumber(db, bhash); number != nil { 75 if header := rawdb.ReadHeader(db, bhash, *number); header != nil { 76 receipts = rawdb.ReadReceipts(db, bhash, *number, header.Time, config) 77 } 78 } 79 } else { 80 if number := rawdb.ReadHeaderNumber(db, bhash); number != nil { 81 receipts, _ = light.GetBlockReceipts(ctx, lc.Odr(), bhash, *number) 82 } 83 } 84 if receipts == nil { 85 return nil 86 } 87 rlp, _ := rlp.EncodeToBytes(receipts) 88 return rlp 89 } 90 91 func TestOdrAccountsLes2(t *testing.T) { testOdr(t, 2, 1, true, odrAccounts) } 92 func TestOdrAccountsLes3(t *testing.T) { testOdr(t, 3, 1, true, odrAccounts) } 93 func TestOdrAccountsLes4(t *testing.T) { testOdr(t, 4, 1, true, odrAccounts) } 94 95 func odrAccounts(ctx context.Context, db zonddb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte { 96 dummyAddr := common.HexToAddress("1234567812345678123456781234567812345678") 97 acc := []common.Address{bankAddr, userAddr1, userAddr2, dummyAddr} 98 99 var ( 100 res []byte 101 st *state.StateDB 102 err error 103 ) 104 for _, addr := range acc { 105 if bc != nil { 106 header := bc.GetHeaderByHash(bhash) 107 st, err = state.New(header.Root, bc.StateCache(), nil) 108 } else { 109 header := lc.GetHeaderByHash(bhash) 110 st = light.NewState(ctx, header, lc.Odr()) 111 } 112 if err == nil { 113 bal := st.GetBalance(addr) 114 rlp, _ := rlp.EncodeToBytes(bal) 115 res = append(res, rlp...) 116 } 117 } 118 return res 119 } 120 121 func TestOdrContractCallLes2(t *testing.T) { testOdr(t, 2, 2, true, odrContractCall) } 122 func TestOdrContractCallLes3(t *testing.T) { testOdr(t, 3, 2, true, odrContractCall) } 123 func TestOdrContractCallLes4(t *testing.T) { testOdr(t, 4, 2, true, odrContractCall) } 124 125 func odrContractCall(ctx context.Context, db zonddb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte { 126 data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000") 127 128 var res []byte 129 for i := 0; i < 3; i++ { 130 data[35] = byte(i) 131 if bc != nil { 132 header := bc.GetHeaderByHash(bhash) 133 statedb, err := state.New(header.Root, bc.StateCache(), nil) 134 135 if err == nil { 136 from := statedb.GetOrNewStateObject(bankAddr) 137 from.SetBalance(math.MaxBig256) 138 139 msg := &core.Message{ 140 From: from.Address(), 141 To: &testContractAddr, 142 Value: new(big.Int), 143 GasLimit: 100000, 144 GasPrice: big.NewInt(params.InitialBaseFee), 145 GasFeeCap: big.NewInt(params.InitialBaseFee), 146 GasTipCap: new(big.Int), 147 Data: data, 148 SkipAccountChecks: true, 149 } 150 151 context := core.NewEVMBlockContext(header, bc, nil) 152 txContext := core.NewEVMTxContext(msg) 153 vmenv := vm.NewEVM(context, txContext, statedb, config, vm.Config{NoBaseFee: true}) 154 155 //vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{}) 156 gp := new(core.GasPool).AddGas(math.MaxUint64) 157 result, _ := core.ApplyMessage(vmenv, msg, gp) 158 res = append(res, result.Return()...) 159 } 160 } else { 161 header := lc.GetHeaderByHash(bhash) 162 state := light.NewState(ctx, header, lc.Odr()) 163 state.SetBalance(bankAddr, math.MaxBig256) 164 msg := &core.Message{ 165 From: bankAddr, 166 To: &testContractAddr, 167 Value: new(big.Int), 168 GasLimit: 100000, 169 GasPrice: big.NewInt(params.InitialBaseFee), 170 GasFeeCap: big.NewInt(params.InitialBaseFee), 171 GasTipCap: new(big.Int), 172 Data: data, 173 SkipAccountChecks: true, 174 } 175 context := core.NewEVMBlockContext(header, lc, nil) 176 txContext := core.NewEVMTxContext(msg) 177 vmenv := vm.NewEVM(context, txContext, state, config, vm.Config{NoBaseFee: true}) 178 gp := new(core.GasPool).AddGas(math.MaxUint64) 179 result, _ := core.ApplyMessage(vmenv, msg, gp) 180 if state.Error() == nil { 181 res = append(res, result.Return()...) 182 } 183 } 184 } 185 return res 186 } 187 188 func TestOdrTxStatusLes2(t *testing.T) { testOdr(t, 2, 1, false, odrTxStatus) } 189 func TestOdrTxStatusLes3(t *testing.T) { testOdr(t, 3, 1, false, odrTxStatus) } 190 func TestOdrTxStatusLes4(t *testing.T) { testOdr(t, 4, 1, false, odrTxStatus) } 191 192 func odrTxStatus(ctx context.Context, db zonddb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte { 193 var txs types.Transactions 194 if bc != nil { 195 block := bc.GetBlockByHash(bhash) 196 txs = block.Transactions() 197 } else { 198 if block, _ := lc.GetBlockByHash(ctx, bhash); block != nil { 199 btxs := block.Transactions() 200 txs = make(types.Transactions, len(btxs)) 201 for i, tx := range btxs { 202 var err error 203 txs[i], _, _, _, err = light.GetTransaction(ctx, lc.Odr(), tx.Hash()) 204 if err != nil { 205 return nil 206 } 207 } 208 } 209 } 210 rlp, _ := rlp.EncodeToBytes(txs) 211 return rlp 212 } 213 214 // testOdr tests odr requests whose validation guaranteed by block headers. 215 func testOdr(t *testing.T, protocol int, expFail uint64, checkCached bool, fn odrTestFn) { 216 // Assemble the test environment 217 netconfig := testnetConfig{ 218 blocks: 4, 219 protocol: protocol, 220 connect: true, 221 nopruning: true, 222 } 223 server, client, tearDown := newClientServerEnv(t, netconfig) 224 defer tearDown() 225 226 // Ensure the client has synced all necessary data. 227 clientHead := client.handler.backend.blockchain.CurrentHeader() 228 if clientHead.Number.Uint64() != 4 { 229 t.Fatalf("Failed to sync the chain with server, head: %v", clientHead.Number.Uint64()) 230 } 231 // Disable the mechanism that we will wait a few time for request 232 // even there is no suitable peer to send right now. 233 waitForPeers = 0 234 235 test := func(expFail uint64) { 236 // Mark this as a helper to put the failures at the correct lines 237 t.Helper() 238 239 for i := uint64(0); i <= server.handler.blockchain.CurrentHeader().Number.Uint64(); i++ { 240 bhash := rawdb.ReadCanonicalHash(server.db, i) 241 b1 := fn(light.NoOdr, server.db, server.handler.server.chainConfig, server.handler.blockchain, nil, bhash) 242 243 // Set the timeout as 1 second here, ensure there is enough time 244 // for travis to make the action. 245 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 246 b2 := fn(ctx, client.db, client.handler.backend.chainConfig, nil, client.handler.backend.blockchain, bhash) 247 cancel() 248 249 eq := bytes.Equal(b1, b2) 250 exp := i < expFail 251 if exp && !eq { 252 t.Fatalf("odr mismatch: have %x, want %x", b2, b1) 253 } 254 if !exp && eq { 255 t.Fatalf("unexpected odr match") 256 } 257 } 258 } 259 260 // expect retrievals to fail (except genesis block) without a les peer 261 client.handler.backend.peers.lock.Lock() 262 client.peer.speer.hasBlockHook = func(common.Hash, uint64, bool) bool { return false } 263 client.handler.backend.peers.lock.Unlock() 264 test(expFail) 265 266 // expect all retrievals to pass 267 client.handler.backend.peers.lock.Lock() 268 client.peer.speer.hasBlockHook = func(common.Hash, uint64, bool) bool { return true } 269 client.handler.backend.peers.lock.Unlock() 270 test(5) 271 272 // still expect all retrievals to pass, now data should be cached locally 273 if checkCached { 274 client.handler.backend.peers.unregister(client.peer.speer.id) 275 time.Sleep(time.Millisecond * 10) // ensure that all peerSetNotify callbacks are executed 276 test(5) 277 } 278 } 279 280 func TestGetTxStatusFromUnindexedPeersLES4(t *testing.T) { testGetTxStatusFromUnindexedPeers(t, lpv4) } 281 282 func testGetTxStatusFromUnindexedPeers(t *testing.T, protocol int) { 283 var ( 284 blocks = 8 285 netconfig = testnetConfig{ 286 blocks: blocks, 287 protocol: protocol, 288 nopruning: true, 289 } 290 ) 291 server, client, tearDown := newClientServerEnv(t, netconfig) 292 defer tearDown() 293 294 // Iterate the chain, create the tx indexes locally 295 var ( 296 testHash common.Hash 297 testStatus light.TxStatus 298 299 txs = make(map[common.Hash]*types.Transaction) // Transaction objects set 300 blockNumbers = make(map[common.Hash]uint64) // Transaction hash to block number mappings 301 blockHashes = make(map[common.Hash]common.Hash) // Transaction hash to block hash mappings 302 intraIndex = make(map[common.Hash]uint64) // Transaction intra-index in block 303 ) 304 for number := uint64(1); number < server.backend.Blockchain().CurrentBlock().Number.Uint64(); number++ { 305 block := server.backend.Blockchain().GetBlockByNumber(number) 306 if block == nil { 307 t.Fatalf("Failed to retrieve block %d", number) 308 } 309 for index, tx := range block.Transactions() { 310 txs[tx.Hash()] = tx 311 blockNumbers[tx.Hash()] = number 312 blockHashes[tx.Hash()] = block.Hash() 313 intraIndex[tx.Hash()] = uint64(index) 314 315 if testHash == (common.Hash{}) { 316 testHash = tx.Hash() 317 testStatus = light.TxStatus{ 318 Status: txpool.TxStatusIncluded, 319 Lookup: &rawdb.LegacyTxLookupEntry{ 320 BlockHash: block.Hash(), 321 BlockIndex: block.NumberU64(), 322 Index: uint64(index), 323 }, 324 } 325 } 326 } 327 } 328 // serveMsg processes incoming GetTxStatusMsg and sends the response back. 329 serveMsg := func(peer *testPeer, txLookup uint64) error { 330 msg, err := peer.app.ReadMsg() 331 if err != nil { 332 return err 333 } 334 if msg.Code != GetTxStatusMsg { 335 return fmt.Errorf("message code mismatch: got %d, expected %d", msg.Code, GetTxStatusMsg) 336 } 337 var r GetTxStatusPacket 338 if err := msg.Decode(&r); err != nil { 339 return err 340 } 341 stats := make([]light.TxStatus, len(r.Hashes)) 342 for i, hash := range r.Hashes { 343 number, exist := blockNumbers[hash] 344 if !exist { 345 continue // Filter out unknown transactions 346 } 347 min := uint64(blocks) - txLookup 348 if txLookup != txIndexUnlimited && (txLookup == txIndexDisabled || number < min) { 349 continue // Filter out unindexed transactions 350 } 351 stats[i].Status = txpool.TxStatusIncluded 352 stats[i].Lookup = &rawdb.LegacyTxLookupEntry{ 353 BlockHash: blockHashes[hash], 354 BlockIndex: number, 355 Index: intraIndex[hash], 356 } 357 } 358 data, _ := rlp.EncodeToBytes(stats) 359 reply := &reply{peer.app, TxStatusMsg, r.ReqID, data} 360 reply.send(testBufLimit) 361 return nil 362 } 363 364 var testspecs = []struct { 365 peers int 366 txLookups []uint64 367 txs []common.Hash 368 results []light.TxStatus 369 }{ 370 // Retrieve mined transaction from the empty peerset 371 { 372 peers: 0, 373 txLookups: []uint64{}, 374 txs: []common.Hash{testHash}, 375 results: []light.TxStatus{{}}, 376 }, 377 // Retrieve unknown transaction from the full peers 378 { 379 peers: 3, 380 txLookups: []uint64{txIndexUnlimited, txIndexUnlimited, txIndexUnlimited}, 381 txs: []common.Hash{randomHash()}, 382 results: []light.TxStatus{{}}, 383 }, 384 // Retrieve mined transaction from the full peers 385 { 386 peers: 3, 387 txLookups: []uint64{txIndexUnlimited, txIndexUnlimited, txIndexUnlimited}, 388 txs: []common.Hash{testHash}, 389 results: []light.TxStatus{testStatus}, 390 }, 391 // Retrieve mixed transactions from the full peers 392 { 393 peers: 3, 394 txLookups: []uint64{txIndexUnlimited, txIndexUnlimited, txIndexUnlimited}, 395 txs: []common.Hash{randomHash(), testHash}, 396 results: []light.TxStatus{{}, testStatus}, 397 }, 398 // Retrieve mixed transactions from unindexed peer(but the target is still available) 399 { 400 peers: 3, 401 txLookups: []uint64{uint64(blocks) - testStatus.Lookup.BlockIndex, uint64(blocks) - testStatus.Lookup.BlockIndex - 1, uint64(blocks) - testStatus.Lookup.BlockIndex - 2}, 402 txs: []common.Hash{randomHash(), testHash}, 403 results: []light.TxStatus{{}, testStatus}, 404 }, 405 // Retrieve mixed transactions from unindexed peer(but the target is not available) 406 { 407 peers: 3, 408 txLookups: []uint64{uint64(blocks) - testStatus.Lookup.BlockIndex - 1, uint64(blocks) - testStatus.Lookup.BlockIndex - 1, uint64(blocks) - testStatus.Lookup.BlockIndex - 2}, 409 txs: []common.Hash{randomHash(), testHash}, 410 results: []light.TxStatus{{}, {}}, 411 }, 412 } 413 for _, testspec := range testspecs { 414 // Create a bunch of server peers with different tx history 415 var ( 416 closeFns []func() 417 ) 418 for i := 0; i < testspec.peers; i++ { 419 peer, closePeer, _ := client.newRawPeer(t, fmt.Sprintf("server-%d", i), protocol, testspec.txLookups[i]) 420 closeFns = append(closeFns, closePeer) 421 422 // Create a one-time routine for serving message 423 go func(i int, peer *testPeer, lookup uint64) { 424 serveMsg(peer, lookup) 425 }(i, peer, testspec.txLookups[i]) 426 } 427 428 // Send out the GetTxStatus requests, compare the result with 429 // expected value. 430 r := &light.TxStatusRequest{Hashes: testspec.txs} 431 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 432 defer cancel() 433 434 err := client.handler.backend.odr.RetrieveTxStatus(ctx, r) 435 if err != nil { 436 t.Errorf("Failed to retrieve tx status %v", err) 437 } else { 438 if !reflect.DeepEqual(testspec.results, r.Status) { 439 t.Errorf("Result mismatch, diff") 440 } 441 } 442 443 // Close all connected peers and start the next round 444 for _, closeFn := range closeFns { 445 closeFn() 446 } 447 } 448 } 449 450 // randomHash generates a random blob of data and returns it as a hash. 451 func randomHash() common.Hash { 452 var hash common.Hash 453 if n, err := rand.Read(hash[:]); n != common.HashLength || err != nil { 454 panic(err) 455 } 456 return hash 457 } 458 */