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