github.com/dis-happy/go-ethereum@v1.8.21-0.20190106040728-7bd69dac7276/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 import ( 20 "bytes" 21 "context" 22 "math/big" 23 "testing" 24 "time" 25 26 "github.com/dis-happy/go-ethereum/common" 27 "github.com/dis-happy/go-ethereum/common/math" 28 "github.com/dis-happy/go-ethereum/core" 29 "github.com/dis-happy/go-ethereum/core/rawdb" 30 "github.com/dis-happy/go-ethereum/core/state" 31 "github.com/dis-happy/go-ethereum/core/types" 32 "github.com/dis-happy/go-ethereum/core/vm" 33 "github.com/dis-happy/go-ethereum/ethdb" 34 "github.com/dis-happy/go-ethereum/light" 35 "github.com/dis-happy/go-ethereum/params" 36 "github.com/dis-happy/go-ethereum/rlp" 37 ) 38 39 type odrTestFn func(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte 40 41 func TestOdrGetBlockLes1(t *testing.T) { testOdr(t, 1, 1, odrGetBlock) } 42 43 func TestOdrGetBlockLes2(t *testing.T) { testOdr(t, 2, 1, odrGetBlock) } 44 45 func odrGetBlock(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte { 46 var block *types.Block 47 if bc != nil { 48 block = bc.GetBlockByHash(bhash) 49 } else { 50 block, _ = lc.GetBlockByHash(ctx, bhash) 51 } 52 if block == nil { 53 return nil 54 } 55 rlp, _ := rlp.EncodeToBytes(block) 56 return rlp 57 } 58 59 func TestOdrGetReceiptsLes1(t *testing.T) { testOdr(t, 1, 1, odrGetReceipts) } 60 61 func TestOdrGetReceiptsLes2(t *testing.T) { testOdr(t, 2, 1, odrGetReceipts) } 62 63 func odrGetReceipts(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte { 64 var receipts types.Receipts 65 if bc != nil { 66 if number := rawdb.ReadHeaderNumber(db, bhash); number != nil { 67 receipts = rawdb.ReadReceipts(db, bhash, *number) 68 } 69 } else { 70 if number := rawdb.ReadHeaderNumber(db, bhash); number != nil { 71 receipts, _ = light.GetBlockReceipts(ctx, lc.Odr(), bhash, *number) 72 } 73 } 74 if receipts == nil { 75 return nil 76 } 77 rlp, _ := rlp.EncodeToBytes(receipts) 78 return rlp 79 } 80 81 func TestOdrAccountsLes1(t *testing.T) { testOdr(t, 1, 1, odrAccounts) } 82 83 func TestOdrAccountsLes2(t *testing.T) { testOdr(t, 2, 1, odrAccounts) } 84 85 func odrAccounts(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte { 86 dummyAddr := common.HexToAddress("1234567812345678123456781234567812345678") 87 acc := []common.Address{testBankAddress, acc1Addr, acc2Addr, dummyAddr} 88 89 var ( 90 res []byte 91 st *state.StateDB 92 err error 93 ) 94 for _, addr := range acc { 95 if bc != nil { 96 header := bc.GetHeaderByHash(bhash) 97 st, err = state.New(header.Root, state.NewDatabase(db)) 98 } else { 99 header := lc.GetHeaderByHash(bhash) 100 st = light.NewState(ctx, header, lc.Odr()) 101 } 102 if err == nil { 103 bal := st.GetBalance(addr) 104 rlp, _ := rlp.EncodeToBytes(bal) 105 res = append(res, rlp...) 106 } 107 } 108 return res 109 } 110 111 func TestOdrContractCallLes1(t *testing.T) { testOdr(t, 1, 2, odrContractCall) } 112 113 func TestOdrContractCallLes2(t *testing.T) { testOdr(t, 2, 2, odrContractCall) } 114 115 type callmsg struct { 116 types.Message 117 } 118 119 func (callmsg) CheckNonce() bool { return false } 120 121 func odrContractCall(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte { 122 data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000") 123 124 var res []byte 125 for i := 0; i < 3; i++ { 126 data[35] = byte(i) 127 if bc != nil { 128 header := bc.GetHeaderByHash(bhash) 129 statedb, err := state.New(header.Root, state.NewDatabase(db)) 130 131 if err == nil { 132 from := statedb.GetOrNewStateObject(testBankAddress) 133 from.SetBalance(math.MaxBig256) 134 135 msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false)} 136 137 context := core.NewEVMContext(msg, header, bc, nil) 138 vmenv := vm.NewEVM(context, statedb, config, vm.Config{}) 139 140 //vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{}) 141 gp := new(core.GasPool).AddGas(math.MaxUint64) 142 ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp) 143 res = append(res, ret...) 144 } 145 } else { 146 header := lc.GetHeaderByHash(bhash) 147 state := light.NewState(ctx, header, lc.Odr()) 148 state.SetBalance(testBankAddress, math.MaxBig256) 149 msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false)} 150 context := core.NewEVMContext(msg, header, lc, nil) 151 vmenv := vm.NewEVM(context, state, config, vm.Config{}) 152 gp := new(core.GasPool).AddGas(math.MaxUint64) 153 ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp) 154 if state.Error() == nil { 155 res = append(res, ret...) 156 } 157 } 158 } 159 return res 160 } 161 162 // testOdr tests odr requests whose validation guaranteed by block headers. 163 func testOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) { 164 // Assemble the test environment 165 server, client, tearDown := newClientServerEnv(t, 4, protocol, nil, true) 166 defer tearDown() 167 client.pm.synchronise(client.rPeer) 168 169 test := func(expFail uint64) { 170 for i := uint64(0); i <= server.pm.blockchain.CurrentHeader().Number.Uint64(); i++ { 171 bhash := rawdb.ReadCanonicalHash(server.db, i) 172 b1 := fn(light.NoOdr, server.db, server.pm.chainConfig, server.pm.blockchain.(*core.BlockChain), nil, bhash) 173 174 ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) 175 defer cancel() 176 b2 := fn(ctx, client.db, client.pm.chainConfig, nil, client.pm.blockchain.(*light.LightChain), bhash) 177 178 eq := bytes.Equal(b1, b2) 179 exp := i < expFail 180 if exp && !eq { 181 t.Errorf("odr mismatch") 182 } 183 if !exp && eq { 184 t.Errorf("unexpected odr match") 185 } 186 } 187 } 188 // temporarily remove peer to test odr fails 189 // expect retrievals to fail (except genesis block) without a les peer 190 client.peers.Unregister(client.rPeer.id) 191 time.Sleep(time.Millisecond * 10) // ensure that all peerSetNotify callbacks are executed 192 test(expFail) 193 // expect all retrievals to pass 194 client.peers.Register(client.rPeer) 195 time.Sleep(time.Millisecond * 10) // ensure that all peerSetNotify callbacks are executed 196 client.peers.lock.Lock() 197 client.rPeer.hasBlock = func(common.Hash, uint64, bool) bool { return true } 198 client.peers.lock.Unlock() 199 test(5) 200 // still expect all retrievals to pass, now data should be cached locally 201 client.peers.Unregister(client.rPeer.id) 202 time.Sleep(time.Millisecond * 10) // ensure that all peerSetNotify callbacks are executed 203 test(5) 204 }