Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ABI support to goal #3088

Merged
merged 106 commits into from
Nov 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
42a56b4
add abi encoding
ahangsu Aug 25, 2021
ab9104e
accord with go-algorand code format
ahangsu Aug 25, 2021
80c1975
minor modification
ahangsu Aug 25, 2021
f5c0f21
add partition test
ahangsu Aug 25, 2021
bdd3c10
resolve review, need more testcase rewrite
ahangsu Aug 30, 2021
3f6d738
move from cmd/goal to data, resolve review
ahangsu Aug 30, 2021
badcc28
rewrite is-dynamic, dynamic array
ahangsu Aug 30, 2021
a613273
update dynamic array 0 element support, test needed
ahangsu Aug 30, 2021
bf4e035
minor
ahangsu Aug 30, 2021
1e8f62b
minor
ahangsu Aug 30, 2021
c570d80
minor
ahangsu Aug 31, 2021
500ad45
add more testcase for abi encode/decode
ahangsu Aug 31, 2021
7d563f1
update comments in encoding test
ahangsu Sep 1, 2021
2f3fe42
minor
ahangsu Sep 1, 2021
c87719c
attempt to split abi.go into 2 files
ahangsu Sep 8, 2021
2dd6028
separate abi files to smaller files
ahangsu Sep 8, 2021
93abb82
resolve reviews, work on random gen tuple value encode/decode
ahangsu Sep 10, 2021
c23cad3
add random tuple test
ahangsu Sep 13, 2021
ba68ea9
remove math-rand, use crypto-rand
ahangsu Sep 13, 2021
438ccd2
minor
ahangsu Sep 21, 2021
825e98d
minor
ahangsu Sep 21, 2021
43ff514
some change requested from community
ahangsu Sep 22, 2021
c757de5
fix for 1 corner case
ahangsu Sep 22, 2021
515ef05
resolve review comments
ahangsu Sep 22, 2021
da39a1f
resolve review comments
ahangsu Sep 22, 2021
1ce16fd
minor
ahangsu Sep 22, 2021
023e10d
minor
ahangsu Sep 22, 2021
1aaf43d
update encode slot capacity
ahangsu Sep 22, 2021
5b60ae6
minor
ahangsu Sep 24, 2021
74f7550
resolve reviews
ahangsu Sep 25, 2021
2d0b85c
update
ahangsu Oct 7, 2021
82555b8
minor update on bool bytelen calculate
ahangsu Oct 8, 2021
87b9d75
update encode/decode from types
ahangsu Oct 8, 2021
a426d78
random test remain to be modified
ahangsu Oct 13, 2021
8aa055e
testing variable renaming, encode int support (u)int types
ahangsu Oct 13, 2021
aba8514
update test scripts and remove value struct
ahangsu Oct 13, 2021
93a57c8
follow golint
ahangsu Oct 13, 2021
7f7a49e
partly resolving comments
ahangsu Oct 13, 2021
33ce8ad
whoops uint encoding update
ahangsu Oct 13, 2021
388a50d
update int decode to primitive types method
ahangsu Oct 14, 2021
6c607bf
go fmt
ahangsu Oct 14, 2021
02163cd
update parseAppArg to accept abi input (attempt)
ahangsu Oct 15, 2021
83c46ba
need to check cmdline arg validity
ahangsu Oct 15, 2021
54f5d3b
Merge remote-tracking branch 'origin/feature/abi-encoding' into featu…
ahangsu Oct 15, 2021
e3eccd3
update unmarshal from JSON in ABI type
ahangsu Oct 15, 2021
1122a10
unmarshal from json for ABI type
ahangsu Oct 16, 2021
4338ef8
update ABI type unmarshal values from JSON bytes
ahangsu Oct 18, 2021
19d48a8
update ABI methods for string/array/address
ahangsu Oct 18, 2021
4ee6cda
update unmarshal from JSON in abi
ahangsu Oct 19, 2021
fccf3b7
fix for error in ufixed json unmarshal
ahangsu Oct 19, 2021
2943164
merge with reformatted in master
ahangsu Oct 20, 2021
d08f5e2
fix
ahangsu Oct 20, 2021
6592d7e
update on method sub command
ahangsu Oct 20, 2021
a08025d
minor
ahangsu Oct 20, 2021
47661a3
probably better separate abi json to a single file
ahangsu Oct 21, 2021
ba2e4d6
i just want to add a required flag plz...
ahangsu Oct 21, 2021
1a4ef0b
minor fix on interface from json
ahangsu Oct 22, 2021
081108a
consider some rough test cases
ahangsu Oct 22, 2021
e4dd7cd
minor
ahangsu Oct 22, 2021
5d3e521
add partition test
ahangsu Oct 22, 2021
ca9c32f
update static uint test
ahangsu Oct 22, 2021
abd37b2
update marshal/unmarshal json methods for abi
ahangsu Oct 24, 2021
2288a23
marshal byte array to b64 string
ahangsu Oct 24, 2021
9e17bfe
abi json polish
ahangsu Oct 25, 2021
55015ff
update golangci lint rules
ahangsu Oct 25, 2021
74b2525
revert golangci config
ahangsu Oct 25, 2021
52ce63d
update method impl
ahangsu Oct 26, 2021
80d3c16
update method signature return type check
ahangsu Oct 26, 2021
aa16911
minor
ahangsu Oct 26, 2021
0ad51a1
copy-paste code from call app cmd
ahangsu Oct 26, 2021
a3ae50b
minor
ahangsu Oct 26, 2021
c1d95ec
add method flag to txn flags
ahangsu Oct 26, 2021
3c1cde8
minor
ahangsu Oct 26, 2021
0b8252c
update changes
ahangsu Oct 26, 2021
7bcdbae
minor
ahangsu Oct 27, 2021
5f1355c
Merge branch 'master' into feature/goal-abi-support
ahangsu Oct 29, 2021
e904eb3
moving helper functions to abi
ahangsu Oct 29, 2021
6a97d23
update comments
ahangsu Oct 29, 2021
e9788a4
update method app call
ahangsu Oct 29, 2021
c576ea4
resolve part in abi impl
ahangsu Nov 5, 2021
88ceeed
add oncomplete support
ahangsu Nov 5, 2021
1905ac5
minor
ahangsu Nov 5, 2021
3e746ee
try to use stringarrayvar
ahangsu Nov 8, 2021
e0d5983
minor
ahangsu Nov 8, 2021
9b8735c
update goal return log handing process
ahangsu Nov 8, 2021
1c413cc
go simple
ahangsu Nov 8, 2021
687637b
add a line of e2e test for now
ahangsu Nov 8, 2021
23f4e80
update
ahangsu Nov 8, 2021
a78cb70
minor
ahangsu Nov 8, 2021
e2019ea
minor
ahangsu Nov 8, 2021
196bbaa
minor
ahangsu Nov 8, 2021
aa1efdc
go fmt
ahangsu Nov 8, 2021
baa5599
approval/clear prog nil
ahangsu Nov 8, 2021
fc0df15
discard all changes to e2d-app-cross-round, going to write separately…
ahangsu Nov 8, 2021
5175e33
update e2d tests
ahangsu Nov 8, 2021
01c0b21
check ret valu
ahangsu Nov 9, 2021
79bff00
use constant
ahangsu Nov 9, 2021
2d06d9f
resolve review partly
ahangsu Nov 9, 2021
3267ff1
resolve review on code reformatting
ahangsu Nov 9, 2021
435cca9
resolve review on code reformatting, use code chunk for datadir and c…
ahangsu Nov 9, 2021
d1e8ead
go fmt
ahangsu Nov 9, 2021
fac68f3
export tuple type maker
ahangsu Nov 9, 2021
78ed7ac
update comments in e2e test
ahangsu Nov 9, 2021
89f3f3a
update filter empty string
ahangsu Nov 9, 2021
34fc96a
resolve issues with JSON abi
ahangsu Nov 9, 2021
310180d
minor
ahangsu Nov 9, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
231 changes: 210 additions & 21 deletions cmd/goal/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package main

