diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 593804daa..b08b2190f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,7 +23,7 @@ jobs: - name: Install python dependencies run: make setup-development - name: Build and Test - run: make build-and-test + run: make lint-and-test run-integration-tests: runs-on: ubuntu-20.04 @@ -63,8 +63,8 @@ jobs: run: make sandbox-dev-up - name: Install python dependencies run: make setup-development - - name: Build, Unit Tests and Integration Tests - run: make all-tests + - name: Integration Tests Only + run: make test-integration - name: Stop running images run: make sandbox-dev-stop diff --git a/.gitignore b/.gitignore index f930cdc2f..26d6609eb 100644 --- a/.gitignore +++ b/.gitignore @@ -102,6 +102,7 @@ celerybeat-schedule *.sage.py # Environments +_env .env .venv env/ @@ -138,3 +139,6 @@ dmypy.json # mac OS .DS_Store + +# asdf +.tool-versions diff --git a/Makefile b/Makefile index 17b8591af..3a8bb1d18 100644 --- a/Makefile +++ b/Makefile @@ -40,8 +40,7 @@ black: flake8: flake8 $(ALLPY) -# TODO: add `tests` to $MYPY when graviton respects mypy (version 🐗) -MYPY = pyteal scripts +MYPY = pyteal scripts tests mypy: mypy $(MYPY) @@ -55,9 +54,9 @@ test-unit: pytest -n $(NUM_PROCS) --durations=10 -sv pyteal tests/unit --ignore tests/unit/blackbox_test.py --ignore tests/unit/user_guide_test.py pytest -n 1 -sv tests/unit/blackbox_test.py tests/unit/user_guide_test.py -build-and-test: check-generate-init lint test-unit +lint-and-test: check-generate-init lint test-unit -# ---- Integration Test (algod required) ---- # +# ---- Integration Tests (algod required) ---- # sandbox-dev-up: docker-compose up -d algod @@ -70,7 +69,7 @@ integration-run: test-integration: integration-run -all-tests: build-and-test test-integration +all-tests: lint-and-test test-integration # ---- Local Github Actions Simulation via `act` ---- # # assumes act is installed, e.g. via `brew install act` diff --git a/pyteal/ast/abi/__init__.py b/pyteal/ast/abi/__init__.py index b9cb974ce..9144bac02 100644 --- a/pyteal/ast/abi/__init__.py +++ b/pyteal/ast/abi/__init__.py @@ -36,7 +36,12 @@ from pyteal.ast.abi.array_dynamic import DynamicArrayTypeSpec, DynamicArray from pyteal.ast.abi.method_return import MethodReturn -from pyteal.ast.abi.util import type_spec_from_annotation, make +from pyteal.ast.abi.util import ( + algosdk_from_annotation, + algosdk_from_type_spec, + make, + type_spec_from_annotation, +) __all__ = [ "String", @@ -81,4 +86,6 @@ "MethodReturn", "type_spec_from_annotation", "make", + "algosdk_from_annotation", + "algosdk_from_type_spec", ] diff --git a/pyteal/ast/abi/address.py b/pyteal/ast/abi/address.py index db21b1adc..1e8da1f0f 100644 --- a/pyteal/ast/abi/address.py +++ b/pyteal/ast/abi/address.py @@ -27,6 +27,9 @@ def __init__(self) -> None: def new_instance(self) -> "Address": return Address() + def annotation_type(self) -> "type[Address]": + return Address + def __str__(self) -> str: return "address" diff --git a/pyteal/ast/abi/address_test.py b/pyteal/ast/abi/address_test.py index c3ce39510..a33b5b123 100644 --- a/pyteal/ast/abi/address_test.py +++ b/pyteal/ast/abi/address_test.py @@ -21,6 +21,10 @@ def test_AddressTypeSpec_byte_length_static(): assert (abi.AddressTypeSpec()).byte_length_static() == abi.AddressLength.Bytes +def test_AddressTypeSpec_length_static(): + assert (abi.AddressTypeSpec()).length_static() == abi.AddressLength.Bytes + + def test_AddressTypeSpec_new_instance(): assert isinstance(abi.AddressTypeSpec().new_instance(), abi.Address) diff --git a/pyteal/ast/abi/array_dynamic.py b/pyteal/ast/abi/array_dynamic.py index 99d0ffffe..33c8e8309 100644 --- a/pyteal/ast/abi/array_dynamic.py +++ b/pyteal/ast/abi/array_dynamic.py @@ -22,6 +22,9 @@ class DynamicArrayTypeSpec(ArrayTypeSpec[T]): def new_instance(self) -> "DynamicArray[T]": return DynamicArray(self) + def annotation_type(self) -> "type[DynamicArray[T]]": + return DynamicArray[self.value_type_spec().annotation_type()] # type: ignore[misc] + def is_length_dynamic(self) -> bool: return True diff --git a/pyteal/ast/abi/array_static.py b/pyteal/ast/abi/array_static.py index 6f8ba4468..b829237b7 100644 --- a/pyteal/ast/abi/array_static.py +++ b/pyteal/ast/abi/array_static.py @@ -1,11 +1,4 @@ -from typing import ( - Union, - Sequence, - TypeVar, - Generic, - Final, - cast, -) +from typing import Final, Generic, Literal, Sequence, TypeVar, Union, cast from pyteal.errors import TealInputError from pyteal.ast.expr import Expr @@ -25,11 +18,18 @@ def __init__(self, value_type_spec: TypeSpec, array_length: int) -> None: super().__init__(value_type_spec) if not isinstance(array_length, int) or array_length < 0: raise TypeError(f"Unsupported StaticArray length: {array_length}") - self.array_length: Final = array_length + + # Casts to `int` to handle downstream usage where value is a subclass of int like `IntEnum`. + self.array_length: Final = int(array_length) def new_instance(self) -> "StaticArray[T, N]": return StaticArray(self) + def annotation_type(self) -> "type[StaticArray[T, N]]": + return StaticArray[ # type: ignore[misc] + self.value_spec.annotation_type(), Literal[self.array_length] # type: ignore + ] + def length_static(self) -> int: """Get the size of this static array type. diff --git a/pyteal/ast/abi/bool.py b/pyteal/ast/abi/bool.py index f1b8a6065..52b8e513c 100644 --- a/pyteal/ast/abi/bool.py +++ b/pyteal/ast/abi/bool.py @@ -17,6 +17,9 @@ class BoolTypeSpec(TypeSpec): def new_instance(self) -> "Bool": return Bool() + def annotation_type(self) -> "type[Bool]": + return Bool + def is_dynamic(self) -> bool: # Only accurate if this value is alone, since up to 8 consecutive bools will fit into a single byte return False diff --git a/pyteal/ast/abi/string.py b/pyteal/ast/abi/string.py index 3bfacf2eb..b4215d65f 100644 --- a/pyteal/ast/abi/string.py +++ b/pyteal/ast/abi/string.py @@ -30,6 +30,9 @@ def __init__(self) -> None: def new_instance(self) -> "String": return String() + def annotation_type(self) -> "type[String]": + return String + def __str__(self) -> str: return "string" diff --git a/pyteal/ast/abi/tuple.py b/pyteal/ast/abi/tuple.py index 3824e701e..17c9bb631 100644 --- a/pyteal/ast/abi/tuple.py +++ b/pyteal/ast/abi/tuple.py @@ -220,6 +220,33 @@ def length_static(self) -> int: def new_instance(self) -> "Tuple": return Tuple(self) + def annotation_type(self) -> "type[Tuple]": + vtses = self.value_type_specs() + + def annotater(): + return [x.annotation_type() for x in vtses] + + match len(vtses): + case 0: + return Tuple0 + case 1: + v0 = annotater()[0] + return Tuple1[v0] # type: ignore[valid-type] + case 2: + v0, v1 = annotater() + return Tuple2[v0, v1] # type: ignore[valid-type] + case 3: + v0, v1, v2 = annotater() + return Tuple3[v0, v1, v2] # type: ignore[valid-type] + case 4: + v0, v1, v2, v3 = annotater() + return Tuple4[v0, v1, v2, v3] # type: ignore[valid-type] + case 5: + v0, v1, v2, v3, v4 = annotater() + return Tuple5[v0, v1, v2, v3, v4] # type: ignore[valid-type] + + raise TypeError(f"Cannot annotate tuple of length {len(vtses)}") + def is_dynamic(self) -> bool: return any(type_spec.is_dynamic() for type_spec in self.value_type_specs()) @@ -243,8 +270,7 @@ def __str__(self) -> str: TupleTypeSpec.__module__ = "pyteal" - -T = TypeVar("T", bound="Tuple") +T_tuple = TypeVar("T_tuple", bound="Tuple") class Tuple(BaseType): @@ -272,7 +298,7 @@ def set(self, *values: BaseType) -> Expr: ... @overload - def set(self: T, value: ComputedValue[T]) -> Expr: + def set(self: T_tuple, value: ComputedValue[T_tuple]) -> Expr: ... def set(self, *values): @@ -307,8 +333,10 @@ def __getitem__(self, index: int) -> "TupleElement": Tuple.__module__ = "pyteal" +T = TypeVar("T", bound=BaseType) + -class TupleElement(ComputedValue[BaseType]): +class TupleElement(ComputedValue[T]): """Represents the extraction of a specific element from a Tuple.""" def __init__(self, tuple: Tuple, index: int) -> None: @@ -319,7 +347,7 @@ def __init__(self, tuple: Tuple, index: int) -> None: def produced_type_spec(self) -> TypeSpec: return self.tuple.type_spec().value_type_specs()[self.index] - def store_into(self, output: BaseType) -> Expr: + def store_into(self, output: T) -> Expr: return indexTuple( self.tuple.type_spec().value_type_specs(), self.tuple.encode(), diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index 52a57fec8..adcba417a 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -19,6 +19,11 @@ def new_instance(self) -> "BaseType": """Create a new instance of the specified type.""" pass + @abstractmethod + def annotation_type(self) -> "type[BaseType]": + """Get the annotation type associated with this spec""" + pass + @abstractmethod def is_dynamic(self) -> bool: """Check if this ABI type is dynamic. diff --git a/pyteal/ast/abi/uint.py b/pyteal/ast/abi/uint.py index ea8e8eded..1474ab7b2 100644 --- a/pyteal/ast/abi/uint.py +++ b/pyteal/ast/abi/uint.py @@ -123,6 +123,10 @@ def __init__(self, bit_size: int) -> None: def new_instance(self) -> "Uint": pass + @abstractmethod + def annotation_type(self) -> "type[Uint]": + pass + def bit_size(self) -> int: """Get the bit size of this uint type""" return self.size @@ -157,6 +161,9 @@ def __init__(self) -> None: def new_instance(self) -> "Byte": return Byte() + def annotation_type(self) -> "type[Byte]": + return Byte + def __str__(self) -> str: return "byte" @@ -171,6 +178,9 @@ def __init__(self) -> None: def new_instance(self) -> "Uint8": return Uint8() + def annotation_type(self) -> "type[Uint8]": + return Uint8 + Uint8TypeSpec.__module__ = "pyteal" @@ -182,6 +192,9 @@ def __init__(self) -> None: def new_instance(self) -> "Uint16": return Uint16() + def annotation_type(self) -> "type[Uint16]": + return Uint16 + Uint16TypeSpec.__module__ = "pyteal" @@ -193,6 +206,9 @@ def __init__(self) -> None: def new_instance(self) -> "Uint32": return Uint32() + def annotation_type(self) -> "type[Uint32]": + return Uint32 + Uint32TypeSpec.__module__ = "pyteal" @@ -204,6 +220,9 @@ def __init__(self) -> None: def new_instance(self) -> "Uint64": return Uint64() + def annotation_type(self) -> "type[Uint64]": + return Uint64 + Uint32TypeSpec.__module__ = "pyteal" diff --git a/pyteal/ast/abi/util.py b/pyteal/ast/abi/util.py index 6cd3aa7c9..594b9ab73 100644 --- a/pyteal/ast/abi/util.py +++ b/pyteal/ast/abi/util.py @@ -1,5 +1,7 @@ from typing import TypeVar, Any, Literal, get_origin, get_args, cast +import algosdk.abi + from pyteal.errors import TealInputError from pyteal.ast.expr import Expr from pyteal.ast.int import Int @@ -232,3 +234,11 @@ def make(t: type[T]) -> T: A new instance of the given type class. """ return cast(T, type_spec_from_annotation(t).new_instance()) + + +def algosdk_from_type_spec(t: TypeSpec) -> algosdk.abi.ABIType: + return algosdk.abi.ABIType.from_string(str(t)) + + +def algosdk_from_annotation(t: type[T]) -> algosdk.abi.ABIType: + return algosdk_from_type_spec(type_spec_from_annotation(t)) diff --git a/pyteal/ast/abi/util_test.py b/pyteal/ast/abi/util_test.py index 36db60676..25ff3d631 100644 --- a/pyteal/ast/abi/util_test.py +++ b/pyteal/ast/abi/util_test.py @@ -2,6 +2,8 @@ from inspect import isabstract import pytest +import algosdk.abi + import pyteal as pt from pyteal import abi from pyteal.ast.abi.util import ( @@ -313,3 +315,176 @@ def test_make(): assert actual.type_spec() == expected_type_spec assert type(actual) is abi.Tuple + + +def test_abi_type_translation(): + test_cases = [ + # Test for byte/bool/address/strings + (algosdk.abi.ByteType(), "byte", abi.ByteTypeSpec(), abi.Byte), + (algosdk.abi.BoolType(), "bool", abi.BoolTypeSpec(), abi.Bool), + (algosdk.abi.AddressType(), "address", abi.AddressTypeSpec(), abi.Address), + (algosdk.abi.StringType(), "string", abi.StringTypeSpec(), abi.String), + # Test for dynamic array type + ( + algosdk.abi.ArrayDynamicType(algosdk.abi.UintType(32)), + "uint32[]", + abi.DynamicArrayTypeSpec(abi.Uint32TypeSpec()), + abi.DynamicArray[abi.Uint32], + ), + ( + algosdk.abi.ArrayDynamicType( + algosdk.abi.ArrayDynamicType(algosdk.abi.ByteType()) + ), + "byte[][]", + abi.DynamicArrayTypeSpec(abi.DynamicArrayTypeSpec(abi.ByteTypeSpec())), + abi.DynamicArray[abi.DynamicArray[abi.Byte]], + ), + # TODO: Turn these tests on when PyTeal supports ufixedx + # cf https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0004.md#types + # ( + # algosdk.abi.ArrayDynamicType(algosdk.abi.UfixedType(256, 64)), + # "ufixed256x64[]", + # abi.DynamicArrayTypeSpec(abi.UfixedTypeSpec(256, 64)), + # ), + # # Test for static array type + # ( + # algosdk.abi.ArrayStaticType(algosdk.abi.UfixedType(128, 10), 100), + # "ufixed128x10[100]", + # abi.ArrayStaticTypeSpec(abi.UfixedTypeSpec(128, 10), 100), + # ), + ( + algosdk.abi.ArrayStaticType( + algosdk.abi.ArrayStaticType(algosdk.abi.BoolType(), 256), + 100, + ), + "bool[256][100]", + abi.StaticArrayTypeSpec( + abi.StaticArrayTypeSpec(abi.BoolTypeSpec(), 256), + 100, + ), + abi.StaticArray[abi.StaticArray[abi.Bool, Literal[256]], Literal[100]], + ), + # Test for tuple + (algosdk.abi.TupleType([]), "()", abi.TupleTypeSpec(), abi.Tuple0), + ( + algosdk.abi.TupleType( + [ + algosdk.abi.UintType(16), + algosdk.abi.TupleType( + [ + algosdk.abi.ByteType(), + algosdk.abi.ArrayStaticType(algosdk.abi.AddressType(), 10), + ] + ), + ] + ), + "(uint16,(byte,address[10]))", + abi.TupleTypeSpec( + abi.Uint16TypeSpec(), + abi.TupleTypeSpec( + abi.ByteTypeSpec(), + abi.StaticArrayTypeSpec(abi.AddressTypeSpec(), 10), + ), + ), + abi.Tuple2[ + abi.Uint16, + abi.Tuple2[ + abi.Byte, + abi.StaticArray[abi.Address, Literal[10]], + ], + ], + ), + ( + algosdk.abi.TupleType( + [ + algosdk.abi.UintType(64), + algosdk.abi.TupleType( + [ + algosdk.abi.ByteType(), + algosdk.abi.ArrayStaticType(algosdk.abi.AddressType(), 10), + ] + ), + algosdk.abi.TupleType([]), + algosdk.abi.BoolType(), + ] + ), + "(uint64,(byte,address[10]),(),bool)", + abi.TupleTypeSpec( + abi.Uint64TypeSpec(), + abi.TupleTypeSpec( + abi.ByteTypeSpec(), + abi.StaticArrayTypeSpec(abi.AddressTypeSpec(), 10), + ), + abi.TupleTypeSpec(), + abi.BoolTypeSpec(), + ), + abi.Tuple4[ + abi.Uint64, + abi.Tuple2[ + abi.Byte, + abi.StaticArray[abi.Address, Literal[10]], + ], + abi.Tuple, + abi.Bool, + ], + ), + # TODO: Turn these tests on when PyTeal supports ufixedx + # cf https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0004.md#types + # ( + # algosdk.abi.TupleType( + # [ + # algosdk.abi.UfixedType(256, 16), + # algosdk.abi.TupleType( + # [ + # algosdk.abi.TupleType( + # [ + # algosdk.abi.StringType(), + # ] + # ), + # algosdk.abi.BoolType(), + # algosdk.abi.TupleType( + # [ + # algosdk.abi.AddressType(), + # algosdk.abi.UintType(8), + # ] + # ), + # ] + # ), + # ] + # ), + # "(ufixed256x16,((string),bool,(address,uint8)))", + # abi.TupleType( + # [ + # abi.UfixedType(256, 16), + # abi.TupleType( + # [ + # abi.TupleType( + # [ + # abi.StringType(), + # ] + # ), + # abi.BoolType(), + # abi.TupleType( + # [ + # abi.AddressType(), + # abi.UintType(8), + # ] + # ), + # ] + # ), + # ] + # ), + # ), + ] + + for algosdk_abi, abi_string, pyteal_abi_ts, pyteal_abi in test_cases: + print(f"({algosdk_abi}, {abi_string}, {pyteal_abi_ts}),") + assert str(algosdk_abi) == abi_string == str(pyteal_abi_ts) + assert ( + algosdk_abi + == algosdk.abi.ABIType.from_string(abi_string) + == algosdk.abi.ABIType.from_string(str(pyteal_abi_ts)) + ) + assert algosdk_abi == abi.algosdk_from_type_spec(pyteal_abi_ts) + assert pyteal_abi_ts == abi.type_spec_from_annotation(pyteal_abi) + assert algosdk_abi == abi.algosdk_from_annotation(pyteal_abi) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 3cec26e4f..49949b49e 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from inspect import isclass, Parameter, signature, get_annotations -from types import MappingProxyType -from typing import Callable, Optional, TYPE_CHECKING, cast, Any, Final +from types import MappingProxyType, NoneType +from typing import Any, Callable, Final, Optional, TYPE_CHECKING, cast from pyteal.ast import abi from pyteal.ast.expr import Expr @@ -66,7 +66,7 @@ def __init__( self.__name: str = name_str if name_str else self.implementation.__name__ def _validate( - self, input_types: list[TealType] = None + self, input_types: list[TealType | None] = None ) -> tuple[ MappingProxyType[str, Parameter], dict[str, type], @@ -77,6 +77,8 @@ def _validate( ]: """Validate the full function signature and annotations for subroutine definition. + NOTE: `self.implementation` should be set before calling `_validate()` + This function iterates through `sig.parameters.items()`, and checks each of subroutine arguments. On each of the subroutine arguments, the following checks are performed: - If argument is not POSITION_ONLY or not POSITIONAL_OR_KEYWORD, error @@ -95,9 +97,12 @@ def _validate( We put the scratch slot id on the stack, rather than the value itself. - `abi_args` - a set of argument names, which are type annotated by ABI types. We load the ABI scratch space stored value to stack, and store them later in subroutine's local ABI values. + - `abi_output_kwarg` - a possibly empty dict which when non-empty contains exactly one key + `ABIReturnSubroutine.OUTPUT_ARG_NAME` with a value that gives abi-tye information about the output Args: input_types (optional): for testing purposes - expected `TealType`s of each parameter + Returns: impl_params: a map from python function implementation's argument name, to argument's parameter. annotations: a dict whose keys are names of type-annotated arguments, @@ -124,18 +129,6 @@ def _validate( abi_args: dict[str, abi.TypeSpec] = {} abi_output_kwarg: dict[str, abi.TypeSpec] = {} - if input_types is not None: - if len(input_types) != len(impl_params): - raise TealInputError( - f"Provided number of input_types ({len(input_types)}) " - f"does not match detected number of parameters ({len(impl_params)})" - ) - for in_type, name in zip(input_types, impl_params): - if not isinstance(in_type, TealType): - raise TealInputError( - f"Function has input type {in_type} for parameter {name} which is not a TealType" - ) - if "return" in annotations and annotations["return"] is not Expr: raise TealInputError( f"Function has return of disallowed type {annotations['return']}. Only Expr is allowed" @@ -178,6 +171,24 @@ def _validate( if isinstance(expected_arg_type, abi.TypeSpec): abi_args[name] = expected_arg_type + if input_types is not None: + input_arg_count = len(impl_params) - len(abi_output_kwarg) + if len(input_types) != input_arg_count: + raise TealInputError( + f"Provided number of input_types ({len(input_types)}) " + f"does not match detected number of input parameters ({input_arg_count})" + ) + for in_type, name in zip(input_types, impl_params): + if not isinstance(in_type, (TealType, NoneType)): + raise TealInputError( + f"Function has input type {in_type} for parameter {name} which is not a TealType" + ) + if in_type is None and name not in abi_args: + raise TealInputError( + f"input_type for {name} is unspecified i.e. None " + f"but this is only allowed for ABI arguments" + ) + return ( impl_params, annotations, diff --git a/pyteal/ast/subroutine_test.py b/pyteal/ast/subroutine_test.py index 0a90f33ee..e01f2910a 100644 --- a/pyteal/ast/subroutine_test.py +++ b/pyteal/ast/subroutine_test.py @@ -129,6 +129,15 @@ def fn_2arg_1ret_with_expr( ) -> pt.Expr: return output.set(b[a % pt.Int(10)]) + @pt.ABIReturnSubroutine + def fn_w_tuple1arg( + a: pt.Expr, + b: pt.abi.Tuple1[pt.abi.Byte], + *, + output: pt.abi.Byte, + ) -> pt.Expr: + return output.set(pt.Int(1)) + cases = ( ABISubroutineTC(fn_0arg_0ret, [], "fn_0arg_0ret", "void"), ABISubroutineTC( @@ -171,6 +180,15 @@ def fn_2arg_1ret_with_expr( "fn_2arg_1ret_with_expr", pt.abi.ByteTypeSpec(), ), + ABISubroutineTC( + fn_w_tuple1arg, + [ + pt.Int(5), + pt.abi.make(pt.abi.Tuple1[pt.abi.Byte]), + ], + "fn_w_tuple1arg", + pt.abi.ByteTypeSpec(), + ), ) for case in cases: @@ -217,22 +235,6 @@ def mock_subroutine_definition(implementation, has_abi_output=False): # input_types: three_params = mock_subroutine_definition(lambda x, y, z: pt.Return(pt.Int(1))) - two_inputs = [pt.TealType.uint64, pt.TealType.bytes] - with pytest.raises(pt.TealInputError) as tie: - three_params._validate(input_types=two_inputs) - - assert tie.value == pt.TealInputError( - "Provided number of input_types (2) does not match detected number of parameters (3)" - ) - - three_inputs_with_a_wrong_type = [pt.TealType.uint64, pt.Expr, pt.TealType.bytes] - - with pytest.raises(pt.TealInputError) as tie: - three_params._validate(input_types=three_inputs_with_a_wrong_type) - - assert tie.value == pt.TealInputError( - "Function has input type for parameter y which is not a TealType" - ) params, anns, arg_types, byrefs, abi_args, output_kwarg = three_params._validate() assert len(params) == 3 @@ -311,15 +313,6 @@ def var_abi_output_impl(*, output: pt.abi.Uint16): "Function has a parameter with a default value, which is not allowed in a subroutine: x" ) - with pytest.raises(pt.TealInputError) as tie: - three_params._validate( - input_types=[pt.TealType.uint64, pt.Expr, pt.TealType.anytype] - ) - - assert tie.value == pt.TealInputError( - "Function has input type for parameter y which is not a TealType" - ) - # Now we get to _validate_annotation(): one_vanilla = mock_subroutine_definition(lambda x: pt.Return(pt.Int(1))) @@ -355,8 +348,6 @@ def one_scratchvar_impl(x: pt.ScratchVar): assert abi_args == {} assert output_kwarg == {} - # for _is_abi_annotation() cf. copacetic x,y,z product below - # not is_class() def one_nontype_impl(x: "blahBlah"): # type: ignore # noqa: F821 return pt.Return(pt.Int(1)) @@ -380,7 +371,57 @@ def one_dynscratchvar_impl(x: pt.DynamicScratchVar): "Function has parameter x of disallowed type . Only the types (, , 'ABI') are allowed" ) - # Now we're back to validate() and everything should be copacetic + # Now we're back to _validate() main body and looking at input_types + + three_params_with_output = mock_subroutine_definition( + lambda x, y, z, *, output: pt.Return(pt.Int(1)), has_abi_output=True + ) + four_inputs = [ + pt.TealType.uint64, + pt.TealType.uint64, + pt.TealType.bytes, + pt.TealType.uint64, + ] + + two_inputs = [pt.TealType.uint64, pt.TealType.bytes] + with pytest.raises(pt.TealInputError) as tie: + three_params._validate(input_types=two_inputs) + + assert tie.value == pt.TealInputError( + "Provided number of input_types (2) does not match detected number of input parameters (3)" + ) + + three_inputs_with_a_wrong_type = [pt.TealType.uint64, pt.Expr, pt.TealType.bytes] + + with pytest.raises(pt.TealInputError) as tie: + three_params._validate(input_types=three_inputs_with_a_wrong_type) + + assert tie.value == pt.TealInputError( + "Function has input type for parameter y which is not a TealType" + ) + + with pytest.raises(pt.TealInputError) as tie: + three_params._validate( + input_types=[pt.TealType.uint64, pt.Expr, pt.TealType.anytype] + ) + + assert tie.value == pt.TealInputError( + "Function has input type for parameter y which is not a TealType" + ) + + with pytest.raises(pt.TealInputError) as tie: + three_params._validate( + input_types=[pt.TealType.uint64, None, pt.TealType.anytype] + ) + assert tie.value == pt.TealInputError( + "input_type for y is unspecified i.e. None but this is only allowed for ABI arguments" + ) + + # this one gets caught inside of _validate_annotation() + with pytest.raises(pt.TealInputError) as tie: + three_params_with_output._validate(input_types=four_inputs) + + # everything should be copacetic for x, y, z in product(pt.TealType, pt.TealType, pt.TealType): ( params, diff --git a/requirements.txt b/requirements.txt index 8735bd72e..5238ceca9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==4.0.1 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/algorand/graviton@v0.1.0 +graviton@git+https://github.com/algorand/graviton@v0.3.0 mypy==0.950 pytest==7.1.1 pytest-cov==3.0.0 diff --git a/tests/abi_roundtrip.py b/tests/abi_roundtrip.py new file mode 100644 index 000000000..6c6a3bf69 --- /dev/null +++ b/tests/abi_roundtrip.py @@ -0,0 +1,132 @@ +from typing import Generic, TypeVar + +import pyteal as pt +from pyteal import abi + +from tests.blackbox import Blackbox, BlackboxWrapper, PyTealDryRunExecutor + +T = TypeVar("T", bound=abi.BaseType) + +DEFAULT_DYNAMIC_ARRAY_LENGTH = 3 + + +class ABIRoundtrip(Generic[T]): + def __init__( + self, + annotation_instance: abi.BaseType, + length: int | None = None, + ): + self.instance: abi.BaseType = annotation_instance + self.type_spec: abi.TypeSpec = annotation_instance.type_spec() + self.annotation: type[abi.BaseType] = self.type_spec.annotation_type() + + self.length: int | None = length + + def pytealer(self) -> PyTealDryRunExecutor: + roundtrip = self.roundtrip_factory() + return PyTealDryRunExecutor(roundtrip, pt.Mode.Application) + + def roundtrip_factory(self) -> BlackboxWrapper: + comp = self.mutator_factory() + + ann_out = abi.Tuple3[self.annotation, self.annotation, self.annotation] # type: ignore[misc,name-defined] + + @Blackbox(input_types=[None]) + @pt.ABIReturnSubroutine + def round_tripper(x: self.annotation, *, output: ann_out): # type: ignore[name-defined] + y = abi.make(self.annotation) + z = abi.make(self.annotation) + return pt.Seq(y.set(comp(x)), z.set(comp(y)), output.set(x, y, z)) # type: ignore[attr-defined] + + return round_tripper + + def mutator_factory(self) -> pt.ABIReturnSubroutine: + if isinstance(self.type_spec, abi.BoolTypeSpec): + return self.bool_comp_factory() + if isinstance(self.type_spec, abi.UintTypeSpec): + return self.numerical_comp_factory() + if isinstance(self.type_spec, abi.StringTypeSpec): + return self.string_reverse_factory() + if isinstance(self.type_spec, abi.TupleTypeSpec): + return self.tuple_comp_factory() + if isinstance(self.type_spec, abi.ArrayTypeSpec): + return self.array_comp_factory() + + raise ValueError(f"uh-oh!!! didn't handle type {self.instance}") + + def bool_comp_factory(self) -> pt.ABIReturnSubroutine: + @pt.ABIReturnSubroutine + def bool_comp(x: abi.Bool, *, output: abi.Bool): + return output.set(pt.Not(x.get())) + + return bool_comp + + @classmethod + def max_int(cls, bit_size): + return (1 << bit_size) - 1 + + def numerical_comp_factory(self) -> pt.ABIReturnSubroutine: + @pt.ABIReturnSubroutine + def numerical_comp(x: self.annotation, *, output: self.annotation): # type: ignore[name-defined] + max_uint = pt.Int(self.max_int(self.type_spec.bit_size())) # type: ignore[attr-defined] + return output.set(max_uint - x.get()) + + return numerical_comp + + def string_reverse_factory(self) -> pt.ABIReturnSubroutine: + """ + Assume strings are python utf-8 compliant and therefore each byte value is at most 127 + """ + if self.length is None: + self.length = DEFAULT_DYNAMIC_ARRAY_LENGTH + + char_type_spec = abi.ByteTypeSpec() + + @pt.ABIReturnSubroutine + def string_reverse(x: self.annotation, *, output: self.annotation): # type: ignore[name-defined] + insts = [char_type_spec.new_instance() for _ in range(self.length)] # type: ignore[arg-type] + setters = [inst.set(x[i]) for i, inst in enumerate(reversed(insts))] + return pt.Seq(*(setters + [output.set(insts)])) + + return string_reverse + + def tuple_comp_factory(self) -> pt.ABIReturnSubroutine: # type: ignore[name-defined] + value_type_specs: list[abi.TypeSpec] = self.type_spec.value_type_specs() # type: ignore[attr-defined] + insts = [vts.new_instance() for vts in value_type_specs] + roundtrips: list[ABIRoundtrip[T]] = [ + ABIRoundtrip(inst, length=None) for inst in insts # type: ignore[arg-type] + ] + + @pt.ABIReturnSubroutine + def tuple_complement(x: self.annotation, *, output: self.annotation): # type: ignore[name-defined] + setters = [inst.set(x[i]) for i, inst in enumerate(insts)] # type: ignore[attr-defined] + comp_funcs = [rtrip.mutator_factory() for rtrip in roundtrips] + compers = [inst.set(comp_funcs[i](inst)) for i, inst in enumerate(insts)] # type: ignore[attr-defined] + return pt.Seq(*(setters + compers + [output.set(*insts)])) + + return tuple_complement + + def array_comp_factory(self) -> pt.ABIReturnSubroutine: + """ + When the length has not been provided for a dynamic array, + default to DEFAULT_DYNAMIC_ARRAY_LENGTH + """ + if self.length is not None: + assert self.type_spec.is_length_dynamic() # type: ignore[attr-defined] + elif not self.type_spec.is_length_dynamic(): # type: ignore[attr-defined] + self.length = self.type_spec.length_static() # type: ignore[attr-defined] + else: + self.length = DEFAULT_DYNAMIC_ARRAY_LENGTH + + internal_type_spec = self.type_spec.value_type_spec() # type: ignore[attr-defined] + internal_ann_inst = internal_type_spec.new_instance() + comp_func = ABIRoundtrip(internal_ann_inst, length=None).mutator_factory() + + @pt.ABIReturnSubroutine + def array_complement(x: self.annotation, *, output: self.annotation): # type: ignore[name-defined] + insts = [internal_type_spec.new_instance() for _ in range(self.length)] # type: ignore[arg-type] + setters = [inst.set(x[i]) for i, inst in enumerate(insts)] + compers = [inst.set(comp_func(inst)) for inst in insts] + return pt.Seq(*(setters + compers + [output.set(insts)])) + + return array_complement diff --git a/tests/blackbox.py b/tests/blackbox.py index 81bca9f69..73be9bc44 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -1,19 +1,27 @@ -from typing import Callable +from typing import Callable, Generic, Sequence, TypeVar, cast +from dataclasses import dataclass +import algosdk.abi from algosdk.v2client import algod from graviton import blackbox +from graviton.blackbox import DryRunInspector, DryRunExecutor + +from pyteal.ast.subroutine import OutputKwArgInfo from pyteal import ( + abi, Arg, Btoi, Bytes, + compileTeal, Expr, Int, Itob, Len, Log, Mode, + Pop, ScratchVar, Seq, SubroutineFnWrapper, @@ -21,6 +29,8 @@ Txn, ) +from pyteal.ast.subroutine import ABIReturnSubroutine + # ---- Clients ---- # @@ -41,20 +51,81 @@ def _algod_client( class BlackboxWrapper: - def __init__(self, subr: SubroutineFnWrapper, input_types: list[TealType]): + def __init__( + self, + subr: SubroutineFnWrapper | ABIReturnSubroutine, + input_types: list[TealType | None], + ): subr.subroutine._validate(input_types=input_types) - self.subroutine = subr - self.input_types = input_types + self.subroutine: SubroutineFnWrapper | ABIReturnSubroutine = subr + self.input_types: list[TealType | abi.TypeSpec | None] = self._fill(input_types) - def __call__(self, *args: Expr | ScratchVar, **kwargs) -> Expr: + def __call__(self, *args: Expr | ScratchVar, **kwargs) -> Expr | abi.ReturnedValue: return self.subroutine(*args, **kwargs) def name(self) -> str: return self.subroutine.name() + def _fill( + self, input_types: list[TealType | None] + ) -> list[TealType | abi.TypeSpec | None]: + match self.subroutine: + case SubroutineFnWrapper(): + return cast(list[TealType | abi.TypeSpec | None], input_types) + case ABIReturnSubroutine(): + args = self.subroutine.subroutine.arguments() + abis = self.subroutine.subroutine.abi_args + return [(x if x else abis[args[i]]) for i, x in enumerate(input_types)] + case _: + raise AssertionError( + f"Cannot handle subroutine of type {type(self.subroutine)}" + ) + + +def Blackbox(input_types: list[TealType | None]): + """ + Decorator for transforming @Subroutine and @ABIReturnSubroutine wrapped functions + into PyTeal expressions that compile into executable Teal programs. + + input_types: list[TealType] (required) + List shadowing the input arguments of the decorated subroutine. In particular: + * the list needs to be the same length as the number of subroutine arguments + * if the subroutine argument is an ABI type, the shadowing input_type must be None + as it will be determined at compile time from the subroutine's annotation + * if the subroutine argument is an Expr or a ScratchVar, the shadowing input_type + must be a TealType of the same kind as expected in the argument + + Some _Correct_ Examples: + + @Blackbox(input_types=[TealType.bytes, TealType.uint64]) + @Subroutine(TealType.bytes) + def string_mult(x, y): + ... + + @Blackbox(input_types=[TealType.bytes, TealType.uint64]) + @Subroutine(TealType.bytes) + def string_mult(x: Expr, y: Expr): + ... + + @Blackbox(input_types=[TealType.bytes, TealType.uint64]) + @Subroutine(TealType.bytes) + def string_mult(x: ScratchVar, y: Expr): + ... + + + @Blackbox(input_types=[None, None]) + @ABIReturnSubroutine + def string_mult(x: abi.String, y: abi.Uint16): + ... + + @Blackbox(input_types=[None, TealType.uint64]) + @ABIReturnSubroutine + def string_mult(x: abi.String, y): + ... -def Blackbox(input_types: list[TealType]): - def decorator_blackbox(func: SubroutineFnWrapper): + """ + + def decorator_blackbox(func: SubroutineFnWrapper | ABIReturnSubroutine): return BlackboxWrapper(func, input_types) return decorator_blackbox @@ -63,139 +134,328 @@ def decorator_blackbox(func: SubroutineFnWrapper): # ---- API ---- # -def mode_to_execution_mode(mode: Mode) -> blackbox.ExecutionMode: - if mode == Mode.Application: - return blackbox.ExecutionMode.Application - if mode == Mode.Signature: - return blackbox.ExecutionMode.Signature - - raise Exception(f"Unknown mode {mode} of type {type(mode)}") - - -def blackbox_pyteal(subr: BlackboxWrapper, mode: Mode) -> Callable[..., Expr]: - """Functor producing ready-to-compile PyTeal programs from annotated subroutines - - Args: - subr: annotated subroutine to wrap inside program. - Note: the `input_types` parameters should be supplied to @Subroutine() annotation - mode: type of program to produce: logic sig (Mode.Signature) or app (Mode.Application) - - Returns: - a function that called with no parameters -e.g. result()- - returns a PyTeal expression compiling to a ready-to-test TEAL program. - - The return type is callable in order to adhere to the API of blackbox tests. - - Generated TEAL code depends on the mode, subroutine input types, and subroutine output types. - * logic sigs: - * input received via `arg i` - * args are converted (cf. "input conversion" below) and passed to the subroutine - * subroutine output is not logged (log is not available) - * subroutine output is converted (cf "output conversion" below) - * apps: - * input received via `txna ApplicationArgs i` - * args are converted (cf. "input conversion" below) and passed to the subroutine - * subroutine output is logged after possible conversion (cf. "logging conversion") - * subroutine output is converted (cf "output conversion" below) - * input conversion: - * Empty input array: - do not read any args and call subroutine immediately - * arg of TealType.bytes and TealType.anytype: - read arg and pass to subroutine as is - * arg of TealType.uint64: - convert arg to int using Btoi() when received - * pass-by-ref ScratchVar arguments: - in addition to the above - - o store the arg (or converted arg) in a ScratchVar - o invoke the subroutine using this ScratchVar instead of the arg (or converted arg) - * output conversion: - * TealType.uint64: - provide subroutine's result to the top of the stack when exiting program - * TealType.bytes: - convert subroutine's result to the top of the stack to its length and then exit - * TealType.none or TealType.anytype: - push Int(1337) to the stack as it is either impossible (TealType.none), - or unknown at compile time (TealType.anytype) to convert to an Int - * logging conversion: - * TealType.uint64: - convert subroutine's output using Itob() and log the result - * TealType.bytes: - log the subroutine's result - * TealType.none or TealType.anytype: - log Itob(Int(1337)) as it is either impossible (TealType.none), - or unknown at compile time (TealType.anytype) how to convert to Bytes - - For illustrative examples of how to use this function please refer to the integration test file `graviton_test.py` and especially: - - * `blackbox_pyteal_example1()`: Using blackbox_pyteal() for a simple test of both an app and logic sig - * `blackbox_pyteal_example2()`: Using blackbox_pyteal() to make 400 assertions and generate a CSV report with 400 dryrun rows - * `blackbox_pyteal_example3()`: declarative Test Driven Development approach through Invariant's - """ - input_types = subr.input_types - assert ( - input_types is not None - ), "please provide input_types in your @Subroutine annotation (crucial for generating proper end-to-end testable PyTeal)" - - subdef = subr.subroutine.subroutine - arg_names = subdef.arguments() - - def arg_prep_n_call(i, p): - name = arg_names[i] - by_ref = name in subdef.by_ref_args - arg_expr = Txn.application_args[i] if mode == Mode.Application else Arg(i) - if p == TealType.uint64: - arg_expr = Btoi(arg_expr) - prep = None - arg_var = arg_expr - if by_ref: - arg_var = ScratchVar(p) - prep = arg_var.store(arg_expr) - return prep, arg_var - - def subr_caller(): - preps_n_calls = [*(arg_prep_n_call(i, p) for i, p in enumerate(input_types))] - preps, calls = zip(*preps_n_calls) if preps_n_calls else ([], []) - preps = [p for p in preps if p] - invocation = subr(*calls) - if preps: - return Seq(*(preps + [invocation])) - return invocation - - def make_return(e): - if e.type_of() == TealType.uint64: - return e - if e.type_of() == TealType.bytes: - return Len(e) - if e.type_of() == TealType.anytype: - x = ScratchVar(TealType.anytype) - return Seq(x.store(e), Int(1337)) - # TealType.none: - return Seq(e, Int(1337)) - - def make_log(e): - if e.type_of() == TealType.uint64: - return Log(Itob(e)) - if e.type_of() == TealType.bytes: - return Log(e) - return Log(Bytes("nada")) - - if mode == Mode.Signature: +Output = TypeVar("Output") +Lazy = Callable[[], Output] - def approval(): - return make_return(subr_caller()) - else: +@dataclass(frozen=True) +class _MatchMode(Generic[Output]): + app_case: Lazy + signature_case: Lazy + + def __call__(self, mode: Mode, *args, **kwargs) -> Output: + match mode: + case Mode.Application: + return self.app_case() + case Mode.Signature: + return self.signature_case() + case _: + raise Exception(f"Unknown mode {mode} of type {type(mode)}") - def approval(): - if subdef.return_type == TealType.none: - result = ScratchVar(TealType.uint64) - part1 = [subr_caller(), result.store(Int(1337))] - else: - result = ScratchVar(subdef.return_type) - part1 = [result.store(subr_caller())] - part2 = [make_log(result.load()), make_return(result.load())] - return Seq(*(part1 + part2)) +def mode_to_execution_mode(mode: Mode) -> blackbox.ExecutionMode: + return _MatchMode( + app_case=lambda: blackbox.ExecutionMode.Application, + signature_case=lambda: blackbox.ExecutionMode.Signature, + )(mode) + + +class PyTealDryRunExecutor: + def __init__(self, subr: BlackboxWrapper, mode: Mode): + """ + Args: + subr: a Subroutine or ABIReturnSubroutine which has been decorated with @Blackbox. + Note: the `input_types` parameters should be supplied to the @Blackbox() decorator + cf. the Blackbox class for futher details about acceptable `input_types` + + mode: type of program to produce: logic sig (Mode.Signature) or app (Mode.Application) + """ + input_types = subr.input_types + assert ( + input_types is not None + ), "please provide input_types in your @Subroutine or @ABIReturnSubroutine annotation (this is crucial for generating proper end-to-end testable PyTeal)" + + self.subr, self.mode, self.input_types = subr, mode, input_types + match subr.subroutine: + case SubroutineFnWrapper(): + approval = self._handle_SubroutineFnWrapper() + case ABIReturnSubroutine(): + approval = self._handle_ABIReturnSubroutine() + case _: + raise AssertionError( + f"Cannot produce Blackbox pyteal for provided subroutine of type {type(subr.subroutine)}" + ) + + self._pyteal_lambda: Callable[..., Expr] = approval + + def is_abi(self) -> bool: + return isinstance(self.subr.subroutine, ABIReturnSubroutine) + + def abi_argument_types(self) -> None | list[algosdk.abi.ABIType]: + if not self.is_abi(): + return None + + def handle_arg(arg): + if isinstance(arg, abi.TypeSpec): + return abi.algosdk_from_type_spec(arg) + return None + + return [handle_arg(arg) for arg in self.input_types] + + def abi_return_type(self) -> None | algosdk.abi.ABIType: + if not self.is_abi(): + return None + + out_info = getattr(self.subr.subroutine, "output_kwarg_info") + if not out_info: + return None + + return abi.algosdk_from_type_spec(cast(OutputKwArgInfo, out_info).abi_type) + + def program(self) -> Expr: + """Get ready-to-compile PyTeal program from Subroutines and ABIReturnSubroutines + + Returns: + a PyTeal expression representing a ready-to-run TEAL program + + Generated TEAL code depends on the self.subr's type, the mode, the input types, and output type + * logic sigs: + * input received via `arg i` + * args are converted (cf. "input conversion" below) and passed to the subroutine + * subroutine output is not logged (log is not available) + * in the case of ABIReturnSubroutine: the output is encoded on to the stack an then popped off + * subroutine output is converted (cf "output conversion" below) + * apps: + * input received via `txna ApplicationArgs i` + * args are converted (cf. "input conversion" below) and passed to the subroutine + * the output is logged in the following ways: + * Subroutine: logged after possible conversion (cf. "logging conversion") + * ABIReturnSubroutine: the encoded output is concatenated to the return method selector and then logged + * subroutine output is converted (cf "output conversion" below) (Subroutine case only) + * input conversion: + * Empty input array: + do not read any args and call subroutine immediately + * Expr arg of TealType.bytes and TealType.anytype: + read arg and pass to subroutine as is + * Expr arg of TealType.uint64: + convert arg to int using Btoi() when received + * pass-by-ref ScratchVar arguments (Subroutine case only): + in addition to the above - + o store the arg (or converted arg) in a ScratchVar + o invoke the subroutine using this ScratchVar instead of the arg (or converted arg) + * ABI arguments (ABIReturnSubroutine case only): + in addition to the above - + o store the decoded arg into the ScratchVar of an ABI Type instance + o invoke the subroutine using this ABI Type instead of the arg + * output conversion: + * Subroutine case: + * TealType.uint64: + provide subroutine's result to the top of the stack when exiting program + * TealType.bytes: + convert subroutine's result to the top of the stack to its length and then exit + * TealType.none or TealType.anytype: + push Int(1337) to the stack as it is either impossible (TealType.none), + or unknown at compile time (TealType.anytype) to convert to an Int + * ABIReturnSubroutine case: + * when present, the output is encoded as TealType.bytes which can be decoded by the receiver using + appropriate ABI-libraries + * logging conversion: + * Subroutine case: + * TealType.uint64: + convert subroutine's output using Itob() and log the result + * TealType.bytes: + log the subroutine's result + * TealType.none or TealType.anytype: + log Itob(Int(1337)) as it is either impossible (TealType.none), + or unknown at compile time (TealType.anytype) how to convert to Bytes + * ABIReturnSubroutine case: + * when present, the output is encoded as TealType.bytes and concatenated to the rewturn + method selector. This can be decoded by the receiver using appropriate ABI-libraries + + For illustrative examples of how to use this method please refer to the integration test file `graviton_test.py` and especially: + + * `blackbox_pyteal_example1()`: Using blackbox_pyteal() for a simple test of both an app and logic sig + * `blackbox_pyteal_example2()`: Using blackbox_pyteal() to make 400 assertions and generate a CSV report with 400 dryrun rows + * `blackbox_pyteal_example3()`: declarative Test Driven Development approach through Invariant's + * `blackbox_pyteal_example4()`: Using PyTealDryRunExecutor to debug an ABIReturnSubroutine with an app, logic sig and csv reports + """ + + return self._pyteal_lambda() + + def _handle_SubroutineFnWrapper(self): + subdef = self.subr.subroutine.subroutine + arg_names = subdef.arguments() + + def arg_prep_n_call(i, p): + name = arg_names[i] + by_ref = name in subdef.by_ref_args + arg_expr = ( + Txn.application_args[i] if self.mode == Mode.Application else Arg(i) + ) + if p == TealType.uint64: + arg_expr = Btoi(arg_expr) + prep = None + arg_var = arg_expr + if by_ref: + arg_var = ScratchVar(p) + prep = arg_var.store(arg_expr) + return prep, arg_var + + def subr_caller(): + preps_n_calls = [ + *(arg_prep_n_call(i, p) for i, p in enumerate(self.input_types)) + ] + preps, calls = zip(*preps_n_calls) if preps_n_calls else ([], []) + preps = [p for p in preps if p] + invocation = self.subr(*calls) + if preps: + return Seq(*(preps + [invocation])) + return invocation + + def make_return(e): + if e.type_of() == TealType.uint64: + return e + if e.type_of() == TealType.bytes: + return Len(e) + if e.type_of() == TealType.anytype: + x = ScratchVar(TealType.anytype) + return Seq(x.store(e), Int(1337)) + # TealType.none: + return Seq(e, Int(1337)) + + def make_log(e): + if e.type_of() == TealType.uint64: + return Log(Itob(e)) + if e.type_of() == TealType.bytes: + return Log(e) + return Log(Bytes("nada")) + + if self.mode == Mode.Signature: + + def approval(): + return make_return(subr_caller()) + + else: + + def approval(): + if subdef.return_type == TealType.none: + result = ScratchVar(TealType.uint64) + part1 = [subr_caller(), result.store(Int(1337))] + else: + result = ScratchVar(subdef.return_type) + part1 = [result.store(subr_caller())] + + part2 = [make_log(result.load()), make_return(result.load())] + return Seq(*(part1 + part2)) + + return approval + + def _handle_ABIReturnSubroutine(self): + subdef = self.subr.subroutine.subroutine + arg_names = subdef.arguments() + + def arg_prep_n_call(i, p): + name = arg_names[i] + arg_expr = ( + Txn.application_args[i] if self.mode == Mode.Application else Arg(i) + ) + if p == TealType.uint64: + arg_expr = Btoi(arg_expr) + prep = None + arg_var = arg_expr + if name in subdef.by_ref_args: + arg_var = ScratchVar(p) + prep = arg_var.store(arg_expr) + elif name in subdef.abi_args: + arg_var = p.new_instance() + prep = arg_var.decode(arg_expr) + return prep, arg_var + + output = None + if self.subr.subroutine.output_kwarg_info: + output = self.subr.subroutine.output_kwarg_info.abi_type.new_instance() - setattr(approval, "__name__", f"sem_{mode}_{subr.name()}") - return approval + def approval(): + preps_n_calls = [ + *(arg_prep_n_call(i, p) for i, p in enumerate(self.input_types)) + ] + preps, calls = zip(*preps_n_calls) if preps_n_calls else ([], []) + preps = [p for p in preps if p] + + # when @ABIReturnSubroutine is void: + # invocation is an Expr of TealType.none + # otherwise: + # it is a ComputedValue + invocation = self.subr(*calls) + if output: + invocation = output.set(invocation) + if self.mode == Mode.Signature: + results = [invocation, Pop(output.encode()), Int(1)] + else: + results = [invocation, abi.MethodReturn(output), Int(1)] + else: + results = [invocation, Int(1)] + + return Seq(*(preps + results)) + + return approval + + def compile(self, version: int, assemble_constants: bool = False) -> str: + return _MatchMode( + app_case=lambda: compileTeal( + self.program(), + self.mode, + version=version, + assembleConstants=assemble_constants, + ), + signature_case=lambda: compileTeal( + self.program(), + self.mode, + version=version, + assembleConstants=assemble_constants, + ), + )(self.mode) + + def dryrun_on_sequence( + self, + inputs: list[Sequence[str | int]], + compiler_version=6, + ) -> list[DryRunInspector]: + return _MatchMode( + app_case=lambda: DryRunExecutor.dryrun_app_on_sequence( + algod_with_assertion(), + self.compile(compiler_version), + inputs, + self.abi_argument_types(), + self.abi_return_type(), + ), + signature_case=lambda: DryRunExecutor.dryrun_logicsig_on_sequence( + algod_with_assertion(), + self.compile(compiler_version), + inputs, + self.abi_argument_types(), + self.abi_return_type(), + ), + )(self.mode) + + def dryrun( + self, + args: Sequence[bytes | str | int], + compiler_version=6, + ) -> DryRunInspector: + return _MatchMode( + app_case=lambda: DryRunExecutor.dryrun_app( + algod_with_assertion(), + self.compile(compiler_version), + args, + self.abi_argument_types(), + self.abi_return_type(), + ), + signature_case=lambda: DryRunExecutor.dryrun_logicsig( + algod_with_assertion(), + self.compile(compiler_version), + args, + self.abi_argument_types(), + self.abi_return_type(), + ), + )(self.mode) diff --git a/tests/integration/abi_roundtrip_test.py b/tests/integration/abi_roundtrip_test.py new file mode 100644 index 000000000..2350f56c0 --- /dev/null +++ b/tests/integration/abi_roundtrip_test.py @@ -0,0 +1,197 @@ +from pathlib import Path +import pytest +from typing import Literal + +import algosdk.abi + +from graviton.abi_strategy import ABIStrategy + +from pyteal import abi + +from tests.abi_roundtrip import ABIRoundtrip +from tests.compile_asserts import assert_teal_as_expected + +PATH = Path.cwd() / "tests" / "integration" +FIXTURES = PATH / "teal" +GENERATED = PATH / "generated" +ABI_TYPES = [ + abi.Address, + abi.Bool, + abi.Byte, + (abi.String, 0), + (abi.String, 1), + (abi.String, 13), + abi.Uint8, + abi.Uint16, + abi.Uint32, + abi.Uint64, + abi.Tuple0, + abi.Tuple1[abi.Bool], + abi.Tuple1[abi.Byte], + abi.Tuple1[abi.Uint8], + abi.Tuple1[abi.Uint16], + abi.Tuple1[abi.Uint32], + abi.Tuple1[abi.Uint64], + abi.Tuple3[abi.Bool, abi.Uint64, abi.Uint32], + abi.Tuple3[abi.Byte, abi.Bool, abi.Uint64], + abi.Tuple3[abi.Uint8, abi.Byte, abi.Bool], + abi.Tuple3[abi.Uint16, abi.Uint8, abi.Byte], + abi.Tuple3[abi.Uint32, abi.Uint16, abi.Uint8], + abi.Tuple3[abi.Uint64, abi.Uint32, abi.Uint16], + abi.StaticArray[abi.Bool, Literal[1]], + abi.StaticArray[abi.Bool, Literal[42]], + abi.StaticArray[abi.Uint64, Literal[1]], + abi.StaticArray[abi.Uint64, Literal[42]], + (abi.DynamicArray[abi.Bool], 0), + (abi.DynamicArray[abi.Bool], 1), + (abi.DynamicArray[abi.Bool], 42), + (abi.DynamicArray[abi.Uint64], 0), + (abi.DynamicArray[abi.Uint64], 1), + (abi.DynamicArray[abi.Uint64], 42), + (abi.DynamicArray[abi.Address], 10), + (abi.DynamicArray[abi.StaticArray[abi.Bool, Literal[3]]], 11), + abi.StaticArray[abi.Tuple1[abi.Bool], Literal[10]], + ( + abi.DynamicArray[ + abi.Tuple4[ + abi.StaticArray[abi.Byte, Literal[4]], + abi.Tuple2[abi.Bool, abi.Bool], + abi.Uint64, + abi.Address, + ] + ], + 7, + ), + ( + abi.DynamicArray[ + abi.Tuple5[ + abi.Bool, + abi.Byte, + abi.Address, + abi.String, + abi.Tuple4[ + abi.Address, + abi.StaticArray[ + abi.Tuple5[ + abi.Uint32, + abi.DynamicArray[abi.String], + abi.StaticArray[abi.Bool, Literal[2]], + abi.Tuple1[abi.Byte], + abi.Uint8, + ], + Literal[2], + ], + abi.String, + abi.DynamicArray[abi.Bool], + ], + ] + ], + 2, + ), +] + + +def roundtrip_setup(abi_type): + dynamic_length = None + if isinstance(abi_type, tuple): + abi_type, dynamic_length = abi_type + + return ( + abi_type, + dynamic_length, + ABIRoundtrip(abi.make(abi_type), length=dynamic_length).pytealer(), + ) + + +@pytest.mark.parametrize("abi_type", ABI_TYPES) +def test_pure_compilation(abi_type): + print(f"Pure Compilation Test for {abi_type=}") + abi_type, dynamic_length, roundtripper = roundtrip_setup(abi_type) + + sdk_abi_type = abi.algosdk_from_annotation(abi_type) + + abi_arg_types = roundtripper.abi_argument_types() + abi_ret_type = roundtripper.abi_return_type() + assert [sdk_abi_type] == abi_arg_types + assert algosdk.abi.TupleType([sdk_abi_type] * 3) == abi_ret_type + + teal = roundtripper.compile(version=6) + + filename = ( + f"app_roundtrip_{sdk_abi_type}" + + ("" if dynamic_length is None else f"_<{dynamic_length}>") + + ".teal" + ) + tealdir = GENERATED / "roundtrip" + tealdir.mkdir(parents=True, exist_ok=True) + + save_to = tealdir / filename + with open(save_to, "w") as f: + f.write(teal) + + assert_teal_as_expected(save_to, FIXTURES / "roundtrip" / filename) + + +GAI_ISSUE_2050 = "https://github.com/algorand/go-algorand-internal/issues/2050" + +BAD_TEALS = { + "()": GAI_ISSUE_2050, +} + + +@pytest.mark.parametrize("abi_type", ABI_TYPES) +def test_roundtrip(abi_type): + print(f"Round Trip Test for {abi_type=}") + + _, dynamic_length, roundtripper = roundtrip_setup(abi_type) + + sdk_abi_types = roundtripper.abi_argument_types() + sdk_ret_type = roundtripper.abi_return_type() + + sdk_abi_str = str(sdk_abi_types[0]) + if sdk_abi_str in BAD_TEALS: + print( + f"Skipping encoding roundtrip test of '{sdk_abi_str}' because of {BAD_TEALS[sdk_abi_str]}" + ) + return + + abi_strat = ABIStrategy(sdk_abi_types[0], dynamic_length=dynamic_length) + rand_abi_instance = abi_strat.get_random() + args = (rand_abi_instance,) + inspector = roundtripper.dryrun(args) + + cost = inspector.cost() + passed = inspector.passed() + original, mut, mut_mut = inspector.last_log() + + print( + f""" +{abi_type=} +{sdk_abi_str=} +{dynamic_length=} +{sdk_abi_types=} +{sdk_ret_type=} +{rand_abi_instance=} +{cost=} +{original=} +{mut=} +{mut_mut=} +""" + ) + + last_rows = 2 + + assert passed == (cost <= 700), inspector.report( + args, f"passed={passed} contradicted cost={cost}", last_rows=last_rows + ) + assert rand_abi_instance == original, inspector.report( + args, "rand_abi_instance v. original", last_rows=last_rows + ) + assert original == mut_mut, inspector.report( + args, "orginal v. mut_mut", last_rows=last_rows + ) + + expected_mut = abi_strat.mutate_for_roundtrip(rand_abi_instance) + assert expected_mut == mut, inspector.report( + args, "expected_mut v. mut", last_rows=last_rows + ) diff --git a/tests/integration/ecdsa_test.py b/tests/integration/ecdsa_test.py index 9bdeaeae6..4efceccb7 100644 --- a/tests/integration/ecdsa_test.py +++ b/tests/integration/ecdsa_test.py @@ -1,5 +1,3 @@ -from graviton.blackbox import DryRunExecutor - from pyteal import ( Bytes, EcdsaCurve, @@ -10,15 +8,13 @@ And, Subroutine, Sha512_256, - compileTeal, Mode, TealType, ) from tests.blackbox import ( Blackbox, - algod_with_assertion, - blackbox_pyteal, + PyTealDryRunExecutor, ) @@ -49,11 +45,10 @@ def verify(): ), ) - approval_app = blackbox_pyteal(verify, Mode.Application) - app_teal = compileTeal(approval_app(), Mode.Application, version=5) args = [] - algod = algod_with_assertion() - app_result = DryRunExecutor.dryrun_app(algod, app_teal, args) + app_result = PyTealDryRunExecutor(verify, Mode.Application).dryrun( + args, compiler_version=5 + ) assert app_result.stack_top() == 1, app_result.report( args, "stack_top() is not equal to 1, indicating ecdsa verification failed." @@ -85,11 +80,10 @@ def verify_fail(): ), ) - approval_app = blackbox_pyteal(verify_fail, Mode.Application) - app_teal = compileTeal(approval_app(), Mode.Application, version=5) args = [] - algod = algod_with_assertion() - app_result = DryRunExecutor.dryrun_app(algod, app_teal, args) + app_result = PyTealDryRunExecutor(verify_fail, Mode.Application).dryrun( + args, compiler_version=5 + ) assert app_result.stack_top() == 0, app_result.report( args, @@ -122,11 +116,10 @@ def decompress(): ) ) - approval_app = blackbox_pyteal(decompress, Mode.Application) - app_teal = compileTeal(approval_app(), Mode.Application, version=5) args = [] - algod = algod_with_assertion() - app_result = DryRunExecutor.dryrun_app(algod, app_teal, args) + app_result = PyTealDryRunExecutor(decompress, Mode.Application).dryrun( + args, compiler_version=5 + ) assert app_result.stack_top() == 1, app_result.report( args, "stack_top() is not equal to 1, indicating ecdsa verification failed." @@ -164,11 +157,10 @@ def recover(): ) ) - approval_app = blackbox_pyteal(recover, Mode.Application) - app_teal = compileTeal(approval_app(), Mode.Application, version=5) args = [] - algod = algod_with_assertion() - app_result = DryRunExecutor.dryrun_app(algod, app_teal, args) + app_result = PyTealDryRunExecutor(recover, Mode.Application).dryrun( + args, compiler_version=5 + ) assert app_result.stack_top() == 1, app_result.report( args, "stack_top() is not equal to 1, indicating ecdsa verification failed." diff --git a/tests/integration/graviton_abi_test.py b/tests/integration/graviton_abi_test.py new file mode 100644 index 000000000..2f6acaa12 --- /dev/null +++ b/tests/integration/graviton_abi_test.py @@ -0,0 +1,484 @@ +import random + +from graviton.blackbox import DryRunInspector + +import pyteal as pt +from pyteal.ast.subroutine import ABIReturnSubroutine + +from tests.blackbox import ( + Blackbox, + PyTealDryRunExecutor, +) + + +# ---- Integers and Complex Integral Numbers (aka Gaussian Integers) ---- # + + +""" +WARNING: The following ABI Types Int65 and Complex130 are ONLY for the purpose of testing/demo'ing +ABISubroutine and graviton-abi, and are NOT the recommended approach for implementing integers and +complex integers. A better appraoch probably leverages `Uint64` without additional types use 2's complement arithmetic. +""" + +Int65 = pt.abi.Tuple2[pt.abi.Bool, pt.abi.Uint64] +Complex130 = pt.abi.Tuple2[Int65, Int65] + + +@Blackbox(input_types=[None, None]) +@pt.ABIReturnSubroutine +def int65_minus_cond(x: Int65, y: Int65, *, output: Int65): + """ + WARNING: not an ideal implementation. See explanation in first WARNING above. + """ + x0 = pt.abi.Bool() + x1 = pt.abi.Uint64() + y0 = pt.abi.Bool() + y1 = pt.abi.Uint64() + z0 = pt.abi.Bool() + z1 = pt.abi.Uint64() + return pt.Seq( + x0.set(x[0]), + x1.set(x[1]), + y0.set(y[0]), + y1.set(y[1]), + pt.Cond( + # Case I. x, y positive + [ + pt.And(x0.get(), y0.get()), + pt.Seq( + z0.set(x1.get() >= y1.get()), + z1.set( + pt.If(x1.get() <= y1.get()) + .Then(y1.get() - x1.get()) + .Else(x1.get() - y1.get()) + ), + ), + ], + # Case II. x positive, y negative + [ + pt.And(x0.get(), pt.Not(y0.get())), + pt.Seq(z0.set(True), z1.set(x1.get() + y1.get())), + ], + # Case III. x negative, y positive + [ + pt.And(pt.Not(x0.get()), y0.get()), + pt.Seq(z0.set(False), z1.set(x1.get() + y1.get())), + ], + # Case IV. x, y negative + [ + pt.Int(1), + pt.Seq( + z0.set(x1.get() <= y1.get()), + z1.set( + pt.If(x1.get() <= y1.get()) + .Then(y1.get() - x1.get()) + .Else(x1.get() - y1.get()) + ), + ), + ], + ), + output.set(z0, z1), + ) + + +@Blackbox(input_types=[None, None]) +@pt.ABIReturnSubroutine +def int65_sub(x: Int65, y: Int65, *, output: Int65): + """ + WARNING: not an ideal implementation. See explanation in first WARNING above. + """ + x0 = pt.abi.Bool() + x1 = pt.abi.Uint64() + y0 = pt.abi.Bool() + y1 = pt.abi.Uint64() + z0 = pt.abi.Bool() + z1 = pt.abi.Uint64() + return pt.Seq( + x0.set(x[0]), + x1.set(x[1]), + y0.set(y[0]), + y1.set(y[1]), + pt.If(x0.get() == y0.get()) + .Then( # Case I. x, y same signature + pt.Seq( + z0.set(pt.Not(x0.get()) ^ (x1.get() >= y1.get())), + z1.set( + pt.If(x1.get() <= y1.get()) + .Then(y1.get() - x1.get()) + .Else(x1.get() - y1.get()) + ), + ) + ) + .Else( # Case II. x, y opposite signatures + pt.Seq( + z0.set(x0.get()), + z1.set(x1.get() + y1.get()), + ), + ), + output.set(z0, z1), + ) + + +@Blackbox(input_types=[None, None]) +@pt.ABIReturnSubroutine +def int65_mult(x: Int65, y: Int65, *, output: Int65): + """ + WARNING: not an ideal implementation. See explanation in first WARNING above. + """ + # TODO: can we get something like the following one-liner working? + # return output.set(pt.Not(x[0].get() ^ y[0].get()), x[1].get() * y[1].get()) + def get(x): + return x.use(lambda ni: ni.get()) + + return pt.Seq( + (z0 := pt.abi.Bool()).set(pt.Not(get(x[0]) ^ get(y[0]))), + (z1 := pt.abi.Uint64()).set(get(x[1]) * get(y[1])), + output.set(z0, z1), + ) + + +@Blackbox(input_types=[None]) +@ABIReturnSubroutine +def int65_negate(x: Int65, *, output: Int65): + """ + WARNING: not an ideal implementation. See explanation in first WARNING above. + """ + # TODO: can I haz a one-liner pls???? + x0 = pt.abi.Bool() + x1 = pt.abi.Uint64() + z0 = pt.abi.Bool() + z1 = pt.abi.Uint64() + return pt.Seq( + x0.set(x[0]), + x1.set(x[1]), + z0.set(pt.Not(x0.get())), + z1.set(x1.get()), + output.set(z0, z1), + ) + + +@Blackbox(input_types=[None, None]) +@ABIReturnSubroutine +def int65_add(x: Int65, y: Int65, *, output: Int65): + """ + WARNING: not an ideal implementation. See explanation in first WARNING above. + """ + return pt.Seq(y.set(int65_negate(y)), output.set(int65_sub(x, y))) + + +@Blackbox(input_types=[None, None]) +@ABIReturnSubroutine +def complex130_add(x: Complex130, y: Complex130, *, output: Complex130): + """ + WARNING: not an ideal implementation. See explanation in first WARNING above. + """ + x0 = pt.abi.make(Int65) + x1 = pt.abi.make(Int65) + y0 = pt.abi.make(Int65) + y1 = pt.abi.make(Int65) + z0 = pt.abi.make(Int65) + z1 = pt.abi.make(Int65) + return pt.Seq( + x0.set(x[0]), + x1.set(x[1]), + y0.set(y[0]), + y1.set(y[1]), + z0.set(int65_add(x0, y0)), + z1.set(int65_add(x1, y1)), + output.set(z0, z1), + ) + + +@Blackbox(input_types=[None, None]) +@ABIReturnSubroutine +def complex130_mult(x: Complex130, y: Complex130, *, output: Complex130): + """ + WARNING: not an ideal implementation. See explanation in first WARNING above. + """ + x0 = pt.abi.make(Int65) + x1 = pt.abi.make(Int65) + y0 = pt.abi.make(Int65) + y1 = pt.abi.make(Int65) + t1 = pt.abi.make(Int65) + t2 = pt.abi.make(Int65) + t3 = pt.abi.make(Int65) + t4 = pt.abi.make(Int65) + z0 = pt.abi.make(Int65) + z1 = pt.abi.make(Int65) + return pt.Seq( + x0.set(x[0]), + x1.set(x[1]), + y0.set(y[0]), + y1.set(y[1]), + # TODO: why can't I chain ABI calls? + # z0.set(int65_sub(int65_mult(x0, y0), int65_mult(x1, y1))), + # z1.set(int65_add(int65_mult(x0, y1), int65_mult(x1, y0))), + t1.set(int65_mult(x0, y0)), + t2.set(int65_mult(x1, y1)), + t3.set(int65_mult(x0, y1)), + t4.set(int65_mult(x1, y0)), + z0.set(int65_sub(t1, t2)), + z1.set(int65_add(t3, t4)), + output.set(z0, z1), + ) + + +@Blackbox(input_types=[None]) +@ABIReturnSubroutine +def complex130_real(x: Complex130, *, output: Int65): + """ + WARNING: not an ideal implementation. See explanation in first WARNING above. + """ + return output.set(x[0]) + + +@Blackbox(input_types=[None]) +@ABIReturnSubroutine +def complex130_imag(x: Complex130, *, output: Int65): + """ + WARNING: not an ideal implementation. See explanation in first WARNING above. + """ + return output.set(x[1]) + + +@Blackbox(input_types=[None]) +@ABIReturnSubroutine +def complex130_conjugate(x: Complex130, *, output: Complex130): + """ + WARNING: not an ideal implementation. See explanation in first WARNING above. + """ + z0 = pt.abi.make(Int65) + z1 = pt.abi.make(Int65) + return pt.Seq( + z0.set(complex130_real(x)), + z1.set(complex130_imag(x)), + z1.set(int65_negate(z1)), + output.set(z0, z1), + ) + + +@Blackbox(input_types=[None]) +@ABIReturnSubroutine +def complex130_norm_squared(x: Complex130, *, output: Int65): + """ + WARNING: not an ideal implementation. See explanation in first WARNING above. + """ + t = pt.abi.make(Complex130) + return pt.Seq( + t.set(complex130_conjugate(x)), + t.set(complex130_mult(t, x)), + output.set(complex130_real(t)), + ) + + +# ---- integration test functions ---- # + + +def test_integer65(): + bbpt_subtract_slick = PyTealDryRunExecutor(int65_sub, pt.Mode.Application) + + bbpt_subtract_cond = PyTealDryRunExecutor(int65_minus_cond, pt.Mode.Application) + + bbpt_mult = PyTealDryRunExecutor(int65_mult, pt.Mode.Application) + + bbpt_negate = PyTealDryRunExecutor(int65_negate, pt.Mode.Application) + + bbpt_add = PyTealDryRunExecutor(int65_add, pt.Mode.Application) + + def pynum_to_tuple(n): + return (n >= 0, abs(n)) + + def pytuple_to_num(t): + s, x = t + return x if s else -x + + N = 100 + random.seed(42) + + choices = range(-9_999, 10_000) + unary_inputs = [(pynum_to_tuple(x),) for x in random.sample(choices, N)] + + binary_inputs = [ + (pynum_to_tuple(x), pynum_to_tuple(y)) + for x, y in zip(random.sample(choices, N), random.sample(choices, N)) + ] + + def binary_dryrun(p: PyTealDryRunExecutor) -> list[DryRunInspector]: + return p.dryrun_on_sequence(binary_inputs) + + # Binary: + inspectors_subtract_slick = binary_dryrun(bbpt_subtract_slick) + + inspectors_subtract_cond = binary_dryrun(bbpt_subtract_cond) + + inspectors_mult = binary_dryrun(bbpt_mult) + + inspectors_add = binary_dryrun(bbpt_add) + + # Unary: + inspectors_negate = bbpt_negate.dryrun_on_sequence(unary_inputs) + + for i in range(N): + binary_args = binary_inputs[i] + x, y = tuple(map(pytuple_to_num, binary_args)) + + unary_args = unary_inputs[i] + u = pytuple_to_num(unary_args[0]) + + inspector_subtract_slick = inspectors_subtract_slick[i] + inspector_subtract_cond = inspectors_subtract_cond[i] + inspector_mult = inspectors_mult[i] + inspector_add = inspectors_add[i] + + inspector_negate = inspectors_negate[i] + + assert x - y == pytuple_to_num( + inspector_subtract_slick.last_log() + ), inspector_subtract_slick.report( + binary_args, f"failed for {binary_args}", row=i + ) + + assert x - y == pytuple_to_num( + inspector_subtract_cond.last_log() + ), inspector_subtract_cond.report( + binary_args, f"failed for {binary_args}", row=i + ) + + assert x * y == pytuple_to_num( + inspector_mult.last_log() + ), inspector_mult.report(binary_args, f"failed for {binary_args}", row=i) + + assert x + y == pytuple_to_num(inspector_add.last_log()), inspector_add.report( + binary_args, f"failed for {binary_args}", row=i + ) + + assert -u == pytuple_to_num( + inspector_negate.last_log() + ), inspector_negate.report(unary_args, f"failed for {unary_args}", row=i) + + +def test_complex130(): + # Binary: + + bbpt_cplx_add = PyTealDryRunExecutor(complex130_add, pt.Mode.Application) + + bbpt_cplx_mult = PyTealDryRunExecutor(complex130_mult, pt.Mode.Application) + + # Unary: + + bbpt_complex_real = PyTealDryRunExecutor(complex130_real, pt.Mode.Application) + + bbpt_complex_imag = PyTealDryRunExecutor(complex130_imag, pt.Mode.Application) + + bbpt_complex_conjugate = PyTealDryRunExecutor( + complex130_conjugate, pt.Mode.Application + ) + + bbpt_complex_norm_squared = PyTealDryRunExecutor( + complex130_norm_squared, pt.Mode.Application + ) + + def pyint_to_tuple(n): + return (n >= 0, abs(n)) + + def pycomplex_to_tuple(z): + return (pyint_to_tuple(int(z.real)), pyint_to_tuple(int(z.imag))) + + def pytuple_to_int(t): + s, x = t + return x if s else -x + + def pytuple_to_complex(tt): + tx, ty = tt + return complex(pytuple_to_int(tx), pytuple_to_int(ty)) + + N = 100 + # just for fun - no random seed - but this shouldn't be flakey + + choices = range(-999_999, 1_000_000) + + unary_inputs = [ + (pycomplex_to_tuple(complex(x, y)),) + for x, y in zip(random.sample(choices, N), random.sample(choices, N)) + ] + + binary_inputs = [ + (pycomplex_to_tuple(complex(x, y)), pycomplex_to_tuple(complex(z, w))) + for x, y, z, w in zip( + random.sample(choices, N), + random.sample(choices, N), + random.sample(choices, N), + random.sample(choices, N), + ) + ] + + # Binary: + def binary_dryrun(p: PyTealDryRunExecutor) -> list[DryRunInspector]: + return p.dryrun_on_sequence(binary_inputs) + + inspectors_cplx_add = binary_dryrun(bbpt_cplx_add) + + inspectors_cplx_mult = binary_dryrun(bbpt_cplx_mult) + + # Unary: + def unary_dryrun(p: PyTealDryRunExecutor) -> list[DryRunInspector]: + return p.dryrun_on_sequence(unary_inputs) + + inspectors_cplx_real = unary_dryrun(bbpt_complex_real) + + inspectors_cplx_imag = unary_dryrun(bbpt_complex_imag) + + inspectors_cplx_conjugate = unary_dryrun(bbpt_complex_conjugate) + + inspectors_cplx_norm_squared = unary_dryrun(bbpt_complex_norm_squared) + + for i in range(N): + binary_args = binary_inputs[i] + x, y = tuple(map(pytuple_to_complex, binary_args)) + + unary_args = unary_inputs[i] + u = pytuple_to_complex(unary_args[0]) + + # Binary: + + inspector_cplx_add = inspectors_cplx_add[i] + + inspector_cplx_mult = inspectors_cplx_mult[i] + + # Unary: + + inspector_cplx_real = inspectors_cplx_real[i] + + inspector_cplx_imag = inspectors_cplx_imag[i] + + inspector_cplx_conjugate = inspectors_cplx_conjugate[i] + + inspector_cplx_norm_squared = inspectors_cplx_norm_squared[i] + + assert x + y == pytuple_to_complex( + inspector_cplx_add.last_log() + ), inspector_cplx_add.report(binary_args, f"failed for {binary_args}", row=i) + + assert x * y == pytuple_to_complex( + inspector_cplx_mult.last_log() + ), inspector_cplx_mult.report(binary_args, f"failed for {binary_args}", row=i) + + assert u.real == pytuple_to_int( + inspector_cplx_real.last_log() + ), inspector_cplx_real.report(unary_args, f"failed for {unary_args}", row=i) + + assert u.imag == pytuple_to_int( + inspector_cplx_imag.last_log() + ), inspector_cplx_imag.report(unary_args, f"failed for {unary_args}", row=i) + + assert u.conjugate() == pytuple_to_complex( + inspector_cplx_conjugate.last_log() + ), inspector_cplx_conjugate.report( + unary_args, f"failed for {unary_args}", row=i + ) + + assert u * u.conjugate() == pytuple_to_int( + inspector_cplx_norm_squared.last_log() + ), inspector_cplx_norm_squared.report( + unary_args, f"failed for {unary_args}", row=i + ) diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index da1a9ab5a..ad43e62f9 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -4,31 +4,15 @@ import pytest -from pyteal import ( - Bytes, - Concat, - For, - If, - Int, - Mode, - ScratchVar, - Seq, - While, - Continue, - Return, - Subroutine, - SubroutineFnWrapper, - TealType, - compileTeal, -) +import pyteal as pt from tests.compile_asserts import assert_teal_as_expected from tests.blackbox import ( Blackbox, BlackboxWrapper, algod_with_assertion, - blackbox_pyteal, mode_to_execution_mode, + PyTealDryRunExecutor, ) from graviton.blackbox import ( @@ -55,15 +39,9 @@ def wrap_compile_and_save( subr, mode, version, assemble_constants, test_name, case_name ): - is_app = mode == Mode.Application - - # 1. PyTeal program Expr generation - approval = blackbox_pyteal(subr, mode) + is_app = mode == pt.Mode.Application - # 2. TEAL generation - teal = compileTeal( - approval(), mode, version=version, assembleConstants=assemble_constants - ) + teal = PyTealDryRunExecutor(subr, mode).compile(version, assemble_constants) tealfile = f'{"app" if is_app else "lsig"}_{case_name}.teal' tealdir = GENERATED / test_name @@ -73,7 +51,7 @@ def wrap_compile_and_save( f.write(teal) print( - f"""subroutine {case_name}@{mode} generated TEAL. + f"""Subroutine {case_name}@{mode} generated TEAL. saved to {tealpath}: ------- {teal} @@ -87,60 +65,60 @@ def wrap_compile_and_save( @Blackbox(input_types=[]) -@Subroutine(TealType.uint64) +@pt.Subroutine(pt.TealType.uint64) def exp(): - return Int(2) ** Int(10) + return pt.Int(2) ** pt.Int(10) -@Blackbox(input_types=[TealType.uint64]) -@Subroutine(TealType.none) -def square_byref(x: ScratchVar): +@Blackbox(input_types=[pt.TealType.uint64]) +@pt.Subroutine(pt.TealType.none) +def square_byref(x: pt.ScratchVar): return x.store(x.load() * x.load()) -@Blackbox(input_types=[TealType.uint64]) -@Subroutine(TealType.uint64) +@Blackbox(input_types=[pt.TealType.uint64]) +@pt.Subroutine(pt.TealType.uint64) def square(x): - return x ** Int(2) + return x ** pt.Int(2) -@Blackbox(input_types=[TealType.anytype, TealType.anytype]) -@Subroutine(TealType.none) -def swap(x: ScratchVar, y: ScratchVar): - z = ScratchVar(TealType.anytype) - return Seq( +@Blackbox(input_types=[pt.TealType.anytype, pt.TealType.anytype]) +@pt.Subroutine(pt.TealType.none) +def swap(x: pt.ScratchVar, y: pt.ScratchVar): + z = pt.ScratchVar(pt.TealType.anytype) + return pt.Seq( z.store(x.load()), x.store(y.load()), y.store(z.load()), ) -@Blackbox(input_types=[TealType.bytes, TealType.uint64]) -@Subroutine(TealType.bytes) -def string_mult(s: ScratchVar, n): - i = ScratchVar(TealType.uint64) - tmp = ScratchVar(TealType.bytes) - start = Seq(i.store(Int(1)), tmp.store(s.load()), s.store(Bytes(""))) - step = i.store(i.load() + Int(1)) - return Seq( - For(start, i.load() <= n, step).Do(s.store(Concat(s.load(), tmp.load()))), +@Blackbox(input_types=[pt.TealType.bytes, pt.TealType.uint64]) +@pt.Subroutine(pt.TealType.bytes) +def string_mult(s: pt.ScratchVar, n): + i = pt.ScratchVar(pt.TealType.uint64) + tmp = pt.ScratchVar(pt.TealType.bytes) + start = pt.Seq(i.store(pt.Int(1)), tmp.store(s.load()), s.store(pt.Bytes(""))) + step = i.store(i.load() + pt.Int(1)) + return pt.Seq( + pt.For(start, i.load() <= n, step).Do(s.store(pt.Concat(s.load(), tmp.load()))), s.load(), ) -@Blackbox(input_types=[TealType.uint64]) -@Subroutine(TealType.uint64) +@Blackbox(input_types=[pt.TealType.uint64]) +@pt.Subroutine(pt.TealType.uint64) def oldfac(n): - return If(n < Int(2)).Then(Int(1)).Else(n * oldfac(n - Int(1))) + return pt.If(n < pt.Int(2)).Then(pt.Int(1)).Else(n * oldfac(n - pt.Int(1))) -@Blackbox(input_types=[TealType.uint64]) -@Subroutine(TealType.uint64) +@Blackbox(input_types=[pt.TealType.uint64]) +@pt.Subroutine(pt.TealType.uint64) def slow_fibonacci(n): return ( - If(n <= Int(1)) + pt.If(n <= pt.Int(1)) .Then(n) - .Else(slow_fibonacci(n - Int(2)) + slow_fibonacci(n - Int(1))) + .Else(slow_fibonacci(n - pt.Int(2)) + slow_fibonacci(n - pt.Int(1))) ) @@ -174,7 +152,7 @@ def fib_cost(args): "subr, mode", product( [exp, square_byref, square, swap, string_mult, oldfac, slow_fibonacci], - [Mode.Application, Mode.Signature], + [pt.Mode.Application, pt.Mode.Signature], ), ) def test_stable_teal_generation(subr, mode): @@ -509,8 +487,8 @@ def test_stable_teal_generation(subr, mode): def blackbox_test_runner( - subr: SubroutineFnWrapper, - mode: Mode, + subr: pt.SubroutineFnWrapper, + mode: pt.Mode, scenario: Dict[str, Any], version: int, assemble_constants: bool = True, @@ -521,7 +499,7 @@ def blackbox_test_runner( # 0. Validations assert isinstance(subr, BlackboxWrapper), f"unexpected subr type {type(subr)}" - assert isinstance(mode, Mode) + assert isinstance(mode, pt.Mode) # 1. Compile to TEAL teal, _, tealfile = wrap_compile_and_save( @@ -567,48 +545,39 @@ def blackbox_test_runner( @pytest.mark.parametrize("subr, scenario", APP_SCENARIOS.items()) def test_blackbox_subroutines_as_apps( - subr: SubroutineFnWrapper, + subr: pt.SubroutineFnWrapper, scenario: Dict[str, Any], ): - blackbox_test_runner(subr, Mode.Application, scenario, 6) + blackbox_test_runner(subr, pt.Mode.Application, scenario, 6) @pytest.mark.parametrize("subr, scenario", LOGICSIG_SCENARIOS.items()) def test_blackbox_subroutines_as_logic_sigs( - subr: SubroutineFnWrapper, + subr: pt.SubroutineFnWrapper, scenario: Dict[str, Any], ): - blackbox_test_runner(subr, Mode.Signature, scenario, 6) + blackbox_test_runner(subr, pt.Mode.Signature, scenario, 6) def blackbox_pyteal_example1(): # Example 1: Using blackbox_pyteal for a simple test of both an app and logic sig: - from graviton.blackbox import DryRunEncoder, DryRunExecutor + from graviton.blackbox import DryRunEncoder - from pyteal import compileTeal, Int, Mode, Subroutine, TealType - from tests.blackbox import Blackbox, algod_with_assertion, blackbox_pyteal + from pyteal import Int, Mode, Subroutine, TealType + from tests.blackbox import Blackbox @Blackbox(input_types=[TealType.uint64]) @Subroutine(TealType.uint64) def square(x): return x ** Int(2) - # create pyteal app and logic sig approvals: - approval_app = blackbox_pyteal(square, Mode.Application) - approval_lsig = blackbox_pyteal(square, Mode.Signature) - - # compile the evaluated approvals to generate TEAL: - app_teal = compileTeal(approval_app(), Mode.Application, version=6) - lsig_teal = compileTeal(approval_lsig(), Mode.Signature, version=6) - # provide args for evaluation (will compute x^2) x = 9 args = [x] # evaluate the programs - algod = algod_with_assertion() - app_result = DryRunExecutor.dryrun_app(algod, app_teal, args) - lsig_result = DryRunExecutor.dryrun_logicsig(algod, lsig_teal, args) + app_result = PyTealDryRunExecutor(square, Mode.Application).dryrun(args) + lsig_result = PyTealDryRunExecutor(square, Mode.Signature).dryrun(args) # check to see that x^2 is at the top of the stack as expected assert app_result.stack_top() == x**2, app_result.report( @@ -631,10 +600,9 @@ def blackbox_pyteal_example2(): from pathlib import Path import random - from graviton.blackbox import DryRunExecutor, DryRunInspector + from graviton.blackbox import DryRunInspector from pyteal import ( - compileTeal, For, If, Int, @@ -646,7 +614,7 @@ def blackbox_pyteal_example2(): TealType, ) - from tests.blackbox import Blackbox, algod_with_assertion, blackbox_pyteal + from tests.blackbox import Blackbox # GCD via the Euclidean Algorithm (iterative version): @Blackbox(input_types=[TealType.uint64, TealType.uint64]) @@ -662,10 +630,6 @@ def euclid(x, y): ) return Seq(For(start, cond, step).Do(Seq()), a.load()) - # create approval PyTeal and compile it to TEAL: - euclid_app = blackbox_pyteal(euclid, Mode.Application) - euclid_app_teal = compileTeal(euclid_app(), Mode.Application, version=6) - # generate a report with 400 = 20*20 dry run rows: N = 20 inputs = list( @@ -675,11 +639,10 @@ def euclid(x, y): ) ) - # execute the dry-run sequence: - algod = algod_with_assertion() - # assert that each result is that same as what Python's math.gcd() computes - inspectors = DryRunExecutor.dryrun_app_on_sequence(algod, euclid_app_teal, inputs) + inspectors = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_on_sequence( + inputs + ) for i, result in enumerate(inspectors): args = inputs[i] assert result.stack_top() == math.gcd(*args), result.report( @@ -700,14 +663,13 @@ def blackbox_pyteal_example3(): from graviton.blackbox import ( DryRunEncoder, - DryRunExecutor, DryRunProperty as DRProp, ) from graviton.invariant import Invariant - from pyteal import compileTeal, If, Int, Mod, Mode, Subroutine, TealType + from pyteal import If, Int, Mod, Mode, Subroutine, TealType - from tests.blackbox import Blackbox, algod_with_assertion, blackbox_pyteal + from tests.blackbox import Blackbox # avoid flaky tests just in case I was wrong about the stack height invariant... random.seed(42) @@ -760,20 +722,127 @@ def euclid(x, y): .Else(If(y == Int(0)).Then(x).Else(euclid(y, Mod(x, y)))) ) - # Generate PyTeal and TEAL for the recursive Euclidean algorithm: - euclid_app = blackbox_pyteal(euclid, Mode.Application) - euclid_app_teal = compileTeal(euclid_app(), Mode.Application, version=6) - # Execute on the input sequence to get a dry-run inspectors: - algod = algod_with_assertion() - inspectors = DryRunExecutor.dryrun_app_on_sequence(algod, euclid_app_teal, inputs) + inspectors = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_on_sequence( + inputs + ) # Assert that each invariant holds on the sequences of inputs and dry-runs: for property, predicate in predicates.items(): Invariant(predicate).validates(property, inputs, inspectors) +def blackbox_pyteal_example4(): + # Example 4: Using PyTealDryRunExecutor to debug an ABIReturnSubroutine with an app, logic sig and csv report + from pathlib import Path + import random + + from graviton.blackbox import DryRunInspector + + from pyteal import ( + abi, + ABIReturnSubroutine, + Expr, + For, + Int, + Mode, + ScratchVar, + Seq, + TealType, + ) + + from tests.blackbox import Blackbox, PyTealDryRunExecutor + + # Sum a dynamic uint64 array + @Blackbox(input_types=[None]) + @ABIReturnSubroutine + def abi_sum(toSum: abi.DynamicArray[abi.Uint64], *, output: abi.Uint64) -> Expr: + i = ScratchVar(TealType.uint64) + valueAtIndex = abi.Uint64() + return Seq( + output.set(0), + For( + i.store(Int(0)), + i.load() < toSum.length(), + i.store(i.load() + Int(1)), + ).Do( + Seq( + toSum[i.load()].store_into(valueAtIndex), + output.set(output.get() + valueAtIndex.get()), + ) + ), + ) + + # instantiate PyTealDryRunExecutor objects for the app and lsig: + app_pytealer = PyTealDryRunExecutor(abi_sum, Mode.Application) + lsig_pytealer = PyTealDryRunExecutor(abi_sum, Mode.Signature) + + # generate reports with the same random inputs (fix the randomness with a seed): + random.seed(42) + + N = 50 # the number of dry runs for each experiment + choices = range(10_000) + inputs = [] + for n in range(N): + inputs.append(tuple([random.sample(choices, n)])) + + app_inspectors = app_pytealer.dryrun_on_sequence(inputs) + + lsig_inspectors = lsig_pytealer.dryrun_on_sequence(inputs) + + for i in range(N): + args = inputs[i] + + app_inspector = app_inspectors[i] + lsig_inspector = lsig_inspectors[i] + + def message(insp): + return insp.report(args, f"failed for {args}", row=i) + + # the app should pass exactly when it's cost was within the 700 budget: + assert app_inspector.passed() == (app_inspector.cost() <= 700), message( + app_inspector + ) + # the lsig always passes (never goes over budget): + assert lsig_inspector.passed(), message(lsig_inspector) + + expected = sum(args[0]) + actual4app = app_inspector.last_log() + assert expected == actual4app, message(app_inspector) + + if i > 0: + assert expected in app_inspector.final_scratch().values(), message( + app_inspector + ) + assert expected in lsig_inspector.final_scratch().values(), message( + lsig_inspector + ) + + def report(kind): + assert kind in ("app", "lsig") + insps = app_inspectors if kind == "app" else lsig_inspectors + csv_report = DryRunInspector.csv_report(inputs, insps) + with open(Path.cwd() / f"abi_sum_{kind}.csv", "w") as f: + f.write(csv_report) + + report("app") + report("lsig") + + def blackbox_pyteal_while_continue_test(): + from tests.blackbox import Blackbox + from pyteal import ( + Continue, + Int, + Mode, + Return, + ScratchVar, + Seq, + Subroutine, + TealType, + While, + ) + @Blackbox(input_types=[TealType.uint64]) @Subroutine(TealType.uint64) def while_continue_accumulation(n): @@ -789,13 +858,11 @@ def while_continue_accumulation(n): Return(i.load()), ) - approval_lsig = blackbox_pyteal(while_continue_accumulation, Mode.Signature) - lsig_teal = compileTeal(approval_lsig(), Mode.Signature, version=6) - algod = algod_with_assertion() - for x in range(30): args = [x] - lsig_result = DryRunExecutor.dryrun_logicsig(algod, lsig_teal, args) + lsig_result = PyTealDryRunExecutor( + while_continue_accumulation, Mode.Signature + ).dryrun(args) if x == 0: assert not lsig_result.passed() else: @@ -812,6 +879,7 @@ def while_continue_accumulation(n): blackbox_pyteal_example1, blackbox_pyteal_example2, blackbox_pyteal_example3, + blackbox_pyteal_example4, blackbox_pyteal_while_continue_test, ], ) diff --git a/tests/integration/pure_logicsig_test.py b/tests/integration/pure_logicsig_test.py new file mode 100644 index 000000000..40e322447 --- /dev/null +++ b/tests/integration/pure_logicsig_test.py @@ -0,0 +1,126 @@ +from itertools import product +from os import environ +from pathlib import Path +import pytest + +from pyteal import compileTeal, Mode + +import examples.signature.factorizer_game as factorizer + +from tests.blackbox import algod_with_assertion +from graviton.blackbox import ( + DryRunExecutor as Executor, + DryRunInspector as Inspector, + DryRunProperty as DRProp, +) +from graviton.invariant import Invariant + +REPORTS_DIR = Path.cwd() / "tests" / "integration" / "reports" +ALGOD = algod_with_assertion() + +DEFAULT = { + "A": 3, + "P": 5, # 13 + "Q": 7, # 13 + "M": 5, # 10 + "N": 5, # 10 +} + + +def get_param_bounds(): + """ + Allow setting the bounds either from the environment via something like: + + % A=3 P=13 Q=13 M=10 N=10 pytest tests/integration/pure_logicsig_test.py::test_many_factorizer_games + + OR - when any of the above is missing, replace with the default version + """ + vars = [] + for var in ("A", "P", "Q", "M", "N"): + val = environ.get(var) + if val is None: + val = DEFAULT[var] + vars.append(int(val)) + return vars + + +def get_factorizer_param_sequence(): + A, P, Q, M, N = get_param_bounds() + return [(a, p, q, M, N) for a in range(A) for p in range(P) for q in range(Q)] + + +def inputs_for_coefficients(a, p, q, M, N): + # TODO: this should really be focused around the roots p and q + return product(range(M), range(N)) + + +def factorizer_game_check(a: int, p: int, q: int, M: int, N: int): + ae = None + if a <= 0 or p < 0 or q <= p: + with pytest.raises(AssertionError) as ae: + factorizer.logicsig(a, p, q), + + if ae: + return + + compiled = compileTeal( + factorizer.logicsig(a, p, q), + version=6, + mode=Mode.Signature, + assembleConstants=True, + ) + inputs = list(inputs_for_coefficients(a, p, q, M, N)) + N = len(inputs) + + def poly(x): + return abs(a * x**2 - a * (p + q) * x + a * p * q) + + def naive_prize(x, y): + return 1_000_000 * max(10 - (sum(map(poly, (x, y))) + 1) // 2, 0) + + def payment_amount(x, y): + return 0 if x == y else naive_prize(x, y) + + amts = list(map(lambda args: payment_amount(*args), inputs)) + + inspectors, txns = [], [] + for args, amt in zip(inputs, amts): + txn = {"amt": amt} + txns.append(txn) + inspectors.append(Executor.dryrun_logicsig(ALGOD, compiled, args, **txn)) + + print( + f"generating a report for (a,p,q) = {a,p,q} with {M, N} dry-run calls and spreadsheet rows" + ) + filebase = f"factorizer_game_{a}_{p}_{q}" + + reports_dir = REPORTS_DIR / "pure_logicsig" + reports_dir.mkdir(parents=True, exist_ok=True) + csvpath = reports_dir / f"{filebase}.csv" + with open(csvpath, "w") as f: + f.write(Inspector.csv_report(inputs, inspectors, txns=txns)) + + print(f"validating passing_invariant for (a,p,q) = {a,p,q} over {N} dry-run calls") + passing_invariant = Invariant( + lambda args: bool(payment_amount(*args)), + name=f"passing invariant for coeffs {a, p, q}", + ) + passing_invariant.validates(DRProp.passed, inputs, inspectors) + + print( + f"validate procedurally that payment amount as expected for (a,p,q) = {a,p,q} over {M, N} dry-rundry-run calls" + ) + + for args, inspector in zip(inputs, inspectors): + x, y = args + eprize = naive_prize(x, y) + final_scratches = inspector.final_scratch().values() + assert eprize == 0 or eprize in final_scratches, inspector.report( + args, + f"(a, p, q, x, y) = {a, p, q, x, y}. final scratch slots expected to contain {eprize} v. actual={final_scratches}", + ) + + +@pytest.mark.parametrize("a, p, q, M, N", get_factorizer_param_sequence()) +def test_many_factorizer_games(a: int, p: int, q: int, M: int, N: int): + factorizer_game_check(a, p, q, M, N) diff --git a/tests/integration/teal/roundtrip/app_roundtrip_().teal b/tests/integration/teal/roundtrip/app_roundtrip_().teal new file mode 100644 index 000000000..b59fbd275 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_().teal @@ -0,0 +1,38 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 1 +load 1 +callsub roundtripper_1 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// tuple_complement +tuplecomplement_0: +store 6 +byte "" +store 7 +load 7 +retsub + +// round_tripper +roundtripper_1: +store 2 +load 2 +callsub tuplecomplement_0 +store 4 +load 4 +callsub tuplecomplement_0 +store 5 +load 2 +load 4 +concat +load 5 +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool).teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool).teal new file mode 100644 index 000000000..6344eb38b --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool).teal @@ -0,0 +1,61 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 2 +load 2 +callsub roundtripper_1 +store 1 +byte 0x151F7C75 +load 1 +concat +log +int 1 +return + +// tuple_complement +tuplecomplement_0: +store 7 +load 7 +int 0 +getbit +store 0 +load 0 +callsub boolcomp_2 +store 0 +byte 0x00 +int 0 +load 0 +setbit +store 8 +load 8 +retsub + +// round_tripper +roundtripper_1: +store 3 +load 3 +callsub tuplecomplement_0 +store 5 +load 5 +callsub tuplecomplement_0 +store 6 +load 3 +load 5 +concat +load 6 +concat +store 4 +load 4 +retsub + +// bool_comp +boolcomp_2: +store 9 +load 9 +! +store 10 +load 10 +int 2 +< +assert +load 10 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10].teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10].teal new file mode 100644 index 000000000..56210aa2a --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10].teal @@ -0,0 +1,187 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 2 +load 2 +callsub roundtripper_2 +store 1 +byte 0x151F7C75 +load 1 +concat +log +int 1 +return + +// tuple_complement +tuplecomplement_0: +store 19 +load 19 +int 0 +getbit +store 0 +load 0 +callsub boolcomp_3 +store 0 +byte 0x00 +int 0 +load 0 +setbit +store 20 +load 20 +retsub + +// array_complement +arraycomplement_1: +store 7 +load 7 +int 1 +int 0 +* +int 1 +extract3 +store 9 +load 7 +int 1 +int 1 +* +int 1 +extract3 +store 10 +load 7 +int 1 +int 2 +* +int 1 +extract3 +store 11 +load 7 +int 1 +int 3 +* +int 1 +extract3 +store 12 +load 7 +int 1 +int 4 +* +int 1 +extract3 +store 13 +load 7 +int 1 +int 5 +* +int 1 +extract3 +store 14 +load 7 +int 1 +int 6 +* +int 1 +extract3 +store 15 +load 7 +int 1 +int 7 +* +int 1 +extract3 +store 16 +load 7 +int 1 +int 8 +* +int 1 +extract3 +store 17 +load 7 +int 1 +int 9 +* +int 1 +extract3 +store 18 +load 9 +callsub tuplecomplement_0 +store 9 +load 10 +callsub tuplecomplement_0 +store 10 +load 11 +callsub tuplecomplement_0 +store 11 +load 12 +callsub tuplecomplement_0 +store 12 +load 13 +callsub tuplecomplement_0 +store 13 +load 14 +callsub tuplecomplement_0 +store 14 +load 15 +callsub tuplecomplement_0 +store 15 +load 16 +callsub tuplecomplement_0 +store 16 +load 17 +callsub tuplecomplement_0 +store 17 +load 18 +callsub tuplecomplement_0 +store 18 +load 9 +load 10 +concat +load 11 +concat +load 12 +concat +load 13 +concat +load 14 +concat +load 15 +concat +load 16 +concat +load 17 +concat +load 18 +concat +store 8 +load 8 +retsub + +// round_tripper +roundtripper_2: +store 3 +load 3 +callsub arraycomplement_1 +store 5 +load 5 +callsub arraycomplement_1 +store 6 +load 3 +load 5 +concat +load 6 +concat +store 4 +load 4 +retsub + +// bool_comp +boolcomp_3: +store 21 +load 21 +! +store 22 +load 22 +int 2 +< +assert +load 22 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_<2>.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_<2>.teal new file mode 100644 index 000000000..f66d64459 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_<2>.teal @@ -0,0 +1,2039 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 6 +load 6 +callsub roundtripper_2 +store 5 +byte 0x151F7C75 +load 5 +concat +log +int 1 +return + +// tuple_complement +tuplecomplement_0: +store 17 +load 17 +int 0 +getbit +store 0 +load 17 +int 1 +getbyte +store 1 +load 17 +extract 2 32 +store 2 +load 17 +load 17 +int 34 +extract_uint16 +load 17 +int 36 +extract_uint16 +substring3 +store 3 +load 17 +load 17 +int 36 +extract_uint16 +dig 1 +len +substring3 +store 4 +load 0 +callsub boolcomp_3 +store 0 +load 1 +callsub numericalcomp_4 +store 1 +load 2 +callsub arraycomplement_6 +store 2 +load 3 +callsub stringreverse_7 +store 3 +load 4 +callsub tuplecomplement_8 +store 4 +byte 0x00 +int 0 +load 0 +setbit +byte 0x00 +int 0 +load 1 +setbyte +concat +load 2 +concat +load 3 +store 180 +load 180 +store 179 +int 38 +store 177 +load 177 +load 180 +len ++ +store 178 +load 178 +int 65536 +< +assert +load 177 +itob +extract 6 0 +concat +load 4 +store 180 +load 179 +load 180 +concat +store 179 +load 178 +store 177 +load 177 +itob +extract 6 0 +concat +load 179 +concat +store 18 +load 18 +retsub + +// array_complement +arraycomplement_1: +store 11 +load 11 +load 11 +int 2 +int 0 +* +int 2 ++ +extract_uint16 +int 2 ++ +int 0 +int 1 ++ +load 11 +int 0 +extract_uint16 +store 15 +load 15 +== +bnz arraycomplement_1_l5 +load 11 +int 2 +int 0 +* +int 2 ++ +int 2 ++ +extract_uint16 +int 2 ++ +arraycomplement_1_l2: +substring3 +store 13 +load 11 +load 11 +int 2 +int 1 +* +int 2 ++ +extract_uint16 +int 2 ++ +int 1 +int 1 ++ +load 11 +int 0 +extract_uint16 +store 16 +load 16 +== +bnz arraycomplement_1_l4 +load 11 +int 2 +int 1 +* +int 2 ++ +int 2 ++ +extract_uint16 +int 2 ++ +b arraycomplement_1_l6 +arraycomplement_1_l4: +load 11 +len +b arraycomplement_1_l6 +arraycomplement_1_l5: +load 11 +len +b arraycomplement_1_l2 +arraycomplement_1_l6: +substring3 +store 14 +load 13 +callsub tuplecomplement_0 +store 13 +load 14 +callsub tuplecomplement_0 +store 14 +int 2 +store 185 +load 185 +itob +extract 6 0 +load 13 +store 184 +load 184 +store 183 +int 4 +store 181 +load 181 +load 184 +len ++ +store 182 +load 182 +int 65536 +< +assert +load 181 +itob +extract 6 0 +load 14 +store 184 +load 183 +load 184 +concat +store 183 +load 182 +store 181 +load 181 +itob +extract 6 0 +concat +load 183 +concat +concat +store 12 +load 12 +retsub + +// round_tripper +roundtripper_2: +store 7 +load 7 +callsub arraycomplement_1 +store 9 +load 9 +callsub arraycomplement_1 +store 10 +load 7 +store 189 +load 189 +store 188 +int 6 +store 186 +load 186 +load 189 +len ++ +store 187 +load 187 +int 65536 +< +assert +load 186 +itob +extract 6 0 +load 9 +store 189 +load 188 +load 189 +concat +store 188 +load 187 +store 186 +load 186 +load 189 +len ++ +store 187 +load 187 +int 65536 +< +assert +load 186 +itob +extract 6 0 +concat +load 10 +store 189 +load 188 +load 189 +concat +store 188 +load 187 +store 186 +load 186 +itob +extract 6 0 +concat +load 188 +concat +store 8 +load 8 +retsub + +// bool_comp +boolcomp_3: +store 23 +load 23 +! +store 24 +load 24 +int 2 +< +assert +load 24 +retsub + +// numerical_comp +numericalcomp_4: +store 25 +int 255 +load 25 +- +store 26 +load 26 +int 256 +< +assert +load 26 +retsub + +// numerical_comp +numericalcomp_5: +store 61 +int 255 +load 61 +- +store 62 +load 62 +int 256 +< +assert +load 62 +retsub + +// array_complement +arraycomplement_6: +store 27 +load 27 +int 1 +int 0 +* +getbyte +store 29 +load 27 +int 1 +int 1 +* +getbyte +store 30 +load 27 +int 1 +int 2 +* +getbyte +store 31 +load 27 +int 1 +int 3 +* +getbyte +store 32 +load 27 +int 1 +int 4 +* +getbyte +store 33 +load 27 +int 1 +int 5 +* +getbyte +store 34 +load 27 +int 1 +int 6 +* +getbyte +store 35 +load 27 +int 1 +int 7 +* +getbyte +store 36 +load 27 +int 1 +int 8 +* +getbyte +store 37 +load 27 +int 1 +int 9 +* +getbyte +store 38 +load 27 +int 1 +int 10 +* +getbyte +store 39 +load 27 +int 1 +int 11 +* +getbyte +store 40 +load 27 +int 1 +int 12 +* +getbyte +store 41 +load 27 +int 1 +int 13 +* +getbyte +store 42 +load 27 +int 1 +int 14 +* +getbyte +store 43 +load 27 +int 1 +int 15 +* +getbyte +store 44 +load 27 +int 1 +int 16 +* +getbyte +store 45 +load 27 +int 1 +int 17 +* +getbyte +store 46 +load 27 +int 1 +int 18 +* +getbyte +store 47 +load 27 +int 1 +int 19 +* +getbyte +store 48 +load 27 +int 1 +int 20 +* +getbyte +store 49 +load 27 +int 1 +int 21 +* +getbyte +store 50 +load 27 +int 1 +int 22 +* +getbyte +store 51 +load 27 +int 1 +int 23 +* +getbyte +store 52 +load 27 +int 1 +int 24 +* +getbyte +store 53 +load 27 +int 1 +int 25 +* +getbyte +store 54 +load 27 +int 1 +int 26 +* +getbyte +store 55 +load 27 +int 1 +int 27 +* +getbyte +store 56 +load 27 +int 1 +int 28 +* +getbyte +store 57 +load 27 +int 1 +int 29 +* +getbyte +store 58 +load 27 +int 1 +int 30 +* +getbyte +store 59 +load 27 +int 1 +int 31 +* +getbyte +store 60 +load 29 +callsub numericalcomp_5 +store 29 +load 30 +callsub numericalcomp_5 +store 30 +load 31 +callsub numericalcomp_5 +store 31 +load 32 +callsub numericalcomp_5 +store 32 +load 33 +callsub numericalcomp_5 +store 33 +load 34 +callsub numericalcomp_5 +store 34 +load 35 +callsub numericalcomp_5 +store 35 +load 36 +callsub numericalcomp_5 +store 36 +load 37 +callsub numericalcomp_5 +store 37 +load 38 +callsub numericalcomp_5 +store 38 +load 39 +callsub numericalcomp_5 +store 39 +load 40 +callsub numericalcomp_5 +store 40 +load 41 +callsub numericalcomp_5 +store 41 +load 42 +callsub numericalcomp_5 +store 42 +load 43 +callsub numericalcomp_5 +store 43 +load 44 +callsub numericalcomp_5 +store 44 +load 45 +callsub numericalcomp_5 +store 45 +load 46 +callsub numericalcomp_5 +store 46 +load 47 +callsub numericalcomp_5 +store 47 +load 48 +callsub numericalcomp_5 +store 48 +load 49 +callsub numericalcomp_5 +store 49 +load 50 +callsub numericalcomp_5 +store 50 +load 51 +callsub numericalcomp_5 +store 51 +load 52 +callsub numericalcomp_5 +store 52 +load 53 +callsub numericalcomp_5 +store 53 +load 54 +callsub numericalcomp_5 +store 54 +load 55 +callsub numericalcomp_5 +store 55 +load 56 +callsub numericalcomp_5 +store 56 +load 57 +callsub numericalcomp_5 +store 57 +load 58 +callsub numericalcomp_5 +store 58 +load 59 +callsub numericalcomp_5 +store 59 +load 60 +callsub numericalcomp_5 +store 60 +byte 0x00 +int 0 +load 29 +setbyte +byte 0x00 +int 0 +load 30 +setbyte +concat +byte 0x00 +int 0 +load 31 +setbyte +concat +byte 0x00 +int 0 +load 32 +setbyte +concat +byte 0x00 +int 0 +load 33 +setbyte +concat +byte 0x00 +int 0 +load 34 +setbyte +concat +byte 0x00 +int 0 +load 35 +setbyte +concat +byte 0x00 +int 0 +load 36 +setbyte +concat +byte 0x00 +int 0 +load 37 +setbyte +concat +byte 0x00 +int 0 +load 38 +setbyte +concat +byte 0x00 +int 0 +load 39 +setbyte +concat +byte 0x00 +int 0 +load 40 +setbyte +concat +byte 0x00 +int 0 +load 41 +setbyte +concat +byte 0x00 +int 0 +load 42 +setbyte +concat +byte 0x00 +int 0 +load 43 +setbyte +concat +byte 0x00 +int 0 +load 44 +setbyte +concat +byte 0x00 +int 0 +load 45 +setbyte +concat +byte 0x00 +int 0 +load 46 +setbyte +concat +byte 0x00 +int 0 +load 47 +setbyte +concat +byte 0x00 +int 0 +load 48 +setbyte +concat +byte 0x00 +int 0 +load 49 +setbyte +concat +byte 0x00 +int 0 +load 50 +setbyte +concat +byte 0x00 +int 0 +load 51 +setbyte +concat +byte 0x00 +int 0 +load 52 +setbyte +concat +byte 0x00 +int 0 +load 53 +setbyte +concat +byte 0x00 +int 0 +load 54 +setbyte +concat +byte 0x00 +int 0 +load 55 +setbyte +concat +byte 0x00 +int 0 +load 56 +setbyte +concat +byte 0x00 +int 0 +load 57 +setbyte +concat +byte 0x00 +int 0 +load 58 +setbyte +concat +byte 0x00 +int 0 +load 59 +setbyte +concat +byte 0x00 +int 0 +load 60 +setbyte +concat +store 28 +load 28 +retsub + +// string_reverse +stringreverse_7: +store 63 +load 63 +int 1 +int 0 +* +int 2 ++ +getbyte +store 67 +load 63 +int 1 +int 1 +* +int 2 ++ +getbyte +store 66 +load 63 +int 1 +int 2 +* +int 2 ++ +getbyte +store 65 +int 3 +store 68 +load 68 +itob +extract 6 0 +byte 0x00 +int 0 +load 65 +setbyte +byte 0x00 +int 0 +load 66 +setbyte +concat +byte 0x00 +int 0 +load 67 +setbyte +concat +concat +store 64 +load 64 +retsub + +// tuple_complement +tuplecomplement_8: +store 69 +load 69 +extract 0 32 +store 19 +load 69 +load 69 +int 32 +extract_uint16 +load 69 +int 34 +extract_uint16 +substring3 +store 20 +load 69 +load 69 +int 34 +extract_uint16 +load 69 +int 36 +extract_uint16 +substring3 +store 21 +load 69 +load 69 +int 36 +extract_uint16 +dig 1 +len +substring3 +store 22 +load 19 +callsub arraycomplement_10 +store 19 +load 20 +callsub arraycomplement_12 +store 20 +load 21 +callsub stringreverse_13 +store 21 +load 22 +callsub arraycomplement_15 +store 22 +load 19 +load 20 +store 176 +load 176 +store 175 +int 38 +store 173 +load 173 +load 176 +len ++ +store 174 +load 174 +int 65536 +< +assert +load 173 +itob +extract 6 0 +concat +load 21 +store 176 +load 175 +load 176 +concat +store 175 +load 174 +store 173 +load 173 +load 176 +len ++ +store 174 +load 174 +int 65536 +< +assert +load 173 +itob +extract 6 0 +concat +load 22 +store 176 +load 175 +load 176 +concat +store 175 +load 174 +store 173 +load 173 +itob +extract 6 0 +concat +load 175 +concat +store 70 +load 70 +retsub + +// numerical_comp +numericalcomp_9: +store 110 +int 255 +load 110 +- +store 111 +load 111 +int 256 +< +assert +load 111 +retsub + +// array_complement +arraycomplement_10: +store 76 +load 76 +int 1 +int 0 +* +getbyte +store 78 +load 76 +int 1 +int 1 +* +getbyte +store 79 +load 76 +int 1 +int 2 +* +getbyte +store 80 +load 76 +int 1 +int 3 +* +getbyte +store 81 +load 76 +int 1 +int 4 +* +getbyte +store 82 +load 76 +int 1 +int 5 +* +getbyte +store 83 +load 76 +int 1 +int 6 +* +getbyte +store 84 +load 76 +int 1 +int 7 +* +getbyte +store 85 +load 76 +int 1 +int 8 +* +getbyte +store 86 +load 76 +int 1 +int 9 +* +getbyte +store 87 +load 76 +int 1 +int 10 +* +getbyte +store 88 +load 76 +int 1 +int 11 +* +getbyte +store 89 +load 76 +int 1 +int 12 +* +getbyte +store 90 +load 76 +int 1 +int 13 +* +getbyte +store 91 +load 76 +int 1 +int 14 +* +getbyte +store 92 +load 76 +int 1 +int 15 +* +getbyte +store 93 +load 76 +int 1 +int 16 +* +getbyte +store 94 +load 76 +int 1 +int 17 +* +getbyte +store 95 +load 76 +int 1 +int 18 +* +getbyte +store 96 +load 76 +int 1 +int 19 +* +getbyte +store 97 +load 76 +int 1 +int 20 +* +getbyte +store 98 +load 76 +int 1 +int 21 +* +getbyte +store 99 +load 76 +int 1 +int 22 +* +getbyte +store 100 +load 76 +int 1 +int 23 +* +getbyte +store 101 +load 76 +int 1 +int 24 +* +getbyte +store 102 +load 76 +int 1 +int 25 +* +getbyte +store 103 +load 76 +int 1 +int 26 +* +getbyte +store 104 +load 76 +int 1 +int 27 +* +getbyte +store 105 +load 76 +int 1 +int 28 +* +getbyte +store 106 +load 76 +int 1 +int 29 +* +getbyte +store 107 +load 76 +int 1 +int 30 +* +getbyte +store 108 +load 76 +int 1 +int 31 +* +getbyte +store 109 +load 78 +callsub numericalcomp_9 +store 78 +load 79 +callsub numericalcomp_9 +store 79 +load 80 +callsub numericalcomp_9 +store 80 +load 81 +callsub numericalcomp_9 +store 81 +load 82 +callsub numericalcomp_9 +store 82 +load 83 +callsub numericalcomp_9 +store 83 +load 84 +callsub numericalcomp_9 +store 84 +load 85 +callsub numericalcomp_9 +store 85 +load 86 +callsub numericalcomp_9 +store 86 +load 87 +callsub numericalcomp_9 +store 87 +load 88 +callsub numericalcomp_9 +store 88 +load 89 +callsub numericalcomp_9 +store 89 +load 90 +callsub numericalcomp_9 +store 90 +load 91 +callsub numericalcomp_9 +store 91 +load 92 +callsub numericalcomp_9 +store 92 +load 93 +callsub numericalcomp_9 +store 93 +load 94 +callsub numericalcomp_9 +store 94 +load 95 +callsub numericalcomp_9 +store 95 +load 96 +callsub numericalcomp_9 +store 96 +load 97 +callsub numericalcomp_9 +store 97 +load 98 +callsub numericalcomp_9 +store 98 +load 99 +callsub numericalcomp_9 +store 99 +load 100 +callsub numericalcomp_9 +store 100 +load 101 +callsub numericalcomp_9 +store 101 +load 102 +callsub numericalcomp_9 +store 102 +load 103 +callsub numericalcomp_9 +store 103 +load 104 +callsub numericalcomp_9 +store 104 +load 105 +callsub numericalcomp_9 +store 105 +load 106 +callsub numericalcomp_9 +store 106 +load 107 +callsub numericalcomp_9 +store 107 +load 108 +callsub numericalcomp_9 +store 108 +load 109 +callsub numericalcomp_9 +store 109 +byte 0x00 +int 0 +load 78 +setbyte +byte 0x00 +int 0 +load 79 +setbyte +concat +byte 0x00 +int 0 +load 80 +setbyte +concat +byte 0x00 +int 0 +load 81 +setbyte +concat +byte 0x00 +int 0 +load 82 +setbyte +concat +byte 0x00 +int 0 +load 83 +setbyte +concat +byte 0x00 +int 0 +load 84 +setbyte +concat +byte 0x00 +int 0 +load 85 +setbyte +concat +byte 0x00 +int 0 +load 86 +setbyte +concat +byte 0x00 +int 0 +load 87 +setbyte +concat +byte 0x00 +int 0 +load 88 +setbyte +concat +byte 0x00 +int 0 +load 89 +setbyte +concat +byte 0x00 +int 0 +load 90 +setbyte +concat +byte 0x00 +int 0 +load 91 +setbyte +concat +byte 0x00 +int 0 +load 92 +setbyte +concat +byte 0x00 +int 0 +load 93 +setbyte +concat +byte 0x00 +int 0 +load 94 +setbyte +concat +byte 0x00 +int 0 +load 95 +setbyte +concat +byte 0x00 +int 0 +load 96 +setbyte +concat +byte 0x00 +int 0 +load 97 +setbyte +concat +byte 0x00 +int 0 +load 98 +setbyte +concat +byte 0x00 +int 0 +load 99 +setbyte +concat +byte 0x00 +int 0 +load 100 +setbyte +concat +byte 0x00 +int 0 +load 101 +setbyte +concat +byte 0x00 +int 0 +load 102 +setbyte +concat +byte 0x00 +int 0 +load 103 +setbyte +concat +byte 0x00 +int 0 +load 104 +setbyte +concat +byte 0x00 +int 0 +load 105 +setbyte +concat +byte 0x00 +int 0 +load 106 +setbyte +concat +byte 0x00 +int 0 +load 107 +setbyte +concat +byte 0x00 +int 0 +load 108 +setbyte +concat +byte 0x00 +int 0 +load 109 +setbyte +concat +store 77 +load 77 +retsub + +// tuple_complement +tuplecomplement_11: +store 116 +load 116 +int 0 +extract_uint32 +store 71 +load 116 +load 116 +int 4 +extract_uint16 +dig 1 +len +substring3 +store 72 +load 116 +extract 6 1 +store 73 +load 116 +extract 7 1 +store 74 +load 116 +int 8 +getbyte +store 75 +load 71 +callsub numericalcomp_16 +store 71 +load 72 +callsub arraycomplement_18 +store 72 +load 73 +callsub arraycomplement_20 +store 73 +load 74 +callsub tuplecomplement_21 +store 74 +load 75 +callsub numericalcomp_22 +store 75 +load 71 +itob +extract 4 0 +load 72 +store 154 +load 154 +store 153 +int 9 +store 152 +load 152 +itob +extract 6 0 +concat +load 73 +concat +load 74 +concat +byte 0x00 +int 0 +load 75 +setbyte +concat +load 153 +concat +store 117 +load 117 +retsub + +// array_complement +arraycomplement_12: +store 112 +load 112 +load 112 +int 2 +int 0 +* +extract_uint16 +int 0 +int 1 ++ +int 2 +== +bnz arraycomplement_12_l5 +load 112 +int 2 +int 0 +* +int 2 ++ +extract_uint16 +arraycomplement_12_l2: +substring3 +store 114 +load 112 +load 112 +int 2 +int 1 +* +extract_uint16 +int 1 +int 1 ++ +int 2 +== +bnz arraycomplement_12_l4 +load 112 +int 2 +int 1 +* +int 2 ++ +extract_uint16 +b arraycomplement_12_l6 +arraycomplement_12_l4: +load 112 +len +b arraycomplement_12_l6 +arraycomplement_12_l5: +load 112 +len +b arraycomplement_12_l2 +arraycomplement_12_l6: +substring3 +store 115 +load 114 +callsub tuplecomplement_11 +store 114 +load 115 +callsub tuplecomplement_11 +store 115 +load 114 +store 158 +load 158 +store 157 +int 4 +store 155 +load 155 +load 158 +len ++ +store 156 +load 156 +int 65536 +< +assert +load 155 +itob +extract 6 0 +load 115 +store 158 +load 157 +load 158 +concat +store 157 +load 156 +store 155 +load 155 +itob +extract 6 0 +concat +load 157 +concat +store 113 +load 113 +retsub + +// string_reverse +stringreverse_13: +store 159 +load 159 +int 1 +int 0 +* +int 2 ++ +getbyte +store 163 +load 159 +int 1 +int 1 +* +int 2 ++ +getbyte +store 162 +load 159 +int 1 +int 2 +* +int 2 ++ +getbyte +store 161 +int 3 +store 164 +load 164 +itob +extract 6 0 +byte 0x00 +int 0 +load 161 +setbyte +byte 0x00 +int 0 +load 162 +setbyte +concat +byte 0x00 +int 0 +load 163 +setbyte +concat +concat +store 160 +load 160 +retsub + +// bool_comp +boolcomp_14: +store 170 +load 170 +! +store 171 +load 171 +int 2 +< +assert +load 171 +retsub + +// array_complement +arraycomplement_15: +store 165 +load 165 +int 0 +int 16 ++ +getbit +store 167 +load 165 +int 1 +int 16 ++ +getbit +store 168 +load 165 +int 2 +int 16 ++ +getbit +store 169 +load 167 +callsub boolcomp_14 +store 167 +load 168 +callsub boolcomp_14 +store 168 +load 169 +callsub boolcomp_14 +store 169 +int 3 +store 172 +load 172 +itob +extract 6 0 +byte 0x00 +int 0 +load 167 +setbit +int 1 +load 168 +setbit +int 2 +load 169 +setbit +concat +store 166 +load 166 +retsub + +// numerical_comp +numericalcomp_16: +store 119 +int 4294967295 +load 119 +- +store 120 +load 120 +int 4294967296 +< +assert +load 120 +retsub + +// string_reverse +stringreverse_17: +store 129 +load 129 +int 1 +int 0 +* +int 2 ++ +getbyte +store 133 +load 129 +int 1 +int 1 +* +int 2 ++ +getbyte +store 132 +load 129 +int 1 +int 2 +* +int 2 ++ +getbyte +store 131 +int 3 +store 134 +load 134 +itob +extract 6 0 +byte 0x00 +int 0 +load 131 +setbyte +byte 0x00 +int 0 +load 132 +setbyte +concat +byte 0x00 +int 0 +load 133 +setbyte +concat +concat +store 130 +load 130 +retsub + +// array_complement +arraycomplement_18: +store 121 +load 121 +load 121 +int 2 +int 0 +* +int 2 ++ +extract_uint16 +int 2 ++ +int 0 +int 1 ++ +load 121 +int 0 +extract_uint16 +store 126 +load 126 +== +bnz arraycomplement_18_l8 +load 121 +int 2 +int 0 +* +int 2 ++ +int 2 ++ +extract_uint16 +int 2 ++ +arraycomplement_18_l2: +substring3 +store 123 +load 121 +load 121 +int 2 +int 1 +* +int 2 ++ +extract_uint16 +int 2 ++ +int 1 +int 1 ++ +load 121 +int 0 +extract_uint16 +store 127 +load 127 +== +bnz arraycomplement_18_l7 +load 121 +int 2 +int 1 +* +int 2 ++ +int 2 ++ +extract_uint16 +int 2 ++ +arraycomplement_18_l4: +substring3 +store 124 +load 121 +load 121 +int 2 +int 2 +* +int 2 ++ +extract_uint16 +int 2 ++ +int 2 +int 1 ++ +load 121 +int 0 +extract_uint16 +store 128 +load 128 +== +bnz arraycomplement_18_l6 +load 121 +int 2 +int 2 +* +int 2 ++ +int 2 ++ +extract_uint16 +int 2 ++ +b arraycomplement_18_l9 +arraycomplement_18_l6: +load 121 +len +b arraycomplement_18_l9 +arraycomplement_18_l7: +load 121 +len +b arraycomplement_18_l4 +arraycomplement_18_l8: +load 121 +len +b arraycomplement_18_l2 +arraycomplement_18_l9: +substring3 +store 125 +load 123 +callsub stringreverse_17 +store 123 +load 124 +callsub stringreverse_17 +store 124 +load 125 +callsub stringreverse_17 +store 125 +int 3 +store 139 +load 139 +itob +extract 6 0 +load 123 +store 138 +load 138 +store 137 +int 6 +store 135 +load 135 +load 138 +len ++ +store 136 +load 136 +int 65536 +< +assert +load 135 +itob +extract 6 0 +load 124 +store 138 +load 137 +load 138 +concat +store 137 +load 136 +store 135 +load 135 +load 138 +len ++ +store 136 +load 136 +int 65536 +< +assert +load 135 +itob +extract 6 0 +concat +load 125 +store 138 +load 137 +load 138 +concat +store 137 +load 136 +store 135 +load 135 +itob +extract 6 0 +concat +load 137 +concat +concat +store 122 +load 122 +retsub + +// bool_comp +boolcomp_19: +store 144 +load 144 +! +store 145 +load 145 +int 2 +< +assert +load 145 +retsub + +// array_complement +arraycomplement_20: +store 140 +load 140 +int 0 +getbit +store 142 +load 140 +int 1 +getbit +store 143 +load 142 +callsub boolcomp_19 +store 142 +load 143 +callsub boolcomp_19 +store 143 +byte 0x00 +int 0 +load 142 +setbit +int 1 +load 143 +setbit +store 141 +load 141 +retsub + +// tuple_complement +tuplecomplement_21: +store 146 +load 146 +int 0 +getbyte +store 118 +load 118 +callsub numericalcomp_23 +store 118 +byte 0x00 +int 0 +load 118 +setbyte +store 147 +load 147 +retsub + +// numerical_comp +numericalcomp_22: +store 150 +int 255 +load 150 +- +store 151 +load 151 +int 256 +< +assert +load 151 +retsub + +// numerical_comp +numericalcomp_23: +store 148 +int 255 +load 148 +- +store 149 +load 149 +int 256 +< +assert +load 149 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32).teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32).teal new file mode 100644 index 000000000..7f8aabc87 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32).teal @@ -0,0 +1,106 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 4 +load 4 +callsub roundtripper_1 +store 3 +byte 0x151F7C75 +load 3 +concat +log +int 1 +return + +// tuple_complement +tuplecomplement_0: +store 9 +load 9 +int 0 +getbit +store 0 +load 9 +int 1 +extract_uint64 +store 1 +load 9 +int 9 +extract_uint32 +store 2 +load 0 +callsub boolcomp_2 +store 0 +load 1 +callsub numericalcomp_3 +store 1 +load 2 +callsub numericalcomp_4 +store 2 +byte 0x00 +int 0 +load 0 +setbit +load 1 +itob +concat +load 2 +itob +extract 4 0 +concat +store 10 +load 10 +retsub + +// round_tripper +roundtripper_1: +store 5 +load 5 +callsub tuplecomplement_0 +store 7 +load 7 +callsub tuplecomplement_0 +store 8 +load 5 +load 7 +concat +load 8 +concat +store 6 +load 6 +retsub + +// bool_comp +boolcomp_2: +store 11 +load 11 +! +store 12 +load 12 +int 2 +< +assert +load 12 +retsub + +// numerical_comp +numericalcomp_3: +store 13 +int 18446744073709551615 +load 13 +- +store 14 +load 14 +retsub + +// numerical_comp +numericalcomp_4: +store 15 +int 4294967295 +load 15 +- +store 16 +load 16 +int 4294967296 +< +assert +load 16 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(byte).teal b/tests/integration/teal/roundtrip/app_roundtrip_(byte).teal new file mode 100644 index 000000000..2a4c05465 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(byte).teal @@ -0,0 +1,62 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 2 +load 2 +callsub roundtripper_1 +store 1 +byte 0x151F7C75 +load 1 +concat +log +int 1 +return + +// tuple_complement +tuplecomplement_0: +store 7 +load 7 +int 0 +getbyte +store 0 +load 0 +callsub numericalcomp_2 +store 0 +byte 0x00 +int 0 +load 0 +setbyte +store 8 +load 8 +retsub + +// round_tripper +roundtripper_1: +store 3 +load 3 +callsub tuplecomplement_0 +store 5 +load 5 +callsub tuplecomplement_0 +store 6 +load 3 +load 5 +concat +load 6 +concat +store 4 +load 4 +retsub + +// numerical_comp +numericalcomp_2: +store 9 +int 255 +load 9 +- +store 10 +load 10 +int 256 +< +assert +load 10 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64).teal b/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64).teal new file mode 100644 index 000000000..cf613fa8c --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64).teal @@ -0,0 +1,107 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 4 +load 4 +callsub roundtripper_1 +store 3 +byte 0x151F7C75 +load 3 +concat +log +int 1 +return + +// tuple_complement +tuplecomplement_0: +store 9 +load 9 +int 0 +getbyte +store 0 +load 9 +int 8 +getbit +store 1 +load 9 +int 2 +extract_uint64 +store 2 +load 0 +callsub numericalcomp_2 +store 0 +load 1 +callsub boolcomp_3 +store 1 +load 2 +callsub numericalcomp_4 +store 2 +byte 0x00 +int 0 +load 0 +setbyte +byte 0x00 +int 0 +load 1 +setbit +concat +load 2 +itob +concat +store 10 +load 10 +retsub + +// round_tripper +roundtripper_1: +store 5 +load 5 +callsub tuplecomplement_0 +store 7 +load 7 +callsub tuplecomplement_0 +store 8 +load 5 +load 7 +concat +load 8 +concat +store 6 +load 6 +retsub + +// numerical_comp +numericalcomp_2: +store 11 +int 255 +load 11 +- +store 12 +load 12 +int 256 +< +assert +load 12 +retsub + +// bool_comp +boolcomp_3: +store 13 +load 13 +! +store 14 +load 14 +int 2 +< +assert +load 14 +retsub + +// numerical_comp +numericalcomp_4: +store 15 +int 18446744073709551615 +load 15 +- +store 16 +load 16 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_<7>.teal b/tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_<7>.teal new file mode 100644 index 000000000..c9b93fc85 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_<7>.teal @@ -0,0 +1,836 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 5 +load 5 +callsub roundtripper_2 +store 4 +byte 0x151F7C75 +load 4 +concat +log +int 1 +return + +// tuple_complement +tuplecomplement_0: +store 19 +load 19 +extract 0 4 +store 0 +load 19 +extract 4 1 +store 1 +load 19 +int 5 +extract_uint64 +store 2 +load 19 +extract 13 0 +store 3 +load 0 +callsub arraycomplement_4 +store 0 +load 1 +callsub tuplecomplement_5 +store 1 +load 2 +callsub numericalcomp_6 +store 2 +load 3 +callsub arraycomplement_8 +store 3 +load 0 +load 1 +concat +load 2 +itob +concat +load 3 +concat +store 20 +load 20 +retsub + +// array_complement +arraycomplement_1: +store 10 +load 10 +int 45 +int 0 +* +int 2 ++ +int 45 +extract3 +store 12 +load 10 +int 45 +int 1 +* +int 2 ++ +int 45 +extract3 +store 13 +load 10 +int 45 +int 2 +* +int 2 ++ +int 45 +extract3 +store 14 +load 10 +int 45 +int 3 +* +int 2 ++ +int 45 +extract3 +store 15 +load 10 +int 45 +int 4 +* +int 2 ++ +int 45 +extract3 +store 16 +load 10 +int 45 +int 5 +* +int 2 ++ +int 45 +extract3 +store 17 +load 10 +int 45 +int 6 +* +int 2 ++ +int 45 +extract3 +store 18 +load 12 +callsub tuplecomplement_0 +store 12 +load 13 +callsub tuplecomplement_0 +store 13 +load 14 +callsub tuplecomplement_0 +store 14 +load 15 +callsub tuplecomplement_0 +store 15 +load 16 +callsub tuplecomplement_0 +store 16 +load 17 +callsub tuplecomplement_0 +store 17 +load 18 +callsub tuplecomplement_0 +store 18 +int 7 +store 75 +load 75 +itob +extract 6 0 +load 12 +load 13 +concat +load 14 +concat +load 15 +concat +load 16 +concat +load 17 +concat +load 18 +concat +concat +store 11 +load 11 +retsub + +// round_tripper +roundtripper_2: +store 6 +load 6 +callsub arraycomplement_1 +store 8 +load 8 +callsub arraycomplement_1 +store 9 +load 6 +store 79 +load 79 +store 78 +int 6 +store 76 +load 76 +load 79 +len ++ +store 77 +load 77 +int 65536 +< +assert +load 76 +itob +extract 6 0 +load 8 +store 79 +load 78 +load 79 +concat +store 78 +load 77 +store 76 +load 76 +load 79 +len ++ +store 77 +load 77 +int 65536 +< +assert +load 76 +itob +extract 6 0 +concat +load 9 +store 79 +load 78 +load 79 +concat +store 78 +load 77 +store 76 +load 76 +itob +extract 6 0 +concat +load 78 +concat +store 7 +load 7 +retsub + +// numerical_comp +numericalcomp_3: +store 29 +int 255 +load 29 +- +store 30 +load 30 +int 256 +< +assert +load 30 +retsub + +// array_complement +arraycomplement_4: +store 23 +load 23 +int 1 +int 0 +* +getbyte +store 25 +load 23 +int 1 +int 1 +* +getbyte +store 26 +load 23 +int 1 +int 2 +* +getbyte +store 27 +load 23 +int 1 +int 3 +* +getbyte +store 28 +load 25 +callsub numericalcomp_3 +store 25 +load 26 +callsub numericalcomp_3 +store 26 +load 27 +callsub numericalcomp_3 +store 27 +load 28 +callsub numericalcomp_3 +store 28 +byte 0x00 +int 0 +load 25 +setbyte +byte 0x00 +int 0 +load 26 +setbyte +concat +byte 0x00 +int 0 +load 27 +setbyte +concat +byte 0x00 +int 0 +load 28 +setbyte +concat +store 24 +load 24 +retsub + +// tuple_complement +tuplecomplement_5: +store 31 +load 31 +int 0 +getbit +store 21 +load 31 +int 1 +getbit +store 22 +load 21 +callsub boolcomp_9 +store 21 +load 22 +callsub boolcomp_10 +store 22 +byte 0x00 +int 0 +load 21 +setbit +int 1 +load 22 +setbit +store 32 +load 32 +retsub + +// numerical_comp +numericalcomp_6: +store 37 +int 18446744073709551615 +load 37 +- +store 38 +load 38 +retsub + +// numerical_comp +numericalcomp_7: +store 73 +int 255 +load 73 +- +store 74 +load 74 +int 256 +< +assert +load 74 +retsub + +// array_complement +arraycomplement_8: +store 39 +load 39 +int 1 +int 0 +* +getbyte +store 41 +load 39 +int 1 +int 1 +* +getbyte +store 42 +load 39 +int 1 +int 2 +* +getbyte +store 43 +load 39 +int 1 +int 3 +* +getbyte +store 44 +load 39 +int 1 +int 4 +* +getbyte +store 45 +load 39 +int 1 +int 5 +* +getbyte +store 46 +load 39 +int 1 +int 6 +* +getbyte +store 47 +load 39 +int 1 +int 7 +* +getbyte +store 48 +load 39 +int 1 +int 8 +* +getbyte +store 49 +load 39 +int 1 +int 9 +* +getbyte +store 50 +load 39 +int 1 +int 10 +* +getbyte +store 51 +load 39 +int 1 +int 11 +* +getbyte +store 52 +load 39 +int 1 +int 12 +* +getbyte +store 53 +load 39 +int 1 +int 13 +* +getbyte +store 54 +load 39 +int 1 +int 14 +* +getbyte +store 55 +load 39 +int 1 +int 15 +* +getbyte +store 56 +load 39 +int 1 +int 16 +* +getbyte +store 57 +load 39 +int 1 +int 17 +* +getbyte +store 58 +load 39 +int 1 +int 18 +* +getbyte +store 59 +load 39 +int 1 +int 19 +* +getbyte +store 60 +load 39 +int 1 +int 20 +* +getbyte +store 61 +load 39 +int 1 +int 21 +* +getbyte +store 62 +load 39 +int 1 +int 22 +* +getbyte +store 63 +load 39 +int 1 +int 23 +* +getbyte +store 64 +load 39 +int 1 +int 24 +* +getbyte +store 65 +load 39 +int 1 +int 25 +* +getbyte +store 66 +load 39 +int 1 +int 26 +* +getbyte +store 67 +load 39 +int 1 +int 27 +* +getbyte +store 68 +load 39 +int 1 +int 28 +* +getbyte +store 69 +load 39 +int 1 +int 29 +* +getbyte +store 70 +load 39 +int 1 +int 30 +* +getbyte +store 71 +load 39 +int 1 +int 31 +* +getbyte +store 72 +load 41 +callsub numericalcomp_7 +store 41 +load 42 +callsub numericalcomp_7 +store 42 +load 43 +callsub numericalcomp_7 +store 43 +load 44 +callsub numericalcomp_7 +store 44 +load 45 +callsub numericalcomp_7 +store 45 +load 46 +callsub numericalcomp_7 +store 46 +load 47 +callsub numericalcomp_7 +store 47 +load 48 +callsub numericalcomp_7 +store 48 +load 49 +callsub numericalcomp_7 +store 49 +load 50 +callsub numericalcomp_7 +store 50 +load 51 +callsub numericalcomp_7 +store 51 +load 52 +callsub numericalcomp_7 +store 52 +load 53 +callsub numericalcomp_7 +store 53 +load 54 +callsub numericalcomp_7 +store 54 +load 55 +callsub numericalcomp_7 +store 55 +load 56 +callsub numericalcomp_7 +store 56 +load 57 +callsub numericalcomp_7 +store 57 +load 58 +callsub numericalcomp_7 +store 58 +load 59 +callsub numericalcomp_7 +store 59 +load 60 +callsub numericalcomp_7 +store 60 +load 61 +callsub numericalcomp_7 +store 61 +load 62 +callsub numericalcomp_7 +store 62 +load 63 +callsub numericalcomp_7 +store 63 +load 64 +callsub numericalcomp_7 +store 64 +load 65 +callsub numericalcomp_7 +store 65 +load 66 +callsub numericalcomp_7 +store 66 +load 67 +callsub numericalcomp_7 +store 67 +load 68 +callsub numericalcomp_7 +store 68 +load 69 +callsub numericalcomp_7 +store 69 +load 70 +callsub numericalcomp_7 +store 70 +load 71 +callsub numericalcomp_7 +store 71 +load 72 +callsub numericalcomp_7 +store 72 +byte 0x00 +int 0 +load 41 +setbyte +byte 0x00 +int 0 +load 42 +setbyte +concat +byte 0x00 +int 0 +load 43 +setbyte +concat +byte 0x00 +int 0 +load 44 +setbyte +concat +byte 0x00 +int 0 +load 45 +setbyte +concat +byte 0x00 +int 0 +load 46 +setbyte +concat +byte 0x00 +int 0 +load 47 +setbyte +concat +byte 0x00 +int 0 +load 48 +setbyte +concat +byte 0x00 +int 0 +load 49 +setbyte +concat +byte 0x00 +int 0 +load 50 +setbyte +concat +byte 0x00 +int 0 +load 51 +setbyte +concat +byte 0x00 +int 0 +load 52 +setbyte +concat +byte 0x00 +int 0 +load 53 +setbyte +concat +byte 0x00 +int 0 +load 54 +setbyte +concat +byte 0x00 +int 0 +load 55 +setbyte +concat +byte 0x00 +int 0 +load 56 +setbyte +concat +byte 0x00 +int 0 +load 57 +setbyte +concat +byte 0x00 +int 0 +load 58 +setbyte +concat +byte 0x00 +int 0 +load 59 +setbyte +concat +byte 0x00 +int 0 +load 60 +setbyte +concat +byte 0x00 +int 0 +load 61 +setbyte +concat +byte 0x00 +int 0 +load 62 +setbyte +concat +byte 0x00 +int 0 +load 63 +setbyte +concat +byte 0x00 +int 0 +load 64 +setbyte +concat +byte 0x00 +int 0 +load 65 +setbyte +concat +byte 0x00 +int 0 +load 66 +setbyte +concat +byte 0x00 +int 0 +load 67 +setbyte +concat +byte 0x00 +int 0 +load 68 +setbyte +concat +byte 0x00 +int 0 +load 69 +setbyte +concat +byte 0x00 +int 0 +load 70 +setbyte +concat +byte 0x00 +int 0 +load 71 +setbyte +concat +byte 0x00 +int 0 +load 72 +setbyte +concat +store 40 +load 40 +retsub + +// bool_comp +boolcomp_9: +store 33 +load 33 +! +store 34 +load 34 +int 2 +< +assert +load 34 +retsub + +// bool_comp +boolcomp_10: +store 35 +load 35 +! +store 36 +load 36 +int 2 +< +assert +load 36 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint16).teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint16).teal new file mode 100644 index 000000000..57d92721d --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint16).teal @@ -0,0 +1,61 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 2 +load 2 +callsub roundtripper_1 +store 1 +byte 0x151F7C75 +load 1 +concat +log +int 1 +return + +// tuple_complement +tuplecomplement_0: +store 7 +load 7 +int 0 +extract_uint16 +store 0 +load 0 +callsub numericalcomp_2 +store 0 +load 0 +itob +extract 6 0 +store 8 +load 8 +retsub + +// round_tripper +roundtripper_1: +store 3 +load 3 +callsub tuplecomplement_0 +store 5 +load 5 +callsub tuplecomplement_0 +store 6 +load 3 +load 5 +concat +load 6 +concat +store 4 +load 4 +retsub + +// numerical_comp +numericalcomp_2: +store 9 +int 65535 +load 9 +- +store 10 +load 10 +int 65536 +< +assert +load 10 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte).teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte).teal new file mode 100644 index 000000000..4af961953 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte).teal @@ -0,0 +1,113 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 4 +load 4 +callsub roundtripper_1 +store 3 +byte 0x151F7C75 +load 3 +concat +log +int 1 +return + +// tuple_complement +tuplecomplement_0: +store 9 +load 9 +int 0 +extract_uint16 +store 0 +load 9 +int 2 +getbyte +store 1 +load 9 +int 3 +getbyte +store 2 +load 0 +callsub numericalcomp_2 +store 0 +load 1 +callsub numericalcomp_3 +store 1 +load 2 +callsub numericalcomp_4 +store 2 +load 0 +itob +extract 6 0 +byte 0x00 +int 0 +load 1 +setbyte +concat +byte 0x00 +int 0 +load 2 +setbyte +concat +store 10 +load 10 +retsub + +// round_tripper +roundtripper_1: +store 5 +load 5 +callsub tuplecomplement_0 +store 7 +load 7 +callsub tuplecomplement_0 +store 8 +load 5 +load 7 +concat +load 8 +concat +store 6 +load 6 +retsub + +// numerical_comp +numericalcomp_2: +store 11 +int 65535 +load 11 +- +store 12 +load 12 +int 65536 +< +assert +load 12 +retsub + +// numerical_comp +numericalcomp_3: +store 13 +int 255 +load 13 +- +store 14 +load 14 +int 256 +< +assert +load 14 +retsub + +// numerical_comp +numericalcomp_4: +store 15 +int 255 +load 15 +- +store 16 +load 16 +int 256 +< +assert +load 16 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint32).teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint32).teal new file mode 100644 index 000000000..e8f3179f1 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint32).teal @@ -0,0 +1,61 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 2 +load 2 +callsub roundtripper_1 +store 1 +byte 0x151F7C75 +load 1 +concat +log +int 1 +return + +// tuple_complement +tuplecomplement_0: +store 7 +load 7 +int 0 +extract_uint32 +store 0 +load 0 +callsub numericalcomp_2 +store 0 +load 0 +itob +extract 4 0 +store 8 +load 8 +retsub + +// round_tripper +roundtripper_1: +store 3 +load 3 +callsub tuplecomplement_0 +store 5 +load 5 +callsub tuplecomplement_0 +store 6 +load 3 +load 5 +concat +load 6 +concat +store 4 +load 4 +retsub + +// numerical_comp +numericalcomp_2: +store 9 +int 4294967295 +load 9 +- +store 10 +load 10 +int 4294967296 +< +assert +load 10 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8).teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8).teal new file mode 100644 index 000000000..0194d3410 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8).teal @@ -0,0 +1,112 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 4 +load 4 +callsub roundtripper_1 +store 3 +byte 0x151F7C75 +load 3 +concat +log +int 1 +return + +// tuple_complement +tuplecomplement_0: +store 9 +load 9 +int 0 +extract_uint32 +store 0 +load 9 +int 4 +extract_uint16 +store 1 +load 9 +int 6 +getbyte +store 2 +load 0 +callsub numericalcomp_2 +store 0 +load 1 +callsub numericalcomp_3 +store 1 +load 2 +callsub numericalcomp_4 +store 2 +load 0 +itob +extract 4 0 +load 1 +itob +extract 6 0 +concat +byte 0x00 +int 0 +load 2 +setbyte +concat +store 10 +load 10 +retsub + +// round_tripper +roundtripper_1: +store 5 +load 5 +callsub tuplecomplement_0 +store 7 +load 7 +callsub tuplecomplement_0 +store 8 +load 5 +load 7 +concat +load 8 +concat +store 6 +load 6 +retsub + +// numerical_comp +numericalcomp_2: +store 11 +int 4294967295 +load 11 +- +store 12 +load 12 +int 4294967296 +< +assert +load 12 +retsub + +// numerical_comp +numericalcomp_3: +store 13 +int 65535 +load 13 +- +store 14 +load 14 +int 65536 +< +assert +load 14 +retsub + +// numerical_comp +numericalcomp_4: +store 15 +int 255 +load 15 +- +store 16 +load 16 +int 256 +< +assert +load 16 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint64).teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint64).teal new file mode 100644 index 000000000..2ef9adcec --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint64).teal @@ -0,0 +1,55 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 2 +load 2 +callsub roundtripper_1 +store 1 +byte 0x151F7C75 +load 1 +concat +log +int 1 +return + +// tuple_complement +tuplecomplement_0: +store 7 +load 7 +btoi +store 0 +load 0 +callsub numericalcomp_2 +store 0 +load 0 +itob +store 8 +load 8 +retsub + +// round_tripper +roundtripper_1: +store 3 +load 3 +callsub tuplecomplement_0 +store 5 +load 5 +callsub tuplecomplement_0 +store 6 +load 3 +load 5 +concat +load 6 +concat +store 4 +load 4 +retsub + +// numerical_comp +numericalcomp_2: +store 9 +int 18446744073709551615 +load 9 +- +store 10 +load 10 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16).teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16).teal new file mode 100644 index 000000000..7e33bb6ac --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16).teal @@ -0,0 +1,106 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 4 +load 4 +callsub roundtripper_1 +store 3 +byte 0x151F7C75 +load 3 +concat +log +int 1 +return + +// tuple_complement +tuplecomplement_0: +store 9 +load 9 +int 0 +extract_uint64 +store 0 +load 9 +int 8 +extract_uint32 +store 1 +load 9 +int 12 +extract_uint16 +store 2 +load 0 +callsub numericalcomp_2 +store 0 +load 1 +callsub numericalcomp_3 +store 1 +load 2 +callsub numericalcomp_4 +store 2 +load 0 +itob +load 1 +itob +extract 4 0 +concat +load 2 +itob +extract 6 0 +concat +store 10 +load 10 +retsub + +// round_tripper +roundtripper_1: +store 5 +load 5 +callsub tuplecomplement_0 +store 7 +load 7 +callsub tuplecomplement_0 +store 8 +load 5 +load 7 +concat +load 8 +concat +store 6 +load 6 +retsub + +// numerical_comp +numericalcomp_2: +store 11 +int 18446744073709551615 +load 11 +- +store 12 +load 12 +retsub + +// numerical_comp +numericalcomp_3: +store 13 +int 4294967295 +load 13 +- +store 14 +load 14 +int 4294967296 +< +assert +load 14 +retsub + +// numerical_comp +numericalcomp_4: +store 15 +int 65535 +load 15 +- +store 16 +load 16 +int 65536 +< +assert +load 16 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint8).teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint8).teal new file mode 100644 index 000000000..2a4c05465 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint8).teal @@ -0,0 +1,62 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 2 +load 2 +callsub roundtripper_1 +store 1 +byte 0x151F7C75 +load 1 +concat +log +int 1 +return + +// tuple_complement +tuplecomplement_0: +store 7 +load 7 +int 0 +getbyte +store 0 +load 0 +callsub numericalcomp_2 +store 0 +byte 0x00 +int 0 +load 0 +setbyte +store 8 +load 8 +retsub + +// round_tripper +roundtripper_1: +store 3 +load 3 +callsub tuplecomplement_0 +store 5 +load 5 +callsub tuplecomplement_0 +store 6 +load 3 +load 5 +concat +load 6 +concat +store 4 +load 4 +retsub + +// numerical_comp +numericalcomp_2: +store 9 +int 255 +load 9 +- +store 10 +load 10 +int 256 +< +assert +load 10 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool).teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool).teal new file mode 100644 index 000000000..8f7115164 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool).teal @@ -0,0 +1,113 @@ +#pragma version 6 +txna ApplicationArgs 0 // [uint8|byte|bool] +store 4 // 4 -> uint8|byte|bool +load 4 // [uint8|byte|bool] +callsub roundtripper_1 // [uint8|byte|bool | 255 - uint8 | 255 - byte | !bool | uint8|byte|bool] +store 3 // 3 -> uint8|byte|bool | 255 - uint8 | 255 - byte | !bool | uint8|byte|bool +byte 0x151F7C75 // [0x151F7C75] +load 3 // [0x151F7C75, uint8|byte|bool | 255 - uint8 | 255 - byte | !bool | uint8|byte|bool] +concat // [0x151F7C75 | uint8|byte|bool | 255 - uint8 | 255 - byte | !bool | uint8|byte|bool] +log // log(0x151F7C75 | uint8|byte|bool | 255 - uint8 | 255 - byte | !bool | uint8|byte|bool) +int 1 // [1] +return // PASSED + +// tuple_complement +tuplecomplement_0: // [uint8|byte|bool] +store 9 // 9 -> uint8|byte|bool +load 9 // [uint8|byte|bool] +int 0 // [uint8|byte|bool, 0] +getbyte // [uint8] +store 0 // 0 -> uint8 +load 9 // [uint8|byte|bool] +int 1 // [uint8|byte|bool, 1] +getbyte // [byte] +store 1 // 1 -> byte +load 9 // [uint8|byte|bool] +int 16 // [uint8|byte|bool, 16] +getbit // bool +store 2 // 2 -> bool +load 0 // [uint8] +callsub numericalcomp_2 // [255 - uint8] +store 0 // 0 -> 255 - uint8 +load 1 // [byte] +callsub numericalcomp_3 // [255 - byte] +store 1 // 1 -> 255 - byte +load 2 // [bool] +callsub boolcomp_4 // [!bool] +store 2 // 2 -> !bool +byte 0x00 // [0x00] +int 0 // [0x00, 0] +load 0 // [0x00, 0, 255 - uint8] +setbyte // [255 - uint8] +byte 0x00 // [255 - uint8, 0x00] +int 0 // [255 - uint8, 0x00, 0] +load 1 // [255 - uint8, 0x00, 0, 255 - byte] +setbyte // [255 - uint8, 255 - byte] +concat // [255 - uint8 | 255 - byte] +byte 0x00 // [255 - uint8 | 255 - byte, 0x00] +int 0 // [255 - uint8 | 255 - byte, 0x00, 0] +load 2 // [255 - uint8 | 255 - byte, 0x00, 0, !bool] +setbit // [255 - uint8 | 255 - byte, !bool] +concat // [255 - uint8 | 255 - byte | !bool] +store 10 // 10 -> 255 - uint8 | 255 - byte | !bool +load 10 // [255 - uint8 | 255 - byte | !bool] +retsub + +// round_tripper +roundtripper_1: // [uint8|byte|bool] +store 5 // 5 -> uint8|byte|bool +load 5 // [uint8|byte|bool] +callsub tuplecomplement_0 // [255 - uint8 | 255 - byte | !bool] +store 7 // 7 -> 255 - uint8 | 255 - byte | !bool +load 7 // [255 - uint8 | 255 - byte | !bool] +callsub tuplecomplement_0 // [255 - (255 - uint8) | 255 - (255 - byte) | !!bool] +store 8 // 8 -> uint8|byte|bool +load 5 // [uint8|byte|bool] +load 7 // [uint8|byte|bool, 255 - uint8 | 255 - byte | !bool] +concat // [uint8|byte|bool | 255 - uint8 | 255 - byte | !bool] +load 8 // [uint8|byte|bool | 255 - uint8 | 255 - byte | !bool, uint8|byte|bool] +concat // [uint8|byte|bool | 255 - uint8 | 255 - byte | !bool | uint8|byte|bool] +store 6 // 6 -> uint8|byte|bool | 255 - uint8 | 255 - byte | !bool | uint8|byte|bool +load 6 // [uint8|byte|bool | 255 - uint8 | 255 - byte | !bool | uint8|byte|bool] +retsub + +// numerical_comp +numericalcomp_2: // [uint8] +store 11 // 11 -> uint8 +int 255 // [255] +load 11 // [255, uint8] +- // [255 - uint8] +store 12 // 12 -> 255 - uint8 +load 12 // [255 - uint8] +int 256 // [255 - uint8, 256] +< // [1] +assert // [] +load 12 // [255 - uint8] +retsub + +// numerical_comp +numericalcomp_3: // [byte] +store 13 // 13 -> byte +int 255 // [255] +load 13 // [255, byte] +- // [255 - byte] +store 14 // 14 -> 255 - byte +load 14 // [255 - byte] +int 256 // [255 - byte, 256] +< // [1] +assert // [] +load 14 // [255 - byte] +retsub + +// bool_comp +boolcomp_4: // [bool] +store 15 // 15 -> bool +load 15 // [bool] +! // [!bool] +store 16 // 16 -> !bool +load 16 // [!bool] +int 2 // [!bool, 2] +< // [1] +assert // [] +load 16 // [!bool] +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_address.teal b/tests/integration/teal/roundtrip/app_roundtrip_address.teal new file mode 100644 index 000000000..0bc930d45 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_address.teal @@ -0,0 +1,498 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 1 +load 1 +callsub roundtripper_2 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// numerical_comp +numericalcomp_0: +store 40 +int 255 +load 40 +- +store 41 +load 41 +int 256 +< +assert +load 41 +retsub + +// array_complement +arraycomplement_1: +store 6 +load 6 +int 1 +int 0 +* +getbyte +store 8 +load 6 +int 1 +int 1 +* +getbyte +store 9 +load 6 +int 1 +int 2 +* +getbyte +store 10 +load 6 +int 1 +int 3 +* +getbyte +store 11 +load 6 +int 1 +int 4 +* +getbyte +store 12 +load 6 +int 1 +int 5 +* +getbyte +store 13 +load 6 +int 1 +int 6 +* +getbyte +store 14 +load 6 +int 1 +int 7 +* +getbyte +store 15 +load 6 +int 1 +int 8 +* +getbyte +store 16 +load 6 +int 1 +int 9 +* +getbyte +store 17 +load 6 +int 1 +int 10 +* +getbyte +store 18 +load 6 +int 1 +int 11 +* +getbyte +store 19 +load 6 +int 1 +int 12 +* +getbyte +store 20 +load 6 +int 1 +int 13 +* +getbyte +store 21 +load 6 +int 1 +int 14 +* +getbyte +store 22 +load 6 +int 1 +int 15 +* +getbyte +store 23 +load 6 +int 1 +int 16 +* +getbyte +store 24 +load 6 +int 1 +int 17 +* +getbyte +store 25 +load 6 +int 1 +int 18 +* +getbyte +store 26 +load 6 +int 1 +int 19 +* +getbyte +store 27 +load 6 +int 1 +int 20 +* +getbyte +store 28 +load 6 +int 1 +int 21 +* +getbyte +store 29 +load 6 +int 1 +int 22 +* +getbyte +store 30 +load 6 +int 1 +int 23 +* +getbyte +store 31 +load 6 +int 1 +int 24 +* +getbyte +store 32 +load 6 +int 1 +int 25 +* +getbyte +store 33 +load 6 +int 1 +int 26 +* +getbyte +store 34 +load 6 +int 1 +int 27 +* +getbyte +store 35 +load 6 +int 1 +int 28 +* +getbyte +store 36 +load 6 +int 1 +int 29 +* +getbyte +store 37 +load 6 +int 1 +int 30 +* +getbyte +store 38 +load 6 +int 1 +int 31 +* +getbyte +store 39 +load 8 +callsub numericalcomp_0 +store 8 +load 9 +callsub numericalcomp_0 +store 9 +load 10 +callsub numericalcomp_0 +store 10 +load 11 +callsub numericalcomp_0 +store 11 +load 12 +callsub numericalcomp_0 +store 12 +load 13 +callsub numericalcomp_0 +store 13 +load 14 +callsub numericalcomp_0 +store 14 +load 15 +callsub numericalcomp_0 +store 15 +load 16 +callsub numericalcomp_0 +store 16 +load 17 +callsub numericalcomp_0 +store 17 +load 18 +callsub numericalcomp_0 +store 18 +load 19 +callsub numericalcomp_0 +store 19 +load 20 +callsub numericalcomp_0 +store 20 +load 21 +callsub numericalcomp_0 +store 21 +load 22 +callsub numericalcomp_0 +store 22 +load 23 +callsub numericalcomp_0 +store 23 +load 24 +callsub numericalcomp_0 +store 24 +load 25 +callsub numericalcomp_0 +store 25 +load 26 +callsub numericalcomp_0 +store 26 +load 27 +callsub numericalcomp_0 +store 27 +load 28 +callsub numericalcomp_0 +store 28 +load 29 +callsub numericalcomp_0 +store 29 +load 30 +callsub numericalcomp_0 +store 30 +load 31 +callsub numericalcomp_0 +store 31 +load 32 +callsub numericalcomp_0 +store 32 +load 33 +callsub numericalcomp_0 +store 33 +load 34 +callsub numericalcomp_0 +store 34 +load 35 +callsub numericalcomp_0 +store 35 +load 36 +callsub numericalcomp_0 +store 36 +load 37 +callsub numericalcomp_0 +store 37 +load 38 +callsub numericalcomp_0 +store 38 +load 39 +callsub numericalcomp_0 +store 39 +byte 0x00 +int 0 +load 8 +setbyte +byte 0x00 +int 0 +load 9 +setbyte +concat +byte 0x00 +int 0 +load 10 +setbyte +concat +byte 0x00 +int 0 +load 11 +setbyte +concat +byte 0x00 +int 0 +load 12 +setbyte +concat +byte 0x00 +int 0 +load 13 +setbyte +concat +byte 0x00 +int 0 +load 14 +setbyte +concat +byte 0x00 +int 0 +load 15 +setbyte +concat +byte 0x00 +int 0 +load 16 +setbyte +concat +byte 0x00 +int 0 +load 17 +setbyte +concat +byte 0x00 +int 0 +load 18 +setbyte +concat +byte 0x00 +int 0 +load 19 +setbyte +concat +byte 0x00 +int 0 +load 20 +setbyte +concat +byte 0x00 +int 0 +load 21 +setbyte +concat +byte 0x00 +int 0 +load 22 +setbyte +concat +byte 0x00 +int 0 +load 23 +setbyte +concat +byte 0x00 +int 0 +load 24 +setbyte +concat +byte 0x00 +int 0 +load 25 +setbyte +concat +byte 0x00 +int 0 +load 26 +setbyte +concat +byte 0x00 +int 0 +load 27 +setbyte +concat +byte 0x00 +int 0 +load 28 +setbyte +concat +byte 0x00 +int 0 +load 29 +setbyte +concat +byte 0x00 +int 0 +load 30 +setbyte +concat +byte 0x00 +int 0 +load 31 +setbyte +concat +byte 0x00 +int 0 +load 32 +setbyte +concat +byte 0x00 +int 0 +load 33 +setbyte +concat +byte 0x00 +int 0 +load 34 +setbyte +concat +byte 0x00 +int 0 +load 35 +setbyte +concat +byte 0x00 +int 0 +load 36 +setbyte +concat +byte 0x00 +int 0 +load 37 +setbyte +concat +byte 0x00 +int 0 +load 38 +setbyte +concat +byte 0x00 +int 0 +load 39 +setbyte +concat +store 7 +load 7 +retsub + +// round_tripper +roundtripper_2: +store 2 +load 2 +callsub arraycomplement_1 +store 4 +load 4 +callsub arraycomplement_1 +store 5 +load 2 +load 4 +concat +load 5 +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_address[]_<10>.teal b/tests/integration/teal/roundtrip/app_roundtrip_address[]_<10>.teal new file mode 100644 index 000000000..c406dcc4c --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_address[]_<10>.teal @@ -0,0 +1,698 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 1 +load 1 +callsub roundtripper_3 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// numerical_comp +numericalcomp_0: +store 52 +int 255 +load 52 +- +store 53 +load 53 +int 256 +< +assert +load 53 +retsub + +// array_complement +arraycomplement_1: +store 18 +load 18 +int 1 +int 0 +* +getbyte +store 20 +load 18 +int 1 +int 1 +* +getbyte +store 21 +load 18 +int 1 +int 2 +* +getbyte +store 22 +load 18 +int 1 +int 3 +* +getbyte +store 23 +load 18 +int 1 +int 4 +* +getbyte +store 24 +load 18 +int 1 +int 5 +* +getbyte +store 25 +load 18 +int 1 +int 6 +* +getbyte +store 26 +load 18 +int 1 +int 7 +* +getbyte +store 27 +load 18 +int 1 +int 8 +* +getbyte +store 28 +load 18 +int 1 +int 9 +* +getbyte +store 29 +load 18 +int 1 +int 10 +* +getbyte +store 30 +load 18 +int 1 +int 11 +* +getbyte +store 31 +load 18 +int 1 +int 12 +* +getbyte +store 32 +load 18 +int 1 +int 13 +* +getbyte +store 33 +load 18 +int 1 +int 14 +* +getbyte +store 34 +load 18 +int 1 +int 15 +* +getbyte +store 35 +load 18 +int 1 +int 16 +* +getbyte +store 36 +load 18 +int 1 +int 17 +* +getbyte +store 37 +load 18 +int 1 +int 18 +* +getbyte +store 38 +load 18 +int 1 +int 19 +* +getbyte +store 39 +load 18 +int 1 +int 20 +* +getbyte +store 40 +load 18 +int 1 +int 21 +* +getbyte +store 41 +load 18 +int 1 +int 22 +* +getbyte +store 42 +load 18 +int 1 +int 23 +* +getbyte +store 43 +load 18 +int 1 +int 24 +* +getbyte +store 44 +load 18 +int 1 +int 25 +* +getbyte +store 45 +load 18 +int 1 +int 26 +* +getbyte +store 46 +load 18 +int 1 +int 27 +* +getbyte +store 47 +load 18 +int 1 +int 28 +* +getbyte +store 48 +load 18 +int 1 +int 29 +* +getbyte +store 49 +load 18 +int 1 +int 30 +* +getbyte +store 50 +load 18 +int 1 +int 31 +* +getbyte +store 51 +load 20 +callsub numericalcomp_0 +store 20 +load 21 +callsub numericalcomp_0 +store 21 +load 22 +callsub numericalcomp_0 +store 22 +load 23 +callsub numericalcomp_0 +store 23 +load 24 +callsub numericalcomp_0 +store 24 +load 25 +callsub numericalcomp_0 +store 25 +load 26 +callsub numericalcomp_0 +store 26 +load 27 +callsub numericalcomp_0 +store 27 +load 28 +callsub numericalcomp_0 +store 28 +load 29 +callsub numericalcomp_0 +store 29 +load 30 +callsub numericalcomp_0 +store 30 +load 31 +callsub numericalcomp_0 +store 31 +load 32 +callsub numericalcomp_0 +store 32 +load 33 +callsub numericalcomp_0 +store 33 +load 34 +callsub numericalcomp_0 +store 34 +load 35 +callsub numericalcomp_0 +store 35 +load 36 +callsub numericalcomp_0 +store 36 +load 37 +callsub numericalcomp_0 +store 37 +load 38 +callsub numericalcomp_0 +store 38 +load 39 +callsub numericalcomp_0 +store 39 +load 40 +callsub numericalcomp_0 +store 40 +load 41 +callsub numericalcomp_0 +store 41 +load 42 +callsub numericalcomp_0 +store 42 +load 43 +callsub numericalcomp_0 +store 43 +load 44 +callsub numericalcomp_0 +store 44 +load 45 +callsub numericalcomp_0 +store 45 +load 46 +callsub numericalcomp_0 +store 46 +load 47 +callsub numericalcomp_0 +store 47 +load 48 +callsub numericalcomp_0 +store 48 +load 49 +callsub numericalcomp_0 +store 49 +load 50 +callsub numericalcomp_0 +store 50 +load 51 +callsub numericalcomp_0 +store 51 +byte 0x00 +int 0 +load 20 +setbyte +byte 0x00 +int 0 +load 21 +setbyte +concat +byte 0x00 +int 0 +load 22 +setbyte +concat +byte 0x00 +int 0 +load 23 +setbyte +concat +byte 0x00 +int 0 +load 24 +setbyte +concat +byte 0x00 +int 0 +load 25 +setbyte +concat +byte 0x00 +int 0 +load 26 +setbyte +concat +byte 0x00 +int 0 +load 27 +setbyte +concat +byte 0x00 +int 0 +load 28 +setbyte +concat +byte 0x00 +int 0 +load 29 +setbyte +concat +byte 0x00 +int 0 +load 30 +setbyte +concat +byte 0x00 +int 0 +load 31 +setbyte +concat +byte 0x00 +int 0 +load 32 +setbyte +concat +byte 0x00 +int 0 +load 33 +setbyte +concat +byte 0x00 +int 0 +load 34 +setbyte +concat +byte 0x00 +int 0 +load 35 +setbyte +concat +byte 0x00 +int 0 +load 36 +setbyte +concat +byte 0x00 +int 0 +load 37 +setbyte +concat +byte 0x00 +int 0 +load 38 +setbyte +concat +byte 0x00 +int 0 +load 39 +setbyte +concat +byte 0x00 +int 0 +load 40 +setbyte +concat +byte 0x00 +int 0 +load 41 +setbyte +concat +byte 0x00 +int 0 +load 42 +setbyte +concat +byte 0x00 +int 0 +load 43 +setbyte +concat +byte 0x00 +int 0 +load 44 +setbyte +concat +byte 0x00 +int 0 +load 45 +setbyte +concat +byte 0x00 +int 0 +load 46 +setbyte +concat +byte 0x00 +int 0 +load 47 +setbyte +concat +byte 0x00 +int 0 +load 48 +setbyte +concat +byte 0x00 +int 0 +load 49 +setbyte +concat +byte 0x00 +int 0 +load 50 +setbyte +concat +byte 0x00 +int 0 +load 51 +setbyte +concat +store 19 +load 19 +retsub + +// array_complement +arraycomplement_2: +store 6 +load 6 +int 32 +int 0 +* +int 2 ++ +int 32 +extract3 +store 8 +load 6 +int 32 +int 1 +* +int 2 ++ +int 32 +extract3 +store 9 +load 6 +int 32 +int 2 +* +int 2 ++ +int 32 +extract3 +store 10 +load 6 +int 32 +int 3 +* +int 2 ++ +int 32 +extract3 +store 11 +load 6 +int 32 +int 4 +* +int 2 ++ +int 32 +extract3 +store 12 +load 6 +int 32 +int 5 +* +int 2 ++ +int 32 +extract3 +store 13 +load 6 +int 32 +int 6 +* +int 2 ++ +int 32 +extract3 +store 14 +load 6 +int 32 +int 7 +* +int 2 ++ +int 32 +extract3 +store 15 +load 6 +int 32 +int 8 +* +int 2 ++ +int 32 +extract3 +store 16 +load 6 +int 32 +int 9 +* +int 2 ++ +int 32 +extract3 +store 17 +load 8 +callsub arraycomplement_1 +store 8 +load 9 +callsub arraycomplement_1 +store 9 +load 10 +callsub arraycomplement_1 +store 10 +load 11 +callsub arraycomplement_1 +store 11 +load 12 +callsub arraycomplement_1 +store 12 +load 13 +callsub arraycomplement_1 +store 13 +load 14 +callsub arraycomplement_1 +store 14 +load 15 +callsub arraycomplement_1 +store 15 +load 16 +callsub arraycomplement_1 +store 16 +load 17 +callsub arraycomplement_1 +store 17 +int 10 +store 54 +load 54 +itob +extract 6 0 +load 8 +load 9 +concat +load 10 +concat +load 11 +concat +load 12 +concat +load 13 +concat +load 14 +concat +load 15 +concat +load 16 +concat +load 17 +concat +concat +store 7 +load 7 +retsub + +// round_tripper +roundtripper_3: +store 2 +load 2 +callsub arraycomplement_2 +store 4 +load 4 +callsub arraycomplement_2 +store 5 +load 2 +store 58 +load 58 +store 57 +int 6 +store 55 +load 55 +load 58 +len ++ +store 56 +load 56 +int 65536 +< +assert +load 55 +itob +extract 6 0 +load 4 +store 58 +load 57 +load 58 +concat +store 57 +load 56 +store 55 +load 55 +load 58 +len ++ +store 56 +load 56 +int 65536 +< +assert +load 55 +itob +extract 6 0 +concat +load 5 +store 58 +load 57 +load 58 +concat +store 57 +load 56 +store 55 +load 55 +itob +extract 6 0 +concat +load 57 +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool.teal new file mode 100644 index 000000000..bc91494eb --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool.teal @@ -0,0 +1,52 @@ +#pragma version 6 +txna ApplicationArgs 0 +int 0 +int 8 +* +getbit +store 1 +load 1 +callsub roundtripper_1 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// bool_comp +boolcomp_0: +store 6 +load 6 +! +store 7 +load 7 +int 2 +< +assert +load 7 +retsub + +// round_tripper +roundtripper_1: +store 2 +load 2 +callsub boolcomp_0 +store 4 +load 4 +callsub boolcomp_0 +store 5 +byte 0x00 +int 0 +load 2 +setbit +int 1 +load 4 +setbit +int 2 +load 5 +setbit +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[1].teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[1].teal new file mode 100644 index 000000000..399bcf910 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[1].teal @@ -0,0 +1,61 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 1 +load 1 +callsub roundtripper_2 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// bool_comp +boolcomp_0: +store 9 +load 9 +! +store 10 +load 10 +int 2 +< +assert +load 10 +retsub + +// array_complement +arraycomplement_1: +store 6 +load 6 +int 0 +getbit +store 8 +load 8 +callsub boolcomp_0 +store 8 +byte 0x00 +int 0 +load 8 +setbit +store 7 +load 7 +retsub + +// round_tripper +roundtripper_2: +store 2 +load 2 +callsub arraycomplement_1 +store 4 +load 4 +callsub arraycomplement_1 +store 5 +load 2 +load 4 +concat +load 5 +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_<11>.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_<11>.teal new file mode 100644 index 000000000..0c8f9c611 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_<11>.teal @@ -0,0 +1,295 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 1 +load 1 +callsub roundtripper_3 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// bool_comp +boolcomp_0: +store 24 +load 24 +! +store 25 +load 25 +int 2 +< +assert +load 25 +retsub + +// array_complement +arraycomplement_1: +store 19 +load 19 +int 0 +getbit +store 21 +load 19 +int 1 +getbit +store 22 +load 19 +int 2 +getbit +store 23 +load 21 +callsub boolcomp_0 +store 21 +load 22 +callsub boolcomp_0 +store 22 +load 23 +callsub boolcomp_0 +store 23 +byte 0x00 +int 0 +load 21 +setbit +int 1 +load 22 +setbit +int 2 +load 23 +setbit +store 20 +load 20 +retsub + +// array_complement +arraycomplement_2: +store 6 +load 6 +int 1 +int 0 +* +int 2 ++ +int 1 +extract3 +store 8 +load 6 +int 1 +int 1 +* +int 2 ++ +int 1 +extract3 +store 9 +load 6 +int 1 +int 2 +* +int 2 ++ +int 1 +extract3 +store 10 +load 6 +int 1 +int 3 +* +int 2 ++ +int 1 +extract3 +store 11 +load 6 +int 1 +int 4 +* +int 2 ++ +int 1 +extract3 +store 12 +load 6 +int 1 +int 5 +* +int 2 ++ +int 1 +extract3 +store 13 +load 6 +int 1 +int 6 +* +int 2 ++ +int 1 +extract3 +store 14 +load 6 +int 1 +int 7 +* +int 2 ++ +int 1 +extract3 +store 15 +load 6 +int 1 +int 8 +* +int 2 ++ +int 1 +extract3 +store 16 +load 6 +int 1 +int 9 +* +int 2 ++ +int 1 +extract3 +store 17 +load 6 +int 1 +int 10 +* +int 2 ++ +int 1 +extract3 +store 18 +load 8 +callsub arraycomplement_1 +store 8 +load 9 +callsub arraycomplement_1 +store 9 +load 10 +callsub arraycomplement_1 +store 10 +load 11 +callsub arraycomplement_1 +store 11 +load 12 +callsub arraycomplement_1 +store 12 +load 13 +callsub arraycomplement_1 +store 13 +load 14 +callsub arraycomplement_1 +store 14 +load 15 +callsub arraycomplement_1 +store 15 +load 16 +callsub arraycomplement_1 +store 16 +load 17 +callsub arraycomplement_1 +store 17 +load 18 +callsub arraycomplement_1 +store 18 +int 11 +store 26 +load 26 +itob +extract 6 0 +load 8 +load 9 +concat +load 10 +concat +load 11 +concat +load 12 +concat +load 13 +concat +load 14 +concat +load 15 +concat +load 16 +concat +load 17 +concat +load 18 +concat +concat +store 7 +load 7 +retsub + +// round_tripper +roundtripper_3: +store 2 +load 2 +callsub arraycomplement_2 +store 4 +load 4 +callsub arraycomplement_2 +store 5 +load 2 +store 30 +load 30 +store 29 +int 6 +store 27 +load 27 +load 30 +len ++ +store 28 +load 28 +int 65536 +< +assert +load 27 +itob +extract 6 0 +load 4 +store 30 +load 29 +load 30 +concat +store 29 +load 28 +store 27 +load 27 +load 30 +len ++ +store 28 +load 28 +int 65536 +< +assert +load 27 +itob +extract 6 0 +concat +load 5 +store 30 +load 29 +load 30 +concat +store 29 +load 28 +store 27 +load 27 +itob +extract 6 0 +concat +load 29 +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[42].teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[42].teal new file mode 100644 index 000000000..c0026b483 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[42].teal @@ -0,0 +1,471 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 1 +load 1 +callsub roundtripper_2 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// bool_comp +boolcomp_0: +store 50 +load 50 +! +store 51 +load 51 +int 2 +< +assert +load 51 +retsub + +// array_complement +arraycomplement_1: +store 6 +load 6 +int 0 +getbit +store 8 +load 6 +int 1 +getbit +store 9 +load 6 +int 2 +getbit +store 10 +load 6 +int 3 +getbit +store 11 +load 6 +int 4 +getbit +store 12 +load 6 +int 5 +getbit +store 13 +load 6 +int 6 +getbit +store 14 +load 6 +int 7 +getbit +store 15 +load 6 +int 8 +getbit +store 16 +load 6 +int 9 +getbit +store 17 +load 6 +int 10 +getbit +store 18 +load 6 +int 11 +getbit +store 19 +load 6 +int 12 +getbit +store 20 +load 6 +int 13 +getbit +store 21 +load 6 +int 14 +getbit +store 22 +load 6 +int 15 +getbit +store 23 +load 6 +int 16 +getbit +store 24 +load 6 +int 17 +getbit +store 25 +load 6 +int 18 +getbit +store 26 +load 6 +int 19 +getbit +store 27 +load 6 +int 20 +getbit +store 28 +load 6 +int 21 +getbit +store 29 +load 6 +int 22 +getbit +store 30 +load 6 +int 23 +getbit +store 31 +load 6 +int 24 +getbit +store 32 +load 6 +int 25 +getbit +store 33 +load 6 +int 26 +getbit +store 34 +load 6 +int 27 +getbit +store 35 +load 6 +int 28 +getbit +store 36 +load 6 +int 29 +getbit +store 37 +load 6 +int 30 +getbit +store 38 +load 6 +int 31 +getbit +store 39 +load 6 +int 32 +getbit +store 40 +load 6 +int 33 +getbit +store 41 +load 6 +int 34 +getbit +store 42 +load 6 +int 35 +getbit +store 43 +load 6 +int 36 +getbit +store 44 +load 6 +int 37 +getbit +store 45 +load 6 +int 38 +getbit +store 46 +load 6 +int 39 +getbit +store 47 +load 6 +int 40 +getbit +store 48 +load 6 +int 41 +getbit +store 49 +load 8 +callsub boolcomp_0 +store 8 +load 9 +callsub boolcomp_0 +store 9 +load 10 +callsub boolcomp_0 +store 10 +load 11 +callsub boolcomp_0 +store 11 +load 12 +callsub boolcomp_0 +store 12 +load 13 +callsub boolcomp_0 +store 13 +load 14 +callsub boolcomp_0 +store 14 +load 15 +callsub boolcomp_0 +store 15 +load 16 +callsub boolcomp_0 +store 16 +load 17 +callsub boolcomp_0 +store 17 +load 18 +callsub boolcomp_0 +store 18 +load 19 +callsub boolcomp_0 +store 19 +load 20 +callsub boolcomp_0 +store 20 +load 21 +callsub boolcomp_0 +store 21 +load 22 +callsub boolcomp_0 +store 22 +load 23 +callsub boolcomp_0 +store 23 +load 24 +callsub boolcomp_0 +store 24 +load 25 +callsub boolcomp_0 +store 25 +load 26 +callsub boolcomp_0 +store 26 +load 27 +callsub boolcomp_0 +store 27 +load 28 +callsub boolcomp_0 +store 28 +load 29 +callsub boolcomp_0 +store 29 +load 30 +callsub boolcomp_0 +store 30 +load 31 +callsub boolcomp_0 +store 31 +load 32 +callsub boolcomp_0 +store 32 +load 33 +callsub boolcomp_0 +store 33 +load 34 +callsub boolcomp_0 +store 34 +load 35 +callsub boolcomp_0 +store 35 +load 36 +callsub boolcomp_0 +store 36 +load 37 +callsub boolcomp_0 +store 37 +load 38 +callsub boolcomp_0 +store 38 +load 39 +callsub boolcomp_0 +store 39 +load 40 +callsub boolcomp_0 +store 40 +load 41 +callsub boolcomp_0 +store 41 +load 42 +callsub boolcomp_0 +store 42 +load 43 +callsub boolcomp_0 +store 43 +load 44 +callsub boolcomp_0 +store 44 +load 45 +callsub boolcomp_0 +store 45 +load 46 +callsub boolcomp_0 +store 46 +load 47 +callsub boolcomp_0 +store 47 +load 48 +callsub boolcomp_0 +store 48 +load 49 +callsub boolcomp_0 +store 49 +byte 0x000000000000 +int 0 +load 8 +setbit +int 1 +load 9 +setbit +int 2 +load 10 +setbit +int 3 +load 11 +setbit +int 4 +load 12 +setbit +int 5 +load 13 +setbit +int 6 +load 14 +setbit +int 7 +load 15 +setbit +int 8 +load 16 +setbit +int 9 +load 17 +setbit +int 10 +load 18 +setbit +int 11 +load 19 +setbit +int 12 +load 20 +setbit +int 13 +load 21 +setbit +int 14 +load 22 +setbit +int 15 +load 23 +setbit +int 16 +load 24 +setbit +int 17 +load 25 +setbit +int 18 +load 26 +setbit +int 19 +load 27 +setbit +int 20 +load 28 +setbit +int 21 +load 29 +setbit +int 22 +load 30 +setbit +int 23 +load 31 +setbit +int 24 +load 32 +setbit +int 25 +load 33 +setbit +int 26 +load 34 +setbit +int 27 +load 35 +setbit +int 28 +load 36 +setbit +int 29 +load 37 +setbit +int 30 +load 38 +setbit +int 31 +load 39 +setbit +int 32 +load 40 +setbit +int 33 +load 41 +setbit +int 34 +load 42 +setbit +int 35 +load 43 +setbit +int 36 +load 44 +setbit +int 37 +load 45 +setbit +int 38 +load 46 +setbit +int 39 +load 47 +setbit +int 40 +load 48 +setbit +int 41 +load 49 +setbit +store 7 +load 7 +retsub + +// round_tripper +roundtripper_2: +store 2 +load 2 +callsub arraycomplement_1 +store 4 +load 4 +callsub arraycomplement_1 +store 5 +load 2 +load 4 +concat +load 5 +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_<0>.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_<0>.teal new file mode 100644 index 000000000..213f6c9af --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_<0>.teal @@ -0,0 +1,92 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 1 +load 1 +callsub roundtripper_1 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// array_complement +arraycomplement_0: +store 6 +int 0 +store 8 +load 8 +itob +extract 6 0 +byte "" +concat +store 7 +load 7 +retsub + +// round_tripper +roundtripper_1: +store 2 +load 2 +callsub arraycomplement_0 +store 4 +load 4 +callsub arraycomplement_0 +store 5 +load 2 +store 12 +load 12 +store 11 +int 6 +store 9 +load 9 +load 12 +len ++ +store 10 +load 10 +int 65536 +< +assert +load 9 +itob +extract 6 0 +load 4 +store 12 +load 11 +load 12 +concat +store 11 +load 10 +store 9 +load 9 +load 12 +len ++ +store 10 +load 10 +int 65536 +< +assert +load 9 +itob +extract 6 0 +concat +load 5 +store 12 +load 11 +load 12 +concat +store 11 +load 10 +store 9 +load 9 +itob +extract 6 0 +concat +load 11 +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_<1>.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_<1>.teal new file mode 100644 index 000000000..3371ff0cd --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_<1>.teal @@ -0,0 +1,117 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 1 +load 1 +callsub roundtripper_2 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// bool_comp +boolcomp_0: +store 9 +load 9 +! +store 10 +load 10 +int 2 +< +assert +load 10 +retsub + +// array_complement +arraycomplement_1: +store 6 +load 6 +int 0 +int 16 ++ +getbit +store 8 +load 8 +callsub boolcomp_0 +store 8 +int 1 +store 11 +load 11 +itob +extract 6 0 +byte 0x00 +int 0 +load 8 +setbit +concat +store 7 +load 7 +retsub + +// round_tripper +roundtripper_2: +store 2 +load 2 +callsub arraycomplement_1 +store 4 +load 4 +callsub arraycomplement_1 +store 5 +load 2 +store 15 +load 15 +store 14 +int 6 +store 12 +load 12 +load 15 +len ++ +store 13 +load 13 +int 65536 +< +assert +load 12 +itob +extract 6 0 +load 4 +store 15 +load 14 +load 15 +concat +store 14 +load 13 +store 12 +load 12 +load 15 +len ++ +store 13 +load 13 +int 65536 +< +assert +load 12 +itob +extract 6 0 +concat +load 5 +store 15 +load 14 +load 15 +concat +store 14 +load 13 +store 12 +load 12 +itob +extract 6 0 +concat +load 14 +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_<42>.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_<42>.teal new file mode 100644 index 000000000..8b4204e83 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_<42>.teal @@ -0,0 +1,609 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 1 +load 1 +callsub roundtripper_2 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// bool_comp +boolcomp_0: +store 50 +load 50 +! +store 51 +load 51 +int 2 +< +assert +load 51 +retsub + +// array_complement +arraycomplement_1: +store 6 +load 6 +int 0 +int 16 ++ +getbit +store 8 +load 6 +int 1 +int 16 ++ +getbit +store 9 +load 6 +int 2 +int 16 ++ +getbit +store 10 +load 6 +int 3 +int 16 ++ +getbit +store 11 +load 6 +int 4 +int 16 ++ +getbit +store 12 +load 6 +int 5 +int 16 ++ +getbit +store 13 +load 6 +int 6 +int 16 ++ +getbit +store 14 +load 6 +int 7 +int 16 ++ +getbit +store 15 +load 6 +int 8 +int 16 ++ +getbit +store 16 +load 6 +int 9 +int 16 ++ +getbit +store 17 +load 6 +int 10 +int 16 ++ +getbit +store 18 +load 6 +int 11 +int 16 ++ +getbit +store 19 +load 6 +int 12 +int 16 ++ +getbit +store 20 +load 6 +int 13 +int 16 ++ +getbit +store 21 +load 6 +int 14 +int 16 ++ +getbit +store 22 +load 6 +int 15 +int 16 ++ +getbit +store 23 +load 6 +int 16 +int 16 ++ +getbit +store 24 +load 6 +int 17 +int 16 ++ +getbit +store 25 +load 6 +int 18 +int 16 ++ +getbit +store 26 +load 6 +int 19 +int 16 ++ +getbit +store 27 +load 6 +int 20 +int 16 ++ +getbit +store 28 +load 6 +int 21 +int 16 ++ +getbit +store 29 +load 6 +int 22 +int 16 ++ +getbit +store 30 +load 6 +int 23 +int 16 ++ +getbit +store 31 +load 6 +int 24 +int 16 ++ +getbit +store 32 +load 6 +int 25 +int 16 ++ +getbit +store 33 +load 6 +int 26 +int 16 ++ +getbit +store 34 +load 6 +int 27 +int 16 ++ +getbit +store 35 +load 6 +int 28 +int 16 ++ +getbit +store 36 +load 6 +int 29 +int 16 ++ +getbit +store 37 +load 6 +int 30 +int 16 ++ +getbit +store 38 +load 6 +int 31 +int 16 ++ +getbit +store 39 +load 6 +int 32 +int 16 ++ +getbit +store 40 +load 6 +int 33 +int 16 ++ +getbit +store 41 +load 6 +int 34 +int 16 ++ +getbit +store 42 +load 6 +int 35 +int 16 ++ +getbit +store 43 +load 6 +int 36 +int 16 ++ +getbit +store 44 +load 6 +int 37 +int 16 ++ +getbit +store 45 +load 6 +int 38 +int 16 ++ +getbit +store 46 +load 6 +int 39 +int 16 ++ +getbit +store 47 +load 6 +int 40 +int 16 ++ +getbit +store 48 +load 6 +int 41 +int 16 ++ +getbit +store 49 +load 8 +callsub boolcomp_0 +store 8 +load 9 +callsub boolcomp_0 +store 9 +load 10 +callsub boolcomp_0 +store 10 +load 11 +callsub boolcomp_0 +store 11 +load 12 +callsub boolcomp_0 +store 12 +load 13 +callsub boolcomp_0 +store 13 +load 14 +callsub boolcomp_0 +store 14 +load 15 +callsub boolcomp_0 +store 15 +load 16 +callsub boolcomp_0 +store 16 +load 17 +callsub boolcomp_0 +store 17 +load 18 +callsub boolcomp_0 +store 18 +load 19 +callsub boolcomp_0 +store 19 +load 20 +callsub boolcomp_0 +store 20 +load 21 +callsub boolcomp_0 +store 21 +load 22 +callsub boolcomp_0 +store 22 +load 23 +callsub boolcomp_0 +store 23 +load 24 +callsub boolcomp_0 +store 24 +load 25 +callsub boolcomp_0 +store 25 +load 26 +callsub boolcomp_0 +store 26 +load 27 +callsub boolcomp_0 +store 27 +load 28 +callsub boolcomp_0 +store 28 +load 29 +callsub boolcomp_0 +store 29 +load 30 +callsub boolcomp_0 +store 30 +load 31 +callsub boolcomp_0 +store 31 +load 32 +callsub boolcomp_0 +store 32 +load 33 +callsub boolcomp_0 +store 33 +load 34 +callsub boolcomp_0 +store 34 +load 35 +callsub boolcomp_0 +store 35 +load 36 +callsub boolcomp_0 +store 36 +load 37 +callsub boolcomp_0 +store 37 +load 38 +callsub boolcomp_0 +store 38 +load 39 +callsub boolcomp_0 +store 39 +load 40 +callsub boolcomp_0 +store 40 +load 41 +callsub boolcomp_0 +store 41 +load 42 +callsub boolcomp_0 +store 42 +load 43 +callsub boolcomp_0 +store 43 +load 44 +callsub boolcomp_0 +store 44 +load 45 +callsub boolcomp_0 +store 45 +load 46 +callsub boolcomp_0 +store 46 +load 47 +callsub boolcomp_0 +store 47 +load 48 +callsub boolcomp_0 +store 48 +load 49 +callsub boolcomp_0 +store 49 +int 42 +store 52 +load 52 +itob +extract 6 0 +byte 0x000000000000 +int 0 +load 8 +setbit +int 1 +load 9 +setbit +int 2 +load 10 +setbit +int 3 +load 11 +setbit +int 4 +load 12 +setbit +int 5 +load 13 +setbit +int 6 +load 14 +setbit +int 7 +load 15 +setbit +int 8 +load 16 +setbit +int 9 +load 17 +setbit +int 10 +load 18 +setbit +int 11 +load 19 +setbit +int 12 +load 20 +setbit +int 13 +load 21 +setbit +int 14 +load 22 +setbit +int 15 +load 23 +setbit +int 16 +load 24 +setbit +int 17 +load 25 +setbit +int 18 +load 26 +setbit +int 19 +load 27 +setbit +int 20 +load 28 +setbit +int 21 +load 29 +setbit +int 22 +load 30 +setbit +int 23 +load 31 +setbit +int 24 +load 32 +setbit +int 25 +load 33 +setbit +int 26 +load 34 +setbit +int 27 +load 35 +setbit +int 28 +load 36 +setbit +int 29 +load 37 +setbit +int 30 +load 38 +setbit +int 31 +load 39 +setbit +int 32 +load 40 +setbit +int 33 +load 41 +setbit +int 34 +load 42 +setbit +int 35 +load 43 +setbit +int 36 +load 44 +setbit +int 37 +load 45 +setbit +int 38 +load 46 +setbit +int 39 +load 47 +setbit +int 40 +load 48 +setbit +int 41 +load 49 +setbit +concat +store 7 +load 7 +retsub + +// round_tripper +roundtripper_2: +store 2 +load 2 +callsub arraycomplement_1 +store 4 +load 4 +callsub arraycomplement_1 +store 5 +load 2 +store 56 +load 56 +store 55 +int 6 +store 53 +load 53 +load 56 +len ++ +store 54 +load 54 +int 65536 +< +assert +load 53 +itob +extract 6 0 +load 4 +store 56 +load 55 +load 56 +concat +store 55 +load 54 +store 53 +load 53 +load 56 +len ++ +store 54 +load 54 +int 65536 +< +assert +load 53 +itob +extract 6 0 +concat +load 5 +store 56 +load 55 +load 56 +concat +store 55 +load 54 +store 53 +load 53 +itob +extract 6 0 +concat +load 55 +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_byte.teal b/tests/integration/teal/roundtrip/app_roundtrip_byte.teal new file mode 100644 index 000000000..851809b8e --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_byte.teal @@ -0,0 +1,55 @@ +#pragma version 6 +txna ApplicationArgs 0 +int 0 +getbyte +store 1 +load 1 +callsub roundtripper_1 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// numerical_comp +numericalcomp_0: +store 6 +int 255 +load 6 +- +store 7 +load 7 +int 256 +< +assert +load 7 +retsub + +// round_tripper +roundtripper_1: +store 2 +load 2 +callsub numericalcomp_0 +store 4 +load 4 +callsub numericalcomp_0 +store 5 +byte 0x00 +int 0 +load 2 +setbyte +byte 0x00 +int 0 +load 4 +setbyte +concat +byte 0x00 +int 0 +load 5 +setbyte +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_string_<0>.teal b/tests/integration/teal/roundtrip/app_roundtrip_string_<0>.teal new file mode 100644 index 000000000..5ae3edff2 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_string_<0>.teal @@ -0,0 +1,92 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 1 +load 1 +callsub roundtripper_1 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// string_reverse +stringreverse_0: +store 6 +int 0 +store 8 +load 8 +itob +extract 6 0 +byte "" +concat +store 7 +load 7 +retsub + +// round_tripper +roundtripper_1: +store 2 +load 2 +callsub stringreverse_0 +store 4 +load 4 +callsub stringreverse_0 +store 5 +load 2 +store 12 +load 12 +store 11 +int 6 +store 9 +load 9 +load 12 +len ++ +store 10 +load 10 +int 65536 +< +assert +load 9 +itob +extract 6 0 +load 4 +store 12 +load 11 +load 12 +concat +store 11 +load 10 +store 9 +load 9 +load 12 +len ++ +store 10 +load 10 +int 65536 +< +assert +load 9 +itob +extract 6 0 +concat +load 5 +store 12 +load 11 +load 12 +concat +store 11 +load 10 +store 9 +load 9 +itob +extract 6 0 +concat +load 11 +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_string_<13>.teal b/tests/integration/teal/roundtrip/app_roundtrip_string_<13>.teal new file mode 100644 index 000000000..6350008aa --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_string_<13>.teal @@ -0,0 +1,259 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 1 +load 1 +callsub roundtripper_1 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// string_reverse +stringreverse_0: +store 6 +load 6 +int 1 +int 0 +* +int 2 ++ +getbyte +store 20 +load 6 +int 1 +int 1 +* +int 2 ++ +getbyte +store 19 +load 6 +int 1 +int 2 +* +int 2 ++ +getbyte +store 18 +load 6 +int 1 +int 3 +* +int 2 ++ +getbyte +store 17 +load 6 +int 1 +int 4 +* +int 2 ++ +getbyte +store 16 +load 6 +int 1 +int 5 +* +int 2 ++ +getbyte +store 15 +load 6 +int 1 +int 6 +* +int 2 ++ +getbyte +store 14 +load 6 +int 1 +int 7 +* +int 2 ++ +getbyte +store 13 +load 6 +int 1 +int 8 +* +int 2 ++ +getbyte +store 12 +load 6 +int 1 +int 9 +* +int 2 ++ +getbyte +store 11 +load 6 +int 1 +int 10 +* +int 2 ++ +getbyte +store 10 +load 6 +int 1 +int 11 +* +int 2 ++ +getbyte +store 9 +load 6 +int 1 +int 12 +* +int 2 ++ +getbyte +store 8 +int 13 +store 21 +load 21 +itob +extract 6 0 +byte 0x00 +int 0 +load 8 +setbyte +byte 0x00 +int 0 +load 9 +setbyte +concat +byte 0x00 +int 0 +load 10 +setbyte +concat +byte 0x00 +int 0 +load 11 +setbyte +concat +byte 0x00 +int 0 +load 12 +setbyte +concat +byte 0x00 +int 0 +load 13 +setbyte +concat +byte 0x00 +int 0 +load 14 +setbyte +concat +byte 0x00 +int 0 +load 15 +setbyte +concat +byte 0x00 +int 0 +load 16 +setbyte +concat +byte 0x00 +int 0 +load 17 +setbyte +concat +byte 0x00 +int 0 +load 18 +setbyte +concat +byte 0x00 +int 0 +load 19 +setbyte +concat +byte 0x00 +int 0 +load 20 +setbyte +concat +concat +store 7 +load 7 +retsub + +// round_tripper +roundtripper_1: +store 2 +load 2 +callsub stringreverse_0 +store 4 +load 4 +callsub stringreverse_0 +store 5 +load 2 +store 25 +load 25 +store 24 +int 6 +store 22 +load 22 +load 25 +len ++ +store 23 +load 23 +int 65536 +< +assert +load 22 +itob +extract 6 0 +load 4 +store 25 +load 24 +load 25 +concat +store 24 +load 23 +store 22 +load 22 +load 25 +len ++ +store 23 +load 23 +int 65536 +< +assert +load 22 +itob +extract 6 0 +concat +load 5 +store 25 +load 24 +load 25 +concat +store 24 +load 23 +store 22 +load 22 +itob +extract 6 0 +concat +load 24 +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_string_<1>.teal b/tests/integration/teal/roundtrip/app_roundtrip_string_<1>.teal new file mode 100644 index 000000000..779c6fc1d --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_string_<1>.teal @@ -0,0 +1,103 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 1 +load 1 +callsub roundtripper_1 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// string_reverse +stringreverse_0: +store 6 +load 6 +int 1 +int 0 +* +int 2 ++ +getbyte +store 8 +int 1 +store 9 +load 9 +itob +extract 6 0 +byte 0x00 +int 0 +load 8 +setbyte +concat +store 7 +load 7 +retsub + +// round_tripper +roundtripper_1: +store 2 +load 2 +callsub stringreverse_0 +store 4 +load 4 +callsub stringreverse_0 +store 5 +load 2 +store 13 +load 13 +store 12 +int 6 +store 10 +load 10 +load 13 +len ++ +store 11 +load 11 +int 65536 +< +assert +load 10 +itob +extract 6 0 +load 4 +store 13 +load 12 +load 13 +concat +store 12 +load 11 +store 10 +load 10 +load 13 +len ++ +store 11 +load 11 +int 65536 +< +assert +load 10 +itob +extract 6 0 +concat +load 5 +store 13 +load 12 +load 13 +concat +store 12 +load 11 +store 10 +load 10 +itob +extract 6 0 +concat +load 12 +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint16.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint16.teal new file mode 100644 index 000000000..dc7d82530 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint16.teal @@ -0,0 +1,52 @@ +#pragma version 6 +txna ApplicationArgs 0 +int 0 +extract_uint16 +store 1 +load 1 +callsub roundtripper_1 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// numerical_comp +numericalcomp_0: +store 6 +int 65535 +load 6 +- +store 7 +load 7 +int 65536 +< +assert +load 7 +retsub + +// round_tripper +roundtripper_1: +store 2 +load 2 +callsub numericalcomp_0 +store 4 +load 4 +callsub numericalcomp_0 +store 5 +load 2 +itob +extract 6 0 +load 4 +itob +extract 6 0 +concat +load 5 +itob +extract 6 0 +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint32.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint32.teal new file mode 100644 index 000000000..a46200138 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint32.teal @@ -0,0 +1,52 @@ +#pragma version 6 +txna ApplicationArgs 0 +int 0 +extract_uint32 +store 1 +load 1 +callsub roundtripper_1 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// numerical_comp +numericalcomp_0: +store 6 +int 4294967295 +load 6 +- +store 7 +load 7 +int 4294967296 +< +assert +load 7 +retsub + +// round_tripper +roundtripper_1: +store 2 +load 2 +callsub numericalcomp_0 +store 4 +load 4 +callsub numericalcomp_0 +store 5 +load 2 +itob +extract 4 0 +load 4 +itob +extract 4 0 +concat +load 5 +itob +extract 4 0 +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64.teal new file mode 100644 index 000000000..9a9169df4 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64.teal @@ -0,0 +1,44 @@ +#pragma version 6 +txna ApplicationArgs 0 +btoi +store 1 +load 1 +callsub roundtripper_1 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// numerical_comp +numericalcomp_0: +store 6 +int 18446744073709551615 +load 6 +- +store 7 +load 7 +retsub + +// round_tripper +roundtripper_1: +store 2 +load 2 +callsub numericalcomp_0 +store 4 +load 4 +callsub numericalcomp_0 +store 5 +load 2 +itob +load 4 +itob +concat +load 5 +itob +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[1].teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[1].teal new file mode 100644 index 000000000..3252a6442 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[1].teal @@ -0,0 +1,58 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 1 +load 1 +callsub roundtripper_2 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// numerical_comp +numericalcomp_0: +store 9 +int 18446744073709551615 +load 9 +- +store 10 +load 10 +retsub + +// array_complement +arraycomplement_1: +store 6 +load 6 +int 8 +int 0 +* +extract_uint64 +store 8 +load 8 +callsub numericalcomp_0 +store 8 +load 8 +itob +store 7 +load 7 +retsub + +// round_tripper +roundtripper_2: +store 2 +load 2 +callsub arraycomplement_1 +store 4 +load 4 +callsub arraycomplement_1 +store 5 +load 2 +load 4 +concat +load 5 +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[42].teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[42].teal new file mode 100644 index 000000000..6afe66a2f --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[42].teal @@ -0,0 +1,550 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 1 +load 1 +callsub roundtripper_2 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// numerical_comp +numericalcomp_0: +store 50 +int 18446744073709551615 +load 50 +- +store 51 +load 51 +retsub + +// array_complement +arraycomplement_1: +store 6 +load 6 +int 8 +int 0 +* +extract_uint64 +store 8 +load 6 +int 8 +int 1 +* +extract_uint64 +store 9 +load 6 +int 8 +int 2 +* +extract_uint64 +store 10 +load 6 +int 8 +int 3 +* +extract_uint64 +store 11 +load 6 +int 8 +int 4 +* +extract_uint64 +store 12 +load 6 +int 8 +int 5 +* +extract_uint64 +store 13 +load 6 +int 8 +int 6 +* +extract_uint64 +store 14 +load 6 +int 8 +int 7 +* +extract_uint64 +store 15 +load 6 +int 8 +int 8 +* +extract_uint64 +store 16 +load 6 +int 8 +int 9 +* +extract_uint64 +store 17 +load 6 +int 8 +int 10 +* +extract_uint64 +store 18 +load 6 +int 8 +int 11 +* +extract_uint64 +store 19 +load 6 +int 8 +int 12 +* +extract_uint64 +store 20 +load 6 +int 8 +int 13 +* +extract_uint64 +store 21 +load 6 +int 8 +int 14 +* +extract_uint64 +store 22 +load 6 +int 8 +int 15 +* +extract_uint64 +store 23 +load 6 +int 8 +int 16 +* +extract_uint64 +store 24 +load 6 +int 8 +int 17 +* +extract_uint64 +store 25 +load 6 +int 8 +int 18 +* +extract_uint64 +store 26 +load 6 +int 8 +int 19 +* +extract_uint64 +store 27 +load 6 +int 8 +int 20 +* +extract_uint64 +store 28 +load 6 +int 8 +int 21 +* +extract_uint64 +store 29 +load 6 +int 8 +int 22 +* +extract_uint64 +store 30 +load 6 +int 8 +int 23 +* +extract_uint64 +store 31 +load 6 +int 8 +int 24 +* +extract_uint64 +store 32 +load 6 +int 8 +int 25 +* +extract_uint64 +store 33 +load 6 +int 8 +int 26 +* +extract_uint64 +store 34 +load 6 +int 8 +int 27 +* +extract_uint64 +store 35 +load 6 +int 8 +int 28 +* +extract_uint64 +store 36 +load 6 +int 8 +int 29 +* +extract_uint64 +store 37 +load 6 +int 8 +int 30 +* +extract_uint64 +store 38 +load 6 +int 8 +int 31 +* +extract_uint64 +store 39 +load 6 +int 8 +int 32 +* +extract_uint64 +store 40 +load 6 +int 8 +int 33 +* +extract_uint64 +store 41 +load 6 +int 8 +int 34 +* +extract_uint64 +store 42 +load 6 +int 8 +int 35 +* +extract_uint64 +store 43 +load 6 +int 8 +int 36 +* +extract_uint64 +store 44 +load 6 +int 8 +int 37 +* +extract_uint64 +store 45 +load 6 +int 8 +int 38 +* +extract_uint64 +store 46 +load 6 +int 8 +int 39 +* +extract_uint64 +store 47 +load 6 +int 8 +int 40 +* +extract_uint64 +store 48 +load 6 +int 8 +int 41 +* +extract_uint64 +store 49 +load 8 +callsub numericalcomp_0 +store 8 +load 9 +callsub numericalcomp_0 +store 9 +load 10 +callsub numericalcomp_0 +store 10 +load 11 +callsub numericalcomp_0 +store 11 +load 12 +callsub numericalcomp_0 +store 12 +load 13 +callsub numericalcomp_0 +store 13 +load 14 +callsub numericalcomp_0 +store 14 +load 15 +callsub numericalcomp_0 +store 15 +load 16 +callsub numericalcomp_0 +store 16 +load 17 +callsub numericalcomp_0 +store 17 +load 18 +callsub numericalcomp_0 +store 18 +load 19 +callsub numericalcomp_0 +store 19 +load 20 +callsub numericalcomp_0 +store 20 +load 21 +callsub numericalcomp_0 +store 21 +load 22 +callsub numericalcomp_0 +store 22 +load 23 +callsub numericalcomp_0 +store 23 +load 24 +callsub numericalcomp_0 +store 24 +load 25 +callsub numericalcomp_0 +store 25 +load 26 +callsub numericalcomp_0 +store 26 +load 27 +callsub numericalcomp_0 +store 27 +load 28 +callsub numericalcomp_0 +store 28 +load 29 +callsub numericalcomp_0 +store 29 +load 30 +callsub numericalcomp_0 +store 30 +load 31 +callsub numericalcomp_0 +store 31 +load 32 +callsub numericalcomp_0 +store 32 +load 33 +callsub numericalcomp_0 +store 33 +load 34 +callsub numericalcomp_0 +store 34 +load 35 +callsub numericalcomp_0 +store 35 +load 36 +callsub numericalcomp_0 +store 36 +load 37 +callsub numericalcomp_0 +store 37 +load 38 +callsub numericalcomp_0 +store 38 +load 39 +callsub numericalcomp_0 +store 39 +load 40 +callsub numericalcomp_0 +store 40 +load 41 +callsub numericalcomp_0 +store 41 +load 42 +callsub numericalcomp_0 +store 42 +load 43 +callsub numericalcomp_0 +store 43 +load 44 +callsub numericalcomp_0 +store 44 +load 45 +callsub numericalcomp_0 +store 45 +load 46 +callsub numericalcomp_0 +store 46 +load 47 +callsub numericalcomp_0 +store 47 +load 48 +callsub numericalcomp_0 +store 48 +load 49 +callsub numericalcomp_0 +store 49 +load 8 +itob +load 9 +itob +concat +load 10 +itob +concat +load 11 +itob +concat +load 12 +itob +concat +load 13 +itob +concat +load 14 +itob +concat +load 15 +itob +concat +load 16 +itob +concat +load 17 +itob +concat +load 18 +itob +concat +load 19 +itob +concat +load 20 +itob +concat +load 21 +itob +concat +load 22 +itob +concat +load 23 +itob +concat +load 24 +itob +concat +load 25 +itob +concat +load 26 +itob +concat +load 27 +itob +concat +load 28 +itob +concat +load 29 +itob +concat +load 30 +itob +concat +load 31 +itob +concat +load 32 +itob +concat +load 33 +itob +concat +load 34 +itob +concat +load 35 +itob +concat +load 36 +itob +concat +load 37 +itob +concat +load 38 +itob +concat +load 39 +itob +concat +load 40 +itob +concat +load 41 +itob +concat +load 42 +itob +concat +load 43 +itob +concat +load 44 +itob +concat +load 45 +itob +concat +load 46 +itob +concat +load 47 +itob +concat +load 48 +itob +concat +load 49 +itob +concat +store 7 +load 7 +retsub + +// round_tripper +roundtripper_2: +store 2 +load 2 +callsub arraycomplement_1 +store 4 +load 4 +callsub arraycomplement_1 +store 5 +load 2 +load 4 +concat +load 5 +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_<0>.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_<0>.teal new file mode 100644 index 000000000..213f6c9af --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_<0>.teal @@ -0,0 +1,92 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 1 +load 1 +callsub roundtripper_1 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// array_complement +arraycomplement_0: +store 6 +int 0 +store 8 +load 8 +itob +extract 6 0 +byte "" +concat +store 7 +load 7 +retsub + +// round_tripper +roundtripper_1: +store 2 +load 2 +callsub arraycomplement_0 +store 4 +load 4 +callsub arraycomplement_0 +store 5 +load 2 +store 12 +load 12 +store 11 +int 6 +store 9 +load 9 +load 12 +len ++ +store 10 +load 10 +int 65536 +< +assert +load 9 +itob +extract 6 0 +load 4 +store 12 +load 11 +load 12 +concat +store 11 +load 10 +store 9 +load 9 +load 12 +len ++ +store 10 +load 10 +int 65536 +< +assert +load 9 +itob +extract 6 0 +concat +load 5 +store 12 +load 11 +load 12 +concat +store 11 +load 10 +store 9 +load 9 +itob +extract 6 0 +concat +load 11 +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_<1>.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_<1>.teal new file mode 100644 index 000000000..70c2016c9 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_<1>.teal @@ -0,0 +1,114 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 1 +load 1 +callsub roundtripper_2 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// numerical_comp +numericalcomp_0: +store 9 +int 18446744073709551615 +load 9 +- +store 10 +load 10 +retsub + +// array_complement +arraycomplement_1: +store 6 +load 6 +int 8 +int 0 +* +int 2 ++ +extract_uint64 +store 8 +load 8 +callsub numericalcomp_0 +store 8 +int 1 +store 11 +load 11 +itob +extract 6 0 +load 8 +itob +concat +store 7 +load 7 +retsub + +// round_tripper +roundtripper_2: +store 2 +load 2 +callsub arraycomplement_1 +store 4 +load 4 +callsub arraycomplement_1 +store 5 +load 2 +store 15 +load 15 +store 14 +int 6 +store 12 +load 12 +load 15 +len ++ +store 13 +load 13 +int 65536 +< +assert +load 12 +itob +extract 6 0 +load 4 +store 15 +load 14 +load 15 +concat +store 14 +load 13 +store 12 +load 12 +load 15 +len ++ +store 13 +load 13 +int 65536 +< +assert +load 12 +itob +extract 6 0 +concat +load 5 +store 15 +load 14 +load 15 +concat +store 14 +load 13 +store 12 +load 12 +itob +extract 6 0 +concat +load 14 +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_<42>.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_<42>.teal new file mode 100644 index 000000000..d2ae51113 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_<42>.teal @@ -0,0 +1,688 @@ +#pragma version 6 +txna ApplicationArgs 0 +store 1 +load 1 +callsub roundtripper_2 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// numerical_comp +numericalcomp_0: +store 50 +int 18446744073709551615 +load 50 +- +store 51 +load 51 +retsub + +// array_complement +arraycomplement_1: +store 6 +load 6 +int 8 +int 0 +* +int 2 ++ +extract_uint64 +store 8 +load 6 +int 8 +int 1 +* +int 2 ++ +extract_uint64 +store 9 +load 6 +int 8 +int 2 +* +int 2 ++ +extract_uint64 +store 10 +load 6 +int 8 +int 3 +* +int 2 ++ +extract_uint64 +store 11 +load 6 +int 8 +int 4 +* +int 2 ++ +extract_uint64 +store 12 +load 6 +int 8 +int 5 +* +int 2 ++ +extract_uint64 +store 13 +load 6 +int 8 +int 6 +* +int 2 ++ +extract_uint64 +store 14 +load 6 +int 8 +int 7 +* +int 2 ++ +extract_uint64 +store 15 +load 6 +int 8 +int 8 +* +int 2 ++ +extract_uint64 +store 16 +load 6 +int 8 +int 9 +* +int 2 ++ +extract_uint64 +store 17 +load 6 +int 8 +int 10 +* +int 2 ++ +extract_uint64 +store 18 +load 6 +int 8 +int 11 +* +int 2 ++ +extract_uint64 +store 19 +load 6 +int 8 +int 12 +* +int 2 ++ +extract_uint64 +store 20 +load 6 +int 8 +int 13 +* +int 2 ++ +extract_uint64 +store 21 +load 6 +int 8 +int 14 +* +int 2 ++ +extract_uint64 +store 22 +load 6 +int 8 +int 15 +* +int 2 ++ +extract_uint64 +store 23 +load 6 +int 8 +int 16 +* +int 2 ++ +extract_uint64 +store 24 +load 6 +int 8 +int 17 +* +int 2 ++ +extract_uint64 +store 25 +load 6 +int 8 +int 18 +* +int 2 ++ +extract_uint64 +store 26 +load 6 +int 8 +int 19 +* +int 2 ++ +extract_uint64 +store 27 +load 6 +int 8 +int 20 +* +int 2 ++ +extract_uint64 +store 28 +load 6 +int 8 +int 21 +* +int 2 ++ +extract_uint64 +store 29 +load 6 +int 8 +int 22 +* +int 2 ++ +extract_uint64 +store 30 +load 6 +int 8 +int 23 +* +int 2 ++ +extract_uint64 +store 31 +load 6 +int 8 +int 24 +* +int 2 ++ +extract_uint64 +store 32 +load 6 +int 8 +int 25 +* +int 2 ++ +extract_uint64 +store 33 +load 6 +int 8 +int 26 +* +int 2 ++ +extract_uint64 +store 34 +load 6 +int 8 +int 27 +* +int 2 ++ +extract_uint64 +store 35 +load 6 +int 8 +int 28 +* +int 2 ++ +extract_uint64 +store 36 +load 6 +int 8 +int 29 +* +int 2 ++ +extract_uint64 +store 37 +load 6 +int 8 +int 30 +* +int 2 ++ +extract_uint64 +store 38 +load 6 +int 8 +int 31 +* +int 2 ++ +extract_uint64 +store 39 +load 6 +int 8 +int 32 +* +int 2 ++ +extract_uint64 +store 40 +load 6 +int 8 +int 33 +* +int 2 ++ +extract_uint64 +store 41 +load 6 +int 8 +int 34 +* +int 2 ++ +extract_uint64 +store 42 +load 6 +int 8 +int 35 +* +int 2 ++ +extract_uint64 +store 43 +load 6 +int 8 +int 36 +* +int 2 ++ +extract_uint64 +store 44 +load 6 +int 8 +int 37 +* +int 2 ++ +extract_uint64 +store 45 +load 6 +int 8 +int 38 +* +int 2 ++ +extract_uint64 +store 46 +load 6 +int 8 +int 39 +* +int 2 ++ +extract_uint64 +store 47 +load 6 +int 8 +int 40 +* +int 2 ++ +extract_uint64 +store 48 +load 6 +int 8 +int 41 +* +int 2 ++ +extract_uint64 +store 49 +load 8 +callsub numericalcomp_0 +store 8 +load 9 +callsub numericalcomp_0 +store 9 +load 10 +callsub numericalcomp_0 +store 10 +load 11 +callsub numericalcomp_0 +store 11 +load 12 +callsub numericalcomp_0 +store 12 +load 13 +callsub numericalcomp_0 +store 13 +load 14 +callsub numericalcomp_0 +store 14 +load 15 +callsub numericalcomp_0 +store 15 +load 16 +callsub numericalcomp_0 +store 16 +load 17 +callsub numericalcomp_0 +store 17 +load 18 +callsub numericalcomp_0 +store 18 +load 19 +callsub numericalcomp_0 +store 19 +load 20 +callsub numericalcomp_0 +store 20 +load 21 +callsub numericalcomp_0 +store 21 +load 22 +callsub numericalcomp_0 +store 22 +load 23 +callsub numericalcomp_0 +store 23 +load 24 +callsub numericalcomp_0 +store 24 +load 25 +callsub numericalcomp_0 +store 25 +load 26 +callsub numericalcomp_0 +store 26 +load 27 +callsub numericalcomp_0 +store 27 +load 28 +callsub numericalcomp_0 +store 28 +load 29 +callsub numericalcomp_0 +store 29 +load 30 +callsub numericalcomp_0 +store 30 +load 31 +callsub numericalcomp_0 +store 31 +load 32 +callsub numericalcomp_0 +store 32 +load 33 +callsub numericalcomp_0 +store 33 +load 34 +callsub numericalcomp_0 +store 34 +load 35 +callsub numericalcomp_0 +store 35 +load 36 +callsub numericalcomp_0 +store 36 +load 37 +callsub numericalcomp_0 +store 37 +load 38 +callsub numericalcomp_0 +store 38 +load 39 +callsub numericalcomp_0 +store 39 +load 40 +callsub numericalcomp_0 +store 40 +load 41 +callsub numericalcomp_0 +store 41 +load 42 +callsub numericalcomp_0 +store 42 +load 43 +callsub numericalcomp_0 +store 43 +load 44 +callsub numericalcomp_0 +store 44 +load 45 +callsub numericalcomp_0 +store 45 +load 46 +callsub numericalcomp_0 +store 46 +load 47 +callsub numericalcomp_0 +store 47 +load 48 +callsub numericalcomp_0 +store 48 +load 49 +callsub numericalcomp_0 +store 49 +int 42 +store 52 +load 52 +itob +extract 6 0 +load 8 +itob +load 9 +itob +concat +load 10 +itob +concat +load 11 +itob +concat +load 12 +itob +concat +load 13 +itob +concat +load 14 +itob +concat +load 15 +itob +concat +load 16 +itob +concat +load 17 +itob +concat +load 18 +itob +concat +load 19 +itob +concat +load 20 +itob +concat +load 21 +itob +concat +load 22 +itob +concat +load 23 +itob +concat +load 24 +itob +concat +load 25 +itob +concat +load 26 +itob +concat +load 27 +itob +concat +load 28 +itob +concat +load 29 +itob +concat +load 30 +itob +concat +load 31 +itob +concat +load 32 +itob +concat +load 33 +itob +concat +load 34 +itob +concat +load 35 +itob +concat +load 36 +itob +concat +load 37 +itob +concat +load 38 +itob +concat +load 39 +itob +concat +load 40 +itob +concat +load 41 +itob +concat +load 42 +itob +concat +load 43 +itob +concat +load 44 +itob +concat +load 45 +itob +concat +load 46 +itob +concat +load 47 +itob +concat +load 48 +itob +concat +load 49 +itob +concat +concat +store 7 +load 7 +retsub + +// round_tripper +roundtripper_2: +store 2 +load 2 +callsub arraycomplement_1 +store 4 +load 4 +callsub arraycomplement_1 +store 5 +load 2 +store 56 +load 56 +store 55 +int 6 +store 53 +load 53 +load 56 +len ++ +store 54 +load 54 +int 65536 +< +assert +load 53 +itob +extract 6 0 +load 4 +store 56 +load 55 +load 56 +concat +store 55 +load 54 +store 53 +load 53 +load 56 +len ++ +store 54 +load 54 +int 65536 +< +assert +load 53 +itob +extract 6 0 +concat +load 5 +store 56 +load 55 +load 56 +concat +store 55 +load 54 +store 53 +load 53 +itob +extract 6 0 +concat +load 55 +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint8.teal new file mode 100644 index 000000000..851809b8e --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint8.teal @@ -0,0 +1,55 @@ +#pragma version 6 +txna ApplicationArgs 0 +int 0 +getbyte +store 1 +load 1 +callsub roundtripper_1 +store 0 +byte 0x151F7C75 +load 0 +concat +log +int 1 +return + +// numerical_comp +numericalcomp_0: +store 6 +int 255 +load 6 +- +store 7 +load 7 +int 256 +< +assert +load 7 +retsub + +// round_tripper +roundtripper_1: +store 2 +load 2 +callsub numericalcomp_0 +store 4 +load 4 +callsub numericalcomp_0 +store 5 +byte 0x00 +int 0 +load 2 +setbyte +byte 0x00 +int 0 +load 4 +setbyte +concat +byte 0x00 +int 0 +load 5 +setbyte +concat +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/unit/blackbox_test.py b/tests/unit/blackbox_test.py index 0cb71c80b..69ee59187 100644 --- a/tests/unit/blackbox_test.py +++ b/tests/unit/blackbox_test.py @@ -1,10 +1,11 @@ from itertools import product from pathlib import Path import pytest +from typing import Literal, Optional, Tuple import pyteal as pt -from tests.blackbox import Blackbox, blackbox_pyteal +from tests.blackbox import Blackbox, BlackboxWrapper, PyTealDryRunExecutor from tests.compile_asserts import assert_teal_as_expected @@ -12,6 +13,8 @@ FIXTURES = PATH / "teal" GENERATED = PATH / "generated" +# ---- Subroutine Unit Test Examples ---- # + @Blackbox(input_types=[]) @pt.Subroutine(pt.TealType.none) @@ -75,19 +78,84 @@ def utest_any_args(x, y, z): ] +# ---- ABI Return Subroutine Unit Test Examples ---- # + + +@Blackbox(input_types=[]) +@pt.ABIReturnSubroutine +def fn_0arg_0ret() -> pt.Expr: + return pt.Return() + + +@Blackbox(input_types=[]) +@pt.ABIReturnSubroutine +def fn_0arg_uint64_ret(*, output: pt.abi.Uint64) -> pt.Expr: + return output.set(1) + + +@Blackbox(input_types=[None]) +@pt.ABIReturnSubroutine +def fn_1arg_0ret(a: pt.abi.Uint64) -> pt.Expr: + return pt.Return() + + +@Blackbox(input_types=[None]) +@pt.ABIReturnSubroutine +def fn_1arg_1ret(a: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr: + return output.set(a) + + +@Blackbox(input_types=[None, None]) +@pt.ABIReturnSubroutine +def fn_2arg_0ret( + a: pt.abi.Uint64, b: pt.abi.StaticArray[pt.abi.Byte, Literal[10]] +) -> pt.Expr: + return pt.Return() + + +@Blackbox(input_types=[pt.TealType.bytes]) +@pt.ABIReturnSubroutine +def fn_1tt_arg_uint64_ret(x, *, output: pt.abi.Uint64) -> pt.Expr: + return output.set(1) + + +@Blackbox(input_types=[None, pt.TealType.uint64, None]) +@pt.ABIReturnSubroutine +def fn_3mixed_args_0ret( + a: pt.abi.Uint64, b: pt.ScratchVar, C: pt.abi.StaticArray[pt.abi.Byte, Literal[10]] +) -> pt.Expr: + return pt.Return() + + +@Blackbox(input_types=[None, pt.TealType.bytes]) +@pt.ABIReturnSubroutine +def fn_2mixed_arg_1ret( + a: pt.abi.Uint64, b: pt.ScratchVar, *, output: pt.abi.Uint64 +) -> pt.Expr: + return pt.Seq(b.store(a.encode()), output.set(a)) + + +ABI_UNITS = [ + (fn_0arg_0ret, None), + (fn_0arg_uint64_ret, pt.abi.Uint64()), + (fn_1arg_0ret, None), + (fn_1arg_1ret, pt.abi.Uint64()), + (fn_2arg_0ret, None), + (fn_1tt_arg_uint64_ret, pt.abi.Uint64()), + (fn_3mixed_args_0ret, None), + (fn_2mixed_arg_1ret, pt.abi.Uint64()), +] + + +# ---- test functions ---- # + + @pytest.mark.parametrize("subr, mode", product(UNITS, pt.Mode)) -def test_blackbox_pyteal(subr, mode): - """ - TODO: here's an example of issue #199 at play - (the thread-safety aspect): - compare the following! - % pytest -n 2 tests/unit/blackbox_test.py::test_blackbox_pyteal - vs - % pytest -n 1 tests/unit/blackbox_test.py::test_blackbox_pyteal - """ +def test_blackbox_pyteal(subr: BlackboxWrapper, mode: pt.Mode): is_app = mode == pt.Mode.Application name = f"{'app' if is_app else 'lsig'}_{subr.name()}" - compiled = pt.compileTeal(blackbox_pyteal(subr, mode)(), mode, version=6) + compiled = PyTealDryRunExecutor(subr, mode).compile(version=6) tealdir = GENERATED / "blackbox" tealdir.mkdir(parents=True, exist_ok=True) save_to = tealdir / (name + ".teal") @@ -95,3 +163,94 @@ def test_blackbox_pyteal(subr, mode): f.write(compiled) assert_teal_as_expected(save_to, FIXTURES / "blackbox" / (name + ".teal")) + + +@pytest.mark.parametrize("subr_abi, mode", product(ABI_UNITS, pt.Mode)) +def test_abi_blackbox_pyteal( + subr_abi: Tuple[BlackboxWrapper, Optional[pt.ast.abi.BaseType]], mode: pt.Mode +): + subr, abi_return_type = subr_abi + name = f"{'app' if mode == pt.Mode.Application else 'lsig'}_{subr.name()}" + print(f"Case {subr.name()=}, {abi_return_type=}, {mode=} ------> {name=}") + + pdre = PyTealDryRunExecutor(subr, mode) + assert pdre.is_abi(), "should be an ABI subroutine" + + arg_types = pdre.abi_argument_types() + if subr.name() != "fn_1tt_arg_uint64_ret": + assert not arg_types or any( + arg_types + ), "abi_argument_types() should have had some abi info" + + if abi_return_type: + expected_sdk_return_type = pt.abi.algosdk_from_type_spec( + abi_return_type.type_spec() + ) + assert expected_sdk_return_type == pdre.abi_return_type() + else: + assert pdre.abi_return_type() is None + + compiled = pdre.compile(version=6) + tealdir = GENERATED / "abi" + tealdir.mkdir(parents=True, exist_ok=True) + save_to = tealdir / (name + ".teal") + with open(save_to, "w") as f: + f.write(compiled) + + assert_teal_as_expected(save_to, FIXTURES / "abi" / (name + ".teal")) + + +@pytest.mark.parametrize("mode", (pt.Mode.Application, pt.Mode.Signature)) +@pytest.mark.parametrize( + "fn, expected_is_abi", ((utest_noop, False), (fn_0arg_uint64_ret, True)) +) +def test_PyTealBlackboxExecutor_is_abi( + mode: pt.Mode, fn: BlackboxWrapper, expected_is_abi: bool +): + p = PyTealDryRunExecutor(fn, mode) + assert p.is_abi() == expected_is_abi + if expected_is_abi: + assert p.abi_argument_types() is not None + assert p.abi_return_type() is not None + else: + assert p.abi_argument_types() is None + assert p.abi_return_type() is None + + +@pytest.mark.parametrize("mode", (pt.Mode.Application, pt.Mode.Signature)) +@pytest.mark.parametrize( + "fn, expected_arg_count", + ( + (fn_0arg_uint64_ret, 0), + (fn_1arg_0ret, 1), + (fn_1arg_1ret, 1), + (fn_2arg_0ret, 2), + (fn_2mixed_arg_1ret, 2), + ), +) +def test_PyTealBlackboxExecutor_abi_argument_types( + mode: pt.Mode, fn: BlackboxWrapper, expected_arg_count: int +): + actual = PyTealDryRunExecutor(fn, mode).abi_argument_types() + assert actual is not None + assert len(actual) == expected_arg_count + + +@pytest.mark.parametrize("mode", (pt.Mode.Application, pt.Mode.Signature)) +@pytest.mark.parametrize( + "fn, expected_does_produce_type", + ( + (fn_0arg_uint64_ret, True), + (fn_1arg_0ret, False), + (fn_1arg_1ret, True), + (fn_2arg_0ret, False), + (fn_2mixed_arg_1ret, True), + ), +) +def test_PyTealBlackboxExecutor_abi_return_type( + mode: pt.Mode, fn: BlackboxWrapper, expected_does_produce_type: bool +): + if expected_does_produce_type: + assert PyTealDryRunExecutor(fn, mode).abi_return_type() is not None + else: + assert PyTealDryRunExecutor(fn, mode).abi_return_type() is None diff --git a/tests/unit/teal/abi/app_fn_0arg_0ret.teal b/tests/unit/teal/abi/app_fn_0arg_0ret.teal new file mode 100644 index 000000000..93cb677df --- /dev/null +++ b/tests/unit/teal/abi/app_fn_0arg_0ret.teal @@ -0,0 +1,8 @@ +#pragma version 6 +callsub fn0arg0ret_0 +int 1 +return + +// fn_0arg_0ret +fn0arg0ret_0: +retsub \ No newline at end of file diff --git a/tests/unit/teal/abi/app_fn_0arg_uint64_ret.teal b/tests/unit/teal/abi/app_fn_0arg_uint64_ret.teal new file mode 100644 index 000000000..54a1a0a58 --- /dev/null +++ b/tests/unit/teal/abi/app_fn_0arg_uint64_ret.teal @@ -0,0 +1,17 @@ +#pragma version 6 +callsub fn0arguint64ret_0 +store 1 +byte 0x151F7C75 +load 1 +itob +concat +log +int 1 +return + +// fn_0arg_uint64_ret +fn0arguint64ret_0: +int 1 +store 0 +load 0 +retsub \ No newline at end of file diff --git a/tests/unit/teal/abi/app_fn_1arg_0ret.teal b/tests/unit/teal/abi/app_fn_1arg_0ret.teal new file mode 100644 index 000000000..a21e04c5d --- /dev/null +++ b/tests/unit/teal/abi/app_fn_1arg_0ret.teal @@ -0,0 +1,13 @@ +#pragma version 6 +txna ApplicationArgs 0 +btoi +store 1 +load 1 +callsub fn1arg0ret_0 +int 1 +return + +// fn_1arg_0ret +fn1arg0ret_0: +store 0 +retsub \ No newline at end of file diff --git a/tests/unit/teal/abi/app_fn_1arg_1ret.teal b/tests/unit/teal/abi/app_fn_1arg_1ret.teal new file mode 100644 index 000000000..6ae354dac --- /dev/null +++ b/tests/unit/teal/abi/app_fn_1arg_1ret.teal @@ -0,0 +1,22 @@ +#pragma version 6 +txna ApplicationArgs 0 +btoi +store 3 +load 3 +callsub fn1arg1ret_0 +store 2 +byte 0x151F7C75 +load 2 +itob +concat +log +int 1 +return + +// fn_1arg_1ret +fn1arg1ret_0: +store 0 +load 0 +store 1 +load 1 +retsub \ No newline at end of file diff --git a/tests/unit/teal/abi/app_fn_1tt_arg_uint64_ret.teal b/tests/unit/teal/abi/app_fn_1tt_arg_uint64_ret.teal new file mode 100644 index 000000000..bae9169fc --- /dev/null +++ b/tests/unit/teal/abi/app_fn_1tt_arg_uint64_ret.teal @@ -0,0 +1,19 @@ +#pragma version 6 +txna ApplicationArgs 0 +callsub fn1ttarguint64ret_0 +store 2 +byte 0x151F7C75 +load 2 +itob +concat +log +int 1 +return + +// fn_1tt_arg_uint64_ret +fn1ttarguint64ret_0: +store 0 +int 1 +store 1 +load 1 +retsub \ No newline at end of file diff --git a/tests/unit/teal/abi/app_fn_2arg_0ret.teal b/tests/unit/teal/abi/app_fn_2arg_0ret.teal new file mode 100644 index 000000000..aec416290 --- /dev/null +++ b/tests/unit/teal/abi/app_fn_2arg_0ret.teal @@ -0,0 +1,17 @@ +#pragma version 6 +txna ApplicationArgs 0 +btoi +store 2 +txna ApplicationArgs 1 +store 3 +load 2 +load 3 +callsub fn2arg0ret_0 +int 1 +return + +// fn_2arg_0ret +fn2arg0ret_0: +store 1 +store 0 +retsub \ No newline at end of file diff --git a/tests/unit/teal/abi/app_fn_2mixed_arg_1ret.teal b/tests/unit/teal/abi/app_fn_2mixed_arg_1ret.teal new file mode 100644 index 000000000..ed0ce47e3 --- /dev/null +++ b/tests/unit/teal/abi/app_fn_2mixed_arg_1ret.teal @@ -0,0 +1,30 @@ +#pragma version 6 +txna ApplicationArgs 0 +btoi +store 4 +txna ApplicationArgs 1 +store 5 +load 4 +int 5 +callsub fn2mixedarg1ret_0 +store 3 +byte 0x151F7C75 +load 3 +itob +concat +log +int 1 +return + +// fn_2mixed_arg_1ret +fn2mixedarg1ret_0: +store 1 +store 0 +load 1 +load 0 +itob +stores +load 0 +store 2 +load 2 +retsub \ No newline at end of file diff --git a/tests/unit/teal/abi/app_fn_3mixed_args_0ret.teal b/tests/unit/teal/abi/app_fn_3mixed_args_0ret.teal new file mode 100644 index 000000000..0264a222e --- /dev/null +++ b/tests/unit/teal/abi/app_fn_3mixed_args_0ret.teal @@ -0,0 +1,22 @@ +#pragma version 6 +txna ApplicationArgs 0 +btoi +store 3 +txna ApplicationArgs 1 +btoi +store 4 +txna ApplicationArgs 2 +store 5 +load 3 +int 4 +load 5 +callsub fn3mixedargs0ret_0 +int 1 +return + +// fn_3mixed_args_0ret +fn3mixedargs0ret_0: +store 2 +store 1 +store 0 +retsub \ No newline at end of file diff --git a/tests/unit/teal/abi/lsig_fn_0arg_0ret.teal b/tests/unit/teal/abi/lsig_fn_0arg_0ret.teal new file mode 100644 index 000000000..93cb677df --- /dev/null +++ b/tests/unit/teal/abi/lsig_fn_0arg_0ret.teal @@ -0,0 +1,8 @@ +#pragma version 6 +callsub fn0arg0ret_0 +int 1 +return + +// fn_0arg_0ret +fn0arg0ret_0: +retsub \ No newline at end of file diff --git a/tests/unit/teal/abi/lsig_fn_0arg_uint64_ret.teal b/tests/unit/teal/abi/lsig_fn_0arg_uint64_ret.teal new file mode 100644 index 000000000..e9355f259 --- /dev/null +++ b/tests/unit/teal/abi/lsig_fn_0arg_uint64_ret.teal @@ -0,0 +1,15 @@ +#pragma version 6 +callsub fn0arguint64ret_0 +store 0 +load 0 +itob +pop +int 1 +return + +// fn_0arg_uint64_ret +fn0arguint64ret_0: +int 1 +store 1 +load 1 +retsub \ No newline at end of file diff --git a/tests/unit/teal/abi/lsig_fn_1arg_0ret.teal b/tests/unit/teal/abi/lsig_fn_1arg_0ret.teal new file mode 100644 index 000000000..cf4a713c8 --- /dev/null +++ b/tests/unit/teal/abi/lsig_fn_1arg_0ret.teal @@ -0,0 +1,13 @@ +#pragma version 6 +arg 0 +btoi +store 0 +load 0 +callsub fn1arg0ret_0 +int 1 +return + +// fn_1arg_0ret +fn1arg0ret_0: +store 1 +retsub \ No newline at end of file diff --git a/tests/unit/teal/abi/lsig_fn_1arg_1ret.teal b/tests/unit/teal/abi/lsig_fn_1arg_1ret.teal new file mode 100644 index 000000000..b9316e7df --- /dev/null +++ b/tests/unit/teal/abi/lsig_fn_1arg_1ret.teal @@ -0,0 +1,20 @@ +#pragma version 6 +arg 0 +btoi +store 1 +load 1 +callsub fn1arg1ret_0 +store 0 +load 0 +itob +pop +int 1 +return + +// fn_1arg_1ret +fn1arg1ret_0: +store 2 +load 2 +store 3 +load 3 +retsub \ No newline at end of file diff --git a/tests/unit/teal/abi/lsig_fn_1tt_arg_uint64_ret.teal b/tests/unit/teal/abi/lsig_fn_1tt_arg_uint64_ret.teal new file mode 100644 index 000000000..8ea2f5585 --- /dev/null +++ b/tests/unit/teal/abi/lsig_fn_1tt_arg_uint64_ret.teal @@ -0,0 +1,17 @@ +#pragma version 6 +arg 0 +callsub fn1ttarguint64ret_0 +store 0 +load 0 +itob +pop +int 1 +return + +// fn_1tt_arg_uint64_ret +fn1ttarguint64ret_0: +store 1 +int 1 +store 2 +load 2 +retsub \ No newline at end of file diff --git a/tests/unit/teal/abi/lsig_fn_2arg_0ret.teal b/tests/unit/teal/abi/lsig_fn_2arg_0ret.teal new file mode 100644 index 000000000..c097d4e6c --- /dev/null +++ b/tests/unit/teal/abi/lsig_fn_2arg_0ret.teal @@ -0,0 +1,17 @@ +#pragma version 6 +arg 0 +btoi +store 0 +arg 1 +store 1 +load 0 +load 1 +callsub fn2arg0ret_0 +int 1 +return + +// fn_2arg_0ret +fn2arg0ret_0: +store 3 +store 2 +retsub \ No newline at end of file diff --git a/tests/unit/teal/abi/lsig_fn_2mixed_arg_1ret.teal b/tests/unit/teal/abi/lsig_fn_2mixed_arg_1ret.teal new file mode 100644 index 000000000..5d2ae86b2 --- /dev/null +++ b/tests/unit/teal/abi/lsig_fn_2mixed_arg_1ret.teal @@ -0,0 +1,28 @@ +#pragma version 6 +arg 0 // [a] +btoi // [btoi(a)] +store 1 // 1 -> btoi(a) +arg 1 // [b] +store 2 // 2 -> b +load 1 // [btoi(a)] +int 2 // [btoi(a), 2] +callsub fn2mixedarg1ret_0 // [btoi(a)] +store 0 // 0 -> btoi(a) +load 0 // [btoi(a)] +itob // [a] +pop // [] +int 1 // [1] +return + +// fn_2mixed_arg_1ret +fn2mixedarg1ret_0: // [btoi(a), 2] +store 4 // 4 -> 2 +store 3 // 3 -> btoi(a) +load 4 // [2] +load 3 // [2, btoi(a)] +itob // [2, a] +stores // 2 -> a +load 3 // [btoi(a)] +store 5 // 5 -> btoi(a) +load 5 // [btoi(a)] +retsub \ No newline at end of file diff --git a/tests/unit/teal/abi/lsig_fn_3mixed_args_0ret.teal b/tests/unit/teal/abi/lsig_fn_3mixed_args_0ret.teal new file mode 100644 index 000000000..fca5fd198 --- /dev/null +++ b/tests/unit/teal/abi/lsig_fn_3mixed_args_0ret.teal @@ -0,0 +1,22 @@ +#pragma version 6 +arg 0 +btoi +store 0 +arg 1 +btoi +store 1 // 1 -> btoi(a) +arg 2 +store 2 +load 0 // [a] +int 1 // [a, 1] +load 2 // [a, 1, b] +callsub fn3mixedargs0ret_0 +int 1 +return + +// fn_3mixed_args_0ret +fn3mixedargs0ret_0: +store 5 +store 4 +store 3 +retsub \ No newline at end of file diff --git a/tests/unit/teal/user_guide/user_guide_snippet_ABIReturnSubroutine.teal b/tests/unit/teal/user_guide/user_guide_snippet_ABIReturnSubroutine.teal new file mode 100644 index 000000000..a19e893be --- /dev/null +++ b/tests/unit/teal/user_guide/user_guide_snippet_ABIReturnSubroutine.teal @@ -0,0 +1,50 @@ +#pragma version 6 +txna ApplicationArgs 1 // x = abi.DynamicArray(abi.Uint64TypeSpec()) +store 0 // 0: x +load 0 // [x] +callsub abisum_0 +store 1 +byte 0x151F7C75 +load 1 +itob +concat +log +int 1 +return + +// abi_sum +abisum_0: // [x] +store 2 // 2: x +int 0 // [0] +store 3 // 3: 0 +int 0 // [0] +store 4 // 4: 0 +abisum_0_l1: // [] +load 4 +load 2 +int 0 // [0, x, 0] +extract_uint16 // [0, len(x)] +store 6 // 6: len(x) +load 6 // [0, len(x)] +< // [1] +bz abisum_0_l3 // [0] +load 2 // ... looks promising ... +int 8 +load 4 +* +int 2 ++ +extract_uint64 +store 5 +load 3 +load 5 ++ +store 3 +load 4 +int 1 ++ +store 4 +b abisum_0_l1 +abisum_0_l3: // [] +load 3 // [0] +retsub \ No newline at end of file diff --git a/tests/unit/user_guide_test.py b/tests/unit/user_guide_test.py index 809e5137e..5f4e8c0ae 100644 --- a/tests/unit/user_guide_test.py +++ b/tests/unit/user_guide_test.py @@ -60,9 +60,52 @@ def ILLEGAL_recursion(i: ScratchVar): return Seq(i.store(Int(15)), ILLEGAL_recursion(i), Int(1)) +def user_guide_snippet_ABIReturnSubroutine(): + from pyteal import ( + ABIReturnSubroutine, + Expr, + For, + Int, + ScratchVar, + Seq, + Txn, + TealType, + ) + from pyteal import abi + + # --- BEGIN doc-comment --- # + @ABIReturnSubroutine + def abi_sum(to_sum: abi.DynamicArray[abi.Uint64], *, output: abi.Uint64) -> Expr: + i = ScratchVar(TealType.uint64) + value_at_index = abi.Uint64() + return Seq( + output.set(0), + For( + i.store(Int(0)), i.load() < to_sum.length(), i.store(i.load() + Int(1)) + ).Do( + Seq( + to_sum[i.load()].store_into(value_at_index), + output.set(output.get() + value_at_index.get()), + ) + ), + ) + + program = Seq( + (to_sum_arr := abi.make(abi.DynamicArray[abi.Uint64])).decode( + Txn.application_args[1] + ), + (res := abi.Uint64()).set(abi_sum(to_sum_arr)), + abi.MethodReturn(res), + Int(1), + ) + # --- END doc-comment --- # + return program + + USER_GUIDE_SNIPPETS_COPACETIC = [ user_guide_snippet_dynamic_scratch_var, user_guide_snippet_recursiveIsEven, + user_guide_snippet_ABIReturnSubroutine, ]