github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/consensus/dbft/core/preprepare.go (about) 1 package core 2 3 import ( 4 "time" 5 6 "github.com/quickchainproject/quickchain/consensus" 7 bft "github.com/quickchainproject/quickchain/consensus/dbft" 8 ) 9 10 func (c *core) sendPreprepare(request *bft.Request) { 11 logger := c.logger.New("state", c.state) 12 13 // If I'm the proposer and I have the same sequence with the proposal 14 if c.current.Sequence().Cmp(request.Proposal.Number()) == 0 && c.isProposer() { 15 curView := c.currentView() 16 preprepare, err := Encode(&bft.Preprepare{ 17 View: curView, 18 Proposal: request.Proposal, 19 }) 20 if err != nil { 21 logger.Error("Failed to encode", "view", curView) 22 return 23 } 24 25 c.broadcast(&message{ 26 Code: msgPreprepare, 27 Msg: preprepare, 28 }) 29 } 30 } 31 32 func (c *core) handlePreprepare(msg *message, src bft.Validator) error { 33 logger := c.logger.New("from", src, "state", c.state) 34 35 // Decode PRE-PREPARE 36 var preprepare *bft.Preprepare 37 err := msg.Decode(&preprepare) 38 if err != nil { 39 return errFailedDecodePreprepare 40 } 41 42 // Ensure we have the same view with the PRE-PREPARE message 43 // If it is old message, see if we need to broadcast COMMIT 44 if err := c.checkMessage(msgPreprepare, preprepare.View); err != nil { 45 if err == errOldMessage { 46 // Get validator set for the given proposal 47 valSet := c.backend.ParentValidators(preprepare.Proposal).Copy() 48 previousProposer := c.backend.GetProposer(preprepare.Proposal.Number().Uint64() - 1) 49 valSet.CalcProposer(previousProposer, preprepare.View.Round.Uint64()) 50 // Broadcast COMMIT if it is an existing block 51 // 1. The proposer needs to be a proposer matches the given (Sequence + Round) 52 // 2. The given block must exist 53 if valSet.IsProposer(src.Address()) && c.backend.HasPropsal(preprepare.Proposal.Hash(), preprepare.Proposal.Number()) { 54 c.sendCommitForOldBlock(preprepare.View, preprepare.Proposal.Hash()) 55 return nil 56 } 57 } 58 return err 59 } 60 61 // Check if the message comes from current proposer 62 if !c.valSet.IsProposer(src.Address()) { 63 logger.Warn("Ignore preprepare messages from non-proposer") 64 return errNotFromProposer 65 } 66 67 // Verify the proposal we received 68 if duration, err := c.backend.Verify(preprepare.Proposal); err != nil { 69 logger.Warn("Failed to verify proposal", "err", err, "duration", duration) 70 // if it's a future block, we will handle it again after the duration 71 if err == consensus.ErrFutureBlock { 72 c.stopFuturePreprepareTimer() 73 c.futurePreprepareTimer = time.AfterFunc(duration, func() { 74 c.sendEvent(backlogEvent{ 75 src: src, 76 msg: msg, 77 }) 78 }) 79 } else { 80 c.sendNextRoundChange() 81 } 82 return err 83 } 84 85 // Here is about to accept the PRE-PREPARE 86 if c.state == StateAcceptRequest { 87 // Send ROUND CHANGE if the locked proposal and the received proposal are different 88 if c.current.IsHashLocked() { 89 if preprepare.Proposal.Hash() == c.current.GetLockedHash() { 90 // Broadcast COMMIT and enters Prepared state directly 91 c.acceptPreprepare(preprepare) 92 c.setState(StatePrepared) 93 c.sendCommit() 94 } else { 95 // Send round change 96 c.sendNextRoundChange() 97 } 98 } else { 99 // Either 100 // 1. the locked proposal and the received proposal match 101 // 2. we have no locked proposal 102 c.acceptPreprepare(preprepare) 103 c.setState(StatePreprepared) 104 c.sendPrepare() 105 } 106 } 107 108 return nil 109 } 110 111 func (c *core) acceptPreprepare(preprepare *bft.Preprepare) { 112 c.consensusTimestamp = time.Now() 113 c.current.SetPreprepare(preprepare) 114 }