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 }