github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/consensus/dpos/bft.go (about) 1 // Copyright 2019 The go-vnt Authors 2 // This file is part of the go-vnt library. 3 // 4 // The go-vnt 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-vnt 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-vnt library. If not, see <http://www.gnu.org/licenses/>. 16 17 package dpos 18 19 import ( 20 "fmt" 21 "math/big" 22 "sync" 23 "sync/atomic" 24 "time" 25 26 "github.com/vntchain/go-vnt/common" 27 "github.com/vntchain/go-vnt/core/types" 28 "github.com/vntchain/go-vnt/log" 29 ) 30 31 // BFT step 32 const ( 33 newRound = uint32(0) 34 prePrePared = uint32(1) 35 preparing = uint32(2) 36 prepared = uint32(3) 37 committing = uint32(4) 38 committed = uint32(5) 39 done = uint32(6) 40 ) 41 42 type BftManager struct { 43 dp *Dpos // DPoS object 44 quorum int // 2f+1 45 coinBase common.Address 46 47 mp *msgPool // message pool of all future round bft messages, and not verified 48 roundMp *msgPool // message pool of current round, and been verified 49 50 // BFT state 51 h *big.Int // local block chain height, protect by newRoundRWLock 52 r uint32 // local BFT round, protect by newRoundRWLock 53 step uint32 // local BFT round, protect by atomic operation 54 witnessList map[common.Address]struct{} // current witness list, rely on producing 55 56 newRoundRWLock sync.RWMutex // RW lock for switch to new round 57 58 blockRound uint32 // round of sealing block, no need lock 59 producing uint32 // producing or not, atomic read and write 60 61 // callbacks 62 sendBftMsg func(types.ConsensusMsg) 63 verifyBlock func(*types.Block) (types.Receipts, []*types.Log, uint64, error) 64 writeBlock func(*types.Block) error 65 } 66 67 func newBftManager(dp *Dpos) *BftManager { 68 n := dp.config.WitnessesNum 69 q := n - (n-1)/3 // N-f 70 return &BftManager{ 71 dp: dp, 72 quorum: q, 73 mp: newMsgPool(q, "msg pool"), 74 roundMp: newMsgPool(q, "round msg pool"), 75 h: big.NewInt(0), 76 r: 0, 77 step: newRound, 78 witnessList: make(map[common.Address]struct{}, dp.config.WitnessesNum), 79 producing: 0, 80 } 81 } 82 83 // startPrePrepare will send pre-prepare msg and prepare msg 84 func (b *BftManager) startPrePrepare(block *types.Block) { 85 log.Trace("Start PrePrepare") 86 87 prePreMsg := b.makePrePrepareMsg(block, b.blockRound) 88 89 // This node is a witness, which can seal block, no need check again 90 b.sendBftMsg(prePreMsg) 91 92 // startPrePrepare may be execute before newRound, so calling handleBftMsg 93 // to check round 94 go b.handleBftMsg(prePreMsg) 95 } 96 97 func (b *BftManager) handleBftMsg(msg types.ConsensusMsg) error { 98 msgBlkNum, msgHash, msgType, msgRound := msg.GetBlockNum(), msg.Hash(), msg.Type(), msg.GetRound() 99 if msgBlkNum == nil { 100 return fmt.Errorf("bft msg's height is empty") 101 } 102 103 log.Trace("Handle bft msg", "type", msgType.String(), 104 "number", msgBlkNum.Uint64(), "round", msgRound, "hash", msgHash) 105 106 // Read lock for critical section 107 b.newRoundRWLock.RLock() 108 defer func() { 109 b.newRoundRWLock.RUnlock() 110 log.Trace("handle msg end", "hash", msgHash) 111 }() 112 113 // If not producing, no need deal with these bft msg right now, 114 // save to msg pool, if you are witness and producing after sync, 115 // you will fast deal with these msg. 116 if atomic.LoadUint32(&b.producing) == 0 { 117 _ = b.mp.addMsg(msg) 118 log.Debug("HandleBftMsg: return for not producing") 119 return nil 120 } 121 122 // 比较高度 123 blkNumCmp := msgBlkNum.Cmp(b.h) 124 if blkNumCmp > 0 { 125 if err := b.mp.addMsg(msg); err != nil { 126 log.Error("add prepare msg to msg pool error", "err", err) 127 return err 128 } 129 if prePrepareMsg, ok := msg.(*types.PreprepareMsg); ok { 130 go b.startSync(prePrepareMsg.Block) 131 } 132 return nil 133 } else if blkNumCmp < 0 { 134 // 比当前高度消息的msg,暂时先直接舍弃掉 135 return fmt.Errorf("the height of msg is lower than current height, msg height :%d, current height : %d", msgBlkNum, b.h) 136 } 137 138 // 高度一致比较轮次 139 if msgRound < b.r { 140 return fmt.Errorf("the round of msg is lower than current round, msg round :%d, current round : %d", msgRound, b.r) 141 } else if msgRound > b.r { 142 if err := b.mp.addMsg(msg); err != nil { 143 log.Error("add msg to msg pool error", "err", err) 144 return err 145 } 146 return nil 147 } 148 149 switch msgType { 150 case types.BftPreprepareMessage: 151 return b.handlePrePrepareMsg(msg.(*types.PreprepareMsg)) 152 case types.BftPrepareMessage: 153 return b.handlePrepareMsg(msg.(*types.PrepareMsg)) 154 case types.BftCommitMessage: 155 return b.handleCommitMsg(msg.(*types.CommitMsg)) 156 default: 157 log.Error("unknown bft message", "type", msgType.String()) 158 return fmt.Errorf("unknown bft message type: %s", msgType.String()) 159 } 160 } 161 162 // handlePrePrepareMsg 163 // WARN: msg pool has only one pre-prepare msg position, only the first correct one can be 164 // saved to msg pool. No need to care about you will vote for two pre-prepare msg. You only 165 // vote for the pre-prepare msg in msg pool. 166 func (b *BftManager) handlePrePrepareMsg(msg *types.PreprepareMsg) error { 167 log.Trace("HandlePrePrepareMsg") 168 defer log.Trace("HandlePrePrepareMsg exit") 169 170 // check bft step, should be at newRound 171 stp := atomic.LoadUint32(&b.step) 172 if stp != newRound { 173 log.Debug("Pre-prepare msg bft step not match", "local round", stp) 174 return nil 175 } 176 177 // Verify msg 178 if err := b.verifyPrePrepareMsg(msg); err != nil { 179 log.Debug("Pre-prepare msg is invalid", "error", err) 180 return err 181 } 182 if _, _, _, err := b.verifyBlock(msg.Block); err != nil { 183 log.Debug("Pre-prepare's block is invalid", "error", err) 184 return nil 185 } else { 186 log.Debug("Pre-prepare block is valid") 187 } 188 189 log.Trace("HandlePrePrepareMsg verified block") 190 191 // Add msg to round msg pool, instead of msg pool 192 if err := b.roundMp.addMsg(msg); err != nil { 193 log.Warn("Add pre-prepare msg failed", "error", err) 194 return err 195 } 196 197 log.Trace("HandlePrePrepareMsg msg has been add to round msg pool") 198 199 // Go to next step 200 if ok := atomic.CompareAndSwapUint32(&b.step, newRound, prePrePared); ok { 201 return b.startPrepare() 202 } 203 return nil 204 } 205 206 // startPrepare enter prepare step, whether 207 func (b *BftManager) startPrepare() error { 208 log.Trace("StartPrepare") 209 defer log.Trace("StartPrepare exit") 210 211 // check our state and make a prepare msg 212 if atomic.LoadUint32(&b.step) != prePrePared { 213 return nil 214 } 215 prePreMsg, err := b.roundMp.getPrePrepareMsg(b.h, b.r) 216 if err != nil { 217 log.Error("Get pre-prepare msg from msg pool in prepare", "error", err) 218 return fmt.Errorf("get pre-prepare msg from msg pool, error: %s", err) 219 } 220 preMsg, err := b.makePrepareMsg(prePreMsg) 221 if err != nil { 222 return err 223 } 224 if err := b.roundMp.addMsg(preMsg); err != nil { 225 return err 226 } 227 228 // The one of first changing step, send the msg 229 if ok := atomic.CompareAndSwapUint32(&b.step, prePrePared, preparing); ok { 230 b.sendMsg(preMsg) 231 } 232 233 // Maybe have enough prepare msg to enter commit, when pre-prepare msg comes after prepare msg 234 return b.tryCommitStep() 235 } 236 237 // tryCommitStep check whether can enter commit step 238 func (b *BftManager) tryCommitStep() error { 239 log.Trace("tryCommitStep") 240 defer log.Trace("tryCommitStep exit") 241 242 stp := atomic.LoadUint32(&b.step) 243 if stp < preparing || stp > prepared { 244 log.Debug("tryCommitStep step not match", "step", stp) 245 return nil 246 } 247 248 var ( 249 prePreMsg *types.PreprepareMsg 250 prepareMsgs []*types.PrepareMsg 251 err error 252 ) 253 if prepareMsgs, err = b.roundMp.getTwoThirdMajorityPrepareMsg(b.h, b.r); err != nil { 254 return nil 255 } 256 if prePreMsg, err = b.roundMp.getPrePrepareMsg(b.h, b.r); err != nil { 257 log.Error("Get pre-prepare msg from msg pool in try commit", "error", err) 258 return fmt.Errorf("get pre-prepare msg from msg pool, error: %s", err) 259 } 260 if prePreMsg.Block.Hash() != prepareMsgs[0].BlockHash { 261 log.Error("Majority prepare msg is not match with pre-prepare msg", "block in prepare", 262 prepareMsgs[0].BlockHash, "block in pre-prepare", prePreMsg.Block.Hash()) 263 return fmt.Errorf("majority prepare msg is not match with pre-prepare msg") 264 } 265 atomic.CompareAndSwapUint32(&b.step, preparing, prepared) 266 return b.startCommit(prePreMsg) 267 } 268 269 // startCommit build commit message and send it 270 func (b *BftManager) startCommit(prePreMsg *types.PreprepareMsg) error { 271 log.Trace("StartCommit") 272 defer log.Trace("StartCommit exit") 273 274 if atomic.LoadUint32(&b.step) != prepared { 275 return nil 276 } 277 278 commitMsg, err := b.makeCommitMsg(prePreMsg) 279 if err != nil { 280 return err 281 } 282 if err := b.roundMp.addMsg(commitMsg); err != nil { 283 return err 284 } 285 286 // The one of first changing step, send the msg 287 if ok := atomic.CompareAndSwapUint32(&b.step, prepared, committing); ok { 288 b.sendMsg(commitMsg) 289 } 290 291 return b.tryWriteBlockStep() 292 } 293 294 // sendMsg only witness send bft message. 295 // Caller make sure has the newRoundRWLock. 296 func (b *BftManager) sendMsg(msg types.ConsensusMsg) { 297 log.Trace("bft sendMsg start") 298 if _, ok := b.witnessList[b.coinBase]; ok { 299 b.sendBftMsg(msg) 300 } 301 log.Trace("bft sendMsg success") 302 } 303 304 func (b *BftManager) tryWriteBlockStep() error { 305 log.Trace("TryWriteBlockStep") 306 defer log.Trace("TryWriteBlockStep exit") 307 308 if atomic.LoadUint32(&b.step) != committing { 309 return nil 310 } 311 // commit消息满足数量要求后写区块 312 if commitMsgs, err := b.roundMp.getTwoThirdMajorityCommitMsg(b.h, b.r); err != nil { 313 return nil 314 } else if ok := atomic.CompareAndSwapUint32(&b.step, committing, committed); ok { 315 if prePrepareMsg, err := b.roundMp.getPrePrepareMsg(b.h, b.r); err != nil { 316 log.Error("Get pre-prepare msg from msg pool in try write block", "err", err) 317 return fmt.Errorf("get pre-prepare msg from msg pool, error: %s", err) 318 } else { 319 if err := b.writeBlockWithSig(prePrepareMsg, commitMsgs); err != nil { 320 log.Error("Write block to chain", "err", err) 321 return fmt.Errorf("write block to chain error: %s", err) 322 } 323 atomic.CompareAndSwapUint32(&b.step, committed, done) 324 } 325 } 326 return nil 327 } 328 329 func (b *BftManager) handlePrepareMsg(msg *types.PrepareMsg) error { 330 stp := atomic.LoadUint32(&b.step) 331 // 当前阶段大于preparing,则prepare消息已经没用了,直接舍弃 332 if stp > preparing { 333 log.Debug("prepare msg bft step not match", "local step", stp) 334 return nil 335 } 336 337 if err := b.verifyPrepareMsg(msg); err != nil { 338 log.Error("failed to verify prepare msg", "err", err) 339 return err 340 } 341 if err := b.roundMp.addMsg(msg); err != nil { 342 log.Error("failed to add prepare msg", "height", b.h, "round", b.r, "err", err) 343 return err 344 } 345 346 return b.tryCommitStep() 347 } 348 349 func (b *BftManager) handleCommitMsg(msg *types.CommitMsg) error { 350 stp := atomic.LoadUint32(&b.step) 351 // 当前阶段大于committing,则commit消息已经没用了,直接舍弃 352 if stp > committing { 353 log.Debug("commit msg bft step not match", "local step", stp) 354 return nil 355 } 356 if err := b.verifyCommitMsg(msg); err != nil { 357 log.Error("failed to verify commit msg", "err", err) 358 return err 359 } 360 if err := b.roundMp.addMsg(msg); err != nil { 361 log.Error("failed to add commit msg", "height", b.h, "round", b.r, "err", err) 362 return err 363 } 364 365 return b.tryWriteBlockStep() 366 } 367 368 // writeBlock to block chain 369 func (b *BftManager) writeBlockWithSig(msg *types.PreprepareMsg, cmtMsg []*types.CommitMsg) error { 370 block := msg.Block 371 // Match pre-prepare msg and commit msg 372 if block.Hash() != cmtMsg[0].BlockHash { 373 return fmt.Errorf("writeBlockWithSig error, commit msg for block: %s, not for block: %s", cmtMsg[0].BlockHash.String(), block.Hash().String()) 374 } 375 376 block.FillBftMsg(cmtMsg) 377 log.Trace("writeBlockWithSig", "h", b.h.String(), "r", b.r, "hash", block.Hash().Hex()) 378 return b.writeBlock(block) 379 } 380 381 // newRound has lock, it maybe time consuming at sometime, call it by routine 382 func (b *BftManager) newRound(h *big.Int, r uint32, witList []common.Address) { 383 log.Trace("New round switch start") 384 b.newRoundRWLock.Lock() 385 386 // Update witness list 387 if b.h.Cmp(h) != 0 { 388 b.witnessList = make(map[common.Address]struct{}) 389 for _, wit := range witList { 390 b.witnessList[wit] = struct{}{} 391 } 392 } 393 394 // Reset state and round msg pool 395 b.h = h 396 b.r = r 397 b.step = newRound 398 399 // Reset round msg pool 400 b.roundMp.cleanAllMessage() 401 402 // Switch to new round finished 403 b.newRoundRWLock.Unlock() 404 405 log.Trace("New round switch finish", "h", b.h.String(), "r", b.r, "time", time.Now().Unix()) 406 407 // New round switch finished, must return right now 408 go b.importCurRoundMsg() 409 } 410 411 // importCurRoundMsg import consensus messages, but can not directly import to round msg pool 412 func (b *BftManager) importCurRoundMsg() { 413 b.newRoundRWLock.RLock() 414 msg := b.mp.getAllMsgOf(b.h, b.r) 415 b.newRoundRWLock.RUnlock() 416 for _, m := range msg { 417 log.Trace("Import Msg", "type", m.Type(), "hash", m.Hash()) 418 go b.handleBftMsg(m) 419 } 420 } 421 422 func (b *BftManager) startSync(block *types.Block) { 423 // TODO Not emergency, sync will be triggered by block hash msg 424 log.Debug("Bft manager startPrePrepare sync") 425 } 426 427 func (b *BftManager) producingStop() { 428 atomic.StoreUint32(&b.producing, 0) 429 log.Debug("BFT stop producing") 430 } 431 432 func (b *BftManager) producingStart() { 433 atomic.StoreUint32(&b.producing, 1) 434 log.Debug("BFT start producing") 435 } 436 437 func (b *BftManager) validWitness(wit common.Address) bool { 438 _, ok := b.witnessList[wit] 439 return ok 440 } 441 442 // cleanOldMsg clean msg pool and keep future message. cleaning only 443 // on height % 100 == 0. 444 func (b *BftManager) cleanOldMsg(h *big.Int) { 445 b.mp.cleanOldMessage(h) 446 }