github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/orderer/multichain/chainsupport.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package multichain 18 19 import ( 20 "github.com/hyperledger/fabric/common/config" 21 "github.com/hyperledger/fabric/common/crypto" 22 "github.com/hyperledger/fabric/common/policies" 23 "github.com/hyperledger/fabric/common/util" 24 "github.com/hyperledger/fabric/orderer/common/blockcutter" 25 "github.com/hyperledger/fabric/orderer/common/broadcast" 26 "github.com/hyperledger/fabric/orderer/common/configtxfilter" 27 "github.com/hyperledger/fabric/orderer/common/filter" 28 "github.com/hyperledger/fabric/orderer/common/sigfilter" 29 "github.com/hyperledger/fabric/orderer/common/sizefilter" 30 "github.com/hyperledger/fabric/orderer/ledger" 31 cb "github.com/hyperledger/fabric/protos/common" 32 "github.com/hyperledger/fabric/protos/utils" 33 ) 34 35 // Consenter defines the backing ordering mechanism 36 type Consenter interface { 37 // HandleChain should create and return a reference to a Chain for the given set of resources 38 // It will only be invoked for a given chain once per process. In general, errors will be treated 39 // as irrecoverable and cause system shutdown. See the description of Chain for more details 40 // The second argument to HandleChain is a pointer to the metadata stored on the `ORDERER` slot of 41 // the last block committed to the ledger of this Chain. For a new chain, this metadata will be 42 // nil, as this field is not set on the genesis block 43 HandleChain(support ConsenterSupport, metadata *cb.Metadata) (Chain, error) 44 } 45 46 // Chain defines a way to inject messages for ordering 47 // Note, that in order to allow flexibility in the implementation, it is the responsibility of the implementer 48 // to take the ordered messages, send them through the blockcutter.Receiver supplied via HandleChain to cut blocks, 49 // and ultimately write the ledger also supplied via HandleChain. This flow allows for two primary flows 50 // 1. Messages are ordered into a stream, the stream is cut into blocks, the blocks are committed (solo, kafka) 51 // 2. Messages are cut into blocks, the blocks are ordered, then the blocks are committed (sbft) 52 type Chain interface { 53 // Enqueue accepts a message and returns true on acceptance, or false on failure 54 Enqueue(env *cb.Envelope) bool 55 56 // Errored returns a channel which will close when an error has occurred 57 // This is especially useful for the Deliver client, who must terminate waiting 58 // clients when the consenter is not up to date 59 Errored() <-chan struct{} 60 61 // Start should allocate whatever resources are needed for staying up to date with the chain 62 // Typically, this involves creating a thread which reads from the ordering source, passes those 63 // messages to a block cutter, and writes the resulting blocks to the ledger 64 Start() 65 66 // Halt frees the resources which were allocated for this Chain 67 Halt() 68 } 69 70 // ConsenterSupport provides the resources available to a Consenter implementation 71 type ConsenterSupport interface { 72 crypto.LocalSigner 73 BlockCutter() blockcutter.Receiver 74 SharedConfig() config.Orderer 75 CreateNextBlock(messages []*cb.Envelope) *cb.Block 76 WriteBlock(block *cb.Block, committers []filter.Committer, encodedMetadataValue []byte) *cb.Block 77 ChainID() string // ChainID returns the chain ID this specific consenter instance is associated with 78 Height() uint64 // Returns the number of blocks on the chain this specific consenter instance is associated with 79 } 80 81 // ChainSupport provides a wrapper for the resources backing a chain 82 type ChainSupport interface { 83 // This interface is actually the union with the deliver.Support but because of a golang 84 // limitation https://github.com/golang/go/issues/6977 the methods must be explicitly declared 85 86 // PolicyManager returns the current policy manager as specified by the chain config 87 PolicyManager() policies.Manager 88 89 // Reader returns the chain Reader for the chain 90 Reader() ledger.Reader 91 92 // Errored returns whether the backing consenter has errored 93 Errored() <-chan struct{} 94 95 broadcast.Support 96 ConsenterSupport 97 98 // Sequence returns the current config sequence number 99 Sequence() uint64 100 101 // ProposeConfigUpdate applies a CONFIG_UPDATE to an existing config to produce a *cb.ConfigEnvelope 102 ProposeConfigUpdate(env *cb.Envelope) (*cb.ConfigEnvelope, error) 103 } 104 105 type chainSupport struct { 106 *ledgerResources 107 chain Chain 108 cutter blockcutter.Receiver 109 filters *filter.RuleSet 110 signer crypto.LocalSigner 111 lastConfig uint64 112 lastConfigSeq uint64 113 } 114 115 func newChainSupport( 116 filters *filter.RuleSet, 117 ledgerResources *ledgerResources, 118 consenters map[string]Consenter, 119 signer crypto.LocalSigner, 120 ) *chainSupport { 121 122 cutter := blockcutter.NewReceiverImpl(ledgerResources.SharedConfig(), filters) 123 consenterType := ledgerResources.SharedConfig().ConsensusType() 124 consenter, ok := consenters[consenterType] 125 if !ok { 126 logger.Fatalf("Error retrieving consenter of type: %s", consenterType) 127 } 128 129 cs := &chainSupport{ 130 ledgerResources: ledgerResources, 131 cutter: cutter, 132 filters: filters, 133 signer: signer, 134 } 135 136 cs.lastConfigSeq = cs.Sequence() 137 138 var err error 139 140 lastBlock := ledger.GetBlock(cs.Reader(), cs.Reader().Height()-1) 141 142 // If this is the genesis block, the lastconfig field may be empty, and, the last config is necessary 0 143 // so no need to initialize lastConfig 144 if lastBlock.Header.Number != 0 { 145 cs.lastConfig, err = utils.GetLastConfigIndexFromBlock(lastBlock) 146 if err != nil { 147 logger.Fatalf("[channel: %s] Error extracting last config block from block metadata: %s", cs.ChainID(), err) 148 } 149 } 150 151 metadata, err := utils.GetMetadataFromBlock(lastBlock, cb.BlockMetadataIndex_ORDERER) 152 // Assuming a block created with cb.NewBlock(), this should not 153 // error even if the orderer metadata is an empty byte slice 154 if err != nil { 155 logger.Fatalf("[channel: %s] Error extracting orderer metadata: %s", cs.ChainID(), err) 156 } 157 logger.Debugf("[channel: %s] Retrieved metadata for tip of chain (blockNumber=%d, lastConfig=%d, lastConfigSeq=%d): %+v", cs.ChainID(), lastBlock.Header.Number, cs.lastConfig, cs.lastConfigSeq, metadata) 158 159 cs.chain, err = consenter.HandleChain(cs, metadata) 160 if err != nil { 161 logger.Fatalf("[channel: %s] Error creating consenter: %s", cs.ChainID(), err) 162 } 163 164 return cs 165 } 166 167 // createStandardFilters creates the set of filters for a normal (non-system) chain 168 func createStandardFilters(ledgerResources *ledgerResources) *filter.RuleSet { 169 return filter.NewRuleSet([]filter.Rule{ 170 filter.EmptyRejectRule, 171 sizefilter.MaxBytesRule(ledgerResources.SharedConfig().BatchSize().AbsoluteMaxBytes), 172 sigfilter.New(policies.ChannelWriters, ledgerResources.PolicyManager()), 173 configtxfilter.NewFilter(ledgerResources), 174 filter.AcceptRule, 175 }) 176 177 } 178 179 // createSystemChainFilters creates the set of filters for the ordering system chain 180 func createSystemChainFilters(ml *multiLedger, ledgerResources *ledgerResources) *filter.RuleSet { 181 return filter.NewRuleSet([]filter.Rule{ 182 filter.EmptyRejectRule, 183 sizefilter.MaxBytesRule(ledgerResources.SharedConfig().BatchSize().AbsoluteMaxBytes), 184 sigfilter.New(policies.ChannelWriters, ledgerResources.PolicyManager()), 185 newSystemChainFilter(ledgerResources, ml), 186 configtxfilter.NewFilter(ledgerResources), 187 filter.AcceptRule, 188 }) 189 } 190 191 func (cs *chainSupport) start() { 192 cs.chain.Start() 193 } 194 195 func (cs *chainSupport) NewSignatureHeader() (*cb.SignatureHeader, error) { 196 return cs.signer.NewSignatureHeader() 197 } 198 199 func (cs *chainSupport) Sign(message []byte) ([]byte, error) { 200 return cs.signer.Sign(message) 201 } 202 203 func (cs *chainSupport) Filters() *filter.RuleSet { 204 return cs.filters 205 } 206 207 func (cs *chainSupport) BlockCutter() blockcutter.Receiver { 208 return cs.cutter 209 } 210 211 func (cs *chainSupport) Reader() ledger.Reader { 212 return cs.ledger 213 } 214 215 func (cs *chainSupport) Enqueue(env *cb.Envelope) bool { 216 return cs.chain.Enqueue(env) 217 } 218 219 func (cs *chainSupport) Errored() <-chan struct{} { 220 return cs.chain.Errored() 221 } 222 223 func (cs *chainSupport) CreateNextBlock(messages []*cb.Envelope) *cb.Block { 224 return ledger.CreateNextBlock(cs.ledger, messages) 225 } 226 227 func (cs *chainSupport) addBlockSignature(block *cb.Block) { 228 logger.Debugf("%+v", cs) 229 logger.Debugf("%+v", cs.signer) 230 231 blockSignature := &cb.MetadataSignature{ 232 SignatureHeader: utils.MarshalOrPanic(utils.NewSignatureHeaderOrPanic(cs.signer)), 233 } 234 235 // Note, this value is intentionally nil, as this metadata is only about the signature, there is no additional metadata 236 // information required beyond the fact that the metadata item is signed. 237 blockSignatureValue := []byte(nil) 238 239 blockSignature.Signature = utils.SignOrPanic(cs.signer, util.ConcatenateBytes(blockSignatureValue, blockSignature.SignatureHeader, block.Header.Bytes())) 240 241 block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = utils.MarshalOrPanic(&cb.Metadata{ 242 Value: blockSignatureValue, 243 Signatures: []*cb.MetadataSignature{ 244 blockSignature, 245 }, 246 }) 247 } 248 249 func (cs *chainSupport) addLastConfigSignature(block *cb.Block) { 250 configSeq := cs.Sequence() 251 if configSeq > cs.lastConfigSeq { 252 logger.Debugf("[channel: %s] Detected lastConfigSeq transitioning from %d to %d, setting lastConfig from %d to %d", cs.ChainID(), cs.lastConfigSeq, configSeq, cs.lastConfig, block.Header.Number) 253 cs.lastConfig = block.Header.Number 254 cs.lastConfigSeq = configSeq 255 } 256 257 lastConfigSignature := &cb.MetadataSignature{ 258 SignatureHeader: utils.MarshalOrPanic(utils.NewSignatureHeaderOrPanic(cs.signer)), 259 } 260 261 lastConfigValue := utils.MarshalOrPanic(&cb.LastConfig{Index: cs.lastConfig}) 262 logger.Debugf("[channel: %s] About to write block, setting its LAST_CONFIG to %d", cs.ChainID(), cs.lastConfig) 263 264 lastConfigSignature.Signature = utils.SignOrPanic(cs.signer, util.ConcatenateBytes(lastConfigValue, lastConfigSignature.SignatureHeader, block.Header.Bytes())) 265 266 block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = utils.MarshalOrPanic(&cb.Metadata{ 267 Value: lastConfigValue, 268 Signatures: []*cb.MetadataSignature{ 269 lastConfigSignature, 270 }, 271 }) 272 } 273 274 func (cs *chainSupport) WriteBlock(block *cb.Block, committers []filter.Committer, encodedMetadataValue []byte) *cb.Block { 275 for _, committer := range committers { 276 committer.Commit() 277 } 278 // Set the orderer-related metadata field 279 if encodedMetadataValue != nil { 280 block.Metadata.Metadata[cb.BlockMetadataIndex_ORDERER] = utils.MarshalOrPanic(&cb.Metadata{Value: encodedMetadataValue}) 281 } 282 cs.addBlockSignature(block) 283 cs.addLastConfigSignature(block) 284 285 err := cs.ledger.Append(block) 286 if err != nil { 287 logger.Panicf("[channel: %s] Could not append block: %s", cs.ChainID(), err) 288 } 289 logger.Debugf("[channel: %s] Wrote block %d", cs.ChainID(), block.GetHeader().Number) 290 291 return block 292 } 293 294 func (cs *chainSupport) Height() uint64 { 295 return cs.Reader().Height() 296 }