github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/light/odr_test.go (about) 1 // This file is part of the go-sberex library. The go-sberex library is 2 // free software: you can redistribute it and/or modify it under the terms 3 // of the GNU Lesser General Public License as published by the Free 4 // Software Foundation, either version 3 of the License, or (at your option) 5 // any later version. 6 // 7 // The go-sberex library is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 // General Public License <http://www.gnu.org/licenses/> for more details. 11 12 package light 13 14 import ( 15 "bytes" 16 "context" 17 "errors" 18 "math/big" 19 "testing" 20 "time" 21 22 "github.com/Sberex/go-sberex/common" 23 "github.com/Sberex/go-sberex/common/math" 24 "github.com/Sberex/go-sberex/consensus/ethash" 25 "github.com/Sberex/go-sberex/core" 26 "github.com/Sberex/go-sberex/core/state" 27 "github.com/Sberex/go-sberex/core/types" 28 "github.com/Sberex/go-sberex/core/vm" 29 "github.com/Sberex/go-sberex/crypto" 30 "github.com/Sberex/go-sberex/ethdb" 31 "github.com/Sberex/go-sberex/params" 32 "github.com/Sberex/go-sberex/rlp" 33 "github.com/Sberex/go-sberex/trie" 34 ) 35 36 var ( 37 testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 38 testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) 39 testBankFunds = big.NewInt(100000000) 40 41 acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 42 acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") 43 acc1Addr = crypto.PubkeyToAddress(acc1Key.PublicKey) 44 acc2Addr = crypto.PubkeyToAddress(acc2Key.PublicKey) 45 46 testContractCode = common.Hex2Bytes("606060405260cc8060106000396000f360606040526000357c01000000000000000000000000000000000000000000000000000000009004806360cd2685146041578063c16431b914606b57603f565b005b6055600480803590602001909190505060a9565b6040518082815260200191505060405180910390f35b60886004808035906020019091908035906020019091905050608a565b005b80600060005083606481101560025790900160005b50819055505b5050565b6000600060005082606481101560025790900160005b5054905060c7565b91905056") 47 testContractAddr common.Address 48 ) 49 50 type testOdr struct { 51 OdrBackend 52 sdb, ldb ethdb.Database 53 disable bool 54 } 55 56 func (odr *testOdr) Database() ethdb.Database { 57 return odr.ldb 58 } 59 60 var ErrOdrDisabled = errors.New("ODR disabled") 61 62 func (odr *testOdr) Retrieve(ctx context.Context, req OdrRequest) error { 63 if odr.disable { 64 return ErrOdrDisabled 65 } 66 switch req := req.(type) { 67 case *BlockRequest: 68 req.Rlp = core.GetBodyRLP(odr.sdb, req.Hash, core.GetBlockNumber(odr.sdb, req.Hash)) 69 case *ReceiptsRequest: 70 req.Receipts = core.GetBlockReceipts(odr.sdb, req.Hash, core.GetBlockNumber(odr.sdb, req.Hash)) 71 case *TrieRequest: 72 t, _ := trie.New(req.Id.Root, trie.NewDatabase(odr.sdb)) 73 nodes := NewNodeSet() 74 t.Prove(req.Key, 0, nodes) 75 req.Proof = nodes 76 case *CodeRequest: 77 req.Data, _ = odr.sdb.Get(req.Hash[:]) 78 } 79 req.StoreResult(odr.ldb) 80 return nil 81 } 82 83 type odrTestFn func(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) 84 85 func TestOdrGetBlockLes1(t *testing.T) { testChainOdr(t, 1, odrGetBlock) } 86 87 func odrGetBlock(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) { 88 var block *types.Block 89 if bc != nil { 90 block = bc.GetBlockByHash(bhash) 91 } else { 92 block, _ = lc.GetBlockByHash(ctx, bhash) 93 } 94 if block == nil { 95 return nil, nil 96 } 97 rlp, _ := rlp.EncodeToBytes(block) 98 return rlp, nil 99 } 100 101 func TestOdrGetReceiptsLes1(t *testing.T) { testChainOdr(t, 1, odrGetReceipts) } 102 103 func odrGetReceipts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) { 104 var receipts types.Receipts 105 if bc != nil { 106 receipts = core.GetBlockReceipts(db, bhash, core.GetBlockNumber(db, bhash)) 107 } else { 108 receipts, _ = GetBlockReceipts(ctx, lc.Odr(), bhash, core.GetBlockNumber(db, bhash)) 109 } 110 if receipts == nil { 111 return nil, nil 112 } 113 rlp, _ := rlp.EncodeToBytes(receipts) 114 return rlp, nil 115 } 116 117 func TestOdrAccountsLes1(t *testing.T) { testChainOdr(t, 1, odrAccounts) } 118 119 func odrAccounts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) { 120 dummyAddr := common.HexToAddress("1234567812345678123456781234567812345678") 121 acc := []common.Address{testBankAddress, acc1Addr, acc2Addr, dummyAddr} 122 123 var st *state.StateDB 124 if bc == nil { 125 header := lc.GetHeaderByHash(bhash) 126 st = NewState(ctx, header, lc.Odr()) 127 } else { 128 header := bc.GetHeaderByHash(bhash) 129 st, _ = state.New(header.Root, state.NewDatabase(db)) 130 } 131 132 var res []byte 133 for _, addr := range acc { 134 bal := st.GetBalance(addr) 135 rlp, _ := rlp.EncodeToBytes(bal) 136 res = append(res, rlp...) 137 } 138 return res, st.Error() 139 } 140 141 func TestOdrContractCallLes1(t *testing.T) { testChainOdr(t, 1, odrContractCall) } 142 143 type callmsg struct { 144 types.Message 145 } 146 147 func (callmsg) CheckNonce() bool { return false } 148 149 func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) { 150 data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000") 151 config := params.TestChainConfig 152 153 var res []byte 154 for i := 0; i < 3; i++ { 155 data[35] = byte(i) 156 157 var ( 158 st *state.StateDB 159 header *types.Header 160 chain core.ChainContext 161 ) 162 if bc == nil { 163 chain = lc 164 header = lc.GetHeaderByHash(bhash) 165 st = NewState(ctx, header, lc.Odr()) 166 } else { 167 chain = bc 168 header = bc.GetHeaderByHash(bhash) 169 st, _ = state.New(header.Root, state.NewDatabase(db)) 170 } 171 172 // Perform read-only call. 173 st.SetBalance(testBankAddress, math.MaxBig256) 174 msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), data, false)} 175 context := core.NewEVMContext(msg, header, chain, nil) 176 vmenv := vm.NewEVM(context, st, config, vm.Config{}) 177 gp := new(core.GasPool).AddGas(math.MaxUint64) 178 ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp) 179 res = append(res, ret...) 180 if st.Error() != nil { 181 return res, st.Error() 182 } 183 } 184 return res, nil 185 } 186 187 func testChainGen(i int, block *core.BlockGen) { 188 signer := types.HomesteadSigner{} 189 switch i { 190 case 0: 191 // In block 1, the test bank sends account #1 some sbr. 192 tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey) 193 block.AddTx(tx) 194 case 1: 195 // In block 2, the test bank sends some more sbr to account #1. 196 // acc1Addr passes it on to account #2. 197 // acc1Addr creates a test contract. 198 tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey) 199 nonce := block.TxNonce(acc1Addr) 200 tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key) 201 nonce++ 202 tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), 1000000, big.NewInt(0), testContractCode), signer, acc1Key) 203 testContractAddr = crypto.CreateAddress(acc1Addr, nonce) 204 block.AddTx(tx1) 205 block.AddTx(tx2) 206 block.AddTx(tx3) 207 case 2: 208 // Block 3 is empty but was mined by account #2. 209 block.SetCoinbase(acc2Addr) 210 block.SetExtra([]byte("yeehaw")) 211 data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001") 212 tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, data), signer, testBankKey) 213 block.AddTx(tx) 214 case 3: 215 // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). 216 b2 := block.PrevBlock(1).Header() 217 b2.Extra = []byte("foo") 218 block.AddUncle(b2) 219 b3 := block.PrevBlock(2).Header() 220 b3.Extra = []byte("foo") 221 block.AddUncle(b3) 222 data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002") 223 tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, data), signer, testBankKey) 224 block.AddTx(tx) 225 } 226 } 227 228 func testChainOdr(t *testing.T, protocol int, fn odrTestFn) { 229 var ( 230 sdb, _ = ethdb.NewMemDatabase() 231 ldb, _ = ethdb.NewMemDatabase() 232 gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}} 233 genesis = gspec.MustCommit(sdb) 234 ) 235 gspec.MustCommit(ldb) 236 // Assemble the test environment 237 blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}) 238 gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, 4, testChainGen) 239 if _, err := blockchain.InsertChain(gchain); err != nil { 240 t.Fatal(err) 241 } 242 243 odr := &testOdr{sdb: sdb, ldb: ldb} 244 lightchain, err := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker()) 245 if err != nil { 246 t.Fatal(err) 247 } 248 headers := make([]*types.Header, len(gchain)) 249 for i, block := range gchain { 250 headers[i] = block.Header() 251 } 252 if _, err := lightchain.InsertHeaderChain(headers, 1); err != nil { 253 t.Fatal(err) 254 } 255 256 test := func(expFail int) { 257 for i := uint64(0); i <= blockchain.CurrentHeader().Number.Uint64(); i++ { 258 bhash := core.GetCanonicalHash(sdb, i) 259 b1, err := fn(NoOdr, sdb, blockchain, nil, bhash) 260 if err != nil { 261 t.Fatalf("error in full-node test for block %d: %v", i, err) 262 } 263 264 ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) 265 defer cancel() 266 267 exp := i < uint64(expFail) 268 b2, err := fn(ctx, ldb, nil, lightchain, bhash) 269 if err != nil && exp { 270 t.Errorf("error in ODR test for block %d: %v", i, err) 271 } 272 273 eq := bytes.Equal(b1, b2) 274 if exp && !eq { 275 t.Errorf("ODR test output for block %d doesn't match full node", i) 276 } 277 } 278 } 279 280 // expect retrievals to fail (except genesis block) without a les peer 281 t.Log("checking without ODR") 282 odr.disable = true 283 test(1) 284 285 // expect all retrievals to pass with ODR enabled 286 t.Log("checking with ODR") 287 odr.disable = false 288 test(len(gchain)) 289 290 // still expect all retrievals to pass, now data should be cached locally 291 t.Log("checking without ODR, should be cached") 292 odr.disable = true 293 test(len(gchain)) 294 }