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