Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
187 changes: 107 additions & 80 deletions cmd/goal/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import (
"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/crypto"
"github.com/algorand/go-algorand/crypto/passphrase"
v1 "github.com/algorand/go-algorand/daemon/algod/api/spec/v1"
generatedV2 "github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated"
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you summarize what we're doing with versioning that forces changes in this PR? We don't have to increment the version for changes like this, right? Maybe you're just migrating to the new version that we previously had to do?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually I had to upgrade to using the v2 endpoint because v1 does not return extra pages values for accounts.

algodAcct "github.com/algorand/go-algorand/data/account"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/transactions"
Expand Down Expand Up @@ -476,7 +476,7 @@ var listCmd = &cobra.Command{

// For each address, request information about it from algod
for _, addr := range addrs {
response, _ := client.AccountInformation(addr.Addr)
response, _ := client.AccountInformationV2(addr.Addr)
// it's okay to proceed without algod info

// Display this information to the user
Expand Down Expand Up @@ -512,7 +512,7 @@ var infoCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
dataDir := ensureSingleDataDir()
client := ensureAlgodClient(dataDir)
response, err := client.AccountInformation(accountAddress)
response, err := client.AccountInformationV2(accountAddress)
if err != nil {
reportErrorf(errorRequestFail, err)
}
Expand All @@ -524,36 +524,50 @@ var infoCmd = &cobra.Command{
},
}

func sortUint64Slice(slice []uint64) {
sort.Slice(slice, func(i, j int) bool {
return slice[i] < slice[j]
})
}

func printAccountInfo(client libgoal.Client, address string, account v1.Account) bool {
createdAssets := []uint64{}
for id := range account.AssetParams {
createdAssets = append(createdAssets, id)
func printAccountInfo(client libgoal.Client, address string, account generatedV2.Account) bool {
var createdAssets []generatedV2.Asset
if account.CreatedAssets != nil {
createdAssets = make([]generatedV2.Asset, len(*account.CreatedAssets))
for i, asset := range *account.CreatedAssets {
createdAssets[i] = asset
}
sort.Slice(createdAssets, func(i, j int) bool {
return createdAssets[i].Index < createdAssets[j].Index
})
}
sortUint64Slice(createdAssets)

heldAssets := []uint64{}
for id := range account.Assets {
heldAssets = append(heldAssets, id)
var heldAssets []generatedV2.AssetHolding
if account.Assets != nil {
heldAssets = make([]generatedV2.AssetHolding, len(*account.Assets))
for i, assetHolding := range *account.Assets {
heldAssets[i] = assetHolding
}
sort.Slice(heldAssets, func(i, j int) bool {
return heldAssets[i].AssetId < heldAssets[j].AssetId
})
}
sortUint64Slice(heldAssets)

createdApps := []uint64{}
for id := range account.AppParams {
createdApps = append(createdApps, id)
var createdApps []generatedV2.Application
if account.CreatedApps != nil {
createdApps = make([]generatedV2.Application, len(*account.CreatedApps))
for i, app := range *account.CreatedApps {
createdApps[i] = app
}
sort.Slice(createdApps, func(i, j int) bool {
return createdApps[i].Id < createdApps[j].Id
})
}
sortUint64Slice(createdApps)

optedInApps := []uint64{}
for id := range account.AppLocalStates {
optedInApps = append(optedInApps, id)
var optedInApps []generatedV2.ApplicationLocalState
if account.AppsLocalState != nil {
optedInApps = make([]generatedV2.ApplicationLocalState, len(*account.AppsLocalState))
for i, appLocalState := range *account.AppsLocalState {
optedInApps[i] = appLocalState
}
sort.Slice(optedInApps, func(i, j int) bool {
return optedInApps[i].Id < optedInApps[j].Id
})
}
sortUint64Slice(optedInApps)

report := &strings.Builder{}
errorReport := &strings.Builder{}
Expand All @@ -563,103 +577,116 @@ func printAccountInfo(client libgoal.Client, address string, account v1.Account)
if len(createdAssets) == 0 {
fmt.Fprintln(report, "\t<none>")
}
for _, id := range createdAssets {
assetParams := account.AssetParams[id]

name := assetParams.AssetName
if len(name) == 0 {
name = "<unnamed>"
for _, createdAsset := range createdAssets {
name := "<unnamed>"
if createdAsset.Params.Name != nil {
_, name = unicodePrintable(*createdAsset.Params.Name)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It may be unnecessary to pipe the string fields through unicodePrintable after #2555, but I've left them in just in case.

}
_, name = unicodePrintable(name)
units := assetParams.UnitName
if len(units) == 0 {
units = "units"

units := "units"
if createdAsset.Params.UnitName != nil {
_, units = unicodePrintable(*createdAsset.Params.UnitName)
}
_, units = unicodePrintable(units)
total := assetDecimalsFmt(assetParams.Total, assetParams.Decimals)

total := assetDecimalsFmt(createdAsset.Params.Total, uint32(createdAsset.Params.Decimals))

url := ""
if len(assetParams.URL) != 0 {
url = fmt.Sprintf(", %s", assetParams.URL)
if createdAsset.Params.Url != nil {
_, safeURL := unicodePrintable(*createdAsset.Params.Url)
url = fmt.Sprintf(", %s", safeURL)
}

fmt.Fprintf(report, "\tID %d, %s, supply %s %s%s\n", id, name, total, units, url)
fmt.Fprintf(report, "\tID %d, %s, supply %s %s%s\n", createdAsset.Index, name, total, units, url)
}

fmt.Fprintln(report, "Held Assets:")
if len(heldAssets) == 0 {
fmt.Fprintln(report, "\t<none>")
}
for _, id := range heldAssets {
assetHolding := account.Assets[id]
assetParams, err := client.AssetInformationV2(id)
for _, assetHolding := range heldAssets {
assetParams, err := client.AssetInformationV2(assetHolding.AssetId)
if err != nil {
hasError = true
fmt.Fprintf(errorReport, "Error: Unable to retrieve asset information for asset %d referred to by account %s: %v\n", id, address, err)
fmt.Fprintf(report, "\tID %d, error\n", id)
fmt.Fprintf(errorReport, "Error: Unable to retrieve asset information for asset %d referred to by account %s: %v\n", assetHolding.AssetId, address, err)
fmt.Fprintf(report, "\tID %d, error\n", assetHolding.AssetId)
}

amount := assetDecimalsFmt(assetHolding.Amount, uint32(assetParams.Params.Decimals))

var assetName string
assetName := "<unnamed>"
if assetParams.Params.Name != nil {
assetName = *assetParams.Params.Name
}
if len(assetName) == 0 {
assetName = "<unnamed>"
_, assetName = unicodePrintable(*assetParams.Params.Name)
}
_, assetName = unicodePrintable(assetName)

var unitName string
unitName := "units"
if assetParams.Params.UnitName != nil {
unitName = *assetParams.Params.UnitName
_, unitName = unicodePrintable(*assetParams.Params.UnitName)
}
if len(unitName) == 0 {
unitName = "units"
}
_, unitName = unicodePrintable(unitName)

frozen := ""
if assetHolding.Frozen {
if assetHolding.IsFrozen {
frozen = " (frozen)"
}

fmt.Fprintf(report, "\tID %d, %s, balance %s %s%s\n", id, assetName, amount, unitName, frozen)
fmt.Fprintf(report, "\tID %d, %s, balance %s %s%s\n", assetHolding.AssetId, assetName, amount, unitName, frozen)
}

fmt.Fprintln(report, "Created Apps:")
if len(createdApps) == 0 {
fmt.Fprintln(report, "\t<none>")
}
for _, id := range createdApps {
appParams := account.AppParams[id]
usedInts := 0
usedBytes := 0
for _, value := range appParams.GlobalState {
if value.Type == "u" {
usedInts++
} else {
usedBytes++
for _, app := range createdApps {
allocatedInts := uint64(0)
allocatedBytes := uint64(0)
if app.Params.GlobalStateSchema != nil {
allocatedInts = app.Params.GlobalStateSchema.NumUint
allocatedBytes = app.Params.GlobalStateSchema.NumByteSlice
}

usedInts := uint64(0)
usedBytes := uint64(0)
if app.Params.GlobalState != nil {
for _, value := range *app.Params.GlobalState {
if basics.TealType(value.Value.Type) == basics.TealUintType {
usedInts++
} else {
usedBytes++
}
}
}
fmt.Fprintf(report, "\tID %d, global state used %d/%d uints, %d/%d byte slices\n", id, usedInts, appParams.GlobalStateSchema.NumUint, usedBytes, appParams.GlobalStateSchema.NumByteSlice)

extraPages := ""
if app.Params.ExtraProgramPages != nil && *app.Params.ExtraProgramPages != 0 {
plural := ""
if *app.Params.ExtraProgramPages != 1 {
plural = "s"
}
extraPages = fmt.Sprintf(", %d extra page%s", *app.Params.ExtraProgramPages, plural)
}

fmt.Fprintf(report, "\tID %d%s, global state used %d/%d uints, %d/%d byte slices\n", app.Id, extraPages, usedInts, allocatedInts, usedBytes, allocatedBytes)
}

fmt.Fprintln(report, "Opted In Apps:")
if len(optedInApps) == 0 {
fmt.Fprintln(report, "\t<none>")
}
for _, id := range optedInApps {
localState := account.AppLocalStates[id]
usedInts := 0
usedBytes := 0
for _, value := range localState.KeyValue {
if value.Type == "u" {
usedInts++
} else {
usedBytes++
for _, localState := range optedInApps {
allocatedInts := localState.Schema.NumUint
allocatedBytes := localState.Schema.NumByteSlice

usedInts := uint64(0)
usedBytes := uint64(0)
if localState.KeyValue != nil {
for _, value := range *localState.KeyValue {
if basics.TealType(value.Value.Type) == basics.TealUintType {
usedInts++
} else {
usedBytes++
}
}
}
fmt.Fprintf(report, "\tID %d, local state used %d/%d uints, %d/%d byte slices\n", id, usedInts, localState.Schema.NumUint, usedBytes, localState.Schema.NumByteSlice)
fmt.Fprintf(report, "\tID %d, local state used %d/%d uints, %d/%d byte slices\n", localState.Id, usedInts, allocatedInts, usedBytes, allocatedBytes)
}

if hasError {
Expand Down
27 changes: 15 additions & 12 deletions cmd/goal/accountsList.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (
"path/filepath"
"strings"

"github.com/algorand/go-algorand/daemon/algod/api/spec/v1"
generatedV2 "github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/libgoal"
)
Expand Down Expand Up @@ -205,7 +205,7 @@ func (accountList *AccountsList) loadList() {
}
}

func (accountList *AccountsList) outputAccount(addr string, acctInfo v1.Account, multisigInfo *libgoal.MultisigInfo) {
func (accountList *AccountsList) outputAccount(addr string, acctInfo generatedV2.Account, multisigInfo *libgoal.MultisigInfo) {
if acctInfo.Address == "" {
fmt.Printf("[n/a]\t%s\t%s\t[n/a] microAlgos", accountList.getNameByAddress(addr), addr)
} else {
Expand All @@ -225,25 +225,28 @@ func (accountList *AccountsList) outputAccount(addr string, acctInfo v1.Account,
if multisigInfo != nil {
fmt.Printf("\t[%d/%d multisig]", multisigInfo.Threshold, len(multisigInfo.PKs))
}
if len(acctInfo.AssetParams) > 0 {
if acctInfo.CreatedAssets != nil && len(*acctInfo.CreatedAssets) > 0 {
var out []string
for curid, params := range acctInfo.AssetParams {
_, unitName := unicodePrintable(params.UnitName)
out = append(out, fmt.Sprintf("%d (%d %s)", curid, params.Total, unitName))
for _, asset := range *acctInfo.CreatedAssets {
var unitName string
if asset.Params.UnitName != nil {
_, unitName = unicodePrintable(*asset.Params.UnitName)
}
out = append(out, fmt.Sprintf("%d (%d %s)", asset.Index, asset.Params.Total, unitName))
}
fmt.Printf("\t[created asset IDs: %s]", strings.Join(out, ", "))
}
if len(acctInfo.AppParams) > 0 {
if acctInfo.CreatedApps != nil && len(*acctInfo.CreatedApps) > 0 {
var out []string
for aid := range acctInfo.AppParams {
out = append(out, fmt.Sprintf("%d", aid))
for _, app := range *acctInfo.CreatedApps {
out = append(out, fmt.Sprintf("%d", app.Id))
}
fmt.Printf("\t[created app IDs: %s]", strings.Join(out, ", "))
}
if len(acctInfo.AppLocalStates) > 0 {
if acctInfo.AppsLocalState != nil && len(*acctInfo.AppsLocalState) > 0 {
var out []string
for aid := range acctInfo.AppLocalStates {
out = append(out, fmt.Sprintf("%d", aid))
for _, app := range *acctInfo.AppsLocalState {
out = append(out, fmt.Sprintf("%d", app.Id))
}
fmt.Printf("\t[opted in app IDs: %s]", strings.Join(out, ", "))
}
Expand Down
5 changes: 5 additions & 0 deletions cmd/goal/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -1014,12 +1014,17 @@ var infoAppCmd = &cobra.Command{

gsch := params.GlobalStateSchema
lsch := params.LocalStateSchema
epp := params.ExtraProgramPages

fmt.Printf("Application ID: %d\n", appIdx)
fmt.Printf("Creator: %v\n", params.Creator)
fmt.Printf("Approval hash: %v\n", basics.Address(logic.HashProgram(params.ApprovalProgram)))
fmt.Printf("Clear hash: %v\n", basics.Address(logic.HashProgram(params.ClearStateProgram)))

if epp != nil {
fmt.Printf("Extra program pages: %d\n", *epp)
}

if gsch != nil {
fmt.Printf("Max global byteslices: %d\n", gsch.NumByteSlice)
fmt.Printf("Max global integers: %d\n", gsch.NumUint)
Expand Down
5 changes: 3 additions & 2 deletions test/e2e-go/cli/goal/expect/goalAccountInfoTest.exp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ Opted In Apps:
puts "Creating global state app"
set GSTATE_GLOBAL_BYTE_SLICES 10
set GSTATE_LOCAL_BYTE_SLICES 0
set GSTATE_APP_ID [::AlgorandGoal::AppCreate $PRIMARY_WALLET_NAME "" $PRIMARY_ACCOUNT_ADDRESS ${TEAL_PROGS_DIR}/globwrite.teal "str:value_to_write" $GSTATE_GLOBAL_BYTE_SLICES $GSTATE_LOCAL_BYTE_SLICES ${TEAL_PROGS_DIR}/clear_program_state.teal $TEST_PRIMARY_NODE_DIR]
set GSTATE_EXTRA_PAGES 2
set GSTATE_APP_ID [::AlgorandGoal::AppCreateExPages $PRIMARY_WALLET_NAME "" $PRIMARY_ACCOUNT_ADDRESS ${TEAL_PROGS_DIR}/globwrite.teal "str:value_to_write" $GSTATE_GLOBAL_BYTE_SLICES $GSTATE_LOCAL_BYTE_SLICES ${TEAL_PROGS_DIR}/clear_program_state.teal $TEST_PRIMARY_NODE_DIR $GSTATE_EXTRA_PAGES]

puts "Creating local state app"
set LSTATE_GLOBAL_BYTE_SLICES 0
Expand All @@ -133,7 +134,7 @@ Held Assets:
\tID $CCOIN_ASSET_ID, C-Coin, balance 1000 units
\tID $DCOIN_ASSET_ID, D-Coin, balance 10.00 $DCOIN_UNIT_NAME (frozen)
Created Apps:
\tID $GSTATE_APP_ID, global state used 0/0 uints, 1/$GSTATE_GLOBAL_BYTE_SLICES byte slices
\tID $GSTATE_APP_ID, $GSTATE_EXTRA_PAGES extra pages, global state used 0/0 uints, 1/$GSTATE_GLOBAL_BYTE_SLICES byte slices
\tID $LSTATE_APP_ID, global state used 0/0 uints, 0/$LSTATE_GLOBAL_BYTE_SLICES byte slices
Opted In Apps:
\tID $LSTATE_APP_ID, local state used 0/1 uints, 1/$LSTATE_LOCAL_BYTE_SLICES byte slices"
Expand Down
14 changes: 10 additions & 4 deletions test/scripts/e2e_subs/e2e-app-extra-pages.sh
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,6 @@ if [[ $RES != *"${EXPERROR}"* ]]; then
fi

# App create with extra pages, succeeded
${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

# App update
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)
EXP="Created app"
APPID=$(echo $RES | awk '{print $NF}')
Expand All @@ -97,8 +94,13 @@ fi

RES=$(${gcmd} app info --app-id ${APPID} 2>&1 || true)
PROGHASH="Approval hash: 7356635AKR4FJOOKXXBWNN6HDJ5U3O2YWAOSK6NZBPMOGIQSWCL2N74VT4"
EXTRAPAGES="Extra program pages: 1"
if [[ $RES != *"${PROGHASH}"* ]]; then
date '+app-extra-pages-test FAIL the application info should succeed %Y%m%d_%H%M%S'
date '+app-extra-pages-test FAIL the application approval program hash is incorrect %Y%m%d_%H%M%S'
Copy link
Contributor

Choose a reason for hiding this comment

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

Might be nice to migrate toward doing this at the top of e2e .sh programs

filename=$(basename "$0")
scriptname="${filename%.*}"
date "+${scriptname} start %Y%m%d_%H%M%S"

So you can use $scriptname here (and elsewhere). No big deal, just makes copying testing for modification easier.

false
fi
if [[ $RES != *"${EXTRAPAGES}"* ]]; then
date '+app-extra-pages-test FAIL the application extra pages value is incorrect %Y%m%d_%H%M%S'
false
fi

Expand All @@ -114,3 +116,7 @@ if [[ $RES == *"${PROGHASH}"* ]]; then
date '+app-extra-pages-test FAIL the application approval program should have been updated %Y%m%d_%H%M%S'
false
fi
if [[ $RES != *"${EXTRAPAGES}"* ]]; then
date '+app-extra-pages-test FAIL the application extra pages value is incorrect after update %Y%m%d_%H%M%S'
false
fi