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  }