github.com/phillinzzz/newBsc@v1.1.6/core/blockchain_diff_test.go (about) 1 // Copyright 2020 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 // Tests that abnormal program termination (i.e.crash) and restart doesn't leave 18 // the database in some strange state with gaps in the chain, nor with block data 19 // dangling in the future. 20 21 package core 22 23 import ( 24 "math/big" 25 "testing" 26 "time" 27 28 "golang.org/x/crypto/sha3" 29 30 "github.com/phillinzzz/newBsc/common" 31 "github.com/phillinzzz/newBsc/consensus/ethash" 32 "github.com/phillinzzz/newBsc/core/rawdb" 33 "github.com/phillinzzz/newBsc/core/state/snapshot" 34 "github.com/phillinzzz/newBsc/core/types" 35 "github.com/phillinzzz/newBsc/core/vm" 36 "github.com/phillinzzz/newBsc/crypto" 37 "github.com/phillinzzz/newBsc/ethdb" 38 "github.com/phillinzzz/newBsc/ethdb/memorydb" 39 "github.com/phillinzzz/newBsc/params" 40 "github.com/phillinzzz/newBsc/rlp" 41 ) 42 43 var ( 44 // testKey is a private key to use for funding a tester account. 45 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 46 // testAddr is the Ethereum address of the tester account. 47 testAddr = crypto.PubkeyToAddress(testKey.PublicKey) 48 // testBlocks is the test parameters array for specific blocks. 49 testBlocks = []testBlockParam{ 50 { 51 // This txs params also used to default block. 52 blockNr: 11, 53 txs: []testTransactionParam{ 54 { 55 to: common.Address{0x01}, 56 value: big.NewInt(1), 57 gasPrice: big.NewInt(1), 58 data: nil, 59 }, 60 }, 61 }, 62 { 63 blockNr: 12, 64 txs: []testTransactionParam{ 65 { 66 to: common.Address{0x01}, 67 value: big.NewInt(1), 68 gasPrice: big.NewInt(1), 69 data: nil, 70 }, 71 { 72 to: common.Address{0x02}, 73 value: big.NewInt(2), 74 gasPrice: big.NewInt(2), 75 data: nil, 76 }, 77 }, 78 }, 79 { 80 blockNr: 13, 81 txs: []testTransactionParam{ 82 { 83 to: common.Address{0x01}, 84 value: big.NewInt(1), 85 gasPrice: big.NewInt(1), 86 data: nil, 87 }, 88 { 89 to: common.Address{0x02}, 90 value: big.NewInt(2), 91 gasPrice: big.NewInt(2), 92 data: nil, 93 }, 94 { 95 to: common.Address{0x03}, 96 value: big.NewInt(3), 97 gasPrice: big.NewInt(3), 98 data: nil, 99 }, 100 }, 101 }, 102 { 103 blockNr: 14, 104 txs: []testTransactionParam{}, 105 }, 106 } 107 ) 108 109 type testTransactionParam struct { 110 to common.Address 111 value *big.Int 112 gasPrice *big.Int 113 data []byte 114 } 115 116 type testBlockParam struct { 117 blockNr int 118 txs []testTransactionParam 119 } 120 121 // testBackend is a mock implementation of the live Ethereum message handler. Its 122 // purpose is to allow testing the request/reply workflows and wire serialization 123 // in the `eth` protocol without actually doing any data processing. 124 type testBackend struct { 125 db ethdb.Database 126 chain *BlockChain 127 } 128 129 // newTestBackend creates an empty chain and wraps it into a mock backend. 130 func newTestBackend(blocks int, light bool) *testBackend { 131 return newTestBackendWithGenerator(blocks, light) 132 } 133 134 // newTestBackend creates a chain with a number of explicitly defined blocks and 135 // wraps it into a mock backend. 136 func newTestBackendWithGenerator(blocks int, lightProcess bool) *testBackend { 137 signer := types.HomesteadSigner{} 138 // Create a database pre-initialize with a genesis block 139 db := rawdb.NewMemoryDatabase() 140 db.SetDiffStore(memorydb.New()) 141 (&Genesis{ 142 Config: params.TestChainConfig, 143 Alloc: GenesisAlloc{testAddr: {Balance: big.NewInt(100000000000000000)}}, 144 }).MustCommit(db) 145 146 chain, _ := NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, EnablePersistDiff(860000)) 147 generator := func(i int, block *BlockGen) { 148 // The chain maker doesn't have access to a chain, so the difficulty will be 149 // lets unset (nil). Set it here to the correct value. 150 block.SetCoinbase(testAddr) 151 152 for idx, testBlock := range testBlocks { 153 // Specific block setting, the index in this generator has 1 diff from specified blockNr. 154 if i+1 == testBlock.blockNr { 155 for _, testTransaction := range testBlock.txs { 156 tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), testTransaction.to, 157 testTransaction.value, params.TxGas, testTransaction.gasPrice, testTransaction.data), signer, testKey) 158 if err != nil { 159 panic(err) 160 } 161 block.AddTxWithChain(chain, tx) 162 } 163 break 164 } 165 166 // Default block setting. 167 if idx == len(testBlocks)-1 { 168 // We want to simulate an empty middle block, having the same state as the 169 // first one. The last is needs a state change again to force a reorg. 170 for _, testTransaction := range testBlocks[0].txs { 171 tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), testTransaction.to, 172 testTransaction.value, params.TxGas, testTransaction.gasPrice, testTransaction.data), signer, testKey) 173 if err != nil { 174 panic(err) 175 } 176 block.AddTxWithChain(chain, tx) 177 } 178 } 179 } 180 181 } 182 bs, _ := GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, blocks, generator) 183 if _, err := chain.InsertChain(bs); err != nil { 184 panic(err) 185 } 186 if lightProcess { 187 EnableLightProcessor(chain) 188 } 189 190 return &testBackend{ 191 db: db, 192 chain: chain, 193 } 194 } 195 196 // close tears down the transaction pool and chain behind the mock backend. 197 func (b *testBackend) close() { 198 b.chain.Stop() 199 } 200 201 func (b *testBackend) Chain() *BlockChain { return b.chain } 202 203 func rawDataToDiffLayer(data rlp.RawValue) (*types.DiffLayer, error) { 204 var diff types.DiffLayer 205 hasher := sha3.NewLegacyKeccak256() 206 err := rlp.DecodeBytes(data, &diff) 207 if err != nil { 208 return nil, err 209 } 210 hasher.Write(data) 211 var diffHash common.Hash 212 hasher.Sum(diffHash[:0]) 213 diff.DiffHash = diffHash 214 hasher.Reset() 215 return &diff, nil 216 } 217 218 func TestProcessDiffLayer(t *testing.T) { 219 blockNum := 128 220 fullBackend := newTestBackend(blockNum, false) 221 falseDiff := 5 222 defer fullBackend.close() 223 224 lightBackend := newTestBackend(0, true) 225 defer lightBackend.close() 226 for i := 1; i <= blockNum-falseDiff; i++ { 227 block := fullBackend.chain.GetBlockByNumber(uint64(i)) 228 if block == nil { 229 t.Fatal("block should not be nil") 230 } 231 blockHash := block.Hash() 232 rawDiff := fullBackend.chain.GetDiffLayerRLP(blockHash) 233 if len(rawDiff) != 0 { 234 diff, err := rawDataToDiffLayer(rawDiff) 235 if err != nil { 236 t.Errorf("failed to decode rawdata %v", err) 237 } 238 if diff == nil { 239 continue 240 } 241 lightBackend.Chain().HandleDiffLayer(diff, "testpid", true) 242 } 243 _, err := lightBackend.chain.insertChain([]*types.Block{block}, true) 244 if err != nil { 245 t.Errorf("failed to insert block %v", err) 246 } 247 } 248 currentBlock := lightBackend.chain.CurrentBlock() 249 nextBlock := fullBackend.chain.GetBlockByNumber(currentBlock.NumberU64() + 1) 250 rawDiff := fullBackend.chain.GetDiffLayerRLP(nextBlock.Hash()) 251 diff, _ := rawDataToDiffLayer(rawDiff) 252 latestAccount, _ := snapshot.FullAccount(diff.Accounts[0].Blob) 253 latestAccount.Balance = big.NewInt(0) 254 bz, _ := rlp.EncodeToBytes(&latestAccount) 255 diff.Accounts[0].Blob = bz 256 257 lightBackend.Chain().HandleDiffLayer(diff, "testpid", true) 258 259 _, err := lightBackend.chain.insertChain([]*types.Block{nextBlock}, true) 260 if err != nil { 261 t.Errorf("failed to process block %v", err) 262 } 263 264 // the diff cache should be cleared 265 if len(lightBackend.chain.diffPeersToDiffHashes) != 0 { 266 t.Errorf("the size of diffPeersToDiffHashes should be 0, but get %d", len(lightBackend.chain.diffPeersToDiffHashes)) 267 } 268 if len(lightBackend.chain.diffHashToPeers) != 0 { 269 t.Errorf("the size of diffHashToPeers should be 0, but get %d", len(lightBackend.chain.diffHashToPeers)) 270 } 271 if len(lightBackend.chain.diffHashToBlockHash) != 0 { 272 t.Errorf("the size of diffHashToBlockHash should be 0, but get %d", len(lightBackend.chain.diffHashToBlockHash)) 273 } 274 if len(lightBackend.chain.blockHashToDiffLayers) != 0 { 275 t.Errorf("the size of blockHashToDiffLayers should be 0, but get %d", len(lightBackend.chain.blockHashToDiffLayers)) 276 } 277 } 278 279 func TestFreezeDiffLayer(t *testing.T) { 280 blockNum := 1024 281 fullBackend := newTestBackend(blockNum, true) 282 defer fullBackend.close() 283 // Minus one empty block. 284 if fullBackend.chain.diffQueue.Size() != blockNum-1 { 285 t.Errorf("size of diff queue is wrong, expected: %d, get: %d", blockNum, fullBackend.chain.diffQueue.Size()) 286 } 287 time.Sleep(diffLayerFreezerRecheckInterval + 1*time.Second) 288 if fullBackend.chain.diffQueue.Size() != int(fullBackend.chain.triesInMemory) { 289 t.Errorf("size of diff queue is wrong, expected: %d, get: %d", blockNum, fullBackend.chain.diffQueue.Size()) 290 } 291 292 block := fullBackend.chain.GetBlockByNumber(uint64(blockNum / 2)) 293 diffStore := fullBackend.chain.db.DiffStore() 294 rawData := rawdb.ReadDiffLayerRLP(diffStore, block.Hash()) 295 if len(rawData) == 0 { 296 t.Error("do not find diff layer in db") 297 } 298 } 299 300 func TestPruneDiffLayer(t *testing.T) { 301 blockNum := 1024 302 fullBackend := newTestBackend(blockNum, true) 303 defer fullBackend.close() 304 305 anotherFullBackend := newTestBackend(2*blockNum, true) 306 defer anotherFullBackend.close() 307 308 for num := uint64(1); num < uint64(blockNum); num++ { 309 header := fullBackend.chain.GetHeaderByNumber(num) 310 rawDiff := fullBackend.chain.GetDiffLayerRLP(header.Hash()) 311 if len(rawDiff) != 0 { 312 diff, _ := rawDataToDiffLayer(rawDiff) 313 fullBackend.Chain().HandleDiffLayer(diff, "testpid1", true) 314 fullBackend.Chain().HandleDiffLayer(diff, "testpid2", true) 315 } 316 } 317 fullBackend.chain.pruneDiffLayer() 318 if len(fullBackend.chain.diffNumToBlockHashes) != maxDiffForkDist { 319 t.Error("unexpected size of diffNumToBlockHashes") 320 } 321 if len(fullBackend.chain.diffPeersToDiffHashes) != 2 { 322 t.Error("unexpected size of diffPeersToDiffHashes") 323 } 324 if len(fullBackend.chain.blockHashToDiffLayers) != maxDiffForkDist { 325 t.Error("unexpected size of diffNumToBlockHashes") 326 } 327 if len(fullBackend.chain.diffHashToBlockHash) != maxDiffForkDist { 328 t.Error("unexpected size of diffHashToBlockHash") 329 } 330 if len(fullBackend.chain.diffHashToPeers) != maxDiffForkDist { 331 t.Error("unexpected size of diffHashToPeers") 332 } 333 334 blocks := make([]*types.Block, 0, blockNum) 335 for i := blockNum + 1; i <= 2*blockNum; i++ { 336 b := anotherFullBackend.chain.GetBlockByNumber(uint64(i)) 337 blocks = append(blocks, b) 338 } 339 fullBackend.chain.insertChain(blocks, true) 340 fullBackend.chain.pruneDiffLayer() 341 if len(fullBackend.chain.diffNumToBlockHashes) != 0 { 342 t.Error("unexpected size of diffNumToBlockHashes") 343 } 344 if len(fullBackend.chain.diffPeersToDiffHashes) != 0 { 345 t.Error("unexpected size of diffPeersToDiffHashes") 346 } 347 if len(fullBackend.chain.blockHashToDiffLayers) != 0 { 348 t.Error("unexpected size of diffNumToBlockHashes") 349 } 350 if len(fullBackend.chain.diffHashToBlockHash) != 0 { 351 t.Error("unexpected size of diffHashToBlockHash") 352 } 353 if len(fullBackend.chain.diffHashToPeers) != 0 { 354 t.Error("unexpected size of diffHashToPeers") 355 } 356 357 } 358 359 func TestGetDiffAccounts(t *testing.T) { 360 blockNum := 128 361 fullBackend := newTestBackend(blockNum, false) 362 defer fullBackend.close() 363 364 for _, testBlock := range testBlocks { 365 block := fullBackend.chain.GetBlockByNumber(uint64(testBlock.blockNr)) 366 if block == nil { 367 t.Fatal("block should not be nil") 368 } 369 blockHash := block.Hash() 370 accounts, err := fullBackend.chain.GetDiffAccounts(blockHash) 371 if err != nil { 372 t.Errorf("get diff accounts eror for block number (%d): %v", testBlock.blockNr, err) 373 } 374 375 for idx, account := range accounts { 376 if testAddr == account { 377 break 378 } 379 380 if idx == len(accounts)-1 { 381 t.Errorf("the diff accounts does't include addr: %v", testAddr) 382 } 383 } 384 385 for _, transaction := range testBlock.txs { 386 for idx, account := range accounts { 387 if transaction.to == account { 388 break 389 } 390 391 if idx == len(accounts)-1 { 392 t.Errorf("the diff accounts does't include addr: %v", transaction.to) 393 } 394 } 395 } 396 } 397 }