github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/consensus/istanbul/ibft/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 "math/big" 22 "time" 23 24 "github.com/kisexp/xdchain/common" 25 "github.com/kisexp/xdchain/consensus/istanbul" 26 ibfttypes "github.com/kisexp/xdchain/consensus/istanbul/ibft/types" 27 "github.com/kisexp/xdchain/consensus/istanbul/validator" 28 "github.com/kisexp/xdchain/core/rawdb" 29 "github.com/kisexp/xdchain/crypto" 30 "github.com/kisexp/xdchain/ethdb" 31 "github.com/kisexp/xdchain/event" 32 elog "github.com/kisexp/xdchain/log" 33 ) 34 35 var testLogger = elog.New() 36 37 type testSystemBackend struct { 38 id uint64 39 sys *testSystem 40 41 engine *core 42 peers istanbul.ValidatorSet 43 events *event.TypeMux 44 45 committedMsgs []testCommittedMsgs 46 sentMsgs [][]byte // store the message when Send is called by core 47 48 address common.Address 49 db ethdb.Database 50 } 51 52 type testCommittedMsgs struct { 53 commitProposal istanbul.Proposal 54 committedSeals [][]byte 55 } 56 57 // ============================================== 58 // 59 // define the functions that needs to be provided for Istanbul. 60 61 func (self *testSystemBackend) Address() common.Address { 62 return self.address 63 } 64 65 // Peers returns all connected peers 66 func (self *testSystemBackend) Validators(proposal istanbul.Proposal) istanbul.ValidatorSet { 67 return self.peers 68 } 69 70 func (self *testSystemBackend) EventMux() *event.TypeMux { 71 return self.events 72 } 73 74 func (self *testSystemBackend) Send(message []byte, code uint64, target common.Address) error { 75 testLogger.Info("enqueuing a message...", "address", self.Address()) 76 self.sentMsgs = append(self.sentMsgs, message) 77 self.sys.queuedMessage <- istanbul.MessageEvent{ 78 Code: code, 79 Payload: message, 80 } 81 return nil 82 } 83 84 func (self *testSystemBackend) Broadcast(valSet istanbul.ValidatorSet, code uint64, message []byte) error { 85 testLogger.Info("enqueuing a message...", "address", self.Address()) 86 self.sentMsgs = append(self.sentMsgs, message) 87 self.sys.queuedMessage <- istanbul.MessageEvent{ 88 Code: code, 89 Payload: message, 90 } 91 return nil 92 } 93 94 func (self *testSystemBackend) Gossip(valSet istanbul.ValidatorSet, code uint64, message []byte) error { 95 testLogger.Warn("not sign any data") 96 return nil 97 } 98 99 func (self *testSystemBackend) Commit(proposal istanbul.Proposal, seals [][]byte, round *big.Int) error { 100 testLogger.Info("commit message", "address", self.Address()) 101 self.committedMsgs = append(self.committedMsgs, testCommittedMsgs{ 102 commitProposal: proposal, 103 committedSeals: seals, 104 }) 105 106 // fake new head events 107 go self.events.Post(istanbul.FinalCommittedEvent{}) 108 return nil 109 } 110 111 func (self *testSystemBackend) Verify(proposal istanbul.Proposal) (time.Duration, error) { 112 return 0, nil 113 } 114 115 func (self *testSystemBackend) Sign(data []byte) ([]byte, error) { 116 testLogger.Info("returning current backend address so that CheckValidatorSignature returns the same value") 117 return self.address.Bytes(), nil 118 } 119 120 func (self *testSystemBackend) SignWithoutHashing(data []byte) ([]byte, error) { 121 testLogger.Info("returning current backend address so that CheckValidatorSignature returns the same value") 122 return self.address.Bytes(), nil 123 } 124 125 func (self *testSystemBackend) CheckSignature([]byte, common.Address, []byte) error { 126 return nil 127 } 128 129 func (self *testSystemBackend) CheckValidatorSignature(data []byte, sig []byte) (common.Address, error) { 130 return common.BytesToAddress(sig), nil 131 } 132 133 func (self *testSystemBackend) Hash(b interface{}) common.Hash { 134 return common.StringToHash("Test") 135 } 136 137 func (self *testSystemBackend) NewRequest(request istanbul.Proposal) { 138 go self.events.Post(istanbul.RequestEvent{ 139 Proposal: request, 140 }) 141 } 142 143 func (self *testSystemBackend) HasBadProposal(hash common.Hash) bool { 144 return false 145 } 146 147 func (self *testSystemBackend) LastProposal() (istanbul.Proposal, common.Address) { 148 l := len(self.committedMsgs) 149 if l > 0 { 150 return self.committedMsgs[l-1].commitProposal, common.Address{} 151 } 152 return makeBlock(0), common.Address{} 153 } 154 155 // Only block height 5 will return true 156 func (self *testSystemBackend) HasPropsal(hash common.Hash, number *big.Int) bool { 157 return number.Cmp(big.NewInt(5)) == 0 158 } 159 160 func (self *testSystemBackend) GetProposer(number uint64) common.Address { 161 return common.Address{} 162 } 163 164 func (self *testSystemBackend) ParentValidators(proposal istanbul.Proposal) istanbul.ValidatorSet { 165 return self.peers 166 } 167 168 func (sb *testSystemBackend) Close() error { 169 return nil 170 } 171 172 func (sb *testSystemBackend) IsQBFTConsensusAt(*big.Int) bool { 173 return false 174 } 175 176 func (sb *testSystemBackend) StartQBFTConsensus() error { 177 return nil 178 } 179 180 // ============================================== 181 // 182 // define the struct that need to be provided for integration tests. 183 184 type testSystem struct { 185 backends []*testSystemBackend 186 187 queuedMessage chan istanbul.MessageEvent 188 quit chan struct{} 189 } 190 191 func newTestSystem(n uint64) *testSystem { 192 testLogger.SetHandler(elog.StdoutHandler) 193 return &testSystem{ 194 backends: make([]*testSystemBackend, n), 195 196 queuedMessage: make(chan istanbul.MessageEvent), 197 quit: make(chan struct{}), 198 } 199 } 200 201 func generateValidators(n int) []common.Address { 202 vals := make([]common.Address, 0) 203 for i := 0; i < n; i++ { 204 privateKey, _ := crypto.GenerateKey() 205 vals = append(vals, crypto.PubkeyToAddress(privateKey.PublicKey)) 206 } 207 return vals 208 } 209 210 func newTestValidatorSet(n int) istanbul.ValidatorSet { 211 return validator.NewSet(generateValidators(n), istanbul.NewRoundRobinProposerPolicy()) 212 } 213 214 // FIXME: int64 is needed for N and F 215 func NewTestSystemWithBackend(n, f uint64) *testSystem { 216 testLogger.SetHandler(elog.StdoutHandler) 217 218 addrs := generateValidators(int(n)) 219 sys := newTestSystem(n) 220 config := istanbul.DefaultConfig 221 222 for i := uint64(0); i < n; i++ { 223 vset := validator.NewSet(addrs, istanbul.NewRoundRobinProposerPolicy()) 224 backend := sys.NewBackend(i) 225 backend.peers = vset 226 backend.address = vset.GetByIndex(i).Address() 227 228 core := New(backend, config) 229 core.state = ibfttypes.StateAcceptRequest 230 core.current = newRoundState(&istanbul.View{ 231 Round: big.NewInt(0), 232 Sequence: big.NewInt(1), 233 }, vset, common.Hash{}, nil, nil, func(hash common.Hash) bool { 234 return false 235 }) 236 core.valSet = vset 237 core.logger = testLogger 238 core.validateFn = backend.CheckValidatorSignature 239 240 backend.engine = core 241 } 242 243 return sys 244 } 245 246 // listen will consume messages from queue and deliver a message to core 247 func (t *testSystem) listen() { 248 for { 249 select { 250 case <-t.quit: 251 return 252 case queuedMessage := <-t.queuedMessage: 253 testLogger.Info("consuming a queue message...") 254 for _, backend := range t.backends { 255 go backend.EventMux().Post(queuedMessage) 256 } 257 } 258 } 259 } 260 261 // Run will start system components based on given flag, and returns a closer 262 // function that caller can control lifecycle 263 // 264 // Given a true for core if you want to initialize core engine. 265 func (t *testSystem) Run(core bool) func() { 266 for _, b := range t.backends { 267 if core { 268 b.engine.Start() // start Istanbul core 269 } 270 } 271 272 go t.listen() 273 closer := func() { t.stop(core) } 274 return closer 275 } 276 277 func (t *testSystem) stop(core bool) { 278 close(t.quit) 279 280 for _, b := range t.backends { 281 if core { 282 b.engine.Stop() 283 } 284 } 285 } 286 287 func (t *testSystem) NewBackend(id uint64) *testSystemBackend { 288 // assume always success 289 ethDB := rawdb.NewMemoryDatabase() 290 backend := &testSystemBackend{ 291 id: id, 292 sys: t, 293 events: new(event.TypeMux), 294 db: ethDB, 295 } 296 297 t.backends[id] = backend 298 return backend 299 } 300 301 // ============================================== 302 // 303 // helper functions. 304 305 func getPublicKeyAddress(privateKey *ecdsa.PrivateKey) common.Address { 306 return crypto.PubkeyToAddress(privateKey.PublicKey) 307 }