/* Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package simple import ( "fmt" "os" "strconv" "github.com/hyperledger/fabric-chaincode-go/shim" pb "github.com/hyperledger/fabric-protos-go/peer" ) // SimpleChaincode example simple Chaincode implementation type SimpleChaincode struct{} func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { fmt.Println("Init invoked") _, args := stub.GetFunctionAndParameters() var A, B string // Entities var Aval, Bval int // Asset holdings var err error if len(args) != 4 { return shim.Error("Incorrect number of arguments. Expecting 4") } // Initialize the chaincode A = args[0] Aval, err = strconv.Atoi(args[1]) if err != nil { return shim.Error("Expecting integer value for asset holding") } B = args[2] Bval, err = strconv.Atoi(args[3]) if err != nil { return shim.Error("Expecting integer value for asset holding") } fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) // Write the state to the ledger err = stub.PutState(A, []byte(strconv.Itoa(Aval))) if err != nil { return shim.Error(err.Error()) } err = stub.PutState(B, []byte(strconv.Itoa(Bval))) if err != nil { return shim.Error(err.Error()) } fmt.Println("Init returning with success") return shim.Success(nil) } func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { fmt.Println("ex02 Invoke") if os.Getenv("DEVMODE_ENABLED") != "" { fmt.Println("invoking in devmode") } function, args := stub.GetFunctionAndParameters() switch function { case "invoke": // Make payment of X units from A to B return t.invoke(stub, args) case "delete": // Deletes an entity from its state return t.delete(stub, args) case "query": // the old "Query" is now implemented in invoke return t.query(stub, args) case "respond": // return with an error return t.respond(stub, args) case "mspid": // Checks the shim's GetMSPID() API return t.mspid(args) case "event": return t.event(stub, args) case "issue": return t.issue(stub, args) default: return shim.Error(`Invalid invoke function name. Expecting "invoke", "delete", "query", "respond", "mspid", or "event"`) } } // Transaction makes payment of X units from A to B func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response { var A, B string // Entities var Aval, Bval int // Asset holdings var X int // Transaction value var err error if len(args) != 3 { return shim.Error("Incorrect number of arguments. Expecting 3") } A = args[0] B = args[1] // Get the state from the ledger // TODO: will be nice to have a GetAllState call to ledger Avalbytes, err := stub.GetState(A) if err != nil { return shim.Error("Failed to get state") } if Avalbytes == nil { return shim.Error("Entity not found") } Aval, _ = strconv.Atoi(string(Avalbytes)) Bvalbytes, err := stub.GetState(B) if err != nil { return shim.Error("Failed to get state") } if Bvalbytes == nil { return shim.Error("Entity not found") } Bval, _ = strconv.Atoi(string(Bvalbytes)) // Perform the execution X, err = strconv.Atoi(args[2]) if err != nil { return shim.Error("Invalid transaction amount, expecting a integer value") } Aval = Aval - X Bval = Bval + X fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) // Write the state back to the ledger err = stub.PutState(A, []byte(strconv.Itoa(Aval))) if err != nil { return shim.Error(err.Error()) } err = stub.PutState(B, []byte(strconv.Itoa(Bval))) if err != nil { return shim.Error(err.Error()) } return shim.Success(nil) } // Deletes an entity from state func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 1 { return shim.Error("Incorrect number of arguments. Expecting 1") } A := args[0] // Delete the key from the state in ledger err := stub.DelState(A) if err != nil { return shim.Error("Failed to delete state") } return shim.Success(nil) } // query callback representing the query of a chaincode func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response { var A string // Entities var err error if len(args) != 1 { return shim.Error("Incorrect number of arguments. Expecting name of the person to query") } A = args[0] // Get the state from the ledger Avalbytes, err := stub.GetState(A) if err != nil { jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}" return shim.Error(jsonResp) } if Avalbytes == nil { jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}" return shim.Error(jsonResp) } jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}" fmt.Printf("Query Response:%s\n", jsonResp) return shim.Success(Avalbytes) } // respond simply generates a response payload from the args func (t *SimpleChaincode) respond(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 3 { return shim.Error("expected three arguments") } status, err := strconv.ParseInt(args[0], 10, 32) if err != nil { return shim.Error(err.Error()) } message := args[1] payload := []byte(args[2]) return pb.Response{ Status: int32(status), Message: message, Payload: payload, } } // mspid simply calls shim.GetMSPID() to verify the mspid was properly passed from the peer // via the CORE_PEER_LOCALMSPID env var func (t *SimpleChaincode) mspid(args []string) pb.Response { if len(args) != 0 { return shim.Error("expected no arguments") } // Get the mspid from the env var mspid, err := shim.GetMSPID() if err != nil { jsonResp := "{\"Error\":\"Failed to get mspid\"}" return shim.Error(jsonResp) } if mspid == "" { jsonResp := "{\"Error\":\"Empty mspid\"}" return shim.Error(jsonResp) } fmt.Printf("MSPID:%s\n", mspid) return shim.Success([]byte(mspid)) } // event emits a chaincode event func (t *SimpleChaincode) event(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 2 { return shim.Error("Incorrect number of arguments. Expecting 2") } if err := stub.SetEvent(args[0], []byte(args[1])); err != nil { return shim.Error(err.Error()) } return shim.Success(nil) } // Issue asset holding. Can only be done once. func (t *SimpleChaincode) issue(stub shim.ChaincodeStubInterface, args []string) pb.Response { fmt.Printf("Entry: issue\n") if len(args) != 2 { return shim.Error("Incorrect number of arguments. Expecting 2") } A := args[0] val, err := stub.GetState(A) if !(val == nil && err == nil) { return shim.Error(fmt.Sprintf("Asset already exists: %s", A)) } Aval, err := strconv.Atoi(args[1]) if err != nil { return shim.Error("Expecting integer value for asset holding") } fmt.Printf("Issue: %s = %d\n", A, Aval) err = stub.PutState(A, []byte(strconv.Itoa(Aval))) if err != nil { return shim.Error(err.Error()) } return shim.Success(nil) }