diff --git a/.circleci/config.yml b/.circleci/config.yml index d98d70c1de..34e111cada 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,6 +22,11 @@ parameters: valid_nightly_branch: type: string default: /hotfix\/.*/ + # The following is intentional - hardcoding a token for public repos + # is recommended here to allow fork access + codecov: + type: string + default: "8b4a1f91-f154-4c26-b84c-c9aaa90159c6" executors: amd64_medium: @@ -239,6 +244,8 @@ jobs: executor: << parameters.platform >>_medium working_directory: << pipeline.parameters.build_dir >>/project parallelism: 32 + environment: + CODECOV_TOKEN: << pipeline.parameters.codecov >> steps: - generic_build - generic_test: @@ -254,6 +261,8 @@ jobs: executor: << parameters.platform >>_large working_directory: << pipeline.parameters.build_dir >>/project parallelism: 4 + environment: + CODECOV_TOKEN: << pipeline.parameters.codecov >> steps: - generic_build - generic_test: diff --git a/catchup/service.go b/catchup/service.go index 2178f92eec..ac5fa730d4 100644 --- a/catchup/service.go +++ b/catchup/service.go @@ -157,6 +157,16 @@ func (s *Service) IsSynchronizing() (synchronizing bool, initialSync bool) { return } +// triggerSync attempts to wake up the sync loop. +func (s *Service) triggerSync() { + if syncing, initial := s.IsSynchronizing(); !syncing && !initial { + select { + case s.syncNow <- struct{}{}: + default: + } + } +} + // SetDisableSyncRound attempts to set the first round we _do_not_ want to fetch from the network // Blocks from disableSyncRound or any round after disableSyncRound will not be fetched while this is set func (s *Service) SetDisableSyncRound(rnd uint64) error { @@ -164,18 +174,14 @@ func (s *Service) SetDisableSyncRound(rnd uint64) error { return ErrSyncRoundInvalid } atomic.StoreUint64(&s.disableSyncRound, rnd) - if syncing, initial := s.IsSynchronizing(); !syncing && !initial { - s.syncNow <- struct{}{} - } + s.triggerSync() return nil } // UnsetDisableSyncRound removes any previously set disabled sync round func (s *Service) UnsetDisableSyncRound() { atomic.StoreUint64(&s.disableSyncRound, 0) - if syncing, initial := s.IsSynchronizing(); !syncing && !initial { - s.syncNow <- struct{}{} - } + s.triggerSync() } // GetDisableSyncRound returns the disabled sync round diff --git a/cmd/goal/README.md b/cmd/goal/README.md index 2ecebf65bf..f33e1ce41b 100644 --- a/cmd/goal/README.md +++ b/cmd/goal/README.md @@ -68,7 +68,7 @@ TEALDIR=cmd/goal/examples echo $TEALDIR # create the app and TAKE NOTE of its "app index" -goal app create --creator ${ACCOUNT} --approval-prog ${TEALDIR}/boxes.teal --clear-prog ${TEALDIR}/clear.teal --global-byteslices 0 --global-ints 0 --local-byteslices 0 --local-ints 0 +goal app create --creator ${ACCOUNT} --approval-prog ${TEALDIR}/boxes.teal --clear-prog ${TEALDIR}/clear.teal ``` For the following questions, you'll need to use the app index. That will be shown in the last line printed. EG: diff --git a/cmd/goal/application.go b/cmd/goal/application.go index 0c5e9e0cbf..cb048ce50d 100644 --- a/cmd/goal/application.go +++ b/cmd/goal/application.go @@ -163,10 +163,6 @@ func init() { readStateAppCmd.Flags().BoolVar(&guessFormat, "guess-format", false, "Format application state using heuristics to guess data encoding.") createAppCmd.MarkFlagRequired("creator") - createAppCmd.MarkFlagRequired("global-ints") - createAppCmd.MarkFlagRequired("global-byteslices") - createAppCmd.MarkFlagRequired("local-ints") - createAppCmd.MarkFlagRequired("local-byteslices") optInAppCmd.MarkFlagRequired("app-id") optInAppCmd.MarkFlagRequired("from") diff --git a/config/consensus.go b/config/consensus.go index e3bf4d527f..59f9721a4e 100644 --- a/config/consensus.go +++ b/config/consensus.go @@ -498,6 +498,9 @@ type ConsensusParams struct { // EnableCatchpointsWithSPContexts specifies when to re-enable version 7 catchpoints. // Version 7 includes state proof verification contexts EnableCatchpointsWithSPContexts bool + + // EnableBoxRefNameError specifies that box ref names should be validated early + EnableBoxRefNameError bool } // PaysetCommitType enumerates possible ways for the block header to commit to @@ -1266,6 +1269,7 @@ func initConsensusProtocols() { vFuture.LogicSigVersion = 9 // When moving this to a release, put a new higher LogicSigVersion here vFuture.EnablePrecheckECDSACurve = true vFuture.EnableBareBudgetError = true + vFuture.EnableBoxRefNameError = true vFuture.StateProofUseTrackerVerification = true vFuture.EnableCatchpointsWithSPContexts = true diff --git a/daemon/algod/api/server/v2/handlers.go b/daemon/algod/api/server/v2/handlers.go index a26d2752de..045b69553d 100644 --- a/daemon/algod/api/server/v2/handlers.go +++ b/daemon/algod/api/server/v2/handlers.go @@ -1348,8 +1348,6 @@ func (v2 *Handlers) startCatchup(ctx echo.Context, catchpoint string) error { code = http.StatusOK case *node.CatchpointUnableToStartError: return badRequest(ctx, err, err.Error(), v2.Log) - case *node.CatchpointSyncRoundFailure: - return badRequest(ctx, err, fmt.Sprintf(errFailedToStartCatchup, err), v2.Log) default: return internalError(ctx, err, fmt.Sprintf(errFailedToStartCatchup, err), v2.Log) } diff --git a/daemon/algod/api/server/v2/test/handlers_test.go b/daemon/algod/api/server/v2/test/handlers_test.go index 0c34aacd5d..fd31a1bef5 100644 --- a/daemon/algod/api/server/v2/test/handlers_test.go +++ b/daemon/algod/api/server/v2/test/handlers_test.go @@ -1222,10 +1222,6 @@ func TestStartCatchup(t *testing.T) { badCatchPoint := "bad catchpoint" startCatchupTest(t, badCatchPoint, nil, 400) - - // Test that a catchup fails w/ 400 when the catchpoint round is > syncRound (while syncRound is set) - syncRoundError := node.MakeCatchpointSyncRoundFailure(goodCatchPoint, 1) - startCatchupTest(t, goodCatchPoint, syncRoundError, 400) } func abortCatchupTest(t *testing.T, catchpoint string, expectedCode int) { diff --git a/daemon/algod/server.go b/daemon/algod/server.go index 2283ef8e0d..010d3aec57 100644 --- a/daemon/algod/server.go +++ b/daemon/algod/server.go @@ -83,7 +83,6 @@ func (s *Server) Initialize(cfg config.Local, phonebookAddresses []string, genes liveLog := filepath.Join(s.RootPath, "node.log") archive := filepath.Join(s.RootPath, cfg.LogArchiveName) - fmt.Println("Logging to: ", liveLog) var maxLogAge time.Duration var err error if cfg.LogArchiveMaxAge != "" { @@ -96,8 +95,10 @@ func (s *Server) Initialize(cfg config.Local, phonebookAddresses []string, genes var logWriter io.Writer if cfg.LogSizeLimit > 0 { + fmt.Println("Logging to: ", liveLog) logWriter = logging.MakeCyclicFileWriter(liveLog, archive, cfg.LogSizeLimit, maxLogAge) } else { + fmt.Println("Logging to: stdout") logWriter = os.Stdout } s.log.SetOutput(logWriter) diff --git a/data/transactions/transaction.go b/data/transactions/transaction.go index 6c1b56fd29..5877e99c7f 100644 --- a/data/transactions/transaction.go +++ b/data/transactions/transaction.go @@ -477,6 +477,9 @@ func (tx Transaction) WellFormed(spec SpecialAddresses, proto config.ConsensusPa if br.Index > uint64(len(tx.ForeignApps)) { return fmt.Errorf("tx.Boxes[%d].Index is %d. Exceeds len(tx.ForeignApps)", i, br.Index) } + if proto.EnableBoxRefNameError && len(br.Name) > proto.MaxAppKeyLen { + return fmt.Errorf("tx.Boxes[%d].Name too long, max len %d bytes", i, proto.MaxAppKeyLen) + } } if tx.LocalStateSchema.NumEntries() > proto.MaxLocalSchemaEntries { diff --git a/data/transactions/transaction_test.go b/data/transactions/transaction_test.go index 51f69ce714..0f3cf18258 100644 --- a/data/transactions/transaction_test.go +++ b/data/transactions/transaction_test.go @@ -274,6 +274,7 @@ func TestWellFormedErrors(t *testing.T) { protoV27 := config.Consensus[protocol.ConsensusV27] protoV28 := config.Consensus[protocol.ConsensusV28] protoV32 := config.Consensus[protocol.ConsensusV32] + protoV36 := config.Consensus[protocol.ConsensusV36] addr1, err := basics.UnmarshalChecksumAddress("NDQCJNNY5WWWFLP4GFZ7MEF2QJSMZYK6OWIV2AQ7OMAVLEFCGGRHFPKJJA") require.NoError(t, err) v5 := []byte{0x05} @@ -566,6 +567,32 @@ func TestWellFormedErrors(t *testing.T) { proto: protoV32, expectedError: fmt.Errorf("tx.Boxes too long, max number of box references is 0"), }, + { + tx: Transaction{ + Type: protocol.ApplicationCallTx, + Header: okHeader, + ApplicationCallTxnFields: ApplicationCallTxnFields{ + ApplicationID: 1, + Boxes: []BoxRef{{Index: 1, Name: make([]byte, 65)}}, + ForeignApps: []basics.AppIndex{1}, + }, + }, + proto: futureProto, + expectedError: fmt.Errorf("tx.Boxes[0].Name too long, max len 64 bytes"), + }, + { + tx: Transaction{ + Type: protocol.ApplicationCallTx, + Header: okHeader, + ApplicationCallTxnFields: ApplicationCallTxnFields{ + ApplicationID: 1, + Boxes: []BoxRef{{Index: 1, Name: make([]byte, 65)}}, + ForeignApps: []basics.AppIndex{1}, + }, + }, + proto: protoV36, + expectedError: nil, + }, } for _, usecase := range usecases { err := usecase.tx.WellFormed(specialAddr, usecase.proto) diff --git a/node/error.go b/node/error.go index dbe036b605..d177f0c870 100644 --- a/node/error.go +++ b/node/error.go @@ -62,24 +62,3 @@ func (e *CatchpointUnableToStartError) Error() string { e.catchpointRequested, e.catchpointRunning) } - -// CatchpointSyncRoundFailure indicates that the requested catchpoint is beyond the currently set sync round -type CatchpointSyncRoundFailure struct { - catchpoint string - syncRound uint64 -} - -// MakeCatchpointSyncRoundFailure creates the error type -func MakeCatchpointSyncRoundFailure(catchpoint string, syncRound uint64) *CatchpointSyncRoundFailure { - return &CatchpointSyncRoundFailure{ - catchpoint: catchpoint, - syncRound: syncRound, - } -} - -// Error satisfies the builtin `error` interface -func (e *CatchpointSyncRoundFailure) Error() string { - return fmt.Sprintf( - "unable to start catchpoint catchup for '%s' - resulting round is beyond current sync round '%v'", - e.catchpoint, e.syncRound) -} diff --git a/node/follower_node.go b/node/follower_node.go index 633515d1c1..ae770c7112 100644 --- a/node/follower_node.go +++ b/node/follower_node.go @@ -342,14 +342,7 @@ func (node *AlgorandFollowerNode) StartCatchup(catchpoint string) error { } return MakeCatchpointUnableToStartError(stats.CatchpointLabel, catchpoint) } - cpRound, _, err := ledgercore.ParseCatchpointLabel(catchpoint) - if err != nil { - return err - } - sRound := node.GetSyncRound() - if sRound > 0 && uint64(cpRound) > sRound { - return MakeCatchpointSyncRoundFailure(catchpoint, sRound) - } + var err error accessor := ledger.MakeCatchpointCatchupAccessor(node.ledger.Ledger, node.log) node.catchpointCatchupService, err = catchup.MakeNewCatchpointCatchupService(catchpoint, node, node.log, node.net, accessor, node.config) if err != nil { @@ -414,7 +407,15 @@ func (node *AlgorandFollowerNode) SetCatchpointCatchupMode(catchpointCatchupMode prevNodeCancelFunc() return } + + // Catchup finished, resume. defer node.mu.Unlock() + + // update sync round before starting services + if err := node.SetSyncRound(uint64(node.ledger.LastRound())); err != nil { + node.log.Warnf("unable to set sync round while resuming fast catchup: %v", err) + } + // start node.catchupService.Start() node.blockService.Start() diff --git a/node/follower_node_test.go b/node/follower_node_test.go index 1295eb0339..c15fb3317d 100644 --- a/node/follower_node_test.go +++ b/node/follower_node_test.go @@ -17,11 +17,13 @@ package node import ( + "context" "testing" "time" "github.com/sirupsen/logrus" "github.com/sirupsen/logrus/hooks/test" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/algorand/go-algorand/agreement" @@ -227,3 +229,22 @@ func TestSyncRoundWithRemake(t *testing.T) { syncRound := followNode.GetSyncRound() require.Equal(t, uint64(maxAcctLookback+1), syncRound) } + +func TestFastCatchupResume(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + node := setupFollowNode(t) + node.ctx = context.Background() + + // Initialize sync round to a future round. + syncRound := uint64(10000) + node.SetSyncRound(syncRound) + require.Equal(t, syncRound, node.GetSyncRound()) + + // Force catchpoint catchup mode to end, this should set the sync round to the current ledger round (0). + out := node.SetCatchpointCatchupMode(false) + <-out + + // Verify the sync was reset. + assert.Equal(t, uint64(0), node.GetSyncRound()) +} diff --git a/scripts/travis/codecov b/scripts/travis/codecov old mode 100755 new mode 100644 index d443a8979c..36513ce06d --- a/scripts/travis/codecov +++ b/scripts/travis/codecov @@ -5,7 +5,7 @@ set -e +o pipefail -VERSION="1.0.3" +VERSION="1.0.6" codecov_flags=( ) url="https://codecov.io" @@ -865,14 +865,17 @@ then if [ "$GITHUB_HEAD_REF" != "" ]; then # PR refs are in the format: refs/pull/7/merge - pr="${GITHUB_REF#refs/pull/}" - pr="${pr%/merge}" + if [[ "$GITHUB_REF" =~ ^refs\/pull\/[0-9]+\/merge$ ]]; + then + pr="${GITHUB_REF#refs/pull/}" + pr="${pr%/merge}" + fi branch="${GITHUB_HEAD_REF}" fi commit="${GITHUB_SHA}" slug="${GITHUB_REPOSITORY}" build="${GITHUB_RUN_ID}" - build_url=$(urlencode "http://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}") + build_url=$(urlencode "${GITHUB_SERVER_URL:-https://github.com}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}") job="$(urlencode "${GITHUB_WORKFLOW}")" # actions/checkout runs in detached HEAD @@ -987,6 +990,7 @@ else fi +say " ${e}current dir: ${x} $PWD" say " ${e}project root:${x} $git_root" # find branch, commit, repo from git command @@ -1618,7 +1622,7 @@ then # [ or ] syntax_list='^[[:space:]]*[][][[:space:]]*(//.*)?$' # func ... { - syntax_go_func='^[[:space:]]*[func].*[\{][[:space:]]*$' + syntax_go_func='^[[:space:]]*func[[:space:]]*[\{][[:space:]]*$' # shellcheck disable=SC2089 skip_dirs="-not -path '*/$bower_components/*' \ @@ -1783,7 +1787,7 @@ if [ "$dump" != "0" ]; then # trim whitespace from query say " ${e}->${x} Dumping upload file (no upload)" - echo "$url/upload/v4?$(echo "package=$package-$VERSION&token=$token&$query" | tr -d ' ')" + echo "$url/upload/v4?$(echo "package=$package-$VERSION&$query" | tr -d ' ')" cat "$upload_file" else if [ "$save_to" != "" ]; @@ -1802,10 +1806,9 @@ else say " ${e}url:${x} $url" say " ${e}query:${x} $query" - # Full query without token (to display on terminal output) - queryNoToken=$(echo "package=$package-$VERSION&token=secret&$query" | tr -d ' ') - # now add token to query + # Full query (to display on terminal output) query=$(echo "package=$package-$VERSION&token=$token&$query" | tr -d ' ') + queryNoToken=$(echo "package=$package-$VERSION&token=&$query" | tr -d ' ') if [ "$ft_s3" = "1" ]; then @@ -1817,6 +1820,7 @@ else -H 'X-Reduced-Redundancy: false' \ -H 'X-Content-Type: application/x-gzip' \ -H 'Content-Length: 0' \ + -H "X-Upload-Token: ${token}" \ --write-out "\n%{response_code}\n" \ $curlargs \ "$url/upload/v4?$query" || true) @@ -1863,6 +1867,7 @@ else -H 'Content-Type: text/plain' \ -H 'Content-Encoding: gzip' \ -H 'X-Content-Encoding: gzip' \ + -H "X-Upload-Token: ${token}" \ -H 'Accept: text/plain' \ $curlargs \ "$url/upload/v2?$query&attempt=$i" || echo 'HTTP 500') diff --git a/scripts/travis/upload_coverage.sh b/scripts/travis/upload_coverage.sh index e861b7ef98..8ab3b56ea6 100755 --- a/scripts/travis/upload_coverage.sh +++ b/scripts/travis/upload_coverage.sh @@ -1,15 +1,9 @@ #!/usr/bin/env bash -# Print a warning when there is a new version notification before uploading the -# coverage report to codecov. set -eo pipefail -# Check if there is a new version. -curl -fLso codecov https://codecov.io/bash -UPSTREAM_VERSION=$(grep -o 'VERSION=\"[0-9\.]*\"' codecov | cut -d'"' -f2) -LOCAL_VERSION=$(grep -o 'VERSION=\"[0-9\.]*\"' scripts/travis/codecov | cut -d'"' -f2) -if [[ "${UPSTREAM_VERSION}" != "${LOCAL_VERSION}" ]]; then - echo "WARN: version ${UPSTREAM_VERSION} of the codecov upload script is available." +if [[ -z "$CODECOV_TOKEN" ]]; then + /usr/bin/env bash scripts/travis/codecov +else + /usr/bin/env bash scripts/travis/codecov -t $CODECOV_TOKEN fi - -/usr/bin/env bash scripts/travis/codecov diff --git a/test/scripts/e2e_subs/access-previous-scratch.sh b/test/scripts/e2e_subs/access-previous-scratch.sh index 7c519ec43d..f8dd54d966 100755 --- a/test/scripts/e2e_subs/access-previous-scratch.sh +++ b/test/scripts/e2e_subs/access-previous-scratch.sh @@ -17,7 +17,7 @@ gcmd="goal -w ${WALLET}" ACCOUNT=$(${gcmd} account list|awk '{ print $3 }') -APPID=$(${gcmd} app create --creator "${ACCOUNT}" --approval-prog=${TEAL}/scratch-rw.teal --global-byteslices 0 --global-ints 0 --local-byteslices 0 --local-ints 0 --clear-prog=${TEAL}/approve-all.teal | grep Created | awk '{ print $6 }') +APPID=$(${gcmd} app create --creator "${ACCOUNT}" --approval-prog=${TEAL}/scratch-rw.teal --clear-prog=${TEAL}/approve-all.teal | grep Created | awk '{ print $6 }') # Create app calls function create_app_call { diff --git a/test/scripts/e2e_subs/box-search.sh b/test/scripts/e2e_subs/box-search.sh index 8803e87851..29ed02757b 100755 --- a/test/scripts/e2e_subs/box-search.sh +++ b/test/scripts/e2e_subs/box-search.sh @@ -20,7 +20,7 @@ ACCOUNT=$(${gcmd} account list|awk '{ print $3 }') # Version 8 clear program printf '#pragma version 8\nint 1' > "${TEMPDIR}/clear.teal" -APPID=$(${gcmd} app create --creator "$ACCOUNT" --approval-prog=${TEAL}/boxes.teal --clear-prog "$TEMPDIR/clear.teal" --global-byteslices 0 --global-ints 0 --local-byteslices 0 --local-ints 0 | grep Created | awk '{ print $6 }') +APPID=$(${gcmd} app create --creator "$ACCOUNT" --approval-prog=${TEAL}/boxes.teal --clear-prog "$TEMPDIR/clear.teal" | grep Created | awk '{ print $6 }') # Fund the app account 10 algos APP_ACCOUNT=$(${gcmd} app info --app-id "$APPID" | grep "Application account" | awk '{print $3}') @@ -38,6 +38,16 @@ EXPECTED="No box found for appid $APPID with name str:not_found" [ "$BOX_INFO" = "$EXPECTED" ] +# Confirm that we error for an invalid box name +BOX_NAME="str:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +RES=$(${gcmd} app call --from "$ACCOUNT" --app-id "$APPID" --box "$BOX_NAME" --app-arg "str:create" --app-arg "$BOX_NAME" 2>&1 || true) +EXPECTED="invalid : tx.Boxes[0].Name too long, max len 64 bytes" + +if [[ "$RES" != *"$EXPECTED" ]]; then + date "+${scriptname} unexpected response from goal app call with invalid box name %Y%m%d_%H%M%S" + false +fi + # Create several boxes BOX_NAMES=("str:box1" "str:with spaces" "b64:YmFzZTY0" "b64:AQIDBA==") # b64:YmFzZTY0 == str:base64, b64:AQIDBA== is not unicode BOX_VALUE="box value" diff --git a/test/scripts/e2e_subs/e2e-app-abi-arg.sh b/test/scripts/e2e_subs/e2e-app-abi-arg.sh index c6f719a479..336e892c2f 100755 --- a/test/scripts/e2e_subs/e2e-app-abi-arg.sh +++ b/test/scripts/e2e_subs/e2e-app-abi-arg.sh @@ -19,7 +19,7 @@ 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-arg.teal --clear-prog ${TEMPDIR}/simple.teal --global-byteslices 0 --global-ints ${GLOBAL_INTS} --local-byteslices 0 --local-ints 0 | grep Created | awk '{ print $6 }') +APPID=$(${gcmd} app create --creator ${ACCOUNT} --approval-prog ${DIR}/tealprogs/app-abi-arg.teal --clear-prog ${TEMPDIR}/simple.teal --global-ints ${GLOBAL_INTS} | grep Created | awk '{ print $6 }') # Should succeed to opt in with string "optin" ${gcmd} app optin --app-id $APPID --from $ACCOUNT --app-arg 'abi:string:"optin"' diff --git a/test/scripts/e2e_subs/e2e-app-abi-method.sh b/test/scripts/e2e_subs/e2e-app-abi-method.sh index ac5d4f5925..b41d87b93e 100755 --- a/test/scripts/e2e_subs/e2e-app-abi-method.sh +++ b/test/scripts/e2e_subs/e2e-app-abi-method.sh @@ -20,7 +20,7 @@ printf '#pragma version 2\nint 1' > "${TEMPDIR}/simple-v2.teal" printf '#pragma version 3\nint 1' > "${TEMPDIR}/simple-v3.teal" # Create -RES=$(${gcmd} app method --method "create(uint64)uint64" --arg "1234" --create --approval-prog ${DIR}/tealprogs/app-abi-method-example.teal --clear-prog ${TEMPDIR}/simple-v2.teal --global-byteslices 0 --global-ints 0 --local-byteslices 1 --local-ints 0 --extra-pages 0 --from $ACCOUNT 2>&1 || true) +RES=$(${gcmd} app method --method "create(uint64)uint64" --arg "1234" --create --approval-prog ${DIR}/tealprogs/app-abi-method-example.teal --clear-prog ${TEMPDIR}/simple-v2.teal --local-byteslices 1 --from $ACCOUNT 2>&1 || true) EXPECTED="method create(uint64)uint64 succeeded with output: 2468" if [[ $RES != *"${EXPECTED}"* ]]; then date '+app-abi-method-test FAIL the method call to create(uint64)uint64 should not fail %Y%m%d_%H%M%S' @@ -112,7 +112,7 @@ if [[ $RES != *"${EXPECTED}"* ]]; then fi # Foreign reference test during creation -RES=$(${gcmd} app method --create --approval-prog ${DIR}/tealprogs/app-abi-method-example.teal --clear-prog ${TEMPDIR}/simple-v2.teal --global-byteslices 0 --global-ints 0 --local-byteslices 1 --local-ints 0 --extra-pages 0 --on-completion deleteapplication --method "referenceTest(account,application,account,asset,account,asset,asset,application,application)uint8[9]" --arg KGTOR3F3Q74JP4LB5M3SOCSJ4BOPOKZ2GPSLMLLGCWYWRXZJNN4LYQJXXU --arg 0 --arg $ACCOUNT --arg 10 --arg KGTOR3F3Q74JP4LB5M3SOCSJ4BOPOKZ2GPSLMLLGCWYWRXZJNN4LYQJXXU --arg 11 --arg 10 --arg 20 --arg 21 --app-account 2R5LMPTYLVMWYEG4RPI26PJAM7ARTGUB7LZSONQPGLUWTPOP6LQCJTQZVE --foreign-app 21 --foreign-asset 10 --from $ACCOUNT 2>&1 || true) +RES=$(${gcmd} app method --create --approval-prog ${DIR}/tealprogs/app-abi-method-example.teal --clear-prog ${TEMPDIR}/simple-v2.teal --local-byteslices 1 --on-completion deleteapplication --method "referenceTest(account,application,account,asset,account,asset,asset,application,application)uint8[9]" --arg KGTOR3F3Q74JP4LB5M3SOCSJ4BOPOKZ2GPSLMLLGCWYWRXZJNN4LYQJXXU --arg 0 --arg $ACCOUNT --arg 10 --arg KGTOR3F3Q74JP4LB5M3SOCSJ4BOPOKZ2GPSLMLLGCWYWRXZJNN4LYQJXXU --arg 11 --arg 10 --arg 20 --arg 21 --app-account 2R5LMPTYLVMWYEG4RPI26PJAM7ARTGUB7LZSONQPGLUWTPOP6LQCJTQZVE --foreign-app 21 --foreign-asset 10 --from $ACCOUNT 2>&1 || true) EXPECTED="method referenceTest(account,application,account,asset,account,asset,asset,application,application)uint8[9] succeeded with output: [2,0,2,0,2,1,0,1,0]" if [[ $RES != *"${EXPECTED}"* ]]; then date '+app-abi-method-test FAIL the creation method call to referenceTest(account,application,account,asset,account,asset,asset,application,application)uint8[9] should not fail %Y%m%d_%H%M%S' diff --git a/test/scripts/e2e_subs/e2e-app-bootloader.sh b/test/scripts/e2e_subs/e2e-app-bootloader.sh index 170a96f09e..e9c22a65fb 100755 --- a/test/scripts/e2e_subs/e2e-app-bootloader.sh +++ b/test/scripts/e2e_subs/e2e-app-bootloader.sh @@ -33,7 +33,7 @@ sed -i"" -e "s/TMPL_CLEARSTATE_HASH/${TARGET_HASH}/g" ${TEMPDIR}/bootloader.teal # Create an app using filled-in bootloader template printf '#pragma version 2\nint 1' > "${TEMPDIR}/int1.teal" -APPID=$(${gcmd} app create --creator ${ACCOUNT} --approval-prog ${TEMPDIR}/bootloader.teal --global-byteslices 1 --global-ints 0 --local-byteslices 0 --local-ints 0 --clear-prog "${TEMPDIR}/int1.teal" | grep Created | awk '{ print $6 }') +APPID=$(${gcmd} app create --creator ${ACCOUNT} --approval-prog ${TEMPDIR}/bootloader.teal --global-byteslices 1 --clear-prog "${TEMPDIR}/int1.teal" | grep Created | awk '{ print $6 }') # Calling app without args and wrong OnCompletion should fail EXPERROR='rejected by ApprovalProgram' diff --git a/test/scripts/e2e_subs/e2e-app-delete-clear.sh b/test/scripts/e2e_subs/e2e-app-delete-clear.sh index 9373c1ba84..2795f869fc 100755 --- a/test/scripts/e2e_subs/e2e-app-delete-clear.sh +++ b/test/scripts/e2e_subs/e2e-app-delete-clear.sh @@ -20,7 +20,7 @@ PROGRAM_FILE="${TEMPDIR}/simple.teal" GLOBAL_INTS=2 # Succeed in creating app with on-completion delete -APPID=$(${gcmd} app create --creator ${ACCOUNT} --on-completion "DeleteApplication" --approval-prog "${PROGRAM_FILE}" --clear-prog "${PROGRAM_FILE}" --global-byteslices 0 --global-ints ${GLOBAL_INTS} --local-byteslices 0 --local-ints 0 | grep Created | awk '{ print $6 }') +APPID=$(${gcmd} app create --creator ${ACCOUNT} --on-completion "DeleteApplication" --approval-prog "${PROGRAM_FILE}" --clear-prog "${PROGRAM_FILE}" --global-ints ${GLOBAL_INTS} | grep Created | awk '{ print $6 }') # Check that the app is not created APPID_CHECK=$(${gcmd} app info --app-id $APPID 2>&1 || true) EXPERROR="application does not exist" @@ -30,7 +30,7 @@ if [[ $APPID_CHECK != *"${EXPERROR}"* ]]; then fi # Fail if creating app with on-completion clear -RES=$(${gcmd} app create --creator ${ACCOUNT} --on-completion "ClearState" --approval-prog "${PROGRAM_FILE}" --clear-prog "${PROGRAM_FILE}" --global-byteslices 0 --global-ints ${GLOBAL_INTS} --local-byteslices 0 --local-ints 0 2>&1 || true ) +RES=$(${gcmd} app create --creator ${ACCOUNT} --on-completion "ClearState" --approval-prog "${PROGRAM_FILE}" --clear-prog "${PROGRAM_FILE}" --global-ints ${GLOBAL_INTS} 2>&1 || true ) EXPERROR1='cannot clear state' EXPERROR2='is not currently opted in' if [[ $RES != *"${EXPERROR1}"*"${EXPERROR2}"* ]]; then diff --git a/test/scripts/e2e_subs/e2e-app-extra-pages.sh b/test/scripts/e2e_subs/e2e-app-extra-pages.sh index 1b9dd779c0..b2d3cf8709 100755 --- a/test/scripts/e2e_subs/e2e-app-extra-pages.sh +++ b/test/scripts/e2e_subs/e2e-app-extra-pages.sh @@ -52,7 +52,7 @@ generate_teal "$APPR_PROG" 4 3072 1 "int 0\nbalance\npop\n" generate_teal "$BIG_APPR_PROG" 4 4098 1 "int 0\nbalance\npop\n" # App create fails. Approval program too long -RES=$(${gcmd} app create --creator ${ACCOUNT} --approval-prog "${BIG_TEAL_FILE}" --clear-prog "${BIG_TEAL_FILE}" --global-byteslices 1 --global-ints 0 --local-byteslices 0 --local-ints 0 2>&1 || true) +RES=$(${gcmd} app create --creator ${ACCOUNT} --approval-prog "${BIG_TEAL_FILE}" --clear-prog "${BIG_TEAL_FILE}" --global-byteslices 1 2>&1 || true) EXPERROR="approval program too long. max len 2048 bytes" if [[ $RES != *"${EXPERROR}"* ]]; then date '+app-extra-pages-test FAIL the application creation should fail %Y%m%d_%H%M%S' @@ -60,7 +60,7 @@ if [[ $RES != *"${EXPERROR}"* ]]; then fi # App create fails. Clear state program too long -RES=$(${gcmd} app create --creator ${ACCOUNT} --approval-prog "${SMALL_TEAL_FILE}" --clear-prog "${BIG_TEAL_FILE}" --global-byteslices 1 --global-ints 0 --local-byteslices 0 --local-ints 0 2>&1 || true) +RES=$(${gcmd} app create --creator ${ACCOUNT} --approval-prog "${SMALL_TEAL_FILE}" --clear-prog "${BIG_TEAL_FILE}" --global-byteslices 1 2>&1 || true) EXPERROR="clear state program too long. max len 2048 bytes" if [[ $RES != *"${EXPERROR}"* ]]; then date '+app-extra-pages-test FAIL the application creation should fail %Y%m%d_%H%M%S' @@ -68,7 +68,7 @@ if [[ $RES != *"${EXPERROR}"* ]]; then fi # App create with extra pages, v3 teal -RES=$(${gcmd} app create --creator ${ACCOUNT} --approval-prog "${BIG_TEAL_FILE}" --clear-prog "${BIG_TEAL_FILE}" --extra-pages 3 --global-byteslices 1 --global-ints 0 --local-byteslices 0 --local-ints 0 2>&1 || true) +RES=$(${gcmd} app create --creator ${ACCOUNT} --approval-prog "${BIG_TEAL_FILE}" --clear-prog "${BIG_TEAL_FILE}" --extra-pages 3 --global-byteslices 1 2>&1 || true) EXPERROR="pc=705 static cost budget of 700 exceeded" if [[ $RES != *"${EXPERROR}"* ]]; then date '+app-extra-pages-test FAIL the application creation should fail %Y%m%d_%H%M%S' @@ -76,7 +76,7 @@ if [[ $RES != *"${EXPERROR}"* ]]; then fi # App create with extra pages, v4 teal -RES=$(${gcmd} app create --creator ${ACCOUNT} --approval-prog "${BIG_TEAL_V4_FILE}" --clear-prog "${BIG_TEAL_V4_FILE}" --extra-pages 3 --global-byteslices 1 --global-ints 0 --local-byteslices 0 --local-ints 0 2>&1 || true) +RES=$(${gcmd} app create --creator ${ACCOUNT} --approval-prog "${BIG_TEAL_V4_FILE}" --clear-prog "${BIG_TEAL_V4_FILE}" --extra-pages 3 --global-byteslices 1 2>&1 || true) EXPERROR="pc=704 dynamic cost budget exceeded, executing intc_0: local program cost was 700" if [[ $RES != *"${EXPERROR}"* ]]; then date '+app-extra-pages-test FAIL the application creation should fail %Y%m%d_%H%M%S' @@ -84,7 +84,7 @@ if [[ $RES != *"${EXPERROR}"* ]]; then fi # App create with extra pages, succeeded -RES=$(${gcmd} app create --creator ${ACCOUNT} --approval-prog "${SMALL_TEAL_FILE}" --clear-prog "${SMALL_TEAL_FILE}" --extra-pages 1 --global-byteslices 1 --global-ints 0 --local-byteslices 0 --local-ints 0 2>&1 || true) +RES=$(${gcmd} app create --creator ${ACCOUNT} --approval-prog "${SMALL_TEAL_FILE}" --clear-prog "${SMALL_TEAL_FILE}" --extra-pages 1 --global-byteslices 1 2>&1 || true) EXP="Created app" APPID=$(echo $RES | awk '{print $NF}') if [[ $RES != *"${EXP}"* ]]; then diff --git a/test/scripts/e2e_subs/goal-app-create-state-defaults.sh b/test/scripts/e2e_subs/goal-app-create-state-defaults.sh new file mode 100755 index 0000000000..c77faa64db --- /dev/null +++ b/test/scripts/e2e_subs/goal-app-create-state-defaults.sh @@ -0,0 +1,64 @@ +#!/bin/bash + +scriptname="goal-app-create-state-defaults" +date "+${scriptname} start %Y%m%d_%H%M%S" + +set -e +set -x +set -o pipefail +export SHELLOPTS + +WALLET=$1 + +# Directory of this bash program +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +gcmd="goal -w ${WALLET}" + +ACCOUNT=$(${gcmd} account list|awk '{ print $3 }') + +printf '#pragma version 2\nint 1' > "${TEMPDIR}/simple.teal" + +# Check goal flags --global-byteslices, --global-ints, --local-byteslices, --local-ints. We want to +# ensure that omitting these flags has the same effect as setting them to 0. + +APP_CREATE_TXN_NO_STATE_FILE="${TEMPDIR}/create_no_state.txn" +APP_CREATE_TXN_NO_FULLY_SPECIFIED_FILE="${TEMPDIR}/create_fully_specified.txn" + +# Checks for 'goal app create' + +# Passing a note is needed because goal will sometimes try to customize a note +# to avoid duplicate txns + +${gcmd} app create --note "hello" --creator "${ACCOUNT}" --approval-prog "${TEMPDIR}/simple.teal" --clear-prog "${TEMPDIR}/simple.teal" --out "${APP_CREATE_TXN_NO_STATE_FILE}" +APP_CREATE_TXN_NO_STATE=$(msgpacktool -d < "${APP_CREATE_TXN_NO_STATE_FILE}") + +FIRSTVALID=$(echo $APP_CREATE_TXN_NO_STATE | jq ".txn.fv") + +# Passing --firstvalid is used for subsequent transactions to ensure they have +# the same valid range as the first txn + +${gcmd} app create --note "hello" --creator "${ACCOUNT}" --approval-prog "${TEMPDIR}/simple.teal" --clear-prog "${TEMPDIR}/simple.teal" --global-byteslices 0 --global-ints 0 --local-byteslices 0 --local-ints 0 --firstvalid $FIRSTVALID --out "${APP_CREATE_TXN_NO_FULLY_SPECIFIED_FILE}" +APP_CREATE_TXN_NO_FULLY_SPECIFIED=$(msgpacktool -d < "${APP_CREATE_TXN_NO_FULLY_SPECIFIED_FILE}") + +if [ "$APP_CREATE_TXN_NO_FULLY_SPECIFIED" != "$APP_CREATE_TXN_NO_STATE" ]; then + date "+${scriptname} transactions made with 'goal app create' are not equal %Y%m%d_%H%M%S" + false +fi + +# Checks for 'goal method --create' + +${gcmd} app method --create --note "hello" --from "${ACCOUNT}" --method "create(uint64)uint64" --arg "1234" --create --approval-prog "${TEMPDIR}/simple.teal" --clear-prog "${TEMPDIR}/simple.teal" --out "${APP_CREATE_TXN_NO_STATE_FILE}" +APP_CREATE_TXN_NO_STATE=$(msgpacktool -d < "${APP_CREATE_TXN_NO_STATE_FILE}") + +FIRSTVALID=$(echo $APP_CREATE_TXN_NO_STATE | jq ".txn.fv") + +${gcmd} app method --create --note "hello" --from "${ACCOUNT}" --method "create(uint64)uint64" --arg "1234" --create --approval-prog "${TEMPDIR}/simple.teal" --clear-prog "${TEMPDIR}/simple.teal" --global-byteslices 0 --global-ints 0 --local-byteslices 0 --local-ints 0 --firstvalid $FIRSTVALID --out "${APP_CREATE_TXN_NO_FULLY_SPECIFIED_FILE}" +APP_CREATE_TXN_NO_FULLY_SPECIFIED=$(msgpacktool -d < "${APP_CREATE_TXN_NO_FULLY_SPECIFIED_FILE}") + +if [ "$APP_CREATE_TXN_NO_FULLY_SPECIFIED" != "$APP_CREATE_TXN_NO_STATE" ]; then + date "+${scriptname} transactions made with 'goal method --create' are not equal %Y%m%d_%H%M%S" + false +fi + +date "+${scriptname} OK %Y%m%d_%H%M%S" diff --git a/test/scripts/e2e_subs/teal-creatable-id.sh b/test/scripts/e2e_subs/teal-creatable-id.sh index 50dff53b3b..b461e11ee1 100755 --- a/test/scripts/e2e_subs/teal-creatable-id.sh +++ b/test/scripts/e2e_subs/teal-creatable-id.sh @@ -17,7 +17,7 @@ gcmd="goal -w ${WALLET}" ACCOUNT=$(${gcmd} account list|awk '{ print $3 }') -APPID=$(${gcmd} app create --creator "${ACCOUNT}" --approval-prog=${TEAL}/check_creatable_id.teal --global-byteslices 0 --global-ints 0 --local-byteslices 0 --local-ints 0 --clear-prog=${TEAL}/approve-all.teal --app-arg=str:skipcreation | grep Created | awk '{ print $6 }') +APPID=$(${gcmd} app create --creator "${ACCOUNT}" --approval-prog=${TEAL}/check_creatable_id.teal --clear-prog=${TEAL}/approve-all.teal --app-arg=str:skipcreation | grep Created | awk '{ print $6 }') # ============================== # > Asset and application test @@ -30,7 +30,7 @@ ${gcmd} asset create --creator "${ACCOUNT}" --total 1000 --unitname "" --assetur ${gcmd} app call --app-id="$APPID" --from="$ACCOUNT" --app-arg=str:skipcreation --app-arg=int:0 --out "$TEMPDIR/unsigned_asset_check_app_call.txn" # Create app transaction -${gcmd} app create --creator "${ACCOUNT}" --approval-prog=${TEAL}/approve-all.teal --global-byteslices 0 --global-ints 0 --local-byteslices 0 --local-ints 0 --clear-prog=${TEAL}/approve-all.teal --out "$TEMPDIR/unsigned_app_create.txn" +${gcmd} app create --creator "${ACCOUNT}" --approval-prog=${TEAL}/approve-all.teal --clear-prog=${TEAL}/approve-all.teal --out "$TEMPDIR/unsigned_app_create.txn" # App call transaction to check app creatable ID ${gcmd} app call --app-id="$APPID" --from="$ACCOUNT" --app-arg=str:skipcreation --app-arg=int:2 --out "$TEMPDIR/unsigned_app_check_app_call.txn"