github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/core/scc/cscc/configure.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 cscc chaincode configer provides functions to manage 18 // configuration transactions as the network is being reconfigured. The 19 // configuration transactions arrive from the ordering service to the committer 20 // who calls this chaincode. The chaincode also provides peer configuration 21 // services such as joining a chain or getting configuration data. 22 package cscc 23 24 import ( 25 "fmt" 26 27 "errors" 28 29 "github.com/golang/protobuf/proto" 30 "github.com/hyperledger/fabric/common/flogging" 31 "github.com/hyperledger/fabric/common/policies" 32 "github.com/hyperledger/fabric/core/chaincode/shim" 33 "github.com/hyperledger/fabric/core/peer" 34 "github.com/hyperledger/fabric/core/policy" 35 "github.com/hyperledger/fabric/events/producer" 36 "github.com/hyperledger/fabric/msp/mgmt" 37 pb "github.com/hyperledger/fabric/protos/peer" 38 "github.com/hyperledger/fabric/protos/utils" 39 ) 40 41 // PeerConfiger implements the configuration handler for the peer. For every 42 // configuration transaction coming in from the ordering service, the 43 // committer calls this system chaincode to process the transaction. 44 type PeerConfiger struct { 45 policyChecker policy.PolicyChecker 46 } 47 48 var cnflogger = flogging.MustGetLogger("cscc") 49 50 // These are function names from Invoke first parameter 51 const ( 52 JoinChain string = "JoinChain" 53 UpdateConfigBlock string = "UpdateConfigBlock" 54 GetConfigBlock string = "GetConfigBlock" 55 GetChannels string = "GetChannels" 56 ) 57 58 // Init is called once per chain when the chain is created. 59 // This allows the chaincode to initialize any variables on the ledger prior 60 // to any transaction execution on the chain. 61 func (e *PeerConfiger) Init(stub shim.ChaincodeStubInterface) pb.Response { 62 cnflogger.Info("Init CSCC") 63 64 // Init policy checker for access control 65 e.policyChecker = policy.NewPolicyChecker( 66 peer.NewChannelPolicyManagerGetter(), 67 mgmt.GetLocalMSP(), 68 mgmt.NewLocalMSPPrincipalGetter(), 69 ) 70 71 return shim.Success(nil) 72 } 73 74 // Invoke is called for the following: 75 // # to process joining a chain (called by app as a transaction proposal) 76 // # to get the current configuration block (called by app) 77 // # to update the configuration block (called by commmitter) 78 // Peer calls this function with 2 arguments: 79 // # args[0] is the function name, which must be JoinChain, GetConfigBlock or 80 // UpdateConfigBlock 81 // # args[1] is a configuration Block if args[0] is JoinChain or 82 // UpdateConfigBlock; otherwise it is the chain id 83 // TODO: Improve the scc interface to avoid marshal/unmarshal args 84 func (e *PeerConfiger) Invoke(stub shim.ChaincodeStubInterface) pb.Response { 85 args := stub.GetArgs() 86 87 if len(args) < 1 { 88 return shim.Error(fmt.Sprintf("Incorrect number of arguments, %d", len(args))) 89 } 90 91 fname := string(args[0]) 92 93 if fname != GetChannels && len(args) < 2 { 94 return shim.Error(fmt.Sprintf("Incorrect number of arguments, %d", len(args))) 95 } 96 97 cnflogger.Debugf("Invoke function: %s", fname) 98 99 // Handle ACL: 100 // 1. get the signed proposal 101 sp, err := stub.GetSignedProposal() 102 if err != nil { 103 return shim.Error(fmt.Sprintf("Failed getting signed proposal from stub: [%s]", err)) 104 } 105 106 switch fname { 107 case JoinChain: 108 // 2. check local MSP Admins policy 109 if err = e.policyChecker.CheckPolicyNoChannel(mgmt.Admins, sp); err != nil { 110 cid, e := utils.GetChainIDFromBlockBytes(args[1]) 111 errorString := fmt.Sprintf("\"JoinChain\" request failed authorization check "+ 112 "for channel [%s]: [%s]", cid, err) 113 if e != nil { 114 errorString = fmt.Sprintf("\"JoinChain\" request failed authorization [%s] and unable "+ 115 "to extract channel id from the block due to [%s]", err, e) 116 } 117 return shim.Error(errorString) 118 } 119 120 return joinChain(args[1]) 121 case GetConfigBlock: 122 // 2. check the channel reader policy 123 if err = e.policyChecker.CheckPolicy(string(args[1]), policies.ChannelApplicationReaders, sp); err != nil { 124 return shim.Error(fmt.Sprintf("\"GetConfigBlock\" request failed authorization check for channel [%s]: [%s]", args[1], err)) 125 } 126 return getConfigBlock(args[1]) 127 case UpdateConfigBlock: 128 // TODO: It needs to be clarified if this is a function invoked by a proposal or not. 129 // The issue is the following: ChannelApplicationAdmins might require multiple signatures 130 // but currently a proposal can be signed by a signle entity only. Therefore, the ChannelApplicationAdmins policy 131 // will be never satisfied. 132 133 return updateConfigBlock(args[1]) 134 case GetChannels: 135 // 2. check local MSP Members policy 136 if err = e.policyChecker.CheckPolicyNoChannel(mgmt.Members, sp); err != nil { 137 return shim.Error(fmt.Sprintf("\"GetChannels\" request failed authorization check: [%s]", err)) 138 } 139 140 return getChannels() 141 142 } 143 return shim.Error(fmt.Sprintf("Requested function %s not found.", fname)) 144 } 145 146 // joinChain will join the specified chain in the configuration block. 147 // Since it is the first block, it is the genesis block containing configuration 148 // for this chain, so we want to update the Chain object with this info 149 func joinChain(blockBytes []byte) pb.Response { 150 if blockBytes == nil { 151 return shim.Error("Genesis block must not be nil.") 152 } 153 154 block, err := utils.GetBlockFromBlockBytes(blockBytes) 155 if err != nil { 156 return shim.Error(fmt.Sprintf("Failed to reconstruct the genesis block, %s", err)) 157 } 158 159 if err = peer.CreateChainFromBlock(block); err != nil { 160 return shim.Error(err.Error()) 161 } 162 163 chainID, err := utils.GetChainIDFromBlock(block) 164 if err != nil { 165 return shim.Error(fmt.Sprintf("Failed to get the chain ID from the configuration block, %s", err)) 166 } 167 168 peer.InitChain(chainID) 169 170 if err := producer.SendProducerBlockEvent(block); err != nil { 171 cnflogger.Errorf("Error sending block event %s", err) 172 } 173 174 return shim.Success(nil) 175 } 176 177 func getChannelFromConfigBlock(blockBytes []byte) (string, error) { 178 if blockBytes == nil { 179 return "", errors.New("Configuration block must not be nil.") 180 } 181 block, err := utils.GetBlockFromBlockBytes(blockBytes) 182 if err != nil { 183 return "", fmt.Errorf("Failed to reconstruct the configuration block, %s", err) 184 } 185 chainID, err := utils.GetChainIDFromBlock(block) 186 if err != nil { 187 return "", fmt.Errorf("Failed to get the chain ID from the configuration block, %s", err) 188 } 189 return chainID, nil 190 } 191 192 func updateConfigBlock(blockBytes []byte) pb.Response { 193 if blockBytes == nil { 194 return shim.Error("Configuration block must not be nil.") 195 } 196 block, err := utils.GetBlockFromBlockBytes(blockBytes) 197 if err != nil { 198 return shim.Error(fmt.Sprintf("Failed to reconstruct the configuration block, %s", err)) 199 } 200 chainID, err := utils.GetChainIDFromBlock(block) 201 if err != nil { 202 return shim.Error(fmt.Sprintf("Failed to get the chain ID from the configuration block, %s", err)) 203 } 204 205 if err := peer.SetCurrConfigBlock(block, chainID); err != nil { 206 207 return shim.Error(err.Error()) 208 } 209 210 return shim.Success(nil) 211 } 212 213 // Return the current configuration block for the specified chainID. If the 214 // peer doesn't belong to the chain, return error 215 func getConfigBlock(chainID []byte) pb.Response { 216 if chainID == nil { 217 return shim.Error("ChainID must not be nil.") 218 } 219 block := peer.GetCurrConfigBlock(string(chainID)) 220 if block == nil { 221 return shim.Error(fmt.Sprintf("Unknown chain ID, %s", string(chainID))) 222 } 223 blockBytes, err := utils.Marshal(block) 224 if err != nil { 225 return shim.Error(err.Error()) 226 } 227 228 return shim.Success(blockBytes) 229 } 230 231 // getChannels returns information about all channels for this peer 232 func getChannels() pb.Response { 233 channelInfoArray := peer.GetChannelsInfo() 234 235 // add array with info about all channels for this peer 236 cqr := &pb.ChannelQueryResponse{Channels: channelInfoArray} 237 238 cqrbytes, err := proto.Marshal(cqr) 239 if err != nil { 240 return shim.Error(err.Error()) 241 } 242 243 return shim.Success(cqrbytes) 244 }