From f3280198afc98307a52763b9d2b5ac7bb3fa2f91 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Fri, 3 Sep 2021 14:08:39 -0400 Subject: [PATCH 01/23] Preliminary AVM 1.0 spec updates --- dev/TEAL.md | 68 ++++++++++++++++---- dev/TEAL_opcodes.md | 152 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 193 insertions(+), 27 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index 049e9fe..e27b6b8 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -88,7 +88,7 @@ An application transaction must indicate the action to be taken following the ex Most operations work with only one type of argument, uint64 or bytes, and panic if the wrong type value is on the stack. -Many instructions accept values to designate Accounts, Assets, or Applications. Beginning with TEAL v4, these values may always be given as an _offset_ in the corresponding Txn fields (Txn.Accounts, Txn.ForeignAssets, Txn.ForeignApps) _or_ as the value itself (a bytes address for Accounts, or a uint64 ID). The values, however, must still be present in the Txn fields. Before TEAL v4, most opcodes required the use of an offset, except for reading account local values of assets or applications, which accepted the IDs directly and did not require the ID to be present in they corresponding _Foreign_ array. (Note that beginning with TEAL v4, those ID are required to be present in their corresponding _Foreign_ array.) See individual opcodes for details. In the case of account offsets or application offsets, 0 is specially defined to Txn.Sender or the ID of the current application, respectively. +Many instructions accept values to designate Accounts, Assets, or Applications. Beginning with TEAL v4, these values may always be given as an _offset_ in the corresponding Txn fields (Txn.Accounts, Txn.ForeignAssets, Txn.ForeignApps) _or_ as the value itself (a bytes address for Accounts, or a uint64 ID). The values, however, must still be present in the Txn fields. Before TEAL v4, most opcodes required the use of an offset, except for reading account local values of assets or applications, which accepted the IDs directly and did not require the ID to be present in they corresponding _Foreign_ array. (Note that beginning with TEAL v4, those IDs are required to be present in their corresponding _Foreign_ array.) See individual opcodes for details. In the case of account offsets or application offsets, 0 is specially defined to Txn.Sender or the ID of the current application, respectively. Many programs need only a few dozen instructions. The instruction set has some optimization built in. `intc`, `bytec`, and `arg` take an immediate value byte, making a 2-byte op to load a value onto the stack, but they also have single byte versions for loading the most common constant values. Any program will benefit from having a few common values loaded with a smaller one byte opcode. Cryptographic hashes and `ed25519verify` are single byte opcodes with powerful libraries behind them. These operations still take more time than other ops (and this is reflected in the cost of each op and the cost limit of a program) but are efficient in compiled code space. @@ -104,7 +104,7 @@ For one-argument ops, `X` is the last element on the stack, which is typically r For two-argument ops, `A` is the penultimate element on the stack and `B` is the top of the stack. These typically result in popping A and B from the stack and pushing the result. -For three-argument ops, `A` is the element two below the top, `B` is the penultimate stack element and `C` is the top of the stack. These operatiosn typically pop A, B, and C from the stack and push the result. +For three-argument ops, `A` is the element two below the top, `B` is the penultimate stack element and `C` is the top of the stack. These operations typically pop A, B, and C from the stack and push the result. | Op | Description | | --- | --- | @@ -114,7 +114,7 @@ For three-argument ops, `A` is the element two below the top, `B` is the penulti | `ed25519verify` | for (data A, signature B, pubkey C) verify the signature of ("ProgData" \|\| program_hash \|\| data) against the pubkey => {0 or 1} | | `+` | A plus B. Panic on overflow. | | `-` | A minus B. Panic if B > A. | -| `/` | A divided by B. Panic if B == 0. | +| `/` | A divided by B (truncated division). Panic if B == 0. | | `*` | A times B. Panic on overflow. | | `<` | A less than B => {0 or 1} | | `>` | A greater than B => {0 or 1} | @@ -147,8 +147,19 @@ For three-argument ops, `A` is the element two below the top, `B` is the penulti | `getbyte` | pop a byte-array A and integer B. Extract the Bth byte of A and push it as an integer | | `setbyte` | pop a byte-array A, integer B, and small integer C (between 0..255). Set the Bth byte of A to C, and push the result | | `concat` | pop two byte-arrays A and B and join them, push the result | + +These opcodes return portions of byte arrays, accessed by position, in +various sizes. + +| Op | Description | +| --- | --- | | `substring s e` | pop a byte-array A. For immediate values in 0..255 S and E: extract a range of bytes from A starting at S up to but not including E, push the substring result. If E < S, or either is larger than the array length, the program fails | | `substring3` | pop a byte-array A and two integers B and C. Extract a range of bytes from A starting at B up to but not including C, push the substring result. If C < B, or either is larger than the array length, the program fails | +| `extract s l` | pop a byte-array A. For immediate values in 0..255 S and L: extract a range of bytes from A starting at S up to but not including S+L, push the substring result. If L is 0, then extract to the end of the string. If S or S+L is larger than the array length, the program fails | +| `extract3` | pop a byte-array A and two integers B and C. Extract a range of bytes from A starting at B up to but not including B+C, push the substring result. If B or B+C is larger than the array length, the program fails | +| `extract16bits` | pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+2, convert bytes as big endian and push the uint64 result. If B or B+2 is larger than the array length, the program fails | +| `extract32bits` | pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+4, convert bytes as big endian and push the uint64 result. If B or B+4 is larger than the array length, the program fails | +| `extract64bits` | pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+8, convert bytes as big endian and push the uint64 result. If B or B+8 is larger than the array length, the program fails | These opcodes take byte-array values that are interpreted as big-endian unsigned integers. For mathematical operators, the @@ -166,7 +177,7 @@ bytes on outputs. | --- | --- | | `b+` | A plus B, where A and B are byte-arrays interpreted as big-endian unsigned integers | | `b-` | A minus B, where A and B are byte-arrays interpreted as big-endian unsigned integers. Panic on underflow. | -| `b/` | A divided by B, where A and B are byte-arrays interpreted as big-endian unsigned integers. Panic if B is zero. | +| `b/` | A divided by B (truncated division), where A and B are byte-arrays interpreted as big-endian unsigned integers. Panic if B is zero. | | `b*` | A times B, where A and B are byte-arrays interpreted as big-endian unsigned integers. | | `b<` | A is less than B, where A and B are byte-arrays interpreted as big-endian unsigned integers => { 0 or 1} | | `b>` | A is greater than B, where A and B are byte-arrays interpreted as big-endian unsigned integers => { 0 or 1} | @@ -189,6 +200,15 @@ these results may contain leading zero bytes. | `b^` | A bitwise-xor B, where A and B are byte-arrays, zero-left extended to the greater of their lengths | | `b~` | X with all bits inverted | +The following opcodes allow for the construction and submission of +"inner transaction" + +| Op | Description | +| --- | --- | +| `tx_begin` | Prepare a new application action | +| `tx_field f` | Set field F of the current application action | +| `tx_submit` | Execute the current application action. Panic on any failure. | + ### Loading Values @@ -241,17 +261,17 @@ Some of these have immediate data in the byte or bytes after the opcode. | 2 | FirstValid | uint64 | round number | | 3 | FirstValidTime | uint64 | Causes program to fail; reserved for future use | | 4 | LastValid | uint64 | round number | -| 5 | Note | []byte | | -| 6 | Lease | []byte | | +| 5 | Note | []byte | Any data up to 1024 bytes | +| 6 | Lease | []byte | 32 byte lease value | | 7 | Receiver | []byte | 32 byte address | | 8 | Amount | uint64 | micro-Algos | | 9 | CloseRemainderTo | []byte | 32 byte address | | 10 | VotePK | []byte | 32 byte address | | 11 | SelectionPK | []byte | 32 byte address | -| 12 | VoteFirst | uint64 | | -| 13 | VoteLast | uint64 | | -| 14 | VoteKeyDilution | uint64 | | -| 15 | Type | []byte | | +| 12 | VoteFirst | uint64 | The first round that the participation key is valid. | +| 13 | VoteLast | uint64 | The last round that the participation key is valid. | +| 14 | VoteKeyDilution | uint64 | Dilution for the 2-level participation key | +| 15 | Type | []byte | Transaction type as bytes | | 16 | TypeEnum | uint64 | See table below | | 17 | XferAsset | uint64 | Asset ID | | 18 | AssetAmount | uint64 | value in Asset's units | @@ -293,6 +313,7 @@ Some of these have immediate data in the byte or bytes after the opcode. | 54 | LocalNumUint | uint64 | Number of local state integers in ApplicationCall. LogicSigVersion >= 3. | | 55 | LocalNumByteSlice | uint64 | Number of local state byteslices in ApplicationCall. LogicSigVersion >= 3. | | 56 | ExtraProgramPages | uint64 | Number of additional pages for each of the application's approval and clear state programs. An ExtraProgramPages of 1 means 2048 more total bytes, or 1024 for each program. LogicSigVersion >= 4. | +| 57 | Nonparticipation | uint64 | Marks an account nonparticipating for rewards. LogicSigVersion >= 5. | Additional details in the [opcodes document](TEAL_opcodes.md#txn) on the `txn` op. @@ -313,11 +334,12 @@ Global fields are fields that are common to all the transactions in the group. I | 7 | LatestTimestamp | uint64 | Last confirmed block UNIX timestamp. Fails if negative. LogicSigVersion >= 2. | | 8 | CurrentApplicationID | uint64 | ID of current application executing. Fails if no such application is executing. LogicSigVersion >= 2. | | 9 | CreatorAddress | []byte | Address of the creator of the current application. Fails if no such application is executing. LogicSigVersion >= 3. | +| 10 | CurrentApplicationAddress | []byte | Address that the current application controls. Fails if no such application is executing. LogicSigVersion >= 5. | **Asset Fields** -Asset fields include `AssetHolding` and `AssetParam` fields that are used in `asset_read_*` opcodes +Asset fields include `AssetHolding` and `AssetParam` fields that are used in the `asset_holding_get` and `asset_params_get` opcodes. | Index | Name | Type | Notes | | --- | --- | --- | --- | @@ -338,6 +360,24 @@ Asset fields include `AssetHolding` and `AssetParam` fields that are used in `as | 8 | AssetReserve | []byte | Reserve address | | 9 | AssetFreeze | []byte | Freeze address | | 10 | AssetClawback | []byte | Clawback address | +| 11 | AssetCreator | []byte | Creator address | + + +**App Fields** + +App fields used in the `app_params_get` opcode. + +| Index | Name | Type | Notes | +| --- | --- | --- | --- | +| 0 | AppApprovalProgram | []byte | Bytecode of Approval Program | +| 1 | AppClearStateProgram | []byte | Bytecode of Clear State Program | +| 2 | AppGlobalNumUint | uint64 | Number of uint64 values allowed in Global State | +| 3 | AppGlobalNumByteSlice | uint64 | Number of byte array values allowed in Global State | +| 4 | AppLocalNumUint | uint64 | Number of uint64 values allowed in Local State | +| 5 | AppLocalNumByteSlice | uint64 | Number of byte array values allowed in Local State | +| 6 | AppExtraProgramPages | uint64 | Number of Extra Program Pages of code space | +| 7 | AppCreator | []byte | Creator address | +| 8 | AppAddress | []byte | Address for which this application has authority | ### Flow Control @@ -353,6 +393,8 @@ Asset fields include `AssetHolding` and `AssetParam` fields that are used in `as | `dup` | duplicate last value on stack | | `dup2` | duplicate two last values on stack: A, B -> A, B, A, B | | `dig n` | push the Nth value from the top of the stack. dig 0 is equivalent to dup | +| `cover n` | remove top of stack, and place it down the stack such that N elements are above it | +| `uncover n` | remove the value at depth N in the stack and shift above items down so the Nth deep value is on top of the stack | | `swap` | swaps two last values on stack: A, B -> B, A | | `select` | selects one of two values based on top-of-stack: A, B, C -> (if C != 0 then B else A) | | `assert` | immediately fail unless value X is a non-zero number | @@ -376,6 +418,8 @@ Asset fields include `AssetHolding` and `AssetParam` fields that are used in `as | `app_global_del` | delete key A from a global state of the current application | | `asset_holding_get i` | read from account A and asset B holding field X (imm arg) => {0 or 1 (top), value} | | `asset_params_get i` | read from asset A params field X (imm arg) => {0 or 1 (top), value} | +| `app_params_get i` | read from app A params field X (imm arg) => {0 or 1 (top), value} | +| `log` | write bytes to log state of the current application | # Assembler Syntax @@ -408,7 +452,7 @@ byte "string literal" `int` constants may be `0x` prefixed for hex, `0` prefixed for octal, or decimal numbers. -`intcblock` may be explictly assembled. It will conflict with the assembler gathering `int` pseudo-ops into a `intcblock` program prefix, but may be used if code only has explicit `intc` references. `intcblock` should be followed by space separated int constants all on one line. +`intcblock` may be explicitly assembled. It will conflict with the assembler gathering `int` pseudo-ops into a `intcblock` program prefix, but may be used if code only has explicit `intc` references. `intcblock` should be followed by space separated int constants all on one line. `bytecblock` may be explicitly assembled. It will conflict with the assembler if there are any `byte` pseudo-ops but may be used if only explicit `bytec` references are used. `bytecblock` should be followed with byte constants all on one line, either 'encoding value' pairs (`b64 AAA...`) or 0x prefix or function-style values (`base64(...)`) or string literal values. diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index f514057..5b4807b 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -26,7 +26,7 @@ Ops have a 'cost' of 1 unless otherwise specified. - SHA256 hash of value X, yields [32]byte - **Cost**: - 7 (LogicSigVersion = 1) - - 35 (2 <= LogicSigVersion <= 4) + - 35 (2 <= LogicSigVersion <= 5) ## keccak256 @@ -36,7 +36,7 @@ Ops have a 'cost' of 1 unless otherwise specified. - Keccak256 hash of value X, yields [32]byte - **Cost**: - 26 (LogicSigVersion = 1) - - 130 (2 <= LogicSigVersion <= 4) + - 130 (2 <= LogicSigVersion <= 5) ## sha512_256 @@ -46,7 +46,7 @@ Ops have a 'cost' of 1 unless otherwise specified. - SHA512_256 hash of value X, yields [32]byte - **Cost**: - 9 (LogicSigVersion = 1) - - 45 (2 <= LogicSigVersion <= 4) + - 45 (2 <= LogicSigVersion <= 5) ## ed25519verify @@ -55,7 +55,6 @@ Ops have a 'cost' of 1 unless otherwise specified. - Pushes: uint64 - for (data A, signature B, pubkey C) verify the signature of ("ProgData" || program_hash || data) against the pubkey => {0 or 1} - **Cost**: 1900 -- Mode: Signature The 32 byte public key is the last element on the stack, preceded by the 64 byte signature at the second-to-last element on the stack, preceded by the data which was signed at the third-to-last element on the stack. @@ -80,7 +79,7 @@ Overflow is an error condition which halts execution and fails the transaction. - Opcode: 0x0a - Pops: *... stack*, {uint64 A}, {uint64 B} - Pushes: uint64 -- A divided by B. Panic if B == 0. +- A divided by B (truncated division). Panic if B == 0. `divmodw` is available to divide the two-element values produced by `mulw` and `addw`. @@ -382,17 +381,17 @@ Overflow is an error condition which halts execution and fails the transaction. | 2 | FirstValid | uint64 | round number | | 3 | FirstValidTime | uint64 | Causes program to fail; reserved for future use | | 4 | LastValid | uint64 | round number | -| 5 | Note | []byte | | -| 6 | Lease | []byte | | +| 5 | Note | []byte | Any data up to 1024 bytes | +| 6 | Lease | []byte | 32 byte lease value | | 7 | Receiver | []byte | 32 byte address | | 8 | Amount | uint64 | micro-Algos | | 9 | CloseRemainderTo | []byte | 32 byte address | | 10 | VotePK | []byte | 32 byte address | | 11 | SelectionPK | []byte | 32 byte address | -| 12 | VoteFirst | uint64 | | -| 13 | VoteLast | uint64 | | -| 14 | VoteKeyDilution | uint64 | | -| 15 | Type | []byte | | +| 12 | VoteFirst | uint64 | The first round that the participation key is valid. | +| 13 | VoteLast | uint64 | The last round that the participation key is valid. | +| 14 | VoteKeyDilution | uint64 | Dilution for the 2-level participation key | +| 15 | Type | []byte | Transaction type as bytes | | 16 | TypeEnum | uint64 | See table below | | 17 | XferAsset | uint64 | Asset ID | | 18 | AssetAmount | uint64 | value in Asset's units | @@ -434,6 +433,7 @@ Overflow is an error condition which halts execution and fails the transaction. | 54 | LocalNumUint | uint64 | Number of local state integers in ApplicationCall. LogicSigVersion >= 3. | | 55 | LocalNumByteSlice | uint64 | Number of local state byteslices in ApplicationCall. LogicSigVersion >= 3. | | 56 | ExtraProgramPages | uint64 | Number of additional pages for each of the application's approval and clear state programs. An ExtraProgramPages of 1 means 2048 more total bytes, or 1024 for each program. LogicSigVersion >= 4. | +| 57 | Nonparticipation | uint64 | Marks an account nonparticipating for rewards. LogicSigVersion >= 5. | TypeEnum mapping: @@ -472,6 +472,7 @@ FirstValidTime causes the program to fail. The field is reserved for future use. | 7 | LatestTimestamp | uint64 | Last confirmed block UNIX timestamp. Fails if negative. LogicSigVersion >= 2. | | 8 | CurrentApplicationID | uint64 | ID of current application executing. Fails if no such application is executing. LogicSigVersion >= 2. | | 9 | CreatorAddress | []byte | Address of the creator of the current application. Fails if no such application is executing. LogicSigVersion >= 3. | +| 10 | CurrentApplicationAddress | []byte | Address that the current application controls. Fails if no such application is executing. LogicSigVersion >= 5. | ## gtxn t f @@ -555,7 +556,7 @@ for notes on transaction fields available, see `txn`. If top of stack is _i_, `g ## gaid t -- Opcode: 0x3c +- Opcode: 0x3c {uint8 transaction group index} - Pops: _None_ - Pushes: uint64 - push the ID of the asset or application created in the Tth transaction of the current group @@ -573,7 +574,7 @@ for notes on transaction fields available, see `txn`. If top of stack is _i_, `g - LogicSigVersion >= 4 - Mode: Application -`gaidx` fails unless the requested transaction created an asset or application and X < GroupIndex. +`gaids` fails unless the requested transaction created an asset or application and X < GroupIndex. ## bnz target @@ -668,6 +669,22 @@ See `bnz` for details on how branches work. `b` always jumps to the offset. - selects one of two values based on top-of-stack: A, B, C -> (if C != 0 then B else A) - LogicSigVersion >= 3 +## cover n + +- Opcode: 0x4e {uint8 depth} +- Pops: *... stack*, any +- Pushes: any +- remove top of stack, and place it down the stack such that N elements are above it +- LogicSigVersion >= 5 + +## uncover n + +- Opcode: 0x4f {uint8 depth} +- Pops: *... stack*, any +- Pushes: any +- remove the value at depth N in the stack and shift above items down so the Nth deep value is on top of the stack +- LogicSigVersion >= 5 + ## concat - Opcode: 0x50 @@ -730,6 +747,46 @@ When A is a uint64, index 0 is the least significant bit. Setting bit 3 to 1 on - pop a byte-array A, integer B, and small integer C (between 0..255). Set the Bth byte of A to C, and push the result - LogicSigVersion >= 3 +## extract s l + +- Opcode: 0x57 {uint8 start position} {uint8 length} +- Pops: *... stack*, []byte +- Pushes: []byte +- pop a byte-array A. For immediate values in 0..255 S and L: extract a range of bytes from A starting at S up to but not including S+L, push the substring result. If L is 0, then extract to the end of the string. If S or S+L is larger than the array length, the program fails +- LogicSigVersion >= 5 + +## extract3 + +- Opcode: 0x58 +- Pops: *... stack*, {[]byte A}, {uint64 B}, {uint64 C} +- Pushes: []byte +- pop a byte-array A and two integers B and C. Extract a range of bytes from A starting at B up to but not including B+C, push the substring result. If B or B+C is larger than the array length, the program fails +- LogicSigVersion >= 5 + +## extract16bits + +- Opcode: 0x59 +- Pops: *... stack*, {[]byte A}, {uint64 B} +- Pushes: uint64 +- pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+2, convert bytes as big endian and push the uint64 result. If B or B+2 is larger than the array length, the program fails +- LogicSigVersion >= 5 + +## extract32bits + +- Opcode: 0x5a +- Pops: *... stack*, {[]byte A}, {uint64 B} +- Pushes: uint64 +- pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+4, convert bytes as big endian and push the uint64 result. If B or B+4 is larger than the array length, the program fails +- LogicSigVersion >= 5 + +## extract64bits + +- Opcode: 0x5b +- Pops: *... stack*, {[]byte A}, {uint64 B} +- Pushes: uint64 +- pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+8, convert bytes as big endian and push the uint64 result. If B or B+8 is larger than the array length, the program fails +- LogicSigVersion >= 5 + ## balance - Opcode: 0x60 @@ -885,10 +942,37 @@ params: Txn.Accounts offset (or, since v4, an account address that appears in Tx | 8 | AssetReserve | []byte | Reserve address | | 9 | AssetFreeze | []byte | Freeze address | | 10 | AssetClawback | []byte | Clawback address | +| 11 | AssetCreator | []byte | Creator address | params: Before v4, Txn.ForeignAssets offset. Since v4, Txn.ForeignAssets offset or an asset id that appears in Txn.ForeignAssets. Return: did_exist flag (1 if exist and 0 otherwise), value. +## app_params_get i + +- Opcode: 0x72 {uint8 app params field index} +- Pops: *... stack*, uint64 +- Pushes: *... stack*, any, uint64 +- read from app A params field X (imm arg) => {0 or 1 (top), value} +- LogicSigVersion >= 5 +- Mode: Application + +`app_params_get` Fields: + +| Index | Name | Type | Notes | +| --- | --- | --- | --- | +| 0 | AppApprovalProgram | []byte | Bytecode of Approval Program | +| 1 | AppClearStateProgram | []byte | Bytecode of Clear State Program | +| 2 | AppGlobalNumUint | uint64 | Number of uint64 values allowed in Global State | +| 3 | AppGlobalNumByteSlice | uint64 | Number of byte array values allowed in Global State | +| 4 | AppLocalNumUint | uint64 | Number of uint64 values allowed in Local State | +| 5 | AppLocalNumByteSlice | uint64 | Number of byte array values allowed in Local State | +| 6 | AppExtraProgramPages | uint64 | Number of Extra Program Pages of code space | +| 7 | AppCreator | []byte | Creator address | +| 8 | AppAddress | []byte | Address for which this application has authority | + + +params: Txn.ForeignApps offset or an app id that appears in Txn.ForeignApps. Return: did_exist flag (1 if exist and 0 otherwise), value. + ## min_balance - Opcode: 0x78 @@ -922,7 +1006,7 @@ pushint args are not added to the intcblock during assembly processes ## callsub target -- Opcode: 0x88 +- Opcode: 0x88 {int16 branch offset, big endian} - Pops: _None_ - Pushes: _None_ - branch unconditionally to TARGET, saving the next instruction on the call stack @@ -1015,7 +1099,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Opcode: 0xa2 - Pops: *... stack*, {[]byte A}, {[]byte B} - Pushes: []byte -- A divided by B, where A and B are byte-arrays interpreted as big-endian unsigned integers. Panic if B is zero. +- A divided by B (truncated division), where A and B are byte-arrays interpreted as big-endian unsigned integers. Panic if B is zero. - **Cost**: 20 - LogicSigVersion >= 4 @@ -1128,3 +1212,41 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Pushes: []byte - push a byte-array of length X, containing all zero bytes - LogicSigVersion >= 4 + +## log + +- Opcode: 0xb0 +- Pops: *... stack*, []byte +- Pushes: _None_ +- write bytes to log state of the current application +- LogicSigVersion >= 5 +- Mode: Application + +`log` can be called up to MaxLogCalls times in a program, and log up to a total of 1k bytes. + +## 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 From 245cc7c845fb87aa5889c533e4c630d32331240f Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Sun, 5 Sep 2021 12:54:55 -0400 Subject: [PATCH 02/23] Initial Shai recomendations --- dev/TEAL.md | 16 ++++++++-------- dev/TEAL_opcodes.md | 22 +++++++++++----------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index e27b6b8..e02ed93 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -156,10 +156,10 @@ various sizes. | `substring s e` | pop a byte-array A. For immediate values in 0..255 S and E: extract a range of bytes from A starting at S up to but not including E, push the substring result. If E < S, or either is larger than the array length, the program fails | | `substring3` | pop a byte-array A and two integers B and C. Extract a range of bytes from A starting at B up to but not including C, push the substring result. If C < B, or either is larger than the array length, the program fails | | `extract s l` | pop a byte-array A. For immediate values in 0..255 S and L: extract a range of bytes from A starting at S up to but not including S+L, push the substring result. If L is 0, then extract to the end of the string. If S or S+L is larger than the array length, the program fails | -| `extract3` | pop a byte-array A and two integers B and C. Extract a range of bytes from A starting at B up to but not including B+C, push the substring result. If B or B+C is larger than the array length, the program fails | -| `extract16bits` | pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+2, convert bytes as big endian and push the uint64 result. If B or B+2 is larger than the array length, the program fails | -| `extract32bits` | pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+4, convert bytes as big endian and push the uint64 result. If B or B+4 is larger than the array length, the program fails | -| `extract64bits` | pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+8, convert bytes as big endian and push the uint64 result. If B or B+8 is larger than the array length, the program fails | +| `extract3` | pop a byte-array A and two integers B and C. Extract a range of bytes from A starting at B up to but not including B+C, push the substring result. If B+C is larger than the array length, the program fails | +| `extract16bits` | pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+2, convert bytes as big endian and push the uint64 result. If B+2 is larger than the array length, the program fails | +| `extract32bits` | pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+4, convert bytes as big endian and push the uint64 result. If B+4 is larger than the array length, the program fails | +| `extract64bits` | pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+8, convert bytes as big endian and push the uint64 result. If B+8 is larger than the array length, the program fails | These opcodes take byte-array values that are interpreted as big-endian unsigned integers. For mathematical operators, the @@ -205,9 +205,9 @@ The following opcodes allow for the construction and submission of | Op | Description | | --- | --- | -| `tx_begin` | Prepare a new application action | -| `tx_field f` | Set field F of the current application action | -| `tx_submit` | Execute the current application action. Panic on any failure. | +| `tx_begin` | Begin preparation of a new inner transaction | +| `tx_field f` | Set field F of the current inner transaction to X | +| `tx_submit` | Execute the current inner transaction. Panic on any failure. | ### Loading Values @@ -393,7 +393,7 @@ App fields used in the `app_params_get` opcode. | `dup` | duplicate last value on stack | | `dup2` | duplicate two last values on stack: A, B -> A, B, A, B | | `dig n` | push the Nth value from the top of the stack. dig 0 is equivalent to dup | -| `cover n` | remove top of stack, and place it down the stack such that N elements are above it | +| `cover n` | remove top of stack, and place it deeper in the stack such that N elements are above it | | `uncover n` | remove the value at depth N in the stack and shift above items down so the Nth deep value is on top of the stack | | `swap` | swaps two last values on stack: A, B -> B, A | | `select` | selects one of two values based on top-of-stack: A, B, C -> (if C != 0 then B else A) | diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index 5b4807b..e6179b4 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -26,7 +26,7 @@ Ops have a 'cost' of 1 unless otherwise specified. - SHA256 hash of value X, yields [32]byte - **Cost**: - 7 (LogicSigVersion = 1) - - 35 (2 <= LogicSigVersion <= 5) + - 35 (LogicSigVersion => 2) ## keccak256 @@ -36,7 +36,7 @@ Ops have a 'cost' of 1 unless otherwise specified. - Keccak256 hash of value X, yields [32]byte - **Cost**: - 26 (LogicSigVersion = 1) - - 130 (2 <= LogicSigVersion <= 5) + - 130 (LogicSigVersion => 2) ## sha512_256 @@ -46,7 +46,7 @@ Ops have a 'cost' of 1 unless otherwise specified. - SHA512_256 hash of value X, yields [32]byte - **Cost**: - 9 (LogicSigVersion = 1) - - 45 (2 <= LogicSigVersion <= 5) + - 45 (LogicSigVersion => 2) ## ed25519verify @@ -674,7 +674,7 @@ See `bnz` for details on how branches work. `b` always jumps to the offset. - Opcode: 0x4e {uint8 depth} - Pops: *... stack*, any - Pushes: any -- remove top of stack, and place it down the stack such that N elements are above it +- remove top of stack, and place it deeper in the stack such that N elements are above it - LogicSigVersion >= 5 ## uncover n @@ -760,7 +760,7 @@ When A is a uint64, index 0 is the least significant bit. Setting bit 3 to 1 on - Opcode: 0x58 - Pops: *... stack*, {[]byte A}, {uint64 B}, {uint64 C} - Pushes: []byte -- pop a byte-array A and two integers B and C. Extract a range of bytes from A starting at B up to but not including B+C, push the substring result. If B or B+C is larger than the array length, the program fails +- pop a byte-array A and two integers B and C. Extract a range of bytes from A starting at B up to but not including B+C, push the substring result. If B+C is larger than the array length, the program fails - LogicSigVersion >= 5 ## extract16bits @@ -768,7 +768,7 @@ When A is a uint64, index 0 is the least significant bit. Setting bit 3 to 1 on - Opcode: 0x59 - Pops: *... stack*, {[]byte A}, {uint64 B} - Pushes: uint64 -- pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+2, convert bytes as big endian and push the uint64 result. If B or B+2 is larger than the array length, the program fails +- pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+2, convert bytes as big endian and push the uint64 result. If B+2 is larger than the array length, the program fails - LogicSigVersion >= 5 ## extract32bits @@ -776,7 +776,7 @@ When A is a uint64, index 0 is the least significant bit. Setting bit 3 to 1 on - Opcode: 0x5a - Pops: *... stack*, {[]byte A}, {uint64 B} - Pushes: uint64 -- pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+4, convert bytes as big endian and push the uint64 result. If B or B+4 is larger than the array length, the program fails +- pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+4, convert bytes as big endian and push the uint64 result. If B+4 is larger than the array length, the program fails - LogicSigVersion >= 5 ## extract64bits @@ -784,7 +784,7 @@ When A is a uint64, index 0 is the least significant bit. Setting bit 3 to 1 on - Opcode: 0x5b - Pops: *... stack*, {[]byte A}, {uint64 B} - Pushes: uint64 -- pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+8, convert bytes as big endian and push the uint64 result. If B or B+8 is larger than the array length, the program fails +- pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+8, convert bytes as big endian and push the uint64 result. If B+8 is larger than the array length, the program fails - LogicSigVersion >= 5 ## balance @@ -1229,7 +1229,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Opcode: 0xb1 - Pops: _None_ - Pushes: _None_ -- Prepare a new application action +- Begin preparation of a new inner transaction - LogicSigVersion >= 5 - Mode: Application @@ -1238,7 +1238,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Opcode: 0xb2 {uint8 transaction field index} - Pops: *... stack*, any - Pushes: _None_ -- Set field F of the current application action +- Set field F of the current inner transaction to X - LogicSigVersion >= 5 - Mode: Application @@ -1247,6 +1247,6 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Opcode: 0xb3 - Pops: _None_ - Pushes: _None_ -- Execute the current application action. Panic on any failure. +- Execute the current inner transaction. Panic on any failure. - LogicSigVersion >= 5 - Mode: Application From 364fca7d941d21dfbb5a52561cbcea511004e067 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Tue, 7 Sep 2021 17:25:05 -0400 Subject: [PATCH 03/23] Describe logs and inner txns in ApplyData. --- dev/ledger.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/dev/ledger.md b/dev/ledger.md index b6352ec..1aab2c4 100644 --- a/dev/ledger.md +++ b/dev/ledger.md @@ -746,10 +746,12 @@ applied to the account state. This information is called ApplyData, and contains the following fields: - The closing amount, $\ClosingAmount$, which specifies how many microalgos - were transferred to the closing address. + were transferred to the closing address, and is encoded as "ca" in + msgpack. - The asset closing amount, $\AssetClosingAmount$, which specifies how many - of the asset units were transsfered to the closing address. + of the asset units were transferred to the closing address. It is + encoded as "aca" in msgpack. - The amount of rewards distributed to each of the accounts touched by this transaction. There are three fields ("rs", "rr", and "rc" keys in msgpack @@ -774,6 +776,18 @@ and contains the following fields: offset 0 is the transaction's sender. Account offsets 1 and greater refer to the account specified at that offset minus one in the transaction's `Accounts` slice. + - Zero or more `Logs` encoded in an array `lg`, recording the arguments + to each call of the `log` opcode in the called application. The order + of the entries follows the execution order of the `log` + invocations. The maximum total number of `log` calls is 32, and the + total size of all logged bytes is limited to 1024. + - Zero or more `InnerTxns`, encoded in an array `itx`. Each element of + `itx` records a succesful invocation of the `tx_submit` opcode. Each + element will contain the transaction fields, encoded under `txn`, in + the same way that the top-level transaction is encoded, recursively, + including `ApplyData` that applies to the inner transaction. Up to 16 + `InnerTxns` may be present. + - InnerTxns are limited to `pay` and `axfer` transactions. ### State Deltas From b16a482f6b4979439f6749f74ae42cdb27b73bed Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Tue, 7 Sep 2021 18:24:10 -0400 Subject: [PATCH 04/23] Several stack oriented version of existing opcodes. --- dev/TEAL.md | 9 +++++++- dev/TEAL_opcodes.md | 52 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index e02ed93..11b7a30 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -241,16 +241,22 @@ Some of these have immediate data in the byte or bytes after the opcode. | `txn f` | push field F of current transaction to stack | | `gtxn t f` | push field F of the Tth transaction in the current group | | `txna f i` | push Ith value of the array field F of the current transaction | +| `txnas f` | push Xth value of the array field F of the current transaction | | `gtxna t f i` | push Ith value of the array field F from the Tth transaction in the current group | +| `gtxnas t f` | push Xth value of the array field F from the Tth transaction in the current group | | `gtxns f` | push field F of the Xth transaction in the current group | | `gtxnsa f i` | push Ith value of the array field F from the Xth 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 | | `global f` | push value from globals to stack | | `load i` | copy a value from scratch space to the stack | -| `store i` | pop a value from the stack and store to scratch space | +| `loads` | copy a value from the Xth scratch space to the stack | +| `store i` | pop value X. store X to the Ith scratch space | +| `stores` | pop indexes A and B. store A to the Bth scratch space | | `gload t i` | push Ith scratch space index of the Tth transaction in the current group | | `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 | +| `args` | push Xth LogicSig argument to stack | **Transaction Fields** @@ -335,6 +341,7 @@ Global fields are fields that are common to all the transactions in the group. I | 8 | CurrentApplicationID | uint64 | ID of current application executing. Fails if no such application is executing. LogicSigVersion >= 2. | | 9 | CreatorAddress | []byte | Address of the creator of the current application. Fails if no such application is executing. LogicSigVersion >= 3. | | 10 | CurrentApplicationAddress | []byte | Address that the current application controls. Fails if no such application is executing. LogicSigVersion >= 5. | +| 11 | GroupID | []byte | ID of the transaction group. 32 zero bytes if the transaction is not part of a group. LogicSigVersion >= 5. | **Asset Fields** diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index e6179b4..bb63b1b 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -473,6 +473,7 @@ FirstValidTime causes the program to fail. The field is reserved for future use. | 8 | CurrentApplicationID | uint64 | ID of current application executing. Fails if no such application is executing. LogicSigVersion >= 2. | | 9 | CreatorAddress | []byte | Address of the creator of the current application. Fails if no such application is executing. LogicSigVersion >= 3. | | 10 | CurrentApplicationAddress | []byte | Address that the current application controls. Fails if no such application is executing. LogicSigVersion >= 5. | +| 11 | GroupID | []byte | ID of the transaction group. 32 zero bytes if the transaction is not part of a group. LogicSigVersion >= 5. | ## gtxn t f @@ -496,7 +497,7 @@ for notes on transaction fields available, see `txn`. If this transaction is _i_ - Opcode: 0x35 {uint8 position in scratch space to store to} - Pops: *... stack*, any - Pushes: _None_ -- pop a value from the stack and store to scratch space +- pop value X. store X to the Ith scratch space ## txna f i @@ -576,6 +577,22 @@ for notes on transaction fields available, see `txn`. If top of stack is _i_, `g `gaids` fails unless the requested transaction created an asset or application and X < GroupIndex. +## loads + +- Opcode: 0x3e +- Pops: *... stack*, uint64 +- Pushes: any +- copy a value from the Xth scratch space to the stack +- LogicSigVersion >= 5 + +## stores + +- Opcode: 0x3f +- Pops: *... stack*, {any A}, {uint64 B} +- Pushes: _None_ +- pop indexes A and B. store A to the Bth scratch space +- LogicSigVersion >= 5 + ## bnz target - Opcode: 0x40 {int16 branch offset, big endian} @@ -1250,3 +1267,36 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Execute the current inner transaction. Panic on any failure. - LogicSigVersion >= 5 - Mode: Application + +## txnas f + +- Opcode: 0xc0 {uint8 transaction field index} +- Pops: *... stack*, uint64 +- Pushes: any +- push Xth 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 +- push Xth 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 + +## args + +- Opcode: 0xc3 +- Pops: *... stack*, uint64 +- Pushes: []byte +- push Xth LogicSig argument to stack +- LogicSigVersion >= 5 +- Mode: Signature From b358c72dabad7e3b76c993b7723b62e6f4c914af Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Thu, 9 Sep 2021 21:39:46 -0400 Subject: [PATCH 05/23] swap stores args --- dev/TEAL.md | 2 +- dev/TEAL_opcodes.md | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index 11b7a30..3748744 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -251,7 +251,7 @@ Some of these have immediate data in the byte or bytes after the opcode. | `load i` | copy a value from scratch space to the stack | | `loads` | copy a value from the Xth scratch space to the stack | | `store i` | pop value X. store X to the Ith scratch space | -| `stores` | pop indexes A and B. store A to the Bth scratch space | +| `stores` | pop indexes A and B. store B to the Ath scratch space | | `gload t i` | push Ith scratch space index of the Tth transaction in the current group | | `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 | diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index bb63b1b..8c5c2fb 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -26,7 +26,7 @@ Ops have a 'cost' of 1 unless otherwise specified. - SHA256 hash of value X, yields [32]byte - **Cost**: - 7 (LogicSigVersion = 1) - - 35 (LogicSigVersion => 2) + - 35 (LogicSigVersion >= 2) ## keccak256 @@ -36,7 +36,7 @@ Ops have a 'cost' of 1 unless otherwise specified. - Keccak256 hash of value X, yields [32]byte - **Cost**: - 26 (LogicSigVersion = 1) - - 130 (LogicSigVersion => 2) + - 130 (LogicSigVersion >= 2) ## sha512_256 @@ -46,7 +46,7 @@ Ops have a 'cost' of 1 unless otherwise specified. - SHA512_256 hash of value X, yields [32]byte - **Cost**: - 9 (LogicSigVersion = 1) - - 45 (LogicSigVersion => 2) + - 45 (LogicSigVersion >= 2) ## ed25519verify @@ -588,9 +588,9 @@ for notes on transaction fields available, see `txn`. If top of stack is _i_, `g ## stores - Opcode: 0x3f -- Pops: *... stack*, {any A}, {uint64 B} +- Pops: *... stack*, {uint64 A}, {any B} - Pushes: _None_ -- pop indexes A and B. store A to the Bth scratch space +- pop indexes A and B. store B to the Ath scratch space - LogicSigVersion >= 5 ## bnz target From 75a9cee39c91f51787bb89c7677ddc1c21b8a7ec Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Thu, 9 Sep 2021 22:34:10 -0400 Subject: [PATCH 06/23] Most of Fabrice's requests --- dev/TEAL.md | 36 ++++++++++++++++++------------------ dev/TEAL_opcodes.md | 40 ++++++++++++++++++++-------------------- dev/ledger.md | 2 +- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index 3748744..efce039 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -112,10 +112,10 @@ For three-argument ops, `A` is the element two below the top, `B` is the penulti | `keccak256` | Keccak256 hash of value X, yields [32]byte | | `sha512_256` | SHA512_256 hash of value X, yields [32]byte | | `ed25519verify` | for (data A, signature B, pubkey C) verify the signature of ("ProgData" \|\| program_hash \|\| data) against the pubkey => {0 or 1} | -| `+` | A plus B. Panic on overflow. | -| `-` | A minus B. Panic if B > A. | -| `/` | A divided by B (truncated division). Panic if B == 0. | -| `*` | A times B. Panic on overflow. | +| `+` | A plus B. Fail on overflow. | +| `-` | A minus B. Fail if B > A. | +| `/` | A divided by B (truncated division). Fail if B == 0. | +| `*` | A times B. Fail on overflow. | | `<` | A less than B => {0 or 1} | | `>` | A greater than B => {0 or 1} | | `<=` | A less than or equal to B => {0 or 1} | @@ -126,14 +126,14 @@ For three-argument ops, `A` is the element two below the top, `B` is the penulti | `shr` | A divided by 2^B | | `sqrt` | The largest integer B such that B^2 <= X | | `bitlen` | The highest set bit in X. If X is a byte-array, it is interpreted as a big-endian unsigned integer. bitlen of 0 is 0, bitlen of 8 is 4 | -| `exp` | A raised to the Bth power. Panic if A == B == 0 and on overflow | +| `exp` | A raised to the Bth power. Fail if A == B == 0 and on overflow | | `==` | A is equal to B => {0 or 1} | | `!=` | A is not equal to B => {0 or 1} | | `!` | X == 0 yields 1; else 0 | | `len` | yields length of byte value X | | `itob` | converts uint64 X to big endian bytes | | `btoi` | converts bytes X as big endian to uint64 | -| `%` | A modulo B. Panic if B == 0. | +| `%` | A modulo B. Fail if B == 0. | | `\|` | A bitwise-or B | | `&` | A bitwise-and B | | `^` | A bitwise-xor B | @@ -141,7 +141,7 @@ For three-argument ops, `A` is the element two below the top, `B` is the penulti | `mulw` | A times B out to 128-bit long result as low (top) and high uint64 values on the stack | | `addw` | A plus B out to 128-bit long result as sum (top) and carry-bit uint64 values on the stack | | `divmodw` | Pop four uint64 values. The deepest two are interpreted as a uint128 dividend (deepest value is high word), the top two are interpreted as a uint128 divisor. Four uint64 values are pushed to the stack. The deepest two are the quotient (deeper value is the high uint64). The top two are the remainder, low bits on top. | -| `expw` | A raised to the Bth power as a 128-bit long result as low (top) and high uint64 values on the stack. Panic if A == B == 0 or if the results exceeds 2^128-1 | +| `expw` | A raised to the Bth power as a 128-bit long result as low (top) and high uint64 values on the stack. Fail if A == B == 0 or if the results exceeds 2^128-1 | | `getbit` | pop a target A (integer or byte-array), and index B. Push the Bth bit of A. | | `setbit` | pop a target A, index B, and bit C. Set the Bth bit of A to C, and push the result | | `getbyte` | pop a byte-array A and integer B. Extract the Bth byte of A and push it as an integer | @@ -176,8 +176,8 @@ bytes on outputs. | Op | Description | | --- | --- | | `b+` | A plus B, where A and B are byte-arrays interpreted as big-endian unsigned integers | -| `b-` | A minus B, where A and B are byte-arrays interpreted as big-endian unsigned integers. Panic on underflow. | -| `b/` | A divided by B (truncated division), where A and B are byte-arrays interpreted as big-endian unsigned integers. Panic if B is zero. | +| `b-` | A minus B, where A and B are byte-arrays interpreted as big-endian unsigned integers. Fail on underflow. | +| `b/` | A divided by B (truncated division), where A and B are byte-arrays interpreted as big-endian unsigned integers. Fail if B is zero. | | `b*` | A times B, where A and B are byte-arrays interpreted as big-endian unsigned integers. | | `b<` | A is less than B, where A and B are byte-arrays interpreted as big-endian unsigned integers => { 0 or 1} | | `b>` | A is greater than B, where A and B are byte-arrays interpreted as big-endian unsigned integers => { 0 or 1} | @@ -185,7 +185,7 @@ bytes on outputs. | `b>=` | A is greater than or equal to B, where A and B are byte-arrays interpreted as big-endian unsigned integers => { 0 or 1} | | `b==` | A is equals to B, where A and B are byte-arrays interpreted as big-endian unsigned integers => { 0 or 1} | | `b!=` | A is not equal to B, where A and B are byte-arrays interpreted as big-endian unsigned integers => { 0 or 1} | -| `b%` | A modulo B, where A and B are byte-arrays interpreted as big-endian unsigned integers. Panic if B is zero. | +| `b%` | A modulo B, where A and B are byte-arrays interpreted as big-endian unsigned integers. Fail if B is zero. | These opcodes operate on the bits of byte-array values. The shorter array is interpeted as though left padded with zeros until it is the @@ -206,8 +206,8 @@ The following opcodes allow for the construction and submission of | Op | Description | | --- | --- | | `tx_begin` | Begin preparation of a new inner transaction | -| `tx_field f` | Set field F of the current inner transaction to X | -| `tx_submit` | Execute the current inner transaction. Panic on any failure. | +| `tx_field f` | Set field F of the current inner transaction to X. Fail if X is the wrong type for F. | +| `tx_submit` | Execute the current inner transaction. Fail if 16 inner transactions have already been executed, or if the transaction fails | ### Loading Values @@ -238,6 +238,7 @@ Some of these have immediate data in the byte or bytes after the opcode. | `arg_1` | push LogicSig argument 1 to stack | | `arg_2` | push LogicSig argument 2 to stack | | `arg_3` | push LogicSig argument 3 to stack | +| `args` | push Xth LogicSig argument to stack | | `txn f` | push field F of current transaction to stack | | `gtxn t f` | push field F of the Tth transaction in the current group | | `txna f i` | push Ith value of the array field F of the current transaction | @@ -248,15 +249,14 @@ Some of these have immediate data in the byte or bytes after the opcode. | `gtxnsa f i` | push Ith value of the array field F from the Xth 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 | | `global f` | push value from globals to stack | -| `load i` | copy a value from scratch space to the stack | -| `loads` | copy a value from the Xth scratch space to the stack | +| `load i` | copy a value from scratch space to the stack. All scratch spaces are 0 at program start. | +| `loads` | copy a value from the Xth scratch space to the stack. All scratch spaces are 0 at program start. | | `store i` | pop value X. store X to the Ith scratch space | | `stores` | pop indexes A and B. store B to the Ath scratch space | | `gload t i` | push Ith scratch space index of the Tth transaction in the current group | | `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 | -| `args` | push Xth LogicSig argument to stack | **Transaction Fields** @@ -338,9 +338,9 @@ Global fields are fields that are common to all the transactions in the group. I | 5 | LogicSigVersion | uint64 | Maximum supported TEAL version. LogicSigVersion >= 2. | | 6 | Round | uint64 | Current round number. LogicSigVersion >= 2. | | 7 | LatestTimestamp | uint64 | Last confirmed block UNIX timestamp. Fails if negative. LogicSigVersion >= 2. | -| 8 | CurrentApplicationID | uint64 | ID of current application executing. Fails if no such application is executing. LogicSigVersion >= 2. | +| 8 | CurrentApplicationID | uint64 | ID of current application executing. Fails in LogicSigs. LogicSigVersion >= 2. | | 9 | CreatorAddress | []byte | Address of the creator of the current application. Fails if no such application is executing. LogicSigVersion >= 3. | -| 10 | CurrentApplicationAddress | []byte | Address that the current application controls. Fails if no such application is executing. LogicSigVersion >= 5. | +| 10 | CurrentApplicationAddress | []byte | Address that the current application controls. Fails in LogicSigs. LogicSigVersion >= 5. | | 11 | GroupID | []byte | ID of the transaction group. 32 zero bytes if the transaction is not part of a group. LogicSigVersion >= 5. | @@ -391,7 +391,7 @@ App fields used in the `app_params_get` opcode. | Op | Description | | --- | --- | -| `err` | Error. Panic immediately. This is primarily a fencepost against accidental zero bytes getting compiled into programs. | +| `err` | Error. Fail immediately. This is primarily a fencepost against accidental zero bytes getting compiled into programs. | | `bnz target` | branch to TARGET if value X is not zero | | `bz target` | branch to TARGET if value X is zero | | `b target` | branch unconditionally to TARGET | diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index 8c5c2fb..bb61602 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -16,7 +16,7 @@ Ops have a 'cost' of 1 unless otherwise specified. - Opcode: 0x00 - Pops: _None_ - Pushes: _None_ -- Error. Panic immediately. This is primarily a fencepost against accidental zero bytes getting compiled into programs. +- Error. Fail immediately. This is primarily a fencepost against accidental zero bytes getting compiled into programs. ## sha256 @@ -63,7 +63,7 @@ The 32 byte public key is the last element on the stack, preceded by the 64 byte - Opcode: 0x08 - Pops: *... stack*, {uint64 A}, {uint64 B} - Pushes: uint64 -- A plus B. Panic on overflow. +- A plus B. Fail on overflow. Overflow is an error condition which halts execution and fails the transaction. Full precision is available from `addw`. @@ -72,14 +72,14 @@ Overflow is an error condition which halts execution and fails the transaction. - Opcode: 0x09 - Pops: *... stack*, {uint64 A}, {uint64 B} - Pushes: uint64 -- A minus B. Panic if B > A. +- A minus B. Fail if B > A. ## / - Opcode: 0x0a - Pops: *... stack*, {uint64 A}, {uint64 B} - Pushes: uint64 -- A divided by B (truncated division). Panic if B == 0. +- A divided by B (truncated division). Fail if B == 0. `divmodw` is available to divide the two-element values produced by `mulw` and `addw`. @@ -88,7 +88,7 @@ Overflow is an error condition which halts execution and fails the transaction. - Opcode: 0x0b - Pops: *... stack*, {uint64 A}, {uint64 B} - Pushes: uint64 -- A times B. Panic on overflow. +- A times B. Fail on overflow. Overflow is an error condition which halts execution and fails the transaction. Full precision is available from `mulw`. @@ -176,14 +176,14 @@ Overflow is an error condition which halts execution and fails the transaction. - Pushes: uint64 - converts bytes X as big endian to uint64 -`btoi` panics if the input is longer than 8 bytes. +`btoi` fails if the input is longer than 8 bytes. ## % - Opcode: 0x18 - Pops: *... stack*, {uint64 A}, {uint64 B} - Pushes: uint64 -- A modulo B. Panic if B == 0. +- A modulo B. Fail if B == 0. ## | @@ -470,9 +470,9 @@ FirstValidTime causes the program to fail. The field is reserved for future use. | 5 | LogicSigVersion | uint64 | Maximum supported TEAL version. LogicSigVersion >= 2. | | 6 | Round | uint64 | Current round number. LogicSigVersion >= 2. | | 7 | LatestTimestamp | uint64 | Last confirmed block UNIX timestamp. Fails if negative. LogicSigVersion >= 2. | -| 8 | CurrentApplicationID | uint64 | ID of current application executing. Fails if no such application is executing. LogicSigVersion >= 2. | +| 8 | CurrentApplicationID | uint64 | ID of current application executing. Fails in LogicSigs. LogicSigVersion >= 2. | | 9 | CreatorAddress | []byte | Address of the creator of the current application. Fails if no such application is executing. LogicSigVersion >= 3. | -| 10 | CurrentApplicationAddress | []byte | Address that the current application controls. Fails if no such application is executing. LogicSigVersion >= 5. | +| 10 | CurrentApplicationAddress | []byte | Address that the current application controls. Fails in LogicSigs. LogicSigVersion >= 5. | | 11 | GroupID | []byte | ID of the transaction group. 32 zero bytes if the transaction is not part of a group. LogicSigVersion >= 5. | @@ -490,7 +490,7 @@ for notes on transaction fields available, see `txn`. If this transaction is _i_ - Opcode: 0x34 {uint8 position in scratch space to load from} - Pops: _None_ - Pushes: any -- copy a value from scratch space to the stack +- copy a value from scratch space to the stack. All scratch spaces are 0 at program start. ## store i @@ -582,7 +582,7 @@ for notes on transaction fields available, see `txn`. If top of stack is _i_, `g - Opcode: 0x3e - Pops: *... stack*, uint64 - Pushes: any -- copy a value from the Xth scratch space to the stack +- copy a value from the Xth scratch space to the stack. All scratch spaces are 0 at program start. - LogicSigVersion >= 5 ## stores @@ -710,7 +710,7 @@ See `bnz` for details on how branches work. `b` always jumps to the offset. - pop two byte-arrays A and B and join them, push the result - LogicSigVersion >= 2 -`concat` panics if the result would be greater than 4096 bytes. +`concat` fails if the result would be greater than 4096 bytes. ## substring s e @@ -1081,7 +1081,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Opcode: 0x94 - Pops: *... stack*, {uint64 A}, {uint64 B} - Pushes: uint64 -- A raised to the Bth power. Panic if A == B == 0 and on overflow +- A raised to the Bth power. Fail if A == B == 0 and on overflow - LogicSigVersion >= 4 ## expw @@ -1089,7 +1089,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Opcode: 0x95 - Pops: *... stack*, {uint64 A}, {uint64 B} - Pushes: *... stack*, uint64, uint64 -- A raised to the Bth power as a 128-bit long result as low (top) and high uint64 values on the stack. Panic if A == B == 0 or if the results exceeds 2^128-1 +- A raised to the Bth power as a 128-bit long result as low (top) and high uint64 values on the stack. Fail if A == B == 0 or if the results exceeds 2^128-1 - **Cost**: 10 - LogicSigVersion >= 4 @@ -1107,7 +1107,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Opcode: 0xa1 - Pops: *... stack*, {[]byte A}, {[]byte B} - Pushes: []byte -- A minus B, where A and B are byte-arrays interpreted as big-endian unsigned integers. Panic on underflow. +- A minus B, where A and B are byte-arrays interpreted as big-endian unsigned integers. Fail on underflow. - **Cost**: 10 - LogicSigVersion >= 4 @@ -1116,7 +1116,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Opcode: 0xa2 - Pops: *... stack*, {[]byte A}, {[]byte B} - Pushes: []byte -- A divided by B (truncated division), where A and B are byte-arrays interpreted as big-endian unsigned integers. Panic if B is zero. +- A divided by B (truncated division), where A and B are byte-arrays interpreted as big-endian unsigned integers. Fail if B is zero. - **Cost**: 20 - LogicSigVersion >= 4 @@ -1182,7 +1182,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Opcode: 0xaa - Pops: *... stack*, {[]byte A}, {[]byte B} - Pushes: []byte -- A modulo B, where A and B are byte-arrays interpreted as big-endian unsigned integers. Panic if B is zero. +- A modulo B, where A and B are byte-arrays interpreted as big-endian unsigned integers. Fail if B is zero. - **Cost**: 20 - LogicSigVersion >= 4 @@ -1239,7 +1239,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - LogicSigVersion >= 5 - Mode: Application -`log` can be called up to MaxLogCalls times in a program, and log up to a total of 1k bytes. +`log` fails if called more than MaxLogCalls times in a program, or if the sum of logged bytes exceeds 1024 bytes. ## tx_begin @@ -1255,7 +1255,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Opcode: 0xb2 {uint8 transaction field index} - Pops: *... stack*, any - Pushes: _None_ -- Set field F of the current inner transaction to X +- Set field F of the current inner transaction to X. Fail if X is the wrong type for F. - LogicSigVersion >= 5 - Mode: Application @@ -1264,7 +1264,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Opcode: 0xb3 - Pops: _None_ - Pushes: _None_ -- Execute the current inner transaction. Panic on any failure. +- Execute the current inner transaction. Fail if 16 inner transactions have already been executed, or if the transaction fails - LogicSigVersion >= 5 - Mode: Application diff --git a/dev/ledger.md b/dev/ledger.md index 1aab2c4..1450af7 100644 --- a/dev/ledger.md +++ b/dev/ledger.md @@ -782,7 +782,7 @@ and contains the following fields: invocations. The maximum total number of `log` calls is 32, and the total size of all logged bytes is limited to 1024. - Zero or more `InnerTxns`, encoded in an array `itx`. Each element of - `itx` records a succesful invocation of the `tx_submit` opcode. Each + `itx` records a successful invocation of the `tx_submit` opcode. Each element will contain the transaction fields, encoded under `txn`, in the same way that the top-level transaction is encoded, recursively, including `ApplyData` that applies to the inner transaction. Up to 16 From bcc7585b835f0658de89f475c2a0ef4ea69bb7d1 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Fri, 10 Sep 2021 12:57:05 -0400 Subject: [PATCH 07/23] tx_begin defaults --- dev/TEAL_opcodes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index bb61602..b8dbdd7 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -1250,6 +1250,8 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - LogicSigVersion >= 5 - Mode: Application +`tx_begin` sets Sender to the application address; Fee to the minimum allowable, taking into account MinTxnFee and credit from overpaying in earlier transactions; and FirstValid/LastValid to the values in the top-level transaction. + ## tx_field f - Opcode: 0xb2 {uint8 transaction field index} From 7979d54807c549f3c278ce1265223263c6dbbf3e Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Fri, 10 Sep 2021 12:59:53 -0400 Subject: [PATCH 08/23] tx_field available fields --- dev/TEAL_opcodes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index b8dbdd7..6dc9f9c 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -1261,6 +1261,8 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - LogicSigVersion >= 5 - Mode: Application +The following fields may be set by `tx_field` - Sender, Fee, Receiver, Amount, CloseRemainderTo, Type, TypeEnum, XferAsset, AssetAmount, AssetSender, AssetReceiver, AssetCloseTo + ## tx_submit - Opcode: 0xb3 From f9478816de4bc14b8cbf277486ed10940248ad6b Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Mon, 13 Sep 2021 09:39:44 -0400 Subject: [PATCH 09/23] ecdsa, and inner txn prose --- dev/TEAL.md | 52 +++++++++++++++++++++++++++++-------------- dev/TEAL_opcodes.md | 54 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 16 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index efce039..eb2e256 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -9,7 +9,7 @@ abstract: > # Transaction Execution Approval Language (TEAL) TEAL is a bytecode based stack language that executes inside Algorand transactions. TEAL programs can be used to check the parameters of the transaction and approve the transaction as if by a signature. This use of TEAL is called a _LogicSig_. Starting with v2, TEAL programs may -also execute as _Applications_ which are invoked with explicit application call transactions. Programs have read-only access to the transaction they are attached to, transactions in their atomic transaction group, and a few global values. In addition, _Application_ programs have access to limited state that is global to the application and per-account local state for each account that has opted-in to the application. Programs cannot modify or create transactions, only reject or approve them. For both types of program, approval is signaled by finishing with the stack containing a single non-zero uint64 value. +also execute as _Applications_ which are invoked with explicit application call transactions. Programs have read-only access to the transaction they are attached to, transactions in their atomic transaction group, and a few global values. In addition, _Application_ programs have access to limited state that is global to the application and per-account local state for each account that has opted-in to the application. For both types of program, approval is signaled by finishing with the stack containing a single non-zero uint64 value. ## The Stack @@ -19,7 +19,10 @@ The maximum stack depth is currently 1000. ## Scratch Space -In addition to the stack there are 256 positions of scratch space, also uint64-bytes union values, accessed by the `load` and `store` ops moving data from or to scratch space, respectively. +In addition to the stack there are 256 positions of scratch space, +also uint64-bytes union values, each initialized as uint64 +zero. Scratch space is acccesed by the `load(s)` and `store(s)` ops +moving data from or to scratch space, respectively. ## Execution Modes @@ -38,14 +41,14 @@ TEAL LogicSigs run in Algorand nodes as part of testing a proposed transaction t If an authorized program executes and finishes with a single non-zero uint64 value on the stack then that program has validated the transaction it is attached to. -The TEAL program has access to data from the transaction it is attached to (`txn` op), any transactions in a transaction group it is part of (`gtxn` op), and a few global values like consensus parameters (`global` op). Some "Args" may be attached to a transaction being validated by a TEAL program. Args are an array of byte strings. A common pattern would be to have the key to unlock some contract as an Arg. Args are recorded on the blockchain and publicly visible when the transaction is submitted to the network. +The TEAL program has access to data from the transaction it is attached to (`txn` op), any transactions in a transaction group it is part of (`gtxn` op), and a few global values like consensus parameters (`global` op). Some "Args" may be attached to a transaction being validated by a TEAL program. Args are an array of byte strings. A common pattern would be to have the key to unlock some contract as an Arg. Args are recorded on the blockchain and publicly visible when the transaction is submitted to the network. These LogicSig Args are _not_signed. A program can either authorize some delegated action on a normal private key signed or multisig account or be wholly in charge of a contract account. * If the account has signed the program (an ed25519 signature on "Program" concatenated with the program bytes) then if the program returns true the transaction is authorized as if the account had signed it. This allows an account to hand out a signed program so that other users can carry out delegated actions which are approved by the program. * If the SHA512_256 hash of the program (prefixed by "Program") is equal to the transaction Sender address then this is a contract account wholly controlled by the program. No other signature is necessary or possible. The only way to execute a transaction against the contract account is for the program to approve it. -The TEAL bytecode plus the length of any Args must add up to less than 1000 bytes (consensus parameter LogicSigMaxSize). Each TEAL op has an associated cost and the program cost must total less than 20000 (consensus parameter LogicSigMaxCost). Most ops have a cost of 1, but a few slow crypto ops are much higher. Prior to v4, the program's cost was estimated as the static sum of all the opcode costs in the program (whether they were actually executed or not). Beginning with v4, the program's cost is tracked dynamically, while being evaluated. If the program exceeds its budget, it fails. +The TEAL bytecode plus the length of all Args must add up to no more than 1000 bytes (consensus parameter LogicSigMaxSize). Each TEAL op has an associated cost and the program cost must total no more than 20000 (consensus parameter LogicSigMaxCost). Most ops have a cost of 1, but a few slow crypto ops are much higher. Prior to v4, the program's cost was estimated as the static sum of all the opcode costs in the program (whether they were actually executed or not). Beginning with v4, the program's cost is tracked dynamically, while being evaluated. If the program exceeds its budget, it fails. ## Constants @@ -94,7 +97,7 @@ Many programs need only a few dozen instructions. The instruction set has some o This summary is supplemented by more detail in the [opcodes document](TEAL_opcodes.md). -Some operations 'panic' and immediately end execution of the program. +Some operations 'panic' and immediately fail the program. A transaction checked by a program that panics is not valid. A contract account governed by a buggy program might not have a way to get assets back out of it. Code carefully. @@ -112,6 +115,9 @@ For three-argument ops, `A` is the element two below the top, `B` is the penulti | `keccak256` | Keccak256 hash of value X, yields [32]byte | | `sha512_256` | SHA512_256 hash of value X, yields [32]byte | | `ed25519verify` | for (data A, signature B, pubkey C) verify the signature of ("ProgData" \|\| program_hash \|\| data) against the pubkey => {0 or 1} | +| `ecdsa_verify v` | for (data A, signature B, C and pubkey D, E) verify the signature of the data against the pubkey => {0 or 1} | +| `ecdsa_pk_recover v` | for (data A, recovery id B, signature C, D) recover a public key => [*... stack*, X, Y] | +| `ecdsa_pk_decompress v` | decompress pubkey A into components X, Y => [*... stack*, X, Y] | | `+` | A plus B. Fail on overflow. | | `-` | A minus B. Fail if B > A. | | `/` | A divided by B (truncated division). Fail if B == 0. | @@ -151,6 +157,8 @@ For three-argument ops, `A` is the element two below the top, `B` is the penulti These opcodes return portions of byte arrays, accessed by position, in various sizes. +### Byte Array Manipulation + | Op | Description | | --- | --- | | `substring s e` | pop a byte-array A. For immediate values in 0..255 S and E: extract a range of bytes from A starting at S up to but not including E, push the substring result. If E < S, or either is larger than the array length, the program fails | @@ -200,16 +208,6 @@ these results may contain leading zero bytes. | `b^` | A bitwise-xor B, where A and B are byte-arrays, zero-left extended to the greater of their lengths | | `b~` | X with all bits inverted | -The following opcodes allow for the construction and submission of -"inner transaction" - -| Op | Description | -| --- | --- | -| `tx_begin` | Begin preparation of a new inner transaction | -| `tx_field f` | Set field F of the current inner transaction to X. Fail if X is the wrong type for F. | -| `tx_submit` | Execute the current inner transaction. Fail if 16 inner transactions have already been executed, or if the transaction fails | - - ### Loading Values Opcodes for getting data onto the stack. @@ -428,6 +426,29 @@ App fields used in the `app_params_get` opcode. | `app_params_get i` | read from app A params field X (imm arg) => {0 or 1 (top), value} | | `log` | write bytes to log state of the current application | +### Inner Transactions + +The following opcodes allow for "inner transactions". Inner +transactions allow stateful applications to have many of the effects +of a true top-level transaction, programatically. However, they are +different in significant ways. The most important differences are +that they are not signed, and do not appear in the block in the usual +away. Instead, their effects are noted in metadata associated with the +associated top-level application call transaction. An inner +transaction's `Sender` must be the SHA512_256 hash of the application +ID (prefixed by "appID"), or an account that has been rekeyed to that +hash. + +Currently, inner transactions may perform `pay`, `axfer`, `acfg`, and +`afrz` effects. + +| Op | Description | +| --- | --- | +| `tx_begin` | Begin preparation of a new inner transaction | +| `tx_field f` | Set field F of the current inner transaction to X. Fail if X is the wrong type for F. | +| `tx_submit` | Execute the current inner transaction. Fail if 16 inner transactions have already been executed, or if the transaction fails | + + # Assembler Syntax The assembler parses line by line. Ops that just use the stack appear on a line by themselves. Ops that take arguments are the op and then whitespace and then any argument or arguments. @@ -498,7 +519,6 @@ A '[proto-buf style variable length unsigned int](https://developers.google.com/ Design and implementation limitations to be aware of with various versions of TEAL. -* TEAL cannot create or change a transaction, only approve or reject. * Stateless TEAL cannot lookup balances of Algos or other assets. (Standard transaction accounting will apply after TEAL has run and authorized a transaction. A TEAL-approved transaction could still be invalid by other accounting rules just as a standard signed transaction could be invalid. e.g. I can't give away money I don't have.) * TEAL cannot access information in previous blocks. TEAL cannot access most information in other transactions in the current block. (TEAL can access fields of the transaction it is attached to and the transactions in an atomic transaction group.) * TEAL cannot know exactly what round the current transaction will commit in (but it is somewhere in FirstValid through LastValid). diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index 6dc9f9c..df9416f 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -58,6 +58,60 @@ Ops have a 'cost' of 1 unless otherwise specified. The 32 byte public key is the last element on the stack, preceded by the 64 byte signature at the second-to-last element on the stack, preceded by the data which was signed at the third-to-last element on the stack. +## ecdsa_verify v + +- Opcode: 0x05 {uint8 curve index} +- Pops: *... stack*, {[]byte A}, {[]byte B}, {[]byte C}, {[]byte D}, {[]byte E} +- Pushes: uint64 +- for (data A, signature B, C and pubkey D, E) verify the signature of the data against the pubkey => {0 or 1} +- **Cost**: 1700 +- LogicSigVersion >= 5 + +`ECDSA` Curves: + +| Index | Name | Notes | +| --- | --- | --- | +| 0 | Secp256k1 | secp256k1 curve | + + +The 32 byte Y-component of a public key is the last element on the stack, preceded by X-component of a pubkey, preceded by S and R components of a signature, preceded by the data that is fifth element on the stack. All values are big-endian encoded. The signed data must be 32 bytes long, and signatures in lower-S form are only accepted. + +## ecdsa_pk_decompress v + +- Opcode: 0x06 {uint8 curve index} +- Pops: *... stack*, []byte +- Pushes: *... stack*, []byte, []byte +- decompress pubkey A into components X, Y => [*... stack*, X, Y] +- **Cost**: 650 +- LogicSigVersion >= 5 + +`ECDSA` Curves: + +| Index | Name | Notes | +| --- | --- | --- | +| 0 | Secp256k1 | secp256k1 curve | + + +The 33 byte public key in a compressed form to be decompressed into X and Y (top) components. All values are big-endian encoded. + +## ecdsa_pk_recover v + +- Opcode: 0x07 {uint8 curve index} +- Pops: *... stack*, {[]byte A}, {uint64 B}, {[]byte C}, {[]byte D} +- Pushes: *... stack*, []byte, []byte +- for (data A, recovery id B, signature C, D) recover a public key => [*... stack*, X, Y] +- **Cost**: 2000 +- LogicSigVersion >= 5 + +`ECDSA` Curves: + +| Index | Name | Notes | +| --- | --- | --- | +| 0 | Secp256k1 | secp256k1 curve | + + +S (top) and R elements of a signature, recovery id and data (bottom) are expected on the stack and used to deriver a public key. All values are big-endian encoded. The signed data must be 32 bytes long. + ## + - Opcode: 0x08 From 5bdb8ebfaab0388e1d2fe2c77557bef805ebd8f8 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Mon, 13 Sep 2021 09:45:10 -0400 Subject: [PATCH 10/23] cleanup --- dev/TEAL_opcodes.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index df9416f..419b665 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -1304,7 +1304,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - LogicSigVersion >= 5 - Mode: Application -`tx_begin` sets Sender to the application address; Fee to the minimum allowable, taking into account MinTxnFee and credit from overpaying in earlier transactions; and FirstValid/LastValid to the values in the top-level transaction. +`tx_begin` initializes Sender to the application address; Fee to the minimum allowable, taking into account MinTxnFee and credit from overpaying in earlier transactions; FirstValid/LastValid to the values in the top-level transaction, and all other fields to zero values. ## tx_field f @@ -1315,8 +1315,6 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - LogicSigVersion >= 5 - Mode: Application -The following fields may be set by `tx_field` - Sender, Fee, Receiver, Amount, CloseRemainderTo, Type, TypeEnum, XferAsset, AssetAmount, AssetSender, AssetReceiver, AssetCloseTo - ## tx_submit - Opcode: 0xb3 From 996de5d22e5b48f364f2ef2560c2db1fd3ce7286 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Mon, 13 Sep 2021 09:50:36 -0400 Subject: [PATCH 11/23] typo --- dev/TEAL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index eb2e256..c3b64ca 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -41,7 +41,7 @@ TEAL LogicSigs run in Algorand nodes as part of testing a proposed transaction t If an authorized program executes and finishes with a single non-zero uint64 value on the stack then that program has validated the transaction it is attached to. -The TEAL program has access to data from the transaction it is attached to (`txn` op), any transactions in a transaction group it is part of (`gtxn` op), and a few global values like consensus parameters (`global` op). Some "Args" may be attached to a transaction being validated by a TEAL program. Args are an array of byte strings. A common pattern would be to have the key to unlock some contract as an Arg. Args are recorded on the blockchain and publicly visible when the transaction is submitted to the network. These LogicSig Args are _not_signed. +The TEAL program has access to data from the transaction it is attached to (`txn` op), any transactions in a transaction group it is part of (`gtxn` op), and a few global values like consensus parameters (`global` op). Some "Args" may be attached to a transaction being validated by a TEAL program. Args are an array of byte strings. A common pattern would be to have the key to unlock some contract as an Arg. Args are recorded on the blockchain and publicly visible when the transaction is submitted to the network. These LogicSig Args are _not_ signed. A program can either authorize some delegated action on a normal private key signed or multisig account or be wholly in charge of a contract account. From 76a832135e8fd46a5691d508d6c7fdc5bd274f41 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Mon, 13 Sep 2021 10:14:43 -0400 Subject: [PATCH 12/23] note versioning on fields --- dev/TEAL.md | 6 +++--- dev/TEAL_opcodes.md | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index c3b64ca..782e639 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -365,7 +365,7 @@ Asset fields include `AssetHolding` and `AssetParam` fields that are used in the | 8 | AssetReserve | []byte | Reserve address | | 9 | AssetFreeze | []byte | Freeze address | | 10 | AssetClawback | []byte | Clawback address | -| 11 | AssetCreator | []byte | Creator address | +| 11 | AssetCreator | []byte | Creator address. LogicSigVersion >= 5. | **App Fields** @@ -381,8 +381,8 @@ App fields used in the `app_params_get` opcode. | 4 | AppLocalNumUint | uint64 | Number of uint64 values allowed in Local State | | 5 | AppLocalNumByteSlice | uint64 | Number of byte array values allowed in Local State | | 6 | AppExtraProgramPages | uint64 | Number of Extra Program Pages of code space | -| 7 | AppCreator | []byte | Creator address | -| 8 | AppAddress | []byte | Address for which this application has authority | +| 7 | AppCreator | []byte | Creator address. LogicSigVersion >= 5. | +| 8 | AppAddress | []byte | Address for which this application has authority. LogicSigVersion >= 5. | ### Flow Control diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index 419b665..d9ca69b 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -1013,7 +1013,7 @@ params: Txn.Accounts offset (or, since v4, an account address that appears in Tx | 8 | AssetReserve | []byte | Reserve address | | 9 | AssetFreeze | []byte | Freeze address | | 10 | AssetClawback | []byte | Clawback address | -| 11 | AssetCreator | []byte | Creator address | +| 11 | AssetCreator | []byte | Creator address. LogicSigVersion >= 5. | params: Before v4, Txn.ForeignAssets offset. Since v4, Txn.ForeignAssets offset or an asset id that appears in Txn.ForeignAssets. Return: did_exist flag (1 if exist and 0 otherwise), value. @@ -1038,8 +1038,8 @@ params: Before v4, Txn.ForeignAssets offset. Since v4, Txn.ForeignAssets offset | 4 | AppLocalNumUint | uint64 | Number of uint64 values allowed in Local State | | 5 | AppLocalNumByteSlice | uint64 | Number of byte array values allowed in Local State | | 6 | AppExtraProgramPages | uint64 | Number of Extra Program Pages of code space | -| 7 | AppCreator | []byte | Creator address | -| 8 | AppAddress | []byte | Address for which this application has authority | +| 7 | AppCreator | []byte | Creator address. LogicSigVersion >= 5. | +| 8 | AppAddress | []byte | Address for which this application has authority. LogicSigVersion >= 5. | params: Txn.ForeignApps offset or an app id that appears in Txn.ForeignApps. Return: did_exist flag (1 if exist and 0 otherwise), value. From db23d01a99cf63c3b4c4a62efdb3eb703efea385 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Mon, 13 Sep 2021 10:27:47 -0400 Subject: [PATCH 13/23] corrected versioning on fields --- dev/TEAL.md | 4 ++-- dev/TEAL_opcodes.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index 782e639..6826aba 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -381,8 +381,8 @@ App fields used in the `app_params_get` opcode. | 4 | AppLocalNumUint | uint64 | Number of uint64 values allowed in Local State | | 5 | AppLocalNumByteSlice | uint64 | Number of byte array values allowed in Local State | | 6 | AppExtraProgramPages | uint64 | Number of Extra Program Pages of code space | -| 7 | AppCreator | []byte | Creator address. LogicSigVersion >= 5. | -| 8 | AppAddress | []byte | Address for which this application has authority. LogicSigVersion >= 5. | +| 7 | AppCreator | []byte | Creator address | +| 8 | AppAddress | []byte | Address for which this application has authority | ### Flow Control diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index d9ca69b..d7ee2af 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -1038,8 +1038,8 @@ params: Before v4, Txn.ForeignAssets offset. Since v4, Txn.ForeignAssets offset | 4 | AppLocalNumUint | uint64 | Number of uint64 values allowed in Local State | | 5 | AppLocalNumByteSlice | uint64 | Number of byte array values allowed in Local State | | 6 | AppExtraProgramPages | uint64 | Number of Extra Program Pages of code space | -| 7 | AppCreator | []byte | Creator address. LogicSigVersion >= 5. | -| 8 | AppAddress | []byte | Address for which this application has authority. LogicSigVersion >= 5. | +| 7 | AppCreator | []byte | Creator address | +| 8 | AppAddress | []byte | Address for which this application has authority | params: Txn.ForeignApps offset or an app id that appears in Txn.ForeignApps. Return: did_exist flag (1 if exist and 0 otherwise), value. From 0a9b26db4e609146f2540cd5efec34bc202001b7 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Mon, 13 Sep 2021 10:32:52 -0400 Subject: [PATCH 14/23] un/cover failure detail --- dev/TEAL.md | 4 ++-- dev/TEAL_opcodes.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index 6826aba..6c4239f 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -398,8 +398,8 @@ App fields used in the `app_params_get` opcode. | `dup` | duplicate last value on stack | | `dup2` | duplicate two last values on stack: A, B -> A, B, A, B | | `dig n` | push the Nth value from the top of the stack. dig 0 is equivalent to dup | -| `cover n` | remove top of stack, and place it deeper in the stack such that N elements are above it | -| `uncover n` | remove the value at depth N in the stack and shift above items down so the Nth deep value is on top of the stack | +| `cover n` | remove top of stack, and place it deeper in the stack such that N elements are above it. Fails if stack depth <= N. | +| `uncover n` | remove the value at depth N in the stack and shift above items down so the Nth deep value is on top of the stack. Fails if stack depth <= N. | | `swap` | swaps two last values on stack: A, B -> B, A | | `select` | selects one of two values based on top-of-stack: A, B, C -> (if C != 0 then B else A) | | `assert` | immediately fail unless value X is a non-zero number | diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index d7ee2af..bc7cb4e 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -745,7 +745,7 @@ See `bnz` for details on how branches work. `b` always jumps to the offset. - Opcode: 0x4e {uint8 depth} - Pops: *... stack*, any - Pushes: any -- remove top of stack, and place it deeper in the stack such that N elements are above it +- remove top of stack, and place it deeper in the stack such that N elements are above it. Fails if stack depth <= N. - LogicSigVersion >= 5 ## uncover n @@ -753,7 +753,7 @@ See `bnz` for details on how branches work. `b` always jumps to the offset. - Opcode: 0x4f {uint8 depth} - Pops: *... stack*, any - Pushes: any -- remove the value at depth N in the stack and shift above items down so the Nth deep value is on top of the stack +- remove the value at depth N in the stack and shift above items down so the Nth deep value is on top of the stack. Fails if stack depth <= N. - LogicSigVersion >= 5 ## concat From 6bf13388e1c09640eec5c26bbe0f60a0f477a793 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Mon, 13 Sep 2021 10:59:22 -0400 Subject: [PATCH 15/23] tx_field failure detail --- dev/TEAL_opcodes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index bc7cb4e..9c19198 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -1315,6 +1315,8 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - LogicSigVersion >= 5 - Mode: Application +`tx_field` fails if X is of the wrong type for F, including a byte array of the wrong size for use as an address when F is an address field. `tx_field` also fails if X is an account or asset that does not appear in `txn.Accounts` or `txn.ForeignAssets` of the top-level transaction. (Setting addresses in asset creation are exempted from this requirement.) + ## tx_submit - Opcode: 0xb3 From db11f83705aaf663da88a0368d54d6159bf420c1 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Mon, 13 Sep 2021 21:24:06 -0400 Subject: [PATCH 16/23] more details. tx -> itxn --- dev/TEAL.md | 30 ++++++++++++++++++++++++----- dev/TEAL_opcodes.md | 46 +++++++++++++++++++++++++++++++++------------ dev/ledger.md | 2 +- 3 files changed, 60 insertions(+), 18 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index 6c4239f..82ca4e0 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -13,7 +13,10 @@ also execute as _Applications_ which are invoked with explicit application call ## The Stack -The stack starts empty and contains values of either uint64 or bytes (`bytes` are implemented in Go as a []byte slice). Most operations act on the stack, popping arguments from it and pushing results to it. +The stack starts empty and contains values of either uint64 or bytes +(`bytes` are implemented in Go as a []byte slice and may not exceed +4096 bytes in length). Most operations act on the stack, popping +arguments from it and pushing results to it. The maximum stack depth is currently 1000. @@ -318,6 +321,10 @@ Some of these have immediate data in the byte or bytes after the opcode. | 55 | LocalNumByteSlice | uint64 | Number of local state byteslices in ApplicationCall. LogicSigVersion >= 3. | | 56 | ExtraProgramPages | uint64 | Number of additional pages for each of the application's approval and clear state programs. An ExtraProgramPages of 1 means 2048 more total bytes, or 1024 for each program. LogicSigVersion >= 4. | | 57 | Nonparticipation | uint64 | Marks an account nonparticipating for rewards. LogicSigVersion >= 5. | +| 58 | Logs | []byte | Log messages emitted by an application call. LogicSigVersion >= 5. | +| 59 | NumLogs | uint64 | Number of Logs. LogicSigVersion >= 5. | +| 60 | EvalConfigAsset | uint64 | Asset ID allocated by the creation of an ASA. LogicSigVersion >= 5. | +| 61 | EvalApplicationID | uint64 | ApplicationID allocated by the creation of an application. LogicSigVersion >= 5. | Additional details in the [opcodes document](TEAL_opcodes.md#txn) on the `txn` op. @@ -440,13 +447,26 @@ ID (prefixed by "appID"), or an account that has been rekeyed to that hash. Currently, inner transactions may perform `pay`, `axfer`, `acfg`, and -`afrz` effects. +`afrz` effects. After executing an inner transaction with +`itxn_submit`, the effects of the transaction are visible begining +with the next instruction with, for example, `balance` and +`min_balance` checks. + +Of the transaction Header fields, only a few fields may be set: +`Type`/`TypeEnum`, `Sender`, and `Fee`. For the specific fields of +each transaction types, any field, except `RekeyTo` may be set. This +allows, for example, clawback transactions, asset opt-ins, and asset +creates in addtion to the more common uses of `axfer` and `acfg`. All +fields default to the zero value, except those described under +`itxn_begin`. | Op | Description | | --- | --- | -| `tx_begin` | Begin preparation of a new inner transaction | -| `tx_field f` | Set field F of the current inner transaction to X. Fail if X is the wrong type for F. | -| `tx_submit` | Execute the current inner transaction. Fail if 16 inner transactions have already been executed, or if the transaction fails | +| `itxn_begin` | Begin preparation of a new inner transaction | +| `itxn_field f` | Set field F of the current inner transaction to X | +| `itxn_submit` | Execute the current inner transaction. Fail if 16 inner transactions have already been executed, or if the transaction itself fails. | +| `itxn f` | push field F of the last inner transaction to stack | +| `itxna f i` | push Ith valoue of the array field F of the last inner transaction to stack | # Assembler Syntax diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index 9c19198..094f7c0 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -488,6 +488,10 @@ Overflow is an error condition which halts execution and fails the transaction. | 55 | LocalNumByteSlice | uint64 | Number of local state byteslices in ApplicationCall. LogicSigVersion >= 3. | | 56 | ExtraProgramPages | uint64 | Number of additional pages for each of the application's approval and clear state programs. An ExtraProgramPages of 1 means 2048 more total bytes, or 1024 for each program. LogicSigVersion >= 4. | | 57 | Nonparticipation | uint64 | Marks an account nonparticipating for rewards. LogicSigVersion >= 5. | +| 58 | Logs | []byte | Log messages emitted by an application call. LogicSigVersion >= 5. | +| 59 | NumLogs | uint64 | Number of Logs. LogicSigVersion >= 5. | +| 60 | EvalConfigAsset | uint64 | Asset ID allocated by the creation of an ASA. LogicSigVersion >= 5. | +| 61 | EvalApplicationID | uint64 | ApplicationID allocated by the creation of an application. LogicSigVersion >= 5. | TypeEnum mapping: @@ -900,7 +904,7 @@ params: Txn.Accounts offset (or, since v4, an account address that appears in Tx - LogicSigVersion >= 2 - Mode: Application -params: Txn.Accounts offset (or, since v4, an account address that appears in Txn.Accounts or is Txn.Sender), application id (or, since v4, a Txn.ForeignApps offset), state key. Return: did_exist flag (top of the stack, 1 if exist and 0 otherwise), value. The value is zero (of type uint64) if the key does not exist. +params: Txn.Accounts offset (or, since v4, an account address that appears in Txn.Accounts or is Txn.Sender), application id (or, since v4, a Txn.ForeignApps offset), state key. Return: did_exist flag (top of the stack, 1 if the application existed and 0 otherwise), value. The value is zero (of type uint64) if the key does not exist. ## app_global_get @@ -922,7 +926,7 @@ params: state key. Return: value. The value is zero (of type uint64) if the key - LogicSigVersion >= 2 - Mode: Application -params: Txn.ForeignApps offset (or, since v4, an application id that appears in Txn.ForeignApps or is the CurrentApplicationID), state key. Return: did_exist flag (top of the stack, 1 if exist and 0 otherwise), value. The value is zero (of type uint64) if the key does not exist. +params: Txn.ForeignApps offset (or, since v4, an application id that appears in Txn.ForeignApps or is the CurrentApplicationID), state key. Return: did_exist flag (top of the stack, 1 if the application existed and 0 otherwise), value. The value is zero (of type uint64) if the key does not exist. ## app_local_put @@ -987,7 +991,7 @@ Deleting a key which is already absent has no effect on the application global s | 1 | AssetFrozen | uint64 | Is the asset frozen or not | -params: Txn.Accounts offset (or, since v4, an account address that appears in Txn.Accounts or is Txn.Sender), asset id (or, since v4, a Txn.ForeignAssets offset). Return: did_exist flag (1 if exist and 0 otherwise), value. +params: Txn.Accounts offset (or, since v4, an account address that appears in Txn.Accounts or is Txn.Sender), asset id (or, since v4, a Txn.ForeignAssets offset). Return: did_exist flag (1 if the asset existed and 0 otherwise), value. ## asset_params_get i @@ -1016,7 +1020,7 @@ params: Txn.Accounts offset (or, since v4, an account address that appears in Tx | 11 | AssetCreator | []byte | Creator address. LogicSigVersion >= 5. | -params: Before v4, Txn.ForeignAssets offset. Since v4, Txn.ForeignAssets offset or an asset id that appears in Txn.ForeignAssets. Return: did_exist flag (1 if exist and 0 otherwise), value. +params: Before v4, Txn.ForeignAssets offset. Since v4, Txn.ForeignAssets offset or an asset id that appears in Txn.ForeignAssets. Return: did_exist flag (1 if the asset existed and 0 otherwise), value. ## app_params_get i @@ -1042,7 +1046,7 @@ params: Before v4, Txn.ForeignAssets offset. Since v4, Txn.ForeignAssets offset | 8 | AppAddress | []byte | Address for which this application has authority | -params: Txn.ForeignApps offset or an app id that appears in Txn.ForeignApps. Return: did_exist flag (1 if exist and 0 otherwise), value. +params: Txn.ForeignApps offset or an app id that appears in Txn.ForeignApps. Return: did_exist flag (1 if the application existed and 0 otherwise), value. ## min_balance @@ -1295,7 +1299,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit `log` fails if called more than MaxLogCalls times in a program, or if the sum of logged bytes exceeds 1024 bytes. -## tx_begin +## itxn_begin - Opcode: 0xb1 - Pops: _None_ @@ -1304,25 +1308,43 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - LogicSigVersion >= 5 - Mode: Application -`tx_begin` initializes Sender to the application address; Fee to the minimum allowable, taking into account MinTxnFee and credit from overpaying in earlier transactions; FirstValid/LastValid to the values in the top-level transaction, and all other fields to zero values. +`itxn_begin` initializes Sender to the application address; Fee to the minimum allowable, taking into account MinTxnFee and credit from overpaying in earlier transactions; FirstValid/LastValid to the values in the top-level transaction, and all other fields to zero values. -## tx_field f +## itxn_field f - Opcode: 0xb2 {uint8 transaction field index} - Pops: *... stack*, any - Pushes: _None_ -- Set field F of the current inner transaction to X. Fail if X is the wrong type for F. +- Set field F of the current inner transaction to X - LogicSigVersion >= 5 - Mode: Application -`tx_field` fails if X is of the wrong type for F, including a byte array of the wrong size for use as an address when F is an address field. `tx_field` also fails if X is an account or asset that does not appear in `txn.Accounts` or `txn.ForeignAssets` of the top-level transaction. (Setting addresses in asset creation are exempted from this requirement.) +`itxn_field` fails if X is of the wrong type for F, including a byte array of the wrong size for use as an address when F is an address field. `itxn_field` also fails if X is an account or asset that does not appear in `txn.Accounts` or `txn.ForeignAssets` of the top-level transaction. (Setting addresses in asset creation are exempted from this requirement.) -## tx_submit +## itxn_submit - Opcode: 0xb3 - Pops: _None_ - Pushes: _None_ -- Execute the current inner transaction. Fail if 16 inner transactions have already been executed, or if the transaction fails +- Execute the current inner transaction. Fail if 16 inner transactions have already been executed, or if the transaction itself fails. +- LogicSigVersion >= 5 +- Mode: Application + +## itxn f + +- Opcode: 0xb4 {uint8 transaction field index} +- Pops: _None_ +- Pushes: any +- push field F of the last inner transaction to stack +- LogicSigVersion >= 5 +- Mode: Application + +## itxna f i + +- Opcode: 0xb5 {uint8 transaction field index} {uint8 transaction field array index} +- Pops: _None_ +- Pushes: any +- push Ith valoue of the array field F of the last inner transaction to stack - LogicSigVersion >= 5 - Mode: Application diff --git a/dev/ledger.md b/dev/ledger.md index 1450af7..f033b86 100644 --- a/dev/ledger.md +++ b/dev/ledger.md @@ -787,7 +787,7 @@ and contains the following fields: the same way that the top-level transaction is encoded, recursively, including `ApplyData` that applies to the inner transaction. Up to 16 `InnerTxns` may be present. - - InnerTxns are limited to `pay` and `axfer` transactions. + - InnerTxns are limited to `pay`, `axfer`, `acfg`, and `afrz` transactions. ### State Deltas From 7b63d41685bad1e1d3c0fd4b87685a1594553f1f Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Mon, 13 Sep 2021 22:38:34 -0400 Subject: [PATCH 17/23] spelling --- dev/TEAL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index 82ca4e0..e6596f8 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -199,7 +199,7 @@ bytes on outputs. | `b%` | A modulo B, where A and B are byte-arrays interpreted as big-endian unsigned integers. Fail if B is zero. | These opcodes operate on the bits of byte-array values. The shorter -array is interpeted as though left padded with zeros until it is the +array is interpreted as though left padded with zeros until it is the same length as the other input. The returned values are the same length as the longest input. Therefore, unlike array arithmetic, these results may contain leading zero bytes. From e1a542f86332fc30298f9af3d43d11c9d51bb731 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Tue, 14 Sep 2021 11:33:45 -0400 Subject: [PATCH 18/23] Rename extractXXbits, add tx_field details. --- dev/TEAL.md | 28 +++++++++++++++++++--------- dev/TEAL_opcodes.md | 6 +++--- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index e6596f8..917127c 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -168,9 +168,9 @@ various sizes. | `substring3` | pop a byte-array A and two integers B and C. Extract a range of bytes from A starting at B up to but not including C, push the substring result. If C < B, or either is larger than the array length, the program fails | | `extract s l` | pop a byte-array A. For immediate values in 0..255 S and L: extract a range of bytes from A starting at S up to but not including S+L, push the substring result. If L is 0, then extract to the end of the string. If S or S+L is larger than the array length, the program fails | | `extract3` | pop a byte-array A and two integers B and C. Extract a range of bytes from A starting at B up to but not including B+C, push the substring result. If B+C is larger than the array length, the program fails | -| `extract16bits` | pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+2, convert bytes as big endian and push the uint64 result. If B+2 is larger than the array length, the program fails | -| `extract32bits` | pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+4, convert bytes as big endian and push the uint64 result. If B+4 is larger than the array length, the program fails | -| `extract64bits` | pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+8, convert bytes as big endian and push the uint64 result. If B+8 is larger than the array length, the program fails | +| `extract_uint16` | pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+2, convert bytes as big endian and push the uint64 result. If B+2 is larger than the array length, the program fails | +| `extract_uint32` | pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+4, convert bytes as big endian and push the uint64 result. If B+4 is larger than the array length, the program fails | +| `extract_uint64` | pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+8, convert bytes as big endian and push the uint64 result. If B+8 is larger than the array length, the program fails | These opcodes take byte-array values that are interpreted as big-endian unsigned integers. For mathematical operators, the @@ -439,12 +439,12 @@ The following opcodes allow for "inner transactions". Inner transactions allow stateful applications to have many of the effects of a true top-level transaction, programatically. However, they are different in significant ways. The most important differences are -that they are not signed, and do not appear in the block in the usual -away. Instead, their effects are noted in metadata associated with the -associated top-level application call transaction. An inner -transaction's `Sender` must be the SHA512_256 hash of the application -ID (prefixed by "appID"), or an account that has been rekeyed to that -hash. +that they are not signed, duplicates are not rejected, and they do not +appear in the block in the usual away. Instead, their effects are +noted in metadata associated with the associated top-level application +call transaction. An inner transaction's `Sender` must be the +SHA512_256 hash of the application ID (prefixed by "appID"), or an +account that has been rekeyed to that hash. Currently, inner transactions may perform `pay`, `axfer`, `acfg`, and `afrz` effects. After executing an inner transaction with @@ -460,6 +460,16 @@ creates in addtion to the more common uses of `axfer` and `acfg`. All fields default to the zero value, except those described under `itxn_begin`. +Fields may be set multiple times, but may not be read. The most recent +setting is used when `itxn_submit` executes. (For this purpose `Type` +and `TypeEnum` are considered to be the same field.) `itxn_field` +fails immediately for unsupported fields, unsupported transaction +types, or improperly typed values for a particular field. `itxn_field` +makes aceptance decisions entirely from the field and value provided, +never considering previously set fields. Illegal interactions between +fields, such as setting fields that belong to two different +transaction types, are rejected by `itxn_submit`. + | Op | Description | | --- | --- | | `itxn_begin` | Begin preparation of a new inner transaction | diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index 094f7c0..04637ab 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -838,7 +838,7 @@ When A is a uint64, index 0 is the least significant bit. Setting bit 3 to 1 on - pop a byte-array A and two integers B and C. Extract a range of bytes from A starting at B up to but not including B+C, push the substring result. If B+C is larger than the array length, the program fails - LogicSigVersion >= 5 -## extract16bits +## extract_uint16 - Opcode: 0x59 - Pops: *... stack*, {[]byte A}, {uint64 B} @@ -846,7 +846,7 @@ When A is a uint64, index 0 is the least significant bit. Setting bit 3 to 1 on - pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+2, convert bytes as big endian and push the uint64 result. If B+2 is larger than the array length, the program fails - LogicSigVersion >= 5 -## extract32bits +## extract_uint32 - Opcode: 0x5a - Pops: *... stack*, {[]byte A}, {uint64 B} @@ -854,7 +854,7 @@ When A is a uint64, index 0 is the least significant bit. Setting bit 3 to 1 on - pop a byte-array A and integer B. Extract a range of bytes from A starting at B up to but not including B+4, convert bytes as big endian and push the uint64 result. If B+4 is larger than the array length, the program fails - LogicSigVersion >= 5 -## extract64bits +## extract_uint64 - Opcode: 0x5b - Pops: *... stack*, {[]byte A}, {uint64 B} From 2d3314ff749cc55fd9e1010d9436929bbd97b814 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Tue, 14 Sep 2021 12:24:28 -0400 Subject: [PATCH 19/23] spelling, itxn field detail --- dev/TEAL.md | 10 +++++----- dev/TEAL_opcodes.md | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index 917127c..c17a546 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -321,10 +321,10 @@ Some of these have immediate data in the byte or bytes after the opcode. | 55 | LocalNumByteSlice | uint64 | Number of local state byteslices in ApplicationCall. LogicSigVersion >= 3. | | 56 | ExtraProgramPages | uint64 | Number of additional pages for each of the application's approval and clear state programs. An ExtraProgramPages of 1 means 2048 more total bytes, or 1024 for each program. LogicSigVersion >= 4. | | 57 | Nonparticipation | uint64 | Marks an account nonparticipating for rewards. LogicSigVersion >= 5. | -| 58 | Logs | []byte | Log messages emitted by an application call. LogicSigVersion >= 5. | -| 59 | NumLogs | uint64 | Number of Logs. LogicSigVersion >= 5. | -| 60 | EvalConfigAsset | uint64 | Asset ID allocated by the creation of an ASA. LogicSigVersion >= 5. | -| 61 | EvalApplicationID | uint64 | ApplicationID allocated by the creation of an application. LogicSigVersion >= 5. | +| 58 | Logs | []byte | Log messages emitted by an application call (itxn only). LogicSigVersion >= 5. | +| 59 | NumLogs | uint64 | Number of Logs (itxn only). LogicSigVersion >= 5. | +| 60 | EvalConfigAsset | uint64 | Asset ID allocated by the creation of an ASA (itxn only). LogicSigVersion >= 5. | +| 61 | EvalApplicationID | uint64 | ApplicationID allocated by the creation of an application (itxn only). LogicSigVersion >= 5. | Additional details in the [opcodes document](TEAL_opcodes.md#txn) on the `txn` op. @@ -476,7 +476,7 @@ transaction types, are rejected by `itxn_submit`. | `itxn_field f` | Set field F of the current inner transaction to X | | `itxn_submit` | Execute the current inner transaction. Fail if 16 inner transactions have already been executed, or if the transaction itself fails. | | `itxn f` | push field F of the last inner transaction to stack | -| `itxna f i` | push Ith valoue of the array field F of the last inner transaction to stack | +| `itxna f i` | push Ith value of the array field F of the last inner transaction to stack | # Assembler Syntax diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index 04637ab..ea77daf 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -488,10 +488,10 @@ Overflow is an error condition which halts execution and fails the transaction. | 55 | LocalNumByteSlice | uint64 | Number of local state byteslices in ApplicationCall. LogicSigVersion >= 3. | | 56 | ExtraProgramPages | uint64 | Number of additional pages for each of the application's approval and clear state programs. An ExtraProgramPages of 1 means 2048 more total bytes, or 1024 for each program. LogicSigVersion >= 4. | | 57 | Nonparticipation | uint64 | Marks an account nonparticipating for rewards. LogicSigVersion >= 5. | -| 58 | Logs | []byte | Log messages emitted by an application call. LogicSigVersion >= 5. | -| 59 | NumLogs | uint64 | Number of Logs. LogicSigVersion >= 5. | -| 60 | EvalConfigAsset | uint64 | Asset ID allocated by the creation of an ASA. LogicSigVersion >= 5. | -| 61 | EvalApplicationID | uint64 | ApplicationID allocated by the creation of an application. LogicSigVersion >= 5. | +| 58 | Logs | []byte | Log messages emitted by an application call (itxn only). LogicSigVersion >= 5. | +| 59 | NumLogs | uint64 | Number of Logs (itxn only). LogicSigVersion >= 5. | +| 60 | EvalConfigAsset | uint64 | Asset ID allocated by the creation of an ASA (itxn only). LogicSigVersion >= 5. | +| 61 | EvalApplicationID | uint64 | ApplicationID allocated by the creation of an application (itxn only). LogicSigVersion >= 5. | TypeEnum mapping: @@ -1344,7 +1344,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Opcode: 0xb5 {uint8 transaction field index} {uint8 transaction field array index} - Pops: _None_ - Pushes: any -- push Ith valoue of the array field F of the last inner transaction to stack +- push Ith value of the array field F of the last inner transaction to stack - LogicSigVersion >= 5 - Mode: Application From d6b377e2e3f6ccbb30a017bab920997e2aaa0469 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Tue, 14 Sep 2021 12:51:17 -0400 Subject: [PATCH 20/23] Field rename --- dev/TEAL.md | 4 ++-- dev/TEAL_opcodes.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index c17a546..7490a52 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -323,8 +323,8 @@ Some of these have immediate data in the byte or bytes after the opcode. | 57 | Nonparticipation | uint64 | Marks an account nonparticipating for rewards. LogicSigVersion >= 5. | | 58 | Logs | []byte | Log messages emitted by an application call (itxn only). LogicSigVersion >= 5. | | 59 | NumLogs | uint64 | Number of Logs (itxn only). LogicSigVersion >= 5. | -| 60 | EvalConfigAsset | uint64 | Asset ID allocated by the creation of an ASA (itxn only). LogicSigVersion >= 5. | -| 61 | EvalApplicationID | uint64 | ApplicationID allocated by the creation of an application (itxn only). LogicSigVersion >= 5. | +| 60 | CreatedAssetID | uint64 | Asset ID allocated by the creation of an ASA (itxn only). LogicSigVersion >= 5. | +| 61 | CreatedApplicationID | uint64 | ApplicationID allocated by the creation of an application (itxn only). LogicSigVersion >= 5. | Additional details in the [opcodes document](TEAL_opcodes.md#txn) on the `txn` op. diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index ea77daf..a930d11 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -490,8 +490,8 @@ Overflow is an error condition which halts execution and fails the transaction. | 57 | Nonparticipation | uint64 | Marks an account nonparticipating for rewards. LogicSigVersion >= 5. | | 58 | Logs | []byte | Log messages emitted by an application call (itxn only). LogicSigVersion >= 5. | | 59 | NumLogs | uint64 | Number of Logs (itxn only). LogicSigVersion >= 5. | -| 60 | EvalConfigAsset | uint64 | Asset ID allocated by the creation of an ASA (itxn only). LogicSigVersion >= 5. | -| 61 | EvalApplicationID | uint64 | ApplicationID allocated by the creation of an application (itxn only). LogicSigVersion >= 5. | +| 60 | CreatedAssetID | uint64 | Asset ID allocated by the creation of an ASA (itxn only). LogicSigVersion >= 5. | +| 61 | CreatedApplicationID | uint64 | ApplicationID allocated by the creation of an application (itxn only). LogicSigVersion >= 5. | TypeEnum mapping: From 2323e4a7342e63e14b4602eab78297a26eeb115a Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Tue, 14 Sep 2021 17:07:22 -0400 Subject: [PATCH 21/23] submit requires a new begin --- dev/TEAL.md | 6 +++--- dev/TEAL_opcodes.md | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index 7490a52..e4bb5e7 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -472,9 +472,9 @@ transaction types, are rejected by `itxn_submit`. | Op | Description | | --- | --- | -| `itxn_begin` | Begin preparation of a new inner transaction | -| `itxn_field f` | Set field F of the current inner transaction to X | -| `itxn_submit` | Execute the current inner transaction. Fail if 16 inner transactions have already been executed, or if the transaction itself fails. | +| `itxn_begin` | begin preparation of a new inner transaction | +| `itxn_field f` | set field F of the current inner transaction to X | +| `itxn_submit` | execute the current inner transaction. Fail if 16 inner transactions have already been executed, or if the transaction itself fails. | | `itxn f` | push field F of the last inner transaction to stack | | `itxna f i` | push Ith value of the array field F of the last inner transaction to stack | diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index a930d11..182bf39 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -1304,7 +1304,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Opcode: 0xb1 - Pops: _None_ - Pushes: _None_ -- Begin preparation of a new inner transaction +- begin preparation of a new inner transaction - LogicSigVersion >= 5 - Mode: Application @@ -1315,7 +1315,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Opcode: 0xb2 {uint8 transaction field index} - Pops: *... stack*, any - Pushes: _None_ -- Set field F of the current inner transaction to X +- set field F of the current inner transaction to X - LogicSigVersion >= 5 - Mode: Application @@ -1326,10 +1326,12 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit - Opcode: 0xb3 - Pops: _None_ - Pushes: _None_ -- Execute the current inner transaction. Fail if 16 inner transactions have already been executed, or if the transaction itself fails. +- execute the current inner transaction. Fail if 16 inner transactions have already been executed, or if the transaction itself fails. - LogicSigVersion >= 5 - Mode: Application +`itxn_submit` resets the current transaction so that it can not be resubmitted. A new `itxn_begin` is required to prepare another inner transaction. + ## itxn f - Opcode: 0xb4 {uint8 transaction field index} From b37c527f2e8a0464136405c2b1b4ada9496b11ff Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Tue, 14 Sep 2021 17:15:40 -0400 Subject: [PATCH 22/23] final review comments? --- dev/TEAL.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index e4bb5e7..e8e5a27 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -18,7 +18,8 @@ The stack starts empty and contains values of either uint64 or bytes 4096 bytes in length). Most operations act on the stack, popping arguments from it and pushing results to it. -The maximum stack depth is currently 1000. +The maximum stack depth is currently 1000. If the stack depth is +exceed or if a `bytes` element exceed 4096 bytes, the program fails. ## Scratch Space @@ -44,11 +45,12 @@ TEAL LogicSigs run in Algorand nodes as part of testing a proposed transaction t If an authorized program executes and finishes with a single non-zero uint64 value on the stack then that program has validated the transaction it is attached to. -The TEAL program has access to data from the transaction it is attached to (`txn` op), any transactions in a transaction group it is part of (`gtxn` op), and a few global values like consensus parameters (`global` op). Some "Args" may be attached to a transaction being validated by a TEAL program. Args are an array of byte strings. A common pattern would be to have the key to unlock some contract as an Arg. Args are recorded on the blockchain and publicly visible when the transaction is submitted to the network. These LogicSig Args are _not_ signed. +The TEAL program has access to data from the transaction it is attached to (`txn` op), any transactions in a transaction group it is part of (`gtxn` op), and a few global values like consensus parameters (`global` op). Some "Args" may be attached to a transaction being validated by a TEAL program. Args are an array of byte strings. A common pattern would be to have the key to unlock some contract as an Arg. Args are recorded on the blockchain and publicly visible when the transaction is submitted to the network. These LogicSig Args are _not_ part of the transaction ID nor of the TxGroup hash. They also cannot be read from other TEAL programs in the group of transactions. A program can either authorize some delegated action on a normal private key signed or multisig account or be wholly in charge of a contract account. -* If the account has signed the program (an ed25519 signature on "Program" concatenated with the program bytes) then if the program returns true the transaction is authorized as if the account had signed it. This allows an account to hand out a signed program so that other users can carry out delegated actions which are approved by the program. +* If the account has signed the program (an ed25519 signature on "Program" concatenated with the program bytes) then if the program returns true the transaction is authorized as if the account had signed it. This allows an account to hand out a signed program so that other users can carry out delegated actions which are approved by the program. Note that LogicSig Args are _not_ signed. + * If the SHA512_256 hash of the program (prefixed by "Program") is equal to the transaction Sender address then this is a contract account wholly controlled by the program. No other signature is necessary or possible. The only way to execute a transaction against the contract account is for the program to approve it. The TEAL bytecode plus the length of all Args must add up to no more than 1000 bytes (consensus parameter LogicSigMaxSize). Each TEAL op has an associated cost and the program cost must total no more than 20000 (consensus parameter LogicSigMaxCost). Most ops have a cost of 1, but a few slow crypto ops are much higher. Prior to v4, the program's cost was estimated as the static sum of all the opcode costs in the program (whether they were actually executed or not). Beginning with v4, the program's cost is tracked dynamically, while being evaluated. If the program exceeds its budget, it fails. From 2fd78672d44fd1219a330151a73140f3fc022fa1 Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Tue, 14 Sep 2021 17:21:42 -0400 Subject: [PATCH 23/23] Update TEAL.md minor typo --- dev/TEAL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index e8e5a27..b60ac8e 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -19,7 +19,7 @@ The stack starts empty and contains values of either uint64 or bytes arguments from it and pushing results to it. The maximum stack depth is currently 1000. If the stack depth is -exceed or if a `bytes` element exceed 4096 bytes, the program fails. +exceeded or if a `bytes` element exceed 4096 bytes, the program fails. ## Scratch Space