From fc520d050aab229b4112de75d5a35585e25475be Mon Sep 17 00:00:00 2001 From: algochoi <86622919+algochoi@users.noreply.github.com> Date: Tue, 7 Sep 2021 09:30:38 -0400 Subject: [PATCH 1/7] Add txnas opcodes --- cmd/opdoc/opdoc.go | 4 +- data/transactions/logic/README.md | 3 + data/transactions/logic/TEAL_opcodes.md | 24 +++++ data/transactions/logic/assembler.go | 82 ++++++++++++++- data/transactions/logic/assembler_test.go | 13 ++- data/transactions/logic/doc.go | 9 +- data/transactions/logic/eval.go | 83 +++++++++++++++ data/transactions/logic/evalStateful_test.go | 3 + data/transactions/logic/eval_test.go | 105 ++++++++++++++++++- data/transactions/logic/opcodes.go | 11 ++ 10 files changed, 327 insertions(+), 10 deletions(-) diff --git a/cmd/opdoc/opdoc.go b/cmd/opdoc/opdoc.go index 334942a324..ad1ce4d2d9 100644 --- a/cmd/opdoc/opdoc.go +++ b/cmd/opdoc/opdoc.go @@ -238,7 +238,7 @@ func argEnum(name string) []string { if name == "global" { return logic.GlobalFieldNames } - if name == "txna" || name == "gtxna" || name == "gtxnsa" { + if name == "txna" || name == "gtxna" || name == "gtxnsa" || name == "txnas" || name == "gtxnas" { return logic.TxnaFieldNames } if name == "asset_holding_get" { @@ -282,7 +282,7 @@ func argEnumTypes(name string) string { if name == "global" { return typeString(logic.GlobalFieldTypes) } - if name == "txna" || name == "gtxna" || name == "gtxnsa" { + if name == "txna" || name == "gtxna" || name == "gtxnsa" || name == "txnas" || name == "gtxnas" { return typeString(logic.TxnaFieldTypes) } if name == "asset_holding_get" { diff --git a/data/transactions/logic/README.md b/data/transactions/logic/README.md index 75765f00cd..acbac33618 100644 --- a/data/transactions/logic/README.md +++ b/data/transactions/logic/README.md @@ -221,6 +221,9 @@ Some of these have immediate data in the byte or bytes after the opcode. | `gloads i` | push Ith scratch space index of the Xth transaction in the current group | | `gaid t` | push the ID of the asset or application created in the Tth transaction of the current group | | `gaids` | push the ID of the asset or application created in the Xth transaction of the current group | +| `txnas f` | pop an index A. push Ath value of the array field F of the current transaction | +| `gtxnas t f` | pop an index A. push Ath value of the array field F from the Tth transaction in the current group | +| `gtxnsas f` | pop an index A and an index B. push Bth value of the array field F from the Ath transaction in the current group | **Transaction Fields** diff --git a/data/transactions/logic/TEAL_opcodes.md b/data/transactions/logic/TEAL_opcodes.md index 70437d2c26..6e70ce9167 100644 --- a/data/transactions/logic/TEAL_opcodes.md +++ b/data/transactions/logic/TEAL_opcodes.md @@ -1213,3 +1213,27 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Mode: Application `log` can be called up to MaxLogCalls times in a program, and log up to a total of 1k bytes. + +## txnas f + +- Opcode: 0xc0 {uint8 transaction field index} +- Pops: *... stack*, uint64 +- Pushes: any +- pop an index A. push Ath value of the array field F of the current transaction +- LogicSigVersion >= 5 + +## gtxnas t f + +- Opcode: 0xc1 {uint8 transaction group index} {uint8 transaction field index} +- Pops: *... stack*, uint64 +- Pushes: any +- pop an index A. push Ath value of the array field F from the Tth transaction in the current group +- LogicSigVersion >= 5 + +## gtxnsas f + +- Opcode: 0xc2 {uint8 transaction field index} +- Pops: *... stack*, {uint64 A}, {uint64 B} +- Pushes: any +- pop an index A and an index B. push Bth value of the array field F from the Ath transaction in the current group +- LogicSigVersion >= 5 diff --git a/data/transactions/logic/assembler.go b/data/transactions/logic/assembler.go index 129cfe7b2c..4db9ebe15b 100644 --- a/data/transactions/logic/assembler.go +++ b/data/transactions/logic/assembler.go @@ -816,7 +816,7 @@ func assembleTxn2(ops *OpStream, spec *OpSpec, args []string) error { func assembleTxna(ops *OpStream, spec *OpSpec, args []string) error { if len(args) != 2 { - return ops.error("txna expects two arguments") + return ops.error("txna expects two immediate arguments") } fs, ok := txnFieldSpecByName[args[0]] if !ok { @@ -844,6 +844,28 @@ func assembleTxna(ops *OpStream, spec *OpSpec, args []string) error { return nil } +func assembleTxnas(ops *OpStream, spec *OpSpec, args []string) error { + if len(args) != 1 { + return ops.error("txnas expects one immediate argument") + } + fs, ok := txnFieldSpecByName[args[0]] + if !ok { + return ops.errorf("txnas unknown field: %#v", args[0]) + } + _, ok = txnaFieldSpecByField[fs.field] + if !ok { + return ops.errorf("txnas unknown field: %#v", args[0]) + } + if fs.version > ops.Version { + return ops.errorf("txnas %#v available in version %d. Missed #pragma version?", args[0], fs.version) + } + + ops.pending.WriteByte(spec.Opcode) + ops.pending.WriteByte(uint8(fs.field)) + ops.returns(fs.ftype) + return nil +} + func assembleGtxn(ops *OpStream, spec *OpSpec, args []string) error { if len(args) != 2 { return ops.error("gtxn expects two arguments") @@ -925,6 +947,38 @@ func assembleGtxna(ops *OpStream, spec *OpSpec, args []string) error { return nil } +func assembleGtxnas(ops *OpStream, spec *OpSpec, args []string) error { + if len(args) != 2 { + return ops.error("gtxnas expects two immediate arguments") + } + + slot, err := strconv.ParseUint(args[0], 0, 64) + if err != nil { + return ops.error(err) + } + if slot > 255 { + return ops.errorf("gtxnas group index beyond 255: %d", slot) + } + + fs, ok := txnFieldSpecByName[args[1]] + if !ok { + return ops.errorf("gtxnas unknown field: %#v", args[1]) + } + _, ok = txnaFieldSpecByField[fs.field] + if !ok { + return ops.errorf("gtxnas unknown field: %#v", args[1]) + } + if fs.version > ops.Version { + return ops.errorf("gtxnas %#v available in version %d. Missed #pragma version?", args[1], fs.version) + } + + ops.pending.WriteByte(spec.Opcode) + ops.pending.WriteByte(uint8(slot)) + ops.pending.WriteByte(uint8(fs.field)) + ops.returns(fs.ftype) + return nil +} + func assembleGtxns(ops *OpStream, spec *OpSpec, args []string) error { if len(args) == 2 { gtxnsa := OpsByName[ops.Version]["gtxnsa"] @@ -980,6 +1034,27 @@ func assembleGtxnsa(ops *OpStream, spec *OpSpec, args []string) error { return nil } +func assembleGtxnsas(ops *OpStream, spec *OpSpec, args []string) error { + if len(args) != 1 { + return ops.error("gtxnsas expects one immediate argument") + } + fs, ok := txnFieldSpecByName[args[0]] + if !ok { + return ops.errorf("gtxnsas unknown field: %#v", args[0]) + } + _, ok = txnaFieldSpecByField[fs.field] + if !ok { + return ops.errorf("gtxnsas unknown field: %#v", args[0]) + } + if fs.version > ops.Version { + return ops.errorf("gtxnsas %#v available in version %d. Missed #pragma version?", args[0], fs.version) + } + ops.pending.WriteByte(spec.Opcode) + ops.pending.WriteByte(uint8(fs.field)) + ops.returns(fs.ftype) + return nil +} + func assembleGlobal(ops *OpStream, spec *OpSpec, args []string) error { if len(args) != 1 { return ops.errorf("%s expects one argument", spec.Name) @@ -2294,7 +2369,7 @@ func checkPushBytes(cx *evalContext) error { return cx.err } -// This is also used to disassemble gtxns +// This is also used to disassemble gtxns, gtxnsas and txnas func disTxn(dis *disassembleState, spec *OpSpec) (string, error) { lastIdx := dis.pc + 1 if len(dis.program) <= lastIdx { @@ -2325,6 +2400,7 @@ func disTxna(dis *disassembleState, spec *OpSpec) (string, error) { return fmt.Sprintf("%s %s %d", spec.Name, TxnFieldNames[txarg], arrayFieldIdx), nil } +// This is also used to disassemble gtxnas func disGtxn(dis *disassembleState, spec *OpSpec) (string, error) { lastIdx := dis.pc + 2 if len(dis.program) <= lastIdx { @@ -2337,7 +2413,7 @@ func disGtxn(dis *disassembleState, spec *OpSpec) (string, error) { if int(txarg) >= len(TxnFieldNames) { return "", fmt.Errorf("invalid txn arg index %d at pc=%d", txarg, dis.pc) } - return fmt.Sprintf("gtxn %d %s", gi, TxnFieldNames[txarg]), nil + return fmt.Sprintf("%s %d %s", spec.Name, gi, TxnFieldNames[txarg]), nil } func disGtxna(dis *disassembleState, spec *OpSpec) (string, error) { diff --git a/data/transactions/logic/assembler_test.go b/data/transactions/logic/assembler_test.go index 82d2e6af9a..0e3b640286 100644 --- a/data/transactions/logic/assembler_test.go +++ b/data/transactions/logic/assembler_test.go @@ -312,6 +312,13 @@ extract16bits log txn Nonparticipation gtxn 0 Nonparticipation +int 1 +txnas ApplicationArgs +int 0 +gtxnas 0 ApplicationArgs +int 0 +int 0 +gtxnsas ApplicationArgs ` var nonsense = map[uint64]string{ @@ -327,7 +334,7 @@ var compiled = map[uint64]string{ 2: "022008b7a60cf8acd19181cf959a12f8acd19181cf951af8acd19181cf15f8acd191810f01020026050212340c68656c6c6f20776f726c6421208dae2087fbba51304eb02b91f656948397a7946390e8cb70fc9ea4d95f92251d024242047465737400320032013202320328292929292a0431003101310231043105310731083109310a310b310c310d310e310f3111311231133114311533000033000133000233000433000533000733000833000933000a33000b33000c33000d33000e33000f3300113300123300133300143300152d2e0102222324252104082209240a220b230c240d250e230f23102311231223132314181b1c2b171615400003290349483403350222231d4a484848482a50512a63222352410003420000432105602105612105270463484821052b62482b642b65484821052b2106662b21056721072b682b692107210570004848210771004848361c0037001a0031183119311b311d311e311f3120210721051e312131223123312431253126312731283129312a312b312c312d312e312f", 3: "032008b7a60cf8acd19181cf959a12f8acd19181cf951af8acd19181cf15f8acd191810f01020026050212340c68656c6c6f20776f726c6421208dae2087fbba51304eb02b91f656948397a7946390e8cb70fc9ea4d95f92251d024242047465737400320032013202320328292929292a0431003101310231043105310731083109310a310b310c310d310e310f3111311231133114311533000033000133000233000433000533000733000833000933000a33000b33000c33000d33000e33000f3300113300123300133300143300152d2e0102222324252104082209240a220b230c240d250e230f23102311231223132314181b1c2b171615400003290349483403350222231d4a484848482a50512a63222352410003420000432105602105612105270463484821052b62482b642b65484821052b2106662b21056721072b682b692107210570004848210771004848361c0037001a0031183119311b311d311e311f3120210721051e312131223123312431253126312731283129312a312b312c312d312e312f4478222105531421055427042106552105082106564c4d4b02210538212106391c0081e80780046a6f686e", 4: "042004010200b7a60c26040242420c68656c6c6f20776f726c6421208dae2087fbba51304eb02b91f656948397a7946390e8cb70fc9ea4d95f92251d047465737400320032013202320380021234292929292a0431003101310231043105310731083109310a310b310c310d310e310f3111311231133114311533000033000133000233000433000533000733000833000933000a33000b33000c33000d33000e33000f3300113300123300133300143300152d2e01022581f8acd19181cf959a1281f8acd19181cf951a81f8acd19181cf1581f8acd191810f082209240a220b230c240d250e230f23102311231223132314181b1c28171615400003290349483403350222231d4a484848482a50512a632223524100034200004322602261222b634848222862482864286548482228236628226724286828692422700048482471004848361c0037001a0031183119311b311d311e311f312024221e312131223123312431253126312731283129312a312b312c312d312e312f44782522531422542b2355220823564c4d4b0222382123391c0081e80780046a6f686e2281d00f24231f880003420001892223902291922394239593a0a1a2a3a4a5a6a7a8a9aaabacadae23af3a00003b003c003d8164", - 5: "052004010200b7a60c26040242420c68656c6c6f20776f726c6421208dae2087fbba51304eb02b91f656948397a7946390e8cb70fc9ea4d95f92251d047465737400320032013202320380021234292929292a0431003101310231043105310731083109310a310b310c310d310e310f3111311231133114311533000033000133000233000433000533000733000833000933000a33000b33000c33000d33000e33000f3300113300123300133300143300152d2e01022581f8acd19181cf959a1281f8acd19181cf951a81f8acd19181cf1581f8acd191810f082209240a220b230c240d250e230f23102311231223132314181b1c28171615400003290349483403350222231d4a484848482a50512a632223524100034200004322602261222b634848222862482864286548482228236628226724286828692422700048482471004848361c0037001a0031183119311b311d311e311f312024221e312131223123312431253126312731283129312a312b312c312d312e312f44782522531422542b2355220823564c4d4b0222382123391c0081e80780046a6f686e2281d00f24231f880003420001892223902291922394239593a0a1a2a3a4a5a6a7a8a9aaabacadae23af3a00003b003c003d816472064e014f0180070123456789abcd57000824810858245b245a2459b03139330039", + 5: "052004010002b7a60c26040242420c68656c6c6f20776f726c6421208dae2087fbba51304eb02b91f656948397a7946390e8cb70fc9ea4d95f92251d047465737400320032013202320380021234292929292a0431003101310231043105310731083109310a310b310c310d310e310f3111311231133114311533000033000133000233000433000533000733000833000933000a33000b33000c33000d33000e33000f3300113300123300133300143300152d2e01022581f8acd19181cf959a1281f8acd19181cf951a81f8acd19181cf1581f8acd191810f082209240a220b230c240d250e230f23102311231223132314181b1c28171615400003290349483403350222231d4a484848482a50512a632223524100034200004322602261222b634848222862482864286548482228246628226723286828692322700048482371004848361c0037001a0031183119311b311d311e311f312023221e312131223123312431253126312731283129312a312b312c312d312e312f44782522531422542b2455220824564c4d4b0222382124391c0081e80780046a6f686e2281d00f23241f880003420001892224902291922494249593a0a1a2a3a4a5a6a7a8a9aaabacadae24af3a00003b003c003d816472064e014f0180070123456789abcd57000823810858235b235a2359b0313933003922c01a23c1001a2323c21a", } func pseudoOp(opcode string) bool { @@ -494,13 +501,15 @@ func TestAssembleTxna(t *testing.T) { testLine(t, "gtxna 0 Sender 256", AssemblerMaxVersion, "gtxna unknown field: \"Sender\"") testLine(t, "txn Accounts 0", 1, "txn expects one argument") testLine(t, "txn Accounts 0 1", 2, "txn expects one or two arguments") - testLine(t, "txna Accounts 0 1", AssemblerMaxVersion, "txna expects two arguments") + testLine(t, "txna Accounts 0 1", AssemblerMaxVersion, "txna expects two immediate arguments") + testLine(t, "txnas Accounts 1", AssemblerMaxVersion, "txnas expects one immediate argument") testLine(t, "txna Accounts a", AssemblerMaxVersion, "strconv.ParseUint...") testLine(t, "gtxn 0 Sender 0", 1, "gtxn expects two arguments") testLine(t, "gtxn 0 Sender 1 2", 2, "gtxn expects two or three arguments") testLine(t, "gtxna 0 Accounts 1 2", AssemblerMaxVersion, "gtxna expects three arguments") testLine(t, "gtxna a Accounts 0", AssemblerMaxVersion, "strconv.ParseUint...") testLine(t, "gtxna 0 Accounts a", AssemblerMaxVersion, "strconv.ParseUint...") + testLine(t, "gtxnas Accounts 1 2", AssemblerMaxVersion, "gtxnas expects two immediate arguments") testLine(t, "txn ABC", 2, "txn unknown field: \"ABC\"") testLine(t, "gtxn 0 ABC", 2, "gtxn unknown field: \"ABC\"") testLine(t, "gtxn a ABC", 2, "strconv.ParseUint...") diff --git a/data/transactions/logic/doc.go b/data/transactions/logic/doc.go index 27d2963a4a..05be72e680 100644 --- a/data/transactions/logic/doc.go +++ b/data/transactions/logic/doc.go @@ -152,6 +152,10 @@ var opDocByName = map[string]string{ "b~": "X with all bits inverted", "log": "write bytes to log state of the current application", + + "txnas": "pop an index A. push Ath value of the array field F of the current transaction", + "gtxnas": "pop an index A. push Ath value of the array field F from the Tth transaction in the current group", + "gtxnsas": "pop an index A and an index B. push Bth value of the array field F from the Ath transaction in the current group", } // OpDoc returns a description of the op @@ -191,6 +195,9 @@ var opcodeImmediateNotes = map[string]string{ "asset_holding_get": "{uint8 asset holding field index}", "asset_params_get": "{uint8 asset params field index}", "app_params_get": "{uint8 app params field index}", + "txnas": "{uint8 transaction field index}", + "gtxnas": "{uint8 transaction group index} {uint8 transaction field index}", + "gtxnsas": "{uint8 transaction field index}", } // OpImmediateNote returns a short string about immediate data which follows the op byte @@ -252,7 +259,7 @@ var OpGroups = map[string][]string{ "Byte Array Slicing": {"substring", "substring3", "extract", "extract3", "extract16bits", "extract32bits", "extract64bits"}, "Byteslice Arithmetic": {"b+", "b-", "b/", "b*", "b<", "b>", "b<=", "b>=", "b==", "b!=", "b%"}, "Byteslice Logic": {"b|", "b&", "b^", "b~"}, - "Loading Values": {"intcblock", "intc", "intc_0", "intc_1", "intc_2", "intc_3", "pushint", "bytecblock", "bytec", "bytec_0", "bytec_1", "bytec_2", "bytec_3", "pushbytes", "bzero", "arg", "arg_0", "arg_1", "arg_2", "arg_3", "txn", "gtxn", "txna", "gtxna", "gtxns", "gtxnsa", "global", "load", "store", "gload", "gloads", "gaid", "gaids"}, + "Loading Values": {"intcblock", "intc", "intc_0", "intc_1", "intc_2", "intc_3", "pushint", "bytecblock", "bytec", "bytec_0", "bytec_1", "bytec_2", "bytec_3", "pushbytes", "bzero", "arg", "arg_0", "arg_1", "arg_2", "arg_3", "txn", "gtxn", "txna", "gtxna", "gtxns", "gtxnsa", "global", "load", "store", "gload", "gloads", "gaid", "gaids", "txnas", "gtxnas", "gtxnsas"}, "Flow Control": {"err", "bnz", "bz", "b", "return", "pop", "dup", "dup2", "dig", "cover", "uncover", "swap", "select", "assert", "callsub", "retsub"}, "State Access": {"balance", "min_balance", "app_opted_in", "app_local_get", "app_local_get_ex", "app_global_get", "app_global_get_ex", "app_local_put", "app_global_put", "app_local_del", "app_global_del", "asset_holding_get", "asset_params_get", "app_params_get", "log"}, } diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index de56fa2850..085a46e07b 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -2062,6 +2062,29 @@ func opTxna(cx *evalContext) { cx.stack = append(cx.stack, sv) } +func opTxnas(cx *evalContext) { + last := len(cx.stack) - 1 + + field := TxnField(uint64(cx.program[cx.pc+1])) + fs, ok := txnFieldSpecByField[field] + if !ok || fs.version > cx.version { + cx.err = fmt.Errorf("invalid txn field %d", field) + return + } + _, ok = txnaFieldSpecByField[field] + if !ok { + cx.err = fmt.Errorf("txnas unsupported field %d", field) + return + } + arrayFieldIdx := cx.stack[last].Uint + sv, err := cx.txnFieldToStack(&cx.Txn.Txn, field, arrayFieldIdx, cx.GroupIndex) + if err != nil { + cx.err = err + return + } + cx.stack[last] = sv +} + func opGtxn(cx *evalContext) { gtxid := int(uint(cx.program[cx.pc+1])) if gtxid >= len(cx.TxnGroup) { @@ -2122,6 +2145,35 @@ func opGtxna(cx *evalContext) { cx.stack = append(cx.stack, sv) } +func opGtxnas(cx *evalContext) { + last := len(cx.stack) - 1 + + gtxid := int(uint(cx.program[cx.pc+1])) + if gtxid >= len(cx.TxnGroup) { + cx.err = fmt.Errorf("gtxnas lookup TxnGroup[%d] but it only has %d", gtxid, len(cx.TxnGroup)) + return + } + tx := &cx.TxnGroup[gtxid].Txn + field := TxnField(uint64(cx.program[cx.pc+2])) + fs, ok := txnFieldSpecByField[field] + if !ok || fs.version > cx.version { + cx.err = fmt.Errorf("invalid txn field %d", field) + return + } + _, ok = txnaFieldSpecByField[field] + if !ok { + cx.err = fmt.Errorf("gtxnas unsupported field %d", field) + return + } + arrayFieldIdx := cx.stack[last].Uint + sv, err := cx.txnFieldToStack(tx, field, arrayFieldIdx, gtxid) + if err != nil { + cx.err = err + return + } + cx.stack[last] = sv +} + func opGtxns(cx *evalContext) { last := len(cx.stack) - 1 gtxid := int(cx.stack[last].Uint) @@ -2184,6 +2236,37 @@ func opGtxnsa(cx *evalContext) { cx.stack[last] = sv } +func opGtxnsas(cx *evalContext) { + last := len(cx.stack) - 1 + prev := last - 1 + + gtxid := int(cx.stack[prev].Uint) + if gtxid >= len(cx.TxnGroup) { + cx.err = fmt.Errorf("gtxnsa lookup TxnGroup[%d] but it only has %d", gtxid, len(cx.TxnGroup)) + return + } + tx := &cx.TxnGroup[gtxid].Txn + field := TxnField(uint64(cx.program[cx.pc+1])) + fs, ok := txnFieldSpecByField[field] + if !ok || fs.version > cx.version { + cx.err = fmt.Errorf("invalid txn field %d", field) + return + } + _, ok = txnaFieldSpecByField[field] + if !ok { + cx.err = fmt.Errorf("gtxnsa unsupported field %d", field) + return + } + arrayFieldIdx := cx.stack[last].Uint + sv, err := cx.txnFieldToStack(tx, field, arrayFieldIdx, gtxid) + if err != nil { + cx.err = err + return + } + cx.stack[prev] = sv + cx.stack = cx.stack[:last] +} + func opGaidImpl(cx *evalContext, groupIdx int, opName string) (sv stackValue, err error) { if groupIdx >= len(cx.TxnGroup) { err = fmt.Errorf("%s lookup TxnGroup[%d] but it only has %d", opName, groupIdx, len(cx.TxnGroup)) diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go index f782fcce9a..8aa10f2f13 100644 --- a/data/transactions/logic/evalStateful_test.go +++ b/data/transactions/logic/evalStateful_test.go @@ -2843,6 +2843,9 @@ func TestReturnTypes(t *testing.T) { "pushbytes": `pushbytes "jojogoodgorilla"`, "app_params_get": "app_params_get AppGlobalNumUint", "extract": "extract 0 2", + "txnas": "txnas ApplicationArgs", + "gtxnas": "gtxnas 0 ApplicationArgs", + "gtxnsas": "pop; pop; int 0; int 0; gtxnsas ApplicationArgs", } byName := OpsByName[LogicVersion] diff --git a/data/transactions/logic/eval_test.go b/data/transactions/logic/eval_test.go index 98587f5ba2..2ddde9660d 100644 --- a/data/transactions/logic/eval_test.go +++ b/data/transactions/logic/eval_test.go @@ -1422,6 +1422,14 @@ txn Nonparticipation pop int 1 == +assert +txn ConfigAssetMetadataHash +int 2 +txnas ApplicationArgs +== +assert + +int 1 ` func makeSampleTxn() transactions.SignedTxn { @@ -1788,7 +1796,7 @@ int 1 == && ` - gtxnText := gtxnTextV2 + ` gtxn 0 ExtraProgramPages + gtxnTextV4 := gtxnTextV2 + ` gtxn 0 ExtraProgramPages int 0 == && @@ -1796,12 +1804,26 @@ gtxn 1 ExtraProgramPages int 2 == && +` + + gtxnText := gtxnTextV4 + `int 0 +gtxnas 0 Accounts +gtxn 0 Sender +== +&& +int 0 +int 0 +gtxnsas Accounts +gtxn 0 Sender +== +&& ` tests := map[uint64]string{ 1: gtxnTextV1, 2: gtxnTextV2, - 4: gtxnText, + 4: gtxnTextV4, + 5: gtxnText, } for v, source := range tests { @@ -2034,6 +2056,85 @@ global ZeroAddress require.True(t, pass) } +func TestTxnas(t *testing.T) { + partitiontest.PartitionTest(t) + + t.Parallel() + + source := `int 1 +txnas Accounts +int 0 +txnas ApplicationArgs +== +` + ops := testProg(t, source, AssemblerMaxVersion) + var txn transactions.SignedTxn + txn.Txn.Accounts = make([]basics.Address, 1) + txn.Txn.Accounts[0] = txn.Txn.Sender + txn.Txn.ApplicationArgs = make([][]byte, 1) + txn.Txn.ApplicationArgs[0] = []byte(protocol.PaymentTx) + txgroup := make([]transactions.SignedTxn, 1) + txgroup[0] = txn + ep := defaultEvalParams(nil, &txn) + ep.TxnGroup = txgroup + _, err := Eval(ops.Program, ep) + require.NoError(t, err) + + // check special case: Account 0 == Sender + // even without any additional context + source = `int 0 +txnas Accounts +txn Sender +== +` + ops2 := testProg(t, source, AssemblerMaxVersion) + var txn2 transactions.SignedTxn + copy(txn2.Txn.Sender[:], []byte("aoeuiaoeuiaoeuiaoeuiaoeuiaoeui00")) + ep2 := defaultEvalParams(nil, &txn2) + pass, err := Eval(ops2.Program, ep2) + require.NoError(t, err) + require.True(t, pass) + + // check gtxnas + source = `int 1 +gtxnas 0 Accounts +txna ApplicationArgs 0 +==` + ops = testProg(t, source, AssemblerMaxVersion) + require.NoError(t, err) + _, err = Eval(ops.Program, ep) + require.NoError(t, err) + + // check special case: Account 0 == Sender + // even without any additional context + source = `int 0 +gtxnas 0 Accounts +txn Sender +== + ` + ops3 := testProg(t, source, AssemblerMaxVersion) + var txn3 transactions.SignedTxn + copy(txn2.Txn.Sender[:], []byte("aoeuiaoeuiaoeuiaoeuiaoeuiaoeui00")) + txgroup3 := make([]transactions.SignedTxn, 1) + txgroup3[0] = txn3 + ep3 := defaultEvalParams(nil, &txn3) + ep3.TxnGroup = txgroup3 + pass, err = Eval(ops3.Program, ep3) + require.NoError(t, err) + require.True(t, pass) + + // check gtxnsas + source = `int 0 +int 1 +gtxnsas Accounts +txna ApplicationArgs 0 +==` + ops = testProg(t, source, AssemblerMaxVersion) + require.NoError(t, err) + _, err = Eval(ops.Program, ep) + require.NoError(t, err) +} + func TestBitOps(t *testing.T) { partitiontest.PartitionTest(t) diff --git a/data/transactions/logic/opcodes.go b/data/transactions/logic/opcodes.go index 2ab59ed9c4..edbe2b6b72 100644 --- a/data/transactions/logic/opcodes.go +++ b/data/transactions/logic/opcodes.go @@ -298,6 +298,17 @@ var OpSpecs = []OpSpec{ // ABI support opcodes. {0xb0, "log", opLog, asmDefault, disDefault, oneBytes, nil, 5, runModeApplication, opDefault}, + + // {0x36, "txna", opTxna, assembleTxna, disTxna, nil, oneAny, 2, modeAny, immediates("f", "i")}, + // {0x37, "gtxna", opGtxna, assembleGtxna, disGtxna, nil, oneAny, 2, modeAny, immediates("t", "f", "i")}, + // // Like gtxn, but gets txn index from stack, rather than immediate arg + // {0x38, "gtxns", opGtxns, assembleGtxns, disTxn, oneInt, oneAny, 3, modeAny, immediates("f")}, + // {0x39, "gtxnsa", opGtxnsa, assembleGtxns, disTxna, oneInt, oneAny, 3, modeAny, immediates("f", "i")}, + + // Dynamically indexing into LogicSigs + {0xc0, "txnas", opTxnas, assembleTxnas, disTxn, oneInt, oneAny, 5, modeAny, immediates("f")}, + {0xc1, "gtxnas", opGtxnas, assembleGtxnas, disGtxn, oneInt, oneAny, 5, modeAny, immediates("t", "f")}, + {0xc2, "gtxnsas", opGtxnsas, assembleGtxnsas, disTxn, twoInts, oneAny, 5, modeAny, immediates("f")}, } type sortByOpcode []OpSpec From f37928bb31e27aa29ec9b503c26fcfe2cd3102bd Mon Sep 17 00:00:00 2001 From: algochoi <86622919+algochoi@users.noreply.github.com> Date: Tue, 7 Sep 2021 09:34:25 -0400 Subject: [PATCH 2/7] Delete comments --- data/transactions/logic/opcodes.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/data/transactions/logic/opcodes.go b/data/transactions/logic/opcodes.go index edbe2b6b72..fba221b59e 100644 --- a/data/transactions/logic/opcodes.go +++ b/data/transactions/logic/opcodes.go @@ -299,12 +299,6 @@ var OpSpecs = []OpSpec{ // ABI support opcodes. {0xb0, "log", opLog, asmDefault, disDefault, oneBytes, nil, 5, runModeApplication, opDefault}, - // {0x36, "txna", opTxna, assembleTxna, disTxna, nil, oneAny, 2, modeAny, immediates("f", "i")}, - // {0x37, "gtxna", opGtxna, assembleGtxna, disGtxna, nil, oneAny, 2, modeAny, immediates("t", "f", "i")}, - // // Like gtxn, but gets txn index from stack, rather than immediate arg - // {0x38, "gtxns", opGtxns, assembleGtxns, disTxn, oneInt, oneAny, 3, modeAny, immediates("f")}, - // {0x39, "gtxnsa", opGtxnsa, assembleGtxns, disTxna, oneInt, oneAny, 3, modeAny, immediates("f", "i")}, - // Dynamically indexing into LogicSigs {0xc0, "txnas", opTxnas, assembleTxnas, disTxn, oneInt, oneAny, 5, modeAny, immediates("f")}, {0xc1, "gtxnas", opGtxnas, assembleGtxnas, disGtxn, oneInt, oneAny, 5, modeAny, immediates("t", "f")}, From bb2cbf64e43c3a9989ffc445d0cb881fa159c38d Mon Sep 17 00:00:00 2001 From: algochoi <86622919+algochoi@users.noreply.github.com> Date: Tue, 7 Sep 2021 11:10:32 -0400 Subject: [PATCH 3/7] Add args opcode --- data/transactions/logic/README.md | 1 + data/transactions/logic/TEAL_opcodes.md | 9 ++++++++ data/transactions/logic/assembler_test.go | 4 +++- data/transactions/logic/doc.go | 3 ++- data/transactions/logic/eval.go | 7 +++++++ data/transactions/logic/evalStateful_test.go | 1 + data/transactions/logic/eval_test.go | 22 +++++++++----------- data/transactions/logic/opcodes.go | 1 + 8 files changed, 34 insertions(+), 14 deletions(-) diff --git a/data/transactions/logic/README.md b/data/transactions/logic/README.md index acbac33618..c2df18c6d7 100644 --- a/data/transactions/logic/README.md +++ b/data/transactions/logic/README.md @@ -224,6 +224,7 @@ Some of these have immediate data in the byte or bytes after the opcode. | `txnas f` | pop an index A. push Ath value of the array field F of the current transaction | | `gtxnas t f` | pop an index A. push Ath value of the array field F from the Tth transaction in the current group | | `gtxnsas f` | pop an index A and an index B. push Bth value of the array field F from the Ath transaction in the current group | +| `args` | push Xth LogicSig argument to stack | **Transaction Fields** diff --git a/data/transactions/logic/TEAL_opcodes.md b/data/transactions/logic/TEAL_opcodes.md index 6e70ce9167..8428e27f08 100644 --- a/data/transactions/logic/TEAL_opcodes.md +++ b/data/transactions/logic/TEAL_opcodes.md @@ -1237,3 +1237,12 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Pushes: any - pop an index A and an index B. push Bth value of the array field F from the Ath transaction in the current group - LogicSigVersion >= 5 + +## args + +- Opcode: 0xc3 +- Pops: *... stack*, uint64 +- Pushes: []byte +- push Xth LogicSig argument to stack +- LogicSigVersion >= 5 +- Mode: Signature diff --git a/data/transactions/logic/assembler_test.go b/data/transactions/logic/assembler_test.go index 0e3b640286..cd53569392 100644 --- a/data/transactions/logic/assembler_test.go +++ b/data/transactions/logic/assembler_test.go @@ -319,6 +319,8 @@ gtxnas 0 ApplicationArgs int 0 int 0 gtxnsas ApplicationArgs +int 0 +args ` var nonsense = map[uint64]string{ @@ -334,7 +336,7 @@ var compiled = map[uint64]string{ 2: "022008b7a60cf8acd19181cf959a12f8acd19181cf951af8acd19181cf15f8acd191810f01020026050212340c68656c6c6f20776f726c6421208dae2087fbba51304eb02b91f656948397a7946390e8cb70fc9ea4d95f92251d024242047465737400320032013202320328292929292a0431003101310231043105310731083109310a310b310c310d310e310f3111311231133114311533000033000133000233000433000533000733000833000933000a33000b33000c33000d33000e33000f3300113300123300133300143300152d2e0102222324252104082209240a220b230c240d250e230f23102311231223132314181b1c2b171615400003290349483403350222231d4a484848482a50512a63222352410003420000432105602105612105270463484821052b62482b642b65484821052b2106662b21056721072b682b692107210570004848210771004848361c0037001a0031183119311b311d311e311f3120210721051e312131223123312431253126312731283129312a312b312c312d312e312f", 3: "032008b7a60cf8acd19181cf959a12f8acd19181cf951af8acd19181cf15f8acd191810f01020026050212340c68656c6c6f20776f726c6421208dae2087fbba51304eb02b91f656948397a7946390e8cb70fc9ea4d95f92251d024242047465737400320032013202320328292929292a0431003101310231043105310731083109310a310b310c310d310e310f3111311231133114311533000033000133000233000433000533000733000833000933000a33000b33000c33000d33000e33000f3300113300123300133300143300152d2e0102222324252104082209240a220b230c240d250e230f23102311231223132314181b1c2b171615400003290349483403350222231d4a484848482a50512a63222352410003420000432105602105612105270463484821052b62482b642b65484821052b2106662b21056721072b682b692107210570004848210771004848361c0037001a0031183119311b311d311e311f3120210721051e312131223123312431253126312731283129312a312b312c312d312e312f4478222105531421055427042106552105082106564c4d4b02210538212106391c0081e80780046a6f686e", 4: "042004010200b7a60c26040242420c68656c6c6f20776f726c6421208dae2087fbba51304eb02b91f656948397a7946390e8cb70fc9ea4d95f92251d047465737400320032013202320380021234292929292a0431003101310231043105310731083109310a310b310c310d310e310f3111311231133114311533000033000133000233000433000533000733000833000933000a33000b33000c33000d33000e33000f3300113300123300133300143300152d2e01022581f8acd19181cf959a1281f8acd19181cf951a81f8acd19181cf1581f8acd191810f082209240a220b230c240d250e230f23102311231223132314181b1c28171615400003290349483403350222231d4a484848482a50512a632223524100034200004322602261222b634848222862482864286548482228236628226724286828692422700048482471004848361c0037001a0031183119311b311d311e311f312024221e312131223123312431253126312731283129312a312b312c312d312e312f44782522531422542b2355220823564c4d4b0222382123391c0081e80780046a6f686e2281d00f24231f880003420001892223902291922394239593a0a1a2a3a4a5a6a7a8a9aaabacadae23af3a00003b003c003d8164", - 5: "052004010002b7a60c26040242420c68656c6c6f20776f726c6421208dae2087fbba51304eb02b91f656948397a7946390e8cb70fc9ea4d95f92251d047465737400320032013202320380021234292929292a0431003101310231043105310731083109310a310b310c310d310e310f3111311231133114311533000033000133000233000433000533000733000833000933000a33000b33000c33000d33000e33000f3300113300123300133300143300152d2e01022581f8acd19181cf959a1281f8acd19181cf951a81f8acd19181cf1581f8acd191810f082209240a220b230c240d250e230f23102311231223132314181b1c28171615400003290349483403350222231d4a484848482a50512a632223524100034200004322602261222b634848222862482864286548482228246628226723286828692322700048482371004848361c0037001a0031183119311b311d311e311f312023221e312131223123312431253126312731283129312a312b312c312d312e312f44782522531422542b2455220824564c4d4b0222382124391c0081e80780046a6f686e2281d00f23241f880003420001892224902291922494249593a0a1a2a3a4a5a6a7a8a9aaabacadae24af3a00003b003c003d816472064e014f0180070123456789abcd57000823810858235b235a2359b0313933003922c01a23c1001a2323c21a", + 5: "052004010002b7a60c26040242420c68656c6c6f20776f726c6421208dae2087fbba51304eb02b91f656948397a7946390e8cb70fc9ea4d95f92251d047465737400320032013202320380021234292929292a0431003101310231043105310731083109310a310b310c310d310e310f3111311231133114311533000033000133000233000433000533000733000833000933000a33000b33000c33000d33000e33000f3300113300123300133300143300152d2e01022581f8acd19181cf959a1281f8acd19181cf951a81f8acd19181cf1581f8acd191810f082209240a220b230c240d250e230f23102311231223132314181b1c28171615400003290349483403350222231d4a484848482a50512a632223524100034200004322602261222b634848222862482864286548482228246628226723286828692322700048482371004848361c0037001a0031183119311b311d311e311f312023221e312131223123312431253126312731283129312a312b312c312d312e312f44782522531422542b2455220824564c4d4b0222382124391c0081e80780046a6f686e2281d00f23241f880003420001892224902291922494249593a0a1a2a3a4a5a6a7a8a9aaabacadae24af3a00003b003c003d816472064e014f0180070123456789abcd57000823810858235b235a2359b0313933003922c01a23c1001a2323c21a23c3", } func pseudoOp(opcode string) bool { diff --git a/data/transactions/logic/doc.go b/data/transactions/logic/doc.go index 05be72e680..9700675d01 100644 --- a/data/transactions/logic/doc.go +++ b/data/transactions/logic/doc.go @@ -156,6 +156,7 @@ var opDocByName = map[string]string{ "txnas": "pop an index A. push Ath value of the array field F of the current transaction", "gtxnas": "pop an index A. push Ath value of the array field F from the Tth transaction in the current group", "gtxnsas": "pop an index A and an index B. push Bth value of the array field F from the Ath transaction in the current group", + "args": "push Xth LogicSig argument to stack", } // OpDoc returns a description of the op @@ -259,7 +260,7 @@ var OpGroups = map[string][]string{ "Byte Array Slicing": {"substring", "substring3", "extract", "extract3", "extract16bits", "extract32bits", "extract64bits"}, "Byteslice Arithmetic": {"b+", "b-", "b/", "b*", "b<", "b>", "b<=", "b>=", "b==", "b!=", "b%"}, "Byteslice Logic": {"b|", "b&", "b^", "b~"}, - "Loading Values": {"intcblock", "intc", "intc_0", "intc_1", "intc_2", "intc_3", "pushint", "bytecblock", "bytec", "bytec_0", "bytec_1", "bytec_2", "bytec_3", "pushbytes", "bzero", "arg", "arg_0", "arg_1", "arg_2", "arg_3", "txn", "gtxn", "txna", "gtxna", "gtxns", "gtxnsa", "global", "load", "store", "gload", "gloads", "gaid", "gaids", "txnas", "gtxnas", "gtxnsas"}, + "Loading Values": {"intcblock", "intc", "intc_0", "intc_1", "intc_2", "intc_3", "pushint", "bytecblock", "bytec", "bytec_0", "bytec_1", "bytec_2", "bytec_3", "pushbytes", "bzero", "arg", "arg_0", "arg_1", "arg_2", "arg_3", "txn", "gtxn", "txna", "gtxna", "gtxns", "gtxnsa", "global", "load", "store", "gload", "gloads", "gaid", "gaids", "txnas", "gtxnas", "gtxnsas", "args"}, "Flow Control": {"err", "bnz", "bz", "b", "return", "pop", "dup", "dup2", "dig", "cover", "uncover", "swap", "select", "assert", "callsub", "retsub"}, "State Access": {"balance", "min_balance", "app_opted_in", "app_local_get", "app_local_get_ex", "app_global_get", "app_global_get_ex", "app_local_put", "app_global_put", "app_local_del", "app_global_del", "asset_holding_get", "asset_params_get", "app_params_get", "log"}, } diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index 085a46e07b..b0d8542a3e 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -1598,6 +1598,13 @@ func opArg2(cx *evalContext) { func opArg3(cx *evalContext) { opArgN(cx, 3) } +func opArgs(cx *evalContext) { + last := len(cx.stack) - 1 + n := cx.stack[last].Uint + // Pop the index and push the result back on the stack. + cx.stack = cx.stack[:last] + opArgN(cx, n) +} func branchTarget(cx *evalContext) (int, error) { offset := int16(uint16(cx.program[cx.pc+1])<<8 | uint16(cx.program[cx.pc+2])) diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go index 8aa10f2f13..931e76bb77 100644 --- a/data/transactions/logic/evalStateful_test.go +++ b/data/transactions/logic/evalStateful_test.go @@ -2846,6 +2846,7 @@ func TestReturnTypes(t *testing.T) { "txnas": "txnas ApplicationArgs", "gtxnas": "gtxnas 0 ApplicationArgs", "gtxnsas": "pop; pop; int 0; int 0; gtxnsas ApplicationArgs", + "args": "args", } byName := OpsByName[LogicVersion] diff --git a/data/transactions/logic/eval_test.go b/data/transactions/logic/eval_test.go index 2ddde9660d..ecd92b15a0 100644 --- a/data/transactions/logic/eval_test.go +++ b/data/transactions/logic/eval_test.go @@ -905,18 +905,11 @@ func TestArg(t *testing.T) { t.Parallel() for v := uint64(1); v <= AssemblerMaxVersion; v++ { t.Run(fmt.Sprintf("v=%d", v), func(t *testing.T) { - ops := testProg(t, `arg 0 -arg 1 -== -arg 2 -arg 3 -!= -&& -arg 4 -len -int 9 -< -&&`, v) + source := "arg 0; arg 1; ==; arg 2; arg 3; !=; &&; arg 4; len; int 9; <; &&;" + if v >= 5 { + source += "int 0; args; int 1; args; ==; assert;" + } + ops := testProg(t, source, v) err := Check(ops.Program, defaultEvalParams(nil, nil)) require.NoError(t, err) var txn transactions.SignedTxn @@ -1428,6 +1421,11 @@ int 2 txnas ApplicationArgs == assert +txn Sender +int 0 +args +== +assert int 1 ` diff --git a/data/transactions/logic/opcodes.go b/data/transactions/logic/opcodes.go index fba221b59e..d56d1b4b27 100644 --- a/data/transactions/logic/opcodes.go +++ b/data/transactions/logic/opcodes.go @@ -303,6 +303,7 @@ var OpSpecs = []OpSpec{ {0xc0, "txnas", opTxnas, assembleTxnas, disTxn, oneInt, oneAny, 5, modeAny, immediates("f")}, {0xc1, "gtxnas", opGtxnas, assembleGtxnas, disGtxn, oneInt, oneAny, 5, modeAny, immediates("t", "f")}, {0xc2, "gtxnsas", opGtxnsas, assembleGtxnsas, disTxn, twoInts, oneAny, 5, modeAny, immediates("f")}, + {0xc3, "args", opArgs, asmDefault, disDefault, oneInt, oneBytes, 5, runModeSignature, opDefault}, } type sortByOpcode []OpSpec From 1cb18d5e8a5f3699f5a9a1f37f5ebb3020c4f21a Mon Sep 17 00:00:00 2001 From: algochoi <86622919+algochoi@users.noreply.github.com> Date: Tue, 7 Sep 2021 11:50:24 -0400 Subject: [PATCH 4/7] Address PR comments --- data/transactions/logic/TEAL_opcodes.md | 56 ++++++++++++------------- data/transactions/logic/eval.go | 10 ++++- data/transactions/logic/eval_test.go | 4 +- 3 files changed, 37 insertions(+), 33 deletions(-) diff --git a/data/transactions/logic/TEAL_opcodes.md b/data/transactions/logic/TEAL_opcodes.md index eb051a5cd8..01f5909410 100644 --- a/data/transactions/logic/TEAL_opcodes.md +++ b/data/transactions/logic/TEAL_opcodes.md @@ -1217,7 +1217,33 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit `log` can be called up to MaxLogCalls times in a program, and log up to a total of 1k bytes. -<<<<<<< HEAD +## tx_begin + +- Opcode: 0xb1 +- Pops: _None_ +- Pushes: _None_ +- Prepare a new application action +- LogicSigVersion >= 5 +- Mode: Application + +## tx_field f + +- Opcode: 0xb2 {uint8 transaction field index} +- Pops: *... stack*, any +- Pushes: _None_ +- Set field F of the current application action +- LogicSigVersion >= 5 +- Mode: Application + +## tx_submit + +- Opcode: 0xb3 +- Pops: _None_ +- Pushes: _None_ +- Execute the current application action. Panic on any failure. +- LogicSigVersion >= 5 +- Mode: Application + ## txnas f - Opcode: 0xc0 {uint8 transaction field index} @@ -1250,31 +1276,3 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - push Xth LogicSig argument to stack - LogicSigVersion >= 5 - Mode: Signature -======= -## tx_begin - -- Opcode: 0xb1 -- Pops: _None_ -- Pushes: _None_ -- Prepare a new application action -- LogicSigVersion >= 5 -- Mode: Application - -## tx_field f - -- Opcode: 0xb2 {uint8 transaction field index} -- Pops: *... stack*, any -- Pushes: _None_ -- Set field F of the current application action -- LogicSigVersion >= 5 -- Mode: Application - -## tx_submit - -- Opcode: 0xb3 -- Pops: _None_ -- Pushes: _None_ -- Execute the current application action. Panic on any failure. -- LogicSigVersion >= 5 -- Mode: Application ->>>>>>> cd832b3c85fdc2ad3d98593b49cbe34b7a6dfc2a diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index 3ae2320cfd..4c88b83bf6 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -2170,6 +2170,9 @@ func opGtxnas(cx *EvalContext) { if gtxid >= len(cx.TxnGroup) { cx.err = fmt.Errorf("gtxnas lookup TxnGroup[%d] but it only has %d", gtxid, len(cx.TxnGroup)) return + } else if gtxid < 0 { + cx.err = fmt.Errorf("gtxnas lookup %d cannot be negative", gtxid) + return } tx := &cx.TxnGroup[gtxid].Txn field := TxnField(cx.program[cx.pc+2]) @@ -2260,7 +2263,10 @@ func opGtxnsas(cx *EvalContext) { gtxid := int(cx.stack[prev].Uint) if gtxid >= len(cx.TxnGroup) { - cx.err = fmt.Errorf("gtxnsa lookup TxnGroup[%d] but it only has %d", gtxid, len(cx.TxnGroup)) + cx.err = fmt.Errorf("gtxnsas lookup TxnGroup[%d] but it only has %d", gtxid, len(cx.TxnGroup)) + return + } else if gtxid < 0 { + cx.err = fmt.Errorf("gtxnsas lookup %d cannot be negative", gtxid) return } tx := &cx.TxnGroup[gtxid].Txn @@ -2272,7 +2278,7 @@ func opGtxnsas(cx *EvalContext) { } _, ok = txnaFieldSpecByField[field] if !ok { - cx.err = fmt.Errorf("gtxnsa unsupported field %d", field) + cx.err = fmt.Errorf("gtxnsas unsupported field %d", field) return } arrayFieldIdx := cx.stack[last].Uint diff --git a/data/transactions/logic/eval_test.go b/data/transactions/logic/eval_test.go index 2fcb2528f8..6ba30249af 100644 --- a/data/transactions/logic/eval_test.go +++ b/data/transactions/logic/eval_test.go @@ -1806,7 +1806,7 @@ int 2 && ` - gtxnText := gtxnTextV4 + `int 0 + gtxnTextV5 := gtxnTextV4 + `int 0 gtxnas 0 Accounts gtxn 0 Sender == @@ -1823,7 +1823,7 @@ gtxn 0 Sender 1: gtxnTextV1, 2: gtxnTextV2, 4: gtxnTextV4, - 5: gtxnText, + 5: gtxnTextV5, } for v, source := range tests { From d18878e6e0b089e7e07378dc077d7af10f59c0ec Mon Sep 17 00:00:00 2001 From: algochoi <86622919+algochoi@users.noreply.github.com> Date: Tue, 7 Sep 2021 14:21:24 -0400 Subject: [PATCH 5/7] Fix op docs --- data/transactions/logic/README.md | 4 ++-- data/transactions/logic/TEAL_opcodes.md | 4 ++-- data/transactions/logic/doc.go | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/data/transactions/logic/README.md b/data/transactions/logic/README.md index cef3e87ed2..d7802ca479 100644 --- a/data/transactions/logic/README.md +++ b/data/transactions/logic/README.md @@ -243,8 +243,8 @@ Some of these have immediate data in the byte or bytes after the opcode. | `gloads i` | push Ith scratch space index of the Xth transaction in the current group | | `gaid t` | push the ID of the asset or application created in the Tth transaction of the current group | | `gaids` | push the ID of the asset or application created in the Xth transaction of the current group | -| `txnas f` | pop an index A. push Ath value of the array field F of the current transaction | -| `gtxnas t f` | pop an index A. push Ath value of the array field F from the Tth transaction in the current group | +| `txnas f` | push Xth value of the array field F of the current transaction | +| `gtxnas t f` | push Xth value of the array field F from the Tth transaction in the current group | | `gtxnsas f` | pop an index A and an index B. push Bth value of the array field F from the Ath transaction in the current group | | `args` | push Xth LogicSig argument to stack | diff --git a/data/transactions/logic/TEAL_opcodes.md b/data/transactions/logic/TEAL_opcodes.md index 01f5909410..32747e61ef 100644 --- a/data/transactions/logic/TEAL_opcodes.md +++ b/data/transactions/logic/TEAL_opcodes.md @@ -1249,7 +1249,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Opcode: 0xc0 {uint8 transaction field index} - Pops: *... stack*, uint64 - Pushes: any -- pop an index A. push Ath value of the array field F of the current transaction +- push Xth value of the array field F of the current transaction - LogicSigVersion >= 5 ## gtxnas t f @@ -1257,7 +1257,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Opcode: 0xc1 {uint8 transaction group index} {uint8 transaction field index} - Pops: *... stack*, uint64 - Pushes: any -- pop an index A. push Ath value of the array field F from the Tth transaction in the current group +- push Xth value of the array field F from the Tth transaction in the current group - LogicSigVersion >= 5 ## gtxnsas f diff --git a/data/transactions/logic/doc.go b/data/transactions/logic/doc.go index 31dbd6a034..760c6a75c0 100644 --- a/data/transactions/logic/doc.go +++ b/data/transactions/logic/doc.go @@ -156,8 +156,8 @@ var opDocByName = map[string]string{ "tx_field": "Set field F of the current application action", "tx_submit": "Execute the current application action. Panic on any failure.", - "txnas": "pop an index A. push Ath value of the array field F of the current transaction", - "gtxnas": "pop an index A. push Ath value of the array field F from the Tth transaction in the current group", + "txnas": "push Xth value of the array field F of the current transaction", + "gtxnas": "push Xth value of the array field F from the Tth transaction in the current group", "gtxnsas": "pop an index A and an index B. push Bth value of the array field F from the Ath transaction in the current group", "args": "push Xth LogicSig argument to stack", } From 1bf8bfd07479d8e3f80cc35433ec811b82723002 Mon Sep 17 00:00:00 2001 From: algochoi <86622919+algochoi@users.noreply.github.com> Date: Tue, 7 Sep 2021 14:22:43 -0400 Subject: [PATCH 6/7] Fix cast --- data/transactions/logic/eval.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index 4c88b83bf6..796b936068 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -2166,7 +2166,7 @@ func opGtxna(cx *EvalContext) { func opGtxnas(cx *EvalContext) { last := len(cx.stack) - 1 - gtxid := int(uint(cx.program[cx.pc+1])) + gtxid := int(cx.program[cx.pc+1]) if gtxid >= len(cx.TxnGroup) { cx.err = fmt.Errorf("gtxnas lookup TxnGroup[%d] but it only has %d", gtxid, len(cx.TxnGroup)) return From 12b0bb8a32b673e9f1887f815522e6d139735268 Mon Sep 17 00:00:00 2001 From: algochoi <86622919+algochoi@users.noreply.github.com> Date: Tue, 7 Sep 2021 16:22:33 -0400 Subject: [PATCH 7/7] Fix gtxnsas opdoc --- cmd/opdoc/opdoc.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/opdoc/opdoc.go b/cmd/opdoc/opdoc.go index ad1ce4d2d9..2516e8ef1b 100644 --- a/cmd/opdoc/opdoc.go +++ b/cmd/opdoc/opdoc.go @@ -238,7 +238,7 @@ func argEnum(name string) []string { if name == "global" { return logic.GlobalFieldNames } - if name == "txna" || name == "gtxna" || name == "gtxnsa" || name == "txnas" || name == "gtxnas" { + if name == "txna" || name == "gtxna" || name == "gtxnsa" || name == "txnas" || name == "gtxnas" || name == "gtxnsas" { return logic.TxnaFieldNames } if name == "asset_holding_get" { @@ -282,7 +282,7 @@ func argEnumTypes(name string) string { if name == "global" { return typeString(logic.GlobalFieldTypes) } - if name == "txna" || name == "gtxna" || name == "gtxnsa" || name == "txnas" || name == "gtxnas" { + if name == "txna" || name == "gtxna" || name == "gtxnsa" || name == "txnas" || name == "gtxnas" || name == "gtxnsas" { return typeString(logic.TxnaFieldTypes) } if name == "asset_holding_get" {