github.com/lzy4123/fabric@v2.1.1+incompatible/orderer/consensus/solo/consensus.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package solo
     8  
     9  import (
    10  	"fmt"
    11  	"time"
    12  
    13  	cb "github.com/hyperledger/fabric-protos-go/common"
    14  	"github.com/hyperledger/fabric/common/flogging"
    15  	"github.com/hyperledger/fabric/orderer/consensus"
    16  )
    17  
    18  var logger = flogging.MustGetLogger("orderer.consensus.solo")
    19  
    20  type consenter struct{}
    21  
    22  type chain struct {
    23  	support  consensus.ConsenterSupport
    24  	sendChan chan *message
    25  	exitChan chan struct{}
    26  }
    27  
    28  type message struct {
    29  	configSeq uint64
    30  	normalMsg *cb.Envelope
    31  	configMsg *cb.Envelope
    32  }
    33  
    34  // New creates a new consenter for the solo consensus scheme.
    35  // The solo consensus scheme is very simple, and allows only one consenter for a given chain (this process).
    36  // It accepts messages being delivered via Order/Configure, orders them, and then uses the blockcutter to form the messages
    37  // into blocks before writing to the given ledger
    38  func New() consensus.Consenter {
    39  	return &consenter{}
    40  }
    41  
    42  func (solo *consenter) HandleChain(support consensus.ConsenterSupport, metadata *cb.Metadata) (consensus.Chain, error) {
    43  	logger.Warningf("Use of the Solo orderer is deprecated and remains only for use in test environments but may be removed in the future.")
    44  	return newChain(support), nil
    45  }
    46  
    47  func newChain(support consensus.ConsenterSupport) *chain {
    48  	return &chain{
    49  		support:  support,
    50  		sendChan: make(chan *message),
    51  		exitChan: make(chan struct{}),
    52  	}
    53  }
    54  
    55  func (ch *chain) Start() {
    56  	go ch.main()
    57  }
    58  
    59  func (ch *chain) Halt() {
    60  	select {
    61  	case <-ch.exitChan:
    62  		// Allow multiple halts without panic
    63  	default:
    64  		close(ch.exitChan)
    65  	}
    66  }
    67  
    68  func (ch *chain) WaitReady() error {
    69  	return nil
    70  }
    71  
    72  // Order accepts normal messages for ordering
    73  func (ch *chain) Order(env *cb.Envelope, configSeq uint64) error {
    74  	select {
    75  	case ch.sendChan <- &message{
    76  		configSeq: configSeq,
    77  		normalMsg: env,
    78  	}:
    79  		return nil
    80  	case <-ch.exitChan:
    81  		return fmt.Errorf("Exiting")
    82  	}
    83  }
    84  
    85  // Configure accepts configuration update messages for ordering
    86  func (ch *chain) Configure(config *cb.Envelope, configSeq uint64) error {
    87  	select {
    88  	case ch.sendChan <- &message{
    89  		configSeq: configSeq,
    90  		configMsg: config,
    91  	}:
    92  		return nil
    93  	case <-ch.exitChan:
    94  		return fmt.Errorf("Exiting")
    95  	}
    96  }
    97  
    98  // Errored only closes on exit
    99  func (ch *chain) Errored() <-chan struct{} {
   100  	return ch.exitChan
   101  }
   102  
   103  func (ch *chain) main() {
   104  	var timer <-chan time.Time
   105  	var err error
   106  
   107  	for {
   108  		seq := ch.support.Sequence()
   109  		err = nil
   110  		select {
   111  		case msg := <-ch.sendChan:
   112  			if msg.configMsg == nil {
   113  				// NormalMsg
   114  				if msg.configSeq < seq {
   115  					_, err = ch.support.ProcessNormalMsg(msg.normalMsg)
   116  					if err != nil {
   117  						logger.Warningf("Discarding bad normal message: %s", err)
   118  						continue
   119  					}
   120  				}
   121  				batches, pending := ch.support.BlockCutter().Ordered(msg.normalMsg)
   122  
   123  				for _, batch := range batches {
   124  					block := ch.support.CreateNextBlock(batch)
   125  					ch.support.WriteBlock(block, nil)
   126  				}
   127  
   128  				switch {
   129  				case timer != nil && !pending:
   130  					// Timer is already running but there are no messages pending, stop the timer
   131  					timer = nil
   132  				case timer == nil && pending:
   133  					// Timer is not already running and there are messages pending, so start it
   134  					timer = time.After(ch.support.SharedConfig().BatchTimeout())
   135  					logger.Debugf("Just began %s batch timer", ch.support.SharedConfig().BatchTimeout().String())
   136  				default:
   137  					// Do nothing when:
   138  					// 1. Timer is already running and there are messages pending
   139  					// 2. Timer is not set and there are no messages pending
   140  				}
   141  
   142  			} else {
   143  				// ConfigMsg
   144  				if msg.configSeq < seq {
   145  					msg.configMsg, _, err = ch.support.ProcessConfigMsg(msg.configMsg)
   146  					if err != nil {
   147  						logger.Warningf("Discarding bad config message: %s", err)
   148  						continue
   149  					}
   150  				}
   151  				batch := ch.support.BlockCutter().Cut()
   152  				if batch != nil {
   153  					block := ch.support.CreateNextBlock(batch)
   154  					ch.support.WriteBlock(block, nil)
   155  				}
   156  
   157  				block := ch.support.CreateNextBlock([]*cb.Envelope{msg.configMsg})
   158  				ch.support.WriteConfigBlock(block, nil)
   159  				timer = nil
   160  			}
   161  		case <-timer:
   162  			//clear the timer
   163  			timer = nil
   164  
   165  			batch := ch.support.BlockCutter().Cut()
   166  			if len(batch) == 0 {
   167  				logger.Warningf("Batch timer expired with no pending requests, this might indicate a bug")
   168  				continue
   169  			}
   170  			logger.Debugf("Batch timer expired, creating block")
   171  			block := ch.support.CreateNextBlock(batch)
   172  			ch.support.WriteBlock(block, nil)
   173  		case <-ch.exitChan:
   174  			logger.Debugf("Exiting")
   175  			return
   176  		}
   177  	}
   178  }