github.com/core-coin/go-core/v2@v2.1.9/light/odr_test.go (about) 1 // Copyright 2016 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core 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-core 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-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package light 18 19 import ( 20 "bytes" 21 "context" 22 "errors" 23 "math/big" 24 "testing" 25 "time" 26 27 "github.com/core-coin/go-core/v2/xcbdb" 28 29 "github.com/core-coin/go-core/v2/consensus/cryptore" 30 31 "github.com/core-coin/go-core/v2/common" 32 "github.com/core-coin/go-core/v2/common/math" 33 "github.com/core-coin/go-core/v2/core" 34 "github.com/core-coin/go-core/v2/core/rawdb" 35 "github.com/core-coin/go-core/v2/core/state" 36 "github.com/core-coin/go-core/v2/core/types" 37 "github.com/core-coin/go-core/v2/core/vm" 38 "github.com/core-coin/go-core/v2/crypto" 39 "github.com/core-coin/go-core/v2/params" 40 "github.com/core-coin/go-core/v2/rlp" 41 "github.com/core-coin/go-core/v2/trie" 42 ) 43 44 var ( 45 testBankKey, _ = crypto.UnmarshalPrivateKeyHex("89bdfaa2b6f9c30b94ee98fec96c58ff8507fabf49d36a6267e6cb5516eaa2a9e854eccc041f9f67e109d0eb4f653586855355c5b2b87bb313") 46 testBankFunds = big.NewInt(100000000) 47 48 acc1Key, _ = crypto.UnmarshalPrivateKeyHex("ab856a9af6b0b651dd2f43b5e12193652ec1701c4da6f1c0d2a366ac4b9dabc9433ef09e41ca129552bd2c029086d9b03604de872a3b343204") 49 acc2Key, _ = crypto.UnmarshalPrivateKeyHex("c0b711eea422df26d5ffdcaae35fe0527cf647c5ce62d3efb5e09a0e14fc8afe57fac1a5daa330bc10bfa1d3db11e172a822dcfffb86a0b26d") 50 51 testContractCode = common.Hex2Bytes("606060405260cc8060106000396000f360606040526000357c01000000000000000000000000000000000000000000000000000000009004806360cd2685146041578063c16431b914606b57603f565b005b6055600480803590602001909190505060a9565b6040518082815260200191505060405180910390f35b60886004808035906020019091908035906020019091905050608a565b005b80600060005083606481101560025790900160005b50819055505b5050565b6000600060005082606481101560025790900160005b5054905060c7565b91905056") 52 testContractAddr common.Address 53 ) 54 55 type testOdr struct { 56 OdrBackend 57 indexerConfig *IndexerConfig 58 sdb, ldb xcbdb.Database 59 disable bool 60 } 61 62 func (odr *testOdr) Database() xcbdb.Database { 63 return odr.ldb 64 } 65 66 var ErrOdrDisabled = errors.New("ODR disabled") 67 68 func (odr *testOdr) Retrieve(ctx context.Context, req OdrRequest) error { 69 if odr.disable { 70 return ErrOdrDisabled 71 } 72 switch req := req.(type) { 73 case *BlockRequest: 74 number := rawdb.ReadHeaderNumber(odr.sdb, req.Hash) 75 if number != nil { 76 req.Rlp = rawdb.ReadBodyRLP(odr.sdb, req.Hash, *number) 77 } 78 case *ReceiptsRequest: 79 number := rawdb.ReadHeaderNumber(odr.sdb, req.Hash) 80 if number != nil { 81 req.Receipts = rawdb.ReadRawReceipts(odr.sdb, req.Hash, *number) 82 } 83 case *TrieRequest: 84 t, _ := trie.New(req.Id.Root, trie.NewDatabase(odr.sdb)) 85 nodes := NewNodeSet() 86 t.Prove(req.Key, 0, nodes) 87 req.Proof = nodes 88 case *CodeRequest: 89 req.Data = rawdb.ReadCode(odr.sdb, req.Hash) 90 } 91 req.StoreResult(odr.ldb) 92 return nil 93 } 94 95 func (odr *testOdr) IndexerConfig() *IndexerConfig { 96 return odr.indexerConfig 97 } 98 99 type odrTestFn func(ctx context.Context, db xcbdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) 100 101 func TestOdrGetBlockLes2(t *testing.T) { testChainOdr(t, 1, odrGetBlock) } 102 103 func odrGetBlock(ctx context.Context, db xcbdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) { 104 var block *types.Block 105 if bc != nil { 106 block = bc.GetBlockByHash(bhash) 107 } else { 108 block, _ = lc.GetBlockByHash(ctx, bhash) 109 } 110 if block == nil { 111 return nil, nil 112 } 113 rlp, _ := rlp.EncodeToBytes(block) 114 return rlp, nil 115 } 116 117 func TestOdrGetReceiptsLes2(t *testing.T) { testChainOdr(t, 1, odrGetReceipts) } 118 119 func odrGetReceipts(ctx context.Context, db xcbdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) { 120 var receipts types.Receipts 121 if bc != nil { 122 number := rawdb.ReadHeaderNumber(db, bhash) 123 if number != nil { 124 receipts = rawdb.ReadReceipts(db, bhash, *number, bc.Config()) 125 } 126 } else { 127 number := rawdb.ReadHeaderNumber(db, bhash) 128 if number != nil { 129 receipts, _ = GetBlockReceipts(ctx, lc.Odr(), bhash, *number) 130 } 131 } 132 if receipts == nil { 133 return nil, nil 134 } 135 rlp, _ := rlp.EncodeToBytes(receipts) 136 return rlp, nil 137 } 138 139 func TestOdrAccountsLes2(t *testing.T) { testChainOdr(t, 1, odrAccounts) } 140 141 func odrAccounts(ctx context.Context, db xcbdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) { 142 dummyAddr, err := common.HexToAddress("cb721234567812345678123456781234567812345678") 143 if err != nil { 144 panic(err) 145 } 146 acc := []common.Address{testBankKey.Address(), acc1Key.Address(), acc2Key.Address(), dummyAddr} 147 148 var st *state.StateDB 149 if bc == nil { 150 header := lc.GetHeaderByHash(bhash) 151 st = NewState(ctx, header, lc.Odr()) 152 } else { 153 header := bc.GetHeaderByHash(bhash) 154 st, _ = state.New(header.Root, state.NewDatabase(db), nil) 155 } 156 157 var res []byte 158 for _, addr := range acc { 159 bal := st.GetBalance(addr) 160 rlp, _ := rlp.EncodeToBytes(bal) 161 res = append(res, rlp...) 162 } 163 return res, st.Error() 164 } 165 166 func TestOdrContractCallLes2(t *testing.T) { testChainOdr(t, 1, odrContractCall) } 167 168 type callmsg struct { 169 types.Message 170 } 171 172 func (callmsg) CheckNonce() bool { return false } 173 174 func odrContractCall(ctx context.Context, db xcbdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) { 175 data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000") 176 config := params.MainnetChainConfig 177 178 var res []byte 179 for i := 0; i < 3; i++ { 180 data[35] = byte(i) 181 182 var ( 183 st *state.StateDB 184 header *types.Header 185 chain core.ChainContext 186 ) 187 if bc == nil { 188 chain = lc 189 header = lc.GetHeaderByHash(bhash) 190 st = NewState(ctx, header, lc.Odr()) 191 } else { 192 chain = bc 193 header = bc.GetHeaderByHash(bhash) 194 st, _ = state.New(header.Root, state.NewDatabase(db), nil) 195 } 196 197 // Perform read-only call. 198 st.SetBalance(testBankKey.Address(), math.MaxBig256) 199 msg := callmsg{types.NewMessage(testBankKey.Address(), &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), data, false)} 200 txContext := core.NewCVMTxContext(msg) 201 context := core.NewCVMBlockContext(header, chain, nil) 202 vmenv := vm.NewCVM(context, txContext, st, config, vm.Config{}) 203 gp := new(core.EnergyPool).AddEnergy(math.MaxUint64) 204 result, _ := core.ApplyMessage(vmenv, msg, gp) 205 res = append(res, result.Return()...) 206 if st.Error() != nil { 207 return res, st.Error() 208 } 209 } 210 return res, nil 211 } 212 213 func testChainGen(i int, block *core.BlockGen) { 214 signer := types.NewNucleusSigner(params.MainnetChainConfig.NetworkID) 215 switch i { 216 case 0: 217 // In block 1, the test bank sends account #1 some core. 218 tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankKey.Address()), acc1Key.Address(), big.NewInt(10000), params.TxEnergy, nil, nil), signer, testBankKey) 219 block.AddTx(tx) 220 case 1: 221 // In block 2, the test bank sends some more core to account #1. 222 // acc1Key.Address() passes it on to account #2. 223 // acc1Key.Address() creates a test contract. 224 tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankKey.Address()), acc1Key.Address(), big.NewInt(1000), params.TxEnergy, nil, nil), signer, testBankKey) 225 nonce := block.TxNonce(acc1Key.Address()) 226 tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Key.Address(), big.NewInt(1000), params.TxEnergy, nil, nil), signer, acc1Key) 227 nonce++ 228 tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), 1000000, big.NewInt(0), testContractCode), signer, acc1Key) 229 testContractAddr = crypto.CreateAddress(acc1Key.Address(), nonce) 230 block.AddTx(tx1) 231 block.AddTx(tx2) 232 block.AddTx(tx3) 233 case 2: 234 // Block 3 is empty but was mined by account #2. 235 block.SetCoinbase(acc2Key.Address()) 236 block.SetExtra([]byte("yeehaw")) 237 data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001") 238 tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankKey.Address()), testContractAddr, big.NewInt(0), 100000, nil, data), signer, testBankKey) 239 block.AddTx(tx) 240 case 3: 241 // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). 242 b2 := block.PrevBlock(1).Header() 243 b2.Extra = []byte("foo") 244 block.AddUncle(b2) 245 b3 := block.PrevBlock(2).Header() 246 b3.Extra = []byte("foo") 247 block.AddUncle(b3) 248 data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002") 249 tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankKey.Address()), testContractAddr, big.NewInt(0), 100000, nil, data), signer, testBankKey) 250 block.AddTx(tx) 251 } 252 } 253 254 func testChainOdr(t *testing.T, protocol int, fn odrTestFn) { 255 var ( 256 sdb = rawdb.NewMemoryDatabase() 257 ldb = rawdb.NewMemoryDatabase() 258 gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankKey.Address(): {Balance: testBankFunds}}} 259 genesis = gspec.MustCommit(sdb) 260 ) 261 gspec.MustCommit(ldb) 262 // Assemble the test environment 263 blockchain, _ := core.NewBlockChain(sdb, nil, params.MainnetChainConfig, cryptore.NewFullFaker(), vm.Config{}, nil, nil) 264 gchain, _ := core.GenerateChain(params.MainnetChainConfig, genesis, cryptore.NewFaker(), sdb, 4, testChainGen) 265 if _, err := blockchain.InsertChain(gchain); err != nil { 266 t.Fatal(err) 267 } 268 269 odr := &testOdr{sdb: sdb, ldb: ldb, indexerConfig: TestClientIndexerConfig} 270 lightchain, err := NewLightChain(odr, params.MainnetChainConfig, cryptore.NewFullFaker(), nil) 271 if err != nil { 272 t.Fatal(err) 273 } 274 headers := make([]*types.Header, len(gchain)) 275 for i, block := range gchain { 276 headers[i] = block.Header() 277 } 278 if _, err := lightchain.InsertHeaderChain(headers, 1); err != nil { 279 t.Fatal(err) 280 } 281 282 test := func(expFail int) { 283 for i := uint64(0); i <= blockchain.CurrentHeader().Number.Uint64(); i++ { 284 bhash := rawdb.ReadCanonicalHash(sdb, i) 285 b1, err := fn(NoOdr, sdb, blockchain, nil, bhash) 286 if err != nil { 287 t.Fatalf("error in full-node test for block %d: %v", i, err) 288 } 289 290 ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) 291 defer cancel() 292 293 exp := i < uint64(expFail) 294 b2, err := fn(ctx, ldb, nil, lightchain, bhash) 295 if err != nil && exp { 296 t.Errorf("error in ODR test for block %d: %v", i, err) 297 } 298 299 eq := bytes.Equal(b1, b2) 300 if exp && !eq { 301 t.Errorf("ODR test output for block %d doesn't match full node", i) 302 } 303 } 304 } 305 306 // expect retrievals to fail (except genesis block) without a les peer 307 t.Log("checking without ODR") 308 odr.disable = true 309 test(1) 310 311 // expect all retrievals to pass with ODR enabled 312 t.Log("checking with ODR") 313 odr.disable = false 314 test(len(gchain)) 315 316 // still expect all retrievals to pass, now data should be cached locally 317 t.Log("checking without ODR, should be cached") 318 odr.disable = true 319 test(len(gchain)) 320 }