github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/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 "github.com/golang/protobuf/proto" 28 "github.com/hyperledger/fabric/core/chaincode/shim" 29 "github.com/hyperledger/fabric/core/peer" 30 pb "github.com/hyperledger/fabric/protos/peer" 31 "github.com/hyperledger/fabric/protos/utils" 32 "github.com/op/go-logging" 33 ) 34 35 // PeerConfiger implements the configuration handler for the peer. For every 36 // configuration transaction coming in from the ordering service, the 37 // committer calls this system chaincode to process the transaction. 38 type PeerConfiger struct { 39 } 40 41 var cnflogger = logging.MustGetLogger("chaincode") 42 43 // These are function names from Invoke first parameter 44 const ( 45 JoinChain string = "JoinChain" 46 UpdateConfigBlock string = "UpdateConfigBlock" 47 GetConfigBlock string = "GetConfigBlock" 48 GetChannels string = "GetChannels" 49 ) 50 51 // Init is called once per chain when the chain is created. 52 // This allows the chaincode to initialize any variables on the ledger prior 53 // to any transaction execution on the chain. 54 func (e *PeerConfiger) Init(stub shim.ChaincodeStubInterface) pb.Response { 55 cnflogger.Info("Init CSCC") 56 return shim.Success(nil) 57 } 58 59 // Invoke is called for the following: 60 // # to process joining a chain (called by app as a transaction proposal) 61 // # to get the current configuration block (called by app) 62 // # to update the configuration block (called by commmitter) 63 // Peer calls this function with 2 arguments: 64 // # args[0] is the function name, which must be JoinChain, GetConfigBlock or 65 // UpdateConfigBlock 66 // # args[1] is a configuration Block if args[0] is JoinChain or 67 // UpdateConfigBlock; otherwise it is the chain id 68 // TODO: Improve the scc interface to avoid marshal/unmarshal args 69 func (e *PeerConfiger) Invoke(stub shim.ChaincodeStubInterface) pb.Response { 70 args := stub.GetArgs() 71 72 if len(args) < 1 { 73 return shim.Error(fmt.Sprintf("Incorrect number of arguments, %d", len(args))) 74 } 75 76 fname := string(args[0]) 77 78 if fname != GetChannels && len(args) < 2 { 79 return shim.Error(fmt.Sprintf("Incorrect number of arguments, %d", len(args))) 80 } 81 82 cnflogger.Debugf("Invoke function: %s", fname) 83 84 // TODO: Handle ACL 85 86 if fname == JoinChain { 87 return joinChain(args[1]) 88 } else if fname == GetConfigBlock { 89 return getConfigBlock(args[1]) 90 } else if fname == UpdateConfigBlock { 91 return updateConfigBlock(args[1]) 92 } else if fname == GetChannels { 93 return getChannels() 94 } 95 96 return shim.Error(fmt.Sprintf("Requested function %s not found.", fname)) 97 } 98 99 // joinChain will join the specified chain in the configuration block. 100 // Since it is the first block, it is the genesis block containing configuration 101 // for this chain, so we want to update the Chain object with this info 102 func joinChain(blockBytes []byte) pb.Response { 103 if blockBytes == nil { 104 return shim.Error("Genesis block must not be nil.") 105 } 106 107 block, err := utils.GetBlockFromBlockBytes(blockBytes) 108 if err != nil { 109 return shim.Error(fmt.Sprintf("Failed to reconstruct the genesis block, %s", err)) 110 } 111 112 if err = peer.CreateChainFromBlock(block); err != nil { 113 return shim.Error(err.Error()) 114 } 115 116 chainID, err := utils.GetChainIDFromBlock(block) 117 if err != nil { 118 return shim.Error(fmt.Sprintf("Failed to get the chain ID from the configuration block, %s", err)) 119 } 120 121 peer.InitChain(chainID) 122 123 return shim.Success(nil) 124 } 125 126 func updateConfigBlock(blockBytes []byte) pb.Response { 127 if blockBytes == nil { 128 return shim.Error("Configuration block must not be nil.") 129 } 130 block, err := utils.GetBlockFromBlockBytes(blockBytes) 131 if err != nil { 132 return shim.Error(fmt.Sprintf("Failed to reconstruct the configuration block, %s", err)) 133 } 134 chainID, err := utils.GetChainIDFromBlock(block) 135 if err != nil { 136 return shim.Error(fmt.Sprintf("Failed to get the chain ID from the configuration block, %s", err)) 137 } 138 139 if err := peer.SetCurrConfigBlock(block, chainID); err != nil { 140 return shim.Error(err.Error()) 141 } 142 143 return shim.Success(nil) 144 } 145 146 // Return the current configuration block for the specified chainID. If the 147 // peer doesn't belong to the chain, return error 148 func getConfigBlock(chainID []byte) pb.Response { 149 if chainID == nil { 150 return shim.Error("ChainID must not be nil.") 151 } 152 block := peer.GetCurrConfigBlock(string(chainID)) 153 if block == nil { 154 return shim.Error(fmt.Sprintf("Unknown chain ID, %s", string(chainID))) 155 } 156 blockBytes, err := utils.Marshal(block) 157 if err != nil { 158 return shim.Error(err.Error()) 159 } 160 161 return shim.Success(blockBytes) 162 } 163 164 // getChannels returns information about all channels for this peer 165 func getChannels() pb.Response { 166 channelInfoArray := peer.GetChannelsInfo() 167 168 // add array with info about all channels for this peer 169 cqr := &pb.ChannelQueryResponse{Channels: channelInfoArray} 170 171 cqrbytes, err := proto.Marshal(cqr) 172 if err != nil { 173 return shim.Error(err.Error()) 174 } 175 176 return shim.Success(cqrbytes) 177 }