github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/consensus/pbft/core/testbackend_test.go (about) 1 // Copyright 2017 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 package core 18 19 import ( 20 "crypto/ecdsa" 21 "github.com/bigzoro/my_simplechain/consensus" 22 "github.com/bigzoro/my_simplechain/core/types" 23 "math/big" 24 "time" 25 26 "github.com/bigzoro/my_simplechain/common" 27 "github.com/bigzoro/my_simplechain/consensus/pbft" 28 "github.com/bigzoro/my_simplechain/consensus/pbft/validator" 29 "github.com/bigzoro/my_simplechain/core/rawdb" 30 "github.com/bigzoro/my_simplechain/crypto" 31 "github.com/bigzoro/my_simplechain/ethdb" 32 "github.com/bigzoro/my_simplechain/event" 33 elog "github.com/bigzoro/my_simplechain/log" 34 ) 35 36 var testLogger = elog.New() 37 38 type testSystemBackend struct { 39 id uint64 40 sys *testSystem 41 42 engine Engine 43 peers pbft.ValidatorSet 44 events *event.TypeMux 45 46 committedMsgs []testCommittedMsgs 47 sentMsgs [][]byte // store the message when Send is called by core 48 49 address common.Address 50 db ethdb.Database 51 filled bool 52 txpool *testSystemTxPool 53 } 54 55 func (self *testSystemBackend) BroadcastMsg(ps map[common.Address]consensus.Peer, hash common.Hash, message []byte) error { 56 testLogger.Info("enqueuing a message...", "address", self.Address()) 57 self.sentMsgs = append(self.sentMsgs, message) 58 self.sys.queuedMessage <- pbft.MessageEvent{ 59 Payload: message, 60 } 61 return nil 62 } 63 64 func (self *testSystemBackend) GetForwardNodes(validators pbft.Validators) (map[common.Address]consensus.Peer, []common.Address) { 65 return nil, nil 66 } 67 68 func (self *testSystemBackend) FillLightProposal(proposal pbft.LightProposal) (bool, []types.MissedTx, error) { 69 lb := proposal.(*types.LightBlock) 70 *lb.Transactions() = make(types.Transactions, len(lb.TxDigests())) 71 72 if self.txpool != nil { 73 fiiled := self.txpool.InitLightBlock(lb) 74 return fiiled, lb.MissedTxs, nil 75 } 76 return true, nil, nil 77 } 78 79 type testCommittedMsgs struct { 80 commitProposal pbft.Conclusion 81 committedSeals [][]byte 82 } 83 84 // ============================================== 85 // 86 // define the functions that needs to be provided for Istanbul. 87 88 func (self *testSystemBackend) Address() common.Address { 89 return self.address 90 } 91 92 // Peers returns all connected peers 93 func (self *testSystemBackend) Validators(proposal pbft.Conclusion) pbft.ValidatorSet { 94 return self.peers 95 } 96 97 func (self *testSystemBackend) EventMux() *event.TypeMux { 98 return self.events 99 } 100 101 func (self *testSystemBackend) SendMsg(val pbft.Validators, message []byte) error { 102 self.sys.sendMessage <- targetMessage{msg: pbft.MessageEvent{ 103 Payload: message, 104 }, vals: val} 105 return nil 106 } 107 108 func (self *testSystemBackend) Broadcast(valSet pbft.ValidatorSet, sender common.Address, message []byte) error { 109 testLogger.Info("enqueuing a message...", "address", self.Address()) 110 self.sentMsgs = append(self.sentMsgs, message) 111 self.sys.queuedMessage <- pbft.MessageEvent{ 112 Payload: message, 113 } 114 return nil 115 } 116 117 func (self *testSystemBackend) Post(payload []byte) { 118 testLogger.Warn("not sign any data") 119 } 120 121 func (self *testSystemBackend) Gossip(valSet pbft.ValidatorSet, message []byte) { 122 testLogger.Warn("not sign any data") 123 } 124 125 func (self *testSystemBackend) Guidance(valSet pbft.ValidatorSet, sender common.Address, message []byte) { 126 testLogger.Warn("not sign any data") 127 } 128 129 func (self *testSystemBackend) Commit(proposal pbft.Conclusion, seals [][]byte) error { 130 testLogger.Info("commit message", "address", self.Address()) 131 self.committedMsgs = append(self.committedMsgs, testCommittedMsgs{ 132 commitProposal: proposal, 133 committedSeals: seals, 134 }) 135 136 // fake new head events 137 go self.events.Post(pbft.FinalCommittedEvent{}) 138 return nil 139 } 140 141 func (self *testSystemBackend) MarkTransactionKnownBy(val pbft.Validator, txs types.Transactions) {} 142 143 func (self *testSystemBackend) Verify(proposal pbft.Proposal, _, _ bool) (time.Duration, error) { 144 return 0, nil 145 } 146 147 func (self *testSystemBackend) Execute(proposal pbft.Proposal) (pbft.Conclusion, error) { 148 return proposal.(pbft.Conclusion), nil 149 } 150 151 func (self *testSystemBackend) OnTimeout() {} 152 153 func (self *testSystemBackend) Sign(data []byte) ([]byte, error) { 154 testLogger.Info("returning current backend address so that CheckValidatorSignature returns the same value") 155 return self.address.Bytes(), nil 156 } 157 158 func (self *testSystemBackend) CheckSignature([]byte, common.Address, []byte) error { 159 return nil 160 } 161 162 func (self *testSystemBackend) CheckValidatorSignature(data []byte, sig []byte) (common.Address, error) { 163 return common.BytesToAddress(sig), nil 164 } 165 166 func (self *testSystemBackend) Hash(b interface{}) common.Hash { 167 return common.BytesToHash([]byte("Test")) 168 } 169 170 func (self *testSystemBackend) NewRequest(request pbft.Proposal) { 171 go self.events.Post(pbft.RequestEvent{ 172 Proposal: request, 173 }) 174 } 175 176 func (self *testSystemBackend) HasBadProposal(hash common.Hash) bool { 177 return false 178 } 179 180 func (self *testSystemBackend) LastProposal() (pbft.Proposal, pbft.Conclusion, common.Address) { 181 l := len(self.committedMsgs) 182 var block pbft.Conclusion 183 if l > 0 { 184 block = self.committedMsgs[l-1].commitProposal 185 } else { 186 block = makeBlock(0) 187 } 188 return block, block, common.Address{} 189 } 190 191 // Only block height 5 will return true 192 func (self *testSystemBackend) HasProposal(hash common.Hash, number *big.Int) (common.Hash, bool) { 193 return hash, number.Cmp(big.NewInt(5)) == 0 194 } 195 196 func (self *testSystemBackend) GetProposer(number uint64) common.Address { 197 return common.Address{} 198 } 199 200 func (self *testSystemBackend) ParentValidators(proposal pbft.Proposal) pbft.ValidatorSet { 201 return self.peers 202 } 203 204 func (self *testSystemBackend) Close() error { 205 return nil 206 } 207 208 type testSystemTxPool struct { 209 all map[common.Hash]*types.Transaction 210 } 211 212 func newTestSystemTxPool(txs ...*types.Transaction) *testSystemTxPool { 213 pool := &testSystemTxPool{make(map[common.Hash]*types.Transaction)} 214 for _, tx := range txs { 215 pool.all[tx.Hash()] = tx 216 } 217 return pool 218 } 219 220 func (pool *testSystemTxPool) AddLocal(tx *types.Transaction) { 221 pool.all[tx.Hash()] = tx 222 } 223 224 func (pool *testSystemTxPool) InitLightBlock(pb *types.LightBlock) bool { 225 digests := pb.TxDigests() 226 transactions := pb.Transactions() 227 228 for index, hash := range digests { 229 if tx := pool.all[hash]; tx != nil { 230 (*transactions)[index] = tx 231 } else { 232 pb.MissedTxs = append(pb.MissedTxs, types.MissedTx{Hash: hash, Index: uint32(index)}) 233 } 234 } 235 236 return len(pb.MissedTxs) == 0 237 } 238 239 // ============================================== 240 // 241 // define the struct that need to be provided for integration tests. 242 243 type targetMessage struct { 244 msg pbft.MessageEvent 245 vals pbft.Validators 246 } 247 248 type testSystem struct { 249 backends []*testSystemBackend 250 251 queuedMessage chan pbft.MessageEvent 252 sendMessage chan targetMessage 253 quit chan struct{} 254 } 255 256 func newTestSystem(n uint64) *testSystem { 257 testLogger.SetHandler(elog.StdoutHandler) 258 return &testSystem{ 259 backends: make([]*testSystemBackend, n), 260 261 queuedMessage: make(chan pbft.MessageEvent), 262 sendMessage: make(chan targetMessage), 263 quit: make(chan struct{}), 264 } 265 } 266 267 func generateValidators(n int) []common.Address { 268 vals := make([]common.Address, 0) 269 for i := 0; i < n; i++ { 270 privateKey, _ := crypto.GenerateKey() 271 vals = append(vals, crypto.PubkeyToAddress(privateKey.PublicKey)) 272 } 273 return vals 274 } 275 276 func newTestValidatorSet(n int) pbft.ValidatorSet { 277 return validator.NewSet(generateValidators(n), pbft.RoundRobin) 278 } 279 280 // FIXME: int64 is needed for N and F 281 func NewTestSystemWithBackend(n, f uint64) *testSystem { 282 testLogger.SetHandler(elog.StdoutHandler) 283 284 addrs := generateValidators(int(n)) 285 sys := newTestSystem(n) 286 config := pbft.DefaultConfig 287 288 for i := uint64(0); i < n; i++ { 289 vset := validator.NewSet(addrs, pbft.RoundRobin) 290 backend := sys.NewBackend(i) 291 backend.peers = vset 292 backend.address = vset.GetByIndex(i).Address() 293 294 core := New(backend, config).(*core) 295 core.state = StateAcceptRequest 296 core.current = newRoundState(&pbft.View{ 297 Round: big.NewInt(0), 298 Sequence: big.NewInt(1), 299 }, vset, common.Hash{}, nil, nil, nil, func(hash common.Hash) bool { 300 return false 301 }) 302 core.valSet = vset 303 core.logger = testLogger 304 core.validateFn = backend.CheckValidatorSignature 305 306 backend.engine = core 307 } 308 309 return sys 310 } 311 312 // listen will consume messages from queue and deliver a message to core 313 func (t *testSystem) listen() { 314 for { 315 select { 316 case <-t.quit: 317 return 318 case queuedMessage := <-t.queuedMessage: 319 testLogger.Info("consuming a queue message...") 320 for _, backend := range t.backends { 321 go backend.EventMux().Post(queuedMessage) 322 } 323 case sendMessage := <-t.sendMessage: 324 target := make(map[common.Address]struct{}) 325 for _, val := range sendMessage.vals { 326 target[val.Address()] = struct{}{} 327 } 328 for _, backend := range t.backends { 329 if _, ok := target[backend.address]; ok { 330 go backend.EventMux().Post(sendMessage) 331 } 332 } 333 } 334 } 335 } 336 337 // Run will start system components based on given flag, and returns a closer 338 // function that caller can control lifecycle 339 // 340 // Given a true for core if you want to initialize core engine. 341 func (t *testSystem) Run(core bool) func() { 342 for _, b := range t.backends { 343 if core { 344 b.engine.Start() // start Istanbul core 345 } 346 } 347 348 go t.listen() 349 closer := func() { t.stop(core) } 350 return closer 351 } 352 353 func (t *testSystem) stop(core bool) { 354 close(t.quit) 355 356 for _, b := range t.backends { 357 if core { 358 b.engine.Stop() 359 } 360 } 361 } 362 363 func (t *testSystem) NewBackend(id uint64) *testSystemBackend { 364 // assume always success 365 ethDB := rawdb.NewMemoryDatabase() 366 backend := &testSystemBackend{ 367 id: id, 368 sys: t, 369 events: new(event.TypeMux), 370 db: ethDB, 371 } 372 373 t.backends[id] = backend 374 return backend 375 } 376 377 // ============================================== 378 // 379 // helper functions. 380 381 func getPublicKeyAddress(privateKey *ecdsa.PrivateKey) common.Address { 382 return crypto.PubkeyToAddress(privateKey.PublicKey) 383 }