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