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
Related
I pasted a section of code that was supposed to catch an AllTopologyNodesDownError error which doesn't work and I have no idea why.
func (sc *ServerConfig) addNodesToCluster(store *ravendb.DocumentStore) error {
clusterTopology, err := sc.getClusterTopology(store)
if errors.Is(err, &ravendb.AllTopologyNodesDownError{}) {
for _, url := range sc.Url.List {
err = addNodeToCluster(store, url)
if err != nil {
return err
}
}
} else if err != nil {
return err
}
the structure of the ravendb.AllTopologyNodesDownError is
// AllTopologyNodesDownError represents "all topology nodes are down" error
type AllTopologyNodesDownError struct {
errorBase
}
type errorBase struct {
wrapped error
ErrorStr string
}
screen shot of the error when debugging the code
errors.Is() is used to tell if any error in the chain is the same instance as the provided error1, that can never be the case here because you provided a literal of your error type, no other code could hold that instance or a reference to it.
Your error looks like a type, to tell if any error in the chain is a given type you should use errors.As():
clusterTopology, err := sc.getClusterTopology(store)
var errAllDown *AllTopologyNodesDownError
if errors.As(err, &errAllDown) {
// err had an *AllTopologyNodesDownError in its
// chain and errAllDown now contains it.
}
Can be overridden by implementing the Unwrap() interface which your error type does not.
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.
This question already has answers here:
Unmarshal 2 different structs in a slice
(3 answers)
Closed 3 years ago.
i'm struggling to create a data structure for unmarshal the following json:
{
"asks": [
["2.049720", "183.556", 1576323009],
["2.049750", "555.125", 1576323009],
["2.049760", "393.580", 1576323008],
["2.049980", "206.514", 1576322995]
],
"bids": [
["2.043800", "20.691", 1576322350],
["2.039080", "755.396", 1576323007],
["2.036960", "214.621", 1576323006],
["2.036930", "700.792", 1576322987]
]
}
If I use the following struct with interfaces, there is no problem:
type OrderBook struct {
Asks [][]interface{} `json:"asks"`
Bids [][]interface{} `json:"bids"`
}
But i need a more strict typing, so i've tried with:
type BitfinexOrderBook struct {
Pair string `json:"pair"`
Asks [][]BitfinexOrder `json:"asks"`
Bids [][]BitfinexOrder `json:"bids"`
}
type BitfinexOrder struct {
Price string
Volume string
Timestamp time.Time
}
But unfortunately i had not success.
This is the code that I have used for parse the Kraken API for retrieve the order book:
// loadKrakenOrderBook is delegated to load the data related to pairs info
func loadKrakenOrderBook(data []byte) (datastructure.BitfinexOrderBook, error) {
var err error
// Creating the maps for the JSON data
m := map[string]interface{}{}
var orderbook datastructure.BitfinexOrderBook
// Parsing/Unmarshalling JSON
err = json.Unmarshal(data, &m)
if err != nil {
zap.S().Debugw("Error unmarshalling data: " + err.Error())
return orderbook, err
}
a := reflect.ValueOf(m["result"])
if a.Kind() == reflect.Map {
key := a.MapKeys()[0]
log.Println("KEY: ", key)
strct := a.MapIndex(key)
log.Println("MAP: ", strct)
m, _ := strct.Interface().(map[string]interface{})
log.Println("M: ", m)
data, err := json.Marshal(m)
if err != nil {
zap.S().Warnw("Panic on key: ", key.String(), " ERR: "+err.Error())
return orderbook, err
}
log.Println("DATA: ", string(data))
err = json.Unmarshal(data, &orderbook)
if err != nil {
zap.S().Warnw("Panic on key: ", key.String(), " during unmarshal. ERR: "+err.Error())
return orderbook, err
}
return orderbook, nil
}
return orderbook, errors.New("UNABLE_PARSE_VALUE")
}
The data that i use for test are the following:
{
"error": [],
"result": {
"LINKUSD": {
"asks": [
["2.049720", "183.556", 1576323009],
["2.049750", "555.125", 1576323009],
["2.049760", "393.580", 1576323008],
["2.049980", "206.514", 1576322995]
],
"bids": [
["2.043800", "20.691", 1576322350],
["2.039080", "755.396", 1576323007],
["2.036960", "214.621", 1576323006],
["2.036930", "700.792", 1576322987]
]
}
}
}
EDIT
NOTE: the data that i receive in input is the latest json that i've post, not the array of bids and asks.
I've tried to integrate the solution proposed by #chmike. Unfortunately there is a few preprocessing to be made, cause the data is the latest json that i've post.
So i've changed to code as following in order to extract the json data related to asks and bids.
func order(data []byte) (datastructure.BitfinexOrderBook, error) {
var err error
// Creating the maps for the JSON data
m := map[string]interface{}{}
var orderbook datastructure.BitfinexOrderBook
// var asks datastructure.BitfinexOrder
// var bids datastructure.BitfinexOrder
// Parsing/Unmarshalling JSON
err = json.Unmarshal(data, &m)
if err != nil {
zap.S().Warn("Error unmarshalling data: " + err.Error())
return orderbook, err
}
// Extract the "result" json
a := reflect.ValueOf(m["result"])
if a.Kind() == reflect.Map {
key := a.MapKeys()[0]
log.Println("KEY: ", key)
log.Println()
strct := a.MapIndex(key)
log.Println("MAP: ", strct)
m, _ := strct.Interface().(map[string]interface{})
log.Println("M: ", m)
log.Println("Asks: ", m["asks"])
log.Println("Bids: ", m["bids"])
// Here i retrieve the asks array
asks_data, err := json.Marshal(m["asks"])
log.Println("OK: ", err)
log.Println("ASKS: ", string(asks_data))
var asks datastructure.BitfinexOrder
// here i try to unmarshal the data into the struct
asks, err = UnmarshalJSON(asks_data)
log.Println(err)
log.Println(asks)
}
return orderbook, errors.New("UNABLE_PARSE_VALUE")
}
Unfortunately, i receive the following error:
json: cannot unmarshal array into Go value of type json.Number
As suggested by #Flimzy, you need a custom Unmarshaler. Here it is.
Note that the BitfinexOrderBook definition is slightly different from yours. There was an error in it.
// BitfinexOrderBook is a book of orders.
type BitfinexOrderBook struct {
Asks []BitfinexOrder `json:"asks"`
Bids []BitfinexOrder `json:"bids"`
}
// BitfinexOrder is a bitfinex order.
type BitfinexOrder struct {
Price string
Volume string
Timestamp time.Time
}
// UnmarshalJSON decode a BifinexOrder.
func (b *BitfinexOrder) UnmarshalJSON(data []byte) error {
var packedData []json.Number
err := json.Unmarshal(data, &packedData)
if err != nil {
return err
}
b.Price = packedData[0].String()
b.Volume = packedData[1].String()
t, err := packedData[2].Int64()
if err != nil {
return err
}
b.Timestamp = time.Unix(t, 0)
return nil
}
Note also that this custom unmarshaler function allows you to convert the price or volume to a float, which is probably what you want.
While you can hack your way by using reflex, or maybe even write your own parser, the most efficient way is to implement a json.Unmarshaler.
There are a few problem remaining, though.
You are transforming a json array to the struct, not just interface{} elements in it, so it should be: Asks []BitfinexOrder and Bids []BitfinexOrder.
You need to wrap the struct BitfinexOrderBook to get it work with its data. It is trivial and much simpler than using reflex.
By default, json.Unmarshal unmarshals a json number into a float64, which is not a good thing when parsing timestamp. You can use json.NewDecoder to get a decoder and then use Decoder.UseNumber to force use a string.
For example,
func (bo *BitfinexOrder) UnmarshalJSON(data []byte) error {
dec := json.NewDecoder(bytes.NewReader(data))
dec.UseNumber()
var x []interface{}
err := dec.Decode(&x)
if err != nil {
return errParse(err.Error())
}
if len(x) != 3 {
return errParse("length is not 3")
}
price, ok := x[0].(string)
if !ok {
return errParse("price is not string")
}
volume, ok := x[1].(string)
if !ok {
return errParse("volume is not string")
}
number, ok := x[2].(json.Number)
if !ok {
return errParse("timestamp is not number")
}
tint64, err := strconv.ParseInt(string(number), 10, 64)
if err != nil {
return errParse(fmt.Sprintf("parsing timestamp: %s", err))
}
*bo = BitfinexOrder{
Price: price,
Volume: volume,
Timestamp: time.Unix(tint64, 0),
}
return nil
}
and main func (wrapping the struct):
func main() {
x := struct {
Result struct{ LINKUSD BitfinexOrderBook }
}{}
err := json.Unmarshal(data, &x)
if err != nil {
log.Fatalln(err)
}
bob := x.Result.LINKUSD
fmt.Println(bob)
}
Playground link: https://play.golang.org/p/pC124F-3M_S .
Note: the playground link use a helper function to create errors. Some might argue it is best to name the helper function NewErrInvalidBitfinexOrder or rename the error. That is not the scope of this question and I think for the sake of typing, I will keep the short name for now.
I have cloned the Stellar Horizon Repo from GitHub written in Go.
I thought to run the test cases first.where the test cases have been written by using GINKGO Testing Framework. I have been running the test cases using ginkgo command
eg : ginkgo (package path name will be given here).
This is how I run test cases. Test cases for particular package has been executing properly.
But I am getting a panic in the first test file only. Which I debugged and found that the panic is occurring while running a command. Please find the below details for reference .
File name : action_accounts_test.go
func name : TestAccountAction_Show() // Has been defined below
func TestAccountActions_Show(t *testing.T) {
ht := StartHTTPTest(t, "allow_trust") **// This function is not returning anything. Its //getting panic inside this //**
defer ht.Finish()
// existing account
w := ht.Get(
"/accounts/GCXKG6RN4ONIEPCMNFB732A436Z5PNDSRLGWK7GBLCMQLIFO4S7EYWVU",
)
if ht.Assert.Equal(200, w.Code) {
var result horizon.Account
err := json.Unmarshal(w.Body.Bytes(), &result)
ht.Require.NoError(err)
ht.Assert.Equal("8589934593", result.Sequence)
ht.Assert.NotEqual(0, result.LastModifiedLedger)
for _, balance := range result.Balances {
if balance.Type == "native" {
ht.Assert.Equal(uint32(0), balance.LastModifiedLedger)
} else {
ht.Assert.NotEqual(uint32(0), balance.LastModifiedLedger)
}
}
}
// missing account
w = ht.Get("/accounts/GDBAPLDCAEJV6LSEDFEAUDAVFYSNFRUYZ4X75YYJJMMX5KFVUOHX46SQ")
ht.Assert.Equal(404, w.Code)
}
I did a Debugging and found that its getting panic in the below func call which happens inside the above func StartHTTPTest()
scenarios.Load(StellarCoreDatabaseURL(), stellarCorePath)
scenarios.Load(DatabaseURL(), horizonPath)
Definition of the particular func
func Load(url string, path string) {
log.Println("database url", url, " Path : ", path)
sql, err := Asset(path)
log.Println("Print err:", err, " sql :", sql)
if err != nil {
log.Panic(err)
}
reader := bytes.NewReader(sql)
cmd := exec.Command("psql", url)
cmd.Stdin = reader
err = cmd.Run() **// Exactly here it return some error**
log.Println("Print err", err)
if err != nil { **// Since err is not nil .the statement will get executed .**
**log.Panic(err)**
}
}
The Error returned by cmd.Run() is exit status 2
I just printed the error and found this is the error exit status 2
What is the reason for the particular error?
Using Go and AWS-SDK
I'm attempting to query route53 CNAME and A records as listed in the AWS Console under Route53 -> Hosted Zones. I'm able to query using the following code, but it requires the (cryptic) HostedZoneId I have to know ahead of time.
Is there a different function, or a HostedZoneId lookup based on the Domain Name such as XXX.XXX.com ?
AWSLogin(instance)
svc := route53.New(instance.AWSSession)
listParams := &route53.ListResourceRecordSetsInput{
HostedZoneId: aws.String("Z2798GPJN9CUFJ"), // Required
// StartRecordType: aws.String("CNAME"),
}
respList, err := svc.ListResourceRecordSets(listParams)
if err != nil {
fmt.Println(err.Error())
return
}
// Pretty-print the response data.
fmt.Println("All records:")
fmt.Println(respList)
edit: oh, additionally, the StartRecordType with the value "CNAME" throws a validation error, so I'm not sure what I should be using there.
You first have to do a lookup to get the HostedZoneID. Here is the func I wrote for it. :
func GetHostedZoneIdByNameLookup(awsSession string, HostedZoneName string) (HostedZoneID string, err error) {
svc := route53.New(awsSession)
listParams := &route53.ListHostedZonesByNameInput{
DNSName: aws.String(HostedZoneName), // Required
}
req, resp := svc.ListHostedZonesByNameRequest(listParams)
err = req.Send()
if err != nil {
return "", err
}
HostedZoneID = *resp.HostedZones[0].Id
// remove the /hostedzone/ path if it's there
if strings.HasPrefix(HostedZoneID, "/hostedzone/") {
HostedZoneID = strings.TrimPrefix(HostedZoneID, "/hostedzone/")
}
return HostedZoneID, nil
}