From 949c95cbebfbd5b6ac795e7c053fc5f7a8c02db0 Mon Sep 17 00:00:00 2001 From: Jason Paulos Date: Thu, 18 Nov 2021 10:17:49 -0800 Subject: [PATCH 01/10] Implement transactions as arguments --- cmd/goal/application.go | 147 +++++++++++++++++++++++++++++++++++----- data/abi/abi_encode.go | 85 +++++++++++++---------- data/abi/abi_type.go | 9 +++ 3 files changed, 187 insertions(+), 54 deletions(-) diff --git a/cmd/goal/application.go b/cmd/goal/application.go index c92bab2b91..b6ba398ba0 100644 --- a/cmd/goal/application.go +++ b/cmd/goal/application.go @@ -1048,6 +1048,43 @@ var infoAppCmd = &cobra.Command{ }, } +// populateMethodCallTxnArgs parses and loads transactions from the files indicated by the values +// slice. An error will occur if the transaction does not matched the expected type, it has a nonzero +// group ID, or if it is signed by a normal signature or Msig signature (but not Lsig signature) +func populateMethodCallTxnArgs(types []string, values []string) ([]transactions.SignedTxn, error) { + loadedTxns := make([]transactions.SignedTxn, len(values)) + + for i, txFilename := range values { + data, err := readFile(txFilename) + if err != nil { + return nil, fmt.Errorf(fileReadError, txFilename, err) + } + + var txn transactions.SignedTxn + err = protocol.Decode(data, &txn) + if err != nil { + return nil, fmt.Errorf(txDecodeError, txFilename, err) + } + + if !txn.Sig.Blank() || !txn.Msig.Blank() { + return nil, fmt.Errorf("Transaction from %s has already been signed", txFilename) + } + + if !txn.Txn.Group.IsZero() { + return nil, fmt.Errorf("Transaction from %s already has a group ID: %s", txFilename, txn.Txn.Group) + } + + expectedType := types[i] + if expectedType != "txn" && txn.Txn.Type != protocol.TxType(expectedType) { + return nil, fmt.Errorf("Transaction from %s does not match method argument type. Expected %s, got %s", txFilename, expectedType, txn.Txn.Type) + } + + loadedTxns[i] = txn + } + + return loadedTxns, nil +} + var methodAppCmd = &cobra.Command{ Use: "method", Short: "Invoke a method", @@ -1080,16 +1117,49 @@ var methodAppCmd = &cobra.Command{ applicationArgs = append(applicationArgs, hash[0:4]) // parse down the ABI type from method signature - argTupleTypeStr, retTypeStr, err := abi.ParseMethodSignature(method) + _, argTypes, retTypeStr, err := abi.ParseMethodSignature(method) if err != nil { reportErrorf("cannot parse method signature: %v", err) } - err = abi.ParseArgJSONtoByteSlice(argTupleTypeStr, methodArgs, &applicationArgs) + + var retType *abi.Type + if retTypeStr != "void" { + *retType, err = abi.TypeOf(retTypeStr) + if err != nil { + reportErrorf("cannot cast %s to abi type: %v", retTypeStr, err) + } + } + + if len(methodArgs) != len(argTypes) { + reportErrorf("incorrect number of arguments, method expected %d but got %d", len(argTypes), len(methodArgs)) + } + + var txnArgTypes []string + var txnArgValues []string + var basicArgTypes []string + var basicArgValues []string + for i, argType := range argTypes { + argValue := methodArgs[i] + if abi.IsTransactionType(argType) { + txnArgTypes = append(txnArgTypes, argType) + txnArgValues = append(txnArgValues, argValue) + } else { + basicArgTypes = append(basicArgTypes, argType) + basicArgValues = append(basicArgValues, argValue) + } + } + + err = abi.ParseArgJSONtoByteSlice(basicArgTypes, basicArgValues, &applicationArgs) if err != nil { reportErrorf("cannot parse arguments to ABI encoding: %v", err) } - tx, err := client.MakeUnsignedApplicationCallTx( + txnArgs, err := populateMethodCallTxnArgs(txnArgTypes, txnArgValues) + if err != nil { + reportErrorf("error populating transaction arguments: %v", err) + } + + appCallTxn, err := client.MakeUnsignedApplicationCallTx( appIdx, applicationArgs, appAccounts, foreignApps, foreignAssets, onCompletion, approvalProg, clearProg, basics.StateSchema{}, basics.StateSchema{}, 0) @@ -1098,8 +1168,8 @@ var methodAppCmd = &cobra.Command{ } // Fill in note and lease - tx.Note = parseNoteField(cmd) - tx.Lease = parseLease(cmd) + appCallTxn.Note = parseNoteField(cmd) + appCallTxn.Lease = parseLease(cmd) // Fill in rounds, fee, etc. fv, lv, err := client.ComputeValidityRounds(firstValid, lastValid, numValidRounds) @@ -1107,29 +1177,74 @@ var methodAppCmd = &cobra.Command{ reportErrorf("Cannot determine last valid round: %s", err) } - tx, err = client.FillUnsignedTxTemplate(account, fv, lv, fee, tx) + appCallTxn, err = client.FillUnsignedTxTemplate(account, fv, lv, fee, appCallTxn) if err != nil { reportErrorf("Cannot construct transaction: %s", err) } explicitFee := cmd.Flags().Changed("fee") if explicitFee { - tx.Fee = basics.MicroAlgos{Raw: fee} + appCallTxn.Fee = basics.MicroAlgos{Raw: fee} } - // Broadcast + // Compile group + txnGroup := []transactions.Transaction{appCallTxn} + if len(txnArgs) != 0 { + for i := range txnArgs { + txnGroup = append(txnGroup, txnArgs[i].Txn) + } + groupId, err := client.GroupID(txnGroup) + if err != nil { + reportErrorf("Cannot assign transaction group ID: %s", err) + } + for i := range txnGroup { + txnGroup[i].Group = groupId + } + } + + // Sign transactions wh, pw := ensureWalletHandleMaybePassword(dataDir, walletName, true) - signedTxn, err := client.SignTransactionWithWallet(wh, pw, tx) - if err != nil { - reportErrorf(errorSigningTX, err) + signedTxnGroup := make([]transactions.SignedTxn, len(txnGroup)) + for i, unsignedTxn := range txnGroup { + txnFromArgs := transactions.SignedTxn{} + if i > 1 { + txnFromArgs = txnArgs[i-1] + } + + if !txnFromArgs.Lsig.Blank() { + signedTxnGroup = append(signedTxnGroup, transactions.SignedTxn{ + Lsig: txnFromArgs.Lsig, + AuthAddr: txnFromArgs.AuthAddr, + Txn: unsignedTxn, + }) + continue + } + + signer := unsignedTxn.Sender + if !txnFromArgs.AuthAddr.IsZero() { + signer = txnFromArgs.AuthAddr + } + + signedTxn, err := client.SignTransactionWithWalletAndSigner(wh, pw, signer.String(), unsignedTxn) + if err != nil { + reportErrorf(errorSigningTX, err) + } + signedTxnGroup = append(signedTxnGroup, signedTxn) } - txid, err := client.BroadcastTransaction(signedTxn) + // Broadcast + err = client.BroadcastTransactionGroup(signedTxnGroup) 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) + reportInfof("Issued %d transaction(s):", len(signedTxnGroup)) + // remember the final txid in this variable + var txid string + for _, stxn := range signedTxnGroup { + txid = stxn.Txn.ID().String() + reportInfof(" Issued transaction from account %s, txid %s (fee %d)", stxn.Txn.Sender, txid, stxn.Txn.Fee.Raw) + } if !noWaitAfterSend { _, err := waitForCommit(client, txid, lv) @@ -1142,7 +1257,7 @@ var methodAppCmd = &cobra.Command{ reportErrorf(err.Error()) } - if retTypeStr == "void" { + if retType == nil { return } @@ -1167,10 +1282,6 @@ var methodAppCmd = &cobra.Command{ 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) diff --git a/data/abi/abi_encode.go b/data/abi/abi_encode.go index fa5dbd57c8..30be5b4b18 100644 --- a/data/abi/abi_encode.go +++ b/data/abi/abi_encode.go @@ -481,37 +481,39 @@ func decodeTuple(encoded []byte, childT []Type) ([]interface{}, error) { // ParseArgJSONtoByteSlice convert input method arguments to ABI encoded bytes // it converts funcArgTypes into a tuple type and apply changes over input argument string (in JSON format) // if there are greater or equal to 15 inputs, then we compact the tailing inputs into one tuple -func ParseArgJSONtoByteSlice(funcArgTypes string, jsonArgs []string, applicationArgs *[][]byte) error { - abiTupleT, err := TypeOf(funcArgTypes) - if err != nil { - return err +func ParseArgJSONtoByteSlice(argTypes []string, jsonArgs []string, applicationArgs *[][]byte) error { + abiTypes := make([]Type, len(argTypes)) + for i, typeString := range argTypes { + abiType, err := TypeOf(typeString) + if err != nil { + return err + } + abiTypes[i] = abiType } - if len(abiTupleT.childTypes) != len(jsonArgs) { - return fmt.Errorf("input argument number %d != method argument number %d", len(jsonArgs), len(abiTupleT.childTypes)) + + if len(abiTypes) != len(jsonArgs) { + return fmt.Errorf("input argument number %d != method argument number %d", len(jsonArgs), len(abiTypes)) } // change the input args to be 1 - 14 + 15 (compacting everything together) if len(jsonArgs) > 14 { - compactedType, err := MakeTupleType(abiTupleT.childTypes[14:]) + compactedType, err := MakeTupleType(abiTypes[14:]) if err != nil { return err } - abiTupleT.childTypes = abiTupleT.childTypes[:14] - abiTupleT.childTypes = append(abiTupleT.childTypes, compactedType) - abiTupleT.staticLength = 15 + abiTypes = append(abiTypes[:14], compactedType) remainingJSON := "[" + strings.Join(jsonArgs[14:], ",") + "]" - jsonArgs = jsonArgs[:14] - jsonArgs = append(jsonArgs, remainingJSON) + jsonArgs = append(jsonArgs[:14], remainingJSON) } // parse JSON value to ABI encoded bytes for i := 0; i < len(jsonArgs); i++ { - interfaceVal, err := abiTupleT.childTypes[i].UnmarshalFromJSON([]byte(jsonArgs[i])) + interfaceVal, err := abiTypes[i].UnmarshalFromJSON([]byte(jsonArgs[i])) if err != nil { return err } - abiEncoded, err := abiTupleT.childTypes[i].Encode(interfaceVal) + abiEncoded, err := abiTypes[i].Encode(interfaceVal) if err != nil { return err } @@ -520,30 +522,41 @@ func ParseArgJSONtoByteSlice(funcArgTypes string, jsonArgs []string, application return nil } -// ParseMethodSignature parses a method of format `method(...argTypes...)retType` -// into `(...argTypes)` and `retType` -func ParseMethodSignature(methodSig string) (string, string, error) { - var stack []int - - for index, chr := range methodSig { - if chr == '(' { - stack = append(stack, index) - } else if chr == ')' { - if len(stack) == 0 { - break +// ParseMethodSignature parses a method of format `method(argType1,argType2,...)retType` +// into `method` {`argType1`,`argType2`,..} and `retType` +func ParseMethodSignature(methodSig string) (name string, argTypes []string, returnType string, err error) { + argsStart := strings.Index(methodSig, "(") + if argsStart == -1 { + err = fmt.Errorf("Invalid method signature: %s", methodSig) + return + } + + argsEnd := -1 + depth := 0 + for index, char := range methodSig { + switch char { + case '(': + depth += 1 + case ')': + if depth == 0 { + err = fmt.Errorf("Unpaired parenthesis in method signature: %s", methodSig) + return } - leftParenIndex := stack[len(stack)-1] - stack = stack[:len(stack)-1] - if len(stack) == 0 { - returnType := methodSig[index+1:] - if _, err := TypeOf(returnType); err != nil { - if returnType != "void" { - return "", "", fmt.Errorf("cannot infer return type: %s", returnType) - } - } - return methodSig[leftParenIndex : index+1], methodSig[index+1:], nil + depth -= 1 + if depth == 0 { + argsEnd = index + break } } } - return "", "", fmt.Errorf("unpaired parentheses: %s", methodSig) + + if argsEnd == -1 { + err = fmt.Errorf("Invalid method signature: %s", methodSig) + return + } + + name = methodSig[:argsStart] + argTypes, err = parseTupleContent(methodSig[argsStart+1 : argsEnd]) + returnType = methodSig[argsEnd+1:] + return } diff --git a/data/abi/abi_type.go b/data/abi/abi_type.go index eb93f9eea1..d46d68102c 100644 --- a/data/abi/abi_type.go +++ b/data/abi/abi_type.go @@ -457,3 +457,12 @@ func (t Type) ByteLen() (int, error) { return -1, fmt.Errorf("%s is a dynamic type", t.String()) } } + +func IsTransactionType(s string) bool { + switch s { + case "txn", "pay", "keyreg", "acfg", "axfer", "afrz", "appl": + return true + default: + return false + } +} From 43a318ddd150ff8974c1267d4bb73656616f0dc7 Mon Sep 17 00:00:00 2001 From: Jason Paulos Date: Fri, 19 Nov 2021 09:39:52 -0800 Subject: [PATCH 02/10] Fix indexing and dryrun issue --- cmd/goal/application.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/goal/application.go b/cmd/goal/application.go index 11a08c91a9..62243d0ab5 100644 --- a/cmd/goal/application.go +++ b/cmd/goal/application.go @@ -1202,12 +1202,12 @@ var methodAppCmd = &cobra.Command{ } // Sign transactions - signedTxnGroup := make([]transactions.SignedTxn, len(txnGroup)) + var signedTxnGroup []transactions.SignedTxn shouldSign := sign || outFilename == "" for i, unsignedTxn := range txnGroup { txnFromArgs := transactions.SignedTxn{} - if i > 1 { - txnFromArgs = txnArgs[i-1] + if i < len(txnArgs) { + txnFromArgs = txnArgs[i] } if !txnFromArgs.Lsig.Blank() { @@ -1230,7 +1230,7 @@ var methodAppCmd = &cobra.Command{ // Output to file if outFilename != "" { if dumpForDryrun { - err = writeDryrunReqToFile(client, txnGroup, outFilename) + err = writeDryrunReqToFile(client, signedTxnGroup, outFilename) } else { err = writeSignedTxnsToFile(signedTxnGroup, outFilename) } From 5bb37ff47399bd2caba01b69dea351f4fa4a6f43 Mon Sep 17 00:00:00 2001 From: Jason Paulos Date: Fri, 19 Nov 2021 10:09:06 -0800 Subject: [PATCH 03/10] Add docstring --- data/abi/abi_type.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/abi/abi_type.go b/data/abi/abi_type.go index d46d68102c..3535170277 100644 --- a/data/abi/abi_type.go +++ b/data/abi/abi_type.go @@ -458,6 +458,8 @@ func (t Type) ByteLen() (int, error) { } } +// IsTransactionType checks if a type string represents a transaction type +// argument, such as "txn", "pay", "keyreg", etc. func IsTransactionType(s string) bool { switch s { case "txn", "pay", "keyreg", "acfg", "axfer", "afrz", "appl": From 13898dc1fe6cb4ac7d5ef9d04b3e132fe430e098 Mon Sep 17 00:00:00 2001 From: Jason Paulos Date: Fri, 19 Nov 2021 10:11:02 -0800 Subject: [PATCH 04/10] Satisfy review dog --- cmd/goal/application.go | 4 ++-- data/abi/abi_encode.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/goal/application.go b/cmd/goal/application.go index 1ce559a759..3d9d53f32e 100644 --- a/cmd/goal/application.go +++ b/cmd/goal/application.go @@ -1193,12 +1193,12 @@ var methodAppCmd = &cobra.Command{ txnGroup = append(txnGroup, appCallTxn) if len(txnGroup) > 1 { // Only if transaction arguments are present, assign group ID - groupId, err := client.GroupID(txnGroup) + groupID, err := client.GroupID(txnGroup) if err != nil { reportErrorf("Cannot assign transaction group ID: %s", err) } for i := range txnGroup { - txnGroup[i].Group = groupId + txnGroup[i].Group = groupID } } diff --git a/data/abi/abi_encode.go b/data/abi/abi_encode.go index 30be5b4b18..397e66856f 100644 --- a/data/abi/abi_encode.go +++ b/data/abi/abi_encode.go @@ -536,13 +536,13 @@ func ParseMethodSignature(methodSig string) (name string, argTypes []string, ret for index, char := range methodSig { switch char { case '(': - depth += 1 + depth++ case ')': if depth == 0 { err = fmt.Errorf("Unpaired parenthesis in method signature: %s", methodSig) return } - depth -= 1 + depth-- if depth == 0 { argsEnd = index break From 0e2d07bd7d7cc476d85d7ac3d5a2ee80947ccbf3 Mon Sep 17 00:00:00 2001 From: Jason Paulos Date: Fri, 19 Nov 2021 10:13:03 -0800 Subject: [PATCH 05/10] Fix pointer issue --- cmd/goal/application.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/goal/application.go b/cmd/goal/application.go index 3d9d53f32e..50e8aeb7a4 100644 --- a/cmd/goal/application.go +++ b/cmd/goal/application.go @@ -1123,10 +1123,11 @@ var methodAppCmd = &cobra.Command{ var retType *abi.Type if retTypeStr != "void" { - *retType, err = abi.TypeOf(retTypeStr) + theRetType, err := abi.TypeOf(retTypeStr) if err != nil { reportErrorf("cannot cast %s to abi type: %v", retTypeStr, err) } + retType = &theRetType } if len(methodArgs) != len(argTypes) { From 3b377ca22773abe1d9240376134147e54f444ba6 Mon Sep 17 00:00:00 2001 From: Jason Paulos Date: Fri, 19 Nov 2021 10:54:19 -0800 Subject: [PATCH 06/10] Fix group command --- cmd/goal/clerk.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/goal/clerk.go b/cmd/goal/clerk.go index cf9baf1288..aac8f1a8b9 100644 --- a/cmd/goal/clerk.go +++ b/cmd/goal/clerk.go @@ -866,8 +866,8 @@ var groupCmd = &cobra.Command{ } groupHash := crypto.HashObj(group) - for _, stxn := range stxns { - stxn.Txn.Group = groupHash + for i := range stxns { + stxns[i].Txn.Group = groupHash } err = writeSignedTxnsToFile(stxns, outFilename) From 83fb06d789f5a81edab31038251149793ab36d39 Mon Sep 17 00:00:00 2001 From: Jason Paulos Date: Fri, 19 Nov 2021 10:54:31 -0800 Subject: [PATCH 07/10] Rename e2e test --- .../{e2e-app-abi-add.sh => e2e-app-abi-method.sh} | 14 +++++++------- ...dd-example.teal => app-abi-method-example.teal} | 0 2 files changed, 7 insertions(+), 7 deletions(-) rename test/scripts/e2e_subs/{e2e-app-abi-add.sh => e2e-app-abi-method.sh} (71%) rename test/scripts/e2e_subs/tealprogs/{app-abi-add-example.teal => app-abi-method-example.teal} (100%) diff --git a/test/scripts/e2e_subs/e2e-app-abi-add.sh b/test/scripts/e2e_subs/e2e-app-abi-method.sh similarity index 71% rename from test/scripts/e2e_subs/e2e-app-abi-add.sh rename to test/scripts/e2e_subs/e2e-app-abi-method.sh index 4ee0494b63..2085d60313 100755 --- a/test/scripts/e2e_subs/e2e-app-abi-add.sh +++ b/test/scripts/e2e_subs/e2e-app-abi-method.sh @@ -1,6 +1,6 @@ #!/bin/bash -date '+app-abi-add-test start %Y%m%d_%H%M%S' +date '+app-abi-method-test start %Y%m%d_%H%M%S' set -e set -x @@ -18,13 +18,13 @@ ACCOUNT=$(${gcmd} account list|awk '{ print $3 }') printf '#pragma version 2\nint 1' > "${TEMPDIR}/simple.teal" PROGRAM=($(${gcmd} clerk compile "${TEMPDIR}/simple.teal")) -APPID=$(${gcmd} app create --creator ${ACCOUNT} --approval-prog ${DIR}/tealprogs/app-abi-add-example.teal --clear-prog ${TEMPDIR}/simple.teal --global-byteslices 0 --global-ints 0 --local-byteslices 1 --local-ints 0 | grep Created | awk '{ print $6 }') +APPID=$(${gcmd} app create --creator ${ACCOUNT} --approval-prog ${DIR}/tealprogs/app-abi-method-example.teal --clear-prog ${TEMPDIR}/simple.teal --global-byteslices 0 --global-ints 0 --local-byteslices 1 --local-ints 0 | grep Created | awk '{ print $6 }') # Opt in RES=$(${gcmd} app method --method "optIn(string)string" --arg "\"Algorand Fan\"" --on-completion optin --app-id $APPID --from $ACCOUNT 2>&1 || true) EXPECTED="method optIn(string)string succeeded with output: \"hello Algorand Fan\"" if [[ $RES != *"${EXPECTED}"* ]]; then - date '+app-abi-add-test FAIL the method call to optIn(string)string should not fail %Y%m%d_%H%M%S' + date '+app-abi-method-test FAIL the method call to optIn(string)string should not fail %Y%m%d_%H%M%S' false fi @@ -32,7 +32,7 @@ fi RES=$(${gcmd} app method --method "add(uint64,uint64)uint64" --arg 1 --arg 2 --app-id $APPID --from $ACCOUNT 2>&1 || true) EXPECTED="method add(uint64,uint64)uint64 succeeded with output: 3" if [[ $RES != *"${EXPECTED}"* ]]; then - date '+app-abi-add-test FAIL the method call to add(uint64,uint64)uint64 should not fail %Y%m%d_%H%M%S' + date '+app-abi-method-test FAIL the method call to add(uint64,uint64)uint64 should not fail %Y%m%d_%H%M%S' false fi @@ -40,7 +40,7 @@ fi RES=$(${gcmd} app method --method "add(uint64,uint64)uint64" --arg 18446744073709551614 --arg 1 --app-id $APPID --from $ACCOUNT 2>&1 || true) EXPECTED="method add(uint64,uint64)uint64 succeeded with output: 18446744073709551615" if [[ $RES != *"${EXPECTED}"* ]]; then - date '+app-abi-add-test FAIL the method call to add(uint64,uint64)uint64 should not fail %Y%m%d_%H%M%S' + date '+app-abi-method-test FAIL the method call to add(uint64,uint64)uint64 should not fail %Y%m%d_%H%M%S' false fi @@ -48,7 +48,7 @@ fi RES=$(${gcmd} app method --method "closeOut()string" --on-completion closeout --app-id $APPID --from $ACCOUNT 2>&1 || true) EXPECTED="method closeOut()string succeeded with output: \"goodbye Algorand Fan\"" if [[ $RES != *"${EXPECTED}"* ]]; then - date '+app-abi-add-test FAIL the method call to closeOut()string should not fail %Y%m%d_%H%M%S' + date '+app-abi-method-test FAIL the method call to closeOut()string should not fail %Y%m%d_%H%M%S' false fi @@ -56,6 +56,6 @@ fi RES=$(${gcmd} app method --method "delete()void" --on-completion deleteapplication --app-id $APPID --from $ACCOUNT 2>&1 || true) EXPECTED="method delete()void succeeded" if [[ $RES != *"${EXPECTED}"* ]]; then - date '+app-abi-add-test FAIL the method call to delete()void should not fail %Y%m%d_%H%M%S' + date '+app-abi-method-test FAIL the method call to delete()void should not fail %Y%m%d_%H%M%S' false fi diff --git a/test/scripts/e2e_subs/tealprogs/app-abi-add-example.teal b/test/scripts/e2e_subs/tealprogs/app-abi-method-example.teal similarity index 100% rename from test/scripts/e2e_subs/tealprogs/app-abi-add-example.teal rename to test/scripts/e2e_subs/tealprogs/app-abi-method-example.teal From 97353e3cd5f7b32eea134827cfd4c8a79cf0c208 Mon Sep 17 00:00:00 2001 From: Jason Paulos Date: Fri, 19 Nov 2021 11:18:24 -0800 Subject: [PATCH 08/10] Fix filename variable --- cmd/goal/clerk.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/goal/clerk.go b/cmd/goal/clerk.go index aac8f1a8b9..c5d69854a5 100644 --- a/cmd/goal/clerk.go +++ b/cmd/goal/clerk.go @@ -223,7 +223,7 @@ func writeSignedTxnsToFile(stxns []transactions.SignedTxn, filename string) erro outData = append(outData, protocol.Encode(&stxn)...) } - return writeFile(outFilename, outData, 0600) + return writeFile(filename, outData, 0600) } func writeTxnToFile(client libgoal.Client, signTx bool, dataDir string, walletName string, tx transactions.Transaction, filename string) error { @@ -232,7 +232,7 @@ func writeTxnToFile(client libgoal.Client, signTx bool, dataDir string, walletNa return err } // Write the SignedTxn to the output file - return writeSignedTxnsToFile([]transactions.SignedTxn{stxn}, outFilename) + return writeSignedTxnsToFile([]transactions.SignedTxn{stxn}, filename) } func getB64Args(args []string) [][]byte { From ee2b7beaab3755aa013cb66c80063ad3bd02a78c Mon Sep 17 00:00:00 2001 From: Jason Paulos Date: Fri, 19 Nov 2021 16:07:19 -0800 Subject: [PATCH 09/10] Add e2e test --- test/scripts/e2e_subs/e2e-app-abi-method.sh | 18 ++++++++++++++++++ .../tealprogs/app-abi-method-example.teal | 16 ++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/test/scripts/e2e_subs/e2e-app-abi-method.sh b/test/scripts/e2e_subs/e2e-app-abi-method.sh index 2085d60313..ec3a0d71e7 100755 --- a/test/scripts/e2e_subs/e2e-app-abi-method.sh +++ b/test/scripts/e2e_subs/e2e-app-abi-method.sh @@ -44,6 +44,24 @@ if [[ $RES != *"${EXPECTED}"* ]]; then false fi +goal clerk send --from $ACCOUNT --to $ACCOUNT --amount 1000000 -o "${TEMPDIR}/pay-txn-arg.tx" + +# Payment with return true +RES=$(${gcmd} app method --method "payment(pay,uint64)bool" --arg ${TEMPDIR}/pay-txn-arg.tx --arg 1000000 --app-id $APPID --from $ACCOUNT 2>&1 || true) +EXPECTED="method payment(pay,uint64)bool succeeded with output: true" +if [[ $RES != *"${EXPECTED}"* ]]; then + date '+app-abi-method-test FAIL the method call to payment(pay,uint64)bool should not fail %Y%m%d_%H%M%S' + false +fi + +# Payment with return false +RES=$(${gcmd} app method --method "payment(pay,uint64)bool" --arg ${TEMPDIR}/pay-txn-arg.tx --arg 1000001 --app-id $APPID --from $ACCOUNT 2>&1 || true) +EXPECTED="method payment(pay,uint64)bool succeeded with output: false" +if [[ $RES != *"${EXPECTED}"* ]]; then + date '+app-abi-method-test FAIL the method call to payment(pay,uint64)bool should not fail %Y%m%d_%H%M%S' + false +fi + # Close out RES=$(${gcmd} app method --method "closeOut()string" --on-completion closeout --app-id $APPID --from $ACCOUNT 2>&1 || true) EXPECTED="method closeOut()string succeeded with output: \"goodbye Algorand Fan\"" diff --git a/test/scripts/e2e_subs/tealprogs/app-abi-method-example.teal b/test/scripts/e2e_subs/tealprogs/app-abi-method-example.teal index a2c8168765..dbc831d7a7 100644 --- a/test/scripts/e2e_subs/tealprogs/app-abi-method-example.teal +++ b/test/scripts/e2e_subs/tealprogs/app-abi-method-example.teal @@ -48,7 +48,7 @@ txn OnCompletion int NoOp == txna ApplicationArgs 0 -byte 0x535a47ba +byte 0x3e3b3d28 == && bnz main_l8 @@ -158,7 +158,19 @@ int pay == assert byte 0x151f7c75 +txn GroupIndex +int 1 +- +gtxns Amount +load 5 +btoi +== +bnz sub5_l2 +byte 0x00 +b sub5_l3 +sub5_l2: byte 0x80 +sub5_l3: concat log -retsub \ No newline at end of file +retsub From 5a25e23c66e2202aee3de6b378d5fdd92c79a560 Mon Sep 17 00:00:00 2001 From: Jason Paulos Date: Fri, 19 Nov 2021 16:07:25 -0800 Subject: [PATCH 10/10] Use tab --- cmd/goal/application.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/goal/application.go b/cmd/goal/application.go index 50e8aeb7a4..49a2ce9c58 100644 --- a/cmd/goal/application.go +++ b/cmd/goal/application.go @@ -1254,7 +1254,7 @@ var methodAppCmd = &cobra.Command{ var txid string for _, stxn := range signedTxnGroup { txid = stxn.Txn.ID().String() - reportInfof(" Issued transaction from account %s, txid %s (fee %d)", stxn.Txn.Sender, txid, stxn.Txn.Fee.Raw) + reportInfof("\tIssued transaction from account %s, txid %s (fee %d)", stxn.Txn.Sender, txid, stxn.Txn.Fee.Raw) } if !noWaitAfterSend {