github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/examples/chaincode/go/asset_management/asset_management.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 main 18 19 import ( 20 "encoding/base64" 21 "errors" 22 "fmt" 23 24 "github.com/hyperledger/fabric/accesscontrol/impl" 25 "github.com/hyperledger/fabric/core/chaincode/shim" 26 "github.com/hyperledger/fabric/core/crypto/primitives" 27 pb "github.com/hyperledger/fabric/protos/peer" 28 "github.com/op/go-logging" 29 ) 30 31 var myLogger = logging.MustGetLogger("asset_mgmt") 32 33 // AssetManagementChaincode is simple chaincode implementing a basic Asset Management system 34 // with access control enforcement at chaincode level. 35 // Look here for more information on how to implement access control at chaincode level: 36 // https://github.com/hyperledger/fabric/blob/master/docs/tech/application-ACL.md 37 // An asset is simply represented by a string. 38 type AssetManagementChaincode struct { 39 } 40 41 // Init method will be called during deployment. 42 // The deploy transaction metadata is supposed to contain the administrator cert 43 func (t *AssetManagementChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { 44 _, args := stub.GetFunctionAndParameters() 45 myLogger.Debug("Init Chaincode...") 46 if len(args) != 0 { 47 return shim.Error("Incorrect number of arguments. Expecting 0") 48 } 49 50 // Set the admin 51 // The metadata will contain the certificate of the administrator 52 adminCert, err := stub.GetCallerMetadata() 53 if err != nil { 54 myLogger.Debug("Failed getting metadata") 55 return shim.Error("Failed getting metadata.") 56 } 57 if len(adminCert) == 0 { 58 myLogger.Debug("Invalid admin certificate. Empty.") 59 return shim.Error("Invalid admin certificate. Empty.") 60 } 61 62 myLogger.Debug("The administrator is [%x]", adminCert) 63 64 stub.PutState("admin", adminCert) 65 66 myLogger.Debug("Init Chaincode...done") 67 68 return shim.Success(nil) 69 } 70 71 func (t *AssetManagementChaincode) assign(stub shim.ChaincodeStubInterface, args []string) pb.Response { 72 myLogger.Debug("Assign...") 73 74 if len(args) != 2 { 75 return shim.Error("Incorrect number of arguments. Expecting 2") 76 } 77 78 asset := args[0] 79 owner, err := base64.StdEncoding.DecodeString(args[1]) 80 if err != nil { 81 return shim.Error("Failed decodinf owner") 82 } 83 84 // Verify the identity of the caller 85 // Only an administrator can invoker assign 86 adminCertificate, err := stub.GetState("admin") 87 if err != nil { 88 return shim.Error("Failed fetching admin identity") 89 } 90 91 ok, err := t.isCaller(stub, adminCertificate) 92 if err != nil { 93 return shim.Error("Failed checking admin identity") 94 } 95 if !ok { 96 return shim.Error("The caller is not an administrator") 97 } 98 99 currentOwner, err := stub.GetState(asset) 100 if len(currentOwner) > 0 && err == nil { 101 return shim.Error("Asset was already assigned.") 102 } 103 104 // Register assignment 105 myLogger.Debugf("New owner of [%s] is [% x]", asset, owner) 106 err = stub.PutState(asset, owner) 107 108 myLogger.Debug("Assign...done!") 109 110 return shim.Success(nil) 111 } 112 113 func (t *AssetManagementChaincode) transfer(stub shim.ChaincodeStubInterface, args []string) pb.Response { 114 myLogger.Debug("Transfer...") 115 116 if len(args) != 2 { 117 return shim.Error("Incorrect number of arguments. Expecting 2") 118 } 119 120 asset := args[0] 121 newOwner, err := base64.StdEncoding.DecodeString(args[1]) 122 if err != nil { 123 return shim.Error("Failed decoding owner") 124 } 125 126 // Verify the identity of the caller 127 // Only the owner can transfer one of his assets 128 prvOwner, err := stub.GetState(asset) 129 if err != nil { 130 return shim.Error(fmt.Sprintf("Failed retrieving asset [%s]: [%s]", asset, err)) 131 } 132 133 myLogger.Debugf("Previous owener of [%s] is [% x]", asset, prvOwner) 134 if len(prvOwner) == 0 { 135 return shim.Error("Invalid previous owner. Nil") 136 } 137 138 // Verify ownership 139 ok, err := t.isCaller(stub, prvOwner) 140 if err != nil { 141 return shim.Error("Failed checking asset owner identity") 142 } 143 if !ok { 144 return shim.Error("The caller is not the owner of the asset") 145 } 146 147 // At this point, the proof of ownership is valid, then register transfer 148 err = stub.PutState(asset, newOwner) 149 if err != nil { 150 return shim.Error("Failed inserting row.") 151 } 152 153 myLogger.Debug("New owner of [%s] is [% x]", asset, newOwner) 154 155 myLogger.Debug("Transfer...done") 156 157 return shim.Success(nil) 158 } 159 160 func (t *AssetManagementChaincode) isCaller(stub shim.ChaincodeStubInterface, certificate []byte) (bool, error) { 161 myLogger.Debug("Check caller...") 162 163 // In order to enforce access control, we require that the 164 // metadata contains the signature under the signing key corresponding 165 // to the verification key inside certificate of 166 // the payload of the transaction (namely, function name and args) and 167 // the transaction binding (to avoid copying attacks) 168 169 // Verify \sigma=Sign(certificate.sk, tx.Payload||tx.Binding) against certificate.vk 170 // \sigma is in the metadata 171 172 sigma, err := stub.GetCallerMetadata() 173 if err != nil { 174 return false, errors.New("Failed getting metadata") 175 } 176 payload, err := stub.GetArgsSlice() 177 if err != nil { 178 return false, errors.New("Failed getting payload") 179 } 180 binding, err := stub.GetBinding() 181 if err != nil { 182 return false, errors.New("Failed getting binding") 183 } 184 185 myLogger.Debugf("passed certificate [% x]", certificate) 186 myLogger.Debugf("passed sigma [% x]", sigma) 187 myLogger.Debugf("passed payload [% x]", payload) 188 myLogger.Debugf("passed binding [% x]", binding) 189 190 ok, err := impl.NewAccessControlShim(stub).VerifySignature( 191 certificate, 192 sigma, 193 append(payload, binding...), 194 ) 195 if err != nil { 196 myLogger.Errorf("Failed checking signature [%s]", err) 197 return ok, err 198 } 199 if !ok { 200 myLogger.Error("Invalid signature") 201 } 202 203 myLogger.Debug("Check caller...Verified!") 204 205 return ok, err 206 } 207 208 // Invoke will be called for every transaction. 209 // Supported functions are the following: 210 // "assign(asset, owner)": to assign ownership of assets. An asset can be owned by a single entity. 211 // Only an administrator can call this function. 212 // "transfer(asset, newOwner)": to transfer the ownership of an asset. Only the owner of the specific 213 // asset can call this function. 214 // An asset is any string to identify it. An owner is representated by one of his ECert/TCert. 215 func (t *AssetManagementChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { 216 function, args := stub.GetFunctionAndParameters() 217 // Handle different functions 218 if function == "assign" { 219 // Assign ownership 220 return t.assign(stub, args) 221 } else if function == "transfer" { 222 // Transfer ownership 223 return t.transfer(stub, args) 224 } else if function == "query" { 225 // Query owner 226 return t.query(stub, args) 227 } 228 229 return shim.Error("Received unknown function invocation") 230 } 231 232 // Supported functions are the following: 233 // "query(asset)": returns the owner of the asset. 234 // Anyone can invoke this function. 235 func (t *AssetManagementChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response { 236 var err error 237 238 if len(args) != 1 { 239 myLogger.Debug("Incorrect number of arguments. Expecting name of an asset to query") 240 return shim.Error("Incorrect number of arguments. Expecting name of an asset to query") 241 } 242 243 // Who is the owner of the asset? 244 asset := args[0] 245 246 myLogger.Debugf("Query [%s]", string(asset)) 247 248 owner, err := stub.GetState(asset) 249 if err != nil { 250 myLogger.Debugf("Failed retriving asset [%s]: [%s]", string(asset), err) 251 return shim.Error(fmt.Sprintf("Failed retriving asset [%s]: [%s]", string(asset), err)) 252 } 253 254 myLogger.Debugf("Query done [% x]", owner) 255 256 return shim.Success([]byte(base64.StdEncoding.EncodeToString(owner))) 257 } 258 259 func main() { 260 primitives.SetSecurityLevel("SHA3", 256) 261 err := shim.Start(new(AssetManagementChaincode)) 262 if err != nil { 263 fmt.Printf("Error starting AssetManagementChaincode: %s", err) 264 } 265 }