github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/light/odr_test.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:39</date> 10 //</624450096536227840> 11 12 13 package light 14 15 import ( 16 "bytes" 17 "context" 18 "errors" 19 "math/big" 20 "testing" 21 "time" 22 23 "github.com/ethereum/go-ethereum/common" 24 "github.com/ethereum/go-ethereum/common/math" 25 "github.com/ethereum/go-ethereum/consensus/ethash" 26 "github.com/ethereum/go-ethereum/core" 27 "github.com/ethereum/go-ethereum/core/rawdb" 28 "github.com/ethereum/go-ethereum/core/state" 29 "github.com/ethereum/go-ethereum/core/types" 30 "github.com/ethereum/go-ethereum/core/vm" 31 "github.com/ethereum/go-ethereum/crypto" 32 "github.com/ethereum/go-ethereum/ethdb" 33 "github.com/ethereum/go-ethereum/params" 34 "github.com/ethereum/go-ethereum/rlp" 35 "github.com/ethereum/go-ethereum/trie" 36 ) 37 38 var ( 39 testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 40 testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) 41 testBankFunds = big.NewInt(100000000) 42 43 acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 44 acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") 45 acc1Addr = crypto.PubkeyToAddress(acc1Key.PublicKey) 46 acc2Addr = crypto.PubkeyToAddress(acc2Key.PublicKey) 47 48 testContractCode = common.Hex2Bytes("606060405260cc8060106000396000f360606040526000357c01000000000000000000000000000000000000000000000000000000009004806360cd2685146041578063c16431b914606b57603f565b005b6055600480803590602001909190505060a9565b6040518082815260200191505060405180910390f35b60886004808035906020019091908035906020019091905050608a565b005b80600060005083606481101560025790900160005b50819055505b5050565b6000600060005082606481101560025790900160005b5054905060c7565b91905056") 49 testContractAddr common.Address 50 ) 51 52 type testOdr struct { 53 OdrBackend 54 indexerConfig *IndexerConfig 55 sdb, ldb ethdb.Database 56 disable bool 57 } 58 59 func (odr *testOdr) Database() ethdb.Database { 60 return odr.ldb 61 } 62 63 var ErrOdrDisabled = errors.New("ODR disabled") 64 65 func (odr *testOdr) Retrieve(ctx context.Context, req OdrRequest) error { 66 if odr.disable { 67 return ErrOdrDisabled 68 } 69 switch req := req.(type) { 70 case *BlockRequest: 71 number := rawdb.ReadHeaderNumber(odr.sdb, req.Hash) 72 if number != nil { 73 req.Rlp = rawdb.ReadBodyRLP(odr.sdb, req.Hash, *number) 74 } 75 case *ReceiptsRequest: 76 number := rawdb.ReadHeaderNumber(odr.sdb, req.Hash) 77 if number != nil { 78 req.Receipts = rawdb.ReadReceipts(odr.sdb, req.Hash, *number) 79 } 80 case *TrieRequest: 81 t, _ := trie.New(req.Id.Root, trie.NewDatabase(odr.sdb)) 82 nodes := NewNodeSet() 83 t.Prove(req.Key, 0, nodes) 84 req.Proof = nodes 85 case *CodeRequest: 86 req.Data, _ = odr.sdb.Get(req.Hash[:]) 87 } 88 req.StoreResult(odr.ldb) 89 return nil 90 } 91 92 func (odr *testOdr) IndexerConfig() *IndexerConfig { 93 return odr.indexerConfig 94 } 95 96 type odrTestFn func(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) 97 98 func TestOdrGetBlockLes1(t *testing.T) { testChainOdr(t, 1, odrGetBlock) } 99 100 func odrGetBlock(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) { 101 var block *types.Block 102 if bc != nil { 103 block = bc.GetBlockByHash(bhash) 104 } else { 105 block, _ = lc.GetBlockByHash(ctx, bhash) 106 } 107 if block == nil { 108 return nil, nil 109 } 110 rlp, _ := rlp.EncodeToBytes(block) 111 return rlp, nil 112 } 113 114 func TestOdrGetReceiptsLes1(t *testing.T) { testChainOdr(t, 1, odrGetReceipts) } 115 116 func odrGetReceipts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) { 117 var receipts types.Receipts 118 if bc != nil { 119 number := rawdb.ReadHeaderNumber(db, bhash) 120 if number != nil { 121 receipts = rawdb.ReadReceipts(db, bhash, *number) 122 } 123 } else { 124 number := rawdb.ReadHeaderNumber(db, bhash) 125 if number != nil { 126 receipts, _ = GetBlockReceipts(ctx, lc.Odr(), bhash, *number) 127 } 128 } 129 if receipts == nil { 130 return nil, nil 131 } 132 rlp, _ := rlp.EncodeToBytes(receipts) 133 return rlp, nil 134 } 135 136 func TestOdrAccountsLes1(t *testing.T) { testChainOdr(t, 1, odrAccounts) } 137 138 func odrAccounts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) { 139 dummyAddr := common.HexToAddress("1234567812345678123456781234567812345678") 140 acc := []common.Address{testBankAddress, acc1Addr, acc2Addr, dummyAddr} 141 142 var st *state.StateDB 143 if bc == nil { 144 header := lc.GetHeaderByHash(bhash) 145 st = NewState(ctx, header, lc.Odr()) 146 } else { 147 header := bc.GetHeaderByHash(bhash) 148 st, _ = state.New(header.Root, state.NewDatabase(db)) 149 } 150 151 var res []byte 152 for _, addr := range acc { 153 bal := st.GetBalance(addr) 154 rlp, _ := rlp.EncodeToBytes(bal) 155 res = append(res, rlp...) 156 } 157 return res, st.Error() 158 } 159 160 func TestOdrContractCallLes1(t *testing.T) { testChainOdr(t, 1, odrContractCall) } 161 162 type callmsg struct { 163 types.Message 164 } 165 166 func (callmsg) CheckNonce() bool { return false } 167 168 func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) { 169 data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000") 170 config := params.TestChainConfig 171 172 var res []byte 173 for i := 0; i < 3; i++ { 174 data[35] = byte(i) 175 176 var ( 177 st *state.StateDB 178 header *types.Header 179 chain core.ChainContext 180 ) 181 if bc == nil { 182 chain = lc 183 header = lc.GetHeaderByHash(bhash) 184 st = NewState(ctx, header, lc.Odr()) 185 } else { 186 chain = bc 187 header = bc.GetHeaderByHash(bhash) 188 st, _ = state.New(header.Root, state.NewDatabase(db)) 189 } 190 191 //执行只读调用。 192 st.SetBalance(testBankAddress, math.MaxBig256) 193 msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), data, false)} 194 context := core.NewEVMContext(msg, header, chain, nil) 195 vmenv := vm.NewEVM(context, st, config, vm.Config{}) 196 gp := new(core.GasPool).AddGas(math.MaxUint64) 197 ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp) 198 res = append(res, ret...) 199 if st.Error() != nil { 200 return res, st.Error() 201 } 202 } 203 return res, nil 204 } 205 206 func testChainGen(i int, block *core.BlockGen) { 207 signer := types.HomesteadSigner{} 208 switch i { 209 case 0: 210 //在块1中,测试银行发送帐户1一些乙醚。 211 tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey) 212 block.AddTx(tx) 213 case 1: 214 //在区块2中,测试银行向账户1发送更多乙醚。 215 //acc1addr将其传递到account_2。 216 //acc1addr创建一个测试合同。 217 tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey) 218 nonce := block.TxNonce(acc1Addr) 219 tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key) 220 nonce++ 221 tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), 1000000, big.NewInt(0), testContractCode), signer, acc1Key) 222 testContractAddr = crypto.CreateAddress(acc1Addr, nonce) 223 block.AddTx(tx1) 224 block.AddTx(tx2) 225 block.AddTx(tx3) 226 case 2: 227 //区块3为空,但由账户2开采。 228 block.SetCoinbase(acc2Addr) 229 block.SetExtra([]byte("yeehaw")) 230 data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001") 231 tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, data), signer, testBankKey) 232 block.AddTx(tx) 233 case 3: 234 //块4包括块2和3作为叔叔头(带有修改的额外数据)。 235 b2 := block.PrevBlock(1).Header() 236 b2.Extra = []byte("foo") 237 block.AddUncle(b2) 238 b3 := block.PrevBlock(2).Header() 239 b3.Extra = []byte("foo") 240 block.AddUncle(b3) 241 data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002") 242 tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, data), signer, testBankKey) 243 block.AddTx(tx) 244 } 245 } 246 247 func testChainOdr(t *testing.T, protocol int, fn odrTestFn) { 248 var ( 249 sdb = ethdb.NewMemDatabase() 250 ldb = ethdb.NewMemDatabase() 251 gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}} 252 genesis = gspec.MustCommit(sdb) 253 ) 254 gspec.MustCommit(ldb) 255 //组装测试环境 256 blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil) 257 gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, 4, testChainGen) 258 if _, err := blockchain.InsertChain(gchain); err != nil { 259 t.Fatal(err) 260 } 261 262 odr := &testOdr{sdb: sdb, ldb: ldb, indexerConfig: TestClientIndexerConfig} 263 lightchain, err := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker()) 264 if err != nil { 265 t.Fatal(err) 266 } 267 headers := make([]*types.Header, len(gchain)) 268 for i, block := range gchain { 269 headers[i] = block.Header() 270 } 271 if _, err := lightchain.InsertHeaderChain(headers, 1); err != nil { 272 t.Fatal(err) 273 } 274 275 test := func(expFail int) { 276 for i := uint64(0); i <= blockchain.CurrentHeader().Number.Uint64(); i++ { 277 bhash := rawdb.ReadCanonicalHash(sdb, i) 278 b1, err := fn(NoOdr, sdb, blockchain, nil, bhash) 279 if err != nil { 280 t.Fatalf("error in full-node test for block %d: %v", i, err) 281 } 282 283 ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) 284 defer cancel() 285 286 exp := i < uint64(expFail) 287 b2, err := fn(ctx, ldb, nil, lightchain, bhash) 288 if err != nil && exp { 289 t.Errorf("error in ODR test for block %d: %v", i, err) 290 } 291 292 eq := bytes.Equal(b1, b2) 293 if exp && !eq { 294 t.Errorf("ODR test output for block %d doesn't match full node", i) 295 } 296 } 297 } 298 299 //预计在没有LES对等机的情况下检索失败(Genesis块除外) 300 t.Log("checking without ODR") 301 odr.disable = true 302 test(1) 303 304 //希望在启用ODR的情况下通过所有检索 305 t.Log("checking with ODR") 306 odr.disable = false 307 test(len(gchain)) 308 309 //仍然希望通过所有检索,现在应该在本地缓存数据 310 t.Log("checking without ODR, should be cached") 311 odr.disable = true 312 test(len(gchain)) 313 } 314