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
PyTeal has a requirement that every expression must push either 0 or 1 new elements to the stack. However, some opcodes, like asset_holding_get, asset_param_get, app_param_get, app_global_get_ex, and app_local_get_ex push 2 new elements to the stack.
In order to handle these opcodes PyTeal uses MaybeValue to contain both elements being pushed to the stack. Internally, MaybeValue allocates two scratch slots and pops the 2 elements into these slots. Then later when .hasValue or .value is called on that MaybeValue, it loads the value from the appropriate scratch slot.
Problem
While the above approach works technically, the existing MaybeValue type is not the easiest to use. This is because you must create a temporary variable to store the MaybeValue and explicitly load it before using it. For example:
The requirement to define a top-level Python variable in order to hold the intermediate value of a MaybeValue means that it does not compose well in other PyTeal expressions. Additionally, it's especially annoying if you only want to examine one of the returned values.
For these reasons, we should introduce a new way for PyTeal to handle operations which push multiple values to the stack.
Solution
The proposed solution is to create a new expression type to represent the return values from opcodes that push 2 or more values to the stack. Let's call this expression type MultiValue.
Instead of always storing the stack values in scratch slots like MaybeValue currently does, MultiValue will allow the user to specify how each return value should be handled, avoiding needing an intermediate storage area for the values and closing the gap between loading and using the values.
This can be achieved through a user-defined reducer function. The number of arguments for the reducer function is the same as the number of elements that operation pushes to the stack, and the reducer function will operate on these elements, eventually returning a PyTeal expression which will result in either 0 or 1 elements being pushed to the stack.
Compatibility
In order to maintain compatibility with existing usage of MaybeValue, we can make MaybeValue a subclass of MultiValue. MaybeValue will continue to have the same usage, unless you call the .reduce function on it, in which case it will behave like a MultiValue instead.
Examples
To store the values in scratch slots, similar to the existing MaybeValue implementation, you could do the following:
Or if you don't need to keep the values for later, you don't need to use scratch variables at all. You could put your condition directly inside of the reducer function:
Since MultiValue provides a general way of handing opcodes that push multiple values to the stack, we can directly expose more opcodes that behave this way, like addw, mulw, divmodw, expw, ecdsa_pk_decompress, and ecdsa_pk_recover.
TODO: think more about how wide math operations can be most conveniently used in this proposal
The text was updated successfully, but these errors were encountered:
Background
PyTeal has a requirement that every expression must push either 0 or 1 new elements to the stack. However, some opcodes, like
asset_holding_get
,asset_param_get
,app_param_get
,app_global_get_ex
, andapp_local_get_ex
push 2 new elements to the stack.In order to handle these opcodes PyTeal uses
MaybeValue
to contain both elements being pushed to the stack. Internally,MaybeValue
allocates two scratch slots and pops the 2 elements into these slots. Then later when.hasValue
or.value
is called on thatMaybeValue
, it loads the value from the appropriate scratch slot.Problem
While the above approach works technically, the existing
MaybeValue
type is not the easiest to use. This is because you must create a temporary variable to store theMaybeValue
and explicitly load it before using it. For example:The requirement to define a top-level Python variable in order to hold the intermediate value of a
MaybeValue
means that it does not compose well in other PyTeal expressions. Additionally, it's especially annoying if you only want to examine one of the returned values.For these reasons, we should introduce a new way for PyTeal to handle operations which push multiple values to the stack.
Solution
The proposed solution is to create a new expression type to represent the return values from opcodes that push 2 or more values to the stack. Let's call this expression type
MultiValue
.Instead of always storing the stack values in scratch slots like
MaybeValue
currently does,MultiValue
will allow the user to specify how each return value should be handled, avoiding needing an intermediate storage area for the values and closing the gap between loading and using the values.This can be achieved through a user-defined reducer function. The number of arguments for the reducer function is the same as the number of elements that operation pushes to the stack, and the reducer function will operate on these elements, eventually returning a PyTeal expression which will result in either 0 or 1 elements being pushed to the stack.
Compatibility
In order to maintain compatibility with existing usage of
MaybeValue
, we can makeMaybeValue
a subclass ofMultiValue
.MaybeValue
will continue to have the same usage, unless you call the.reduce
function on it, in which case it will behave like aMultiValue
instead.Examples
To store the values in scratch slots, similar to the existing
MaybeValue
implementation, you could do the following:Or if you don't need to keep the values for later, you don't need to use scratch variables at all. You could put your condition directly inside of the reducer function:
Instead, if you want to assert that
hasValue
is always true, you could do:Further usage
Since
MultiValue
provides a general way of handing opcodes that push multiple values to the stack, we can directly expose more opcodes that behave this way, likeaddw
,mulw
,divmodw
,expw
,ecdsa_pk_decompress
, andecdsa_pk_recover
.TODO: think more about how wide math operations can be most conveniently used in this proposal
The text was updated successfully, but these errors were encountered: