I'm new to smart contract developing, and trying to make it work for handling assets. My assets are called GOcerts.
I have used the token UTXO smart contract as a basis to start learning, and added changes and functions depending on my needs.
I have added an aditional function called ClaimGO(), which is supposed to delete the asset and create and store two new assets in the ledger. But function DeleteState and putState do not seem to be storing anything on the ledger, because when I query the ledger after calling the function, is like if nothing had changed the ledger state.
The implementation of the ClaimGO function is as follows:
//ClaimGO claims an amount X of GOcert Y. This function is implemented following the UTXO model
func (s *SmartContract) ClaimGO(ctx contractapi.TransactionContextInterface, goCertInputKey string, amount int) ([]GOCERT, error) {
//1. Get ID of submitting client identity
clientID, err := ctx.GetClientIdentity().GetID()
if err != nil {
return nil, fmt.Errorf("failed to get client id: %v", err)
}
//2. Validate GOcert input
goCertInputCompositeKey, err := ctx.GetStub().CreateCompositeKey("goCert", []string{clientID, goCertInputKey})
if err != nil {
return nil, fmt.Errorf("failed to create composite key: %v", err)
}
goCertInput := GOCERT{}
//2.1 Validate that client has a GOcert matching the input key
goCertAsBytes, err := ctx.GetStub().GetState(goCertInputCompositeKey)
if err != nil {
return nil, fmt.Errorf("failed to read goCertInputCompositeKey %s from world state: %v", goCertInputCompositeKey, err)
}
errr := json.Unmarshal(goCertAsBytes, &goCertInput)
if errr != nil {
return nil, fmt.Errorf("goCertInput %s not found for client %s: %v\n, gocertInput: %#v\n gocerAsbytes: %v", goCertInputKey, clientID, errr, goCertInput, goCertAsBytes)
}
txID := ctx.GetStub().GetTxID()
pbKey := goCertInput.ProdBatchKey
expDate := goCertInput.ExpirationDate
//erase previous GOcert
err = ctx.GetStub().DelState(goCertInputCompositeKey)
if err != nil {
return nil, err
}
log.Printf("goCertInput deleted: %+v", goCertInput)
var goCertOutputs []GOCERT
//goCertOutput1 is the GO with the cancelled amount
goCertOutput1 := GOCERT{}
goCertOutput1.Amount = amount
goCertOutput1.ExpirationDate = expDate
goCertOutput1.Owner = clientID
goCertOutput1.ProdBatchKey = pbKey
goCertOutput1.State = "Cancelled"
goCertOutput1.Key = fmt.Sprintf("%s.%d", txID, 0)
goCertOutputs = append(goCertOutputs, goCertOutput1)
goCertAsBytes, _ := json.Marshal(goCertOutput1)
goCertOutputCompositeKey, err := ctx.GetStub().CreateCompositeKey("goCert", []string{goCertOutput1.Owner, goCertOutput1.Key})
err = ctx.GetStub().PutState(goCertOutputCompositeKey, goCertAsBytes)
if err != nil {
return nil, err
}
log.Printf("goCertOutput created: %+v", goCertOutput1)
//goCertOutput 2 is the GO with the remaining amount that has not been claimed yet
goCertOutput2 := GOCERT{}
goCertOutput2.Amount = goCertInput.Amount - amount
goCertOutput2.ExpirationDate = expDate
goCertOutput2.Owner = clientID
goCertOutput2.ProdBatchKey = pbKey
goCertOutput2.State = "Issued"
goCertOutput2.Key = fmt.Sprintf("%s.%d", txID, 1)
goCertOutputs = append(goCertOutputs, goCertOutput2)
goCertAsBytes2, _ := json.Marshal(goCertOutput2)
goCertOutputCompositeKey2, err := ctx.GetStub().CreateCompositeKey("goCert", []string{goCertOutput2.Owner, goCertOutput2.Key})
err = ctx.GetStub().PutState(goCertOutputCompositeKey2, goCertAsBytes2)
if err != nil {
return nil, err
}
log.Printf("goCertOutput created: %+v", goCertOutput2)
return goCertOutputs, nil
}
I'm trying the smart contract with the Hyperledger Fabric test-network. Using the logspout tool, I can see that the two log messages are displayed, so I know that the code is being executed correctly. The issue is that, eve though it executes with no errors, the functions DeleteState and PutState are not actually changing anything on the ledger.
Any help on what could be the issue will be highly appreciated.
Thank you very much.
The ledger doesn't actually get updated until after a transaction is endorsed, submitted to the orderer, committed in a block, and distributed to peers so they can update their local ledger state. It is still possible for the transaction to fail to commit successfully after sending to the orderer if some endorsement requirements have not been met.
If you are using the peer chaincode query command to do your invocation, the transaction is not sent to the orderer so no ledger update occurs. If you are using the peer chaincode invoke command then the endorsed transaction will be sent to the orderer and update the ledger.
However, query commands following an invoke command will not see the ledger update caused by the invoke until the peer they execute on has received the committed block from the orderer and updated its local ledger state. To have the peer chaincode invoke command wait for transactions to be committed in peer ledgers before exiting, use the --waitForEvent command-line flag.
Run peer chaincode invoke --help for details of the available command-line flags.
Related
While trying to run the msgraph-sdk-go training code from here: https://github.com/microsoftgraph/msgraph-training-go, I'm getting InvalidAuthenticationTokenmsg: Access token is empty while executing the Graph API calls.
I configured a Microsoft developer account with instant sandbox for trial purpose.
I created an app registration as mentioned in the tutorial here and granted required permissions for the app.
The code is able to get the AppToken, but for calls to get Users, it fails with the above error. Am I missing something here?
I tried below code from the example for msgraph-training
func (g *GraphHelper) InitializeGraphForAppAuth() error {
clientId := os.Getenv("CLIENT_ID")
tenantId := os.Getenv("TENANT_ID")
clientSecret := os.Getenv("CLIENT_SECRET")
credential, err := azidentity.NewClientSecretCredential(tenantId, clientId, clientSecret, nil)
if err != nil {
return err
}
g.clientSecretCredential = credential
// Create an auth provider using the credential
authProvider, err := auth.NewAzureIdentityAuthenticationProviderWithScopes(g.clientSecretCredential, []string{
"https://graph.microsoft.com/.default",
})
if err != nil {
return err
}
// Create a request adapter using the auth provider
adapter, err := msgraphsdk.NewGraphRequestAdapter(authProvider)
if err != nil {
return err
}
// Create a Graph client using request adapter
client := msgraphsdk.NewGraphServiceClient(adapter)
g.appClient = client
return nil
}
// This part works, and I get the AppToken with required scope, once decoded.
func (g *GraphHelper) GetAppToken() (*string, error) {
token, err := g.clientSecretCredential.GetToken(context.Background(), policy.TokenRequestOptions{
Scopes: []string{
"https://graph.microsoft.com/.default",
},
})
if err != nil {
return nil, err
}
fmt.Println("expires on : ", token.ExpiresOn)
return &token.Token, nil
}
// The GetUsers function errors out
func (g *GraphHelper) GetUsers() (models.UserCollectionResponseable, error) {
var topValue int32 = 25
query := users.UsersRequestBuilderGetQueryParameters{
// Only request specific properties
Select: []string{"displayName", "id", "mail"},
// Get at most 25 results
Top: &topValue,
// Sort by display name
Orderby: []string{"displayName"},
}
resp, err := g.appClient.Users().
Get(context.Background(),
&users.UsersRequestBuilderGetRequestConfiguration{
QueryParameters: &query,
})
if err != nil {
fmt.Println("Users.Get got Error", err.Error(), resp)
printOdataError(err)
}
resp, err = g.appClient.Users().
Get(context.Background(),
nil)
if err != nil {
fmt.Println("Users.Get got Error with nil", err.Error(), resp)
}
return resp, err
}
I have added the User.Read.All permission in the app as mentioned in the tutorial.
Instead of getting the list of users, I'm getting below error:
Users.Get got Error error status code received from the API <nil>
error: error status code received from the API
code: InvalidAuthenticationTokenmsg: Access token is empty.Users.Get got Error with nil error status code received from the API <nil>
As you are using client Credential Flow ,you can verify your permission in azure portal , if you have User.Read.All delegated permission , Removes the delegated ones and add the corresponding application ones and don't forget to click on grant administrator consent after that. It should then work.
Hope this helps
Thanks.
Okay, so the fix that did work for me after trial and error was a version mismatch in the example and the actual application I was trying out.
The version of the beta msgraph application I was using was v0.49, whereas the msgraphsdk tutorial was using v0.48. The go mod command picked up the latest v0.49 initially I guess, I updated the go.mod file to use v0.48 after looking at the go.mod file from msgraph-training repository and things started working.
Hope this helps someone else later on.
I'd like to connect from Go to the running instance of the Memgraph database. I'm using Docker and I've installed the Memgraph Platform. What exactly do I need to do?
The procedure for connecting fro Go to Memgraph is rather simple. For this you need to use Bolt protocol. Here are the needed steps:
First, create a new directory for your app, /MyApp, and position yourself in it. Next, create a program.go file with the following code:
package main
import (
"fmt"
"github.com/neo4j/neo4j-go-driver/v4/neo4j"
)
func main() {
dbUri := "bolt://localhost:7687"
driver, err := neo4j.NewDriver(dbUri, neo4j.BasicAuth("username", "password", ""))
if err != nil {
panic(err)
}
// Handle driver lifetime based on your application lifetime requirements driver's lifetime is usually
// bound by the application lifetime, which usually implies one driver instance per application
defer driver.Close()
item, err := insertItem(driver)
if err != nil {
panic(err)
}
fmt.Printf("%v\n", item.Message)
}
func insertItem(driver neo4j.Driver) (*Item, error) {
// Sessions are short-lived, cheap to create and NOT thread safe. Typically create one or more sessions
// per request in your web application. Make sure to call Close on the session when done.
// For multi-database support, set sessionConfig.DatabaseName to requested database
// Session config will default to write mode, if only reads are to be used configure session for
// read mode.
session := driver.NewSession(neo4j.SessionConfig{})
defer session.Close()
result, err := session.WriteTransaction(createItemFn)
if err != nil {
return nil, err
}
return result.(*Item), nil
}
func createItemFn(tx neo4j.Transaction) (interface{}, error) {
records, err := tx.Run(
"CREATE (a:Greeting) SET a.message = $message RETURN 'Node ' + id(a) + ': ' + a.message",
map[string]interface{}{"message": "Hello, World!"})
// In face of driver native errors, make sure to return them directly.
// Depending on the error, the driver may try to execute the function again.
if err != nil {
return nil, err
}
record, err := records.Single()
if err != nil {
return nil, err
}
// You can also retrieve values by name, with e.g. `id, found := record.Get("n.id")`
return &Item{
Message: record.Values[0].(string),
}, nil
}
type Item struct {
Message string
}
Now, create a go.mod file using the go mod init example.com/hello command.
I've mentioned the Bolt driver earlier. You need to add it with go get github.com/neo4j/neo4j-go-driver/v4#v4.3.1. You can run your program with go run .\program.go.
The complete documentation is located at Memgraph site.
I am trying to deploy a contract on Hedera; the file is 9766 bytes, so I created a file and appended the contract to it, but now I get the error "exceptional receipt status: ERROR_DECODING_BYTESTRING: error retrieving contract creation record". I believe I did something wrong in my code. Any help will be appreciated.
package blockchain
import (
"encoding/json"
"fmt"
"io/ioutil"
"github.com/.../scanner/env"
"github.com/hashgraph/hedera-sdk-go/v2"
)
type contract struct {
Abi string `json:"abi"`
Bin string `json:"bin"`
}
type contracts struct {
Contracts map[string]contract `json:"contracts"`
Version string `json:"version"`
}
func DeployContract() {
var client *hedera.Client
var err error
// Retrieving network type from environment variable HEDERA_NETWORK
client, err = hedera.ClientForName(env.GetEnv["HEDERA_NETWORK"])
if err != nil {
println(err.Error(), ": error creating client")
return
}
// Retrieving operator ID from environment variable OPERATOR_ID
operatorAccountID, err := hedera.AccountIDFromString(env.GetEnv["OPERATOR_ID"])
if err != nil {
println(err.Error(), ": error converting string to AccountID")
return
}
// Retrieving operator key from environment variable OPERATOR_KEY
operatorKey, err := hedera.PrivateKeyFromString(env.GetEnv["OPERATOR_KEY"])
if err != nil {
println(err.Error(), ": error converting string to PrivateKey")
return
}
// Setting the client operator ID and key
client.SetOperator(operatorAccountID, operatorKey)
// Make sure to close client after running
defer func() {
err = client.Close()
if err != nil {
println(err.Error(), ": error closing client")
return
}
}()
// Read in the compiled contract from contract.json
rawSmartContract, err := ioutil.ReadFile("./contract/contract.json")
if err != nil {
println(err.Error(), ": error reading contract.json")
return
}
// Initialize contracts
var smartContract contracts = contracts{}
// Parse the rawSmartContract into smartContract
err = json.Unmarshal([]byte(rawSmartContract), &smartContract)
if err != nil {
println(err.Error(), ": error unmarshaling")
return
}
// Retrieve the bytecode from the parsed smart contract
smartContractByteCode := smartContract.Contracts["contract.sol:ScanInput"].Bin
//output contract bytecode size
fmt.Printf("Contract bytecode size: %v bytes\n", len(smartContractByteCode))
// Create a new file
newFileResponse, err := hedera.NewFileCreateTransaction().
// Accepts both Key and []Key
// All keys at the top level of a key list must sign to create or modify the file. Any one of
// the keys at the top level key list can sign to delete the file.
SetKeys(client.GetOperatorPublicKey()).
// Basic starting file content
SetContents([]byte("Initializing file.")).
SetMemo("go file append test").
// Set max fee if we don't want to get overcharged
SetMaxTransactionFee(hedera.NewHbar(2)).
Execute(client)
if err != nil {
println(err.Error(), ": error creating file")
return
}
// Get receipt to make sure the transaction worked
receipt, err := newFileResponse.GetReceipt(client)
if err != nil {
println(err.Error(), ": error retrieving file creation receipt")
return
}
// Retrieve file ID from the receipt
fileID := *receipt.FileID
// File append
fileResponse, err := hedera.NewFileAppendTransaction().
// Make sure the node is the same as the new file, as we don't have to wait for propagation
SetNodeAccountIDs([]hedera.AccountID{newFileResponse.NodeID}).
// File ID to append to
SetFileID(fileID).
// Contents that will be appended to the end of the file
SetContents([]byte(smartContractByteCode)).
// Set max transaction when you are not sure how much it will cost.
SetMaxTransactionFee(hedera.NewHbar(5)).
Execute(client)
if err != nil {
println(err.Error(), ": error executing file append transaction")
return
}
// Checking if transaction went through
receipt, err = fileResponse.GetReceipt(client)
if err != nil {
println(err.Error(), ": error retrieving file append transaction receipt")
return
}
// Checking if append succeeded
println(receipt.Status.String())
info, err := hedera.NewFileInfoQuery().
// Once again same node account ID
SetNodeAccountIDs([]hedera.AccountID{fileResponse.NodeID}).
// Only the file ID is required for this
SetFileID(fileID).
Execute(client)
if err != nil {
println(err.Error(), ": error executing file info query")
return
}
println("File size according to `FileInfoQuery`:", info.Size)
println("File memo according to `FileInfoQuery`:", info.FileMemo)
// Retrieve the receipt to make sure the transaction went through and to get bytecode file ID
byteCodeTransactionReceipt, err := newFileResponse.GetReceipt(client)
if err != nil {
println(err.Error(), ": error getting file create transaction receipt")
return
}
// Retrieve bytecode file ID from the receipt
byteCodeFileID := *byteCodeTransactionReceipt.FileID
fmt.Printf("contract bytecode file: %v\n", byteCodeFileID)
// Instantiate the contract instance
contractTransactionID, err := hedera.NewContractCreateTransaction().
// Set gas to create the contract
// Failing to set this to a sufficient amount will result in "INSUFFICIENT_GAS" status
SetGas(100000).
// The contract bytecode must be set to the file ID containing the contract bytecode
SetBytecodeFileID(byteCodeFileID).
// Set the admin key on the contract in case the contract should be deleted or
// updated in the future
SetAdminKey(client.GetOperatorPublicKey()).
Execute(client)
if err != nil {
println(err.Error(), ": error creating contract")
return
}
// Get the new contract record to make sure the transaction ran successfully
contractRecord, err := contractTransactionID.GetRecord(client)
if err != nil {
println(err.Error(), ": error retrieving contract creation record")
return
}
// Get the contract create result from the record
contractCreateResult, err := contractRecord.GetContractCreateResult()
if err != nil {
println(err.Error(), ": error retrieving contract creation result")
return
}
// Get the new contract ID from the receipt contained in the record
newContractID := *contractRecord.Receipt.ContractID
fmt.Printf("Contract create gas used: %v\n", contractCreateResult.GasUsed)
fmt.Printf("Contract create transaction fee: %v\n", contractRecord.TransactionFee)
fmt.Printf("contract: %v\n", newContractID)
}
Solidity Contract: https://drive.google.com/file/d/1YQ5B9Z2CL4i3R_4eSS3OQSEAbzSooehr/view?usp=sharing
I think I responded to this in Discord, but here goes for completion. I think the issue is that your code looks for Bin in the Json when it's bin.
Switch
smartContractByteCode := smartContract.Contracts["contract.sol:ScanInput"].Bin
for
smartContractByteCode := smartContract.Contracts["contract.sol:ScanInput"].bin
I use an interface to interact with my entGO repository. But I have a problem: I'm using the CRUD model to design my repository, and I want to know if I need to use Transaction to create a user and then generate a token. I need to do that with Transaction to roll back in case of failure. My problem is I can only use my client at a repository level. What is the best manner to handle the transaction? Do I need to create a custom function to handle the Transaction or design my function to take transaction parameters? Here is an example of what I have:
// mariaUserRepository is data/repository implementation
// of service layer UserRepository
type mariaUserRepository struct {
Client *ent.Client
}
// NewUserRepository is a factory for initializing User Repositories
func NewUserRepository(client *ent.Client) models.UserRepository {
return &mariaUserRepository{
Client: client,
}
}
// Create reaches out to database entGO api
func (r *mariaUserRepository) Create(ctx context.Context, u *ent.User) error {
// check if a user already exist
check, err := r.Client.User.
Query().
Where(user.Email(u.Email)).Exist(ctx)
if err != nil {
utils.Logger.Info("Error when checking user",
zap.String("email", u.Email),
zap.Error(err),
)
return handle_errors.NewInternal()
}
if check {
err := handle_errors.NewConflict("email", u.Email)
utils.Logger.Info("Error when Register User",
zap.String("email", u.Email),
zap.Error(err),
)
return err
}
if u, err = r.Client.User.
Create().
SetFirstName(u.FirstName).
SetLastName(u.LastName).
SetEmail(u.Email).
SetGender(u.Gender).
SetUserType(u.UserType).
SetPasswordHash(u.PasswordHash).
Save(ctx); err != nil {
utils.Logger.Info("Error when create user",
zap.Any("User", u),
zap.Error(err),
)
return handle_errors.NewInternal()
}
return nil
}
My problem come from the comment that say to implement rollback in case of failure.
err := h.UserService.Signup(ctx, u)
if err != nil {
log.Printf("Failed to sign up user: %v\n", err.Error())
c.JSON(apperrors.Status(err), gin.H{
"error": err,
})
return
}
// create token pair as strings
tokens, err := h.TokenService.NewPairFromUser(ctx, u, "")
if err != nil {
log.Printf("Failed to create tokens for user: %v\n", err.Error())
// may eventually implement rollback logic here
// meaning, if we fail to create tokens after creating a user,
// we make sure to clear/delete the created user in the database
c.JSON(apperrors.Status(err), gin.H{
"error": err,
})
return
}
```
I'm deploying some kubernetes object with a client of type dynamic.Interface during the creation of these object, kubernetes return this information.
I0530 17:31:13.728423 8992 request.go:665] Waited for 1.144205975s due to client-side throttling, not priority and fairness, request: GET:https://xx.xx.xx.xx:6443/apis/batch/v1beta1
I0530 17:31:23.729687 8992 request.go:665] Waited for 6.377372125s due to client-side throttling, not priority and fairness, request: GET:https://xx.xx.xx.xx:6443/apis/snapshot.storage.k8s.io/v1beta1
There are useful but the package display them without asking me the permission and I want to controll that. Is there a way to delete them, and get a string or en error, or at least increase the log level to display. I instantiate the dynamic client like this:
config, err := buildConfigFromFlags(context, kubeconfig)
if err != nil {
return nil, fmt.Errorf("Cannot create the config to communicate with kuberntes, %s", err)
}
dclient, err := dynamic.NewForConfig(config)
if err != nil {
return nil, fmt.Errorf("Cannot login into kubernetes (DClient): %s", err)
}
Thanks