gitlab.com/flarenetwork/coreth@v0.1.1/chain/chain_test.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package chain 5 6 import ( 7 cryptorand "crypto/rand" 8 "math/big" 9 "math/rand" 10 "testing" 11 12 "github.com/ethereum/go-ethereum/common" 13 "github.com/ethereum/go-ethereum/common/hexutil" 14 "github.com/ethereum/go-ethereum/log" 15 "github.com/ethereum/go-ethereum/rlp" 16 "gitlab.com/flarenetwork/coreth/accounts/keystore" 17 "gitlab.com/flarenetwork/coreth/consensus/dummy" 18 "gitlab.com/flarenetwork/coreth/core" 19 "gitlab.com/flarenetwork/coreth/core/rawdb" 20 "gitlab.com/flarenetwork/coreth/core/state" 21 "gitlab.com/flarenetwork/coreth/core/types" 22 "gitlab.com/flarenetwork/coreth/eth" 23 "gitlab.com/flarenetwork/coreth/eth/ethconfig" 24 "gitlab.com/flarenetwork/coreth/node" 25 "gitlab.com/flarenetwork/coreth/params" 26 ) 27 28 type testChain struct { 29 t *testing.T 30 name string 31 hasBlock map[common.Hash]struct{} 32 blocks []common.Hash 33 blkCount uint32 34 chain *ETHChain 35 outBlockCh chan<- []byte 36 inAckCh <-chan struct{} 37 } 38 39 func (tc *testChain) insertBlock(block *types.Block) { 40 if _, ok := tc.hasBlock[block.Hash()]; !ok { 41 tc.hasBlock[block.Hash()] = struct{}{} 42 tc.blocks = append(tc.blocks, block.Hash()) 43 } 44 } 45 46 func newTestChain(name string, config *eth.Config, 47 inBlockCh <-chan []byte, outBlockCh chan<- []byte, 48 inAckCh <-chan struct{}, outAckCh chan<- struct{}, 49 t *testing.T) *testChain { 50 chain, err := NewETHChain( 51 config, 52 &node.Config{}, 53 rawdb.NewMemoryDatabase(), 54 eth.DefaultSettings, 55 &dummy.ConsensusCallbacks{ 56 OnFinalizeAndAssemble: func(head *types.Header, _ *state.StateDB, _ []*types.Transaction) ([]byte, error) { 57 randData := make([]byte, 32) 58 _, err := rand.Read(randData) 59 if err != nil { 60 t.Fatal(err) 61 } 62 return randData, nil 63 }, 64 }, 65 common.Hash{}, 66 ) 67 if err != nil { 68 t.Fatal(err) 69 } 70 tc := &testChain{ 71 t: t, 72 name: name, 73 hasBlock: make(map[common.Hash]struct{}), 74 blocks: make([]common.Hash, 0), 75 blkCount: 0, 76 chain: chain, 77 outBlockCh: outBlockCh, 78 inAckCh: inAckCh, 79 } 80 tc.insertBlock(tc.chain.GetGenesisBlock()) 81 // Start a goroutine to deserialize and insert each block received from [inBlockCh] 82 // and send an acknowledgement via [outAckCh] 83 go func() { 84 for serialized := range inBlockCh { 85 block := new(types.Block) 86 err := rlp.DecodeBytes(serialized, block) 87 if err != nil { 88 panic(err) 89 } 90 if block.Hash() != tc.chain.GetGenesisBlock().Hash() { 91 if err = tc.chain.InsertBlock(block); err != nil { 92 tc.t.Fatalf("Failed to insert block for chain %q: %s", name, err) 93 } 94 } 95 tc.insertBlock(block) 96 outAckCh <- struct{}{} 97 } 98 }() 99 return tc 100 } 101 102 func (tc *testChain) start() { 103 tc.chain.Start() 104 } 105 106 func (tc *testChain) stop() { 107 tc.chain.Stop() 108 } 109 110 func (tc *testChain) GenRandomTree(genBlocks int) { 111 for i := 0; i < genBlocks; i++ { 112 numBlocks := len(tc.blocks) 113 parentIndex := rand.Intn(numBlocks) 114 parentBlockHash := tc.blocks[parentIndex] 115 parentBlock := tc.chain.GetBlockByHash(parentBlockHash) 116 if parentBlock == nil { 117 tc.t.Fatalf("Failed to get parent block by hash %s, %d", parentBlockHash, numBlocks) 118 } 119 if err := tc.chain.SetPreference(parentBlock); err != nil { 120 tc.t.Fatal(err) 121 } 122 block, err := tc.chain.GenerateBlock() 123 if err != nil { 124 tc.t.Fatalf("chain %s failed to generate block: %s", tc.name, err) 125 } 126 if err := tc.chain.InsertBlock(block); err != nil { 127 tc.t.Fatal(err) 128 } 129 130 tc.blkCount++ 131 if len(block.Uncles()) != 0 { 132 tc.t.Fatal("#uncles should be zero") 133 } 134 tc.insertBlock(block) 135 if tc.outBlockCh != nil { 136 serialized, err := rlp.EncodeToBytes(block) 137 if err != nil { 138 tc.t.Fatal(err) 139 } 140 tc.outBlockCh <- serialized 141 <-tc.inAckCh 142 } 143 } 144 } 145 146 func run(config *eth.Config, size1, size2 int, t *testing.T) { 147 aliceBlk := make(chan []byte) 148 bobBlk := make(chan []byte) 149 aliceAck := make(chan struct{}) 150 bobAck := make(chan struct{}) 151 alice := newTestChain("alice", config, bobBlk, aliceBlk, bobAck, aliceAck, t) 152 bob := newTestChain("bob", config, aliceBlk, bobBlk, aliceAck, bobAck, t) 153 alice.start() 154 bob.start() 155 log.Info("alice genesis", "block", alice.chain.GetGenesisBlock().Hash().Hex()) 156 log.Info("bob genesis", "block", bob.chain.GetGenesisBlock().Hash().Hex()) 157 alice.GenRandomTree(size1) 158 log.Info("alice finished generating the tree") 159 160 bob.outBlockCh = nil 161 bob.GenRandomTree(size2) 162 for i := range bob.blocks { 163 serialized, err := rlp.EncodeToBytes(bob.chain.GetBlockByHash(bob.blocks[i])) 164 if err != nil { 165 t.Fatal(err) 166 } 167 bobBlk <- serialized 168 <-aliceAck 169 } 170 log.Info("bob finished generating the tree") 171 172 log.Info("comparing two trees") 173 if len(alice.blocks) != len(bob.blocks) { 174 t.Fatalf("mismatching tree size %d != %d", len(alice.blocks), len(bob.blocks)) 175 } 176 gn := big.NewInt(0) 177 for i := range alice.blocks { 178 ablk := alice.chain.GetBlockByHash(alice.blocks[i]) 179 bblk := bob.chain.GetBlockByHash(alice.blocks[i]) 180 for ablk.Number().Cmp(gn) > 0 && bblk.Number().Cmp(gn) > 0 { 181 result := ablk.Hash() == bblk.Hash() 182 if !result { 183 t.Fatal("mismatching path") 184 } 185 ablk = alice.chain.GetBlockByHash(ablk.ParentHash()) 186 bblk = bob.chain.GetBlockByHash(bblk.ParentHash()) 187 } 188 } 189 alice.stop() 190 bob.stop() 191 } 192 193 // TestChain randomly generates a chain (tree of blocks) on each of two 194 // entities ("Alice" and "Bob") and lets them exchange each other's blocks via 195 // a go channel and finally checks if they have the identical chain structure. 196 func TestChain(t *testing.T) { 197 // configure the chain 198 config := ethconfig.DefaultConfig 199 chainConfig := ¶ms.ChainConfig{ 200 ChainID: big.NewInt(1), 201 HomesteadBlock: big.NewInt(0), 202 DAOForkBlock: big.NewInt(0), 203 DAOForkSupport: true, 204 EIP150Block: big.NewInt(0), 205 EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"), 206 EIP155Block: big.NewInt(0), 207 EIP158Block: big.NewInt(0), 208 ByzantiumBlock: big.NewInt(0), 209 ConstantinopleBlock: big.NewInt(0), 210 PetersburgBlock: big.NewInt(0), 211 IstanbulBlock: big.NewInt(0), 212 ApricotPhase1BlockTimestamp: big.NewInt(0), 213 } 214 215 // configure the genesis block 216 genBalance := big.NewInt(100000000000000000) 217 genKey, _ := keystore.NewKey(cryptorand.Reader) 218 219 config.Genesis = &core.Genesis{ 220 Config: chainConfig, 221 Nonce: 0, 222 Number: 0, 223 ExtraData: hexutil.MustDecode("0x00"), 224 GasLimit: 100000000, 225 Difficulty: big.NewInt(0), 226 Alloc: core.GenesisAlloc{genKey.Address: {Balance: genBalance}}, 227 } 228 229 run(&config, 20, 20, t) 230 }