github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/examples/chaincode/go/asset_management_interactive/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_mgm") 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 // Create ownership table 51 err := stub.CreateTable("AssetsOwnership", []*shim.ColumnDefinition{ 52 &shim.ColumnDefinition{Name: "Asset", Type: shim.ColumnDefinition_STRING, Key: true}, 53 &shim.ColumnDefinition{Name: "Owner", Type: shim.ColumnDefinition_BYTES, Key: false}, 54 }) 55 if err != nil { 56 return shim.Error("Failed creating AssetsOnwership table.") 57 } 58 59 // Set the admin 60 // The metadata will contain the certificate of the administrator 61 adminCert, err := stub.GetCallerMetadata() 62 if err != nil { 63 myLogger.Debug("Failed getting metadata") 64 return shim.Error("Failed getting metadata.") 65 } 66 if len(adminCert) == 0 { 67 myLogger.Debug("Invalid admin certificate. Empty.") 68 return shim.Error("Invalid admin certificate. Empty.") 69 } 70 71 myLogger.Debug("The administrator is [%x]", adminCert) 72 73 stub.PutState("admin", adminCert) 74 75 myLogger.Debug("Init Chaincode...done") 76 77 return shim.Success(nil) 78 } 79 80 func (t *AssetManagementChaincode) assign(stub shim.ChaincodeStubInterface, args []string) pb.Response { 81 myLogger.Debug("Assign...") 82 83 if len(args) != 2 { 84 return shim.Error("Incorrect number of arguments. Expecting 2") 85 } 86 87 asset := args[0] 88 owner, err := base64.StdEncoding.DecodeString(args[1]) 89 if err != nil { 90 return shim.Error("Failed decodinf owner") 91 } 92 93 // Verify the identity of the caller 94 // Only an administrator can invoker assign 95 adminCertificate, err := stub.GetState("admin") 96 if err != nil { 97 return shim.Error("Failed fetching admin identity") 98 } 99 100 ok, err := t.isCaller(stub, adminCertificate) 101 if err != nil { 102 return shim.Error("Failed checking admin identity") 103 } 104 if !ok { 105 return shim.Error("The caller is not an administrator") 106 } 107 108 // Register assignment 109 myLogger.Debugf("New owner of [%s] is [% x]", asset, owner) 110 111 ok, err = stub.InsertRow("AssetsOwnership", shim.Row{ 112 Columns: []*shim.Column{ 113 &shim.Column{Value: &shim.Column_String_{String_: asset}}, 114 &shim.Column{Value: &shim.Column_Bytes{Bytes: owner}}}, 115 }) 116 117 if !ok && err == nil { 118 return shim.Error("Asset was already assigned.") 119 } 120 121 if err != nil { 122 return shim.Error(err.Error()) 123 } 124 125 myLogger.Debug("Assign...done!") 126 127 return shim.Success(nil) 128 } 129 130 func (t *AssetManagementChaincode) transfer(stub shim.ChaincodeStubInterface, args []string) pb.Response { 131 myLogger.Debug("Transfer...") 132 133 if len(args) != 2 { 134 return shim.Error("Incorrect number of arguments. Expecting 2") 135 } 136 137 asset := args[0] 138 newOwner, err := base64.StdEncoding.DecodeString(args[1]) 139 if err != nil { 140 return shim.Error("Failed decoding owner") 141 } 142 143 // Verify the identity of the caller 144 // Only the owner can transfer one of his assets 145 var columns []shim.Column 146 col1 := shim.Column{Value: &shim.Column_String_{String_: asset}} 147 columns = append(columns, col1) 148 149 row, err := stub.GetRow("AssetsOwnership", columns) 150 if err != nil { 151 return shim.Error(fmt.Sprintf("Failed retrieving asset [%s]: [%s]", asset, err)) 152 } 153 154 prvOwner := row.Columns[1].GetBytes() 155 myLogger.Debugf("Previous owener of [%s] is [% x]", asset, prvOwner) 156 if len(prvOwner) == 0 { 157 return shim.Error("Invalid previous owner. Nil") 158 } 159 160 // Verify ownership 161 ok, err := t.isCaller(stub, prvOwner) 162 if err != nil { 163 return shim.Error("Failed checking asset owner identity") 164 } 165 if !ok { 166 return shim.Error("The caller is not the owner of the asset") 167 } 168 169 // At this point, the proof of ownership is valid, then register transfer 170 err = stub.DeleteRow( 171 "AssetsOwnership", 172 []shim.Column{shim.Column{Value: &shim.Column_String_{String_: asset}}}, 173 ) 174 if err != nil { 175 return shim.Error("Failed deliting row.") 176 } 177 178 _, err = stub.InsertRow( 179 "AssetsOwnership", 180 shim.Row{ 181 Columns: []*shim.Column{ 182 &shim.Column{Value: &shim.Column_String_{String_: asset}}, 183 &shim.Column{Value: &shim.Column_Bytes{Bytes: newOwner}}, 184 }, 185 }) 186 if err != nil { 187 return shim.Error("Failed inserting row.") 188 } 189 190 myLogger.Debug("New owner of [%s] is [% x]", asset, newOwner) 191 192 myLogger.Debug("Transfer...done") 193 194 return shim.Success(nil) 195 } 196 197 func (t *AssetManagementChaincode) isCaller(stub shim.ChaincodeStubInterface, certificate []byte) (bool, error) { 198 myLogger.Debug("Check caller...") 199 200 // In order to enforce access control, we require that the 201 // metadata contains the signature under the signing key corresponding 202 // to the verification key inside certificate of 203 // the payload of the transaction (namely, function name and args) and 204 // the transaction binding (to avoid copying attacks) 205 206 // Verify \sigma=Sign(certificate.sk, tx.Payload||tx.Binding) against certificate.vk 207 // \sigma is in the metadata 208 209 sigma, err := stub.GetCallerMetadata() 210 if err != nil { 211 return false, errors.New("Failed getting metadata") 212 } 213 payload, err := stub.GetArgsSlice() 214 if err != nil { 215 return false, errors.New("Failed getting payload") 216 } 217 binding, err := stub.GetBinding() 218 if err != nil { 219 return false, errors.New("Failed getting binding") 220 } 221 222 myLogger.Debugf("passed certificate [% x]", certificate) 223 myLogger.Debugf("passed sigma [% x]", sigma) 224 myLogger.Debugf("passed payload [% x]", payload) 225 myLogger.Debugf("passed binding [% x]", binding) 226 227 ok, err := impl.NewAccessControlShim(stub).VerifySignature( 228 certificate, 229 sigma, 230 append(payload, binding...), 231 ) 232 if err != nil { 233 myLogger.Errorf("Failed checking signature [%s]", err) 234 return ok, err 235 } 236 if !ok { 237 myLogger.Error("Invalid signature") 238 } 239 240 myLogger.Debug("Check caller...Verified!") 241 242 return ok, err 243 } 244 245 // Invoke will be called for every transaction. 246 // Supported functions are the following: 247 // "assign(asset, owner)": to assign ownership of assets. An asset can be owned by a single entity. 248 // Only an administrator can call this function. 249 // "transfer(asset, newOwner)": to transfer the ownership of an asset. Only the owner of the specific 250 // asset can call this function. 251 // An asset is any string to identify it. An owner is representated by one of his ECert/TCert. 252 func (t *AssetManagementChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { 253 function, args := stub.GetFunctionAndParameters() 254 // Handle different functions 255 if function == "assign" { 256 // Assign ownership 257 return t.assign(stub, args) 258 } else if function == "transfer" { 259 // Transfer ownership 260 return t.transfer(stub, args) 261 } 262 263 return shim.Error("Received unknown function invocation") 264 } 265 266 // Query callback representing the query of a chaincode 267 // Supported functions are the following: 268 // "query(asset)": returns the owner of the asset. 269 // Anyone can invoke this function. 270 func (t *AssetManagementChaincode) Query(stub shim.ChaincodeStubInterface) pb.Response { 271 function, args := stub.GetFunctionAndParameters() 272 myLogger.Debugf("Query [%s]", function) 273 274 if function != "query" { 275 return shim.Error("Invalid query function name. Expecting 'query' but found '" + function + "'") 276 } 277 278 var err error 279 280 if len(args) != 1 { 281 myLogger.Debug("Incorrect number of arguments. Expecting name of an asset to query") 282 return shim.Error("Incorrect number of arguments. Expecting name of an asset to query") 283 } 284 285 // Who is the owner of the asset? 286 asset := args[0] 287 288 myLogger.Debugf("Arg [%s]", string(asset)) 289 290 var columns []shim.Column 291 col1 := shim.Column{Value: &shim.Column_String_{String_: asset}} 292 columns = append(columns, col1) 293 294 row, err := stub.GetRow("AssetsOwnership", columns) 295 if err != nil { 296 myLogger.Debugf("Failed retriving asset [%s]: [%s]", string(asset), err) 297 return shim.Error(fmt.Sprintf("Failed retriving asset [%s]: [%s]", string(asset), err)) 298 } 299 300 myLogger.Debugf("Query done [% x]", row.Columns[1].GetBytes()) 301 302 return shim.Success(row.Columns[1].GetBytes()) 303 } 304 305 func main() { 306 primitives.SetSecurityLevel("SHA3", 256) 307 err := shim.Start(new(AssetManagementChaincode)) 308 if err != nil { 309 fmt.Printf("Error starting AssetManagementChaincode: %s", err) 310 } 311 }