import (
"bytes"
"crypto/sha512"
"encoding/base32"
"encoding/base64"
"encoding/binary"
Expand All @@ -28,9 +30,11 @@ import (
"github.com/spf13/cobra"

"github.com/algorand/go-algorand/crypto"
"github.com/algorand/go-algorand/data/abi"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/transactions"
"github.com/algorand/go-algorand/data/transactions/logic"
"github.com/algorand/go-algorand/libgoal"
"github.com/algorand/go-algorand/protocol"
)

Expand All @@ -41,6 +45,9 @@ var (
approvalProgFile string
clearProgFile string

method string
methodArgs []string

approvalProgRawFile string
clearProgRawFile string

Expand Down Expand Up @@ -79,9 +86,10 @@ func init() {
appCmd.AddCommand(clearAppCmd)
appCmd.AddCommand(readStateAppCmd)
appCmd.AddCommand(infoAppCmd)
appCmd.AddCommand(methodAppCmd)

appCmd.PersistentFlags().StringVarP(&walletName, "wallet", "w", "", "Set the wallet to be used for the selected operation")
appCmd.PersistentFlags().StringSliceVar(&appArgs, "app-arg", nil, "Args to encode for application transactions (all will be encoded to a byte slice). For ints, use the form 'int:1234'. For raw bytes, use the form 'b64:A=='. For printable strings, use the form 'str:hello'. For addresses, use the form 'addr:XYZ...'.")
appCmd.PersistentFlags().StringArrayVar(&appArgs, "app-arg", nil, "Args to encode for application transactions (all will be encoded to a byte slice). For ints, use the form 'int:1234'. For raw bytes, use the form 'b64:A=='. For printable strings, use the form 'str:hello'. For addresses, use the form 'addr:XYZ...'.")
ahangsu marked this conversation as resolved.
Show resolved Hide resolved
appCmd.PersistentFlags().StringSliceVar(&foreignApps, "foreign-app", nil, "Indexes of other apps whose global state is read in this transaction")
appCmd.PersistentFlags().StringSliceVar(&foreignAssets, "foreign-asset", nil, "Indexes of assets whose parameters are read in this transaction")
appCmd.PersistentFlags().StringSliceVar(&appStrAccounts, "app-account", nil, "Accounts that may be accessed from application logic")
Expand All @@ -108,6 +116,10 @@ func init() {
deleteAppCmd.Flags().StringVarP(&account, "from", "f", "", "Account to send delete transaction from")
readStateAppCmd.Flags().StringVarP(&account, "from", "f", "", "Account to fetch state from")
updateAppCmd.Flags().StringVarP(&account, "from", "f", "", "Account to send update transaction from")
methodAppCmd.Flags().StringVarP(&account, "from", "f", "", "Account to call method from")

methodAppCmd.Flags().StringVar(&method, "method", "", "Method to be called")
methodAppCmd.Flags().StringArrayVar(&methodArgs, "arg", nil, "Args to pass in for calling a method")

// Can't use PersistentFlags on the root because for some reason marking
// a root command as required with MarkPersistentFlagRequired isn't
Expand All @@ -120,6 +132,7 @@ func init() {
readStateAppCmd.Flags().Uint64Var(&appIdx, "app-id", 0, "Application ID")
updateAppCmd.Flags().Uint64Var(&appIdx, "app-id", 0, "Application ID")
infoAppCmd.Flags().Uint64Var(&appIdx, "app-id", 0, "Application ID")
methodAppCmd.Flags().Uint64Var(&appIdx, "app-id", 0, "Application ID")

// Add common transaction flags to all txn-generating app commands
addTxnFlags(createAppCmd)
Expand All @@ -129,6 +142,7 @@ func init() {
addTxnFlags(optInAppCmd)
addTxnFlags(closeOutAppCmd)
addTxnFlags(clearAppCmd)
addTxnFlags(methodAppCmd)

readStateAppCmd.Flags().BoolVar(&fetchLocal, "local", false, "Fetch account-specific state for this application. `--from` address is required when using this flag")
readStateAppCmd.Flags().BoolVar(&fetchGlobal, "global", false, "Fetch global state for this application.")
Expand Down Expand Up @@ -161,6 +175,13 @@ func init() {
readStateAppCmd.MarkFlagRequired("app-id")

infoAppCmd.MarkFlagRequired("app-id")

methodAppCmd.MarkFlagRequired("method") // nolint:errcheck // follow previous required flag format
methodAppCmd.MarkFlagRequired("app-id") // nolint:errcheck
methodAppCmd.MarkFlagRequired("from") // nolint:errcheck
methodAppCmd.Flags().MarkHidden("app-arg") // nolint:errcheck
methodAppCmd.Flags().MarkHidden("app-input") // nolint:errcheck
methodAppCmd.Flags().MarkHidden("i") // nolint:errcheck
}

type appCallArg struct {
Expand Down Expand Up @@ -229,6 +250,23 @@ func parseAppArg(arg appCallArg) (rawValue []byte, parseErr error) {
return
}
rawValue = data
case "abi":
typeAndValue := strings.SplitN(arg.Value, ":", 2)
if len(typeAndValue) != 2 {
parseErr = fmt.Errorf("Could not decode abi string (%s): should split abi-type and abi-value with colon", arg.Value)
return
}
abiType, err := abi.TypeOf(typeAndValue[0])
if err != nil {
parseErr = fmt.Errorf("Could not decode abi type string (%s): %v", typeAndValue[0], err)
return
}
value, err := abiType.UnmarshalFromJSON([]byte(typeAndValue[1]))
if err != nil {
parseErr = fmt.Errorf("Could not decode abi value string (%s):%v ", typeAndValue[1], err)
return
}
return abiType.Encode(value)
default:
parseErr = fmt.Errorf("Unknown encoding: %s", arg.Encoding)
}
Expand Down Expand Up @@ -266,6 +304,20 @@ func processAppInputFile() (args [][]byte, accounts []string, foreignApps []uint
return parseAppInputs(inputs)
}

// filterEmptyStrings filters out empty string parsed in by StringArrayVar
// this function is added to support abi argument parsing
// since parsing of `appArg` diverted from `StringSliceVar` to `StringArrayVar`
func filterEmptyStrings(strSlice []string) []string {
var newStrSlice []string

for _, str := range strSlice {
if len(str) > 0 {
newStrSlice = append(newStrSlice, str)
}
}
return newStrSlice
}

func getAppInputs() (args [][]byte, accounts []string, foreignApps []uint64, foreignAssets []uint64) {
if (appArgs != nil || appStrAccounts != nil || foreignApps != nil) && appInputFilename != "" {
reportErrorf("Cannot specify both command-line arguments/accounts and JSON input filename")
Expand All @@ -275,7 +327,11 @@ func getAppInputs() (args [][]byte, accounts []string, foreignApps []uint64, for
}

var encodedArgs []appCallArg
for _, arg := range appArgs {

// we need to filter out empty strings from appArgs first, caused by change to `StringArrayVar`
newAppArgs := filterEmptyStrings(appArgs)

for _, arg := range newAppArgs {
encodingValue := strings.SplitN(arg, ":", 2)
if len(encodingValue) != 2 {
reportErrorf("all arguments should be of the form 'encoding:value'")
Expand Down Expand Up @@ -327,6 +383,12 @@ func mustParseOnCompletion(ocString string) (oc transactions.OnCompletion) {
}
}

func getDataDirAndClient() (dataDir string, client libgoal.Client) {
dataDir = ensureSingleDataDir()
client = ensureFullClient(dataDir)
return
}

func mustParseProgArgs() (approval []byte, clear []byte) {
// Ensure we don't have ambiguous or all empty args
if (approvalProgFile == "") == (approvalProgRawFile == "") {
Expand Down Expand Up @@ -357,9 +419,7 @@ var createAppCmd = &cobra.Command{
Long: `Issue a transaction that creates an application`,
Args: validateNoPosArgsFn,
Run: func(cmd *cobra.Command, _ []string) {

dataDir := ensureSingleDataDir()
client := ensureFullClient(dataDir)
dataDir, client := getDataDirAndClient()

// Construct schemas from args
localSchema := basics.StateSchema{
Expand Down Expand Up @@ -451,8 +511,7 @@ var updateAppCmd = &cobra.Command{
Long: `Issue a transaction that updates an application's ApprovalProgram and ClearStateProgram`,
Args: validateNoPosArgsFn,
Run: func(cmd *cobra.Command, _ []string) {
dataDir := ensureSingleDataDir()
client := ensureFullClient(dataDir)
dataDir, client := getDataDirAndClient()

// Parse transaction parameters
approvalProg, clearProg := mustParseProgArgs()
Expand Down Expand Up @@ -523,8 +582,7 @@ var optInAppCmd = &cobra.Command{
Long: `Opt an account in to an application, allocating local state in your account`,
Args: validateNoPosArgsFn,
Run: func(cmd *cobra.Command, _ []string) {
dataDir := ensureSingleDataDir()
client := ensureFullClient(dataDir)
dataDir, client := getDataDirAndClient()

// Parse transaction parameters
appArgs, appAccounts, foreignApps, foreignAssets := getAppInputs()
Expand Down Expand Up @@ -594,8 +652,7 @@ var closeOutAppCmd = &cobra.Command{
Long: `Close an account out of an application, removing local state from your account. The application must still exist. If it doesn't, use 'goal app clear'.`,
Args: validateNoPosArgsFn,
Run: func(cmd *cobra.Command, _ []string) {
dataDir := ensureSingleDataDir()
client := ensureFullClient(dataDir)
dataDir, client := getDataDirAndClient()

// Parse transaction parameters
appArgs, appAccounts, foreignApps, foreignAssets := getAppInputs()
Expand Down Expand Up @@ -665,8 +722,7 @@ var clearAppCmd = &cobra.Command{
Long: `Remove any local state from your account associated with an application. The application does not need to exist anymore.`,
Args: validateNoPosArgsFn,
Run: func(cmd *cobra.Command, _ []string) {
dataDir := ensureSingleDataDir()
client := ensureFullClient(dataDir)
dataDir, client := getDataDirAndClient()

// Parse transaction parameters
appArgs, appAccounts, foreignApps, foreignAssets := getAppInputs()
Expand Down Expand Up @@ -736,8 +792,7 @@ var callAppCmd = &cobra.Command{
Long: `Call an application, invoking application-specific functionality`,
Args: validateNoPosArgsFn,
Run: func(cmd *cobra.Command, _ []string) {
dataDir := ensureSingleDataDir()
client := ensureFullClient(dataDir)
dataDir, client := getDataDirAndClient()

// Parse transaction parameters
appArgs, appAccounts, foreignApps, foreignAssets := getAppInputs()
Expand Down Expand Up @@ -807,8 +862,7 @@ var deleteAppCmd = &cobra.Command{
Long: `Delete an application, removing the global state and other application parameters from the creator's account`,
Args: validateNoPosArgsFn,
Run: func(cmd *cobra.Command, _ []string) {
dataDir := ensureSingleDataDir()
client := ensureFullClient(dataDir)
dataDir, client := getDataDirAndClient()

// Parse transaction parameters
appArgs, appAccounts, foreignApps, foreignAssets := getAppInputs()
Expand Down Expand Up @@ -879,8 +933,7 @@ var readStateAppCmd = &cobra.Command{
Long: `Read global or local (account-specific) state for an application`,
Args: validateNoPosArgsFn,
Run: func(cmd *cobra.Command, _ []string) {
dataDir := ensureSingleDataDir()
client := ensureFullClient(dataDir)
_, client := getDataDirAndClient()

// Ensure exactly one of --local or --global is specified
if fetchLocal == fetchGlobal {
Expand Down Expand Up @@ -961,8 +1014,7 @@ var infoAppCmd = &cobra.Command{
Long: `Look up application information stored on the network, such as program hash.`,
Args: validateNoPosArgsFn,
Run: func(cmd *cobra.Command, _ []string) {
dataDir := ensureSingleDataDir()
client := ensureFullClient(dataDir)
_, client := getDataDirAndClient()

meta, err := client.ApplicationInformation(appIdx)
if err != nil {
Expand Down Expand Up @@ -995,3 +1047,140 @@ var infoAppCmd = &cobra.Command{
}
},
}

var methodAppCmd = &cobra.Command{
Use: "method",
Short: "Invoke a method",
Long: `Invoke a method in an App (stateful contract) with an application call transaction`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not proposing any changes here, but view this as a learning opportunity for me about Algorand's conventions. Cleary the convention in the file is for this field to use raw string literals. I guess that makes sense, because in theory the Long description could span several lines. However, none of the descriptions in this file seem to utilize any of the string literal's special features. Any thoughts? You can also totally ignore.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have specific thoughts or idea about it, just following the previous conventions. I just noticed the nearest editing for adding method/updating description is 16 months ago... and I suppose they might want to do something with string literal.

Args: validateNoPosArgsFn,
Run: func(cmd *cobra.Command, args []string) {
dataDir, client := getDataDirAndClient()

// Parse transaction parameters
appArgsParsed, appAccounts, foreignApps, foreignAssets := getAppInputs()
if len(appArgsParsed) > 0 {
reportErrorf("in goal app method: --arg and --app-arg are mutually exclusive, do not use --app-arg")
}

onCompletion := mustParseOnCompletion(createOnCompletion)

if appIdx == 0 {
reportErrorf("app id == 0, goal app create not supported in goal app method")
}

var approvalProg, clearProg []byte
if onCompletion == transactions.UpdateApplicationOC {
approvalProg, clearProg = mustParseProgArgs()
}

var applicationArgs [][]byte

// insert the method selector hash
hash := sha512.Sum512_256([]byte(method))
applicationArgs = append(applicationArgs, hash[0:4])

// parse down the ABI type from method signature
argTupleTypeStr, retTypeStr, err := abi.ParseMethodSignature(method)
if err != nil {
reportErrorf("cannot parse method signature: %v", err)
}
err = abi.ParseArgJSONtoByteSlice(argTupleTypeStr, methodArgs, &applicationArgs)
if err != nil {
reportErrorf("cannot parse arguments to ABI encoding: %v", err)
}

tx, err := client.MakeUnsignedApplicationCallTx(
appIdx, applicationArgs, appAccounts, foreignApps, foreignAssets,
onCompletion, approvalProg, clearProg, basics.StateSchema{}, basics.StateSchema{}, 0)

if err != nil {
reportErrorf("Cannot create application txn: %v", err)
}

// Fill in note and lease
tx.Note = parseNoteField(cmd)
tx.Lease = parseLease(cmd)

// Fill in rounds, fee, etc.
fv, lv, err := client.ComputeValidityRounds(firstValid, lastValid, numValidRounds)
if err != nil {
reportErrorf("Cannot determine last valid round: %s", err)
}

tx, err = client.FillUnsignedTxTemplate(account, fv, lv, fee, tx)
if err != nil {
reportErrorf("Cannot construct transaction: %s", err)
}
explicitFee := cmd.Flags().Changed("fee")
if explicitFee {
tx.Fee = basics.MicroAlgos{Raw: fee}
}

// Broadcast
wh, pw := ensureWalletHandleMaybePassword(dataDir, walletName, true)
signedTxn, err := client.SignTransactionWithWallet(wh, pw, tx)
if err != nil {
reportErrorf(errorSigningTX, err)
}

txid, err := client.BroadcastTransaction(signedTxn)
if err != nil {
reportErrorf(errorBroadcastingTX, err)
}

// Report tx details to user
reportInfof("Issued transaction from account %s, txid %s (fee %d)", tx.Sender, txid, tx.Fee.Raw)

if !noWaitAfterSend {
_, err := waitForCommit(client, txid, lv)
if err != nil {
reportErrorf(err.Error())
}

resp, err := client.PendingTransactionInformationV2(txid)
if err != nil {
reportErrorf(err.Error())
}

if retTypeStr == "void" {
return
}

// specify the return hash prefix
hashRet := sha512.Sum512_256([]byte("return"))
hashRetPrefix := hashRet[:4]

var abiEncodedRet []byte
foundRet := false
if resp.Logs != nil {
for i := len(*resp.Logs) - 1; i >= 0; i-- {
retLog := (*resp.Logs)[i]
if bytes.HasPrefix(retLog, hashRetPrefix) {
abiEncodedRet = retLog[4:]
foundRet = true
break
}
}
}

if !foundRet {
reportErrorf("cannot find return log for abi type %s", retTypeStr)
}

retType, err := abi.TypeOf(retTypeStr)
if err != nil {
reportErrorf("cannot cast %s to abi type: %v", retTypeStr, err)
}
decoded, err := retType.Decode(abiEncodedRet)
if err != nil {
reportErrorf("cannot decode return value %v: %v", abiEncodedRet, err)
}

decodedJSON, err := retType.MarshalToJSON(decoded)
if err != nil {
reportErrorf("cannot marshal returned bytes %v to JSON: %v", decoded, err)
}
fmt.Printf("method %s output: %s", method, string(decodedJSON))
}
},
}
Loading