diff --git a/Dockerfile b/Dockerfile
index 89296cf6ec..ab55a90940 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -11,7 +11,7 @@ ARG TARGETARCH
ADD https://go.dev/dl/go${GO_VERSION}.linux-${TARGETARCH}.tar.gz /go.tar.gz
# Basic dependencies.
-ENV HOME="/node" DEBIAN_FRONTEND="noninteractive" GOPATH="/node"
+ENV HOME="/node" DEBIAN_FRONTEND="noninteractive" GOPATH="/dist"
RUN apt-get update && \
apt-get install -y --no-install-recommends \
@@ -27,15 +27,15 @@ RUN apt-get update && \
ENV PATH="/usr/local/go/bin:${PATH}"
-COPY ./docker/files/ /node/files
-COPY ./installer/genesis /node/files/run/genesis
-COPY ./cmd/updater/update.sh /node/files/build/update.sh
-COPY ./installer/config.json.example /node/files/run/config.json.example
+COPY ./docker/files/ /dist/files
+COPY ./installer/genesis /dist/files/run/genesis
+COPY ./cmd/updater/update.sh /dist/files/build/update.sh
+COPY ./installer/config.json.example /dist/files/run/config.json.example
# Install algod binaries.
-RUN /node/files/build/install.sh \
+RUN /dist/files/build/install.sh \
-p "${GOPATH}/bin" \
- -d "/node/data" \
+ -d "/algod/data" \
-c "${CHANNEL}" \
-u "${URL}" \
-b "${BRANCH}" \
@@ -55,10 +55,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates
USER algorand
-COPY --chown=algorand:algorand --from=builder "/node/bin/" "/node/bin/"
-COPY --chown=algorand:algorand --from=builder "/node/files/run/" "/node/run/"
+COPY --chown=algorand:algorand --from=builder "/dist/bin/" "/node/bin/"
+COPY --chown=algorand:algorand --from=builder "/dist/files/run/" "/node/run/"
# Expose Algod REST API, Algod Gossip, and Prometheus Metrics ports
EXPOSE $ALGOD_PORT 4160 9100
+WORKDIR /algod
+
CMD ["/node/run/run.sh"]
diff --git a/cmd/catchpointdump/file.go b/cmd/catchpointdump/file.go
index 2a39f98d37..79a426c0a5 100644
--- a/cmd/catchpointdump/file.go
+++ b/cmd/catchpointdump/file.go
@@ -32,11 +32,11 @@ import (
"github.com/spf13/cobra"
+ "github.com/algorand/avm-abi/apps"
cmdutil "github.com/algorand/go-algorand/cmd/util"
"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/bookkeeping"
- "github.com/algorand/go-algorand/data/transactions/logic"
"github.com/algorand/go-algorand/ledger"
"github.com/algorand/go-algorand/ledger/ledgercore"
"github.com/algorand/go-algorand/ledger/store"
@@ -436,7 +436,7 @@ func printAccountsDatabase(databaseName string, stagingTables bool, fileHeader l
func printKeyValue(writer *bufio.Writer, key, value []byte) {
var pretty string
- ai, rest, err := logic.SplitBoxKey(string(key))
+ ai, rest, err := apps.SplitBoxKey(string(key))
if err == nil {
pretty = fmt.Sprintf("box(%d, %s)", ai, base64.StdEncoding.EncodeToString([]byte(rest)))
} else {
diff --git a/cmd/goal/application.go b/cmd/goal/application.go
index 00a35eeac5..e01e1fdee5 100644
--- a/cmd/goal/application.go
+++ b/cmd/goal/application.go
@@ -31,6 +31,7 @@ import (
"github.com/spf13/cobra"
"github.com/algorand/avm-abi/abi"
+ "github.com/algorand/avm-abi/apps"
"github.com/algorand/go-algorand/crypto"
apiclient "github.com/algorand/go-algorand/daemon/algod/api/client"
"github.com/algorand/go-algorand/data/basics"
@@ -198,8 +199,8 @@ func panicIfErr(err error) {
}
}
-func newAppCallBytes(arg string) logic.AppCallBytes {
- appBytes, err := logic.NewAppCallBytes(arg)
+func newAppCallBytes(arg string) apps.AppCallBytes {
+ appBytes, err := apps.NewAppCallBytes(arg)
if err != nil {
reportErrorf(err.Error())
}
@@ -207,16 +208,16 @@ func newAppCallBytes(arg string) logic.AppCallBytes {
}
type appCallInputs struct {
- Accounts []string `codec:"accounts"`
- ForeignApps []uint64 `codec:"foreignapps"`
- ForeignAssets []uint64 `codec:"foreignassets"`
- Boxes []boxRef `codec:"boxes"`
- Args []logic.AppCallBytes `codec:"args"`
+ Accounts []string `codec:"accounts"`
+ ForeignApps []uint64 `codec:"foreignapps"`
+ ForeignAssets []uint64 `codec:"foreignassets"`
+ Boxes []boxRef `codec:"boxes"`
+ Args []apps.AppCallBytes `codec:"args"`
}
type boxRef struct {
- appID uint64 `codec:"app"`
- name logic.AppCallBytes `codec:"name"`
+ appID uint64 `codec:"app"`
+ name apps.AppCallBytes `codec:"name"`
}
// newBoxRef parses a command-line box ref, which is an optional appId, a comma,
@@ -335,7 +336,7 @@ func processAppInputFile() (args [][]byte, accounts []string, foreignApps []uint
return parseAppInputs(inputs)
}
-func getAppInputs() (args [][]byte, accounts []string, apps []uint64, assets []uint64, boxes []transactions.BoxRef) {
+func getAppInputs() (args [][]byte, accounts []string, _ []uint64, assets []uint64, boxes []transactions.BoxRef) {
if appInputFilename != "" {
if appArgs != nil || appStrAccounts != nil || foreignApps != nil || foreignAssets != nil {
reportErrorf("Cannot specify both command-line arguments/resources and JSON input filename")
@@ -348,7 +349,7 @@ func getAppInputs() (args [][]byte, accounts []string, apps []uint64, assets []u
// on it. appArgs became `StringArrayVar` in order to support abi arguments
// which contain commas.
- var encodedArgs []logic.AppCallBytes
+ var encodedArgs []apps.AppCallBytes
for _, arg := range appArgs {
if len(arg) > 0 {
encodedArgs = append(encodedArgs, newAppCallBytes(arg))
diff --git a/cmd/goal/clerk.go b/cmd/goal/clerk.go
index e467064ee1..dce74a81d4 100644
--- a/cmd/goal/clerk.go
+++ b/cmd/goal/clerk.go
@@ -962,7 +962,7 @@ func assembleFileImpl(fname string, printWarnings bool) *logic.OpStream {
}
ops, err := logic.AssembleString(string(text))
if err != nil {
- ops.ReportProblems(fname, os.Stderr)
+ ops.ReportMultipleErrors(fname, os.Stderr)
reportErrorf("%s: %s", fname, err)
}
_, params := getProto(protoVersion)
diff --git a/cmd/goal/interact.go b/cmd/goal/interact.go
index e578713d29..000b7e8459 100644
--- a/cmd/goal/interact.go
+++ b/cmd/goal/interact.go
@@ -29,6 +29,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/algorand/avm-abi/apps"
"github.com/algorand/go-algorand/crypto"
apiclient "github.com/algorand/go-algorand/daemon/algod/api/client"
"github.com/algorand/go-algorand/data/basics"
@@ -513,7 +514,7 @@ var appExecuteCmd = &cobra.Command{
var inputs appCallInputs
for _, arg := range proc.Args {
- var callArg logic.AppCallBytes
+ var callArg apps.AppCallBytes
callArg.Encoding = arg.Kind
if !procFlags.Changed(arg.Name) && arg.Default != "" {
diff --git a/cmd/goal/multisig.go b/cmd/goal/multisig.go
index e4526f44f8..5db3d09af9 100644
--- a/cmd/goal/multisig.go
+++ b/cmd/goal/multisig.go
@@ -163,7 +163,7 @@ var signProgramCmd = &cobra.Command{
}
ops, err := logic.AssembleString(string(text))
if err != nil {
- ops.ReportProblems(programSource, os.Stderr)
+ ops.ReportMultipleErrors(programSource, os.Stderr)
reportErrorf("%s: %s", programSource, err)
}
if outname == "" {
diff --git a/cmd/pingpong/runCmd.go b/cmd/pingpong/runCmd.go
index ac95b16e07..1ebf4fc95c 100644
--- a/cmd/pingpong/runCmd.go
+++ b/cmd/pingpong/runCmd.go
@@ -316,7 +316,7 @@ var runCmd = &cobra.Command{
}
ops, err := logic.AssembleString(programStr)
if err != nil {
- ops.ReportProblems(teal, os.Stderr)
+ ops.ReportMultipleErrors(teal, os.Stderr)
reportErrorf("Internal error, cannot assemble %v \n", programStr)
}
cfg.Program = ops.Program
diff --git a/daemon/algod/api/server/v2/handlers.go b/daemon/algod/api/server/v2/handlers.go
index e314de31a7..21e1f91703 100644
--- a/daemon/algod/api/server/v2/handlers.go
+++ b/daemon/algod/api/server/v2/handlers.go
@@ -30,6 +30,7 @@ import (
"github.com/labstack/echo/v4"
+ "github.com/algorand/avm-abi/apps"
"github.com/algorand/go-codec/codec"
"github.com/algorand/go-algorand/agreement"
@@ -1382,7 +1383,7 @@ func (v2 *Handlers) GetApplicationBoxes(ctx echo.Context, applicationID uint64,
appIdx := basics.AppIndex(applicationID)
ledger := v2.Node.LedgerForAPI()
lastRound := ledger.Latest()
- keyPrefix := logic.MakeBoxKey(appIdx, "")
+ keyPrefix := apps.MakeBoxKey(uint64(appIdx), "")
requestedMax, algodMax := nilToZero(params.Max), v2.Node.Config().MaxAPIBoxPerApplication
max := applicationBoxesMaxKeys(requestedMax, algodMax)
@@ -1428,7 +1429,7 @@ func (v2 *Handlers) GetApplicationBoxByName(ctx echo.Context, applicationID uint
lastRound := ledger.Latest()
encodedBoxName := params.Name
- boxNameBytes, err := logic.NewAppCallBytes(encodedBoxName)
+ boxNameBytes, err := apps.NewAppCallBytes(encodedBoxName)
if err != nil {
return badRequest(ctx, err, err.Error(), v2.Log)
}
@@ -1437,7 +1438,7 @@ func (v2 *Handlers) GetApplicationBoxByName(ctx echo.Context, applicationID uint
return badRequest(ctx, err, err.Error(), v2.Log)
}
- value, err := ledger.LookupKv(lastRound, logic.MakeBoxKey(appIdx, string(boxName)))
+ value, err := ledger.LookupKv(lastRound, apps.MakeBoxKey(uint64(appIdx), string(boxName)))
if err != nil {
return internalError(ctx, err, errFailedLookingUpLedger, v2.Log)
}
@@ -1528,7 +1529,7 @@ func (v2 *Handlers) TealCompile(ctx echo.Context, params model.TealCompileParams
ops, err := logic.AssembleString(source)
if err != nil {
sb := strings.Builder{}
- ops.ReportProblems("", &sb)
+ ops.ReportMultipleErrors("", &sb)
return badRequest(ctx, err, sb.String(), v2.Log)
}
pd := logic.HashProgram(ops.Program)
diff --git a/daemon/algod/api/server/v2/test/handlers_test.go b/daemon/algod/api/server/v2/test/handlers_test.go
index 5584224941..dedd902c94 100644
--- a/daemon/algod/api/server/v2/test/handlers_test.go
+++ b/daemon/algod/api/server/v2/test/handlers_test.go
@@ -815,7 +815,7 @@ func TestTealCompile(t *testing.T) {
t.Parallel()
params := model.TealCompileParams{}
- tealCompileTest(t, nil, 200, true, params, nil) // nil program should work
+ tealCompileTest(t, nil, 400, true, params, nil) // nil program should NOT work
goodProgram := fmt.Sprintf(`#pragma version %d
int 1
diff --git a/data/transactions/logic/assembler.go b/data/transactions/logic/assembler.go
index 3ed539feab..9e8da08d1a 100644
--- a/data/transactions/logic/assembler.go
+++ b/data/transactions/logic/assembler.go
@@ -1622,7 +1622,7 @@ func isFullSpec(spec OpSpec) bool {
}
// mergeProtos allows us to support typetracking of pseudo-ops which are given an improper number of immediates
-//by creating a new proto that is a combination of all the pseudo-op's possibilities
+// by creating a new proto that is a combination of all the pseudo-op's possibilities
func mergeProtos(specs map[int]OpSpec) (Proto, uint64, bool) {
var args StackTypes
var returns StackTypes
@@ -1857,10 +1857,13 @@ func splitTokens(tokens []string) (current, rest []string) {
// assemble reads text from an input and accumulates the program
func (ops *OpStream) assemble(text string) error {
- fin := strings.NewReader(text)
if ops.Version > LogicVersion && ops.Version != assemblerNoVersion {
return ops.errorf("Can not assemble version %d", ops.Version)
}
+ if strings.TrimSpace(text) == "" {
+ return ops.errorf("Cannot assemble empty program text")
+ }
+ fin := strings.NewReader(text)
scanner := bufio.NewScanner(fin)
for scanner.Scan() {
ops.sourceLine++
@@ -2411,8 +2414,19 @@ func (ops *OpStream) warnf(format string, a ...interface{}) error {
return ops.warn(fmt.Errorf(format, a...))
}
-// ReportProblems issues accumulated warnings and outputs errors to an io.Writer.
-func (ops *OpStream) ReportProblems(fname string, writer io.Writer) {
+// ReportMultipleErrors issues accumulated warnings and outputs errors to an io.Writer.
+// In the case of exactly 1 error and no warnings, a slightly different format is provided
+// to handle the cases when the original error is or isn't reported elsewhere.
+// In the case of > 10 errors, only the first 10 errors will be reported.
+func (ops *OpStream) ReportMultipleErrors(fname string, writer io.Writer) {
+ if len(ops.Errors) == 1 && len(ops.Warnings) == 0 {
+ prefix := ""
+ if fname != "" {
+ prefix = fmt.Sprintf("%s: ", fname)
+ }
+ fmt.Fprintf(writer, "%s1 error: %s\n", prefix, ops.Errors[0])
+ return
+ }
for i, e := range ops.Errors {
if i > 9 {
break
diff --git a/data/transactions/logic/assembler_test.go b/data/transactions/logic/assembler_test.go
index 24a3afaf50..cc5cd97a44 100644
--- a/data/transactions/logic/assembler_test.go
+++ b/data/transactions/logic/assembler_test.go
@@ -19,6 +19,7 @@ package logic
import (
"bytes"
"encoding/hex"
+ "errors"
"fmt"
"regexp"
"strings"
@@ -1457,7 +1458,7 @@ done:`
require.Equal(t, expectedProgBytes, ops.Program)
}
-func TestMultipleErrors(t *testing.T) {
+func TestSeveralErrors(t *testing.T) {
partitiontest.PartitionTest(t)
t.Parallel()
@@ -3053,3 +3054,108 @@ func TestAssemblePushConsts(t *testing.T) {
source = `pushbytess "x" "y"; +`
testProg(t, source, AssemblerMaxVersion, Expect{1, "+ arg 1 wanted type uint64 got []byte"})
}
+
+func TestAssembleEmpty(t *testing.T) {
+ partitiontest.PartitionTest(t)
+ t.Parallel()
+
+ emptyExpect := Expect{0, "Cannot assemble empty program text"}
+ emptyPrograms := []string{
+ "",
+ " ",
+ " \n\t\t\t\n\n ",
+ " \n \t \t \t \n \n \n\n",
+ }
+
+ nonEmpty := " \n \t \t \t int 1 \n \n \t \t \n\n"
+
+ for version := uint64(1); version <= AssemblerMaxVersion; version++ {
+ for _, prog := range emptyPrograms {
+ testProg(t, prog, version, emptyExpect)
+ }
+ testProg(t, nonEmpty, version)
+ }
+}
+
+func TestReportMultipleErrors(t *testing.T) {
+ partitiontest.PartitionTest(t)
+ t.Parallel()
+
+ assertWithMsg := func(t *testing.T, expectedOutput string, b bytes.Buffer) {
+ if b.String() != expectedOutput {
+ t.Errorf("Unexpected output: got %q, want %q", b.String(), expectedOutput)
+ }
+ }
+
+ ops := &OpStream{
+ Errors: []lineError{
+ {Line: 1, Err: errors.New("error 1")},
+ {Err: errors.New("error 2")},
+ {Line: 3, Err: errors.New("error 3")},
+ },
+ Warnings: []error{
+ errors.New("warning 1"),
+ errors.New("warning 2"),
+ },
+ }
+
+ // Test the case where fname is not empty
+ var b bytes.Buffer
+ ops.ReportMultipleErrors("test.txt", &b)
+ expected := `test.txt: 1: error 1
+test.txt: 0: error 2
+test.txt: 3: error 3
+test.txt: warning 1
+test.txt: warning 2
+`
+ assertWithMsg(t, expected, b)
+
+ // Test the case where fname is empty
+ b.Reset()
+ ops.ReportMultipleErrors("", &b)
+ expected = `1: error 1
+0: error 2
+3: error 3
+warning 1
+warning 2
+`
+ assertWithMsg(t, expected, b)
+
+ // no errors or warnings at all
+ ops = &OpStream{}
+ b.Reset()
+ ops.ReportMultipleErrors("blah blah", &b)
+ expected = ""
+ assertWithMsg(t, expected, b)
+
+ // more than 10 errors:
+ file := "great-file.go"
+ les := []lineError{}
+ expectedStrs := []string{}
+ for i := 1; i <= 11; i++ {
+ errS := fmt.Errorf("error %d", i)
+ les = append(les, lineError{i, errS})
+ if i <= 10 {
+ expectedStrs = append(expectedStrs, fmt.Sprintf("%s: %d: %s", file, i, errS))
+ }
+ }
+ expected = strings.Join(expectedStrs, "\n") + "\n"
+ ops = &OpStream{Errors: les}
+ b.Reset()
+ ops.ReportMultipleErrors(file, &b)
+ assertWithMsg(t, expected, b)
+
+ // exactly 1 error + filename
+ ops = &OpStream{Errors: []lineError{{42, errors.New("super annoying error")}}}
+ b.Reset()
+ ops.ReportMultipleErrors("galaxy.py", &b)
+ expected = "galaxy.py: 1 error: 42: super annoying error\n"
+ assertWithMsg(t, expected, b)
+
+ // exactly 1 error w/o filename
+ ops = &OpStream{Errors: []lineError{{42, errors.New("super annoying error")}}}
+ b.Reset()
+ ops.ReportMultipleErrors("", &b)
+ expected = "1 error: 42: super annoying error\n"
+ assertWithMsg(t, expected, b)
+}
diff --git a/data/transactions/logic/box.go b/data/transactions/logic/box.go
index 0f82f9a560..ebc1c25f2e 100644
--- a/data/transactions/logic/box.go
+++ b/data/transactions/logic/box.go
@@ -17,7 +17,6 @@
package logic
import (
- "encoding/binary"
"fmt"
"github.com/algorand/go-algorand/data/basics"
@@ -283,36 +282,3 @@ func opBoxPut(cx *EvalContext) error {
appAddr := cx.getApplicationAddress(cx.appID)
return cx.Ledger.NewBox(cx.appID, name, value, appAddr)
}
-
-const boxPrefix = "bx:"
-const boxPrefixLength = len(boxPrefix)
-const boxNameIndex = boxPrefixLength + 8 // len("bx:") + 8 (appIdx, big-endian)
-
-// MakeBoxKey creates the key that a box named `name` under app `appIdx` should use.
-func MakeBoxKey(appIdx basics.AppIndex, name string) string {
- /* This format is chosen so that a simple indexing scheme on the key would
- allow for quick lookups of all the boxes of a certain app, or even all
- the boxes of a certain app with a certain prefix.
-
- The "bx:" prefix is so that the kvstore might be usable for things
- besides boxes.
- */
- key := make([]byte, boxNameIndex+len(name))
- copy(key, boxPrefix)
- binary.BigEndian.PutUint64(key[boxPrefixLength:], uint64(appIdx))
- copy(key[boxNameIndex:], name)
- return string(key)
-}
-
-// SplitBoxKey extracts an appid and box name from a string that was created by MakeBoxKey()
-func SplitBoxKey(key string) (basics.AppIndex, string, error) {
- if len(key) < boxNameIndex {
- return 0, "", fmt.Errorf("SplitBoxKey() cannot extract AppIndex as key (%s) too short (length=%d)", key, len(key))
- }
- if key[:boxPrefixLength] != boxPrefix {
- return 0, "", fmt.Errorf("SplitBoxKey() illegal app box prefix in key (%s). Expected prefix '%s'", key, boxPrefix)
- }
- keyBytes := []byte(key)
- app := basics.AppIndex(binary.BigEndian.Uint64(keyBytes[boxPrefixLength:boxNameIndex]))
- return app, key[boxNameIndex:], nil
-}
diff --git a/data/transactions/logic/box_test.go b/data/transactions/logic/box_test.go
index fbca75ee0b..77c3adf1b2 100644
--- a/data/transactions/logic/box_test.go
+++ b/data/transactions/logic/box_test.go
@@ -27,7 +27,6 @@ import (
"github.com/algorand/go-algorand/data/txntest"
"github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-algorand/test/partitiontest"
- "github.com/stretchr/testify/require"
)
func TestBoxNewDel(t *testing.T) {
@@ -568,45 +567,3 @@ func TestBoxTotals(t *testing.T) {
logic.TestApp(t, `int 888; app_params_get AppAddress; assert;
acct_params_get AcctTotalBoxBytes; pop; int 35; ==`, ep)
}
-
-func TestMakeBoxKey(t *testing.T) {
- partitiontest.PartitionTest(t)
- t.Parallel()
-
- type testCase struct {
- description string
- name string
- app basics.AppIndex
- key string
- err string
- }
-
- pp := func(tc testCase) string {
- return fmt.Sprintf("<<<%s>>> (name, app) = (%#v, %d) --should--> key = %#v (err = [%s])", tc.description, tc.name, tc.app, tc.key, tc.err)
- }
-
- var testCases = []testCase{
- // COPACETIC:
- {"zero appid", "stranger", 0, "bx:\x00\x00\x00\x00\x00\x00\x00\x00stranger", ""},
- {"typical", "348-8uj", 131231, "bx:\x00\x00\x00\x00\x00\x02\x00\x9f348-8uj", ""},
- {"empty box name", "", 42, "bx:\x00\x00\x00\x00\x00\x00\x00*", ""},
- {"random byteslice", "{\xbb\x04\a\xd1\xe2\xc6I\x81{", 13475904583033571713, "bx:\xbb\x04\a\xd1\xe2\xc6I\x81{\xbb\x04\a\xd1\xe2\xc6I\x81{", ""},
-
- // ERRORS:
- {"too short", "", 0, "stranger", "SplitBoxKey() cannot extract AppIndex as key (stranger) too short (length=8)"},
- {"wrong prefix", "", 0, "strangersINTHEdark", "SplitBoxKey() illegal app box prefix in key (strangersINTHEdark). Expected prefix 'bx:'"},
- }
-
- for _, tc := range testCases {
- app, name, err := logic.SplitBoxKey(tc.key)
-
- if tc.err == "" {
- key := logic.MakeBoxKey(tc.app, tc.name)
- require.Equal(t, tc.app, app, pp(tc))
- require.Equal(t, tc.name, name, pp(tc))
- require.Equal(t, tc.key, key, pp(tc))
- } else {
- require.EqualError(t, err, tc.err, pp(tc))
- }
- }
-}
diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go
index 2815c2e97c..f7bb120482 100644
--- a/data/transactions/logic/eval.go
+++ b/data/transactions/logic/eval.go
@@ -1822,6 +1822,15 @@ func opBytesSqrt(cx *EvalContext) error {
return nil
}
+func nonzero(b []byte) []byte {
+ for i := range b {
+ if b[i] != 0 {
+ return b[i:]
+ }
+ }
+ return nil
+}
+
func opBytesLt(cx *EvalContext) error {
last := len(cx.stack) - 1
prev := last - 1
@@ -1830,9 +1839,11 @@ func opBytesLt(cx *EvalContext) error {
return errors.New("math attempted on large byte-array")
}
- rhs := new(big.Int).SetBytes(cx.stack[last].Bytes)
- lhs := new(big.Int).SetBytes(cx.stack[prev].Bytes)
- cx.stack[prev] = boolToSV(lhs.Cmp(rhs) < 0)
+ rhs := nonzero(cx.stack[last].Bytes)
+ lhs := nonzero(cx.stack[prev].Bytes)
+
+ cx.stack[prev] = boolToSV(len(lhs) < len(rhs) || bytes.Compare(lhs, rhs) < 0)
+
cx.stack = cx.stack[:last]
return nil
}
@@ -1866,9 +1877,10 @@ func opBytesEq(cx *EvalContext) error {
return errors.New("math attempted on large byte-array")
}
- rhs := new(big.Int).SetBytes(cx.stack[last].Bytes)
- lhs := new(big.Int).SetBytes(cx.stack[prev].Bytes)
- cx.stack[prev] = boolToSV(lhs.Cmp(rhs) == 0)
+ rhs := nonzero(cx.stack[last].Bytes)
+ lhs := nonzero(cx.stack[prev].Bytes)
+
+ cx.stack[prev] = boolToSV(bytes.Equal(lhs, rhs))
cx.stack = cx.stack[:last]
return nil
}
diff --git a/data/transactions/logic/evalCrypto_test.go b/data/transactions/logic/evalCrypto_test.go
index 26665c7041..65f0787a97 100644
--- a/data/transactions/logic/evalCrypto_test.go
+++ b/data/transactions/logic/evalCrypto_test.go
@@ -147,18 +147,27 @@ func BenchmarkVerify(b *testing.B) {
benches := [][]string{
{"pop", "", "int 1234576; int 6712; pop; pop", "int 1"},
{"add", "", "int 1234576; int 6712; +; pop", "int 1"},
- /*
- {"ed25519verify_bare", "", `byte 0x
- byte 0x
- addr
- ed25519verify_bare
- assert`, "int 1"},*/
- {"ecdsa_verify", "", `byte 0x71a5910445820f57989c027bdf9391c80097874d249e0f38bf90834fdec2877f
+ {"ed25519verify_bare", "", `
+byte 0x62fdfc072182654f163f5f0f9a621d729566c74d0aa413bf009c9800418c19cd
+byte 0xaab40a8b4f1f386504af2473804abbc03bbd94506e8e0c8db881fc2b2c3aee65b867b25caa47fa25ae2105bf1731398df336213707f2d25f9b1d31b3dc133307;
+addr C7ZCK6N2AJQMVEP4FRTK2UW45UFR6DKPRJHJVWB5O4VQOZMFPK2KCMR7M4
+ed25519verify_bare; assert
+`, "int 1"},
+ {"ecdsa_verify k1", "", `
+byte 0x71a5910445820f57989c027bdf9391c80097874d249e0f38bf90834fdec2877f
byte 0x5eb27782eb1a5df8de9a5d51613ad5ca730840ddf4af919c6feb15cde14f9978
byte 0x0cb3c0d636ed991ee030d09c295de3121eb166cb9e1552cf0ef0fb2358f35f0f
byte 0x79de0699673571df1de8486718d06a3e7838f6831ec4ef3fb963788fbfb773b7
byte 0xd76446a3393af3e2eefada16df80cc6a881a56f4cf41fa2ab4769c5708ce878d
ecdsa_verify Secp256k1
+assert`, "int 1"},
+ {"ecdsa_verify r1", "", `
+byte 0x71a5910445820f57989c027bdf9391c80097874d249e0f38bf90834fdec2877f
+byte 0xc010fc83ea196d6f5ce8a44637060bdcfb5bf1199cfc5bb893684d450c4f160c
+byte 0x8e391a7b9cd75a99e8ebfe703036caebd9e91ae8339bd7e2abfb0f273eb8e972
+byte 0x13e49a19378bbfa8d55ac81a35b87d7bae456c79fcf04a78803d8eb45b253fab
+byte 0xa2d237cd897ca70787abf04d2155c6dc2fbe26fd642e0472cd75c13dc919ef1a
+ecdsa_verify Secp256r1
assert`, "int 1"},
{"vrf_verify", "", `byte 0x72
byte 0xae5b66bdf04b4c010bfe32b2fc126ead2107b697634f6f7337b9bff8785ee111200095ece87dde4dbe87343f6df3b107d91798c8a7eb1245d3bb9c5aafb093358c13e6ae1111a55717e895fd15f99f07
diff --git a/data/transactions/logic/eval_test.go b/data/transactions/logic/eval_test.go
index 8d23b20416..f63eae7dad 100644
--- a/data/transactions/logic/eval_test.go
+++ b/data/transactions/logic/eval_test.go
@@ -3728,27 +3728,37 @@ main:
}
func BenchmarkByteLogic(b *testing.B) {
+ e64 := "byte 0x8090a0b0c0d0e0f0;"
+ o64 := "byte 0x1020304050607080;"
+ hex128e := "90a0b0c0d0e0f0001020304050607080"
+ hex128o := "102030405060708090a0b0c0d0e0f000"
+ e128 := "byte 0x" + strings.Repeat(hex128e, 1) + ";"
+ o128 := "byte 0x" + strings.Repeat(hex128o, 1) + ";"
+ e256 := "byte 0x" + strings.Repeat(hex128e, 2) + ";"
+ o256 := "byte 0x" + strings.Repeat(hex128o, 2) + ";"
+ e512 := "byte 0x" + strings.Repeat(hex128e, 4) + ";"
+ o512 := "byte 0x" + strings.Repeat(hex128o, 4) + ";"
+
benches := [][]string{
- {"b&", "", "byte 0x012345678901feab; byte 0x01ffffffffffffff; b&; pop", "int 1"},
- {"b|", "", "byte 0x0ffff1234576abef; byte 0x1202120212021202; b|; pop", "int 1"},
- {"b^", "", "byte 0x0ffff1234576abef; byte 0x1202120212021202; b^; pop", "int 1"},
- {"b~", "byte 0x0123457673624736", "b~", "pop; int 1"},
-
- {"b&big",
- "byte 0x0123457601234576012345760123457601234576012345760123457601234576",
- "byte 0x01ffffffffffffff01ffffffffffffff01234576012345760123457601234576; b&",
- "pop; int 1"},
- {"b|big",
- "byte 0x0123457601234576012345760123457601234576012345760123457601234576",
- "byte 0xffffff01ffffffffffffff01234576012345760123457601234576; b|",
- "pop; int 1"},
- {"b^big", "", // u256^u256
- `byte 0x123457601234576012345760123457601234576012345760123457601234576a
- byte 0xf123457601234576012345760123457601234576012345760123457601234576; b^; pop`,
- "int 1"},
- {"b~big", "byte 0xa123457601234576012345760123457601234576012345760123457601234576",
- "b~",
- "pop; int 1"},
+ {"b& 8", "", e64 + o64 + "b&; pop", "int 1"},
+ {"b| 8", "", e64 + o64 + "b|; pop", "int 1"},
+ {"b^ 8", "", e64 + o64 + "b^; pop", "int 1"},
+ {"b~ 8", e64, "b~", "pop; int 1"},
+
+ {"b& 16", "", e128 + o128 + "b&; pop", "int 1"},
+ {"b| 16", "", e128 + o128 + "b|; pop", "int 1"},
+ {"b^ 16", "", e128 + o128 + "b^; pop", "int 1"},
+ {"b~ 16", e128, "b~", "pop; int 1"},
+
+ {"b& 32", "", e256 + o256 + "b&; pop", "int 1"},
+ {"b| 32", "", e256 + o256 + "b|; pop", "int 1"},
+ {"b^ 32", "", e256 + o256 + "b^; pop", "int 1"},
+ {"b~ 32", e256, "b~", "pop; int 1"},
+
+ {"b& 64", "", e512 + o512 + "b&; pop", "int 1"},
+ {"b| 64", "", e512 + o512 + "b|; pop", "int 1"},
+ {"b^ 64", "", e512 + o512 + "b^; pop", "int 1"},
+ {"b~ 64", e512, "b~", "pop; int 1"},
}
for _, bench := range benches {
b.Run(bench[0], func(b *testing.B) {
@@ -3759,44 +3769,79 @@ func BenchmarkByteLogic(b *testing.B) {
}
func BenchmarkByteMath(b *testing.B) {
+ u64 := "byte 0x8090a0b0c0d0e0f0;"
+ hex128 := "102030405060708090a0b0c0d0e0f000"
+ u128 := "byte 0x" + strings.Repeat(hex128, 1) + ";"
+ u256 := "byte 0x" + strings.Repeat(hex128, 2) + ";"
+ u512 := "byte 0x" + strings.Repeat(hex128, 4) + ";"
+
benches := [][]string{
- {"bpop", "", "byte 0x01ffffffffffffff; pop", "int 1"},
-
- {"b+", "byte 0x01234576", "byte 0x01ffffffffffffff; b+", "pop; int 1"},
- {"b-", "byte 0x0ffff1234576", "byte 0x1202; b-", "pop; int 1"},
- {"b*", "", "byte 0x01234576; byte 0x0223627389; b*; pop", "int 1"},
- {"b/", "", "byte 0x0123457673624736; byte 0x0223627389; b/; pop", "int 1"},
- {"b%", "", "byte 0x0123457673624736; byte 0x0223627389; b/; pop", "int 1"},
- {"bsqrt", "", "byte 0x0123457673624736; bsqrt; pop", "int 1"},
-
- {"b+big", // u256 + u256
- "byte 0x0123457601234576012345760123457601234576012345760123457601234576",
- "byte 0x01ffffffffffffff01ffffffffffffff01234576012345760123457601234576; b+",
- "pop; int 1"},
- {"b-big", // second is a bit small, so we can subtract it over and over
- "byte 0x0123457601234576012345760123457601234576012345760123457601234576",
- "byte 0xffffff01ffffffffffffff01234576012345760123457601234576; b-",
- "pop; int 1"},
- {"b*big", "", // u256*u256
- `byte 0xa123457601234576012345760123457601234576012345760123457601234576
- byte 0xf123457601234576012345760123457601234576012345760123457601234576; b*; pop`,
- "int 1"},
- {"b/big", "", // u256 / u128 (half sized divisor seems pessimal)
- `byte 0xa123457601234576012345760123457601234576012345760123457601234576
- byte 0x34576012345760123457601234576312; b/; pop`,
- "int 1"},
- {"b%big", "", // u256 / u128 (half sized divisor seems pessimal)
- `byte 0xa123457601234576012345760123457601234576012345760123457601234576
- byte 0x34576012345760123457601234576312; b/; pop`,
- "int 1"},
- {"bsqrt-big", "",
- `byte 0xa123457601234576012345760123457601234576012345760123457601234576
- bsqrt; pop`,
- "int 1"},
+ {"bytec", u128 + "pop"},
+
+ {"b+ 128", u128 + u128 + "b+; pop"},
+ {"b- 128", u128 + u128 + "b-; pop"},
+ {"b* 128", u128 + u128 + "b*; pop"},
+ // half sized divisor seems pessimal for / and %
+ {"b/ 128", u128 + u64 + "b/; pop"},
+ {"b% 128", u128 + u64 + "b%; pop"},
+ {"bsqrt 128", u128 + "bsqrt; pop"},
+
+ {"b+ 256", u256 + u256 + "b+; pop"},
+ {"b- 256", u256 + u256 + "b-; pop"},
+ {"b* 256", u256 + u256 + "b*; pop"},
+ {"b/ 256", u256 + u128 + "b/; pop"},
+ {"b% 256", u256 + u128 + "b%; pop"},
+ {"bsqrt 256", u256 + "bsqrt; pop"},
+
+ {"b+ 512", u512 + u512 + "b+; pop"},
+ {"b- 512", u512 + u512 + "b-; pop"},
+ {"b* 512", u512 + u512 + "b*; pop"},
+ {"b/ 512", u512 + u256 + "b/; pop"},
+ {"b% 512", u512 + u256 + "b%; pop"},
+ {"bsqrt 512", u512 + "bsqrt; pop"},
+
+ {"bytec recheck", u128 + "pop"},
}
for _, bench := range benches {
b.Run(bench[0], func(b *testing.B) {
- benchmarkOperation(b, bench[1], bench[2], bench[3])
+ b.ReportAllocs()
+ benchmarkOperation(b, "", bench[1], "int 1")
+ })
+ }
+}
+
+func BenchmarkByteCompare(b *testing.B) {
+ u64 := "byte 0x8090a0b0c0d0e0f0;"
+ hex128 := "102030405060708090a0b0c0d0e0f000"
+ u128 := "byte 0x" + strings.Repeat(hex128, 1) + ";"
+ u256 := "byte 0x" + strings.Repeat(hex128, 2) + ";"
+ u512 := "byte 0x" + strings.Repeat(hex128, 4) + ";"
+ //u4k := "byte 0x" + strings.Repeat(hex128, 256) + ";"
+
+ benches := [][]string{
+ {"b== 64", u64 + u64 + "b==; pop"},
+ {"b< 64", u64 + u64 + "b<; pop"},
+ {"b<= 64", u64 + u64 + "b<=; pop"},
+ {"b== 128", u128 + u128 + "b==; pop"},
+ {"b< 128", u128 + u128 + "b<; pop"},
+ {"b<= 128", u128 + u128 + "b<=; pop"},
+ {"b== 256", u256 + u256 + "b==; pop"},
+ {"b< 256", u256 + u256 + "b<; pop"},
+ {"b<= 256", u256 + u256 + "b<=; pop"},
+ {"b== 512", u512 + u512 + "b==; pop"},
+ {"b< 512", u512 + u512 + "b<; pop"},
+ {"b<= 512", u512 + u512 + "b<=; pop"},
+ // These can only be run with the maxByteMathSize check removed. They
+ // show that we can remove that check in a later AVM version, as there
+ // is no appreciable cost to even a 4k compare.
+ // {"b== 4k", u4k + u4k + "b==; pop"},
+ // {"b< 4k", u4k + u4k + "b<; pop"},
+ // {"b<= 4k", u4k + u4k + "b<=; pop"},
+ }
+ for _, bench := range benches {
+ b.Run(bench[0], func(b *testing.B) {
+ b.ReportAllocs()
+ benchmarkOperation(b, "", bench[1], "int 1")
})
}
}
@@ -4871,9 +4916,20 @@ func TestBytesCompare(t *testing.T) {
testPanics(t, "byte 0x10; int 65; bzero; b<=", 4)
testAccepts(t, "byte 0x10; int 64; bzero; b>", 4)
testPanics(t, "byte 0x10; int 65; bzero; b>", 4)
+ testAccepts(t, "byte 0x1010; byte 0x10; b<; !", 4)
+
+ // All zero input are interesting, because they lead to bytes.Compare being
+ // called with nils. Show that is correct.
+ testAccepts(t, "byte 0x10; byte 0x00; b<; !", 4)
+ testAccepts(t, "byte 0x10; byte 0x0000; b<; !", 4)
+ testAccepts(t, "byte 0x00; byte 0x10; b<", 4)
+ testAccepts(t, "byte 0x0000; byte 0x10; b<", 4)
+ testAccepts(t, "byte 0x0000; byte 0x00; b<; !", 4)
+ testAccepts(t, "byte 0x; byte 0x00; b==", 4)
testAccepts(t, "byte 0x11; byte 0x10; b>", 4)
testAccepts(t, "byte 0x11; byte 0x0010; b>", 4)
+ testAccepts(t, "byte 0x1010; byte 0x11; b>", 4)
testAccepts(t, "byte 0x11; byte 0x10; b>=", 4)
testAccepts(t, "byte 0x11; byte 0x0011; b>=", 4)
diff --git a/data/transactions/logic/parsing.go b/data/transactions/logic/parsing.go
deleted file mode 100644
index 6bb2c5c714..0000000000
--- a/data/transactions/logic/parsing.go
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright (C) 2019-2023 Algorand, Inc.
-// This file is part of go-algorand
-//
-// go-algorand is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// go-algorand is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with go-algorand. If not, see .
-
-package logic
-
-import (
- "encoding/base32"
- "encoding/base64"
- "encoding/binary"
- "fmt"
- "strconv"
- "strings"
-
- "github.com/algorand/avm-abi/abi"
- "github.com/algorand/go-algorand/data/basics"
-)
-
-// AppCallBytes represents an encoding and a value of an app call argument.
-type AppCallBytes struct {
- Encoding string `codec:"encoding"`
- Value string `codec:"value"`
-}
-
-// NewAppCallBytes parses an argument of the form "encoding:value" to AppCallBytes.
-func NewAppCallBytes(arg string) (AppCallBytes, error) {
- parts := strings.SplitN(arg, ":", 2)
- if len(parts) != 2 {
- return AppCallBytes{}, fmt.Errorf("all arguments and box names should be of the form 'encoding:value'")
- }
- return AppCallBytes{
- Encoding: parts[0],
- Value: parts[1],
- }, nil
-}
-
-// Raw converts an AppCallBytes arg to a byte array.
-func (arg AppCallBytes) Raw() (rawValue []byte, parseErr error) {
- switch arg.Encoding {
- case "str", "string":
- rawValue = []byte(arg.Value)
- case "int", "integer":
- num, err := strconv.ParseUint(arg.Value, 10, 64)
- if err != nil {
- parseErr = fmt.Errorf("Could not parse uint64 from string (%s): %v", arg.Value, err)
- return
- }
- ibytes := make([]byte, 8)
- binary.BigEndian.PutUint64(ibytes, num)
- rawValue = ibytes
- case "addr", "address":
- addr, err := basics.UnmarshalChecksumAddress(arg.Value)
- if err != nil {
- parseErr = fmt.Errorf("Could not unmarshal checksummed address from string (%s): %v", arg.Value, err)
- return
- }
- rawValue = addr[:]
- case "b32", "base32", "byte base32":
- data, err := base32.StdEncoding.DecodeString(arg.Value)
- if err != nil {
- parseErr = fmt.Errorf("Could not decode base32-encoded string (%s): %v", arg.Value, err)
- return
- }
- rawValue = data
- case "b64", "base64", "byte base64":
- data, err := base64.StdEncoding.DecodeString(arg.Value)
- if err != nil {
- parseErr = fmt.Errorf("Could not decode base64-encoded string (%s): %v", arg.Value, err)
- 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)
- }
- return
-}
diff --git a/data/transactions/logic/parsing_test.go b/data/transactions/logic/parsing_test.go
deleted file mode 100644
index 14830b011f..0000000000
--- a/data/transactions/logic/parsing_test.go
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright (C) 2019-2023 Algorand, Inc.
-// This file is part of go-algorand
-//
-// go-algorand is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// go-algorand is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with go-algorand. If not, see .
-
-package logic
-
-import (
- "encoding/base32"
- "encoding/base64"
- "encoding/binary"
- "fmt"
- "math"
- "testing"
-
- "github.com/algorand/avm-abi/abi"
- "github.com/algorand/go-algorand/data/basics"
-
- "github.com/algorand/go-algorand/test/partitiontest"
- "github.com/stretchr/testify/require"
-)
-
-func TestNewAppCallBytes(t *testing.T) {
- partitiontest.PartitionTest(t)
- t.Parallel()
-
- t.Run("errors", func(t *testing.T) {
- t.Parallel()
- _, err := NewAppCallBytes("hello")
- require.Error(t, err)
-
- for _, v := range []string{":x", "int:-1"} {
- acb, err := NewAppCallBytes(v)
- _, err = acb.Raw()
- require.Error(t, err)
- }
- })
-
- for _, v := range []string{"hello", "1:2"} {
- for _, e := range []string{"str", "string"} {
- v, e := v, e
- t.Run(fmt.Sprintf("encoding=%v,value=%v", e, v), func(t *testing.T) {
- t.Parallel()
- acb, err := NewAppCallBytes(fmt.Sprintf("%v:%v", e, v))
- require.NoError(t, err)
- r, err := acb.Raw()
- require.NoError(t, err)
- require.Equal(t, v, string(r))
- })
- }
-
- for _, e := range []string{"b32", "base32", "byte base32"} {
- ve := base32.StdEncoding.EncodeToString([]byte(v))
- e := e
- t.Run(fmt.Sprintf("encoding=%v,value=%v", e, ve), func(t *testing.T) {
- acb, err := NewAppCallBytes(fmt.Sprintf("%v:%v", e, ve))
- require.NoError(t, err)
- r, err := acb.Raw()
- require.NoError(t, err)
- require.Equal(t, ve, base32.StdEncoding.EncodeToString(r))
- })
- }
-
- for _, e := range []string{"b64", "base64", "byte base64"} {
- ve := base64.StdEncoding.EncodeToString([]byte(v))
- e := e
- t.Run(fmt.Sprintf("encoding=%v,value=%v", e, ve), func(t *testing.T) {
- t.Parallel()
- acb, err := NewAppCallBytes(fmt.Sprintf("%v:%v", e, ve))
- require.NoError(t, err)
- r, err := acb.Raw()
- require.NoError(t, err)
- require.Equal(t, ve, base64.StdEncoding.EncodeToString(r))
- })
- }
- }
-
- for _, v := range []uint64{1, 0, math.MaxUint64} {
- for _, e := range []string{"int", "integer"} {
- v, e := v, e
- t.Run(fmt.Sprintf("encoding=%v,value=%v", e, v), func(t *testing.T) {
- t.Parallel()
- acb, err := NewAppCallBytes(fmt.Sprintf("%v:%v", e, v))
- require.NoError(t, err)
- r, err := acb.Raw()
- require.NoError(t, err)
- require.Equal(t, v, binary.BigEndian.Uint64(r))
- })
- }
- }
-
- for _, v := range []string{"737777777777777777777777777777777777777777777777777UFEJ2CI"} {
- for _, e := range []string{"addr", "address"} {
- v, e := v, e
- t.Run(fmt.Sprintf("encoding=%v,value=%v", e, v), func(t *testing.T) {
- t.Parallel()
- acb, err := NewAppCallBytes(fmt.Sprintf("%v:%v", e, v))
- require.NoError(t, err)
- r, err := acb.Raw()
- require.NoError(t, err)
- addr, err := basics.UnmarshalChecksumAddress(v)
- require.NoError(t, err)
- expectedBytes := []byte{}
- expectedBytes = addr[:]
- require.Equal(t, expectedBytes, r)
- })
- }
- }
-
- type abiCase struct {
- abiType, rawValue string
- }
- for _, v := range []abiCase{
- {
- `(uint64,string,bool[])`,
- `[399,"should pass",[true,false,false,true]]`,
- }} {
- for _, e := range []string{"abi"} {
- v, e := v, e
- t.Run(fmt.Sprintf("encoding=%v,value=%v", e, v), func(t *testing.T) {
- t.Parallel()
- acb, err := NewAppCallBytes(fmt.Sprintf(
- "%v:%v:%v", e, v.abiType, v.rawValue))
- require.NoError(t, err)
- r, err := acb.Raw()
- require.NoError(t, err)
- require.NotEmpty(t, r)
-
- // Confirm round-trip works.
- abiType, err := abi.TypeOf(v.abiType)
- require.NoError(t, err)
- d, err := abiType.Decode(r)
- require.NoError(t, err)
- vv, err := abiType.Encode(d)
- require.NoError(t, err)
- require.Equal(t, r, vv)
- })
- }
- }
-}
diff --git a/docker/README.md b/docker/README.md
index b3027655e6..78099e6027 100644
--- a/docker/README.md
+++ b/docker/README.md
@@ -1,5 +1,7 @@
# Algod Container
+[![DockerHub](https://img.shields.io/badge/DockerHub-blue)](https://hub.docker.com/r/algorand/algod)
+
General purpose algod container image.
## Image Configuration
@@ -39,11 +41,12 @@ Configuration can be modified by specifying certain files. These can be changed
| File | Description |
| ---- | ----------- |
-| /etc/config.json | Override default configurations by providing your own file. |
-| /etc/algod.token | Override default randomized REST API token. |
-| /etc/algod.admin.token | Override default randomized REST API admin token. |
+| /etc/algorand/config.json | Override default configurations by providing your own file. |
+| /etc/algorand/algod.token | Override default randomized REST API token. |
+| /etc/algorand/algod.admin.token | Override default randomized REST API admin token. |
+| /etc/algorand/logging.config | Use a custom [logging.config](https://developer.algorand.org/docs/run-a-node/reference/telemetry-config/#configuration) file for configuring telemetry. |
-TODO: `/etc/template.json` for overriding the private network topology.
+TODO: `/etc/algorand/template.json` for overriding the private network topology.
## Example Configuration
@@ -66,7 +69,7 @@ Explanation of parts:
* `-p 4190:8080` maps the internal algod REST API to local port 4190
* `-e NETWORK=` can be set to any of the supported public networks.
* `-e FAST_CATCHUP=` causes fast catchup to start shortly after launching the network.
-* `-e TELEMETRY_NAME=` enables telemetry reporting to Algorand for network health analysis.
+* `-e TELEMETRY_NAME=` enables telemetry reporting to Algorand for network health analysis. The value of this variable takes precedence over the `name` attribute set in `/etc/algorand/logging.config`.
* `-e TOKEN=` sets the REST API token to use.
* `-v ${PWD}/data:/algod/data/` mounts a local volume to the data directory, which can be used to restart and upgrade the deployment.
@@ -74,6 +77,37 @@ Explanation of parts:
The data directory located at `/algod/data`. Mounting a volume at that location will allow you to shutdown and resume the node.
+### Volume Permissions
+
+The container executes in the context of the `algorand` user with it's own UID and GID which is handled differently depending on your operating system. Here are a few options for how to work with this environment:
+
+#### Named Volume
+
+Using a named volume will work without any specific configuration in most cases:
+
+```bash
+docker volume create algod-data
+docker run -it --rm -d -v algod-data:/algod/data algorand/algod
+```
+
+#### Local Directory without SELinux
+
+Explicitly set the UID and GID of the container:
+
+```bash
+docker run -it --rm -d -v /srv/data:/algod/data -u $UID:$GID algorand/algod
+```
+
+#### Local Directory with SELinux
+
+Set the UID and GID of the container while add the `Z` option to the volume definition:
+
+```bash
+docker run -it --rm -d -v /srv/data:/algod/data:Z -u $UID:$GID algorand/algod
+```
+
+> See the documentation on [configuring the selinux label](https://docs.docker.com/storage/bind-mounts/#configure-the-selinux-label).
+
### Private Network
Private networks work a little bit differently. They are configured with, potentially, several data directories. The default topology supplied with this container is installed to `/algod/`, and has a single node named `data`. This means the private network has a data directory at `/algod/data`, matching the production configuration.
diff --git a/docker/files/build/install.sh b/docker/files/build/install.sh
index 9cfef5e858..abc57cc5ec 100755
--- a/docker/files/build/install.sh
+++ b/docker/files/build/install.sh
@@ -87,6 +87,6 @@ BUILD_NUMBER="" BRANCH="$BRANCH" make build
shopt -s extglob
-cd "$BINDIR" && rm -vrf !(algocfg|algod|algoh|algokey|carpenter|catchupsrv|ddconfig.sh|diagcfg|find-nodes.sh|goal|kmd|msgpacktool|node_exporter|tealcut|tealdbg|update.sh|updater|COPYING)
+cd "$BINDIR" && rm -vrf !(algocfg|algod|algokey|diagcfg|goal|kmd|msgpacktool|node_exporter|tealdbg|update.sh|updater|COPYING)
"$BINDIR"/algod -v
diff --git a/docker/files/run/run.sh b/docker/files/run/run.sh
index 24e59ae145..627665dd6f 100755
--- a/docker/files/run/run.sh
+++ b/docker/files/run/run.sh
@@ -13,25 +13,25 @@ function apply_configuration() {
cd "$ALGORAND_DATA"
# check for config file overrides.
- if [ -f "/etc/config.json" ]; then
- cp /etc/config.json config.json
+ if [ -f "/etc/algorand/config.json" ]; then
+ cp /etc/algorand/config.json config.json
fi
- if [ -f "/etc/algod.token" ]; then
- cp /etc/algod.token algod.token
+ if [ -f "/etc/algorand/algod.token" ]; then
+ cp /etc/algorand/algod.token algod.token
fi
- if [ -f "/etc/algod.admin.token" ]; then
- cp /etc/algod.admin.token algod.admin.token
+ if [ -f "/etc/algorand/algod.admin.token" ]; then
+ cp /etc/algorand/algod.admin.token algod.admin.token
fi
- if [ -f "/etc/logging.config" ]; then
- cp /etc/logging.config logging.config
+ if [ -f "/etc/algorand/logging.config" ]; then
+ cp /etc/algorand/logging.config logging.config
fi
# check for environment variable overrides.
if [ "$TOKEN" != "" ]; then
- echo "$TOKEN" > algod.token
+ echo "$TOKEN" >algod.token
fi
if [ "$ADMIN_TOKEN" != "" ]; then
- echo "$ADMIN_TOKEN" > algod.admin.token
+ echo "$ADMIN_TOKEN" >algod.admin.token
fi
# configure telemetry
@@ -78,8 +78,8 @@ function configure_data_dir() {
}
function start_new_public_network() {
- cd /node
- if [ ! -d "run/genesis/$NETWORK" ]; then
+ cd /algod
+ if [ ! -d "/node/run/genesis/${NETWORK}" ]; then
echo "No genesis file for '$NETWORK' is available."
exit 1
fi
@@ -88,7 +88,7 @@ function start_new_public_network() {
cd "$ALGORAND_DATA"
- cp "/node/run/genesis/$NETWORK/genesis.json" genesis.json
+ cp "/node/run/genesis/${NETWORK}/genesis.json" genesis.json
cp /node/run/config.json.example config.json
configure_data_dir
@@ -111,18 +111,17 @@ function start_private_network() {
apply_configuration
# TODO: Is there a way to properly exec a private network?
- goal network start -r "$ALGORAND_DATA/.."
- tail -f "$ALGORAND_DATA/node.log"
+ goal network start -r "${ALGORAND_DATA}/.."
+ tail -f "${ALGORAND_DATA}/node.log"
}
function start_new_private_network() {
- cd /node
local TEMPLATE="template.json"
if [ "$DEV_MODE" ]; then
TEMPLATE="devmode_template.json"
fi
- sed -i "s/NUM_ROUNDS/${NUM_ROUNDS:-30000}/" "run/$TEMPLATE"
- goal network create -n dockernet -r "$ALGORAND_DATA/.." -t "run/$TEMPLATE"
+ sed -i "s/NUM_ROUNDS/${NUM_ROUNDS:-30000}/" "/node/run/$TEMPLATE"
+ goal network create --noclean -n dockernet -r "${ALGORAND_DATA}/.." -t "/node/run/$TEMPLATE"
configure_data_dir
start_private_network
}
diff --git a/go.mod b/go.mod
index d605367586..a1f20d7dfe 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.17
require (
github.com/DataDog/zstd v1.5.2
- github.com/algorand/avm-abi v0.1.1
+ github.com/algorand/avm-abi v0.2.0
github.com/algorand/falcon v0.0.0-20220727072124-02a2a64c4414
github.com/algorand/go-codec/codec v1.1.8
github.com/algorand/go-deadlock v0.2.2
diff --git a/go.sum b/go.sum
index 0cb01bcb2e..68a08e0848 100644
--- a/go.sum
+++ b/go.sum
@@ -1,8 +1,8 @@
github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8=
github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
-github.com/algorand/avm-abi v0.1.1 h1:dbyQKzXiyaEbzpmqXFB30yAhyqseBsyqXTyZbNbkh2Y=
-github.com/algorand/avm-abi v0.1.1/go.mod h1:+CgwM46dithy850bpTeHh9MC99zpn2Snirb3QTl2O/g=
+github.com/algorand/avm-abi v0.2.0 h1:bkjsG+BOEcxUcnGSALLosmltE0JZdg+ZisXKx0UDX2k=
+github.com/algorand/avm-abi v0.2.0/go.mod h1:+CgwM46dithy850bpTeHh9MC99zpn2Snirb3QTl2O/g=
github.com/algorand/falcon v0.0.0-20220727072124-02a2a64c4414 h1:nwYN+GQ7Z5OOfZwqBO1ma7DSlP7S1YrKWICOyjkwqrc=
github.com/algorand/falcon v0.0.0-20220727072124-02a2a64c4414/go.mod h1:OkQyHlGvS0kLNcIWbC21/uQcnbfwSOQm+wiqWwBG9pQ=
github.com/algorand/go-codec v1.1.8/go.mod h1:XhzVs6VVyWMLu6cApb9/192gBjGRVGm5cX5j203Heg4=
diff --git a/ledger/acctdeltas_test.go b/ledger/acctdeltas_test.go
index de5efc9f54..21ac1e5dcc 100644
--- a/ledger/acctdeltas_test.go
+++ b/ledger/acctdeltas_test.go
@@ -32,15 +32,14 @@ import (
"testing"
"time"
- "github.com/algorand/go-algorand/data/transactions/logic"
- "github.com/algorand/go-algorand/ledger/encoded"
-
"github.com/stretchr/testify/require"
+ "github.com/algorand/avm-abi/apps"
"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/crypto"
"github.com/algorand/go-algorand/crypto/merklesignature"
"github.com/algorand/go-algorand/data/basics"
+ "github.com/algorand/go-algorand/ledger/encoded"
"github.com/algorand/go-algorand/ledger/ledgercore"
"github.com/algorand/go-algorand/ledger/store"
storetesting "github.com/algorand/go-algorand/ledger/store/testing"
@@ -1181,12 +1180,12 @@ func BenchmarkLookupKeyByPrefix(b *testing.B) {
crypto.RandBytes(nameBuffer)
crypto.RandBytes(valueBuffer)
appID := basics.AppIndex(crypto.RandUint64())
- boxKey := logic.MakeBoxKey(appID, string(nameBuffer))
+ boxKey := apps.MakeBoxKey(uint64(appID), string(nameBuffer))
err = writer.UpsertKvPair(boxKey, valueBuffer)
require.NoError(b, err)
if i == 0 {
- prefix = logic.MakeBoxKey(appID, "")
+ prefix = apps.MakeBoxKey(uint64(appID), "")
}
}
err = tx.Commit()
diff --git a/ledger/acctupdates_test.go b/ledger/acctupdates_test.go
index 0642bb0096..723e2c1986 100644
--- a/ledger/acctupdates_test.go
+++ b/ledger/acctupdates_test.go
@@ -31,11 +31,11 @@ import (
"github.com/stretchr/testify/require"
+ "github.com/algorand/avm-abi/apps"
"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/crypto"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/bookkeeping"
- "github.com/algorand/go-algorand/data/transactions/logic"
"github.com/algorand/go-algorand/ledger/internal"
"github.com/algorand/go-algorand/ledger/ledgercore"
"github.com/algorand/go-algorand/ledger/store"
@@ -1290,7 +1290,7 @@ func TestBoxNamesByAppIDs(t *testing.T) {
boxChange := ledgercore.KvValueDelta{Data: []byte(boxName)}
auNewBlock(t, currentRound, au, accts, opts, map[string]ledgercore.KvValueDelta{
- logic.MakeBoxKey(appID, boxName): boxChange,
+ apps.MakeBoxKey(uint64(appID), boxName): boxChange,
})
auCommitSync(t, currentRound, au, ml)
@@ -1305,10 +1305,10 @@ func TestBoxNamesByAppIDs(t *testing.T) {
// check input, see all present keys are all still there
for _, storedBoxName := range testingBoxNames[:i+1] {
- res, err := au.LookupKeysByPrefix(currentRound, logic.MakeBoxKey(boxNameToAppID[storedBoxName], ""), 10000)
+ res, err := au.LookupKeysByPrefix(currentRound, apps.MakeBoxKey(uint64(boxNameToAppID[storedBoxName]), ""), 10000)
require.NoError(t, err)
require.Len(t, res, 1)
- require.Equal(t, logic.MakeBoxKey(boxNameToAppID[storedBoxName], storedBoxName), res[0])
+ require.Equal(t, apps.MakeBoxKey(uint64(boxNameToAppID[storedBoxName]), storedBoxName), res[0])
}
}
@@ -1319,12 +1319,12 @@ func TestBoxNamesByAppIDs(t *testing.T) {
// remove inserted box
appID := boxNameToAppID[boxName]
auNewBlock(t, currentRound, au, accts, opts, map[string]ledgercore.KvValueDelta{
- logic.MakeBoxKey(appID, boxName): {},
+ apps.MakeBoxKey(uint64(appID), boxName): {},
})
auCommitSync(t, currentRound, au, ml)
// ensure recently removed key is not present, and it is not part of the result
- res, err := au.LookupKeysByPrefix(currentRound, logic.MakeBoxKey(boxNameToAppID[boxName], ""), 10000)
+ res, err := au.LookupKeysByPrefix(currentRound, apps.MakeBoxKey(uint64(boxNameToAppID[boxName]), ""), 10000)
require.NoError(t, err)
require.Len(t, res, 0)
}
diff --git a/ledger/catchpointwriter_test.go b/ledger/catchpointwriter_test.go
index 0530991e01..478df2bb25 100644
--- a/ledger/catchpointwriter_test.go
+++ b/ledger/catchpointwriter_test.go
@@ -32,12 +32,12 @@ import (
"github.com/stretchr/testify/require"
+ "github.com/algorand/avm-abi/apps"
"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/crypto"
"github.com/algorand/go-algorand/crypto/merkletrie"
"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/data/txntest"
"github.com/algorand/go-algorand/ledger/encoded"
"github.com/algorand/go-algorand/ledger/ledgercore"
@@ -779,7 +779,7 @@ func TestCatchpointAfterTxns(t *testing.T) {
values, err = l.LookupKeysByPrefix(l.Latest(), "bx:", 10)
require.NoError(t, err)
require.Len(t, values, 1)
- v, err := l.LookupKv(l.Latest(), logic.MakeBoxKey(boxApp, "xxx"))
+ v, err := l.LookupKv(l.Latest(), apps.MakeBoxKey(uint64(boxApp), "xxx"))
require.NoError(t, err)
require.Equal(t, strings.Repeat("\x00", 24), string(v))
@@ -869,7 +869,7 @@ func TestCatchpointAfterBoxTxns(t *testing.T) {
values, err := l.LookupKeysByPrefix(l.Latest(), "bx:", 10)
require.NoError(t, err)
require.Len(t, values, 1)
- v, err := l.LookupKv(l.Latest(), logic.MakeBoxKey(boxApp, "xxx"))
+ v, err := l.LookupKv(l.Latest(), apps.MakeBoxKey(uint64(boxApp), "xxx"))
require.NoError(t, err)
require.Equal(t, strings.Repeat("f", 24), string(v))
}
diff --git a/ledger/encoded/recordsV6_test.go b/ledger/encoded/recordsV6_test.go
index e966bd60fe..9e5dd14384 100644
--- a/ledger/encoded/recordsV6_test.go
+++ b/ledger/encoded/recordsV6_test.go
@@ -20,10 +20,9 @@ import (
"math"
"testing"
+ "github.com/algorand/avm-abi/apps"
"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/crypto"
- "github.com/algorand/go-algorand/data/basics"
- "github.com/algorand/go-algorand/data/transactions/logic"
"github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-algorand/test/partitiontest"
"github.com/stretchr/testify/require"
@@ -36,7 +35,7 @@ func TestEncodedKVRecordV6Allocbounds(t *testing.T) {
for version, params := range config.Consensus {
require.GreaterOrEqualf(t, uint64(KVRecordV6MaxValueLength), params.MaxBoxSize, "Allocbound constant no longer valid as of consensus version %s", version)
longestPossibleBoxName := string(make([]byte, params.MaxAppKeyLen))
- longestPossibleKey := logic.MakeBoxKey(basics.AppIndex(math.MaxUint64), longestPossibleBoxName)
+ longestPossibleKey := apps.MakeBoxKey(math.MaxUint64, longestPossibleBoxName)
require.GreaterOrEqualf(t, KVRecordV6MaxValueLength, len(longestPossibleKey), "Allocbound constant no longer valid as of consensus version %s", version)
}
}
diff --git a/ledger/internal/applications.go b/ledger/internal/applications.go
index 37c50d321d..f0466b7d4a 100644
--- a/ledger/internal/applications.go
+++ b/ledger/internal/applications.go
@@ -19,6 +19,7 @@ package internal
import (
"fmt"
+ "github.com/algorand/avm-abi/apps"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/bookkeeping"
"github.com/algorand/go-algorand/data/transactions/logic"
@@ -222,7 +223,7 @@ func (cs *roundCowState) NewBox(appIdx basics.AppIndex, key string, value []byte
return fmt.Errorf("box size too large: %d, maximum is %d", size, cs.proto.MaxBoxSize)
}
- fullKey := logic.MakeBoxKey(appIdx, key)
+ fullKey := apps.MakeBoxKey(uint64(appIdx), key)
_, exists, err := cs.kvGet(fullKey)
if err != nil {
return err
@@ -246,12 +247,12 @@ func (cs *roundCowState) NewBox(appIdx basics.AppIndex, key string, value []byte
}
func (cs *roundCowState) GetBox(appIdx basics.AppIndex, key string) ([]byte, bool, error) {
- fullKey := logic.MakeBoxKey(appIdx, key)
+ fullKey := apps.MakeBoxKey(uint64(appIdx), key)
return cs.kvGet(fullKey)
}
func (cs *roundCowState) SetBox(appIdx basics.AppIndex, key string, value []byte) error {
- fullKey := logic.MakeBoxKey(appIdx, key)
+ fullKey := apps.MakeBoxKey(uint64(appIdx), key)
old, ok, err := cs.kvGet(fullKey)
if err != nil {
return err
@@ -267,7 +268,7 @@ func (cs *roundCowState) SetBox(appIdx basics.AppIndex, key string, value []byte
}
func (cs *roundCowState) DelBox(appIdx basics.AppIndex, key string, appAddr basics.Address) (bool, error) {
- fullKey := logic.MakeBoxKey(appIdx, key)
+ fullKey := apps.MakeBoxKey(uint64(appIdx), key)
value, ok, err := cs.kvGet(fullKey)
if err != nil {
diff --git a/libgoal/libgoal.go b/libgoal/libgoal.go
index ebe69e4b5e..4a27b70587 100644
--- a/libgoal/libgoal.go
+++ b/libgoal/libgoal.go
@@ -765,7 +765,7 @@ func (c *Client) ApplicationBoxes(appID uint64, maxBoxNum uint64) (resp model.Bo
}
// GetApplicationBoxByName takes an app's index and box name and returns its value.
-// The box name should be of the form `encoding:value`. See logic.AppCallBytes for more information.
+// The box name should be of the form `encoding:value`. See apps.AppCallBytes for more information.
func (c *Client) GetApplicationBoxByName(index uint64, name string) (resp model.BoxResponse, err error) {
algod, err := c.ensureAlgodClient()
if err == nil {
diff --git a/test/scripts/e2e_subs/e2e-app-simple.sh b/test/scripts/e2e_subs/e2e-app-simple.sh
index e1f1458ce4..660487621d 100755
--- a/test/scripts/e2e_subs/e2e-app-simple.sh
+++ b/test/scripts/e2e_subs/e2e-app-simple.sh
@@ -122,3 +122,27 @@ ${gcmd} app optin --app-id $APPID --from $ACCOUNT
# Succeed in clearing state for the app
${gcmd} app clear --app-id $APPID --from $ACCOUNT
+
+
+# Empty program:
+printf ' ' > "${TEMPDIR}/empty_clear.teal"
+
+# Fail to compile an empty program
+RES=$(${gcmd} clerk compile "${TEMPDIR}/empty_clear.teal" 2>&1 | tr -d '\n' || true)
+EXPERROR='Cannot assemble empty program text'
+if [[ $RES != *"${EXPERROR}"* ]]; then
+ echo RES="$RES"
+ echo EXPERROR="$EXPERROR"
+ date '+clerk-compile-test FAIL wrong error for compiling empty program %Y%m%d_%H%M%S'
+ false
+fi
+
+# Fail to create an app because the clear program is empty
+RES=$(${gcmd} app create --creator "${ACCOUNT}" --approval-prog "${TEMPDIR}/simple.teal" --clear-prog "${TEMPDIR}/empty_clear.teal" --global-byteslices 0 --global-ints 0 --local-byteslices 0 --local-ints 0 2>&1 | tr -d '\n' || true)
+EXPERROR='Cannot assemble empty program text'
+if [[ $RES != *"${EXPERROR}"* ]]; then
+ echo RES="$RES"
+ echo EXPERROR="$EXPERROR"
+ date '+app-create-test FAIL wrong error for creating app with empty clear program %Y%m%d_%H%M%S'
+ false
+fi
diff --git a/tools/boxkey/convertBoxKey.go b/tools/boxkey/convertBoxKey.go
new file mode 100644
index 0000000000..0d249fa1e0
--- /dev/null
+++ b/tools/boxkey/convertBoxKey.go
@@ -0,0 +1,49 @@
+// Copyright (C) 2019-2023 Algorand, Inc.
+// This file is part of go-algorand
+//
+// go-algorand is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// go-algorand is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with go-algorand. If not, see .
+
+package main
+
+import (
+ "encoding/base64"
+ "encoding/hex"
+ "flag"
+ "fmt"
+
+ "github.com/algorand/go-algorand/data/basics"
+ "github.com/algorand/go-algorand/data/transactions/logic"
+)
+
+func main() {
+ var name string
+ var appIdx uint64
+ flag.Uint64Var(&appIdx, "a", 0, "base64/algorand address to convert to the other")
+ flag.StringVar(&name, "n", "", "base64 box name")
+ flag.Parse()
+
+ if appIdx == 0 && name == "" {
+ fmt.Println("provide input with '-a' and '-k' flags.")
+ return
+ }
+
+ nameBytes, err := base64.StdEncoding.DecodeString(name)
+ if err != nil {
+ fmt.Println("invalid key value")
+ return
+ }
+ key := logic.MakeBoxKey(basics.AppIndex(appIdx), string(nameBytes))
+ fmt.Println(base64.StdEncoding.EncodeToString([]byte(key)))
+ fmt.Println(hex.EncodeToString([]byte(key)))
+}