github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/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 configvaluesapi "github.com/hyperledger/fabric/common/configvalues" 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 ordererledger "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 a 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 shutdown 54 Enqueue(env *cb.Envelope) bool 55 56 // Start should allocate whatever resources are needed for staying up to date with the chain 57 // Typically, this involves creating a thread which reads from the ordering source, passes those 58 // messages to a block cutter, and writes the resulting blocks to the ledger 59 Start() 60 61 // Halt frees the resources which were allocated for this Chain 62 Halt() 63 } 64 65 // ConsenterSupport provides the resources available to a Consenter implementation 66 type ConsenterSupport interface { 67 crypto.LocalSigner 68 BlockCutter() blockcutter.Receiver 69 SharedConfig() configvaluesapi.Orderer 70 CreateNextBlock(messages []*cb.Envelope) *cb.Block 71 WriteBlock(block *cb.Block, committers []filter.Committer, encodedMetadataValue []byte) *cb.Block 72 ChainID() string // ChainID returns the chain ID this specific consenter instance is associated with 73 } 74 75 // ChainSupport provides a wrapper for the resources backing a chain 76 type ChainSupport interface { 77 // This interface is actually the union with the deliver.Support but because of a golang 78 // limitation https://github.com/golang/go/issues/6977 the methods must be explicitly declared 79 80 // PolicyManager returns the current policy manager as specified by the chain config 81 PolicyManager() policies.Manager 82 83 // Reader returns the chain Reader for the chain 84 Reader() ordererledger.Reader 85 86 broadcast.Support 87 ConsenterSupport 88 89 // ProposeConfigUpdate applies a CONFIG_UPDATE to an existing config to produce a *cb.ConfigEnvelope 90 ProposeConfigUpdate(env *cb.Envelope) (*cb.ConfigEnvelope, error) 91 } 92 93 type chainSupport struct { 94 *ledgerResources 95 chain Chain 96 cutter blockcutter.Receiver 97 filters *filter.RuleSet 98 signer crypto.LocalSigner 99 lastConfig uint64 100 lastConfigSeq uint64 101 } 102 103 func newChainSupport( 104 filters *filter.RuleSet, 105 ledgerResources *ledgerResources, 106 consenters map[string]Consenter, 107 signer crypto.LocalSigner, 108 ) *chainSupport { 109 110 cutter := blockcutter.NewReceiverImpl(ledgerResources.SharedConfig(), filters) 111 consenterType := ledgerResources.SharedConfig().ConsensusType() 112 consenter, ok := consenters[consenterType] 113 if !ok { 114 logger.Fatalf("Error retrieving consenter of type: %s", consenterType) 115 } 116 117 cs := &chainSupport{ 118 ledgerResources: ledgerResources, 119 cutter: cutter, 120 filters: filters, 121 signer: signer, 122 } 123 124 var err error 125 126 lastBlock := ordererledger.GetBlock(cs.Reader(), cs.Reader().Height()-1) 127 metadata, err := utils.GetMetadataFromBlock(lastBlock, cb.BlockMetadataIndex_ORDERER) 128 // Assuming a block created with cb.NewBlock(), this should not 129 // error even if the orderer metadata is an empty byte slice 130 if err != nil { 131 logger.Fatalf("Error extracting orderer metadata for chain %x: %s", cs.ChainID(), err) 132 } 133 logger.Debugf("Retrieved metadata for tip of chain (block #%d): %+v", cs.Reader().Height()-1, metadata) 134 135 cs.chain, err = consenter.HandleChain(cs, metadata) 136 if err != nil { 137 logger.Fatalf("Error creating consenter for chain %x: %s", ledgerResources.ChainID(), err) 138 } 139 140 return cs 141 } 142 143 // createStandardFilters creates the set of filters for a normal (non-system) chain 144 func createStandardFilters(ledgerResources *ledgerResources) *filter.RuleSet { 145 return filter.NewRuleSet([]filter.Rule{ 146 filter.EmptyRejectRule, 147 sizefilter.MaxBytesRule(ledgerResources.SharedConfig().BatchSize().AbsoluteMaxBytes), 148 sigfilter.New(ledgerResources.SharedConfig().IngressPolicyNames, ledgerResources.PolicyManager()), 149 configtxfilter.NewFilter(ledgerResources), 150 filter.AcceptRule, 151 }) 152 153 } 154 155 // createSystemChainFilters creates the set of filters for the ordering system chain 156 func createSystemChainFilters(ml *multiLedger, ledgerResources *ledgerResources) *filter.RuleSet { 157 return filter.NewRuleSet([]filter.Rule{ 158 filter.EmptyRejectRule, 159 sizefilter.MaxBytesRule(ledgerResources.SharedConfig().BatchSize().AbsoluteMaxBytes), 160 sigfilter.New(ledgerResources.SharedConfig().IngressPolicyNames, ledgerResources.PolicyManager()), 161 newSystemChainFilter(ledgerResources, ml), 162 configtxfilter.NewFilter(ledgerResources), 163 filter.AcceptRule, 164 }) 165 } 166 167 func (cs *chainSupport) start() { 168 cs.chain.Start() 169 } 170 171 func (cs *chainSupport) NewSignatureHeader() (*cb.SignatureHeader, error) { 172 return cs.signer.NewSignatureHeader() 173 } 174 175 func (cs *chainSupport) Sign(message []byte) ([]byte, error) { 176 return cs.signer.Sign(message) 177 } 178 179 func (cs *chainSupport) Filters() *filter.RuleSet { 180 return cs.filters 181 } 182 183 func (cs *chainSupport) BlockCutter() blockcutter.Receiver { 184 return cs.cutter 185 } 186 187 func (cs *chainSupport) Reader() ordererledger.Reader { 188 return cs.ledger 189 } 190 191 func (cs *chainSupport) Enqueue(env *cb.Envelope) bool { 192 return cs.chain.Enqueue(env) 193 } 194 195 func (cs *chainSupport) CreateNextBlock(messages []*cb.Envelope) *cb.Block { 196 return ordererledger.CreateNextBlock(cs.ledger, messages) 197 } 198 199 func (cs *chainSupport) addBlockSignature(block *cb.Block) { 200 logger.Debugf("%+v", cs) 201 logger.Debugf("%+v", cs.signer) 202 203 blockSignature := &cb.MetadataSignature{ 204 SignatureHeader: utils.MarshalOrPanic(utils.NewSignatureHeaderOrPanic(cs.signer)), 205 } 206 207 // Note, this value is intentionally nil, as this metadata is only about the signature, there is no additional metadata 208 // information required beyond the fact that the metadata item is signed. 209 blockSignatureValue := []byte(nil) 210 211 blockSignature.Signature = utils.SignOrPanic(cs.signer, util.ConcatenateBytes(blockSignatureValue, blockSignature.SignatureHeader, block.Header.Bytes())) 212 213 block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = utils.MarshalOrPanic(&cb.Metadata{ 214 Value: blockSignatureValue, 215 Signatures: []*cb.MetadataSignature{ 216 blockSignature, 217 }, 218 }) 219 } 220 221 func (cs *chainSupport) addLastConfigSignature(block *cb.Block) { 222 configSeq := cs.Sequence() 223 if configSeq > cs.lastConfigSeq { 224 cs.lastConfig = block.Header.Number 225 cs.lastConfigSeq = configSeq 226 } 227 228 lastConfigSignature := &cb.MetadataSignature{ 229 SignatureHeader: utils.MarshalOrPanic(utils.NewSignatureHeaderOrPanic(cs.signer)), 230 } 231 232 lastConfigValue := utils.MarshalOrPanic(&cb.LastConfig{Index: cs.lastConfig}) 233 234 lastConfigSignature.Signature = utils.SignOrPanic(cs.signer, util.ConcatenateBytes(lastConfigValue, lastConfigSignature.SignatureHeader, block.Header.Bytes())) 235 236 block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = utils.MarshalOrPanic(&cb.Metadata{ 237 Value: lastConfigValue, 238 Signatures: []*cb.MetadataSignature{ 239 lastConfigSignature, 240 }, 241 }) 242 } 243 244 func (cs *chainSupport) WriteBlock(block *cb.Block, committers []filter.Committer, encodedMetadataValue []byte) *cb.Block { 245 for _, committer := range committers { 246 committer.Commit() 247 } 248 // Set the orderer-related metadata field 249 if encodedMetadataValue != nil { 250 block.Metadata.Metadata[cb.BlockMetadataIndex_ORDERER] = utils.MarshalOrPanic(&cb.Metadata{Value: encodedMetadataValue}) 251 } 252 cs.addBlockSignature(block) 253 cs.addLastConfigSignature(block) 254 255 err := cs.ledger.Append(block) 256 if err != nil { 257 logger.Panicf("Could not append block: %s", err) 258 } 259 return block 260 }