From 5f22105303183e482f5c45bd43668e4f186bb158 Mon Sep 17 00:00:00 2001 From: j75689 Date: Wed, 27 Apr 2022 16:20:47 +0800 Subject: [PATCH] add unit-test for fastnode --- core/blockchain_notries_test.go | 187 ++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 core/blockchain_notries_test.go diff --git a/core/blockchain_notries_test.go b/core/blockchain_notries_test.go new file mode 100644 index 0000000000..19481a044f --- /dev/null +++ b/core/blockchain_notries_test.go @@ -0,0 +1,187 @@ +// Copyright 2020 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// Tests that abnormal program termination (i.e.crash) and restart doesn't leave +// the database in some strange state with gaps in the chain, nor with block data +// dangling in the future. + +package core + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/ethdb/memorydb" + "github.com/ethereum/go-ethereum/params" +) + +func newMockVerifyPeer() *mockVerifyPeer { + return &mockVerifyPeer{} +} + +type requestRoot struct { + blockNumber uint64 + blockHash common.Hash + diffHash common.Hash +} + +// mockVerifyPeer is a mocking struct that simulates p2p signals for verification tasks. +type mockVerifyPeer struct { + callback func(*requestRoot) +} + +func (peer *mockVerifyPeer) setCallBack(callback func(*requestRoot)) { + peer.callback = callback +} + +func (peer *mockVerifyPeer) RequestRoot(blockNumber uint64, blockHash common.Hash, diffHash common.Hash) error { + if peer.callback != nil { + peer.callback(&requestRoot{blockNumber, blockHash, diffHash}) + } + return nil +} + +func (peer *mockVerifyPeer) ID() string { + return "mock_peer" +} + +type mockVerifyPeers struct { + peers []VerifyPeer +} + +func (peers *mockVerifyPeers) GetVerifyPeers() []VerifyPeer { + return peers.peers +} + +func newMockRemoteVerifyPeer(peers []VerifyPeer) *mockVerifyPeers { + return &mockVerifyPeers{peers} +} + +func makeTestBackendWithRemoteValidator(blocks int) (*testBackend, *testBackend, []*types.Block, error) { + signer := types.HomesteadSigner{} + + // Create a database pre-initialize with a genesis block + db := rawdb.NewMemoryDatabase() + db.SetDiffStore(memorydb.New()) + (&Genesis{ + Config: params.TestChainConfig, + Alloc: GenesisAlloc{testAddr: {Balance: big.NewInt(100000000000000000)}}, + }).MustCommit(db) + engine := ethash.NewFaker() + + db2 := rawdb.NewMemoryDatabase() + db2.SetDiffStore(memorydb.New()) + (&Genesis{ + Config: params.TestChainConfig, + Alloc: GenesisAlloc{testAddr: {Balance: big.NewInt(100000000000000000)}}, + }).MustCommit(db2) + engine2 := ethash.NewFaker() + + peer := newMockVerifyPeer() + peers := []VerifyPeer{peer} + + verifier, err := NewBlockChain(db, nil, params.TestChainConfig, engine, vm.Config{}, + nil, nil, EnablePersistDiff(100000), EnableBlockValidator(params.TestChainConfig, engine2, LocalVerify, nil)) + if err != nil { + return nil, nil, nil, err + } + + fastnode, err := NewBlockChain(db2, nil, params.TestChainConfig, engine2, vm.Config{}, + nil, nil, EnableBlockValidator(params.TestChainConfig, engine2, FullVerify, newMockRemoteVerifyPeer(peers))) + if err != nil { + return nil, nil, nil, err + } + + generator := func(i int, block *BlockGen) { + // The chain maker doesn't have access to a chain, so the difficulty will be + // lets unset (nil). Set it here to the correct value. + block.SetCoinbase(testAddr) + + for idx, testBlock := range testBlocks { + // Specific block setting, the index in this generator has 1 diff from specified blockNr. + if i+1 == testBlock.blockNr { + for _, testTransaction := range testBlock.txs { + var transaction *types.Transaction + if testTransaction.to == nil { + transaction = types.NewContractCreation(block.TxNonce(testAddr), + testTransaction.value, uint64(commonGas), testTransaction.gasPrice, testTransaction.data) + } else { + transaction = types.NewTransaction(block.TxNonce(testAddr), *testTransaction.to, + testTransaction.value, uint64(commonGas), testTransaction.gasPrice, testTransaction.data) + } + tx, err := types.SignTx(transaction, signer, testKey) + if err != nil { + panic(err) + } + block.AddTxWithChain(verifier, tx) + } + break + } + + // Default block setting. + if idx == len(testBlocks)-1 { + // We want to simulate an empty middle block, having the same state as the + // first one. The last is needs a state change again to force a reorg. + for _, testTransaction := range testBlocks[0].txs { + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), *testTransaction.to, + testTransaction.value, uint64(commonGas), testTransaction.gasPrice, testTransaction.data), signer, testKey) + if err != nil { + panic(err) + } + block.AddTxWithChain(verifier, tx) + } + } + } + } + + bs, _ := GenerateChain(params.TestChainConfig, verifier.Genesis(), ethash.NewFaker(), db, blocks, generator) + + peer.setCallBack(func(req *requestRoot) { + if fastnode.validator != nil && fastnode.validator.RemoteVerifyManager() != nil { + fastnode.validator.RemoteVerifyManager(). + HandleRootResponse( + verifier.GetRootByDiffHash(req.blockNumber, req.blockHash, req.diffHash), "mock") + } + }) + if _, err := verifier.InsertChain(bs); err != nil { + return nil, nil, nil, err + } + + return &testBackend{ + db: db, + chain: verifier, + }, + &testBackend{ + db: db2, + chain: fastnode, + }, bs, nil +} + +func TestFastNode(t *testing.T) { + _, fastnode, blocks, err := makeTestBackendWithRemoteValidator(10240) + if err != nil { + t.Fatalf(err.Error()) + } + _, err = fastnode.chain.InsertChain(blocks) + if err != nil { + t.Fatalf(err.Error()) + } +}