github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/scc/cscc/configure.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 // Package cscc chaincode configer provides functions to manage 8 // configuration transactions as the network is being reconfigured. The 9 // configuration transactions arrive from the ordering service to the committer 10 // who calls this chaincode. The chaincode also provides peer configuration 11 // services such as joining a chain or getting configuration data. 12 package cscc 13 14 import ( 15 "fmt" 16 17 "github.com/golang/protobuf/proto" 18 "github.com/hechain20/hechain/bccsp" 19 "github.com/hechain20/hechain/common/channelconfig" 20 "github.com/hechain20/hechain/common/flogging" 21 "github.com/hechain20/hechain/core/aclmgmt" 22 "github.com/hechain20/hechain/core/aclmgmt/resources" 23 "github.com/hechain20/hechain/core/committer/txvalidator/v20/plugindispatcher" 24 "github.com/hechain20/hechain/core/ledger" 25 "github.com/hechain20/hechain/core/peer" 26 "github.com/hechain20/hechain/internal/pkg/txflags" 27 "github.com/hechain20/hechain/protoutil" 28 "github.com/hyperledger/fabric-chaincode-go/shim" 29 "github.com/hyperledger/fabric-protos-go/common" 30 pb "github.com/hyperledger/fabric-protos-go/peer" 31 "github.com/pkg/errors" 32 ) 33 34 // New creates a new instance of the CSCC. 35 // Typically, only one will be created per peer instance. 36 func New( 37 aclProvider aclmgmt.ACLProvider, 38 deployedCCInfoProvider ledger.DeployedChaincodeInfoProvider, 39 lr plugindispatcher.LifecycleResources, 40 nr plugindispatcher.CollectionAndLifecycleResources, 41 p *peer.Peer, 42 bccsp bccsp.BCCSP, 43 ) *PeerConfiger { 44 return &PeerConfiger{ 45 aclProvider: aclProvider, 46 deployedCCInfoProvider: deployedCCInfoProvider, 47 legacyLifecycle: lr, 48 newLifecycle: nr, 49 peer: p, 50 bccsp: bccsp, 51 } 52 } 53 54 func (e *PeerConfiger) Name() string { return "cscc" } 55 func (e *PeerConfiger) Chaincode() shim.Chaincode { return e } 56 57 // PeerConfiger implements the configuration handler for the peer. For every 58 // configuration transaction coming in from the ordering service, the 59 // committer calls this system chaincode to process the transaction. 60 type PeerConfiger struct { 61 aclProvider aclmgmt.ACLProvider 62 deployedCCInfoProvider ledger.DeployedChaincodeInfoProvider 63 legacyLifecycle plugindispatcher.LifecycleResources 64 newLifecycle plugindispatcher.CollectionAndLifecycleResources 65 peer *peer.Peer 66 bccsp bccsp.BCCSP 67 } 68 69 var cnflogger = flogging.MustGetLogger("cscc") 70 71 // These are function names from Invoke first parameter 72 const ( 73 JoinChain string = "JoinChain" 74 JoinChainBySnapshot string = "JoinChainBySnapshot" 75 JoinBySnapshotStatus string = "JoinBySnapshotStatus" 76 GetConfigBlock string = "GetConfigBlock" 77 GetChannelConfig string = "GetChannelConfig" 78 GetChannels string = "GetChannels" 79 ) 80 81 // Init is mostly useless from an SCC perspective 82 func (e *PeerConfiger) Init(stub shim.ChaincodeStubInterface) pb.Response { 83 cnflogger.Info("Init CSCC") 84 return shim.Success(nil) 85 } 86 87 // Invoke is called for the following: 88 // # to process joining a chain (called by app as a transaction proposal) 89 // # to get the current configuration block (called by app) 90 // # to update the configuration block (called by committer) 91 // Peer calls this function with 2 arguments: 92 // # args[0] is the function name, which must be JoinChain, GetConfigBlock or 93 // UpdateConfigBlock 94 // # args[1] is a configuration Block if args[0] is JoinChain or 95 // UpdateConfigBlock; otherwise it is the chain id 96 // TODO: Improve the scc interface to avoid marshal/unmarshal args 97 func (e *PeerConfiger) Invoke(stub shim.ChaincodeStubInterface) pb.Response { 98 args := stub.GetArgs() 99 100 if len(args) < 1 { 101 return shim.Error(fmt.Sprintf("Incorrect number of arguments, %d", len(args))) 102 } 103 104 fname := string(args[0]) 105 106 if fname != GetChannels && fname != JoinBySnapshotStatus && len(args) < 2 { 107 return shim.Error(fmt.Sprintf("Incorrect number of arguments, %d", len(args))) 108 } 109 110 cnflogger.Debugf("Invoke function: %s", fname) 111 112 // Handle ACL: 113 // 1. get the signed proposal 114 sp, err := stub.GetSignedProposal() 115 if err != nil { 116 return shim.Error(fmt.Sprintf("Failed getting signed proposal from stub: [%s]", err)) 117 } 118 119 name, err := protoutil.InvokedChaincodeName(sp.ProposalBytes) 120 if err != nil { 121 return shim.Error(fmt.Sprintf("Failed to identify the called chaincode: %s", err)) 122 } 123 124 if name != e.Name() { 125 return shim.Error(fmt.Sprintf("Rejecting invoke of CSCC from another chaincode, original invocation for '%s'", name)) 126 } 127 128 return e.InvokeNoShim(args, sp) 129 } 130 131 func (e *PeerConfiger) InvokeNoShim(args [][]byte, sp *pb.SignedProposal) pb.Response { 132 var err error 133 fname := string(args[0]) 134 135 switch fname { 136 case JoinChain: 137 if args[1] == nil { 138 return shim.Error("Cannot join the channel <nil> configuration block provided") 139 } 140 141 block, err := protoutil.UnmarshalBlock(args[1]) 142 if err != nil { 143 return shim.Error(fmt.Sprintf("Failed to reconstruct the genesis block, %s", err)) 144 } 145 146 cid, err := protoutil.GetChannelIDFromBlock(block) 147 if err != nil { 148 return shim.Error(fmt.Sprintf("\"JoinChain\" request failed to extract "+ 149 "channel id from the block due to [%s]", err)) 150 } 151 152 // 1. check config block's format and capabilities requirement. 153 if err := validateConfigBlock(block, e.bccsp); err != nil { 154 return shim.Error(fmt.Sprintf("\"JoinChain\" for channelID = %s failed because of validation "+ 155 "of configuration block, because of %s", cid, err)) 156 } 157 158 // 2. check join policy. 159 if err = e.aclProvider.CheckACL(resources.Cscc_JoinChain, "", sp); err != nil { 160 return shim.Error(fmt.Sprintf("access denied for [%s][%s]: [%s]", fname, cid, err)) 161 } 162 163 // Initialize txsFilter if it does not yet exist. We can do this safely since 164 // it's the genesis block anyway 165 txsFilter := txflags.ValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) 166 if len(txsFilter) == 0 { 167 // add array of validation code hardcoded to valid 168 txsFilter = txflags.NewWithValues(len(block.Data.Data), pb.TxValidationCode_VALID) 169 block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter 170 } 171 172 return e.joinChain(cid, block, e.deployedCCInfoProvider, e.legacyLifecycle, e.newLifecycle) 173 case JoinChainBySnapshot: 174 if len(args[1]) == 0 { 175 return shim.Error("Cannot join the channel, no snapshot directory provided") 176 } 177 // check policy 178 if err = e.aclProvider.CheckACL(resources.Cscc_JoinChainBySnapshot, "", sp); err != nil { 179 return shim.Error(fmt.Sprintf("access denied for [%s]: [%s]", fname, err)) 180 } 181 snapshotDir := string(args[1]) 182 return e.JoinChainBySnapshot(snapshotDir, e.deployedCCInfoProvider, e.legacyLifecycle, e.newLifecycle) 183 case JoinBySnapshotStatus: 184 if err = e.aclProvider.CheckACL(resources.Cscc_JoinBySnapshotStatus, "", sp); err != nil { 185 return shim.Error(fmt.Sprintf("access denied for [%s]: %s", fname, err)) 186 } 187 return e.joinBySnapshotStatus() 188 case GetConfigBlock: 189 // 2. check policy 190 if err = e.aclProvider.CheckACL(resources.Cscc_GetConfigBlock, string(args[1]), sp); err != nil { 191 return shim.Error(fmt.Sprintf("access denied for [%s][%s]: %s", fname, args[1], err)) 192 } 193 194 return e.getConfigBlock(args[1]) 195 case GetChannelConfig: 196 if len(args[1]) == 0 { 197 return shim.Error("empty channel name provided") 198 } 199 if err = e.aclProvider.CheckACL(resources.Cscc_GetChannelConfig, string(args[1]), sp); err != nil { 200 return shim.Error(fmt.Sprintf("access denied for [%s][%s]: %s", fname, args[1], err)) 201 } 202 return e.getChannelConfig(args[1]) 203 case GetChannels: 204 // 2. check get channels policy 205 if err = e.aclProvider.CheckACL(resources.Cscc_GetChannels, "", sp); err != nil { 206 return shim.Error(fmt.Sprintf("access denied for [%s]: %s", fname, err)) 207 } 208 209 return e.getChannels() 210 211 } 212 return shim.Error(fmt.Sprintf("Requested function %s not found.", fname)) 213 } 214 215 // validateConfigBlock validate configuration block to see whenever it's contains valid config transaction 216 func validateConfigBlock(block *common.Block, bccsp bccsp.BCCSP) error { 217 envelopeConfig, err := protoutil.ExtractEnvelope(block, 0) 218 if err != nil { 219 return errors.Errorf("Failed to %s", err) 220 } 221 222 configEnv := &common.ConfigEnvelope{} 223 _, err = protoutil.UnmarshalEnvelopeOfType(envelopeConfig, common.HeaderType_CONFIG, configEnv) 224 if err != nil { 225 return errors.Errorf("Bad configuration envelope: %s", err) 226 } 227 228 if configEnv.Config == nil { 229 return errors.New("Nil config envelope Config") 230 } 231 232 if configEnv.Config.ChannelGroup == nil { 233 return errors.New("Nil channel group") 234 } 235 236 if configEnv.Config.ChannelGroup.Groups == nil { 237 return errors.New("No channel configuration groups are available") 238 } 239 240 _, exists := configEnv.Config.ChannelGroup.Groups[channelconfig.ApplicationGroupKey] 241 if !exists { 242 return errors.Errorf("Invalid configuration block, missing %s "+ 243 "configuration group", channelconfig.ApplicationGroupKey) 244 } 245 246 // Check the capabilities requirement 247 if err = channelconfig.ValidateCapabilities(block, bccsp); err != nil { 248 return errors.Errorf("Failed capabilities check: [%s]", err) 249 } 250 251 return nil 252 } 253 254 // joinChain will join the specified chain in the configuration block. 255 // Since it is the first block, it is the genesis block containing configuration 256 // for this chain, so we want to update the Chain object with this info 257 func (e *PeerConfiger) joinChain( 258 channelID string, 259 block *common.Block, 260 deployedCCInfoProvider ledger.DeployedChaincodeInfoProvider, 261 lr plugindispatcher.LifecycleResources, 262 nr plugindispatcher.CollectionAndLifecycleResources, 263 ) pb.Response { 264 if err := e.peer.CreateChannel(channelID, block, deployedCCInfoProvider, lr, nr); err != nil { 265 return shim.Error(err.Error()) 266 } 267 268 return shim.Success(nil) 269 } 270 271 // JohnChainBySnapshot will join the channel by the specified snapshot. 272 func (e *PeerConfiger) JoinChainBySnapshot( 273 snapshotDir string, 274 deployedCCInfoProvider ledger.DeployedChaincodeInfoProvider, 275 lr plugindispatcher.LifecycleResources, 276 nr plugindispatcher.CollectionAndLifecycleResources, 277 ) pb.Response { 278 if err := e.peer.CreateChannelFromSnapshot(snapshotDir, deployedCCInfoProvider, lr, nr); err != nil { 279 return shim.Error(err.Error()) 280 } 281 282 return shim.Success(nil) 283 } 284 285 // Return the current configuration block for the specified channelID. If the 286 // peer doesn't belong to the channel, return error 287 func (e *PeerConfiger) getConfigBlock(channelID []byte) pb.Response { 288 if channelID == nil { 289 return shim.Error("ChannelID must not be nil.") 290 } 291 292 channel := e.peer.Channel(string(channelID)) 293 if channel == nil { 294 return shim.Error(fmt.Sprintf("Unknown channel ID, %s", string(channelID))) 295 } 296 block, err := peer.ConfigBlockFromLedger(channel.Ledger()) 297 if err != nil { 298 return shim.Error(err.Error()) 299 } 300 301 blockBytes, err := protoutil.Marshal(block) 302 if err != nil { 303 return shim.Error(err.Error()) 304 } 305 306 return shim.Success(blockBytes) 307 } 308 309 func (e *PeerConfiger) getChannelConfig(channelID []byte) pb.Response { 310 channel := e.peer.Channel(string(channelID)) 311 if channel == nil { 312 return shim.Error(fmt.Sprintf("unknown channel ID, %s", string(channelID))) 313 } 314 channelConfig, err := peer.RetrievePersistedChannelConfig(channel.Ledger()) 315 if err != nil { 316 return shim.Error(err.Error()) 317 } 318 319 channelConfigBytes, err := protoutil.Marshal(channelConfig) 320 if err != nil { 321 return shim.Error(err.Error()) 322 } 323 return shim.Success(channelConfigBytes) 324 } 325 326 // getChannels returns information about all channels for this peer 327 func (e *PeerConfiger) getChannels() pb.Response { 328 channelInfoArray := e.peer.GetChannelsInfo() 329 330 // add array with info about all channels for this peer 331 cqr := &pb.ChannelQueryResponse{Channels: channelInfoArray} 332 333 cqrbytes, err := proto.Marshal(cqr) 334 if err != nil { 335 return shim.Error(err.Error()) 336 } 337 338 return shim.Success(cqrbytes) 339 } 340 341 // joinBySnapshotStatus returns information about joinbysnapshot running status. 342 func (e *PeerConfiger) joinBySnapshotStatus() pb.Response { 343 status := e.peer.JoinBySnaphotStatus() 344 345 statusBytes, err := proto.Marshal(status) 346 if err != nil { 347 return shim.Error(err.Error()) 348 } 349 350 return shim.Success(statusBytes) 351 }