github.com/pfcoder/quorum@v2.0.3-0.20180501191142-d4a1b0958135+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.Warn("not sign any data") 113 return data, 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.Address{}, 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 // ============================================== 160 // 161 // define the struct that need to be provided for integration tests. 162 163 type testSystem struct { 164 backends []*testSystemBackend 165 166 queuedMessage chan istanbul.MessageEvent 167 quit chan struct{} 168 } 169 170 func newTestSystem(n uint64) *testSystem { 171 testLogger.SetHandler(elog.StdoutHandler) 172 return &testSystem{ 173 backends: make([]*testSystemBackend, n), 174 175 queuedMessage: make(chan istanbul.MessageEvent), 176 quit: make(chan struct{}), 177 } 178 } 179 180 func generateValidators(n int) []common.Address { 181 vals := make([]common.Address, 0) 182 for i := 0; i < n; i++ { 183 privateKey, _ := crypto.GenerateKey() 184 vals = append(vals, crypto.PubkeyToAddress(privateKey.PublicKey)) 185 } 186 return vals 187 } 188 189 func newTestValidatorSet(n int) istanbul.ValidatorSet { 190 return validator.NewSet(generateValidators(n), istanbul.RoundRobin) 191 } 192 193 // FIXME: int64 is needed for N and F 194 func NewTestSystemWithBackend(n, f uint64) *testSystem { 195 testLogger.SetHandler(elog.StdoutHandler) 196 197 addrs := generateValidators(int(n)) 198 sys := newTestSystem(n) 199 config := istanbul.DefaultConfig 200 201 for i := uint64(0); i < n; i++ { 202 vset := validator.NewSet(addrs, istanbul.RoundRobin) 203 backend := sys.NewBackend(i) 204 backend.peers = vset 205 backend.address = vset.GetByIndex(i).Address() 206 207 core := New(backend, config).(*core) 208 core.state = StateAcceptRequest 209 core.current = newRoundState(&istanbul.View{ 210 Round: big.NewInt(0), 211 Sequence: big.NewInt(1), 212 }, vset, common.Hash{}, nil, nil, func(hash common.Hash) bool { 213 return false 214 }) 215 core.valSet = vset 216 core.logger = testLogger 217 core.validateFn = backend.CheckValidatorSignature 218 219 backend.engine = core 220 } 221 222 return sys 223 } 224 225 // listen will consume messages from queue and deliver a message to core 226 func (t *testSystem) listen() { 227 for { 228 select { 229 case <-t.quit: 230 return 231 case queuedMessage := <-t.queuedMessage: 232 testLogger.Info("consuming a queue message...") 233 for _, backend := range t.backends { 234 go backend.EventMux().Post(queuedMessage) 235 } 236 } 237 } 238 } 239 240 // Run will start system components based on given flag, and returns a closer 241 // function that caller can control lifecycle 242 // 243 // Given a true for core if you want to initialize core engine. 244 func (t *testSystem) Run(core bool) func() { 245 for _, b := range t.backends { 246 if core { 247 b.engine.Start() // start Istanbul core 248 } 249 } 250 251 go t.listen() 252 closer := func() { t.stop(core) } 253 return closer 254 } 255 256 func (t *testSystem) stop(core bool) { 257 close(t.quit) 258 259 for _, b := range t.backends { 260 if core { 261 b.engine.Stop() 262 } 263 } 264 } 265 266 func (t *testSystem) NewBackend(id uint64) *testSystemBackend { 267 // assume always success 268 ethDB, _ := ethdb.NewMemDatabase() 269 backend := &testSystemBackend{ 270 id: id, 271 sys: t, 272 events: new(event.TypeMux), 273 db: ethDB, 274 } 275 276 t.backends[id] = backend 277 return backend 278 } 279 280 // ============================================== 281 // 282 // helper functions. 283 284 func getPublicKeyAddress(privateKey *ecdsa.PrivateKey) common.Address { 285 return crypto.PubkeyToAddress(privateKey.PublicKey) 286 }