github.com/elastos/Elastos.ELA.SideChain.ETH@v0.2.2/consensus/pbft/pbft_test.go (about)

     1  // Copyright (c) 2017-2019 The Elastos Foundation
     2  // Use of this source code is governed by an MIT
     3  // license that can be found in the LICENSE file.
     4  //
     5  
     6  package pbft
     7  
     8  import (
     9  	"bytes"
    10  	"github.com/stretchr/testify/assert"
    11  	"math/big"
    12  	"math/rand"
    13  	"testing"
    14  	"time"
    15  
    16  	ecom "github.com/elastos/Elastos.ELA/common"
    17  	"github.com/elastos/Elastos.ELA/core/types/payload"
    18  	"github.com/elastos/Elastos.ELA/dpos/account"
    19  
    20  	"github.com/elastos/Elastos.ELA.SideChain.ESC/common"
    21  	"github.com/elastos/Elastos.ELA.SideChain.ESC/consensus/clique"
    22  	"github.com/elastos/Elastos.ELA.SideChain.ESC/core"
    23  	"github.com/elastos/Elastos.ELA.SideChain.ESC/core/rawdb"
    24  	"github.com/elastos/Elastos.ELA.SideChain.ESC/core/types"
    25  	"github.com/elastos/Elastos.ELA.SideChain.ESC/core/vm"
    26  	"github.com/elastos/Elastos.ELA.SideChain.ESC/crypto"
    27  	"github.com/elastos/Elastos.ELA.SideChain.ESC/dpos"
    28  	"github.com/elastos/Elastos.ELA.SideChain.ESC/params"
    29  )
    30  
    31  func TestReimportMirroredState(t *testing.T) {
    32  	// Initialize a Clique chain with a single signer
    33  	cfg := &params.PbftConfig{
    34  		Producers: []string{
    35  			"03bfd8bd2b10e887ec785360f9b329c2ae567975c784daca2f223cb19840b51914",
    36  		},
    37  	}
    38  	PbftProtocolChanges := &params.ChainConfig{OldChainID: big.NewInt(1), ChainID: big.NewInt(20), HomesteadBlock: big.NewInt(0), DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), EIP150Hash: common.Hash{}, EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ChainIDBlock: big.NewInt(0), ByzantiumBlock: big.NewInt(0), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: nil, EWASMBlock: nil, PBFTBlock: big.NewInt(0), Ethash: nil, Clique: nil, Pbft: cfg, BlackContractAddr: "", PassBalance: 0, EvilSignersJournalDir: "", PreConnectOffset: 1, PbftKeyStore: "test/keystore.dat", PbftKeyStorePassWord: "123"}
    39  	var (
    40  		db     = rawdb.NewMemoryDatabase()
    41  		key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
    42  		addr   = crypto.PubkeyToAddress(key.PublicKey)
    43  		engine = New(PbftProtocolChanges, "")
    44  		signer = new(types.HomesteadSigner)
    45  	)
    46  	engine.IsCurrent = func() bool {
    47  		return true
    48  	}
    49  	genspec := &core.Genesis{
    50  		ExtraData: make([]byte, extraVanity+common.AddressLength+extraSeal),
    51  		Alloc: map[common.Address]core.GenesisAccount{
    52  			addr: {Balance: big.NewInt(1)},
    53  		},
    54  	}
    55  	copy(genspec.ExtraData[extraVanity:], addr[:])
    56  	genesis := genspec.MustCommit(db)
    57  
    58  	// Generate a batch of blocks, each properly signed
    59  	chain, _ := core.NewBlockChain(db, nil, PbftProtocolChanges, engine, engine, vm.Config{}, nil)
    60  	defer chain.Stop()
    61  
    62  	blocks, _ := core.GenerateChain(PbftProtocolChanges, genesis, engine, db, 4, func(i int, block *core.BlockGen) {
    63  		// We want to simulate an empty middle block, having the same state as the
    64  		// first one. The last is needs a state change again to force a reorg.
    65  		if i != 1 {
    66  			tx, err := types.SignTx(types.NewTransaction(block.TxNonce(addr), common.Address{0x00}, new(big.Int), params.TxGas, nil, nil), signer, key)
    67  			if err != nil {
    68  				panic(err)
    69  			}
    70  			block.AddTxWithChain(chain, tx)
    71  		}
    72  		block.SetDifficulty(diffInTurn)
    73  	})
    74  	for i, block := range blocks {
    75  		header := block.Header()
    76  		if i > 0 {
    77  			header.ParentHash = blocks[i-1].Hash()
    78  		}
    79  
    80  		confirm := createConfirm(block, engine.account)
    81  		sealBuf := new(bytes.Buffer)
    82  		confirm.Serialize(sealBuf)
    83  		header.Extra = make([]byte, sealBuf.Len())
    84  		copy(header.Extra[:], sealBuf.Bytes()[:])
    85  
    86  		blocks[i] = block.WithSeal(header)
    87  	}
    88  	// Insert the first two blocks and make sure the chain is valid
    89  	db = rawdb.NewMemoryDatabase()
    90  	genspec.MustCommit(db)
    91  
    92  	chain, _ = core.NewBlockChain(db, nil, PbftProtocolChanges, engine, engine, vm.Config{}, nil)
    93  
    94  	if _, err := chain.InsertChain(blocks[:2]); err != nil {
    95  		t.Fatalf("failed to insert initial blocks: %v", err)
    96  	}
    97  	if head := chain.CurrentBlock().NumberU64(); head != 2 {
    98  		t.Fatalf("chain head mismatch: have %d, want %d", head, 2)
    99  	}
   100  	chain.Stop()
   101  	// Simulate a crash by creating a new chain on top of the database, without
   102  	// flushing the dirty states out. Insert the last block, trigerring a sidechain
   103  	// reimport.
   104  	engine = New(PbftProtocolChanges, "")
   105  	chain, _ = core.NewBlockChain(db, nil, PbftProtocolChanges, engine, engine, vm.Config{}, nil)
   106  	defer chain.Stop()
   107  
   108  	if _, err := chain.InsertChain(blocks[2:]); err != nil {
   109  		t.Fatalf("failed to insert final block: %v", err)
   110  	}
   111  	if head := chain.CurrentBlock().NumberU64(); head != 4 {
   112  		t.Fatalf("chain head mismatch: have %d, want %d", head, 3)
   113  	}
   114  }
   115  
   116  func createConfirm(block *types.Block, ac account.Account) *payload.Confirm {
   117  	hash := SealHash(block.Header())
   118  	sealHash, _ := ecom.Uint256FromBytes(hash.Bytes())
   119  	proposal, _ := dpos.StartProposal(ac, *sealHash, 0)
   120  
   121  	proposalHash := proposal.Hash()
   122  	confirm := &payload.Confirm{
   123  		Proposal: *proposal,
   124  		Votes:    make([]payload.DPOSProposalVote, 0),
   125  	}
   126  	for i := 1; i <= 8; i++ {
   127  		vote, _ := dpos.StartVote(&proposalHash, true, ac)
   128  		confirm.Votes = append(confirm.Votes, *vote)
   129  	}
   130  	return confirm
   131  }
   132  
   133  func TestBeforeChangEngine(t *testing.T) {
   134  	for i := 0; i < 100; i++ {
   135  		TestChangeEngine(t)
   136  		time.Sleep(10)
   137  	}
   138  }
   139  
   140  func TestChangeEngine(t *testing.T) {
   141  	cfg := &params.PbftConfig{
   142  		Producers: []string{
   143  			"03bfd8bd2b10e887ec785360f9b329c2ae567975c784daca2f223cb19840b51914",
   144  		},
   145  	}
   146  	cliqueCfg := &params.CliqueConfig{Period: 0, Epoch: 30000}
   147  	var (
   148  		PbftProtocolChanges = &params.ChainConfig{OldChainID: big.NewInt(1), ChainID: big.NewInt(20), HomesteadBlock: big.NewInt(0), DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), EIP150Hash: common.Hash{}, EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ChainIDBlock: big.NewInt(0), ByzantiumBlock: big.NewInt(0), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: nil, EWASMBlock: nil, PBFTBlock: big.NewInt(10), Ethash: nil, Clique: cliqueCfg, Pbft: cfg, BlackContractAddr: "", PassBalance: 0, EvilSignersJournalDir: "", PreConnectOffset: 1, PbftKeyStore: "test/keystore.dat", PbftKeyStorePassWord: "123"}
   149  		db                  = rawdb.NewMemoryDatabase()
   150  		key, _              = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
   151  		addr                = crypto.PubkeyToAddress(key.PublicKey)
   152  		engine              = clique.New(PbftProtocolChanges.Clique, db)
   153  		diffInTurn          = big.NewInt(2)
   154  	)
   155  	engine.SetFakeDiff(true)
   156  	genspec := &core.Genesis{
   157  		ExtraData: make([]byte, extraVanity+common.AddressLength+extraSeal),
   158  		Alloc: map[common.Address]core.GenesisAccount{
   159  			addr: {Balance: big.NewInt(1)},
   160  		},
   161  	}
   162  	copy(genspec.ExtraData[extraVanity:], addr[:])
   163  	genesis := genspec.MustCommit(db)
   164  
   165  	blocks, _ := core.GenerateChain(PbftProtocolChanges, genesis, engine, db, int(PbftProtocolChanges.PBFTBlock.Uint64()-2), func(i int, block *core.BlockGen) {
   166  		block.SetDifficulty(diffInTurn)
   167  	})
   168  	for i, block := range blocks {
   169  		header := block.Header()
   170  		if i > 0 {
   171  			header.ParentHash = blocks[i-1].Hash()
   172  		}
   173  		header.Extra = make([]byte, extraVanity+extraSeal)
   174  		header.Difficulty = big.NewInt(int64(rand.Intn(2) + 1))
   175  
   176  		sig, _ := crypto.Sign(clique.SealHash(header).Bytes(), key)
   177  		copy(header.Extra[len(header.Extra)-extraSeal:], sig)
   178  		blocks[i] = block.WithSeal(header)
   179  
   180  	}
   181  	// Insert the first two blocks and make sure the chain is valid
   182  	db = rawdb.NewMemoryDatabase()
   183  	genspec.MustCommit(db)
   184  
   185  	chain, _ := core.NewBlockChain(db, nil, PbftProtocolChanges, engine, engine, vm.Config{}, nil)
   186  	defer chain.Stop()
   187  
   188  	if _, err := chain.InsertChain(blocks[:]); err != nil {
   189  		t.Fatalf("failed to insert initial blocks: %v", err)
   190  	}
   191  	blocks2, _ := core.GenerateChain(PbftProtocolChanges, genesis, engine, db, int(PbftProtocolChanges.PBFTBlock.Uint64()-1), func(i int, block *core.BlockGen) {
   192  		block.SetDifficulty(diffInTurn)
   193  	})
   194  	for i, block := range blocks2 {
   195  		header := block.Header()
   196  		if i > 0 {
   197  			header.ParentHash = blocks2[i-1].Hash()
   198  		}
   199  		header.Extra = make([]byte, extraVanity+extraSeal)
   200  		if i < len(blocks)-2 {
   201  			header.Difficulty = blocks[i].Difficulty()
   202  		} else if i >= len(blocks)-2 && i < len(blocks2)-1 {
   203  			if header.Difficulty == diffInTurn {
   204  				header.Difficulty = big.NewInt(1)
   205  			} else {
   206  				header.Difficulty = diffInTurn
   207  			}
   208  		} else {
   209  			header.Difficulty = diffInTurn
   210  		}
   211  
   212  		sig, _ := crypto.Sign(clique.SealHash(header).Bytes(), key)
   213  		copy(header.Extra[len(header.Extra)-extraSeal:], sig)
   214  		blocks2[i] = block.WithSeal(header)
   215  	}
   216  	if _, err := chain.InsertChain(blocks2[:]); err != nil {
   217  		t.Fatalf("failed to insert initial blocks: %v", err)
   218  	}
   219  	assert.Equal(t, chain.CurrentHeader().Hash(), blocks2[len(blocks2)-1].Hash())
   220  	assert.Equal(t, chain.CurrentHeader().Difficulty, diffInTurn)
   221  	assert.Equal(t, chain.CurrentHeader().Number.Uint64(), uint64(len(blocks2)))
   222  }