You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Is your addition related to a problem? Please describe.
As far as I can tell, for several kinds of opcodes, the TEAL opcode reference (https://developer.algorand.org/docs/reference/teal/opcodes/) does not provide a complete description of their behavior. In particular, several descriptions of opcodes that deal with reading state do not seem to specify what happens when uninitialized state is read. See specific examples below.
Before continuing, I want to be clear that I understand there are two terms which have dual meanings: Accounts and ForeignApps.
these both refer to application call transaction array-like fields
these both refer to a separate VM-created array which is defined based on the txn field except:
index 0 refers to the account currently executing the application call or currently executing application, respectively.
index i with i != 1 refers to the i - 1th entry in the array-like field described in sense (1).
Note: In the descriptions below, I'm using definition (2). Thus, the minimum length of these arrays will always be 1.
From my reading, the return value is unspecified when:
load - loading an uninitialized scratch space cell
txn/gtxn - a transaction has type t and we read a field f of t where f was optional and unspecified
txn/gtxn - a transaction has type t and we read a field f of a different transaction type t2
txna/gtxna - a transaction has type t and an array-like field f and we read a value f[i] where index i >= len(f)
gtxn/gtxna - we attempt to access a transaction at group index i where i >= GroupSize
balance - we attempt to access the balance of the account at index i when i >= len(Accounts)
arg_i/arg - we attempt to access the argument at index i when i >= len(Args)
bytec_i/bytec - we attempt to access the byte constant in the byte block at index i when i >= len(bytecblock)
intc_i/intc - we attempt to access the int constant in the int block at index i when i >= len(intcblock)
app_local_put - we attempt to write to the application state of an account at index i when i >= len(Accounts)
The TEAL opcode reference on the opcode return value seems slightly unclear to me in the following cases. Typically, it says something like the value is zero if the key does not exist. I'm not sure if that explanation adequately covers all of the following cases. It would be helpful to extend the behavior description to specifically reference the following cases.
app_local_get/app_local_get_ex - we attempt to access the application state of an account at index i when i >= len(Accounts)
app_local_get/app_local_get_ex - the account at Accounts[i] has not not opted into the given application ID
app_local_get_ex - we attempt to access the local application state of an application ID that is invalid
app_global_get_ex - we attempt to access the global application state of the foreign application at index i when i >= len(ForeignApps)
asset_holding_get - we attempt to access the asset holdings of an account at index i when i >= len(Accounts)
asset_holding_get - we attempt to access the asset holdings of Accounts[i] that has not opted into using the given asset ID
asset_params_get - we attempt to access the asset parameters of an asset at index i when i >= len(ForeignAssets)
Describe the solution you'd like
For any case listed above which is indeed unspecified, I would like the TEAL opcode reference to define what happens.
If my understanding is correct, I would like the TEAL opcode reference to always clarify the distinction between the two meanings of Accounts and ForeignApps.
Describe alternatives you've considered
Any unspecified behaviors could be documented as unspecified in the TEAL opcode reference.
Additional context
One might believe he/she could determine the type of a transaction at index i by doing (for example)
gtxn i CloseRemainderTo
since the CloseRemainderTo field only exists for payment transactions. However, upon inspection of the interpreter code, it appears that the txn family of opcodes will never panic; instead, it looks like they return a zero value in case a field is accessed that does not exist for the given transaction. This behavior has implications for transaction type checking. It means that either: we must check that the gtxn i f return value is non-zero (or possibly, depending on how transactions are validated) just directly check the return value of gtxn i Type. I think it may be worth updating the TEAL guidelines page (https://developer.algorand.org/docs/reference/teal/guidelines/) to replace:
- Type or TypeEnum can be checked to ensure something is a Payment or AssetXfer or another transaction type.
with something like (if the following is true):
- Checking the transaction Type or TypeEnum is the only way to ensure something is a Payment or AssetXfer or another transaction type.
If there are other ways to check that a transaction has the correct type, e.g., my suggestion about gtxn i f being non-zero, it would be good to add that to the list as well.
The text was updated successfully, but these errors were encountered:
Is your addition related to a problem? Please describe.
As far as I can tell, for several kinds of opcodes, the TEAL opcode reference (https://developer.algorand.org/docs/reference/teal/opcodes/) does not provide a complete description of their behavior. In particular, several descriptions of opcodes that deal with reading state do not seem to specify what happens when uninitialized state is read. See specific examples below.
Before continuing, I want to be clear that I understand there are two terms which have dual meanings:
Accounts
andForeignApps
.i
withi != 1
refers to thei - 1
th entry in the array-like field described in sense (1).Note: In the descriptions below, I'm using definition (2). Thus, the minimum length of these arrays will always be 1.
From my reading, the return value is unspecified when:
load
- loading an uninitialized scratch space celltxn/gtxn
- a transaction has typet
and we read a fieldf
oft
wheref
was optional and unspecifiedtxn/gtxn
- a transaction has typet
and we read a fieldf
of a different transaction typet2
txna/gtxna
- a transaction has typet
and an array-like fieldf
and we read a valuef[i]
where indexi >= len(f)
gtxn/gtxna
- we attempt to access a transaction at group indexi
wherei >= GroupSize
balance
- we attempt to access the balance of the account at indexi
wheni >= len(Accounts)
arg_i/arg
- we attempt to access the argument at indexi
wheni >= len(Args)
bytec_i/bytec
- we attempt to access the byte constant in the byte block at indexi
wheni >= len(bytecblock)
intc_i/intc
- we attempt to access the int constant in the int block at indexi
wheni >= len(intcblock)
app_local_put
- we attempt to write to the application state of an account at indexi
wheni >= len(Accounts)
The TEAL opcode reference on the opcode return value seems slightly unclear to me in the following cases. Typically, it says something like
the value is zero if the key does not exist
. I'm not sure if that explanation adequately covers all of the following cases. It would be helpful to extend the behavior description to specifically reference the following cases.app_local_get/app_local_get_ex
- we attempt to access the application state of an account at indexi
wheni >= len(Accounts)
app_local_get/app_local_get_ex
- the account atAccounts[i]
has not not opted into the given application IDapp_local_get_ex
- we attempt to access the local application state of an application ID that is invalidapp_global_get_ex
- we attempt to access the global application state of the foreign application at indexi
wheni >= len(ForeignApps)
asset_holding_get
- we attempt to access the asset holdings of an account at indexi
wheni >= len(Accounts)
asset_holding_get
- we attempt to access the asset holdings ofAccounts[i]
that has not opted into using the given asset IDasset_params_get
- we attempt to access the asset parameters of an asset at indexi
wheni >= len(ForeignAssets)
Describe the solution you'd like
Accounts
andForeignApps
.Describe alternatives you've considered
Any unspecified behaviors could be documented as unspecified in the TEAL opcode reference.
Additional context
One might believe he/she could determine the type of a transaction at index
i
by doing (for example)since the
CloseRemainderTo
field only exists for payment transactions. However, upon inspection of the interpreter code, it appears that thetxn
family of opcodes will never panic; instead, it looks like they return a zero value in case a field is accessed that does not exist for the given transaction. This behavior has implications for transaction type checking. It means that either: we must check that thegtxn i f
return value is non-zero (or possibly, depending on how transactions are validated) just directly check the return value ofgtxn i Type
. I think it may be worth updating the TEAL guidelines page (https://developer.algorand.org/docs/reference/teal/guidelines/) to replace:with something like (if the following is true):
If there are other ways to check that a transaction has the correct type, e.g., my suggestion about
gtxn i f
being non-zero, it would be good to add that to the list as well.The text was updated successfully, but these errors were encountered: