github.com/anjalikarhana/fabric@v2.1.1+incompatible/orderer/common/multichannel/chainsupport.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package multichannel 8 9 import ( 10 cb "github.com/hyperledger/fabric-protos-go/common" 11 "github.com/hyperledger/fabric/bccsp" 12 "github.com/hyperledger/fabric/common/channelconfig" 13 "github.com/hyperledger/fabric/common/ledger/blockledger" 14 "github.com/hyperledger/fabric/common/policies" 15 "github.com/hyperledger/fabric/internal/pkg/identity" 16 "github.com/hyperledger/fabric/orderer/common/blockcutter" 17 "github.com/hyperledger/fabric/orderer/common/msgprocessor" 18 "github.com/hyperledger/fabric/orderer/consensus" 19 "github.com/hyperledger/fabric/protoutil" 20 "github.com/pkg/errors" 21 ) 22 23 // ChainSupport holds the resources for a particular channel. 24 type ChainSupport struct { 25 *ledgerResources 26 msgprocessor.Processor 27 *BlockWriter 28 consensus.Chain 29 cutter blockcutter.Receiver 30 identity.SignerSerializer 31 BCCSP bccsp.BCCSP 32 33 // NOTE: It makes sense to add this to the ChainSupport since the design of Registrar does not assume 34 // that there is a single consensus type at this orderer node and therefore the resolution of 35 // the consensus type too happens only at the ChainSupport level. 36 consensus.MetadataValidator 37 } 38 39 func newChainSupport( 40 registrar *Registrar, 41 ledgerResources *ledgerResources, 42 consenters map[string]consensus.Consenter, 43 signer identity.SignerSerializer, 44 blockcutterMetrics *blockcutter.Metrics, 45 bccsp bccsp.BCCSP, 46 ) *ChainSupport { 47 // Read in the last block and metadata for the channel 48 lastBlock := blockledger.GetBlock(ledgerResources, ledgerResources.Height()-1) 49 metadata, err := protoutil.GetConsenterMetadataFromBlock(lastBlock) 50 // Assuming a block created with cb.NewBlock(), this should not 51 // error even if the orderer metadata is an empty byte slice 52 if err != nil { 53 logger.Fatalf("[channel: %s] Error extracting orderer metadata: %s", ledgerResources.ConfigtxValidator().ChannelID(), err) 54 } 55 56 // Construct limited support needed as a parameter for additional support 57 cs := &ChainSupport{ 58 ledgerResources: ledgerResources, 59 SignerSerializer: signer, 60 cutter: blockcutter.NewReceiverImpl( 61 ledgerResources.ConfigtxValidator().ChannelID(), 62 ledgerResources, 63 blockcutterMetrics, 64 ), 65 BCCSP: bccsp, 66 } 67 68 // Set up the msgprocessor 69 cs.Processor = msgprocessor.NewStandardChannel(cs, msgprocessor.CreateStandardChannelFilters(cs, registrar.config), bccsp) 70 71 // Set up the block writer 72 cs.BlockWriter = newBlockWriter(lastBlock, registrar, cs) 73 74 // Set up the consenter 75 consenterType := ledgerResources.SharedConfig().ConsensusType() 76 consenter, ok := consenters[consenterType] 77 if !ok { 78 logger.Panicf("Error retrieving consenter of type: %s", consenterType) 79 } 80 81 cs.Chain, err = consenter.HandleChain(cs, metadata) 82 if err != nil { 83 logger.Panicf("[channel: %s] Error creating consenter: %s", cs.ChannelID(), err) 84 } 85 86 cs.MetadataValidator, ok = cs.Chain.(consensus.MetadataValidator) 87 if !ok { 88 cs.MetadataValidator = consensus.NoOpMetadataValidator{} 89 } 90 91 logger.Debugf("[channel: %s] Done creating channel support resources", cs.ChannelID()) 92 93 return cs 94 } 95 96 // Block returns a block with the following number, 97 // or nil if such a block doesn't exist. 98 func (cs *ChainSupport) Block(number uint64) *cb.Block { 99 if cs.Height() <= number { 100 return nil 101 } 102 return blockledger.GetBlock(cs.Reader(), number) 103 } 104 105 func (cs *ChainSupport) Reader() blockledger.Reader { 106 return cs 107 } 108 109 // Signer returns the SignerSerializer for this channel. 110 func (cs *ChainSupport) Signer() identity.SignerSerializer { 111 return cs 112 } 113 114 func (cs *ChainSupport) start() { 115 cs.Chain.Start() 116 } 117 118 // BlockCutter returns the blockcutter.Receiver instance for this channel. 119 func (cs *ChainSupport) BlockCutter() blockcutter.Receiver { 120 return cs.cutter 121 } 122 123 // Validate passes through to the underlying configtx.Validator 124 func (cs *ChainSupport) Validate(configEnv *cb.ConfigEnvelope) error { 125 return cs.ConfigtxValidator().Validate(configEnv) 126 } 127 128 // ProposeConfigUpdate validates a config update using the underlying configtx.Validator 129 // and the consensus.MetadataValidator. 130 func (cs *ChainSupport) ProposeConfigUpdate(configtx *cb.Envelope) (*cb.ConfigEnvelope, error) { 131 env, err := cs.ConfigtxValidator().ProposeConfigUpdate(configtx) 132 if err != nil { 133 return nil, err 134 } 135 136 bundle, err := cs.CreateBundle(cs.ChannelID(), env.Config) 137 if err != nil { 138 return nil, err 139 } 140 141 if err = checkResources(bundle); err != nil { 142 return nil, errors.Wrap(err, "config update is not compatible") 143 } 144 145 if err = cs.ValidateNew(bundle); err != nil { 146 return nil, err 147 } 148 149 oldOrdererConfig, ok := cs.OrdererConfig() 150 if !ok { 151 logger.Panic("old config is missing orderer group") 152 } 153 oldMetadata := oldOrdererConfig.ConsensusMetadata() 154 155 // we can remove this check since this is being validated in checkResources earlier 156 newOrdererConfig, ok := bundle.OrdererConfig() 157 if !ok { 158 return nil, errors.New("new config is missing orderer group") 159 } 160 newMetadata := newOrdererConfig.ConsensusMetadata() 161 162 if err = cs.ValidateConsensusMetadata(oldMetadata, newMetadata, false); err != nil { 163 return nil, errors.Wrap(err, "consensus metadata update for channel config update is invalid") 164 } 165 return env, nil 166 } 167 168 // ChannelID passes through to the underlying configtx.Validator 169 func (cs *ChainSupport) ChannelID() string { 170 return cs.ConfigtxValidator().ChannelID() 171 } 172 173 // ConfigProto passes through to the underlying configtx.Validator 174 func (cs *ChainSupport) ConfigProto() *cb.Config { 175 return cs.ConfigtxValidator().ConfigProto() 176 } 177 178 // Sequence passes through to the underlying configtx.Validator 179 func (cs *ChainSupport) Sequence() uint64 { 180 return cs.ConfigtxValidator().Sequence() 181 } 182 183 // Append appends a new block to the ledger in its raw form, 184 // unlike WriteBlock that also mutates its metadata. 185 func (cs *ChainSupport) Append(block *cb.Block) error { 186 return cs.ledgerResources.ReadWriter.Append(block) 187 } 188 189 // VerifyBlockSignature verifies a signature of a block. 190 // It has an optional argument of a configuration envelope 191 // which would make the block verification to use validation rules 192 // based on the given configuration in the ConfigEnvelope. 193 // If the config envelope passed is nil, then the validation rules used 194 // are the ones that were applied at commit of previous blocks. 195 func (cs *ChainSupport) VerifyBlockSignature(sd []*protoutil.SignedData, envelope *cb.ConfigEnvelope) error { 196 policyMgr := cs.PolicyManager() 197 // If the envelope passed isn't nil, we should use a different policy manager. 198 if envelope != nil { 199 bundle, err := channelconfig.NewBundle(cs.ChannelID(), envelope.Config, cs.BCCSP) 200 if err != nil { 201 return err 202 } 203 policyMgr = bundle.PolicyManager() 204 } 205 policy, exists := policyMgr.GetPolicy(policies.BlockValidation) 206 if !exists { 207 return errors.Errorf("policy %s wasn't found", policies.BlockValidation) 208 } 209 err := policy.EvaluateSignedData(sd) 210 if err != nil { 211 return errors.Wrap(err, "block verification failed") 212 } 213 return nil 214 }