Based on hyperledger SDK doc, we can use nodeJS SDK to query for the block and the transaction info. Is it possible to use this SDK to query the latest world state, e.g, query the value for a given key?
To being able to query for latest world state your chaincode has to provide this capability, namely you have to implement this logic and incorporate it into your chaincode. Then it will simply require to execute the chaincode to get the value for the key you are interested it.
For example you can do something similar to this:
package main
import (
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/protos/peer"
)
// Person
type Asset struct {
ID string `json:"id"`
Name string `json:"name"`
Price string `json:"price"`
}
// assetManagement the chaincode interface implementation to manage
// the ledger of person records
type assetManagement struct {
}
func (p *assetManagement) Init(stub shim.ChaincodeStubInterface) peer.Response {
return shim.Success(nil)
}
func (p *assetManagement) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
actionName, params := stub.GetFunctionAndParameters()
if actionName == "addAsset" {
return p.addAsset(stub)
} else if actionName == "getAsset" {
return p.getAsset(stub)
}
return shim.Error("Unknown function name")
}
func (p *assetManagement) getAsset(stub shim.ChaincodeStubInterface) peer.Response {
_, params := stub.GetFunctionAndParameters()
assetID := params[0]
state, err := stub.GetState(assetID)
if err != nil {
return shim.Error(fmt.Sprintf("%s", err))
}
return shim.Success(state)
}
func (p *assetManagement) addAsset(stub shim.ChaincodeStubInterface) peer.Response {
// TODO add loggic adding new asset
}
func main() {
err := shim.Start(new(assetManagement))
if err != nil {
fmt.Printf("Error starting Simple chaincode: %s", err)
}
}
Next all you need is to invoke chaincode passing function name getAsset with asset ID and will get latest state for that asset. Here is the code based on Go SDK:
// Skipped initialization.
txRequest := apitxn.ChaincodeInvokeRequest{
Targets: []apitxn.ProposalProcessor{p},
Fcn: "getAsset",
Args: []string{"42"},
TransientMap: map[string][]byte{},
ChaincodeID: "assetChaincode",
}
proposalResponse, _, err := ch.SendTransactionProposal(txRequest)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%v\n", proposalResponse[0].ProposalResponse)
tx, err := ch.CreateTransaction(proposalResponse)
if err != nil {
fmt.Println(err)
return
}
txResponse, err := ch.SendTransaction(tx)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(txResponse[0])
Related
I would like to list all images from Azure registry via Golang.
What I founded is this: https://github.com/Azure-Samples/azure-sdk-for-go-samples/tree/main/sdk/resourcemanager/containerregistry but nothing from there seems to help me.
Any ideas please?
LE:
I ended up with this code
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"net/url"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/runtime/2019-08-15-preview/containerregistry"
"github.com/Azure/go-autorest/autorest"
)
type ACRTokenProvider struct {
accessToken string
}
func (a *ACRTokenProvider) OAuthToken() string {
return a.accessToken
}
func newACRAuthorizer() (*autorest.BearerAuthorizer, error) {
tenantId := "TENANT_ID"
acrService := "servicename.azurecr.io"
cred, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
panic(err)
}
ctx := context.Background()
aadToken, err := cred.GetToken(ctx, policy.TokenRequestOptions{Scopes: []string{"https://management.azure.com/"}})
if err != nil {
panic(err)
}
formData := url.Values{
"grant_type": {"access_token"},
"service": {acrService},
"tenant": {tenantId},
"access_token": {aadToken.Token},
}
jsonResponse, err := http.PostForm(fmt.Sprintf("https://%s/oauth2/exchange", acrService), formData)
if err != nil {
panic(err)
}
var response map[string]interface{}
json.NewDecoder(jsonResponse.Body).Decode(&response)
return autorest.NewBearerAuthorizer(&ACRTokenProvider{accessToken: fmt.Sprint(response["refresh_token"])}), nil
}
func main() {
client := containerregistry.NewRepositoryClient("https://servicename.azurecr.io")
authorizer, err := newACRAuthorizer()
if err != nil {
fmt.Println(err)
}
client.Authorizer = authorizer
// Do what you need to do with client here
attributes, err := client.GetList(context.Background(), "registryName", nil)
if err != nil {
log.Printf("Error while fetching attributes, %v ", err)
}
fmt.Print(attributes)
}
But the response is this
Original Error: autorest/azure: Service returned an error. Status=401 Code="Unknown" Message="Unknown service error" Details=[{"errors":[{"code":"UNAUTHORIZED","detail":[{"Action":"*","Name":"catalog","Type":"registry"}],"message":"authentication required, visit https://aka.ms/acr/authorization for more information."}]}]
What I'm missing?
i'm not sure about the GO SDK, but you can always consume the REST API directly:
GET https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.ContainerRegistry/registries?api-version=2019-05-01
https://learn.microsoft.com/en-us/rest/api/containerregistry/registries/list?tabs=HTTP
I am seeing this when querying data from implicit private data collection.
Please see code snippet below.
When I query individual key (using QueryBidPrivate/GetPrivateData), I get corresponding data.
But if I query the complete collection (using GetPrivateDataByRange(collection, "", "")), I get nothing from the Iterator.
peer chaincode query -C mychannel -n govtcontract -c '{"function":"QueryBidPrivate","Args":["100", "1035"]}'
{"bidamt":100,"biddate":"2022-05-04","contractid":"1035","salt":"4567ab4567","vendorid":"100"}
peer chaincode query -C mychannel -n govtcontract -c '{"function":"ListAllBids","Args":[]}'
No output
Is there anything I am missing here ?
// ListAllBids returns all Bids details from private state
func (s *SmartContract) ListAllBids(ctx contractapi.TransactionContextInterface) ([]VendorBid, error) {
// Get client org id and verify it matches peer org id.
// In this scenario, client is only authorized to read/write private data from its own peer.
clientOrgID, err := getClientOrgID(ctx, true)
if err != nil {
return nil, fmt.Errorf("failed to get verified OrgID: %s", err.Error())
}
collection := "_implicit_org_" + clientOrgID
BidIterator, err := ctx.GetStub().GetPrivateDataByRange(collection, "", "")
if err != nil {
logger.Infof("ListAllBids error: %s", err.Error())
return nil, fmt.Errorf("failed to read bid list : %s", err.Error())
}
if BidIterator == nil {
logger.Infof("ListAllBids : null iterator ")
return nil, fmt.Errorf("bid private details does not exist ")
}
defer BidIterator.Close()
logger.Infof("ListAllBids in govtcontract: no error")
var allbids []VendorBid
myMSPID, err := ctx.GetClientIdentity().GetMSPID()
logger.Infof("myMSPID: %s", myMSPID)
for BidIterator.HasNext() {
logger.Infof("Iterator has element: ")
entrybid, err := BidIterator.Next()
if err != nil {
return nil, err
}
var bidvar VendorBid
err = json.Unmarshal(entrybid.Value, &bidvar)
if err != nil {
return nil, err
}
allbids = append(allbids, bidvar)
logger.Infof("Iterator element: %s", entrybid.Value)
}
return allbids, nil
}
=========================================
// QueryBidPrivate returns the Bid details from owner's private data collection
func (s *SmartContract) QueryBidPrivate(ctx contractapi.TransactionContextInterface, vendorId string, contractId string) (string, error) {
// Get client org id and verify it matches peer org id.
// In this scenario, client is only authorized to read/write private data from its own peer.
clientOrgID, err := getClientOrgID(ctx, true)
if err != nil {
return "", fmt.Errorf("failed to get verified OrgID: %s", err.Error())
}
collection := "_implicit_org_" + clientOrgID
bidconkey, err := ctx.GetStub().CreateCompositeKey(vendorId, []string{contractId})
bidDetails, err := ctx.GetStub().GetPrivateData(collection, bidconkey)
if err != nil {
return "", fmt.Errorf("failed to read bid private properties from client org's collection: %s", err.Error())
}
if bidDetails == nil {
return "", fmt.Errorf("bid private details does not exist in client org's collection: %s", contractId)
}
return string(bidDetails), nil
}
GetPrivateDataByPartialCompositeKey() is the function for querying a range of private data that was stored using a composite key. GetPrivateDataByRange() won't retrieve the data stored with a composite key. I think in the above code snippet you have to replace the function call GetPrivateDataByRange(collection, "", "") with GetPrivateDataByPartialCompositeKey(collection, vendorId, []string{})
Sample usage can be found here.
I faced the same error in the smart contract. The issue here is because of storing data on the composite key.
Instead of below code :
for BidIterator.HasNext() {
logger.Infof("Iterator has element: ")
entrybid, err := BidIterator.Next()
if err != nil {
return nil, err
}
var bidvar VendorBid
err = json.Unmarshal(entrybid.Value, &bidvar)
if err != nil {
return nil, err
}
allbids = append(allbids, bidvar)
logger.Infof("Iterator element: %s", entrybid.Value)
}
Use the below function
func constructQueryResponseFromIterator(resultsIterator shim.StateQueryIteratorInterface)
(*bytes.Buffer, error)
{
// buffer is a JSON array containing QueryResults
var buffer bytes.Buffer
buffer.WriteString("[")
bArrayMemberAlreadyWritten := false
for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next()
if err != nil {
return nil, err
}
// Add a comma before array members, suppress it for the first array member
if bArrayMemberAlreadyWritten == true {
buffer.WriteString(",")
}
buffer.WriteString("{")
//buffer.WriteString("{\"Key\":")
//buffer.WriteString("\"")
//buffer.WriteString(queryResponse.Key)
//buffer.WriteString("\"")
buffer.WriteString(", \"Record\":")
// Record is a JSON object, so we write as-is
buffer.WriteString(string(queryResponse.Value))
buffer.WriteString("}")
bArrayMemberAlreadyWritten = true
}
buffer.WriteString("]")
return &buffer, nil
}
I have written the chaincode its in local system, now i need to install chaincode in hyperledger fabric peers.How it is done from local system to install the chaincode to my peer node. below code is taken from hyperledger fabric chaincode example.please suggest me
package main
import (
"fmt"
"strconv"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos/peer"
)
// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface)
pb.Response {
fmt.Println("ex02 Init")
_, 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())
}
return shim.Success(nil)
}
You can install the chaincode in several ways
NodeSDK
JavaSDK
CLI
I would suggest you try with CLI first, fabric-samples has one example.
Behind the seen fabric compile and only binary file will be deployed to the peer
I'm getting an error when I invoke a chaincode function. I've created two adaptations for the function. One uses a regular key, the other a composite key. I thought that using a composite key would solve any MVCC_READ_CONFLICT's since I'm no longer updating the same key.
However I get the error on both functions. Note that both function are contained in the same chaincode. I don't know if that can cause conflicts.
Here's the function with a regular key:
func (*AddTokenCallFunction) Start(stub shim.ChaincodeStubInterface, args []string) pb.Response {
if len(args) != 2 {
s := fmt.Sprintf(ERROR_INCORRECT_AMOUNT_OF_ARGUMENTS, "add-tokens", 2, len(args))
return shim.Error(s)
}
account := args[0]
tokens := args[1]
currentTokensBytes, err := stub.GetState(account)
if err != nil {
s := fmt.Sprintf(ERROR_SYSTEM, err.Error())
return shim.Error(s)
}
currentAmountOfTokens := binary.LittleEndian.Uint64(currentTokensBytes)
tokensToAdd, err := strconv.ParseUint(tokens, 10, 64)
if err != nil {
s := fmt.Sprintf(ERROR_SYSTEM, err.Error())
return shim.Error(s)
}
currentAmountOfTokens += tokensToAdd
tokenBytes, err := UintToBytes(currentAmountOfTokens)
if err != nil {
s := fmt.Sprintf(ERROR_SYSTEM, err.Error())
return shim.Error(s)
}
err = stub.PutState(account, tokenBytes)
if err != nil {
s := fmt.Sprintf(ERROR_SYSTEM, err.Error())
return shim.Error(s)
}
return shim.Success(nil)
}
Here's the same function but with a composite-key:
func (*AddTokenCompositeCallFunction) Start(stub shim.ChaincodeStubInterface, args []string) pb.Response {
if len(args) != 2 {
s := fmt.Sprintf(ERROR_INCORRECT_AMOUNT_OF_ARGUMENTS, "add-composite-tokens", 2, len(args))
return shim.Error(s)
}
account := args[0]
tokens := args[1]
// Retrieve info needed for the update procedure
txid := stub.GetTxID()
compositeIndexaccount := "account~tokens~txID"
// Create the composite key that will allow us to query for all deltas on a particular variable
compositeKey, compositeErr := stub.CreateCompositeKey(compositeIndexaccount, []string{account, tokens, txid})
if compositeErr != nil {
return shim.Error(fmt.Sprintf("Could not create a composite key for %s: %s", account, compositeErr.Error()))
}
// Save the composite key index
compositePutErr := stub.PutState(compositeKey, []byte{0x00})
if compositePutErr != nil {
return shim.Error(fmt.Sprintf("Could not put operation for %s in the ledger: %s", account, compositePutErr.Error()))
}
return shim.Success([]byte(fmt.Sprintf("Successfully added %s to %s", tokens, account)))
}
Could someone explain why I'm still getting a MVCC_READ_CONFLICT on the later implementation? What am I doing wrong? I'm benchmarking and sending the same accountID several times. Though I was under the impression that this would not matter when using a composite-key.
Thanks in advance.
I resolved this issue by removing my own implementation and replacing it with the one from the high-throughput sample [ https://github.com/hyperledger/fabric-samples/blob/release/high-throughput/chaincode/high-throughput.go ].
My guess is that I'm doing something in my implementation that Golang does not agree with. Since the implementations are not that different.
I am learning how to use Hyperledger Fabric DLT framework.
I am building an application that allows a seller of Tuna to transact with a buyer at a discount without compromising the marker price at which the seller sells to other buyers.
Problem: However each time a execute the code this message is thrown
2018-01-14 18:45:11.292 EST [shim] SetupChaincodeLogging -> INFO 001 Chaincode log level not provided; defaulting to: INFO
2018-01-14 18:45:11.292 EST [shim] SetupChaincodeLogging -> INFO 002 Chaincode (build level: ) starting up ...
This is the error that I constantly get each time I run the code:
Error creating new Smart Contract: Error chaincode id not providedeloiim:fabric_
This is the code I created
package main
import ( "github.com/hyperledger/fabric/core/chaincode/shim"; sc"github.com/hyperledger/fabric/protos/peer"; "bytes"; "encoding/json"; "strconv"; "fmt"; )
type SmartContract struct {
}
type Tuna struct {
TxID int `json:"txid"`
Container string `json:"container"`
Timestamp string `json:"timestamp"`
Location string `json:"location"`
Owner string `json:"owner"`
}
changeTunaHolder - As the tuna fish is passed to different parties in the supply chain, the data in the world state can be updated with who has possession. The changeTunaHolder method takes in 2 arguments, tuna id and new holder name.
I suspect the error is with the changeTunaHolder method given that it takes the id and Owner fields
func (S_ *SmartContract) changeTunaHolder(APIstub shim.ChaincodeStubInterface, parameters []string) sc.Response {
if len(parameters) != 2 {
return shim.Error("Incorrect number of arguments. Expecting 2")
}
tunaAsBytes, _ := APIstub.GetState(parameters[0])
if tunaAsBytes == nil {
return shim.Error("Could not locate tuna")
}
TUNA := Tuna{}
json.Unmarshal(tunaAsBytes, &TUNA)
// Normally check that the specified argument is a valid holder of tuna
// we are skipping this check for this example
TUNA.Owner = parameters[1]
tunaAsBytes, _ = json.Marshal(TUNA)
_error := APIstub.PutState(parameters[0], tunaAsBytes)
if _error != nil {
return shim.Error(fmt.Sprintf("Failed to change tuna holder: %s", parameters[0]))
}
return shim.Success(nil)
}
Init METHOD - In this the code attempts to retrieve the requested Smart Contract function and arguments
func (S_ *SmartContract) Init(APIstub shim.ChaincodeStubInterface) sc.Response {
return shim.Success(nil)
}
func (S_ *SmartContract ) Invoke(APIstub shim.ChaincodeStubInterface) sc.Response {
function, parameters := APIstub.GetFunctionAndParameters()
if function == "queryTuna" {
return S_.queryTuna(APIstub, parameters)
} else if function == "initLedger"{
return S_.initLedger(APIstub)
} else if function == "recordTuna" {
return S_.recordTuna(APIstub, parameters)
} else if function == "changeTunaHolder" {
return S_.changeTunaHolder(APIstub, parameters)
}
return shim.Error("Invalid Smart Contract function name.")
}
queryTuna - The queryTuna method would be used by a fisherman, regulator, or restaurateur to view the record of one particular tuna. It takes one argument - the key for the tuna in question.
func (S_ *SmartContract) queryTuna(APIstub shim.ChaincodeStubInterface, parameters []string) sc.Response {
if len(parameters) != 1{
return shim.Error("Incorrect number of arguments. Expecting 1")
}
tunaAsBytes, _ := APIstub.GetState(parameters[0])
if tunaAsBytes == nil {
return shim.Error("Could not locate tuna")
}
return shim.Success(tunaAsBytes)
}
initLedger - The initLedger method will add test data to our network.
func (S_ *SmartContract) initLedger(APIstub shim.ChaincodeStubInterface) sc.Response{
TUNA := []Tuna {
Tuna{TxID: 1,Container: "923F", Location: "67.0006, -70.5476", Timestamp: "1504054225", Owner: "Miriam"},
Tuna{TxID: 2,Container: "M83T", Location: "91.2395, -49.4594", Timestamp: "1504057825", Owner: "Dave"},
Tuna{TxID: 3,Container: "T012", Location: "58.0148, 59.01391", Timestamp: "1493517025", Owner: "Igor"},
Tuna{TxID: 4,Container: "P490", Location: "-45.0945, 0.7949", Timestamp: "1496105425", Owner: "Amalea"},
Tuna{TxID: 5,Container: "S439", Location: "-107.6043, 19.5003", Timestamp: "1493512301", Owner: "Rafa"},
Tuna{TxID: 6,Container: "J205", Location: "-155.2304, -15.8723", Timestamp: "1494117101", Owner: "Shen"},
Tuna{TxID: 7,Container: "S22L", Location: "103.8842, 22.1277", Timestamp: "1496104301", Owner: "Leila"},
Tuna{TxID: 8,Container: "EI89", Location: "-132.3207, -34.0983", Timestamp: "1485066691", Owner: "Yuan"},
Tuna{TxID: 9,Container: "129R", Location: "153.0054, 12.6429", Timestamp: "1485153091", Owner: "Carlo"},
Tuna{TxID: 10,Container: "49W4", Location: "51.9435, 8.2735", Timestamp: "1487745091", Owner: "Fatima"},
}
iter := 0
for iter < len(TUNA) {
println("iter is", iter)
tunaAsBytes, _ := json.Marshal(TUNA[iter])
APIstub.PutState(strconv.Itoa(iter+1), tunaAsBytes)
fmt.Println("ADDED", TUNA[iter])
iter += 1
}
return shim.Success(nil)
}
recordTuna - The recordTuna method is the method a fisherman like Sarah would use to record each of her tuna catches. This method takes in five arguments (attributes to be saved in the ledger).
func (S_ *SmartContract) recordTuna(APIstub shim.ChaincodeStubInterface, parameters[]string) sc.Response {
if len(parameters) != 5 {
return shim.Error("Incorrect number of arguments. Expecting 5")
}
TUNA := Tuna{Container:parameters[1], Location:parameters[2], Timestamp:parameters[3], Owner:parameters[4]}
tunaAsBytes, _:=json.Marshal(TUNA)
_error := APIstub.PutState(parameters[0], tunaAsBytes)
if _error != nil {
return shim.Error(fmt.Sprintf("Failed to record tuna catch: %s", parameters[0]))
}
return shim.Success(nil)
}
queryAllTuna - The queryAllTuna method allows for assessing all the records; in this case, all the Tuna records added to the ledger. This method does not take any arguments. It will return a JSON string containing the results.
func (S_ *SmartContract) queryAllTuna(APIstub shim.ChaincodeStubInterface) sc.Response {
init_key := "0"
end_key := "999"
results_iterator, _error := APIstub.GetStateByRange(init_key, end_key)
if _error != nil {
return shim.Error(_error.Error())
}
defer results_iterator.Close()
var buffer bytes.Buffer
buffer.WriteString("[")
b_array_member_already_written := false
for results_iterator.HasNext() {
query_response, _error := results_iterator.Next()
if _error != nil {
return shim.Error(_error.Error())
}
if b_array_member_already_written == true {
buffer.WriteString(",")
}
buffer.WriteString("{\"Key\":")
buffer.WriteString("\"")
buffer.WriteString(query_response.Key)
buffer.WriteString("\"")
buffer.WriteString(", \"Record\":")
buffer.WriteString(string(query_response.Value))
buffer.WriteString("}")
b_array_member_already_written = true
}
buffer.WriteString("]")
fmt.Printf("- queryAllTuna:\n%s\n", buffer.String())
return shim.Success(buffer.Bytes())
}
MAIN FUNCTION
func main() {
_error := shim.Start(new(SmartContract))
if _error != nil {
fmt.Printf("Error creating new Smart Contract: %s", _error)
}
}
have you tried to go with the terminal in chaincode-docker-devmode?
cd fabric-samples/chaincode-docker-devmode
as in Chaincode for Developers
Me I got the same error when I forgot to jump in the repository
And make sure to put the version in CORE_CHAINCODE_ID_NAME (e.g: CORE_CHAINCODE_ID_NAME=mycc:0)