Skip to content

Commit 60b99b2

Browse files
authored
Regularize access to "foreign" references. (algorand#2264)
All opcodes that take accounts, asas, or apps can use the thing itself (an address, or asa/app id) or an "indirect" reference through the "foreign" arrays of the app transaction. In all cases, the "thing" must appear in those foreign arrays, it's just more convenient sometimes to use the item in code, rather than indirect. (Note this is a new requirement for some opcodes that previously allowed access to any number of local state objects of an account asset_holding_get asset_opted_in and app_local_*)
1 parent e9f73a3 commit 60b99b2

File tree

13 files changed

+550
-502
lines changed

13 files changed

+550
-502
lines changed

data/transactions/application.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -102,19 +102,22 @@ type ApplicationCallTxnFields struct {
102102
// ApprovalProgram or ClearStateProgram.
103103
ApplicationArgs [][]byte `codec:"apaa,allocbound=encodedMaxApplicationArgs"`
104104

105-
// Accounts are accounts whose balance records are accessible by the
106-
// executing ApprovalProgram or ClearStateProgram. To access LocalState
107-
// for an account besides the sender, that account's address must be
108-
// listed here.
105+
// Accounts are accounts whose balance records are accessible
106+
// by the executing ApprovalProgram or ClearStateProgram. To
107+
// access LocalState or an ASA balance for an account besides
108+
// the sender, that account's address must be listed here (and
109+
// since v4, the ForeignApp or ForeignAsset must also include
110+
// the app or asset id).
109111
Accounts []basics.Address `codec:"apat,allocbound=encodedMaxAccounts"`
110112

111-
// ForeignApps are application IDs for applications besides this one
112-
// whose GlobalState may be read by the executing ApprovalProgram or
113-
// ClearStateProgram.
113+
// ForeignApps are application IDs for applications besides
114+
// this one whose GlobalState (or Local, since v4) may be read
115+
// by the executing ApprovalProgram or ClearStateProgram.
114116
ForeignApps []basics.AppIndex `codec:"apfa,allocbound=encodedMaxForeignApps"`
115117

116-
// ForeignAssets are asset IDs for assets whose AssetParams may be read
117-
// by the executing ApprovalProgram or ClearStateProgram.
118+
// ForeignAssets are asset IDs for assets whose AssetParams
119+
// (and since v4, Holdings) may be read by the executing
120+
// ApprovalProgram or ClearStateProgram.
118121
ForeignAssets []basics.AssetIndex `codec:"apas,allocbound=encodedMaxForeignAssets"`
119122

120123
// LocalStateSchema specifies the maximum number of each type that may
@@ -204,7 +207,7 @@ func (ac *ApplicationCallTxnFields) AddressByIndex(accountIdx uint64, sender bas
204207
// An index > 0 corresponds to an offset into txn.Accounts. Check to
205208
// make sure the index is valid.
206209
if accountIdx > uint64(len(ac.Accounts)) {
207-
err := fmt.Errorf("cannot load account[%d] of %d", accountIdx, len(ac.Accounts))
210+
err := fmt.Errorf("invalid Account reference %d", accountIdx)
208211
return basics.Address{}, err
209212
}
210213

@@ -228,5 +231,5 @@ func (ac *ApplicationCallTxnFields) IndexByAddress(target basics.Address, sender
228231
}
229232
}
230233

231-
return 0, fmt.Errorf("could not find offset of address %s", target)
234+
return 0, fmt.Errorf("invalid Account reference %s", target)
232235
}

data/transactions/logic/README.md

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ Differences between modes include:
4242

4343
## Constants
4444

45-
Constants are loaded into the environment into storage separate from the stack. They can then be pushed onto the stack by referring to the type and index. This makes for efficient re-use of byte constants used for account addresses, etc.
45+
Constants are loaded into the environment into storage separate from the stack. They can then be pushed onto the stack by referring to the type and index. This makes for efficient re-use of byte constants used for account addresses, etc. Constants that are not reused can be pushed with `pushint` or `pushbytes`.
4646

4747
The assembler will hide most of this, allowing simple use of `int 1234` and `byte 0xcafed00d`. These constants will automatically get assembled into int and byte pages of constants, de-duplicated, and operations to load them from constant storage space inserted.
4848

4949
Constants are loaded into the environment by two opcodes, `intcblock` and `bytecblock`. Both of these use [proto-buf style variable length unsigned int](https://developers.google.com/protocol-buffers/docs/encoding#varint), reproduced [here](#varuint). The `intcblock` opcode is followed by a varuint specifying the length of the array and then that number of varuint. The `bytecblock` opcode is followed by a varuint array length then that number of pairs of (varuint, bytes) length prefixed byte strings. This should efficiently load 32 and 64 byte constants which will be common as addresses, hashes, and signatures.
5050

51-
Constants are pushed onto the stack by `intc`, `intc_[0123]`, `bytec`, and `bytec_[0123]`. The assembler will handle converting `int N` or `byte N` into the appropriate form of the instruction needed.
51+
Constants are pushed onto the stack by `intc`, `intc_[0123]`, `pushint`, `bytec`, `bytec_[0123]`, and `pushbytes`. The assembler will handle converting `int N` or `byte N` into the appropriate form of the instruction needed.
5252

5353
### Named Integer Constants
5454

@@ -81,6 +81,8 @@ An application transaction must indicate the action to be taken following the ex
8181

8282
Most operations work with only one type of argument, uint64 or bytes, and panic if the wrong type value is on the stack.
8383

84+
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. 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.
85+
8486
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.
8587

8688
This summary is supplemented by more detail in the [opcodes document](TEAL_opcodes.md).
@@ -348,19 +350,19 @@ Asset fields include `AssetHolding` and `AssetParam` fields that are used in `as
348350

349351
| Op | Description |
350352
| --- | --- |
351-
| `balance` | get balance for the requested account specified by Txn.Accounts[A] in microalgos. A is specified as an account index in the Accounts field of the ApplicationCall transaction, zero index means the sender. The balance is observed after the effects of previous transactions in the group, and after the fee for the current transaction is deducted. |
352-
| `min_balance` | get minimum required balance for the requested account specified by Txn.Accounts[A] in microalgos. A is specified as an account index in the Accounts field of the ApplicationCall transaction, zero index means the sender. Required balance is affected by [ASA](https://developer.algorand.org/docs/features/asa/#assets-overview) and [App](https://developer.algorand.org/docs/features/asc1/stateful/#minimum-balance-requirement-for-a-smart-contract) usage. When creating or opting into an app, the minimum balance grows before the app code runs, therefore the increase is visible there. When deleting or closing out, the minimum balance decreases after the app executes. |
353-
| `app_opted_in` | check if account specified by Txn.Accounts[A] opted in for the application B => {0 or 1} |
354-
| `app_local_get` | read from account specified by Txn.Accounts[A] from local state of the current application key B => value |
355-
| `app_local_get_ex` | read from account specified by Txn.Accounts[A] from local state of the application B key C => [*... stack*, value, 0 or 1] |
353+
| `balance` | get balance account A, in microalgos. The balance is observed after the effects of previous transactions in the group, and after the fee for the current transaction is deducted. |
354+
| `min_balance` | get minimum required balance account A, in microalgos. Required balance is affected by [ASA](https://developer.algorand.org/docs/features/asa/#assets-overview) and [App](https://developer.algorand.org/docs/features/asc1/stateful/#minimum-balance-requirement-for-a-smart-contract) usage. When creating or opting into an app, the minimum balance grows before the app code runs, therefore the increase is visible there. When deleting or closing out, the minimum balance decreases after the app executes. |
355+
| `app_opted_in` | check if account A opted in for the application B => {0 or 1} |
356+
| `app_local_get` | read from account A from local state of the current application key B => value |
357+
| `app_local_get_ex` | read from account A from local state of the application B key C => [*... stack*, value, 0 or 1] |
356358
| `app_global_get` | read key A from global state of a current application => value |
357-
| `app_global_get_ex` | read from application Txn.ForeignApps[A] global state key B => [*... stack*, value, 0 or 1]. A is specified as an account index in the ForeignApps field of the ApplicationCall transaction, zero index means this app |
358-
| `app_local_put` | write to account specified by Txn.Accounts[A] to local state of a current application key B with value C |
359+
| `app_global_get_ex` | read from application A global state key B => [*... stack*, value, 0 or 1] |
360+
| `app_local_put` | write to account specified by A to local state of a current application key B with value C |
359361
| `app_global_put` | write key A and value B to global state of the current application |
360-
| `app_local_del` | delete from account specified by Txn.Accounts[A] local state key B of the current application |
362+
| `app_local_del` | delete from account A local state key B of the current application |
361363
| `app_global_del` | delete key A from a global state of the current application |
362-
| `asset_holding_get i` | read from account specified by Txn.Accounts[A] and asset B holding field X (imm arg) => {0 or 1 (top), value} |
363-
| `asset_params_get i` | read from asset Txn.ForeignAssets[A] params field X (imm arg) => {0 or 1 (top), value} |
364+
| `asset_holding_get i` | read from account A and asset B holding field X (imm arg) => {0 or 1 (top), value} |
365+
| `asset_params_get i` | read from asset A params field X (imm arg) => {0 or 1 (top), value} |
364366

365367
# Assembler Syntax
366368

data/transactions/logic/README_in.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ Differences between modes include:
4242

4343
## Constants
4444

45-
Constants are loaded into the environment into storage separate from the stack. They can then be pushed onto the stack by referring to the type and index. This makes for efficient re-use of byte constants used for account addresses, etc.
45+
Constants are loaded into the environment into storage separate from the stack. They can then be pushed onto the stack by referring to the type and index. This makes for efficient re-use of byte constants used for account addresses, etc. Constants that are not reused can be pushed with `pushint` or `pushbytes`.
4646

4747
The assembler will hide most of this, allowing simple use of `int 1234` and `byte 0xcafed00d`. These constants will automatically get assembled into int and byte pages of constants, de-duplicated, and operations to load them from constant storage space inserted.
4848

4949
Constants are loaded into the environment by two opcodes, `intcblock` and `bytecblock`. Both of these use [proto-buf style variable length unsigned int](https://developers.google.com/protocol-buffers/docs/encoding#varint), reproduced [here](#varuint). The `intcblock` opcode is followed by a varuint specifying the length of the array and then that number of varuint. The `bytecblock` opcode is followed by a varuint array length then that number of pairs of (varuint, bytes) length prefixed byte strings. This should efficiently load 32 and 64 byte constants which will be common as addresses, hashes, and signatures.
5050

51-
Constants are pushed onto the stack by `intc`, `intc_[0123]`, `bytec`, and `bytec_[0123]`. The assembler will handle converting `int N` or `byte N` into the appropriate form of the instruction needed.
51+
Constants are pushed onto the stack by `intc`, `intc_[0123]`, `pushint`, `bytec`, `bytec_[0123]`, and `pushbytes`. The assembler will handle converting `int N` or `byte N` into the appropriate form of the instruction needed.
5252

5353
### Named Integer Constants
5454

@@ -58,6 +58,8 @@ Constants are pushed onto the stack by `intc`, `intc_[0123]`, `bytec`, and `byte
5858

5959
Most operations work with only one type of argument, uint64 or bytes, and panic if the wrong type value is on the stack.
6060

61+
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. 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.
62+
6163
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.
6264

6365
This summary is supplemented by more detail in the [opcodes document](TEAL_opcodes.md).

0 commit comments

Comments
 (0)