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 := ¶ms.PbftConfig{ 34 Producers: []string{ 35 "03bfd8bd2b10e887ec785360f9b329c2ae567975c784daca2f223cb19840b51914", 36 }, 37 } 38 PbftProtocolChanges := ¶ms.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 := ¶ms.PbftConfig{ 142 Producers: []string{ 143 "03bfd8bd2b10e887ec785360f9b329c2ae567975c784daca2f223cb19840b51914", 144 }, 145 } 146 cliqueCfg := ¶ms.CliqueConfig{Period: 0, Epoch: 30000} 147 var ( 148 PbftProtocolChanges = ¶ms.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 }