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