github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/consensus/pbft/core/commit.go (about)

     1  // Copyright 2020 The go-simplechain Authors
     2  // This file is part of the go-simplechain library.
     3  //
     4  // The go-simplechain 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-simplechain 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-simplechain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package core
    18  
    19  import (
    20  	"reflect"
    21  	"time"
    22  
    23  	"github.com/bigzoro/my_simplechain/common"
    24  	"github.com/bigzoro/my_simplechain/consensus/pbft"
    25  )
    26  
    27  func (c *core) sendCommit() {
    28  	sub := c.current.Subject()
    29  	c.broadcastCommit(sub, true)
    30  }
    31  
    32  func (c *core) sendCommitForOldBlock(view *pbft.View, pending, digest common.Hash) {
    33  	sub := &pbft.Subject{
    34  		View:    view,
    35  		Pending: pending,
    36  		Digest:  digest,
    37  	}
    38  	c.broadcastCommit(sub, false)
    39  }
    40  
    41  func (c *core) broadcastCommit(commit *pbft.Subject, fresh bool) {
    42  	logger := c.logger.New("state", c.state)
    43  
    44  	//logger.Error("send commit", "subject", commit, "fresh", fresh)
    45  
    46  	encodedSubject, err := Encode(commit)
    47  	if err != nil {
    48  		logger.Error("Failed to encode", "commit", commit)
    49  		return
    50  	}
    51  
    52  	commitMsg := &message{
    53  		Code: msgCommit,
    54  		Msg:  encodedSubject,
    55  	}
    56  
    57  	//c.broadcast(commitMsg, true)
    58  	c.broadcast(commitMsg, false)
    59  
    60  	// if commit is fresh, refresh current state
    61  	if fresh {
    62  		c.acceptCommit(commitMsg)
    63  		c.checkAndCommit(commit)
    64  	}
    65  }
    66  
    67  func (c *core) handleCommit(msg *message, src pbft.Validator) error {
    68  	c.commitTimestamp = time.Now()
    69  
    70  	// Decode COMMIT message
    71  	var commit *pbft.Subject
    72  	err := msg.Decode(&commit)
    73  	if err != nil {
    74  		return errFailedDecodeCommit
    75  	}
    76  
    77  	if err := c.checkMessage(msgCommit, commit.View); err != nil {
    78  		return err
    79  	}
    80  
    81  	if err := c.verifyCommit(commit, src); err != nil {
    82  		return err
    83  	}
    84  
    85  	c.acceptCommit(msg)
    86  	c.checkAndCommit(commit)
    87  	return nil
    88  }
    89  
    90  // verifyCommit verifies if the received COMMIT message is equivalent to our subject
    91  func (c *core) verifyCommit(commit *pbft.Subject, src pbft.Validator) error {
    92  	logger := c.logger.New("from", src, "state", c.state)
    93  
    94  	sub := c.current.Subject()
    95  	if !reflect.DeepEqual(commit, sub) {
    96  		logger.Warn("Inconsistent subjects between commit and proposal", "expected", sub, "got", commit)
    97  		//return errInconsistentSubject
    98  	}
    99  
   100  	return nil
   101  }
   102  
   103  func (c *core) acceptCommit(msg *message) error {
   104  	logger := c.logger.New("from", msg.Address, "state", c.state)
   105  	logger.Trace("accept commit msg", "view", c.currentView(), "lockHash", c.current.lockedHash)
   106  
   107  	// Add the COMMIT message to current round state
   108  	if err := c.current.Commits.Add(msg); err != nil {
   109  		logger.Error("Failed to record commit message", "msg", msg, "err", err)
   110  		return err
   111  	}
   112  
   113  	return nil
   114  }
   115  
   116  func (c *core) checkAndCommit(commit *pbft.Subject) {
   117  	// Commit the proposal once we have enough COMMIT messages and we are not in the Committed state.
   118  	//
   119  	// If we already have a proposal, we may have chance to speed up the consensus process
   120  	// by committing the proposal without PREPARE messages.
   121  	if c.current.Commits.Size() >= c.Confirmations() && c.state.Cmp(StateCommitted) < 0 {
   122  		// Still need to call LockHash here since state can skip Prepared state and jump directly to the Committed state.
   123  		c.current.LockHash()
   124  		c.commit()
   125  		return
   126  	}
   127  
   128  	// Check and send commit-message, if state is not prepared
   129  	// Sometimes our node received a commit-message from another hashLocked node,
   130  	// the node cannot have enough prepare-messages to upgrade state to prepared or send commit-message
   131  	if c.state.Cmp(StatePrepared) < 0 {
   132  		c.checkAndPrepare(commit)
   133  	}
   134  }