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