From d0f9d8d68a32ae28d6d09d91a92ca61013b6ab11 Mon Sep 17 00:00:00 2001 From: Ben Guidarelli Date: Fri, 24 Jun 2022 10:05:29 -0400 Subject: [PATCH 001/206] upping max teal version --- pyteal/compiler/compiler.py | 2 +- pyteal/compiler/compiler_test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyteal/compiler/compiler.py b/pyteal/compiler/compiler.py index 5a6709efe..2a68be57a 100644 --- a/pyteal/compiler/compiler.py +++ b/pyteal/compiler/compiler.py @@ -25,7 +25,7 @@ ) from pyteal.compiler.constants import createConstantBlocks -MAX_TEAL_VERSION = 6 +MAX_TEAL_VERSION = 7 MIN_TEAL_VERSION = 2 DEFAULT_TEAL_VERSION = MIN_TEAL_VERSION diff --git a/pyteal/compiler/compiler_test.py b/pyteal/compiler/compiler_test.py index 0d6fdbe09..b3e528506 100644 --- a/pyteal/compiler/compiler_test.py +++ b/pyteal/compiler/compiler_test.py @@ -139,7 +139,7 @@ def test_compile_version_invalid(): pt.compileTeal(expr, pt.Mode.Signature, version=1) # too small with pytest.raises(pt.TealInputError): - pt.compileTeal(expr, pt.Mode.Signature, version=7) # too large + pt.compileTeal(expr, pt.Mode.Signature, version=8) # too large with pytest.raises(pt.TealInputError): pt.compileTeal(expr, pt.Mode.Signature, version=2.0) # decimal From 749fb8c8e4cd956d5cd855f2288f5ba1c09eb160 Mon Sep 17 00:00:00 2001 From: Ben Guidarelli Date: Thu, 30 Jun 2022 11:02:28 -0400 Subject: [PATCH 002/206] adding program page related ops (#412) * adding program page related ops --- docs/accessing_transaction_field.rst | 44 ++++++++++++---------- pyteal/ast/txn.py | 56 ++++++++++++++++++++++++++++ pyteal/ast/txn_test.py | 6 +++ 3 files changed, 86 insertions(+), 20 deletions(-) diff --git a/docs/accessing_transaction_field.rst b/docs/accessing_transaction_field.rst index adb8125e8..ea37663e5 100644 --- a/docs/accessing_transaction_field.rst +++ b/docs/accessing_transaction_field.rst @@ -37,26 +37,30 @@ Operator Application Call ....................................................... -================================================================================ ========================= ================ ============================================================================ -Operator Type Min TEAL Version Notes -================================================================================ ========================= ================ ============================================================================ -:any:`Txn.application_id() ` :code:`TealType.uint64` 2 -:any:`Txn.on_completion() ` :code:`TealType.uint64` 2 -:any:`Txn.approval_program() ` :code:`TealType.bytes` 2 -:any:`Txn.global_num_uints() ` :code:`TealType.uint64` 3 Maximum global integers in app schema -:any:`Txn.global_num_byte_slices() ` :code:`TealType.uint64` 3 Maximum global byte strings in app schema -:any:`Txn.local_num_uints() ` :code:`TealType.uint64` 3 Maximum local integers in app schema -:any:`Txn.local_num_byte_slices() ` :code:`TealType.uint64` 3 Maximum local byte strings in app schema -:any:`Txn.accounts ` :code:`TealType.bytes[]` 2 Array of accounts available to the application -:any:`Txn.assets ` :code:`TealType.uint64[]` 3 Array of assets available to the application -:any:`Txn.applications ` :code:`TealType.uint64[]` 3 Array of applications -:any:`Txn.clear_state_program() ` :code:`TealType.bytes` 2 -:any:`Txn.extra_program_pages() ` :code:`TealType.uint64` 4 Number of extra program pages for app -:any:`Txn.application_args ` :code:`TealType.bytes[]` 2 Array of application arguments -:any:`Txn.created_application_id() ` :code:`TealType.uint64` 5 The ID of the newly created application in this transaction. In v5, only valid on inner transactions. >= v6 works with top-level and inner transactions. -:any:`Txn.logs ` :code:`TealType.bytes[]` 5 Array of application logged items. In v5, only valid on inner transactions. >= v6 works with top-level and inner transactions. -:any:`Txn.last_log() ` :code:`TealType.bytes[]` 6 The last message emitted. Empty bytes if none were emitted. Application mode only. -================================================================================ ========================= ================ ============================================================================ +==================================================================================== ========================= ================ ============================================================================ +Operator Type Min TEAL Version Notes +==================================================================================== ========================= ================ ============================================================================ +:any:`Txn.application_id() ` :code:`TealType.uint64` 2 +:any:`Txn.on_completion() ` :code:`TealType.uint64` 2 +:any:`Txn.approval_program() ` :code:`TealType.bytes` 2 +:any:`Txn.global_num_uints() ` :code:`TealType.uint64` 3 Maximum global integers in app schema +:any:`Txn.global_num_byte_slices() ` :code:`TealType.uint64` 3 Maximum global byte strings in app schema +:any:`Txn.local_num_uints() ` :code:`TealType.uint64` 3 Maximum local integers in app schema +:any:`Txn.local_num_byte_slices() ` :code:`TealType.uint64` 3 Maximum local byte strings in app schema +:any:`Txn.accounts ` :code:`TealType.bytes[]` 2 Array of accounts available to the application +:any:`Txn.assets ` :code:`TealType.uint64[]` 3 Array of assets available to the application +:any:`Txn.applications ` :code:`TealType.uint64[]` 3 Array of applications +:any:`Txn.clear_state_program() ` :code:`TealType.bytes` 2 +:any:`Txn.extra_program_pages() ` :code:`TealType.uint64` 4 Number of extra program pages for app +:any:`Txn.application_args ` :code:`TealType.bytes[]` 2 Array of application arguments +:any:`Txn.created_application_id() ` :code:`TealType.uint64` 5 The ID of the newly created application in this transaction. In v5, only valid on inner transactions. >= v6 works with top-level and inner transactions. +:any:`Txn.logs ` :code:`TealType.bytes[]` 5 Array of application logged items. In v5, only valid on inner transactions. >= v6 works with top-level and inner transactions. +:any:`Txn.last_log() ` :code:`TealType.bytes[]` 6 The last message emitted. Empty bytes if none were emitted. Application mode only. +:any:`Txn.approval_program_pages() ` :code:`TealType.bytes[]` 7 The pages of the approval program as an array +:any:`Txn.num_approval_program_pages() ` :code:`TealType.uint64` 7 The number of approval program pages +:any:`Txn.clear_state_program_pages() ` :code:`TealType.bytes[]` 7 The pages of a clear state program as an array +:any:`Txn.num_clear_state_program_pages() ` :code:`TealType.uint64` 7 The number of clear state program pages +==================================================================================== ========================= ================ ============================================================================ Asset Config ....................................................... diff --git a/pyteal/ast/txn.py b/pyteal/ast/txn.py index e9182b74f..3c0fc0f4e 100644 --- a/pyteal/ast/txn.py +++ b/pyteal/ast/txn.py @@ -110,6 +110,22 @@ class TxnField(Enum): created_application_id = (61, "CreatedApplicationID", TealType.uint64, False, 5) last_log = (62, "LastLog", TealType.bytes, False, 6) state_proof_pk = (63, "StateProofPK", TealType.bytes, False, 6) + approval_program_pages = (64, "ApprovalProgramPages", TealType.bytes, True, 7) + num_approval_program_pages = ( + 65, + "NumApprovalProgramPages", + TealType.uint64, + False, + 7, + ) + clear_state_program_pages = (66, "ClearStateProgramPages", TealType.bytes, True, 7) + num_clear_state_program_pages = ( + 67, + "NumClearStateProgramPages", + TealType.uint64, + False, + 7, + ) def __init__( self, id: int, name: str, type: TealType, is_array: bool, min_version: int @@ -728,6 +744,20 @@ def state_proof_pk(self) -> TxnExpr: """ return self.makeTxnExpr(TxnField.state_proof_pk) + def num_approval_program_pages(self) -> TxnExpr: + """Get the number of pages in the approval program. + + Requires TEAL version 7 or higher. + """ + return self.makeTxnExpr(TxnField.num_approval_program_pages) + + def num_clear_state_program_pages(self) -> TxnExpr: + """Get the number of pages in the clear state program. + + Requires TEAL version 7 or higher. + """ + return self.makeTxnExpr(TxnField.num_clear_state_program_pages) + @property def application_args(self) -> TxnArray: """Application call arguments array. @@ -777,6 +807,32 @@ def logs(self) -> TxnArray: """ return TxnArray(self, TxnField.logs, TxnField.num_logs) + @property + def approval_program_pages(self) -> TxnArray: + """The approval program pages. + + :type: TxnArray + + Requires TEAL version 7 or higher. + """ + return TxnArray( + self, TxnField.approval_program_pages, TxnField.num_approval_program_pages + ) + + @property + def clear_state_program_pages(self) -> TxnArray: + """The clear state program pages. + + :type: TxnArray + + Requires TEAL version 7 or higher. + """ + return TxnArray( + self, + TxnField.clear_state_program_pages, + TxnField.num_clear_state_program_pages, + ) + TxnObject.__module__ = "pyteal" diff --git a/pyteal/ast/txn_test.py b/pyteal/ast/txn_test.py index eaaf01464..c0477fd23 100644 --- a/pyteal/ast/txn_test.py +++ b/pyteal/ast/txn_test.py @@ -58,6 +58,8 @@ pt.TxnField.created_application_id: lambda txn: txn.created_application_id(), pt.TxnField.last_log: lambda txn: txn.last_log(), pt.TxnField.state_proof_pk: lambda txn: txn.state_proof_pk(), + pt.TxnField.num_approval_program_pages: lambda txn: txn.num_approval_program_pages(), + pt.TxnField.num_clear_state_program_pages: lambda txn: txn.num_clear_state_program_pages(), } arrayFieldToProperty: Dict[pt.TxnField, Callable[[pt.TxnObject], pt.TxnArray]] = { @@ -66,6 +68,8 @@ pt.TxnField.assets: lambda txn: txn.assets, pt.TxnField.applications: lambda txn: txn.applications, pt.TxnField.logs: lambda txn: txn.logs, + pt.TxnField.approval_program_pages: lambda txn: txn.approval_program_pages, + pt.TxnField.clear_state_program_pages: lambda txn: txn.clear_state_program_pages, } arrayFieldToLengthField: Dict[pt.TxnField, pt.TxnField] = { @@ -74,6 +78,8 @@ pt.TxnField.assets: pt.TxnField.num_assets, pt.TxnField.applications: pt.TxnField.num_applications, pt.TxnField.logs: pt.TxnField.num_logs, + pt.TxnField.approval_program_pages: pt.TxnField.num_approval_program_pages, + pt.TxnField.clear_state_program_pages: pt.TxnField.num_clear_state_program_pages, } From 39a11c283eaa101d8188811ce22bc1e583baf151 Mon Sep 17 00:00:00 2001 From: Jacob Daitzman Date: Thu, 30 Jun 2022 11:50:44 -0400 Subject: [PATCH 003/206] Add Replace (#413) * Add Replace * Remove replace auto-import * Use scripts/generate_init.py * Add more tests to replace, substring, and extract (#1) Co-authored-by: Michael Diamant --- pyteal/__init__.pyi | 1 + pyteal/ast/__init__.py | 2 + pyteal/ast/replace.py | 86 ++++++++++++++++++++++++++++++++ pyteal/ast/replace_test.py | 97 ++++++++++++++++++++++++++++++++++++ pyteal/ast/substring.py | 12 ++--- pyteal/ast/substring_test.py | 82 ++++++++++++++++++++++++++++++ pyteal/ir/ops.py | 2 + 7 files changed, 276 insertions(+), 6 deletions(-) create mode 100644 pyteal/ast/replace.py create mode 100644 pyteal/ast/replace_test.py diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index 4fa32d071..20bc15dd4 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -138,6 +138,7 @@ __all__ = [ "Or", "Pop", "Reject", + "Replace", "Return", "ScratchIndex", "ScratchLoad", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 613a39480..a72c064fc 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -102,6 +102,7 @@ # ternary ops from pyteal.ast.ternaryexpr import Divw, Ed25519Verify, SetBit, SetByte from pyteal.ast.substring import Substring, Extract, Suffix +from pyteal.ast.replace import Replace # more ops from pyteal.ast.naryexpr import NaryExpr, And, Or, Concat @@ -272,6 +273,7 @@ "ExtractUint16", "ExtractUint32", "ExtractUint64", + "Replace", "Log", "While", "For", diff --git a/pyteal/ast/replace.py b/pyteal/ast/replace.py new file mode 100644 index 000000000..2b7968978 --- /dev/null +++ b/pyteal/ast/replace.py @@ -0,0 +1,86 @@ +from typing import cast, TYPE_CHECKING + +from pyteal.types import TealType, require_type +from pyteal.errors import verifyTealVersion +from pyteal.ir import TealOp, Op, TealBlock +from pyteal.ast.expr import Expr +from pyteal.ast.int import Int +from pyteal.ast.ternaryexpr import TernaryExpr + +if TYPE_CHECKING: + from pyteal.compiler import CompileOptions + + +class ReplaceExpr(Expr): + """An expression for replacing a section of a byte string at a given start index""" + + def __init__(self, original: Expr, start: Expr, replacement: Expr) -> None: + super().__init__() + + require_type(original, TealType.bytes) + require_type(start, TealType.uint64) + require_type(replacement, TealType.bytes) + + self.original = original + self.start = start + self.replacement = replacement + + # helper method for correctly populating op + def __get_op(self, options: "CompileOptions"): + s = cast(Int, self.start).value + if s < 2**8: + return Op.replace2 + else: + return Op.replace3 + + def __teal__(self, options: "CompileOptions"): + if not isinstance(self.start, Int): + return TernaryExpr( + Op.replace3, + (TealType.bytes, TealType.uint64, TealType.bytes), + TealType.bytes, + self.original, + self.start, + self.replacement, + ).__teal__(options) + + op = self.__get_op(options) + + verifyTealVersion( + op.min_version, + options.version, + "TEAL version too low to use op {}".format(op), + ) + + s = cast(Int, self.start).value + if op == Op.replace2: + return TealBlock.FromOp( + options, TealOp(self, op, s), self.original, self.replacement + ) + elif op == Op.replace3: + return TealBlock.FromOp( + options, TealOp(self, op), self.original, self.start, self.replacement + ) + + def __str__(self): + return "(Replace {} {} {})".format(self.original, self.start, self.replacement) + + def type_of(self): + return TealType.bytes + + def has_return(self): + return False + + +def Replace(original: Expr, start: Expr, replacement: Expr) -> Expr: + """ + Replace a portion of original bytes with new bytes at a given starting point. + + Requires TEAL version 7 or higher. + + Args: + original: The value containing the original bytes. Must evaluate to bytes. + start: The index of the byte where replacement starts. Must evaluate to an integer less than Len(original). + replacement: The value containing the replacement bytes. Must evaluate to bytes with length at most Len(original) - start. + """ + return ReplaceExpr(original, start, replacement) diff --git a/pyteal/ast/replace_test.py b/pyteal/ast/replace_test.py new file mode 100644 index 000000000..b72a5d879 --- /dev/null +++ b/pyteal/ast/replace_test.py @@ -0,0 +1,97 @@ +import pytest + +import pyteal as pt + +teal6Options = pt.CompileOptions(version=6) +teal7Options = pt.CompileOptions(version=7) + + +def test_replace_immediate(): + args = [pt.Bytes("my string"), pt.Int(0), pt.Bytes("abcdefghi")] + expr = pt.Replace(args[0], args[1], args[2]) + assert expr.type_of() == pt.TealType.bytes + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(args[0], pt.Op.byte, '"my string"'), + pt.TealOp(args[2], pt.Op.byte, '"abcdefghi"'), + pt.TealOp(expr, pt.Op.replace2, 0), + ] + ) + + actual, _ = expr.__teal__(teal7Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + with pytest.raises(pt.TealInputError): + expr.__teal__(teal6Options) + + +def test_replace_stack_int(): + my_string = "*" * 257 + args = [pt.Bytes(my_string), pt.Int(256), pt.Bytes("ab")] + expr = pt.Replace(args[0], args[1], args[2]) + assert expr.type_of() == pt.TealType.bytes + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(args[0], pt.Op.byte, '"{my_string}"'.format(my_string=my_string)), + pt.TealOp(args[1], pt.Op.int, 256), + pt.TealOp(args[2], pt.Op.byte, '"ab"'), + pt.TealOp(expr, pt.Op.replace3), + ] + ) + + actual, _ = expr.__teal__(teal7Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + with pytest.raises(pt.TealInputError): + expr.__teal__(teal6Options) + + +# Mirrors `test_replace_stack_int`, but attempts replacement with start != pt.Int. +def test_replace_stack_not_int(): + my_string = "*" * 257 + add = pt.Add(pt.Int(254), pt.Int(2)) + args = [pt.Bytes(my_string), add, pt.Bytes("ab")] + expr = pt.Replace(args[0], args[1], args[2]) + assert expr.type_of() == pt.TealType.bytes + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(args[0], pt.Op.byte, '"{my_string}"'.format(my_string=my_string)), + pt.TealOp(pt.Int(254), pt.Op.int, 254), + pt.TealOp(pt.Int(2), pt.Op.int, 2), + pt.TealOp(add, pt.Op.add), + pt.TealOp(args[2], pt.Op.byte, '"ab"'), + pt.TealOp(expr, pt.Op.replace3), + ] + ) + + actual, _ = expr.__teal__(teal7Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + with pt.TealComponent.Context.ignoreExprEquality(): + assert actual == expected + + with pytest.raises(pt.TealInputError): + expr.__teal__(teal6Options) + + +def test_replace_invalid(): + with pytest.raises(pt.TealTypeError): + pt.Replace(pt.Bytes("my string"), pt.Int(0), pt.Int(1)) + + with pytest.raises(pt.TealTypeError): + pt.Replace( + pt.Bytes("my string"), pt.Bytes("should be int"), pt.Bytes("abcdefghi") + ) + + with pytest.raises(pt.TealTypeError): + pt.Replace(pt.Bytes("my string"), pt.Txn.sender(), pt.Bytes("abcdefghi")) diff --git a/pyteal/ast/substring.py b/pyteal/ast/substring.py index 438b40933..6febf69dc 100644 --- a/pyteal/ast/substring.py +++ b/pyteal/ast/substring.py @@ -26,7 +26,7 @@ def __init__(self, stringArg: Expr, startArg: Expr, endArg: Expr) -> None: self.endArg = endArg # helper method for correctly populating op - def __getOp(self, options: "CompileOptions"): + def __get_op(self, options: "CompileOptions"): s, e = cast(Int, self.startArg).value, cast(Int, self.endArg).value l = e - s @@ -58,7 +58,7 @@ def __teal__(self, options: "CompileOptions"): self.endArg, ).__teal__(options) - op = self.__getOp(options) + op = self.__get_op(options) verifyTealVersion( op.min_version, @@ -121,7 +121,7 @@ def __init__(self, stringArg: Expr, startArg: Expr, lenArg: Expr) -> None: self.lenArg = lenArg # helper method for correctly populating op - def __getOp(self, options: "CompileOptions"): + def __get_op(self, options: "CompileOptions"): s, l = cast(Int, self.startArg).value, cast(Int, self.lenArg).value if s < 2**8 and l > 0 and l < 2**8: return Op.extract @@ -139,7 +139,7 @@ def __teal__(self, options: "CompileOptions"): self.lenArg, ).__teal__(options) - op = self.__getOp(options) + op = self.__get_op(options) verifyTealVersion( op.min_version, @@ -186,7 +186,7 @@ def __init__( self.startArg = startArg # helper method for correctly populating op - def __getOp(self, options: "CompileOptions"): + def __get_op(self, options: "CompileOptions"): if not isinstance(self.startArg, Int): return Op.substring3 @@ -197,7 +197,7 @@ def __getOp(self, options: "CompileOptions"): return Op.substring3 def __teal__(self, options: "CompileOptions"): - op = self.__getOp(options) + op = self.__get_op(options) verifyTealVersion( op.min_version, diff --git a/pyteal/ast/substring_test.py b/pyteal/ast/substring_test.py index 2aafeabfd..ae5bcace2 100644 --- a/pyteal/ast/substring_test.py +++ b/pyteal/ast/substring_test.py @@ -272,6 +272,88 @@ def test_suffix_stack(): assert actual == expected +@pytest.mark.parametrize("op", [pt.Op.extract3, pt.Op.substring3]) +def test_startArg_not_int(op: pt.Op): + my_string = "*" * 257 + add = pt.Add(pt.Int(254), pt.Int(2)) + args = [pt.Bytes(my_string), add, pt.Int(257)] + + def generate_expr() -> pt.Expr: + match op: + case pt.Op.extract3: + return pt.Extract(args[0], args[1], args[2]) + case pt.Op.substring3: + return pt.Substring(args[0], args[1], args[2]) + case _: + raise Exception(f"Unsupported {op=}") + + expr = generate_expr() + assert expr.type_of() == pt.TealType.bytes + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(args[0], pt.Op.byte, '"{my_string}"'.format(my_string=my_string)), + pt.TealOp(pt.Int(254), pt.Op.int, 254), + pt.TealOp(pt.Int(2), pt.Op.int, 2), + pt.TealOp(add, pt.Op.add), + pt.TealOp(args[2], pt.Op.int, 257), + pt.TealOp(None, op), + ] + ) + + actual, _ = expr.__teal__(teal5Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + with pt.TealComponent.Context.ignoreExprEquality(): + assert actual == expected + + if op == pt.Op.extract3: + with pytest.raises(pt.TealInputError): + expr.__teal__(teal4Options) + + +@pytest.mark.parametrize("op", [pt.Op.extract3, pt.Op.substring3]) +def test_endArg_not_int(op: pt.Op): + my_string = "*" * 257 + add = pt.Add(pt.Int(254), pt.Int(3)) + args = [pt.Bytes(my_string), pt.Int(256), add] + + def generate_expr() -> pt.Expr: + match op: + case pt.Op.extract3: + return pt.Extract(args[0], args[1], args[2]) + case pt.Op.substring3: + return pt.Substring(args[0], args[1], args[2]) + case _: + raise Exception(f"Unsupported {op=}") + + expr = generate_expr() + assert expr.type_of() == pt.TealType.bytes + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(args[0], pt.Op.byte, '"{my_string}"'.format(my_string=my_string)), + pt.TealOp(args[1], pt.Op.int, 256), + pt.TealOp(pt.Int(254), pt.Op.int, 254), + pt.TealOp(pt.Int(3), pt.Op.int, 3), + pt.TealOp(add, pt.Op.add), + pt.TealOp(None, op), + ] + ) + + actual, _ = expr.__teal__(teal5Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + with pt.TealComponent.Context.ignoreExprEquality(): + assert actual == expected + + if op == pt.Op.extract3: + with pytest.raises(pt.TealInputError): + expr.__teal__(teal4Options) + + def test_suffix_invalid(): with pytest.raises(pt.TealTypeError): pt.Suffix(pt.Int(0), pt.Int(0)) diff --git a/pyteal/ir/ops.py b/pyteal/ir/ops.py index 7d91dab42..f9a8f731e 100644 --- a/pyteal/ir/ops.py +++ b/pyteal/ir/ops.py @@ -179,6 +179,8 @@ def min_version(self) -> int: gitxnas = OpType("gitxnas", Mode.Application, 6) gloadss = OpType("gloadss", Mode.Application, 6) acct_params_get = OpType("acct_params_get", Mode.Application, 6) + replace2 = OpType("replace2", Mode.Signature | Mode.Application, 7) + replace3 = OpType("replace3", Mode.Signature | Mode.Application, 7) # fmt: on From dd2c7ecc0617137411951e87452a58fde2887a8e Mon Sep 17 00:00:00 2001 From: Jacob Daitzman Date: Thu, 30 Jun 2022 12:09:30 -0400 Subject: [PATCH 004/206] Add Block (#415) * Add Block # Conflicts: # pyteal/ir/ops.py * Disable flake8 errors on formatted lines * Add past version failure check * Remove unnecessary ignore Expr equality context --- pyteal/__init__.pyi | 1 + pyteal/ast/__init__.py | 2 + pyteal/ast/block.py | 80 ++++++++++++++++++++++++++++++++++++++++ pyteal/ast/block_test.py | 60 ++++++++++++++++++++++++++++++ pyteal/ir/ops.py | 1 + 5 files changed, 144 insertions(+) create mode 100644 pyteal/ast/block.py create mode 100644 pyteal/ast/block_test.py diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index 20bc15dd4..85f89147a 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -43,6 +43,7 @@ __all__ = [ "BitwiseNot", "BitwiseOr", "BitwiseXor", + "Block", "Break", "Btoi", "Bytes", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index a72c064fc..de22eb659 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -20,6 +20,7 @@ Txn, ) from pyteal.ast.gtxn import GtxnExpr, GtxnaExpr, TxnGroup, Gtxn +from pyteal.ast.block import Block from pyteal.ast.gaid import GeneratedID from pyteal.ast.gitxn import Gitxn, GitxnExpr, GitxnaExpr, InnerTxnGroup from pyteal.ast.gload import ImportScratchValue @@ -162,6 +163,7 @@ "GtxnaExpr", "TxnGroup", "Gtxn", + "Block", "GeneratedID", "ImportScratchValue", "Global", diff --git a/pyteal/ast/block.py b/pyteal/ast/block.py new file mode 100644 index 000000000..041483aae --- /dev/null +++ b/pyteal/ast/block.py @@ -0,0 +1,80 @@ +from typing import TYPE_CHECKING +from enum import Enum + +from pyteal.types import TealType, require_type +from pyteal.errors import verifyFieldVersion +from pyteal.ir import TealOp, Op, TealBlock +from pyteal.ast.expr import Expr +from pyteal.ast.leafexpr import LeafExpr + +if TYPE_CHECKING: + from pyteal.compiler import CompileOptions + + +class BlockField(Enum): + # fmt: off + # id | name | type | min version + block_seed = (0, "BlkSeed", TealType.bytes, 7) # noqa: E222 + block_timestamp = (1, "BlkTimestamp", TealType.uint64, 7) # noqa: E222 + + # fmt: on + + def __init__(self, id: int, name: str, type: TealType, min_version: int) -> None: + self.id = id + self.arg_name = name + self.ret_type = type + self.min_version = min_version + + def type_of(self) -> TealType: + return self.ret_type + + +BlockField.__module__ = "pyteal" + + +class Block(LeafExpr): + """An expression that accesses a block property.""" + + def __init__(self, field: BlockField, block: Expr) -> None: + super().__init__() + self.field = field + + require_type(block, TealType.uint64) + self.block = block + + def __teal__(self, options: "CompileOptions"): + verifyFieldVersion(self.field.arg_name, self.field.min_version, options.version) + + op = TealOp(self, Op.block, self.field.arg_name) + return TealBlock.FromOp(options, op, self.block) + + def __str__(self): + return "(Block {})".format(self.field.arg_name) + + def type_of(self): + return self.field.type_of() + + @classmethod + def seed(cls, block: Expr) -> "Block": + """Get the seed of a block. + + Args: + block: A block index that corresponds to the block to check, + must be evaluated to uint64. Fails if the block index is not less than the + current round or more than 1001 rounds before txn.LastValid. + """ + return cls(BlockField.block_seed, block) + + @classmethod + def timestamp(cls, block: Expr) -> "Block": + """Get the timestamp of a block. + + Args: + block: A block index that corresponds to the block to check, + must be evaluated to uint64. Fails if the block index is not less than the + current round or more than 1001 rounds before txn.LastValid. + """ + return cls(BlockField.block_timestamp, block) + + +Block.__module__ = "pyteal" diff --git a/pyteal/ast/block_test.py b/pyteal/ast/block_test.py new file mode 100644 index 000000000..0cd571063 --- /dev/null +++ b/pyteal/ast/block_test.py @@ -0,0 +1,60 @@ +import pytest + +import pyteal as pt + +teal6Options = pt.CompileOptions(version=6) +teal7Options = pt.CompileOptions(version=7) + + +def test_block_seed(): + arg = pt.Int(0) + expr = pt.Block.seed(arg) + assert expr.type_of() == pt.TealType.bytes + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(arg, pt.Op.int, 0), + pt.TealOp(expr, pt.Op.block, "BlkSeed"), + ] + ) + + actual, _ = expr.__teal__(teal7Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + with pytest.raises(pt.TealInputError): + expr.__teal__(teal6Options) + + +def test_block_seed_invalid(): + with pytest.raises(pt.TealTypeError): + pt.Block.seed(pt.Bytes("")) + + +def test_block_timestamp(): + arg = pt.Int(0) + expr = pt.Block.timestamp(arg) + assert expr.type_of() == pt.TealType.uint64 + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(arg, pt.Op.int, 0), + pt.TealOp(expr, pt.Op.block, "BlkTimestamp"), + ] + ) + + actual, _ = expr.__teal__(teal7Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + with pytest.raises(pt.TealInputError): + expr.__teal__(teal6Options) + + +def test_block_timestamp_invalid(): + with pytest.raises(pt.TealTypeError): + pt.Block.timestamp(pt.Txn.sender()) diff --git a/pyteal/ir/ops.py b/pyteal/ir/ops.py index f9a8f731e..3a2c49f37 100644 --- a/pyteal/ir/ops.py +++ b/pyteal/ir/ops.py @@ -181,6 +181,7 @@ def min_version(self) -> int: acct_params_get = OpType("acct_params_get", Mode.Application, 6) replace2 = OpType("replace2", Mode.Signature | Mode.Application, 7) replace3 = OpType("replace3", Mode.Signature | Mode.Application, 7) + block = OpType("block", Mode.Signature | Mode.Application, 7) # fmt: on From 8c3d2a03200e29694329e6102993b0460e6ea587 Mon Sep 17 00:00:00 2001 From: Jacob Daitzman Date: Thu, 30 Jun 2022 12:25:30 -0400 Subject: [PATCH 005/206] Add JsonRef (#417) * Add JsonRef * Use named class methods to specify value type * Remove unnecessary ignore Expr equality context * Fix docstring link --- pyteal/__init__.pyi | 1 + pyteal/ast/__init__.py | 2 + pyteal/ast/jsonref.py | 107 +++++++++++++++++++++++++++++++++++++ pyteal/ast/jsonref_test.py | 83 ++++++++++++++++++++++++++++ pyteal/ir/ops.py | 1 + 5 files changed, 194 insertions(+) create mode 100644 pyteal/ast/jsonref.py create mode 100644 pyteal/ast/jsonref_test.py diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index 85f89147a..ec4af54a0 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -108,6 +108,7 @@ __all__ = [ "InnerTxnGroup", "Int", "Itob", + "JsonRef", "Keccak256", "LabelReference", "Le", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index de22eb659..919e8b6d6 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -104,6 +104,7 @@ from pyteal.ast.ternaryexpr import Divw, Ed25519Verify, SetBit, SetByte from pyteal.ast.substring import Substring, Extract, Suffix from pyteal.ast.replace import Replace +from pyteal.ast.jsonref import JsonRef # more ops from pyteal.ast.naryexpr import NaryExpr, And, Or, Concat @@ -285,4 +286,5 @@ "EcdsaVerify", "EcdsaDecompress", "EcdsaRecover", + "JsonRef", ] diff --git a/pyteal/ast/jsonref.py b/pyteal/ast/jsonref.py new file mode 100644 index 000000000..91018d714 --- /dev/null +++ b/pyteal/ast/jsonref.py @@ -0,0 +1,107 @@ +from typing import TYPE_CHECKING +from enum import Enum + +from pyteal.types import TealType, require_type +from pyteal.errors import verifyFieldVersion, verifyTealVersion +from pyteal.ir import TealOp, Op, TealBlock +from pyteal.ast.expr import Expr +from pyteal.ast.leafexpr import LeafExpr + +if TYPE_CHECKING: + from pyteal.compiler import CompileOptions + + +class JsonRefType(Enum): + # fmt: off + # id | name | type | min version + string = (0, "JSONString", TealType.bytes, 7) + uint64 = (1, "JSONUint64", TealType.uint64, 7) + object = (2, "JSONObject", TealType.bytes, 7) + # fmt: on + + def __init__(self, id: int, name: str, type: TealType, min_version: int) -> None: + self.id = id + self.arg_name = name + self.ret_type = type + self.min_version = min_version + + def type_of(self) -> TealType: + return self.ret_type + + +JsonRefType.__module__ = "pyteal" + + +class JsonRef(LeafExpr): + """An expression that accesses the value associated with a given key from a supported utf-8 encoded json object. + + The json object must satisfy a `particular specification `_. + """ + + def __init__(self, type: JsonRefType, json_obj: Expr, key: Expr) -> None: + super().__init__() + + self.type = type + + require_type(json_obj, TealType.bytes) + self.json_obj = json_obj + + require_type(key, TealType.bytes) + self.key = key + + def __teal__(self, options: "CompileOptions"): + verifyTealVersion( + Op.json_ref.min_version, + options.version, + "TEAL version too low to use op json_ref", + ) + + verifyFieldVersion(self.type.arg_name, self.type.min_version, options.version) + + op = TealOp(self, Op.json_ref, self.type.arg_name) + return TealBlock.FromOp(options, op, self.json_obj, self.key) + + def __str__(self): + return "(JsonRef {})".format(self.type.arg_name) + + def type_of(self): + return self.type.type_of() + + @classmethod + def as_string(cls, json_obj: Expr, key: Expr) -> "JsonRef": + """Access the value of a given key as a string. + + Refer to the `JsonRef` class documentation for valid json specification. + + Args: + json_obj: The utf-8 encoded json object. + key: The key to access in the json object. + """ + return cls(JsonRefType.string, json_obj, key) + + @classmethod + def as_uint64(cls, json_obj: Expr, key: Expr) -> "JsonRef": + """Access the value of a given key as a uint64. + + Refer to the `JsonRef` class documentation for valid json specification. + + Args: + json_obj: The utf-8 encoded json object. + key: The key to access in the json object. + """ + return cls(JsonRefType.uint64, json_obj, key) + + @classmethod + def as_object(cls, json_obj: Expr, key: Expr) -> "JsonRef": + """Access the value of a given key as a json object. + + Refer to the `JsonRef` class documentation for valid json specification. + + Args: + json_obj: The utf-8 encoded json object. + key: The key to access in the json object. + """ + return cls(JsonRefType.object, json_obj, key) + + +JsonRef.__module__ = "pyteal" diff --git a/pyteal/ast/jsonref_test.py b/pyteal/ast/jsonref_test.py new file mode 100644 index 000000000..356c74591 --- /dev/null +++ b/pyteal/ast/jsonref_test.py @@ -0,0 +1,83 @@ +import pytest + +import pyteal as pt + +teal6Options = pt.CompileOptions(version=6) +teal7Options = pt.CompileOptions(version=7) + + +def test_json_string(): + args = [pt.Bytes('{"foo":"bar"}'), pt.Bytes("foo")] + expr = pt.JsonRef.as_string(*args) + assert expr.type_of() == pt.TealType.bytes + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(args[0], pt.Op.byte, '"{\\"foo\\":\\"bar\\"}"'), + pt.TealOp(args[1], pt.Op.byte, '"foo"'), + pt.TealOp(expr, pt.Op.json_ref, "JSONString"), + ] + ) + + actual, _ = expr.__teal__(teal7Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + with pytest.raises(pt.TealInputError): + expr.__teal__(teal6Options) + + +def test_json_uint64(): + args = [pt.Bytes('{"foo":123456789}'), pt.Bytes("foo")] + expr = pt.JsonRef.as_uint64(*args) + assert expr.type_of() == pt.TealType.uint64 + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(args[0], pt.Op.byte, '"{\\"foo\\":123456789}"'), + pt.TealOp(args[1], pt.Op.byte, '"foo"'), + pt.TealOp(expr, pt.Op.json_ref, "JSONUint64"), + ] + ) + + actual, _ = expr.__teal__(teal7Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + with pytest.raises(pt.TealInputError): + expr.__teal__(teal6Options) + + +def test_json_object(): + args = [pt.Bytes('{"foo":{"key": "value"}}'), pt.Bytes("foo")] + expr = pt.JsonRef.as_object(*args) + assert expr.type_of() == pt.TealType.bytes + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(args[0], pt.Op.byte, '"{\\"foo\\":{\\"key\\": \\"value\\"}}"'), + pt.TealOp(args[1], pt.Op.byte, '"foo"'), + pt.TealOp(expr, pt.Op.json_ref, "JSONObject"), + ] + ) + + actual, _ = expr.__teal__(teal7Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + with pytest.raises(pt.TealInputError): + expr.__teal__(teal6Options) + + +def test_json_ref_invalid(): + with pytest.raises(pt.TealTypeError): + pt.JsonRef.as_object(pt.Int(0), pt.Bytes("a")) + + with pytest.raises(pt.TealTypeError): + pt.JsonRef.as_string(pt.Bytes("a"), pt.Int(0)) diff --git a/pyteal/ir/ops.py b/pyteal/ir/ops.py index 3a2c49f37..f3ffc1a44 100644 --- a/pyteal/ir/ops.py +++ b/pyteal/ir/ops.py @@ -181,6 +181,7 @@ def min_version(self) -> int: acct_params_get = OpType("acct_params_get", Mode.Application, 6) replace2 = OpType("replace2", Mode.Signature | Mode.Application, 7) replace3 = OpType("replace3", Mode.Signature | Mode.Application, 7) + json_ref = OpType("json_ref", Mode.Signature | Mode.Application, 7) block = OpType("block", Mode.Signature | Mode.Application, 7) # fmt: on From 839b9852521479a7a8be3e12de832c1ba4980258 Mon Sep 17 00:00:00 2001 From: Jacob Daitzman Date: Thu, 30 Jun 2022 13:47:58 -0400 Subject: [PATCH 006/206] Add Base64Decode (#418) * Add Base64Decode * Remove unnecessary ignore Expr equality context --- pyteal/__init__.pyi | 1 + pyteal/ast/__init__.py | 2 + pyteal/ast/base64decode.py | 85 +++++++++++++++++++++++++++++++++ pyteal/ast/base64decode_test.py | 57 ++++++++++++++++++++++ pyteal/ir/ops.py | 1 + 5 files changed, 146 insertions(+) create mode 100644 pyteal/ast/base64decode.py create mode 100644 pyteal/ast/base64decode_test.py diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index ec4af54a0..c4f1dd670 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -37,6 +37,7 @@ __all__ = [ "AssetHolding", "AssetParam", "Balance", + "Base64Decode", "BinaryExpr", "BitLen", "BitwiseAnd", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 919e8b6d6..f42ee4ec0 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -99,6 +99,7 @@ ExtractUint32, ExtractUint64, ) +from pyteal.ast.base64decode import Base64Decode # ternary ops from pyteal.ast.ternaryexpr import Divw, Ed25519Verify, SetBit, SetByte @@ -277,6 +278,7 @@ "ExtractUint32", "ExtractUint64", "Replace", + "Base64Decode", "Log", "While", "For", diff --git a/pyteal/ast/base64decode.py b/pyteal/ast/base64decode.py new file mode 100644 index 000000000..7dcf47c18 --- /dev/null +++ b/pyteal/ast/base64decode.py @@ -0,0 +1,85 @@ +from typing import TYPE_CHECKING +from enum import Enum + +from pyteal.types import TealType, require_type +from pyteal.errors import verifyFieldVersion +from pyteal.ir import TealOp, Op, TealBlock +from pyteal.ast.expr import Expr +from pyteal.ast.leafexpr import LeafExpr + +if TYPE_CHECKING: + from pyteal.compiler import CompileOptions + + +class Base64Encoding(Enum): + # fmt: off + # id | name | min version + url = (0, "URLEncoding", 7) + std = (1, "StdEncoding", 7) + # fmt: on + + def __init__(self, id: int, name: str, min_version: int) -> None: + self.id = id + self.arg_name = name + self.min_version = min_version + + +Base64Encoding.__module__ = "pyteal" + + +class Base64Decode(LeafExpr): + """An expression that decodes a base64-encoded byte string according to a specific encoding. + + See [RFC 4648](https://rfc-editor.org/rfc/rfc4648.html#section-4) (sections 4 and 5) for information on specifications. + + It is assumed that the encoding ends with the exact number of = padding characters as required by the RFC. + When padding occurs, any unused pad bits in the encoding must be set to zero or the decoding will fail. + The special cases of \\n and \\r are allowed but completely ignored. An error will result when attempting + to decode a string with a character that is not in the encoding alphabet or not one of =, \\r, or \\n. + """ + + def __init__(self, encoding: Base64Encoding, base64: Expr) -> None: + super().__init__() + self.encoding = encoding + + require_type(base64, TealType.bytes) + self.base64 = base64 + + def __teal__(self, options: "CompileOptions"): + verifyFieldVersion( + self.encoding.arg_name, self.encoding.min_version, options.version + ) + + op = TealOp(self, Op.base64_decode, self.encoding.arg_name) + return TealBlock.FromOp(options, op, self.base64) + + def __str__(self): + return "(Base64Decode {})".format(self.encoding.arg_name) + + def type_of(self): + return TealType.bytes + + @classmethod + def url(cls, base64: Expr) -> "Base64Decode": + """Decode a base64-encoded byte string according to the URL encoding. + + Refer to the `Base64Decode` class documentation for more information. + + Args: + base64: A base64-encoded byte string. + """ + return cls(Base64Encoding.url, base64) + + @classmethod + def std(cls, base64: Expr) -> "Base64Decode": + """Decode a base64-encoded byte string according to the Standard encoding. + + Refer to the `Base64Decode` class documentation for more information. + + Args: + base64: A base64-encoded byte string. + """ + return cls(Base64Encoding.std, base64) + + +Base64Decode.__module__ = "pyteal" diff --git a/pyteal/ast/base64decode_test.py b/pyteal/ast/base64decode_test.py new file mode 100644 index 000000000..14eb48799 --- /dev/null +++ b/pyteal/ast/base64decode_test.py @@ -0,0 +1,57 @@ +import pytest + +import pyteal as pt + +teal6Options = pt.CompileOptions(version=6) +teal7Options = pt.CompileOptions(version=7) + + +def test_base64decode_std(): + arg = pt.Bytes("aGVsbG8gd29ybGQ=") + expr = pt.Base64Decode.std(arg) + assert expr.type_of() == pt.TealType.bytes + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(arg, pt.Op.byte, '"aGVsbG8gd29ybGQ="'), + pt.TealOp(expr, pt.Op.base64_decode, "StdEncoding"), + ] + ) + + actual, _ = expr.__teal__(teal7Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + with pytest.raises(pt.TealInputError): + expr.__teal__(teal6Options) + + +def test_base64decode_url(): + arg = pt.Bytes("aGVsbG8gd29ybGQ") + expr = pt.Base64Decode.url(arg) + assert expr.type_of() == pt.TealType.bytes + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(arg, pt.Op.byte, '"aGVsbG8gd29ybGQ"'), + pt.TealOp(expr, pt.Op.base64_decode, "URLEncoding"), + ] + ) + + actual, _ = expr.__teal__(teal7Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + with pytest.raises(pt.TealInputError): + expr.__teal__(teal6Options) + + +def test_base64decode_invalid(): + with pytest.raises(pt.TealTypeError): + pt.Base64Decode.std(pt.Int(0)) + with pytest.raises(pt.TealTypeError): + pt.Base64Decode.url(pt.Int(0)) diff --git a/pyteal/ir/ops.py b/pyteal/ir/ops.py index f3ffc1a44..a21e34bc4 100644 --- a/pyteal/ir/ops.py +++ b/pyteal/ir/ops.py @@ -181,6 +181,7 @@ def min_version(self) -> int: acct_params_get = OpType("acct_params_get", Mode.Application, 6) replace2 = OpType("replace2", Mode.Signature | Mode.Application, 7) replace3 = OpType("replace3", Mode.Signature | Mode.Application, 7) + base64_decode = OpType("base64_decode", Mode.Application | Mode.Signature, 7) json_ref = OpType("json_ref", Mode.Signature | Mode.Application, 7) block = OpType("block", Mode.Signature | Mode.Application, 7) # fmt: on From 7cccdcb9b9ab14b7539e349e1fa3b2ba9ea18ab0 Mon Sep 17 00:00:00 2001 From: Jacob Daitzman Date: Thu, 30 Jun 2022 14:00:06 -0400 Subject: [PATCH 007/206] Support Secp256r1 curve (#423) * Support Secp256r1 curve * Fix type errors in ecdsa tests * Fix typo * Test Secp256k1 curve against TEAL 5 instead * Add compile check to `MultiValue` class * Use `MultiValue` compile checks instead of inheritance --- pyteal/ast/ecdsa.py | 18 +++-- pyteal/ast/ecdsa_test.py | 162 +++++++++++++++++++++++++++------------ pyteal/ast/multi.py | 6 +- pyteal/ast/multi_test.py | 102 ++++++++++++++---------- 4 files changed, 191 insertions(+), 97 deletions(-) diff --git a/pyteal/ast/ecdsa.py b/pyteal/ast/ecdsa.py index b85acf2c1..06e4e49db 100644 --- a/pyteal/ast/ecdsa.py +++ b/pyteal/ast/ecdsa.py @@ -2,7 +2,7 @@ from typing import Tuple, TYPE_CHECKING from pyteal.ast import Expr, MultiValue -from pyteal.errors import TealTypeError, verifyTealVersion +from pyteal.errors import TealTypeError, verifyFieldVersion, verifyTealVersion from pyteal.ir import Op, TealBlock, TealOp from pyteal.types import TealType, require_type @@ -17,6 +17,7 @@ class EcdsaCurve(Enum): """Enum representing an elliptic curve specification used in ECDSA.""" Secp256k1 = (0, "Secp256k1", 5) + Secp256r1 = (1, "Secp256r1", 7) def __init__(self, id: int, name: str, min_version: int) -> None: self.id = id @@ -52,11 +53,13 @@ def __init__( def __teal__(self, options: "CompileOptions"): verifyTealVersion( - max(self.op.min_version, self.curve.min_version), + self.op.min_version, options.version, "TEAL version too low to use op {}".format(self.op), ) + verifyFieldVersion(self.curve.arg_name, self.curve.min_version, options.version) + return TealBlock.FromOp( options, TealOp(self, self.op, self.curve.arg_name), *self.args ) @@ -113,11 +116,9 @@ def EcdsaVerify( def EcdsaDecompress(curve: EcdsaCurve, compressed_pk: Expr) -> MultiValue: """Decompress an ECDSA public key. - Args: curve: Enum representing the ECDSA curve used for the public key compressed_pk: The compressed public key. Must be 33 bytes long and big endian encoded. - Returns: A MultiValue expression representing the two components of the public key, big endian encoded. @@ -132,6 +133,9 @@ def EcdsaDecompress(curve: EcdsaCurve, compressed_pk: Expr) -> MultiValue: EcdsaPubkey, immediate_args=[curve.arg_name], args=[compressed_pk], + compile_check=lambda options: verifyFieldVersion( + curve.arg_name, curve.min_version, options.version + ), ) @@ -139,16 +143,13 @@ def EcdsaRecover( curve: EcdsaCurve, data: Expr, recovery_id: Expr, sigA: Expr, sigB: Expr ) -> MultiValue: """Reover an ECDSA public key from a signature. - All byte arguments must be big endian encoded. - Args: curve: Enum representing the ECDSA curve used for the public key data: Hash value of the signed data. Must be 32 bytes long. recovery_id: value used to extract public key from signature. Must evaluate to uint. sigA: First component of the signature. Must evaluate to bytes. sigB: Second component of the signature. Must evaluate to bytes. - Returns: A MultiValue expression representing the two components of the public key, big endian encoded. @@ -166,4 +167,7 @@ def EcdsaRecover( EcdsaPubkey, immediate_args=[curve.arg_name], args=[data, recovery_id, sigA, sigB], + compile_check=lambda options: verifyFieldVersion( + curve.arg_name, curve.min_version, options.version + ), ) diff --git a/pyteal/ast/ecdsa_test.py b/pyteal/ast/ecdsa_test.py index 681755a65..03cec2207 100644 --- a/pyteal/ast/ecdsa_test.py +++ b/pyteal/ast/ecdsa_test.py @@ -1,22 +1,28 @@ import pytest +from typing import Union, List, cast import pyteal as pt teal4Options = pt.CompileOptions(version=4) teal5Options = pt.CompileOptions(version=5) +teal7Options = pt.CompileOptions(version=7) +curve_options_map = { + pt.EcdsaCurve.Secp256k1: teal5Options, + pt.EcdsaCurve.Secp256r1: teal7Options, +} -def test_ecdsa_decompress(): + +@pytest.mark.parametrize("curve", [pt.EcdsaCurve.Secp256k1, pt.EcdsaCurve.Secp256r1]) +def test_ecdsa_decompress(curve: pt.EcdsaCurve): compressed_pubkey = pt.Bytes("XY") - pubkey = pt.EcdsaDecompress(pt.EcdsaCurve.Secp256k1, compressed_pubkey) + pubkey = pt.EcdsaDecompress(curve, compressed_pubkey) assert pubkey.type_of() == pt.TealType.none expected = pt.TealSimpleBlock( [ pt.TealOp(compressed_pubkey, pt.Op.byte, '"XY"'), - pt.TealOp( - pubkey, pt.Op.ecdsa_pk_decompress, pt.EcdsaCurve.Secp256k1.arg_name - ), + pt.TealOp(pubkey, pt.Op.ecdsa_pk_decompress, curve.arg_name), pt.TealOp( pubkey.output_slots[1].store(), pt.Op.store, pubkey.output_slots[1] ), @@ -26,7 +32,7 @@ def test_ecdsa_decompress(): ] ) - actual, _ = pubkey.__teal__(teal5Options) + actual, _ = pubkey.__teal__(curve_options_map[curve]) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -34,14 +40,22 @@ def test_ecdsa_decompress(): assert actual == expected # compile without errors this is necessary so assembly is also tested - pt.compileTeal(pt.Seq(pubkey, pt.Approve()), pt.Mode.Application, version=5) + pt.compileTeal( + pt.Seq(pubkey, pt.Approve()), pt.Mode.Application, version=curve.min_version + ) + with pytest.raises(pt.TealInputError): + pt.compileTeal( + pt.Seq(pubkey, pt.Approve()), + pt.Mode.Application, + version=curve.min_version - 1, + ) -def test_ecdsa_recover(): + +@pytest.mark.parametrize("curve", [pt.EcdsaCurve.Secp256k1, pt.EcdsaCurve.Secp256r1]) +def test_ecdsa_recover(curve: pt.EcdsaCurve): args = [pt.Bytes("data"), pt.Int(1), pt.Bytes("sigA"), pt.Bytes("sigB")] - pubkey = pt.EcdsaRecover( - pt.EcdsaCurve.Secp256k1, args[0], args[1], args[2], args[3] - ) + pubkey = pt.EcdsaRecover(curve, args[0], args[1], args[2], args[3]) assert pubkey.type_of() == pt.TealType.none expected = pt.TealSimpleBlock( @@ -50,7 +64,7 @@ def test_ecdsa_recover(): pt.TealOp(args[1], pt.Op.int, 1), pt.TealOp(args[2], pt.Op.byte, '"sigA"'), pt.TealOp(args[3], pt.Op.byte, '"sigB"'), - pt.TealOp(pubkey, pt.Op.ecdsa_pk_recover, pt.EcdsaCurve.Secp256k1.arg_name), + pt.TealOp(pubkey, pt.Op.ecdsa_pk_recover, curve.arg_name), pt.TealOp( pubkey.output_slots[1].store(), pt.Op.store, pubkey.output_slots[1] ), @@ -60,7 +74,7 @@ def test_ecdsa_recover(): ] ) - actual, _ = pubkey.__teal__(teal5Options) + actual, _ = pubkey.__teal__(curve_options_map[curve]) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -68,13 +82,23 @@ def test_ecdsa_recover(): assert actual == expected # compile without errors this is necessary so assembly is also tested - pt.compileTeal(pt.Seq(pubkey, pt.Approve()), pt.Mode.Application, version=5) + pt.compileTeal( + pt.Seq(pubkey, pt.Approve()), pt.Mode.Application, version=curve.min_version + ) + + with pytest.raises(pt.TealInputError): + pt.compileTeal( + pt.Seq(pubkey, pt.Approve()), + pt.Mode.Application, + version=curve.min_version - 1, + ) -def test_ecdsa_verify_basic(): +@pytest.mark.parametrize("curve", [pt.EcdsaCurve.Secp256k1, pt.EcdsaCurve.Secp256r1]) +def test_ecdsa_verify_basic(curve: pt.EcdsaCurve): args = [pt.Bytes("data"), pt.Bytes("sigA"), pt.Bytes("sigB")] pubkey = (pt.Bytes("X"), pt.Bytes("Y")) - expr = pt.EcdsaVerify(pt.EcdsaCurve.Secp256k1, args[0], args[1], args[2], pubkey) + expr = pt.EcdsaVerify(curve, args[0], args[1], args[2], pubkey) assert expr.type_of() == pt.TealType.uint64 expected = pt.TealSimpleBlock( @@ -84,33 +108,43 @@ def test_ecdsa_verify_basic(): pt.TealOp(args[2], pt.Op.byte, '"sigB"'), pt.TealOp(pubkey[0], pt.Op.byte, '"X"'), pt.TealOp(pubkey[1], pt.Op.byte, '"Y"'), - pt.TealOp(expr, pt.Op.ecdsa_verify, pt.EcdsaCurve.Secp256k1.arg_name), + pt.TealOp(expr, pt.Op.ecdsa_verify, curve.arg_name), ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(curve_options_map[curve]) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected # compile without errors this is necessary so assembly is also tested - pt.compileTeal(pt.Seq(pt.Pop(expr), pt.Approve()), pt.Mode.Application, version=5) + pt.compileTeal( + pt.Seq(pt.Pop(expr), pt.Approve()), + pt.Mode.Application, + version=curve.min_version, + ) + + with pytest.raises(pt.TealInputError): + pt.compileTeal( + pt.Seq(pt.Pop(expr), pt.Approve()), + pt.Mode.Application, + version=curve.min_version - 1, + ) -def test_ecdsa_verify_compressed_pk(): +@pytest.mark.parametrize("curve", [pt.EcdsaCurve.Secp256k1, pt.EcdsaCurve.Secp256r1]) +def test_ecdsa_verify_compressed_pk(curve: pt.EcdsaCurve): args = [pt.Bytes("data"), pt.Bytes("sigA"), pt.Bytes("sigB")] compressed_pubkey = pt.Bytes("XY") - pubkey = pt.EcdsaDecompress(pt.EcdsaCurve.Secp256k1, compressed_pubkey) - expr = pt.EcdsaVerify(pt.EcdsaCurve.Secp256k1, args[0], args[1], args[2], pubkey) + pubkey = pt.EcdsaDecompress(curve, compressed_pubkey) + expr = pt.EcdsaVerify(curve, args[0], args[1], args[2], pubkey) assert expr.type_of() == pt.TealType.uint64 expected = pt.TealSimpleBlock( [ pt.TealOp(compressed_pubkey, pt.Op.byte, '"XY"'), - pt.TealOp( - pubkey, pt.Op.ecdsa_pk_decompress, pt.EcdsaCurve.Secp256k1.arg_name - ), + pt.TealOp(pubkey, pt.Op.ecdsa_pk_decompress, curve.arg_name), pt.TealOp( pubkey.output_slots[1].store(), pt.Op.store, pubkey.output_slots[1] ), @@ -126,11 +160,11 @@ def test_ecdsa_verify_compressed_pk(): pt.TealOp( pubkey.output_slots[1].load(), pt.Op.load, pubkey.output_slots[1] ), - pt.TealOp(expr, pt.Op.ecdsa_verify, pt.EcdsaCurve.Secp256k1.arg_name), + pt.TealOp(expr, pt.Op.ecdsa_verify, curve.arg_name), ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(curve_options_map[curve]) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -138,15 +172,25 @@ def test_ecdsa_verify_compressed_pk(): assert actual == expected # compile without errors this is necessary so assembly is also tested - pt.compileTeal(pt.Seq(pt.Pop(expr), pt.Approve()), pt.Mode.Application, version=5) + pt.compileTeal( + pt.Seq(pt.Pop(expr), pt.Approve()), + pt.Mode.Application, + version=curve.min_version, + ) + with pytest.raises(pt.TealInputError): + pt.compileTeal( + pt.Seq(pt.Pop(expr), pt.Approve()), + pt.Mode.Application, + version=curve.min_version - 1, + ) -def test_ecdsa_verify_recovered_pk(): + +@pytest.mark.parametrize("curve", [pt.EcdsaCurve.Secp256k1, pt.EcdsaCurve.Secp256r1]) +def test_ecdsa_verify_recovered_pk(curve: pt.EcdsaCurve): args = [pt.Bytes("data"), pt.Int(1), pt.Bytes("sigA"), pt.Bytes("sigB")] - pubkey = pt.EcdsaRecover( - pt.EcdsaCurve.Secp256k1, args[0], args[1], args[2], args[3] - ) - expr = pt.EcdsaVerify(pt.EcdsaCurve.Secp256k1, args[0], args[2], args[3], pubkey) + pubkey = pt.EcdsaRecover(curve, args[0], args[1], args[2], args[3]) + expr = pt.EcdsaVerify(curve, args[0], args[2], args[3], pubkey) assert expr.type_of() == pt.TealType.uint64 expected = pt.TealSimpleBlock( @@ -155,7 +199,7 @@ def test_ecdsa_verify_recovered_pk(): pt.TealOp(args[1], pt.Op.int, 1), pt.TealOp(args[2], pt.Op.byte, '"sigA"'), pt.TealOp(args[3], pt.Op.byte, '"sigB"'), - pt.TealOp(pubkey, pt.Op.ecdsa_pk_recover, pt.EcdsaCurve.Secp256k1.arg_name), + pt.TealOp(pubkey, pt.Op.ecdsa_pk_recover, curve.arg_name), pt.TealOp( pubkey.output_slots[1].store(), pt.Op.store, pubkey.output_slots[1] ), @@ -171,11 +215,11 @@ def test_ecdsa_verify_recovered_pk(): pt.TealOp( pubkey.output_slots[1].load(), pt.Op.load, pubkey.output_slots[1] ), - pt.TealOp(expr, pt.Op.ecdsa_verify, pt.EcdsaCurve.Secp256k1.arg_name), + pt.TealOp(expr, pt.Op.ecdsa_verify, curve.arg_name), ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(curve_options_map[curve]) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -183,26 +227,46 @@ def test_ecdsa_verify_recovered_pk(): assert actual == expected # compile without errors this is necessary so assembly is also tested - pt.compileTeal(pt.Seq(pt.Pop(expr), pt.Approve()), pt.Mode.Application, version=5) + pt.compileTeal( + pt.Seq(pt.Pop(expr), pt.Approve()), + pt.Mode.Application, + version=curve.min_version, + ) + + with pytest.raises(pt.TealInputError): + pt.compileTeal( + pt.Seq(pt.Pop(expr), pt.Approve()), + pt.Mode.Application, + version=curve.min_version - 1, + ) -def test_ecdsa_invalid(): +@pytest.mark.parametrize("curve", [pt.EcdsaCurve.Secp256k1, pt.EcdsaCurve.Secp256r1]) +def test_ecdsa_invalid(curve: pt.EcdsaCurve): with pytest.raises(pt.TealTypeError): - args = [pt.Bytes("data"), pt.Bytes("1"), pt.Bytes("sigA"), pt.Bytes("sigB")] - pt.EcdsaRecover(pt.EcdsaCurve.Secp256k1, args[0], args[1], args[2], args[3]) + args: List[Union[pt.Bytes, pt.Int]] = [ + pt.Bytes("data"), + pt.Bytes("1"), + pt.Bytes("sigA"), + pt.Bytes("sigB"), + ] + pt.EcdsaRecover(curve, args[0], args[1], args[2], args[3]) with pytest.raises(pt.TealTypeError): - pt.EcdsaDecompress(pt.EcdsaCurve.Secp256k1, pt.Int(1)) + pt.EcdsaDecompress(curve, pt.Int(1)) with pytest.raises(pt.TealTypeError): args = [pt.Bytes("data"), pt.Bytes("sigA"), pt.Bytes("sigB")] - pubkey = (pt.Bytes("X"), pt.Int(1)) - pt.EcdsaVerify(pt.EcdsaCurve.Secp256k1, args[0], args[1], args[2], pubkey) + pubkey: Union[tuple[pt.Bytes, Union[pt.Int, pt.Bytes]], pt.MultiValue] = ( + pt.Bytes("X"), + pt.Int(1), + ) + pt.EcdsaVerify(curve, args[0], args[1], args[2], pubkey) with pytest.raises(pt.TealTypeError): args = [pt.Bytes("data"), pt.Int(1), pt.Bytes("sigB")] pubkey = (pt.Bytes("X"), pt.Bytes("Y")) - pt.EcdsaVerify(pt.EcdsaCurve.Secp256k1, args[0], args[1], args[2], pubkey) + pt.EcdsaVerify(curve, args[0], args[1], args[2], pubkey) with pytest.raises(pt.TealTypeError): args = [pt.Bytes("data"), pt.Bytes("sigA"), pt.Bytes("sigB")] @@ -210,21 +274,19 @@ def test_ecdsa_invalid(): pubkey = pt.MultiValue( pt.Op.ecdsa_pk_decompress, [pt.TealType.uint64, pt.TealType.bytes], - immediate_args=[pt.EcdsaCurve.Secp256k1], + immediate_args=[curve.__str__()], args=[compressed_pk], ) - pt.EcdsaVerify(pt.EcdsaCurve.Secp256k1, args[0], args[1], args[2], pubkey) + pt.EcdsaVerify(curve, args[0], args[1], args[2], pubkey) with pytest.raises(pt.TealInputError): args = [pt.Bytes("data"), pt.Bytes("sigA"), pt.Bytes("sigB")] pubkey = (pt.Bytes("X"), pt.Bytes("Y")) - expr = pt.EcdsaVerify( - pt.EcdsaCurve.Secp256k1, args[0], args[1], args[2], pubkey - ) + expr = pt.EcdsaVerify(curve, args[0], args[1], args[2], pubkey) expr.__teal__(teal4Options) with pytest.raises(pt.TealTypeError): args = [pt.Bytes("data"), pt.Bytes("sigA"), pt.Bytes("sigB")] pubkey = (pt.Bytes("X"), pt.Bytes("Y")) - expr = pt.EcdsaVerify(5, args[0], args[1], args[2], pubkey) + expr = pt.EcdsaVerify(cast(pt.EcdsaCurve, 5), args[0], args[1], args[2], pubkey) diff --git a/pyteal/ast/multi.py b/pyteal/ast/multi.py index 63a4dec11..e61af4b4a 100644 --- a/pyteal/ast/multi.py +++ b/pyteal/ast/multi.py @@ -20,7 +20,8 @@ def __init__( types: List[TealType], *, immediate_args: List[Union[int, str]] = None, - args: List[Expr] = None + args: List[Expr] = None, + compile_check: Callable[["CompileOptions"], None] = lambda _: None, ): """Create a new MultiValue. @@ -35,6 +36,7 @@ def __init__( self.types = types self.immediate_args = immediate_args if immediate_args is not None else [] self.args = args if args is not None else [] + self.compile_check = compile_check self.output_slots = [ScratchSlot() for _ in self.types] @@ -57,6 +59,8 @@ def __str__(self): return ret_str def __teal__(self, options: "CompileOptions"): + self.compile_check(options) + tealOp = TealOp(self, self.op, *self.immediate_args) callStart, callEnd = TealBlock.FromOp(options, tealOp, *self.args) diff --git a/pyteal/ast/multi_test.py b/pyteal/ast/multi_test.py index e0fe3d58c..a85cebed7 100644 --- a/pyteal/ast/multi_test.py +++ b/pyteal/ast/multi_test.py @@ -1,3 +1,4 @@ +import pytest from typing import List import pyteal as pt @@ -147,47 +148,70 @@ def __test_single_with_vars( assert actual == expected -def test_multi_value(): - ops = ( +@pytest.mark.parametrize( + "op", + [ pt.Op.app_global_get_ex, pt.Op.app_local_get_ex, pt.Op.asset_holding_get, pt.Op.asset_params_get, + ], +) +@pytest.mark.parametrize( + "type", [pt.TealType.uint64, pt.TealType.bytes, pt.TealType.anytype] +) +@pytest.mark.parametrize("iargs", [[], ["AssetFrozen"]]) +@pytest.mark.parametrize("args", [[], [pt.Int(0)], [pt.Int(1), pt.Int(2)]]) +def test_multi_value(op, type, iargs, args): + reducer = ( + lambda value, hasValue: pt.If(hasValue) + .Then(value) + .Else(pt.App.globalGet(pt.Bytes("None"))) + ) + expr = pt.MultiValue( + op, [type, pt.TealType.uint64], immediate_args=iargs, args=args + ) + __test_single_conditional(expr, op, args, iargs, reducer) + + reducer = lambda value, hasValue: pt.Seq(pt.Assert(hasValue), value) # noqa: E731 + expr = pt.MultiValue( + op, [type, pt.TealType.uint64], immediate_args=iargs, args=args + ) + __test_single_assert(expr, op, args, iargs, reducer) + + hasValueVar = pt.ScratchVar(pt.TealType.uint64) + valueVar = pt.ScratchVar(type) + reducer = lambda value, hasValue: pt.Seq( # noqa: E731 + hasValueVar.store(hasValue), valueVar.store(value) + ) + expr = pt.MultiValue( + op, [type, pt.TealType.uint64], immediate_args=iargs, args=args + ) + __test_single_with_vars(expr, op, args, iargs, hasValueVar, valueVar, reducer) + + +def test_multi_compile_check(): + def never_fails(options): + return + + program_never_fails = pt.MultiValue( + pt.Op.app_global_get_ex, + [pt.TealType.uint64, pt.TealType.uint64], + compile_check=never_fails, ) - types = (pt.TealType.uint64, pt.TealType.bytes, pt.TealType.anytype) - immedate_argv = ([], ["AssetFrozen"]) - argv = ([], [pt.Int(0)], [pt.Int(1), pt.Int(2)]) - - for op in ops: - for type in types: - for iargs in immedate_argv: - for args in argv: - reducer = ( - lambda value, hasValue: pt.If(hasValue) - .Then(value) - .Else(pt.App.globalGet(pt.Bytes("None"))) - ) - expr = pt.MultiValue( - op, [type, pt.TealType.uint64], immediate_args=iargs, args=args - ) - __test_single_conditional(expr, op, args, iargs, reducer) - - reducer = lambda value, hasValue: pt.Seq( # noqa: E731 - pt.Assert(hasValue), value - ) - expr = pt.MultiValue( - op, [type, pt.TealType.uint64], immediate_args=iargs, args=args - ) - __test_single_assert(expr, op, args, iargs, reducer) - - hasValueVar = pt.ScratchVar(pt.TealType.uint64) - valueVar = pt.ScratchVar(type) - reducer = lambda value, hasValue: pt.Seq( # noqa: E731 - hasValueVar.store(hasValue), valueVar.store(value) - ) - expr = pt.MultiValue( - op, [type, pt.TealType.uint64], immediate_args=iargs, args=args - ) - __test_single_with_vars( - expr, op, args, iargs, hasValueVar, valueVar, reducer - ) + program_never_fails.__teal__(options) + + class TestException(Exception): + pass + + def always_fails(options): + raise TestException() + + program_always_fails = pt.MultiValue( + pt.Op.app_global_get_ex, + [pt.TealType.uint64, pt.TealType.uint64], + compile_check=always_fails, + ) + + with pytest.raises(TestException): + program_always_fails.__teal__(options) From 9a26fec4602d8f7ac1c9309ac148e6d43aa363e8 Mon Sep 17 00:00:00 2001 From: Jacob Daitzman Date: Thu, 30 Jun 2022 14:12:21 -0400 Subject: [PATCH 008/206] Add VrfVerify (#419) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add VrfVerify # Conflicts: # pyteal/ast/__init__.py # pyteal/ir/ops.py * Tidy with `MultiValue`’s compile check --- pyteal/__init__.pyi | 1 + pyteal/ast/__init__.py | 4 ++ pyteal/ast/vrfverify.py | 80 ++++++++++++++++++++++++++++++++++++ pyteal/ast/vrfverify_test.py | 71 ++++++++++++++++++++++++++++++++ pyteal/ir/ops.py | 1 + 5 files changed, 157 insertions(+) create mode 100644 pyteal/ast/vrfverify.py create mode 100644 pyteal/ast/vrfverify_test.py diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index c4f1dd670..4008461a8 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -185,6 +185,7 @@ __all__ = [ "TxnType", "TxnaExpr", "UnaryExpr", + "VrfVerify", "While", "WideRatio", "compileTeal", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index f42ee4ec0..6cce690a2 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -107,6 +107,9 @@ from pyteal.ast.replace import Replace from pyteal.ast.jsonref import JsonRef +# quaternary ops +from pyteal.ast.vrfverify import VrfVerify + # more ops from pyteal.ast.naryexpr import NaryExpr, And, Or, Concat from pyteal.ast.widemath import WideRatio @@ -289,4 +292,5 @@ "EcdsaDecompress", "EcdsaRecover", "JsonRef", + "VrfVerify", ] diff --git a/pyteal/ast/vrfverify.py b/pyteal/ast/vrfverify.py new file mode 100644 index 000000000..110671c7f --- /dev/null +++ b/pyteal/ast/vrfverify.py @@ -0,0 +1,80 @@ +from enum import Enum + +from pyteal.types import TealType, require_type +from pyteal.errors import verifyFieldVersion +from pyteal.ir import Op +from pyteal.ast.multi import MultiValue +from pyteal.ast.expr import Expr + + +class VrfVerifyStandard(Enum): + # fmt: off + # id | name | min version + algorand = (0, "VrfAlgorand", 7) # noqa: E222 + chainlink = (1, "VrfChainlink", 7) + # fmt: on + + def __init__(self, id: int, name: str, min_version: int) -> None: + self.id = id + self.arg_name = name + self.min_version = min_version + + +VrfVerifyStandard.__module__ = "pyteal" + + +class VrfVerify(MultiValue): + """An expression that verifies the proof of a message against a public key.""" + + def __init__( + self, standard: VrfVerifyStandard, message: Expr, proof: Expr, public_key: Expr + ) -> None: + require_type(message, TealType.bytes) + require_type(proof, TealType.bytes) + require_type(public_key, TealType.bytes) + + self.standard = standard + + super().__init__( + Op.vrf_verify, + [TealType.bytes, TealType.uint64], + immediate_args=[standard.arg_name], + args=[message, proof, public_key], + compile_check=lambda options: verifyFieldVersion( + standard.arg_name, standard.min_version, options.version + ), + ) + + def __str__(self): + return "(VrfVerify {})".format(self.standard.arg_name) + + @classmethod + def algorand(cls, message: Expr, proof: Expr, public_key: Expr) -> "VrfVerify": + """Verifies the proof of a message against a public key using the Algorand VRF standard. + + Args: + message: The message to verify. + proof: The proof of the message. + public_key: The public key to use to verify the proof. + + Returns: + A MultiValue expression representing the VRF output and a verification flag. + """ + return cls(VrfVerifyStandard.algorand, message, proof, public_key) + + @classmethod + def chainlink(cls, message: Expr, proof: Expr, public_key: Expr) -> "VrfVerify": + """Verifies the proof of a message against a public key using the Chainlink VRF standard. + + Args: + message: The message to verify. + proof: The proof of the message. + public_key: The public key to use to verify the proof. + + Returns: + A MultiValue expression representing the VRF output and a verification flag. + """ + return cls(VrfVerifyStandard.chainlink, message, proof, public_key) + + +VrfVerify.__module__ = "pyteal" diff --git a/pyteal/ast/vrfverify_test.py b/pyteal/ast/vrfverify_test.py new file mode 100644 index 000000000..8380d053c --- /dev/null +++ b/pyteal/ast/vrfverify_test.py @@ -0,0 +1,71 @@ +import pytest + +import pyteal as pt + +teal6Options = pt.CompileOptions(version=6) +teal7Options = pt.CompileOptions(version=7) + + +def test_vrf_verify_algorand(): + args = [pt.Bytes("a"), pt.Bytes("b"), pt.Bytes("c")] + expr = pt.VrfVerify.algorand(*args) + assert expr.type_of() == pt.TealType.none + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(args[0], pt.Op.byte, '"a"'), + pt.TealOp(args[1], pt.Op.byte, '"b"'), + pt.TealOp(args[2], pt.Op.byte, '"c"'), + pt.TealOp(expr, pt.Op.vrf_verify, "VrfAlgorand"), + pt.TealOp(expr.output_slots[1], pt.Op.store, expr.output_slots[1]), + pt.TealOp(expr.output_slots[0], pt.Op.store, expr.output_slots[0]), + ] + ) + + actual, _ = expr.__teal__(teal7Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + with pt.TealComponent.Context.ignoreExprEquality(): + assert actual == expected + + with pytest.raises(pt.TealInputError): + expr.__teal__(teal6Options) + + +def test_vrf_verify_chainlink(): + args = [pt.Bytes("a"), pt.Bytes("b"), pt.Bytes("c")] + expr = pt.VrfVerify.chainlink(*args) + assert expr.type_of() == pt.TealType.none + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(args[0], pt.Op.byte, '"a"'), + pt.TealOp(args[1], pt.Op.byte, '"b"'), + pt.TealOp(args[2], pt.Op.byte, '"c"'), + pt.TealOp(expr, pt.Op.vrf_verify, "VrfChainlink"), + pt.TealOp(expr.output_slots[1], pt.Op.store, expr.output_slots[1]), + pt.TealOp(expr.output_slots[0], pt.Op.store, expr.output_slots[0]), + ] + ) + + actual, _ = expr.__teal__(teal7Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + with pt.TealComponent.Context.ignoreExprEquality(): + assert actual == expected + + with pytest.raises(pt.TealInputError): + expr.__teal__(teal6Options) + + +def test_vrf_verify_invalid(): + with pytest.raises(pt.TealTypeError): + pt.VrfVerify.algorand(pt.Int(0), pt.Bytes("b"), pt.Bytes("c")) + + with pytest.raises(pt.TealTypeError): + pt.VrfVerify.chainlink(pt.Bytes("a"), pt.Int(0), pt.Bytes("c")) + + with pytest.raises(pt.TealTypeError): + pt.VrfVerify.chainlink(pt.Bytes("a"), pt.Bytes("b"), pt.Int(0)) diff --git a/pyteal/ir/ops.py b/pyteal/ir/ops.py index a21e34bc4..50563da94 100644 --- a/pyteal/ir/ops.py +++ b/pyteal/ir/ops.py @@ -183,6 +183,7 @@ def min_version(self) -> int: replace3 = OpType("replace3", Mode.Signature | Mode.Application, 7) base64_decode = OpType("base64_decode", Mode.Application | Mode.Signature, 7) json_ref = OpType("json_ref", Mode.Signature | Mode.Application, 7) + vrf_verify = OpType("vrf_verify", Mode.Signature | Mode.Application, 7) block = OpType("block", Mode.Signature | Mode.Application, 7) # fmt: on From cc544aae783b466450dae5aed5456920bba2526b Mon Sep 17 00:00:00 2001 From: Jacob Daitzman Date: Thu, 30 Jun 2022 14:23:33 -0400 Subject: [PATCH 009/206] Add `Sha3_256` (#425) * Add sha3_256 * Add crypto docs --- docs/crypto.rst | 1 + pyteal/__init__.pyi | 1 + pyteal/ast/__init__.py | 2 ++ pyteal/ast/unaryexpr.py | 5 +++++ pyteal/ast/unaryexpr_test.py | 22 ++++++++++++++++++++++ pyteal/ir/ops.py | 1 + 6 files changed, 32 insertions(+) diff --git a/docs/crypto.rst b/docs/crypto.rst index d062eb671..2ae4055b1 100644 --- a/docs/crypto.rst +++ b/docs/crypto.rst @@ -14,6 +14,7 @@ Below is how you express cryptographic primitives in PyTeal: Operator Cost Description ==================================== ========= ================================================================================================================== :code:`Sha256(e)` `35` `SHA-256` hash function, produces 32 bytes +:code:`Sha3_256(e)` `130` `SHA3-256` hash function, produces 32 bytes :code:`Keccak256(e)` `130` `Keccak-256` hash funciton, produces 32 bytes :code:`Sha512_256(e)` `45` `SHA-512/256` hash function, produces 32 bytes :code:`Ed25519Verify(d, s, p)` `1900`\* `1` if :code:`s` is the signature of :code:`d` signed by the private key corresponding to the public key :code:`p`, else `0` diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index 4008461a8..79545ec99 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -153,6 +153,7 @@ __all__ = [ "SetBit", "SetByte", "Sha256", + "Sha3_256", "Sha512_256", "ShiftLeft", "ShiftRight", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 6cce690a2..61d3254d3 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -46,6 +46,7 @@ BitLen, Sha256, Sha512_256, + Sha3_256, Keccak256, Not, BitwiseNot, @@ -197,6 +198,7 @@ "BitLen", "Sha256", "Sha512_256", + "Sha3_256", "Keccak256", "Not", "BitwiseNot", diff --git a/pyteal/ast/unaryexpr.py b/pyteal/ast/unaryexpr.py index 619bfab46..1fad9903b 100644 --- a/pyteal/ast/unaryexpr.py +++ b/pyteal/ast/unaryexpr.py @@ -80,6 +80,11 @@ def Sha512_256(arg: Expr) -> UnaryExpr: return UnaryExpr(Op.sha512_256, TealType.bytes, TealType.bytes, arg) +def Sha3_256(arg: Expr) -> UnaryExpr: + """Get the SHA3-256 hash of a byte string.""" + return UnaryExpr(Op.sha3_256, TealType.bytes, TealType.bytes, arg) + + def Keccak256(arg: Expr) -> UnaryExpr: """Get the KECCAK-256 hash of a byte string.""" return UnaryExpr(Op.keccak256, TealType.bytes, TealType.bytes, arg) diff --git a/pyteal/ast/unaryexpr_test.py b/pyteal/ast/unaryexpr_test.py index 50a6e2f15..5a096fcbd 100644 --- a/pyteal/ast/unaryexpr_test.py +++ b/pyteal/ast/unaryexpr_test.py @@ -7,6 +7,7 @@ teal4Options = pt.CompileOptions(version=4) teal5Options = pt.CompileOptions(version=5) teal6Options = pt.CompileOptions(version=6) +teal7Options = pt.CompileOptions(version=7) def test_btoi(): @@ -146,6 +147,27 @@ def test_sha512_256_invalid(): pt.Sha512_256(pt.Int(1)) +def test_sha3_256(): + arg = pt.Arg(0) + expr = pt.Sha3_256(arg) + assert expr.type_of() == pt.TealType.bytes + + expected = pt.TealSimpleBlock( + [pt.TealOp(arg, pt.Op.arg, 0), pt.TealOp(expr, pt.Op.sha3_256)] + ) + + actual, _ = expr.__teal__(teal7Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + +def test_sha3_256_invalid(): + with pytest.raises(pt.TealTypeError): + pt.Sha3_256(pt.Int(1)) + + def test_keccak256(): arg = pt.Arg(0) expr = pt.Keccak256(arg) diff --git a/pyteal/ir/ops.py b/pyteal/ir/ops.py index 50563da94..4a040cac0 100644 --- a/pyteal/ir/ops.py +++ b/pyteal/ir/ops.py @@ -183,6 +183,7 @@ def min_version(self) -> int: replace3 = OpType("replace3", Mode.Signature | Mode.Application, 7) base64_decode = OpType("base64_decode", Mode.Application | Mode.Signature, 7) json_ref = OpType("json_ref", Mode.Signature | Mode.Application, 7) + sha3_256 = OpType("sha3_256", Mode.Signature | Mode.Application, 7) vrf_verify = OpType("vrf_verify", Mode.Signature | Mode.Application, 7) block = OpType("block", Mode.Signature | Mode.Application, 7) # fmt: on From 6e83ae65261dd3d33ea0d11a1c3d6876aaf58a1e Mon Sep 17 00:00:00 2001 From: Jacob Daitzman Date: Thu, 30 Jun 2022 14:24:11 -0400 Subject: [PATCH 010/206] Support `FirstValidTime` transaction field (#424) * Add first valid time factory and update min version * Include FirstValidTime in txn tests * Add transaction field docs --- docs/accessing_transaction_field.rst | 1 + pyteal/ast/txn.py | 9 ++++++++- pyteal/ast/txn_test.py | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/accessing_transaction_field.rst b/docs/accessing_transaction_field.rst index ea37663e5..64c5f0b65 100644 --- a/docs/accessing_transaction_field.rst +++ b/docs/accessing_transaction_field.rst @@ -27,6 +27,7 @@ Operator :any:`Txn.sender() ` :code:`TealType.bytes` 2 32 byte address :any:`Txn.fee() ` :code:`TealType.uint64` 2 in microAlgos :any:`Txn.first_valid() ` :code:`TealType.uint64` 2 round number +:any:`Txn.first_valid_time() ` :code:`TealType.uint64` 7 UNIX timestamp of block before :code:`Txn.first_valid()`. Fails if negative :any:`Txn.last_valid() ` :code:`TealType.uint64` 2 round number :any:`Txn.note() ` :code:`TealType.bytes` 2 transaction note in bytes :any:`Txn.lease() ` :code:`TealType.bytes` 2 transaction lease in bytes diff --git a/pyteal/ast/txn.py b/pyteal/ast/txn.py index 3c0fc0f4e..a4d011ddf 100644 --- a/pyteal/ast/txn.py +++ b/pyteal/ast/txn.py @@ -37,7 +37,7 @@ class TxnField(Enum): sender = (0, "Sender", TealType.bytes, False, 2) fee = (1, "Fee", TealType.uint64, False, 2) first_valid = (2, "FirstValid", TealType.uint64, False, 2) - first_valid_time = (3, "FirstValidTime", TealType.uint64, False, 2) + first_valid_time = (3, "FirstValidTime", TealType.uint64, False, 7) last_valid = (4, "LastValid", TealType.uint64, False, 2) note = (5, "Note", TealType.bytes, False, 2) lease = (6, "Lease", TealType.bytes, False, 2) @@ -319,6 +319,13 @@ def first_valid(self) -> TxnExpr: """ return self.makeTxnExpr(TxnField.first_valid) + def first_valid_time(self) -> TxnExpr: + """Get the UNIX timestamp of block before txn.FirstValid. Fails if negative. + + For more information, see https://developer.algorand.org/docs/reference/transactions/#firstvalidtime + """ + return self.makeTxnExpr(TxnField.first_valid_time) + def last_valid(self) -> TxnExpr: """Get the last valid round number. diff --git a/pyteal/ast/txn_test.py b/pyteal/ast/txn_test.py index c0477fd23..d169b459b 100644 --- a/pyteal/ast/txn_test.py +++ b/pyteal/ast/txn_test.py @@ -8,6 +8,7 @@ pt.TxnField.sender: lambda txn: txn.sender(), pt.TxnField.fee: lambda txn: txn.fee(), pt.TxnField.first_valid: lambda txn: txn.first_valid(), + pt.TxnField.first_valid_time: lambda txn: txn.first_valid_time(), pt.TxnField.last_valid: lambda txn: txn.last_valid(), pt.TxnField.note: lambda txn: txn.note(), pt.TxnField.lease: lambda txn: txn.lease(), From 594e8e42349219f70d6804bbed7f31fbf267802c Mon Sep 17 00:00:00 2001 From: Jacob Daitzman Date: Thu, 30 Jun 2022 14:41:49 -0400 Subject: [PATCH 011/206] Add `Ed25519Verify_Bare` (#426) * Add ed25519verify_bare * Fix typos in Ed25519 docstrings (#2) * Add crypto doc for Ed25519Verify_Bare Co-authored-by: Michael Diamant --- docs/crypto.rst | 3 ++- pyteal/__init__.pyi | 1 + pyteal/ast/__init__.py | 9 ++++++++- pyteal/ast/ternaryexpr.py | 22 +++++++++++++++++++-- pyteal/ast/ternaryexpr_test.py | 36 ++++++++++++++++++++++++++++++++++ pyteal/ir/ops.py | 1 + 6 files changed, 68 insertions(+), 4 deletions(-) diff --git a/docs/crypto.rst b/docs/crypto.rst index 2ae4055b1..6a80b2567 100644 --- a/docs/crypto.rst +++ b/docs/crypto.rst @@ -17,7 +17,8 @@ Operator Cost Description :code:`Sha3_256(e)` `130` `SHA3-256` hash function, produces 32 bytes :code:`Keccak256(e)` `130` `Keccak-256` hash funciton, produces 32 bytes :code:`Sha512_256(e)` `45` `SHA-512/256` hash function, produces 32 bytes -:code:`Ed25519Verify(d, s, p)` `1900`\* `1` if :code:`s` is the signature of :code:`d` signed by the private key corresponding to the public key :code:`p`, else `0` +:code:`Ed25519Verify(d, s, p)` `1900`\* `1` if :code:`s` is the signature of the concatenation :code:`("ProgData" + hash_of_current_program + d)` signed by the private key corresponding to the public key :code:`p`, else `0` +:code:`Ed25519Verify_Bare(d, s, p)` `1900` `1` if :code:`s` is the signature of :code:`d` signed by the private key corresponding to the public key :code:`p`, else `0` :code:`EcdsaVerify(c, d, r, s, pk)` `1700` `1` if :code:`(r, s)` is the signature of :code:`d` by private key corresponding to public key :code:`pk`, else 0 :code:`EcdsaDecompress(c, short_pk)` `650` produces the decompressed public key associated with the compressed public key :code:`short_pk` :code:`EcdsaRecover(c, d, id, r, s)` `2000` produces the public key associated with the signature :code:`(r, s)` and recovery id :code:`id` diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index 79545ec99..4e2e3b65b 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -78,6 +78,7 @@ __all__ = [ "EcdsaRecover", "EcdsaVerify", "Ed25519Verify", + "Ed25519Verify_Bare", "EnumInt", "Eq", "Err", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 61d3254d3..145e7f2f3 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -103,7 +103,13 @@ from pyteal.ast.base64decode import Base64Decode # ternary ops -from pyteal.ast.ternaryexpr import Divw, Ed25519Verify, SetBit, SetByte +from pyteal.ast.ternaryexpr import ( + Divw, + Ed25519Verify, + Ed25519Verify_Bare, + SetBit, + SetByte, +) from pyteal.ast.substring import Substring, Extract, Suffix from pyteal.ast.replace import Replace from pyteal.ast.jsonref import JsonRef @@ -228,6 +234,7 @@ "GetBit", "GetByte", "Ed25519Verify", + "Ed25519Verify_Bare", "Substring", "Extract", "Suffix", diff --git a/pyteal/ast/ternaryexpr.py b/pyteal/ast/ternaryexpr.py index b329165de..ad2c36bd6 100644 --- a/pyteal/ast/ternaryexpr.py +++ b/pyteal/ast/ternaryexpr.py @@ -62,9 +62,9 @@ def Ed25519Verify(data: Expr, sig: Expr, key: Expr) -> TernaryExpr: """Verify the ed25519 signature of the concatenation ("ProgData" + hash_of_current_program + data). Args: - data: The data signed by the public key. Must evalutes to bytes. + data: The data signed by the public key. Must evaluate to bytes. sig: The proposed 64-byte signature of the concatenation ("ProgData" + hash_of_current_program + data). - Must evalute to bytes. + Must evaluate to bytes. key: The 32 byte public key that produced the signature. Must evaluate to bytes. """ return TernaryExpr( @@ -77,6 +77,24 @@ def Ed25519Verify(data: Expr, sig: Expr, key: Expr) -> TernaryExpr: ) +def Ed25519Verify_Bare(data: Expr, sig: Expr, key: Expr) -> TernaryExpr: + """Verify the ed25519 signature of the data against the public key. + + Args: + data: The data signed by the public key. Must evaluate to bytes. + sig: The proposed 64-byte signature of the data. Must evaluate to bytes. + key: The 32 byte public key that produced the signature. Must evaluate to bytes. + """ + return TernaryExpr( + Op.ed25519verify_bare, + (TealType.bytes, TealType.bytes, TealType.bytes), + TealType.uint64, + data, + sig, + key, + ) + + def SetBit(value: Expr, index: Expr, newBitValue: Expr) -> TernaryExpr: """Set the bit value of an expression at a specific index. diff --git a/pyteal/ast/ternaryexpr_test.py b/pyteal/ast/ternaryexpr_test.py index 996c58635..51a01958a 100644 --- a/pyteal/ast/ternaryexpr_test.py +++ b/pyteal/ast/ternaryexpr_test.py @@ -7,6 +7,7 @@ teal4Options = pt.CompileOptions(version=4) teal5Options = pt.CompileOptions(version=5) teal6Options = pt.CompileOptions(version=6) +teal7Options = pt.CompileOptions(version=7) def test_ed25519verify(): @@ -41,6 +42,41 @@ def test_ed25519verify_invalid(): pt.Ed25519Verify(pt.Bytes("data"), pt.Bytes("sig"), pt.Int(0)) +def test_ed25519verify_bare(): + args = [pt.Bytes("data"), pt.Bytes("sig"), pt.Bytes("key")] + expr = pt.Ed25519Verify_Bare(args[0], args[1], args[2]) + assert expr.type_of() == pt.TealType.uint64 + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(args[0], pt.Op.byte, '"data"'), + pt.TealOp(args[1], pt.Op.byte, '"sig"'), + pt.TealOp(args[2], pt.Op.byte, '"key"'), + pt.TealOp(expr, pt.Op.ed25519verify_bare), + ] + ) + + actual, _ = expr.__teal__(teal7Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + with pytest.raises(pt.TealInputError): + expr.__teal__(teal6Options) + + +def test_ed25519verify_bare_invalid(): + with pytest.raises(pt.TealTypeError): + pt.Ed25519Verify_Bare(pt.Int(0), pt.Bytes("sig"), pt.Bytes("key")) + + with pytest.raises(pt.TealTypeError): + pt.Ed25519Verify_Bare(pt.Bytes("data"), pt.Int(0), pt.Bytes("key")) + + with pytest.raises(pt.TealTypeError): + pt.Ed25519Verify_Bare(pt.Bytes("data"), pt.Bytes("sig"), pt.Int(0)) + + def test_set_bit_int(): args = [pt.Int(0), pt.Int(2), pt.Int(1)] expr = pt.SetBit(args[0], args[1], args[2]) diff --git a/pyteal/ir/ops.py b/pyteal/ir/ops.py index 4a040cac0..f0e217a63 100644 --- a/pyteal/ir/ops.py +++ b/pyteal/ir/ops.py @@ -183,6 +183,7 @@ def min_version(self) -> int: replace3 = OpType("replace3", Mode.Signature | Mode.Application, 7) base64_decode = OpType("base64_decode", Mode.Application | Mode.Signature, 7) json_ref = OpType("json_ref", Mode.Signature | Mode.Application, 7) + ed25519verify_bare = OpType("ed25519verify_bare", Mode.Signature | Mode.Application, 7) sha3_256 = OpType("sha3_256", Mode.Signature | Mode.Application, 7) vrf_verify = OpType("vrf_verify", Mode.Signature | Mode.Application, 7) block = OpType("block", Mode.Signature | Mode.Application, 7) From 7c24013f60150851994af29e89a0f79f054edeb5 Mon Sep 17 00:00:00 2001 From: Hang Su <87964331+ahangsu@users.noreply.github.com> Date: Wed, 20 Jul 2022 13:25:28 -0400 Subject: [PATCH 012/206] AVM Boxes Ops in Pyteal (#438) * add box ops * full support on ops * first set of test, add versioning in multi * remove some seemingly not necessary code? * update testcase * check invalid arguments * finish testcase * move stuffs to app * version check trick * verifyTealVersion apply * error message * update docs structures * period * update doc * update doc * update doc * per pr review on implementation * Update docs/state.rst Co-authored-by: Zeph Grunschlag * Update docs/state.rst Co-authored-by: Zeph Grunschlag * Update docs/state.rst Co-authored-by: Zeph Grunschlag * Update docs/state.rst Co-authored-by: Zeph Grunschlag * Update docs/state.rst Co-authored-by: Zeph Grunschlag * Update docs/state.rst Co-authored-by: Zeph Grunschlag * Update docs/state.rst Co-authored-by: Zeph Grunschlag * Update docs/state.rst Co-authored-by: Zeph Grunschlag * Update docs/state.rst Co-authored-by: Zeph Grunschlag * hex box size goes wild * Update docs/state.rst Co-authored-by: Zeph Grunschlag * warning about MBR * wording * Update docs/state.rst Co-authored-by: Zeph Grunschlag * emphasize * Update docs/state.rst Co-authored-by: Zeph Grunschlag * Update docs/state.rst Co-authored-by: Zeph Grunschlag * polishing * remove redundant box_put doc segment * per zeph pr review * use note and warning * per zeph's pr review * Update docs/state.rst Co-authored-by: Michael Diamant * creating boxes * Update docs/state.rst Co-authored-by: Michael Diamant * per pr review * table for state types Co-authored-by: Ben Guidarelli Co-authored-by: Zeph Grunschlag Co-authored-by: Michael Diamant --- docs/state.rst | 165 ++++++++++++++++++++-- pyteal/__init__.pyi | 7 + pyteal/ast/__init__.py | 17 +++ pyteal/ast/app.py | 87 +++++++++++- pyteal/ast/box.py | 226 +++++++++++++++++++++++++++++++ pyteal/ast/box_test.py | 184 +++++++++++++++++++++++++ pyteal/ast/maybe.py | 28 +++- pyteal/compiler/compiler.py | 2 +- pyteal/compiler/compiler_test.py | 2 +- pyteal/ir/ops.py | 7 + 10 files changed, 707 insertions(+), 18 deletions(-) create mode 100644 pyteal/ast/box.py create mode 100644 pyteal/ast/box_test.py diff --git a/docs/state.rst b/docs/state.rst index 71f1c638f..adb585b26 100644 --- a/docs/state.rst +++ b/docs/state.rst @@ -7,20 +7,30 @@ PyTeal can be used to write `Stateful Algorand Smart Contracts "App": Args: key: The key to write in the global application state. Must evaluate to bytes. - value: THe value to write in the global application state. Can evaluate to any type. + value: The value to write in the global application state. Can evaluate to any type. """ require_type(key, TealType.bytes) require_type(value, TealType.anytype) @@ -211,6 +220,82 @@ def globalDel(cls, key: Expr) -> "App": require_type(key, TealType.bytes) return cls(AppField.globalDel, [key]) + @classmethod + def box_create(cls, name: Expr, size: Expr) -> BoxCreate: + """ + Create a box with a given name and size. + + Args: + name: The key used to reference this box. Must evaluate to a bytes. + size: The number of bytes to reserve for this box. Must evaluate to a uint64. + """ + return BoxCreate(name, size) + + @classmethod + def box_delete(cls, name: Expr) -> BoxDelete: + """ + Deletes a box given it's name. + + Args: + name: The key the box was created with. Must evaluate to bytes. + """ + return BoxDelete(name) + + @classmethod + def box_extract(cls, name: Expr, start: Expr, length: Expr) -> BoxExtract: + """ + Extracts bytes in a box given its name, start index and stop index. + + Args: + name: The key the box was created with. Must evaluate to bytes. + start: The byte index into the box to start reading. Must evaluate to uint64. + length: The byte length into the box from start to stop reading. Must evaluate to uint64. + """ + return BoxExtract(name, start, length) + + @classmethod + def box_replace(cls, name: Expr, start: Expr, value: Expr) -> BoxReplace: + """ + Replaces bytes in a box given its name, start index, and value. + + Args: + name: The key the box was created with. Must evaluate to bytes. + start: The byte index into the box to start writing. Must evaluate to uint64. + value: The value to start writing at start index. Must evaluate to bytes. + """ + return BoxReplace(name, start, value) + + @classmethod + def box_length(cls, name: Expr) -> MaybeValue: + """ + Get the byte length of the box specified by its name. + + Args: + name: The key the box was created with. Must evaluate to bytes. + """ + return BoxLen(name) + + @classmethod + def box_get(cls, name: Expr) -> MaybeValue: + """ + Get the full contents of a box given its name. + + Args: + name: The key the box was created with. Must evaluate to bytes. + """ + return BoxGet(name) + + @classmethod + def box_put(cls, name: Expr, value: Expr) -> BoxPut: + """ + Write all contents to a box given its name. + + Args: + name: The key the box was created with. Must evaluate to bytes. + value: The value to write to the box. Must evaluate to bytes. + """ + return BoxPut(name, value) + App.__module__ = "pyteal" diff --git a/pyteal/ast/box.py b/pyteal/ast/box.py new file mode 100644 index 000000000..33b9712e3 --- /dev/null +++ b/pyteal/ast/box.py @@ -0,0 +1,226 @@ +from typing import TYPE_CHECKING +from pyteal.ast.maybe import MaybeValue +from pyteal.errors import verifyTealVersion + +from pyteal.types import TealType, require_type +from pyteal.ir import TealOp, Op, TealBlock +from pyteal.ast.expr import Expr + +if TYPE_CHECKING: + from pyteal.compiler import CompileOptions + + +class BoxCreate(Expr): + """Create a box with a given name and size.""" + + def __init__(self, name: Expr, size: Expr) -> None: + """ + Args: + name: The key used to reference this box. Must evaluate to a bytes. + size: The number of bytes to reserve for this box. Must evaluate to a uint64. + """ + + super().__init__() + require_type(name, TealType.bytes) + require_type(size, TealType.uint64) + self.name = name + self.size = size + + def __teal__(self, options: "CompileOptions"): + verifyTealVersion( + minVersion=Op.box_create.min_version, + version=options.version, + msg=f"{Op.box_create} unavailable", + ) + return TealBlock.FromOp( + options, TealOp(self, Op.box_create), self.size, self.name + ) + + def __str__(self): + return f"(box_create {self.name} {self.size})" + + def type_of(self): + return TealType.none + + def has_return(self): + return False + + +BoxCreate.__module__ = "pyteal" + + +class BoxDelete(Expr): + """Deletes a box given its name.""" + + def __init__(self, name: Expr) -> None: + """ + Args: + name: The key the box was created with. Must evaluate to bytes. + """ + super().__init__() + require_type(name, TealType.bytes) + self.name = name + + def __teal__(self, options: "CompileOptions"): + verifyTealVersion( + minVersion=Op.box_del.min_version, + version=options.version, + msg=f"{Op.box_del} unavailable", + ) + return TealBlock.FromOp(options, TealOp(self, Op.box_del), self.name) + + def __str__(self): + return f"(box_del {self.name})" + + def type_of(self): + return TealType.none + + def has_return(self): + return False + + +BoxDelete.__module__ = "pyteal" + + +class BoxReplace(Expr): + """Replaces bytes in a box given its name, start index, and value.""" + + def __init__(self, name: Expr, start: Expr, value: Expr) -> None: + """ + Args: + name: The key the box was created with. Must evaluate to bytes. + start: The byte index into the box to start writing. Must evaluate to uint64. + value: The value to start writing at start index. Must evaluate to bytes. + """ + super().__init__() + require_type(name, TealType.bytes) + require_type(start, TealType.uint64) + require_type(value, TealType.bytes) + self.name = name + self.start = start + self.value = value + + def __teal__(self, options: "CompileOptions"): + verifyTealVersion( + minVersion=Op.box_replace.min_version, + version=options.version, + msg=f"{Op.box_replace} unavailable", + ) + return TealBlock.FromOp( + options, TealOp(self, Op.box_replace), self.name, self.start, self.value + ) + + def __str__(self): + return f"(box_replace {self.name} {self.start} {self.value})" + + def type_of(self): + return TealType.none + + def has_return(self): + return False + + +BoxReplace.__module__ = "pyteal" + + +class BoxExtract(Expr): + """Extracts bytes in a box given its name, start index and stop index.""" + + def __init__(self, name: Expr, start: Expr, length: Expr) -> None: + """ + Args: + name: The key the box was created with. Must evaluate to bytes. + start: The byte index into the box to start reading. Must evaluate to uint64. + length: The byte length into the box from start to stop reading. Must evaluate to uint64. + """ + + super().__init__() + require_type(name, TealType.bytes) + require_type(start, TealType.uint64) + require_type(length, TealType.uint64) + self.name = name + self.start = start + self.length = length + + def __teal__(self, options: "CompileOptions"): + verifyTealVersion( + minVersion=Op.box_extract.min_version, + version=options.version, + msg=f"{Op.box_extract} unavailable", + ) + return TealBlock.FromOp( + options, TealOp(self, Op.box_extract), self.name, self.start, self.length + ) + + def __str__(self): + return f"(box_extract {self.name} {self.start} {self.length})" + + def type_of(self): + return TealType.bytes + + def has_return(self): + return False + + +BoxExtract.__module__ = "pyteal" + + +def BoxLen(name: Expr) -> MaybeValue: + """ + Get the byte length of the box specified by its name. + + Args: + name: The key the box was created with. Must evaluate to bytes. + """ + require_type(name, TealType.bytes) + return MaybeValue(Op.box_len, TealType.uint64, args=[name]) + + +def BoxGet(name: Expr) -> MaybeValue: + """ + Get the full contents of a box given its name. + + Args: + name: The key the box was created with. Must evaluate to bytes. + """ + require_type(name, TealType.bytes) + return MaybeValue(Op.box_get, TealType.bytes, args=[name]) + + +class BoxPut(Expr): + """Write all contents to a box given its name.""" + + def __init__(self, name: Expr, value: Expr) -> None: + """ + Args: + name: The key the box was created with. Must evaluate to bytes. + value: The value to write to the box. Must evaluate to bytes. + """ + + super().__init__() + require_type(name, TealType.bytes) + require_type(value, TealType.bytes) + self.name = name + self.value = value + + def __teal__(self, options: "CompileOptions"): + verifyTealVersion( + minVersion=Op.box_put.min_version, + version=options.version, + msg=f"{Op.box_put} unavailable", + ) + return TealBlock.FromOp( + options, TealOp(self, Op.box_put), self.name, self.value + ) + + def __str__(self): + return f"(box_put {self.name})" + + def type_of(self): + return TealType.none + + def has_return(self): + return False + + +BoxPut.__module__ = "pyteal" diff --git a/pyteal/ast/box_test.py b/pyteal/ast/box_test.py new file mode 100644 index 000000000..87968ce2f --- /dev/null +++ b/pyteal/ast/box_test.py @@ -0,0 +1,184 @@ +from typing import Callable, Tuple + +import pytest +import pyteal as pt + +teal7Options = pt.CompileOptions(version=7) +teal8Options = pt.CompileOptions(version=8) + +POSITIVE_TEST_CASES: list[Tuple[pt.Expr, pt.TealType]] = [ + (pt.BoxCreate(pt.Bytes("box"), pt.Int(10)), pt.TealType.none), + (pt.BoxDelete(pt.Bytes("box")), pt.TealType.none), + (pt.BoxExtract(pt.Bytes("box"), pt.Int(2), pt.Int(4)), pt.TealType.bytes), + ( + pt.BoxReplace(pt.Bytes("box"), pt.Int(3), pt.Bytes("replace")), + pt.TealType.none, + ), + (pt.BoxLen(pt.Bytes("box")), pt.TealType.none), + (pt.BoxGet(pt.Bytes("box")), pt.TealType.none), + (pt.BoxPut(pt.Bytes("box"), pt.Bytes("goonery")), pt.TealType.none), +] + + +@pytest.mark.parametrize("test_case, test_case_type", POSITIVE_TEST_CASES) +def test_compile_version_and_type(test_case, test_case_type): + with pytest.raises(pt.TealInputError): + test_case.__teal__(teal7Options) + + test_case.__teal__(teal8Options) + assert test_case.type_of() == test_case_type + assert not test_case.has_return() + + return + + +INVALID_TEST_CASES: list[Tuple[list[pt.Expr], type | Callable[..., pt.MaybeValue]]] = [ + ([pt.Bytes("box"), pt.Bytes("ten")], pt.BoxCreate), + ([pt.Int(0xB0B), pt.Int(10)], pt.BoxCreate), + ([pt.Int(0xA11CE)], pt.BoxDelete), + ([pt.Bytes("box"), pt.Int(2), pt.Bytes("three")], pt.BoxExtract), + ([pt.Bytes("box"), pt.Int(2), pt.Int(0x570FF)], pt.BoxReplace), + ([pt.Int(12)], pt.BoxLen), + ([pt.Int(45)], pt.BoxGet), + ([pt.Bytes("box"), pt.Int(123)], pt.BoxPut), +] + + +@pytest.mark.parametrize("test_args, test_expr", INVALID_TEST_CASES) +def test_box_invalid_args(test_args, test_expr): + with pytest.raises(pt.TealTypeError): + test_expr(*test_args) + + +def test_box_create_compile(): + name_arg: pt.Expr = pt.Bytes("eineName") + size_arg: pt.Expr = pt.Int(10) + expr: pt.Expr = pt.BoxCreate(name_arg, size_arg) + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(size_arg, pt.Op.int, 10), + pt.TealOp(name_arg, pt.Op.byte, '"eineName"'), + pt.TealOp(expr, pt.Op.box_create), + ] + ) + actual, _ = expr.__teal__(teal8Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert expected == actual + + +def test_box_delete_compile(): + name_arg: pt.Expr = pt.Bytes("eineName") + expr: pt.Expr = pt.BoxDelete(name_arg) + + expected = pt.TealSimpleBlock( + [pt.TealOp(name_arg, pt.Op.byte, '"eineName"'), pt.TealOp(expr, pt.Op.box_del)] + ) + actual, _ = expr.__teal__(teal8Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert expected == actual + + +def test_box_extract(): + name_arg: pt.Expr = pt.Bytes("eineName") + srt_arg: pt.Expr = pt.Int(10) + end_arg: pt.Expr = pt.Int(15) + expr: pt.Expr = pt.BoxExtract(name_arg, srt_arg, end_arg) + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(name_arg, pt.Op.byte, '"eineName"'), + pt.TealOp(srt_arg, pt.Op.int, 10), + pt.TealOp(end_arg, pt.Op.int, 15), + pt.TealOp(expr, pt.Op.box_extract), + ] + ) + actual, _ = expr.__teal__(teal8Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert expected == actual + + +def test_box_replace(): + name_arg: pt.Expr = pt.Bytes("eineName") + srt_arg: pt.Expr = pt.Int(10) + replace_arg: pt.Expr = pt.Bytes("replace-str") + expr: pt.Expr = pt.BoxReplace(name_arg, srt_arg, replace_arg) + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(name_arg, pt.Op.byte, '"eineName"'), + pt.TealOp(srt_arg, pt.Op.int, 10), + pt.TealOp(replace_arg, pt.Op.byte, '"replace-str"'), + pt.TealOp(expr, pt.Op.box_replace), + ] + ) + actual, _ = expr.__teal__(teal8Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert expected == actual + + +def test_box_length(): + name_arg: pt.Expr = pt.Bytes("eineName") + expr: pt.MaybeValue = pt.BoxLen(name_arg) + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(name_arg, pt.Op.byte, '"eineName"'), + pt.TealOp(expr, pt.Op.box_len), + pt.TealOp(expr.output_slots[1].store(), pt.Op.store, expr.output_slots[1]), + pt.TealOp(expr.output_slots[0].store(), pt.Op.store, expr.output_slots[0]), + ] + ) + actual, _ = expr.__teal__(teal8Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + with pt.TealComponent.Context.ignoreExprEquality(): + assert expected == actual + + +def test_box_get(): + name_arg: pt.Expr = pt.Bytes("eineName") + expr: pt.MaybeValue = pt.BoxGet(name_arg) + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(name_arg, pt.Op.byte, '"eineName"'), + pt.TealOp(expr, pt.Op.box_get), + pt.TealOp(expr.output_slots[1].store(), pt.Op.store, expr.output_slots[1]), + pt.TealOp(expr.output_slots[0].store(), pt.Op.store, expr.output_slots[0]), + ] + ) + actual, _ = expr.__teal__(teal8Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + with pt.TealComponent.Context.ignoreExprEquality(): + assert expected == actual + + +def test_box_put(): + name_arg: pt.Expr = pt.Bytes("eineName") + put_arg: pt.Expr = pt.Bytes("put-str") + expr: pt.Expr = pt.BoxPut(name_arg, put_arg) + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(name_arg, pt.Op.byte, '"eineName"'), + pt.TealOp(put_arg, pt.Op.byte, '"put-str"'), + pt.TealOp(expr, pt.Op.box_put), + ] + ) + actual, _ = expr.__teal__(teal8Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert expected == actual diff --git a/pyteal/ast/maybe.py b/pyteal/ast/maybe.py index 43846384d..ebe3d03e7 100644 --- a/pyteal/ast/maybe.py +++ b/pyteal/ast/maybe.py @@ -1,11 +1,15 @@ -from typing import List, Union - -from pyteal.ast.multi import MultiValue +from typing import List, Union, TYPE_CHECKING +from pyteal.errors import verifyTealVersion from pyteal.types import TealType from pyteal.ir import Op + from pyteal.ast.expr import Expr from pyteal.ast.scratch import ScratchLoad, ScratchSlot +from pyteal.ast.multi import MultiValue + +if TYPE_CHECKING: + from pyteal.compiler import CompileOptions class MaybeValue(MultiValue): @@ -17,7 +21,7 @@ def __init__( type: TealType, *, immediate_args: List[Union[int, str]] = None, - args: List[Expr] = None + args: List[Expr] = None, ): """Create a new MaybeValue. @@ -27,8 +31,22 @@ def __init__( immediate_args (optional): Immediate arguments for the op. Defaults to None. args (optional): Stack arguments for the op. Defaults to None. """ + + def local_version_check(option: "CompileOptions"): + verifyTealVersion( + minVersion=op.min_version, + version=option.version, + msg=f"{op.value} unavailable", + ) + types = [type, TealType.uint64] - super().__init__(op, types, immediate_args=immediate_args, args=args) + super().__init__( + op, + types, + immediate_args=immediate_args, + args=args, + compile_check=local_version_check, + ) def hasValue(self) -> ScratchLoad: """Check if the value exists. diff --git a/pyteal/compiler/compiler.py b/pyteal/compiler/compiler.py index 2a68be57a..faf8717bd 100644 --- a/pyteal/compiler/compiler.py +++ b/pyteal/compiler/compiler.py @@ -25,7 +25,7 @@ ) from pyteal.compiler.constants import createConstantBlocks -MAX_TEAL_VERSION = 7 +MAX_TEAL_VERSION = 8 MIN_TEAL_VERSION = 2 DEFAULT_TEAL_VERSION = MIN_TEAL_VERSION diff --git a/pyteal/compiler/compiler_test.py b/pyteal/compiler/compiler_test.py index b3e528506..014607465 100644 --- a/pyteal/compiler/compiler_test.py +++ b/pyteal/compiler/compiler_test.py @@ -139,7 +139,7 @@ def test_compile_version_invalid(): pt.compileTeal(expr, pt.Mode.Signature, version=1) # too small with pytest.raises(pt.TealInputError): - pt.compileTeal(expr, pt.Mode.Signature, version=8) # too large + pt.compileTeal(expr, pt.Mode.Signature, version=9) # too large with pytest.raises(pt.TealInputError): pt.compileTeal(expr, pt.Mode.Signature, version=2.0) # decimal diff --git a/pyteal/ir/ops.py b/pyteal/ir/ops.py index f0e217a63..d87c76250 100644 --- a/pyteal/ir/ops.py +++ b/pyteal/ir/ops.py @@ -187,6 +187,13 @@ def min_version(self) -> int: sha3_256 = OpType("sha3_256", Mode.Signature | Mode.Application, 7) vrf_verify = OpType("vrf_verify", Mode.Signature | Mode.Application, 7) block = OpType("block", Mode.Signature | Mode.Application, 7) + box_create = OpType("box_create", Mode.Application, 8) + box_extract = OpType("box_extract", Mode.Application, 8) + box_replace = OpType("box_replace", Mode.Application, 8) + box_del = OpType("box_del", Mode.Application, 8) + box_len = OpType("box_len", Mode.Application, 8) + box_get = OpType("box_get", Mode.Application, 8) + box_put = OpType("box_put", Mode.Application, 8) # fmt: on From ba260e6c337933b017a708b952eaf2f7842b1e03 Mon Sep 17 00:00:00 2001 From: Hang Su <87964331+ahangsu@users.noreply.github.com> Date: Fri, 22 Jul 2022 13:33:24 -0400 Subject: [PATCH 013/206] Merge Teal7 to AVM8, and consolidate Teal to AVM versioning (#470) * swapping base64 modes to match the rest (#446) * Merge master into teal7 (#450) * AVM 7: Address integration branch feedback (#452) * Add Execute Method (#444) * adding execute method to allow omission of begin/submit for common use case * exec docstring * update testcase Co-authored-by: Hang Su * Merge branch 'master' into teal7 (#463) * fix misspelling of uint (#431) * fix misspelling of uint * Clarify minimum Python version management docs (#435) * Foreign prefix on App and Asset arrays (#440) * replacing foreignapps with applications * fix assets as well * Add Execute Method (#444) * adding execute method to allow omission of begin/submit for common use case * exec docstring * update testcase Co-authored-by: Hang Su Co-authored-by: Ben Guidarelli Co-authored-by: Hang Su * Consolidate TEAL and AVM versioning (#441) * fix misspelling of uint (#431) * fix misspelling of uint * Clarify minimum Python version management docs (#435) * Convert TEAL version references to program version by hand * Replace `teal#Options` with `avm#Options` * Deprecate `*_TEAL_VERSION` in favor of `*_PROGRAM_VERSION` * Fix docs typo Co-authored-by: Michael Diamant * Minor `versions.rst` changes * Fix `verifyTealVersion` in new opcode files * Fix linter errors * Fix language discrepencies introduced by the merge * Remove incorrect avm replacement * Fix inconsistent language introduced by merge Co-authored-by: Ben Guidarelli Co-authored-by: Michael Diamant * max program version Co-authored-by: Ben Guidarelli Co-authored-by: Michael Diamant Co-authored-by: Jacob Daitzman --- docs/accessing_transaction_field.rst | 184 +++++++++++++------------- docs/arithmetic_expression.rst | 2 +- docs/byte_expression.rst | 2 +- docs/control_structures.rst | 8 +- docs/crypto.rst | 4 +- docs/loading_group_transaction.rst | 2 +- docs/versions.rst | 19 +-- examples/signature/factorizer_game.py | 2 +- pyteal/__init__.py | 6 + pyteal/__init__.pyi | 6 + pyteal/ast/acct_test.py | 12 +- pyteal/ast/app_test.py | 24 ++-- pyteal/ast/arg.py | 8 +- pyteal/ast/arg_test.py | 12 +- pyteal/ast/assert_test.py | 12 +- pyteal/ast/asset_test.py | 60 ++++----- pyteal/ast/base64decode.py | 12 +- pyteal/ast/base64decode_test.py | 12 +- pyteal/ast/binaryexpr.py | 50 +++---- pyteal/ast/binaryexpr_test.py | 170 ++++++++++++------------ pyteal/ast/block.py | 4 +- pyteal/ast/block_test.py | 12 +- pyteal/ast/box.py | 12 +- pyteal/ast/box_test.py | 22 +-- pyteal/ast/ecdsa.py | 16 ++- pyteal/ast/ecdsa_test.py | 105 ++++++++------- pyteal/ast/gaid.py | 8 +- pyteal/ast/gaid_test.py | 12 +- pyteal/ast/gitxn.py | 10 +- pyteal/ast/gitxn_test.py | 12 +- pyteal/ast/gload.py | 8 +- pyteal/ast/gload_test.py | 20 +-- pyteal/ast/global_.py | 14 +- pyteal/ast/global_test.py | 50 +++---- pyteal/ast/gtxn.py | 16 ++- pyteal/ast/gtxn_test.py | 6 +- pyteal/ast/itxn.py | 43 ++++-- pyteal/ast/itxn_test.py | 94 ++++++++----- pyteal/ast/jsonref.py | 18 +-- pyteal/ast/jsonref_test.py | 16 +-- pyteal/ast/maybe.py | 4 +- pyteal/ast/opup.py | 4 +- pyteal/ast/replace.py | 8 +- pyteal/ast/replace_test.py | 16 +-- pyteal/ast/return_.py | 6 +- pyteal/ast/subroutine.py | 6 +- pyteal/ast/substring.py | 20 +-- pyteal/ast/substring_test.py | 46 +++---- pyteal/ast/ternaryexpr.py | 12 +- pyteal/ast/ternaryexpr_test.py | 32 ++--- pyteal/ast/txn.py | 54 +++----- pyteal/ast/txn_test.py | 2 - pyteal/ast/unaryexpr.py | 22 +-- pyteal/ast/unaryexpr_test.py | 60 ++++----- pyteal/ast/widemath.py | 4 +- pyteal/compiler/__init__.py | 6 + pyteal/compiler/compiler.py | 32 +++-- pyteal/compiler/subroutines.py | 4 +- pyteal/errors.py | 6 +- pyteal/ir/ops.py | 2 +- 60 files changed, 764 insertions(+), 687 deletions(-) diff --git a/docs/accessing_transaction_field.rst b/docs/accessing_transaction_field.rst index 64c5f0b65..cf13f99a6 100644 --- a/docs/accessing_transaction_field.rst +++ b/docs/accessing_transaction_field.rst @@ -19,56 +19,54 @@ Fields by Transaction Type Common Fields ....................................................... -================================================================================ ========================= ================ ============================================================================ -Operator Type Min TEAL Version Notes -================================================================================ ========================= ================ ============================================================================ +================================================================================ ========================= ==================== ============================================================================ +Operator Type Min Program Version Notes +================================================================================ ========================= ==================== ============================================================================ :any:`Txn.type() ` :code:`TealType.bytes` 2 -:any:`Txn.type_enum() ` :code:`TealType.uint64` 2 see table below -:any:`Txn.sender() ` :code:`TealType.bytes` 2 32 byte address -:any:`Txn.fee() ` :code:`TealType.uint64` 2 in microAlgos -:any:`Txn.first_valid() ` :code:`TealType.uint64` 2 round number -:any:`Txn.first_valid_time() ` :code:`TealType.uint64` 7 UNIX timestamp of block before :code:`Txn.first_valid()`. Fails if negative -:any:`Txn.last_valid() ` :code:`TealType.uint64` 2 round number -:any:`Txn.note() ` :code:`TealType.bytes` 2 transaction note in bytes -:any:`Txn.lease() ` :code:`TealType.bytes` 2 transaction lease in bytes -:any:`Txn.group_index() ` :code:`TealType.uint64` 2 position of this transaction within a transaction group, starting at 0 -:any:`Txn.tx_id() ` :code:`TealType.bytes` 2 the computed ID for this transaction, 32 bytes -:any:`Txn.rekey_to() ` :code:`TealType.bytes` 2 32 byte address -================================================================================ ========================= ================ ============================================================================ +:any:`Txn.type_enum() ` :code:`TealType.uint64` 2 see table below +:any:`Txn.sender() ` :code:`TealType.bytes` 2 32 byte address +:any:`Txn.fee() ` :code:`TealType.uint64` 2 in microAlgos +:any:`Txn.first_valid() ` :code:`TealType.uint64` 2 round number +:any:`Txn.first_valid_time() ` :code:`TealType.uint64` 7 UNIX timestamp of block before :code:`Txn.first_valid()`. Fails if negative +:any:`Txn.last_valid() ` :code:`TealType.uint64` 2 round number +:any:`Txn.note() ` :code:`TealType.bytes` 2 transaction note in bytes +:any:`Txn.lease() ` :code:`TealType.bytes` 2 transaction lease in bytes +:any:`Txn.group_index() ` :code:`TealType.uint64` 2 position of this transaction within a transaction group, starting at 0 +:any:`Txn.tx_id() ` :code:`TealType.bytes` 2 the computed ID for this transaction, 32 bytes +:any:`Txn.rekey_to() ` :code:`TealType.bytes` 2 32 byte address +================================================================================ ========================= ==================== ============================================================================ Application Call ....................................................... -==================================================================================== ========================= ================ ============================================================================ -Operator Type Min TEAL Version Notes -==================================================================================== ========================= ================ ============================================================================ +==================================================================================== ========================= ==================== ============================================================================ +Operator Type Min Program Version Notes +==================================================================================== ========================= ==================== ============================================================================ :any:`Txn.application_id() ` :code:`TealType.uint64` 2 :any:`Txn.on_completion() ` :code:`TealType.uint64` 2 :any:`Txn.approval_program() ` :code:`TealType.bytes` 2 -:any:`Txn.global_num_uints() ` :code:`TealType.uint64` 3 Maximum global integers in app schema -:any:`Txn.global_num_byte_slices() ` :code:`TealType.uint64` 3 Maximum global byte strings in app schema -:any:`Txn.local_num_uints() ` :code:`TealType.uint64` 3 Maximum local integers in app schema -:any:`Txn.local_num_byte_slices() ` :code:`TealType.uint64` 3 Maximum local byte strings in app schema -:any:`Txn.accounts ` :code:`TealType.bytes[]` 2 Array of accounts available to the application -:any:`Txn.assets ` :code:`TealType.uint64[]` 3 Array of assets available to the application -:any:`Txn.applications ` :code:`TealType.uint64[]` 3 Array of applications +:any:`Txn.global_num_uints() ` :code:`TealType.uint64` 3 Maximum global integers in app schema +:any:`Txn.global_num_byte_slices() ` :code:`TealType.uint64` 3 Maximum global byte strings in app schema +:any:`Txn.local_num_uints() ` :code:`TealType.uint64` 3 Maximum local integers in app schema +:any:`Txn.local_num_byte_slices() ` :code:`TealType.uint64` 3 Maximum local byte strings in app schema +:any:`Txn.accounts ` :code:`TealType.bytes[]` 2 Array of accounts available to the application +:any:`Txn.assets ` :code:`TealType.uint64[]` 3 Array of assets available to the application +:any:`Txn.applications ` :code:`TealType.uint64[]` 3 Array of applications :any:`Txn.clear_state_program() ` :code:`TealType.bytes` 2 -:any:`Txn.extra_program_pages() ` :code:`TealType.uint64` 4 Number of extra program pages for app -:any:`Txn.application_args ` :code:`TealType.bytes[]` 2 Array of application arguments -:any:`Txn.created_application_id() ` :code:`TealType.uint64` 5 The ID of the newly created application in this transaction. In v5, only valid on inner transactions. >= v6 works with top-level and inner transactions. -:any:`Txn.logs ` :code:`TealType.bytes[]` 5 Array of application logged items. In v5, only valid on inner transactions. >= v6 works with top-level and inner transactions. -:any:`Txn.last_log() ` :code:`TealType.bytes[]` 6 The last message emitted. Empty bytes if none were emitted. Application mode only. -:any:`Txn.approval_program_pages() ` :code:`TealType.bytes[]` 7 The pages of the approval program as an array -:any:`Txn.num_approval_program_pages() ` :code:`TealType.uint64` 7 The number of approval program pages -:any:`Txn.clear_state_program_pages() ` :code:`TealType.bytes[]` 7 The pages of a clear state program as an array -:any:`Txn.num_clear_state_program_pages() ` :code:`TealType.uint64` 7 The number of clear state program pages -==================================================================================== ========================= ================ ============================================================================ +:any:`Txn.extra_program_pages() ` :code:`TealType.uint64` 4 Number of extra program pages for app +:any:`Txn.application_args ` :code:`TealType.bytes[]` 2 Array of application arguments +:any:`Txn.created_application_id() ` :code:`TealType.uint64` 5 The ID of the newly created application in this transaction. In v5, only valid on inner transactions. >= v6 works with top-level and inner transactions. +:any:`Txn.logs ` :code:`TealType.bytes[]` 5 Array of application logged items. In v5, only valid on inner transactions. >= v6 works with top-level and inner transactions. +:any:`Txn.last_log() ` :code:`TealType.bytes` 6 The last message emitted. Empty bytes if none were emitted. Application mode only. +:any:`Txn.approval_program_pages() ` :code:`TealType.bytes[]` 7 The pages of the approval program as an array +:any:`Txn.clear_state_program_pages() ` :code:`TealType.bytes[]` 7 The pages of a clear state program as an array +==================================================================================== ========================= ==================== ============================================================================ Asset Config ....................................................... -================================================================================ ========================= ================ ============================================================================ -Operator Type Min TEAL Version Notes -================================================================================ ========================= ================ ============================================================================ -:any:`Txn.config_asset() ` :code:`TealType.uint64` 2 ID of asset being configured +================================================================================ ========================= ==================== ============================================================================ +Operator Type Min Program Version Notes +================================================================================ ========================= ==================== ============================================================================ +:any:`Txn.config_asset() ` :code:`TealType.uint64` 2 ID of asset being configured :any:`Txn.config_asset_total() ` :code:`TealType.uint64` 2 :any:`Txn.config_asset_decimals() ` :code:`TealType.uint64` 2 :any:`Txn.config_asset_default_frozen() ` :code:`TealType.uint64` 2 @@ -76,58 +74,58 @@ Operator :any:`Txn.config_asset_name() ` :code:`TealType.bytes` 2 :any:`Txn.config_asset_url() ` :code:`TealType.bytes` 2 :any:`Txn.config_asset_metadata_hash() ` :code:`TealType.bytes` 2 -:any:`Txn.config_asset_manager() ` :code:`TealType.bytes` 2 32 byte address -:any:`Txn.config_asset_reserve() ` :code:`TealType.bytes` 2 32 byte address -:any:`Txn.config_asset_freeze() ` :code:`TealType.bytes` 2 32 byte address -:any:`Txn.config_asset_clawback() ` :code:`TealType.bytes` 2 32 byte address -:any:`Txn.created_asset_id() ` :code:`TealType.uint64` 5 The ID of the newly created asset in this transaction. In v5, only valid on inner transactions. >= v6 works with top-level and inner transactions. -================================================================================ ========================= ================ ============================================================================ +:any:`Txn.config_asset_manager() ` :code:`TealType.bytes` 2 32 byte address +:any:`Txn.config_asset_reserve() ` :code:`TealType.bytes` 2 32 byte address +:any:`Txn.config_asset_freeze() ` :code:`TealType.bytes` 2 32 byte address +:any:`Txn.config_asset_clawback() ` :code:`TealType.bytes` 2 32 byte address +:any:`Txn.created_asset_id() ` :code:`TealType.uint64` 5 The ID of the newly created asset in this transaction. In v5, only valid on inner transactions. >= v6 works with top-level and inner transactions. +================================================================================ ========================= ==================== ============================================================================ Asset Freeze ....................................................... -================================================================================ ========================= ================ ============================================================================ -Operator Type Min TEAL Version Notes -================================================================================ ========================= ================ ============================================================================ +================================================================================ ========================= ==================== ============================================================================ +Operator Type Min Program Version Notes +================================================================================ ========================= ==================== ============================================================================ :any:`Txn.freeze_asset() ` :code:`TealType.uint64` 2 -:any:`Txn.freeze_asset_account() ` :code:`TealType.bytes` 2 32 byte address +:any:`Txn.freeze_asset_account() ` :code:`TealType.bytes` 2 32 byte address :any:`Txn.freeze_asset_frozen() ` :code:`TealType.uint64` 2 -================================================================================ ========================= ================ ============================================================================ +================================================================================ ========================= ==================== ============================================================================ Asset Transfer ....................................................... -================================================================================ ========================= ================ ============================================================================ -Operator Type Min TEAL Version Notes -================================================================================ ========================= ================ ============================================================================ -:any:`Txn.xfer_asset() ` :code:`TealType.uint64` 2 ID of asset being transferred -:any:`Txn.asset_amount() ` :code:`TealType.uint64` 2 value in Asset's units -:any:`Txn.asset_sender() ` :code:`TealType.bytes` 2 32 byte address, causes clawback of all value if sender is the clawback -:any:`Txn.asset_receiver() ` :code:`TealType.bytes` 2 32 byte address -:any:`Txn.asset_close_to() ` :code:`TealType.bytes` 2 32 byte address -================================================================================ ========================= ================ ============================================================================ +================================================================================ ========================= ==================== ============================================================================ +Operator Type Min Program Version Notes +================================================================================ ========================= ==================== ============================================================================ +:any:`Txn.xfer_asset() ` :code:`TealType.uint64` 2 ID of asset being transferred +:any:`Txn.asset_amount() ` :code:`TealType.uint64` 2 value in Asset's units +:any:`Txn.asset_sender() ` :code:`TealType.bytes` 2 32 byte address, causes clawback of all value if sender is the clawback +:any:`Txn.asset_receiver() ` :code:`TealType.bytes` 2 32 byte address +:any:`Txn.asset_close_to() ` :code:`TealType.bytes` 2 32 byte address +================================================================================ ========================= ==================== ============================================================================ Key Registration ....................................................... -================================================================================ ========================= ================ ============================================================================ -Operator Type Min TEAL Version Notes -================================================================================ ========================= ================ ============================================================================ -:any:`Txn.vote_pk() ` :code:`TealType.bytes` 2 32 byte address -:any:`Txn.selection_pk() ` :code:`TealType.bytes` 2 32 byte address -:any:`Txn.state_proof_pk ` :code:`TealType.bytes` 6 64 byte state proof public key commitment. +================================================================================ ========================= ==================== ============================================================================ +Operator Type Min Program Version Notes +================================================================================ ========================= ==================== ============================================================================ +:any:`Txn.vote_pk() ` :code:`TealType.bytes` 2 32 byte address +:any:`Txn.selection_pk() ` :code:`TealType.bytes` 2 32 byte address +:any:`Txn.state_proof_pk ` :code:`TealType.bytes` 6 64 byte state proof public key commitment. :any:`Txn.vote_first() ` :code:`TealType.uint64` 2 :any:`Txn.vote_last() ` :code:`TealType.uint64` 2 :any:`Txn.vote_key_dilution() ` :code:`TealType.uint64` 2 -:any:`Txn.nonparticipation() ` :code:`TealType.uint64` 5 Marks an account nonparticipating for rewards -================================================================================ ========================= ================ ============================================================================ +:any:`Txn.nonparticipation() ` :code:`TealType.uint64` 5 Marks an account nonparticipating for rewards +================================================================================ ========================= ==================== ============================================================================ Payment ....................................................... -================================================================================ ========================= ================ ============================================================================ -Operator Type Min TEAL Version Notes -================================================================================ ========================= ================ ============================================================================ -:any:`Txn.receiver() ` :code:`TealType.bytes` 2 32 byte address -:any:`Txn.amount() ` :code:`TealType.uint64` 2 in microAlgos -:any:`Txn.close_remainder_to() ` :code:`TealType.bytes` 2 32 byte address -================================================================================ ========================= ================ ============================================================================ +================================================================================ ========================= ==================== ============================================================================ +Operator Type Min Program Version Notes +================================================================================ ========================= ==================== ============================================================================ +:any:`Txn.receiver() ` :code:`TealType.bytes` 2 32 byte address +:any:`Txn.amount() ` :code:`TealType.uint64` 2 in microAlgos +:any:`Txn.close_remainder_to() ` :code:`TealType.bytes` 2 32 byte address +================================================================================ ========================= ==================== ============================================================================ Transaction Types ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -162,7 +160,7 @@ items can be accessed using bracket notation. For example: Txn.application_args[0] # get the first application argument Txn.application_args[1] # get the second application argument - # as of TEAL v5, PyTeal expressions can be used to dynamically index into array properties as well + # as of AVM v5, PyTeal expressions can be used to dynamically index into array properties as well Txn.application_args[Txn.application_args.length() - Int(1)] # get the last application argument .. _txn_special_case_arrays: @@ -197,7 +195,7 @@ available on the elements of :code:`Gtxn`. For example: Gtxn[0].sender() # get the sender of the first transaction in the atomic transfer group Gtxn[1].receiver() # get the receiver of the second transaction in the atomic transfer group - # as of TEAL v3, PyTeal expressions can be used to dynamically index into Gtxn as well + # as of AVM v3, PyTeal expressions can be used to dynamically index into Gtxn as well Gtxn[Txn.group_index() - Int(1)].sender() # get the sender of the previous transaction in the atomic transfer group :code:`Gtxn` is zero-indexed and the maximum size of an atomic transfer group is 16. The size of the @@ -211,7 +209,7 @@ Inner Transactions ------------------ .. note:: - Inner transactions are only available in TEAL version 5 or higher. + Inner transactions are only available in AVM version 5 or higher. Inner transactions can be created and submitted with expressions from the :any:`InnerTxnBuilder` class. The properties of the most recently submitted inner transaction can be accessed using the :any:`InnerTxn` @@ -224,19 +222,19 @@ Global Parameters Information about the current state of the blockchain can be obtained using the following :any:`Global` expressions: -=========================================== ======================= ================ ============================================================= -Operator Type Min TEAL Version Notes -=========================================== ======================= ================ ============================================================= -:any:`Global.min_txn_fee()` :code:`TealType.uint64` 2 in microAlgos -:any:`Global.min_balance()` :code:`TealType.uint64` 2 in microAlgos -:any:`Global.max_txn_life()` :code:`TealType.uint64` 2 number of rounds -:any:`Global.zero_address()` :code:`TealType.bytes` 2 32 byte address of all zero bytes -:any:`Global.group_size()` :code:`TealType.uint64` 2 number of txns in this atomic transaction group, at least 1 -:any:`Global.logic_sig_version()` :code:`TealType.uint64` 2 the maximum supported TEAL version -:any:`Global.round()` :code:`TealType.uint64` 2 the current round number -:any:`Global.latest_timestamp()` :code:`TealType.uint64` 2 the latest confirmed block UNIX timestamp -:any:`Global.current_application_id()` :code:`TealType.uint64` 2 the ID of the current application executing -:any:`Global.creator_address()` :code:`TealType.bytes` 3 32 byte address of the creator of the current application -:any:`Global.current_application_address()` :code:`TealType.bytes` 5 32 byte address of the current application controlled account -:any:`Global.group_id()` :code:`TealType.bytes` 5 32 byte ID of the current transaction group -=========================================== ======================= ================ ============================================================= +=========================================== ======================= ==================== ============================================================= +Operator Type Min Program Version Notes +=========================================== ======================= ==================== ============================================================= +:any:`Global.min_txn_fee()` :code:`TealType.uint64` 2 in microAlgos +:any:`Global.min_balance()` :code:`TealType.uint64` 2 in microAlgos +:any:`Global.max_txn_life()` :code:`TealType.uint64` 2 number of rounds +:any:`Global.zero_address()` :code:`TealType.bytes` 2 32 byte address of all zero bytes +:any:`Global.group_size()` :code:`TealType.uint64` 2 number of txns in this atomic transaction group, at least 1 +:any:`Global.logic_sig_version()` :code:`TealType.uint64` 2 the maximum supported program version +:any:`Global.round()` :code:`TealType.uint64` 2 the current round number +:any:`Global.latest_timestamp()` :code:`TealType.uint64` 2 the latest confirmed block UNIX timestamp +:any:`Global.current_application_id()` :code:`TealType.uint64` 2 the ID of the current application executing +:any:`Global.creator_address()` :code:`TealType.bytes` 3 32 byte address of the creator of the current application +:any:`Global.current_application_address()` :code:`TealType.bytes` 5 32 byte address of the current application controlled account +:any:`Global.group_id()` :code:`TealType.bytes` 5 32 byte ID of the current transaction group +=========================================== ======================= ==================== ============================================================= diff --git a/docs/arithmetic_expression.rst b/docs/arithmetic_expression.rst index daa4619c6..a9d0f75aa 100644 --- a/docs/arithmetic_expression.rst +++ b/docs/arithmetic_expression.rst @@ -49,7 +49,7 @@ The associativity and precedence of the overloaded Python arithmetic operators a Byteslice Arithmetic -------------------- -Byteslice arithemetic is available for Teal V4 and above. +Byteslice arithmetic is available for AVM V4 and above. Byteslice arithmetic operators allow up to 512-bit arithmetic. In PyTeal, byteslice arithmetic expressions include :code:`TealType.Bytes` values as arguments (with the exception of :code:`BytesZero`) diff --git a/docs/byte_expression.rst b/docs/byte_expression.rst index acc535576..b457e756b 100644 --- a/docs/byte_expression.rst +++ b/docs/byte_expression.rst @@ -48,7 +48,7 @@ Extract ~~~~~~~ .. note:: - :code:`Extract` is only available in TEAL version 5 or higher. + :code:`Extract` is only available in program version 5 or higher. The :any:`Extract` expression can extract part of a byte slice given the start index and length. For example: diff --git a/docs/control_structures.rst b/docs/control_structures.rst index a62bfec2c..b464b1535 100644 --- a/docs/control_structures.rst +++ b/docs/control_structures.rst @@ -11,7 +11,7 @@ Exiting the Program: :code:`Approve` and :code:`Reject` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. note:: - The :code:`Approve` and :code:`Reject` expressions are only available in TEAL version 4 or higher. + The :code:`Approve` and :code:`Reject` expressions are only available in program version 4 or higher. Prior to this, :code:`Return(Int(1))` is equivalent to :code:`Approve()` and :code:`Return(Int(0))` is equivalent to :code:`Reject()`. @@ -166,7 +166,7 @@ Looping: :code:`While` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. note:: - This expression is only available in TEAL version 4 or higher. + This expression is only available in program version 4 or higher. The :any:`While` expression can be used to create simple loops in PyTeal. The syntax of :code:`While` is: @@ -203,7 +203,7 @@ Looping: :code:`For` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. note:: - This expression is only available in TEAL version 4 or higher. + This expression is only available in program version 4 or higher. Similar to :code:`While`, the :any:`For` expression can also be used to create loops in PyTeal. The syntax of :code:`For` is: @@ -294,7 +294,7 @@ Subroutines ~~~~~~~~~~~ .. note:: - Subroutines are only available in TEAL version 4 or higher. + Subroutines are only available in program version 4 or higher. A subroutine is section of code that can be called multiple times from within a program. Subroutines are PyTeal's equivalent to functions. Subroutine constraints include: diff --git a/docs/crypto.rst b/docs/crypto.rst index 6a80b2567..7f9a0ef75 100644 --- a/docs/crypto.rst +++ b/docs/crypto.rst @@ -24,9 +24,9 @@ Operator Cost Description :code:`EcdsaRecover(c, d, id, r, s)` `2000` produces the public key associated with the signature :code:`(r, s)` and recovery id :code:`id` ==================================== ========= ================================================================================================================== -\* :code:`Ed25519Verify` is only available in signature mode up to version 4 of TEAL. From version 5 upwards, `Ed25519Verify` can be used in any mode. +\* :code:`Ed25519Verify` is only available in signature mode up to version 4 of AVM. From version 5 upwards, `Ed25519Verify` can be used in any mode. -Note the cost amount is accurate for version 2 of TEAL and higher. The parameter :code:`c` in the ECDSA expressions defined above represents the elliptic curve +Note the cost amount is accurate for version 2 of AVM and higher. The parameter :code:`c` in the ECDSA expressions defined above represents the elliptic curve specification to be used (for example, :code:`Secp256k1`). These cryptographic primitives cover the most used ones in blockchains and cryptocurrencies. For example, Bitcoin uses `SHA-256` for creating Bitcoin addresses; diff --git a/docs/loading_group_transaction.rst b/docs/loading_group_transaction.rst index 90ada05d5..be2753a7d 100644 --- a/docs/loading_group_transaction.rst +++ b/docs/loading_group_transaction.rst @@ -3,7 +3,7 @@ Loading Values from Group Transactions ====================================== -Since TEAL version 4 and above, programs can load values from transactions within an atomic +Since program version 4 and above, programs can load values from transactions within an atomic group transaction. For instance, you can import values from the scratch space of another application call, and you can access the generated ID of a new application or asset. These operations are only permitted in application mode. diff --git a/docs/versions.rst b/docs/versions.rst index b64910451..15a9bfad0 100644 --- a/docs/versions.rst +++ b/docs/versions.rst @@ -1,14 +1,14 @@ .. _versions: -TEAL Versions +AVM Versions ============= -Each version of PyTeal compiles contracts for a specific version of TEAL. Newer versions of TEAL +Each version of PyTeal compiles contracts for a specific AVM version. Newer versions of the AVM introduce new opcodes and transaction fields, so PyTeal must be updated to support these new -features. Below is a table which shows the relationship between TEAL and PyTeal versions. +features. Below is a table which shows the relationship between AVM and PyTeal versions. ============ ============== -TEAL Version PyTeal Version +AVM Version PyTeal Version ============ ============== 1 <= 0.5.4 2 >= 0.6.0 @@ -16,16 +16,17 @@ TEAL Version PyTeal Version 4 >= 0.8.0 5 >= 0.9.0 6 >= 0.10.0 +7 >= 0.14.0 ============ ============== -In order to support TEAL v2, PyTeal v0.6.0 breaks backward compatibility with v0.5.4. PyTeal +In order to support AVM v2, PyTeal v0.6.0 breaks backward compatibility with v0.5.4. PyTeal programs written for PyTeal version 0.5.4 and below will not compile properly and most likely will display an error of the form :code:`AttributeError: * object has no attribute 'teal'`. -**WARNING:** before updating PyTeal to a version with generates TEAL v2 contracts and fixing the +**WARNING:** before updating PyTeal to a version with generates AVM v2 contracts and fixing the programs to use the global function :any:`compileTeal` rather the class method :code:`.teal()`, make -sure your program abides by the TEAL safety guidelines ``_. -Changing a v1 TEAL program to a v2 TEAL program without any code changes is insecure because v2 -TEAL programs allow rekeying. Specifically, you must add a check that the :code:`RekeyTo` property +sure your program abides by the AVM safety guidelines ``_. +Changing a v1 AVM program to a v2 AVM program without any code changes is insecure because v2 +AVM programs allow rekeying. Specifically, you must add a check that the :code:`RekeyTo` property of any transaction is set to the zero address when updating an older PyTeal program from v0.5.4 and below. diff --git a/examples/signature/factorizer_game.py b/examples/signature/factorizer_game.py index ad8ffe3b7..6f4ba48c7 100644 --- a/examples/signature/factorizer_game.py +++ b/examples/signature/factorizer_game.py @@ -47,7 +47,7 @@ def logicsig(a: int, p: int, q: int) -> Expr: """ Choices * (a, p, q) = (1, 5, 7) - * compiling on TEAL version 5 and + * compiling on program version 5 and * with assembleConstants = True results in Logic-Sig Contract Account Address: WO3TQD3WBSDKB6WEHUMSEBFH53GZVVXYGPWYDWKUZCKEXTVCDNDHJGG6II diff --git a/pyteal/__init__.py b/pyteal/__init__.py index ae30dd312..1d8d92f3d 100644 --- a/pyteal/__init__.py +++ b/pyteal/__init__.py @@ -6,6 +6,9 @@ MAX_TEAL_VERSION, MIN_TEAL_VERSION, DEFAULT_TEAL_VERSION, + MAX_PROGRAM_VERSION, + MIN_PROGRAM_VERSION, + DEFAULT_PROGRAM_VERSION, CompileOptions, compileTeal, OptimizeOptions, @@ -27,6 +30,9 @@ "MAX_TEAL_VERSION", "MIN_TEAL_VERSION", "DEFAULT_TEAL_VERSION", + "MAX_PROGRAM_VERSION", + "MIN_PROGRAM_VERSION", + "DEFAULT_PROGRAM_VERSION", "CompileOptions", "compileTeal", "OptimizeOptions", diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index a94633317..1ea51a5a1 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -9,6 +9,9 @@ from pyteal.compiler import ( MAX_TEAL_VERSION, MIN_TEAL_VERSION, DEFAULT_TEAL_VERSION, + MAX_PROGRAM_VERSION, + MIN_PROGRAM_VERSION, + DEFAULT_PROGRAM_VERSION, CompileOptions, compileTeal, OptimizeOptions, @@ -76,6 +79,7 @@ __all__ = [ "Concat", "Cond", "Continue", + "DEFAULT_PROGRAM_VERSION", "DEFAULT_TEAL_VERSION", "Div", "Divw", @@ -126,7 +130,9 @@ __all__ = [ "Log", "Lt", "MAX_GROUP_SIZE", + "MAX_PROGRAM_VERSION", "MAX_TEAL_VERSION", + "MIN_PROGRAM_VERSION", "MIN_TEAL_VERSION", "MaybeValue", "MethodSignature", diff --git a/pyteal/ast/acct_test.py b/pyteal/ast/acct_test.py index 52fc89132..ee60690d8 100644 --- a/pyteal/ast/acct_test.py +++ b/pyteal/ast/acct_test.py @@ -1,9 +1,9 @@ import pyteal as pt options = pt.CompileOptions() -teal4Options = pt.CompileOptions(version=4) -teal5Options = pt.CompileOptions(version=5) -teal6Options = pt.CompileOptions(version=6) +avm4Options = pt.CompileOptions(version=4) +avm5Options = pt.CompileOptions(version=5) +avm6Options = pt.CompileOptions(version=6) def test_acct_param_balance_valid(): @@ -21,7 +21,7 @@ def test_acct_param_balance_valid(): ] ) - actual, _ = expr.__teal__(teal6Options) + actual, _ = expr.__teal__(avm6Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -44,7 +44,7 @@ def test_acct_param_min_balance_valid(): ] ) - actual, _ = expr.__teal__(teal6Options) + actual, _ = expr.__teal__(avm6Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -67,7 +67,7 @@ def test_acct_param_auth_addr_valid(): ] ) - actual, _ = expr.__teal__(teal6Options) + actual, _ = expr.__teal__(avm6Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) diff --git a/pyteal/ast/app_test.py b/pyteal/ast/app_test.py index 79a6c1491..a74e66332 100644 --- a/pyteal/ast/app_test.py +++ b/pyteal/ast/app_test.py @@ -3,8 +3,8 @@ import pyteal as pt options = pt.CompileOptions() -teal4Options = pt.CompileOptions(version=4) -teal5Options = pt.CompileOptions(version=5) +avm4Options = pt.CompileOptions(version=4) +avm5Options = pt.CompileOptions(version=5) def test_on_complete(): @@ -258,7 +258,7 @@ def test_global_get_ex_direct_ref(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -439,7 +439,7 @@ def test_app_param_approval_program_valid(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -467,7 +467,7 @@ def test_app_param_clear_state_program_valid(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -495,7 +495,7 @@ def test_app_param_global_num_uint_valid(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -523,7 +523,7 @@ def test_app_param_global_num_byte_slice_valid(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -551,7 +551,7 @@ def test_app_param_local_num_uint_valid(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -579,7 +579,7 @@ def test_app_param_local_num_byte_slice_valid(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -607,7 +607,7 @@ def test_app_param_extra_programs_page_valid(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -635,7 +635,7 @@ def test_app_param_creator_valid(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -663,7 +663,7 @@ def test_app_param_address_valid(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) diff --git a/pyteal/ast/arg.py b/pyteal/ast/arg.py index 4c5697eda..25f7cb45c 100644 --- a/pyteal/ast/arg.py +++ b/pyteal/ast/arg.py @@ -2,7 +2,7 @@ from pyteal.types import TealType, require_type from pyteal.ir import TealOp, Op, TealBlock -from pyteal.errors import TealInputError, verifyTealVersion +from pyteal.errors import TealInputError, verifyProgramVersion from pyteal.ast.expr import Expr from pyteal.ast.leafexpr import LeafExpr @@ -21,7 +21,7 @@ def __init__(self, index: Union[int, Expr]) -> None: Args: index: The index of the argument to get. The index must be between 0 and 255 inclusive. - Starting in TEAL v5, the index may be a PyTeal expression that evaluates to uint64. + Starting in AVM v5, the index may be a PyTeal expression that evaluates to uint64. """ super().__init__() @@ -38,10 +38,10 @@ def __teal__(self, options: "CompileOptions"): op = TealOp(self, Op.arg, self.index) return TealBlock.FromOp(options, op) - verifyTealVersion( + verifyProgramVersion( Op.args.min_version, options.version, - "TEAL version too low to use dynamic indexes with Arg", + "Program version too low to use dynamic indexes with Arg", ) op = TealOp(self, Op.args) diff --git a/pyteal/ast/arg_test.py b/pyteal/ast/arg_test.py index 90cfc8929..b4feca2ad 100644 --- a/pyteal/ast/arg_test.py +++ b/pyteal/ast/arg_test.py @@ -2,9 +2,9 @@ import pyteal as pt -teal2Options = pt.CompileOptions(version=2) -teal4Options = pt.CompileOptions(version=4) -teal5Options = pt.CompileOptions(version=5) +avm2Options = pt.CompileOptions(version=2) +avm4Options = pt.CompileOptions(version=4) +avm5Options = pt.CompileOptions(version=5) def test_arg_static(): @@ -15,7 +15,7 @@ def test_arg_static(): expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.arg, i)]) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) assert actual == expected @@ -29,14 +29,14 @@ def test_arg_dynamic(): [pt.TealOp(i, pt.Op.int, 7), pt.TealOp(expr, pt.Op.args)] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal4Options) + expr.__teal__(avm4Options) def test_arg_invalid(): diff --git a/pyteal/ast/assert_test.py b/pyteal/ast/assert_test.py index fd6b756ab..1291a799c 100644 --- a/pyteal/ast/assert_test.py +++ b/pyteal/ast/assert_test.py @@ -2,8 +2,8 @@ import pyteal as pt -teal2Options = pt.CompileOptions(version=2) -teal3Options = pt.CompileOptions(version=3) +avm2Options = pt.CompileOptions(version=2) +avm3Options = pt.CompileOptions(version=3) def test_teal_2_assert(): @@ -11,13 +11,13 @@ def test_teal_2_assert(): expr = pt.Assert(arg) assert expr.type_of() == pt.TealType.none - expected, _ = arg.__teal__(teal2Options) + expected, _ = arg.__teal__(avm2Options) expectedBranch = pt.TealConditionalBlock([]) expectedBranch.setTrueBlock(pt.TealSimpleBlock([])) - expectedBranch.setFalseBlock(pt.Err().__teal__(teal2Options)[0]) + expectedBranch.setFalseBlock(pt.Err().__teal__(avm2Options)[0]) expected.setNextBlock(expectedBranch) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) with pt.TealComponent.Context.ignoreExprEquality(): assert actual == expected @@ -32,7 +32,7 @@ def test_teal_3_assert(): [pt.TealOp(arg, pt.Op.int, 1), pt.TealOp(expr, pt.Op.assert_)] ) - actual, _ = expr.__teal__(teal3Options) + actual, _ = expr.__teal__(avm3Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) diff --git a/pyteal/ast/asset_test.py b/pyteal/ast/asset_test.py index 6ac9cf0e1..8bdaf57b1 100644 --- a/pyteal/ast/asset_test.py +++ b/pyteal/ast/asset_test.py @@ -2,9 +2,9 @@ import pyteal as pt -teal2Options = pt.CompileOptions() -teal4Options = pt.CompileOptions(version=4) -teal5Options = pt.CompileOptions(version=5) +avm2Options = pt.CompileOptions() +avm4Options = pt.CompileOptions(version=4) +avm5Options = pt.CompileOptions(version=5) def test_asset_holding_balance(): @@ -23,7 +23,7 @@ def test_asset_holding_balance(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -47,7 +47,7 @@ def test_asset_holding_balance_direct_ref(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -79,7 +79,7 @@ def test_asset_holding_frozen(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -103,7 +103,7 @@ def test_asset_holding_frozen_direct_ref(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -134,7 +134,7 @@ def test_asset_param_total(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -157,7 +157,7 @@ def test_asset_param_total_direct_ref(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -185,7 +185,7 @@ def test_asset_param_decimals(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -208,7 +208,7 @@ def test_asset_param_decimals_direct_ref(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -236,7 +236,7 @@ def test_asset_param_default_frozen(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -259,7 +259,7 @@ def test_asset_param_default_frozen_direct_ref(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -287,7 +287,7 @@ def test_asset_param_unit_name(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -310,7 +310,7 @@ def test_asset_param_unit_name_direct_ref(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -338,7 +338,7 @@ def test_asset_param_name(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -361,7 +361,7 @@ def test_asset_param_name_direct_ref(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -389,7 +389,7 @@ def test_asset_param_url(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -412,7 +412,7 @@ def test_asset_param_url_direct_ref(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -440,7 +440,7 @@ def test_asset_param_metadata_hash(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -463,7 +463,7 @@ def test_asset_param_metadata_hash_direct_ref(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -491,7 +491,7 @@ def test_asset_param_manager(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -514,7 +514,7 @@ def test_asset_param_manager_direct_ref(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -542,7 +542,7 @@ def test_asset_param_reserve(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -565,7 +565,7 @@ def test_asset_param_reserve_direct_ref(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -593,7 +593,7 @@ def test_asset_param_freeze(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -616,7 +616,7 @@ def test_asset_param_freeze_direct_ref(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -644,7 +644,7 @@ def test_asset_param_clawback(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -667,7 +667,7 @@ def test_asset_param_clawback_direct_ref(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -695,7 +695,7 @@ def test_asset_param_creator_valid(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) diff --git a/pyteal/ast/base64decode.py b/pyteal/ast/base64decode.py index 7dcf47c18..be850a001 100644 --- a/pyteal/ast/base64decode.py +++ b/pyteal/ast/base64decode.py @@ -5,7 +5,6 @@ from pyteal.errors import verifyFieldVersion from pyteal.ir import TealOp, Op, TealBlock from pyteal.ast.expr import Expr -from pyteal.ast.leafexpr import LeafExpr if TYPE_CHECKING: from pyteal.compiler import CompileOptions @@ -27,7 +26,7 @@ def __init__(self, id: int, name: str, min_version: int) -> None: Base64Encoding.__module__ = "pyteal" -class Base64Decode(LeafExpr): +class Base64Decode(Expr): """An expression that decodes a base64-encoded byte string according to a specific encoding. See [RFC 4648](https://rfc-editor.org/rfc/rfc4648.html#section-4) (sections 4 and 5) for information on specifications. @@ -36,6 +35,8 @@ class Base64Decode(LeafExpr): When padding occurs, any unused pad bits in the encoding must be set to zero or the decoding will fail. The special cases of \\n and \\r are allowed but completely ignored. An error will result when attempting to decode a string with a character that is not in the encoding alphabet or not one of =, \\r, or \\n. + + NOTE: Base64Decode usage is not intended for introducing constants. Instead, use :any:`Bytes`. """ def __init__(self, encoding: Base64Encoding, base64: Expr) -> None: @@ -59,8 +60,11 @@ def __str__(self): def type_of(self): return TealType.bytes + def has_return(self): + return False + @classmethod - def url(cls, base64: Expr) -> "Base64Decode": + def url(cls, base64: Expr) -> Expr: """Decode a base64-encoded byte string according to the URL encoding. Refer to the `Base64Decode` class documentation for more information. @@ -71,7 +75,7 @@ def url(cls, base64: Expr) -> "Base64Decode": return cls(Base64Encoding.url, base64) @classmethod - def std(cls, base64: Expr) -> "Base64Decode": + def std(cls, base64: Expr) -> Expr: """Decode a base64-encoded byte string according to the Standard encoding. Refer to the `Base64Decode` class documentation for more information. diff --git a/pyteal/ast/base64decode_test.py b/pyteal/ast/base64decode_test.py index 14eb48799..724dbc4aa 100644 --- a/pyteal/ast/base64decode_test.py +++ b/pyteal/ast/base64decode_test.py @@ -2,8 +2,8 @@ import pyteal as pt -teal6Options = pt.CompileOptions(version=6) -teal7Options = pt.CompileOptions(version=7) +avm6Options = pt.CompileOptions(version=6) +avm7Options = pt.CompileOptions(version=7) def test_base64decode_std(): @@ -18,14 +18,14 @@ def test_base64decode_std(): ] ) - actual, _ = expr.__teal__(teal7Options) + actual, _ = expr.__teal__(avm7Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal6Options) + expr.__teal__(avm6Options) def test_base64decode_url(): @@ -40,14 +40,14 @@ def test_base64decode_url(): ] ) - actual, _ = expr.__teal__(teal7Options) + actual, _ = expr.__teal__(avm7Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal6Options) + expr.__teal__(avm6Options) def test_base64decode_invalid(): diff --git a/pyteal/ast/binaryexpr.py b/pyteal/ast/binaryexpr.py index c6f879f7c..7b2ebebe2 100644 --- a/pyteal/ast/binaryexpr.py +++ b/pyteal/ast/binaryexpr.py @@ -1,7 +1,7 @@ from typing import Union, Tuple, cast, TYPE_CHECKING from pyteal.types import TealType, require_type -from pyteal.errors import verifyTealVersion +from pyteal.errors import verifyProgramVersion from pyteal.ir import TealOp, Op, TealBlock from pyteal.ast.expr import Expr @@ -35,10 +35,10 @@ def __init__( self.argRight = argRight def __teal__(self, options: "CompileOptions"): - verifyTealVersion( + verifyProgramVersion( self.op.min_version, options.version, - "TEAL version too low to use op {}".format(self.op), + "Program version too low to use op {}".format(self.op), ) return TealBlock.FromOp( @@ -123,7 +123,7 @@ def Exp(a: Expr, b: Expr) -> BinaryExpr: Produces a ** b. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. Args: a: Must evaluate to uint64. @@ -173,7 +173,7 @@ def ShiftLeft(a: Expr, b: Expr) -> BinaryExpr: Produces a << b. This is equivalent to a times 2^b, modulo 2^64. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. Args: a: Must evaluate to uint64. @@ -187,7 +187,7 @@ def ShiftRight(a: Expr, b: Expr) -> BinaryExpr: Produces a >> b. This is equivalent to a divided by 2^b. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. Args: a: Must evaluate to uint64. @@ -281,7 +281,7 @@ def GetBit(value: Expr, index: Expr) -> BinaryExpr: yields 1. Any index less than 4 would yield 1, and any valid index 4 or greater would yield 0. Any integer less than 8*Len(value) is a valid index. - Requires TEAL version 3 or higher. + Requires program version 3 or higher. Args: value: The value containing bits. Can evaluate to any type. @@ -298,7 +298,7 @@ def GetByte(value: Expr, index: Expr) -> BinaryExpr: Similar to GetBit, indexing begins at the first byte. For example, :code:`GetByte(Bytes("base16", "0xff0000"), Int(0))` yields 255. Any other valid index would yield 0. - Requires TEAL version 3 or higher. + Requires program version 3 or higher. Args: value: The value containing the bytes. Must evaluate to bytes. @@ -315,7 +315,7 @@ def BytesAdd(left: Expr, right: Expr) -> BinaryExpr: Produces left + right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. Args: left: Must evaluate to bytes. @@ -330,7 +330,7 @@ def BytesMinus(left: Expr, right: Expr) -> BinaryExpr: Produces left - right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. Args: left: Must evaluate to bytes. @@ -347,7 +347,7 @@ def BytesDiv(left: Expr, right: Expr) -> BinaryExpr: Panics if right is 0. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. Args: left: Must evaluate to bytes. @@ -362,7 +362,7 @@ def BytesMul(left: Expr, right: Expr) -> BinaryExpr: Produces left * right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. Args: left: Must evaluate to bytes. @@ -379,7 +379,7 @@ def BytesMod(left: Expr, right: Expr) -> BinaryExpr: Panics if right is 0. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. Args: left: Must evaluate to bytes. @@ -395,7 +395,7 @@ def BytesAnd(left: Expr, right: Expr) -> BinaryExpr: Left and right are zero-left extended to the greater of their lengths. Arguments must not exceed 64 bytes. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. Args: left: Must evaluate to bytes. @@ -411,7 +411,7 @@ def BytesOr(left: Expr, right: Expr) -> BinaryExpr: Left and right are zero-left extended to the greater of their lengths. Arguments must not exceed 64 bytes. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. Args: left: Must evaluate to bytes. @@ -427,7 +427,7 @@ def BytesXor(left: Expr, right: Expr) -> BinaryExpr: Left and right are zero-left extended to the greater of their lengths. Arguments must not exceed 64 bytes. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. Args: left: Must evaluate to bytes. @@ -442,7 +442,7 @@ def BytesEq(left: Expr, right: Expr) -> BinaryExpr: Checks if left == right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. Args: left: Must evaluate to bytes. @@ -457,7 +457,7 @@ def BytesNeq(left: Expr, right: Expr) -> BinaryExpr: Checks if left != right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. Args: left: Must evaluate to bytes. @@ -472,7 +472,7 @@ def BytesLt(left: Expr, right: Expr) -> BinaryExpr: Checks if left < right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. Args: left: Must evaluate to bytes. @@ -487,7 +487,7 @@ def BytesLe(left: Expr, right: Expr) -> BinaryExpr: Checks if left <= right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. Args: left: Must evaluate to bytes. @@ -502,7 +502,7 @@ def BytesGt(left: Expr, right: Expr) -> BinaryExpr: Checks if left > right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. Args: left: Must evaluate to bytes. @@ -517,7 +517,7 @@ def BytesGe(left: Expr, right: Expr) -> BinaryExpr: Checks if left >= right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. Args: left: Must evaluate to bytes. @@ -534,7 +534,7 @@ def ExtractUint16(string: Expr, offset: Expr) -> BinaryExpr: If :code:`offset + 2` exceeds :code:`Len(string)`, the program fails. - Requires TEAL version 5 or higher. + Requires program version 5 or higher. Args: string: The bytestring to extract from. Must evaluate to bytes. @@ -557,7 +557,7 @@ def ExtractUint32(string: Expr, offset: Expr) -> BinaryExpr: If :code:`offset + 4` exceeds :code:`Len(string)`, the program fails. - Requires TEAL version 5 or higher. + Requires program version 5 or higher. Args: string: The bytestring to extract from. Must evaluate to bytes. @@ -580,7 +580,7 @@ def ExtractUint64(string: Expr, offset: Expr) -> BinaryExpr: If :code:`offset + 8` exceeds :code:`Len(string)`, the program fails. - Requires TEAL version 5 or higher. + Requires program version 5 or higher. Args: string: The bytestring to extract from. Must evaluate to bytes. diff --git a/pyteal/ast/binaryexpr_test.py b/pyteal/ast/binaryexpr_test.py index a1b493365..1d050fd1e 100644 --- a/pyteal/ast/binaryexpr_test.py +++ b/pyteal/ast/binaryexpr_test.py @@ -2,10 +2,10 @@ import pyteal as pt -teal2Options = pt.CompileOptions(version=2) -teal3Options = pt.CompileOptions(version=3) -teal4Options = pt.CompileOptions(version=4) -teal5Options = pt.CompileOptions(version=5) +avm2Options = pt.CompileOptions(version=2) +avm3Options = pt.CompileOptions(version=3) +avm4Options = pt.CompileOptions(version=4) +avm5Options = pt.CompileOptions(version=5) def test_add(): @@ -21,7 +21,7 @@ def test_add(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -43,7 +43,7 @@ def test_add_overload(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -72,7 +72,7 @@ def test_minus(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -94,7 +94,7 @@ def test_minus_overload(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -123,7 +123,7 @@ def test_mul(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -145,7 +145,7 @@ def test_mul_overload(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -174,7 +174,7 @@ def test_div(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -196,7 +196,7 @@ def test_div_overload(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -225,7 +225,7 @@ def test_mod(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -247,7 +247,7 @@ def test_mod_overload(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -276,14 +276,14 @@ def test_exp(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_exp_overload(): @@ -302,7 +302,7 @@ def test_exp_overload(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -310,7 +310,7 @@ def test_exp_overload(): assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_exp_invalid(): @@ -342,7 +342,7 @@ def test_arithmetic(): ] ) - actual, _ = v.__teal__(teal2Options) + actual, _ = v.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -363,7 +363,7 @@ def test_bitwise_and(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -385,7 +385,7 @@ def test_bitwise_and_overload(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -414,7 +414,7 @@ def test_bitwise_or(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -436,7 +436,7 @@ def test_bitwise_or_overload(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -465,7 +465,7 @@ def test_bitwise_xor(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -487,7 +487,7 @@ def test_bitwise_xor_overload(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -516,14 +516,14 @@ def test_shift_left(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_shift_left_overload(): @@ -541,7 +541,7 @@ def test_shift_left_overload(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -549,7 +549,7 @@ def test_shift_left_overload(): assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_shift_left_invalid(): @@ -573,14 +573,14 @@ def test_shift_right(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_shift_right_overload(): @@ -598,7 +598,7 @@ def test_shift_right_overload(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -606,7 +606,7 @@ def test_shift_right_overload(): assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_shift_right_invalid(): @@ -630,7 +630,7 @@ def test_eq(): ] ) - actual_int, _ = expr_int.__teal__(teal2Options) + actual_int, _ = expr_int.__teal__(avm2Options) actual_int.addIncoming() actual_int = pt.TealBlock.NormalizeBlocks(actual_int) @@ -648,7 +648,7 @@ def test_eq(): ] ) - actual_bytes, _ = expr_bytes.__teal__(teal2Options) + actual_bytes, _ = expr_bytes.__teal__(avm2Options) actual_bytes.addIncoming() actual_bytes = pt.TealBlock.NormalizeBlocks(actual_bytes) @@ -668,7 +668,7 @@ def test_eq_overload(): ] ) - actual_int, _ = expr_int.__teal__(teal2Options) + actual_int, _ = expr_int.__teal__(avm2Options) actual_int.addIncoming() actual_int = pt.TealBlock.NormalizeBlocks(actual_int) @@ -686,7 +686,7 @@ def test_eq_overload(): ] ) - actual_bytes, _ = expr_bytes.__teal__(teal2Options) + actual_bytes, _ = expr_bytes.__teal__(avm2Options) actual_bytes.addIncoming() actual_bytes = pt.TealBlock.NormalizeBlocks(actual_bytes) @@ -714,7 +714,7 @@ def test_neq(): ] ) - actual_int, _ = expr_int.__teal__(teal2Options) + actual_int, _ = expr_int.__teal__(avm2Options) actual_int.addIncoming() actual_int = pt.TealBlock.NormalizeBlocks(actual_int) @@ -732,7 +732,7 @@ def test_neq(): ] ) - actual_bytes, _ = expr_bytes.__teal__(teal2Options) + actual_bytes, _ = expr_bytes.__teal__(avm2Options) actual_bytes.addIncoming() actual_bytes = pt.TealBlock.NormalizeBlocks(actual_bytes) @@ -752,7 +752,7 @@ def test_neq_overload(): ] ) - actual_int, _ = expr_int.__teal__(teal2Options) + actual_int, _ = expr_int.__teal__(avm2Options) actual_int.addIncoming() actual_int = pt.TealBlock.NormalizeBlocks(actual_int) @@ -770,7 +770,7 @@ def test_neq_overload(): ] ) - actual_bytes, _ = expr_bytes.__teal__(teal2Options) + actual_bytes, _ = expr_bytes.__teal__(avm2Options) actual_bytes.addIncoming() actual_bytes = pt.TealBlock.NormalizeBlocks(actual_bytes) @@ -798,7 +798,7 @@ def test_lt(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -818,7 +818,7 @@ def test_lt_overload(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -846,7 +846,7 @@ def test_le(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -866,7 +866,7 @@ def test_le_overload(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -894,7 +894,7 @@ def test_gt(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -914,7 +914,7 @@ def test_gt_overload(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -942,7 +942,7 @@ def test_ge(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -962,7 +962,7 @@ def test_ge_overload(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -990,14 +990,14 @@ def test_get_bit_int(): ] ) - actual, _ = expr.__teal__(teal3Options) + actual, _ = expr.__teal__(avm3Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal2Options) + expr.__teal__(avm2Options) def test_get_bit_bytes(): @@ -1013,14 +1013,14 @@ def test_get_bit_bytes(): ] ) - actual, _ = expr.__teal__(teal3Options) + actual, _ = expr.__teal__(avm3Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal2Options) + expr.__teal__(avm2Options) def test_get_bit_invalid(): @@ -1044,14 +1044,14 @@ def test_get_byte(): ] ) - actual, _ = expr.__teal__(teal3Options) + actual, _ = expr.__teal__(avm3Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal2Options) + expr.__teal__(avm2Options) def test_get_byte_invalid(): @@ -1078,14 +1078,14 @@ def test_b_add(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_b_add_invalid(): @@ -1112,14 +1112,14 @@ def test_b_minus(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_b_minus_invalid(): @@ -1143,14 +1143,14 @@ def test_b_div(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_b_div_invalid(): @@ -1174,14 +1174,14 @@ def test_b_mul(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_b_mul_invalid(): @@ -1205,14 +1205,14 @@ def test_b_mod(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_b_mod_invalid(): @@ -1236,14 +1236,14 @@ def test_b_and(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_b_and_invalid(): @@ -1267,14 +1267,14 @@ def test_b_or(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_b_or_invalid(): @@ -1298,14 +1298,14 @@ def test_b_xor(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_b_xor_invalid(): @@ -1332,14 +1332,14 @@ def test_b_eq(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_b_eq_invalid(): @@ -1366,14 +1366,14 @@ def test_b_neq(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_b_neq_invalid(): @@ -1400,14 +1400,14 @@ def test_b_lt(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_b_lt_invalid(): @@ -1434,14 +1434,14 @@ def test_b_le(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_b_le_invalid(): @@ -1468,14 +1468,14 @@ def test_b_gt(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_b_gt_invalid(): @@ -1502,14 +1502,14 @@ def test_b_ge(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_b_ge_invalid(): @@ -1541,14 +1541,14 @@ def test_extract_uint(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal4Options) + expr.__teal__(avm4Options) def test_extract_uint_invalid(): diff --git a/pyteal/ast/block.py b/pyteal/ast/block.py index 041483aae..775f1593c 100644 --- a/pyteal/ast/block.py +++ b/pyteal/ast/block.py @@ -55,7 +55,7 @@ def type_of(self): return self.field.type_of() @classmethod - def seed(cls, block: Expr) -> "Block": + def seed(cls, block: Expr) -> Expr: """Get the seed of a block. Args: @@ -66,7 +66,7 @@ def seed(cls, block: Expr) -> "Block": return cls(BlockField.block_seed, block) @classmethod - def timestamp(cls, block: Expr) -> "Block": + def timestamp(cls, block: Expr) -> Expr: """Get the timestamp of a block. Args: diff --git a/pyteal/ast/block_test.py b/pyteal/ast/block_test.py index 0cd571063..e55ddf319 100644 --- a/pyteal/ast/block_test.py +++ b/pyteal/ast/block_test.py @@ -2,8 +2,8 @@ import pyteal as pt -teal6Options = pt.CompileOptions(version=6) -teal7Options = pt.CompileOptions(version=7) +avm6Options = pt.CompileOptions(version=6) +avm7Options = pt.CompileOptions(version=7) def test_block_seed(): @@ -18,14 +18,14 @@ def test_block_seed(): ] ) - actual, _ = expr.__teal__(teal7Options) + actual, _ = expr.__teal__(avm7Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal6Options) + expr.__teal__(avm6Options) def test_block_seed_invalid(): @@ -45,14 +45,14 @@ def test_block_timestamp(): ] ) - actual, _ = expr.__teal__(teal7Options) + actual, _ = expr.__teal__(avm7Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal6Options) + expr.__teal__(avm6Options) def test_block_timestamp_invalid(): diff --git a/pyteal/ast/box.py b/pyteal/ast/box.py index 33b9712e3..368c001e0 100644 --- a/pyteal/ast/box.py +++ b/pyteal/ast/box.py @@ -1,6 +1,6 @@ from typing import TYPE_CHECKING from pyteal.ast.maybe import MaybeValue -from pyteal.errors import verifyTealVersion +from pyteal.errors import verifyProgramVersion from pyteal.types import TealType, require_type from pyteal.ir import TealOp, Op, TealBlock @@ -27,7 +27,7 @@ def __init__(self, name: Expr, size: Expr) -> None: self.size = size def __teal__(self, options: "CompileOptions"): - verifyTealVersion( + verifyProgramVersion( minVersion=Op.box_create.min_version, version=options.version, msg=f"{Op.box_create} unavailable", @@ -62,7 +62,7 @@ def __init__(self, name: Expr) -> None: self.name = name def __teal__(self, options: "CompileOptions"): - verifyTealVersion( + verifyProgramVersion( minVersion=Op.box_del.min_version, version=options.version, msg=f"{Op.box_del} unavailable", @@ -101,7 +101,7 @@ def __init__(self, name: Expr, start: Expr, value: Expr) -> None: self.value = value def __teal__(self, options: "CompileOptions"): - verifyTealVersion( + verifyProgramVersion( minVersion=Op.box_replace.min_version, version=options.version, msg=f"{Op.box_replace} unavailable", @@ -143,7 +143,7 @@ def __init__(self, name: Expr, start: Expr, length: Expr) -> None: self.length = length def __teal__(self, options: "CompileOptions"): - verifyTealVersion( + verifyProgramVersion( minVersion=Op.box_extract.min_version, version=options.version, msg=f"{Op.box_extract} unavailable", @@ -204,7 +204,7 @@ def __init__(self, name: Expr, value: Expr) -> None: self.value = value def __teal__(self, options: "CompileOptions"): - verifyTealVersion( + verifyProgramVersion( minVersion=Op.box_put.min_version, version=options.version, msg=f"{Op.box_put} unavailable", diff --git a/pyteal/ast/box_test.py b/pyteal/ast/box_test.py index 87968ce2f..4000b3974 100644 --- a/pyteal/ast/box_test.py +++ b/pyteal/ast/box_test.py @@ -3,8 +3,8 @@ import pytest import pyteal as pt -teal7Options = pt.CompileOptions(version=7) -teal8Options = pt.CompileOptions(version=8) +avm7Options = pt.CompileOptions(version=7) +avm8Options = pt.CompileOptions(version=8) POSITIVE_TEST_CASES: list[Tuple[pt.Expr, pt.TealType]] = [ (pt.BoxCreate(pt.Bytes("box"), pt.Int(10)), pt.TealType.none), @@ -23,9 +23,9 @@ @pytest.mark.parametrize("test_case, test_case_type", POSITIVE_TEST_CASES) def test_compile_version_and_type(test_case, test_case_type): with pytest.raises(pt.TealInputError): - test_case.__teal__(teal7Options) + test_case.__teal__(avm7Options) - test_case.__teal__(teal8Options) + test_case.__teal__(avm8Options) assert test_case.type_of() == test_case_type assert not test_case.has_return() @@ -62,7 +62,7 @@ def test_box_create_compile(): pt.TealOp(expr, pt.Op.box_create), ] ) - actual, _ = expr.__teal__(teal8Options) + actual, _ = expr.__teal__(avm8Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -76,7 +76,7 @@ def test_box_delete_compile(): expected = pt.TealSimpleBlock( [pt.TealOp(name_arg, pt.Op.byte, '"eineName"'), pt.TealOp(expr, pt.Op.box_del)] ) - actual, _ = expr.__teal__(teal8Options) + actual, _ = expr.__teal__(avm8Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -97,7 +97,7 @@ def test_box_extract(): pt.TealOp(expr, pt.Op.box_extract), ] ) - actual, _ = expr.__teal__(teal8Options) + actual, _ = expr.__teal__(avm8Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -118,7 +118,7 @@ def test_box_replace(): pt.TealOp(expr, pt.Op.box_replace), ] ) - actual, _ = expr.__teal__(teal8Options) + actual, _ = expr.__teal__(avm8Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -137,7 +137,7 @@ def test_box_length(): pt.TealOp(expr.output_slots[0].store(), pt.Op.store, expr.output_slots[0]), ] ) - actual, _ = expr.__teal__(teal8Options) + actual, _ = expr.__teal__(avm8Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -157,7 +157,7 @@ def test_box_get(): pt.TealOp(expr.output_slots[0].store(), pt.Op.store, expr.output_slots[0]), ] ) - actual, _ = expr.__teal__(teal8Options) + actual, _ = expr.__teal__(avm8Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -177,7 +177,7 @@ def test_box_put(): pt.TealOp(expr, pt.Op.box_put), ] ) - actual, _ = expr.__teal__(teal8Options) + actual, _ = expr.__teal__(avm8Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) diff --git a/pyteal/ast/ecdsa.py b/pyteal/ast/ecdsa.py index 06e4e49db..b71e7ae46 100644 --- a/pyteal/ast/ecdsa.py +++ b/pyteal/ast/ecdsa.py @@ -2,7 +2,12 @@ from typing import Tuple, TYPE_CHECKING from pyteal.ast import Expr, MultiValue -from pyteal.errors import TealTypeError, verifyFieldVersion, verifyTealVersion +from pyteal.errors import ( + TealTypeError, + verifyFieldVersion, + verifyProgramVersion, + TealInputError, +) from pyteal.ir import Op, TealBlock, TealOp from pyteal.types import TealType, require_type @@ -52,10 +57,10 @@ def __init__( self.args = [data, sigA, sigB, pkX, pkY] def __teal__(self, options: "CompileOptions"): - verifyTealVersion( + verifyProgramVersion( self.op.min_version, options.version, - "TEAL version too low to use op {}".format(self.op), + "Program version too low to use op {}".format(self.op), ) verifyFieldVersion(self.curve.arg_name, self.curve.min_version, options.version) @@ -142,7 +147,7 @@ def EcdsaDecompress(curve: EcdsaCurve, compressed_pk: Expr) -> MultiValue: def EcdsaRecover( curve: EcdsaCurve, data: Expr, recovery_id: Expr, sigA: Expr, sigB: Expr ) -> MultiValue: - """Reover an ECDSA public key from a signature. + """Recover an ECDSA public key from a signature. All byte arguments must be big endian encoded. Args: curve: Enum representing the ECDSA curve used for the public key @@ -158,6 +163,9 @@ def EcdsaRecover( if not isinstance(curve, EcdsaCurve): raise TealTypeError(curve, EcdsaCurve) + if curve != EcdsaCurve.Secp256k1: + raise TealInputError("Recover only supports Secp256k1") + require_type(data, TealType.bytes) require_type(recovery_id, TealType.uint64) require_type(sigA, TealType.bytes) diff --git a/pyteal/ast/ecdsa_test.py b/pyteal/ast/ecdsa_test.py index 03cec2207..c6dc1bdb1 100644 --- a/pyteal/ast/ecdsa_test.py +++ b/pyteal/ast/ecdsa_test.py @@ -3,13 +3,13 @@ import pyteal as pt -teal4Options = pt.CompileOptions(version=4) -teal5Options = pt.CompileOptions(version=5) -teal7Options = pt.CompileOptions(version=7) +avm4Options = pt.CompileOptions(version=4) +avm5Options = pt.CompileOptions(version=5) +avm7Options = pt.CompileOptions(version=7) curve_options_map = { - pt.EcdsaCurve.Secp256k1: teal5Options, - pt.EcdsaCurve.Secp256r1: teal7Options, + pt.EcdsaCurve.Secp256k1: avm5Options, + pt.EcdsaCurve.Secp256r1: avm7Options, } @@ -54,45 +54,51 @@ def test_ecdsa_decompress(curve: pt.EcdsaCurve): @pytest.mark.parametrize("curve", [pt.EcdsaCurve.Secp256k1, pt.EcdsaCurve.Secp256r1]) def test_ecdsa_recover(curve: pt.EcdsaCurve): - args = [pt.Bytes("data"), pt.Int(1), pt.Bytes("sigA"), pt.Bytes("sigB")] - pubkey = pt.EcdsaRecover(curve, args[0], args[1], args[2], args[3]) - assert pubkey.type_of() == pt.TealType.none - - expected = pt.TealSimpleBlock( - [ - pt.TealOp(args[0], pt.Op.byte, '"data"'), - pt.TealOp(args[1], pt.Op.int, 1), - pt.TealOp(args[2], pt.Op.byte, '"sigA"'), - pt.TealOp(args[3], pt.Op.byte, '"sigB"'), - pt.TealOp(pubkey, pt.Op.ecdsa_pk_recover, curve.arg_name), - pt.TealOp( - pubkey.output_slots[1].store(), pt.Op.store, pubkey.output_slots[1] - ), - pt.TealOp( - pubkey.output_slots[0].store(), pt.Op.store, pubkey.output_slots[0] - ), - ] - ) + if curve != pt.EcdsaCurve.Secp256k1: + with pytest.raises(pt.TealInputError): + pt.EcdsaRecover( + curve, pt.Bytes("data"), pt.Int(1), pt.Bytes("sigA"), pt.Bytes("sigB") + ) + else: + args = [pt.Bytes("data"), pt.Int(1), pt.Bytes("sigA"), pt.Bytes("sigB")] + pubkey = pt.EcdsaRecover(curve, args[0], args[1], args[2], args[3]) + assert pubkey.type_of() == pt.TealType.none + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(args[0], pt.Op.byte, '"data"'), + pt.TealOp(args[1], pt.Op.int, 1), + pt.TealOp(args[2], pt.Op.byte, '"sigA"'), + pt.TealOp(args[3], pt.Op.byte, '"sigB"'), + pt.TealOp(pubkey, pt.Op.ecdsa_pk_recover, curve.arg_name), + pt.TealOp( + pubkey.output_slots[1].store(), pt.Op.store, pubkey.output_slots[1] + ), + pt.TealOp( + pubkey.output_slots[0].store(), pt.Op.store, pubkey.output_slots[0] + ), + ] + ) - actual, _ = pubkey.__teal__(curve_options_map[curve]) - actual.addIncoming() - actual = pt.TealBlock.NormalizeBlocks(actual) + actual, _ = pubkey.__teal__(curve_options_map[curve]) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) - with pt.TealComponent.Context.ignoreExprEquality(): - assert actual == expected + with pt.TealComponent.Context.ignoreExprEquality(): + assert actual == expected - # compile without errors this is necessary so assembly is also tested - pt.compileTeal( - pt.Seq(pubkey, pt.Approve()), pt.Mode.Application, version=curve.min_version - ) - - with pytest.raises(pt.TealInputError): + # compile without errors this is necessary so assembly is also tested pt.compileTeal( - pt.Seq(pubkey, pt.Approve()), - pt.Mode.Application, - version=curve.min_version - 1, + pt.Seq(pubkey, pt.Approve()), pt.Mode.Application, version=curve.min_version ) + with pytest.raises(pt.TealInputError): + pt.compileTeal( + pt.Seq(pubkey, pt.Approve()), + pt.Mode.Application, + version=curve.min_version - 1, + ) + @pytest.mark.parametrize("curve", [pt.EcdsaCurve.Secp256k1, pt.EcdsaCurve.Secp256r1]) def test_ecdsa_verify_basic(curve: pt.EcdsaCurve): @@ -186,8 +192,8 @@ def test_ecdsa_verify_compressed_pk(curve: pt.EcdsaCurve): ) -@pytest.mark.parametrize("curve", [pt.EcdsaCurve.Secp256k1, pt.EcdsaCurve.Secp256r1]) -def test_ecdsa_verify_recovered_pk(curve: pt.EcdsaCurve): +def test_ecdsa_verify_recovered_pk(): + curve = pt.EcdsaCurve.Secp256k1 args = [pt.Bytes("data"), pt.Int(1), pt.Bytes("sigA"), pt.Bytes("sigB")] pubkey = pt.EcdsaRecover(curve, args[0], args[1], args[2], args[3]) expr = pt.EcdsaVerify(curve, args[0], args[2], args[3], pubkey) @@ -243,14 +249,15 @@ def test_ecdsa_verify_recovered_pk(curve: pt.EcdsaCurve): @pytest.mark.parametrize("curve", [pt.EcdsaCurve.Secp256k1, pt.EcdsaCurve.Secp256r1]) def test_ecdsa_invalid(curve: pt.EcdsaCurve): - with pytest.raises(pt.TealTypeError): - args: List[Union[pt.Bytes, pt.Int]] = [ - pt.Bytes("data"), - pt.Bytes("1"), - pt.Bytes("sigA"), - pt.Bytes("sigB"), - ] - pt.EcdsaRecover(curve, args[0], args[1], args[2], args[3]) + if curve == pt.EcdsaCurve.Secp256k1: + with pytest.raises(pt.TealTypeError): + args: List[Union[pt.Bytes, pt.Int]] = [ + pt.Bytes("data"), + pt.Bytes("1"), + pt.Bytes("sigA"), + pt.Bytes("sigB"), + ] + pt.EcdsaRecover(curve, args[0], args[1], args[2], args[3]) with pytest.raises(pt.TealTypeError): pt.EcdsaDecompress(curve, pt.Int(1)) @@ -284,7 +291,7 @@ def test_ecdsa_invalid(curve: pt.EcdsaCurve): pubkey = (pt.Bytes("X"), pt.Bytes("Y")) expr = pt.EcdsaVerify(curve, args[0], args[1], args[2], pubkey) - expr.__teal__(teal4Options) + expr.__teal__(avm4Options) with pytest.raises(pt.TealTypeError): args = [pt.Bytes("data"), pt.Bytes("sigA"), pt.Bytes("sigB")] diff --git a/pyteal/ast/gaid.py b/pyteal/ast/gaid.py index d9faa6128..371aa86ac 100644 --- a/pyteal/ast/gaid.py +++ b/pyteal/ast/gaid.py @@ -2,7 +2,7 @@ from pyteal.types import TealType, require_type from pyteal.ir import TealOp, Op, TealBlock -from pyteal.errors import TealInputError, verifyTealVersion +from pyteal.errors import TealInputError, verifyProgramVersion from pyteal.config import MAX_GROUP_SIZE from pyteal.ast.expr import Expr from pyteal.ast.leafexpr import LeafExpr @@ -17,7 +17,7 @@ class GeneratedID(LeafExpr): def __init__(self, txnIndex: Union[int, Expr]) -> None: """Create an expression to extract the created ID from a transaction in the current group. - Requires TEAL version 4 or higher. This operation is only permitted in application mode. + Requires program version 4 or higher. This operation is only permitted in application mode. Args: txnIndex: The index of the transaction from which the created ID should be obtained. @@ -41,10 +41,10 @@ def __str__(self): return "(Gaid {})".format(self.txnIndex) def __teal__(self, options: "CompileOptions"): - verifyTealVersion( + verifyProgramVersion( Op.gaid.min_version, options.version, - "TEAL version too low to use Gaid expression", + "Program version too low to use Gaid expression", ) if type(self.txnIndex) is int: diff --git a/pyteal/ast/gaid_test.py b/pyteal/ast/gaid_test.py index 9da4fe254..51e896200 100644 --- a/pyteal/ast/gaid_test.py +++ b/pyteal/ast/gaid_test.py @@ -2,13 +2,13 @@ import pyteal as pt -teal3Options = pt.CompileOptions(version=3) -teal4Options = pt.CompileOptions(version=4) +avm3Options = pt.CompileOptions(version=3) +avm4Options = pt.CompileOptions(version=4) def test_gaid_teal_3(): with pytest.raises(pt.TealInputError): - pt.GeneratedID(0).__teal__(teal3Options) + pt.GeneratedID(0).__teal__(avm3Options) def test_gaid(): @@ -17,7 +17,7 @@ def test_gaid(): expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.gaid, 0)]) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) assert actual == expected @@ -32,7 +32,7 @@ def test_gaid_invalid(): def test_gaid_dynamic_teal_3(): with pytest.raises(pt.TealInputError): - pt.GeneratedID(pt.Int(0)).__teal__(teal3Options) + pt.GeneratedID(pt.Int(0)).__teal__(avm3Options) def test_gaid_dynamic(): @@ -44,7 +44,7 @@ def test_gaid_dynamic(): [pt.TealOp(arg, pt.Op.int, 0), pt.TealOp(expr, pt.Op.gaids)] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) diff --git a/pyteal/ast/gitxn.py b/pyteal/ast/gitxn.py index 486120e07..ad6c5aa06 100644 --- a/pyteal/ast/gitxn.py +++ b/pyteal/ast/gitxn.py @@ -2,7 +2,7 @@ from pyteal.config import MAX_GROUP_SIZE -from pyteal.errors import TealInputError, verifyFieldVersion, verifyTealVersion +from pyteal.errors import TealInputError, verifyFieldVersion, verifyProgramVersion from pyteal.ir import TealOp, Op, TealBlock from pyteal.ast.expr import Expr from pyteal.ast.txn import TxnExpr, TxnField, TxnObject, TxnaExpr @@ -33,10 +33,10 @@ def __str__(self): def __teal__(self, options: "CompileOptions"): verifyFieldVersion(self.field.arg_name, self.field.min_version, options.version) - verifyTealVersion( + verifyProgramVersion( Op.gitxn.min_version, options.version, - "TEAL version too low to use gitxn", + "Program version too low to use gitxn", ) op = TealOp(self, Op.gitxn, self.txnIndex, self.field.arg_name) return TealBlock.FromOp(options, op) @@ -71,10 +71,10 @@ def __teal__(self, options: "CompileOptions"): else: opToUse = Op.gitxnas - verifyTealVersion( + verifyProgramVersion( opToUse.min_version, options.version, - "TEAL version too low to use op {}".format(opToUse), + "Program version too low to use op {}".format(opToUse), ) if type(self.index) is int: diff --git a/pyteal/ast/gitxn_test.py b/pyteal/ast/gitxn_test.py index 44415df83..8501cc4e7 100644 --- a/pyteal/ast/gitxn_test.py +++ b/pyteal/ast/gitxn_test.py @@ -2,8 +2,8 @@ import pyteal as pt -teal5Options = pt.CompileOptions(version=5) -teal6Options = pt.CompileOptions(version=6) +avm5Options = pt.CompileOptions(version=5) +avm6Options = pt.CompileOptions(version=6) def test_gitxn_invalid(): @@ -33,7 +33,7 @@ def test_gitxn_expr_invalid(): pt.TealInputError, ), ( - lambda: pt.GitxnExpr(1, pt.TxnField.sender).__teal__(teal5Options), + lambda: pt.GitxnExpr(1, pt.TxnField.sender).__teal__(avm5Options), pt.TealInputError, ), ]: @@ -42,7 +42,7 @@ def test_gitxn_expr_invalid(): def test_gitxn_expr_valid(): - pt.GitxnExpr(1, pt.TxnField.sender).__teal__(teal6Options) + pt.GitxnExpr(1, pt.TxnField.sender).__teal__(avm6Options) def test_gitxna_expr_invalid(): @@ -63,7 +63,7 @@ def test_gitxna_expr_invalid(): ), ( lambda: pt.GitxnaExpr(0, pt.TxnField.application_args, 0).__teal__( - teal5Options + avm5Options ), pt.TealInputError, ), @@ -74,7 +74,7 @@ def test_gitxna_expr_invalid(): def test_gitxna_valid(): [ - e.__teal__(teal6Options) + e.__teal__(avm6Options) for e in [ pt.GitxnaExpr(0, pt.TxnField.application_args, 1), pt.GitxnaExpr(0, pt.TxnField.application_args, pt.Int(1)), diff --git a/pyteal/ast/gload.py b/pyteal/ast/gload.py index 0c4b86c55..6b85a4725 100644 --- a/pyteal/ast/gload.py +++ b/pyteal/ast/gload.py @@ -2,7 +2,7 @@ from pyteal.types import TealType, require_type from pyteal.ir import TealOp, Op, TealBlock -from pyteal.errors import TealInputError, verifyTealVersion +from pyteal.errors import TealInputError, verifyProgramVersion from pyteal.config import MAX_GROUP_SIZE, NUM_SLOTS from pyteal.ast.expr import Expr from pyteal.ast.leafexpr import LeafExpr @@ -17,7 +17,7 @@ class ImportScratchValue(LeafExpr): def __init__(self, txnIndex: Union[int, Expr], slotId: Union[int, Expr]) -> None: """Create an expression to load a scratch space slot from a transaction in the current group. - Requires TEAL version 4 or higher. This operation is only permitted in application mode. + Requires program version 4 or higher. This operation is only permitted in application mode. Args: txnIndex: The index of the transaction from which the created ID should be obtained. @@ -62,10 +62,10 @@ def __str__(self) -> str: def __teal__(self, options: "CompileOptions"): def local_version_check(opcode: TealOp): - verifyTealVersion( + verifyProgramVersion( opcode.op.min_version, options.version, - "TEAL version too low to use {} experssion".format(opcode.op.name), + "Program version too low to use {} experssion".format(opcode.op.name), ) # For txnIndex and slotId, there are only three scenario as following diff --git a/pyteal/ast/gload_test.py b/pyteal/ast/gload_test.py index fe182af6a..3be3390ea 100644 --- a/pyteal/ast/gload_test.py +++ b/pyteal/ast/gload_test.py @@ -2,25 +2,25 @@ import pyteal as pt -teal3Options = pt.CompileOptions(version=3) -teal4Options = pt.CompileOptions(version=4) -teal6Options = pt.CompileOptions(version=6) +avm3Options = pt.CompileOptions(version=3) +avm4Options = pt.CompileOptions(version=4) +avm6Options = pt.CompileOptions(version=6) def test_gload_teal_3(): with pytest.raises(pt.TealInputError): - pt.ImportScratchValue(0, 1).__teal__(teal3Options) + pt.ImportScratchValue(0, 1).__teal__(avm3Options) with pytest.raises(pt.TealInputError): - pt.ImportScratchValue(pt.Int(0), 1).__teal__(teal3Options) + pt.ImportScratchValue(pt.Int(0), 1).__teal__(avm3Options) with pytest.raises(pt.TealInputError): - pt.ImportScratchValue(pt.Int(0), pt.Int(1)).__teal__(teal3Options) + pt.ImportScratchValue(pt.Int(0), pt.Int(1)).__teal__(avm3Options) def test_gload_teal_4(): with pytest.raises(pt.TealInputError): - pt.ImportScratchValue(pt.Int(0), pt.Int(2)).__teal__(teal4Options) + pt.ImportScratchValue(pt.Int(0), pt.Int(2)).__teal__(avm4Options) def test_gload(): @@ -29,7 +29,7 @@ def test_gload(): expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.gload, 0, 1)]) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) assert actual == expected @@ -43,7 +43,7 @@ def test_gloads(): [pt.TealOp(arg, pt.Op.int, 1), pt.TealOp(expr, pt.Op.gloads, 0)] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -64,7 +64,7 @@ def test_gloadss(): ] ) - actual, _ = expr.__teal__(teal6Options) + actual, _ = expr.__teal__(avm6Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) diff --git a/pyteal/ast/global_.py b/pyteal/ast/global_.py index 9c311e84e..1ed4c313a 100644 --- a/pyteal/ast/global_.py +++ b/pyteal/ast/global_.py @@ -89,7 +89,7 @@ def group_size(cls) -> "Global": @classmethod def logic_sig_version(cls) -> "Global": - """Get the maximum supported TEAL version.""" + """Get the maximum supported program version.""" return cls(GlobalField.logic_sig_version) @classmethod @@ -115,14 +115,14 @@ def current_application_id(cls) -> "Global": def creator_address(cls) -> "Global": """Address of the creator of the current application. - Fails during Signature mode. Requires TEAL version 3 or higher.""" + Fails during Signature mode. Requires program version 3 or higher.""" return cls(GlobalField.creator_address) @classmethod def current_application_address(cls) -> "Global": """Get the address of that the current application controls. - Fails during Signature mode. Requires TEAL version 5 or higher.""" + Fails during Signature mode. Requires program version 5 or higher.""" return cls(GlobalField.current_app_address) @classmethod @@ -131,14 +131,14 @@ def group_id(cls) -> "Global": If the current transaction is not part of a group, this will return 32 zero bytes. - Requires TEAL version 5 or higher.""" + Requires program version 5 or higher.""" return cls(GlobalField.group_id) @classmethod def opcode_budget(cls) -> "Global": """Get the remaining opcode execution budget - Requires TEAL version 6 or higher.""" + Requires program version 6 or higher.""" return cls(GlobalField.opcode_budget) @classmethod @@ -147,7 +147,7 @@ def caller_app_id(cls) -> "Global": If not called from another app, this will return 0 - Requires TEAL version 6 or higher.""" + Requires program version 6 or higher.""" return cls(GlobalField.caller_app_id) @classmethod @@ -156,7 +156,7 @@ def caller_app_address(cls) -> "Global": If not called from another app, this will return the ZeroAddress - Requires TEAL version 6 or higher.""" + Requires program version 6 or higher.""" return cls(GlobalField.caller_app_address) diff --git a/pyteal/ast/global_test.py b/pyteal/ast/global_test.py index 4e72b3bd1..b06addefb 100644 --- a/pyteal/ast/global_test.py +++ b/pyteal/ast/global_test.py @@ -2,10 +2,10 @@ import pyteal as pt -teal2Options = pt.CompileOptions(version=2) -teal3Options = pt.CompileOptions(version=3) -teal5Options = pt.CompileOptions(version=5) -teal6Options = pt.CompileOptions(version=6) +avm2Options = pt.CompileOptions(version=2) +avm3Options = pt.CompileOptions(version=3) +avm5Options = pt.CompileOptions(version=5) +avm6Options = pt.CompileOptions(version=6) def test_global_min_txn_fee(): @@ -14,7 +14,7 @@ def test_global_min_txn_fee(): expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.global_, "MinTxnFee")]) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) assert actual == expected @@ -25,7 +25,7 @@ def test_global_min_balance(): expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.global_, "MinBalance")]) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) assert actual == expected @@ -36,7 +36,7 @@ def test_global_max_txn_life(): expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.global_, "MaxTxnLife")]) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) assert actual == expected @@ -47,7 +47,7 @@ def test_global_zero_address(): expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.global_, "ZeroAddress")]) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) assert actual == expected @@ -58,7 +58,7 @@ def test_global_group_size(): expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.global_, "GroupSize")]) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) assert actual == expected @@ -69,7 +69,7 @@ def test_global_logic_sig_version(): expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.global_, "LogicSigVersion")]) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) assert actual == expected @@ -80,7 +80,7 @@ def test_global_round(): expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.global_, "Round")]) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) assert actual == expected @@ -91,7 +91,7 @@ def test_global_latest_timestamp(): expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.global_, "LatestTimestamp")]) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) assert actual == expected @@ -104,7 +104,7 @@ def test_global_current_application_id(): [pt.TealOp(expr, pt.Op.global_, "CurrentApplicationID")] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) assert actual == expected @@ -115,12 +115,12 @@ def test_global_creator_address(): expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.global_, "CreatorAddress")]) - actual, _ = expr.__teal__(teal3Options) + actual, _ = expr.__teal__(avm3Options) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal2Options) + expr.__teal__(avm2Options) def test_global_current_application_address(): @@ -131,12 +131,12 @@ def test_global_current_application_address(): [pt.TealOp(expr, pt.Op.global_, "CurrentApplicationAddress")] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_global_group_id(): @@ -145,12 +145,12 @@ def test_global_group_id(): expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.global_, "GroupID")]) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal3Options) + expr.__teal__(avm3Options) def test_global_opcode_budget(): @@ -159,12 +159,12 @@ def test_global_opcode_budget(): expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.global_, "OpcodeBudget")]) - actual, _ = expr.__teal__(teal6Options) + actual, _ = expr.__teal__(avm6Options) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal5Options) + expr.__teal__(avm5Options) def test_global_caller_application_id(): @@ -175,12 +175,12 @@ def test_global_caller_application_id(): [pt.TealOp(expr, pt.Op.global_, "CallerApplicationID")] ) - actual, _ = expr.__teal__(teal6Options) + actual, _ = expr.__teal__(avm6Options) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal5Options) + expr.__teal__(avm5Options) def test_global_caller_app_address(): @@ -191,9 +191,9 @@ def test_global_caller_app_address(): [pt.TealOp(expr, pt.Op.global_, "CallerApplicationAddress")] ) - actual, _ = expr.__teal__(teal6Options) + actual, _ = expr.__teal__(avm6Options) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal5Options) + expr.__teal__(avm5Options) diff --git a/pyteal/ast/gtxn.py b/pyteal/ast/gtxn.py index 640f0605d..f1f59a95d 100644 --- a/pyteal/ast/gtxn.py +++ b/pyteal/ast/gtxn.py @@ -2,7 +2,7 @@ from pyteal.types import TealType, require_type from pyteal.ir import TealOp, Op, TealBlock -from pyteal.errors import TealInputError, verifyFieldVersion, verifyTealVersion +from pyteal.errors import TealInputError, verifyFieldVersion, verifyProgramVersion from pyteal.config import MAX_GROUP_SIZE from pyteal.ast.expr import Expr from pyteal.ast.txn import TxnField, TxnExpr, TxnaExpr, TxnObject @@ -35,16 +35,18 @@ def __teal__(self, options: "CompileOptions"): verifyFieldVersion(self.field.arg_name, self.field.min_version, options.version) if type(self.txnIndex) is int: - verifyTealVersion( - Op.gtxn.min_version, options.version, "TEAL version too low to use gtxn" + verifyProgramVersion( + Op.gtxn.min_version, + options.version, + "Program version too low to use gtxn", ) op = TealOp(self, Op.gtxn, self.txnIndex, self.field.arg_name) return TealBlock.FromOp(options, op) - verifyTealVersion( + verifyProgramVersion( Op.gtxns.min_version, options.version, - "TEAL version too low to index Gtxn with dynamic values", + "Program version too low to index Gtxn with dynamic values", ) op = TealOp(self, Op.gtxns, self.field.arg_name) @@ -83,10 +85,10 @@ def __teal__(self, options: "CompileOptions"): else: opToUse = Op.gtxnsas - verifyTealVersion( + verifyProgramVersion( opToUse.min_version, options.version, - "TEAL version too low to use op {}".format(opToUse), + "Program version too low to use op {}".format(opToUse), ) if type(self.txnIndex) is int: diff --git a/pyteal/ast/gtxn_test.py b/pyteal/ast/gtxn_test.py index 9f48e5317..a42135bec 100644 --- a/pyteal/ast/gtxn_test.py +++ b/pyteal/ast/gtxn_test.py @@ -2,7 +2,7 @@ import pyteal as pt -teal6Options = pt.CompileOptions(version=6) +avm6Options = pt.CompileOptions(version=6) def test_gtxn_invalid(): @@ -29,7 +29,7 @@ def test_gtxn_expr_invalid(): def test_gtxn_expr_valid(): [ - e.__teal__(teal6Options) + e.__teal__(avm6Options) for e in [ pt.GtxnExpr(1, pt.TxnField.sender), pt.GtxnExpr(pt.Int(1), pt.TxnField.sender), @@ -62,7 +62,7 @@ def test_gtxna_expr_invalid(): def test_gtxna_expr_valid(): [ - e.__teal__(teal6Options) + e.__teal__(avm6Options) for e in [ pt.GtxnaExpr(1, pt.TxnField.assets, 1), pt.GtxnaExpr(pt.Int(1), pt.TxnField.assets, pt.Int(1)), diff --git a/pyteal/ast/itxn.py b/pyteal/ast/itxn.py index af7704198..b2cfae2ad 100644 --- a/pyteal/ast/itxn.py +++ b/pyteal/ast/itxn.py @@ -2,7 +2,7 @@ from typing import Dict, TYPE_CHECKING, List, Union, cast from pyteal.types import TealType, require_type -from pyteal.errors import TealInputError, verifyTealVersion +from pyteal.errors import TealInputError, verifyProgramVersion from pyteal.ir import TealOp, Op, TealBlock from pyteal.ast.expr import Expr from pyteal.ast.txn import TxnField, TxnExprBuilder, TxnaExprBuilder, TxnObject @@ -32,10 +32,10 @@ def __str__(self): def __teal__(self, options: "CompileOptions"): op = self.action.value - verifyTealVersion( + verifyProgramVersion( op.min_version, options.version, - "TEAL version too low to create inner transactions", + "Program version too low to create inner transactions", ) return TealBlock.FromOp(options, TealOp(self, op)) @@ -58,10 +58,10 @@ def __str__(self): return "(InnerTxnSetField {} {})".format(self.field.arg_name, self.value) def __teal__(self, options: "CompileOptions"): - verifyTealVersion( + verifyProgramVersion( Op.itxn_field.min_version, options.version, - "TEAL version too low to create inner transactions", + "Program version too low to create inner transactions", ) return TealBlock.FromOp( @@ -81,7 +81,7 @@ class InnerTxnBuilder: Inner transactions are transactions which applications can dynamically create. Each inner transaction will appear as a transaction inside of the current transaction being executed. - As of TEAL version 5, only the transaction types :any:`TxnType.Payment`, :any:`TxnType.AssetTransfer`, + As of program version 5, only the transaction types :any:`TxnType.Payment`, :any:`TxnType.AssetTransfer`, :any:`TxnType.AssetConfig`, and :any:`TxnType.AssetFreeze` are allowed. Additionally, not all fields are allowed to be set. For example, it is not currently allowed to set the rekeyTo field of an inner transaction. @@ -96,7 +96,7 @@ def Begin(cls) -> Expr: overpaying in earlier transactions; :code:`FirstValid`/:code:`LastValid` to the values in the top-level transaction, and all other fields to zero values. - Requires TEAL version 5 or higher. This operation is only permitted in application mode. + Requires program version 5 or higher. This operation is only permitted in application mode. """ return InnerTxnActionExpr(InnerTxnAction.Begin) @@ -109,7 +109,7 @@ def Next(cls) -> Expr: overpaying in earlier transactions; :code:`FirstValid`/:code:`LastValid` to the values in the top-level transaction, and all other fields to zero values. - Requires TEAL version 6 or higher. This operation is only permitted in application mode. + Requires program version 6 or higher. This operation is only permitted in application mode. """ return InnerTxnActionExpr(InnerTxnAction.Next) @@ -130,7 +130,7 @@ def Submit(cls) -> Expr: If the inner transaction creates an asset, the new asset ID can be found by looking at :any:`InnerTxn.created_asset_id() `. - Requires TEAL version 5 or higher. This operation is only permitted in application mode. + Requires program version 5 or higher. This operation is only permitted in application mode. """ return InnerTxnActionExpr(InnerTxnAction.Submit) @@ -144,7 +144,7 @@ def SetField(cls, field: TxnField, value: Union[Expr, List[Expr]]) -> Expr: Note: For non-array field (e.g., note), setting it twice will overwrite the original value. While for array field (e.g., accounts), setting it multiple times will append the values. - Requires TEAL version 5 or higher. This operation is only permitted in application mode. + Requires program version 5 or higher. This operation is only permitted in application mode. Args: field: The field to set on the inner transaction. @@ -180,6 +180,27 @@ def SetField(cls, field: TxnField, value: Union[Expr, List[Expr]]) -> Expr: ] ) + @classmethod + def Execute(cls, fields: Dict[TxnField, Union[Expr, List[Expr]]]) -> Expr: + """Performs a single transaction given fields passed in. + + A convenience method that accepts fields to submit a single inner transaction, which is equivalent to: + + .. code-block:: python + + InnerTxnBuilder.Begin() + InnerTxnBuilder.SetFields(fields) + InnerTxnBuilder.End() + + Requires program version 5 or higher. This operation is only permitted in application mode. + + Args: + fields: A dictionary whose keys are fields to set and whose values are the value each + field should take. Each value must evaluate to a type that is compatible with the + field being set. + """ + return Seq(cls.Begin(), cls.SetFields(fields), cls.Submit()) + @classmethod def SetFields(cls, fields: Dict[TxnField, Union[Expr, List[Expr]]]) -> Expr: """Set multiple fields of the current inner transaction. @@ -190,7 +211,7 @@ def SetFields(cls, fields: Dict[TxnField, Union[Expr, List[Expr]]]) -> Expr: Note: For non-array field (e.g., note), setting it twice will overwrite the original value. While for array field (e.g., accounts), setting it multiple times will append the values. - Requires TEAL version 5 or higher. This operation is only permitted in application mode. + Requires program version 5 or higher. This operation is only permitted in application mode. Args: fields: A dictionary whose keys are fields to set and whose values are the value each diff --git a/pyteal/ast/itxn_test.py b/pyteal/ast/itxn_test.py index af9c3a79c..b4da1b7dc 100644 --- a/pyteal/ast/itxn_test.py +++ b/pyteal/ast/itxn_test.py @@ -3,9 +3,9 @@ import pyteal as pt from pyteal.types import types_match -teal4Options = pt.CompileOptions(version=4) -teal5Options = pt.CompileOptions(version=5) -teal6Options = pt.CompileOptions(version=6) +avm4Options = pt.CompileOptions(version=4) +avm5Options = pt.CompileOptions(version=5) +avm6Options = pt.CompileOptions(version=6) def test_InnerTxnBuilder_Begin(): @@ -15,12 +15,12 @@ def test_InnerTxnBuilder_Begin(): expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.itxn_begin)]) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal4Options) + expr.__teal__(avm4Options) def test_InnerTxnBuilder_Submit(): @@ -30,12 +30,12 @@ def test_InnerTxnBuilder_Submit(): expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.itxn_submit)]) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal4Options) + expr.__teal__(avm4Options) def test_InnerTxnBuilder_Next(): @@ -45,12 +45,12 @@ def test_InnerTxnBuilder_Next(): expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.itxn_next)]) - actual, _ = expr.__teal__(teal6Options) + actual, _ = expr.__teal__(avm6Options) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal5Options) + expr.__teal__(avm5Options) def test_InnerTxnBuilder_SetField(): @@ -82,47 +82,48 @@ def test_InnerTxnBuilder_SetField(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal4Options) - - -def test_InnerTxnBuilder_SetFields(): - cases = ( - ({}, pt.Seq()), - ( - {pt.TxnField.amount: pt.Int(5)}, - pt.InnerTxnBuilder.SetField(pt.TxnField.amount, pt.Int(5)), - ), - ( - { - pt.TxnField.type_enum: pt.TxnType.Payment, - pt.TxnField.close_remainder_to: pt.Txn.sender(), - }, - pt.Seq( - pt.InnerTxnBuilder.SetField(pt.TxnField.type_enum, pt.TxnType.Payment), - pt.InnerTxnBuilder.SetField( - pt.TxnField.close_remainder_to, pt.Txn.sender() - ), + expr.__teal__(avm4Options) + + +ITXN_FIELDS_CASES = [ + ({}, pt.Seq()), + ( + {pt.TxnField.amount: pt.Int(5)}, + pt.InnerTxnBuilder.SetField(pt.TxnField.amount, pt.Int(5)), + ), + ( + { + pt.TxnField.type_enum: pt.TxnType.Payment, + pt.TxnField.close_remainder_to: pt.Txn.sender(), + }, + pt.Seq( + pt.InnerTxnBuilder.SetField(pt.TxnField.type_enum, pt.TxnType.Payment), + pt.InnerTxnBuilder.SetField( + pt.TxnField.close_remainder_to, pt.Txn.sender() ), ), - ) + ), +] + - for fields, expectedExpr in cases: +def test_InnerTxnBuilder_SetFields(): + for fields, expectedExpr in ITXN_FIELDS_CASES: expr = pt.InnerTxnBuilder.SetFields(fields) assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expected, _ = expectedExpr.__teal__(teal5Options) + expected, _ = expectedExpr.__teal__(avm5Options) expected.addIncoming() expected = pt.TealBlock.NormalizeBlocks(expected) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -131,7 +132,30 @@ def test_InnerTxnBuilder_SetFields(): if len(fields) != 0: with pytest.raises(pt.TealInputError): - expr.__teal__(teal4Options) + expr.__teal__(avm4Options) + + +def test_InnerTxnBuilder_Execute(): + for fields, expectedExpr in ITXN_FIELDS_CASES: + expr = pt.InnerTxnBuilder.Execute(fields) + + expected, _ = pt.Seq( + pt.InnerTxnBuilder.Begin(), + expectedExpr, + pt.InnerTxnBuilder.Submit(), + ).__teal__(avm5Options) + expected.addIncoming() + expected = pt.TealBlock.NormalizeBlocks(expected) + + actual, _ = expr.__teal__(avm5Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + with pt.TealComponent.Context.ignoreExprEquality(): + assert actual == expected + + with pytest.raises(pt.TealInputError): + expr.__teal__(avm4Options) # txn_test.py performs additional testing diff --git a/pyteal/ast/jsonref.py b/pyteal/ast/jsonref.py index 91018d714..5173218c4 100644 --- a/pyteal/ast/jsonref.py +++ b/pyteal/ast/jsonref.py @@ -2,10 +2,9 @@ from enum import Enum from pyteal.types import TealType, require_type -from pyteal.errors import verifyFieldVersion, verifyTealVersion +from pyteal.errors import verifyFieldVersion, verifyProgramVersion from pyteal.ir import TealOp, Op, TealBlock from pyteal.ast.expr import Expr -from pyteal.ast.leafexpr import LeafExpr if TYPE_CHECKING: from pyteal.compiler import CompileOptions @@ -32,7 +31,7 @@ def type_of(self) -> TealType: JsonRefType.__module__ = "pyteal" -class JsonRef(LeafExpr): +class JsonRef(Expr): """An expression that accesses the value associated with a given key from a supported utf-8 encoded json object. The json object must satisfy a `particular specification `_. @@ -50,10 +49,10 @@ def __init__(self, type: JsonRefType, json_obj: Expr, key: Expr) -> None: self.key = key def __teal__(self, options: "CompileOptions"): - verifyTealVersion( + verifyProgramVersion( Op.json_ref.min_version, options.version, - "TEAL version too low to use op json_ref", + "Program version too low to use op json_ref", ) verifyFieldVersion(self.type.arg_name, self.type.min_version, options.version) @@ -62,13 +61,16 @@ def __teal__(self, options: "CompileOptions"): return TealBlock.FromOp(options, op, self.json_obj, self.key) def __str__(self): - return "(JsonRef {})".format(self.type.arg_name) + return "(JsonRef {} {} {})".format(self.type.arg_name, self.json_obj, self.key) def type_of(self): return self.type.type_of() + def has_return(self): + return False + @classmethod - def as_string(cls, json_obj: Expr, key: Expr) -> "JsonRef": + def as_string(cls, json_obj: Expr, key: Expr) -> Expr: """Access the value of a given key as a string. Refer to the `JsonRef` class documentation for valid json specification. @@ -80,7 +82,7 @@ def as_string(cls, json_obj: Expr, key: Expr) -> "JsonRef": return cls(JsonRefType.string, json_obj, key) @classmethod - def as_uint64(cls, json_obj: Expr, key: Expr) -> "JsonRef": + def as_uint64(cls, json_obj: Expr, key: Expr) -> Expr: """Access the value of a given key as a uint64. Refer to the `JsonRef` class documentation for valid json specification. diff --git a/pyteal/ast/jsonref_test.py b/pyteal/ast/jsonref_test.py index 356c74591..10733952f 100644 --- a/pyteal/ast/jsonref_test.py +++ b/pyteal/ast/jsonref_test.py @@ -2,8 +2,8 @@ import pyteal as pt -teal6Options = pt.CompileOptions(version=6) -teal7Options = pt.CompileOptions(version=7) +avm6Options = pt.CompileOptions(version=6) +avm7Options = pt.CompileOptions(version=7) def test_json_string(): @@ -19,14 +19,14 @@ def test_json_string(): ] ) - actual, _ = expr.__teal__(teal7Options) + actual, _ = expr.__teal__(avm7Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal6Options) + expr.__teal__(avm6Options) def test_json_uint64(): @@ -42,14 +42,14 @@ def test_json_uint64(): ] ) - actual, _ = expr.__teal__(teal7Options) + actual, _ = expr.__teal__(avm7Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal6Options) + expr.__teal__(avm6Options) def test_json_object(): @@ -65,14 +65,14 @@ def test_json_object(): ] ) - actual, _ = expr.__teal__(teal7Options) + actual, _ = expr.__teal__(avm7Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal6Options) + expr.__teal__(avm6Options) def test_json_ref_invalid(): diff --git a/pyteal/ast/maybe.py b/pyteal/ast/maybe.py index ebe3d03e7..4d863e6ff 100644 --- a/pyteal/ast/maybe.py +++ b/pyteal/ast/maybe.py @@ -1,6 +1,6 @@ from typing import List, Union, TYPE_CHECKING -from pyteal.errors import verifyTealVersion +from pyteal.errors import verifyProgramVersion from pyteal.types import TealType from pyteal.ir import Op @@ -33,7 +33,7 @@ def __init__( """ def local_version_check(option: "CompileOptions"): - verifyTealVersion( + verifyProgramVersion( minVersion=op.min_version, version=option.version, msg=f"{op.value} unavailable", diff --git a/pyteal/ast/opup.py b/pyteal/ast/opup.py index 45a84d37d..af862b10b 100644 --- a/pyteal/ast/opup.py +++ b/pyteal/ast/opup.py @@ -29,14 +29,14 @@ class OpUpMode(Enum): OnCall = 1 -ON_CALL_APP = Bytes("base16", "068101") # v6 teal program "int 1" +ON_CALL_APP = Bytes("base16", "068101") # v6 program "int 1" MIN_TXN_FEE = Int(1000) class OpUp: """Utility for increasing opcode budget during app execution. - Requires TEAL version 6 or higher. + Requires program version 6 or higher. Example: .. code-block:: python diff --git a/pyteal/ast/replace.py b/pyteal/ast/replace.py index 2b7968978..fa625df8a 100644 --- a/pyteal/ast/replace.py +++ b/pyteal/ast/replace.py @@ -1,7 +1,7 @@ from typing import cast, TYPE_CHECKING from pyteal.types import TealType, require_type -from pyteal.errors import verifyTealVersion +from pyteal.errors import verifyProgramVersion from pyteal.ir import TealOp, Op, TealBlock from pyteal.ast.expr import Expr from pyteal.ast.int import Int @@ -46,10 +46,10 @@ def __teal__(self, options: "CompileOptions"): op = self.__get_op(options) - verifyTealVersion( + verifyProgramVersion( op.min_version, options.version, - "TEAL version too low to use op {}".format(op), + "Program version too low to use op {}".format(op), ) s = cast(Int, self.start).value @@ -76,7 +76,7 @@ def Replace(original: Expr, start: Expr, replacement: Expr) -> Expr: """ Replace a portion of original bytes with new bytes at a given starting point. - Requires TEAL version 7 or higher. + Requires program version 7 or higher. Args: original: The value containing the original bytes. Must evaluate to bytes. diff --git a/pyteal/ast/replace_test.py b/pyteal/ast/replace_test.py index b72a5d879..5f7076ed0 100644 --- a/pyteal/ast/replace_test.py +++ b/pyteal/ast/replace_test.py @@ -2,8 +2,8 @@ import pyteal as pt -teal6Options = pt.CompileOptions(version=6) -teal7Options = pt.CompileOptions(version=7) +avm6Options = pt.CompileOptions(version=6) +avm7Options = pt.CompileOptions(version=7) def test_replace_immediate(): @@ -19,14 +19,14 @@ def test_replace_immediate(): ] ) - actual, _ = expr.__teal__(teal7Options) + actual, _ = expr.__teal__(avm7Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal6Options) + expr.__teal__(avm6Options) def test_replace_stack_int(): @@ -44,14 +44,14 @@ def test_replace_stack_int(): ] ) - actual, _ = expr.__teal__(teal7Options) + actual, _ = expr.__teal__(avm7Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal6Options) + expr.__teal__(avm6Options) # Mirrors `test_replace_stack_int`, but attempts replacement with start != pt.Int. @@ -73,7 +73,7 @@ def test_replace_stack_not_int(): ] ) - actual, _ = expr.__teal__(teal7Options) + actual, _ = expr.__teal__(avm7Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -81,7 +81,7 @@ def test_replace_stack_not_int(): assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal6Options) + expr.__teal__(avm6Options) def test_replace_invalid(): diff --git a/pyteal/ast/return_.py b/pyteal/ast/return_.py index be27155fe..0540a4ff2 100644 --- a/pyteal/ast/return_.py +++ b/pyteal/ast/return_.py @@ -1,7 +1,7 @@ from typing import TYPE_CHECKING from pyteal.types import TealType, require_type, types_match -from pyteal.errors import verifyTealVersion, TealCompileError +from pyteal.errors import verifyProgramVersion, TealCompileError from pyteal.ir import TealOp, Op, TealBlock from pyteal.ast.expr import Expr from pyteal.ast.int import Int @@ -31,10 +31,10 @@ def __init__(self, value: Expr = None) -> None: def __teal__(self, options: "CompileOptions"): if options.currentSubroutine is not None: - verifyTealVersion( + verifyProgramVersion( Op.retsub.min_version, options.version, - "TEAL version too low to use subroutines", + "Program version too low to use subroutines", ) returnType = options.currentSubroutine.returnType if returnType == TealType.none: diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 657134bee..026f1c27d 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -2,7 +2,7 @@ from types import MappingProxyType from typing import Callable, List, Optional, Type, Union, TYPE_CHECKING -from pyteal.errors import TealInputError, verifyTealVersion +from pyteal.errors import TealInputError, verifyProgramVersion from pyteal.ir import TealOp, Op, TealBlock from pyteal.types import TealType @@ -263,10 +263,10 @@ def __teal__(self, options: "CompileOptions"): 2. (by-reference) In the case of a by-reference argument of type ScratchVar, its SLOT INDEX is put on the stack and will be stored in a local DynamicScratchVar for subroutine evaluation """ - verifyTealVersion( + verifyProgramVersion( Op.callsub.min_version, options.version, - "TEAL version too low to use SubroutineCall expression", + "Program version too low to use SubroutineCall expression", ) def handle_arg(arg): diff --git a/pyteal/ast/substring.py b/pyteal/ast/substring.py index 6febf69dc..fe4ce4809 100644 --- a/pyteal/ast/substring.py +++ b/pyteal/ast/substring.py @@ -1,7 +1,7 @@ from typing import cast, TYPE_CHECKING from pyteal.types import TealType, require_type -from pyteal.errors import TealCompileError, verifyTealVersion +from pyteal.errors import TealCompileError, verifyProgramVersion from pyteal.ir import TealOp, Op, TealBlock, TealSimpleBlock from pyteal.ast.expr import Expr from pyteal.ast.int import Int @@ -60,10 +60,10 @@ def __teal__(self, options: "CompileOptions"): op = self.__get_op(options) - verifyTealVersion( + verifyProgramVersion( op.min_version, options.version, - "TEAL version too low to use op {}".format(op), + "Program version too low to use op {}".format(op), ) start, end = cast(Int, self.startArg).value, cast(Int, self.endArg).value @@ -141,10 +141,10 @@ def __teal__(self, options: "CompileOptions"): op = self.__get_op(options) - verifyTealVersion( + verifyProgramVersion( op.min_version, options.version, - "TEAL version too low to use op {}".format(op), + "Program version too low to use op {}".format(op), ) s, l = cast(Int, self.startArg).value, cast(Int, self.lenArg).value @@ -199,10 +199,10 @@ def __get_op(self, options: "CompileOptions"): def __teal__(self, options: "CompileOptions"): op = self.__get_op(options) - verifyTealVersion( + verifyProgramVersion( op.min_version, options.version, - "TEAL version too low to use op {}".format(op), + "Program version too low to use op {}".format(op), ) if op == Op.extract: @@ -248,7 +248,7 @@ def Substring(string: Expr, start: Expr, end: Expr) -> Expr: This expression is similar to :any:`Extract`, except this expression uses start and end indexes, while :code:`Extract` uses a start index and length. - Requires TEAL version 2 or higher. + Requires program version 2 or higher. Args: string: The byte string. @@ -273,7 +273,7 @@ def Extract(string: Expr, start: Expr, length: Expr) -> Expr: This expression is similar to :any:`Substring`, except this expression uses a start index and length, while :code:`Substring` uses start and end indexes. - Requires TEAL version 5 or higher. + Requires program version 5 or higher. Args: string: The byte string. @@ -296,7 +296,7 @@ def Suffix(string: Expr, start: Expr) -> Expr: This expression is similar to :any:`Substring` and :any:`Extract`, except this expression only uses a start index. - Requires TEAL version 5 or higher. + Requires program version 5 or higher. Args: string: The byte string. diff --git a/pyteal/ast/substring_test.py b/pyteal/ast/substring_test.py index ae5bcace2..3e10c5f51 100644 --- a/pyteal/ast/substring_test.py +++ b/pyteal/ast/substring_test.py @@ -2,10 +2,10 @@ import pyteal as pt -teal2Options = pt.CompileOptions(version=2) -teal3Options = pt.CompileOptions(version=3) -teal4Options = pt.CompileOptions(version=4) -teal5Options = pt.CompileOptions(version=5) +avm2Options = pt.CompileOptions(version=2) +avm3Options = pt.CompileOptions(version=3) +avm4Options = pt.CompileOptions(version=4) +avm5Options = pt.CompileOptions(version=5) def test_substring_immediate_v2(): @@ -20,7 +20,7 @@ def test_substring_immediate_v2(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -39,7 +39,7 @@ def test_substring_immediate_v5(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -59,7 +59,7 @@ def test_substring_to_extract(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -82,7 +82,7 @@ def test_substring_stack_v2(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -105,7 +105,7 @@ def test_substring_stack_v5(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -126,7 +126,7 @@ def test_zero_length_substring_immediate(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -145,7 +145,7 @@ def test_substring_invalid(): pt.Substring(pt.Bytes("my string"), pt.Int(0), pt.Txn.sender()) with pytest.raises(Exception): - pt.Substring(pt.Bytes("my string"), pt.Int(1), pt.Int(0)).__teal__(teal5Options) + pt.Substring(pt.Bytes("my string"), pt.Int(1), pt.Int(0)).__teal__(avm5Options) def test_extract_immediate(): @@ -160,14 +160,14 @@ def test_extract_immediate(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal4Options) + expr.__teal__(avm4Options) def test_extract_zero(): @@ -184,14 +184,14 @@ def test_extract_zero(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal4Options) + expr.__teal__(avm4Options) def test_extract_stack(): @@ -209,14 +209,14 @@ def test_extract_stack(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal4Options) + expr.__teal__(avm4Options) def test_extract_invalid(): @@ -242,7 +242,7 @@ def test_suffix_immediate(): ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -265,7 +265,7 @@ def test_suffix_stack(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -301,7 +301,7 @@ def generate_expr() -> pt.Expr: ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -310,7 +310,7 @@ def generate_expr() -> pt.Expr: if op == pt.Op.extract3: with pytest.raises(pt.TealInputError): - expr.__teal__(teal4Options) + expr.__teal__(avm4Options) @pytest.mark.parametrize("op", [pt.Op.extract3, pt.Op.substring3]) @@ -342,7 +342,7 @@ def generate_expr() -> pt.Expr: ] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -351,7 +351,7 @@ def generate_expr() -> pt.Expr: if op == pt.Op.extract3: with pytest.raises(pt.TealInputError): - expr.__teal__(teal4Options) + expr.__teal__(avm4Options) def test_suffix_invalid(): diff --git a/pyteal/ast/ternaryexpr.py b/pyteal/ast/ternaryexpr.py index ad2c36bd6..a8a526cff 100644 --- a/pyteal/ast/ternaryexpr.py +++ b/pyteal/ast/ternaryexpr.py @@ -1,7 +1,7 @@ from typing import Tuple, TYPE_CHECKING from pyteal.types import TealType, require_type -from pyteal.errors import verifyTealVersion +from pyteal.errors import verifyProgramVersion from pyteal.ir import TealOp, Op, TealBlock from pyteal.ast.expr import Expr @@ -33,10 +33,10 @@ def __init__( self.thirdArg = thirdArg def __teal__(self, options: "CompileOptions"): - verifyTealVersion( + verifyProgramVersion( self.op.min_version, options.version, - "TEAL version too low to use op {}".format(self.op), + "Program version too low to use op {}".format(self.op), ) return TealBlock.FromOp( @@ -106,7 +106,7 @@ def SetBit(value: Expr, index: Expr, newBitValue: Expr) -> TernaryExpr: * For byte strings, bit indexing begins at the first byte. For example, :code:`SetBit(Bytes("base16", "0x00"), Int(7), Int(1))` yields the byte string 0x01. Any integer less than 8*Len(value) is a valid index. - Requires TEAL version 3 or higher. + Requires program version 3 or higher. Args: value: The value containing bits. Can evaluate to any type. @@ -129,7 +129,7 @@ def SetByte(value: Expr, index: Expr, newByteValue: Expr) -> TernaryExpr: Similar to SetBit, indexing begins at the first byte. For example, :code:`SetByte(Bytes("base16", "0x000000"), Int(0), Int(255))` yields the byte string 0xff0000. - Requires TEAL version 3 or higher. + Requires program version 3 or higher. Args: value: The value containing the bytes. Must evaluate to bytes. @@ -150,7 +150,7 @@ def Divw(hi: Expr, lo: Expr, y: Expr) -> TernaryExpr: """ Performs wide division by interpreting `hi` and `lo` as a uint128 value. - Requires TEAL version 6 or higher. + Requires program version 6 or higher. Args: hi: Quotient's high 64 bits. Must evaluate to uint64. diff --git a/pyteal/ast/ternaryexpr_test.py b/pyteal/ast/ternaryexpr_test.py index 51a01958a..0530ec6b6 100644 --- a/pyteal/ast/ternaryexpr_test.py +++ b/pyteal/ast/ternaryexpr_test.py @@ -2,12 +2,12 @@ import pyteal as pt -teal2Options = pt.CompileOptions(version=2) -teal3Options = pt.CompileOptions(version=3) -teal4Options = pt.CompileOptions(version=4) -teal5Options = pt.CompileOptions(version=5) -teal6Options = pt.CompileOptions(version=6) -teal7Options = pt.CompileOptions(version=7) +avm2Options = pt.CompileOptions(version=2) +avm3Options = pt.CompileOptions(version=3) +avm4Options = pt.CompileOptions(version=4) +avm5Options = pt.CompileOptions(version=5) +avm6Options = pt.CompileOptions(version=6) +avm7Options = pt.CompileOptions(version=7) def test_ed25519verify(): @@ -24,7 +24,7 @@ def test_ed25519verify(): ] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -56,14 +56,14 @@ def test_ed25519verify_bare(): ] ) - actual, _ = expr.__teal__(teal7Options) + actual, _ = expr.__teal__(avm7Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal6Options) + expr.__teal__(avm6Options) def test_ed25519verify_bare_invalid(): @@ -91,14 +91,14 @@ def test_set_bit_int(): ] ) - actual, _ = expr.__teal__(teal3Options) + actual, _ = expr.__teal__(avm3Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal2Options) + expr.__teal__(avm2Options) def test_set_bit_bytes(): @@ -115,14 +115,14 @@ def test_set_bit_bytes(): ] ) - actual, _ = expr.__teal__(teal3Options) + actual, _ = expr.__teal__(avm3Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal2Options) + expr.__teal__(avm2Options) def test_set_bit_invalid(): @@ -153,14 +153,14 @@ def test_set_byte(): ] ) - actual, _ = expr.__teal__(teal3Options) + actual, _ = expr.__teal__(avm3Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal2Options) + expr.__teal__(avm2Options) def test_set_byte_invalid(): @@ -188,7 +188,7 @@ def test_divw(): ] ) - actual, _ = expr.__teal__(teal6Options) + actual, _ = expr.__teal__(avm6Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) diff --git a/pyteal/ast/txn.py b/pyteal/ast/txn.py index a4d011ddf..d8de1bd84 100644 --- a/pyteal/ast/txn.py +++ b/pyteal/ast/txn.py @@ -6,7 +6,7 @@ TealInputError, TealCompileError, verifyFieldVersion, - verifyTealVersion, + verifyProgramVersion, ) from pyteal.ir import TealOp, Op, TealBlock from pyteal.ast.leafexpr import LeafExpr @@ -159,10 +159,10 @@ def __str__(self): def __teal__(self, options: "CompileOptions"): verifyFieldVersion(self.field.arg_name, self.field.min_version, options.version) - verifyTealVersion( + verifyProgramVersion( self.op.min_version, options.version, - "TEAL version too low to use op {}".format(self.op), + "Program version too low to use op {}".format(self.op), ) op = TealOp(self, self.op, self.field.arg_name) @@ -216,10 +216,10 @@ def __teal__(self, options: "CompileOptions"): if opToUse is None: raise TealCompileError("Dynamic array indexing not supported", self) - verifyTealVersion( + verifyProgramVersion( opToUse.min_version, options.version, - "TEAL version too low to use op {}".format(opToUse), + "Program version too low to use op {}".format(opToUse), ) if type(self.index) is int: @@ -426,7 +426,7 @@ def nonparticipation(self) -> TxnExpr: For more information, see https://developer.algorand.org/docs/reference/transactions/#nonparticipation - Requires TEAL version 5 or higher. + Requires program version 5 or higher. """ return self.makeTxnExpr(TxnField.nonparticipation) @@ -643,7 +643,7 @@ def created_asset_id(self) -> TxnExpr: Only set when :any:`type_enum()` is :any:`TxnType.AssetConfig` and this is an asset creation transaction. - Requires TEAL version 5 or higher. + Requires program version 5 or higher. * v5 - Only works on inner transactions. * >= v6 - Works on top-level and inner transactions. @@ -679,7 +679,7 @@ def global_num_uints(self) -> TxnExpr: Only set when :any:`type_enum()` is :any:`TxnType.ApplicationCall` and this is an app creation call. - Requires TEAL version 3 or higher. + Requires program version 3 or higher. """ return self.makeTxnExpr(TxnField.global_num_uints) @@ -688,7 +688,7 @@ def global_num_byte_slices(self) -> TxnExpr: Only set when :any:`type_enum()` is :any:`TxnType.ApplicationCall` and this is an app creation call. - Requires TEAL version 3 or higher. + Requires program version 3 or higher. """ return self.makeTxnExpr(TxnField.global_num_byte_slices) @@ -697,7 +697,7 @@ def local_num_uints(self) -> TxnExpr: Only set when :any:`type_enum()` is :any:`TxnType.ApplicationCall` and this is an app creation call. - Requires TEAL version 3 or higher. + Requires program version 3 or higher. """ return self.makeTxnExpr(TxnField.local_num_uints) @@ -706,7 +706,7 @@ def local_num_byte_slices(self) -> TxnExpr: Only set when :any:`type_enum()` is :any:`TxnType.ApplicationCall` and this is an app creation call. - Requires TEAL version 3 or higher. + Requires program version 3 or higher. """ return self.makeTxnExpr(TxnField.local_num_byte_slices) @@ -717,7 +717,7 @@ def extra_program_pages(self) -> TxnExpr: Only set when :any:`type_enum()` is :any:`TxnType.ApplicationCall` and this is an app creation call. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. """ return self.makeTxnExpr(TxnField.extra_program_pages) @@ -726,7 +726,7 @@ def created_application_id(self) -> TxnExpr: Only set when :any:`type_enum()` is :any:`TxnType.ApplicationCall` and this is an app creation call. - Requires TEAL version 5 or higher. + Requires program version 5 or higher. * v5 - Only works on inner transactions. * >= v6 - Works on top-level and inner transactions. @@ -740,31 +740,17 @@ def last_log(self) -> TxnExpr: Only set when :any:`type_enum()` is :any:`TxnType.ApplicationCall`. - Requires TEAL version 6 or higher. + Requires program version 6 or higher. """ return self.makeTxnExpr(TxnField.last_log) def state_proof_pk(self) -> TxnExpr: """Get the state proof public key commitment from a transaction. - Requires TEAL version 6 or higher. + Requires program version 6 or higher. """ return self.makeTxnExpr(TxnField.state_proof_pk) - def num_approval_program_pages(self) -> TxnExpr: - """Get the number of pages in the approval program. - - Requires TEAL version 7 or higher. - """ - return self.makeTxnExpr(TxnField.num_approval_program_pages) - - def num_clear_state_program_pages(self) -> TxnExpr: - """Get the number of pages in the clear state program. - - Requires TEAL version 7 or higher. - """ - return self.makeTxnExpr(TxnField.num_clear_state_program_pages) - @property def application_args(self) -> TxnArray: """Application call arguments array. @@ -787,7 +773,7 @@ def assets(self) -> TxnArray: :type: TxnArray - Requires TEAL version 3 or higher. + Requires program version 3 or higher. """ return TxnArray(self, TxnField.assets, TxnField.num_assets) @@ -797,7 +783,7 @@ def applications(self) -> TxnArray: :type: TxnArray - Requires TEAL version 3 or higher. + Requires program version 3 or higher. """ return TxnArray(self, TxnField.applications, TxnField.num_applications) @@ -807,7 +793,7 @@ def logs(self) -> TxnArray: :type: TxnArray - Requires TEAL version 5 or higher. + Requires program version 5 or higher. * v5 - Only works on inner transactions. * >= v6 - Works on top-level and inner transactions. @@ -820,7 +806,7 @@ def approval_program_pages(self) -> TxnArray: :type: TxnArray - Requires TEAL version 7 or higher. + Requires program version 7 or higher. """ return TxnArray( self, TxnField.approval_program_pages, TxnField.num_approval_program_pages @@ -832,7 +818,7 @@ def clear_state_program_pages(self) -> TxnArray: :type: TxnArray - Requires TEAL version 7 or higher. + Requires program version 7 or higher. """ return TxnArray( self, diff --git a/pyteal/ast/txn_test.py b/pyteal/ast/txn_test.py index d169b459b..a53273376 100644 --- a/pyteal/ast/txn_test.py +++ b/pyteal/ast/txn_test.py @@ -59,8 +59,6 @@ pt.TxnField.created_application_id: lambda txn: txn.created_application_id(), pt.TxnField.last_log: lambda txn: txn.last_log(), pt.TxnField.state_proof_pk: lambda txn: txn.state_proof_pk(), - pt.TxnField.num_approval_program_pages: lambda txn: txn.num_approval_program_pages(), - pt.TxnField.num_clear_state_program_pages: lambda txn: txn.num_clear_state_program_pages(), } arrayFieldToProperty: Dict[pt.TxnField, Callable[[pt.TxnObject], pt.TxnArray]] = { diff --git a/pyteal/ast/unaryexpr.py b/pyteal/ast/unaryexpr.py index 1fad9903b..9d532a2b1 100644 --- a/pyteal/ast/unaryexpr.py +++ b/pyteal/ast/unaryexpr.py @@ -1,7 +1,7 @@ from typing import TYPE_CHECKING from pyteal.types import TealType, require_type -from pyteal.errors import verifyTealVersion +from pyteal.errors import verifyProgramVersion from pyteal.ir import TealOp, Op, TealBlock from pyteal.ast.expr import Expr @@ -22,10 +22,10 @@ def __init__( self.arg = arg def __teal__(self, options: "CompileOptions"): - verifyTealVersion( + verifyProgramVersion( self.op.min_version, options.version, - "TEAL version too low to use op {}".format(self.op), + "Program version too low to use op {}".format(self.op), ) return TealBlock.FromOp(options, TealOp(self, self.op), self.arg) @@ -65,7 +65,7 @@ def BitLen(arg: Expr) -> UnaryExpr: If the argument is a byte array, it is interpreted as a big-endian unsigned integer. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. """ return UnaryExpr(Op.bitlen, TealType.anytype, TealType.uint64, arg) @@ -111,7 +111,7 @@ def Sqrt(arg: Expr) -> UnaryExpr: This will return the largest integer X such that X^2 <= arg. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. """ return UnaryExpr(Op.sqrt, TealType.uint64, TealType.uint64, arg) @@ -142,7 +142,7 @@ def MinBalance(account: Expr) -> UnaryExpr: must be evaluated to uint64 (or, since v4, an account address that appears in Txn.Accounts or is Txn.Sender). - Requires TEAL version 3 or higher. This operation is only permitted in application mode. + Requires program version 3 or higher. This operation is only permitted in application mode. """ return UnaryExpr(Op.min_balance, TealType.anytype, TealType.uint64, account) @@ -153,7 +153,7 @@ def BytesNot(arg: Expr) -> UnaryExpr: Produces ~arg. Argument must not exceed 64 bytes. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. """ return UnaryExpr(Op.b_not, TealType.bytes, TealType.bytes, arg) @@ -163,7 +163,7 @@ def BytesSqrt(arg: Expr) -> UnaryExpr: This will return the largest integer X such that X^2 <= arg. - Requires TEAL version 6 or higher. + Requires program version 6 or higher. """ return UnaryExpr(Op.bsqrt, TealType.bytes, TealType.bytes, arg) @@ -173,7 +173,7 @@ def BytesZero(arg: Expr) -> UnaryExpr: Argument must evaluate to uint64. - Requires TEAL version 4 or higher. + Requires program version 4 or higher. """ return UnaryExpr(Op.bzero, TealType.uint64, TealType.bytes, arg) @@ -181,12 +181,12 @@ def BytesZero(arg: Expr) -> UnaryExpr: def Log(message: Expr) -> UnaryExpr: """Write a message to log state of the current application. - This will fail if called more than :code:`MaxLogCalls` times in a program (32 as of TEAL v5), or + This will fail if called more than :code:`MaxLogCalls` times in a program (32 as of AVM v5), or if the sum of the lengths of all logged messages in a program exceeds 1024 bytes. Args: message: The message to write. Must evaluate to bytes. - Requires TEAL version 5 or higher. + Requires program version 5 or higher. """ return UnaryExpr(Op.log, TealType.bytes, TealType.none, message) diff --git a/pyteal/ast/unaryexpr_test.py b/pyteal/ast/unaryexpr_test.py index 5a096fcbd..589286b75 100644 --- a/pyteal/ast/unaryexpr_test.py +++ b/pyteal/ast/unaryexpr_test.py @@ -2,12 +2,12 @@ import pyteal as pt -teal2Options = pt.CompileOptions(version=2) -teal3Options = pt.CompileOptions(version=3) -teal4Options = pt.CompileOptions(version=4) -teal5Options = pt.CompileOptions(version=5) -teal6Options = pt.CompileOptions(version=6) -teal7Options = pt.CompileOptions(version=7) +avm2Options = pt.CompileOptions(version=2) +avm3Options = pt.CompileOptions(version=3) +avm4Options = pt.CompileOptions(version=4) +avm5Options = pt.CompileOptions(version=5) +avm6Options = pt.CompileOptions(version=6) +avm7Options = pt.CompileOptions(version=7) def test_btoi(): @@ -19,7 +19,7 @@ def test_btoi(): [pt.TealOp(arg, pt.Op.arg, 1), pt.TealOp(expr, pt.Op.btoi)] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -40,7 +40,7 @@ def test_itob(): [pt.TealOp(arg, pt.Op.int, 1), pt.TealOp(expr, pt.Op.itob)] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -61,7 +61,7 @@ def test_len(): [pt.TealOp(arg, pt.Op.txn, "Receiver"), pt.TealOp(expr, pt.Op.len)] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -82,7 +82,7 @@ def test_bitlen_int(): [pt.TealOp(arg, pt.Op.int, 7), pt.TealOp(expr, pt.Op.bitlen)] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -98,7 +98,7 @@ def test_bitlen_bytes(): [pt.TealOp(arg, pt.Op.txn, "Receiver"), pt.TealOp(expr, pt.Op.bitlen)] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -114,7 +114,7 @@ def test_sha256(): [pt.TealOp(arg, pt.Op.arg, 0), pt.TealOp(expr, pt.Op.sha256)] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -135,7 +135,7 @@ def test_sha512_256(): [pt.TealOp(arg, pt.Op.arg, 0), pt.TealOp(expr, pt.Op.sha512_256)] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -156,7 +156,7 @@ def test_sha3_256(): [pt.TealOp(arg, pt.Op.arg, 0), pt.TealOp(expr, pt.Op.sha3_256)] ) - actual, _ = expr.__teal__(teal7Options) + actual, _ = expr.__teal__(avm7Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -177,7 +177,7 @@ def test_keccak256(): [pt.TealOp(arg, pt.Op.arg, 0), pt.TealOp(expr, pt.Op.keccak256)] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -198,7 +198,7 @@ def test_not(): [pt.TealOp(arg, pt.Op.int, 1), pt.TealOp(expr, pt.Op.logic_not)] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -219,7 +219,7 @@ def test_bitwise_not(): [pt.TealOp(arg, pt.Op.int, 2), pt.TealOp(expr, pt.Op.bitwise_not)] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -235,7 +235,7 @@ def test_bitwise_not_overload(): [pt.TealOp(arg, pt.Op.int, 10), pt.TealOp(expr, pt.Op.bitwise_not)] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -256,7 +256,7 @@ def test_sqrt(): [pt.TealOp(arg, pt.Op.int, 4), pt.TealOp(expr, pt.Op.sqrt)] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -277,7 +277,7 @@ def test_pop(): [pt.TealOp(arg_int, pt.Op.int, 3), pt.TealOp(expr_int, pt.Op.pop)] ) - actual_int, _ = expr_int.__teal__(teal2Options) + actual_int, _ = expr_int.__teal__(avm2Options) actual_int.addIncoming() actual_int = pt.TealBlock.NormalizeBlocks(actual_int) @@ -291,7 +291,7 @@ def test_pop(): [pt.TealOp(arg_bytes, pt.Op.txn, "Receiver"), pt.TealOp(expr_bytes, pt.Op.pop)] ) - actual_bytes, _ = expr_bytes.__teal__(teal2Options) + actual_bytes, _ = expr_bytes.__teal__(avm2Options) actual_bytes.addIncoming() actual_bytes = pt.TealBlock.NormalizeBlocks(actual_bytes) @@ -313,7 +313,7 @@ def test_balance(): [pt.TealOp(arg, pt.Op.int, 0), pt.TealOp(expr, pt.Op.balance)] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -329,7 +329,7 @@ def test_balance_direct_ref(): [pt.TealOp(arg, pt.Op.txn, "Sender"), pt.TealOp(expr, pt.Op.balance)] ) - actual, _ = expr.__teal__(teal2Options) + actual, _ = expr.__teal__(avm2Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -352,7 +352,7 @@ def test_min_balance(): [pt.TealOp(arg, pt.Op.int, 0), pt.TealOp(expr, pt.Op.min_balance)] ) - actual, _ = expr.__teal__(teal3Options) + actual, _ = expr.__teal__(avm3Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -368,7 +368,7 @@ def test_min_balance_direct_ref(): [pt.TealOp(arg, pt.Op.txn, "Sender"), pt.TealOp(expr, pt.Op.min_balance)] ) - actual, _ = expr.__teal__(teal3Options) + actual, _ = expr.__teal__(avm3Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -394,7 +394,7 @@ def test_b_not(): ] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -415,7 +415,7 @@ def test_bsqrt(): [pt.TealOp(arg, pt.Op.byte, "0xFEDCBA9876543210"), pt.TealOp(expr, pt.Op.bsqrt)] ) - actual, _ = expr.__teal__(teal6Options) + actual, _ = expr.__teal__(avm6Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -436,7 +436,7 @@ def test_b_zero(): [pt.TealOp(arg, pt.Op.int, 8), pt.TealOp(expr, pt.Op.bzero)] ) - actual, _ = expr.__teal__(teal4Options) + actual, _ = expr.__teal__(avm4Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) @@ -458,14 +458,14 @@ def test_log(): [pt.TealOp(arg, pt.Op.byte, '"message"'), pt.TealOp(expr, pt.Op.log)] ) - actual, _ = expr.__teal__(teal5Options) + actual, _ = expr.__teal__(avm5Options) actual.addIncoming() actual = pt.TealBlock.NormalizeBlocks(actual) assert actual == expected with pytest.raises(pt.TealInputError): - expr.__teal__(teal4Options) + expr.__teal__(avm4Options) def test_log_invalid(): diff --git a/pyteal/ast/widemath.py b/pyteal/ast/widemath.py index 3098a7d3a..b70c4c2e8 100644 --- a/pyteal/ast/widemath.py +++ b/pyteal/ast/widemath.py @@ -90,7 +90,7 @@ def __init__( :code:`N_i` represents an element in :code:`numeratorFactors` and each :code:`D_i` represents an element in :code:`denominatorFactors`. - Requires TEAL version 5 or higher. + Requires program version 5 or higher. Args: numeratorFactors: The factors in the numerator of the ratio. This list must have at @@ -114,7 +114,7 @@ def __init__( def __teal__(self, options: "CompileOptions"): if options.version < Op.cover.min_version: raise TealCompileError( - "WideRatio requires TEAL version {} or higher".format( + "WideRatio requires program version {} or higher".format( Op.cover.min_version ), self, diff --git a/pyteal/compiler/__init__.py b/pyteal/compiler/__init__.py index 13a3e6e92..e0d29450d 100644 --- a/pyteal/compiler/__init__.py +++ b/pyteal/compiler/__init__.py @@ -2,6 +2,9 @@ MAX_TEAL_VERSION, MIN_TEAL_VERSION, DEFAULT_TEAL_VERSION, + MAX_PROGRAM_VERSION, + MIN_PROGRAM_VERSION, + DEFAULT_PROGRAM_VERSION, CompileOptions, compileTeal, ) @@ -12,6 +15,9 @@ "MAX_TEAL_VERSION", "MIN_TEAL_VERSION", "DEFAULT_TEAL_VERSION", + "MAX_PROGRAM_VERSION", + "MIN_PROGRAM_VERSION", + "DEFAULT_PROGRAM_VERSION", "CompileOptions", "compileTeal", "OptimizeOptions", diff --git a/pyteal/compiler/compiler.py b/pyteal/compiler/compiler.py index faf8717bd..f98396e36 100644 --- a/pyteal/compiler/compiler.py +++ b/pyteal/compiler/compiler.py @@ -25,9 +25,17 @@ ) from pyteal.compiler.constants import createConstantBlocks -MAX_TEAL_VERSION = 8 -MIN_TEAL_VERSION = 2 -DEFAULT_TEAL_VERSION = MIN_TEAL_VERSION +MAX_PROGRAM_VERSION = 8 +MIN_PROGRAM_VERSION = 2 +DEFAULT_PROGRAM_VERSION = MIN_PROGRAM_VERSION + + +"""Deprecated. Use MAX_PROGRAM_VERSION instead.""" +MAX_TEAL_VERSION = MAX_PROGRAM_VERSION +"""Deprecated. Use MIN_PROGRAM_VERSION instead.""" +MIN_TEAL_VERSION = MIN_PROGRAM_VERSION +"""Deprecated. Use DEFAULT_PROGRAM_VERSION instead.""" +DEFAULT_TEAL_VERSION = DEFAULT_PROGRAM_VERSION class CompileOptions: @@ -35,7 +43,7 @@ def __init__( self, *, mode: Mode = Mode.Signature, - version: int = DEFAULT_TEAL_VERSION, + version: int = DEFAULT_PROGRAM_VERSION, optimize: OptimizeOptions = None, ) -> None: self.mode = mode @@ -88,7 +96,7 @@ def verifyOpsForVersion(teal: List[TealComponent], version: int): op = stmt.getOp() if op.min_version > version: raise TealInputError( - "Op not supported in TEAL version {}: {}. Minimum required version is {}".format( + "Op not supported in program version {}: {}. Minimum required version is {}".format( version, op, op.min_version ) ) @@ -192,7 +200,7 @@ def compileTeal( ast: Expr, mode: Mode, *, - version: int = DEFAULT_TEAL_VERSION, + version: int = DEFAULT_PROGRAM_VERSION, assembleConstants: bool = False, optimize: OptimizeOptions = None, ) -> str: @@ -201,13 +209,13 @@ def compileTeal( Args: ast: The PyTeal expression to assemble. mode: The mode of the program to assemble. Must be Signature or Application. - version (optional): The TEAL version used to assemble the program. This will determine which + version (optional): The program version used to assemble the program. This will determine which expressions and fields are able to be used in the program and how expressions compile to TEAL opcodes. Defaults to 2 if not included. assembleConstants (optional): When true, the compiler will produce a program with fully assembled constants, rather than using the pseudo-ops `int`, `byte`, and `addr`. These constants will be assembled in the most space-efficient way, so enabling this may reduce - the compiled program's size. Enabling this option requires a minimum TEAL version of 3. + the compiled program's size. Enabling this option requires a minimum program version of 3. Defaults to false. optimize (optional): OptimizeOptions that determine which optimizations will be applied. @@ -219,12 +227,12 @@ def compileTeal( TealInternalError: if an internal error is encounter during compilation. """ if ( - not (MIN_TEAL_VERSION <= version <= MAX_TEAL_VERSION) + not (MIN_PROGRAM_VERSION <= version <= MAX_PROGRAM_VERSION) or type(version) is not int ): raise TealInputError( - "Unsupported TEAL version: {}. Excepted an integer in the range [{}, {}]".format( - version, MIN_TEAL_VERSION, MAX_TEAL_VERSION + "Unsupported program version: {}. Excepted an integer in the range [{}, {}]".format( + version, MIN_PROGRAM_VERSION, MAX_PROGRAM_VERSION ) ) @@ -265,7 +273,7 @@ def compileTeal( if assembleConstants: if version < 3: raise TealInternalError( - "The minimum TEAL version required to enable assembleConstants is 3. The current version is {}".format( + "The minimum program version required to enable assembleConstants is 3. The current version is {}".format( version ) ) diff --git a/pyteal/compiler/subroutines.py b/pyteal/compiler/subroutines.py index 6335b82b3..bcde38b1b 100644 --- a/pyteal/compiler/subroutines.py +++ b/pyteal/compiler/subroutines.py @@ -103,7 +103,7 @@ def spillLocalSlotsDuringRecursion( slots from being modifying by a new recursive invocation of the current subroutine. Args: - version: The current TEAL version being assembled. + version: The current program version being assembled. subroutineMapping: A dictionary containing a list of TealComponents for every subroutine in a program. The key None is taken to indicate the main program routine. This input may be modified by this function in order to spill subroutine slots. @@ -209,7 +209,7 @@ def spillLocalSlotsDuringRecursion( stackDistance, ) ) - # because we are stuck using dig instead of uncover in TEAL 4, we'll need to + # because we are stuck using dig instead of uncover in AVM 4, we'll need to # pop all of the dug up arguments after the function returns hideReturnValueInFirstSlot = False diff --git a/pyteal/errors.py b/pyteal/errors.py index 03e597e2f..f5b4d34ef 100644 --- a/pyteal/errors.py +++ b/pyteal/errors.py @@ -64,7 +64,7 @@ def __eq__(self, other) -> bool: TealCompileError.__module__ = "pyteal" -def verifyTealVersion(minVersion: int, version: int, msg: str): +def verifyProgramVersion(minVersion: int, version: int, msg: str): if minVersion > version: msg = "{}. Minimum version needed is {}, but current version being compiled is {}".format( msg, minVersion, version @@ -73,8 +73,8 @@ def verifyTealVersion(minVersion: int, version: int, msg: str): def verifyFieldVersion(fieldName: str, fieldMinVersion: int, version: int): - verifyTealVersion( + verifyProgramVersion( fieldMinVersion, version, - "TEAL version too low to use field {}".format(fieldName), + "Program version too low to use field {}".format(fieldName), ) diff --git a/pyteal/ir/ops.py b/pyteal/ir/ops.py index d87c76250..c0be2e59c 100644 --- a/pyteal/ir/ops.py +++ b/pyteal/ir/ops.py @@ -181,7 +181,7 @@ def min_version(self) -> int: acct_params_get = OpType("acct_params_get", Mode.Application, 6) replace2 = OpType("replace2", Mode.Signature | Mode.Application, 7) replace3 = OpType("replace3", Mode.Signature | Mode.Application, 7) - base64_decode = OpType("base64_decode", Mode.Application | Mode.Signature, 7) + base64_decode = OpType("base64_decode", Mode.Signature | Mode.Application, 7) json_ref = OpType("json_ref", Mode.Signature | Mode.Application, 7) ed25519verify_bare = OpType("ed25519verify_bare", Mode.Signature | Mode.Application, 7) sha3_256 = OpType("sha3_256", Mode.Signature | Mode.Application, 7) From 055c981619904f0a4cb979ff48dad05eccf1e432 Mon Sep 17 00:00:00 2001 From: Hang Su <87964331+ahangsu@users.noreply.github.com> Date: Wed, 3 Aug 2022 18:46:21 -0400 Subject: [PATCH 014/206] change according to https://github.com/algorand/go-algorand/pull/4323/files (#488) --- pyteal/ast/box.py | 6 +++--- pyteal/ast/box_test.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pyteal/ast/box.py b/pyteal/ast/box.py index 368c001e0..119f7f24e 100644 --- a/pyteal/ast/box.py +++ b/pyteal/ast/box.py @@ -33,14 +33,14 @@ def __teal__(self, options: "CompileOptions"): msg=f"{Op.box_create} unavailable", ) return TealBlock.FromOp( - options, TealOp(self, Op.box_create), self.size, self.name + options, TealOp(self, Op.box_create), self.name, self.size ) def __str__(self): return f"(box_create {self.name} {self.size})" def type_of(self): - return TealType.none + return TealType.uint64 def has_return(self): return False @@ -73,7 +73,7 @@ def __str__(self): return f"(box_del {self.name})" def type_of(self): - return TealType.none + return TealType.uint64 def has_return(self): return False diff --git a/pyteal/ast/box_test.py b/pyteal/ast/box_test.py index 4000b3974..c3ec419f3 100644 --- a/pyteal/ast/box_test.py +++ b/pyteal/ast/box_test.py @@ -7,8 +7,8 @@ avm8Options = pt.CompileOptions(version=8) POSITIVE_TEST_CASES: list[Tuple[pt.Expr, pt.TealType]] = [ - (pt.BoxCreate(pt.Bytes("box"), pt.Int(10)), pt.TealType.none), - (pt.BoxDelete(pt.Bytes("box")), pt.TealType.none), + (pt.BoxCreate(pt.Bytes("box"), pt.Int(10)), pt.TealType.uint64), + (pt.BoxDelete(pt.Bytes("box")), pt.TealType.uint64), (pt.BoxExtract(pt.Bytes("box"), pt.Int(2), pt.Int(4)), pt.TealType.bytes), ( pt.BoxReplace(pt.Bytes("box"), pt.Int(3), pt.Bytes("replace")), @@ -57,8 +57,8 @@ def test_box_create_compile(): expected = pt.TealSimpleBlock( [ - pt.TealOp(size_arg, pt.Op.int, 10), pt.TealOp(name_arg, pt.Op.byte, '"eineName"'), + pt.TealOp(size_arg, pt.Op.int, 10), pt.TealOp(expr, pt.Op.box_create), ] ) From 76010b27c81e0b52fba33814f3124c7ee982e921 Mon Sep 17 00:00:00 2001 From: Jason Paulos Date: Thu, 29 Sep 2022 12:31:21 -0700 Subject: [PATCH 015/206] Changes to avm8 docs (#546) --- docs/state.rst | 63 +++++++++++++++++++++++++----------------- pyteal/ast/app.py | 42 +++++++++++++++------------- pyteal/ast/box_test.py | 16 +++++------ pyteal/ast/maybe.py | 4 +-- 4 files changed, 70 insertions(+), 55 deletions(-) diff --git a/docs/state.rst b/docs/state.rst index adb585b26..b45a5a0c6 100644 --- a/docs/state.rst +++ b/docs/state.rst @@ -28,8 +28,8 @@ Current App Global :any:`App.globalPut` :any:`App.gl Current App Local :any:`App.localPut` :any:`App.localGet` :any:`App.localDel` :any:`App.localGetEx` Other App Global :any:`App.globalGetEx` :any:`App.globalGetEx` Other App Local :any:`App.localGetEx` :any:`App.localGetEx` -Current App Boxes | :any:`App.box_create` | :any:`App.box_put` | :any:`App.box_extract` :any:`App.box_delete` | :any:`App.box_length` - | :any:`App.box_put` | :any:`App.box_replace` | :any:`App.box_get` | :any:`App.box_get` +Current App Boxes :any:`App.box_create` :any:`App.box_put` :any:`App.box_extract` :any:`App.box_delete` :any:`App.box_length` + :any:`App.box_put` :any:`App.box_replace` :any:`App.box_get` :any:`App.box_get` ================== ======================= ======================== ======================== ===================== ======================= Global State @@ -279,30 +279,35 @@ Creating Boxes To create a box, use :any:`App.box_create`, or :any:`App.box_put` method. -:any:`App.box_create` makes a box with a specified name and byte length. -The first argument is the box name, and the second argument is the byte size to be allocated. +For :any:`App.box_create`, the first argument is the box name, and the second argument is the byte size to be allocated. + +:any:`App.box_create` creates a new box with the specified name and byte length. New boxes will contain a byte string of all zeros. Performing this operation on a box that already exists will not change its contents. + +If successful, :any:`App.box_create` will return :code:`0` if the box already existed, otherwise it will return :code:`1`. A failure will occur if you attempt to create a box that already exists with a different size. For example: .. code-block:: python - # Allocate a box called "BoxA" of byte size 100 - App.box_create(Bytes("BoxA"), Int(100)) - # Allocate a box called "BoxB" of byte size 90 - App.box_create(Bytes("BoxB"), Int(90) + # Allocate a box called "BoxA" of byte size 100 and ignore the return value + Pop(App.box_create(Bytes("BoxA"), Int(100))) + + # Allocate a box called "BoxB" of byte size 90, asserting that it didn't exist before. + Assert(App.box_create(Bytes("BoxB"), Int(90)) For :any:`App.box_put`, the first argument is the box name to create or to write to, and the second argument is the bytes to write. .. note:: If the box exists, then :any:`App.box_put` will write the contents to the box - (fails when the replacement length is **not identical** to the box's byte size); + (fails when the content length is **not identical** to the existing box's byte size); otherwise, it will create a box containing exactly the same input bytes. .. code-block:: python # create a 42 bytes length box called `poemLine` with content App.box_put(Bytes("poemLine"), Bytes("Of that colossal wreck, boundless and bare")) + # write to box `poemLine` with new value App.box_put(Bytes("poemLine"), Bytes("The lone and level sands stretch far away.")) @@ -335,7 +340,7 @@ and the third argument is the length of bytes to extract. For example: .. code-block:: python - # extract a segment of length 10 starting at the 5'th byte in a box named `NoteBook` + # extract a segment of length 10 starting at the 5th byte in a box named `NoteBook` App.box_extract(Bytes("NoteBook"), Int(5), Int(10)) :any:`App.box_get` gets the full contents of a box. @@ -348,27 +353,29 @@ For example: .. code-block:: python - # get the full contents from a box named `NoteBook` - App.box_get(Bytes("NoteBook")).value() - - -.. note:: - - :any:`App.box_get` can also be used to check the existence of a box. For example: - - .. code-block:: python - - # check existence of a box named `NoteBook` - App.box_get(Bytes("NoteBook")).hasValue() + # get the full contents from a box named `NoteBook`, asserting that it exists + Seq( + contents := App.box_get(Bytes("NoteBook")), + Assert(contents.hasValue()), + contents.value() + ) Deleting a Box ~~~~~~~~~~~~~~ -To delete a box, use :any:`App.box_delete` method. The only argument is the box name. For example: +To delete a box, use :any:`App.box_delete` method. The only argument is the box name. + +:any:`App.box_delete` will return :code:`1` if the box already existed, otherwise it will return :code:`0`. Deleting a nonexistent box is allowed, but has no effect. + +For example: .. code-block:: python - App.box_delete(Bytes("boxToRemove")) + # delete the box `boxToRemove`, asserting that it existed prior to this + Assert(App.box_delete(Bytes("boxToRemove"))) + + # delete the box `mightExist` and ignore the return value + Pop(App.box_delete(Bytes("mightExist"))) Checking if a Box Exists and Reads its Length ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -383,8 +390,12 @@ For example: .. code-block:: python - # search for the box length for box `someBox`, and get the bool value for box existence - App.box_length(Bytes("someBox")).hasValue() + # get the length of the box `someBox`, and assert that the box exists + Seq( + length := App.box_length(Bytes("someBox")), + Assert(length.hasValue()), + length.value() + ) .. note:: diff --git a/pyteal/ast/app.py b/pyteal/ast/app.py index cf9993d46..e6f9d0de9 100644 --- a/pyteal/ast/app.py +++ b/pyteal/ast/app.py @@ -221,9 +221,15 @@ def globalDel(cls, key: Expr) -> "App": return cls(AppField.globalDel, [key]) @classmethod - def box_create(cls, name: Expr, size: Expr) -> BoxCreate: - """ - Create a box with a given name and size. + def box_create(cls, name: Expr, size: Expr) -> Expr: + """Create a box with a given name and size. + + New boxes will contain a byte string of all zeros. Performing this operation on a box that + already exists will not change its contents. + + If successful, this expression returns 0 if the box already existed, otherwise it returns 1. + + A failure will occur if you attempt to create a box that already exists with a different size. Args: name: The key used to reference this box. Must evaluate to a bytes. @@ -232,9 +238,12 @@ def box_create(cls, name: Expr, size: Expr) -> BoxCreate: return BoxCreate(name, size) @classmethod - def box_delete(cls, name: Expr) -> BoxDelete: - """ - Deletes a box given it's name. + def box_delete(cls, name: Expr) -> Expr: + """Deletes a box given it's name. + + This expression returns 1 if the box existed, otherwise it returns 0. + + Deleting a nonexistent box is allowed, but has no effect. Args: name: The key the box was created with. Must evaluate to bytes. @@ -242,9 +251,8 @@ def box_delete(cls, name: Expr) -> BoxDelete: return BoxDelete(name) @classmethod - def box_extract(cls, name: Expr, start: Expr, length: Expr) -> BoxExtract: - """ - Extracts bytes in a box given its name, start index and stop index. + def box_extract(cls, name: Expr, start: Expr, length: Expr) -> Expr: + """Extracts bytes in a box given its name, start index and stop index. Args: name: The key the box was created with. Must evaluate to bytes. @@ -254,9 +262,8 @@ def box_extract(cls, name: Expr, start: Expr, length: Expr) -> BoxExtract: return BoxExtract(name, start, length) @classmethod - def box_replace(cls, name: Expr, start: Expr, value: Expr) -> BoxReplace: - """ - Replaces bytes in a box given its name, start index, and value. + def box_replace(cls, name: Expr, start: Expr, value: Expr) -> Expr: + """Replaces bytes in a box given its name, start index, and value. Args: name: The key the box was created with. Must evaluate to bytes. @@ -267,8 +274,7 @@ def box_replace(cls, name: Expr, start: Expr, value: Expr) -> BoxReplace: @classmethod def box_length(cls, name: Expr) -> MaybeValue: - """ - Get the byte length of the box specified by its name. + """Get the byte length of the box specified by its name. Args: name: The key the box was created with. Must evaluate to bytes. @@ -277,8 +283,7 @@ def box_length(cls, name: Expr) -> MaybeValue: @classmethod def box_get(cls, name: Expr) -> MaybeValue: - """ - Get the full contents of a box given its name. + """Get the full contents of a box given its name. Args: name: The key the box was created with. Must evaluate to bytes. @@ -286,9 +291,8 @@ def box_get(cls, name: Expr) -> MaybeValue: return BoxGet(name) @classmethod - def box_put(cls, name: Expr, value: Expr) -> BoxPut: - """ - Write all contents to a box given its name. + def box_put(cls, name: Expr, value: Expr) -> Expr: + """Write all contents to a box given its name. Args: name: The key the box was created with. Must evaluate to bytes. diff --git a/pyteal/ast/box_test.py b/pyteal/ast/box_test.py index c3ec419f3..008ffb580 100644 --- a/pyteal/ast/box_test.py +++ b/pyteal/ast/box_test.py @@ -131,10 +131,10 @@ def test_box_length(): expected = pt.TealSimpleBlock( [ - pt.TealOp(name_arg, pt.Op.byte, '"eineName"'), - pt.TealOp(expr, pt.Op.box_len), - pt.TealOp(expr.output_slots[1].store(), pt.Op.store, expr.output_slots[1]), - pt.TealOp(expr.output_slots[0].store(), pt.Op.store, expr.output_slots[0]), + pt.TealOp(None, pt.Op.byte, '"eineName"'), + pt.TealOp(None, pt.Op.box_len), + pt.TealOp(None, pt.Op.store, expr.output_slots[1]), + pt.TealOp(None, pt.Op.store, expr.output_slots[0]), ] ) actual, _ = expr.__teal__(avm8Options) @@ -151,10 +151,10 @@ def test_box_get(): expected = pt.TealSimpleBlock( [ - pt.TealOp(name_arg, pt.Op.byte, '"eineName"'), - pt.TealOp(expr, pt.Op.box_get), - pt.TealOp(expr.output_slots[1].store(), pt.Op.store, expr.output_slots[1]), - pt.TealOp(expr.output_slots[0].store(), pt.Op.store, expr.output_slots[0]), + pt.TealOp(None, pt.Op.byte, '"eineName"'), + pt.TealOp(None, pt.Op.box_get), + pt.TealOp(None, pt.Op.store, expr.output_slots[1]), + pt.TealOp(None, pt.Op.store, expr.output_slots[0]), ] ) actual, _ = expr.__teal__(avm8Options) diff --git a/pyteal/ast/maybe.py b/pyteal/ast/maybe.py index 4d863e6ff..4c6091953 100644 --- a/pyteal/ast/maybe.py +++ b/pyteal/ast/maybe.py @@ -67,7 +67,7 @@ def value(self) -> ScratchLoad: def slotOk(self) -> ScratchSlot: """Get the scratch slot that stores hasValue. - Note: This is mainly added for backwards compatability and normally shouldn't be used + Note: This is mainly added for backwards compatibility and normally shouldn't be used directly in pyteal code. """ return self.output_slots[1] @@ -77,7 +77,7 @@ def slotValue(self) -> ScratchSlot: """Get the scratch slot that stores the value or the zero value for the type if the value doesn't exist. - Note: This is mainly added for backwards compatability and normally shouldn't be used + Note: This is mainly added for backwards compatibility and normally shouldn't be used directly in pyteal code. """ return self.output_slots[0] From cc49a55b96356108068b1771a785451438b68e11 Mon Sep 17 00:00:00 2001 From: Jacob Daitzman Date: Wed, 26 Oct 2022 07:50:23 -0400 Subject: [PATCH 016/206] Support new AVM 8 account parameters (#555) --- pyteal/ast/acct.py | 225 ++++++++++++++++++++++++++++++++++++---- pyteal/ast/acct_test.py | 190 ++++++++++++++++++++------------- pyteal/ast/maybe.py | 14 ++- 3 files changed, 332 insertions(+), 97 deletions(-) diff --git a/pyteal/ast/acct.py b/pyteal/ast/acct.py index 7f61e10ee..7bc19ec78 100644 --- a/pyteal/ast/acct.py +++ b/pyteal/ast/acct.py @@ -1,12 +1,67 @@ -from typing import Final +from enum import Enum +from typing import Final, TYPE_CHECKING +from pyteal.errors import verifyFieldVersion, verifyProgramVersion from pyteal.types import TealType, require_type from pyteal.ir import Op from pyteal.ast.expr import Expr from pyteal.ast.maybe import MaybeValue +if TYPE_CHECKING: + from pyteal.compiler import CompileOptions + + +class AccountParamField(Enum): + # fmt: off + # id | name | type | min version + balance = (0, "AcctBalance", TealType.uint64, 6) # noqa: E221 + min_balance = (1, "AcctMinBalance", TealType.uint64, 6) # noqa: E221 + auth_addr = (2, "AcctAuthAddr", TealType.bytes, 6) # noqa: E221 + total_num_uint = (3, "AcctTotalNumUint", TealType.uint64, 8) # noqa: E221 + total_num_byte_slice = (4, "AcctTotalNumByteSlice", TealType.uint64, 8) # noqa: E221 + total_extra_app_pages = (5, "AcctTotalExtraAppPages", TealType.uint64, 8) # noqa: E221 + total_apps_created = (6, "AcctTotalAppsCreated", TealType.uint64, 8) # noqa: E221 + total_apps_opted_in = (7, "AcctTotalAppsOptedIn", TealType.uint64, 8) # noqa: E221 + total_assets_created = (8, "AcctTotalAssetsCreated", TealType.uint64, 8) # noqa: E221 + total_assets = (9, "AcctTotalAssets", TealType.uint64, 8) # noqa: E221 + total_boxes = (10, "AcctTotalBoxes", TealType.uint64, 8) # noqa: E221 + total_box_bytes = (11, "AcctTotalBoxBytes", TealType.uint64, 8) # noqa: E221 + # fmt: on + + def __init__(self, id: int, name: str, type: TealType, min_version: int) -> None: + self.id = id + self.arg_name = name + self.type = type + self.min_version = min_version + + def type_of(self) -> TealType: + return self.type + + +AccountParamField.__module__ = "pyteal" + class AccountParam: + @staticmethod + def __makeAccountParamExpr(field: AccountParamField, acct: Expr) -> MaybeValue: + require_type(acct, TealType.anytype) + + def field_and_program_version_check(options: "CompileOptions"): + verifyProgramVersion( + minVersion=Op.acct_params_get.min_version, + version=options.version, + msg=f"{Op.acct_params_get.value} unavailable", + ) + verifyFieldVersion(field.arg_name, field.min_version, options.version) + + return MaybeValue( + Op.acct_params_get, + field.type_of(), + immediate_args=[field.arg_name], + args=[acct], + compile_check=field_and_program_version_check, + ) + @classmethod def balance(cls, acct: Expr) -> MaybeValue: """Get the current balance in microalgos an account. @@ -15,13 +70,7 @@ def balance(cls, acct: Expr) -> MaybeValue: acct: An index into Txn.accounts that corresponds to the application to check or an address available at runtime. May evaluate to uint64 or an address. """ - require_type(acct, TealType.anytype) - return MaybeValue( - Op.acct_params_get, - TealType.uint64, - immediate_args=["AcctBalance"], - args=[acct], - ) + return cls.__makeAccountParamExpr(AccountParamField.balance, acct) @classmethod def minBalance(cls, acct: Expr) -> MaybeValue: @@ -31,13 +80,7 @@ def minBalance(cls, acct: Expr) -> MaybeValue: acct: An index into Txn.accounts that corresponds to the application to check or an address available at runtime. May evaluate to uint64 or an address. """ - require_type(acct, TealType.anytype) - return MaybeValue( - Op.acct_params_get, - TealType.uint64, - immediate_args=["AcctMinBalance"], - args=[acct], - ) + return cls.__makeAccountParamExpr(AccountParamField.min_balance, acct) @classmethod def authAddr(cls, acct: Expr) -> MaybeValue: @@ -47,13 +90,115 @@ def authAddr(cls, acct: Expr) -> MaybeValue: acct: An index into Txn.accounts that corresponds to the application to check or an address available at runtime. May evaluate to uint64 or an address. """ - require_type(acct, TealType.anytype) - return MaybeValue( - Op.acct_params_get, - TealType.bytes, - immediate_args=["AcctAuthAddr"], - args=[acct], - ) + return cls.__makeAccountParamExpr(AccountParamField.auth_addr, acct) + + @classmethod + def totalNumUint(cls, acct: Expr) -> MaybeValue: + """Get the total number of uint64 values allocated by the account in Global and Local States. + + Requires program version 8 or higher. + + Args: + acct: An index into Txn.accounts that corresponds to the application to check or an address available at runtime. + May evaluate to uint64 or an address. + """ + return cls.__makeAccountParamExpr(AccountParamField.total_num_uint, acct) + + @classmethod + def totalNumByteSlice(cls, acct: Expr) -> MaybeValue: + """Get the total number of byte array values allocated by the account in Global and Local States. + + Requires program version 8 or higher. + + Args: + acct: An index into Txn.accounts that corresponds to the application to check or an address available at runtime. + May evaluate to uint64 or an address. + """ + return cls.__makeAccountParamExpr(AccountParamField.total_num_byte_slice, acct) + + @classmethod + def totalExtraAppPages(cls, acct: Expr) -> MaybeValue: + """Get the number of extra app code pages used by the account. + + Requires program version 8 or higher. + + Args: + acct: An index into Txn.accounts that corresponds to the application to check or an address available at runtime. + May evaluate to uint64 or an address. + """ + return cls.__makeAccountParamExpr(AccountParamField.total_extra_app_pages, acct) + + @classmethod + def totalAppsCreated(cls, acct: Expr) -> MaybeValue: + """Get the number of existing apps created by the account. + + Requires program version 8 or higher. + + Args: + acct: An index into Txn.accounts that corresponds to the application to check or an address available at runtime. + May evaluate to uint64 or an address. + """ + return cls.__makeAccountParamExpr(AccountParamField.total_apps_created, acct) + + @classmethod + def totalAppsOptedIn(cls, acct: Expr) -> MaybeValue: + """Get the number of apps the account is opted into. + + Requires program version 8 or higher. + + Args: + acct: An index into Txn.accounts that corresponds to the application to check or an address available at runtime. + May evaluate to uint64 or an address. + """ + return cls.__makeAccountParamExpr(AccountParamField.total_apps_opted_in, acct) + + @classmethod + def totalAssetsCreated(cls, acct: Expr) -> MaybeValue: + """Get the number of existing ASAs created by the account. + + Requires program version 8 or higher. + + Args: + acct: An index into Txn.accounts that corresponds to the application to check or an address available at runtime. + May evaluate to uint64 or an address. + """ + return cls.__makeAccountParamExpr(AccountParamField.total_assets_created, acct) + + @classmethod + def totalAssets(cls, acct: Expr) -> MaybeValue: + """Get the number of ASAs held by the account (including ASAs the account created). + + Requires program version 8 or higher. + + Args: + acct: An index into Txn.accounts that corresponds to the application to check or an address available at runtime. + May evaluate to uint64 or an address. + """ + return cls.__makeAccountParamExpr(AccountParamField.total_assets, acct) + + @classmethod + def totalBoxes(cls, acct: Expr) -> MaybeValue: + """Get the number of existing boxes created by the account's app. + + Requires program version 8 or higher. + + Args: + acct: An index into Txn.accounts that corresponds to the application to check or an address available at runtime. + May evaluate to uint64 or an address. + """ + return cls.__makeAccountParamExpr(AccountParamField.total_boxes, acct) + + @classmethod + def totalBoxBytes(cls, acct: Expr) -> MaybeValue: + """Get the total number of bytes used by the account's app's box keys and values. + + Requires program version 8 or higher. + + Args: + acct: An index into Txn.accounts that corresponds to the application to check or an address available at runtime. + May evaluate to uint64 or an address. + """ + return cls.__makeAccountParamExpr(AccountParamField.total_box_bytes, acct) AccountParam.__module__ = "pyteal" @@ -85,5 +230,41 @@ def auth_address(self) -> MaybeValue: If the account is not rekeyed, the empty address is returned.""" return AccountParam.authAddr(self._account) + def total_num_uint(self) -> MaybeValue: + """Get the total number of uint64 values allocated by the account in Global and Local States.""" + return AccountParam.totalNumUint(self._account) + + def total_num_byte_slice(self) -> MaybeValue: + """Get the total number of byte array values allocated by the account in Global and Local States.""" + return AccountParam.totalNumByteSlice(self._account) + + def total_extra_app_pages(self) -> MaybeValue: + """Get the number of extra app code pages used by the account.""" + return AccountParam.totalExtraAppPages(self._account) + + def total_apps_created(self) -> MaybeValue: + """Get the number of existing apps created by the account.""" + return AccountParam.totalAppsCreated(self._account) + + def total_apps_opted_in(self) -> MaybeValue: + """Get the number of apps the account is opted into.""" + return AccountParam.totalAppsOptedIn(self._account) + + def total_assets_created(self) -> MaybeValue: + """Get the number of existing ASAs created by the account.""" + return AccountParam.totalAssetsCreated(self._account) + + def total_assets(self) -> MaybeValue: + """Get the number of ASAs held by the account (including ASAs the account created).""" + return AccountParam.totalAssets(self._account) + + def total_boxes(self) -> MaybeValue: + """Get the number of existing boxes created by the account's app.""" + return AccountParam.totalBoxes(self._account) + + def total_box_bytes(self) -> MaybeValue: + """Get the total number of bytes used by the account's app's box keys and values.""" + return AccountParam.totalBoxBytes(self._account) + AccountParamObject.__module__ = "pyteal" diff --git a/pyteal/ast/acct_test.py b/pyteal/ast/acct_test.py index e4f12f958..8259f8ac6 100644 --- a/pyteal/ast/acct_test.py +++ b/pyteal/ast/acct_test.py @@ -1,79 +1,89 @@ +import pytest + import pyteal as pt +from pyteal.ast.acct import AccountParamField from pyteal.ast.maybe_test import assert_MaybeValue_equality -options = pt.CompileOptions() -avm4Options = pt.CompileOptions(version=4) -avm5Options = pt.CompileOptions(version=5) avm6Options = pt.CompileOptions(version=6) +avm8Options = pt.CompileOptions(version=8) + + +@pytest.mark.parametrize( + "method_name,field_name", + [ + ("balance", "balance"), + ("minBalance", "min_balance"), + ("authAddr", "auth_addr"), + ("totalNumUint", "total_num_uint"), + ("totalNumByteSlice", "total_num_byte_slice"), + ("totalExtraAppPages", "total_extra_app_pages"), + ("totalAppsCreated", "total_apps_created"), + ("totalAppsOptedIn", "total_apps_opted_in"), + ("totalAssetsCreated", "total_assets_created"), + ("totalAssets", "total_assets"), + ("totalBoxes", "total_boxes"), + ("totalBoxBytes", "total_box_bytes"), + ], +) +class TestAcctParam: + @staticmethod + def test_acct_param_fields_valid(method_name, field_name): + arg = pt.Int(1) + account_param_method = getattr(pt.AccountParam, method_name) + expr = account_param_method(arg) + assert expr.type_of() == pt.TealType.none + + account_param_field = AccountParamField[field_name] + assert expr.value().type_of() == account_param_field.type_of() + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(arg, pt.Op.int, 1), + pt.TealOp(expr, pt.Op.acct_params_get, account_param_field.arg_name), + pt.TealOp(None, pt.Op.store, expr.slotOk), + pt.TealOp(None, pt.Op.store, expr.slotValue), + ] + ) - -def test_acct_param_balance_valid(): - arg = pt.Int(1) - expr = pt.AccountParam.balance(arg) - assert expr.type_of() == pt.TealType.none - assert expr.value().type_of() == pt.TealType.uint64 - - expected = pt.TealSimpleBlock( - [ - pt.TealOp(arg, pt.Op.int, 1), - pt.TealOp(expr, pt.Op.acct_params_get, "AcctBalance"), - pt.TealOp(None, pt.Op.store, expr.slotOk), - pt.TealOp(None, pt.Op.store, expr.slotValue), - ] - ) - - actual, _ = expr.__teal__(avm6Options) - actual.addIncoming() - actual = pt.TealBlock.NormalizeBlocks(actual) - - with pt.TealComponent.Context.ignoreExprEquality(): - assert actual == expected - - -def test_acct_param_min_balance_valid(): - arg = pt.Int(0) - expr = pt.AccountParam.minBalance(arg) - assert expr.type_of() == pt.TealType.none - assert expr.value().type_of() == pt.TealType.uint64 - - expected = pt.TealSimpleBlock( - [ - pt.TealOp(arg, pt.Op.int, 0), - pt.TealOp(expr, pt.Op.acct_params_get, "AcctMinBalance"), - pt.TealOp(None, pt.Op.store, expr.slotOk), - pt.TealOp(None, pt.Op.store, expr.slotValue), - ] - ) - - actual, _ = expr.__teal__(avm6Options) - actual.addIncoming() - actual = pt.TealBlock.NormalizeBlocks(actual) - - with pt.TealComponent.Context.ignoreExprEquality(): - assert actual == expected - - -def test_acct_param_auth_addr_valid(): - arg = pt.Int(1) - expr = pt.AccountParam.authAddr(arg) - assert expr.type_of() == pt.TealType.none - assert expr.value().type_of() == pt.TealType.bytes - - expected = pt.TealSimpleBlock( - [ - pt.TealOp(arg, pt.Op.int, 1), - pt.TealOp(expr, pt.Op.acct_params_get, "AcctAuthAddr"), - pt.TealOp(None, pt.Op.store, expr.slotOk), - pt.TealOp(None, pt.Op.store, expr.slotValue), - ] - ) - - actual, _ = expr.__teal__(avm6Options) - actual.addIncoming() - actual = pt.TealBlock.NormalizeBlocks(actual) - - with pt.TealComponent.Context.ignoreExprEquality(): - assert actual == expected + supported_options_version = pt.CompileOptions( + version=account_param_field.min_version + ) + actual, _ = expr.__teal__(supported_options_version) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + with pt.TealComponent.Context.ignoreExprEquality(): + assert actual == expected + + @staticmethod + def test_acct_param_version_checks(method_name, field_name): + arg = pt.Int(1) + account_param_method = getattr(pt.AccountParam, method_name) + expr = account_param_method(arg) + + account_param_field = AccountParamField[field_name] + + def test_unsupported_version(version: int, match: str = None): + with pytest.raises(pt.TealInputError, match=match): + unsupported_options_version = pt.CompileOptions(version=version) + expr.__teal__(unsupported_options_version) + + # Test program and field version checks + program_unsupported_version = pt.ir.Op.acct_params_get.min_version - 1 + program_error_match = "unavailable" + test_unsupported_version(program_unsupported_version, program_error_match) + + field_unsupported_version = account_param_field.min_version - 1 + + # Since program version dominates, we conditionally check field error message or program error message + # depending on whether the unsupported field version is less than or equal to the program unsupported + # version. + field_error_match = ( + "Program version too low to use field" + if field_unsupported_version > program_unsupported_version + else program_error_match + ) + test_unsupported_version(field_unsupported_version, field_error_match) def test_AccountParamObject(): @@ -94,3 +104,41 @@ def test_AccountParamObject(): assert_MaybeValue_equality( obj.auth_address(), pt.AccountParam.authAddr(account), avm6Options ) + + assert_MaybeValue_equality( + obj.total_num_uint(), pt.AccountParam.totalNumUint(account), avm8Options + ) + assert_MaybeValue_equality( + obj.total_num_byte_slice(), + pt.AccountParam.totalNumByteSlice(account), + avm8Options, + ) + assert_MaybeValue_equality( + obj.total_extra_app_pages(), + pt.AccountParam.totalExtraAppPages(account), + avm8Options, + ) + assert_MaybeValue_equality( + obj.total_apps_created(), + pt.AccountParam.totalAppsCreated(account), + avm8Options, + ) + assert_MaybeValue_equality( + obj.total_apps_opted_in(), + pt.AccountParam.totalAppsOptedIn(account), + avm8Options, + ) + assert_MaybeValue_equality( + obj.total_assets_created(), + pt.AccountParam.totalAssetsCreated(account), + avm8Options, + ) + assert_MaybeValue_equality( + obj.total_assets(), pt.AccountParam.totalAssets(account), avm8Options + ) + assert_MaybeValue_equality( + obj.total_boxes(), pt.AccountParam.totalBoxes(account), avm8Options + ) + assert_MaybeValue_equality( + obj.total_box_bytes(), pt.AccountParam.totalBoxBytes(account), avm8Options + ) diff --git a/pyteal/ast/maybe.py b/pyteal/ast/maybe.py index 4c6091953..9ae1f0245 100644 --- a/pyteal/ast/maybe.py +++ b/pyteal/ast/maybe.py @@ -1,4 +1,4 @@ -from typing import List, Union, TYPE_CHECKING +from typing import Callable, List, Union, TYPE_CHECKING from pyteal.errors import verifyProgramVersion from pyteal.types import TealType @@ -22,6 +22,7 @@ def __init__( *, immediate_args: List[Union[int, str]] = None, args: List[Expr] = None, + compile_check: Callable[["CompileOptions"], None] = None, ): """Create a new MaybeValue. @@ -30,12 +31,15 @@ def __init__( type: The type of the returned value. immediate_args (optional): Immediate arguments for the op. Defaults to None. args (optional): Stack arguments for the op. Defaults to None. + compile_check (optional): Callable compile check. Defaults to program version check. + This parameter overwrites the default program version check. """ - def local_version_check(option: "CompileOptions"): + # Default compile check if one is not given + def local_version_check(options: "CompileOptions"): verifyProgramVersion( minVersion=op.min_version, - version=option.version, + version=options.version, msg=f"{op.value} unavailable", ) @@ -45,7 +49,9 @@ def local_version_check(option: "CompileOptions"): types, immediate_args=immediate_args, args=args, - compile_check=local_version_check, + compile_check=( + local_version_check if compile_check is None else compile_check + ), ) def hasValue(self) -> ScratchLoad: From 1d7cd6ad0b5b01eec9a9e3fa428020eb42493b4b Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 26 Oct 2022 09:56:48 -0400 Subject: [PATCH 017/206] add frame ops to avm8 branch --- pyteal/__init__.pyi | 6 ++ pyteal/ast/__init__.py | 7 ++ pyteal/ast/frame.py | 188 +++++++++++++++++++++++++++++++++++++++ pyteal/ast/frame_test.py | 159 +++++++++++++++++++++++++++++++++ pyteal/ir/ops.py | 8 +- 5 files changed, 367 insertions(+), 1 deletion(-) create mode 100644 pyteal/ast/frame.py create mode 100644 pyteal/ast/frame_test.py diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index ce347b0eb..69e3c55eb 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -70,6 +70,7 @@ __all__ = [ "BoxReplace", "Break", "Btoi", + "Bury", "Bytes", "BytesAdd", "BytesAnd", @@ -98,6 +99,7 @@ __all__ = [ "DEFAULT_TEAL_VERSION", "Div", "Divw", + "DupN", "DynamicScratchVar", "EcdsaCurve", "EcdsaDecompress", @@ -115,6 +117,8 @@ __all__ = [ "ExtractUint32", "ExtractUint64", "For", + "FrameBury", + "FrameDig", "Ge", "GeneratedID", "GetBit", @@ -173,7 +177,9 @@ __all__ = [ "OptimizeOptions", "Or", "Pop", + "PopN", "Pragma", + "Proto", "RETURN_HASH_PREFIX", "Reject", "Replace", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 9efe807c5..1ca49a2e5 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -155,6 +155,7 @@ from pyteal.ast.for_ import For from pyteal.ast.break_ import Break from pyteal.ast.continue_ import Continue +from pyteal.ast.frame import Proto, FrameDig, FrameBury, PopN, DupN, Bury # misc from pyteal.ast.scratch import ( @@ -336,6 +337,12 @@ "For", "Break", "Continue", + "Proto", + "FrameDig", + "FrameBury", + "Bury", + "DupN", + "PopN", "Router", "CallConfig", "MethodConfig", diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py new file mode 100644 index 000000000..8b1cb6080 --- /dev/null +++ b/pyteal/ast/frame.py @@ -0,0 +1,188 @@ +from typing import TYPE_CHECKING + +from pyteal.ast.expr import Expr +from pyteal.types import TealType, require_type +from pyteal.errors import TealInputError, verifyProgramVersion +from pyteal.ir import TealBlock, TealSimpleBlock, TealOp, Op + +if TYPE_CHECKING: + from pyteal.compiler import CompileOptions + + +class Proto(Expr): + def __init__(self, arg_num: int, ret_num: int): + super().__init__() + if arg_num < 0: + raise TealInputError(f"subroutine arg number {arg_num} must be >= 0") + if ret_num < 0: + raise TealInputError(f"return value number {ret_num} must be >= 0") + self.arg_num = arg_num + self.ret_num = ret_num + + def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: + verifyProgramVersion( + Op.proto.min_version, + options.version, + "Program version too low to use op proto", + ) + op = TealOp(self, Op.proto, self.arg_num, self.ret_num) + return TealBlock.FromOp(options, op) + + def __str__(self) -> str: + return f"(proto: arg_num = {self.arg_num}, ret_num = {self.ret_num})" + + def type_of(self) -> TealType: + return TealType.none + + def has_return(self) -> bool: + return False + + +Proto.__module__ = "pyteal" + + +class FrameDig(Expr): + def __init__(self, depth: int): + super().__init__() + self.depth = depth + + def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: + verifyProgramVersion( + Op.frame_dig.min_version, + options.version, + "Program version too low to use op frame_dig", + ) + op = TealOp(self, Op.frame_dig, self.depth) + return TealBlock.FromOp(options, op) + + def __str__(self) -> str: + return f"(frame_dig: dig_depth = {self.depth})" + + def type_of(self) -> TealType: + return TealType.anytype + + def has_return(self) -> bool: + return False + + +FrameDig.__module__ = "pyteal" + + +class FrameBury(Expr): + def __init__(self, what: Expr, depth: int): + super().__init__() + require_type(what, TealType.anytype) + self.what = what + self.depth = depth + + def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: + verifyProgramVersion( + Op.frame_bury.min_version, + options.version, + "Program version too low to use op frame_bury", + ) + op = TealOp(self, Op.frame_bury, self.depth) + return TealBlock.FromOp(options, op, self.what) + + def __str__(self) -> str: + return f"(frame_bury (bury_depth = {self.depth}) ({self.what}))" + + def type_of(self) -> TealType: + return TealType.none + + def has_return(self) -> bool: + return False + + +FrameBury.__module__ = "pyteal" + + +class Bury(Expr): + def __init__(self, what: Expr, depth: int): + super().__init__() + require_type(what, TealType.anytype) + if depth <= 0: + raise TealInputError("bury depth should be strictly positive") + self.what = what + self.depth = depth + + def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: + verifyProgramVersion( + Op.bury.min_version, + options.version, + "Program version too low to use op bury", + ) + op = TealOp(self, Op.bury, self.depth) + return TealBlock.FromOp(options, op, self.what) + + def __str__(self) -> str: + return f"(bury (depth = {self.depth}) ({self.what}))" + + def type_of(self) -> TealType: + return TealType.none + + def has_return(self) -> bool: + return False + + +Bury.__module__ = "pyteal" + + +class DupN(Expr): + def __init__(self, what: Expr, repetition: int): + super().__init__() + require_type(what, TealType.anytype) + if repetition < 0: + raise TealInputError("dupn repetition should be non negative") + self.what = what + self.repetition = repetition + + def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: + verifyProgramVersion( + Op.dupn.min_version, + options.version, + "Program version too low to use op dupn", + ) + op = TealOp(self, Op.dupn, self.repetition) + return TealBlock.FromOp(options, op, self.what) + + def __str__(self) -> str: + return f"(dupn (repetition = {self.repetition}) ({self.what}))" + + def type_of(self) -> TealType: + return self.what.type_of() + + def has_return(self) -> bool: + return False + + +DupN.__module__ = "pyteal" + + +class PopN(Expr): + def __init__(self, repetition: int): + super().__init__() + if repetition < 0: + raise TealInputError("popn repetition should be non negative") + self.repetition = repetition + + def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: + verifyProgramVersion( + Op.popn.min_version, + options.version, + "Program version too low to use op popn", + ) + op = TealOp(self, Op.popn, self.repetition) + return TealBlock.FromOp(options, op) + + def __str__(self) -> str: + return f"(popn {self.repetition})" + + def type_of(self) -> TealType: + return TealType.none + + def has_return(self) -> bool: + return False + + +PopN.__module__ = "pyteal" diff --git a/pyteal/ast/frame_test.py b/pyteal/ast/frame_test.py new file mode 100644 index 000000000..b21b47d0e --- /dev/null +++ b/pyteal/ast/frame_test.py @@ -0,0 +1,159 @@ +import pytest +import pyteal as pt +from pyteal.types import TealType + +avm7Options = pt.CompileOptions(version=7) +avm8Options = pt.CompileOptions(version=8) + + +@pytest.mark.parametrize("input_num, output_num", [(1, 1), (1, 0), (5, 5)]) +def test_proto(input_num: int, output_num: int): + expr = pt.Proto(input_num, output_num) + assert not expr.has_return() + assert expr.type_of() == pt.TealType.none + + expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.proto, input_num, output_num)]) + actual, _ = expr.__teal__(avm8Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + +def test_proto_invalid(): + with pytest.raises(pt.TealInputError): + pt.Proto(-1, 1) + + with pytest.raises(pt.TealInputError): + pt.Proto(1, -1) + + with pytest.raises(pt.TealInputError): + pt.Proto(1, 1).__teal__(avm7Options) + + +@pytest.mark.parametrize("depth", [-1, 0, 1, 2]) +def test_frame_dig(depth: int): + expr = pt.FrameDig(depth) + assert not expr.has_return() + assert expr.type_of() == pt.TealType.anytype + + expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.frame_dig, depth)]) + actual, _ = expr.__teal__(avm8Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + +def test_frame_dig_invalid(): + with pytest.raises(pt.TealInputError): + pt.FrameDig(1).__teal__(avm7Options) + + +def test_frame_bury(): + byte_expr = pt.Bytes("Astartes") + expr = pt.FrameBury(byte_expr, 4) + assert not expr.has_return() + assert expr.type_of() == TealType.none + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(byte_expr, pt.Op.byte, '"Astartes"'), + pt.TealOp(expr, pt.Op.frame_bury, 4), + ] + ) + actual, _ = expr.__teal__(avm8Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + +def test_frame_bury_invalid(): + with pytest.raises(pt.TealTypeError): + pt.FrameBury(pt.Seq(), 1) + + with pytest.raises(pt.TealInputError): + pt.FrameBury(pt.Int(1), 1).__teal__(avm7Options) + + +def test_bury(): + byte_expr = pt.Bytes("Astartes") + expr = pt.Bury(byte_expr, 4) + assert not expr.has_return() + assert expr.type_of() == TealType.none + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(byte_expr, pt.Op.byte, '"Astartes"'), + pt.TealOp(expr, pt.Op.bury, 4), + ] + ) + actual, _ = expr.__teal__(avm8Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + +def test_bury_invalid(): + with pytest.raises(pt.TealTypeError): + pt.Bury(pt.Seq(), 1) + + with pytest.raises(pt.TealInputError): + pt.Bury(pt.Int(1), 0) + + with pytest.raises(pt.TealInputError): + pt.Bury(pt.Int(1), 1).__teal__(avm7Options) + + +@pytest.mark.parametrize("repetition", [0, 1, 2, 3, 4, 5]) +def test_popn(repetition: int): + expr = pt.PopN(repetition) + assert not expr.has_return() + assert expr.type_of() == pt.TealType.none + + expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.popn, repetition)]) + actual, _ = expr.__teal__(avm8Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + +def test_popn_invalid(): + with pytest.raises(pt.TealInputError): + pt.PopN(-1) + + with pytest.raises(pt.TealInputError): + pt.PopN(5).__teal__(avm7Options) + + +def test_dupn(): + byte_expr = pt.Bytes("Astartes") + expr = pt.DupN(byte_expr, 4) + assert not expr.has_return() + assert expr.type_of() == byte_expr.type_of() + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(byte_expr, pt.Op.byte, '"Astartes"'), + pt.TealOp(expr, pt.Op.dupn, 4), + ] + ) + actual, _ = expr.__teal__(avm8Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + +def test_dupn_invalid(): + with pytest.raises(pt.TealTypeError): + pt.DupN(pt.Seq(), 1) + + with pytest.raises(pt.TealInputError): + pt.DupN(pt.Int(1), -1) + + with pytest.raises(pt.TealInputError): + pt.DupN(pt.Int(1), 1).__teal__(avm7Options) diff --git a/pyteal/ir/ops.py b/pyteal/ir/ops.py index 43a62b5d4..9ec496288 100644 --- a/pyteal/ir/ops.py +++ b/pyteal/ir/ops.py @@ -33,7 +33,7 @@ def min_version(self) -> int: # fmt: off # meta comment = OpType("//", Mode.Signature | Mode.Application, 0) - # avm + # avm err = OpType("err", Mode.Signature | Mode.Application, 2) sha256 = OpType("sha256", Mode.Signature | Mode.Application, 2) keccak256 = OpType("keccak256", Mode.Signature | Mode.Application, 2) @@ -197,6 +197,12 @@ def min_version(self) -> int: box_len = OpType("box_len", Mode.Application, 8) box_get = OpType("box_get", Mode.Application, 8) box_put = OpType("box_put", Mode.Application, 8) + popn = OpType("popn", Mode.Signature | Mode.Application, 8) + dupn = OpType("dupn", Mode.Signature | Mode.Application, 8) + bury = OpType("bury", Mode.Signature | Mode.Application, 8) + frame_dig = OpType("frame_dig", Mode.Signature | Mode.Application, 8) + frame_bury = OpType("frame_bury", Mode.Signature | Mode.Application, 8) + proto = OpType("proto", Mode.Signature | Mode.Application, 8) # fmt: on From 49d169ed4e7dd4bbd7ea1cedcdc5a5d70718d33d Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 26 Oct 2022 13:52:43 -0400 Subject: [PATCH 018/206] specify FRAME_POINTER_VERSION in frame-op branch --- pyteal/__init__.py | 2 ++ pyteal/__init__.pyi | 2 ++ pyteal/compiler/__init__.py | 2 ++ pyteal/compiler/compiler.py | 1 + 4 files changed, 7 insertions(+) diff --git a/pyteal/__init__.py b/pyteal/__init__.py index ac28dd641..ba6e8eead 100644 --- a/pyteal/__init__.py +++ b/pyteal/__init__.py @@ -8,6 +8,7 @@ MIN_TEAL_VERSION, DEFAULT_TEAL_VERSION, MAX_PROGRAM_VERSION, + FRAME_POINTER_VERSION, MIN_PROGRAM_VERSION, DEFAULT_PROGRAM_VERSION, CompileOptions, @@ -38,6 +39,7 @@ "MIN_TEAL_VERSION", "DEFAULT_TEAL_VERSION", "MAX_PROGRAM_VERSION", + "FRAME_POINTER_VERSION", "MIN_PROGRAM_VERSION", "DEFAULT_PROGRAM_VERSION", "CompileOptions", diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index 69e3c55eb..40600d561 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -11,6 +11,7 @@ from pyteal.compiler import ( MIN_TEAL_VERSION, DEFAULT_TEAL_VERSION, MAX_PROGRAM_VERSION, + FRAME_POINTER_VERSION, MIN_PROGRAM_VERSION, DEFAULT_PROGRAM_VERSION, CompileOptions, @@ -116,6 +117,7 @@ __all__ = [ "ExtractUint16", "ExtractUint32", "ExtractUint64", + "FRAME_POINTER_VERSION", "For", "FrameBury", "FrameDig", diff --git a/pyteal/compiler/__init__.py b/pyteal/compiler/__init__.py index e0d29450d..9755ead4f 100644 --- a/pyteal/compiler/__init__.py +++ b/pyteal/compiler/__init__.py @@ -3,6 +3,7 @@ MIN_TEAL_VERSION, DEFAULT_TEAL_VERSION, MAX_PROGRAM_VERSION, + FRAME_POINTER_VERSION, MIN_PROGRAM_VERSION, DEFAULT_PROGRAM_VERSION, CompileOptions, @@ -16,6 +17,7 @@ "MIN_TEAL_VERSION", "DEFAULT_TEAL_VERSION", "MAX_PROGRAM_VERSION", + "FRAME_POINTER_VERSION", "MIN_PROGRAM_VERSION", "DEFAULT_PROGRAM_VERSION", "CompileOptions", diff --git a/pyteal/compiler/compiler.py b/pyteal/compiler/compiler.py index 1955d0430..f2b25b489 100644 --- a/pyteal/compiler/compiler.py +++ b/pyteal/compiler/compiler.py @@ -26,6 +26,7 @@ from pyteal.compiler.constants import createConstantBlocks MAX_PROGRAM_VERSION = 8 +FRAME_POINTER_VERSION = 8 MIN_PROGRAM_VERSION = 2 DEFAULT_PROGRAM_VERSION = MIN_PROGRAM_VERSION From 02f3775fa62d351ee9af27b884656ec5984d38c3 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 26 Oct 2022 17:12:46 -0400 Subject: [PATCH 019/206] just the work of abi data schema --- pyteal/ast/abi/__init__.py | 13 ++++- pyteal/ast/abi/address.py | 15 +++--- pyteal/ast/abi/address_test.py | 73 ++++++++++++++++++++++----- pyteal/ast/abi/array_base.py | 6 +-- pyteal/ast/abi/array_dynamic.py | 8 +-- pyteal/ast/abi/array_dynamic_test.py | 68 ++++++++++++++++++++----- pyteal/ast/abi/array_static.py | 10 ++-- pyteal/ast/abi/array_static_test.py | 49 ++++++++++++++---- pyteal/ast/abi/bool.py | 8 +-- pyteal/ast/abi/bool_test.py | 66 ++++++++++++++++++++---- pyteal/ast/abi/reference_type.py | 8 +-- pyteal/ast/abi/reference_type_test.py | 27 ++++++++-- pyteal/ast/abi/string.py | 29 +++++++---- pyteal/ast/abi/string_test.py | 65 ++++++++++++++++++++---- pyteal/ast/abi/transaction.py | 8 +-- pyteal/ast/abi/transaction_test.py | 8 ++- pyteal/ast/abi/tuple.py | 6 +-- pyteal/ast/abi/tuple_test.py | 22 ++++++-- pyteal/ast/abi/type.py | 64 ++++++++++++++++++++++- pyteal/ast/abi/type_test.py | 2 +- pyteal/ast/abi/uint.py | 39 +++++++------- pyteal/ast/abi/uint_test.py | 64 +++++++++++++++++++---- pyteal/ast/comment.py | 4 +- pyteal/ast/expr.py | 6 +-- pyteal/ast/router.py | 2 +- pyteal/ast/subroutine.py | 18 ++++--- 26 files changed, 529 insertions(+), 159 deletions(-) diff --git a/pyteal/ast/abi/__init__.py b/pyteal/ast/abi/__init__.py index f1cb3a58c..3113b8d72 100644 --- a/pyteal/ast/abi/__init__.py +++ b/pyteal/ast/abi/__init__.py @@ -4,7 +4,15 @@ Address, AddressLength, ) -from pyteal.ast.abi.type import TypeSpec, BaseType, ComputedValue, ReturnedValue +from pyteal.ast.abi.type import ( + TypeSpec, + BaseType, + ComputedValue, + ReturnedValue, + DataStorageSchema, + FrameStorage, + ScratchVarStorage, +) from pyteal.ast.abi.bool import BoolTypeSpec, Bool from pyteal.ast.abi.uint import ( UintTypeSpec, @@ -166,6 +174,9 @@ "type_specs_from_signature", "make", "size_of", + "DataStorageSchema", + "FrameStorage", + "ScratchVarStorage", "algosdk_from_annotation", "algosdk_from_type_spec", "contains_type_spec", diff --git a/pyteal/ast/abi/address.py b/pyteal/ast/abi/address.py index d0413cf6c..3165fcd9a 100644 --- a/pyteal/ast/abi/address.py +++ b/pyteal/ast/abi/address.py @@ -56,7 +56,7 @@ def get(self) -> Expr: The expression will have the type TealType.bytes. """ - return self.stored_value.load() + return self._data_storage.load_value() def set( self, @@ -108,25 +108,28 @@ def set( or value.type_spec() == StaticArrayTypeSpec(ByteTypeSpec(), AddressLength.Bytes) ): - return self.stored_value.store(value.stored_value.load()) + return self._data_storage.store_value( + value._data_storage.load_value() + ) raise TealInputError( f"Got {value} with type spec {value.type_spec()}, expected AddressTypeSpec" ) case str(): # Addr throws if value is invalid address - return self.stored_value.store(Addr(value)) + return self._data_storage.store_value(Addr(value)) case bytes(): if len(value) == AddressLength.Bytes: - return self.stored_value.store(Bytes(value)) + return self._data_storage.store_value(Bytes(value)) raise TealInputError( f"Got bytes with length {len(value)}, expected {AddressLength.Bytes}" ) case Expr(): return Seq( - self.stored_value.store(value), + self._data_storage.store_value(value), Assert( - Len(self.stored_value.load()) == Int(AddressLength.Bytes.value) + Len(self._data_storage.load_value()) + == Int(AddressLength.Bytes.value) ), ) case CollectionSequence(): diff --git a/pyteal/ast/abi/address_test.py b/pyteal/ast/abi/address_test.py index 7cc9cd449..305046619 100644 --- a/pyteal/ast/abi/address_test.py +++ b/pyteal/ast/abi/address_test.py @@ -1,4 +1,5 @@ import pytest +from typing import cast import pyteal as pt from pyteal import abi @@ -48,7 +49,13 @@ def test_Address_encode(): assert expr.has_return() is False expected = pt.TealSimpleBlock( - [pt.TealOp(expr, pt.Op.load, value.stored_value.slot)] + [ + pt.TealOp( + expr, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + ] ) actual, _ = expr.__teal__(options) assert actual == expected @@ -79,7 +86,7 @@ def test_Address_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expectedExpr = value.stored_value.store( + expectedExpr = value._data_storage.store_value( substring_for_decoding( encoded, start_index=start_index, @@ -106,7 +113,13 @@ def test_Address_get(): assert expr.has_return() is False expected = pt.TealSimpleBlock( - [pt.TealOp(expr, pt.Op.load, value.stored_value.slot)] + [ + pt.TealOp( + expr, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + ] ) actual, _ = expr.__teal__(options) assert actual == expected @@ -123,8 +136,16 @@ def test_Address_set_StaticArray(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, value_to_set.stored_value.slot), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value_to_set._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -150,7 +171,11 @@ def test_Address_set_str(): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.addr, value_to_set), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -175,7 +200,11 @@ def test_Address_set_bytes(): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.byte, f"0x{value_to_set.hex()}"), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -204,8 +233,16 @@ def test_Address_set_expr(): expected = pt.TealSimpleBlock( [ vts.ops[0], - pt.TealOp(None, pt.Op.store, value.stored_value.slot), - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.int, AddressLength.Bytes.value), pt.TealOp(None, pt.Op.eq), @@ -230,8 +267,16 @@ def test_Address_set_copy(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, other.stored_value.slot), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -259,7 +304,11 @@ def test_Address_set_computed(): expected = pt.TealSimpleBlock( [ byte_ops.ops[0], - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) diff --git a/pyteal/ast/abi/array_base.py b/pyteal/ast/abi/array_base.py index aea164c81..4674f1d90 100644 --- a/pyteal/ast/abi/array_base.py +++ b/pyteal/ast/abi/array_base.py @@ -104,7 +104,7 @@ def decode( extracted = substring_for_decoding( encoded, start_index=start_index, end_index=end_index, length=length ) - return self.stored_value.store(extracted) + return self._data_storage.store_value(extracted) def set(self, values: Sequence[T]) -> Expr: """Set the ABI array with a sequence of ABI type variables. @@ -142,7 +142,7 @@ def set(self, values: Sequence[T]) -> Expr: length_prefix = Seq(length_tmp.set(len(values)), length_tmp.encode()) encoded = Concat(length_prefix, encoded) - return self.stored_value.store(encoded) + return self._data_storage.store_value(encoded) def encode(self) -> Expr: """Encode the ABI array to be a byte string. @@ -150,7 +150,7 @@ def encode(self) -> Expr: Returns: A PyTeal expression that encodes this ABI array to a byte string. """ - return self.stored_value.load() + return self._data_storage.load_value() @abstractmethod def length(self) -> Expr: diff --git a/pyteal/ast/abi/array_dynamic.py b/pyteal/ast/abi/array_dynamic.py index 9d53e0559..2a5f7367d 100644 --- a/pyteal/ast/abi/array_dynamic.py +++ b/pyteal/ast/abi/array_dynamic.py @@ -79,7 +79,7 @@ def set( raise TealInputError( f"Cannot assign type {values.type_spec()} to {self.type_spec()}" ) - return self.stored_value.store(values.encode()) + return self._data_storage.store_value(values.encode()) return super().set(values) def length(self) -> Expr: @@ -165,10 +165,10 @@ def set( match values: case bytes() | bytearray(): - return self.stored_value.store(_encoded_byte_string(values)) + return self._data_storage.store_value(_encoded_byte_string(values)) case Expr(): return _store_encoded_expr_byte_string_into_var( - values, self.stored_value + values, self._data_storage ) return super().set(values) @@ -181,7 +181,7 @@ def get(self) -> Expr: Returns: A Pyteal expression that loads byte encoding of this DynamicBytes, and drop the first uint16 DynamicArray length encoding. """ - return Suffix(self.stored_value.load(), Int(2)) + return Suffix(self._data_storage.load_value(), Int(2)) DynamicBytes.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/array_dynamic_test.py b/pyteal/ast/abi/array_dynamic_test.py index 326f72294..fa0e122e1 100644 --- a/pyteal/ast/abi/array_dynamic_test.py +++ b/pyteal/ast/abi/array_dynamic_test.py @@ -1,4 +1,4 @@ -from typing import List +from typing import List, cast import pytest import pyteal as pt @@ -106,7 +106,7 @@ def test_DynamicArray_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value.stored_value.store( + expectedExpr = value._data_storage.store_value( substring_for_decoding( encoded, start_index=start_index, @@ -141,7 +141,7 @@ def test_DynamicArray_set_values(): assert not expr.has_return() length_tmp = abi.Uint16() - expectedExpr = value.stored_value.store( + expectedExpr = value._data_storage.store_value( pt.Concat( pt.Seq(length_tmp.set(len(values)), length_tmp.encode()), _encode_tuple(values), @@ -182,8 +182,16 @@ def test_DynamicArray_set_copy(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, otherArray.stored_value.slot), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, otherArray._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -207,7 +215,11 @@ def test_DynamicArray_set_computed(): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.byte, '"this should be a dynamic array"'), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) actual, _ = expr.__teal__(options) @@ -253,7 +265,11 @@ def test_DynamicBytes_set_py_bytes(test_case: bytes | bytearray): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.byte, "0x" + length_encoding + BYTE_HEX_TEST_CASE), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -280,14 +296,30 @@ def test_DynamicBytes_set_expr(test_case: bytes | bytearray): pt.TealOp(None, pt.Op.byte, "0x" + BYTE_HEX_TEST_CASE), pt.TealOp(None, pt.Op.byte, "0x" + BYTE_HEX_TEST_CASE), pt.TealOp(None, pt.Op.concat), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.itob), pt.TealOp(None, pt.Op.extract, 6, 0), - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.concat), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -308,7 +340,11 @@ def test_DynamicBytes_get(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.extract, 2, 0), ] ) @@ -325,7 +361,13 @@ def test_DynamicArray_encode(): assert not expr.has_return() expected = pt.TealSimpleBlock( - [pt.TealOp(None, pt.Op.load, value.stored_value.slot)] + [ + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + ] ) actual, _ = expr.__teal__(options) diff --git a/pyteal/ast/abi/array_static.py b/pyteal/ast/abi/array_static.py index 7744a6edb..caf2dcc88 100644 --- a/pyteal/ast/abi/array_static.py +++ b/pyteal/ast/abi/array_static.py @@ -109,7 +109,7 @@ def set( raise TealInputError( f"Cannot assign type {values.type_spec()} to {self.type_spec()}" ) - return self.stored_value.store(values.encode()) + return self._data_storage.store_value(values.encode()) if self.type_spec().length_static() != len(values): raise TealInputError( @@ -207,11 +207,11 @@ def set( raise TealInputError( f"Got bytes with length {len(values)}, expect {self.type_spec().length_static()}" ) - return self.stored_value.store(Bytes(values)) + return self._data_storage.store_value(Bytes(values)) case Expr(): return Seq( - self.stored_value.store(values), - Assert(self.length() == Len(self.stored_value.load())), + self._data_storage.store_value(values), + Assert(self.length() == Len(self._data_storage.load_value())), ) return super().set(values) @@ -222,7 +222,7 @@ def get(self) -> Expr: Returns: A Pyteal expression that loads byte encoding of this StaticBytes. """ - return self.stored_value.load() + return self._data_storage.load_value() StaticBytes.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/array_static_test.py b/pyteal/ast/abi/array_static_test.py index 91781a682..236e2591e 100644 --- a/pyteal/ast/abi/array_static_test.py +++ b/pyteal/ast/abi/array_static_test.py @@ -1,4 +1,5 @@ import pytest +from typing import cast import pyteal as pt from pyteal import abi @@ -158,7 +159,7 @@ def test_StaticArray_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value.stored_value.store( + expectedExpr = value._data_storage.store_value( substring_for_decoding( encoded, start_index=start_index, @@ -201,7 +202,7 @@ def test_StaticArray_set_values(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value.stored_value.store(_encode_tuple(values)) + expectedExpr = value._data_storage.store_value(_encode_tuple(values)) expected, _ = expectedExpr.__teal__(options) expected.addIncoming() expected = pt.TealBlock.NormalizeBlocks(expected) @@ -233,8 +234,16 @@ def test_StaticArray_set_copy(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, otherArray.stored_value.slot), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, otherArray._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -258,7 +267,11 @@ def test_StaticArray_set_computed(): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.byte, '"indeed this is hard to simulate"'), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) actual, _ = expr.__teal__(options) @@ -301,7 +314,11 @@ def test_StaticBytes_set_py_bytes(test_case: bytes | bytearray): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.byte, "0x" + BYTE_HEX_TEST_CASE), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -332,9 +349,17 @@ def test_StaticBytes_expr(test_case: bytes | bytearray): pt.TealOp(None, pt.Op.byte, "0x" + BYTE_HEX_TEST_CASE), pt.TealOp(None, pt.Op.byte, "0x" + BYTE_HEX_TEST_CASE), pt.TealOp(None, pt.Op.concat), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.int, 32), - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.eq), pt.TealOp(None, pt.Op.assert_), @@ -352,7 +377,13 @@ def test_StaticArray_encode(): assert not expr.has_return() expected = pt.TealSimpleBlock( - [pt.TealOp(None, pt.Op.load, value.stored_value.slot)] + [ + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + ] ) actual, _ = expr.__teal__(options) diff --git a/pyteal/ast/abi/bool.py b/pyteal/ast/abi/bool.py index 13552b6db..2bfbd3aca 100644 --- a/pyteal/ast/abi/bool.py +++ b/pyteal/ast/abi/bool.py @@ -50,7 +50,7 @@ def get(self) -> Expr: expression that evaluates to 0 will be returned. In either case, the expression will have the type TealType.uint64. """ - return self.stored_value.load() + return self._data_storage.load_value() def set(self, value: Union[bool, Expr, "Bool", ComputedValue["Bool"]]) -> Expr: """Set the value of this Bool to the input value. @@ -85,10 +85,10 @@ def set(self, value: Union[bool, Expr, "Bool", ComputedValue["Bool"]]) -> Expr: checked = True if checked: - return self.stored_value.store(value) + return self._data_storage.store_value(value) # Not(Not(value)) coerces all values greater than 0 to 1 - return self.stored_value.store(Not(Not(value))) + return self._data_storage.store_value(Not(Not(value))) def decode( self, @@ -103,7 +103,7 @@ def decode( return self.decode_bit(encoded, start_index * Int(NUM_BITS_IN_BYTE)) def decode_bit(self, encoded, bit_index: Expr) -> Expr: - return self.stored_value.store(GetBit(encoded, bit_index)) + return self._data_storage.store_value(GetBit(encoded, bit_index)) def encode(self) -> Expr: return SetBit(Bytes(b"\x00"), Int(0), self.get()) diff --git a/pyteal/ast/abi/bool_test.py b/pyteal/ast/abi/bool_test.py index 45ffa7e30..411bdf376 100644 --- a/pyteal/ast/abi/bool_test.py +++ b/pyteal/ast/abi/bool_test.py @@ -1,4 +1,4 @@ -from typing import NamedTuple, List +from typing import NamedTuple, List, cast import pytest import pyteal as pt @@ -53,7 +53,11 @@ def test_Bool_set_static(): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.int, 1 if value_to_set else 0), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -78,7 +82,11 @@ def test_Bool_set_expr(): pt.TealOp(None, pt.Op.logic_or), pt.TealOp(None, pt.Op.logic_not), pt.TealOp(None, pt.Op.logic_not), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -99,8 +107,16 @@ def test_Bool_set_copy(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, other.stored_value.slot), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -125,7 +141,11 @@ def test_Bool_set_computed(): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.int, 0x80), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -147,7 +167,13 @@ def test_Bool_get(): assert not expr.has_return() expected = pt.TealSimpleBlock( - [pt.TealOp(expr, pt.Op.load, value.stored_value.slot)] + [ + pt.TealOp( + expr, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + ] ) actual, _ = expr.__teal__(options) @@ -174,7 +200,13 @@ def test_Bool_decode(): pt.TealOp(None, pt.Op.int, 8), pt.TealOp(None, pt.Op.mul), pt.TealOp(None, pt.Op.getbit), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast( + abi.ScratchVarStorage, value._data_storage + ).scratchvar.slot, + ), ] ) @@ -199,7 +231,11 @@ def test_Bool_decode_bit(): pt.TealOp(None, pt.Op.byte, '"encoded"'), pt.TealOp(None, pt.Op.int, 17), pt.TealOp(None, pt.Op.getbit), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -221,7 +257,11 @@ def test_Bool_encode(): [ pt.TealOp(None, pt.Op.byte, "0x00"), pt.TealOp(None, pt.Op.int, 0), - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.setbit), ] ) @@ -401,7 +441,11 @@ class EncodeSeqTest(NamedTuple): setBits = [ [ pt.TealOp(None, pt.Op.int, j), - pt.TealOp(None, pt.Op.load, testType.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, testType._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.setbit), ] for j, testType in enumerate(test.types) diff --git a/pyteal/ast/abi/reference_type.py b/pyteal/ast/abi/reference_type.py index f4882fc97..2ea723b92 100644 --- a/pyteal/ast/abi/reference_type.py +++ b/pyteal/ast/abi/reference_type.py @@ -58,7 +58,7 @@ def referenced_index(self) -> Expr: If this reference type is an application or asset, note that this DOES NOT return the application or asset ID. See :code:`application_id()` or :code:`asset_id()` for that. """ - return self.stored_value.load() + return self._data_storage.load_value() def decode( self, @@ -70,7 +70,7 @@ def decode( ) -> Expr: return uint_decode( self.type_spec().bit_size(), - self.stored_value, + self._data_storage, encoded, start_index, end_index, @@ -107,7 +107,7 @@ def __init__(self) -> None: def address(self) -> Expr: """Get the address of the account.""" - return Txn.accounts[self.stored_value.load()] + return Txn.accounts[self._data_storage.load_value()] def params(self) -> AccountParamObject: """Get information about the account.""" @@ -205,7 +205,7 @@ def __init__(self) -> None: def application_id(self) -> Expr: """Get the ID of the application.""" - return Txn.applications[self.stored_value.load()] + return Txn.applications[self._data_storage.load_value()] def params(self) -> AppParamObject: """Get information about the application's parameters.""" diff --git a/pyteal/ast/abi/reference_type_test.py b/pyteal/ast/abi/reference_type_test.py index 99555ab12..aaa1e5d97 100644 --- a/pyteal/ast/abi/reference_type_test.py +++ b/pyteal/ast/abi/reference_type_test.py @@ -1,4 +1,5 @@ import pytest +from typing import cast import pyteal as pt from pyteal import abi @@ -22,7 +23,11 @@ def test_ReferenceType_referenced_index(): expected = pt.TealSimpleBlock( [ - pt.TealOp(expr, pt.Op.load, value.stored_value.slot), + pt.TealOp( + expr, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) actual, _ = expr.__teal__(options) @@ -56,7 +61,7 @@ def test_ReferenceType_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expected_decoding = value.stored_value.store( + expected_decoding = value._data_storage.store_value( pt.GetByte( encoded, start_index if start_index is not None else pt.Int(0), @@ -109,7 +114,11 @@ def test_Account_address(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.txnas, "Accounts"), ] ) @@ -192,7 +201,11 @@ def test_Asset_asset_id(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.txnas, "Assets"), ] ) @@ -282,7 +295,11 @@ def test_Application_application_id(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.txnas, "Applications"), ] ) diff --git a/pyteal/ast/abi/string.py b/pyteal/ast/abi/string.py index 4c9b31c08..0359aee76 100644 --- a/pyteal/ast/abi/string.py +++ b/pyteal/ast/abi/string.py @@ -4,7 +4,7 @@ from algosdk.abi import ABIType from pyteal.ast.abi.uint import Byte -from pyteal.ast.abi.type import ComputedValue, BaseType +from pyteal.ast.abi.type import ComputedValue, BaseType, DataStorageSchema from pyteal.ast.abi.array_dynamic import DynamicArray, DynamicArrayTypeSpec from pyteal.ast.abi.uint import ByteTypeSpec, Uint16TypeSpec @@ -12,7 +12,6 @@ from pyteal.ast.expr import Expr from pyteal.ast.bytes import Bytes from pyteal.ast.seq import Seq -from pyteal.ast.scratchvar import ScratchVar from pyteal.ast.unaryexpr import Itob, Len from pyteal.ast.substring import Suffix from pyteal.ast.naryexpr import Concat @@ -25,11 +24,15 @@ def _encoded_byte_string(s: bytes | bytearray) -> Expr: return Bytes(prefix + s) -def _store_encoded_expr_byte_string_into_var(value: Expr, location: ScratchVar) -> Expr: +def _store_encoded_expr_byte_string_into_var( + value: Expr, location: DataStorageSchema +) -> Expr: return Seq( - location.store(value), - location.store( - Concat(Suffix(Itob(Len(location.load())), Int(6)), location.load()) + location.store_value(value), + location.store_value( + Concat( + Suffix(Itob(Len(location.load_value())), Int(6)), location.load_value() + ) ), ) @@ -67,7 +70,7 @@ def get(self) -> Expr: The expression will have the type TealType.bytes. """ return Suffix( - self.stored_value.load(), Int(Uint16TypeSpec().byte_length_static()) + self._data_storage.load_value(), Int(Uint16TypeSpec().byte_length_static()) ) def set( @@ -110,18 +113,22 @@ def set( if value.type_spec() == StringTypeSpec() or ( value.type_spec() == DynamicArrayTypeSpec(ByteTypeSpec()) ): - return self.stored_value.store(value.stored_value.load()) + return self._data_storage.store_value( + value._data_storage.load_value() + ) raise TealInputError( f"Got {value} with type spec {value.type_spec()}, expected {StringTypeSpec}" ) case bytes() | bytearray(): - return self.stored_value.store(_encoded_byte_string(value)) + return self._data_storage.store_value(_encoded_byte_string(value)) case str(): - return self.stored_value.store(_encoded_byte_string(value.encode())) + return self._data_storage.store_value( + _encoded_byte_string(value.encode()) + ) case Expr(): return _store_encoded_expr_byte_string_into_var( - value, self.stored_value + value, self._data_storage ) case CollectionSequence(): return super().set(cast(Sequence[Byte], value)) diff --git a/pyteal/ast/abi/string_test.py b/pyteal/ast/abi/string_test.py index 6a600d55a..79a699a4c 100644 --- a/pyteal/ast/abi/string_test.py +++ b/pyteal/ast/abi/string_test.py @@ -1,4 +1,5 @@ import pytest +from typing import cast import pyteal as pt from pyteal import abi @@ -39,7 +40,13 @@ def test_String_encode(): assert expr.has_return() is False expected = pt.TealSimpleBlock( - [pt.TealOp(expr, pt.Op.load, value.stored_value.slot)] + [ + pt.TealOp( + expr, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + ] ) actual, _ = expr.__teal__(options) assert actual == expected @@ -69,7 +76,7 @@ def test_DynamicArray_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expectedExpr = value.stored_value.store( + expectedExpr = value._data_storage.store_value( substring_for_decoding( encoded, start_index=start_index, @@ -97,7 +104,11 @@ def test_String_get(): expected = pt.TealSimpleBlock( [ - pt.TealOp(expr, pt.Op.load, value.stored_value.slot), + pt.TealOp( + expr, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.extract, 2, 0), ] ) @@ -129,7 +140,11 @@ def test_String_set_static(value_to_set, value_encoded): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.byte, "0x" + value_encoded.hex()), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -156,14 +171,30 @@ def test_String_set_expr(): value_start, value_end = value_to_set.__teal__(options) expected_body = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.store, value.stored_value.slot), - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.itob), pt.TealOp(None, pt.Op.extract, 6, 0), - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.concat), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) value_end.setNextBlock(expected_body) @@ -188,8 +219,16 @@ def test_String_set_copy(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, other.stored_value.slot), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -217,7 +256,11 @@ def test_String_set_computed(): expected = pt.TealSimpleBlock( [ byte_ops.ops[0], - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) diff --git a/pyteal/ast/abi/transaction.py b/pyteal/ast/abi/transaction.py index aeb5c7a33..2451a1285 100644 --- a/pyteal/ast/abi/transaction.py +++ b/pyteal/ast/abi/transaction.py @@ -82,16 +82,16 @@ def _set_index( case ComputedValue(): return self._set_with_computed_type(value) case BaseType(): - return self.stored_value.store(self.stored_value.load()) + return self._data_storage.store_value(self._data_storage.load_value()) case int(): - return self.stored_value.store(Int(value)) + return self._data_storage.store_value(Int(value)) case Expr(): - return self.stored_value.store(value) + return self._data_storage.store_value(value) case _: raise TealInputError(f"Cant store a {type(value)} in a Transaction") def index(self) -> Expr: - return self.stored_value.load() + return self._data_storage.load_value() def decode( self, diff --git a/pyteal/ast/abi/transaction_test.py b/pyteal/ast/abi/transaction_test.py index 5803b8f32..573d6f440 100644 --- a/pyteal/ast/abi/transaction_test.py +++ b/pyteal/ast/abi/transaction_test.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import List +from typing import List, cast import pyteal as pt from pyteal import abi import pytest @@ -131,7 +131,11 @@ def test_Transaction__set_index(): expected = pt.TealSimpleBlock( [ pt.TealOp(expr, pt.Op.int, val_to_set), - pt.TealOp(None, pt.Op.store, tv.t.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, tv.t._data_storage).scratchvar.slot, + ), ] ) actual, _ = expr.__teal__(options) diff --git a/pyteal/ast/abi/tuple.py b/pyteal/ast/abi/tuple.py index bc1966414..2f2dceeab 100644 --- a/pyteal/ast/abi/tuple.py +++ b/pyteal/ast/abi/tuple.py @@ -309,7 +309,7 @@ def decode( extracted = substring_for_decoding( encoded, start_index=start_index, end_index=end_index, length=length ) - return self.stored_value.store(extracted) + return self._data_storage.store_value(extracted) @overload def set(self, *values: BaseType) -> Expr: @@ -352,10 +352,10 @@ def set(self, *values): ) if not all(myTypes[i] == values[i].type_spec() for i in range(len(myTypes))): raise TealInputError("Input values do not match type") - return self.stored_value.store(_encode_tuple(values)) + return self._data_storage.store_value(_encode_tuple(values)) def encode(self) -> Expr: - return self.stored_value.load() + return self._data_storage.load_value() def length(self) -> Expr: """Get the number of values this tuple holds as an Expr.""" diff --git a/pyteal/ast/abi/tuple_test.py b/pyteal/ast/abi/tuple_test.py index 7fc98cdae..8365769cc 100644 --- a/pyteal/ast/abi/tuple_test.py +++ b/pyteal/ast/abi/tuple_test.py @@ -1,4 +1,4 @@ -from typing import NamedTuple, List, Callable, Literal +from typing import NamedTuple, List, Callable, Literal, cast import pytest import pyteal as pt @@ -623,7 +623,7 @@ def test_Tuple_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = tupleValue.stored_value.store( + expectedExpr = tupleValue._data_storage.store_value( substring_for_decoding( encoded, start_index=start_index, @@ -672,7 +672,9 @@ def test_Tuple_set(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = tupleValue.stored_value.store(_encode_tuple([uint8, uint16, uint32])) + expectedExpr = tupleValue._data_storage.store_value( + _encode_tuple([uint8, uint16, uint32]) + ) expected, _ = expectedExpr.__teal__(options) expected.addIncoming() expected = pt.TealBlock.NormalizeBlocks(expected) @@ -701,7 +703,11 @@ def test_Tuple_set_Computed(): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.byte, '"internal representation"'), - pt.TealOp(None, pt.Op.store, tupleValue.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, tupleValue._data_storage).scratchvar.slot, + ), ] ) actual, _ = expr.__teal__(options) @@ -727,7 +733,13 @@ def test_Tuple_encode(): assert not expr.has_return() expected = pt.TealSimpleBlock( - [pt.TealOp(None, pt.Op.load, tupleValue.stored_value.slot)] + [ + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, tupleValue._data_storage).scratchvar.slot, + ), + ] ) actual, _ = expr.__teal__(options) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index 4b0b1e0f3..67d75cc4b 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -65,6 +65,55 @@ def __str__(self) -> str: TypeSpec.__module__ = "pyteal.abi" +class DataStorageSchema(ABC): + @abstractmethod + def store_value(self, value: Expr) -> Expr: + pass + + @abstractmethod + def load_value(self) -> Expr: + pass + + @abstractmethod + def storage_type(self) -> TealType: + pass + + +class ScratchVarStorage(DataStorageSchema): + def __init__(self, storage_type: TealType) -> None: + super().__init__() + self.scratchvar: Final = ScratchVar(storage_type) + + def load_value(self) -> Expr: + return self.scratchvar.load() + + def store_value(self, value: Expr) -> Expr: + return self.scratchvar.slot.store(value) + + def storage_type(self) -> TealType: + return self.scratchvar.storage_type() + + +class FrameStorage(DataStorageSchema): + def __init__(self, storage_type: TealType, stack_depth: int) -> None: + super().__init__() + self.stack_type = storage_type + self.stack_depth = stack_depth + + def storage_type(self) -> TealType: + return self.stack_type + + def store_value(self, value: Expr) -> Expr: + from pyteal.ast import FrameBury + + return FrameBury(value, self.stack_depth) + + def load_value(self) -> Expr: + from pyteal.ast import FrameDig + + return FrameDig(self.stack_depth) + + class BaseType(ABC): """The abstract base class for all ABI type instances. @@ -77,7 +126,18 @@ def __init__(self, spec: TypeSpec) -> None: """Create a new BaseType.""" super().__init__() self._type_spec: Final = spec - self.stored_value: Final = ScratchVar(spec.storage_type()) + self._data_storage: DataStorageSchema = ScratchVarStorage(spec.storage_type()) + + # self.stored_value: Final = ScratchVar(spec.storage_type()) + + def _set_data_source(self, storage: DataStorageSchema) -> None: + self._data_storage = storage + + def _load_value(self) -> Expr: + return self._data_storage.load_value() + + def _store_value(self, value: Expr) -> Expr: + return self._data_storage.store_value(value) def type_spec(self) -> TypeSpec: """Get the TypeSpec for this ABI type instance.""" @@ -231,7 +291,7 @@ def store_into(self, output: BaseType) -> Expr: f"ABI return subroutine deferred_expr is expected to be typed {output.type_spec().storage_type()}, " f"but has type {declaration.deferred_expr.type_of()}." ) - return output.stored_value.slot.store(self.computation) + return output._data_storage.store_value(self.computation) ReturnedValue.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/type_test.py b/pyteal/ast/abi/type_test.py index 56a9e6c76..b5134ef7d 100644 --- a/pyteal/ast/abi/type_test.py +++ b/pyteal/ast/abi/type_test.py @@ -17,7 +17,7 @@ def store_into(self, output: abi.BaseType) -> pt.Expr: raise pt.TealInputError( f"expected type_spec {self.type_spec} but get {output.type_spec()}" ) - return output.stored_value.store(self.encodings) + return output._data_storage.store_value(self.encodings) def test_ComputedType_use(): diff --git a/pyteal/ast/abi/uint.py b/pyteal/ast/abi/uint.py index 9855c29b9..e34daac9a 100644 --- a/pyteal/ast/abi/uint.py +++ b/pyteal/ast/abi/uint.py @@ -8,7 +8,6 @@ from pyteal.types import TealType from pyteal.errors import TealInputError -from pyteal.ast.scratchvar import ScratchVar from pyteal.ast.expr import Expr from pyteal.ast.seq import Seq from pyteal.ast.assert_ import Assert @@ -18,7 +17,7 @@ from pyteal.ast.unaryexpr import Itob, Btoi from pyteal.ast.binaryexpr import GetByte, ExtractUint16, ExtractUint32, ExtractUint64 from pyteal.ast.ternaryexpr import SetByte -from pyteal.ast.abi.type import ComputedValue, TypeSpec, BaseType +from pyteal.ast.abi.type import ComputedValue, TypeSpec, BaseType, DataStorageSchema NUM_BITS_IN_BYTE = 8 @@ -31,7 +30,9 @@ def uint_storage_type(size: int) -> TealType: return TealType.bytes -def uint_set(size: int, uint_var: ScratchVar, value: Union[int, Expr, "Uint"]) -> Expr: +def uint_set( + size: int, uint_var: DataStorageSchema, value: Union[int, Expr, "Uint"] +) -> Expr: if size > 64: raise NotImplementedError( "Uint operations have not yet been implemented for bit sizes larger than 64" @@ -49,17 +50,17 @@ def uint_set(size: int, uint_var: ScratchVar, value: Union[int, Expr, "Uint"]) - checked = True if checked or size == 64: - return uint_var.store(cast(Expr, value)) + return uint_var.store_value(cast(Expr, value)) return Seq( - uint_var.store(cast(Expr, value)), - Assert(uint_var.load() < Int(2**size)), + uint_var.store_value(cast(Expr, value)), + Assert(uint_var.load_value() < Int(2**size)), ) def uint_decode( size: int, - uint_var: ScratchVar, + uint_var: DataStorageSchema, encoded: Expr, start_index: Optional[Expr], end_index: Optional[Expr], @@ -73,27 +74,27 @@ def uint_decode( if size == 64: if start_index is None: if end_index is None and length is None: - return uint_var.store(Btoi(encoded)) + return uint_var.store_value(Btoi(encoded)) start_index = Int(0) - return uint_var.store(ExtractUint64(encoded, start_index)) + return uint_var.store_value(ExtractUint64(encoded, start_index)) if start_index is None: start_index = Int(0) if size == 8: - return uint_var.store(GetByte(encoded, start_index)) + return uint_var.store_value(GetByte(encoded, start_index)) if size == 16: - return uint_var.store(ExtractUint16(encoded, start_index)) + return uint_var.store_value(ExtractUint16(encoded, start_index)) if size == 32: - return uint_var.store(ExtractUint32(encoded, start_index)) + return uint_var.store_value(ExtractUint32(encoded, start_index)) raise ValueError("Unsupported uint size: {}".format(size)) -def uint_encode(size: int, uint_var: Expr | ScratchVar) -> Expr: +def uint_encode(size: int, uint_var: Expr | DataStorageSchema) -> Expr: - if isinstance(uint_var, ScratchVar): - uint_var = uint_var.load() + if isinstance(uint_var, DataStorageSchema): + uint_var = uint_var.load_value() if size > 64: raise NotImplementedError( @@ -240,7 +241,7 @@ def get(self) -> Expr: The expression will have the type TealType.uint64. """ - return self.stored_value.load() + return self._data_storage.load_value() def set(self, value: Union[int, Expr, "Uint", ComputedValue["Uint"]]) -> Expr: """Set the value of this Uint to the input value. @@ -275,7 +276,7 @@ def set(self, value: Union[int, Expr, "Uint", ComputedValue["Uint"]]) -> Expr: value.type_spec(), self.type_spec() ) ) - return uint_set(self.type_spec().bit_size(), self.stored_value, value) + return uint_set(self.type_spec().bit_size(), self._data_storage, value) def decode( self, @@ -287,7 +288,7 @@ def decode( ) -> Expr: return uint_decode( self.type_spec().bit_size(), - self.stored_value, + self._data_storage, encoded, start_index, end_index, @@ -295,7 +296,7 @@ def decode( ) def encode(self) -> Expr: - return uint_encode(self.type_spec().bit_size(), self.stored_value) + return uint_encode(self.type_spec().bit_size(), self._data_storage) Uint.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/uint_test.py b/pyteal/ast/abi/uint_test.py index 3af64f865..c4659fdb9 100644 --- a/pyteal/ast/abi/uint_test.py +++ b/pyteal/ast/abi/uint_test.py @@ -1,4 +1,4 @@ -from typing import List, Tuple, NamedTuple, Callable, Union, Optional +from typing import List, Tuple, NamedTuple, Callable, Union, Optional, cast from pyteal.ast.abi.type_test import ContainerType import pyteal as pt from pyteal import abi @@ -139,7 +139,13 @@ def test_Uint_set_static(): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.int, value_to_set), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast( + abi.ScratchVarStorage, value._data_storage + ).scratchvar.slot, + ), ] ) @@ -167,7 +173,11 @@ def test_Uint_set_expr(): upperBoundCheck = [] if test.checkUpperBound: upperBoundCheck = [ - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.int, test.maxValue + 1), pt.TealOp(None, pt.Op.lt), pt.TealOp(None, pt.Op.assert_), @@ -178,7 +188,11 @@ def test_Uint_set_expr(): pt.TealOp(None, pt.Op.int, 10), pt.TealOp(None, pt.Op.int, 1), pt.TealOp(None, pt.Op.add), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] + upperBoundCheck ) @@ -201,8 +215,16 @@ def test_Uint_set_copy(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, other.stored_value.slot), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -230,7 +252,11 @@ def test_Uint_set_computed(): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.int, 0x44), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -253,7 +279,13 @@ def test_Uint_get(): assert not expr.has_return() expected = pt.TealSimpleBlock( - [pt.TealOp(expr, pt.Op.load, value.stored_value.slot)] + [ + pt.TealOp( + expr, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + ] ) actual, _ = expr.__teal__(options) @@ -277,7 +309,7 @@ def test_Uint_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedDecoding = value.stored_value.store( + expectedDecoding = value._data_storage.store_value( test.expectedDecoding(encoded, start_index, end_index, length) ) expected, _ = expectedDecoding.__teal__(options) @@ -326,8 +358,18 @@ def test_ByteUint8_mutual_conversion(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, other.stored_value.slot), - pt.TealOp(None, pt.Op.store, type_b_instance.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.store, + cast( + abi.ScratchVarStorage, type_b_instance._data_storage + ).scratchvar.slot, + ), ] ) diff --git a/pyteal/ast/comment.py b/pyteal/ast/comment.py index 58c89d63d..361694677 100644 --- a/pyteal/ast/comment.py +++ b/pyteal/ast/comment.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Tuple +from typing import TYPE_CHECKING from pyteal.errors import TealInputError from pyteal.types import TealType @@ -26,7 +26,7 @@ def __init__(self, single_line_comment: str) -> None: ) self.comment = single_line_comment - def __teal__(self, options: "CompileOptions") -> Tuple[TealBlock, TealSimpleBlock]: + def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: op = TealOp(self, Op.comment, self.comment) return TealBlock.FromOp(options, op) diff --git a/pyteal/ast/expr.py b/pyteal/ast/expr.py index c2de1ca32..0f57eebce 100644 --- a/pyteal/ast/expr.py +++ b/pyteal/ast/expr.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from typing import Tuple, List, TYPE_CHECKING +from typing import TYPE_CHECKING from pyteal.types import TealType from pyteal.ir import TealBlock, TealSimpleBlock @@ -16,7 +16,7 @@ def __init__(self): self.trace = traceback.format_stack()[0:-1] - def getDefinitionTrace(self) -> List[str]: + def getDefinitionTrace(self) -> list[str]: return self.trace @abstractmethod @@ -35,7 +35,7 @@ def __str__(self) -> str: pass @abstractmethod - def __teal__(self, options: "CompileOptions") -> Tuple[TealBlock, TealSimpleBlock]: + def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: """Assemble TEAL IR for this component and its arguments.""" pass diff --git a/pyteal/ast/router.py b/pyteal/ast/router.py index 5349cfe84..d10204501 100644 --- a/pyteal/ast/router.py +++ b/pyteal/ast/router.py @@ -352,7 +352,7 @@ def wrap_handler( ) # All subroutine arg values, initialize here and use below instead of - # creating new instances on the fly so we dont have to think about splicing + # creating new instances on the fly, so we don't have to think about splicing # back in the transaction types arg_vals = [typespec.new_instance() for typespec in arg_type_specs] diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 0c5e0205f..7fd38bc9d 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -9,7 +9,7 @@ from pyteal.ast.expr import Expr from pyteal.ast.seq import Seq from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar -from pyteal.errors import TealInputError, verifyProgramVersion +from pyteal.errors import TealInputError, TealInternalError, verifyProgramVersion from pyteal.ir import TealOp, Op, TealBlock from pyteal.types import TealType @@ -378,7 +378,7 @@ def __init__( elif isinstance(arg, ScratchVar): arg_type = arg.type elif isinstance(arg, abi.BaseType): - arg_type = cast(abi.BaseType, arg).stored_value.type + arg_type = cast(abi.BaseType, arg)._data_storage.storage_type() else: raise TealInputError( f"Subroutine argument {arg} at index {i} was of unexpected Python type {type(arg)}" @@ -420,7 +420,7 @@ def handle_arg(arg: Expr | ScratchVar | abi.BaseType) -> Expr: elif isinstance(arg, Expr): return arg elif isinstance(arg, abi.BaseType): - return arg.stored_value.load() + return arg._data_storage.load_value() else: raise TealInputError( f"cannot handle current arg: {arg} to put it on stack" @@ -595,8 +595,6 @@ def __call__( ) return invoked - self.subroutine.get_declaration() - return abi.ReturnedValue( self.output_kwarg_info.abi_type, invoked, @@ -793,6 +791,8 @@ def evaluate_subroutine(subroutine: SubroutineDefinition) -> SubroutineDeclarati def var_n_loaded( param: str, ) -> tuple[ScratchVar, ScratchVar | abi.BaseType | Expr]: + from pyteal.ast.abi.type import ScratchVarStorage + loaded_var: ScratchVar | abi.BaseType | Expr argument_var: ScratchVar @@ -801,7 +801,11 @@ def var_n_loaded( loaded_var = argument_var elif param in subroutine.abi_args: internal_abi_var = subroutine.abi_args[param].new_instance() - argument_var = internal_abi_var.stored_value + if not isinstance(internal_abi_var._data_storage, ScratchVarStorage): + raise TealInternalError( + "subroutine ABI args must have data schema being ScratchVarStorage" + ) + argument_var = internal_abi_var._data_storage.scratchvar loaded_var = internal_abi_var else: argument_var = ScratchVar(TealType.anytype) @@ -849,7 +853,7 @@ def var_n_loaded( f"ABI returning subroutine definition should evaluate to TealType.none, " f"while evaluate to {subroutine_body.type_of()}." ) - deferred_expr = output_carrying_abi.stored_value.load() + deferred_expr = output_carrying_abi._data_storage.load_value() # Arg usage "A" to be pick up and store in scratch parameters that have been placed on the stack # need to reverse order of argumentVars because the last argument will be on top of the stack From e8c5d2ca085a3194c21ed762e5abf95a952c6797 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 19 Oct 2022 13:22:41 -0400 Subject: [PATCH 020/206] squashed --- pyteal/ast/subroutine.py | 253 ++++++++++++++++++++++++++++++++++-- pyteal/compiler/compiler.py | 10 +- 2 files changed, 250 insertions(+), 13 deletions(-) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 7fd38bc9d..bad4b5cb1 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -8,7 +8,8 @@ from pyteal.ast import abi from pyteal.ast.expr import Expr from pyteal.ast.seq import Seq -from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar +from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar, ScratchSlot +from pyteal.ast.frame import FrameDig, Proto from pyteal.errors import TealInputError, TealInternalError, verifyProgramVersion from pyteal.ir import TealOp, Op, TealBlock from pyteal.types import TealType @@ -17,6 +18,100 @@ from pyteal.compiler import CompileOptions +class _SubroutineDeclByVersion: + def __init__(self, subroutine_def: "SubroutineDefinition") -> None: + from pyteal.compiler.compiler import FRAME_POINTER_VERSION, MAX_PROGRAM_VERSION + from pyteal.ir import Op + + self.subroutine: SubroutineDefinition = subroutine_def + self.version_map: dict[range, Optional[SubroutineDeclaration]] = { + range(Op.callsub.min_version, FRAME_POINTER_VERSION): None, + range(FRAME_POINTER_VERSION, MAX_PROGRAM_VERSION + 1): None, + } + self.version_method: dict[range, Callable[..., SubroutineDeclaration]] = { + range( + Op.callsub.min_version, FRAME_POINTER_VERSION + ): SubroutineEval.evaluator_gen(SubroutineEval.var_n_loaded), + range( + FRAME_POINTER_VERSION, MAX_PROGRAM_VERSION + 1 + ): SubroutineEval.evaluator_gen( + SubroutineEval.var_n_loaded_fp, use_proto=True + ), + } + self.has_return: Optional[bool] = None + self.type_of: Optional[TealType] = None + + def get_declaration(self) -> "SubroutineDeclaration": + # XXX MARK THIS METHOD TO BE DEPRECATED LATER I GUESS + from pyteal.ir import Op + + return self.get_declaration_by_version(Op.callsub.min_version) + + def get_declaration_by_version(self, version: int) -> "SubroutineDeclaration": + from pyteal.compiler.compiler import MAX_PROGRAM_VERSION + from pyteal.ir import Op + + for _r, decl in self.version_map.items(): + if version not in _r: + continue + if decl: + return decl + self.version_map[_r] = self.version_method[_r](self.subroutine) + return cast(SubroutineDeclaration, self.version_map[_r]) + + raise TealInputError( + f"version {version} must be in range [{Op.callsub.min_version}, {MAX_PROGRAM_VERSION}]." + ) + + def __erase_version(self, version: int): + for _r in self.version_map: + if version in _r: + self.version_map[_r] = None + + def __is_version_pre_existing(self, version: int) -> bool: + for _r in self.version_map: + if version in _r: + return self.version_map[_r] is not None + raise TealInputError(f"no such versioning {version}") + + def __probe_info(self, version: int) -> tuple[bool, TealType]: + current_slot_id = ScratchSlot.nextSlotId + is_pre_existing = self.__is_version_pre_existing(version) + decl = self.get_declaration_by_version(version) + has_return = decl.has_return() + type_of = decl.type_of() + if not is_pre_existing: + self.__erase_version(version) + ScratchSlot.nextSlotId = current_slot_id + return has_return, type_of + + def __info_prepare(self): + from pyteal.compiler.compiler import FRAME_POINTER_VERSION + + if self.has_return is not None and self.type_of is not None: + return + v2_ret, v2_type = self.__probe_info(FRAME_POINTER_VERSION - 1) + v8_ret, v8_type = self.__probe_info(FRAME_POINTER_VERSION) + assert v2_ret == v8_ret + assert v2_type == v8_type + self.has_return = v2_ret + self.type_of = v2_type + + def versions_type_of(self) -> TealType: + self.__info_prepare() + return cast(TealType, self.type_of) + + def versions_has_return(self) -> bool: + self.__info_prepare() + return cast(bool, self.has_return) + + def get_declarations(self): + for _r, decl in self.version_map.items(): + if decl: + continue + self.version_map[_r] = self.get_declaration_by_version(_r.start) + + class SubroutineDefinition: """ Class that leverages TEAL's `callsub` and `retsub` opcode-pair for subroutines @@ -45,6 +140,7 @@ def __init__( self.return_type = return_type self.declaration: Optional["SubroutineDeclaration"] = None + self.declarations: _SubroutineDeclByVersion = _SubroutineDeclByVersion(self) self.implementation: Callable = implementation self.has_abi_output: bool = has_abi_output @@ -239,10 +335,11 @@ def _validate_annotation( ) def get_declaration(self) -> "SubroutineDeclaration": - if self.declaration is None: - # lazy evaluate subroutine - self.declaration = evaluate_subroutine(self) - return self.declaration + # XXX MARK THIS METHOD TO BE DEPRECATED LATER I GUESS + return self.declarations.get_declaration() + + def get_declaration_by_version(self, version: int) -> "SubroutineDeclaration": + return self.declarations.get_declaration_by_version(version) def name(self) -> str: return self.__name @@ -472,10 +569,10 @@ def name(self) -> str: return self.subroutine.name() def type_of(self): - return self.subroutine.get_declaration().type_of() + return self.subroutine.declarations.versions_type_of() def has_return(self): - return self.subroutine.get_declaration().has_return() + return self.subroutine.declarations.versions_type_of() SubroutineFnWrapper.__module__ = "pyteal" @@ -744,6 +841,144 @@ def __call__(self, fn_implementation: Callable[..., Expr]) -> SubroutineFnWrappe Subroutine.__module__ = "pyteal" +# Personally prefer not to expose this evaluator static class, also not exposing evaluate_subroutine (to be deprecated) +class SubroutineEval: + @staticmethod + def var_n_loaded( + subroutine: SubroutineDefinition, + param: str, + ) -> tuple[ScratchVar, ScratchVar | abi.BaseType | Expr]: + from pyteal.ast.abi.type import ScratchVarStorage + + loaded_var: ScratchVar | abi.BaseType | Expr + argument_var: ScratchVar + + if param in subroutine.by_ref_args: + argument_var = DynamicScratchVar(TealType.anytype) + loaded_var = argument_var + elif param in subroutine.abi_args: + internal_abi_var = subroutine.abi_args[param].new_instance() + if not isinstance(internal_abi_var._data_storage, ScratchVarStorage): + raise TealInternalError("...") + argument_var = internal_abi_var._data_storage.scratchvar + loaded_var = internal_abi_var + else: + argument_var = ScratchVar(TealType.anytype) + loaded_var = argument_var.load() + + return argument_var, loaded_var + + @staticmethod + def var_n_loaded_fp( + subroutine: SubroutineDefinition, + param: str, + ) -> tuple[Optional[ScratchVar], ScratchVar | abi.BaseType | Expr]: + from pyteal.ast.abi.type import FrameStorage + + loaded_var: ScratchVar | abi.BaseType | Expr + argument_var: Optional[ScratchVar] + + if param in subroutine.by_ref_args: + argument_var = DynamicScratchVar(TealType.anytype) + loaded_var = argument_var + elif param in subroutine.abi_args: + internal_abi_var = subroutine.abi_args[param].new_instance() + dig_index = ( + subroutine.arguments().index(param) - subroutine.argument_count() + ) + internal_abi_var._set_data_source(FrameStorage(TealType.anytype, dig_index)) + argument_var = None + loaded_var = internal_abi_var + else: + dig_index = ( + subroutine.arguments().index(param) - subroutine.argument_count() + ) + argument_var = None + loaded_var = FrameDig(dig_index) + + return argument_var, loaded_var + + @staticmethod + def evaluator_gen( + var_n_loaded: Callable[ + [SubroutineDefinition, str], + tuple[Optional[ScratchVar], ScratchVar | abi.BaseType | Expr], + ], + /, + *, + use_proto: bool = False, + ) -> Callable[[SubroutineDefinition], SubroutineDeclaration]: + from pyteal.ast.abi.type import FrameStorage + + def evaluator(subroutine: SubroutineDefinition) -> SubroutineDeclaration: + args = subroutine.arguments() + arg_vars: list[ScratchVar] = [] + loaded_args: list[ScratchVar | Expr | abi.BaseType] = [] + for arg in args: + arg_var, loaded_arg = var_n_loaded(subroutine, arg) + if arg_var: + arg_vars.append(arg_var) + loaded_args.append(loaded_arg) + + abi_output_kwargs: dict[str, abi.BaseType] = {} + output_kwarg_info = OutputKwArgInfo.from_dict(subroutine.output_kwarg) + output_carrying_abi: Optional[abi.BaseType] = None + + if output_kwarg_info: + output_carrying_abi = output_kwarg_info.abi_type.new_instance() + if use_proto: + output_carrying_abi._data_storage = FrameStorage( + TealType.anytype, 0 + ) + abi_output_kwargs[output_kwarg_info.name] = output_carrying_abi + + # Arg usage "B" supplied to build an AST from the user-defined PyTEAL function: + subroutine_body = subroutine.implementation( + *loaded_args, **abi_output_kwargs + ) + if not isinstance(subroutine_body, Expr): + raise TealInputError( + f"Subroutine function does not return a PyTeal expression. Got type {type(subroutine_body)}." + ) + + deferred_expr: Optional[Expr] = None + + # if there is an output keyword argument for ABI, place the storing on the stack + if output_carrying_abi: + if subroutine_body.type_of() != TealType.none: + raise TealInputError( + f"ABI returning subroutine definition should evaluate to TealType.none, " + f"while evaluate to {subroutine_body.type_of()}." + ) + deferred_expr = output_carrying_abi._data_storage.load_value() + + # Arg usage "A" to be pick up and store in scratch parameters that have been placed on the stack + # need to reverse order of argumentVars because the last argument will be on top of the stack + body_ops: list[Expr] = [] + if use_proto: + body_ops += [ + Proto( + subroutine.argument_count(), + int( + subroutine_body.type_of() != TealType.none + if not subroutine.has_abi_output + else len(abi_output_kwargs) + ), + ) + ] + body_ops += [var.slot.store() for var in arg_vars[::-1]] + body_ops.append(subroutine_body) + + sd = SubroutineDeclaration(subroutine, Seq(body_ops), deferred_expr) + sd.trace = subroutine_body.trace + return sd + + return evaluator + + +SubroutineEval.__module__ = "pyteal" + + def evaluate_subroutine(subroutine: SubroutineDefinition) -> SubroutineDeclaration: """ Puts together the data necessary to define the code for a subroutine. @@ -802,9 +1037,7 @@ def var_n_loaded( elif param in subroutine.abi_args: internal_abi_var = subroutine.abi_args[param].new_instance() if not isinstance(internal_abi_var._data_storage, ScratchVarStorage): - raise TealInternalError( - "subroutine ABI args must have data schema being ScratchVarStorage" - ) + raise TealInternalError("...") argument_var = internal_abi_var._data_storage.scratchvar loaded_var = internal_abi_var else: diff --git a/pyteal/compiler/compiler.py b/pyteal/compiler/compiler.py index f2b25b489..3231b8e85 100644 --- a/pyteal/compiler/compiler.py +++ b/pyteal/compiler/compiler.py @@ -155,10 +155,14 @@ def compileSubroutine( if ( currentSubroutine is not None - and currentSubroutine.get_declaration().deferred_expr is not None + and currentSubroutine.get_declaration_by_version(options.version).deferred_expr + is not None ): # this represents code that should be inserted before each retsub op - deferred_expr = cast(Expr, currentSubroutine.get_declaration().deferred_expr) + deferred_expr = cast( + Expr, + currentSubroutine.get_declaration_by_version(options.version).deferred_expr, + ) for block in TealBlock.Iterate(start): if not any(op.getOp() == Op.retsub for op in block.ops): @@ -209,7 +213,7 @@ def compileSubroutine( newSubroutines = referencedSubroutines - subroutine_start_blocks.keys() for subroutine in sorted(newSubroutines, key=lambda subroutine: subroutine.id): compileSubroutine( - subroutine.get_declaration(), + subroutine.get_declaration_by_version(options.version), options, subroutineGraph, subroutine_start_blocks, From a044f803f2424a0f241530bb0f60a6db2024377b Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 19 Oct 2022 14:34:00 -0400 Subject: [PATCH 021/206] change in round trip test, stop something blocking me --- tests/abi_roundtrip.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/tests/abi_roundtrip.py b/tests/abi_roundtrip.py index efde3ecd3..ba0f4d8c0 100644 --- a/tests/abi_roundtrip.py +++ b/tests/abi_roundtrip.py @@ -1,4 +1,4 @@ -from typing import Generic, TypeVar +from typing import Generic, TypeVar, Optional import pyteal as pt from pyteal import abi @@ -14,13 +14,13 @@ class ABIRoundtrip(Generic[T]): def __init__( self, annotation_instance: abi.BaseType, - length: int | None = None, + length: Optional[int] = 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 + self.length: Optional[int] = length def pytealer(self) -> PyTealDryRunExecutor: roundtrip = self.roundtrip_factory() @@ -120,13 +120,21 @@ 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: + if not self.type_spec.is_length_dynamic(): # type: ignore[attr-defined] + if self.length: + assert self.length == self.type_spec.length_static() # type: ignore[attr-defined] + else: + self.length = self.type_spec.length_static() # type: ignore[attr-defined] + elif self.length is None: self.length = 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() From 6739c00cbf1296d32dd694c854d8a5b8e31a1a01 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 19 Oct 2022 15:43:27 -0400 Subject: [PATCH 022/206] update frame dig and proto use --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 50b59f15f..b18775124 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,6 +11,6 @@ services: - DEV_MODE - TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa healthcheck: - test: goal node status || exit 1 + test: goal node status interval: 2s retries: 10 From ce9aec85f5825a8295dd6e18159ddab3e1dbc3cb Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 19 Oct 2022 19:29:48 -0400 Subject: [PATCH 023/206] fix var n loaded --- pyteal/ast/subroutine.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index bad4b5cb1..ab63e15e6 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -21,7 +21,6 @@ class _SubroutineDeclByVersion: def __init__(self, subroutine_def: "SubroutineDefinition") -> None: from pyteal.compiler.compiler import FRAME_POINTER_VERSION, MAX_PROGRAM_VERSION - from pyteal.ir import Op self.subroutine: SubroutineDefinition = subroutine_def self.version_map: dict[range, Optional[SubroutineDeclaration]] = { @@ -43,13 +42,10 @@ def __init__(self, subroutine_def: "SubroutineDefinition") -> None: def get_declaration(self) -> "SubroutineDeclaration": # XXX MARK THIS METHOD TO BE DEPRECATED LATER I GUESS - from pyteal.ir import Op - return self.get_declaration_by_version(Op.callsub.min_version) def get_declaration_by_version(self, version: int) -> "SubroutineDeclaration": from pyteal.compiler.compiler import MAX_PROGRAM_VERSION - from pyteal.ir import Op for _r, decl in self.version_map.items(): if version not in _r: From 620c61e6880d26dcfa83ceb7c6672459835b6263 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 26 Oct 2022 16:45:21 -0400 Subject: [PATCH 024/206] documentation --- pyteal/ast/subroutine.py | 110 +++++++++++++++++++++++++++++++----- pyteal/compiler/compiler.py | 3 +- 2 files changed, 97 insertions(+), 16 deletions(-) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index ab63e15e6..b9c95d221 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -30,12 +30,10 @@ def __init__(self, subroutine_def: "SubroutineDefinition") -> None: self.version_method: dict[range, Callable[..., SubroutineDeclaration]] = { range( Op.callsub.min_version, FRAME_POINTER_VERSION - ): SubroutineEval.evaluator_gen(SubroutineEval.var_n_loaded), + ): SubroutineEval.normal_evaluator, range( FRAME_POINTER_VERSION, MAX_PROGRAM_VERSION + 1 - ): SubroutineEval.evaluator_gen( - SubroutineEval.var_n_loaded_fp, use_proto=True - ), + ): SubroutineEval.fp_evaluator, } self.has_return: Optional[bool] = None self.type_of: Optional[TealType] = None @@ -59,10 +57,16 @@ def get_declaration_by_version(self, version: int) -> "SubroutineDeclaration": f"version {version} must be in range [{Op.callsub.min_version}, {MAX_PROGRAM_VERSION}]." ) - def __erase_version(self, version: int): + def __erase_version(self, version: int) -> None: + from pyteal.compiler.compiler import MAX_PROGRAM_VERSION + for _r in self.version_map: if version in _r: self.version_map[_r] = None + return + raise TealInputError( + f"version {version} must be in range [{Op.callsub.min_version}, {MAX_PROGRAM_VERSION}]." + ) def __is_version_pre_existing(self, version: int) -> bool: for _r in self.version_map: @@ -74,17 +78,16 @@ def __probe_info(self, version: int) -> tuple[bool, TealType]: current_slot_id = ScratchSlot.nextSlotId is_pre_existing = self.__is_version_pre_existing(version) decl = self.get_declaration_by_version(version) - has_return = decl.has_return() - type_of = decl.type_of() + has_return, type_of = decl.has_return(), decl.type_of() if not is_pre_existing: self.__erase_version(version) ScratchSlot.nextSlotId = current_slot_id return has_return, type_of - def __info_prepare(self): + def __info_prepare(self) -> None: from pyteal.compiler.compiler import FRAME_POINTER_VERSION - if self.has_return is not None and self.type_of is not None: + if self.has_return and self.type_of: return v2_ret, v2_type = self.__probe_info(FRAME_POINTER_VERSION - 1) v8_ret, v8_type = self.__probe_info(FRAME_POINTER_VERSION) @@ -101,7 +104,7 @@ def versions_has_return(self) -> bool: self.__info_prepare() return cast(bool, self.has_return) - def get_declarations(self): + def get_declarations(self) -> None: for _r, decl in self.version_map.items(): if decl: continue @@ -837,10 +840,77 @@ def __call__(self, fn_implementation: Callable[..., Expr]) -> SubroutineFnWrappe Subroutine.__module__ = "pyteal" -# Personally prefer not to expose this evaluator static class, also not exposing evaluate_subroutine (to be deprecated) class SubroutineEval: + """ + Puts together the data necessary to define the code for a subroutine. + "evaluate" is used here to connote evaluating the PyTEAL AST into a SubroutineDeclaration, + but not actually placing it at call locations. The trickiest part here is managing the subroutine's arguments. + The arguments are needed for two different code-paths, and there are 2 different argument types to consider + for each of the code-paths. + + 2 Argument Usages / Code-Paths + - -------- ------ ---------- + Usage (A) for run-time: "argumentVars" --reverse--> "body_ops" + These are "store" expressions that pick up parameters that have been pre-placed on the stack prior to subroutine invocation. + The argumentVars are stored into local scratch space to be used by the TEAL subroutine. + + Usage (B) for compile-time: "loadedArgs" + These are expressions supplied to the user-defined PyTEAL function. + The loadedArgs are invoked to by the subroutine to create a self-contained AST which will translate into a TEAL subroutine. + + In both usage cases, we need to handle + + 4 Argument Types + - -------- ----- + Type 1 (by-value): these have python type Expr + Type 2 (by-reference): these have python type ScratchVar + Type 3 (ABI): these are ABI typed variables with scratch space storage, and still pass by value + Type 4 (ABI-output-arg): ABI typed variables with scratch space, a new ABI instance is generated inside function body, + not one of the cases in the previous three options + + Because of the introduction of frame pointer, the "argumentVars" and "loadedArgs" are different before and after program version 8. + + "argumentVars" and "loadedArgs" before version 8 (frame pointer version) + -------------- --- ------------ ------ ------- - ----------------------- + + Usage (A) "argumentVars" - Storing pre-placed stack variables into local scratch space: + Type 1. (by-value) use ScratchVar.store() to pick the actual value into a local scratch space + Type 2. (by-reference) ALSO use ScratchVar.store() to pick up from the stack + NOTE: SubroutineCall.__teal__() has placed the _SLOT INDEX_ on the stack so this is stored into the local scratch space + Type 3. (ABI) abi_value.stored_value.store() to pick from the stack + Type 4. (ABI-output-arg) it is not really used here, since it is only generated internal of the subroutine + + Usage (B) "loadedArgs" - Passing through to an invoked PyTEAL subroutine AST: + Type 1. (by-value) use ScratchVar.load() to have an Expr that can be compiled in python by the PyTEAL subroutine + Type 2. (by-reference) use a DynamicScratchVar as the user will have written the PyTEAL in a way that satisfies + the ScratchVar API. I.e., the user will write `x.load()` and `x.store(val)` as opposed to just `x`. + Type 3. (ABI) use abi_value itself after storing stack value into scratch space. + Type 4. (ABI-output-arg) generates a new instance of the ABI value, + and appends a return expression of stored value of the ABI keyword value. + + "argumentVars" and "loadedArgs" after version 8 (frame pointer version) + -------------- --- ------------ ----- ------- - ----------------------- + + Usage (A) "argumentVars" - Storing pre-placed stack variables with frame pointer: + Type 1. (by-value) use None for we can load from stack with FrameDig() + Type 2. (by-reference) ALSO use FrameDig to pick up from the stack + NOTE: SubroutineCall.__teal__() has placed the _SLOT INDEX_ on the stack so this is stored into the local scratch space + Type 3. (ABI) use None for we can load from stack with FrameDig() + NOTE: SubroutineCall.__teal__() has placed the ABI encoding on the stack, so ABI set and get methods are working over stack + Type 4. (ABI-output-arg) it is not really used here, but we use FrameDig/Bury to interact with it + + TODO need to repolish later after merge and rebase + Usage (B) "loadedArgs" - Passing through to an invoked PyTEAL subroutine AST: + Type 1. (by-value) use FrameDig() to have an Expr that can be compiled in python by the PyTEAL subroutine + Type 2. (by-reference) use a DynamicScratchVar as the user will have written the PyTEAL in a way that satisfies + the ScratchVar API. I.e., the user will write `x.load()` and `x.store(val)` as opposed to just `x`. + Type 3. (ABI) use abi_value that interface with stack data through FrameDig/FrameBury + Type 4. (ABI-output-arg) generates a new instance of the ABI value, + and appends a return expression of stored value of the ABI keyword value. + """ + @staticmethod - def var_n_loaded( + def __var_n_loaded( subroutine: SubroutineDefinition, param: str, ) -> tuple[ScratchVar, ScratchVar | abi.BaseType | Expr]: @@ -865,7 +935,7 @@ def var_n_loaded( return argument_var, loaded_var @staticmethod - def var_n_loaded_fp( + def __var_n_loaded_fp( subroutine: SubroutineDefinition, param: str, ) -> tuple[Optional[ScratchVar], ScratchVar | abi.BaseType | Expr]: @@ -895,7 +965,7 @@ def var_n_loaded_fp( return argument_var, loaded_var @staticmethod - def evaluator_gen( + def __evaluator_gen( var_n_loaded: Callable[ [SubroutineDefinition, str], tuple[Optional[ScratchVar], ScratchVar | abi.BaseType | Expr], @@ -971,12 +1041,24 @@ def evaluator(subroutine: SubroutineDefinition) -> SubroutineDeclaration: return evaluator + @staticmethod + def normal_evaluator(subroutine: SubroutineDefinition) -> SubroutineDeclaration: + return SubroutineEval.__evaluator_gen(SubroutineEval.__var_n_loaded)(subroutine) + + @staticmethod + def fp_evaluator(subroutine: SubroutineDefinition) -> SubroutineDeclaration: + return SubroutineEval.__evaluator_gen( + SubroutineEval.__var_n_loaded_fp, use_proto=True + )(subroutine) + SubroutineEval.__module__ = "pyteal" def evaluate_subroutine(subroutine: SubroutineDefinition) -> SubroutineDeclaration: """ + NOTE: THIS METHOD IS DEPRECATED, USE CLASS `SubroutineEval` INSTEAD FOR SUBROUTINE EVALUATOR + Puts together the data necessary to define the code for a subroutine. "evaluate" is used here to connote evaluating the PyTEAL AST into a SubroutineDeclaration, but not actually placing it at call locations. The trickiest part here is managing the subroutine's arguments. diff --git a/pyteal/compiler/compiler.py b/pyteal/compiler/compiler.py index 3231b8e85..304c40383 100644 --- a/pyteal/compiler/compiler.py +++ b/pyteal/compiler/compiler.py @@ -154,9 +154,8 @@ def compileSubroutine( start.validateTree() if ( - currentSubroutine is not None + currentSubroutine and currentSubroutine.get_declaration_by_version(options.version).deferred_expr - is not None ): # this represents code that should be inserted before each retsub op deferred_expr = cast( From 87d97b1e41924771e4a02927e34ff4338b844113 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Thu, 27 Oct 2022 10:49:51 -0400 Subject: [PATCH 025/206] narrower name, module name --- pyteal/ast/abi/__init__.py | 4 ++-- pyteal/ast/abi/address_test.py | 22 +++++++++++----------- pyteal/ast/abi/array_dynamic_test.py | 20 ++++++++++---------- pyteal/ast/abi/array_static_test.py | 14 +++++++------- pyteal/ast/abi/bool_test.py | 20 ++++++++++---------- pyteal/ast/abi/reference_type_test.py | 8 ++++---- pyteal/ast/abi/string_test.py | 20 ++++++++++---------- pyteal/ast/abi/transaction_test.py | 2 +- pyteal/ast/abi/tuple_test.py | 4 ++-- pyteal/ast/abi/type.py | 13 +++++++++++-- pyteal/ast/abi/uint_test.py | 20 +++++++++----------- pyteal/ast/subroutine.py | 4 ++-- 12 files changed, 79 insertions(+), 72 deletions(-) diff --git a/pyteal/ast/abi/__init__.py b/pyteal/ast/abi/__init__.py index 3113b8d72..3ca3ab290 100644 --- a/pyteal/ast/abi/__init__.py +++ b/pyteal/ast/abi/__init__.py @@ -11,7 +11,7 @@ ReturnedValue, DataStorageSchema, FrameStorage, - ScratchVarStorage, + ScratchStorage, ) from pyteal.ast.abi.bool import BoolTypeSpec, Bool from pyteal.ast.abi.uint import ( @@ -176,7 +176,7 @@ "size_of", "DataStorageSchema", "FrameStorage", - "ScratchVarStorage", + "ScratchStorage", "algosdk_from_annotation", "algosdk_from_type_spec", "contains_type_spec", diff --git a/pyteal/ast/abi/address_test.py b/pyteal/ast/abi/address_test.py index 305046619..dca9136dc 100644 --- a/pyteal/ast/abi/address_test.py +++ b/pyteal/ast/abi/address_test.py @@ -53,7 +53,7 @@ def test_Address_encode(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -117,7 +117,7 @@ def test_Address_get(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -139,12 +139,12 @@ def test_Address_set_StaticArray(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value_to_set._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value_to_set._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -174,7 +174,7 @@ def test_Address_set_str(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -203,7 +203,7 @@ def test_Address_set_bytes(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -236,12 +236,12 @@ def test_Address_set_expr(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.int, AddressLength.Bytes.value), @@ -270,12 +270,12 @@ def test_Address_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -307,7 +307,7 @@ def test_Address_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) diff --git a/pyteal/ast/abi/array_dynamic_test.py b/pyteal/ast/abi/array_dynamic_test.py index fa0e122e1..3e172eeee 100644 --- a/pyteal/ast/abi/array_dynamic_test.py +++ b/pyteal/ast/abi/array_dynamic_test.py @@ -185,12 +185,12 @@ def test_DynamicArray_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, otherArray._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, otherArray._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -218,7 +218,7 @@ def test_DynamicArray_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -268,7 +268,7 @@ def test_DynamicBytes_set_py_bytes(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -299,12 +299,12 @@ def test_DynamicBytes_set_expr(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.itob), @@ -312,13 +312,13 @@ def test_DynamicBytes_set_expr(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.concat), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -343,7 +343,7 @@ def test_DynamicBytes_get(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.extract, 2, 0), ] @@ -365,7 +365,7 @@ def test_DynamicArray_encode(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) diff --git a/pyteal/ast/abi/array_static_test.py b/pyteal/ast/abi/array_static_test.py index 236e2591e..7d0a8ae0a 100644 --- a/pyteal/ast/abi/array_static_test.py +++ b/pyteal/ast/abi/array_static_test.py @@ -237,12 +237,12 @@ def test_StaticArray_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, otherArray._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, otherArray._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -270,7 +270,7 @@ def test_StaticArray_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -317,7 +317,7 @@ def test_StaticBytes_set_py_bytes(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -352,13 +352,13 @@ def test_StaticBytes_expr(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.int, 32), pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.eq), @@ -381,7 +381,7 @@ def test_StaticArray_encode(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) diff --git a/pyteal/ast/abi/bool_test.py b/pyteal/ast/abi/bool_test.py index 411bdf376..4299b72ce 100644 --- a/pyteal/ast/abi/bool_test.py +++ b/pyteal/ast/abi/bool_test.py @@ -56,7 +56,7 @@ def test_Bool_set_static(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -85,7 +85,7 @@ def test_Bool_set_expr(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -110,12 +110,12 @@ def test_Bool_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -144,7 +144,7 @@ def test_Bool_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -171,7 +171,7 @@ def test_Bool_get(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -204,7 +204,7 @@ def test_Bool_decode(): None, pt.Op.store, cast( - abi.ScratchVarStorage, value._data_storage + abi.ScratchStorage, value._data_storage ).scratchvar.slot, ), ] @@ -234,7 +234,7 @@ def test_Bool_decode_bit(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -260,7 +260,7 @@ def test_Bool_encode(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.setbit), ] @@ -444,7 +444,7 @@ class EncodeSeqTest(NamedTuple): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, testType._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, testType._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.setbit), ] diff --git a/pyteal/ast/abi/reference_type_test.py b/pyteal/ast/abi/reference_type_test.py index aaa1e5d97..d3b8aaf93 100644 --- a/pyteal/ast/abi/reference_type_test.py +++ b/pyteal/ast/abi/reference_type_test.py @@ -26,7 +26,7 @@ def test_ReferenceType_referenced_index(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -117,7 +117,7 @@ def test_Account_address(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.txnas, "Accounts"), ] @@ -204,7 +204,7 @@ def test_Asset_asset_id(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.txnas, "Assets"), ] @@ -298,7 +298,7 @@ def test_Application_application_id(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.txnas, "Applications"), ] diff --git a/pyteal/ast/abi/string_test.py b/pyteal/ast/abi/string_test.py index 79a699a4c..fb8de7fb9 100644 --- a/pyteal/ast/abi/string_test.py +++ b/pyteal/ast/abi/string_test.py @@ -44,7 +44,7 @@ def test_String_encode(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -107,7 +107,7 @@ def test_String_get(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.extract, 2, 0), ] @@ -143,7 +143,7 @@ def test_String_set_static(value_to_set, value_encoded): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -174,12 +174,12 @@ def test_String_set_expr(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.itob), @@ -187,13 +187,13 @@ def test_String_set_expr(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.concat), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -222,12 +222,12 @@ def test_String_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -259,7 +259,7 @@ def test_String_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) diff --git a/pyteal/ast/abi/transaction_test.py b/pyteal/ast/abi/transaction_test.py index 573d6f440..e21802950 100644 --- a/pyteal/ast/abi/transaction_test.py +++ b/pyteal/ast/abi/transaction_test.py @@ -134,7 +134,7 @@ def test_Transaction__set_index(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, tv.t._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, tv.t._data_storage).scratchvar.slot, ), ] ) diff --git a/pyteal/ast/abi/tuple_test.py b/pyteal/ast/abi/tuple_test.py index 8365769cc..777d3688e 100644 --- a/pyteal/ast/abi/tuple_test.py +++ b/pyteal/ast/abi/tuple_test.py @@ -706,7 +706,7 @@ def test_Tuple_set_Computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, tupleValue._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, tupleValue._data_storage).scratchvar.slot, ), ] ) @@ -737,7 +737,7 @@ def test_Tuple_encode(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, tupleValue._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, tupleValue._data_storage).scratchvar.slot, ), ] ) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index 67d75cc4b..c505021c0 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -79,7 +79,10 @@ def storage_type(self) -> TealType: pass -class ScratchVarStorage(DataStorageSchema): +DataStorageSchema.__module__ = "pyteal" + + +class ScratchStorage(DataStorageSchema): def __init__(self, storage_type: TealType) -> None: super().__init__() self.scratchvar: Final = ScratchVar(storage_type) @@ -94,6 +97,9 @@ def storage_type(self) -> TealType: return self.scratchvar.storage_type() +ScratchStorage.__module__ = "pyteal" + + class FrameStorage(DataStorageSchema): def __init__(self, storage_type: TealType, stack_depth: int) -> None: super().__init__() @@ -114,6 +120,9 @@ def load_value(self) -> Expr: return FrameDig(self.stack_depth) +FrameStorage.__module__ = "pyteal" + + class BaseType(ABC): """The abstract base class for all ABI type instances. @@ -126,7 +135,7 @@ def __init__(self, spec: TypeSpec) -> None: """Create a new BaseType.""" super().__init__() self._type_spec: Final = spec - self._data_storage: DataStorageSchema = ScratchVarStorage(spec.storage_type()) + self._data_storage: DataStorageSchema = ScratchStorage(spec.storage_type()) # self.stored_value: Final = ScratchVar(spec.storage_type()) diff --git a/pyteal/ast/abi/uint_test.py b/pyteal/ast/abi/uint_test.py index c4659fdb9..d4b7cd137 100644 --- a/pyteal/ast/abi/uint_test.py +++ b/pyteal/ast/abi/uint_test.py @@ -142,9 +142,7 @@ def test_Uint_set_static(): pt.TealOp( None, pt.Op.store, - cast( - abi.ScratchVarStorage, value._data_storage - ).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -176,7 +174,7 @@ def test_Uint_set_expr(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.int, test.maxValue + 1), pt.TealOp(None, pt.Op.lt), @@ -191,7 +189,7 @@ def test_Uint_set_expr(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] + upperBoundCheck @@ -218,12 +216,12 @@ def test_Uint_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -255,7 +253,7 @@ def test_Uint_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -283,7 +281,7 @@ def test_Uint_get(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -361,13 +359,13 @@ def test_ByteUint8_mutual_conversion(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.store, cast( - abi.ScratchVarStorage, type_b_instance._data_storage + abi.ScratchStorage, type_b_instance._data_storage ).scratchvar.slot, ), ] diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 7fd38bc9d..70365d756 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -791,7 +791,7 @@ def evaluate_subroutine(subroutine: SubroutineDefinition) -> SubroutineDeclarati def var_n_loaded( param: str, ) -> tuple[ScratchVar, ScratchVar | abi.BaseType | Expr]: - from pyteal.ast.abi.type import ScratchVarStorage + from pyteal.ast.abi.type import ScratchStorage loaded_var: ScratchVar | abi.BaseType | Expr argument_var: ScratchVar @@ -801,7 +801,7 @@ def var_n_loaded( loaded_var = argument_var elif param in subroutine.abi_args: internal_abi_var = subroutine.abi_args[param].new_instance() - if not isinstance(internal_abi_var._data_storage, ScratchVarStorage): + if not isinstance(internal_abi_var._data_storage, ScratchStorage): raise TealInternalError( "subroutine ABI args must have data schema being ScratchVarStorage" ) From 208be8008e7ea4c0a8456e70a0ed977e2bb41308 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Thu, 27 Oct 2022 11:30:59 -0400 Subject: [PATCH 026/206] reformat evaluator code, less indentation --- pyteal/ast/subroutine.py | 155 ++++++++++++++++++--------------------- 1 file changed, 73 insertions(+), 82 deletions(-) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index b32df07e8..d9b87beb8 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -27,13 +27,13 @@ def __init__(self, subroutine_def: "SubroutineDefinition") -> None: range(Op.callsub.min_version, FRAME_POINTER_VERSION): None, range(FRAME_POINTER_VERSION, MAX_PROGRAM_VERSION + 1): None, } - self.version_method: dict[range, Callable[..., SubroutineDeclaration]] = { + self.version_method: dict[range, SubroutineEval] = { range( Op.callsub.min_version, FRAME_POINTER_VERSION - ): SubroutineEval.normal_evaluator, + ): SubroutineEval.normal_evaluator(), range( FRAME_POINTER_VERSION, MAX_PROGRAM_VERSION + 1 - ): SubroutineEval.fp_evaluator, + ): SubroutineEval.fp_evaluator(), } self.has_return: Optional[bool] = None self.type_of: Optional[TealType] = None @@ -111,6 +111,9 @@ def get_declarations(self) -> None: self.version_map[_r] = self.get_declaration_by_version(_r.start) +_SubroutineDeclByVersion.__module__ = "pyteal" + + class SubroutineDefinition: """ Class that leverages TEAL's `callsub` and `retsub` opcode-pair for subroutines @@ -840,6 +843,7 @@ def __call__(self, fn_implementation: Callable[..., Expr]) -> SubroutineFnWrappe Subroutine.__module__ = "pyteal" +@dataclass class SubroutineEval: """ Puts together the data necessary to define the code for a subroutine. @@ -909,6 +913,12 @@ class SubroutineEval: and appends a return expression of stored value of the ABI keyword value. """ + var_n_loaded: Callable[ + [SubroutineDefinition, str], + tuple[Optional[ScratchVar], ScratchVar | abi.BaseType | Expr], + ] + use_frame_pt: bool = False + @staticmethod def __var_n_loaded( subroutine: SubroutineDefinition, @@ -966,92 +976,73 @@ def __var_n_loaded_fp( return argument_var, loaded_var - @staticmethod - def __evaluator_gen( - var_n_loaded: Callable[ - [SubroutineDefinition, str], - tuple[Optional[ScratchVar], ScratchVar | abi.BaseType | Expr], - ], - /, - *, - use_proto: bool = False, - ) -> Callable[[SubroutineDefinition], SubroutineDeclaration]: + def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: from pyteal.ast.abi.type import FrameStorage - def evaluator(subroutine: SubroutineDefinition) -> SubroutineDeclaration: - args = subroutine.arguments() - arg_vars: list[ScratchVar] = [] - loaded_args: list[ScratchVar | Expr | abi.BaseType] = [] - for arg in args: - arg_var, loaded_arg = var_n_loaded(subroutine, arg) - if arg_var: - arg_vars.append(arg_var) - loaded_args.append(loaded_arg) - - abi_output_kwargs: dict[str, abi.BaseType] = {} - output_kwarg_info = OutputKwArgInfo.from_dict(subroutine.output_kwarg) - output_carrying_abi: Optional[abi.BaseType] = None - - if output_kwarg_info: - output_carrying_abi = output_kwarg_info.abi_type.new_instance() - if use_proto: - output_carrying_abi._data_storage = FrameStorage( - TealType.anytype, 0 - ) - abi_output_kwargs[output_kwarg_info.name] = output_carrying_abi - - # Arg usage "B" supplied to build an AST from the user-defined PyTEAL function: - subroutine_body = subroutine.implementation( - *loaded_args, **abi_output_kwargs + args = subroutine.arguments() + arg_vars: list[ScratchVar] = [] + loaded_args: list[ScratchVar | Expr | abi.BaseType] = [] + for arg in args: + arg_var, loaded_arg = self.var_n_loaded(subroutine, arg) + if arg_var: + arg_vars.append(arg_var) + loaded_args.append(loaded_arg) + + abi_output_kwargs: dict[str, abi.BaseType] = {} + output_kwarg_info = OutputKwArgInfo.from_dict(subroutine.output_kwarg) + output_carrying_abi: Optional[abi.BaseType] = None + + if output_kwarg_info: + output_carrying_abi = output_kwarg_info.abi_type.new_instance() + if self.use_frame_pt: + output_carrying_abi._data_storage = FrameStorage(TealType.anytype, 0) + abi_output_kwargs[output_kwarg_info.name] = output_carrying_abi + + # Arg usage "B" supplied to build an AST from the user-defined PyTEAL function: + subroutine_body = subroutine.implementation(*loaded_args, **abi_output_kwargs) + if not isinstance(subroutine_body, Expr): + raise TealInputError( + f"Subroutine function does not return a PyTeal expression. Got type {type(subroutine_body)}." ) - if not isinstance(subroutine_body, Expr): - raise TealInputError( - f"Subroutine function does not return a PyTeal expression. Got type {type(subroutine_body)}." - ) - - deferred_expr: Optional[Expr] = None - # if there is an output keyword argument for ABI, place the storing on the stack - if output_carrying_abi: - if subroutine_body.type_of() != TealType.none: - raise TealInputError( - f"ABI returning subroutine definition should evaluate to TealType.none, " - f"while evaluate to {subroutine_body.type_of()}." - ) - deferred_expr = output_carrying_abi._data_storage.load_value() - - # Arg usage "A" to be pick up and store in scratch parameters that have been placed on the stack - # need to reverse order of argumentVars because the last argument will be on top of the stack - body_ops: list[Expr] = [] - if use_proto: - body_ops += [ - Proto( - subroutine.argument_count(), - int( - subroutine_body.type_of() != TealType.none - if not subroutine.has_abi_output - else len(abi_output_kwargs) - ), - ) - ] - body_ops += [var.slot.store() for var in arg_vars[::-1]] - body_ops.append(subroutine_body) + deferred_expr: Optional[Expr] = None - sd = SubroutineDeclaration(subroutine, Seq(body_ops), deferred_expr) - sd.trace = subroutine_body.trace - return sd - - return evaluator + # if there is an output keyword argument for ABI, place the storing on the stack + if output_carrying_abi: + if subroutine_body.type_of() != TealType.none: + raise TealInputError( + f"ABI returning subroutine definition should evaluate to TealType.none, " + f"while evaluate to {subroutine_body.type_of()}." + ) + deferred_expr = output_carrying_abi._data_storage.load_value() + + # Arg usage "A" to be pick up and store in scratch parameters that have been placed on the stack + # need to reverse order of argumentVars because the last argument will be on top of the stack + body_ops: list[Expr] = [] + if self.use_frame_pt: + body_ops += [ + Proto( + subroutine.argument_count(), + int( + subroutine_body.type_of() != TealType.none + if not subroutine.has_abi_output + else len(abi_output_kwargs) + ), + ) + ] + body_ops += [var.slot.store() for var in arg_vars[::-1]] + body_ops.append(subroutine_body) + sd = SubroutineDeclaration(subroutine, Seq(body_ops), deferred_expr) + sd.trace = subroutine_body.trace + return sd - @staticmethod - def normal_evaluator(subroutine: SubroutineDefinition) -> SubroutineDeclaration: - return SubroutineEval.__evaluator_gen(SubroutineEval.__var_n_loaded)(subroutine) + @classmethod + def normal_evaluator(cls) -> "SubroutineEval": + return cls(SubroutineEval.__var_n_loaded, False) - @staticmethod - def fp_evaluator(subroutine: SubroutineDefinition) -> SubroutineDeclaration: - return SubroutineEval.__evaluator_gen( - SubroutineEval.__var_n_loaded_fp, use_proto=True - )(subroutine) + @classmethod + def fp_evaluator(cls) -> "SubroutineEval": + return cls(SubroutineEval.__var_n_loaded_fp, True) SubroutineEval.__module__ = "pyteal" From d3fd16d58e46c278d50d5957f345ff55e112b0a6 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Thu, 27 Oct 2022 12:42:26 -0400 Subject: [PATCH 027/206] minor, found a bug on output setting in subroutine in frame pointer compile --- pyteal/ast/subroutine.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index d9b87beb8..20a831493 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -8,8 +8,9 @@ from pyteal.ast import abi from pyteal.ast.expr import Expr from pyteal.ast.seq import Seq +from pyteal.ast.int import Int from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar, ScratchSlot -from pyteal.ast.frame import FrameDig, Proto +from pyteal.ast.frame import FrameBury, FrameDig, Proto from pyteal.errors import TealInputError, TealInternalError, verifyProgramVersion from pyteal.ir import TealOp, Op, TealBlock from pyteal.types import TealType @@ -1019,17 +1020,22 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: # Arg usage "A" to be pick up and store in scratch parameters that have been placed on the stack # need to reverse order of argumentVars because the last argument will be on top of the stack body_ops: list[Expr] = [] + + stack_output_cnt: int + if not subroutine.has_abi_output: + # if subroutine do not have abi output, then only two cases happen: + # - subroutine is a normal subroutine, then check subroutine body evaluates to something, rather than none + # - subroutine is an ABIReturnSubroutine, the type is void, and its subroutine body type of is always none + stack_output_cnt = int(subroutine_body.type_of() != TealType.none) + else: + stack_output_cnt = len(abi_output_kwargs) + if self.use_frame_pt: - body_ops += [ - Proto( - subroutine.argument_count(), - int( - subroutine_body.type_of() != TealType.none - if not subroutine.has_abi_output - else len(abi_output_kwargs) - ), - ) - ] + body_ops = [Proto(subroutine.argument_count(), stack_output_cnt)] + # reserve a spot for output variable on stack? + if stack_output_cnt > 0 and subroutine.has_abi_output: + body_ops.append(FrameBury(Int(0), 0)) + body_ops += [var.slot.store() for var in arg_vars[::-1]] body_ops.append(subroutine_body) sd = SubroutineDeclaration(subroutine, Seq(body_ops), deferred_expr) From 2b4bb176e44a4b7bb772174519cbf6757a7b1c4e Mon Sep 17 00:00:00 2001 From: Hang Su Date: Thu, 27 Oct 2022 17:33:01 -0400 Subject: [PATCH 028/206] one small step in testing, a big step for frame pointer! --- docker-compose.yml | 2 +- tests/integration/graviton_test.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index b18775124..8c18a1501 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ services: - "4160:4160" # gossip - "9100:9100" # prometheus environment: - - DEV_MODE + - DEV_MODE=true - TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa healthcheck: test: goal node status diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index 1b0bc3c04..91d2a655e 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -549,6 +549,7 @@ def test_blackbox_subroutines_as_apps( scenario: Dict[str, Any], ): blackbox_test_runner(subr, pt.Mode.Application, scenario, 6) + blackbox_test_runner(subr, pt.Mode.Application, scenario, 8) @pytest.mark.parametrize("subr, scenario", LOGICSIG_SCENARIOS.items()) @@ -557,6 +558,7 @@ def test_blackbox_subroutines_as_logic_sigs( scenario: Dict[str, Any], ): blackbox_test_runner(subr, pt.Mode.Signature, scenario, 6) + blackbox_test_runner(subr, pt.Mode.Signature, scenario, 8) def blackbox_pyteal_example1(): From 411f007b93b9a06de33448a8cce511932a047ea8 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Fri, 28 Oct 2022 13:38:35 -0400 Subject: [PATCH 029/206] work in black box testing --- pyteal/ast/subroutine.py | 18 ++++--- tests/integration/graviton_test.py | 84 ++++++++++++++++++++++++++++-- 2 files changed, 91 insertions(+), 11 deletions(-) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 20a831493..3f1feb24d 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -8,9 +8,10 @@ from pyteal.ast import abi from pyteal.ast.expr import Expr from pyteal.ast.seq import Seq -from pyteal.ast.int import Int + +# from pyteal.ast.int import Int from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar, ScratchSlot -from pyteal.ast.frame import FrameBury, FrameDig, Proto +from pyteal.ast.frame import FrameDig, Proto # FrameBury from pyteal.errors import TealInputError, TealInternalError, verifyProgramVersion from pyteal.ir import TealOp, Op, TealBlock from pyteal.types import TealType @@ -978,7 +979,7 @@ def __var_n_loaded_fp( return argument_var, loaded_var def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: - from pyteal.ast.abi.type import FrameStorage + # from pyteal.ast.abi.type import FrameStorage args = subroutine.arguments() arg_vars: list[ScratchVar] = [] @@ -995,8 +996,9 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: if output_kwarg_info: output_carrying_abi = output_kwarg_info.abi_type.new_instance() - if self.use_frame_pt: - output_carrying_abi._data_storage = FrameStorage(TealType.anytype, 0) + # TODO seems to need a "prefix expr" to let output frame bury work + # if self.use_frame_pt: + # output_carrying_abi._data_storage = FrameStorage(TealType.anytype, 0) abi_output_kwargs[output_kwarg_info.name] = output_carrying_abi # Arg usage "B" supplied to build an AST from the user-defined PyTEAL function: @@ -1026,15 +1028,15 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: # if subroutine do not have abi output, then only two cases happen: # - subroutine is a normal subroutine, then check subroutine body evaluates to something, rather than none # - subroutine is an ABIReturnSubroutine, the type is void, and its subroutine body type of is always none - stack_output_cnt = int(subroutine_body.type_of() != TealType.none) + stack_output_cnt = int(subroutine.return_type != TealType.none) else: stack_output_cnt = len(abi_output_kwargs) if self.use_frame_pt: body_ops = [Proto(subroutine.argument_count(), stack_output_cnt)] # reserve a spot for output variable on stack? - if stack_output_cnt > 0 and subroutine.has_abi_output: - body_ops.append(FrameBury(Int(0), 0)) + # if stack_output_cnt > 0 and subroutine.has_abi_output: + # body_ops += [Int(0), FrameBury(Int(0), 0)] body_ops += [var.slot.store() for var in arg_vars[::-1]] body_ops.append(subroutine_body) diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index 91d2a655e..36c5bbdf9 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -594,6 +594,27 @@ def square(x): args, "last_log() gave unexpected results from app" ) + # evaluate the programs in version 8 + app_result = PyTealDryRunExecutor(square, Mode.Application).dryrun( + args, compiler_version=8 + ) + lsig_result = PyTealDryRunExecutor(square, Mode.Signature).dryrun( + args, compiler_version=8 + ) + + # 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( + args, "stack_top() gave unexpected results for app" + ) + assert lsig_result.stack_top() == x**2, lsig_result.report( + args, "stack_top() gave unexpected results for lsig" + ) + + # check to see that itob of x^2 has been logged (only for the app case) + assert app_result.last_log() == DryRunEncoder.hex(x**2), app_result.report( + args, "last_log() gave unexpected results from app" + ) + def blackbox_pyteal_example2(): # Example 2: Using blackbox_pyteal to make 400 assertions and generate a CSV report with 400 dryrun rows @@ -656,6 +677,22 @@ def euclid(x, y): with open(Path.cwd() / "euclid.csv", "w") as f: f.write(euclid_csv) + # assert that each result is that same as what Python's math.gcd() computes + # (over v8) + inspectors = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_on_sequence( + inputs, compiler_version=8 + ) + for i, result in enumerate(inspectors): + args = inputs[i] + assert result.stack_top() == math.gcd(*args), result.report( + args, f"failed for {args}" + ) + + # save the CSV to ...current working directory.../euclid_v8.csv + euclid_csv = DryRunInspector.csv_report(inputs, inspectors) + with open(Path.cwd() / "euclid_v8.csv", "w") as f: + f.write(euclid_csv) + def blackbox_pyteal_example3(): # Example 3: declarative Test Driven Development approach through Invariant's @@ -733,6 +770,15 @@ def euclid(x, y): for property, predicate in predicates.items(): Invariant(predicate).validates(property, inputs, inspectors) + # Execute on the input sequence to get a dry-run inspectors: + inspectors = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_on_sequence( + inputs, compiler_version=8 + ) + + # 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 @@ -865,6 +911,24 @@ def cubed(n: abi.Uint64): args=inputs[index], msg="stack_top() gave unexpected results from app" ) + app_inspect = app_pytealer.dryrun_on_sequence(inputs, compiler_version=8) + lsig_inspect = lsig_pytealer.dryrun_on_sequence(inputs, compiler_version=8) + + for index, inspect in enumerate(app_inspect): + input_var = inputs[index][0] + assert inspect.stack_top() == input_var**3, inspect.report( + args=inputs[index], msg="stack_top() gave unexpected results from app" + ) + assert inspect.last_log() == DryRunEncoder.hex(input_var**3), inspect.report( + args=inputs[index], msg="last_log() gave unexpected results from app" + ) + + for index, inspect in enumerate(lsig_inspect): + input_var = inputs[index][0] + assert inspect.stack_top() == input_var**3, inspect.report( + args=inputs[index], msg="stack_top() gave unexpected results from app" + ) + def blackbox_pyteal_while_continue_test(): from tests.blackbox import Blackbox @@ -895,11 +959,21 @@ def while_continue_accumulation(n): Return(i.load()), ) + executor = PyTealDryRunExecutor(while_continue_accumulation, Mode.Signature) + for x in range(30): args = [x] - lsig_result = PyTealDryRunExecutor( - while_continue_accumulation, Mode.Signature - ).dryrun(args) + lsig_result = executor.dryrun(args) + if x == 0: + assert not lsig_result.passed() + else: + assert lsig_result.passed() + + assert lsig_result.stack_top() == x, lsig_result.report( + args, "stack_top() gave unexpected results for lsig" + ) + + lsig_result = executor.dryrun(args, compiler_version=8) if x == 0: assert not lsig_result.passed() else: @@ -969,6 +1043,10 @@ def named_tuple_field_access( assert inspector.stack_top() == 1 assert inspector.passed() + inspector = lsig_pytealer.dryrun(args, compiler_version=8) + assert inspector.passed() + assert inspector.stack_top() == 1 + @pytest.mark.parametrize( "example", From a70c125933898bbb69a82d2a7f95d6bf89641266 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Fri, 28 Oct 2022 14:27:51 -0400 Subject: [PATCH 030/206] 0xBAD hack, need to revisit for ugly pass by for type system --- pyteal/ast/subroutine.py | 49 +++++++++++++++++++++++------- tests/integration/graviton_test.py | 4 +-- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 3f1feb24d..7cdddc809 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -8,10 +8,8 @@ from pyteal.ast import abi from pyteal.ast.expr import Expr from pyteal.ast.seq import Seq - -# from pyteal.ast.int import Int from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar, ScratchSlot -from pyteal.ast.frame import FrameDig, Proto # FrameBury +from pyteal.ast.frame import FrameDig, Proto from pyteal.errors import TealInputError, TealInternalError, verifyProgramVersion from pyteal.ir import TealOp, Op, TealBlock from pyteal.types import TealType @@ -979,7 +977,10 @@ def __var_n_loaded_fp( return argument_var, loaded_var def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: - # from pyteal.ast.abi.type import FrameStorage + # TODO need to make it better for my temp hack, kinda ugly but it works + from pyteal.ast.abi.type import FrameStorage + from pyteal.compiler.compiler import TealSimpleBlock + from pyteal.ast.int import Int args = subroutine.arguments() arg_vars: list[ScratchVar] = [] @@ -996,9 +997,8 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: if output_kwarg_info: output_carrying_abi = output_kwarg_info.abi_type.new_instance() - # TODO seems to need a "prefix expr" to let output frame bury work - # if self.use_frame_pt: - # output_carrying_abi._data_storage = FrameStorage(TealType.anytype, 0) + if self.use_frame_pt: + output_carrying_abi._data_storage = FrameStorage(TealType.anytype, 0) abi_output_kwargs[output_kwarg_info.name] = output_carrying_abi # Arg usage "B" supplied to build an AST from the user-defined PyTEAL function: @@ -1033,10 +1033,37 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: stack_output_cnt = len(abi_output_kwargs) if self.use_frame_pt: - body_ops = [Proto(subroutine.argument_count(), stack_output_cnt)] - # reserve a spot for output variable on stack? - # if stack_output_cnt > 0 and subroutine.has_abi_output: - # body_ops += [Int(0), FrameBury(Int(0), 0)] + if not subroutine.has_abi_output: + body_ops = [Proto(subroutine.argument_count(), stack_output_cnt)] + else: + + class TempStuff(Expr): + def __init__(self, arg_cnt, stack_out_cnt): + super().__init__() + self.arg_cnt = arg_cnt + self.stack_cnt = stack_out_cnt + + def __teal__( + self, options: "CompileOptions" + ) -> tuple[TealBlock, TealSimpleBlock]: + proto_srt, proto_end = Proto( + self.arg_cnt, self.stack_cnt + ).__teal__(options) + int_srt, int_end = Int(0xB0BA7EA).__teal__(options) + srt, end = proto_srt, int_end + proto_end.setNextBlock(int_srt) + return srt, end + + def has_return(self) -> bool: + return False + + def type_of(self) -> TealType: + return TealType.none + + def __str__(self) -> str: + return "why_are_you_here" + + body_ops = [TempStuff(subroutine.argument_count(), stack_output_cnt)] body_ops += [var.slot.store() for var in arg_vars[::-1]] body_ops.append(subroutine_body) diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index 36c5bbdf9..2ce12d2a9 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -834,9 +834,9 @@ def abi_sum(toSum: abi.DynamicArray[abi.Uint64], *, output: abi.Uint64) -> Expr: for n in range(N): inputs.append(tuple([random.sample(choices, n)])) - app_inspectors = app_pytealer.dryrun_on_sequence(inputs) + app_inspectors = app_pytealer.dryrun_on_sequence(inputs, compiler_version=8) - lsig_inspectors = lsig_pytealer.dryrun_on_sequence(inputs) + lsig_inspectors = lsig_pytealer.dryrun_on_sequence(inputs, compiler_version=8) for i in range(N): args = inputs[i] From 1e12ca0e322b12e5d81cbab72405a0b614fd9886 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Fri, 28 Oct 2022 17:02:26 -0400 Subject: [PATCH 031/206] move spot reserving in proto --- pyteal/ast/frame.py | 22 +++++++++++++++++++--- pyteal/ast/subroutine.py | 40 +++++++--------------------------------- 2 files changed, 26 insertions(+), 36 deletions(-) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 8b1cb6080..d31e99138 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -1,6 +1,7 @@ from typing import TYPE_CHECKING from pyteal.ast.expr import Expr +from pyteal.ast.int import Int from pyteal.types import TealType, require_type from pyteal.errors import TealInputError, verifyProgramVersion from pyteal.ir import TealBlock, TealSimpleBlock, TealOp, Op @@ -10,14 +11,17 @@ class Proto(Expr): - def __init__(self, arg_num: int, ret_num: int): + def __init__(self, arg_num: int, ret_num: int, /, *, reserve_spot: int = 0): super().__init__() if arg_num < 0: raise TealInputError(f"subroutine arg number {arg_num} must be >= 0") if ret_num < 0: raise TealInputError(f"return value number {ret_num} must be >= 0") + if reserve_spot < 0: + raise TealInputError(f"reserve spot number {reserve_spot} must be >= 0") self.arg_num = arg_num self.ret_num = ret_num + self.reserve_spot = reserve_spot def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: verifyProgramVersion( @@ -26,10 +30,22 @@ def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBloc "Program version too low to use op proto", ) op = TealOp(self, Op.proto, self.arg_num, self.ret_num) - return TealBlock.FromOp(options, op) + proto_srt, proto_end = TealBlock.FromOp(options, op) + if self.reserve_spot == 0: + return proto_srt, proto_end + elif self.reserve_spot == 1: + int_srt, int_end = Int(0xD00D1E).__teal__(options) + proto_end.setNextBlock(int_srt) + return proto_srt, int_end + else: + dupn_srt, dupn_end = DupN(Int(0x5EA51DE), self.reserve_spot).__teal__( + options + ) + proto_end.setNextBlock(dupn_srt) + return proto_srt, dupn_end def __str__(self) -> str: - return f"(proto: arg_num = {self.arg_num}, ret_num = {self.ret_num})" + return f"(proto: arg_num = {self.arg_num}, ret_num = {self.ret_num}, reserve_spot = {self.reserve_spot})" def type_of(self) -> TealType: return TealType.none diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 7cdddc809..0280d0834 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -979,8 +979,6 @@ def __var_n_loaded_fp( def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: # TODO need to make it better for my temp hack, kinda ugly but it works from pyteal.ast.abi.type import FrameStorage - from pyteal.compiler.compiler import TealSimpleBlock - from pyteal.ast.int import Int args = subroutine.arguments() arg_vars: list[ScratchVar] = [] @@ -1033,37 +1031,13 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: stack_output_cnt = len(abi_output_kwargs) if self.use_frame_pt: - if not subroutine.has_abi_output: - body_ops = [Proto(subroutine.argument_count(), stack_output_cnt)] - else: - - class TempStuff(Expr): - def __init__(self, arg_cnt, stack_out_cnt): - super().__init__() - self.arg_cnt = arg_cnt - self.stack_cnt = stack_out_cnt - - def __teal__( - self, options: "CompileOptions" - ) -> tuple[TealBlock, TealSimpleBlock]: - proto_srt, proto_end = Proto( - self.arg_cnt, self.stack_cnt - ).__teal__(options) - int_srt, int_end = Int(0xB0BA7EA).__teal__(options) - srt, end = proto_srt, int_end - proto_end.setNextBlock(int_srt) - return srt, end - - def has_return(self) -> bool: - return False - - def type_of(self) -> TealType: - return TealType.none - - def __str__(self) -> str: - return "why_are_you_here" - - body_ops = [TempStuff(subroutine.argument_count(), stack_output_cnt)] + body_ops = [ + Proto( + subroutine.argument_count(), + stack_output_cnt, + reserve_spot=int(subroutine.has_abi_output), + ) + ] body_ops += [var.slot.store() for var in arg_vars[::-1]] body_ops.append(subroutine_body) From a5cd38aa87e11282f4d6baa114ef66008877a193 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Mon, 31 Oct 2022 10:43:16 -0400 Subject: [PATCH 032/206] reformat code a bit on black box example part --- tests/integration/graviton_test.py | 225 +++++++++++++---------------- 1 file changed, 98 insertions(+), 127 deletions(-) diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index 2ce12d2a9..77c1451f7 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -42,7 +42,7 @@ def wrap_compile_and_save( is_app = mode == pt.Mode.Application teal = PyTealDryRunExecutor(subr, mode).compile(version, assemble_constants) - tealfile = f'{"app" if is_app else "lsig"}_{case_name}.teal' + tealfile = f'{"app" if is_app else "lsig"}_{case_name}_v{version}.teal' tealdir = GENERATED / test_name tealdir.mkdir(parents=True, exist_ok=True) @@ -519,7 +519,7 @@ def blackbox_test_runner( inspectors = list(map(lambda a: execute(algod, teal, a, exec_mode), inputs)) # 4. Statistical report: - csvpath = GENERATED / "blackbox" / f"{tealfile}.csv" + csvpath = GENERATED / "blackbox" / f"{tealfile}_v{version}.csv" with open(csvpath, "w") as f: f.write(DryRunInspector.csv_report(inputs, inspectors)) @@ -577,43 +577,30 @@ def square(x): x = 9 args = [x] - # evaluate the programs - 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( - args, "stack_top() gave unexpected results for app" - ) - assert lsig_result.stack_top() == x**2, lsig_result.report( - args, "stack_top() gave unexpected results for lsig" - ) - - # check to see that itob of x^2 has been logged (only for the app case) - assert app_result.last_log() == DryRunEncoder.hex(x**2), app_result.report( - args, "last_log() gave unexpected results from app" - ) + def evaluate_and_check(_version: int): + # evaluate the programs + app_result = PyTealDryRunExecutor(square, Mode.Application).dryrun( + args, compiler_version=_version + ) + lsig_result = PyTealDryRunExecutor(square, Mode.Signature).dryrun( + args, compiler_version=_version + ) - # evaluate the programs in version 8 - app_result = PyTealDryRunExecutor(square, Mode.Application).dryrun( - args, compiler_version=8 - ) - lsig_result = PyTealDryRunExecutor(square, Mode.Signature).dryrun( - args, compiler_version=8 - ) + # 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( + args, "stack_top() gave unexpected results for app" + ) + assert lsig_result.stack_top() == x**2, lsig_result.report( + args, "stack_top() gave unexpected results for lsig" + ) - # 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( - args, "stack_top() gave unexpected results for app" - ) - assert lsig_result.stack_top() == x**2, lsig_result.report( - args, "stack_top() gave unexpected results for lsig" - ) + # check to see that itob of x^2 has been logged (only for the app case) + assert app_result.last_log() == DryRunEncoder.hex(x**2), app_result.report( + args, "last_log() gave unexpected results from app" + ) - # check to see that itob of x^2 has been logged (only for the app case) - assert app_result.last_log() == DryRunEncoder.hex(x**2), app_result.report( - args, "last_log() gave unexpected results from app" - ) + evaluate_and_check(6) + evaluate_and_check(8) def blackbox_pyteal_example2(): @@ -662,36 +649,24 @@ def euclid(x, y): ) ) - # assert that each result is that same as what Python's math.gcd() computes - 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( - args, f"failed for {args}" + def test_and_report(_verison: int): + # assert that each result is that same as what Python's math.gcd() computes + inspectors = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_on_sequence( + inputs, compiler_version=_verison ) + for i, result in enumerate(inspectors): + args = inputs[i] + assert result.stack_top() == math.gcd(*args), result.report( + args, f"failed for {args}" + ) - # save the CSV to ...current working directory.../euclid.csv - euclid_csv = DryRunInspector.csv_report(inputs, inspectors) - with open(Path.cwd() / "euclid.csv", "w") as f: - f.write(euclid_csv) - - # assert that each result is that same as what Python's math.gcd() computes - # (over v8) - inspectors = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_on_sequence( - inputs, compiler_version=8 - ) - for i, result in enumerate(inspectors): - args = inputs[i] - assert result.stack_top() == math.gcd(*args), result.report( - args, f"failed for {args}" - ) + # save the CSV to ...current working directory.../euclid_v{version}.csv + euclid_csv = DryRunInspector.csv_report(inputs, inspectors) + with open(Path.cwd() / f"euclid_v{_verison}.csv", "w") as f: + f.write(euclid_csv) - # save the CSV to ...current working directory.../euclid_v8.csv - euclid_csv = DryRunInspector.csv_report(inputs, inspectors) - with open(Path.cwd() / "euclid_v8.csv", "w") as f: - f.write(euclid_csv) + test_and_report(6) + test_and_report(8) def blackbox_pyteal_example3(): @@ -834,47 +809,53 @@ def abi_sum(toSum: abi.DynamicArray[abi.Uint64], *, output: abi.Uint64) -> Expr: for n in range(N): inputs.append(tuple([random.sample(choices, n)])) - app_inspectors = app_pytealer.dryrun_on_sequence(inputs, compiler_version=8) + def test_and_report_for_app_and_lsig(_version: int): + app_inspectors = app_pytealer.dryrun_on_sequence( + inputs, compiler_version=_version + ) + lsig_inspectors = lsig_pytealer.dryrun_on_sequence( + inputs, compiler_version=_version + ) + for i in range(N): + args = inputs[i] - lsig_inspectors = lsig_pytealer.dryrun_on_sequence(inputs, compiler_version=8) + app_inspector = app_inspectors[i] + lsig_inspector = lsig_inspectors[i] - for i in range(N): - args = inputs[i] + def message(insp): + return insp.report(args, f"failed for {args}", row=i) - app_inspector = app_inspectors[i] - lsig_inspector = lsig_inspectors[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) - def message(insp): - return insp.report(args, f"failed for {args}", row=i) + expected = sum(args[0]) + actual4app = app_inspector.last_log() + assert expected == actual4app, message(app_inspector) - # 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) + 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 + ) - expected = sum(args[0]) - actual4app = app_inspector.last_log() - assert expected == actual4app, message(app_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}_v{_version}.csv", "w") as f: + f.write(csv_report) - 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 - ) + report("app") + report("lsig") - 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") + test_and_report_for_app_and_lsig(6) + test_and_report_for_app_and_lsig(8) def blackbox_pyteal_example5(): @@ -893,41 +874,31 @@ def cubed(n: abi.Uint64): inputs = [[i] for i in range(1, 11)] - app_inspect = app_pytealer.dryrun_on_sequence(inputs) - lsig_inspect = lsig_pytealer.dryrun_on_sequence(inputs) - - for index, inspect in enumerate(app_inspect): - input_var = inputs[index][0] - assert inspect.stack_top() == input_var**3, inspect.report( - args=inputs[index], msg="stack_top() gave unexpected results from app" - ) - assert inspect.last_log() == DryRunEncoder.hex(input_var**3), inspect.report( - args=inputs[index], msg="last_log() gave unexpected results from app" - ) - - for index, inspect in enumerate(lsig_inspect): - input_var = inputs[index][0] - assert inspect.stack_top() == input_var**3, inspect.report( - args=inputs[index], msg="stack_top() gave unexpected results from app" + def test_app_and_lsig(_version: int): + app_inspect = app_pytealer.dryrun_on_sequence(inputs, compiler_version=_version) + lsig_inspect = lsig_pytealer.dryrun_on_sequence( + inputs, compiler_version=_version ) - app_inspect = app_pytealer.dryrun_on_sequence(inputs, compiler_version=8) - lsig_inspect = lsig_pytealer.dryrun_on_sequence(inputs, compiler_version=8) + for index, inspect in enumerate(app_inspect): + input_var = inputs[index][0] + assert inspect.stack_top() == input_var**3, inspect.report( + args=inputs[index], msg="stack_top() gave unexpected results from app" + ) + assert inspect.last_log() == DryRunEncoder.hex( + input_var**3 + ), inspect.report( + args=inputs[index], msg="last_log() gave unexpected results from app" + ) - for index, inspect in enumerate(app_inspect): - input_var = inputs[index][0] - assert inspect.stack_top() == input_var**3, inspect.report( - args=inputs[index], msg="stack_top() gave unexpected results from app" - ) - assert inspect.last_log() == DryRunEncoder.hex(input_var**3), inspect.report( - args=inputs[index], msg="last_log() gave unexpected results from app" - ) + for index, inspect in enumerate(lsig_inspect): + input_var = inputs[index][0] + assert inspect.stack_top() == input_var**3, inspect.report( + args=inputs[index], msg="stack_top() gave unexpected results from app" + ) - for index, inspect in enumerate(lsig_inspect): - input_var = inputs[index][0] - assert inspect.stack_top() == input_var**3, inspect.report( - args=inputs[index], msg="stack_top() gave unexpected results from app" - ) + test_app_and_lsig(6) + test_app_and_lsig(8) def blackbox_pyteal_while_continue_test(): From 7db5dfae8412128cfbd20a0d36ef98a8c00a1252 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Mon, 31 Oct 2022 11:26:24 -0400 Subject: [PATCH 033/206] start changing abi roundtrip tesal file name --- tests/integration/abi_roundtrip_test.py | 6 +- tests/integration/graviton_abi_test.py | 20 ++-- tests/integration/graviton_test.py | 2 + ...dtrip_().teal => app_roundtrip_()_v6.teal} | 0 ....teal => app_roundtrip_(bool)[10]_v6.teal} | 0 ...ool).teal => app_roundtrip_(bool)_v6.teal} | 0 ...64,bool),byte[10],bool[4],uint64)_v6.teal} | 0 ...teal => app_roundtrip_(bool,byte)_v6.teal} | 0 ...ndtrip_(bool,byte,address,string)_v6.teal} | 0 ...te),uint8)[2],string,bool[]))[]_2_v6.teal} | 0 ...(bool,byte,address,string,uint64)_v6.teal} | 0 ...pp_roundtrip_(bool,uint64,uint32)_v6.teal} | 0 ...yte).teal => app_roundtrip_(byte)_v6.teal} | 0 ... app_roundtrip_(byte,bool,uint64)_v6.teal} | 0 ...],(bool,bool),uint64,address)[]_7_v6.teal} | 0 ...6).teal => app_roundtrip_(uint16)_v6.teal} | 0 ...app_roundtrip_(uint16,uint8,byte)_v6.teal} | 0 ...2).teal => app_roundtrip_(uint32)_v6.teal} | 0 ...p_roundtrip_(uint32,uint16,uint8)_v6.teal} | 0 ...4).teal => app_roundtrip_(uint64)_v6.teal} | 0 ..._roundtrip_(uint64,uint32,uint16)_v6.teal} | 0 ...t8).teal => app_roundtrip_(uint8)_v6.teal} | 0 .../app_roundtrip_(uint8,byte,bool).teal | 111 ------------------ .../app_roundtrip_(uint8,byte,bool)_v6.teal | 111 ++++++++++++++++++ ...eal => app_roundtrip_address[]_10_v6.teal} | 0 ...ess.teal => app_roundtrip_address_v6.teal} | 0 ...[1].teal => app_roundtrip_bool[1]_v6.teal} | 0 ...eal => app_roundtrip_bool[3][]_11_v6.teal} | 0 ...2].teal => app_roundtrip_bool[42]_v6.teal} | 0 ..._0.teal => app_roundtrip_bool[]_0_v6.teal} | 0 ..._1.teal => app_roundtrip_bool[]_1_v6.teal} | 0 ...2.teal => app_roundtrip_bool[]_42_v6.teal} | 0 ...p_bool.teal => app_roundtrip_bool_v6.teal} | 0 ...6].teal => app_roundtrip_byte[16]_v6.teal} | 0 ...6.teal => app_roundtrip_byte[]_36_v6.teal} | 0 ...p_byte.teal => app_roundtrip_byte_v6.teal} | 0 ..._0.teal => app_roundtrip_string_0_v6.teal} | 0 ...3.teal => app_roundtrip_string_13_v6.teal} | 0 ..._1.teal => app_roundtrip_string_1_v6.teal} | 0 ...nt16.teal => app_roundtrip_uint16_v6.teal} | 0 ...nt32.teal => app_roundtrip_uint32_v6.teal} | 0 ...].teal => app_roundtrip_uint64[1]_v6.teal} | 0 ....teal => app_roundtrip_uint64[42]_v6.teal} | 0 ....teal => app_roundtrip_uint64[]_0_v6.teal} | 0 ....teal => app_roundtrip_uint64[]_1_v6.teal} | 0 ...teal => app_roundtrip_uint64[]_42_v6.teal} | 0 ...nt64.teal => app_roundtrip_uint64_v6.teal} | 0 ...uint8.teal => app_roundtrip_uint8_v6.teal} | 0 48 files changed, 130 insertions(+), 120 deletions(-) rename tests/integration/teal/roundtrip/{app_roundtrip_().teal => app_roundtrip_()_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_(bool)[10].teal => app_roundtrip_(bool)[10]_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_(bool).teal => app_roundtrip_(bool)_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64).teal => app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64)_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_(bool,byte).teal => app_roundtrip_(bool,byte)_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_(bool,byte,address,string).teal => app_roundtrip_(bool,byte,address,string)_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_2.teal => app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_2_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_(bool,byte,address,string,uint64).teal => app_roundtrip_(bool,byte,address,string,uint64)_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_(bool,uint64,uint32).teal => app_roundtrip_(bool,uint64,uint32)_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_(byte).teal => app_roundtrip_(byte)_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_(byte,bool,uint64).teal => app_roundtrip_(byte,bool,uint64)_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7.teal => app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_(uint16).teal => app_roundtrip_(uint16)_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_(uint16,uint8,byte).teal => app_roundtrip_(uint16,uint8,byte)_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_(uint32).teal => app_roundtrip_(uint32)_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_(uint32,uint16,uint8).teal => app_roundtrip_(uint32,uint16,uint8)_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_(uint64).teal => app_roundtrip_(uint64)_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_(uint64,uint32,uint16).teal => app_roundtrip_(uint64,uint32,uint16)_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_(uint8).teal => app_roundtrip_(uint8)_v6.teal} (100%) delete mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool).teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v6.teal rename tests/integration/teal/roundtrip/{app_roundtrip_address[]_10.teal => app_roundtrip_address[]_10_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_address.teal => app_roundtrip_address_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_bool[1].teal => app_roundtrip_bool[1]_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_bool[3][]_11.teal => app_roundtrip_bool[3][]_11_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_bool[42].teal => app_roundtrip_bool[42]_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_bool[]_0.teal => app_roundtrip_bool[]_0_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_bool[]_1.teal => app_roundtrip_bool[]_1_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_bool[]_42.teal => app_roundtrip_bool[]_42_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_bool.teal => app_roundtrip_bool_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_byte[16].teal => app_roundtrip_byte[16]_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_byte[]_36.teal => app_roundtrip_byte[]_36_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_byte.teal => app_roundtrip_byte_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_string_0.teal => app_roundtrip_string_0_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_string_13.teal => app_roundtrip_string_13_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_string_1.teal => app_roundtrip_string_1_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_uint16.teal => app_roundtrip_uint16_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_uint32.teal => app_roundtrip_uint32_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_uint64[1].teal => app_roundtrip_uint64[1]_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_uint64[42].teal => app_roundtrip_uint64[42]_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_uint64[]_0.teal => app_roundtrip_uint64[]_0_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_uint64[]_1.teal => app_roundtrip_uint64[]_1_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_uint64[]_42.teal => app_roundtrip_uint64[]_42_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_uint64.teal => app_roundtrip_uint64_v6.teal} (100%) rename tests/integration/teal/roundtrip/{app_roundtrip_uint8.teal => app_roundtrip_uint8_v6.teal} (100%) diff --git a/tests/integration/abi_roundtrip_test.py b/tests/integration/abi_roundtrip_test.py index e0ca05484..debded3aa 100644 --- a/tests/integration/abi_roundtrip_test.py +++ b/tests/integration/abi_roundtrip_test.py @@ -196,6 +196,10 @@ def test_pure_compilation(abi_type): print(f"Pure Compilation Test for {abi_type=}") abi_type, type_str, dynamic_length, roundtripper = roundtrip_setup(abi_type) + # TODO neeed to make this version flexible + + _version = 6 + if type_str in BAD_TYPES: print( f"Skipping encoding roundtrip test of '{abi_type}' because of {BAD_TYPES[type_str]}" @@ -214,7 +218,7 @@ def test_pure_compilation(abi_type): filename = ( f"app_roundtrip_{sdk_abi_type}" + ("" if dynamic_length is None else f"_{dynamic_length}") - + ".teal" + + f"_v{_version}.teal" ) tealdir = GENERATED / "roundtrip" tealdir.mkdir(parents=True, exist_ok=True) diff --git a/tests/integration/graviton_abi_test.py b/tests/integration/graviton_abi_test.py index 229b7a671..0b571824c 100644 --- a/tests/integration/graviton_abi_test.py +++ b/tests/integration/graviton_abi_test.py @@ -15,8 +15,8 @@ """ -WARNING: The following ABI types Int65 and Complex130 are ONLY for the purpose of testing/demo'ing -ABISubroutine and graviton ABI capabilities and are NOT the recommended approach for +WARNING: The following ABI types Int65 and Complex130 are ONLY for the purpose of testing/demo'ing +ABISubroutine and graviton ABI capabilities and are NOT the recommended approach for implementing integers and complex integers. A better approach would likely leverage `Uint64` (if any ABI type at all) and make use of 2's complement arithmetic. @@ -438,17 +438,21 @@ def pytuple_to_complex(tt): ] # Binary: - def binary_dryrun(p: PyTealDryRunExecutor) -> list[DryRunInspector]: - return p.dryrun_on_sequence(binary_inputs) + def binary_dryrun( + p: PyTealDryRunExecutor, _version: int = 6 + ) -> list[DryRunInspector]: + return p.dryrun_on_sequence(binary_inputs, compiler_version=_version) + + # Unary: + def unary_dryrun( + p: PyTealDryRunExecutor, _version: int = 6 + ) -> list[DryRunInspector]: + return p.dryrun_on_sequence(unary_inputs, compiler_version=_version) 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) diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index 77c1451f7..8dd141180 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -163,6 +163,8 @@ def test_stable_teal_generation(subr, mode): case_name = subr.name() print(f"stable TEAL generation test for {case_name} in mode {mode}") + # HANG NOTE: I prefer not to modify this test, for it is skipped now on thread-unsafe behavior, + # and I would suggest revisiting later after we have satisfied solution for #199. _, _, tealfile = wrap_compile_and_save(subr, mode, 6, True, "stability", case_name) path2actual = GENERATED / "stability" / tealfile path2expected = FIXTURES / "stability" / tealfile diff --git a/tests/integration/teal/roundtrip/app_roundtrip_().teal b/tests/integration/teal/roundtrip/app_roundtrip_()_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_().teal rename to tests/integration/teal/roundtrip/app_roundtrip_()_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10].teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10]_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_(bool)[10].teal rename to tests/integration/teal/roundtrip/app_roundtrip_(bool)[10]_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool).teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool)_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_(bool).teal rename to tests/integration/teal/roundtrip/app_roundtrip_(bool)_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64).teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64)_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64).teal rename to tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64)_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte).teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte)_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_(bool,byte).teal rename to tests/integration/teal/roundtrip/app_roundtrip_(bool,byte)_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string).teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string)_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string).teal rename to tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string)_v6.teal 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_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_2.teal rename to tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_2_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64).teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64)_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64).teal rename to tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64)_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32).teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32)_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32).teal rename to tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32)_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(byte).teal b/tests/integration/teal/roundtrip/app_roundtrip_(byte)_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_(byte).teal rename to tests/integration/teal/roundtrip/app_roundtrip_(byte)_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64).teal b/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64)_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64).teal rename to tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64)_v6.teal 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_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7.teal rename to tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint16).teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint16)_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_(uint16).teal rename to tests/integration/teal/roundtrip/app_roundtrip_(uint16)_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte).teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte)_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte).teal rename to tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte)_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint32).teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint32)_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_(uint32).teal rename to tests/integration/teal/roundtrip/app_roundtrip_(uint32)_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8).teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8)_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8).teal rename to tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8)_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint64).teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint64)_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_(uint64).teal rename to tests/integration/teal/roundtrip/app_roundtrip_(uint64)_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16).teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16)_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16).teal rename to tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16)_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint8).teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint8)_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_(uint8).teal rename to tests/integration/teal/roundtrip/app_roundtrip_(uint8)_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool).teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool).teal deleted file mode 100644 index 251e70b5e..000000000 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool).teal +++ /dev/null @@ -1,111 +0,0 @@ -#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] -retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v6.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v6.teal new file mode 100644 index 000000000..d2f050703 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v6.teal @@ -0,0 +1,111 @@ +#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 1 +getbyte +store 1 +load 9 +int 16 +getbit +store 2 +load 0 +callsub numericalcomp_2 +store 0 +load 1 +callsub numericalcomp_3 +store 1 +load 2 +callsub boolcomp_4 +store 2 +byte 0x00 +int 0 +load 0 +setbyte +byte 0x00 +int 0 +load 1 +setbyte +concat +byte 0x00 +int 0 +load 2 +setbit +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 + +// numerical_comp +numericalcomp_3: +store 13 +int 255 +load 13 +- +store 14 +load 14 +int 256 +< +assert +load 14 +retsub + +// bool_comp +boolcomp_4: +store 15 +load 15 +! +! +! +store 16 +load 16 +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_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_address[]_10.teal rename to tests/integration/teal/roundtrip/app_roundtrip_address[]_10_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_address.teal b/tests/integration/teal/roundtrip/app_roundtrip_address_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_address.teal rename to tests/integration/teal/roundtrip/app_roundtrip_address_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[1].teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[1]_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_bool[1].teal rename to tests/integration/teal/roundtrip/app_roundtrip_bool[1]_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11.teal rename to tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[42].teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[42]_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_bool[42].teal rename to tests/integration/teal/roundtrip/app_roundtrip_bool[42]_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_0.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_0_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_bool[]_0.teal rename to tests/integration/teal/roundtrip/app_roundtrip_bool[]_0_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_1.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_1_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_bool[]_1.teal rename to tests/integration/teal/roundtrip/app_roundtrip_bool[]_1_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_42.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_42_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_bool[]_42.teal rename to tests/integration/teal/roundtrip/app_roundtrip_bool[]_42_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_bool.teal rename to tests/integration/teal/roundtrip/app_roundtrip_bool_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_byte[16].teal b/tests/integration/teal/roundtrip/app_roundtrip_byte[16]_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_byte[16].teal rename to tests/integration/teal/roundtrip/app_roundtrip_byte[16]_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_byte[]_36.teal b/tests/integration/teal/roundtrip/app_roundtrip_byte[]_36_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_byte[]_36.teal rename to tests/integration/teal/roundtrip/app_roundtrip_byte[]_36_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_byte.teal b/tests/integration/teal/roundtrip/app_roundtrip_byte_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_byte.teal rename to tests/integration/teal/roundtrip/app_roundtrip_byte_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_string_0.teal b/tests/integration/teal/roundtrip/app_roundtrip_string_0_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_string_0.teal rename to tests/integration/teal/roundtrip/app_roundtrip_string_0_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_string_13.teal b/tests/integration/teal/roundtrip/app_roundtrip_string_13_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_string_13.teal rename to tests/integration/teal/roundtrip/app_roundtrip_string_13_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_string_1.teal b/tests/integration/teal/roundtrip/app_roundtrip_string_1_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_string_1.teal rename to tests/integration/teal/roundtrip/app_roundtrip_string_1_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint16.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint16_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_uint16.teal rename to tests/integration/teal/roundtrip/app_roundtrip_uint16_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint32.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint32_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_uint32.teal rename to tests/integration/teal/roundtrip/app_roundtrip_uint32_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[1].teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[1]_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_uint64[1].teal rename to tests/integration/teal/roundtrip/app_roundtrip_uint64[1]_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[42].teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[42]_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_uint64[42].teal rename to tests/integration/teal/roundtrip/app_roundtrip_uint64[42]_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0.teal rename to tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1.teal rename to tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42.teal rename to tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_uint64.teal rename to tests/integration/teal/roundtrip/app_roundtrip_uint64_v6.teal diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint8_v6.teal similarity index 100% rename from tests/integration/teal/roundtrip/app_roundtrip_uint8.teal rename to tests/integration/teal/roundtrip/app_roundtrip_uint8_v6.teal From e1dbcd77e637c6b9acb6eb04aa858bb43b32f433 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Mon, 31 Oct 2022 12:37:20 -0400 Subject: [PATCH 034/206] roundtrip test --- pyteal/ast/abi/tuple.py | 4 + pyteal/ast/subroutine.py | 2 +- tests/integration/abi_roundtrip_test.py | 6 +- .../teal/roundtrip/app_roundtrip_()_v8.teal | 40 + .../app_roundtrip_(bool)[10]_v8.teal | 189 ++ .../roundtrip/app_roundtrip_(bool)_v8.teal | 62 + ...t64,bool),byte[10],bool[4],uint64)_v8.teal | 860 +++++++ .../app_roundtrip_(bool,byte)_v8.teal | 89 + ...undtrip_(bool,byte,address,string)_v8.teal | 690 ++++++ ...yte),uint8)[2],string,bool[]))[]_2_v8.teal | 2057 +++++++++++++++++ ..._(bool,byte,address,string,uint64)_v8.teal | 711 ++++++ ...app_roundtrip_(bool,uint64,uint32)_v8.teal | 109 + .../roundtrip/app_roundtrip_(byte)_v8.teal | 65 + .../app_roundtrip_(byte,bool,uint64)_v8.teal | 110 + ...4],(bool,bool),uint64,address)[]_7_v8.teal | 843 +++++++ .../roundtrip/app_roundtrip_(uint16)_v8.teal | 64 + .../app_roundtrip_(uint16,uint8,byte)_v8.teal | 118 + .../roundtrip/app_roundtrip_(uint32)_v8.teal | 64 + ...pp_roundtrip_(uint32,uint16,uint8)_v8.teal | 117 + .../roundtrip/app_roundtrip_(uint64)_v8.teal | 58 + ...p_roundtrip_(uint64,uint32,uint16)_v8.teal | 111 + .../roundtrip/app_roundtrip_(uint8)_v8.teal | 65 + .../app_roundtrip_(uint8,byte,bool)_v8.teal | 116 + .../app_roundtrip_address[]_10_v8.teal | 702 ++++++ .../roundtrip/app_roundtrip_address_v8.teal | 501 ++++ .../roundtrip/app_roundtrip_bool[1]_v8.teal | 62 + .../app_roundtrip_bool[3][]_11_v8.teal | 297 +++ .../roundtrip/app_roundtrip_bool[42]_v8.teal | 472 ++++ .../roundtrip/app_roundtrip_bool[]_0_v8.teal | 94 + .../roundtrip/app_roundtrip_bool[]_1_v8.teal | 118 + .../roundtrip/app_roundtrip_bool[]_42_v8.teal | 610 +++++ .../teal/roundtrip/app_roundtrip_bool_v8.teal | 52 + .../roundtrip/app_roundtrip_byte[16]_v8.teal | 277 +++ .../roundtrip/app_roundtrip_byte[]_36_v8.teal | 683 ++++++ .../teal/roundtrip/app_roundtrip_byte_v8.teal | 57 + .../roundtrip/app_roundtrip_string_0_v8.teal | 94 + .../roundtrip/app_roundtrip_string_13_v8.teal | 261 +++ .../roundtrip/app_roundtrip_string_1_v8.teal | 105 + .../roundtrip/app_roundtrip_uint16_v8.teal | 54 + .../roundtrip/app_roundtrip_uint32_v8.teal | 54 + .../roundtrip/app_roundtrip_uint64[1]_v8.teal | 61 + .../app_roundtrip_uint64[42]_v8.teal | 553 +++++ .../app_roundtrip_uint64[]_0_v8.teal | 94 + .../app_roundtrip_uint64[]_1_v8.teal | 117 + .../app_roundtrip_uint64[]_42_v8.teal | 691 ++++++ .../roundtrip/app_roundtrip_uint64_v8.teal | 46 + .../roundtrip/app_roundtrip_uint8_v8.teal | 57 + 47 files changed, 12658 insertions(+), 4 deletions(-) create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_()_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(bool)[10]_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(bool)_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64)_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(bool,byte)_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string)_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_2_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64)_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32)_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(byte)_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64)_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(uint16)_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte)_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(uint32)_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8)_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(uint64)_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16)_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(uint8)_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_address[]_10_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_address_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_bool[1]_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_bool[42]_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_bool[]_0_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_bool[]_1_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_bool[]_42_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_bool_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_byte[16]_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_byte[]_36_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_byte_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_string_0_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_string_13_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_string_1_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_uint16_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_uint32_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_uint64[1]_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_uint64[42]_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_uint64_v8.teal create mode 100644 tests/integration/teal/roundtrip/app_roundtrip_uint8_v8.teal diff --git a/pyteal/ast/abi/tuple.py b/pyteal/ast/abi/tuple.py index 2f2dceeab..cabe52f7c 100644 --- a/pyteal/ast/abi/tuple.py +++ b/pyteal/ast/abi/tuple.py @@ -679,6 +679,10 @@ def __setattr__(self, name: str, field: Any) -> None: if name == "_NamedTuple__ready" or not self.__ready: super().__setattr__(name, field) return + # TODO need to relax this part lol + if name.startswith("_") and name != "_NamedTuple__ready" and self.__ready: + super().__setattr__(name, field) + return raise TealInputError("cannot assign to NamedTuple attributes.") diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 0280d0834..739bc498a 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -996,7 +996,7 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: if output_kwarg_info: output_carrying_abi = output_kwarg_info.abi_type.new_instance() if self.use_frame_pt: - output_carrying_abi._data_storage = FrameStorage(TealType.anytype, 0) + output_carrying_abi._set_data_source(FrameStorage(TealType.anytype, 0)) abi_output_kwargs[output_kwarg_info.name] = output_carrying_abi # Arg usage "B" supplied to build an AST from the user-defined PyTEAL function: diff --git a/tests/integration/abi_roundtrip_test.py b/tests/integration/abi_roundtrip_test.py index debded3aa..52b226471 100644 --- a/tests/integration/abi_roundtrip_test.py +++ b/tests/integration/abi_roundtrip_test.py @@ -198,7 +198,7 @@ def test_pure_compilation(abi_type): # TODO neeed to make this version flexible - _version = 6 + _version = 8 if type_str in BAD_TYPES: print( @@ -213,7 +213,7 @@ def test_pure_compilation(abi_type): assert [sdk_abi_type] == abi_arg_types assert algosdk.abi.TupleType([sdk_abi_type] * 3) == abi_ret_type - teal = roundtripper.compile(version=6) + teal = roundtripper.compile(version=_version) filename = ( f"app_roundtrip_{sdk_abi_type}" @@ -255,7 +255,7 @@ def test_roundtrip(abi_type): 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) + inspector = roundtripper.dryrun(args, compiler_version=8) cost = inspector.cost() passed = inspector.passed() diff --git a/tests/integration/teal/roundtrip/app_roundtrip_()_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_()_v8.teal new file mode 100644 index 000000000..7f74c2e54 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_()_v8.teal @@ -0,0 +1,40 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +byte "" +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub tuplecomplement_0 +store 2 +load 2 +callsub tuplecomplement_0 +store 3 +frame_dig -1 +load 2 +concat +load 3 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10]_v8.teal new file mode 100644 index 000000000..f2c4408b5 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10]_v8.teal @@ -0,0 +1,189 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +getbit +store 0 +load 0 +callsub boolcomp_3 +store 0 +byte 0x00 +int 0 +load 0 +setbit +frame_bury 0 +frame_dig 0 +retsub + +// array_complement +arraycomplement_1: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +int 1 +extract3 +store 5 +frame_dig -1 +int 1 +int 1 +* +int 1 +extract3 +store 6 +frame_dig -1 +int 1 +int 2 +* +int 1 +extract3 +store 7 +frame_dig -1 +int 1 +int 3 +* +int 1 +extract3 +store 8 +frame_dig -1 +int 1 +int 4 +* +int 1 +extract3 +store 9 +frame_dig -1 +int 1 +int 5 +* +int 1 +extract3 +store 10 +frame_dig -1 +int 1 +int 6 +* +int 1 +extract3 +store 11 +frame_dig -1 +int 1 +int 7 +* +int 1 +extract3 +store 12 +frame_dig -1 +int 1 +int 8 +* +int 1 +extract3 +store 13 +frame_dig -1 +int 1 +int 9 +* +int 1 +extract3 +store 14 +load 5 +callsub tuplecomplement_0 +store 5 +load 6 +callsub tuplecomplement_0 +store 6 +load 7 +callsub tuplecomplement_0 +store 7 +load 8 +callsub tuplecomplement_0 +store 8 +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 5 +load 6 +concat +load 7 +concat +load 8 +concat +load 9 +concat +load 10 +concat +load 11 +concat +load 12 +concat +load 13 +concat +load 14 +concat +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_2: +proto 1 1 +int 13634846 +frame_dig -1 +callsub arraycomplement_1 +store 3 +load 3 +callsub arraycomplement_1 +store 4 +frame_dig -1 +load 3 +concat +load 4 +concat +frame_bury 0 +frame_dig 0 +retsub + +// bool_comp +boolcomp_3: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool)_v8.teal new file mode 100644 index 000000000..740a8041a --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool)_v8.teal @@ -0,0 +1,62 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +getbit +store 0 +load 0 +callsub boolcomp_2 +store 0 +byte 0x00 +int 0 +load 0 +setbit +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub tuplecomplement_0 +store 3 +load 3 +callsub tuplecomplement_0 +store 4 +frame_dig -1 +load 3 +concat +load 4 +concat +frame_bury 0 +frame_dig 0 +retsub + +// bool_comp +boolcomp_2: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64)_v8.teal new file mode 100644 index 000000000..cc255e503 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64)_v8.teal @@ -0,0 +1,860 @@ +#pragma version 8 +txna ApplicationArgs 0 +store 7 +load 7 +callsub roundtripper_1 +store 6 +byte 0x151f7c75 +load 6 +concat +log +int 1 +return + +// tuple_complement +tuplecomplement_0: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +getbit +store 0 +frame_dig -1 +extract 1 32 +store 1 +frame_dig -1 +extract 33 9 +store 2 +frame_dig -1 +extract 42 10 +store 3 +frame_dig -1 +extract 52 1 +store 4 +frame_dig -1 +int 53 +extract_uint64 +store 5 +load 0 +callsub boolcomp_2 +store 0 +load 1 +callsub arraycomplement_4 +store 1 +load 2 +callsub tuplecomplement_5 +store 2 +load 3 +callsub arraycomplement_7 +store 3 +load 4 +callsub arraycomplement_9 +store 4 +load 5 +callsub numericalcomp_10 +store 5 +byte 0x00 +int 0 +load 0 +setbit +load 1 +concat +load 2 +concat +load 3 +concat +load 4 +concat +load 5 +itob +concat +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub tuplecomplement_0 +store 8 +load 8 +callsub tuplecomplement_0 +store 9 +frame_dig -1 +load 8 +concat +load 9 +concat +frame_bury 0 +frame_dig 0 +retsub + +// bool_comp +boolcomp_2: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_3: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// array_complement +arraycomplement_4: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +getbyte +store 12 +frame_dig -1 +int 1 +int 1 +* +getbyte +store 13 +frame_dig -1 +int 1 +int 2 +* +getbyte +store 14 +frame_dig -1 +int 1 +int 3 +* +getbyte +store 15 +frame_dig -1 +int 1 +int 4 +* +getbyte +store 16 +frame_dig -1 +int 1 +int 5 +* +getbyte +store 17 +frame_dig -1 +int 1 +int 6 +* +getbyte +store 18 +frame_dig -1 +int 1 +int 7 +* +getbyte +store 19 +frame_dig -1 +int 1 +int 8 +* +getbyte +store 20 +frame_dig -1 +int 1 +int 9 +* +getbyte +store 21 +frame_dig -1 +int 1 +int 10 +* +getbyte +store 22 +frame_dig -1 +int 1 +int 11 +* +getbyte +store 23 +frame_dig -1 +int 1 +int 12 +* +getbyte +store 24 +frame_dig -1 +int 1 +int 13 +* +getbyte +store 25 +frame_dig -1 +int 1 +int 14 +* +getbyte +store 26 +frame_dig -1 +int 1 +int 15 +* +getbyte +store 27 +frame_dig -1 +int 1 +int 16 +* +getbyte +store 28 +frame_dig -1 +int 1 +int 17 +* +getbyte +store 29 +frame_dig -1 +int 1 +int 18 +* +getbyte +store 30 +frame_dig -1 +int 1 +int 19 +* +getbyte +store 31 +frame_dig -1 +int 1 +int 20 +* +getbyte +store 32 +frame_dig -1 +int 1 +int 21 +* +getbyte +store 33 +frame_dig -1 +int 1 +int 22 +* +getbyte +store 34 +frame_dig -1 +int 1 +int 23 +* +getbyte +store 35 +frame_dig -1 +int 1 +int 24 +* +getbyte +store 36 +frame_dig -1 +int 1 +int 25 +* +getbyte +store 37 +frame_dig -1 +int 1 +int 26 +* +getbyte +store 38 +frame_dig -1 +int 1 +int 27 +* +getbyte +store 39 +frame_dig -1 +int 1 +int 28 +* +getbyte +store 40 +frame_dig -1 +int 1 +int 29 +* +getbyte +store 41 +frame_dig -1 +int 1 +int 30 +* +getbyte +store 42 +frame_dig -1 +int 1 +int 31 +* +getbyte +store 43 +load 12 +callsub numericalcomp_3 +store 12 +load 13 +callsub numericalcomp_3 +store 13 +load 14 +callsub numericalcomp_3 +store 14 +load 15 +callsub numericalcomp_3 +store 15 +load 16 +callsub numericalcomp_3 +store 16 +load 17 +callsub numericalcomp_3 +store 17 +load 18 +callsub numericalcomp_3 +store 18 +load 19 +callsub numericalcomp_3 +store 19 +load 20 +callsub numericalcomp_3 +store 20 +load 21 +callsub numericalcomp_3 +store 21 +load 22 +callsub numericalcomp_3 +store 22 +load 23 +callsub numericalcomp_3 +store 23 +load 24 +callsub numericalcomp_3 +store 24 +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 +load 29 +callsub numericalcomp_3 +store 29 +load 30 +callsub numericalcomp_3 +store 30 +load 31 +callsub numericalcomp_3 +store 31 +load 32 +callsub numericalcomp_3 +store 32 +load 33 +callsub numericalcomp_3 +store 33 +load 34 +callsub numericalcomp_3 +store 34 +load 35 +callsub numericalcomp_3 +store 35 +load 36 +callsub numericalcomp_3 +store 36 +load 37 +callsub numericalcomp_3 +store 37 +load 38 +callsub numericalcomp_3 +store 38 +load 39 +callsub numericalcomp_3 +store 39 +load 40 +callsub numericalcomp_3 +store 40 +load 41 +callsub numericalcomp_3 +store 41 +load 42 +callsub numericalcomp_3 +store 42 +load 43 +callsub numericalcomp_3 +store 43 +byte 0x00 +int 0 +load 12 +setbyte +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 +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 +frame_bury 0 +frame_dig 0 +retsub + +// tuple_complement +tuplecomplement_5: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +extract_uint64 +store 10 +frame_dig -1 +int 64 +getbit +store 11 +load 10 +callsub numericalcomp_11 +store 10 +load 11 +callsub boolcomp_12 +store 11 +load 10 +itob +byte 0x00 +int 0 +load 11 +setbit +concat +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_6: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// array_complement +arraycomplement_7: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +getbyte +store 44 +frame_dig -1 +int 1 +int 1 +* +getbyte +store 45 +frame_dig -1 +int 1 +int 2 +* +getbyte +store 46 +frame_dig -1 +int 1 +int 3 +* +getbyte +store 47 +frame_dig -1 +int 1 +int 4 +* +getbyte +store 48 +frame_dig -1 +int 1 +int 5 +* +getbyte +store 49 +frame_dig -1 +int 1 +int 6 +* +getbyte +store 50 +frame_dig -1 +int 1 +int 7 +* +getbyte +store 51 +frame_dig -1 +int 1 +int 8 +* +getbyte +store 52 +frame_dig -1 +int 1 +int 9 +* +getbyte +store 53 +load 44 +callsub numericalcomp_6 +store 44 +load 45 +callsub numericalcomp_6 +store 45 +load 46 +callsub numericalcomp_6 +store 46 +load 47 +callsub numericalcomp_6 +store 47 +load 48 +callsub numericalcomp_6 +store 48 +load 49 +callsub numericalcomp_6 +store 49 +load 50 +callsub numericalcomp_6 +store 50 +load 51 +callsub numericalcomp_6 +store 51 +load 52 +callsub numericalcomp_6 +store 52 +load 53 +callsub numericalcomp_6 +store 53 +byte 0x00 +int 0 +load 44 +setbyte +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 +frame_bury 0 +frame_dig 0 +retsub + +// bool_comp +boolcomp_8: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub + +// array_complement +arraycomplement_9: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +getbit +store 54 +frame_dig -1 +int 1 +getbit +store 55 +frame_dig -1 +int 2 +getbit +store 56 +frame_dig -1 +int 3 +getbit +store 57 +load 54 +callsub boolcomp_8 +store 54 +load 55 +callsub boolcomp_8 +store 55 +load 56 +callsub boolcomp_8 +store 56 +load 57 +callsub boolcomp_8 +store 57 +byte 0x00 +int 0 +load 54 +setbit +int 1 +load 55 +setbit +int 2 +load 56 +setbit +int 3 +load 57 +setbit +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_10: +proto 1 1 +int 13634846 +int 18446744073709551615 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_11: +proto 1 1 +int 13634846 +int 18446744073709551615 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +retsub + +// bool_comp +boolcomp_12: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte)_v8.teal new file mode 100644 index 000000000..c8147ff68 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte)_v8.teal @@ -0,0 +1,89 @@ +#pragma version 8 +txna ApplicationArgs 0 +store 3 +load 3 +callsub roundtripper_1 +store 2 +byte 0x151f7c75 +load 2 +concat +log +int 1 +return + +// tuple_complement +tuplecomplement_0: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +getbit +store 0 +frame_dig -1 +int 1 +getbyte +store 1 +load 0 +callsub boolcomp_2 +store 0 +load 1 +callsub numericalcomp_3 +store 1 +byte 0x00 +int 0 +load 0 +setbit +byte 0x00 +int 0 +load 1 +setbyte +concat +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub tuplecomplement_0 +store 4 +load 4 +callsub tuplecomplement_0 +store 5 +frame_dig -1 +load 4 +concat +load 5 +concat +frame_bury 0 +frame_dig 0 +retsub + +// bool_comp +boolcomp_2: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_3: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string)_v8.teal new file mode 100644 index 000000000..1840f754d --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string)_v8.teal @@ -0,0 +1,690 @@ +#pragma version 8 +txna ApplicationArgs 0 +store 5 +load 5 +callsub roundtripper_1 +store 4 +byte 0x151f7c75 +load 4 +concat +log +int 1 +return + +// tuple_complement +tuplecomplement_0: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +getbit +store 0 +frame_dig -1 +int 1 +getbyte +store 1 +frame_dig -1 +extract 2 32 +store 2 +frame_dig -1 +frame_dig -1 +int 34 +extract_uint16 +dig 1 +len +substring3 +store 3 +load 0 +callsub boolcomp_2 +store 0 +load 1 +callsub numericalcomp_3 +store 1 +load 2 +callsub arraycomplement_5 +store 2 +load 3 +callsub stringreverse_6 +store 3 +byte 0x00 +int 0 +load 0 +setbit +byte 0x00 +int 0 +load 1 +setbyte +concat +load 2 +concat +load 3 +store 14 +load 14 +store 13 +int 36 +store 12 +load 12 +itob +extract 6 0 +concat +load 13 +concat +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub tuplecomplement_0 +store 6 +load 6 +callsub tuplecomplement_0 +store 7 +frame_dig -1 +store 11 +load 11 +store 10 +int 6 +store 8 +load 8 +load 11 +len ++ +store 9 +load 9 +int 65536 +< +assert +load 8 +itob +extract 6 0 +load 6 +store 11 +load 10 +load 11 +concat +store 10 +load 9 +store 8 +load 8 +load 11 +len ++ +store 9 +load 9 +int 65536 +< +assert +load 8 +itob +extract 6 0 +concat +load 7 +store 11 +load 10 +load 11 +concat +store 10 +load 9 +store 8 +load 8 +itob +extract 6 0 +concat +load 10 +concat +frame_bury 0 +frame_dig 0 +retsub + +// bool_comp +boolcomp_2: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_3: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_4: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// array_complement +arraycomplement_5: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +getbyte +store 15 +frame_dig -1 +int 1 +int 1 +* +getbyte +store 16 +frame_dig -1 +int 1 +int 2 +* +getbyte +store 17 +frame_dig -1 +int 1 +int 3 +* +getbyte +store 18 +frame_dig -1 +int 1 +int 4 +* +getbyte +store 19 +frame_dig -1 +int 1 +int 5 +* +getbyte +store 20 +frame_dig -1 +int 1 +int 6 +* +getbyte +store 21 +frame_dig -1 +int 1 +int 7 +* +getbyte +store 22 +frame_dig -1 +int 1 +int 8 +* +getbyte +store 23 +frame_dig -1 +int 1 +int 9 +* +getbyte +store 24 +frame_dig -1 +int 1 +int 10 +* +getbyte +store 25 +frame_dig -1 +int 1 +int 11 +* +getbyte +store 26 +frame_dig -1 +int 1 +int 12 +* +getbyte +store 27 +frame_dig -1 +int 1 +int 13 +* +getbyte +store 28 +frame_dig -1 +int 1 +int 14 +* +getbyte +store 29 +frame_dig -1 +int 1 +int 15 +* +getbyte +store 30 +frame_dig -1 +int 1 +int 16 +* +getbyte +store 31 +frame_dig -1 +int 1 +int 17 +* +getbyte +store 32 +frame_dig -1 +int 1 +int 18 +* +getbyte +store 33 +frame_dig -1 +int 1 +int 19 +* +getbyte +store 34 +frame_dig -1 +int 1 +int 20 +* +getbyte +store 35 +frame_dig -1 +int 1 +int 21 +* +getbyte +store 36 +frame_dig -1 +int 1 +int 22 +* +getbyte +store 37 +frame_dig -1 +int 1 +int 23 +* +getbyte +store 38 +frame_dig -1 +int 1 +int 24 +* +getbyte +store 39 +frame_dig -1 +int 1 +int 25 +* +getbyte +store 40 +frame_dig -1 +int 1 +int 26 +* +getbyte +store 41 +frame_dig -1 +int 1 +int 27 +* +getbyte +store 42 +frame_dig -1 +int 1 +int 28 +* +getbyte +store 43 +frame_dig -1 +int 1 +int 29 +* +getbyte +store 44 +frame_dig -1 +int 1 +int 30 +* +getbyte +store 45 +frame_dig -1 +int 1 +int 31 +* +getbyte +store 46 +load 15 +callsub numericalcomp_4 +store 15 +load 16 +callsub numericalcomp_4 +store 16 +load 17 +callsub numericalcomp_4 +store 17 +load 18 +callsub numericalcomp_4 +store 18 +load 19 +callsub numericalcomp_4 +store 19 +load 20 +callsub numericalcomp_4 +store 20 +load 21 +callsub numericalcomp_4 +store 21 +load 22 +callsub numericalcomp_4 +store 22 +load 23 +callsub numericalcomp_4 +store 23 +load 24 +callsub numericalcomp_4 +store 24 +load 25 +callsub numericalcomp_4 +store 25 +load 26 +callsub numericalcomp_4 +store 26 +load 27 +callsub numericalcomp_4 +store 27 +load 28 +callsub numericalcomp_4 +store 28 +load 29 +callsub numericalcomp_4 +store 29 +load 30 +callsub numericalcomp_4 +store 30 +load 31 +callsub numericalcomp_4 +store 31 +load 32 +callsub numericalcomp_4 +store 32 +load 33 +callsub numericalcomp_4 +store 33 +load 34 +callsub numericalcomp_4 +store 34 +load 35 +callsub numericalcomp_4 +store 35 +load 36 +callsub numericalcomp_4 +store 36 +load 37 +callsub numericalcomp_4 +store 37 +load 38 +callsub numericalcomp_4 +store 38 +load 39 +callsub numericalcomp_4 +store 39 +load 40 +callsub numericalcomp_4 +store 40 +load 41 +callsub numericalcomp_4 +store 41 +load 42 +callsub numericalcomp_4 +store 42 +load 43 +callsub numericalcomp_4 +store 43 +load 44 +callsub numericalcomp_4 +store 44 +load 45 +callsub numericalcomp_4 +store 45 +load 46 +callsub numericalcomp_4 +store 46 +byte 0x00 +int 0 +load 15 +setbyte +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 +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 +frame_bury 0 +frame_dig 0 +retsub + +// string_reverse +stringreverse_6: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +int 2 ++ +getbyte +store 49 +frame_dig -1 +int 1 +int 1 +* +int 2 ++ +getbyte +store 48 +frame_dig -1 +int 1 +int 2 +* +int 2 ++ +getbyte +store 47 +int 3 +store 50 +load 50 +itob +extract 6 0 +byte 0x00 +int 0 +load 47 +setbyte +byte 0x00 +int 0 +load 48 +setbyte +concat +byte 0x00 +int 0 +load 49 +setbyte +concat +concat +frame_bury 0 +frame_dig 0 +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_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_2_v8.teal new file mode 100644 index 000000000..b2fae5c07 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_2_v8.teal @@ -0,0 +1,2057 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +getbit +store 0 +frame_dig -1 +int 1 +getbyte +store 1 +frame_dig -1 +extract 2 32 +store 2 +frame_dig -1 +frame_dig -1 +int 34 +extract_uint16 +frame_dig -1 +int 36 +extract_uint16 +substring3 +store 3 +frame_dig -1 +frame_dig -1 +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 29 +load 29 +store 28 +int 38 +store 26 +load 26 +load 29 +len ++ +store 27 +load 27 +int 65536 +< +assert +load 26 +itob +extract 6 0 +concat +load 4 +store 29 +load 28 +load 29 +concat +store 28 +load 27 +store 26 +load 26 +itob +extract 6 0 +concat +load 28 +concat +frame_bury 0 +frame_dig 0 +retsub + +// array_complement +arraycomplement_1: +proto 1 1 +int 13634846 +frame_dig -1 +frame_dig -1 +int 2 +int 0 +* +int 2 ++ +extract_uint16 +int 2 ++ +int 0 +int 1 ++ +frame_dig -1 +int 0 +extract_uint16 +store 15 +load 15 +== +bnz arraycomplement_1_l5 +frame_dig -1 +int 2 +int 0 +* +int 2 ++ +int 2 ++ +extract_uint16 +int 2 ++ +arraycomplement_1_l2: +substring3 +store 13 +frame_dig -1 +frame_dig -1 +int 2 +int 1 +* +int 2 ++ +extract_uint16 +int 2 ++ +int 1 +int 1 ++ +frame_dig -1 +int 0 +extract_uint16 +store 16 +load 16 +== +bnz arraycomplement_1_l4 +frame_dig -1 +int 2 +int 1 +* +int 2 ++ +int 2 ++ +extract_uint16 +int 2 ++ +b arraycomplement_1_l6 +arraycomplement_1_l4: +frame_dig -1 +len +b arraycomplement_1_l6 +arraycomplement_1_l5: +frame_dig -1 +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 21 +load 21 +itob +extract 6 0 +load 13 +store 20 +load 20 +store 19 +int 4 +store 17 +load 17 +load 20 +len ++ +store 18 +load 18 +int 65536 +< +assert +load 17 +itob +extract 6 0 +load 14 +store 20 +load 19 +load 20 +concat +store 19 +load 18 +store 17 +load 17 +itob +extract 6 0 +concat +load 19 +concat +concat +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_2: +proto 1 1 +int 13634846 +frame_dig -1 +callsub arraycomplement_1 +store 7 +load 7 +callsub arraycomplement_1 +store 8 +frame_dig -1 +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 7 +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 8 +store 12 +load 11 +load 12 +concat +store 11 +load 10 +store 9 +load 9 +itob +extract 6 0 +concat +load 11 +concat +frame_bury 0 +frame_dig 0 +retsub + +// bool_comp +boolcomp_3: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_4: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_5: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// array_complement +arraycomplement_6: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +getbyte +store 30 +frame_dig -1 +int 1 +int 1 +* +getbyte +store 31 +frame_dig -1 +int 1 +int 2 +* +getbyte +store 32 +frame_dig -1 +int 1 +int 3 +* +getbyte +store 33 +frame_dig -1 +int 1 +int 4 +* +getbyte +store 34 +frame_dig -1 +int 1 +int 5 +* +getbyte +store 35 +frame_dig -1 +int 1 +int 6 +* +getbyte +store 36 +frame_dig -1 +int 1 +int 7 +* +getbyte +store 37 +frame_dig -1 +int 1 +int 8 +* +getbyte +store 38 +frame_dig -1 +int 1 +int 9 +* +getbyte +store 39 +frame_dig -1 +int 1 +int 10 +* +getbyte +store 40 +frame_dig -1 +int 1 +int 11 +* +getbyte +store 41 +frame_dig -1 +int 1 +int 12 +* +getbyte +store 42 +frame_dig -1 +int 1 +int 13 +* +getbyte +store 43 +frame_dig -1 +int 1 +int 14 +* +getbyte +store 44 +frame_dig -1 +int 1 +int 15 +* +getbyte +store 45 +frame_dig -1 +int 1 +int 16 +* +getbyte +store 46 +frame_dig -1 +int 1 +int 17 +* +getbyte +store 47 +frame_dig -1 +int 1 +int 18 +* +getbyte +store 48 +frame_dig -1 +int 1 +int 19 +* +getbyte +store 49 +frame_dig -1 +int 1 +int 20 +* +getbyte +store 50 +frame_dig -1 +int 1 +int 21 +* +getbyte +store 51 +frame_dig -1 +int 1 +int 22 +* +getbyte +store 52 +frame_dig -1 +int 1 +int 23 +* +getbyte +store 53 +frame_dig -1 +int 1 +int 24 +* +getbyte +store 54 +frame_dig -1 +int 1 +int 25 +* +getbyte +store 55 +frame_dig -1 +int 1 +int 26 +* +getbyte +store 56 +frame_dig -1 +int 1 +int 27 +* +getbyte +store 57 +frame_dig -1 +int 1 +int 28 +* +getbyte +store 58 +frame_dig -1 +int 1 +int 29 +* +getbyte +store 59 +frame_dig -1 +int 1 +int 30 +* +getbyte +store 60 +frame_dig -1 +int 1 +int 31 +* +getbyte +store 61 +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 +load 61 +callsub numericalcomp_5 +store 61 +byte 0x00 +int 0 +load 30 +setbyte +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 +byte 0x00 +int 0 +load 61 +setbyte +concat +frame_bury 0 +frame_dig 0 +retsub + +// string_reverse +stringreverse_7: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +int 2 ++ +getbyte +store 64 +frame_dig -1 +int 1 +int 1 +* +int 2 ++ +getbyte +store 63 +frame_dig -1 +int 1 +int 2 +* +int 2 ++ +getbyte +store 62 +int 3 +store 65 +load 65 +itob +extract 6 0 +byte 0x00 +int 0 +load 62 +setbyte +byte 0x00 +int 0 +load 63 +setbyte +concat +byte 0x00 +int 0 +load 64 +setbyte +concat +concat +frame_bury 0 +frame_dig 0 +retsub + +// tuple_complement +tuplecomplement_8: +proto 1 1 +int 13634846 +frame_dig -1 +extract 0 32 +store 22 +frame_dig -1 +frame_dig -1 +int 32 +extract_uint16 +frame_dig -1 +int 34 +extract_uint16 +substring3 +store 23 +frame_dig -1 +frame_dig -1 +int 34 +extract_uint16 +frame_dig -1 +int 36 +extract_uint16 +substring3 +store 24 +frame_dig -1 +frame_dig -1 +int 36 +extract_uint16 +dig 1 +len +substring3 +store 25 +load 22 +callsub arraycomplement_10 +store 22 +load 23 +callsub arraycomplement_12 +store 23 +load 24 +callsub stringreverse_13 +store 24 +load 25 +callsub arraycomplement_15 +store 25 +load 22 +load 23 +store 74 +load 74 +store 73 +int 38 +store 71 +load 71 +load 74 +len ++ +store 72 +load 72 +int 65536 +< +assert +load 71 +itob +extract 6 0 +concat +load 24 +store 74 +load 73 +load 74 +concat +store 73 +load 72 +store 71 +load 71 +load 74 +len ++ +store 72 +load 72 +int 65536 +< +assert +load 71 +itob +extract 6 0 +concat +load 25 +store 74 +load 73 +load 74 +concat +store 73 +load 72 +store 71 +load 71 +itob +extract 6 0 +concat +load 73 +concat +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_9: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// array_complement +arraycomplement_10: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +getbyte +store 75 +frame_dig -1 +int 1 +int 1 +* +getbyte +store 76 +frame_dig -1 +int 1 +int 2 +* +getbyte +store 77 +frame_dig -1 +int 1 +int 3 +* +getbyte +store 78 +frame_dig -1 +int 1 +int 4 +* +getbyte +store 79 +frame_dig -1 +int 1 +int 5 +* +getbyte +store 80 +frame_dig -1 +int 1 +int 6 +* +getbyte +store 81 +frame_dig -1 +int 1 +int 7 +* +getbyte +store 82 +frame_dig -1 +int 1 +int 8 +* +getbyte +store 83 +frame_dig -1 +int 1 +int 9 +* +getbyte +store 84 +frame_dig -1 +int 1 +int 10 +* +getbyte +store 85 +frame_dig -1 +int 1 +int 11 +* +getbyte +store 86 +frame_dig -1 +int 1 +int 12 +* +getbyte +store 87 +frame_dig -1 +int 1 +int 13 +* +getbyte +store 88 +frame_dig -1 +int 1 +int 14 +* +getbyte +store 89 +frame_dig -1 +int 1 +int 15 +* +getbyte +store 90 +frame_dig -1 +int 1 +int 16 +* +getbyte +store 91 +frame_dig -1 +int 1 +int 17 +* +getbyte +store 92 +frame_dig -1 +int 1 +int 18 +* +getbyte +store 93 +frame_dig -1 +int 1 +int 19 +* +getbyte +store 94 +frame_dig -1 +int 1 +int 20 +* +getbyte +store 95 +frame_dig -1 +int 1 +int 21 +* +getbyte +store 96 +frame_dig -1 +int 1 +int 22 +* +getbyte +store 97 +frame_dig -1 +int 1 +int 23 +* +getbyte +store 98 +frame_dig -1 +int 1 +int 24 +* +getbyte +store 99 +frame_dig -1 +int 1 +int 25 +* +getbyte +store 100 +frame_dig -1 +int 1 +int 26 +* +getbyte +store 101 +frame_dig -1 +int 1 +int 27 +* +getbyte +store 102 +frame_dig -1 +int 1 +int 28 +* +getbyte +store 103 +frame_dig -1 +int 1 +int 29 +* +getbyte +store 104 +frame_dig -1 +int 1 +int 30 +* +getbyte +store 105 +frame_dig -1 +int 1 +int 31 +* +getbyte +store 106 +load 75 +callsub numericalcomp_9 +store 75 +load 76 +callsub numericalcomp_9 +store 76 +load 77 +callsub numericalcomp_9 +store 77 +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 +byte 0x00 +int 0 +load 75 +setbyte +byte 0x00 +int 0 +load 76 +setbyte +concat +byte 0x00 +int 0 +load 77 +setbyte +concat +byte 0x00 +int 0 +load 78 +setbyte +concat +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 +frame_bury 0 +frame_dig 0 +retsub + +// tuple_complement +tuplecomplement_11: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +extract_uint32 +store 66 +frame_dig -1 +frame_dig -1 +int 4 +extract_uint16 +dig 1 +len +substring3 +store 67 +frame_dig -1 +extract 6 1 +store 68 +frame_dig -1 +extract 7 1 +store 69 +frame_dig -1 +int 8 +getbyte +store 70 +load 66 +callsub numericalcomp_16 +store 66 +load 67 +callsub arraycomplement_18 +store 67 +load 68 +callsub arraycomplement_20 +store 68 +load 69 +callsub tuplecomplement_21 +store 69 +load 70 +callsub numericalcomp_22 +store 70 +load 66 +itob +extract 4 0 +load 67 +store 116 +load 116 +store 115 +int 9 +store 114 +load 114 +itob +extract 6 0 +concat +load 68 +concat +load 69 +concat +byte 0x00 +int 0 +load 70 +setbyte +concat +load 115 +concat +frame_bury 0 +frame_dig 0 +retsub + +// array_complement +arraycomplement_12: +proto 1 1 +int 13634846 +frame_dig -1 +frame_dig -1 +int 2 +int 0 +* +extract_uint16 +int 0 +int 1 ++ +int 2 +== +bnz arraycomplement_12_l5 +frame_dig -1 +int 2 +int 0 +* +int 2 ++ +extract_uint16 +arraycomplement_12_l2: +substring3 +store 107 +frame_dig -1 +frame_dig -1 +int 2 +int 1 +* +extract_uint16 +int 1 +int 1 ++ +int 2 +== +bnz arraycomplement_12_l4 +frame_dig -1 +int 2 +int 1 +* +int 2 ++ +extract_uint16 +b arraycomplement_12_l6 +arraycomplement_12_l4: +frame_dig -1 +len +b arraycomplement_12_l6 +arraycomplement_12_l5: +frame_dig -1 +len +b arraycomplement_12_l2 +arraycomplement_12_l6: +substring3 +store 108 +load 107 +callsub tuplecomplement_11 +store 107 +load 108 +callsub tuplecomplement_11 +store 108 +load 107 +store 112 +load 112 +store 111 +int 4 +store 109 +load 109 +load 112 +len ++ +store 110 +load 110 +int 65536 +< +assert +load 109 +itob +extract 6 0 +load 108 +store 112 +load 111 +load 112 +concat +store 111 +load 110 +store 109 +load 109 +itob +extract 6 0 +concat +load 111 +concat +frame_bury 0 +frame_dig 0 +retsub + +// string_reverse +stringreverse_13: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +int 2 ++ +getbyte +store 136 +frame_dig -1 +int 1 +int 1 +* +int 2 ++ +getbyte +store 135 +frame_dig -1 +int 1 +int 2 +* +int 2 ++ +getbyte +store 134 +int 3 +store 137 +load 137 +itob +extract 6 0 +byte 0x00 +int 0 +load 134 +setbyte +byte 0x00 +int 0 +load 135 +setbyte +concat +byte 0x00 +int 0 +load 136 +setbyte +concat +concat +frame_bury 0 +frame_dig 0 +retsub + +// bool_comp +boolcomp_14: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub + +// array_complement +arraycomplement_15: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +int 16 ++ +getbit +store 138 +frame_dig -1 +int 1 +int 16 ++ +getbit +store 139 +frame_dig -1 +int 2 +int 16 ++ +getbit +store 140 +load 138 +callsub boolcomp_14 +store 138 +load 139 +callsub boolcomp_14 +store 139 +load 140 +callsub boolcomp_14 +store 140 +int 3 +store 141 +load 141 +itob +extract 6 0 +byte 0x00 +int 0 +load 138 +setbit +int 1 +load 139 +setbit +int 2 +load 140 +setbit +concat +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_16: +proto 1 1 +int 13634846 +int 4294967295 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 4294967296 +< +assert +frame_dig 0 +retsub + +// string_reverse +stringreverse_17: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +int 2 ++ +getbyte +store 130 +frame_dig -1 +int 1 +int 1 +* +int 2 ++ +getbyte +store 129 +frame_dig -1 +int 1 +int 2 +* +int 2 ++ +getbyte +store 128 +int 3 +store 131 +load 131 +itob +extract 6 0 +byte 0x00 +int 0 +load 128 +setbyte +byte 0x00 +int 0 +load 129 +setbyte +concat +byte 0x00 +int 0 +load 130 +setbyte +concat +concat +frame_bury 0 +frame_dig 0 +retsub + +// array_complement +arraycomplement_18: +proto 1 1 +int 13634846 +frame_dig -1 +frame_dig -1 +int 2 +int 0 +* +int 2 ++ +extract_uint16 +int 2 ++ +int 0 +int 1 ++ +frame_dig -1 +int 0 +extract_uint16 +store 120 +load 120 +== +bnz arraycomplement_18_l8 +frame_dig -1 +int 2 +int 0 +* +int 2 ++ +int 2 ++ +extract_uint16 +int 2 ++ +arraycomplement_18_l2: +substring3 +store 117 +frame_dig -1 +frame_dig -1 +int 2 +int 1 +* +int 2 ++ +extract_uint16 +int 2 ++ +int 1 +int 1 ++ +frame_dig -1 +int 0 +extract_uint16 +store 121 +load 121 +== +bnz arraycomplement_18_l7 +frame_dig -1 +int 2 +int 1 +* +int 2 ++ +int 2 ++ +extract_uint16 +int 2 ++ +arraycomplement_18_l4: +substring3 +store 118 +frame_dig -1 +frame_dig -1 +int 2 +int 2 +* +int 2 ++ +extract_uint16 +int 2 ++ +int 2 +int 1 ++ +frame_dig -1 +int 0 +extract_uint16 +store 122 +load 122 +== +bnz arraycomplement_18_l6 +frame_dig -1 +int 2 +int 2 +* +int 2 ++ +int 2 ++ +extract_uint16 +int 2 ++ +b arraycomplement_18_l9 +arraycomplement_18_l6: +frame_dig -1 +len +b arraycomplement_18_l9 +arraycomplement_18_l7: +frame_dig -1 +len +b arraycomplement_18_l4 +arraycomplement_18_l8: +frame_dig -1 +len +b arraycomplement_18_l2 +arraycomplement_18_l9: +substring3 +store 119 +load 117 +callsub stringreverse_17 +store 117 +load 118 +callsub stringreverse_17 +store 118 +load 119 +callsub stringreverse_17 +store 119 +int 3 +store 127 +load 127 +itob +extract 6 0 +load 117 +store 126 +load 126 +store 125 +int 6 +store 123 +load 123 +load 126 +len ++ +store 124 +load 124 +int 65536 +< +assert +load 123 +itob +extract 6 0 +load 118 +store 126 +load 125 +load 126 +concat +store 125 +load 124 +store 123 +load 123 +load 126 +len ++ +store 124 +load 124 +int 65536 +< +assert +load 123 +itob +extract 6 0 +concat +load 119 +store 126 +load 125 +load 126 +concat +store 125 +load 124 +store 123 +load 123 +itob +extract 6 0 +concat +load 125 +concat +concat +frame_bury 0 +frame_dig 0 +retsub + +// bool_comp +boolcomp_19: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub + +// array_complement +arraycomplement_20: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +getbit +store 132 +frame_dig -1 +int 1 +getbit +store 133 +load 132 +callsub boolcomp_19 +store 132 +load 133 +callsub boolcomp_19 +store 133 +byte 0x00 +int 0 +load 132 +setbit +int 1 +load 133 +setbit +frame_bury 0 +frame_dig 0 +retsub + +// tuple_complement +tuplecomplement_21: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +getbyte +store 113 +load 113 +callsub numericalcomp_23 +store 113 +byte 0x00 +int 0 +load 113 +setbyte +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_22: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_23: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64)_v8.teal new file mode 100644 index 000000000..0d22f98ea --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64)_v8.teal @@ -0,0 +1,711 @@ +#pragma version 8 +txna ApplicationArgs 0 +store 6 +load 6 +callsub roundtripper_1 +store 5 +byte 0x151f7c75 +load 5 +concat +log +int 1 +return + +// tuple_complement +tuplecomplement_0: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +getbit +store 0 +frame_dig -1 +int 1 +getbyte +store 1 +frame_dig -1 +extract 2 32 +store 2 +frame_dig -1 +frame_dig -1 +int 34 +extract_uint16 +dig 1 +len +substring3 +store 3 +frame_dig -1 +int 36 +extract_uint64 +store 4 +load 0 +callsub boolcomp_2 +store 0 +load 1 +callsub numericalcomp_3 +store 1 +load 2 +callsub arraycomplement_5 +store 2 +load 3 +callsub stringreverse_6 +store 3 +load 4 +callsub numericalcomp_7 +store 4 +byte 0x00 +int 0 +load 0 +setbit +byte 0x00 +int 0 +load 1 +setbyte +concat +load 2 +concat +load 3 +store 15 +load 15 +store 14 +int 44 +store 13 +load 13 +itob +extract 6 0 +concat +load 4 +itob +concat +load 14 +concat +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub tuplecomplement_0 +store 7 +load 7 +callsub tuplecomplement_0 +store 8 +frame_dig -1 +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 7 +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 8 +store 12 +load 11 +load 12 +concat +store 11 +load 10 +store 9 +load 9 +itob +extract 6 0 +concat +load 11 +concat +frame_bury 0 +frame_dig 0 +retsub + +// bool_comp +boolcomp_2: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_3: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_4: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// array_complement +arraycomplement_5: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +getbyte +store 16 +frame_dig -1 +int 1 +int 1 +* +getbyte +store 17 +frame_dig -1 +int 1 +int 2 +* +getbyte +store 18 +frame_dig -1 +int 1 +int 3 +* +getbyte +store 19 +frame_dig -1 +int 1 +int 4 +* +getbyte +store 20 +frame_dig -1 +int 1 +int 5 +* +getbyte +store 21 +frame_dig -1 +int 1 +int 6 +* +getbyte +store 22 +frame_dig -1 +int 1 +int 7 +* +getbyte +store 23 +frame_dig -1 +int 1 +int 8 +* +getbyte +store 24 +frame_dig -1 +int 1 +int 9 +* +getbyte +store 25 +frame_dig -1 +int 1 +int 10 +* +getbyte +store 26 +frame_dig -1 +int 1 +int 11 +* +getbyte +store 27 +frame_dig -1 +int 1 +int 12 +* +getbyte +store 28 +frame_dig -1 +int 1 +int 13 +* +getbyte +store 29 +frame_dig -1 +int 1 +int 14 +* +getbyte +store 30 +frame_dig -1 +int 1 +int 15 +* +getbyte +store 31 +frame_dig -1 +int 1 +int 16 +* +getbyte +store 32 +frame_dig -1 +int 1 +int 17 +* +getbyte +store 33 +frame_dig -1 +int 1 +int 18 +* +getbyte +store 34 +frame_dig -1 +int 1 +int 19 +* +getbyte +store 35 +frame_dig -1 +int 1 +int 20 +* +getbyte +store 36 +frame_dig -1 +int 1 +int 21 +* +getbyte +store 37 +frame_dig -1 +int 1 +int 22 +* +getbyte +store 38 +frame_dig -1 +int 1 +int 23 +* +getbyte +store 39 +frame_dig -1 +int 1 +int 24 +* +getbyte +store 40 +frame_dig -1 +int 1 +int 25 +* +getbyte +store 41 +frame_dig -1 +int 1 +int 26 +* +getbyte +store 42 +frame_dig -1 +int 1 +int 27 +* +getbyte +store 43 +frame_dig -1 +int 1 +int 28 +* +getbyte +store 44 +frame_dig -1 +int 1 +int 29 +* +getbyte +store 45 +frame_dig -1 +int 1 +int 30 +* +getbyte +store 46 +frame_dig -1 +int 1 +int 31 +* +getbyte +store 47 +load 16 +callsub numericalcomp_4 +store 16 +load 17 +callsub numericalcomp_4 +store 17 +load 18 +callsub numericalcomp_4 +store 18 +load 19 +callsub numericalcomp_4 +store 19 +load 20 +callsub numericalcomp_4 +store 20 +load 21 +callsub numericalcomp_4 +store 21 +load 22 +callsub numericalcomp_4 +store 22 +load 23 +callsub numericalcomp_4 +store 23 +load 24 +callsub numericalcomp_4 +store 24 +load 25 +callsub numericalcomp_4 +store 25 +load 26 +callsub numericalcomp_4 +store 26 +load 27 +callsub numericalcomp_4 +store 27 +load 28 +callsub numericalcomp_4 +store 28 +load 29 +callsub numericalcomp_4 +store 29 +load 30 +callsub numericalcomp_4 +store 30 +load 31 +callsub numericalcomp_4 +store 31 +load 32 +callsub numericalcomp_4 +store 32 +load 33 +callsub numericalcomp_4 +store 33 +load 34 +callsub numericalcomp_4 +store 34 +load 35 +callsub numericalcomp_4 +store 35 +load 36 +callsub numericalcomp_4 +store 36 +load 37 +callsub numericalcomp_4 +store 37 +load 38 +callsub numericalcomp_4 +store 38 +load 39 +callsub numericalcomp_4 +store 39 +load 40 +callsub numericalcomp_4 +store 40 +load 41 +callsub numericalcomp_4 +store 41 +load 42 +callsub numericalcomp_4 +store 42 +load 43 +callsub numericalcomp_4 +store 43 +load 44 +callsub numericalcomp_4 +store 44 +load 45 +callsub numericalcomp_4 +store 45 +load 46 +callsub numericalcomp_4 +store 46 +load 47 +callsub numericalcomp_4 +store 47 +byte 0x00 +int 0 +load 16 +setbyte +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 +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 +frame_bury 0 +frame_dig 0 +retsub + +// string_reverse +stringreverse_6: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +int 2 ++ +getbyte +store 50 +frame_dig -1 +int 1 +int 1 +* +int 2 ++ +getbyte +store 49 +frame_dig -1 +int 1 +int 2 +* +int 2 ++ +getbyte +store 48 +int 3 +store 51 +load 51 +itob +extract 6 0 +byte 0x00 +int 0 +load 48 +setbyte +byte 0x00 +int 0 +load 49 +setbyte +concat +byte 0x00 +int 0 +load 50 +setbyte +concat +concat +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_7: +proto 1 1 +int 13634846 +int 18446744073709551615 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32)_v8.teal new file mode 100644 index 000000000..a1ba69bfb --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32)_v8.teal @@ -0,0 +1,109 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +getbit +store 0 +frame_dig -1 +int 1 +extract_uint64 +store 1 +frame_dig -1 +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 +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub tuplecomplement_0 +store 5 +load 5 +callsub tuplecomplement_0 +store 6 +frame_dig -1 +load 5 +concat +load 6 +concat +frame_bury 0 +frame_dig 0 +retsub + +// bool_comp +boolcomp_2: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_3: +proto 1 1 +int 13634846 +int 18446744073709551615 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_4: +proto 1 1 +int 13634846 +int 4294967295 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 4294967296 +< +assert +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(byte)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(byte)_v8.teal new file mode 100644 index 000000000..ea0e98fc2 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(byte)_v8.teal @@ -0,0 +1,65 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +getbyte +store 0 +load 0 +callsub numericalcomp_2 +store 0 +byte 0x00 +int 0 +load 0 +setbyte +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub tuplecomplement_0 +store 3 +load 3 +callsub tuplecomplement_0 +store 4 +frame_dig -1 +load 3 +concat +load 4 +concat +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_2: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64)_v8.teal new file mode 100644 index 000000000..d0db45543 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64)_v8.teal @@ -0,0 +1,110 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +getbyte +store 0 +frame_dig -1 +int 8 +getbit +store 1 +frame_dig -1 +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 +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub tuplecomplement_0 +store 5 +load 5 +callsub tuplecomplement_0 +store 6 +frame_dig -1 +load 5 +concat +load 6 +concat +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_2: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// bool_comp +boolcomp_3: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_4: +proto 1 1 +int 13634846 +int 18446744073709551615 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7_v8.teal new file mode 100644 index 000000000..915b57058 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7_v8.teal @@ -0,0 +1,843 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +extract 0 4 +store 0 +frame_dig -1 +extract 4 1 +store 1 +frame_dig -1 +int 5 +extract_uint64 +store 2 +frame_dig -1 +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 +frame_bury 0 +frame_dig 0 +retsub + +// array_complement +arraycomplement_1: +proto 1 1 +int 13634846 +frame_dig -1 +int 45 +int 0 +* +int 2 ++ +int 45 +extract3 +store 12 +frame_dig -1 +int 45 +int 1 +* +int 2 ++ +int 45 +extract3 +store 13 +frame_dig -1 +int 45 +int 2 +* +int 2 ++ +int 45 +extract3 +store 14 +frame_dig -1 +int 45 +int 3 +* +int 2 ++ +int 45 +extract3 +store 15 +frame_dig -1 +int 45 +int 4 +* +int 2 ++ +int 45 +extract3 +store 16 +frame_dig -1 +int 45 +int 5 +* +int 2 ++ +int 45 +extract3 +store 17 +frame_dig -1 +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 19 +load 19 +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 +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_2: +proto 1 1 +int 13634846 +frame_dig -1 +callsub arraycomplement_1 +store 6 +load 6 +callsub arraycomplement_1 +store 7 +frame_dig -1 +store 11 +load 11 +store 10 +int 6 +store 8 +load 8 +load 11 +len ++ +store 9 +load 9 +int 65536 +< +assert +load 8 +itob +extract 6 0 +load 6 +store 11 +load 10 +load 11 +concat +store 10 +load 9 +store 8 +load 8 +load 11 +len ++ +store 9 +load 9 +int 65536 +< +assert +load 8 +itob +extract 6 0 +concat +load 7 +store 11 +load 10 +load 11 +concat +store 10 +load 9 +store 8 +load 8 +itob +extract 6 0 +concat +load 10 +concat +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_3: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// array_complement +arraycomplement_4: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +getbyte +store 22 +frame_dig -1 +int 1 +int 1 +* +getbyte +store 23 +frame_dig -1 +int 1 +int 2 +* +getbyte +store 24 +frame_dig -1 +int 1 +int 3 +* +getbyte +store 25 +load 22 +callsub numericalcomp_3 +store 22 +load 23 +callsub numericalcomp_3 +store 23 +load 24 +callsub numericalcomp_3 +store 24 +load 25 +callsub numericalcomp_3 +store 25 +byte 0x00 +int 0 +load 22 +setbyte +byte 0x00 +int 0 +load 23 +setbyte +concat +byte 0x00 +int 0 +load 24 +setbyte +concat +byte 0x00 +int 0 +load 25 +setbyte +concat +frame_bury 0 +frame_dig 0 +retsub + +// tuple_complement +tuplecomplement_5: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +getbit +store 20 +frame_dig -1 +int 1 +getbit +store 21 +load 20 +callsub boolcomp_9 +store 20 +load 21 +callsub boolcomp_10 +store 21 +byte 0x00 +int 0 +load 20 +setbit +int 1 +load 21 +setbit +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_6: +proto 1 1 +int 13634846 +int 18446744073709551615 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_7: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// array_complement +arraycomplement_8: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +getbyte +store 26 +frame_dig -1 +int 1 +int 1 +* +getbyte +store 27 +frame_dig -1 +int 1 +int 2 +* +getbyte +store 28 +frame_dig -1 +int 1 +int 3 +* +getbyte +store 29 +frame_dig -1 +int 1 +int 4 +* +getbyte +store 30 +frame_dig -1 +int 1 +int 5 +* +getbyte +store 31 +frame_dig -1 +int 1 +int 6 +* +getbyte +store 32 +frame_dig -1 +int 1 +int 7 +* +getbyte +store 33 +frame_dig -1 +int 1 +int 8 +* +getbyte +store 34 +frame_dig -1 +int 1 +int 9 +* +getbyte +store 35 +frame_dig -1 +int 1 +int 10 +* +getbyte +store 36 +frame_dig -1 +int 1 +int 11 +* +getbyte +store 37 +frame_dig -1 +int 1 +int 12 +* +getbyte +store 38 +frame_dig -1 +int 1 +int 13 +* +getbyte +store 39 +frame_dig -1 +int 1 +int 14 +* +getbyte +store 40 +frame_dig -1 +int 1 +int 15 +* +getbyte +store 41 +frame_dig -1 +int 1 +int 16 +* +getbyte +store 42 +frame_dig -1 +int 1 +int 17 +* +getbyte +store 43 +frame_dig -1 +int 1 +int 18 +* +getbyte +store 44 +frame_dig -1 +int 1 +int 19 +* +getbyte +store 45 +frame_dig -1 +int 1 +int 20 +* +getbyte +store 46 +frame_dig -1 +int 1 +int 21 +* +getbyte +store 47 +frame_dig -1 +int 1 +int 22 +* +getbyte +store 48 +frame_dig -1 +int 1 +int 23 +* +getbyte +store 49 +frame_dig -1 +int 1 +int 24 +* +getbyte +store 50 +frame_dig -1 +int 1 +int 25 +* +getbyte +store 51 +frame_dig -1 +int 1 +int 26 +* +getbyte +store 52 +frame_dig -1 +int 1 +int 27 +* +getbyte +store 53 +frame_dig -1 +int 1 +int 28 +* +getbyte +store 54 +frame_dig -1 +int 1 +int 29 +* +getbyte +store 55 +frame_dig -1 +int 1 +int 30 +* +getbyte +store 56 +frame_dig -1 +int 1 +int 31 +* +getbyte +store 57 +load 26 +callsub numericalcomp_7 +store 26 +load 27 +callsub numericalcomp_7 +store 27 +load 28 +callsub numericalcomp_7 +store 28 +load 29 +callsub numericalcomp_7 +store 29 +load 30 +callsub numericalcomp_7 +store 30 +load 31 +callsub numericalcomp_7 +store 31 +load 32 +callsub numericalcomp_7 +store 32 +load 33 +callsub numericalcomp_7 +store 33 +load 34 +callsub numericalcomp_7 +store 34 +load 35 +callsub numericalcomp_7 +store 35 +load 36 +callsub numericalcomp_7 +store 36 +load 37 +callsub numericalcomp_7 +store 37 +load 38 +callsub numericalcomp_7 +store 38 +load 39 +callsub numericalcomp_7 +store 39 +load 40 +callsub numericalcomp_7 +store 40 +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 +byte 0x00 +int 0 +load 26 +setbyte +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 +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 +frame_bury 0 +frame_dig 0 +retsub + +// bool_comp +boolcomp_9: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub + +// bool_comp +boolcomp_10: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint16)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint16)_v8.teal new file mode 100644 index 000000000..306ab7acb --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint16)_v8.teal @@ -0,0 +1,64 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +extract_uint16 +store 0 +load 0 +callsub numericalcomp_2 +store 0 +load 0 +itob +extract 6 0 +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub tuplecomplement_0 +store 3 +load 3 +callsub tuplecomplement_0 +store 4 +frame_dig -1 +load 3 +concat +load 4 +concat +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_2: +proto 1 1 +int 13634846 +int 65535 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 65536 +< +assert +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte)_v8.teal new file mode 100644 index 000000000..ef7c2428d --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte)_v8.teal @@ -0,0 +1,118 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +extract_uint16 +store 0 +frame_dig -1 +int 2 +getbyte +store 1 +frame_dig -1 +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 +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub tuplecomplement_0 +store 5 +load 5 +callsub tuplecomplement_0 +store 6 +frame_dig -1 +load 5 +concat +load 6 +concat +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_2: +proto 1 1 +int 13634846 +int 65535 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 65536 +< +assert +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_3: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_4: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint32)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint32)_v8.teal new file mode 100644 index 000000000..741db6e80 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint32)_v8.teal @@ -0,0 +1,64 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +extract_uint32 +store 0 +load 0 +callsub numericalcomp_2 +store 0 +load 0 +itob +extract 4 0 +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub tuplecomplement_0 +store 3 +load 3 +callsub tuplecomplement_0 +store 4 +frame_dig -1 +load 3 +concat +load 4 +concat +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_2: +proto 1 1 +int 13634846 +int 4294967295 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 4294967296 +< +assert +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8)_v8.teal new file mode 100644 index 000000000..03e6b2c06 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8)_v8.teal @@ -0,0 +1,117 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +extract_uint32 +store 0 +frame_dig -1 +int 4 +extract_uint16 +store 1 +frame_dig -1 +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 +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub tuplecomplement_0 +store 5 +load 5 +callsub tuplecomplement_0 +store 6 +frame_dig -1 +load 5 +concat +load 6 +concat +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_2: +proto 1 1 +int 13634846 +int 4294967295 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 4294967296 +< +assert +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_3: +proto 1 1 +int 13634846 +int 65535 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 65536 +< +assert +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_4: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint64)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint64)_v8.teal new file mode 100644 index 000000000..b88127140 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint64)_v8.teal @@ -0,0 +1,58 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +btoi +store 0 +load 0 +callsub numericalcomp_2 +store 0 +load 0 +itob +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub tuplecomplement_0 +store 3 +load 3 +callsub tuplecomplement_0 +store 4 +frame_dig -1 +load 3 +concat +load 4 +concat +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_2: +proto 1 1 +int 13634846 +int 18446744073709551615 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16)_v8.teal new file mode 100644 index 000000000..eacfb78f8 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16)_v8.teal @@ -0,0 +1,111 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +extract_uint64 +store 0 +frame_dig -1 +int 8 +extract_uint32 +store 1 +frame_dig -1 +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 +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub tuplecomplement_0 +store 5 +load 5 +callsub tuplecomplement_0 +store 6 +frame_dig -1 +load 5 +concat +load 6 +concat +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_2: +proto 1 1 +int 13634846 +int 18446744073709551615 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_3: +proto 1 1 +int 13634846 +int 4294967295 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 4294967296 +< +assert +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_4: +proto 1 1 +int 13634846 +int 65535 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 65536 +< +assert +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint8)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint8)_v8.teal new file mode 100644 index 000000000..ea0e98fc2 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint8)_v8.teal @@ -0,0 +1,65 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +getbyte +store 0 +load 0 +callsub numericalcomp_2 +store 0 +byte 0x00 +int 0 +load 0 +setbyte +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub tuplecomplement_0 +store 3 +load 3 +callsub tuplecomplement_0 +store 4 +frame_dig -1 +load 3 +concat +load 4 +concat +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_2: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v8.teal new file mode 100644 index 000000000..9addccd5d --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v8.teal @@ -0,0 +1,116 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +getbyte +store 0 +frame_dig -1 +int 1 +getbyte +store 1 +frame_dig -1 +int 16 +getbit +store 2 +load 0 +callsub numericalcomp_2 +store 0 +load 1 +callsub numericalcomp_3 +store 1 +load 2 +callsub boolcomp_4 +store 2 +byte 0x00 +int 0 +load 0 +setbyte +byte 0x00 +int 0 +load 1 +setbyte +concat +byte 0x00 +int 0 +load 2 +setbit +concat +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub tuplecomplement_0 +store 5 +load 5 +callsub tuplecomplement_0 +store 6 +frame_dig -1 +load 5 +concat +load 6 +concat +frame_bury 0 +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_2: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// numerical_comp +numericalcomp_3: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// bool_comp +boolcomp_4: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_address[]_10_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_address[]_10_v8.teal new file mode 100644 index 000000000..be15e1a34 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_address[]_10_v8.teal @@ -0,0 +1,702 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// array_complement +arraycomplement_1: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +getbyte +store 19 +frame_dig -1 +int 1 +int 1 +* +getbyte +store 20 +frame_dig -1 +int 1 +int 2 +* +getbyte +store 21 +frame_dig -1 +int 1 +int 3 +* +getbyte +store 22 +frame_dig -1 +int 1 +int 4 +* +getbyte +store 23 +frame_dig -1 +int 1 +int 5 +* +getbyte +store 24 +frame_dig -1 +int 1 +int 6 +* +getbyte +store 25 +frame_dig -1 +int 1 +int 7 +* +getbyte +store 26 +frame_dig -1 +int 1 +int 8 +* +getbyte +store 27 +frame_dig -1 +int 1 +int 9 +* +getbyte +store 28 +frame_dig -1 +int 1 +int 10 +* +getbyte +store 29 +frame_dig -1 +int 1 +int 11 +* +getbyte +store 30 +frame_dig -1 +int 1 +int 12 +* +getbyte +store 31 +frame_dig -1 +int 1 +int 13 +* +getbyte +store 32 +frame_dig -1 +int 1 +int 14 +* +getbyte +store 33 +frame_dig -1 +int 1 +int 15 +* +getbyte +store 34 +frame_dig -1 +int 1 +int 16 +* +getbyte +store 35 +frame_dig -1 +int 1 +int 17 +* +getbyte +store 36 +frame_dig -1 +int 1 +int 18 +* +getbyte +store 37 +frame_dig -1 +int 1 +int 19 +* +getbyte +store 38 +frame_dig -1 +int 1 +int 20 +* +getbyte +store 39 +frame_dig -1 +int 1 +int 21 +* +getbyte +store 40 +frame_dig -1 +int 1 +int 22 +* +getbyte +store 41 +frame_dig -1 +int 1 +int 23 +* +getbyte +store 42 +frame_dig -1 +int 1 +int 24 +* +getbyte +store 43 +frame_dig -1 +int 1 +int 25 +* +getbyte +store 44 +frame_dig -1 +int 1 +int 26 +* +getbyte +store 45 +frame_dig -1 +int 1 +int 27 +* +getbyte +store 46 +frame_dig -1 +int 1 +int 28 +* +getbyte +store 47 +frame_dig -1 +int 1 +int 29 +* +getbyte +store 48 +frame_dig -1 +int 1 +int 30 +* +getbyte +store 49 +frame_dig -1 +int 1 +int 31 +* +getbyte +store 50 +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 50 +callsub numericalcomp_0 +store 50 +byte 0x00 +int 0 +load 19 +setbyte +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 +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 +frame_bury 0 +frame_dig 0 +retsub + +// array_complement +arraycomplement_2: +proto 1 1 +int 13634846 +frame_dig -1 +int 32 +int 0 +* +int 2 ++ +int 32 +extract3 +store 8 +frame_dig -1 +int 32 +int 1 +* +int 2 ++ +int 32 +extract3 +store 9 +frame_dig -1 +int 32 +int 2 +* +int 2 ++ +int 32 +extract3 +store 10 +frame_dig -1 +int 32 +int 3 +* +int 2 ++ +int 32 +extract3 +store 11 +frame_dig -1 +int 32 +int 4 +* +int 2 ++ +int 32 +extract3 +store 12 +frame_dig -1 +int 32 +int 5 +* +int 2 ++ +int 32 +extract3 +store 13 +frame_dig -1 +int 32 +int 6 +* +int 2 ++ +int 32 +extract3 +store 14 +frame_dig -1 +int 32 +int 7 +* +int 2 ++ +int 32 +extract3 +store 15 +frame_dig -1 +int 32 +int 8 +* +int 2 ++ +int 32 +extract3 +store 16 +frame_dig -1 +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 18 +load 18 +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 +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_3: +proto 1 1 +int 13634846 +frame_dig -1 +callsub arraycomplement_2 +store 2 +load 2 +callsub arraycomplement_2 +store 3 +frame_dig -1 +store 7 +load 7 +store 6 +int 6 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +load 2 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +concat +load 3 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +itob +extract 6 0 +concat +load 6 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_address_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_address_v8.teal new file mode 100644 index 000000000..7444fb267 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_address_v8.teal @@ -0,0 +1,501 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// array_complement +arraycomplement_1: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +getbyte +store 4 +frame_dig -1 +int 1 +int 1 +* +getbyte +store 5 +frame_dig -1 +int 1 +int 2 +* +getbyte +store 6 +frame_dig -1 +int 1 +int 3 +* +getbyte +store 7 +frame_dig -1 +int 1 +int 4 +* +getbyte +store 8 +frame_dig -1 +int 1 +int 5 +* +getbyte +store 9 +frame_dig -1 +int 1 +int 6 +* +getbyte +store 10 +frame_dig -1 +int 1 +int 7 +* +getbyte +store 11 +frame_dig -1 +int 1 +int 8 +* +getbyte +store 12 +frame_dig -1 +int 1 +int 9 +* +getbyte +store 13 +frame_dig -1 +int 1 +int 10 +* +getbyte +store 14 +frame_dig -1 +int 1 +int 11 +* +getbyte +store 15 +frame_dig -1 +int 1 +int 12 +* +getbyte +store 16 +frame_dig -1 +int 1 +int 13 +* +getbyte +store 17 +frame_dig -1 +int 1 +int 14 +* +getbyte +store 18 +frame_dig -1 +int 1 +int 15 +* +getbyte +store 19 +frame_dig -1 +int 1 +int 16 +* +getbyte +store 20 +frame_dig -1 +int 1 +int 17 +* +getbyte +store 21 +frame_dig -1 +int 1 +int 18 +* +getbyte +store 22 +frame_dig -1 +int 1 +int 19 +* +getbyte +store 23 +frame_dig -1 +int 1 +int 20 +* +getbyte +store 24 +frame_dig -1 +int 1 +int 21 +* +getbyte +store 25 +frame_dig -1 +int 1 +int 22 +* +getbyte +store 26 +frame_dig -1 +int 1 +int 23 +* +getbyte +store 27 +frame_dig -1 +int 1 +int 24 +* +getbyte +store 28 +frame_dig -1 +int 1 +int 25 +* +getbyte +store 29 +frame_dig -1 +int 1 +int 26 +* +getbyte +store 30 +frame_dig -1 +int 1 +int 27 +* +getbyte +store 31 +frame_dig -1 +int 1 +int 28 +* +getbyte +store 32 +frame_dig -1 +int 1 +int 29 +* +getbyte +store 33 +frame_dig -1 +int 1 +int 30 +* +getbyte +store 34 +frame_dig -1 +int 1 +int 31 +* +getbyte +store 35 +load 4 +callsub numericalcomp_0 +store 4 +load 5 +callsub numericalcomp_0 +store 5 +load 6 +callsub numericalcomp_0 +store 6 +load 7 +callsub numericalcomp_0 +store 7 +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 +byte 0x00 +int 0 +load 4 +setbyte +byte 0x00 +int 0 +load 5 +setbyte +concat +byte 0x00 +int 0 +load 6 +setbyte +concat +byte 0x00 +int 0 +load 7 +setbyte +concat +byte 0x00 +int 0 +load 8 +setbyte +concat +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 +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_2: +proto 1 1 +int 13634846 +frame_dig -1 +callsub arraycomplement_1 +store 2 +load 2 +callsub arraycomplement_1 +store 3 +frame_dig -1 +load 2 +concat +load 3 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[1]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[1]_v8.teal new file mode 100644 index 000000000..065807402 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[1]_v8.teal @@ -0,0 +1,62 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub + +// array_complement +arraycomplement_1: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +getbit +store 4 +load 4 +callsub boolcomp_0 +store 4 +byte 0x00 +int 0 +load 4 +setbit +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_2: +proto 1 1 +int 13634846 +frame_dig -1 +callsub arraycomplement_1 +store 2 +load 2 +callsub arraycomplement_1 +store 3 +frame_dig -1 +load 2 +concat +load 3 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11_v8.teal new file mode 100644 index 000000000..3f5d168b2 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11_v8.teal @@ -0,0 +1,297 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub + +// array_complement +arraycomplement_1: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +getbit +store 20 +frame_dig -1 +int 1 +getbit +store 21 +frame_dig -1 +int 2 +getbit +store 22 +load 20 +callsub boolcomp_0 +store 20 +load 21 +callsub boolcomp_0 +store 21 +load 22 +callsub boolcomp_0 +store 22 +byte 0x00 +int 0 +load 20 +setbit +int 1 +load 21 +setbit +int 2 +load 22 +setbit +frame_bury 0 +frame_dig 0 +retsub + +// array_complement +arraycomplement_2: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +int 2 ++ +int 1 +extract3 +store 8 +frame_dig -1 +int 1 +int 1 +* +int 2 ++ +int 1 +extract3 +store 9 +frame_dig -1 +int 1 +int 2 +* +int 2 ++ +int 1 +extract3 +store 10 +frame_dig -1 +int 1 +int 3 +* +int 2 ++ +int 1 +extract3 +store 11 +frame_dig -1 +int 1 +int 4 +* +int 2 ++ +int 1 +extract3 +store 12 +frame_dig -1 +int 1 +int 5 +* +int 2 ++ +int 1 +extract3 +store 13 +frame_dig -1 +int 1 +int 6 +* +int 2 ++ +int 1 +extract3 +store 14 +frame_dig -1 +int 1 +int 7 +* +int 2 ++ +int 1 +extract3 +store 15 +frame_dig -1 +int 1 +int 8 +* +int 2 ++ +int 1 +extract3 +store 16 +frame_dig -1 +int 1 +int 9 +* +int 2 ++ +int 1 +extract3 +store 17 +frame_dig -1 +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 19 +load 19 +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 +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_3: +proto 1 1 +int 13634846 +frame_dig -1 +callsub arraycomplement_2 +store 2 +load 2 +callsub arraycomplement_2 +store 3 +frame_dig -1 +store 7 +load 7 +store 6 +int 6 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +load 2 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +concat +load 3 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +itob +extract 6 0 +concat +load 6 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[42]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[42]_v8.teal new file mode 100644 index 000000000..20e422692 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[42]_v8.teal @@ -0,0 +1,472 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub + +// array_complement +arraycomplement_1: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +getbit +store 4 +frame_dig -1 +int 1 +getbit +store 5 +frame_dig -1 +int 2 +getbit +store 6 +frame_dig -1 +int 3 +getbit +store 7 +frame_dig -1 +int 4 +getbit +store 8 +frame_dig -1 +int 5 +getbit +store 9 +frame_dig -1 +int 6 +getbit +store 10 +frame_dig -1 +int 7 +getbit +store 11 +frame_dig -1 +int 8 +getbit +store 12 +frame_dig -1 +int 9 +getbit +store 13 +frame_dig -1 +int 10 +getbit +store 14 +frame_dig -1 +int 11 +getbit +store 15 +frame_dig -1 +int 12 +getbit +store 16 +frame_dig -1 +int 13 +getbit +store 17 +frame_dig -1 +int 14 +getbit +store 18 +frame_dig -1 +int 15 +getbit +store 19 +frame_dig -1 +int 16 +getbit +store 20 +frame_dig -1 +int 17 +getbit +store 21 +frame_dig -1 +int 18 +getbit +store 22 +frame_dig -1 +int 19 +getbit +store 23 +frame_dig -1 +int 20 +getbit +store 24 +frame_dig -1 +int 21 +getbit +store 25 +frame_dig -1 +int 22 +getbit +store 26 +frame_dig -1 +int 23 +getbit +store 27 +frame_dig -1 +int 24 +getbit +store 28 +frame_dig -1 +int 25 +getbit +store 29 +frame_dig -1 +int 26 +getbit +store 30 +frame_dig -1 +int 27 +getbit +store 31 +frame_dig -1 +int 28 +getbit +store 32 +frame_dig -1 +int 29 +getbit +store 33 +frame_dig -1 +int 30 +getbit +store 34 +frame_dig -1 +int 31 +getbit +store 35 +frame_dig -1 +int 32 +getbit +store 36 +frame_dig -1 +int 33 +getbit +store 37 +frame_dig -1 +int 34 +getbit +store 38 +frame_dig -1 +int 35 +getbit +store 39 +frame_dig -1 +int 36 +getbit +store 40 +frame_dig -1 +int 37 +getbit +store 41 +frame_dig -1 +int 38 +getbit +store 42 +frame_dig -1 +int 39 +getbit +store 43 +frame_dig -1 +int 40 +getbit +store 44 +frame_dig -1 +int 41 +getbit +store 45 +load 4 +callsub boolcomp_0 +store 4 +load 5 +callsub boolcomp_0 +store 5 +load 6 +callsub boolcomp_0 +store 6 +load 7 +callsub boolcomp_0 +store 7 +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 +byte 0x000000000000 +int 0 +load 4 +setbit +int 1 +load 5 +setbit +int 2 +load 6 +setbit +int 3 +load 7 +setbit +int 4 +load 8 +setbit +int 5 +load 9 +setbit +int 6 +load 10 +setbit +int 7 +load 11 +setbit +int 8 +load 12 +setbit +int 9 +load 13 +setbit +int 10 +load 14 +setbit +int 11 +load 15 +setbit +int 12 +load 16 +setbit +int 13 +load 17 +setbit +int 14 +load 18 +setbit +int 15 +load 19 +setbit +int 16 +load 20 +setbit +int 17 +load 21 +setbit +int 18 +load 22 +setbit +int 19 +load 23 +setbit +int 20 +load 24 +setbit +int 21 +load 25 +setbit +int 22 +load 26 +setbit +int 23 +load 27 +setbit +int 24 +load 28 +setbit +int 25 +load 29 +setbit +int 26 +load 30 +setbit +int 27 +load 31 +setbit +int 28 +load 32 +setbit +int 29 +load 33 +setbit +int 30 +load 34 +setbit +int 31 +load 35 +setbit +int 32 +load 36 +setbit +int 33 +load 37 +setbit +int 34 +load 38 +setbit +int 35 +load 39 +setbit +int 36 +load 40 +setbit +int 37 +load 41 +setbit +int 38 +load 42 +setbit +int 39 +load 43 +setbit +int 40 +load 44 +setbit +int 41 +load 45 +setbit +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_2: +proto 1 1 +int 13634846 +frame_dig -1 +callsub arraycomplement_1 +store 2 +load 2 +callsub arraycomplement_1 +store 3 +frame_dig -1 +load 2 +concat +load 3 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_0_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_0_v8.teal new file mode 100644 index 000000000..542046cc4 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_0_v8.teal @@ -0,0 +1,94 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +int 0 +store 8 +load 8 +itob +extract 6 0 +byte "" +concat +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub arraycomplement_0 +store 2 +load 2 +callsub arraycomplement_0 +store 3 +frame_dig -1 +store 7 +load 7 +store 6 +int 6 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +load 2 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +concat +load 3 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +itob +extract 6 0 +concat +load 6 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_1_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_1_v8.teal new file mode 100644 index 000000000..879b7adb5 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_1_v8.teal @@ -0,0 +1,118 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub + +// array_complement +arraycomplement_1: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +int 16 ++ +getbit +store 8 +load 8 +callsub boolcomp_0 +store 8 +int 1 +store 9 +load 9 +itob +extract 6 0 +byte 0x00 +int 0 +load 8 +setbit +concat +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_2: +proto 1 1 +int 13634846 +frame_dig -1 +callsub arraycomplement_1 +store 2 +load 2 +callsub arraycomplement_1 +store 3 +frame_dig -1 +store 7 +load 7 +store 6 +int 6 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +load 2 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +concat +load 3 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +itob +extract 6 0 +concat +load 6 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_42_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_42_v8.teal new file mode 100644 index 000000000..34f1528fe --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_42_v8.teal @@ -0,0 +1,610 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub + +// array_complement +arraycomplement_1: +proto 1 1 +int 13634846 +frame_dig -1 +int 0 +int 16 ++ +getbit +store 8 +frame_dig -1 +int 1 +int 16 ++ +getbit +store 9 +frame_dig -1 +int 2 +int 16 ++ +getbit +store 10 +frame_dig -1 +int 3 +int 16 ++ +getbit +store 11 +frame_dig -1 +int 4 +int 16 ++ +getbit +store 12 +frame_dig -1 +int 5 +int 16 ++ +getbit +store 13 +frame_dig -1 +int 6 +int 16 ++ +getbit +store 14 +frame_dig -1 +int 7 +int 16 ++ +getbit +store 15 +frame_dig -1 +int 8 +int 16 ++ +getbit +store 16 +frame_dig -1 +int 9 +int 16 ++ +getbit +store 17 +frame_dig -1 +int 10 +int 16 ++ +getbit +store 18 +frame_dig -1 +int 11 +int 16 ++ +getbit +store 19 +frame_dig -1 +int 12 +int 16 ++ +getbit +store 20 +frame_dig -1 +int 13 +int 16 ++ +getbit +store 21 +frame_dig -1 +int 14 +int 16 ++ +getbit +store 22 +frame_dig -1 +int 15 +int 16 ++ +getbit +store 23 +frame_dig -1 +int 16 +int 16 ++ +getbit +store 24 +frame_dig -1 +int 17 +int 16 ++ +getbit +store 25 +frame_dig -1 +int 18 +int 16 ++ +getbit +store 26 +frame_dig -1 +int 19 +int 16 ++ +getbit +store 27 +frame_dig -1 +int 20 +int 16 ++ +getbit +store 28 +frame_dig -1 +int 21 +int 16 ++ +getbit +store 29 +frame_dig -1 +int 22 +int 16 ++ +getbit +store 30 +frame_dig -1 +int 23 +int 16 ++ +getbit +store 31 +frame_dig -1 +int 24 +int 16 ++ +getbit +store 32 +frame_dig -1 +int 25 +int 16 ++ +getbit +store 33 +frame_dig -1 +int 26 +int 16 ++ +getbit +store 34 +frame_dig -1 +int 27 +int 16 ++ +getbit +store 35 +frame_dig -1 +int 28 +int 16 ++ +getbit +store 36 +frame_dig -1 +int 29 +int 16 ++ +getbit +store 37 +frame_dig -1 +int 30 +int 16 ++ +getbit +store 38 +frame_dig -1 +int 31 +int 16 ++ +getbit +store 39 +frame_dig -1 +int 32 +int 16 ++ +getbit +store 40 +frame_dig -1 +int 33 +int 16 ++ +getbit +store 41 +frame_dig -1 +int 34 +int 16 ++ +getbit +store 42 +frame_dig -1 +int 35 +int 16 ++ +getbit +store 43 +frame_dig -1 +int 36 +int 16 ++ +getbit +store 44 +frame_dig -1 +int 37 +int 16 ++ +getbit +store 45 +frame_dig -1 +int 38 +int 16 ++ +getbit +store 46 +frame_dig -1 +int 39 +int 16 ++ +getbit +store 47 +frame_dig -1 +int 40 +int 16 ++ +getbit +store 48 +frame_dig -1 +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 50 +load 50 +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 +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_2: +proto 1 1 +int 13634846 +frame_dig -1 +callsub arraycomplement_1 +store 2 +load 2 +callsub arraycomplement_1 +store 3 +frame_dig -1 +store 7 +load 7 +store 6 +int 6 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +load 2 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +concat +load 3 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +itob +extract 6 0 +concat +load 6 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool_v8.teal new file mode 100644 index 000000000..1e8311ecf --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool_v8.teal @@ -0,0 +1,52 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +! +! +! +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub boolcomp_0 +store 2 +load 2 +callsub boolcomp_0 +store 3 +byte 0x00 +int 0 +frame_dig -1 +setbit +int 1 +load 2 +setbit +int 2 +load 3 +setbit +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_byte[16]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_byte[16]_v8.teal new file mode 100644 index 000000000..f96c0c3b4 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_byte[16]_v8.teal @@ -0,0 +1,277 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// array_complement +arraycomplement_1: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +getbyte +store 4 +frame_dig -1 +int 1 +int 1 +* +getbyte +store 5 +frame_dig -1 +int 1 +int 2 +* +getbyte +store 6 +frame_dig -1 +int 1 +int 3 +* +getbyte +store 7 +frame_dig -1 +int 1 +int 4 +* +getbyte +store 8 +frame_dig -1 +int 1 +int 5 +* +getbyte +store 9 +frame_dig -1 +int 1 +int 6 +* +getbyte +store 10 +frame_dig -1 +int 1 +int 7 +* +getbyte +store 11 +frame_dig -1 +int 1 +int 8 +* +getbyte +store 12 +frame_dig -1 +int 1 +int 9 +* +getbyte +store 13 +frame_dig -1 +int 1 +int 10 +* +getbyte +store 14 +frame_dig -1 +int 1 +int 11 +* +getbyte +store 15 +frame_dig -1 +int 1 +int 12 +* +getbyte +store 16 +frame_dig -1 +int 1 +int 13 +* +getbyte +store 17 +frame_dig -1 +int 1 +int 14 +* +getbyte +store 18 +frame_dig -1 +int 1 +int 15 +* +getbyte +store 19 +load 4 +callsub numericalcomp_0 +store 4 +load 5 +callsub numericalcomp_0 +store 5 +load 6 +callsub numericalcomp_0 +store 6 +load 7 +callsub numericalcomp_0 +store 7 +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 +byte 0x00 +int 0 +load 4 +setbyte +byte 0x00 +int 0 +load 5 +setbyte +concat +byte 0x00 +int 0 +load 6 +setbyte +concat +byte 0x00 +int 0 +load 7 +setbyte +concat +byte 0x00 +int 0 +load 8 +setbyte +concat +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 +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_2: +proto 1 1 +int 13634846 +frame_dig -1 +callsub arraycomplement_1 +store 2 +load 2 +callsub arraycomplement_1 +store 3 +frame_dig -1 +load 2 +concat +load 3 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_byte[]_36_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_byte[]_36_v8.teal new file mode 100644 index 000000000..9cab660b5 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_byte[]_36_v8.teal @@ -0,0 +1,683 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// array_complement +arraycomplement_1: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +int 2 ++ +getbyte +store 8 +frame_dig -1 +int 1 +int 1 +* +int 2 ++ +getbyte +store 9 +frame_dig -1 +int 1 +int 2 +* +int 2 ++ +getbyte +store 10 +frame_dig -1 +int 1 +int 3 +* +int 2 ++ +getbyte +store 11 +frame_dig -1 +int 1 +int 4 +* +int 2 ++ +getbyte +store 12 +frame_dig -1 +int 1 +int 5 +* +int 2 ++ +getbyte +store 13 +frame_dig -1 +int 1 +int 6 +* +int 2 ++ +getbyte +store 14 +frame_dig -1 +int 1 +int 7 +* +int 2 ++ +getbyte +store 15 +frame_dig -1 +int 1 +int 8 +* +int 2 ++ +getbyte +store 16 +frame_dig -1 +int 1 +int 9 +* +int 2 ++ +getbyte +store 17 +frame_dig -1 +int 1 +int 10 +* +int 2 ++ +getbyte +store 18 +frame_dig -1 +int 1 +int 11 +* +int 2 ++ +getbyte +store 19 +frame_dig -1 +int 1 +int 12 +* +int 2 ++ +getbyte +store 20 +frame_dig -1 +int 1 +int 13 +* +int 2 ++ +getbyte +store 21 +frame_dig -1 +int 1 +int 14 +* +int 2 ++ +getbyte +store 22 +frame_dig -1 +int 1 +int 15 +* +int 2 ++ +getbyte +store 23 +frame_dig -1 +int 1 +int 16 +* +int 2 ++ +getbyte +store 24 +frame_dig -1 +int 1 +int 17 +* +int 2 ++ +getbyte +store 25 +frame_dig -1 +int 1 +int 18 +* +int 2 ++ +getbyte +store 26 +frame_dig -1 +int 1 +int 19 +* +int 2 ++ +getbyte +store 27 +frame_dig -1 +int 1 +int 20 +* +int 2 ++ +getbyte +store 28 +frame_dig -1 +int 1 +int 21 +* +int 2 ++ +getbyte +store 29 +frame_dig -1 +int 1 +int 22 +* +int 2 ++ +getbyte +store 30 +frame_dig -1 +int 1 +int 23 +* +int 2 ++ +getbyte +store 31 +frame_dig -1 +int 1 +int 24 +* +int 2 ++ +getbyte +store 32 +frame_dig -1 +int 1 +int 25 +* +int 2 ++ +getbyte +store 33 +frame_dig -1 +int 1 +int 26 +* +int 2 ++ +getbyte +store 34 +frame_dig -1 +int 1 +int 27 +* +int 2 ++ +getbyte +store 35 +frame_dig -1 +int 1 +int 28 +* +int 2 ++ +getbyte +store 36 +frame_dig -1 +int 1 +int 29 +* +int 2 ++ +getbyte +store 37 +frame_dig -1 +int 1 +int 30 +* +int 2 ++ +getbyte +store 38 +frame_dig -1 +int 1 +int 31 +* +int 2 ++ +getbyte +store 39 +frame_dig -1 +int 1 +int 32 +* +int 2 ++ +getbyte +store 40 +frame_dig -1 +int 1 +int 33 +* +int 2 ++ +getbyte +store 41 +frame_dig -1 +int 1 +int 34 +* +int 2 ++ +getbyte +store 42 +frame_dig -1 +int 1 +int 35 +* +int 2 ++ +getbyte +store 43 +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 +int 36 +store 44 +load 44 +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 +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 +concat +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_2: +proto 1 1 +int 13634846 +frame_dig -1 +callsub arraycomplement_1 +store 2 +load 2 +callsub arraycomplement_1 +store 3 +frame_dig -1 +store 7 +load 7 +store 6 +int 6 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +load 2 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +concat +load 3 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +itob +extract 6 0 +concat +load 6 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_byte_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_byte_v8.teal new file mode 100644 index 000000000..5fcfe7e85 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_byte_v8.teal @@ -0,0 +1,57 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub numericalcomp_0 +store 2 +load 2 +callsub numericalcomp_0 +store 3 +byte 0x00 +int 0 +frame_dig -1 +setbyte +byte 0x00 +int 0 +load 2 +setbyte +concat +byte 0x00 +int 0 +load 3 +setbyte +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_string_0_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_string_0_v8.teal new file mode 100644 index 000000000..68dbf97f6 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_string_0_v8.teal @@ -0,0 +1,94 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +int 0 +store 8 +load 8 +itob +extract 6 0 +byte "" +concat +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub stringreverse_0 +store 2 +load 2 +callsub stringreverse_0 +store 3 +frame_dig -1 +store 7 +load 7 +store 6 +int 6 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +load 2 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +concat +load 3 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +itob +extract 6 0 +concat +load 6 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_string_13_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_string_13_v8.teal new file mode 100644 index 000000000..0b7ef9286 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_string_13_v8.teal @@ -0,0 +1,261 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +int 1 +int 0 +* +int 2 ++ +getbyte +store 20 +frame_dig -1 +int 1 +int 1 +* +int 2 ++ +getbyte +store 19 +frame_dig -1 +int 1 +int 2 +* +int 2 ++ +getbyte +store 18 +frame_dig -1 +int 1 +int 3 +* +int 2 ++ +getbyte +store 17 +frame_dig -1 +int 1 +int 4 +* +int 2 ++ +getbyte +store 16 +frame_dig -1 +int 1 +int 5 +* +int 2 ++ +getbyte +store 15 +frame_dig -1 +int 1 +int 6 +* +int 2 ++ +getbyte +store 14 +frame_dig -1 +int 1 +int 7 +* +int 2 ++ +getbyte +store 13 +frame_dig -1 +int 1 +int 8 +* +int 2 ++ +getbyte +store 12 +frame_dig -1 +int 1 +int 9 +* +int 2 ++ +getbyte +store 11 +frame_dig -1 +int 1 +int 10 +* +int 2 ++ +getbyte +store 10 +frame_dig -1 +int 1 +int 11 +* +int 2 ++ +getbyte +store 9 +frame_dig -1 +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 +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub stringreverse_0 +store 2 +load 2 +callsub stringreverse_0 +store 3 +frame_dig -1 +store 7 +load 7 +store 6 +int 6 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +load 2 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +concat +load 3 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +itob +extract 6 0 +concat +load 6 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_string_1_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_string_1_v8.teal new file mode 100644 index 000000000..453a7cdb9 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_string_1_v8.teal @@ -0,0 +1,105 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +frame_dig -1 +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 +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub stringreverse_0 +store 2 +load 2 +callsub stringreverse_0 +store 3 +frame_dig -1 +store 7 +load 7 +store 6 +int 6 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +load 2 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +concat +load 3 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +itob +extract 6 0 +concat +load 6 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint16_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint16_v8.teal new file mode 100644 index 000000000..b307d4c40 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint16_v8.teal @@ -0,0 +1,54 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +int 65535 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 65536 +< +assert +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub numericalcomp_0 +store 2 +load 2 +callsub numericalcomp_0 +store 3 +frame_dig -1 +itob +extract 6 0 +load 2 +itob +extract 6 0 +concat +load 3 +itob +extract 6 0 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint32_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint32_v8.teal new file mode 100644 index 000000000..1cb435373 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint32_v8.teal @@ -0,0 +1,54 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +int 4294967295 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 4294967296 +< +assert +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub numericalcomp_0 +store 2 +load 2 +callsub numericalcomp_0 +store 3 +frame_dig -1 +itob +extract 4 0 +load 2 +itob +extract 4 0 +concat +load 3 +itob +extract 4 0 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[1]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[1]_v8.teal new file mode 100644 index 000000000..19e3be236 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[1]_v8.teal @@ -0,0 +1,61 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +int 18446744073709551615 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +retsub + +// array_complement +arraycomplement_1: +proto 1 1 +int 13634846 +frame_dig -1 +int 8 +int 0 +* +extract_uint64 +store 4 +load 4 +callsub numericalcomp_0 +store 4 +load 4 +itob +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_2: +proto 1 1 +int 13634846 +frame_dig -1 +callsub arraycomplement_1 +store 2 +load 2 +callsub arraycomplement_1 +store 3 +frame_dig -1 +load 2 +concat +load 3 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[42]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[42]_v8.teal new file mode 100644 index 000000000..6f93ba204 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[42]_v8.teal @@ -0,0 +1,553 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +int 18446744073709551615 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +retsub + +// array_complement +arraycomplement_1: +proto 1 1 +int 13634846 +frame_dig -1 +int 8 +int 0 +* +extract_uint64 +store 4 +frame_dig -1 +int 8 +int 1 +* +extract_uint64 +store 5 +frame_dig -1 +int 8 +int 2 +* +extract_uint64 +store 6 +frame_dig -1 +int 8 +int 3 +* +extract_uint64 +store 7 +frame_dig -1 +int 8 +int 4 +* +extract_uint64 +store 8 +frame_dig -1 +int 8 +int 5 +* +extract_uint64 +store 9 +frame_dig -1 +int 8 +int 6 +* +extract_uint64 +store 10 +frame_dig -1 +int 8 +int 7 +* +extract_uint64 +store 11 +frame_dig -1 +int 8 +int 8 +* +extract_uint64 +store 12 +frame_dig -1 +int 8 +int 9 +* +extract_uint64 +store 13 +frame_dig -1 +int 8 +int 10 +* +extract_uint64 +store 14 +frame_dig -1 +int 8 +int 11 +* +extract_uint64 +store 15 +frame_dig -1 +int 8 +int 12 +* +extract_uint64 +store 16 +frame_dig -1 +int 8 +int 13 +* +extract_uint64 +store 17 +frame_dig -1 +int 8 +int 14 +* +extract_uint64 +store 18 +frame_dig -1 +int 8 +int 15 +* +extract_uint64 +store 19 +frame_dig -1 +int 8 +int 16 +* +extract_uint64 +store 20 +frame_dig -1 +int 8 +int 17 +* +extract_uint64 +store 21 +frame_dig -1 +int 8 +int 18 +* +extract_uint64 +store 22 +frame_dig -1 +int 8 +int 19 +* +extract_uint64 +store 23 +frame_dig -1 +int 8 +int 20 +* +extract_uint64 +store 24 +frame_dig -1 +int 8 +int 21 +* +extract_uint64 +store 25 +frame_dig -1 +int 8 +int 22 +* +extract_uint64 +store 26 +frame_dig -1 +int 8 +int 23 +* +extract_uint64 +store 27 +frame_dig -1 +int 8 +int 24 +* +extract_uint64 +store 28 +frame_dig -1 +int 8 +int 25 +* +extract_uint64 +store 29 +frame_dig -1 +int 8 +int 26 +* +extract_uint64 +store 30 +frame_dig -1 +int 8 +int 27 +* +extract_uint64 +store 31 +frame_dig -1 +int 8 +int 28 +* +extract_uint64 +store 32 +frame_dig -1 +int 8 +int 29 +* +extract_uint64 +store 33 +frame_dig -1 +int 8 +int 30 +* +extract_uint64 +store 34 +frame_dig -1 +int 8 +int 31 +* +extract_uint64 +store 35 +frame_dig -1 +int 8 +int 32 +* +extract_uint64 +store 36 +frame_dig -1 +int 8 +int 33 +* +extract_uint64 +store 37 +frame_dig -1 +int 8 +int 34 +* +extract_uint64 +store 38 +frame_dig -1 +int 8 +int 35 +* +extract_uint64 +store 39 +frame_dig -1 +int 8 +int 36 +* +extract_uint64 +store 40 +frame_dig -1 +int 8 +int 37 +* +extract_uint64 +store 41 +frame_dig -1 +int 8 +int 38 +* +extract_uint64 +store 42 +frame_dig -1 +int 8 +int 39 +* +extract_uint64 +store 43 +frame_dig -1 +int 8 +int 40 +* +extract_uint64 +store 44 +frame_dig -1 +int 8 +int 41 +* +extract_uint64 +store 45 +load 4 +callsub numericalcomp_0 +store 4 +load 5 +callsub numericalcomp_0 +store 5 +load 6 +callsub numericalcomp_0 +store 6 +load 7 +callsub numericalcomp_0 +store 7 +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 4 +itob +load 5 +itob +concat +load 6 +itob +concat +load 7 +itob +concat +load 8 +itob +concat +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 +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_2: +proto 1 1 +int 13634846 +frame_dig -1 +callsub arraycomplement_1 +store 2 +load 2 +callsub arraycomplement_1 +store 3 +frame_dig -1 +load 2 +concat +load 3 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0_v8.teal new file mode 100644 index 000000000..542046cc4 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0_v8.teal @@ -0,0 +1,94 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +int 0 +store 8 +load 8 +itob +extract 6 0 +byte "" +concat +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub arraycomplement_0 +store 2 +load 2 +callsub arraycomplement_0 +store 3 +frame_dig -1 +store 7 +load 7 +store 6 +int 6 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +load 2 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +concat +load 3 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +itob +extract 6 0 +concat +load 6 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1_v8.teal new file mode 100644 index 000000000..4cc83c458 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1_v8.teal @@ -0,0 +1,117 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +int 18446744073709551615 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +retsub + +// array_complement +arraycomplement_1: +proto 1 1 +int 13634846 +frame_dig -1 +int 8 +int 0 +* +int 2 ++ +extract_uint64 +store 8 +load 8 +callsub numericalcomp_0 +store 8 +int 1 +store 9 +load 9 +itob +extract 6 0 +load 8 +itob +concat +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_2: +proto 1 1 +int 13634846 +frame_dig -1 +callsub arraycomplement_1 +store 2 +load 2 +callsub arraycomplement_1 +store 3 +frame_dig -1 +store 7 +load 7 +store 6 +int 6 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +load 2 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +concat +load 3 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +itob +extract 6 0 +concat +load 6 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42_v8.teal new file mode 100644 index 000000000..c3b990138 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42_v8.teal @@ -0,0 +1,691 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +int 18446744073709551615 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +retsub + +// array_complement +arraycomplement_1: +proto 1 1 +int 13634846 +frame_dig -1 +int 8 +int 0 +* +int 2 ++ +extract_uint64 +store 8 +frame_dig -1 +int 8 +int 1 +* +int 2 ++ +extract_uint64 +store 9 +frame_dig -1 +int 8 +int 2 +* +int 2 ++ +extract_uint64 +store 10 +frame_dig -1 +int 8 +int 3 +* +int 2 ++ +extract_uint64 +store 11 +frame_dig -1 +int 8 +int 4 +* +int 2 ++ +extract_uint64 +store 12 +frame_dig -1 +int 8 +int 5 +* +int 2 ++ +extract_uint64 +store 13 +frame_dig -1 +int 8 +int 6 +* +int 2 ++ +extract_uint64 +store 14 +frame_dig -1 +int 8 +int 7 +* +int 2 ++ +extract_uint64 +store 15 +frame_dig -1 +int 8 +int 8 +* +int 2 ++ +extract_uint64 +store 16 +frame_dig -1 +int 8 +int 9 +* +int 2 ++ +extract_uint64 +store 17 +frame_dig -1 +int 8 +int 10 +* +int 2 ++ +extract_uint64 +store 18 +frame_dig -1 +int 8 +int 11 +* +int 2 ++ +extract_uint64 +store 19 +frame_dig -1 +int 8 +int 12 +* +int 2 ++ +extract_uint64 +store 20 +frame_dig -1 +int 8 +int 13 +* +int 2 ++ +extract_uint64 +store 21 +frame_dig -1 +int 8 +int 14 +* +int 2 ++ +extract_uint64 +store 22 +frame_dig -1 +int 8 +int 15 +* +int 2 ++ +extract_uint64 +store 23 +frame_dig -1 +int 8 +int 16 +* +int 2 ++ +extract_uint64 +store 24 +frame_dig -1 +int 8 +int 17 +* +int 2 ++ +extract_uint64 +store 25 +frame_dig -1 +int 8 +int 18 +* +int 2 ++ +extract_uint64 +store 26 +frame_dig -1 +int 8 +int 19 +* +int 2 ++ +extract_uint64 +store 27 +frame_dig -1 +int 8 +int 20 +* +int 2 ++ +extract_uint64 +store 28 +frame_dig -1 +int 8 +int 21 +* +int 2 ++ +extract_uint64 +store 29 +frame_dig -1 +int 8 +int 22 +* +int 2 ++ +extract_uint64 +store 30 +frame_dig -1 +int 8 +int 23 +* +int 2 ++ +extract_uint64 +store 31 +frame_dig -1 +int 8 +int 24 +* +int 2 ++ +extract_uint64 +store 32 +frame_dig -1 +int 8 +int 25 +* +int 2 ++ +extract_uint64 +store 33 +frame_dig -1 +int 8 +int 26 +* +int 2 ++ +extract_uint64 +store 34 +frame_dig -1 +int 8 +int 27 +* +int 2 ++ +extract_uint64 +store 35 +frame_dig -1 +int 8 +int 28 +* +int 2 ++ +extract_uint64 +store 36 +frame_dig -1 +int 8 +int 29 +* +int 2 ++ +extract_uint64 +store 37 +frame_dig -1 +int 8 +int 30 +* +int 2 ++ +extract_uint64 +store 38 +frame_dig -1 +int 8 +int 31 +* +int 2 ++ +extract_uint64 +store 39 +frame_dig -1 +int 8 +int 32 +* +int 2 ++ +extract_uint64 +store 40 +frame_dig -1 +int 8 +int 33 +* +int 2 ++ +extract_uint64 +store 41 +frame_dig -1 +int 8 +int 34 +* +int 2 ++ +extract_uint64 +store 42 +frame_dig -1 +int 8 +int 35 +* +int 2 ++ +extract_uint64 +store 43 +frame_dig -1 +int 8 +int 36 +* +int 2 ++ +extract_uint64 +store 44 +frame_dig -1 +int 8 +int 37 +* +int 2 ++ +extract_uint64 +store 45 +frame_dig -1 +int 8 +int 38 +* +int 2 ++ +extract_uint64 +store 46 +frame_dig -1 +int 8 +int 39 +* +int 2 ++ +extract_uint64 +store 47 +frame_dig -1 +int 8 +int 40 +* +int 2 ++ +extract_uint64 +store 48 +frame_dig -1 +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 50 +load 50 +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 +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_2: +proto 1 1 +int 13634846 +frame_dig -1 +callsub arraycomplement_1 +store 2 +load 2 +callsub arraycomplement_1 +store 3 +frame_dig -1 +store 7 +load 7 +store 6 +int 6 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +load 2 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +load 7 +len ++ +store 5 +load 5 +int 65536 +< +assert +load 4 +itob +extract 6 0 +concat +load 3 +store 7 +load 6 +load 7 +concat +store 6 +load 5 +store 4 +load 4 +itob +extract 6 0 +concat +load 6 +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64_v8.teal new file mode 100644 index 000000000..03467d10c --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64_v8.teal @@ -0,0 +1,46 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +int 18446744073709551615 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub numericalcomp_0 +store 2 +load 2 +callsub numericalcomp_0 +store 3 +frame_dig -1 +itob +load 2 +itob +concat +load 3 +itob +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint8_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint8_v8.teal new file mode 100644 index 000000000..5fcfe7e85 --- /dev/null +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint8_v8.teal @@ -0,0 +1,57 @@ +#pragma version 8 +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: +proto 1 1 +int 13634846 +int 255 +frame_dig -1 +- +frame_bury 0 +frame_dig 0 +int 256 +< +assert +frame_dig 0 +retsub + +// round_tripper +roundtripper_1: +proto 1 1 +int 13634846 +frame_dig -1 +callsub numericalcomp_0 +store 2 +load 2 +callsub numericalcomp_0 +store 3 +byte 0x00 +int 0 +frame_dig -1 +setbyte +byte 0x00 +int 0 +load 2 +setbyte +concat +byte 0x00 +int 0 +load 3 +setbyte +concat +frame_bury 0 +frame_dig 0 +retsub \ No newline at end of file From ac98d94848bd8bdc11ea141012529ca49469f7f1 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Mon, 31 Oct 2022 12:46:12 -0400 Subject: [PATCH 035/206] comments --- pyteal/ast/abi/tuple.py | 5 ++++- pyteal/ast/subroutine.py | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pyteal/ast/abi/tuple.py b/pyteal/ast/abi/tuple.py index cabe52f7c..05878ec12 100644 --- a/pyteal/ast/abi/tuple.py +++ b/pyteal/ast/abi/tuple.py @@ -679,7 +679,10 @@ def __setattr__(self, name: str, field: Any) -> None: if name == "_NamedTuple__ready" or not self.__ready: super().__setattr__(name, field) return - # TODO need to relax this part lol + # NOTE this pass condition is for following scenario: + # NamedTuple is an argument, and inside subroutine, subroutine set internal ABI value with FrameStorage + # This used to violate `__setattr__` for not allowing any assignment to attributes + # Now this case is lifted such that we can shift the storage scheme. if name.startswith("_") and name != "_NamedTuple__ready" and self.__ready: super().__setattr__(name, field) return diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 739bc498a..7c7da13b7 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -977,7 +977,6 @@ def __var_n_loaded_fp( return argument_var, loaded_var def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: - # TODO need to make it better for my temp hack, kinda ugly but it works from pyteal.ast.abi.type import FrameStorage args = subroutine.arguments() From cf0c331e3f2f93b5eabd4d958c83ec1097479b66 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Mon, 31 Oct 2022 13:20:14 -0400 Subject: [PATCH 036/206] still wristing with docker, revert space reserving stuffs --- pyteal/ast/frame.py | 6 +-- .../teal/roundtrip/app_roundtrip_()_v8.teal | 4 +- .../app_roundtrip_(bool)[10]_v8.teal | 8 ++-- .../roundtrip/app_roundtrip_(bool)_v8.teal | 6 +-- ...t64,bool),byte[10],bool[4],uint64)_v8.teal | 26 +++++----- .../app_roundtrip_(bool,byte)_v8.teal | 8 ++-- ...undtrip_(bool,byte,address,string)_v8.teal | 14 +++--- ...yte),uint8)[2],string,bool[]))[]_2_v8.teal | 48 +++++++++---------- ..._(bool,byte,address,string,uint64)_v8.teal | 16 +++---- ...app_roundtrip_(bool,uint64,uint32)_v8.teal | 10 ++-- .../roundtrip/app_roundtrip_(byte)_v8.teal | 6 +-- .../app_roundtrip_(byte,bool,uint64)_v8.teal | 10 ++-- ...4],(bool,bool),uint64,address)[]_7_v8.teal | 22 ++++----- .../roundtrip/app_roundtrip_(uint16)_v8.teal | 6 +-- .../app_roundtrip_(uint16,uint8,byte)_v8.teal | 10 ++-- .../roundtrip/app_roundtrip_(uint32)_v8.teal | 6 +-- ...pp_roundtrip_(uint32,uint16,uint8)_v8.teal | 10 ++-- .../roundtrip/app_roundtrip_(uint64)_v8.teal | 6 +-- ...p_roundtrip_(uint64,uint32,uint16)_v8.teal | 10 ++-- .../roundtrip/app_roundtrip_(uint8)_v8.teal | 6 +-- .../app_roundtrip_(uint8,byte,bool)_v8.teal | 10 ++-- .../app_roundtrip_address[]_10_v8.teal | 8 ++-- .../roundtrip/app_roundtrip_address_v8.teal | 6 +-- .../roundtrip/app_roundtrip_bool[1]_v8.teal | 6 +-- .../app_roundtrip_bool[3][]_11_v8.teal | 8 ++-- .../roundtrip/app_roundtrip_bool[42]_v8.teal | 6 +-- .../roundtrip/app_roundtrip_bool[]_0_v8.teal | 4 +- .../roundtrip/app_roundtrip_bool[]_1_v8.teal | 6 +-- .../roundtrip/app_roundtrip_bool[]_42_v8.teal | 6 +-- .../teal/roundtrip/app_roundtrip_bool_v8.teal | 4 +- .../roundtrip/app_roundtrip_byte[16]_v8.teal | 6 +-- .../roundtrip/app_roundtrip_byte[]_36_v8.teal | 6 +-- .../teal/roundtrip/app_roundtrip_byte_v8.teal | 4 +- .../roundtrip/app_roundtrip_string_0_v8.teal | 4 +- .../roundtrip/app_roundtrip_string_13_v8.teal | 4 +- .../roundtrip/app_roundtrip_string_1_v8.teal | 4 +- .../roundtrip/app_roundtrip_uint16_v8.teal | 4 +- .../roundtrip/app_roundtrip_uint32_v8.teal | 4 +- .../roundtrip/app_roundtrip_uint64[1]_v8.teal | 6 +-- .../app_roundtrip_uint64[42]_v8.teal | 6 +-- .../app_roundtrip_uint64[]_0_v8.teal | 4 +- .../app_roundtrip_uint64[]_1_v8.teal | 6 +-- .../app_roundtrip_uint64[]_42_v8.teal | 6 +-- .../roundtrip/app_roundtrip_uint64_v8.teal | 4 +- .../roundtrip/app_roundtrip_uint8_v8.teal | 4 +- 45 files changed, 186 insertions(+), 188 deletions(-) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index d31e99138..cca2f6447 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -34,13 +34,11 @@ def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBloc if self.reserve_spot == 0: return proto_srt, proto_end elif self.reserve_spot == 1: - int_srt, int_end = Int(0xD00D1E).__teal__(options) + int_srt, int_end = Int(0).__teal__(options) proto_end.setNextBlock(int_srt) return proto_srt, int_end else: - dupn_srt, dupn_end = DupN(Int(0x5EA51DE), self.reserve_spot).__teal__( - options - ) + dupn_srt, dupn_end = DupN(Int(0), self.reserve_spot).__teal__(options) proto_end.setNextBlock(dupn_srt) return proto_srt, dupn_end diff --git a/tests/integration/teal/roundtrip/app_roundtrip_()_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_()_v8.teal index 7f74c2e54..a15a4fc89 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_()_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_()_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 byte "" frame_bury 0 frame_dig 0 @@ -23,7 +23,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub tuplecomplement_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10]_v8.teal index f2c4408b5..3fd706e70 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10]_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10]_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 getbit @@ -33,7 +33,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -160,7 +160,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub arraycomplement_1 store 3 @@ -179,7 +179,7 @@ retsub // bool_comp boolcomp_3: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool)_v8.teal index 740a8041a..007dc02ea 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 getbit @@ -33,7 +33,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub tuplecomplement_0 store 3 @@ -52,7 +52,7 @@ retsub // bool_comp boolcomp_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64)_v8.teal index cc255e503..6f72201c2 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 getbit @@ -75,7 +75,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub tuplecomplement_0 store 8 @@ -94,7 +94,7 @@ retsub // bool_comp boolcomp_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! @@ -106,7 +106,7 @@ retsub // numerical_comp numericalcomp_3: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -121,7 +121,7 @@ retsub // array_complement arraycomplement_4: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -576,7 +576,7 @@ retsub // tuple_complement tuplecomplement_5: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 extract_uint64 @@ -605,7 +605,7 @@ retsub // numerical_comp numericalcomp_6: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -620,7 +620,7 @@ retsub // array_complement arraycomplement_7: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -767,7 +767,7 @@ retsub // bool_comp boolcomp_8: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! @@ -779,7 +779,7 @@ retsub // array_complement arraycomplement_9: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 getbit @@ -828,7 +828,7 @@ retsub // numerical_comp numericalcomp_10: proto 1 1 -int 13634846 +int 0 int 18446744073709551615 frame_dig -1 - @@ -839,7 +839,7 @@ retsub // numerical_comp numericalcomp_11: proto 1 1 -int 13634846 +int 0 int 18446744073709551615 frame_dig -1 - @@ -850,7 +850,7 @@ retsub // bool_comp boolcomp_12: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte)_v8.teal index c8147ff68..7de062794 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 getbit @@ -45,7 +45,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub tuplecomplement_0 store 4 @@ -64,7 +64,7 @@ retsub // bool_comp boolcomp_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! @@ -76,7 +76,7 @@ retsub // numerical_comp numericalcomp_3: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string)_v8.teal index 1840f754d..c015db7d2 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 getbit @@ -76,7 +76,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub tuplecomplement_0 store 6 @@ -143,7 +143,7 @@ retsub // bool_comp boolcomp_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! @@ -155,7 +155,7 @@ retsub // numerical_comp numericalcomp_3: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -170,7 +170,7 @@ retsub // numerical_comp numericalcomp_4: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -185,7 +185,7 @@ retsub // array_complement arraycomplement_5: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -640,7 +640,7 @@ retsub // string_reverse stringreverse_6: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_2_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_2_v8.teal index b2fae5c07..c7436e670 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_2_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_2_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 getbit @@ -109,7 +109,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 frame_dig -1 int 2 @@ -238,7 +238,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub arraycomplement_1 store 7 @@ -305,7 +305,7 @@ retsub // bool_comp boolcomp_3: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! @@ -317,7 +317,7 @@ retsub // numerical_comp numericalcomp_4: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -332,7 +332,7 @@ retsub // numerical_comp numericalcomp_5: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -347,7 +347,7 @@ retsub // array_complement arraycomplement_6: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -802,7 +802,7 @@ retsub // string_reverse stringreverse_7: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -854,7 +854,7 @@ retsub // tuple_complement tuplecomplement_8: proto 1 1 -int 13634846 +int 0 frame_dig -1 extract 0 32 store 22 @@ -958,7 +958,7 @@ retsub // numerical_comp numericalcomp_9: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -973,7 +973,7 @@ retsub // array_complement arraycomplement_10: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -1428,7 +1428,7 @@ retsub // tuple_complement tuplecomplement_11: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 extract_uint32 @@ -1497,7 +1497,7 @@ retsub // array_complement arraycomplement_12: proto 1 1 -int 13634846 +int 0 frame_dig -1 frame_dig -1 int 2 @@ -1596,7 +1596,7 @@ retsub // string_reverse stringreverse_13: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -1648,7 +1648,7 @@ retsub // bool_comp boolcomp_14: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! @@ -1660,7 +1660,7 @@ retsub // array_complement arraycomplement_15: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 int 16 @@ -1711,7 +1711,7 @@ retsub // numerical_comp numericalcomp_16: proto 1 1 -int 13634846 +int 0 int 4294967295 frame_dig -1 - @@ -1726,7 +1726,7 @@ retsub // string_reverse stringreverse_17: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -1778,7 +1778,7 @@ retsub // array_complement arraycomplement_18: proto 1 1 -int 13634846 +int 0 frame_dig -1 frame_dig -1 int 2 @@ -1969,7 +1969,7 @@ retsub // bool_comp boolcomp_19: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! @@ -1981,7 +1981,7 @@ retsub // array_complement arraycomplement_20: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 getbit @@ -2010,7 +2010,7 @@ retsub // tuple_complement tuplecomplement_21: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 getbyte @@ -2029,7 +2029,7 @@ retsub // numerical_comp numericalcomp_22: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -2044,7 +2044,7 @@ retsub // numerical_comp numericalcomp_23: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64)_v8.teal index 0d22f98ea..b20a2929e 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 getbit @@ -86,7 +86,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub tuplecomplement_0 store 7 @@ -153,7 +153,7 @@ retsub // bool_comp boolcomp_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! @@ -165,7 +165,7 @@ retsub // numerical_comp numericalcomp_3: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -180,7 +180,7 @@ retsub // numerical_comp numericalcomp_4: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -195,7 +195,7 @@ retsub // array_complement arraycomplement_5: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -650,7 +650,7 @@ retsub // string_reverse stringreverse_6: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -702,7 +702,7 @@ retsub // numerical_comp numericalcomp_7: proto 1 1 -int 13634846 +int 0 int 18446744073709551615 frame_dig -1 - diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32)_v8.teal index a1ba69bfb..c6cb8d92a 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 getbit @@ -54,7 +54,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub tuplecomplement_0 store 5 @@ -73,7 +73,7 @@ retsub // bool_comp boolcomp_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! @@ -85,7 +85,7 @@ retsub // numerical_comp numericalcomp_3: proto 1 1 -int 13634846 +int 0 int 18446744073709551615 frame_dig -1 - @@ -96,7 +96,7 @@ retsub // numerical_comp numericalcomp_4: proto 1 1 -int 13634846 +int 0 int 4294967295 frame_dig -1 - diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(byte)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(byte)_v8.teal index ea0e98fc2..ed37a3f74 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(byte)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(byte)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 getbyte @@ -33,7 +33,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub tuplecomplement_0 store 3 @@ -52,7 +52,7 @@ retsub // numerical_comp numericalcomp_2: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64)_v8.teal index d0db45543..328541097 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 getbyte @@ -55,7 +55,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub tuplecomplement_0 store 5 @@ -74,7 +74,7 @@ retsub // numerical_comp numericalcomp_2: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -89,7 +89,7 @@ retsub // bool_comp boolcomp_3: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! @@ -101,7 +101,7 @@ retsub // numerical_comp numericalcomp_4: proto 1 1 -int 13634846 +int 0 int 18446744073709551615 frame_dig -1 - diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7_v8.teal index 915b57058..12e8535c4 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 extract 0 4 store 0 @@ -55,7 +55,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 45 int 0 @@ -166,7 +166,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub arraycomplement_1 store 6 @@ -233,7 +233,7 @@ retsub // numerical_comp numericalcomp_3: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -248,7 +248,7 @@ retsub // array_complement arraycomplement_4: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -311,7 +311,7 @@ retsub // tuple_complement tuplecomplement_5: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 getbit @@ -340,7 +340,7 @@ retsub // numerical_comp numericalcomp_6: proto 1 1 -int 13634846 +int 0 int 18446744073709551615 frame_dig -1 - @@ -351,7 +351,7 @@ retsub // numerical_comp numericalcomp_7: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -366,7 +366,7 @@ retsub // array_complement arraycomplement_8: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -821,7 +821,7 @@ retsub // bool_comp boolcomp_9: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! @@ -833,7 +833,7 @@ retsub // bool_comp boolcomp_10: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint16)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint16)_v8.teal index 306ab7acb..ce75f2421 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint16)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint16)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 extract_uint16 @@ -32,7 +32,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub tuplecomplement_0 store 3 @@ -51,7 +51,7 @@ retsub // numerical_comp numericalcomp_2: proto 1 1 -int 13634846 +int 0 int 65535 frame_dig -1 - diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte)_v8.teal index ef7c2428d..b2cde5b27 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 extract_uint16 @@ -56,7 +56,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub tuplecomplement_0 store 5 @@ -75,7 +75,7 @@ retsub // numerical_comp numericalcomp_2: proto 1 1 -int 13634846 +int 0 int 65535 frame_dig -1 - @@ -90,7 +90,7 @@ retsub // numerical_comp numericalcomp_3: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -105,7 +105,7 @@ retsub // numerical_comp numericalcomp_4: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint32)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint32)_v8.teal index 741db6e80..4e9b98403 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint32)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint32)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 extract_uint32 @@ -32,7 +32,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub tuplecomplement_0 store 3 @@ -51,7 +51,7 @@ retsub // numerical_comp numericalcomp_2: proto 1 1 -int 13634846 +int 0 int 4294967295 frame_dig -1 - diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8)_v8.teal index 03e6b2c06..fe6043f2f 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 extract_uint32 @@ -55,7 +55,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub tuplecomplement_0 store 5 @@ -74,7 +74,7 @@ retsub // numerical_comp numericalcomp_2: proto 1 1 -int 13634846 +int 0 int 4294967295 frame_dig -1 - @@ -89,7 +89,7 @@ retsub // numerical_comp numericalcomp_3: proto 1 1 -int 13634846 +int 0 int 65535 frame_dig -1 - @@ -104,7 +104,7 @@ retsub // numerical_comp numericalcomp_4: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint64)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint64)_v8.teal index b88127140..64e19a464 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint64)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint64)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 btoi store 0 @@ -30,7 +30,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub tuplecomplement_0 store 3 @@ -49,7 +49,7 @@ retsub // numerical_comp numericalcomp_2: proto 1 1 -int 13634846 +int 0 int 18446744073709551615 frame_dig -1 - diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16)_v8.teal index eacfb78f8..cdbd5954b 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 extract_uint64 @@ -53,7 +53,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub tuplecomplement_0 store 5 @@ -72,7 +72,7 @@ retsub // numerical_comp numericalcomp_2: proto 1 1 -int 13634846 +int 0 int 18446744073709551615 frame_dig -1 - @@ -83,7 +83,7 @@ retsub // numerical_comp numericalcomp_3: proto 1 1 -int 13634846 +int 0 int 4294967295 frame_dig -1 - @@ -98,7 +98,7 @@ retsub // numerical_comp numericalcomp_4: proto 1 1 -int 13634846 +int 0 int 65535 frame_dig -1 - diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint8)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint8)_v8.teal index ea0e98fc2..ed37a3f74 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint8)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint8)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 getbyte @@ -33,7 +33,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub tuplecomplement_0 store 3 @@ -52,7 +52,7 @@ retsub // numerical_comp numericalcomp_2: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v8.teal index 9addccd5d..689248d79 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 getbyte @@ -57,7 +57,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub tuplecomplement_0 store 5 @@ -76,7 +76,7 @@ retsub // numerical_comp numericalcomp_2: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -91,7 +91,7 @@ retsub // numerical_comp numericalcomp_3: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -106,7 +106,7 @@ retsub // bool_comp boolcomp_4: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! diff --git a/tests/integration/teal/roundtrip/app_roundtrip_address[]_10_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_address[]_10_v8.teal index be15e1a34..280f65569 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_address[]_10_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_address[]_10_v8.teal @@ -14,7 +14,7 @@ return // numerical_comp numericalcomp_0: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -29,7 +29,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -484,7 +484,7 @@ retsub // array_complement arraycomplement_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 32 int 0 @@ -637,7 +637,7 @@ retsub // round_tripper roundtripper_3: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub arraycomplement_2 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_address_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_address_v8.teal index 7444fb267..33347e57b 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_address_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_address_v8.teal @@ -14,7 +14,7 @@ return // numerical_comp numericalcomp_0: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -29,7 +29,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -484,7 +484,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[1]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[1]_v8.teal index 065807402..35258686a 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool[1]_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[1]_v8.teal @@ -14,7 +14,7 @@ return // bool_comp boolcomp_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! @@ -26,7 +26,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 getbit @@ -45,7 +45,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11_v8.teal index 3f5d168b2..07faee81c 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11_v8.teal @@ -14,7 +14,7 @@ return // bool_comp boolcomp_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! @@ -26,7 +26,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 getbit @@ -65,7 +65,7 @@ retsub // array_complement arraycomplement_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -232,7 +232,7 @@ retsub // round_tripper roundtripper_3: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub arraycomplement_2 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[42]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[42]_v8.teal index 20e422692..31fa09e84 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool[42]_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[42]_v8.teal @@ -14,7 +14,7 @@ return // bool_comp boolcomp_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! @@ -26,7 +26,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 getbit @@ -455,7 +455,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_0_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_0_v8.teal index 542046cc4..67050ca70 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_0_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_0_v8.teal @@ -14,7 +14,7 @@ return // array_complement arraycomplement_0: proto 1 1 -int 13634846 +int 0 int 0 store 8 load 8 @@ -29,7 +29,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub arraycomplement_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_1_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_1_v8.teal index 879b7adb5..61b164f60 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_1_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_1_v8.teal @@ -14,7 +14,7 @@ return // bool_comp boolcomp_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! @@ -26,7 +26,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 int 16 @@ -53,7 +53,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_42_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_42_v8.teal index 34f1528fe..a5c7c3d9f 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_42_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_42_v8.teal @@ -14,7 +14,7 @@ return // bool_comp boolcomp_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! @@ -26,7 +26,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 0 int 16 @@ -545,7 +545,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool_v8.teal index 1e8311ecf..b241c509d 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool_v8.teal @@ -18,7 +18,7 @@ return // bool_comp boolcomp_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 ! ! @@ -30,7 +30,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub boolcomp_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_byte[16]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_byte[16]_v8.teal index f96c0c3b4..4d3b6e7c2 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_byte[16]_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_byte[16]_v8.teal @@ -14,7 +14,7 @@ return // numerical_comp numericalcomp_0: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -29,7 +29,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -260,7 +260,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_byte[]_36_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_byte[]_36_v8.teal index 9cab660b5..731fb06d0 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_byte[]_36_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_byte[]_36_v8.teal @@ -14,7 +14,7 @@ return // numerical_comp numericalcomp_0: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -29,7 +29,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -618,7 +618,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_byte_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_byte_v8.teal index 5fcfe7e85..b1ec9822c 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_byte_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_byte_v8.teal @@ -16,7 +16,7 @@ return // numerical_comp numericalcomp_0: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -31,7 +31,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub numericalcomp_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_string_0_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_string_0_v8.teal index 68dbf97f6..fb6e4bfeb 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_string_0_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_string_0_v8.teal @@ -14,7 +14,7 @@ return // string_reverse stringreverse_0: proto 1 1 -int 13634846 +int 0 int 0 store 8 load 8 @@ -29,7 +29,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub stringreverse_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_string_13_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_string_13_v8.teal index 0b7ef9286..6b9d3620f 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_string_13_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_string_13_v8.teal @@ -14,7 +14,7 @@ return // string_reverse stringreverse_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -196,7 +196,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub stringreverse_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_string_1_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_string_1_v8.teal index 453a7cdb9..15bec0ea9 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_string_1_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_string_1_v8.teal @@ -14,7 +14,7 @@ return // string_reverse stringreverse_0: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 1 int 0 @@ -40,7 +40,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub stringreverse_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint16_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint16_v8.teal index b307d4c40..4204c502b 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint16_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint16_v8.teal @@ -16,7 +16,7 @@ return // numerical_comp numericalcomp_0: proto 1 1 -int 13634846 +int 0 int 65535 frame_dig -1 - @@ -31,7 +31,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub numericalcomp_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint32_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint32_v8.teal index 1cb435373..2ed29b2ee 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint32_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint32_v8.teal @@ -16,7 +16,7 @@ return // numerical_comp numericalcomp_0: proto 1 1 -int 13634846 +int 0 int 4294967295 frame_dig -1 - @@ -31,7 +31,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub numericalcomp_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[1]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[1]_v8.teal index 19e3be236..fb6a67b3a 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint64[1]_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[1]_v8.teal @@ -14,7 +14,7 @@ return // numerical_comp numericalcomp_0: proto 1 1 -int 13634846 +int 0 int 18446744073709551615 frame_dig -1 - @@ -25,7 +25,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 8 int 0 @@ -44,7 +44,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[42]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[42]_v8.teal index 6f93ba204..e82c27443 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint64[42]_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[42]_v8.teal @@ -14,7 +14,7 @@ return // numerical_comp numericalcomp_0: proto 1 1 -int 13634846 +int 0 int 18446744073709551615 frame_dig -1 - @@ -25,7 +25,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 8 int 0 @@ -536,7 +536,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0_v8.teal index 542046cc4..67050ca70 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0_v8.teal @@ -14,7 +14,7 @@ return // array_complement arraycomplement_0: proto 1 1 -int 13634846 +int 0 int 0 store 8 load 8 @@ -29,7 +29,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub arraycomplement_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1_v8.teal index 4cc83c458..cd6867a22 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1_v8.teal @@ -14,7 +14,7 @@ return // numerical_comp numericalcomp_0: proto 1 1 -int 13634846 +int 0 int 18446744073709551615 frame_dig -1 - @@ -25,7 +25,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 8 int 0 @@ -52,7 +52,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42_v8.teal index c3b990138..0b2bddb45 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42_v8.teal @@ -14,7 +14,7 @@ return // numerical_comp numericalcomp_0: proto 1 1 -int 13634846 +int 0 int 18446744073709551615 frame_dig -1 - @@ -25,7 +25,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 int 8 int 0 @@ -626,7 +626,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64_v8.teal index 03467d10c..4f6069984 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint64_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64_v8.teal @@ -15,7 +15,7 @@ return // numerical_comp numericalcomp_0: proto 1 1 -int 13634846 +int 0 int 18446744073709551615 frame_dig -1 - @@ -26,7 +26,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub numericalcomp_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint8_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint8_v8.teal index 5fcfe7e85..b1ec9822c 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint8_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint8_v8.teal @@ -16,7 +16,7 @@ return // numerical_comp numericalcomp_0: proto 1 1 -int 13634846 +int 0 int 255 frame_dig -1 - @@ -31,7 +31,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 13634846 +int 0 frame_dig -1 callsub numericalcomp_0 store 2 From 769419b1f330c35cd0e73cccd71ca7cc55b09eb0 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Mon, 31 Oct 2022 15:26:55 -0400 Subject: [PATCH 037/206] minor, pure compilation more flexible --- tests/integration/abi_roundtrip_test.py | 32 ++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/integration/abi_roundtrip_test.py b/tests/integration/abi_roundtrip_test.py index 52b226471..3f9961415 100644 --- a/tests/integration/abi_roundtrip_test.py +++ b/tests/integration/abi_roundtrip_test.py @@ -196,10 +196,6 @@ def test_pure_compilation(abi_type): print(f"Pure Compilation Test for {abi_type=}") abi_type, type_str, dynamic_length, roundtripper = roundtrip_setup(abi_type) - # TODO neeed to make this version flexible - - _version = 8 - if type_str in BAD_TYPES: print( f"Skipping encoding roundtrip test of '{abi_type}' because of {BAD_TYPES[type_str]}" @@ -213,21 +209,25 @@ def test_pure_compilation(abi_type): assert [sdk_abi_type] == abi_arg_types assert algosdk.abi.TupleType([sdk_abi_type] * 3) == abi_ret_type - teal = roundtripper.compile(version=_version) + def compile_and_compare(_version: int): + teal = roundtripper.compile(_version) - filename = ( - f"app_roundtrip_{sdk_abi_type}" - + ("" if dynamic_length is None else f"_{dynamic_length}") - + f"_v{_version}.teal" - ) - tealdir = GENERATED / "roundtrip" - tealdir.mkdir(parents=True, exist_ok=True) + filename = ( + f"app_roundtrip_{sdk_abi_type}" + + ("" if dynamic_length is None else f"_{dynamic_length}") + + f"_v{_version}.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) - save_to = tealdir / filename - with open(save_to, "w") as f: - f.write(teal) + assert_teal_as_expected(save_to, FIXTURES / "roundtrip" / filename) - assert_teal_as_expected(save_to, FIXTURES / "roundtrip" / filename) + compile_and_compare(6) + compile_and_compare(8) @pytest.mark.parametrize("abi_type", ABI_TYPES) From d77b4421b63b8448218c32114ff761c439cf3c79 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Mon, 31 Oct 2022 15:45:37 -0400 Subject: [PATCH 038/206] roundtrip dryrun flexibility --- tests/integration/abi_roundtrip_test.py | 54 ++++++++++++++----------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/tests/integration/abi_roundtrip_test.py b/tests/integration/abi_roundtrip_test.py index 3f9961415..ef611f385 100644 --- a/tests/integration/abi_roundtrip_test.py +++ b/tests/integration/abi_roundtrip_test.py @@ -255,14 +255,17 @@ def test_roundtrip(abi_type): 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, compiler_version=8) - cost = inspector.cost() - passed = inspector.passed() - original, mut, mut_mut = inspector.last_log() + def dryrun_roundtrip(_version: int): + inspector = roundtripper.dryrun(args, compiler_version=_version) - print( - f""" + cost = inspector.cost() + passed = inspector.passed() + original, mut, mut_mut = inspector.last_log() + + print( + f""" +version={_version} {abi_type=} {sdk_abi_str=} {dynamic_length=} @@ -274,21 +277,24 @@ def test_roundtrip(abi_type): {mut=} {mut_mut=} """ - ) - - last_steps = 2 - - assert passed == (cost <= 700), inspector.report( - args, f"passed={passed} contradicted cost={cost}", last_steps=last_steps - ) - assert rand_abi_instance == original, inspector.report( - args, "rand_abi_instance v. original", last_steps=last_steps - ) - assert original == mut_mut, inspector.report( - args, "orginal v. mut_mut", last_steps=last_steps - ) - - expected_mut = abi_strat.mutate_for_roundtrip(rand_abi_instance) - assert expected_mut == mut, inspector.report( - args, "expected_mut v. mut", last_steps=last_steps - ) + ) + + last_steps = 2 + + assert passed == (cost <= 700), inspector.report( + args, f"passed={passed} contradicted cost={cost}", last_steps=last_steps + ) + assert rand_abi_instance == original, inspector.report( + args, "rand_abi_instance v. original", last_steps=last_steps + ) + assert original == mut_mut, inspector.report( + args, "orginal v. mut_mut", last_steps=last_steps + ) + + expected_mut = abi_strat.mutate_for_roundtrip(rand_abi_instance) + assert expected_mut == mut, inspector.report( + args, "expected_mut v. mut", last_steps=last_steps + ) + + dryrun_roundtrip(6) + dryrun_roundtrip(8) From 20c0ef891240da57c002845d53d64d36c29ff8b2 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Mon, 31 Oct 2022 15:55:21 -0400 Subject: [PATCH 039/206] conditional factorial done, need int65 and complex130 --- tests/integration/graviton_abi_test.py | 41 +++++++++++++++----------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/tests/integration/graviton_abi_test.py b/tests/integration/graviton_abi_test.py index 0b571824c..5927589d1 100644 --- a/tests/integration/graviton_abi_test.py +++ b/tests/integration/graviton_abi_test.py @@ -520,21 +520,26 @@ def py_factorial(n): def test_conditional_factorial(): ptdre = PyTealDryRunExecutor(conditional_factorial, pt.Mode.Application) inputs = [(n,) for n in range(20)] - inspectors = ptdre.dryrun_on_sequence(inputs) - for i, args in enumerate(inputs): - inspector = inspectors[i] - n = args[0] - assert inspector.passed(), inspector.report(args, row=i + 1) - - expected = py_factorial(n) - assert expected == inspector.last_log(), inspector.report(args, row=i + 1) - - n = 21 - args = (n,) - inspector = ptdre.dryrun(args) - assert inspector.rejected(), inspector.report( - args, f"FAILED: should have rejected for {n=}", row=n + 1 - ) - assert inspector.error(), inspector.report( - args, f"FAILED: should error for {n=}", row=n + 1 - ) + + def dryrun_on_version(_version: int): + inspectors = ptdre.dryrun_on_sequence(inputs, compiler_version=_version) + for i, args in enumerate(inputs): + inspector = inspectors[i] + n = args[0] + assert inspector.passed(), inspector.report(args, row=i + 1) + + expected = py_factorial(n) + assert expected == inspector.last_log(), inspector.report(args, row=i + 1) + + n = 21 + args = (n,) + inspector = ptdre.dryrun(args) + assert inspector.rejected(), inspector.report( + args, f"FAILED: should have rejected for {n=}", row=n + 1 + ) + assert inspector.error(), inspector.report( + args, f"FAILED: should error for {n=}", row=n + 1 + ) + + dryrun_on_version(6) + dryrun_on_version(8) From d056f4af2a7841bb87cee58900d4088727b1c535 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Tue, 1 Nov 2022 10:48:03 -0400 Subject: [PATCH 040/206] gravition abi test pytest mark parameterized --- pyteal/ast/frame.py | 1 - pyteal/ast/frame_test.py | 3 -- tests/integration/graviton_abi_test.py | 66 +++++++++++++------------- 3 files changed, 32 insertions(+), 38 deletions(-) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index cca2f6447..1fe9d9c88 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -85,7 +85,6 @@ def has_return(self) -> bool: class FrameBury(Expr): def __init__(self, what: Expr, depth: int): super().__init__() - require_type(what, TealType.anytype) self.what = what self.depth = depth diff --git a/pyteal/ast/frame_test.py b/pyteal/ast/frame_test.py index b21b47d0e..c1cf5edd1 100644 --- a/pyteal/ast/frame_test.py +++ b/pyteal/ast/frame_test.py @@ -70,9 +70,6 @@ def test_frame_bury(): def test_frame_bury_invalid(): - with pytest.raises(pt.TealTypeError): - pt.FrameBury(pt.Seq(), 1) - with pytest.raises(pt.TealInputError): pt.FrameBury(pt.Int(1), 1).__teal__(avm7Options) diff --git a/tests/integration/graviton_abi_test.py b/tests/integration/graviton_abi_test.py index 5927589d1..0806ee96e 100644 --- a/tests/integration/graviton_abi_test.py +++ b/tests/integration/graviton_abi_test.py @@ -1,4 +1,5 @@ import random +import pytest from graviton.blackbox import DryRunInspector @@ -299,7 +300,8 @@ def conditional_factorial(_factor: pt.abi.Uint64, *, output: pt.abi.Uint64) -> p # ---- integration test functions ---- # -def test_integer65(): +@pytest.mark.parametrize("version", [6, 8]) +def test_integer65(version: int): bbpt_subtract_slick = PyTealDryRunExecutor(int65_sub, pt.Mode.Application) bbpt_subtract_cond = PyTealDryRunExecutor(int65_minus_cond, pt.Mode.Application) @@ -329,7 +331,7 @@ def pytuple_to_num(t): ] def binary_dryrun(p: PyTealDryRunExecutor) -> list[DryRunInspector]: - return p.dryrun_on_sequence(binary_inputs) + return p.dryrun_on_sequence(binary_inputs, compiler_version=version) # type: ignore # Binary: inspectors_subtract_slick = binary_dryrun(bbpt_subtract_slick) @@ -341,7 +343,9 @@ def binary_dryrun(p: PyTealDryRunExecutor) -> list[DryRunInspector]: inspectors_add = binary_dryrun(bbpt_add) # Unary: - inspectors_negate = bbpt_negate.dryrun_on_sequence(unary_inputs) + inspectors_negate = bbpt_negate.dryrun_on_sequence( + unary_inputs, compiler_version=version # type: ignore + ) for i in range(N): binary_args = binary_inputs[i] @@ -382,7 +386,8 @@ def binary_dryrun(p: PyTealDryRunExecutor) -> list[DryRunInspector]: ), inspector_negate.report(unary_args, f"failed for {unary_args}", row=i) -def test_complex130(): +@pytest.mark.parametrize("version", [6, 8]) +def test_complex130(version: int): # Binary: bbpt_cplx_add = PyTealDryRunExecutor(complex130_add, pt.Mode.Application) @@ -438,16 +443,12 @@ def pytuple_to_complex(tt): ] # Binary: - def binary_dryrun( - p: PyTealDryRunExecutor, _version: int = 6 - ) -> list[DryRunInspector]: - return p.dryrun_on_sequence(binary_inputs, compiler_version=_version) + def binary_dryrun(p: PyTealDryRunExecutor) -> list[DryRunInspector]: + return p.dryrun_on_sequence(binary_inputs, compiler_version=version) # type: ignore # Unary: - def unary_dryrun( - p: PyTealDryRunExecutor, _version: int = 6 - ) -> list[DryRunInspector]: - return p.dryrun_on_sequence(unary_inputs, compiler_version=_version) + def unary_dryrun(p: PyTealDryRunExecutor) -> list[DryRunInspector]: + return p.dryrun_on_sequence(unary_inputs, compiler_version=version) # type: ignore inspectors_cplx_add = binary_dryrun(bbpt_cplx_add) @@ -517,29 +518,26 @@ def py_factorial(n): return 1 if n <= 1 else n * py_factorial(n - 1) -def test_conditional_factorial(): +@pytest.mark.parametrize("version", [6, 8]) +def test_conditional_factorial(version: int): ptdre = PyTealDryRunExecutor(conditional_factorial, pt.Mode.Application) inputs = [(n,) for n in range(20)] - def dryrun_on_version(_version: int): - inspectors = ptdre.dryrun_on_sequence(inputs, compiler_version=_version) - for i, args in enumerate(inputs): - inspector = inspectors[i] - n = args[0] - assert inspector.passed(), inspector.report(args, row=i + 1) - - expected = py_factorial(n) - assert expected == inspector.last_log(), inspector.report(args, row=i + 1) - - n = 21 - args = (n,) - inspector = ptdre.dryrun(args) - assert inspector.rejected(), inspector.report( - args, f"FAILED: should have rejected for {n=}", row=n + 1 - ) - assert inspector.error(), inspector.report( - args, f"FAILED: should error for {n=}", row=n + 1 - ) + inspectors = ptdre.dryrun_on_sequence(inputs, compiler_version=version) # type: ignore + for i, args in enumerate(inputs): + inspector = inspectors[i] + n = args[0] + assert inspector.passed(), inspector.report(args, row=i + 1) - dryrun_on_version(6) - dryrun_on_version(8) + expected = py_factorial(n) + assert expected == inspector.last_log(), inspector.report(args, row=i + 1) + + n = 21 + args = (n,) + inspector = ptdre.dryrun(args) + assert inspector.rejected(), inspector.report( + args, f"FAILED: should have rejected for {n=}", row=n + 1 + ) + assert inspector.error(), inspector.report( + args, f"FAILED: should error for {n=}", row=n + 1 + ) From 6ba772a69721fe43409a7fa03f8235741dd38d8b Mon Sep 17 00:00:00 2001 From: Hang Su Date: Tue, 1 Nov 2022 11:31:04 -0400 Subject: [PATCH 041/206] module --- pyteal/ast/abi/type.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index c505021c0..e1475166c 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -79,7 +79,7 @@ def storage_type(self) -> TealType: pass -DataStorageSchema.__module__ = "pyteal" +DataStorageSchema.__module__ = "pyteal.abi" class ScratchStorage(DataStorageSchema): @@ -97,7 +97,7 @@ def storage_type(self) -> TealType: return self.scratchvar.storage_type() -ScratchStorage.__module__ = "pyteal" +ScratchStorage.__module__ = "pyteal.abi" class FrameStorage(DataStorageSchema): @@ -120,7 +120,7 @@ def load_value(self) -> Expr: return FrameDig(self.stack_depth) -FrameStorage.__module__ = "pyteal" +FrameStorage.__module__ = "pyteal.abi" class BaseType(ABC): From 5840a8bb772416254c3ab8cc5cc11c5278912e02 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Tue, 1 Nov 2022 14:19:15 -0400 Subject: [PATCH 042/206] per review comments --- pyteal/ast/frame.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 8b1cb6080..5799ef90b 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -10,14 +10,18 @@ class Proto(Expr): - def __init__(self, arg_num: int, ret_num: int): + def __init__(self, num_args: int, num_returns: int): super().__init__() - if arg_num < 0: - raise TealInputError(f"subroutine arg number {arg_num} must be >= 0") - if ret_num < 0: - raise TealInputError(f"return value number {ret_num} must be >= 0") - self.arg_num = arg_num - self.ret_num = ret_num + if num_args < 0: + raise TealInputError( + f"the number of arguments provided to Proto must be >= 0 but {num_args=}" + ) + if num_returns < 0: + raise TealInputError( + f"the number of return values provided to Proto must be >= 0 but {num_returns=}" + ) + self.num_args = num_args + self.num_returns = num_returns def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: verifyProgramVersion( @@ -25,11 +29,11 @@ def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBloc options.version, "Program version too low to use op proto", ) - op = TealOp(self, Op.proto, self.arg_num, self.ret_num) + op = TealOp(self, Op.proto, self.num_args, self.num_returns) return TealBlock.FromOp(options, op) def __str__(self) -> str: - return f"(proto: arg_num = {self.arg_num}, ret_num = {self.ret_num})" + return f"(proto: num_args = {self.num_args}, num_returns = {self.num_returns})" def type_of(self) -> TealType: return TealType.none From a596fc15472029b2445f6e7351c4c18bdbb9a616 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 08:42:32 -0400 Subject: [PATCH 043/206] per review comments --- pyteal/ast/frame.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 5799ef90b..7334a39b6 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -73,10 +73,10 @@ def has_return(self) -> bool: class FrameBury(Expr): - def __init__(self, what: Expr, depth: int): + def __init__(self, value: Expr, depth: int): super().__init__() - require_type(what, TealType.anytype) - self.what = what + require_type(value, TealType.anytype) + self.value = value self.depth = depth def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: @@ -86,10 +86,10 @@ def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBloc "Program version too low to use op frame_bury", ) op = TealOp(self, Op.frame_bury, self.depth) - return TealBlock.FromOp(options, op, self.what) + return TealBlock.FromOp(options, op, self.value) def __str__(self) -> str: - return f"(frame_bury (bury_depth = {self.depth}) ({self.what}))" + return f"(frame_bury (bury_depth = {self.depth}) ({self.value}))" def type_of(self) -> TealType: return TealType.none @@ -102,12 +102,12 @@ def has_return(self) -> bool: class Bury(Expr): - def __init__(self, what: Expr, depth: int): + def __init__(self, value: Expr, depth: int): super().__init__() - require_type(what, TealType.anytype) + require_type(value, TealType.anytype) if depth <= 0: raise TealInputError("bury depth should be strictly positive") - self.what = what + self.value = value self.depth = depth def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: @@ -117,10 +117,10 @@ def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBloc "Program version too low to use op bury", ) op = TealOp(self, Op.bury, self.depth) - return TealBlock.FromOp(options, op, self.what) + return TealBlock.FromOp(options, op, self.value) def __str__(self) -> str: - return f"(bury (depth = {self.depth}) ({self.what}))" + return f"(bury (depth = {self.depth}) ({self.value}))" def type_of(self) -> TealType: return TealType.none @@ -133,12 +133,12 @@ def has_return(self) -> bool: class DupN(Expr): - def __init__(self, what: Expr, repetition: int): + def __init__(self, value: Expr, repetition: int): super().__init__() - require_type(what, TealType.anytype) + require_type(value, TealType.anytype) if repetition < 0: raise TealInputError("dupn repetition should be non negative") - self.what = what + self.value = value self.repetition = repetition def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: @@ -148,13 +148,13 @@ def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBloc "Program version too low to use op dupn", ) op = TealOp(self, Op.dupn, self.repetition) - return TealBlock.FromOp(options, op, self.what) + return TealBlock.FromOp(options, op, self.value) def __str__(self) -> str: - return f"(dupn (repetition = {self.repetition}) ({self.what}))" + return f"(dupn (repetition = {self.repetition}) ({self.value}))" def type_of(self) -> TealType: - return self.what.type_of() + return self.value.type_of() def has_return(self) -> bool: return False From 519c7528b6f301d077bf3133ba41f6dab1d06e74 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 08:46:45 -0400 Subject: [PATCH 044/206] per review comments, depth -> frame_depth --- pyteal/ast/frame.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 7334a39b6..68ce3a2f2 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -46,9 +46,9 @@ def has_return(self) -> bool: class FrameDig(Expr): - def __init__(self, depth: int): + def __init__(self, frame_index: int): super().__init__() - self.depth = depth + self.frame_index = frame_index def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: verifyProgramVersion( @@ -56,11 +56,11 @@ def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBloc options.version, "Program version too low to use op frame_dig", ) - op = TealOp(self, Op.frame_dig, self.depth) + op = TealOp(self, Op.frame_dig, self.frame_index) return TealBlock.FromOp(options, op) def __str__(self) -> str: - return f"(frame_dig: dig_depth = {self.depth})" + return f"(frame_dig: dig_from = {self.frame_index})" def type_of(self) -> TealType: return TealType.anytype @@ -73,11 +73,11 @@ def has_return(self) -> bool: class FrameBury(Expr): - def __init__(self, value: Expr, depth: int): + def __init__(self, value: Expr, frame_index: int): super().__init__() require_type(value, TealType.anytype) self.value = value - self.depth = depth + self.frame_index = frame_index def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: verifyProgramVersion( @@ -85,11 +85,11 @@ def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBloc options.version, "Program version too low to use op frame_bury", ) - op = TealOp(self, Op.frame_bury, self.depth) + op = TealOp(self, Op.frame_bury, self.frame_index) return TealBlock.FromOp(options, op, self.value) def __str__(self) -> str: - return f"(frame_bury (bury_depth = {self.depth}) ({self.value}))" + return f"(frame_bury (bury_to = {self.frame_index}) ({self.value}))" def type_of(self) -> TealType: return TealType.none From 48d06786aa53ff2b65aa57008ab43c2584420ddb Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 09:05:09 -0400 Subject: [PATCH 045/206] per review comments, on final type annotation --- pyteal/ast/abi/type.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index c505021c0..dfaa9bd16 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -85,7 +85,7 @@ def storage_type(self) -> TealType: class ScratchStorage(DataStorageSchema): def __init__(self, storage_type: TealType) -> None: super().__init__() - self.scratchvar: Final = ScratchVar(storage_type) + self.scratchvar: Final[ScratchVar] = ScratchVar(storage_type) def load_value(self) -> Expr: return self.scratchvar.load() @@ -134,7 +134,7 @@ class BaseType(ABC): def __init__(self, spec: TypeSpec) -> None: """Create a new BaseType.""" super().__init__() - self._type_spec: Final = spec + self._type_spec: Final[TypeSpec] = spec self._data_storage: DataStorageSchema = ScratchStorage(spec.storage_type()) # self.stored_value: Final = ScratchVar(spec.storage_type()) From 7d4277b5cfb64317bd5253dcd7f96eee64fdfb78 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 09:33:35 -0400 Subject: [PATCH 046/206] per review comments, renaem to AbstractVar/FrameVar --- pyteal/ast/abi/__init__.py | 4 ++-- pyteal/ast/abi/address.py | 15 +++++-------- pyteal/ast/abi/address_test.py | 2 +- pyteal/ast/abi/array_base.py | 6 ++--- pyteal/ast/abi/array_dynamic.py | 6 ++--- pyteal/ast/abi/array_dynamic_test.py | 4 ++-- pyteal/ast/abi/array_static.py | 10 ++++----- pyteal/ast/abi/array_static_test.py | 4 ++-- pyteal/ast/abi/bool.py | 8 +++---- pyteal/ast/abi/reference_type.py | 6 ++--- pyteal/ast/abi/reference_type_test.py | 2 +- pyteal/ast/abi/string.py | 24 ++++++++------------ pyteal/ast/abi/string_test.py | 2 +- pyteal/ast/abi/transaction.py | 8 +++---- pyteal/ast/abi/tuple.py | 6 ++--- pyteal/ast/abi/tuple_test.py | 4 ++-- pyteal/ast/abi/type.py | 30 ++++++++++++------------- pyteal/ast/abi/type_test.py | 2 +- pyteal/ast/abi/uint.py | 32 +++++++++++++-------------- pyteal/ast/abi/uint_test.py | 2 +- pyteal/ast/subroutine.py | 4 ++-- 21 files changed, 85 insertions(+), 96 deletions(-) diff --git a/pyteal/ast/abi/__init__.py b/pyteal/ast/abi/__init__.py index 3ca3ab290..4baa3bc16 100644 --- a/pyteal/ast/abi/__init__.py +++ b/pyteal/ast/abi/__init__.py @@ -9,7 +9,7 @@ BaseType, ComputedValue, ReturnedValue, - DataStorageSchema, + AbstractVar, FrameStorage, ScratchStorage, ) @@ -174,7 +174,7 @@ "type_specs_from_signature", "make", "size_of", - "DataStorageSchema", + "AbstractVar", "FrameStorage", "ScratchStorage", "algosdk_from_annotation", diff --git a/pyteal/ast/abi/address.py b/pyteal/ast/abi/address.py index 3165fcd9a..0fea62c8a 100644 --- a/pyteal/ast/abi/address.py +++ b/pyteal/ast/abi/address.py @@ -56,7 +56,7 @@ def get(self) -> Expr: The expression will have the type TealType.bytes. """ - return self._data_storage.load_value() + return self._data_storage.load() def set( self, @@ -108,28 +108,25 @@ def set( or value.type_spec() == StaticArrayTypeSpec(ByteTypeSpec(), AddressLength.Bytes) ): - return self._data_storage.store_value( - value._data_storage.load_value() - ) + return self._data_storage.store(value._data_storage.load()) raise TealInputError( f"Got {value} with type spec {value.type_spec()}, expected AddressTypeSpec" ) case str(): # Addr throws if value is invalid address - return self._data_storage.store_value(Addr(value)) + return self._data_storage.store(Addr(value)) case bytes(): if len(value) == AddressLength.Bytes: - return self._data_storage.store_value(Bytes(value)) + return self._data_storage.store(Bytes(value)) raise TealInputError( f"Got bytes with length {len(value)}, expected {AddressLength.Bytes}" ) case Expr(): return Seq( - self._data_storage.store_value(value), + self._data_storage.store(value), Assert( - Len(self._data_storage.load_value()) - == Int(AddressLength.Bytes.value) + Len(self._data_storage.load()) == Int(AddressLength.Bytes.value) ), ) case CollectionSequence(): diff --git a/pyteal/ast/abi/address_test.py b/pyteal/ast/abi/address_test.py index dca9136dc..ccecb0ecf 100644 --- a/pyteal/ast/abi/address_test.py +++ b/pyteal/ast/abi/address_test.py @@ -86,7 +86,7 @@ def test_Address_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expectedExpr = value._data_storage.store_value( + expectedExpr = value._data_storage.store( substring_for_decoding( encoded, start_index=start_index, diff --git a/pyteal/ast/abi/array_base.py b/pyteal/ast/abi/array_base.py index 4674f1d90..417e401e1 100644 --- a/pyteal/ast/abi/array_base.py +++ b/pyteal/ast/abi/array_base.py @@ -104,7 +104,7 @@ def decode( extracted = substring_for_decoding( encoded, start_index=start_index, end_index=end_index, length=length ) - return self._data_storage.store_value(extracted) + return self._data_storage.store(extracted) def set(self, values: Sequence[T]) -> Expr: """Set the ABI array with a sequence of ABI type variables. @@ -142,7 +142,7 @@ def set(self, values: Sequence[T]) -> Expr: length_prefix = Seq(length_tmp.set(len(values)), length_tmp.encode()) encoded = Concat(length_prefix, encoded) - return self._data_storage.store_value(encoded) + return self._data_storage.store(encoded) def encode(self) -> Expr: """Encode the ABI array to be a byte string. @@ -150,7 +150,7 @@ def encode(self) -> Expr: Returns: A PyTeal expression that encodes this ABI array to a byte string. """ - return self._data_storage.load_value() + return self._data_storage.load() @abstractmethod def length(self) -> Expr: diff --git a/pyteal/ast/abi/array_dynamic.py b/pyteal/ast/abi/array_dynamic.py index 2a5f7367d..a39373324 100644 --- a/pyteal/ast/abi/array_dynamic.py +++ b/pyteal/ast/abi/array_dynamic.py @@ -79,7 +79,7 @@ def set( raise TealInputError( f"Cannot assign type {values.type_spec()} to {self.type_spec()}" ) - return self._data_storage.store_value(values.encode()) + return self._data_storage.store(values.encode()) return super().set(values) def length(self) -> Expr: @@ -165,7 +165,7 @@ def set( match values: case bytes() | bytearray(): - return self._data_storage.store_value(_encoded_byte_string(values)) + return self._data_storage.store(_encoded_byte_string(values)) case Expr(): return _store_encoded_expr_byte_string_into_var( values, self._data_storage @@ -181,7 +181,7 @@ def get(self) -> Expr: Returns: A Pyteal expression that loads byte encoding of this DynamicBytes, and drop the first uint16 DynamicArray length encoding. """ - return Suffix(self._data_storage.load_value(), Int(2)) + return Suffix(self._data_storage.load(), Int(2)) DynamicBytes.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/array_dynamic_test.py b/pyteal/ast/abi/array_dynamic_test.py index 3e172eeee..589d52664 100644 --- a/pyteal/ast/abi/array_dynamic_test.py +++ b/pyteal/ast/abi/array_dynamic_test.py @@ -106,7 +106,7 @@ def test_DynamicArray_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value._data_storage.store_value( + expectedExpr = value._data_storage.store( substring_for_decoding( encoded, start_index=start_index, @@ -141,7 +141,7 @@ def test_DynamicArray_set_values(): assert not expr.has_return() length_tmp = abi.Uint16() - expectedExpr = value._data_storage.store_value( + expectedExpr = value._data_storage.store( pt.Concat( pt.Seq(length_tmp.set(len(values)), length_tmp.encode()), _encode_tuple(values), diff --git a/pyteal/ast/abi/array_static.py b/pyteal/ast/abi/array_static.py index caf2dcc88..a631687f3 100644 --- a/pyteal/ast/abi/array_static.py +++ b/pyteal/ast/abi/array_static.py @@ -109,7 +109,7 @@ def set( raise TealInputError( f"Cannot assign type {values.type_spec()} to {self.type_spec()}" ) - return self._data_storage.store_value(values.encode()) + return self._data_storage.store(values.encode()) if self.type_spec().length_static() != len(values): raise TealInputError( @@ -207,11 +207,11 @@ def set( raise TealInputError( f"Got bytes with length {len(values)}, expect {self.type_spec().length_static()}" ) - return self._data_storage.store_value(Bytes(values)) + return self._data_storage.store(Bytes(values)) case Expr(): return Seq( - self._data_storage.store_value(values), - Assert(self.length() == Len(self._data_storage.load_value())), + self._data_storage.store(values), + Assert(self.length() == Len(self._data_storage.load())), ) return super().set(values) @@ -222,7 +222,7 @@ def get(self) -> Expr: Returns: A Pyteal expression that loads byte encoding of this StaticBytes. """ - return self._data_storage.load_value() + return self._data_storage.load() StaticBytes.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/array_static_test.py b/pyteal/ast/abi/array_static_test.py index 7d0a8ae0a..7174c2ebb 100644 --- a/pyteal/ast/abi/array_static_test.py +++ b/pyteal/ast/abi/array_static_test.py @@ -159,7 +159,7 @@ def test_StaticArray_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value._data_storage.store_value( + expectedExpr = value._data_storage.store( substring_for_decoding( encoded, start_index=start_index, @@ -202,7 +202,7 @@ def test_StaticArray_set_values(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value._data_storage.store_value(_encode_tuple(values)) + expectedExpr = value._data_storage.store(_encode_tuple(values)) expected, _ = expectedExpr.__teal__(options) expected.addIncoming() expected = pt.TealBlock.NormalizeBlocks(expected) diff --git a/pyteal/ast/abi/bool.py b/pyteal/ast/abi/bool.py index 2bfbd3aca..6d42c2fdd 100644 --- a/pyteal/ast/abi/bool.py +++ b/pyteal/ast/abi/bool.py @@ -50,7 +50,7 @@ def get(self) -> Expr: expression that evaluates to 0 will be returned. In either case, the expression will have the type TealType.uint64. """ - return self._data_storage.load_value() + return self._data_storage.load() def set(self, value: Union[bool, Expr, "Bool", ComputedValue["Bool"]]) -> Expr: """Set the value of this Bool to the input value. @@ -85,10 +85,10 @@ def set(self, value: Union[bool, Expr, "Bool", ComputedValue["Bool"]]) -> Expr: checked = True if checked: - return self._data_storage.store_value(value) + return self._data_storage.store(value) # Not(Not(value)) coerces all values greater than 0 to 1 - return self._data_storage.store_value(Not(Not(value))) + return self._data_storage.store(Not(Not(value))) def decode( self, @@ -103,7 +103,7 @@ def decode( return self.decode_bit(encoded, start_index * Int(NUM_BITS_IN_BYTE)) def decode_bit(self, encoded, bit_index: Expr) -> Expr: - return self._data_storage.store_value(GetBit(encoded, bit_index)) + return self._data_storage.store(GetBit(encoded, bit_index)) def encode(self) -> Expr: return SetBit(Bytes(b"\x00"), Int(0), self.get()) diff --git a/pyteal/ast/abi/reference_type.py b/pyteal/ast/abi/reference_type.py index 2ea723b92..aa0709ffe 100644 --- a/pyteal/ast/abi/reference_type.py +++ b/pyteal/ast/abi/reference_type.py @@ -58,7 +58,7 @@ def referenced_index(self) -> Expr: If this reference type is an application or asset, note that this DOES NOT return the application or asset ID. See :code:`application_id()` or :code:`asset_id()` for that. """ - return self._data_storage.load_value() + return self._data_storage.load() def decode( self, @@ -107,7 +107,7 @@ def __init__(self) -> None: def address(self) -> Expr: """Get the address of the account.""" - return Txn.accounts[self._data_storage.load_value()] + return Txn.accounts[self._data_storage.load()] def params(self) -> AccountParamObject: """Get information about the account.""" @@ -205,7 +205,7 @@ def __init__(self) -> None: def application_id(self) -> Expr: """Get the ID of the application.""" - return Txn.applications[self._data_storage.load_value()] + return Txn.applications[self._data_storage.load()] def params(self) -> AppParamObject: """Get information about the application's parameters.""" diff --git a/pyteal/ast/abi/reference_type_test.py b/pyteal/ast/abi/reference_type_test.py index d3b8aaf93..edc0a857c 100644 --- a/pyteal/ast/abi/reference_type_test.py +++ b/pyteal/ast/abi/reference_type_test.py @@ -61,7 +61,7 @@ def test_ReferenceType_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expected_decoding = value._data_storage.store_value( + expected_decoding = value._data_storage.store( pt.GetByte( encoded, start_index if start_index is not None else pt.Int(0), diff --git a/pyteal/ast/abi/string.py b/pyteal/ast/abi/string.py index 0359aee76..f91eb272f 100644 --- a/pyteal/ast/abi/string.py +++ b/pyteal/ast/abi/string.py @@ -4,7 +4,7 @@ from algosdk.abi import ABIType from pyteal.ast.abi.uint import Byte -from pyteal.ast.abi.type import ComputedValue, BaseType, DataStorageSchema +from pyteal.ast.abi.type import ComputedValue, BaseType, AbstractVar from pyteal.ast.abi.array_dynamic import DynamicArray, DynamicArrayTypeSpec from pyteal.ast.abi.uint import ByteTypeSpec, Uint16TypeSpec @@ -25,14 +25,12 @@ def _encoded_byte_string(s: bytes | bytearray) -> Expr: def _store_encoded_expr_byte_string_into_var( - value: Expr, location: DataStorageSchema + value: Expr, location: AbstractVar ) -> Expr: return Seq( - location.store_value(value), - location.store_value( - Concat( - Suffix(Itob(Len(location.load_value())), Int(6)), location.load_value() - ) + location.store(value), + location.store( + Concat(Suffix(Itob(Len(location.load())), Int(6)), location.load()) ), ) @@ -70,7 +68,7 @@ def get(self) -> Expr: The expression will have the type TealType.bytes. """ return Suffix( - self._data_storage.load_value(), Int(Uint16TypeSpec().byte_length_static()) + self._data_storage.load(), Int(Uint16TypeSpec().byte_length_static()) ) def set( @@ -113,19 +111,15 @@ def set( if value.type_spec() == StringTypeSpec() or ( value.type_spec() == DynamicArrayTypeSpec(ByteTypeSpec()) ): - return self._data_storage.store_value( - value._data_storage.load_value() - ) + return self._data_storage.store(value._data_storage.load()) raise TealInputError( f"Got {value} with type spec {value.type_spec()}, expected {StringTypeSpec}" ) case bytes() | bytearray(): - return self._data_storage.store_value(_encoded_byte_string(value)) + return self._data_storage.store(_encoded_byte_string(value)) case str(): - return self._data_storage.store_value( - _encoded_byte_string(value.encode()) - ) + return self._data_storage.store(_encoded_byte_string(value.encode())) case Expr(): return _store_encoded_expr_byte_string_into_var( value, self._data_storage diff --git a/pyteal/ast/abi/string_test.py b/pyteal/ast/abi/string_test.py index fb8de7fb9..e335da1a1 100644 --- a/pyteal/ast/abi/string_test.py +++ b/pyteal/ast/abi/string_test.py @@ -76,7 +76,7 @@ def test_DynamicArray_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expectedExpr = value._data_storage.store_value( + expectedExpr = value._data_storage.store( substring_for_decoding( encoded, start_index=start_index, diff --git a/pyteal/ast/abi/transaction.py b/pyteal/ast/abi/transaction.py index 2451a1285..1f3ea9ba2 100644 --- a/pyteal/ast/abi/transaction.py +++ b/pyteal/ast/abi/transaction.py @@ -82,16 +82,16 @@ def _set_index( case ComputedValue(): return self._set_with_computed_type(value) case BaseType(): - return self._data_storage.store_value(self._data_storage.load_value()) + return self._data_storage.store(self._data_storage.load()) case int(): - return self._data_storage.store_value(Int(value)) + return self._data_storage.store(Int(value)) case Expr(): - return self._data_storage.store_value(value) + return self._data_storage.store(value) case _: raise TealInputError(f"Cant store a {type(value)} in a Transaction") def index(self) -> Expr: - return self._data_storage.load_value() + return self._data_storage.load() def decode( self, diff --git a/pyteal/ast/abi/tuple.py b/pyteal/ast/abi/tuple.py index 2f2dceeab..efea10e36 100644 --- a/pyteal/ast/abi/tuple.py +++ b/pyteal/ast/abi/tuple.py @@ -309,7 +309,7 @@ def decode( extracted = substring_for_decoding( encoded, start_index=start_index, end_index=end_index, length=length ) - return self._data_storage.store_value(extracted) + return self._data_storage.store(extracted) @overload def set(self, *values: BaseType) -> Expr: @@ -352,10 +352,10 @@ def set(self, *values): ) if not all(myTypes[i] == values[i].type_spec() for i in range(len(myTypes))): raise TealInputError("Input values do not match type") - return self._data_storage.store_value(_encode_tuple(values)) + return self._data_storage.store(_encode_tuple(values)) def encode(self) -> Expr: - return self._data_storage.load_value() + return self._data_storage.load() def length(self) -> Expr: """Get the number of values this tuple holds as an Expr.""" diff --git a/pyteal/ast/abi/tuple_test.py b/pyteal/ast/abi/tuple_test.py index 777d3688e..ad231784f 100644 --- a/pyteal/ast/abi/tuple_test.py +++ b/pyteal/ast/abi/tuple_test.py @@ -623,7 +623,7 @@ def test_Tuple_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = tupleValue._data_storage.store_value( + expectedExpr = tupleValue._data_storage.store( substring_for_decoding( encoded, start_index=start_index, @@ -672,7 +672,7 @@ def test_Tuple_set(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = tupleValue._data_storage.store_value( + expectedExpr = tupleValue._data_storage.store( _encode_tuple([uint8, uint16, uint32]) ) expected, _ = expectedExpr.__teal__(options) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index dfaa9bd16..3ae5d585c 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -65,13 +65,13 @@ def __str__(self) -> str: TypeSpec.__module__ = "pyteal.abi" -class DataStorageSchema(ABC): +class AbstractVar(ABC): @abstractmethod - def store_value(self, value: Expr) -> Expr: + def store(self, value: Expr) -> Expr: pass @abstractmethod - def load_value(self) -> Expr: + def load(self) -> Expr: pass @abstractmethod @@ -79,18 +79,18 @@ def storage_type(self) -> TealType: pass -DataStorageSchema.__module__ = "pyteal" +AbstractVar.__module__ = "pyteal" -class ScratchStorage(DataStorageSchema): +class ScratchStorage(AbstractVar): def __init__(self, storage_type: TealType) -> None: super().__init__() self.scratchvar: Final[ScratchVar] = ScratchVar(storage_type) - def load_value(self) -> Expr: + def load(self) -> Expr: return self.scratchvar.load() - def store_value(self, value: Expr) -> Expr: + def store(self, value: Expr) -> Expr: return self.scratchvar.slot.store(value) def storage_type(self) -> TealType: @@ -100,7 +100,7 @@ def storage_type(self) -> TealType: ScratchStorage.__module__ = "pyteal" -class FrameStorage(DataStorageSchema): +class FrameStorage(AbstractVar): def __init__(self, storage_type: TealType, stack_depth: int) -> None: super().__init__() self.stack_type = storage_type @@ -109,12 +109,12 @@ def __init__(self, storage_type: TealType, stack_depth: int) -> None: def storage_type(self) -> TealType: return self.stack_type - def store_value(self, value: Expr) -> Expr: + def store(self, value: Expr) -> Expr: from pyteal.ast import FrameBury return FrameBury(value, self.stack_depth) - def load_value(self) -> Expr: + def load(self) -> Expr: from pyteal.ast import FrameDig return FrameDig(self.stack_depth) @@ -135,18 +135,18 @@ def __init__(self, spec: TypeSpec) -> None: """Create a new BaseType.""" super().__init__() self._type_spec: Final[TypeSpec] = spec - self._data_storage: DataStorageSchema = ScratchStorage(spec.storage_type()) + self._data_storage: AbstractVar = ScratchStorage(spec.storage_type()) # self.stored_value: Final = ScratchVar(spec.storage_type()) - def _set_data_source(self, storage: DataStorageSchema) -> None: + def _set_data_source(self, storage: AbstractVar) -> None: self._data_storage = storage def _load_value(self) -> Expr: - return self._data_storage.load_value() + return self._data_storage.load() def _store_value(self, value: Expr) -> Expr: - return self._data_storage.store_value(value) + return self._data_storage.store(value) def type_spec(self) -> TypeSpec: """Get the TypeSpec for this ABI type instance.""" @@ -300,7 +300,7 @@ def store_into(self, output: BaseType) -> Expr: f"ABI return subroutine deferred_expr is expected to be typed {output.type_spec().storage_type()}, " f"but has type {declaration.deferred_expr.type_of()}." ) - return output._data_storage.store_value(self.computation) + return output._data_storage.store(self.computation) ReturnedValue.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/type_test.py b/pyteal/ast/abi/type_test.py index b5134ef7d..30f39e0fc 100644 --- a/pyteal/ast/abi/type_test.py +++ b/pyteal/ast/abi/type_test.py @@ -17,7 +17,7 @@ def store_into(self, output: abi.BaseType) -> pt.Expr: raise pt.TealInputError( f"expected type_spec {self.type_spec} but get {output.type_spec()}" ) - return output._data_storage.store_value(self.encodings) + return output._data_storage.store(self.encodings) def test_ComputedType_use(): diff --git a/pyteal/ast/abi/uint.py b/pyteal/ast/abi/uint.py index e34daac9a..67d3ff428 100644 --- a/pyteal/ast/abi/uint.py +++ b/pyteal/ast/abi/uint.py @@ -17,7 +17,7 @@ from pyteal.ast.unaryexpr import Itob, Btoi from pyteal.ast.binaryexpr import GetByte, ExtractUint16, ExtractUint32, ExtractUint64 from pyteal.ast.ternaryexpr import SetByte -from pyteal.ast.abi.type import ComputedValue, TypeSpec, BaseType, DataStorageSchema +from pyteal.ast.abi.type import ComputedValue, TypeSpec, BaseType, AbstractVar NUM_BITS_IN_BYTE = 8 @@ -30,9 +30,7 @@ def uint_storage_type(size: int) -> TealType: return TealType.bytes -def uint_set( - size: int, uint_var: DataStorageSchema, value: Union[int, Expr, "Uint"] -) -> Expr: +def uint_set(size: int, uint_var: AbstractVar, value: Union[int, Expr, "Uint"]) -> Expr: if size > 64: raise NotImplementedError( "Uint operations have not yet been implemented for bit sizes larger than 64" @@ -50,17 +48,17 @@ def uint_set( checked = True if checked or size == 64: - return uint_var.store_value(cast(Expr, value)) + return uint_var.store(cast(Expr, value)) return Seq( - uint_var.store_value(cast(Expr, value)), - Assert(uint_var.load_value() < Int(2**size)), + uint_var.store(cast(Expr, value)), + Assert(uint_var.load() < Int(2**size)), ) def uint_decode( size: int, - uint_var: DataStorageSchema, + uint_var: AbstractVar, encoded: Expr, start_index: Optional[Expr], end_index: Optional[Expr], @@ -74,27 +72,27 @@ def uint_decode( if size == 64: if start_index is None: if end_index is None and length is None: - return uint_var.store_value(Btoi(encoded)) + return uint_var.store(Btoi(encoded)) start_index = Int(0) - return uint_var.store_value(ExtractUint64(encoded, start_index)) + return uint_var.store(ExtractUint64(encoded, start_index)) if start_index is None: start_index = Int(0) if size == 8: - return uint_var.store_value(GetByte(encoded, start_index)) + return uint_var.store(GetByte(encoded, start_index)) if size == 16: - return uint_var.store_value(ExtractUint16(encoded, start_index)) + return uint_var.store(ExtractUint16(encoded, start_index)) if size == 32: - return uint_var.store_value(ExtractUint32(encoded, start_index)) + return uint_var.store(ExtractUint32(encoded, start_index)) raise ValueError("Unsupported uint size: {}".format(size)) -def uint_encode(size: int, uint_var: Expr | DataStorageSchema) -> Expr: +def uint_encode(size: int, uint_var: Expr | AbstractVar) -> Expr: - if isinstance(uint_var, DataStorageSchema): - uint_var = uint_var.load_value() + if isinstance(uint_var, AbstractVar): + uint_var = uint_var.load() if size > 64: raise NotImplementedError( @@ -241,7 +239,7 @@ def get(self) -> Expr: The expression will have the type TealType.uint64. """ - return self._data_storage.load_value() + return self._data_storage.load() def set(self, value: Union[int, Expr, "Uint", ComputedValue["Uint"]]) -> Expr: """Set the value of this Uint to the input value. diff --git a/pyteal/ast/abi/uint_test.py b/pyteal/ast/abi/uint_test.py index d4b7cd137..d571e7aa6 100644 --- a/pyteal/ast/abi/uint_test.py +++ b/pyteal/ast/abi/uint_test.py @@ -307,7 +307,7 @@ def test_Uint_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedDecoding = value._data_storage.store_value( + expectedDecoding = value._data_storage.store( test.expectedDecoding(encoded, start_index, end_index, length) ) expected, _ = expectedDecoding.__teal__(options) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 70365d756..d509f980b 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -420,7 +420,7 @@ def handle_arg(arg: Expr | ScratchVar | abi.BaseType) -> Expr: elif isinstance(arg, Expr): return arg elif isinstance(arg, abi.BaseType): - return arg._data_storage.load_value() + return arg._data_storage.load() else: raise TealInputError( f"cannot handle current arg: {arg} to put it on stack" @@ -853,7 +853,7 @@ def var_n_loaded( f"ABI returning subroutine definition should evaluate to TealType.none, " f"while evaluate to {subroutine_body.type_of()}." ) - deferred_expr = output_carrying_abi._data_storage.load_value() + deferred_expr = output_carrying_abi._data_storage.load() # Arg usage "A" to be pick up and store in scratch parameters that have been placed on the stack # need to reverse order of argumentVars because the last argument will be on top of the stack From d93207d84a0c55983903b8947dda5e345d7030fb Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 10:42:18 -0400 Subject: [PATCH 047/206] per review comments, move storage model to AbstractVar, rough hack to make returned value type check deactivate --- pyteal/__init__.pyi | 1 + pyteal/ast/__init__.py | 3 ++- pyteal/ast/abi/__init__.py | 2 -- pyteal/ast/abi/address.py | 12 +++++----- pyteal/ast/abi/address_test.py | 24 ++++++++++---------- pyteal/ast/abi/array_base.py | 6 ++--- pyteal/ast/abi/array_dynamic.py | 8 +++---- pyteal/ast/abi/array_dynamic_test.py | 24 ++++++++++---------- pyteal/ast/abi/array_static.py | 10 ++++----- pyteal/ast/abi/array_static_test.py | 18 +++++++-------- pyteal/ast/abi/bool.py | 8 +++---- pyteal/ast/abi/bool_test.py | 22 +++++++++--------- pyteal/ast/abi/reference_type.py | 8 +++---- pyteal/ast/abi/reference_type_test.py | 10 ++++----- pyteal/ast/abi/string.py | 10 ++++----- pyteal/ast/abi/string_test.py | 22 +++++++++--------- pyteal/ast/abi/transaction.py | 8 +++---- pyteal/ast/abi/transaction_test.py | 2 +- pyteal/ast/abi/tuple.py | 6 ++--- pyteal/ast/abi/tuple_test.py | 10 ++++----- pyteal/ast/abi/type.py | 32 ++++++--------------------- pyteal/ast/abi/type_test.py | 2 +- pyteal/ast/abi/uint.py | 8 +++---- pyteal/ast/abi/uint_test.py | 22 +++++++++--------- pyteal/ast/scratchvar.py | 21 +++++++++++++++++- pyteal/ast/subroutine.py | 12 +++++----- 26 files changed, 152 insertions(+), 159 deletions(-) diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index 40600d561..ed1d3c1e1 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -35,6 +35,7 @@ from pyteal.config import ( __all__ = [ "ABIReturnSubroutine", + "AbstractVar", "AccountParam", "AccountParamObject", "Add", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 1ca49a2e5..3d2671068 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -165,7 +165,7 @@ ScratchStackStore, ScratchStore, ) -from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar +from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar, AbstractVar from pyteal.ast.maybe import MaybeValue from pyteal.ast.multi import MultiValue from pyteal.ast.opup import OpUp, OpUpMode, OpUpFeeSource @@ -305,6 +305,7 @@ "ScratchStore", "DynamicScratchVar", "ScratchVar", + "AbstractVar", "MaybeValue", "MultiValue", "OpUp", diff --git a/pyteal/ast/abi/__init__.py b/pyteal/ast/abi/__init__.py index 4baa3bc16..bb2a0d1b2 100644 --- a/pyteal/ast/abi/__init__.py +++ b/pyteal/ast/abi/__init__.py @@ -9,7 +9,6 @@ BaseType, ComputedValue, ReturnedValue, - AbstractVar, FrameStorage, ScratchStorage, ) @@ -174,7 +173,6 @@ "type_specs_from_signature", "make", "size_of", - "AbstractVar", "FrameStorage", "ScratchStorage", "algosdk_from_annotation", diff --git a/pyteal/ast/abi/address.py b/pyteal/ast/abi/address.py index 0fea62c8a..d0413cf6c 100644 --- a/pyteal/ast/abi/address.py +++ b/pyteal/ast/abi/address.py @@ -56,7 +56,7 @@ def get(self) -> Expr: The expression will have the type TealType.bytes. """ - return self._data_storage.load() + return self.stored_value.load() def set( self, @@ -108,25 +108,25 @@ def set( or value.type_spec() == StaticArrayTypeSpec(ByteTypeSpec(), AddressLength.Bytes) ): - return self._data_storage.store(value._data_storage.load()) + return self.stored_value.store(value.stored_value.load()) raise TealInputError( f"Got {value} with type spec {value.type_spec()}, expected AddressTypeSpec" ) case str(): # Addr throws if value is invalid address - return self._data_storage.store(Addr(value)) + return self.stored_value.store(Addr(value)) case bytes(): if len(value) == AddressLength.Bytes: - return self._data_storage.store(Bytes(value)) + return self.stored_value.store(Bytes(value)) raise TealInputError( f"Got bytes with length {len(value)}, expected {AddressLength.Bytes}" ) case Expr(): return Seq( - self._data_storage.store(value), + self.stored_value.store(value), Assert( - Len(self._data_storage.load()) == Int(AddressLength.Bytes.value) + Len(self.stored_value.load()) == Int(AddressLength.Bytes.value) ), ) case CollectionSequence(): diff --git a/pyteal/ast/abi/address_test.py b/pyteal/ast/abi/address_test.py index ccecb0ecf..d115082cd 100644 --- a/pyteal/ast/abi/address_test.py +++ b/pyteal/ast/abi/address_test.py @@ -53,7 +53,7 @@ def test_Address_encode(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -86,7 +86,7 @@ def test_Address_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expectedExpr = value._data_storage.store( + expectedExpr = value.stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -117,7 +117,7 @@ def test_Address_get(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -139,12 +139,12 @@ def test_Address_set_StaticArray(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value_to_set._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value_to_set.stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -174,7 +174,7 @@ def test_Address_set_str(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -203,7 +203,7 @@ def test_Address_set_bytes(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -236,12 +236,12 @@ def test_Address_set_expr(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.int, AddressLength.Bytes.value), @@ -270,12 +270,12 @@ def test_Address_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, + cast(pt.ScratchVar, other.stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -307,7 +307,7 @@ def test_Address_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/array_base.py b/pyteal/ast/abi/array_base.py index 417e401e1..aea164c81 100644 --- a/pyteal/ast/abi/array_base.py +++ b/pyteal/ast/abi/array_base.py @@ -104,7 +104,7 @@ def decode( extracted = substring_for_decoding( encoded, start_index=start_index, end_index=end_index, length=length ) - return self._data_storage.store(extracted) + return self.stored_value.store(extracted) def set(self, values: Sequence[T]) -> Expr: """Set the ABI array with a sequence of ABI type variables. @@ -142,7 +142,7 @@ def set(self, values: Sequence[T]) -> Expr: length_prefix = Seq(length_tmp.set(len(values)), length_tmp.encode()) encoded = Concat(length_prefix, encoded) - return self._data_storage.store(encoded) + return self.stored_value.store(encoded) def encode(self) -> Expr: """Encode the ABI array to be a byte string. @@ -150,7 +150,7 @@ def encode(self) -> Expr: Returns: A PyTeal expression that encodes this ABI array to a byte string. """ - return self._data_storage.load() + return self.stored_value.load() @abstractmethod def length(self) -> Expr: diff --git a/pyteal/ast/abi/array_dynamic.py b/pyteal/ast/abi/array_dynamic.py index a39373324..9d53e0559 100644 --- a/pyteal/ast/abi/array_dynamic.py +++ b/pyteal/ast/abi/array_dynamic.py @@ -79,7 +79,7 @@ def set( raise TealInputError( f"Cannot assign type {values.type_spec()} to {self.type_spec()}" ) - return self._data_storage.store(values.encode()) + return self.stored_value.store(values.encode()) return super().set(values) def length(self) -> Expr: @@ -165,10 +165,10 @@ def set( match values: case bytes() | bytearray(): - return self._data_storage.store(_encoded_byte_string(values)) + return self.stored_value.store(_encoded_byte_string(values)) case Expr(): return _store_encoded_expr_byte_string_into_var( - values, self._data_storage + values, self.stored_value ) return super().set(values) @@ -181,7 +181,7 @@ def get(self) -> Expr: Returns: A Pyteal expression that loads byte encoding of this DynamicBytes, and drop the first uint16 DynamicArray length encoding. """ - return Suffix(self._data_storage.load(), Int(2)) + return Suffix(self.stored_value.load(), Int(2)) DynamicBytes.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/array_dynamic_test.py b/pyteal/ast/abi/array_dynamic_test.py index 589d52664..e8e930787 100644 --- a/pyteal/ast/abi/array_dynamic_test.py +++ b/pyteal/ast/abi/array_dynamic_test.py @@ -106,7 +106,7 @@ def test_DynamicArray_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value._data_storage.store( + expectedExpr = value.stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -141,7 +141,7 @@ def test_DynamicArray_set_values(): assert not expr.has_return() length_tmp = abi.Uint16() - expectedExpr = value._data_storage.store( + expectedExpr = value.stored_value.store( pt.Concat( pt.Seq(length_tmp.set(len(values)), length_tmp.encode()), _encode_tuple(values), @@ -185,12 +185,12 @@ def test_DynamicArray_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, otherArray._data_storage).scratchvar.slot, + cast(pt.ScratchVar, otherArray.stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -218,7 +218,7 @@ def test_DynamicArray_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -268,7 +268,7 @@ def test_DynamicBytes_set_py_bytes(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -299,12 +299,12 @@ def test_DynamicBytes_set_expr(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.itob), @@ -312,13 +312,13 @@ def test_DynamicBytes_set_expr(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.concat), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -343,7 +343,7 @@ def test_DynamicBytes_get(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.extract, 2, 0), ] @@ -365,7 +365,7 @@ def test_DynamicArray_encode(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/array_static.py b/pyteal/ast/abi/array_static.py index a631687f3..7744a6edb 100644 --- a/pyteal/ast/abi/array_static.py +++ b/pyteal/ast/abi/array_static.py @@ -109,7 +109,7 @@ def set( raise TealInputError( f"Cannot assign type {values.type_spec()} to {self.type_spec()}" ) - return self._data_storage.store(values.encode()) + return self.stored_value.store(values.encode()) if self.type_spec().length_static() != len(values): raise TealInputError( @@ -207,11 +207,11 @@ def set( raise TealInputError( f"Got bytes with length {len(values)}, expect {self.type_spec().length_static()}" ) - return self._data_storage.store(Bytes(values)) + return self.stored_value.store(Bytes(values)) case Expr(): return Seq( - self._data_storage.store(values), - Assert(self.length() == Len(self._data_storage.load())), + self.stored_value.store(values), + Assert(self.length() == Len(self.stored_value.load())), ) return super().set(values) @@ -222,7 +222,7 @@ def get(self) -> Expr: Returns: A Pyteal expression that loads byte encoding of this StaticBytes. """ - return self._data_storage.load() + return self.stored_value.load() StaticBytes.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/array_static_test.py b/pyteal/ast/abi/array_static_test.py index 7174c2ebb..7c2e914ec 100644 --- a/pyteal/ast/abi/array_static_test.py +++ b/pyteal/ast/abi/array_static_test.py @@ -159,7 +159,7 @@ def test_StaticArray_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value._data_storage.store( + expectedExpr = value.stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -202,7 +202,7 @@ def test_StaticArray_set_values(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value._data_storage.store(_encode_tuple(values)) + expectedExpr = value.stored_value.store(_encode_tuple(values)) expected, _ = expectedExpr.__teal__(options) expected.addIncoming() expected = pt.TealBlock.NormalizeBlocks(expected) @@ -237,12 +237,12 @@ def test_StaticArray_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, otherArray._data_storage).scratchvar.slot, + cast(pt.ScratchVar, otherArray.stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -270,7 +270,7 @@ def test_StaticArray_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -317,7 +317,7 @@ def test_StaticBytes_set_py_bytes(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -352,13 +352,13 @@ def test_StaticBytes_expr(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.int, 32), pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.eq), @@ -381,7 +381,7 @@ def test_StaticArray_encode(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/bool.py b/pyteal/ast/abi/bool.py index 6d42c2fdd..13552b6db 100644 --- a/pyteal/ast/abi/bool.py +++ b/pyteal/ast/abi/bool.py @@ -50,7 +50,7 @@ def get(self) -> Expr: expression that evaluates to 0 will be returned. In either case, the expression will have the type TealType.uint64. """ - return self._data_storage.load() + return self.stored_value.load() def set(self, value: Union[bool, Expr, "Bool", ComputedValue["Bool"]]) -> Expr: """Set the value of this Bool to the input value. @@ -85,10 +85,10 @@ def set(self, value: Union[bool, Expr, "Bool", ComputedValue["Bool"]]) -> Expr: checked = True if checked: - return self._data_storage.store(value) + return self.stored_value.store(value) # Not(Not(value)) coerces all values greater than 0 to 1 - return self._data_storage.store(Not(Not(value))) + return self.stored_value.store(Not(Not(value))) def decode( self, @@ -103,7 +103,7 @@ def decode( return self.decode_bit(encoded, start_index * Int(NUM_BITS_IN_BYTE)) def decode_bit(self, encoded, bit_index: Expr) -> Expr: - return self._data_storage.store(GetBit(encoded, bit_index)) + return self.stored_value.store(GetBit(encoded, bit_index)) def encode(self) -> Expr: return SetBit(Bytes(b"\x00"), Int(0), self.get()) diff --git a/pyteal/ast/abi/bool_test.py b/pyteal/ast/abi/bool_test.py index 4299b72ce..1cf881d55 100644 --- a/pyteal/ast/abi/bool_test.py +++ b/pyteal/ast/abi/bool_test.py @@ -56,7 +56,7 @@ def test_Bool_set_static(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -85,7 +85,7 @@ def test_Bool_set_expr(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -110,12 +110,12 @@ def test_Bool_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, + cast(pt.ScratchVar, other.stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -144,7 +144,7 @@ def test_Bool_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -171,7 +171,7 @@ def test_Bool_get(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -203,9 +203,7 @@ def test_Bool_decode(): pt.TealOp( None, pt.Op.store, - cast( - abi.ScratchStorage, value._data_storage - ).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -234,7 +232,7 @@ def test_Bool_decode_bit(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -260,7 +258,7 @@ def test_Bool_encode(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.setbit), ] @@ -444,7 +442,7 @@ class EncodeSeqTest(NamedTuple): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, testType._data_storage).scratchvar.slot, + cast(pt.ScratchVar, testType.stored_value).slot, ), pt.TealOp(None, pt.Op.setbit), ] diff --git a/pyteal/ast/abi/reference_type.py b/pyteal/ast/abi/reference_type.py index aa0709ffe..f4882fc97 100644 --- a/pyteal/ast/abi/reference_type.py +++ b/pyteal/ast/abi/reference_type.py @@ -58,7 +58,7 @@ def referenced_index(self) -> Expr: If this reference type is an application or asset, note that this DOES NOT return the application or asset ID. See :code:`application_id()` or :code:`asset_id()` for that. """ - return self._data_storage.load() + return self.stored_value.load() def decode( self, @@ -70,7 +70,7 @@ def decode( ) -> Expr: return uint_decode( self.type_spec().bit_size(), - self._data_storage, + self.stored_value, encoded, start_index, end_index, @@ -107,7 +107,7 @@ def __init__(self) -> None: def address(self) -> Expr: """Get the address of the account.""" - return Txn.accounts[self._data_storage.load()] + return Txn.accounts[self.stored_value.load()] def params(self) -> AccountParamObject: """Get information about the account.""" @@ -205,7 +205,7 @@ def __init__(self) -> None: def application_id(self) -> Expr: """Get the ID of the application.""" - return Txn.applications[self._data_storage.load()] + return Txn.applications[self.stored_value.load()] def params(self) -> AppParamObject: """Get information about the application's parameters.""" diff --git a/pyteal/ast/abi/reference_type_test.py b/pyteal/ast/abi/reference_type_test.py index edc0a857c..4ec862e66 100644 --- a/pyteal/ast/abi/reference_type_test.py +++ b/pyteal/ast/abi/reference_type_test.py @@ -26,7 +26,7 @@ def test_ReferenceType_referenced_index(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -61,7 +61,7 @@ def test_ReferenceType_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expected_decoding = value._data_storage.store( + expected_decoding = value.stored_value.store( pt.GetByte( encoded, start_index if start_index is not None else pt.Int(0), @@ -117,7 +117,7 @@ def test_Account_address(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.txnas, "Accounts"), ] @@ -204,7 +204,7 @@ def test_Asset_asset_id(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.txnas, "Assets"), ] @@ -298,7 +298,7 @@ def test_Application_application_id(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.txnas, "Applications"), ] diff --git a/pyteal/ast/abi/string.py b/pyteal/ast/abi/string.py index f91eb272f..ac5866cb2 100644 --- a/pyteal/ast/abi/string.py +++ b/pyteal/ast/abi/string.py @@ -68,7 +68,7 @@ def get(self) -> Expr: The expression will have the type TealType.bytes. """ return Suffix( - self._data_storage.load(), Int(Uint16TypeSpec().byte_length_static()) + self.stored_value.load(), Int(Uint16TypeSpec().byte_length_static()) ) def set( @@ -111,18 +111,18 @@ def set( if value.type_spec() == StringTypeSpec() or ( value.type_spec() == DynamicArrayTypeSpec(ByteTypeSpec()) ): - return self._data_storage.store(value._data_storage.load()) + return self.stored_value.store(value.stored_value.load()) raise TealInputError( f"Got {value} with type spec {value.type_spec()}, expected {StringTypeSpec}" ) case bytes() | bytearray(): - return self._data_storage.store(_encoded_byte_string(value)) + return self.stored_value.store(_encoded_byte_string(value)) case str(): - return self._data_storage.store(_encoded_byte_string(value.encode())) + return self.stored_value.store(_encoded_byte_string(value.encode())) case Expr(): return _store_encoded_expr_byte_string_into_var( - value, self._data_storage + value, self.stored_value ) case CollectionSequence(): return super().set(cast(Sequence[Byte], value)) diff --git a/pyteal/ast/abi/string_test.py b/pyteal/ast/abi/string_test.py index e335da1a1..c60ac52f4 100644 --- a/pyteal/ast/abi/string_test.py +++ b/pyteal/ast/abi/string_test.py @@ -44,7 +44,7 @@ def test_String_encode(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -76,7 +76,7 @@ def test_DynamicArray_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expectedExpr = value._data_storage.store( + expectedExpr = value.stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -107,7 +107,7 @@ def test_String_get(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.extract, 2, 0), ] @@ -143,7 +143,7 @@ def test_String_set_static(value_to_set, value_encoded): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -174,12 +174,12 @@ def test_String_set_expr(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.itob), @@ -187,13 +187,13 @@ def test_String_set_expr(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.concat), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -222,12 +222,12 @@ def test_String_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, + cast(pt.ScratchVar, other.stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -259,7 +259,7 @@ def test_String_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/transaction.py b/pyteal/ast/abi/transaction.py index 1f3ea9ba2..aeb5c7a33 100644 --- a/pyteal/ast/abi/transaction.py +++ b/pyteal/ast/abi/transaction.py @@ -82,16 +82,16 @@ def _set_index( case ComputedValue(): return self._set_with_computed_type(value) case BaseType(): - return self._data_storage.store(self._data_storage.load()) + return self.stored_value.store(self.stored_value.load()) case int(): - return self._data_storage.store(Int(value)) + return self.stored_value.store(Int(value)) case Expr(): - return self._data_storage.store(value) + return self.stored_value.store(value) case _: raise TealInputError(f"Cant store a {type(value)} in a Transaction") def index(self) -> Expr: - return self._data_storage.load() + return self.stored_value.load() def decode( self, diff --git a/pyteal/ast/abi/transaction_test.py b/pyteal/ast/abi/transaction_test.py index e21802950..b4c27a97c 100644 --- a/pyteal/ast/abi/transaction_test.py +++ b/pyteal/ast/abi/transaction_test.py @@ -134,7 +134,7 @@ def test_Transaction__set_index(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, tv.t._data_storage).scratchvar.slot, + cast(pt.ScratchVar, tv.t.stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/tuple.py b/pyteal/ast/abi/tuple.py index efea10e36..bc1966414 100644 --- a/pyteal/ast/abi/tuple.py +++ b/pyteal/ast/abi/tuple.py @@ -309,7 +309,7 @@ def decode( extracted = substring_for_decoding( encoded, start_index=start_index, end_index=end_index, length=length ) - return self._data_storage.store(extracted) + return self.stored_value.store(extracted) @overload def set(self, *values: BaseType) -> Expr: @@ -352,10 +352,10 @@ def set(self, *values): ) if not all(myTypes[i] == values[i].type_spec() for i in range(len(myTypes))): raise TealInputError("Input values do not match type") - return self._data_storage.store(_encode_tuple(values)) + return self.stored_value.store(_encode_tuple(values)) def encode(self) -> Expr: - return self._data_storage.load() + return self.stored_value.load() def length(self) -> Expr: """Get the number of values this tuple holds as an Expr.""" diff --git a/pyteal/ast/abi/tuple_test.py b/pyteal/ast/abi/tuple_test.py index ad231784f..a761d88af 100644 --- a/pyteal/ast/abi/tuple_test.py +++ b/pyteal/ast/abi/tuple_test.py @@ -623,7 +623,7 @@ def test_Tuple_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = tupleValue._data_storage.store( + expectedExpr = tupleValue.stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -672,9 +672,7 @@ def test_Tuple_set(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = tupleValue._data_storage.store( - _encode_tuple([uint8, uint16, uint32]) - ) + expectedExpr = tupleValue.stored_value.store(_encode_tuple([uint8, uint16, uint32])) expected, _ = expectedExpr.__teal__(options) expected.addIncoming() expected = pt.TealBlock.NormalizeBlocks(expected) @@ -706,7 +704,7 @@ def test_Tuple_set_Computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, tupleValue._data_storage).scratchvar.slot, + cast(pt.ScratchVar, tupleValue.stored_value).slot, ), ] ) @@ -737,7 +735,7 @@ def test_Tuple_encode(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, tupleValue._data_storage).scratchvar.slot, + cast(pt.ScratchVar, tupleValue.stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index 3ae5d585c..2e9027c5d 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -4,7 +4,7 @@ from pyteal.errors import TealInputError from pyteal.types import TealType from pyteal.ast.expr import Expr -from pyteal.ast.scratchvar import ScratchVar +from pyteal.ast.scratchvar import ScratchVar, AbstractVar from pyteal.ast.seq import Seq @@ -65,23 +65,6 @@ def __str__(self) -> str: TypeSpec.__module__ = "pyteal.abi" -class AbstractVar(ABC): - @abstractmethod - def store(self, value: Expr) -> Expr: - pass - - @abstractmethod - def load(self) -> Expr: - pass - - @abstractmethod - def storage_type(self) -> TealType: - pass - - -AbstractVar.__module__ = "pyteal" - - class ScratchStorage(AbstractVar): def __init__(self, storage_type: TealType) -> None: super().__init__() @@ -135,18 +118,16 @@ def __init__(self, spec: TypeSpec) -> None: """Create a new BaseType.""" super().__init__() self._type_spec: Final[TypeSpec] = spec - self._data_storage: AbstractVar = ScratchStorage(spec.storage_type()) - - # self.stored_value: Final = ScratchVar(spec.storage_type()) + self.stored_value: AbstractVar = ScratchVar(spec.storage_type()) def _set_data_source(self, storage: AbstractVar) -> None: - self._data_storage = storage + self.stored_value = storage def _load_value(self) -> Expr: - return self._data_storage.load() + return self.stored_value.load() def _store_value(self, value: Expr) -> Expr: - return self._data_storage.store(value) + return self.stored_value.store(value) def type_spec(self) -> TypeSpec: """Get the TypeSpec for this ABI type instance.""" @@ -300,7 +281,8 @@ def store_into(self, output: BaseType) -> Expr: f"ABI return subroutine deferred_expr is expected to be typed {output.type_spec().storage_type()}, " f"but has type {declaration.deferred_expr.type_of()}." ) - return output._data_storage.store(self.computation) + assert isinstance(output.stored_value, ScratchVar) + return output.stored_value.slot.store(self.computation) ReturnedValue.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/type_test.py b/pyteal/ast/abi/type_test.py index 30f39e0fc..56a9e6c76 100644 --- a/pyteal/ast/abi/type_test.py +++ b/pyteal/ast/abi/type_test.py @@ -17,7 +17,7 @@ def store_into(self, output: abi.BaseType) -> pt.Expr: raise pt.TealInputError( f"expected type_spec {self.type_spec} but get {output.type_spec()}" ) - return output._data_storage.store(self.encodings) + return output.stored_value.store(self.encodings) def test_ComputedType_use(): diff --git a/pyteal/ast/abi/uint.py b/pyteal/ast/abi/uint.py index 67d3ff428..0a99eb27f 100644 --- a/pyteal/ast/abi/uint.py +++ b/pyteal/ast/abi/uint.py @@ -239,7 +239,7 @@ def get(self) -> Expr: The expression will have the type TealType.uint64. """ - return self._data_storage.load() + return self.stored_value.load() def set(self, value: Union[int, Expr, "Uint", ComputedValue["Uint"]]) -> Expr: """Set the value of this Uint to the input value. @@ -274,7 +274,7 @@ def set(self, value: Union[int, Expr, "Uint", ComputedValue["Uint"]]) -> Expr: value.type_spec(), self.type_spec() ) ) - return uint_set(self.type_spec().bit_size(), self._data_storage, value) + return uint_set(self.type_spec().bit_size(), self.stored_value, value) def decode( self, @@ -286,7 +286,7 @@ def decode( ) -> Expr: return uint_decode( self.type_spec().bit_size(), - self._data_storage, + self.stored_value, encoded, start_index, end_index, @@ -294,7 +294,7 @@ def decode( ) def encode(self) -> Expr: - return uint_encode(self.type_spec().bit_size(), self._data_storage) + return uint_encode(self.type_spec().bit_size(), self.stored_value) Uint.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/uint_test.py b/pyteal/ast/abi/uint_test.py index d571e7aa6..26ba3541f 100644 --- a/pyteal/ast/abi/uint_test.py +++ b/pyteal/ast/abi/uint_test.py @@ -142,7 +142,7 @@ def test_Uint_set_static(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -174,7 +174,7 @@ def test_Uint_set_expr(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.int, test.maxValue + 1), pt.TealOp(None, pt.Op.lt), @@ -189,7 +189,7 @@ def test_Uint_set_expr(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] + upperBoundCheck @@ -216,12 +216,12 @@ def test_Uint_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, + cast(pt.ScratchVar, other.stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -253,7 +253,7 @@ def test_Uint_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -281,7 +281,7 @@ def test_Uint_get(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -307,7 +307,7 @@ def test_Uint_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedDecoding = value._data_storage.store( + expectedDecoding = value.stored_value.store( test.expectedDecoding(encoded, start_index, end_index, length) ) expected, _ = expectedDecoding.__teal__(options) @@ -359,14 +359,12 @@ def test_ByteUint8_mutual_conversion(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, + cast(pt.ScratchVar, other.stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast( - abi.ScratchStorage, type_b_instance._data_storage - ).scratchvar.slot, + cast(pt.ScratchVar, type_b_instance.stored_value).slot, ), ] ) diff --git a/pyteal/ast/scratchvar.py b/pyteal/ast/scratchvar.py index 81ce27fff..44d422782 100644 --- a/pyteal/ast/scratchvar.py +++ b/pyteal/ast/scratchvar.py @@ -1,3 +1,5 @@ +from abc import ABC, abstractmethod + from pyteal.errors import TealInputError from pyteal.types import TealType, require_type @@ -5,7 +7,24 @@ from pyteal.ast.scratch import ScratchSlot, ScratchLoad, ScratchStore -class ScratchVar: +class AbstractVar(ABC): + @abstractmethod + def store(self, value: Expr) -> Expr: + pass + + @abstractmethod + def load(self) -> Expr: + pass + + @abstractmethod + def storage_type(self) -> TealType: + pass + + +AbstractVar.__module__ = "pyteal" + + +class ScratchVar(AbstractVar): """ Interface around Scratch space, similar to get/put local/global state diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index d509f980b..437c9535d 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -378,7 +378,7 @@ def __init__( elif isinstance(arg, ScratchVar): arg_type = arg.type elif isinstance(arg, abi.BaseType): - arg_type = cast(abi.BaseType, arg)._data_storage.storage_type() + arg_type = cast(abi.BaseType, arg).stored_value.storage_type() else: raise TealInputError( f"Subroutine argument {arg} at index {i} was of unexpected Python type {type(arg)}" @@ -420,7 +420,7 @@ def handle_arg(arg: Expr | ScratchVar | abi.BaseType) -> Expr: elif isinstance(arg, Expr): return arg elif isinstance(arg, abi.BaseType): - return arg._data_storage.load() + return arg.stored_value.load() else: raise TealInputError( f"cannot handle current arg: {arg} to put it on stack" @@ -791,8 +791,6 @@ def evaluate_subroutine(subroutine: SubroutineDefinition) -> SubroutineDeclarati def var_n_loaded( param: str, ) -> tuple[ScratchVar, ScratchVar | abi.BaseType | Expr]: - from pyteal.ast.abi.type import ScratchStorage - loaded_var: ScratchVar | abi.BaseType | Expr argument_var: ScratchVar @@ -801,11 +799,11 @@ def var_n_loaded( loaded_var = argument_var elif param in subroutine.abi_args: internal_abi_var = subroutine.abi_args[param].new_instance() - if not isinstance(internal_abi_var._data_storage, ScratchStorage): + if not isinstance(internal_abi_var.stored_value, ScratchVar): raise TealInternalError( "subroutine ABI args must have data schema being ScratchVarStorage" ) - argument_var = internal_abi_var._data_storage.scratchvar + argument_var = internal_abi_var.stored_value loaded_var = internal_abi_var else: argument_var = ScratchVar(TealType.anytype) @@ -853,7 +851,7 @@ def var_n_loaded( f"ABI returning subroutine definition should evaluate to TealType.none, " f"while evaluate to {subroutine_body.type_of()}." ) - deferred_expr = output_carrying_abi._data_storage.load() + deferred_expr = output_carrying_abi.stored_value.load() # Arg usage "A" to be pick up and store in scratch parameters that have been placed on the stack # need to reverse order of argumentVars because the last argument will be on top of the stack From 71ad8a65f81d0e294e469bd656bb7c64e069e311 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 10:51:50 -0400 Subject: [PATCH 048/206] better type checking in scratch slot --- pyteal/ast/abi/type.py | 3 +-- pyteal/ast/scratchvar.py | 9 +++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index 2e9027c5d..f9368cbda 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -281,8 +281,7 @@ def store_into(self, output: BaseType) -> Expr: f"ABI return subroutine deferred_expr is expected to be typed {output.type_spec().storage_type()}, " f"but has type {declaration.deferred_expr.type_of()}." ) - assert isinstance(output.stored_value, ScratchVar) - return output.stored_value.slot.store(self.computation) + return output.stored_value.store(self.computation) ReturnedValue.__module__ = "pyteal.abi" diff --git a/pyteal/ast/scratchvar.py b/pyteal/ast/scratchvar.py index 44d422782..7b4962f97 100644 --- a/pyteal/ast/scratchvar.py +++ b/pyteal/ast/scratchvar.py @@ -1,7 +1,7 @@ from abc import ABC, abstractmethod from pyteal.errors import TealInputError -from pyteal.types import TealType, require_type +from pyteal.types import TealType, require_type, types_match from pyteal.ast.expr import Expr from pyteal.ast.scratch import ScratchSlot, ScratchLoad, ScratchStore @@ -61,7 +61,12 @@ def store(self, value: Expr) -> Expr: Args: value: The value to store. Must conform to this ScratchVar's type. """ - require_type(value, self.type) + from pyteal.ast.subroutine import SubroutineCall + + if not isinstance(value, SubroutineCall) or not value.output_kwarg: + require_type(value, self.type) + else: + assert types_match(value.output_kwarg.abi_type.storage_type(), self.type) return self.slot.store(value) def load(self) -> ScratchLoad: From 921bf85b656a78c6ccfea7a7a015c60b6c4f85f3 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 10:55:21 -0400 Subject: [PATCH 049/206] reformat imports and class decl for FrameVar and ScratchVar --- pyteal/__init__.pyi | 1 + pyteal/ast/__init__.py | 3 ++- pyteal/ast/abi/__init__.py | 11 +--------- pyteal/ast/abi/type.py | 41 -------------------------------------- pyteal/ast/frame.py | 24 ++++++++++++++++++++++ 5 files changed, 28 insertions(+), 52 deletions(-) diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index ed1d3c1e1..baf5ae050 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -122,6 +122,7 @@ __all__ = [ "For", "FrameBury", "FrameDig", + "FrameStorage", "Ge", "GeneratedID", "GetBit", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 3d2671068..0f2bcaa34 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -155,7 +155,7 @@ from pyteal.ast.for_ import For from pyteal.ast.break_ import Break from pyteal.ast.continue_ import Continue -from pyteal.ast.frame import Proto, FrameDig, FrameBury, PopN, DupN, Bury +from pyteal.ast.frame import Proto, FrameDig, FrameBury, PopN, DupN, Bury, FrameStorage # misc from pyteal.ast.scratch import ( @@ -344,6 +344,7 @@ "Bury", "DupN", "PopN", + "FrameStorage", "Router", "CallConfig", "MethodConfig", diff --git a/pyteal/ast/abi/__init__.py b/pyteal/ast/abi/__init__.py index bb2a0d1b2..f1cb3a58c 100644 --- a/pyteal/ast/abi/__init__.py +++ b/pyteal/ast/abi/__init__.py @@ -4,14 +4,7 @@ Address, AddressLength, ) -from pyteal.ast.abi.type import ( - TypeSpec, - BaseType, - ComputedValue, - ReturnedValue, - FrameStorage, - ScratchStorage, -) +from pyteal.ast.abi.type import TypeSpec, BaseType, ComputedValue, ReturnedValue from pyteal.ast.abi.bool import BoolTypeSpec, Bool from pyteal.ast.abi.uint import ( UintTypeSpec, @@ -173,8 +166,6 @@ "type_specs_from_signature", "make", "size_of", - "FrameStorage", - "ScratchStorage", "algosdk_from_annotation", "algosdk_from_type_spec", "contains_type_spec", diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index f9368cbda..b87fe1282 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -65,47 +65,6 @@ def __str__(self) -> str: TypeSpec.__module__ = "pyteal.abi" -class ScratchStorage(AbstractVar): - def __init__(self, storage_type: TealType) -> None: - super().__init__() - self.scratchvar: Final[ScratchVar] = ScratchVar(storage_type) - - def load(self) -> Expr: - return self.scratchvar.load() - - def store(self, value: Expr) -> Expr: - return self.scratchvar.slot.store(value) - - def storage_type(self) -> TealType: - return self.scratchvar.storage_type() - - -ScratchStorage.__module__ = "pyteal" - - -class FrameStorage(AbstractVar): - def __init__(self, storage_type: TealType, stack_depth: int) -> None: - super().__init__() - self.stack_type = storage_type - self.stack_depth = stack_depth - - def storage_type(self) -> TealType: - return self.stack_type - - def store(self, value: Expr) -> Expr: - from pyteal.ast import FrameBury - - return FrameBury(value, self.stack_depth) - - def load(self) -> Expr: - from pyteal.ast import FrameDig - - return FrameDig(self.stack_depth) - - -FrameStorage.__module__ = "pyteal" - - class BaseType(ABC): """The abstract base class for all ABI type instances. diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 68ce3a2f2..25aa437fc 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -1,6 +1,7 @@ from typing import TYPE_CHECKING from pyteal.ast.expr import Expr +from pyteal.ast.scratchvar import AbstractVar from pyteal.types import TealType, require_type from pyteal.errors import TealInputError, verifyProgramVersion from pyteal.ir import TealBlock, TealSimpleBlock, TealOp, Op @@ -101,6 +102,29 @@ def has_return(self) -> bool: FrameBury.__module__ = "pyteal" +class FrameStorage(AbstractVar): + def __init__(self, storage_type: TealType, stack_depth: int) -> None: + super().__init__() + self.stack_type = storage_type + self.stack_depth = stack_depth + + def storage_type(self) -> TealType: + return self.stack_type + + def store(self, value: Expr) -> Expr: + from pyteal.ast import FrameBury + + return FrameBury(value, self.stack_depth) + + def load(self) -> Expr: + from pyteal.ast import FrameDig + + return FrameDig(self.stack_depth) + + +FrameStorage.__module__ = "pyteal" + + class Bury(Expr): def __init__(self, value: Expr, depth: int): super().__init__() From 304f273990572b0f457d742f834824cf741f5c06 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 11:27:24 -0400 Subject: [PATCH 050/206] still thinking about hiding the _stored value --- pyteal/ast/abi/address.py | 12 ++++++------ pyteal/ast/abi/address_test.py | 24 ++++++++++++------------ pyteal/ast/abi/array_base.py | 6 +++--- pyteal/ast/abi/array_dynamic.py | 8 ++++---- pyteal/ast/abi/array_dynamic_test.py | 24 ++++++++++++------------ pyteal/ast/abi/array_static.py | 10 +++++----- pyteal/ast/abi/array_static_test.py | 18 +++++++++--------- pyteal/ast/abi/bool.py | 8 ++++---- pyteal/ast/abi/bool_test.py | 20 ++++++++++---------- pyteal/ast/abi/reference_type.py | 8 ++++---- pyteal/ast/abi/reference_type_test.py | 10 +++++----- pyteal/ast/abi/string.py | 10 +++++----- pyteal/ast/abi/string_test.py | 22 +++++++++++----------- pyteal/ast/abi/transaction.py | 8 ++++---- pyteal/ast/abi/transaction_test.py | 2 +- pyteal/ast/abi/tuple.py | 6 +++--- pyteal/ast/abi/tuple_test.py | 10 ++++++---- pyteal/ast/abi/type.py | 10 +++++----- pyteal/ast/abi/type_test.py | 2 +- pyteal/ast/abi/uint.py | 8 ++++---- pyteal/ast/abi/uint_test.py | 20 ++++++++++---------- pyteal/ast/subroutine.py | 10 +++++----- 22 files changed, 129 insertions(+), 127 deletions(-) diff --git a/pyteal/ast/abi/address.py b/pyteal/ast/abi/address.py index d0413cf6c..d8ad3cbc2 100644 --- a/pyteal/ast/abi/address.py +++ b/pyteal/ast/abi/address.py @@ -56,7 +56,7 @@ def get(self) -> Expr: The expression will have the type TealType.bytes. """ - return self.stored_value.load() + return self._stored_value.load() def set( self, @@ -108,25 +108,25 @@ def set( or value.type_spec() == StaticArrayTypeSpec(ByteTypeSpec(), AddressLength.Bytes) ): - return self.stored_value.store(value.stored_value.load()) + return self._stored_value.store(value._stored_value.load()) raise TealInputError( f"Got {value} with type spec {value.type_spec()}, expected AddressTypeSpec" ) case str(): # Addr throws if value is invalid address - return self.stored_value.store(Addr(value)) + return self._stored_value.store(Addr(value)) case bytes(): if len(value) == AddressLength.Bytes: - return self.stored_value.store(Bytes(value)) + return self._stored_value.store(Bytes(value)) raise TealInputError( f"Got bytes with length {len(value)}, expected {AddressLength.Bytes}" ) case Expr(): return Seq( - self.stored_value.store(value), + self._stored_value.store(value), Assert( - Len(self.stored_value.load()) == Int(AddressLength.Bytes.value) + Len(self._stored_value.load()) == Int(AddressLength.Bytes.value) ), ) case CollectionSequence(): diff --git a/pyteal/ast/abi/address_test.py b/pyteal/ast/abi/address_test.py index d115082cd..c70cbe5ea 100644 --- a/pyteal/ast/abi/address_test.py +++ b/pyteal/ast/abi/address_test.py @@ -53,7 +53,7 @@ def test_Address_encode(): pt.TealOp( expr, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -86,7 +86,7 @@ def test_Address_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expectedExpr = value.stored_value.store( + expectedExpr = value._stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -117,7 +117,7 @@ def test_Address_get(): pt.TealOp( expr, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -139,12 +139,12 @@ def test_Address_set_StaticArray(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value_to_set.stored_value).slot, + cast(pt.ScratchVar, value_to_set._stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -174,7 +174,7 @@ def test_Address_set_str(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -203,7 +203,7 @@ def test_Address_set_bytes(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -236,12 +236,12 @@ def test_Address_set_expr(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.int, AddressLength.Bytes.value), @@ -270,12 +270,12 @@ def test_Address_set_copy(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, other.stored_value).slot, + cast(pt.ScratchVar, other._stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -307,7 +307,7 @@ def test_Address_set_computed(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/array_base.py b/pyteal/ast/abi/array_base.py index aea164c81..8920637bc 100644 --- a/pyteal/ast/abi/array_base.py +++ b/pyteal/ast/abi/array_base.py @@ -104,7 +104,7 @@ def decode( extracted = substring_for_decoding( encoded, start_index=start_index, end_index=end_index, length=length ) - return self.stored_value.store(extracted) + return self._stored_value.store(extracted) def set(self, values: Sequence[T]) -> Expr: """Set the ABI array with a sequence of ABI type variables. @@ -142,7 +142,7 @@ def set(self, values: Sequence[T]) -> Expr: length_prefix = Seq(length_tmp.set(len(values)), length_tmp.encode()) encoded = Concat(length_prefix, encoded) - return self.stored_value.store(encoded) + return self._stored_value.store(encoded) def encode(self) -> Expr: """Encode the ABI array to be a byte string. @@ -150,7 +150,7 @@ def encode(self) -> Expr: Returns: A PyTeal expression that encodes this ABI array to a byte string. """ - return self.stored_value.load() + return self._stored_value.load() @abstractmethod def length(self) -> Expr: diff --git a/pyteal/ast/abi/array_dynamic.py b/pyteal/ast/abi/array_dynamic.py index 9d53e0559..ecbeeb49c 100644 --- a/pyteal/ast/abi/array_dynamic.py +++ b/pyteal/ast/abi/array_dynamic.py @@ -79,7 +79,7 @@ def set( raise TealInputError( f"Cannot assign type {values.type_spec()} to {self.type_spec()}" ) - return self.stored_value.store(values.encode()) + return self._stored_value.store(values.encode()) return super().set(values) def length(self) -> Expr: @@ -165,10 +165,10 @@ def set( match values: case bytes() | bytearray(): - return self.stored_value.store(_encoded_byte_string(values)) + return self._stored_value.store(_encoded_byte_string(values)) case Expr(): return _store_encoded_expr_byte_string_into_var( - values, self.stored_value + values, self._stored_value ) return super().set(values) @@ -181,7 +181,7 @@ def get(self) -> Expr: Returns: A Pyteal expression that loads byte encoding of this DynamicBytes, and drop the first uint16 DynamicArray length encoding. """ - return Suffix(self.stored_value.load(), Int(2)) + return Suffix(self._stored_value.load(), Int(2)) DynamicBytes.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/array_dynamic_test.py b/pyteal/ast/abi/array_dynamic_test.py index e8e930787..91497500a 100644 --- a/pyteal/ast/abi/array_dynamic_test.py +++ b/pyteal/ast/abi/array_dynamic_test.py @@ -106,7 +106,7 @@ def test_DynamicArray_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value.stored_value.store( + expectedExpr = value._stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -141,7 +141,7 @@ def test_DynamicArray_set_values(): assert not expr.has_return() length_tmp = abi.Uint16() - expectedExpr = value.stored_value.store( + expectedExpr = value._stored_value.store( pt.Concat( pt.Seq(length_tmp.set(len(values)), length_tmp.encode()), _encode_tuple(values), @@ -185,12 +185,12 @@ def test_DynamicArray_set_copy(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, otherArray.stored_value).slot, + cast(pt.ScratchVar, otherArray._stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -218,7 +218,7 @@ def test_DynamicArray_set_computed(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -268,7 +268,7 @@ def test_DynamicBytes_set_py_bytes(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -299,12 +299,12 @@ def test_DynamicBytes_set_expr(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.itob), @@ -312,13 +312,13 @@ def test_DynamicBytes_set_expr(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.concat), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -343,7 +343,7 @@ def test_DynamicBytes_get(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.extract, 2, 0), ] @@ -365,7 +365,7 @@ def test_DynamicArray_encode(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/array_static.py b/pyteal/ast/abi/array_static.py index 7744a6edb..3d9d56557 100644 --- a/pyteal/ast/abi/array_static.py +++ b/pyteal/ast/abi/array_static.py @@ -109,7 +109,7 @@ def set( raise TealInputError( f"Cannot assign type {values.type_spec()} to {self.type_spec()}" ) - return self.stored_value.store(values.encode()) + return self._stored_value.store(values.encode()) if self.type_spec().length_static() != len(values): raise TealInputError( @@ -207,11 +207,11 @@ def set( raise TealInputError( f"Got bytes with length {len(values)}, expect {self.type_spec().length_static()}" ) - return self.stored_value.store(Bytes(values)) + return self._stored_value.store(Bytes(values)) case Expr(): return Seq( - self.stored_value.store(values), - Assert(self.length() == Len(self.stored_value.load())), + self._stored_value.store(values), + Assert(self.length() == Len(self._stored_value.load())), ) return super().set(values) @@ -222,7 +222,7 @@ def get(self) -> Expr: Returns: A Pyteal expression that loads byte encoding of this StaticBytes. """ - return self.stored_value.load() + return self._stored_value.load() StaticBytes.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/array_static_test.py b/pyteal/ast/abi/array_static_test.py index 7c2e914ec..7a61e2b65 100644 --- a/pyteal/ast/abi/array_static_test.py +++ b/pyteal/ast/abi/array_static_test.py @@ -159,7 +159,7 @@ def test_StaticArray_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value.stored_value.store( + expectedExpr = value._stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -202,7 +202,7 @@ def test_StaticArray_set_values(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value.stored_value.store(_encode_tuple(values)) + expectedExpr = value._stored_value.store(_encode_tuple(values)) expected, _ = expectedExpr.__teal__(options) expected.addIncoming() expected = pt.TealBlock.NormalizeBlocks(expected) @@ -237,12 +237,12 @@ def test_StaticArray_set_copy(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, otherArray.stored_value).slot, + cast(pt.ScratchVar, otherArray._stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -270,7 +270,7 @@ def test_StaticArray_set_computed(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -317,7 +317,7 @@ def test_StaticBytes_set_py_bytes(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -352,13 +352,13 @@ def test_StaticBytes_expr(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.int, 32), pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.eq), @@ -381,7 +381,7 @@ def test_StaticArray_encode(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/bool.py b/pyteal/ast/abi/bool.py index 13552b6db..6fa6d72a3 100644 --- a/pyteal/ast/abi/bool.py +++ b/pyteal/ast/abi/bool.py @@ -50,7 +50,7 @@ def get(self) -> Expr: expression that evaluates to 0 will be returned. In either case, the expression will have the type TealType.uint64. """ - return self.stored_value.load() + return self._stored_value.load() def set(self, value: Union[bool, Expr, "Bool", ComputedValue["Bool"]]) -> Expr: """Set the value of this Bool to the input value. @@ -85,10 +85,10 @@ def set(self, value: Union[bool, Expr, "Bool", ComputedValue["Bool"]]) -> Expr: checked = True if checked: - return self.stored_value.store(value) + return self._stored_value.store(value) # Not(Not(value)) coerces all values greater than 0 to 1 - return self.stored_value.store(Not(Not(value))) + return self._stored_value.store(Not(Not(value))) def decode( self, @@ -103,7 +103,7 @@ def decode( return self.decode_bit(encoded, start_index * Int(NUM_BITS_IN_BYTE)) def decode_bit(self, encoded, bit_index: Expr) -> Expr: - return self.stored_value.store(GetBit(encoded, bit_index)) + return self._stored_value.store(GetBit(encoded, bit_index)) def encode(self) -> Expr: return SetBit(Bytes(b"\x00"), Int(0), self.get()) diff --git a/pyteal/ast/abi/bool_test.py b/pyteal/ast/abi/bool_test.py index 1cf881d55..7dfb5c684 100644 --- a/pyteal/ast/abi/bool_test.py +++ b/pyteal/ast/abi/bool_test.py @@ -56,7 +56,7 @@ def test_Bool_set_static(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -85,7 +85,7 @@ def test_Bool_set_expr(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -110,12 +110,12 @@ def test_Bool_set_copy(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, other.stored_value).slot, + cast(pt.ScratchVar, other._stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -144,7 +144,7 @@ def test_Bool_set_computed(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -171,7 +171,7 @@ def test_Bool_get(): pt.TealOp( expr, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -203,7 +203,7 @@ def test_Bool_decode(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -232,7 +232,7 @@ def test_Bool_decode_bit(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -258,7 +258,7 @@ def test_Bool_encode(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.setbit), ] @@ -442,7 +442,7 @@ class EncodeSeqTest(NamedTuple): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, testType.stored_value).slot, + cast(pt.ScratchVar, testType._stored_value).slot, ), pt.TealOp(None, pt.Op.setbit), ] diff --git a/pyteal/ast/abi/reference_type.py b/pyteal/ast/abi/reference_type.py index f4882fc97..e1a228245 100644 --- a/pyteal/ast/abi/reference_type.py +++ b/pyteal/ast/abi/reference_type.py @@ -58,7 +58,7 @@ def referenced_index(self) -> Expr: If this reference type is an application or asset, note that this DOES NOT return the application or asset ID. See :code:`application_id()` or :code:`asset_id()` for that. """ - return self.stored_value.load() + return self._stored_value.load() def decode( self, @@ -70,7 +70,7 @@ def decode( ) -> Expr: return uint_decode( self.type_spec().bit_size(), - self.stored_value, + self._stored_value, encoded, start_index, end_index, @@ -107,7 +107,7 @@ def __init__(self) -> None: def address(self) -> Expr: """Get the address of the account.""" - return Txn.accounts[self.stored_value.load()] + return Txn.accounts[self._stored_value.load()] def params(self) -> AccountParamObject: """Get information about the account.""" @@ -205,7 +205,7 @@ def __init__(self) -> None: def application_id(self) -> Expr: """Get the ID of the application.""" - return Txn.applications[self.stored_value.load()] + return Txn.applications[self._stored_value.load()] def params(self) -> AppParamObject: """Get information about the application's parameters.""" diff --git a/pyteal/ast/abi/reference_type_test.py b/pyteal/ast/abi/reference_type_test.py index 4ec862e66..cbbc45d34 100644 --- a/pyteal/ast/abi/reference_type_test.py +++ b/pyteal/ast/abi/reference_type_test.py @@ -26,7 +26,7 @@ def test_ReferenceType_referenced_index(): pt.TealOp( expr, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -61,7 +61,7 @@ def test_ReferenceType_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expected_decoding = value.stored_value.store( + expected_decoding = value._stored_value.store( pt.GetByte( encoded, start_index if start_index is not None else pt.Int(0), @@ -117,7 +117,7 @@ def test_Account_address(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.txnas, "Accounts"), ] @@ -204,7 +204,7 @@ def test_Asset_asset_id(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.txnas, "Assets"), ] @@ -298,7 +298,7 @@ def test_Application_application_id(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.txnas, "Applications"), ] diff --git a/pyteal/ast/abi/string.py b/pyteal/ast/abi/string.py index ac5866cb2..f142eaa55 100644 --- a/pyteal/ast/abi/string.py +++ b/pyteal/ast/abi/string.py @@ -68,7 +68,7 @@ def get(self) -> Expr: The expression will have the type TealType.bytes. """ return Suffix( - self.stored_value.load(), Int(Uint16TypeSpec().byte_length_static()) + self._stored_value.load(), Int(Uint16TypeSpec().byte_length_static()) ) def set( @@ -111,18 +111,18 @@ def set( if value.type_spec() == StringTypeSpec() or ( value.type_spec() == DynamicArrayTypeSpec(ByteTypeSpec()) ): - return self.stored_value.store(value.stored_value.load()) + return self._stored_value.store(value._stored_value.load()) raise TealInputError( f"Got {value} with type spec {value.type_spec()}, expected {StringTypeSpec}" ) case bytes() | bytearray(): - return self.stored_value.store(_encoded_byte_string(value)) + return self._stored_value.store(_encoded_byte_string(value)) case str(): - return self.stored_value.store(_encoded_byte_string(value.encode())) + return self._stored_value.store(_encoded_byte_string(value.encode())) case Expr(): return _store_encoded_expr_byte_string_into_var( - value, self.stored_value + value, self._stored_value ) case CollectionSequence(): return super().set(cast(Sequence[Byte], value)) diff --git a/pyteal/ast/abi/string_test.py b/pyteal/ast/abi/string_test.py index c60ac52f4..9ebcbfadd 100644 --- a/pyteal/ast/abi/string_test.py +++ b/pyteal/ast/abi/string_test.py @@ -44,7 +44,7 @@ def test_String_encode(): pt.TealOp( expr, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -76,7 +76,7 @@ def test_DynamicArray_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expectedExpr = value.stored_value.store( + expectedExpr = value._stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -107,7 +107,7 @@ def test_String_get(): pt.TealOp( expr, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.extract, 2, 0), ] @@ -143,7 +143,7 @@ def test_String_set_static(value_to_set, value_encoded): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -174,12 +174,12 @@ def test_String_set_expr(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.itob), @@ -187,13 +187,13 @@ def test_String_set_expr(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.concat), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -222,12 +222,12 @@ def test_String_set_copy(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, other.stored_value).slot, + cast(pt.ScratchVar, other._stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -259,7 +259,7 @@ def test_String_set_computed(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/transaction.py b/pyteal/ast/abi/transaction.py index aeb5c7a33..69de7ea29 100644 --- a/pyteal/ast/abi/transaction.py +++ b/pyteal/ast/abi/transaction.py @@ -82,16 +82,16 @@ def _set_index( case ComputedValue(): return self._set_with_computed_type(value) case BaseType(): - return self.stored_value.store(self.stored_value.load()) + return self._stored_value.store(self._stored_value.load()) case int(): - return self.stored_value.store(Int(value)) + return self._stored_value.store(Int(value)) case Expr(): - return self.stored_value.store(value) + return self._stored_value.store(value) case _: raise TealInputError(f"Cant store a {type(value)} in a Transaction") def index(self) -> Expr: - return self.stored_value.load() + return self._stored_value.load() def decode( self, diff --git a/pyteal/ast/abi/transaction_test.py b/pyteal/ast/abi/transaction_test.py index b4c27a97c..3b0cdeae1 100644 --- a/pyteal/ast/abi/transaction_test.py +++ b/pyteal/ast/abi/transaction_test.py @@ -134,7 +134,7 @@ def test_Transaction__set_index(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, tv.t.stored_value).slot, + cast(pt.ScratchVar, tv.t._stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/tuple.py b/pyteal/ast/abi/tuple.py index bc1966414..3149250a6 100644 --- a/pyteal/ast/abi/tuple.py +++ b/pyteal/ast/abi/tuple.py @@ -309,7 +309,7 @@ def decode( extracted = substring_for_decoding( encoded, start_index=start_index, end_index=end_index, length=length ) - return self.stored_value.store(extracted) + return self._stored_value.store(extracted) @overload def set(self, *values: BaseType) -> Expr: @@ -352,10 +352,10 @@ def set(self, *values): ) if not all(myTypes[i] == values[i].type_spec() for i in range(len(myTypes))): raise TealInputError("Input values do not match type") - return self.stored_value.store(_encode_tuple(values)) + return self._stored_value.store(_encode_tuple(values)) def encode(self) -> Expr: - return self.stored_value.load() + return self._stored_value.load() def length(self) -> Expr: """Get the number of values this tuple holds as an Expr.""" diff --git a/pyteal/ast/abi/tuple_test.py b/pyteal/ast/abi/tuple_test.py index a761d88af..b175ce7bd 100644 --- a/pyteal/ast/abi/tuple_test.py +++ b/pyteal/ast/abi/tuple_test.py @@ -623,7 +623,7 @@ def test_Tuple_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = tupleValue.stored_value.store( + expectedExpr = tupleValue._stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -672,7 +672,9 @@ def test_Tuple_set(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = tupleValue.stored_value.store(_encode_tuple([uint8, uint16, uint32])) + expectedExpr = tupleValue._stored_value.store( + _encode_tuple([uint8, uint16, uint32]) + ) expected, _ = expectedExpr.__teal__(options) expected.addIncoming() expected = pt.TealBlock.NormalizeBlocks(expected) @@ -704,7 +706,7 @@ def test_Tuple_set_Computed(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, tupleValue.stored_value).slot, + cast(pt.ScratchVar, tupleValue._stored_value).slot, ), ] ) @@ -735,7 +737,7 @@ def test_Tuple_encode(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, tupleValue.stored_value).slot, + cast(pt.ScratchVar, tupleValue._stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index b87fe1282..adb76ecf3 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -77,16 +77,16 @@ def __init__(self, spec: TypeSpec) -> None: """Create a new BaseType.""" super().__init__() self._type_spec: Final[TypeSpec] = spec - self.stored_value: AbstractVar = ScratchVar(spec.storage_type()) + self._stored_value: AbstractVar = ScratchVar(spec.storage_type()) def _set_data_source(self, storage: AbstractVar) -> None: - self.stored_value = storage + self._stored_value = storage def _load_value(self) -> Expr: - return self.stored_value.load() + return self._stored_value.load() def _store_value(self, value: Expr) -> Expr: - return self.stored_value.store(value) + return self._stored_value.store(value) def type_spec(self) -> TypeSpec: """Get the TypeSpec for this ABI type instance.""" @@ -240,7 +240,7 @@ def store_into(self, output: BaseType) -> Expr: f"ABI return subroutine deferred_expr is expected to be typed {output.type_spec().storage_type()}, " f"but has type {declaration.deferred_expr.type_of()}." ) - return output.stored_value.store(self.computation) + return output._stored_value.store(self.computation) ReturnedValue.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/type_test.py b/pyteal/ast/abi/type_test.py index 56a9e6c76..568ebf94c 100644 --- a/pyteal/ast/abi/type_test.py +++ b/pyteal/ast/abi/type_test.py @@ -17,7 +17,7 @@ def store_into(self, output: abi.BaseType) -> pt.Expr: raise pt.TealInputError( f"expected type_spec {self.type_spec} but get {output.type_spec()}" ) - return output.stored_value.store(self.encodings) + return output._stored_value.store(self.encodings) def test_ComputedType_use(): diff --git a/pyteal/ast/abi/uint.py b/pyteal/ast/abi/uint.py index 0a99eb27f..c3f7c7f98 100644 --- a/pyteal/ast/abi/uint.py +++ b/pyteal/ast/abi/uint.py @@ -239,7 +239,7 @@ def get(self) -> Expr: The expression will have the type TealType.uint64. """ - return self.stored_value.load() + return self._stored_value.load() def set(self, value: Union[int, Expr, "Uint", ComputedValue["Uint"]]) -> Expr: """Set the value of this Uint to the input value. @@ -274,7 +274,7 @@ def set(self, value: Union[int, Expr, "Uint", ComputedValue["Uint"]]) -> Expr: value.type_spec(), self.type_spec() ) ) - return uint_set(self.type_spec().bit_size(), self.stored_value, value) + return uint_set(self.type_spec().bit_size(), self._stored_value, value) def decode( self, @@ -286,7 +286,7 @@ def decode( ) -> Expr: return uint_decode( self.type_spec().bit_size(), - self.stored_value, + self._stored_value, encoded, start_index, end_index, @@ -294,7 +294,7 @@ def decode( ) def encode(self) -> Expr: - return uint_encode(self.type_spec().bit_size(), self.stored_value) + return uint_encode(self.type_spec().bit_size(), self._stored_value) Uint.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/uint_test.py b/pyteal/ast/abi/uint_test.py index 26ba3541f..b9a74b64d 100644 --- a/pyteal/ast/abi/uint_test.py +++ b/pyteal/ast/abi/uint_test.py @@ -142,7 +142,7 @@ def test_Uint_set_static(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -174,7 +174,7 @@ def test_Uint_set_expr(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.int, test.maxValue + 1), pt.TealOp(None, pt.Op.lt), @@ -189,7 +189,7 @@ def test_Uint_set_expr(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] + upperBoundCheck @@ -216,12 +216,12 @@ def test_Uint_set_copy(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, other.stored_value).slot, + cast(pt.ScratchVar, other._stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -253,7 +253,7 @@ def test_Uint_set_computed(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -281,7 +281,7 @@ def test_Uint_get(): pt.TealOp( expr, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -307,7 +307,7 @@ def test_Uint_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedDecoding = value.stored_value.store( + expectedDecoding = value._stored_value.store( test.expectedDecoding(encoded, start_index, end_index, length) ) expected, _ = expectedDecoding.__teal__(options) @@ -359,12 +359,12 @@ def test_ByteUint8_mutual_conversion(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, other.stored_value).slot, + cast(pt.ScratchVar, other._stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, type_b_instance.stored_value).slot, + cast(pt.ScratchVar, type_b_instance._stored_value).slot, ), ] ) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 437c9535d..f3bf83a2c 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -378,7 +378,7 @@ def __init__( elif isinstance(arg, ScratchVar): arg_type = arg.type elif isinstance(arg, abi.BaseType): - arg_type = cast(abi.BaseType, arg).stored_value.storage_type() + arg_type = cast(abi.BaseType, arg)._stored_value.storage_type() else: raise TealInputError( f"Subroutine argument {arg} at index {i} was of unexpected Python type {type(arg)}" @@ -420,7 +420,7 @@ def handle_arg(arg: Expr | ScratchVar | abi.BaseType) -> Expr: elif isinstance(arg, Expr): return arg elif isinstance(arg, abi.BaseType): - return arg.stored_value.load() + return arg._stored_value.load() else: raise TealInputError( f"cannot handle current arg: {arg} to put it on stack" @@ -799,11 +799,11 @@ def var_n_loaded( loaded_var = argument_var elif param in subroutine.abi_args: internal_abi_var = subroutine.abi_args[param].new_instance() - if not isinstance(internal_abi_var.stored_value, ScratchVar): + if not isinstance(internal_abi_var._stored_value, ScratchVar): raise TealInternalError( "subroutine ABI args must have data schema being ScratchVarStorage" ) - argument_var = internal_abi_var.stored_value + argument_var = internal_abi_var._stored_value loaded_var = internal_abi_var else: argument_var = ScratchVar(TealType.anytype) @@ -851,7 +851,7 @@ def var_n_loaded( f"ABI returning subroutine definition should evaluate to TealType.none, " f"while evaluate to {subroutine_body.type_of()}." ) - deferred_expr = output_carrying_abi.stored_value.load() + deferred_expr = output_carrying_abi._stored_value.load() # Arg usage "A" to be pick up and store in scratch parameters that have been placed on the stack # need to reverse order of argumentVars because the last argument will be on top of the stack From 4b688dfd4879af15617ecbd934194c3c01018b2d Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 11:35:33 -0400 Subject: [PATCH 051/206] proto renaming stuffs --- pyteal/ast/frame.py | 12 ++++++------ pyteal/ast/subroutine.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 0a15e1a6b..7cccefb58 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -12,7 +12,7 @@ class Proto(Expr): - def __init__(self, num_args: int, num_returns: int, /, *, reserve_spot: int = 0): + def __init__(self, num_args: int, num_returns: int, /, *, num_local_vars: int = 0): super().__init__() if num_args < 0: raise TealInputError( @@ -24,7 +24,7 @@ def __init__(self, num_args: int, num_returns: int, /, *, reserve_spot: int = 0) ) self.num_args = num_args self.num_returns = num_returns - self.reserve_spot = reserve_spot + self.num_local_vars = num_local_vars def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: verifyProgramVersion( @@ -34,19 +34,19 @@ def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBloc ) op = TealOp(self, Op.proto, self.num_args, self.num_returns) proto_srt, proto_end = TealBlock.FromOp(options, op) - if self.reserve_spot == 0: + if self.num_local_vars == 0: return proto_srt, proto_end - elif self.reserve_spot == 1: + elif self.num_local_vars == 1: int_srt, int_end = Int(0).__teal__(options) proto_end.setNextBlock(int_srt) return proto_srt, int_end else: - dupn_srt, dupn_end = DupN(Int(0), self.reserve_spot).__teal__(options) + dupn_srt, dupn_end = DupN(Int(0), self.num_local_vars).__teal__(options) proto_end.setNextBlock(dupn_srt) return proto_srt, dupn_end def __str__(self) -> str: - return f"(proto: arg_num = {self.num_args}, ret_num = {self.num_returns}, reserve_spot = {self.reserve_spot})" + return f"(proto: num_args = {self.num_args}, num_rets = {self.num_returns}, num_local_vars = {self.num_local_vars})" def type_of(self) -> TealType: return TealType.none diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index d40f04746..8ac61c066 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -1032,7 +1032,7 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: Proto( subroutine.argument_count(), stack_output_cnt, - reserve_spot=int(subroutine.has_abi_output), + num_local_vars=int(subroutine.has_abi_output), ) ] From 0f5c916cec9946146cc5c9e5508c783d6d7ecb33 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 12:06:10 -0400 Subject: [PATCH 052/206] per pr comment, rename to FrameVar --- pyteal/__init__.pyi | 2 +- pyteal/ast/__init__.py | 4 ++-- pyteal/ast/frame.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index baf5ae050..2e03200b2 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -122,7 +122,7 @@ __all__ = [ "For", "FrameBury", "FrameDig", - "FrameStorage", + "FrameVar", "Ge", "GeneratedID", "GetBit", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 0f2bcaa34..f4ebd5f88 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -155,7 +155,7 @@ from pyteal.ast.for_ import For from pyteal.ast.break_ import Break from pyteal.ast.continue_ import Continue -from pyteal.ast.frame import Proto, FrameDig, FrameBury, PopN, DupN, Bury, FrameStorage +from pyteal.ast.frame import Proto, FrameDig, FrameBury, PopN, DupN, Bury, FrameVar # misc from pyteal.ast.scratch import ( @@ -344,7 +344,7 @@ "Bury", "DupN", "PopN", - "FrameStorage", + "FrameVar", "Router", "CallConfig", "MethodConfig", diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 25aa437fc..7c71333f5 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -102,7 +102,7 @@ def has_return(self) -> bool: FrameBury.__module__ = "pyteal" -class FrameStorage(AbstractVar): +class FrameVar(AbstractVar): def __init__(self, storage_type: TealType, stack_depth: int) -> None: super().__init__() self.stack_type = storage_type @@ -122,7 +122,7 @@ def load(self) -> Expr: return FrameDig(self.stack_depth) -FrameStorage.__module__ = "pyteal" +FrameVar.__module__ = "pyteal" class Bury(Expr): From 0924d94de17751eed420349717341d6064913f75 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 12:11:45 -0400 Subject: [PATCH 053/206] take bury out --- pyteal/__init__.pyi | 1 - pyteal/ast/__init__.py | 3 +-- pyteal/ast/frame.py | 31 ------------------------------- pyteal/ast/frame_test.py | 30 ------------------------------ 4 files changed, 1 insertion(+), 64 deletions(-) diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index 40600d561..7682ab0b7 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -71,7 +71,6 @@ __all__ = [ "BoxReplace", "Break", "Btoi", - "Bury", "Bytes", "BytesAdd", "BytesAnd", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 1ca49a2e5..a1b21e071 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -155,7 +155,7 @@ from pyteal.ast.for_ import For from pyteal.ast.break_ import Break from pyteal.ast.continue_ import Continue -from pyteal.ast.frame import Proto, FrameDig, FrameBury, PopN, DupN, Bury +from pyteal.ast.frame import Proto, FrameDig, FrameBury, PopN, DupN # misc from pyteal.ast.scratch import ( @@ -340,7 +340,6 @@ "Proto", "FrameDig", "FrameBury", - "Bury", "DupN", "PopN", "Router", diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 68ce3a2f2..9260d3064 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -101,37 +101,6 @@ def has_return(self) -> bool: FrameBury.__module__ = "pyteal" -class Bury(Expr): - def __init__(self, value: Expr, depth: int): - super().__init__() - require_type(value, TealType.anytype) - if depth <= 0: - raise TealInputError("bury depth should be strictly positive") - self.value = value - self.depth = depth - - def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: - verifyProgramVersion( - Op.bury.min_version, - options.version, - "Program version too low to use op bury", - ) - op = TealOp(self, Op.bury, self.depth) - return TealBlock.FromOp(options, op, self.value) - - def __str__(self) -> str: - return f"(bury (depth = {self.depth}) ({self.value}))" - - def type_of(self) -> TealType: - return TealType.none - - def has_return(self) -> bool: - return False - - -Bury.__module__ = "pyteal" - - class DupN(Expr): def __init__(self, value: Expr, repetition: int): super().__init__() diff --git a/pyteal/ast/frame_test.py b/pyteal/ast/frame_test.py index b21b47d0e..8bbbf26c1 100644 --- a/pyteal/ast/frame_test.py +++ b/pyteal/ast/frame_test.py @@ -77,36 +77,6 @@ def test_frame_bury_invalid(): pt.FrameBury(pt.Int(1), 1).__teal__(avm7Options) -def test_bury(): - byte_expr = pt.Bytes("Astartes") - expr = pt.Bury(byte_expr, 4) - assert not expr.has_return() - assert expr.type_of() == TealType.none - - expected = pt.TealSimpleBlock( - [ - pt.TealOp(byte_expr, pt.Op.byte, '"Astartes"'), - pt.TealOp(expr, pt.Op.bury, 4), - ] - ) - actual, _ = expr.__teal__(avm8Options) - actual.addIncoming() - actual = pt.TealBlock.NormalizeBlocks(actual) - - assert actual == expected - - -def test_bury_invalid(): - with pytest.raises(pt.TealTypeError): - pt.Bury(pt.Seq(), 1) - - with pytest.raises(pt.TealInputError): - pt.Bury(pt.Int(1), 0) - - with pytest.raises(pt.TealInputError): - pt.Bury(pt.Int(1), 1).__teal__(avm7Options) - - @pytest.mark.parametrize("repetition", [0, 1, 2, 3, 4, 5]) def test_popn(repetition: int): expr = pt.PopN(repetition) From d1c52a2504d2190064533cdaf410bc613449fd3c Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 12:29:53 -0400 Subject: [PATCH 054/206] pop popn --- pyteal/__init__.pyi | 1 - pyteal/ast/__init__.py | 3 +-- pyteal/ast/frame.py | 29 ----------------------------- pyteal/ast/frame_test.py | 22 ---------------------- 4 files changed, 1 insertion(+), 54 deletions(-) diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index 7682ab0b7..19dcc01fb 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -178,7 +178,6 @@ __all__ = [ "OptimizeOptions", "Or", "Pop", - "PopN", "Pragma", "Proto", "RETURN_HASH_PREFIX", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index a1b21e071..4a0b4e181 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -155,7 +155,7 @@ from pyteal.ast.for_ import For from pyteal.ast.break_ import Break from pyteal.ast.continue_ import Continue -from pyteal.ast.frame import Proto, FrameDig, FrameBury, PopN, DupN +from pyteal.ast.frame import Proto, FrameDig, FrameBury, DupN # misc from pyteal.ast.scratch import ( @@ -341,7 +341,6 @@ "FrameDig", "FrameBury", "DupN", - "PopN", "Router", "CallConfig", "MethodConfig", diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 9260d3064..8f5e24891 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -130,32 +130,3 @@ def has_return(self) -> bool: DupN.__module__ = "pyteal" - - -class PopN(Expr): - def __init__(self, repetition: int): - super().__init__() - if repetition < 0: - raise TealInputError("popn repetition should be non negative") - self.repetition = repetition - - def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: - verifyProgramVersion( - Op.popn.min_version, - options.version, - "Program version too low to use op popn", - ) - op = TealOp(self, Op.popn, self.repetition) - return TealBlock.FromOp(options, op) - - def __str__(self) -> str: - return f"(popn {self.repetition})" - - def type_of(self) -> TealType: - return TealType.none - - def has_return(self) -> bool: - return False - - -PopN.__module__ = "pyteal" diff --git a/pyteal/ast/frame_test.py b/pyteal/ast/frame_test.py index 8bbbf26c1..d02f526ba 100644 --- a/pyteal/ast/frame_test.py +++ b/pyteal/ast/frame_test.py @@ -77,28 +77,6 @@ def test_frame_bury_invalid(): pt.FrameBury(pt.Int(1), 1).__teal__(avm7Options) -@pytest.mark.parametrize("repetition", [0, 1, 2, 3, 4, 5]) -def test_popn(repetition: int): - expr = pt.PopN(repetition) - assert not expr.has_return() - assert expr.type_of() == pt.TealType.none - - expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.popn, repetition)]) - actual, _ = expr.__teal__(avm8Options) - actual.addIncoming() - actual = pt.TealBlock.NormalizeBlocks(actual) - - assert actual == expected - - -def test_popn_invalid(): - with pytest.raises(pt.TealInputError): - pt.PopN(-1) - - with pytest.raises(pt.TealInputError): - pt.PopN(5).__teal__(avm7Options) - - def test_dupn(): byte_expr = pt.Bytes("Astartes") expr = pt.DupN(byte_expr, 4) From d457f99da2649f7a4060d747757abee73a83b2f6 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 12:53:59 -0400 Subject: [PATCH 055/206] abstractvar.py --- pyteal/ast/__init__.py | 3 ++- pyteal/ast/abstractvar.py | 20 ++++++++++++++++++++ pyteal/ast/scratchvar.py | 20 +------------------- 3 files changed, 23 insertions(+), 20 deletions(-) create mode 100644 pyteal/ast/abstractvar.py diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 1721ce522..7de5e044a 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -165,7 +165,8 @@ ScratchStackStore, ScratchStore, ) -from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar, AbstractVar +from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar +from pyteal.ast.abstractvar import AbstractVar from pyteal.ast.maybe import MaybeValue from pyteal.ast.multi import MultiValue from pyteal.ast.opup import OpUp, OpUpMode, OpUpFeeSource diff --git a/pyteal/ast/abstractvar.py b/pyteal/ast/abstractvar.py new file mode 100644 index 000000000..59788e001 --- /dev/null +++ b/pyteal/ast/abstractvar.py @@ -0,0 +1,20 @@ +from abc import ABC, abstractmethod +from pyteal.types import TealType +from pyteal.ast.expr import Expr + + +class AbstractVar(ABC): + @abstractmethod + def store(self, value: Expr) -> Expr: + pass + + @abstractmethod + def load(self) -> Expr: + pass + + @abstractmethod + def storage_type(self) -> TealType: + pass + + +AbstractVar.__module__ = "pyteal" diff --git a/pyteal/ast/scratchvar.py b/pyteal/ast/scratchvar.py index 7b4962f97..e97b5d1ef 100644 --- a/pyteal/ast/scratchvar.py +++ b/pyteal/ast/scratchvar.py @@ -1,29 +1,11 @@ -from abc import ABC, abstractmethod - from pyteal.errors import TealInputError from pyteal.types import TealType, require_type, types_match +from pyteal.ast.abstractvar import AbstractVar from pyteal.ast.expr import Expr from pyteal.ast.scratch import ScratchSlot, ScratchLoad, ScratchStore -class AbstractVar(ABC): - @abstractmethod - def store(self, value: Expr) -> Expr: - pass - - @abstractmethod - def load(self) -> Expr: - pass - - @abstractmethod - def storage_type(self) -> TealType: - pass - - -AbstractVar.__module__ = "pyteal" - - class ScratchVar(AbstractVar): """ Interface around Scratch space, similar to get/put local/global state From 95bc48a97520da835394ffdb01a374ef542bbfd7 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 14:00:46 -0400 Subject: [PATCH 056/206] unexport FrameVar and AbstractVar --- pyteal/__init__.pyi | 2 -- pyteal/ast/__init__.py | 5 +---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index 56c22a572..19dcc01fb 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -35,7 +35,6 @@ from pyteal.config import ( __all__ = [ "ABIReturnSubroutine", - "AbstractVar", "AccountParam", "AccountParamObject", "Add", @@ -121,7 +120,6 @@ __all__ = [ "For", "FrameBury", "FrameDig", - "FrameVar", "Ge", "GeneratedID", "GetBit", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 7de5e044a..4a0b4e181 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -155,7 +155,7 @@ from pyteal.ast.for_ import For from pyteal.ast.break_ import Break from pyteal.ast.continue_ import Continue -from pyteal.ast.frame import Proto, FrameDig, FrameBury, DupN, FrameVar +from pyteal.ast.frame import Proto, FrameDig, FrameBury, DupN # misc from pyteal.ast.scratch import ( @@ -166,7 +166,6 @@ ScratchStore, ) from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar -from pyteal.ast.abstractvar import AbstractVar from pyteal.ast.maybe import MaybeValue from pyteal.ast.multi import MultiValue from pyteal.ast.opup import OpUp, OpUpMode, OpUpFeeSource @@ -306,7 +305,6 @@ "ScratchStore", "DynamicScratchVar", "ScratchVar", - "AbstractVar", "MaybeValue", "MultiValue", "OpUp", @@ -343,7 +341,6 @@ "FrameDig", "FrameBury", "DupN", - "FrameVar", "Router", "CallConfig", "MethodConfig", From 8c41726c6d663ee5aff5241062e91a42ce336f4c Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 14:04:58 -0400 Subject: [PATCH 057/206] unexport use of frame ops --- pyteal/__init__.pyi | 4 ---- pyteal/ast/__init__.py | 5 ----- pyteal/ast/frame_test.py | 30 +++++++++++++++--------------- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index 19dcc01fb..3f69e10bd 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -99,7 +99,6 @@ __all__ = [ "DEFAULT_TEAL_VERSION", "Div", "Divw", - "DupN", "DynamicScratchVar", "EcdsaCurve", "EcdsaDecompress", @@ -118,8 +117,6 @@ __all__ = [ "ExtractUint64", "FRAME_POINTER_VERSION", "For", - "FrameBury", - "FrameDig", "Ge", "GeneratedID", "GetBit", @@ -179,7 +176,6 @@ __all__ = [ "Or", "Pop", "Pragma", - "Proto", "RETURN_HASH_PREFIX", "Reject", "Replace", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 4a0b4e181..9efe807c5 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -155,7 +155,6 @@ from pyteal.ast.for_ import For from pyteal.ast.break_ import Break from pyteal.ast.continue_ import Continue -from pyteal.ast.frame import Proto, FrameDig, FrameBury, DupN # misc from pyteal.ast.scratch import ( @@ -337,10 +336,6 @@ "For", "Break", "Continue", - "Proto", - "FrameDig", - "FrameBury", - "DupN", "Router", "CallConfig", "MethodConfig", diff --git a/pyteal/ast/frame_test.py b/pyteal/ast/frame_test.py index d02f526ba..e4cde2aa4 100644 --- a/pyteal/ast/frame_test.py +++ b/pyteal/ast/frame_test.py @@ -1,6 +1,6 @@ import pytest import pyteal as pt -from pyteal.types import TealType +from pyteal.ast.frame import FrameBury, FrameDig, Proto, DupN avm7Options = pt.CompileOptions(version=7) avm8Options = pt.CompileOptions(version=8) @@ -8,7 +8,7 @@ @pytest.mark.parametrize("input_num, output_num", [(1, 1), (1, 0), (5, 5)]) def test_proto(input_num: int, output_num: int): - expr = pt.Proto(input_num, output_num) + expr = Proto(input_num, output_num) assert not expr.has_return() assert expr.type_of() == pt.TealType.none @@ -22,18 +22,18 @@ def test_proto(input_num: int, output_num: int): def test_proto_invalid(): with pytest.raises(pt.TealInputError): - pt.Proto(-1, 1) + Proto(-1, 1) with pytest.raises(pt.TealInputError): - pt.Proto(1, -1) + Proto(1, -1) with pytest.raises(pt.TealInputError): - pt.Proto(1, 1).__teal__(avm7Options) + Proto(1, 1).__teal__(avm7Options) @pytest.mark.parametrize("depth", [-1, 0, 1, 2]) def test_frame_dig(depth: int): - expr = pt.FrameDig(depth) + expr = FrameDig(depth) assert not expr.has_return() assert expr.type_of() == pt.TealType.anytype @@ -47,14 +47,14 @@ def test_frame_dig(depth: int): def test_frame_dig_invalid(): with pytest.raises(pt.TealInputError): - pt.FrameDig(1).__teal__(avm7Options) + FrameDig(1).__teal__(avm7Options) def test_frame_bury(): byte_expr = pt.Bytes("Astartes") - expr = pt.FrameBury(byte_expr, 4) + expr = FrameBury(byte_expr, 4) assert not expr.has_return() - assert expr.type_of() == TealType.none + assert expr.type_of() == pt.TealType.none expected = pt.TealSimpleBlock( [ @@ -71,15 +71,15 @@ def test_frame_bury(): def test_frame_bury_invalid(): with pytest.raises(pt.TealTypeError): - pt.FrameBury(pt.Seq(), 1) + FrameBury(pt.Seq(), 1) with pytest.raises(pt.TealInputError): - pt.FrameBury(pt.Int(1), 1).__teal__(avm7Options) + FrameBury(pt.Int(1), 1).__teal__(avm7Options) def test_dupn(): byte_expr = pt.Bytes("Astartes") - expr = pt.DupN(byte_expr, 4) + expr = DupN(byte_expr, 4) assert not expr.has_return() assert expr.type_of() == byte_expr.type_of() @@ -98,10 +98,10 @@ def test_dupn(): def test_dupn_invalid(): with pytest.raises(pt.TealTypeError): - pt.DupN(pt.Seq(), 1) + DupN(pt.Seq(), 1) with pytest.raises(pt.TealInputError): - pt.DupN(pt.Int(1), -1) + DupN(pt.Int(1), -1) with pytest.raises(pt.TealInputError): - pt.DupN(pt.Int(1), 1).__teal__(avm7Options) + DupN(pt.Int(1), 1).__teal__(avm7Options) From 075710e38114c9294061e2381e6433d19f034a95 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 14:34:17 -0400 Subject: [PATCH 058/206] rename to num allocs --- pyteal/ast/frame.py | 12 ++++++------ pyteal/ast/subroutine.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 88d0a1798..ff2cb9e6c 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -12,7 +12,7 @@ class Proto(Expr): - def __init__(self, num_args: int, num_returns: int, /, *, num_local_vars: int = 0): + def __init__(self, num_args: int, num_returns: int, /, *, num_allocs: int = 0): super().__init__() if num_args < 0: raise TealInputError( @@ -24,7 +24,7 @@ def __init__(self, num_args: int, num_returns: int, /, *, num_local_vars: int = ) self.num_args = num_args self.num_returns = num_returns - self.num_local_vars = num_local_vars + self.num_allocs = num_allocs def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: verifyProgramVersion( @@ -34,19 +34,19 @@ def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBloc ) op = TealOp(self, Op.proto, self.num_args, self.num_returns) proto_srt, proto_end = TealBlock.FromOp(options, op) - if self.num_local_vars == 0: + if self.num_allocs == 0: return proto_srt, proto_end - elif self.num_local_vars == 1: + elif self.num_allocs == 1: int_srt, int_end = Int(0).__teal__(options) proto_end.setNextBlock(int_srt) return proto_srt, int_end else: - dupn_srt, dupn_end = DupN(Int(0), self.num_local_vars).__teal__(options) + dupn_srt, dupn_end = DupN(Int(0), self.num_allocs).__teal__(options) proto_end.setNextBlock(dupn_srt) return proto_srt, dupn_end def __str__(self) -> str: - return f"(proto: num_args = {self.num_args}, num_rets = {self.num_returns}, num_local_vars = {self.num_local_vars})" + return f"(proto: num_args = {self.num_args}, num_rets = {self.num_returns}, num_allocs = {self.num_allocs})" def type_of(self) -> TealType: return TealType.none diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index a57d100b4..36c343a8f 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -1032,7 +1032,7 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: Proto( subroutine.argument_count(), stack_output_cnt, - num_local_vars=int(subroutine.has_abi_output), + num_allocs=int(subroutine.has_abi_output), ) ] From 61551b83d6d8beac69b3c1c6469a43f17fea320f Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 14:49:48 -0400 Subject: [PATCH 059/206] remove _set_data_storage --- pyteal/ast/abi/type.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index adb76ecf3..24f396cf3 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -79,9 +79,6 @@ def __init__(self, spec: TypeSpec) -> None: self._type_spec: Final[TypeSpec] = spec self._stored_value: AbstractVar = ScratchVar(spec.storage_type()) - def _set_data_source(self, storage: AbstractVar) -> None: - self._stored_value = storage - def _load_value(self) -> Expr: return self._stored_value.load() From 885500281e98aaff7827fdd887d7bebf45e42acb Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 15:05:56 -0400 Subject: [PATCH 060/206] namedtuple set var method --- pyteal/ast/abi/tuple.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyteal/ast/abi/tuple.py b/pyteal/ast/abi/tuple.py index 458604f70..2d744eeeb 100644 --- a/pyteal/ast/abi/tuple.py +++ b/pyteal/ast/abi/tuple.py @@ -683,7 +683,7 @@ def __setattr__(self, name: str, field: Any) -> None: # NamedTuple is an argument, and inside subroutine, subroutine set internal ABI value with FrameStorage # This used to violate `__setattr__` for not allowing any assignment to attributes # Now this case is lifted such that we can shift the storage scheme. - if name.startswith("_") and name != "_NamedTuple__ready" and self.__ready: + if name == "_stored_value" and self.__ready: super().__setattr__(name, field) return raise TealInputError("cannot assign to NamedTuple attributes.") From 8eca96d6b1f1b29a1661bf7c0de95d4dbd411071 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 15:19:04 -0400 Subject: [PATCH 061/206] rename from stack_depth to frame_index --- pyteal/ast/frame.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index ac32eabd0..9ddcf237a 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -103,19 +103,19 @@ def has_return(self) -> bool: class FrameVar(AbstractVar): - def __init__(self, storage_type: TealType, stack_depth: int) -> None: + def __init__(self, storage_type: TealType, frame_index: int) -> None: super().__init__() self.stack_type = storage_type - self.stack_depth = stack_depth + self.frame_index = frame_index def storage_type(self) -> TealType: return self.stack_type def store(self, value: Expr) -> Expr: - return FrameBury(value, self.stack_depth) + return FrameBury(value, self.frame_index) def load(self) -> Expr: - return FrameDig(self.stack_depth) + return FrameDig(self.frame_index) FrameVar.__module__ = "pyteal" From c241cfa19c8290072b4707f21aace38e0a720053 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 16:29:57 -0400 Subject: [PATCH 062/206] CHANGELOG.md --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ff7c84a7..3b3f7c841 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Unreleased +## Added +* adding program page related ops ([#412](https://github.com/algorand/pyteal/pull/412)) +* Add Replace ([#413](https://github.com/algorand/pyteal/pull/413)) +* Add Block ([#415](https://github.com/algorand/pyteal/pull/415)) +* Add JsonRef ([#417](https://github.com/algorand/pyteal/pull/417)) +* Add Base64Decode ([#418](https://github.com/algorand/pyteal/pull/418)) +* Support Secp256r1 curve ([#423](https://github.com/algorand/pyteal/pull/423)) +* Add VrfVerify ([#419](https://github.com/algorand/pyteal/pull/419)) +* Add Sha3_256 ([#425](https://github.com/algorand/pyteal/pull/425)) +* Support FirstValidTime transaction field ([#424](https://github.com/algorand/pyteal/pull/424)) +* Add Ed25519Verify_Bare ([#426](https://github.com/algorand/pyteal/pull/426)) +* AVM Boxes Ops in Pyteal ([#438](https://github.com/algorand/pyteal/pull/438)) +* Support new AVM 8 account parameters ([#555](https://github.com/algorand/pyteal/pull/555)) + +## Changed +* Changes to avm8 docs ([#546](https://github.com/algorand/pyteal/pull/546)) + # 0.19.0 ## Added From dd687c7643b2e87f241f96250f43e689abb91abf Mon Sep 17 00:00:00 2001 From: Hang Su <87964331+ahangsu@users.noreply.github.com> Date: Wed, 2 Nov 2022 17:12:36 -0400 Subject: [PATCH 063/206] Frame Ops to `avm8` branch PR (#585) * add frame ops to avm8 branch * specify FRAME_POINTER_VERSION in frame-op branch * per review comments * per review comments * per review comments, depth -> frame_depth * take bury out * pop popn * unexport use of frame ops * hide FRAME_POINTER_VERISON --- pyteal/ast/frame.py | 132 ++++++++++++++++++++++++++++++++++++ pyteal/ast/frame_test.py | 107 +++++++++++++++++++++++++++++ pyteal/compiler/compiler.py | 1 + pyteal/ir/ops.py | 8 ++- 4 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 pyteal/ast/frame.py create mode 100644 pyteal/ast/frame_test.py diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py new file mode 100644 index 000000000..8f5e24891 --- /dev/null +++ b/pyteal/ast/frame.py @@ -0,0 +1,132 @@ +from typing import TYPE_CHECKING + +from pyteal.ast.expr import Expr +from pyteal.types import TealType, require_type +from pyteal.errors import TealInputError, verifyProgramVersion +from pyteal.ir import TealBlock, TealSimpleBlock, TealOp, Op + +if TYPE_CHECKING: + from pyteal.compiler import CompileOptions + + +class Proto(Expr): + def __init__(self, num_args: int, num_returns: int): + super().__init__() + if num_args < 0: + raise TealInputError( + f"the number of arguments provided to Proto must be >= 0 but {num_args=}" + ) + if num_returns < 0: + raise TealInputError( + f"the number of return values provided to Proto must be >= 0 but {num_returns=}" + ) + self.num_args = num_args + self.num_returns = num_returns + + def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: + verifyProgramVersion( + Op.proto.min_version, + options.version, + "Program version too low to use op proto", + ) + op = TealOp(self, Op.proto, self.num_args, self.num_returns) + return TealBlock.FromOp(options, op) + + def __str__(self) -> str: + return f"(proto: num_args = {self.num_args}, num_returns = {self.num_returns})" + + def type_of(self) -> TealType: + return TealType.none + + def has_return(self) -> bool: + return False + + +Proto.__module__ = "pyteal" + + +class FrameDig(Expr): + def __init__(self, frame_index: int): + super().__init__() + self.frame_index = frame_index + + def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: + verifyProgramVersion( + Op.frame_dig.min_version, + options.version, + "Program version too low to use op frame_dig", + ) + op = TealOp(self, Op.frame_dig, self.frame_index) + return TealBlock.FromOp(options, op) + + def __str__(self) -> str: + return f"(frame_dig: dig_from = {self.frame_index})" + + def type_of(self) -> TealType: + return TealType.anytype + + def has_return(self) -> bool: + return False + + +FrameDig.__module__ = "pyteal" + + +class FrameBury(Expr): + def __init__(self, value: Expr, frame_index: int): + super().__init__() + require_type(value, TealType.anytype) + self.value = value + self.frame_index = frame_index + + def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: + verifyProgramVersion( + Op.frame_bury.min_version, + options.version, + "Program version too low to use op frame_bury", + ) + op = TealOp(self, Op.frame_bury, self.frame_index) + return TealBlock.FromOp(options, op, self.value) + + def __str__(self) -> str: + return f"(frame_bury (bury_to = {self.frame_index}) ({self.value}))" + + def type_of(self) -> TealType: + return TealType.none + + def has_return(self) -> bool: + return False + + +FrameBury.__module__ = "pyteal" + + +class DupN(Expr): + def __init__(self, value: Expr, repetition: int): + super().__init__() + require_type(value, TealType.anytype) + if repetition < 0: + raise TealInputError("dupn repetition should be non negative") + self.value = value + self.repetition = repetition + + def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: + verifyProgramVersion( + Op.dupn.min_version, + options.version, + "Program version too low to use op dupn", + ) + op = TealOp(self, Op.dupn, self.repetition) + return TealBlock.FromOp(options, op, self.value) + + def __str__(self) -> str: + return f"(dupn (repetition = {self.repetition}) ({self.value}))" + + def type_of(self) -> TealType: + return self.value.type_of() + + def has_return(self) -> bool: + return False + + +DupN.__module__ = "pyteal" diff --git a/pyteal/ast/frame_test.py b/pyteal/ast/frame_test.py new file mode 100644 index 000000000..e4cde2aa4 --- /dev/null +++ b/pyteal/ast/frame_test.py @@ -0,0 +1,107 @@ +import pytest +import pyteal as pt +from pyteal.ast.frame import FrameBury, FrameDig, Proto, DupN + +avm7Options = pt.CompileOptions(version=7) +avm8Options = pt.CompileOptions(version=8) + + +@pytest.mark.parametrize("input_num, output_num", [(1, 1), (1, 0), (5, 5)]) +def test_proto(input_num: int, output_num: int): + expr = Proto(input_num, output_num) + assert not expr.has_return() + assert expr.type_of() == pt.TealType.none + + expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.proto, input_num, output_num)]) + actual, _ = expr.__teal__(avm8Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + +def test_proto_invalid(): + with pytest.raises(pt.TealInputError): + Proto(-1, 1) + + with pytest.raises(pt.TealInputError): + Proto(1, -1) + + with pytest.raises(pt.TealInputError): + Proto(1, 1).__teal__(avm7Options) + + +@pytest.mark.parametrize("depth", [-1, 0, 1, 2]) +def test_frame_dig(depth: int): + expr = FrameDig(depth) + assert not expr.has_return() + assert expr.type_of() == pt.TealType.anytype + + expected = pt.TealSimpleBlock([pt.TealOp(expr, pt.Op.frame_dig, depth)]) + actual, _ = expr.__teal__(avm8Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + +def test_frame_dig_invalid(): + with pytest.raises(pt.TealInputError): + FrameDig(1).__teal__(avm7Options) + + +def test_frame_bury(): + byte_expr = pt.Bytes("Astartes") + expr = FrameBury(byte_expr, 4) + assert not expr.has_return() + assert expr.type_of() == pt.TealType.none + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(byte_expr, pt.Op.byte, '"Astartes"'), + pt.TealOp(expr, pt.Op.frame_bury, 4), + ] + ) + actual, _ = expr.__teal__(avm8Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + +def test_frame_bury_invalid(): + with pytest.raises(pt.TealTypeError): + FrameBury(pt.Seq(), 1) + + with pytest.raises(pt.TealInputError): + FrameBury(pt.Int(1), 1).__teal__(avm7Options) + + +def test_dupn(): + byte_expr = pt.Bytes("Astartes") + expr = DupN(byte_expr, 4) + assert not expr.has_return() + assert expr.type_of() == byte_expr.type_of() + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(byte_expr, pt.Op.byte, '"Astartes"'), + pt.TealOp(expr, pt.Op.dupn, 4), + ] + ) + actual, _ = expr.__teal__(avm8Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + +def test_dupn_invalid(): + with pytest.raises(pt.TealTypeError): + DupN(pt.Seq(), 1) + + with pytest.raises(pt.TealInputError): + DupN(pt.Int(1), -1) + + with pytest.raises(pt.TealInputError): + DupN(pt.Int(1), 1).__teal__(avm7Options) diff --git a/pyteal/compiler/compiler.py b/pyteal/compiler/compiler.py index 1955d0430..f2b25b489 100644 --- a/pyteal/compiler/compiler.py +++ b/pyteal/compiler/compiler.py @@ -26,6 +26,7 @@ from pyteal.compiler.constants import createConstantBlocks MAX_PROGRAM_VERSION = 8 +FRAME_POINTER_VERSION = 8 MIN_PROGRAM_VERSION = 2 DEFAULT_PROGRAM_VERSION = MIN_PROGRAM_VERSION diff --git a/pyteal/ir/ops.py b/pyteal/ir/ops.py index 43a62b5d4..9ec496288 100644 --- a/pyteal/ir/ops.py +++ b/pyteal/ir/ops.py @@ -33,7 +33,7 @@ def min_version(self) -> int: # fmt: off # meta comment = OpType("//", Mode.Signature | Mode.Application, 0) - # avm + # avm err = OpType("err", Mode.Signature | Mode.Application, 2) sha256 = OpType("sha256", Mode.Signature | Mode.Application, 2) keccak256 = OpType("keccak256", Mode.Signature | Mode.Application, 2) @@ -197,6 +197,12 @@ def min_version(self) -> int: box_len = OpType("box_len", Mode.Application, 8) box_get = OpType("box_get", Mode.Application, 8) box_put = OpType("box_put", Mode.Application, 8) + popn = OpType("popn", Mode.Signature | Mode.Application, 8) + dupn = OpType("dupn", Mode.Signature | Mode.Application, 8) + bury = OpType("bury", Mode.Signature | Mode.Application, 8) + frame_dig = OpType("frame_dig", Mode.Signature | Mode.Application, 8) + frame_bury = OpType("frame_bury", Mode.Signature | Mode.Application, 8) + proto = OpType("proto", Mode.Signature | Mode.Application, 8) # fmt: on From 6ae67e6cf0dda8cc783b2965ab6d2c210150c382 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 26 Oct 2022 09:56:48 -0400 Subject: [PATCH 064/206] add frame ops to avm8 branch --- pyteal/__init__.pyi | 6 ++++++ pyteal/ast/__init__.py | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index ce347b0eb..69e3c55eb 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -70,6 +70,7 @@ __all__ = [ "BoxReplace", "Break", "Btoi", + "Bury", "Bytes", "BytesAdd", "BytesAnd", @@ -98,6 +99,7 @@ __all__ = [ "DEFAULT_TEAL_VERSION", "Div", "Divw", + "DupN", "DynamicScratchVar", "EcdsaCurve", "EcdsaDecompress", @@ -115,6 +117,8 @@ __all__ = [ "ExtractUint32", "ExtractUint64", "For", + "FrameBury", + "FrameDig", "Ge", "GeneratedID", "GetBit", @@ -173,7 +177,9 @@ __all__ = [ "OptimizeOptions", "Or", "Pop", + "PopN", "Pragma", + "Proto", "RETURN_HASH_PREFIX", "Reject", "Replace", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 9efe807c5..1ca49a2e5 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -155,6 +155,7 @@ from pyteal.ast.for_ import For from pyteal.ast.break_ import Break from pyteal.ast.continue_ import Continue +from pyteal.ast.frame import Proto, FrameDig, FrameBury, PopN, DupN, Bury # misc from pyteal.ast.scratch import ( @@ -336,6 +337,12 @@ "For", "Break", "Continue", + "Proto", + "FrameDig", + "FrameBury", + "Bury", + "DupN", + "PopN", "Router", "CallConfig", "MethodConfig", From 917229aa8a9b8339cfeac39cf2521274ea19816a Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 26 Oct 2022 13:52:43 -0400 Subject: [PATCH 065/206] specify FRAME_POINTER_VERSION in frame-op branch --- pyteal/__init__.py | 2 ++ pyteal/__init__.pyi | 2 ++ pyteal/compiler/__init__.py | 2 ++ 3 files changed, 6 insertions(+) diff --git a/pyteal/__init__.py b/pyteal/__init__.py index ac28dd641..ba6e8eead 100644 --- a/pyteal/__init__.py +++ b/pyteal/__init__.py @@ -8,6 +8,7 @@ MIN_TEAL_VERSION, DEFAULT_TEAL_VERSION, MAX_PROGRAM_VERSION, + FRAME_POINTER_VERSION, MIN_PROGRAM_VERSION, DEFAULT_PROGRAM_VERSION, CompileOptions, @@ -38,6 +39,7 @@ "MIN_TEAL_VERSION", "DEFAULT_TEAL_VERSION", "MAX_PROGRAM_VERSION", + "FRAME_POINTER_VERSION", "MIN_PROGRAM_VERSION", "DEFAULT_PROGRAM_VERSION", "CompileOptions", diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index 69e3c55eb..40600d561 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -11,6 +11,7 @@ from pyteal.compiler import ( MIN_TEAL_VERSION, DEFAULT_TEAL_VERSION, MAX_PROGRAM_VERSION, + FRAME_POINTER_VERSION, MIN_PROGRAM_VERSION, DEFAULT_PROGRAM_VERSION, CompileOptions, @@ -116,6 +117,7 @@ __all__ = [ "ExtractUint16", "ExtractUint32", "ExtractUint64", + "FRAME_POINTER_VERSION", "For", "FrameBury", "FrameDig", diff --git a/pyteal/compiler/__init__.py b/pyteal/compiler/__init__.py index e0d29450d..9755ead4f 100644 --- a/pyteal/compiler/__init__.py +++ b/pyteal/compiler/__init__.py @@ -3,6 +3,7 @@ MIN_TEAL_VERSION, DEFAULT_TEAL_VERSION, MAX_PROGRAM_VERSION, + FRAME_POINTER_VERSION, MIN_PROGRAM_VERSION, DEFAULT_PROGRAM_VERSION, CompileOptions, @@ -16,6 +17,7 @@ "MIN_TEAL_VERSION", "DEFAULT_TEAL_VERSION", "MAX_PROGRAM_VERSION", + "FRAME_POINTER_VERSION", "MIN_PROGRAM_VERSION", "DEFAULT_PROGRAM_VERSION", "CompileOptions", From 892dd503023ee5eda563872ea6916d9bb0495207 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 26 Oct 2022 17:12:46 -0400 Subject: [PATCH 066/206] just the work of abi data schema --- pyteal/ast/abi/__init__.py | 13 ++++- pyteal/ast/abi/address.py | 15 +++--- pyteal/ast/abi/address_test.py | 73 ++++++++++++++++++++++----- pyteal/ast/abi/array_base.py | 6 +-- pyteal/ast/abi/array_dynamic.py | 8 +-- pyteal/ast/abi/array_dynamic_test.py | 68 ++++++++++++++++++++----- pyteal/ast/abi/array_static.py | 10 ++-- pyteal/ast/abi/array_static_test.py | 49 ++++++++++++++---- pyteal/ast/abi/bool.py | 8 +-- pyteal/ast/abi/bool_test.py | 66 ++++++++++++++++++++---- pyteal/ast/abi/reference_type.py | 8 +-- pyteal/ast/abi/reference_type_test.py | 27 ++++++++-- pyteal/ast/abi/string.py | 29 +++++++---- pyteal/ast/abi/string_test.py | 65 ++++++++++++++++++++---- pyteal/ast/abi/transaction.py | 8 +-- pyteal/ast/abi/transaction_test.py | 8 ++- pyteal/ast/abi/tuple.py | 6 +-- pyteal/ast/abi/tuple_test.py | 22 ++++++-- pyteal/ast/abi/type.py | 64 ++++++++++++++++++++++- pyteal/ast/abi/type_test.py | 2 +- pyteal/ast/abi/uint.py | 39 +++++++------- pyteal/ast/abi/uint_test.py | 64 +++++++++++++++++++---- pyteal/ast/comment.py | 4 +- pyteal/ast/expr.py | 6 +-- pyteal/ast/router.py | 2 +- pyteal/ast/subroutine.py | 18 ++++--- 26 files changed, 529 insertions(+), 159 deletions(-) diff --git a/pyteal/ast/abi/__init__.py b/pyteal/ast/abi/__init__.py index f1cb3a58c..3113b8d72 100644 --- a/pyteal/ast/abi/__init__.py +++ b/pyteal/ast/abi/__init__.py @@ -4,7 +4,15 @@ Address, AddressLength, ) -from pyteal.ast.abi.type import TypeSpec, BaseType, ComputedValue, ReturnedValue +from pyteal.ast.abi.type import ( + TypeSpec, + BaseType, + ComputedValue, + ReturnedValue, + DataStorageSchema, + FrameStorage, + ScratchVarStorage, +) from pyteal.ast.abi.bool import BoolTypeSpec, Bool from pyteal.ast.abi.uint import ( UintTypeSpec, @@ -166,6 +174,9 @@ "type_specs_from_signature", "make", "size_of", + "DataStorageSchema", + "FrameStorage", + "ScratchVarStorage", "algosdk_from_annotation", "algosdk_from_type_spec", "contains_type_spec", diff --git a/pyteal/ast/abi/address.py b/pyteal/ast/abi/address.py index d0413cf6c..3165fcd9a 100644 --- a/pyteal/ast/abi/address.py +++ b/pyteal/ast/abi/address.py @@ -56,7 +56,7 @@ def get(self) -> Expr: The expression will have the type TealType.bytes. """ - return self.stored_value.load() + return self._data_storage.load_value() def set( self, @@ -108,25 +108,28 @@ def set( or value.type_spec() == StaticArrayTypeSpec(ByteTypeSpec(), AddressLength.Bytes) ): - return self.stored_value.store(value.stored_value.load()) + return self._data_storage.store_value( + value._data_storage.load_value() + ) raise TealInputError( f"Got {value} with type spec {value.type_spec()}, expected AddressTypeSpec" ) case str(): # Addr throws if value is invalid address - return self.stored_value.store(Addr(value)) + return self._data_storage.store_value(Addr(value)) case bytes(): if len(value) == AddressLength.Bytes: - return self.stored_value.store(Bytes(value)) + return self._data_storage.store_value(Bytes(value)) raise TealInputError( f"Got bytes with length {len(value)}, expected {AddressLength.Bytes}" ) case Expr(): return Seq( - self.stored_value.store(value), + self._data_storage.store_value(value), Assert( - Len(self.stored_value.load()) == Int(AddressLength.Bytes.value) + Len(self._data_storage.load_value()) + == Int(AddressLength.Bytes.value) ), ) case CollectionSequence(): diff --git a/pyteal/ast/abi/address_test.py b/pyteal/ast/abi/address_test.py index 7cc9cd449..305046619 100644 --- a/pyteal/ast/abi/address_test.py +++ b/pyteal/ast/abi/address_test.py @@ -1,4 +1,5 @@ import pytest +from typing import cast import pyteal as pt from pyteal import abi @@ -48,7 +49,13 @@ def test_Address_encode(): assert expr.has_return() is False expected = pt.TealSimpleBlock( - [pt.TealOp(expr, pt.Op.load, value.stored_value.slot)] + [ + pt.TealOp( + expr, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + ] ) actual, _ = expr.__teal__(options) assert actual == expected @@ -79,7 +86,7 @@ def test_Address_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expectedExpr = value.stored_value.store( + expectedExpr = value._data_storage.store_value( substring_for_decoding( encoded, start_index=start_index, @@ -106,7 +113,13 @@ def test_Address_get(): assert expr.has_return() is False expected = pt.TealSimpleBlock( - [pt.TealOp(expr, pt.Op.load, value.stored_value.slot)] + [ + pt.TealOp( + expr, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + ] ) actual, _ = expr.__teal__(options) assert actual == expected @@ -123,8 +136,16 @@ def test_Address_set_StaticArray(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, value_to_set.stored_value.slot), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value_to_set._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -150,7 +171,11 @@ def test_Address_set_str(): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.addr, value_to_set), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -175,7 +200,11 @@ def test_Address_set_bytes(): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.byte, f"0x{value_to_set.hex()}"), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -204,8 +233,16 @@ def test_Address_set_expr(): expected = pt.TealSimpleBlock( [ vts.ops[0], - pt.TealOp(None, pt.Op.store, value.stored_value.slot), - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.int, AddressLength.Bytes.value), pt.TealOp(None, pt.Op.eq), @@ -230,8 +267,16 @@ def test_Address_set_copy(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, other.stored_value.slot), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -259,7 +304,11 @@ def test_Address_set_computed(): expected = pt.TealSimpleBlock( [ byte_ops.ops[0], - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) diff --git a/pyteal/ast/abi/array_base.py b/pyteal/ast/abi/array_base.py index aea164c81..4674f1d90 100644 --- a/pyteal/ast/abi/array_base.py +++ b/pyteal/ast/abi/array_base.py @@ -104,7 +104,7 @@ def decode( extracted = substring_for_decoding( encoded, start_index=start_index, end_index=end_index, length=length ) - return self.stored_value.store(extracted) + return self._data_storage.store_value(extracted) def set(self, values: Sequence[T]) -> Expr: """Set the ABI array with a sequence of ABI type variables. @@ -142,7 +142,7 @@ def set(self, values: Sequence[T]) -> Expr: length_prefix = Seq(length_tmp.set(len(values)), length_tmp.encode()) encoded = Concat(length_prefix, encoded) - return self.stored_value.store(encoded) + return self._data_storage.store_value(encoded) def encode(self) -> Expr: """Encode the ABI array to be a byte string. @@ -150,7 +150,7 @@ def encode(self) -> Expr: Returns: A PyTeal expression that encodes this ABI array to a byte string. """ - return self.stored_value.load() + return self._data_storage.load_value() @abstractmethod def length(self) -> Expr: diff --git a/pyteal/ast/abi/array_dynamic.py b/pyteal/ast/abi/array_dynamic.py index 9d53e0559..2a5f7367d 100644 --- a/pyteal/ast/abi/array_dynamic.py +++ b/pyteal/ast/abi/array_dynamic.py @@ -79,7 +79,7 @@ def set( raise TealInputError( f"Cannot assign type {values.type_spec()} to {self.type_spec()}" ) - return self.stored_value.store(values.encode()) + return self._data_storage.store_value(values.encode()) return super().set(values) def length(self) -> Expr: @@ -165,10 +165,10 @@ def set( match values: case bytes() | bytearray(): - return self.stored_value.store(_encoded_byte_string(values)) + return self._data_storage.store_value(_encoded_byte_string(values)) case Expr(): return _store_encoded_expr_byte_string_into_var( - values, self.stored_value + values, self._data_storage ) return super().set(values) @@ -181,7 +181,7 @@ def get(self) -> Expr: Returns: A Pyteal expression that loads byte encoding of this DynamicBytes, and drop the first uint16 DynamicArray length encoding. """ - return Suffix(self.stored_value.load(), Int(2)) + return Suffix(self._data_storage.load_value(), Int(2)) DynamicBytes.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/array_dynamic_test.py b/pyteal/ast/abi/array_dynamic_test.py index 326f72294..fa0e122e1 100644 --- a/pyteal/ast/abi/array_dynamic_test.py +++ b/pyteal/ast/abi/array_dynamic_test.py @@ -1,4 +1,4 @@ -from typing import List +from typing import List, cast import pytest import pyteal as pt @@ -106,7 +106,7 @@ def test_DynamicArray_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value.stored_value.store( + expectedExpr = value._data_storage.store_value( substring_for_decoding( encoded, start_index=start_index, @@ -141,7 +141,7 @@ def test_DynamicArray_set_values(): assert not expr.has_return() length_tmp = abi.Uint16() - expectedExpr = value.stored_value.store( + expectedExpr = value._data_storage.store_value( pt.Concat( pt.Seq(length_tmp.set(len(values)), length_tmp.encode()), _encode_tuple(values), @@ -182,8 +182,16 @@ def test_DynamicArray_set_copy(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, otherArray.stored_value.slot), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, otherArray._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -207,7 +215,11 @@ def test_DynamicArray_set_computed(): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.byte, '"this should be a dynamic array"'), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) actual, _ = expr.__teal__(options) @@ -253,7 +265,11 @@ def test_DynamicBytes_set_py_bytes(test_case: bytes | bytearray): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.byte, "0x" + length_encoding + BYTE_HEX_TEST_CASE), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -280,14 +296,30 @@ def test_DynamicBytes_set_expr(test_case: bytes | bytearray): pt.TealOp(None, pt.Op.byte, "0x" + BYTE_HEX_TEST_CASE), pt.TealOp(None, pt.Op.byte, "0x" + BYTE_HEX_TEST_CASE), pt.TealOp(None, pt.Op.concat), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.itob), pt.TealOp(None, pt.Op.extract, 6, 0), - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.concat), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -308,7 +340,11 @@ def test_DynamicBytes_get(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.extract, 2, 0), ] ) @@ -325,7 +361,13 @@ def test_DynamicArray_encode(): assert not expr.has_return() expected = pt.TealSimpleBlock( - [pt.TealOp(None, pt.Op.load, value.stored_value.slot)] + [ + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + ] ) actual, _ = expr.__teal__(options) diff --git a/pyteal/ast/abi/array_static.py b/pyteal/ast/abi/array_static.py index 7744a6edb..caf2dcc88 100644 --- a/pyteal/ast/abi/array_static.py +++ b/pyteal/ast/abi/array_static.py @@ -109,7 +109,7 @@ def set( raise TealInputError( f"Cannot assign type {values.type_spec()} to {self.type_spec()}" ) - return self.stored_value.store(values.encode()) + return self._data_storage.store_value(values.encode()) if self.type_spec().length_static() != len(values): raise TealInputError( @@ -207,11 +207,11 @@ def set( raise TealInputError( f"Got bytes with length {len(values)}, expect {self.type_spec().length_static()}" ) - return self.stored_value.store(Bytes(values)) + return self._data_storage.store_value(Bytes(values)) case Expr(): return Seq( - self.stored_value.store(values), - Assert(self.length() == Len(self.stored_value.load())), + self._data_storage.store_value(values), + Assert(self.length() == Len(self._data_storage.load_value())), ) return super().set(values) @@ -222,7 +222,7 @@ def get(self) -> Expr: Returns: A Pyteal expression that loads byte encoding of this StaticBytes. """ - return self.stored_value.load() + return self._data_storage.load_value() StaticBytes.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/array_static_test.py b/pyteal/ast/abi/array_static_test.py index 91781a682..236e2591e 100644 --- a/pyteal/ast/abi/array_static_test.py +++ b/pyteal/ast/abi/array_static_test.py @@ -1,4 +1,5 @@ import pytest +from typing import cast import pyteal as pt from pyteal import abi @@ -158,7 +159,7 @@ def test_StaticArray_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value.stored_value.store( + expectedExpr = value._data_storage.store_value( substring_for_decoding( encoded, start_index=start_index, @@ -201,7 +202,7 @@ def test_StaticArray_set_values(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value.stored_value.store(_encode_tuple(values)) + expectedExpr = value._data_storage.store_value(_encode_tuple(values)) expected, _ = expectedExpr.__teal__(options) expected.addIncoming() expected = pt.TealBlock.NormalizeBlocks(expected) @@ -233,8 +234,16 @@ def test_StaticArray_set_copy(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, otherArray.stored_value.slot), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, otherArray._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -258,7 +267,11 @@ def test_StaticArray_set_computed(): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.byte, '"indeed this is hard to simulate"'), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) actual, _ = expr.__teal__(options) @@ -301,7 +314,11 @@ def test_StaticBytes_set_py_bytes(test_case: bytes | bytearray): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.byte, "0x" + BYTE_HEX_TEST_CASE), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -332,9 +349,17 @@ def test_StaticBytes_expr(test_case: bytes | bytearray): pt.TealOp(None, pt.Op.byte, "0x" + BYTE_HEX_TEST_CASE), pt.TealOp(None, pt.Op.byte, "0x" + BYTE_HEX_TEST_CASE), pt.TealOp(None, pt.Op.concat), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.int, 32), - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.eq), pt.TealOp(None, pt.Op.assert_), @@ -352,7 +377,13 @@ def test_StaticArray_encode(): assert not expr.has_return() expected = pt.TealSimpleBlock( - [pt.TealOp(None, pt.Op.load, value.stored_value.slot)] + [ + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + ] ) actual, _ = expr.__teal__(options) diff --git a/pyteal/ast/abi/bool.py b/pyteal/ast/abi/bool.py index 13552b6db..2bfbd3aca 100644 --- a/pyteal/ast/abi/bool.py +++ b/pyteal/ast/abi/bool.py @@ -50,7 +50,7 @@ def get(self) -> Expr: expression that evaluates to 0 will be returned. In either case, the expression will have the type TealType.uint64. """ - return self.stored_value.load() + return self._data_storage.load_value() def set(self, value: Union[bool, Expr, "Bool", ComputedValue["Bool"]]) -> Expr: """Set the value of this Bool to the input value. @@ -85,10 +85,10 @@ def set(self, value: Union[bool, Expr, "Bool", ComputedValue["Bool"]]) -> Expr: checked = True if checked: - return self.stored_value.store(value) + return self._data_storage.store_value(value) # Not(Not(value)) coerces all values greater than 0 to 1 - return self.stored_value.store(Not(Not(value))) + return self._data_storage.store_value(Not(Not(value))) def decode( self, @@ -103,7 +103,7 @@ def decode( return self.decode_bit(encoded, start_index * Int(NUM_BITS_IN_BYTE)) def decode_bit(self, encoded, bit_index: Expr) -> Expr: - return self.stored_value.store(GetBit(encoded, bit_index)) + return self._data_storage.store_value(GetBit(encoded, bit_index)) def encode(self) -> Expr: return SetBit(Bytes(b"\x00"), Int(0), self.get()) diff --git a/pyteal/ast/abi/bool_test.py b/pyteal/ast/abi/bool_test.py index 45ffa7e30..411bdf376 100644 --- a/pyteal/ast/abi/bool_test.py +++ b/pyteal/ast/abi/bool_test.py @@ -1,4 +1,4 @@ -from typing import NamedTuple, List +from typing import NamedTuple, List, cast import pytest import pyteal as pt @@ -53,7 +53,11 @@ def test_Bool_set_static(): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.int, 1 if value_to_set else 0), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -78,7 +82,11 @@ def test_Bool_set_expr(): pt.TealOp(None, pt.Op.logic_or), pt.TealOp(None, pt.Op.logic_not), pt.TealOp(None, pt.Op.logic_not), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -99,8 +107,16 @@ def test_Bool_set_copy(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, other.stored_value.slot), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -125,7 +141,11 @@ def test_Bool_set_computed(): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.int, 0x80), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -147,7 +167,13 @@ def test_Bool_get(): assert not expr.has_return() expected = pt.TealSimpleBlock( - [pt.TealOp(expr, pt.Op.load, value.stored_value.slot)] + [ + pt.TealOp( + expr, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + ] ) actual, _ = expr.__teal__(options) @@ -174,7 +200,13 @@ def test_Bool_decode(): pt.TealOp(None, pt.Op.int, 8), pt.TealOp(None, pt.Op.mul), pt.TealOp(None, pt.Op.getbit), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast( + abi.ScratchVarStorage, value._data_storage + ).scratchvar.slot, + ), ] ) @@ -199,7 +231,11 @@ def test_Bool_decode_bit(): pt.TealOp(None, pt.Op.byte, '"encoded"'), pt.TealOp(None, pt.Op.int, 17), pt.TealOp(None, pt.Op.getbit), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -221,7 +257,11 @@ def test_Bool_encode(): [ pt.TealOp(None, pt.Op.byte, "0x00"), pt.TealOp(None, pt.Op.int, 0), - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.setbit), ] ) @@ -401,7 +441,11 @@ class EncodeSeqTest(NamedTuple): setBits = [ [ pt.TealOp(None, pt.Op.int, j), - pt.TealOp(None, pt.Op.load, testType.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, testType._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.setbit), ] for j, testType in enumerate(test.types) diff --git a/pyteal/ast/abi/reference_type.py b/pyteal/ast/abi/reference_type.py index f4882fc97..2ea723b92 100644 --- a/pyteal/ast/abi/reference_type.py +++ b/pyteal/ast/abi/reference_type.py @@ -58,7 +58,7 @@ def referenced_index(self) -> Expr: If this reference type is an application or asset, note that this DOES NOT return the application or asset ID. See :code:`application_id()` or :code:`asset_id()` for that. """ - return self.stored_value.load() + return self._data_storage.load_value() def decode( self, @@ -70,7 +70,7 @@ def decode( ) -> Expr: return uint_decode( self.type_spec().bit_size(), - self.stored_value, + self._data_storage, encoded, start_index, end_index, @@ -107,7 +107,7 @@ def __init__(self) -> None: def address(self) -> Expr: """Get the address of the account.""" - return Txn.accounts[self.stored_value.load()] + return Txn.accounts[self._data_storage.load_value()] def params(self) -> AccountParamObject: """Get information about the account.""" @@ -205,7 +205,7 @@ def __init__(self) -> None: def application_id(self) -> Expr: """Get the ID of the application.""" - return Txn.applications[self.stored_value.load()] + return Txn.applications[self._data_storage.load_value()] def params(self) -> AppParamObject: """Get information about the application's parameters.""" diff --git a/pyteal/ast/abi/reference_type_test.py b/pyteal/ast/abi/reference_type_test.py index 99555ab12..aaa1e5d97 100644 --- a/pyteal/ast/abi/reference_type_test.py +++ b/pyteal/ast/abi/reference_type_test.py @@ -1,4 +1,5 @@ import pytest +from typing import cast import pyteal as pt from pyteal import abi @@ -22,7 +23,11 @@ def test_ReferenceType_referenced_index(): expected = pt.TealSimpleBlock( [ - pt.TealOp(expr, pt.Op.load, value.stored_value.slot), + pt.TealOp( + expr, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) actual, _ = expr.__teal__(options) @@ -56,7 +61,7 @@ def test_ReferenceType_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expected_decoding = value.stored_value.store( + expected_decoding = value._data_storage.store_value( pt.GetByte( encoded, start_index if start_index is not None else pt.Int(0), @@ -109,7 +114,11 @@ def test_Account_address(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.txnas, "Accounts"), ] ) @@ -192,7 +201,11 @@ def test_Asset_asset_id(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.txnas, "Assets"), ] ) @@ -282,7 +295,11 @@ def test_Application_application_id(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.txnas, "Applications"), ] ) diff --git a/pyteal/ast/abi/string.py b/pyteal/ast/abi/string.py index 4c9b31c08..0359aee76 100644 --- a/pyteal/ast/abi/string.py +++ b/pyteal/ast/abi/string.py @@ -4,7 +4,7 @@ from algosdk.abi import ABIType from pyteal.ast.abi.uint import Byte -from pyteal.ast.abi.type import ComputedValue, BaseType +from pyteal.ast.abi.type import ComputedValue, BaseType, DataStorageSchema from pyteal.ast.abi.array_dynamic import DynamicArray, DynamicArrayTypeSpec from pyteal.ast.abi.uint import ByteTypeSpec, Uint16TypeSpec @@ -12,7 +12,6 @@ from pyteal.ast.expr import Expr from pyteal.ast.bytes import Bytes from pyteal.ast.seq import Seq -from pyteal.ast.scratchvar import ScratchVar from pyteal.ast.unaryexpr import Itob, Len from pyteal.ast.substring import Suffix from pyteal.ast.naryexpr import Concat @@ -25,11 +24,15 @@ def _encoded_byte_string(s: bytes | bytearray) -> Expr: return Bytes(prefix + s) -def _store_encoded_expr_byte_string_into_var(value: Expr, location: ScratchVar) -> Expr: +def _store_encoded_expr_byte_string_into_var( + value: Expr, location: DataStorageSchema +) -> Expr: return Seq( - location.store(value), - location.store( - Concat(Suffix(Itob(Len(location.load())), Int(6)), location.load()) + location.store_value(value), + location.store_value( + Concat( + Suffix(Itob(Len(location.load_value())), Int(6)), location.load_value() + ) ), ) @@ -67,7 +70,7 @@ def get(self) -> Expr: The expression will have the type TealType.bytes. """ return Suffix( - self.stored_value.load(), Int(Uint16TypeSpec().byte_length_static()) + self._data_storage.load_value(), Int(Uint16TypeSpec().byte_length_static()) ) def set( @@ -110,18 +113,22 @@ def set( if value.type_spec() == StringTypeSpec() or ( value.type_spec() == DynamicArrayTypeSpec(ByteTypeSpec()) ): - return self.stored_value.store(value.stored_value.load()) + return self._data_storage.store_value( + value._data_storage.load_value() + ) raise TealInputError( f"Got {value} with type spec {value.type_spec()}, expected {StringTypeSpec}" ) case bytes() | bytearray(): - return self.stored_value.store(_encoded_byte_string(value)) + return self._data_storage.store_value(_encoded_byte_string(value)) case str(): - return self.stored_value.store(_encoded_byte_string(value.encode())) + return self._data_storage.store_value( + _encoded_byte_string(value.encode()) + ) case Expr(): return _store_encoded_expr_byte_string_into_var( - value, self.stored_value + value, self._data_storage ) case CollectionSequence(): return super().set(cast(Sequence[Byte], value)) diff --git a/pyteal/ast/abi/string_test.py b/pyteal/ast/abi/string_test.py index 6a600d55a..79a699a4c 100644 --- a/pyteal/ast/abi/string_test.py +++ b/pyteal/ast/abi/string_test.py @@ -1,4 +1,5 @@ import pytest +from typing import cast import pyteal as pt from pyteal import abi @@ -39,7 +40,13 @@ def test_String_encode(): assert expr.has_return() is False expected = pt.TealSimpleBlock( - [pt.TealOp(expr, pt.Op.load, value.stored_value.slot)] + [ + pt.TealOp( + expr, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + ] ) actual, _ = expr.__teal__(options) assert actual == expected @@ -69,7 +76,7 @@ def test_DynamicArray_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expectedExpr = value.stored_value.store( + expectedExpr = value._data_storage.store_value( substring_for_decoding( encoded, start_index=start_index, @@ -97,7 +104,11 @@ def test_String_get(): expected = pt.TealSimpleBlock( [ - pt.TealOp(expr, pt.Op.load, value.stored_value.slot), + pt.TealOp( + expr, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.extract, 2, 0), ] ) @@ -129,7 +140,11 @@ def test_String_set_static(value_to_set, value_encoded): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.byte, "0x" + value_encoded.hex()), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -156,14 +171,30 @@ def test_String_set_expr(): value_start, value_end = value_to_set.__teal__(options) expected_body = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.store, value.stored_value.slot), - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.itob), pt.TealOp(None, pt.Op.extract, 6, 0), - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.concat), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) value_end.setNextBlock(expected_body) @@ -188,8 +219,16 @@ def test_String_set_copy(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, other.stored_value.slot), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -217,7 +256,11 @@ def test_String_set_computed(): expected = pt.TealSimpleBlock( [ byte_ops.ops[0], - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) diff --git a/pyteal/ast/abi/transaction.py b/pyteal/ast/abi/transaction.py index aeb5c7a33..2451a1285 100644 --- a/pyteal/ast/abi/transaction.py +++ b/pyteal/ast/abi/transaction.py @@ -82,16 +82,16 @@ def _set_index( case ComputedValue(): return self._set_with_computed_type(value) case BaseType(): - return self.stored_value.store(self.stored_value.load()) + return self._data_storage.store_value(self._data_storage.load_value()) case int(): - return self.stored_value.store(Int(value)) + return self._data_storage.store_value(Int(value)) case Expr(): - return self.stored_value.store(value) + return self._data_storage.store_value(value) case _: raise TealInputError(f"Cant store a {type(value)} in a Transaction") def index(self) -> Expr: - return self.stored_value.load() + return self._data_storage.load_value() def decode( self, diff --git a/pyteal/ast/abi/transaction_test.py b/pyteal/ast/abi/transaction_test.py index 5803b8f32..573d6f440 100644 --- a/pyteal/ast/abi/transaction_test.py +++ b/pyteal/ast/abi/transaction_test.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import List +from typing import List, cast import pyteal as pt from pyteal import abi import pytest @@ -131,7 +131,11 @@ def test_Transaction__set_index(): expected = pt.TealSimpleBlock( [ pt.TealOp(expr, pt.Op.int, val_to_set), - pt.TealOp(None, pt.Op.store, tv.t.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, tv.t._data_storage).scratchvar.slot, + ), ] ) actual, _ = expr.__teal__(options) diff --git a/pyteal/ast/abi/tuple.py b/pyteal/ast/abi/tuple.py index bc1966414..2f2dceeab 100644 --- a/pyteal/ast/abi/tuple.py +++ b/pyteal/ast/abi/tuple.py @@ -309,7 +309,7 @@ def decode( extracted = substring_for_decoding( encoded, start_index=start_index, end_index=end_index, length=length ) - return self.stored_value.store(extracted) + return self._data_storage.store_value(extracted) @overload def set(self, *values: BaseType) -> Expr: @@ -352,10 +352,10 @@ def set(self, *values): ) if not all(myTypes[i] == values[i].type_spec() for i in range(len(myTypes))): raise TealInputError("Input values do not match type") - return self.stored_value.store(_encode_tuple(values)) + return self._data_storage.store_value(_encode_tuple(values)) def encode(self) -> Expr: - return self.stored_value.load() + return self._data_storage.load_value() def length(self) -> Expr: """Get the number of values this tuple holds as an Expr.""" diff --git a/pyteal/ast/abi/tuple_test.py b/pyteal/ast/abi/tuple_test.py index 7fc98cdae..8365769cc 100644 --- a/pyteal/ast/abi/tuple_test.py +++ b/pyteal/ast/abi/tuple_test.py @@ -1,4 +1,4 @@ -from typing import NamedTuple, List, Callable, Literal +from typing import NamedTuple, List, Callable, Literal, cast import pytest import pyteal as pt @@ -623,7 +623,7 @@ def test_Tuple_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = tupleValue.stored_value.store( + expectedExpr = tupleValue._data_storage.store_value( substring_for_decoding( encoded, start_index=start_index, @@ -672,7 +672,9 @@ def test_Tuple_set(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = tupleValue.stored_value.store(_encode_tuple([uint8, uint16, uint32])) + expectedExpr = tupleValue._data_storage.store_value( + _encode_tuple([uint8, uint16, uint32]) + ) expected, _ = expectedExpr.__teal__(options) expected.addIncoming() expected = pt.TealBlock.NormalizeBlocks(expected) @@ -701,7 +703,11 @@ def test_Tuple_set_Computed(): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.byte, '"internal representation"'), - pt.TealOp(None, pt.Op.store, tupleValue.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, tupleValue._data_storage).scratchvar.slot, + ), ] ) actual, _ = expr.__teal__(options) @@ -727,7 +733,13 @@ def test_Tuple_encode(): assert not expr.has_return() expected = pt.TealSimpleBlock( - [pt.TealOp(None, pt.Op.load, tupleValue.stored_value.slot)] + [ + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, tupleValue._data_storage).scratchvar.slot, + ), + ] ) actual, _ = expr.__teal__(options) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index 4b0b1e0f3..67d75cc4b 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -65,6 +65,55 @@ def __str__(self) -> str: TypeSpec.__module__ = "pyteal.abi" +class DataStorageSchema(ABC): + @abstractmethod + def store_value(self, value: Expr) -> Expr: + pass + + @abstractmethod + def load_value(self) -> Expr: + pass + + @abstractmethod + def storage_type(self) -> TealType: + pass + + +class ScratchVarStorage(DataStorageSchema): + def __init__(self, storage_type: TealType) -> None: + super().__init__() + self.scratchvar: Final = ScratchVar(storage_type) + + def load_value(self) -> Expr: + return self.scratchvar.load() + + def store_value(self, value: Expr) -> Expr: + return self.scratchvar.slot.store(value) + + def storage_type(self) -> TealType: + return self.scratchvar.storage_type() + + +class FrameStorage(DataStorageSchema): + def __init__(self, storage_type: TealType, stack_depth: int) -> None: + super().__init__() + self.stack_type = storage_type + self.stack_depth = stack_depth + + def storage_type(self) -> TealType: + return self.stack_type + + def store_value(self, value: Expr) -> Expr: + from pyteal.ast import FrameBury + + return FrameBury(value, self.stack_depth) + + def load_value(self) -> Expr: + from pyteal.ast import FrameDig + + return FrameDig(self.stack_depth) + + class BaseType(ABC): """The abstract base class for all ABI type instances. @@ -77,7 +126,18 @@ def __init__(self, spec: TypeSpec) -> None: """Create a new BaseType.""" super().__init__() self._type_spec: Final = spec - self.stored_value: Final = ScratchVar(spec.storage_type()) + self._data_storage: DataStorageSchema = ScratchVarStorage(spec.storage_type()) + + # self.stored_value: Final = ScratchVar(spec.storage_type()) + + def _set_data_source(self, storage: DataStorageSchema) -> None: + self._data_storage = storage + + def _load_value(self) -> Expr: + return self._data_storage.load_value() + + def _store_value(self, value: Expr) -> Expr: + return self._data_storage.store_value(value) def type_spec(self) -> TypeSpec: """Get the TypeSpec for this ABI type instance.""" @@ -231,7 +291,7 @@ def store_into(self, output: BaseType) -> Expr: f"ABI return subroutine deferred_expr is expected to be typed {output.type_spec().storage_type()}, " f"but has type {declaration.deferred_expr.type_of()}." ) - return output.stored_value.slot.store(self.computation) + return output._data_storage.store_value(self.computation) ReturnedValue.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/type_test.py b/pyteal/ast/abi/type_test.py index 56a9e6c76..b5134ef7d 100644 --- a/pyteal/ast/abi/type_test.py +++ b/pyteal/ast/abi/type_test.py @@ -17,7 +17,7 @@ def store_into(self, output: abi.BaseType) -> pt.Expr: raise pt.TealInputError( f"expected type_spec {self.type_spec} but get {output.type_spec()}" ) - return output.stored_value.store(self.encodings) + return output._data_storage.store_value(self.encodings) def test_ComputedType_use(): diff --git a/pyteal/ast/abi/uint.py b/pyteal/ast/abi/uint.py index 9855c29b9..e34daac9a 100644 --- a/pyteal/ast/abi/uint.py +++ b/pyteal/ast/abi/uint.py @@ -8,7 +8,6 @@ from pyteal.types import TealType from pyteal.errors import TealInputError -from pyteal.ast.scratchvar import ScratchVar from pyteal.ast.expr import Expr from pyteal.ast.seq import Seq from pyteal.ast.assert_ import Assert @@ -18,7 +17,7 @@ from pyteal.ast.unaryexpr import Itob, Btoi from pyteal.ast.binaryexpr import GetByte, ExtractUint16, ExtractUint32, ExtractUint64 from pyteal.ast.ternaryexpr import SetByte -from pyteal.ast.abi.type import ComputedValue, TypeSpec, BaseType +from pyteal.ast.abi.type import ComputedValue, TypeSpec, BaseType, DataStorageSchema NUM_BITS_IN_BYTE = 8 @@ -31,7 +30,9 @@ def uint_storage_type(size: int) -> TealType: return TealType.bytes -def uint_set(size: int, uint_var: ScratchVar, value: Union[int, Expr, "Uint"]) -> Expr: +def uint_set( + size: int, uint_var: DataStorageSchema, value: Union[int, Expr, "Uint"] +) -> Expr: if size > 64: raise NotImplementedError( "Uint operations have not yet been implemented for bit sizes larger than 64" @@ -49,17 +50,17 @@ def uint_set(size: int, uint_var: ScratchVar, value: Union[int, Expr, "Uint"]) - checked = True if checked or size == 64: - return uint_var.store(cast(Expr, value)) + return uint_var.store_value(cast(Expr, value)) return Seq( - uint_var.store(cast(Expr, value)), - Assert(uint_var.load() < Int(2**size)), + uint_var.store_value(cast(Expr, value)), + Assert(uint_var.load_value() < Int(2**size)), ) def uint_decode( size: int, - uint_var: ScratchVar, + uint_var: DataStorageSchema, encoded: Expr, start_index: Optional[Expr], end_index: Optional[Expr], @@ -73,27 +74,27 @@ def uint_decode( if size == 64: if start_index is None: if end_index is None and length is None: - return uint_var.store(Btoi(encoded)) + return uint_var.store_value(Btoi(encoded)) start_index = Int(0) - return uint_var.store(ExtractUint64(encoded, start_index)) + return uint_var.store_value(ExtractUint64(encoded, start_index)) if start_index is None: start_index = Int(0) if size == 8: - return uint_var.store(GetByte(encoded, start_index)) + return uint_var.store_value(GetByte(encoded, start_index)) if size == 16: - return uint_var.store(ExtractUint16(encoded, start_index)) + return uint_var.store_value(ExtractUint16(encoded, start_index)) if size == 32: - return uint_var.store(ExtractUint32(encoded, start_index)) + return uint_var.store_value(ExtractUint32(encoded, start_index)) raise ValueError("Unsupported uint size: {}".format(size)) -def uint_encode(size: int, uint_var: Expr | ScratchVar) -> Expr: +def uint_encode(size: int, uint_var: Expr | DataStorageSchema) -> Expr: - if isinstance(uint_var, ScratchVar): - uint_var = uint_var.load() + if isinstance(uint_var, DataStorageSchema): + uint_var = uint_var.load_value() if size > 64: raise NotImplementedError( @@ -240,7 +241,7 @@ def get(self) -> Expr: The expression will have the type TealType.uint64. """ - return self.stored_value.load() + return self._data_storage.load_value() def set(self, value: Union[int, Expr, "Uint", ComputedValue["Uint"]]) -> Expr: """Set the value of this Uint to the input value. @@ -275,7 +276,7 @@ def set(self, value: Union[int, Expr, "Uint", ComputedValue["Uint"]]) -> Expr: value.type_spec(), self.type_spec() ) ) - return uint_set(self.type_spec().bit_size(), self.stored_value, value) + return uint_set(self.type_spec().bit_size(), self._data_storage, value) def decode( self, @@ -287,7 +288,7 @@ def decode( ) -> Expr: return uint_decode( self.type_spec().bit_size(), - self.stored_value, + self._data_storage, encoded, start_index, end_index, @@ -295,7 +296,7 @@ def decode( ) def encode(self) -> Expr: - return uint_encode(self.type_spec().bit_size(), self.stored_value) + return uint_encode(self.type_spec().bit_size(), self._data_storage) Uint.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/uint_test.py b/pyteal/ast/abi/uint_test.py index 3af64f865..c4659fdb9 100644 --- a/pyteal/ast/abi/uint_test.py +++ b/pyteal/ast/abi/uint_test.py @@ -1,4 +1,4 @@ -from typing import List, Tuple, NamedTuple, Callable, Union, Optional +from typing import List, Tuple, NamedTuple, Callable, Union, Optional, cast from pyteal.ast.abi.type_test import ContainerType import pyteal as pt from pyteal import abi @@ -139,7 +139,13 @@ def test_Uint_set_static(): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.int, value_to_set), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast( + abi.ScratchVarStorage, value._data_storage + ).scratchvar.slot, + ), ] ) @@ -167,7 +173,11 @@ def test_Uint_set_expr(): upperBoundCheck = [] if test.checkUpperBound: upperBoundCheck = [ - pt.TealOp(None, pt.Op.load, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), pt.TealOp(None, pt.Op.int, test.maxValue + 1), pt.TealOp(None, pt.Op.lt), pt.TealOp(None, pt.Op.assert_), @@ -178,7 +188,11 @@ def test_Uint_set_expr(): pt.TealOp(None, pt.Op.int, 10), pt.TealOp(None, pt.Op.int, 1), pt.TealOp(None, pt.Op.add), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] + upperBoundCheck ) @@ -201,8 +215,16 @@ def test_Uint_set_copy(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, other.stored_value.slot), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -230,7 +252,11 @@ def test_Uint_set_computed(): expected = pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.int, 0x44), - pt.TealOp(None, pt.Op.store, value.stored_value.slot), + pt.TealOp( + None, + pt.Op.store, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), ] ) @@ -253,7 +279,13 @@ def test_Uint_get(): assert not expr.has_return() expected = pt.TealSimpleBlock( - [pt.TealOp(expr, pt.Op.load, value.stored_value.slot)] + [ + pt.TealOp( + expr, + pt.Op.load, + cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + ), + ] ) actual, _ = expr.__teal__(options) @@ -277,7 +309,7 @@ def test_Uint_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedDecoding = value.stored_value.store( + expectedDecoding = value._data_storage.store_value( test.expectedDecoding(encoded, start_index, end_index, length) ) expected, _ = expectedDecoding.__teal__(options) @@ -326,8 +358,18 @@ def test_ByteUint8_mutual_conversion(): expected = pt.TealSimpleBlock( [ - pt.TealOp(None, pt.Op.load, other.stored_value.slot), - pt.TealOp(None, pt.Op.store, type_b_instance.stored_value.slot), + pt.TealOp( + None, + pt.Op.load, + cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + ), + pt.TealOp( + None, + pt.Op.store, + cast( + abi.ScratchVarStorage, type_b_instance._data_storage + ).scratchvar.slot, + ), ] ) diff --git a/pyteal/ast/comment.py b/pyteal/ast/comment.py index 58c89d63d..361694677 100644 --- a/pyteal/ast/comment.py +++ b/pyteal/ast/comment.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Tuple +from typing import TYPE_CHECKING from pyteal.errors import TealInputError from pyteal.types import TealType @@ -26,7 +26,7 @@ def __init__(self, single_line_comment: str) -> None: ) self.comment = single_line_comment - def __teal__(self, options: "CompileOptions") -> Tuple[TealBlock, TealSimpleBlock]: + def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: op = TealOp(self, Op.comment, self.comment) return TealBlock.FromOp(options, op) diff --git a/pyteal/ast/expr.py b/pyteal/ast/expr.py index c2de1ca32..0f57eebce 100644 --- a/pyteal/ast/expr.py +++ b/pyteal/ast/expr.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from typing import Tuple, List, TYPE_CHECKING +from typing import TYPE_CHECKING from pyteal.types import TealType from pyteal.ir import TealBlock, TealSimpleBlock @@ -16,7 +16,7 @@ def __init__(self): self.trace = traceback.format_stack()[0:-1] - def getDefinitionTrace(self) -> List[str]: + def getDefinitionTrace(self) -> list[str]: return self.trace @abstractmethod @@ -35,7 +35,7 @@ def __str__(self) -> str: pass @abstractmethod - def __teal__(self, options: "CompileOptions") -> Tuple[TealBlock, TealSimpleBlock]: + def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: """Assemble TEAL IR for this component and its arguments.""" pass diff --git a/pyteal/ast/router.py b/pyteal/ast/router.py index 5349cfe84..d10204501 100644 --- a/pyteal/ast/router.py +++ b/pyteal/ast/router.py @@ -352,7 +352,7 @@ def wrap_handler( ) # All subroutine arg values, initialize here and use below instead of - # creating new instances on the fly so we dont have to think about splicing + # creating new instances on the fly, so we don't have to think about splicing # back in the transaction types arg_vals = [typespec.new_instance() for typespec in arg_type_specs] diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 0c5e0205f..7fd38bc9d 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -9,7 +9,7 @@ from pyteal.ast.expr import Expr from pyteal.ast.seq import Seq from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar -from pyteal.errors import TealInputError, verifyProgramVersion +from pyteal.errors import TealInputError, TealInternalError, verifyProgramVersion from pyteal.ir import TealOp, Op, TealBlock from pyteal.types import TealType @@ -378,7 +378,7 @@ def __init__( elif isinstance(arg, ScratchVar): arg_type = arg.type elif isinstance(arg, abi.BaseType): - arg_type = cast(abi.BaseType, arg).stored_value.type + arg_type = cast(abi.BaseType, arg)._data_storage.storage_type() else: raise TealInputError( f"Subroutine argument {arg} at index {i} was of unexpected Python type {type(arg)}" @@ -420,7 +420,7 @@ def handle_arg(arg: Expr | ScratchVar | abi.BaseType) -> Expr: elif isinstance(arg, Expr): return arg elif isinstance(arg, abi.BaseType): - return arg.stored_value.load() + return arg._data_storage.load_value() else: raise TealInputError( f"cannot handle current arg: {arg} to put it on stack" @@ -595,8 +595,6 @@ def __call__( ) return invoked - self.subroutine.get_declaration() - return abi.ReturnedValue( self.output_kwarg_info.abi_type, invoked, @@ -793,6 +791,8 @@ def evaluate_subroutine(subroutine: SubroutineDefinition) -> SubroutineDeclarati def var_n_loaded( param: str, ) -> tuple[ScratchVar, ScratchVar | abi.BaseType | Expr]: + from pyteal.ast.abi.type import ScratchVarStorage + loaded_var: ScratchVar | abi.BaseType | Expr argument_var: ScratchVar @@ -801,7 +801,11 @@ def var_n_loaded( loaded_var = argument_var elif param in subroutine.abi_args: internal_abi_var = subroutine.abi_args[param].new_instance() - argument_var = internal_abi_var.stored_value + if not isinstance(internal_abi_var._data_storage, ScratchVarStorage): + raise TealInternalError( + "subroutine ABI args must have data schema being ScratchVarStorage" + ) + argument_var = internal_abi_var._data_storage.scratchvar loaded_var = internal_abi_var else: argument_var = ScratchVar(TealType.anytype) @@ -849,7 +853,7 @@ def var_n_loaded( f"ABI returning subroutine definition should evaluate to TealType.none, " f"while evaluate to {subroutine_body.type_of()}." ) - deferred_expr = output_carrying_abi.stored_value.load() + deferred_expr = output_carrying_abi._data_storage.load_value() # Arg usage "A" to be pick up and store in scratch parameters that have been placed on the stack # need to reverse order of argumentVars because the last argument will be on top of the stack From 5ec41244e6db30ac9723cac5ea5b5da35f338177 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Thu, 27 Oct 2022 10:49:51 -0400 Subject: [PATCH 067/206] narrower name, module name --- pyteal/ast/abi/__init__.py | 4 ++-- pyteal/ast/abi/address_test.py | 22 +++++++++++----------- pyteal/ast/abi/array_dynamic_test.py | 20 ++++++++++---------- pyteal/ast/abi/array_static_test.py | 14 +++++++------- pyteal/ast/abi/bool_test.py | 20 ++++++++++---------- pyteal/ast/abi/reference_type_test.py | 8 ++++---- pyteal/ast/abi/string_test.py | 20 ++++++++++---------- pyteal/ast/abi/transaction_test.py | 2 +- pyteal/ast/abi/tuple_test.py | 4 ++-- pyteal/ast/abi/type.py | 13 +++++++++++-- pyteal/ast/abi/uint_test.py | 20 +++++++++----------- pyteal/ast/subroutine.py | 4 ++-- 12 files changed, 79 insertions(+), 72 deletions(-) diff --git a/pyteal/ast/abi/__init__.py b/pyteal/ast/abi/__init__.py index 3113b8d72..3ca3ab290 100644 --- a/pyteal/ast/abi/__init__.py +++ b/pyteal/ast/abi/__init__.py @@ -11,7 +11,7 @@ ReturnedValue, DataStorageSchema, FrameStorage, - ScratchVarStorage, + ScratchStorage, ) from pyteal.ast.abi.bool import BoolTypeSpec, Bool from pyteal.ast.abi.uint import ( @@ -176,7 +176,7 @@ "size_of", "DataStorageSchema", "FrameStorage", - "ScratchVarStorage", + "ScratchStorage", "algosdk_from_annotation", "algosdk_from_type_spec", "contains_type_spec", diff --git a/pyteal/ast/abi/address_test.py b/pyteal/ast/abi/address_test.py index 305046619..dca9136dc 100644 --- a/pyteal/ast/abi/address_test.py +++ b/pyteal/ast/abi/address_test.py @@ -53,7 +53,7 @@ def test_Address_encode(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -117,7 +117,7 @@ def test_Address_get(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -139,12 +139,12 @@ def test_Address_set_StaticArray(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value_to_set._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value_to_set._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -174,7 +174,7 @@ def test_Address_set_str(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -203,7 +203,7 @@ def test_Address_set_bytes(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -236,12 +236,12 @@ def test_Address_set_expr(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.int, AddressLength.Bytes.value), @@ -270,12 +270,12 @@ def test_Address_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -307,7 +307,7 @@ def test_Address_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) diff --git a/pyteal/ast/abi/array_dynamic_test.py b/pyteal/ast/abi/array_dynamic_test.py index fa0e122e1..3e172eeee 100644 --- a/pyteal/ast/abi/array_dynamic_test.py +++ b/pyteal/ast/abi/array_dynamic_test.py @@ -185,12 +185,12 @@ def test_DynamicArray_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, otherArray._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, otherArray._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -218,7 +218,7 @@ def test_DynamicArray_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -268,7 +268,7 @@ def test_DynamicBytes_set_py_bytes(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -299,12 +299,12 @@ def test_DynamicBytes_set_expr(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.itob), @@ -312,13 +312,13 @@ def test_DynamicBytes_set_expr(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.concat), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -343,7 +343,7 @@ def test_DynamicBytes_get(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.extract, 2, 0), ] @@ -365,7 +365,7 @@ def test_DynamicArray_encode(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) diff --git a/pyteal/ast/abi/array_static_test.py b/pyteal/ast/abi/array_static_test.py index 236e2591e..7d0a8ae0a 100644 --- a/pyteal/ast/abi/array_static_test.py +++ b/pyteal/ast/abi/array_static_test.py @@ -237,12 +237,12 @@ def test_StaticArray_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, otherArray._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, otherArray._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -270,7 +270,7 @@ def test_StaticArray_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -317,7 +317,7 @@ def test_StaticBytes_set_py_bytes(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -352,13 +352,13 @@ def test_StaticBytes_expr(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.int, 32), pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.eq), @@ -381,7 +381,7 @@ def test_StaticArray_encode(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) diff --git a/pyteal/ast/abi/bool_test.py b/pyteal/ast/abi/bool_test.py index 411bdf376..4299b72ce 100644 --- a/pyteal/ast/abi/bool_test.py +++ b/pyteal/ast/abi/bool_test.py @@ -56,7 +56,7 @@ def test_Bool_set_static(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -85,7 +85,7 @@ def test_Bool_set_expr(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -110,12 +110,12 @@ def test_Bool_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -144,7 +144,7 @@ def test_Bool_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -171,7 +171,7 @@ def test_Bool_get(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -204,7 +204,7 @@ def test_Bool_decode(): None, pt.Op.store, cast( - abi.ScratchVarStorage, value._data_storage + abi.ScratchStorage, value._data_storage ).scratchvar.slot, ), ] @@ -234,7 +234,7 @@ def test_Bool_decode_bit(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -260,7 +260,7 @@ def test_Bool_encode(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.setbit), ] @@ -444,7 +444,7 @@ class EncodeSeqTest(NamedTuple): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, testType._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, testType._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.setbit), ] diff --git a/pyteal/ast/abi/reference_type_test.py b/pyteal/ast/abi/reference_type_test.py index aaa1e5d97..d3b8aaf93 100644 --- a/pyteal/ast/abi/reference_type_test.py +++ b/pyteal/ast/abi/reference_type_test.py @@ -26,7 +26,7 @@ def test_ReferenceType_referenced_index(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -117,7 +117,7 @@ def test_Account_address(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.txnas, "Accounts"), ] @@ -204,7 +204,7 @@ def test_Asset_asset_id(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.txnas, "Assets"), ] @@ -298,7 +298,7 @@ def test_Application_application_id(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.txnas, "Applications"), ] diff --git a/pyteal/ast/abi/string_test.py b/pyteal/ast/abi/string_test.py index 79a699a4c..fb8de7fb9 100644 --- a/pyteal/ast/abi/string_test.py +++ b/pyteal/ast/abi/string_test.py @@ -44,7 +44,7 @@ def test_String_encode(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -107,7 +107,7 @@ def test_String_get(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.extract, 2, 0), ] @@ -143,7 +143,7 @@ def test_String_set_static(value_to_set, value_encoded): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -174,12 +174,12 @@ def test_String_set_expr(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.itob), @@ -187,13 +187,13 @@ def test_String_set_expr(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.concat), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -222,12 +222,12 @@ def test_String_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -259,7 +259,7 @@ def test_String_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) diff --git a/pyteal/ast/abi/transaction_test.py b/pyteal/ast/abi/transaction_test.py index 573d6f440..e21802950 100644 --- a/pyteal/ast/abi/transaction_test.py +++ b/pyteal/ast/abi/transaction_test.py @@ -134,7 +134,7 @@ def test_Transaction__set_index(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, tv.t._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, tv.t._data_storage).scratchvar.slot, ), ] ) diff --git a/pyteal/ast/abi/tuple_test.py b/pyteal/ast/abi/tuple_test.py index 8365769cc..777d3688e 100644 --- a/pyteal/ast/abi/tuple_test.py +++ b/pyteal/ast/abi/tuple_test.py @@ -706,7 +706,7 @@ def test_Tuple_set_Computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, tupleValue._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, tupleValue._data_storage).scratchvar.slot, ), ] ) @@ -737,7 +737,7 @@ def test_Tuple_encode(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, tupleValue._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, tupleValue._data_storage).scratchvar.slot, ), ] ) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index 67d75cc4b..c505021c0 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -79,7 +79,10 @@ def storage_type(self) -> TealType: pass -class ScratchVarStorage(DataStorageSchema): +DataStorageSchema.__module__ = "pyteal" + + +class ScratchStorage(DataStorageSchema): def __init__(self, storage_type: TealType) -> None: super().__init__() self.scratchvar: Final = ScratchVar(storage_type) @@ -94,6 +97,9 @@ def storage_type(self) -> TealType: return self.scratchvar.storage_type() +ScratchStorage.__module__ = "pyteal" + + class FrameStorage(DataStorageSchema): def __init__(self, storage_type: TealType, stack_depth: int) -> None: super().__init__() @@ -114,6 +120,9 @@ def load_value(self) -> Expr: return FrameDig(self.stack_depth) +FrameStorage.__module__ = "pyteal" + + class BaseType(ABC): """The abstract base class for all ABI type instances. @@ -126,7 +135,7 @@ def __init__(self, spec: TypeSpec) -> None: """Create a new BaseType.""" super().__init__() self._type_spec: Final = spec - self._data_storage: DataStorageSchema = ScratchVarStorage(spec.storage_type()) + self._data_storage: DataStorageSchema = ScratchStorage(spec.storage_type()) # self.stored_value: Final = ScratchVar(spec.storage_type()) diff --git a/pyteal/ast/abi/uint_test.py b/pyteal/ast/abi/uint_test.py index c4659fdb9..d4b7cd137 100644 --- a/pyteal/ast/abi/uint_test.py +++ b/pyteal/ast/abi/uint_test.py @@ -142,9 +142,7 @@ def test_Uint_set_static(): pt.TealOp( None, pt.Op.store, - cast( - abi.ScratchVarStorage, value._data_storage - ).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -176,7 +174,7 @@ def test_Uint_set_expr(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), pt.TealOp(None, pt.Op.int, test.maxValue + 1), pt.TealOp(None, pt.Op.lt), @@ -191,7 +189,7 @@ def test_Uint_set_expr(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] + upperBoundCheck @@ -218,12 +216,12 @@ def test_Uint_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -255,7 +253,7 @@ def test_Uint_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -283,7 +281,7 @@ def test_Uint_get(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchVarStorage, value._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, ), ] ) @@ -361,13 +359,13 @@ def test_ByteUint8_mutual_conversion(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchVarStorage, other._data_storage).scratchvar.slot, + cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, ), pt.TealOp( None, pt.Op.store, cast( - abi.ScratchVarStorage, type_b_instance._data_storage + abi.ScratchStorage, type_b_instance._data_storage ).scratchvar.slot, ), ] diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 7fd38bc9d..70365d756 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -791,7 +791,7 @@ def evaluate_subroutine(subroutine: SubroutineDefinition) -> SubroutineDeclarati def var_n_loaded( param: str, ) -> tuple[ScratchVar, ScratchVar | abi.BaseType | Expr]: - from pyteal.ast.abi.type import ScratchVarStorage + from pyteal.ast.abi.type import ScratchStorage loaded_var: ScratchVar | abi.BaseType | Expr argument_var: ScratchVar @@ -801,7 +801,7 @@ def var_n_loaded( loaded_var = argument_var elif param in subroutine.abi_args: internal_abi_var = subroutine.abi_args[param].new_instance() - if not isinstance(internal_abi_var._data_storage, ScratchVarStorage): + if not isinstance(internal_abi_var._data_storage, ScratchStorage): raise TealInternalError( "subroutine ABI args must have data schema being ScratchVarStorage" ) From 7b60233d11b10cec15f5e9dc69a26f5c4468dc80 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 09:05:09 -0400 Subject: [PATCH 068/206] per review comments, on final type annotation --- pyteal/ast/abi/type.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index c505021c0..dfaa9bd16 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -85,7 +85,7 @@ def storage_type(self) -> TealType: class ScratchStorage(DataStorageSchema): def __init__(self, storage_type: TealType) -> None: super().__init__() - self.scratchvar: Final = ScratchVar(storage_type) + self.scratchvar: Final[ScratchVar] = ScratchVar(storage_type) def load_value(self) -> Expr: return self.scratchvar.load() @@ -134,7 +134,7 @@ class BaseType(ABC): def __init__(self, spec: TypeSpec) -> None: """Create a new BaseType.""" super().__init__() - self._type_spec: Final = spec + self._type_spec: Final[TypeSpec] = spec self._data_storage: DataStorageSchema = ScratchStorage(spec.storage_type()) # self.stored_value: Final = ScratchVar(spec.storage_type()) From 2055ce69affc011dc8992fa0166f753157699be9 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 09:33:35 -0400 Subject: [PATCH 069/206] per review comments, renaem to AbstractVar/FrameVar --- pyteal/ast/abi/__init__.py | 4 ++-- pyteal/ast/abi/address.py | 15 +++++-------- pyteal/ast/abi/address_test.py | 2 +- pyteal/ast/abi/array_base.py | 6 ++--- pyteal/ast/abi/array_dynamic.py | 6 ++--- pyteal/ast/abi/array_dynamic_test.py | 4 ++-- pyteal/ast/abi/array_static.py | 10 ++++----- pyteal/ast/abi/array_static_test.py | 4 ++-- pyteal/ast/abi/bool.py | 8 +++---- pyteal/ast/abi/reference_type.py | 6 ++--- pyteal/ast/abi/reference_type_test.py | 2 +- pyteal/ast/abi/string.py | 24 ++++++++------------ pyteal/ast/abi/string_test.py | 2 +- pyteal/ast/abi/transaction.py | 8 +++---- pyteal/ast/abi/tuple.py | 6 ++--- pyteal/ast/abi/tuple_test.py | 4 ++-- pyteal/ast/abi/type.py | 30 ++++++++++++------------- pyteal/ast/abi/type_test.py | 2 +- pyteal/ast/abi/uint.py | 32 +++++++++++++-------------- pyteal/ast/abi/uint_test.py | 2 +- pyteal/ast/subroutine.py | 4 ++-- 21 files changed, 85 insertions(+), 96 deletions(-) diff --git a/pyteal/ast/abi/__init__.py b/pyteal/ast/abi/__init__.py index 3ca3ab290..4baa3bc16 100644 --- a/pyteal/ast/abi/__init__.py +++ b/pyteal/ast/abi/__init__.py @@ -9,7 +9,7 @@ BaseType, ComputedValue, ReturnedValue, - DataStorageSchema, + AbstractVar, FrameStorage, ScratchStorage, ) @@ -174,7 +174,7 @@ "type_specs_from_signature", "make", "size_of", - "DataStorageSchema", + "AbstractVar", "FrameStorage", "ScratchStorage", "algosdk_from_annotation", diff --git a/pyteal/ast/abi/address.py b/pyteal/ast/abi/address.py index 3165fcd9a..0fea62c8a 100644 --- a/pyteal/ast/abi/address.py +++ b/pyteal/ast/abi/address.py @@ -56,7 +56,7 @@ def get(self) -> Expr: The expression will have the type TealType.bytes. """ - return self._data_storage.load_value() + return self._data_storage.load() def set( self, @@ -108,28 +108,25 @@ def set( or value.type_spec() == StaticArrayTypeSpec(ByteTypeSpec(), AddressLength.Bytes) ): - return self._data_storage.store_value( - value._data_storage.load_value() - ) + return self._data_storage.store(value._data_storage.load()) raise TealInputError( f"Got {value} with type spec {value.type_spec()}, expected AddressTypeSpec" ) case str(): # Addr throws if value is invalid address - return self._data_storage.store_value(Addr(value)) + return self._data_storage.store(Addr(value)) case bytes(): if len(value) == AddressLength.Bytes: - return self._data_storage.store_value(Bytes(value)) + return self._data_storage.store(Bytes(value)) raise TealInputError( f"Got bytes with length {len(value)}, expected {AddressLength.Bytes}" ) case Expr(): return Seq( - self._data_storage.store_value(value), + self._data_storage.store(value), Assert( - Len(self._data_storage.load_value()) - == Int(AddressLength.Bytes.value) + Len(self._data_storage.load()) == Int(AddressLength.Bytes.value) ), ) case CollectionSequence(): diff --git a/pyteal/ast/abi/address_test.py b/pyteal/ast/abi/address_test.py index dca9136dc..ccecb0ecf 100644 --- a/pyteal/ast/abi/address_test.py +++ b/pyteal/ast/abi/address_test.py @@ -86,7 +86,7 @@ def test_Address_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expectedExpr = value._data_storage.store_value( + expectedExpr = value._data_storage.store( substring_for_decoding( encoded, start_index=start_index, diff --git a/pyteal/ast/abi/array_base.py b/pyteal/ast/abi/array_base.py index 4674f1d90..417e401e1 100644 --- a/pyteal/ast/abi/array_base.py +++ b/pyteal/ast/abi/array_base.py @@ -104,7 +104,7 @@ def decode( extracted = substring_for_decoding( encoded, start_index=start_index, end_index=end_index, length=length ) - return self._data_storage.store_value(extracted) + return self._data_storage.store(extracted) def set(self, values: Sequence[T]) -> Expr: """Set the ABI array with a sequence of ABI type variables. @@ -142,7 +142,7 @@ def set(self, values: Sequence[T]) -> Expr: length_prefix = Seq(length_tmp.set(len(values)), length_tmp.encode()) encoded = Concat(length_prefix, encoded) - return self._data_storage.store_value(encoded) + return self._data_storage.store(encoded) def encode(self) -> Expr: """Encode the ABI array to be a byte string. @@ -150,7 +150,7 @@ def encode(self) -> Expr: Returns: A PyTeal expression that encodes this ABI array to a byte string. """ - return self._data_storage.load_value() + return self._data_storage.load() @abstractmethod def length(self) -> Expr: diff --git a/pyteal/ast/abi/array_dynamic.py b/pyteal/ast/abi/array_dynamic.py index 2a5f7367d..a39373324 100644 --- a/pyteal/ast/abi/array_dynamic.py +++ b/pyteal/ast/abi/array_dynamic.py @@ -79,7 +79,7 @@ def set( raise TealInputError( f"Cannot assign type {values.type_spec()} to {self.type_spec()}" ) - return self._data_storage.store_value(values.encode()) + return self._data_storage.store(values.encode()) return super().set(values) def length(self) -> Expr: @@ -165,7 +165,7 @@ def set( match values: case bytes() | bytearray(): - return self._data_storage.store_value(_encoded_byte_string(values)) + return self._data_storage.store(_encoded_byte_string(values)) case Expr(): return _store_encoded_expr_byte_string_into_var( values, self._data_storage @@ -181,7 +181,7 @@ def get(self) -> Expr: Returns: A Pyteal expression that loads byte encoding of this DynamicBytes, and drop the first uint16 DynamicArray length encoding. """ - return Suffix(self._data_storage.load_value(), Int(2)) + return Suffix(self._data_storage.load(), Int(2)) DynamicBytes.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/array_dynamic_test.py b/pyteal/ast/abi/array_dynamic_test.py index 3e172eeee..589d52664 100644 --- a/pyteal/ast/abi/array_dynamic_test.py +++ b/pyteal/ast/abi/array_dynamic_test.py @@ -106,7 +106,7 @@ def test_DynamicArray_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value._data_storage.store_value( + expectedExpr = value._data_storage.store( substring_for_decoding( encoded, start_index=start_index, @@ -141,7 +141,7 @@ def test_DynamicArray_set_values(): assert not expr.has_return() length_tmp = abi.Uint16() - expectedExpr = value._data_storage.store_value( + expectedExpr = value._data_storage.store( pt.Concat( pt.Seq(length_tmp.set(len(values)), length_tmp.encode()), _encode_tuple(values), diff --git a/pyteal/ast/abi/array_static.py b/pyteal/ast/abi/array_static.py index caf2dcc88..a631687f3 100644 --- a/pyteal/ast/abi/array_static.py +++ b/pyteal/ast/abi/array_static.py @@ -109,7 +109,7 @@ def set( raise TealInputError( f"Cannot assign type {values.type_spec()} to {self.type_spec()}" ) - return self._data_storage.store_value(values.encode()) + return self._data_storage.store(values.encode()) if self.type_spec().length_static() != len(values): raise TealInputError( @@ -207,11 +207,11 @@ def set( raise TealInputError( f"Got bytes with length {len(values)}, expect {self.type_spec().length_static()}" ) - return self._data_storage.store_value(Bytes(values)) + return self._data_storage.store(Bytes(values)) case Expr(): return Seq( - self._data_storage.store_value(values), - Assert(self.length() == Len(self._data_storage.load_value())), + self._data_storage.store(values), + Assert(self.length() == Len(self._data_storage.load())), ) return super().set(values) @@ -222,7 +222,7 @@ def get(self) -> Expr: Returns: A Pyteal expression that loads byte encoding of this StaticBytes. """ - return self._data_storage.load_value() + return self._data_storage.load() StaticBytes.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/array_static_test.py b/pyteal/ast/abi/array_static_test.py index 7d0a8ae0a..7174c2ebb 100644 --- a/pyteal/ast/abi/array_static_test.py +++ b/pyteal/ast/abi/array_static_test.py @@ -159,7 +159,7 @@ def test_StaticArray_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value._data_storage.store_value( + expectedExpr = value._data_storage.store( substring_for_decoding( encoded, start_index=start_index, @@ -202,7 +202,7 @@ def test_StaticArray_set_values(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value._data_storage.store_value(_encode_tuple(values)) + expectedExpr = value._data_storage.store(_encode_tuple(values)) expected, _ = expectedExpr.__teal__(options) expected.addIncoming() expected = pt.TealBlock.NormalizeBlocks(expected) diff --git a/pyteal/ast/abi/bool.py b/pyteal/ast/abi/bool.py index 2bfbd3aca..6d42c2fdd 100644 --- a/pyteal/ast/abi/bool.py +++ b/pyteal/ast/abi/bool.py @@ -50,7 +50,7 @@ def get(self) -> Expr: expression that evaluates to 0 will be returned. In either case, the expression will have the type TealType.uint64. """ - return self._data_storage.load_value() + return self._data_storage.load() def set(self, value: Union[bool, Expr, "Bool", ComputedValue["Bool"]]) -> Expr: """Set the value of this Bool to the input value. @@ -85,10 +85,10 @@ def set(self, value: Union[bool, Expr, "Bool", ComputedValue["Bool"]]) -> Expr: checked = True if checked: - return self._data_storage.store_value(value) + return self._data_storage.store(value) # Not(Not(value)) coerces all values greater than 0 to 1 - return self._data_storage.store_value(Not(Not(value))) + return self._data_storage.store(Not(Not(value))) def decode( self, @@ -103,7 +103,7 @@ def decode( return self.decode_bit(encoded, start_index * Int(NUM_BITS_IN_BYTE)) def decode_bit(self, encoded, bit_index: Expr) -> Expr: - return self._data_storage.store_value(GetBit(encoded, bit_index)) + return self._data_storage.store(GetBit(encoded, bit_index)) def encode(self) -> Expr: return SetBit(Bytes(b"\x00"), Int(0), self.get()) diff --git a/pyteal/ast/abi/reference_type.py b/pyteal/ast/abi/reference_type.py index 2ea723b92..aa0709ffe 100644 --- a/pyteal/ast/abi/reference_type.py +++ b/pyteal/ast/abi/reference_type.py @@ -58,7 +58,7 @@ def referenced_index(self) -> Expr: If this reference type is an application or asset, note that this DOES NOT return the application or asset ID. See :code:`application_id()` or :code:`asset_id()` for that. """ - return self._data_storage.load_value() + return self._data_storage.load() def decode( self, @@ -107,7 +107,7 @@ def __init__(self) -> None: def address(self) -> Expr: """Get the address of the account.""" - return Txn.accounts[self._data_storage.load_value()] + return Txn.accounts[self._data_storage.load()] def params(self) -> AccountParamObject: """Get information about the account.""" @@ -205,7 +205,7 @@ def __init__(self) -> None: def application_id(self) -> Expr: """Get the ID of the application.""" - return Txn.applications[self._data_storage.load_value()] + return Txn.applications[self._data_storage.load()] def params(self) -> AppParamObject: """Get information about the application's parameters.""" diff --git a/pyteal/ast/abi/reference_type_test.py b/pyteal/ast/abi/reference_type_test.py index d3b8aaf93..edc0a857c 100644 --- a/pyteal/ast/abi/reference_type_test.py +++ b/pyteal/ast/abi/reference_type_test.py @@ -61,7 +61,7 @@ def test_ReferenceType_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expected_decoding = value._data_storage.store_value( + expected_decoding = value._data_storage.store( pt.GetByte( encoded, start_index if start_index is not None else pt.Int(0), diff --git a/pyteal/ast/abi/string.py b/pyteal/ast/abi/string.py index 0359aee76..f91eb272f 100644 --- a/pyteal/ast/abi/string.py +++ b/pyteal/ast/abi/string.py @@ -4,7 +4,7 @@ from algosdk.abi import ABIType from pyteal.ast.abi.uint import Byte -from pyteal.ast.abi.type import ComputedValue, BaseType, DataStorageSchema +from pyteal.ast.abi.type import ComputedValue, BaseType, AbstractVar from pyteal.ast.abi.array_dynamic import DynamicArray, DynamicArrayTypeSpec from pyteal.ast.abi.uint import ByteTypeSpec, Uint16TypeSpec @@ -25,14 +25,12 @@ def _encoded_byte_string(s: bytes | bytearray) -> Expr: def _store_encoded_expr_byte_string_into_var( - value: Expr, location: DataStorageSchema + value: Expr, location: AbstractVar ) -> Expr: return Seq( - location.store_value(value), - location.store_value( - Concat( - Suffix(Itob(Len(location.load_value())), Int(6)), location.load_value() - ) + location.store(value), + location.store( + Concat(Suffix(Itob(Len(location.load())), Int(6)), location.load()) ), ) @@ -70,7 +68,7 @@ def get(self) -> Expr: The expression will have the type TealType.bytes. """ return Suffix( - self._data_storage.load_value(), Int(Uint16TypeSpec().byte_length_static()) + self._data_storage.load(), Int(Uint16TypeSpec().byte_length_static()) ) def set( @@ -113,19 +111,15 @@ def set( if value.type_spec() == StringTypeSpec() or ( value.type_spec() == DynamicArrayTypeSpec(ByteTypeSpec()) ): - return self._data_storage.store_value( - value._data_storage.load_value() - ) + return self._data_storage.store(value._data_storage.load()) raise TealInputError( f"Got {value} with type spec {value.type_spec()}, expected {StringTypeSpec}" ) case bytes() | bytearray(): - return self._data_storage.store_value(_encoded_byte_string(value)) + return self._data_storage.store(_encoded_byte_string(value)) case str(): - return self._data_storage.store_value( - _encoded_byte_string(value.encode()) - ) + return self._data_storage.store(_encoded_byte_string(value.encode())) case Expr(): return _store_encoded_expr_byte_string_into_var( value, self._data_storage diff --git a/pyteal/ast/abi/string_test.py b/pyteal/ast/abi/string_test.py index fb8de7fb9..e335da1a1 100644 --- a/pyteal/ast/abi/string_test.py +++ b/pyteal/ast/abi/string_test.py @@ -76,7 +76,7 @@ def test_DynamicArray_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expectedExpr = value._data_storage.store_value( + expectedExpr = value._data_storage.store( substring_for_decoding( encoded, start_index=start_index, diff --git a/pyteal/ast/abi/transaction.py b/pyteal/ast/abi/transaction.py index 2451a1285..1f3ea9ba2 100644 --- a/pyteal/ast/abi/transaction.py +++ b/pyteal/ast/abi/transaction.py @@ -82,16 +82,16 @@ def _set_index( case ComputedValue(): return self._set_with_computed_type(value) case BaseType(): - return self._data_storage.store_value(self._data_storage.load_value()) + return self._data_storage.store(self._data_storage.load()) case int(): - return self._data_storage.store_value(Int(value)) + return self._data_storage.store(Int(value)) case Expr(): - return self._data_storage.store_value(value) + return self._data_storage.store(value) case _: raise TealInputError(f"Cant store a {type(value)} in a Transaction") def index(self) -> Expr: - return self._data_storage.load_value() + return self._data_storage.load() def decode( self, diff --git a/pyteal/ast/abi/tuple.py b/pyteal/ast/abi/tuple.py index 2f2dceeab..efea10e36 100644 --- a/pyteal/ast/abi/tuple.py +++ b/pyteal/ast/abi/tuple.py @@ -309,7 +309,7 @@ def decode( extracted = substring_for_decoding( encoded, start_index=start_index, end_index=end_index, length=length ) - return self._data_storage.store_value(extracted) + return self._data_storage.store(extracted) @overload def set(self, *values: BaseType) -> Expr: @@ -352,10 +352,10 @@ def set(self, *values): ) if not all(myTypes[i] == values[i].type_spec() for i in range(len(myTypes))): raise TealInputError("Input values do not match type") - return self._data_storage.store_value(_encode_tuple(values)) + return self._data_storage.store(_encode_tuple(values)) def encode(self) -> Expr: - return self._data_storage.load_value() + return self._data_storage.load() def length(self) -> Expr: """Get the number of values this tuple holds as an Expr.""" diff --git a/pyteal/ast/abi/tuple_test.py b/pyteal/ast/abi/tuple_test.py index 777d3688e..ad231784f 100644 --- a/pyteal/ast/abi/tuple_test.py +++ b/pyteal/ast/abi/tuple_test.py @@ -623,7 +623,7 @@ def test_Tuple_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = tupleValue._data_storage.store_value( + expectedExpr = tupleValue._data_storage.store( substring_for_decoding( encoded, start_index=start_index, @@ -672,7 +672,7 @@ def test_Tuple_set(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = tupleValue._data_storage.store_value( + expectedExpr = tupleValue._data_storage.store( _encode_tuple([uint8, uint16, uint32]) ) expected, _ = expectedExpr.__teal__(options) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index dfaa9bd16..3ae5d585c 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -65,13 +65,13 @@ def __str__(self) -> str: TypeSpec.__module__ = "pyteal.abi" -class DataStorageSchema(ABC): +class AbstractVar(ABC): @abstractmethod - def store_value(self, value: Expr) -> Expr: + def store(self, value: Expr) -> Expr: pass @abstractmethod - def load_value(self) -> Expr: + def load(self) -> Expr: pass @abstractmethod @@ -79,18 +79,18 @@ def storage_type(self) -> TealType: pass -DataStorageSchema.__module__ = "pyteal" +AbstractVar.__module__ = "pyteal" -class ScratchStorage(DataStorageSchema): +class ScratchStorage(AbstractVar): def __init__(self, storage_type: TealType) -> None: super().__init__() self.scratchvar: Final[ScratchVar] = ScratchVar(storage_type) - def load_value(self) -> Expr: + def load(self) -> Expr: return self.scratchvar.load() - def store_value(self, value: Expr) -> Expr: + def store(self, value: Expr) -> Expr: return self.scratchvar.slot.store(value) def storage_type(self) -> TealType: @@ -100,7 +100,7 @@ def storage_type(self) -> TealType: ScratchStorage.__module__ = "pyteal" -class FrameStorage(DataStorageSchema): +class FrameStorage(AbstractVar): def __init__(self, storage_type: TealType, stack_depth: int) -> None: super().__init__() self.stack_type = storage_type @@ -109,12 +109,12 @@ def __init__(self, storage_type: TealType, stack_depth: int) -> None: def storage_type(self) -> TealType: return self.stack_type - def store_value(self, value: Expr) -> Expr: + def store(self, value: Expr) -> Expr: from pyteal.ast import FrameBury return FrameBury(value, self.stack_depth) - def load_value(self) -> Expr: + def load(self) -> Expr: from pyteal.ast import FrameDig return FrameDig(self.stack_depth) @@ -135,18 +135,18 @@ def __init__(self, spec: TypeSpec) -> None: """Create a new BaseType.""" super().__init__() self._type_spec: Final[TypeSpec] = spec - self._data_storage: DataStorageSchema = ScratchStorage(spec.storage_type()) + self._data_storage: AbstractVar = ScratchStorage(spec.storage_type()) # self.stored_value: Final = ScratchVar(spec.storage_type()) - def _set_data_source(self, storage: DataStorageSchema) -> None: + def _set_data_source(self, storage: AbstractVar) -> None: self._data_storage = storage def _load_value(self) -> Expr: - return self._data_storage.load_value() + return self._data_storage.load() def _store_value(self, value: Expr) -> Expr: - return self._data_storage.store_value(value) + return self._data_storage.store(value) def type_spec(self) -> TypeSpec: """Get the TypeSpec for this ABI type instance.""" @@ -300,7 +300,7 @@ def store_into(self, output: BaseType) -> Expr: f"ABI return subroutine deferred_expr is expected to be typed {output.type_spec().storage_type()}, " f"but has type {declaration.deferred_expr.type_of()}." ) - return output._data_storage.store_value(self.computation) + return output._data_storage.store(self.computation) ReturnedValue.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/type_test.py b/pyteal/ast/abi/type_test.py index b5134ef7d..30f39e0fc 100644 --- a/pyteal/ast/abi/type_test.py +++ b/pyteal/ast/abi/type_test.py @@ -17,7 +17,7 @@ def store_into(self, output: abi.BaseType) -> pt.Expr: raise pt.TealInputError( f"expected type_spec {self.type_spec} but get {output.type_spec()}" ) - return output._data_storage.store_value(self.encodings) + return output._data_storage.store(self.encodings) def test_ComputedType_use(): diff --git a/pyteal/ast/abi/uint.py b/pyteal/ast/abi/uint.py index e34daac9a..67d3ff428 100644 --- a/pyteal/ast/abi/uint.py +++ b/pyteal/ast/abi/uint.py @@ -17,7 +17,7 @@ from pyteal.ast.unaryexpr import Itob, Btoi from pyteal.ast.binaryexpr import GetByte, ExtractUint16, ExtractUint32, ExtractUint64 from pyteal.ast.ternaryexpr import SetByte -from pyteal.ast.abi.type import ComputedValue, TypeSpec, BaseType, DataStorageSchema +from pyteal.ast.abi.type import ComputedValue, TypeSpec, BaseType, AbstractVar NUM_BITS_IN_BYTE = 8 @@ -30,9 +30,7 @@ def uint_storage_type(size: int) -> TealType: return TealType.bytes -def uint_set( - size: int, uint_var: DataStorageSchema, value: Union[int, Expr, "Uint"] -) -> Expr: +def uint_set(size: int, uint_var: AbstractVar, value: Union[int, Expr, "Uint"]) -> Expr: if size > 64: raise NotImplementedError( "Uint operations have not yet been implemented for bit sizes larger than 64" @@ -50,17 +48,17 @@ def uint_set( checked = True if checked or size == 64: - return uint_var.store_value(cast(Expr, value)) + return uint_var.store(cast(Expr, value)) return Seq( - uint_var.store_value(cast(Expr, value)), - Assert(uint_var.load_value() < Int(2**size)), + uint_var.store(cast(Expr, value)), + Assert(uint_var.load() < Int(2**size)), ) def uint_decode( size: int, - uint_var: DataStorageSchema, + uint_var: AbstractVar, encoded: Expr, start_index: Optional[Expr], end_index: Optional[Expr], @@ -74,27 +72,27 @@ def uint_decode( if size == 64: if start_index is None: if end_index is None and length is None: - return uint_var.store_value(Btoi(encoded)) + return uint_var.store(Btoi(encoded)) start_index = Int(0) - return uint_var.store_value(ExtractUint64(encoded, start_index)) + return uint_var.store(ExtractUint64(encoded, start_index)) if start_index is None: start_index = Int(0) if size == 8: - return uint_var.store_value(GetByte(encoded, start_index)) + return uint_var.store(GetByte(encoded, start_index)) if size == 16: - return uint_var.store_value(ExtractUint16(encoded, start_index)) + return uint_var.store(ExtractUint16(encoded, start_index)) if size == 32: - return uint_var.store_value(ExtractUint32(encoded, start_index)) + return uint_var.store(ExtractUint32(encoded, start_index)) raise ValueError("Unsupported uint size: {}".format(size)) -def uint_encode(size: int, uint_var: Expr | DataStorageSchema) -> Expr: +def uint_encode(size: int, uint_var: Expr | AbstractVar) -> Expr: - if isinstance(uint_var, DataStorageSchema): - uint_var = uint_var.load_value() + if isinstance(uint_var, AbstractVar): + uint_var = uint_var.load() if size > 64: raise NotImplementedError( @@ -241,7 +239,7 @@ def get(self) -> Expr: The expression will have the type TealType.uint64. """ - return self._data_storage.load_value() + return self._data_storage.load() def set(self, value: Union[int, Expr, "Uint", ComputedValue["Uint"]]) -> Expr: """Set the value of this Uint to the input value. diff --git a/pyteal/ast/abi/uint_test.py b/pyteal/ast/abi/uint_test.py index d4b7cd137..d571e7aa6 100644 --- a/pyteal/ast/abi/uint_test.py +++ b/pyteal/ast/abi/uint_test.py @@ -307,7 +307,7 @@ def test_Uint_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedDecoding = value._data_storage.store_value( + expectedDecoding = value._data_storage.store( test.expectedDecoding(encoded, start_index, end_index, length) ) expected, _ = expectedDecoding.__teal__(options) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 70365d756..d509f980b 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -420,7 +420,7 @@ def handle_arg(arg: Expr | ScratchVar | abi.BaseType) -> Expr: elif isinstance(arg, Expr): return arg elif isinstance(arg, abi.BaseType): - return arg._data_storage.load_value() + return arg._data_storage.load() else: raise TealInputError( f"cannot handle current arg: {arg} to put it on stack" @@ -853,7 +853,7 @@ def var_n_loaded( f"ABI returning subroutine definition should evaluate to TealType.none, " f"while evaluate to {subroutine_body.type_of()}." ) - deferred_expr = output_carrying_abi._data_storage.load_value() + deferred_expr = output_carrying_abi._data_storage.load() # Arg usage "A" to be pick up and store in scratch parameters that have been placed on the stack # need to reverse order of argumentVars because the last argument will be on top of the stack From f6899374313f08ae5a852988cebd7c4f056febf1 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 10:42:18 -0400 Subject: [PATCH 070/206] per review comments, move storage model to AbstractVar, rough hack to make returned value type check deactivate --- pyteal/__init__.pyi | 1 + pyteal/ast/__init__.py | 3 ++- pyteal/ast/abi/__init__.py | 2 -- pyteal/ast/abi/address.py | 12 +++++----- pyteal/ast/abi/address_test.py | 24 ++++++++++---------- pyteal/ast/abi/array_base.py | 6 ++--- pyteal/ast/abi/array_dynamic.py | 8 +++---- pyteal/ast/abi/array_dynamic_test.py | 24 ++++++++++---------- pyteal/ast/abi/array_static.py | 10 ++++----- pyteal/ast/abi/array_static_test.py | 18 +++++++-------- pyteal/ast/abi/bool.py | 8 +++---- pyteal/ast/abi/bool_test.py | 22 +++++++++--------- pyteal/ast/abi/reference_type.py | 8 +++---- pyteal/ast/abi/reference_type_test.py | 10 ++++----- pyteal/ast/abi/string.py | 10 ++++----- pyteal/ast/abi/string_test.py | 22 +++++++++--------- pyteal/ast/abi/transaction.py | 8 +++---- pyteal/ast/abi/transaction_test.py | 2 +- pyteal/ast/abi/tuple.py | 6 ++--- pyteal/ast/abi/tuple_test.py | 10 ++++----- pyteal/ast/abi/type.py | 32 ++++++--------------------- pyteal/ast/abi/type_test.py | 2 +- pyteal/ast/abi/uint.py | 8 +++---- pyteal/ast/abi/uint_test.py | 22 +++++++++--------- pyteal/ast/scratchvar.py | 21 +++++++++++++++++- pyteal/ast/subroutine.py | 12 +++++----- 26 files changed, 152 insertions(+), 159 deletions(-) diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index 40600d561..ed1d3c1e1 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -35,6 +35,7 @@ from pyteal.config import ( __all__ = [ "ABIReturnSubroutine", + "AbstractVar", "AccountParam", "AccountParamObject", "Add", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 1ca49a2e5..3d2671068 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -165,7 +165,7 @@ ScratchStackStore, ScratchStore, ) -from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar +from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar, AbstractVar from pyteal.ast.maybe import MaybeValue from pyteal.ast.multi import MultiValue from pyteal.ast.opup import OpUp, OpUpMode, OpUpFeeSource @@ -305,6 +305,7 @@ "ScratchStore", "DynamicScratchVar", "ScratchVar", + "AbstractVar", "MaybeValue", "MultiValue", "OpUp", diff --git a/pyteal/ast/abi/__init__.py b/pyteal/ast/abi/__init__.py index 4baa3bc16..bb2a0d1b2 100644 --- a/pyteal/ast/abi/__init__.py +++ b/pyteal/ast/abi/__init__.py @@ -9,7 +9,6 @@ BaseType, ComputedValue, ReturnedValue, - AbstractVar, FrameStorage, ScratchStorage, ) @@ -174,7 +173,6 @@ "type_specs_from_signature", "make", "size_of", - "AbstractVar", "FrameStorage", "ScratchStorage", "algosdk_from_annotation", diff --git a/pyteal/ast/abi/address.py b/pyteal/ast/abi/address.py index 0fea62c8a..d0413cf6c 100644 --- a/pyteal/ast/abi/address.py +++ b/pyteal/ast/abi/address.py @@ -56,7 +56,7 @@ def get(self) -> Expr: The expression will have the type TealType.bytes. """ - return self._data_storage.load() + return self.stored_value.load() def set( self, @@ -108,25 +108,25 @@ def set( or value.type_spec() == StaticArrayTypeSpec(ByteTypeSpec(), AddressLength.Bytes) ): - return self._data_storage.store(value._data_storage.load()) + return self.stored_value.store(value.stored_value.load()) raise TealInputError( f"Got {value} with type spec {value.type_spec()}, expected AddressTypeSpec" ) case str(): # Addr throws if value is invalid address - return self._data_storage.store(Addr(value)) + return self.stored_value.store(Addr(value)) case bytes(): if len(value) == AddressLength.Bytes: - return self._data_storage.store(Bytes(value)) + return self.stored_value.store(Bytes(value)) raise TealInputError( f"Got bytes with length {len(value)}, expected {AddressLength.Bytes}" ) case Expr(): return Seq( - self._data_storage.store(value), + self.stored_value.store(value), Assert( - Len(self._data_storage.load()) == Int(AddressLength.Bytes.value) + Len(self.stored_value.load()) == Int(AddressLength.Bytes.value) ), ) case CollectionSequence(): diff --git a/pyteal/ast/abi/address_test.py b/pyteal/ast/abi/address_test.py index ccecb0ecf..d115082cd 100644 --- a/pyteal/ast/abi/address_test.py +++ b/pyteal/ast/abi/address_test.py @@ -53,7 +53,7 @@ def test_Address_encode(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -86,7 +86,7 @@ def test_Address_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expectedExpr = value._data_storage.store( + expectedExpr = value.stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -117,7 +117,7 @@ def test_Address_get(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -139,12 +139,12 @@ def test_Address_set_StaticArray(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value_to_set._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value_to_set.stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -174,7 +174,7 @@ def test_Address_set_str(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -203,7 +203,7 @@ def test_Address_set_bytes(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -236,12 +236,12 @@ def test_Address_set_expr(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.int, AddressLength.Bytes.value), @@ -270,12 +270,12 @@ def test_Address_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, + cast(pt.ScratchVar, other.stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -307,7 +307,7 @@ def test_Address_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/array_base.py b/pyteal/ast/abi/array_base.py index 417e401e1..aea164c81 100644 --- a/pyteal/ast/abi/array_base.py +++ b/pyteal/ast/abi/array_base.py @@ -104,7 +104,7 @@ def decode( extracted = substring_for_decoding( encoded, start_index=start_index, end_index=end_index, length=length ) - return self._data_storage.store(extracted) + return self.stored_value.store(extracted) def set(self, values: Sequence[T]) -> Expr: """Set the ABI array with a sequence of ABI type variables. @@ -142,7 +142,7 @@ def set(self, values: Sequence[T]) -> Expr: length_prefix = Seq(length_tmp.set(len(values)), length_tmp.encode()) encoded = Concat(length_prefix, encoded) - return self._data_storage.store(encoded) + return self.stored_value.store(encoded) def encode(self) -> Expr: """Encode the ABI array to be a byte string. @@ -150,7 +150,7 @@ def encode(self) -> Expr: Returns: A PyTeal expression that encodes this ABI array to a byte string. """ - return self._data_storage.load() + return self.stored_value.load() @abstractmethod def length(self) -> Expr: diff --git a/pyteal/ast/abi/array_dynamic.py b/pyteal/ast/abi/array_dynamic.py index a39373324..9d53e0559 100644 --- a/pyteal/ast/abi/array_dynamic.py +++ b/pyteal/ast/abi/array_dynamic.py @@ -79,7 +79,7 @@ def set( raise TealInputError( f"Cannot assign type {values.type_spec()} to {self.type_spec()}" ) - return self._data_storage.store(values.encode()) + return self.stored_value.store(values.encode()) return super().set(values) def length(self) -> Expr: @@ -165,10 +165,10 @@ def set( match values: case bytes() | bytearray(): - return self._data_storage.store(_encoded_byte_string(values)) + return self.stored_value.store(_encoded_byte_string(values)) case Expr(): return _store_encoded_expr_byte_string_into_var( - values, self._data_storage + values, self.stored_value ) return super().set(values) @@ -181,7 +181,7 @@ def get(self) -> Expr: Returns: A Pyteal expression that loads byte encoding of this DynamicBytes, and drop the first uint16 DynamicArray length encoding. """ - return Suffix(self._data_storage.load(), Int(2)) + return Suffix(self.stored_value.load(), Int(2)) DynamicBytes.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/array_dynamic_test.py b/pyteal/ast/abi/array_dynamic_test.py index 589d52664..e8e930787 100644 --- a/pyteal/ast/abi/array_dynamic_test.py +++ b/pyteal/ast/abi/array_dynamic_test.py @@ -106,7 +106,7 @@ def test_DynamicArray_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value._data_storage.store( + expectedExpr = value.stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -141,7 +141,7 @@ def test_DynamicArray_set_values(): assert not expr.has_return() length_tmp = abi.Uint16() - expectedExpr = value._data_storage.store( + expectedExpr = value.stored_value.store( pt.Concat( pt.Seq(length_tmp.set(len(values)), length_tmp.encode()), _encode_tuple(values), @@ -185,12 +185,12 @@ def test_DynamicArray_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, otherArray._data_storage).scratchvar.slot, + cast(pt.ScratchVar, otherArray.stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -218,7 +218,7 @@ def test_DynamicArray_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -268,7 +268,7 @@ def test_DynamicBytes_set_py_bytes(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -299,12 +299,12 @@ def test_DynamicBytes_set_expr(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.itob), @@ -312,13 +312,13 @@ def test_DynamicBytes_set_expr(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.concat), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -343,7 +343,7 @@ def test_DynamicBytes_get(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.extract, 2, 0), ] @@ -365,7 +365,7 @@ def test_DynamicArray_encode(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/array_static.py b/pyteal/ast/abi/array_static.py index a631687f3..7744a6edb 100644 --- a/pyteal/ast/abi/array_static.py +++ b/pyteal/ast/abi/array_static.py @@ -109,7 +109,7 @@ def set( raise TealInputError( f"Cannot assign type {values.type_spec()} to {self.type_spec()}" ) - return self._data_storage.store(values.encode()) + return self.stored_value.store(values.encode()) if self.type_spec().length_static() != len(values): raise TealInputError( @@ -207,11 +207,11 @@ def set( raise TealInputError( f"Got bytes with length {len(values)}, expect {self.type_spec().length_static()}" ) - return self._data_storage.store(Bytes(values)) + return self.stored_value.store(Bytes(values)) case Expr(): return Seq( - self._data_storage.store(values), - Assert(self.length() == Len(self._data_storage.load())), + self.stored_value.store(values), + Assert(self.length() == Len(self.stored_value.load())), ) return super().set(values) @@ -222,7 +222,7 @@ def get(self) -> Expr: Returns: A Pyteal expression that loads byte encoding of this StaticBytes. """ - return self._data_storage.load() + return self.stored_value.load() StaticBytes.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/array_static_test.py b/pyteal/ast/abi/array_static_test.py index 7174c2ebb..7c2e914ec 100644 --- a/pyteal/ast/abi/array_static_test.py +++ b/pyteal/ast/abi/array_static_test.py @@ -159,7 +159,7 @@ def test_StaticArray_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value._data_storage.store( + expectedExpr = value.stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -202,7 +202,7 @@ def test_StaticArray_set_values(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value._data_storage.store(_encode_tuple(values)) + expectedExpr = value.stored_value.store(_encode_tuple(values)) expected, _ = expectedExpr.__teal__(options) expected.addIncoming() expected = pt.TealBlock.NormalizeBlocks(expected) @@ -237,12 +237,12 @@ def test_StaticArray_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, otherArray._data_storage).scratchvar.slot, + cast(pt.ScratchVar, otherArray.stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -270,7 +270,7 @@ def test_StaticArray_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -317,7 +317,7 @@ def test_StaticBytes_set_py_bytes(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -352,13 +352,13 @@ def test_StaticBytes_expr(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.int, 32), pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.eq), @@ -381,7 +381,7 @@ def test_StaticArray_encode(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/bool.py b/pyteal/ast/abi/bool.py index 6d42c2fdd..13552b6db 100644 --- a/pyteal/ast/abi/bool.py +++ b/pyteal/ast/abi/bool.py @@ -50,7 +50,7 @@ def get(self) -> Expr: expression that evaluates to 0 will be returned. In either case, the expression will have the type TealType.uint64. """ - return self._data_storage.load() + return self.stored_value.load() def set(self, value: Union[bool, Expr, "Bool", ComputedValue["Bool"]]) -> Expr: """Set the value of this Bool to the input value. @@ -85,10 +85,10 @@ def set(self, value: Union[bool, Expr, "Bool", ComputedValue["Bool"]]) -> Expr: checked = True if checked: - return self._data_storage.store(value) + return self.stored_value.store(value) # Not(Not(value)) coerces all values greater than 0 to 1 - return self._data_storage.store(Not(Not(value))) + return self.stored_value.store(Not(Not(value))) def decode( self, @@ -103,7 +103,7 @@ def decode( return self.decode_bit(encoded, start_index * Int(NUM_BITS_IN_BYTE)) def decode_bit(self, encoded, bit_index: Expr) -> Expr: - return self._data_storage.store(GetBit(encoded, bit_index)) + return self.stored_value.store(GetBit(encoded, bit_index)) def encode(self) -> Expr: return SetBit(Bytes(b"\x00"), Int(0), self.get()) diff --git a/pyteal/ast/abi/bool_test.py b/pyteal/ast/abi/bool_test.py index 4299b72ce..1cf881d55 100644 --- a/pyteal/ast/abi/bool_test.py +++ b/pyteal/ast/abi/bool_test.py @@ -56,7 +56,7 @@ def test_Bool_set_static(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -85,7 +85,7 @@ def test_Bool_set_expr(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -110,12 +110,12 @@ def test_Bool_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, + cast(pt.ScratchVar, other.stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -144,7 +144,7 @@ def test_Bool_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -171,7 +171,7 @@ def test_Bool_get(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -203,9 +203,7 @@ def test_Bool_decode(): pt.TealOp( None, pt.Op.store, - cast( - abi.ScratchStorage, value._data_storage - ).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -234,7 +232,7 @@ def test_Bool_decode_bit(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -260,7 +258,7 @@ def test_Bool_encode(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.setbit), ] @@ -444,7 +442,7 @@ class EncodeSeqTest(NamedTuple): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, testType._data_storage).scratchvar.slot, + cast(pt.ScratchVar, testType.stored_value).slot, ), pt.TealOp(None, pt.Op.setbit), ] diff --git a/pyteal/ast/abi/reference_type.py b/pyteal/ast/abi/reference_type.py index aa0709ffe..f4882fc97 100644 --- a/pyteal/ast/abi/reference_type.py +++ b/pyteal/ast/abi/reference_type.py @@ -58,7 +58,7 @@ def referenced_index(self) -> Expr: If this reference type is an application or asset, note that this DOES NOT return the application or asset ID. See :code:`application_id()` or :code:`asset_id()` for that. """ - return self._data_storage.load() + return self.stored_value.load() def decode( self, @@ -70,7 +70,7 @@ def decode( ) -> Expr: return uint_decode( self.type_spec().bit_size(), - self._data_storage, + self.stored_value, encoded, start_index, end_index, @@ -107,7 +107,7 @@ def __init__(self) -> None: def address(self) -> Expr: """Get the address of the account.""" - return Txn.accounts[self._data_storage.load()] + return Txn.accounts[self.stored_value.load()] def params(self) -> AccountParamObject: """Get information about the account.""" @@ -205,7 +205,7 @@ def __init__(self) -> None: def application_id(self) -> Expr: """Get the ID of the application.""" - return Txn.applications[self._data_storage.load()] + return Txn.applications[self.stored_value.load()] def params(self) -> AppParamObject: """Get information about the application's parameters.""" diff --git a/pyteal/ast/abi/reference_type_test.py b/pyteal/ast/abi/reference_type_test.py index edc0a857c..4ec862e66 100644 --- a/pyteal/ast/abi/reference_type_test.py +++ b/pyteal/ast/abi/reference_type_test.py @@ -26,7 +26,7 @@ def test_ReferenceType_referenced_index(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -61,7 +61,7 @@ def test_ReferenceType_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expected_decoding = value._data_storage.store( + expected_decoding = value.stored_value.store( pt.GetByte( encoded, start_index if start_index is not None else pt.Int(0), @@ -117,7 +117,7 @@ def test_Account_address(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.txnas, "Accounts"), ] @@ -204,7 +204,7 @@ def test_Asset_asset_id(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.txnas, "Assets"), ] @@ -298,7 +298,7 @@ def test_Application_application_id(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.txnas, "Applications"), ] diff --git a/pyteal/ast/abi/string.py b/pyteal/ast/abi/string.py index f91eb272f..ac5866cb2 100644 --- a/pyteal/ast/abi/string.py +++ b/pyteal/ast/abi/string.py @@ -68,7 +68,7 @@ def get(self) -> Expr: The expression will have the type TealType.bytes. """ return Suffix( - self._data_storage.load(), Int(Uint16TypeSpec().byte_length_static()) + self.stored_value.load(), Int(Uint16TypeSpec().byte_length_static()) ) def set( @@ -111,18 +111,18 @@ def set( if value.type_spec() == StringTypeSpec() or ( value.type_spec() == DynamicArrayTypeSpec(ByteTypeSpec()) ): - return self._data_storage.store(value._data_storage.load()) + return self.stored_value.store(value.stored_value.load()) raise TealInputError( f"Got {value} with type spec {value.type_spec()}, expected {StringTypeSpec}" ) case bytes() | bytearray(): - return self._data_storage.store(_encoded_byte_string(value)) + return self.stored_value.store(_encoded_byte_string(value)) case str(): - return self._data_storage.store(_encoded_byte_string(value.encode())) + return self.stored_value.store(_encoded_byte_string(value.encode())) case Expr(): return _store_encoded_expr_byte_string_into_var( - value, self._data_storage + value, self.stored_value ) case CollectionSequence(): return super().set(cast(Sequence[Byte], value)) diff --git a/pyteal/ast/abi/string_test.py b/pyteal/ast/abi/string_test.py index e335da1a1..c60ac52f4 100644 --- a/pyteal/ast/abi/string_test.py +++ b/pyteal/ast/abi/string_test.py @@ -44,7 +44,7 @@ def test_String_encode(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -76,7 +76,7 @@ def test_DynamicArray_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expectedExpr = value._data_storage.store( + expectedExpr = value.stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -107,7 +107,7 @@ def test_String_get(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.extract, 2, 0), ] @@ -143,7 +143,7 @@ def test_String_set_static(value_to_set, value_encoded): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -174,12 +174,12 @@ def test_String_set_expr(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.itob), @@ -187,13 +187,13 @@ def test_String_set_expr(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.concat), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -222,12 +222,12 @@ def test_String_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, + cast(pt.ScratchVar, other.stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -259,7 +259,7 @@ def test_String_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/transaction.py b/pyteal/ast/abi/transaction.py index 1f3ea9ba2..aeb5c7a33 100644 --- a/pyteal/ast/abi/transaction.py +++ b/pyteal/ast/abi/transaction.py @@ -82,16 +82,16 @@ def _set_index( case ComputedValue(): return self._set_with_computed_type(value) case BaseType(): - return self._data_storage.store(self._data_storage.load()) + return self.stored_value.store(self.stored_value.load()) case int(): - return self._data_storage.store(Int(value)) + return self.stored_value.store(Int(value)) case Expr(): - return self._data_storage.store(value) + return self.stored_value.store(value) case _: raise TealInputError(f"Cant store a {type(value)} in a Transaction") def index(self) -> Expr: - return self._data_storage.load() + return self.stored_value.load() def decode( self, diff --git a/pyteal/ast/abi/transaction_test.py b/pyteal/ast/abi/transaction_test.py index e21802950..b4c27a97c 100644 --- a/pyteal/ast/abi/transaction_test.py +++ b/pyteal/ast/abi/transaction_test.py @@ -134,7 +134,7 @@ def test_Transaction__set_index(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, tv.t._data_storage).scratchvar.slot, + cast(pt.ScratchVar, tv.t.stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/tuple.py b/pyteal/ast/abi/tuple.py index efea10e36..bc1966414 100644 --- a/pyteal/ast/abi/tuple.py +++ b/pyteal/ast/abi/tuple.py @@ -309,7 +309,7 @@ def decode( extracted = substring_for_decoding( encoded, start_index=start_index, end_index=end_index, length=length ) - return self._data_storage.store(extracted) + return self.stored_value.store(extracted) @overload def set(self, *values: BaseType) -> Expr: @@ -352,10 +352,10 @@ def set(self, *values): ) if not all(myTypes[i] == values[i].type_spec() for i in range(len(myTypes))): raise TealInputError("Input values do not match type") - return self._data_storage.store(_encode_tuple(values)) + return self.stored_value.store(_encode_tuple(values)) def encode(self) -> Expr: - return self._data_storage.load() + return self.stored_value.load() def length(self) -> Expr: """Get the number of values this tuple holds as an Expr.""" diff --git a/pyteal/ast/abi/tuple_test.py b/pyteal/ast/abi/tuple_test.py index ad231784f..a761d88af 100644 --- a/pyteal/ast/abi/tuple_test.py +++ b/pyteal/ast/abi/tuple_test.py @@ -623,7 +623,7 @@ def test_Tuple_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = tupleValue._data_storage.store( + expectedExpr = tupleValue.stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -672,9 +672,7 @@ def test_Tuple_set(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = tupleValue._data_storage.store( - _encode_tuple([uint8, uint16, uint32]) - ) + expectedExpr = tupleValue.stored_value.store(_encode_tuple([uint8, uint16, uint32])) expected, _ = expectedExpr.__teal__(options) expected.addIncoming() expected = pt.TealBlock.NormalizeBlocks(expected) @@ -706,7 +704,7 @@ def test_Tuple_set_Computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, tupleValue._data_storage).scratchvar.slot, + cast(pt.ScratchVar, tupleValue.stored_value).slot, ), ] ) @@ -737,7 +735,7 @@ def test_Tuple_encode(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, tupleValue._data_storage).scratchvar.slot, + cast(pt.ScratchVar, tupleValue.stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index 3ae5d585c..2e9027c5d 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -4,7 +4,7 @@ from pyteal.errors import TealInputError from pyteal.types import TealType from pyteal.ast.expr import Expr -from pyteal.ast.scratchvar import ScratchVar +from pyteal.ast.scratchvar import ScratchVar, AbstractVar from pyteal.ast.seq import Seq @@ -65,23 +65,6 @@ def __str__(self) -> str: TypeSpec.__module__ = "pyteal.abi" -class AbstractVar(ABC): - @abstractmethod - def store(self, value: Expr) -> Expr: - pass - - @abstractmethod - def load(self) -> Expr: - pass - - @abstractmethod - def storage_type(self) -> TealType: - pass - - -AbstractVar.__module__ = "pyteal" - - class ScratchStorage(AbstractVar): def __init__(self, storage_type: TealType) -> None: super().__init__() @@ -135,18 +118,16 @@ def __init__(self, spec: TypeSpec) -> None: """Create a new BaseType.""" super().__init__() self._type_spec: Final[TypeSpec] = spec - self._data_storage: AbstractVar = ScratchStorage(spec.storage_type()) - - # self.stored_value: Final = ScratchVar(spec.storage_type()) + self.stored_value: AbstractVar = ScratchVar(spec.storage_type()) def _set_data_source(self, storage: AbstractVar) -> None: - self._data_storage = storage + self.stored_value = storage def _load_value(self) -> Expr: - return self._data_storage.load() + return self.stored_value.load() def _store_value(self, value: Expr) -> Expr: - return self._data_storage.store(value) + return self.stored_value.store(value) def type_spec(self) -> TypeSpec: """Get the TypeSpec for this ABI type instance.""" @@ -300,7 +281,8 @@ def store_into(self, output: BaseType) -> Expr: f"ABI return subroutine deferred_expr is expected to be typed {output.type_spec().storage_type()}, " f"but has type {declaration.deferred_expr.type_of()}." ) - return output._data_storage.store(self.computation) + assert isinstance(output.stored_value, ScratchVar) + return output.stored_value.slot.store(self.computation) ReturnedValue.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/type_test.py b/pyteal/ast/abi/type_test.py index 30f39e0fc..56a9e6c76 100644 --- a/pyteal/ast/abi/type_test.py +++ b/pyteal/ast/abi/type_test.py @@ -17,7 +17,7 @@ def store_into(self, output: abi.BaseType) -> pt.Expr: raise pt.TealInputError( f"expected type_spec {self.type_spec} but get {output.type_spec()}" ) - return output._data_storage.store(self.encodings) + return output.stored_value.store(self.encodings) def test_ComputedType_use(): diff --git a/pyteal/ast/abi/uint.py b/pyteal/ast/abi/uint.py index 67d3ff428..0a99eb27f 100644 --- a/pyteal/ast/abi/uint.py +++ b/pyteal/ast/abi/uint.py @@ -239,7 +239,7 @@ def get(self) -> Expr: The expression will have the type TealType.uint64. """ - return self._data_storage.load() + return self.stored_value.load() def set(self, value: Union[int, Expr, "Uint", ComputedValue["Uint"]]) -> Expr: """Set the value of this Uint to the input value. @@ -274,7 +274,7 @@ def set(self, value: Union[int, Expr, "Uint", ComputedValue["Uint"]]) -> Expr: value.type_spec(), self.type_spec() ) ) - return uint_set(self.type_spec().bit_size(), self._data_storage, value) + return uint_set(self.type_spec().bit_size(), self.stored_value, value) def decode( self, @@ -286,7 +286,7 @@ def decode( ) -> Expr: return uint_decode( self.type_spec().bit_size(), - self._data_storage, + self.stored_value, encoded, start_index, end_index, @@ -294,7 +294,7 @@ def decode( ) def encode(self) -> Expr: - return uint_encode(self.type_spec().bit_size(), self._data_storage) + return uint_encode(self.type_spec().bit_size(), self.stored_value) Uint.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/uint_test.py b/pyteal/ast/abi/uint_test.py index d571e7aa6..26ba3541f 100644 --- a/pyteal/ast/abi/uint_test.py +++ b/pyteal/ast/abi/uint_test.py @@ -142,7 +142,7 @@ def test_Uint_set_static(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -174,7 +174,7 @@ def test_Uint_set_expr(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), pt.TealOp(None, pt.Op.int, test.maxValue + 1), pt.TealOp(None, pt.Op.lt), @@ -189,7 +189,7 @@ def test_Uint_set_expr(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] + upperBoundCheck @@ -216,12 +216,12 @@ def test_Uint_set_copy(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, + cast(pt.ScratchVar, other.stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -253,7 +253,7 @@ def test_Uint_set_computed(): pt.TealOp( None, pt.Op.store, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -281,7 +281,7 @@ def test_Uint_get(): pt.TealOp( expr, pt.Op.load, - cast(abi.ScratchStorage, value._data_storage).scratchvar.slot, + cast(pt.ScratchVar, value.stored_value).slot, ), ] ) @@ -307,7 +307,7 @@ def test_Uint_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedDecoding = value._data_storage.store( + expectedDecoding = value.stored_value.store( test.expectedDecoding(encoded, start_index, end_index, length) ) expected, _ = expectedDecoding.__teal__(options) @@ -359,14 +359,12 @@ def test_ByteUint8_mutual_conversion(): pt.TealOp( None, pt.Op.load, - cast(abi.ScratchStorage, other._data_storage).scratchvar.slot, + cast(pt.ScratchVar, other.stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast( - abi.ScratchStorage, type_b_instance._data_storage - ).scratchvar.slot, + cast(pt.ScratchVar, type_b_instance.stored_value).slot, ), ] ) diff --git a/pyteal/ast/scratchvar.py b/pyteal/ast/scratchvar.py index 81ce27fff..44d422782 100644 --- a/pyteal/ast/scratchvar.py +++ b/pyteal/ast/scratchvar.py @@ -1,3 +1,5 @@ +from abc import ABC, abstractmethod + from pyteal.errors import TealInputError from pyteal.types import TealType, require_type @@ -5,7 +7,24 @@ from pyteal.ast.scratch import ScratchSlot, ScratchLoad, ScratchStore -class ScratchVar: +class AbstractVar(ABC): + @abstractmethod + def store(self, value: Expr) -> Expr: + pass + + @abstractmethod + def load(self) -> Expr: + pass + + @abstractmethod + def storage_type(self) -> TealType: + pass + + +AbstractVar.__module__ = "pyteal" + + +class ScratchVar(AbstractVar): """ Interface around Scratch space, similar to get/put local/global state diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index d509f980b..437c9535d 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -378,7 +378,7 @@ def __init__( elif isinstance(arg, ScratchVar): arg_type = arg.type elif isinstance(arg, abi.BaseType): - arg_type = cast(abi.BaseType, arg)._data_storage.storage_type() + arg_type = cast(abi.BaseType, arg).stored_value.storage_type() else: raise TealInputError( f"Subroutine argument {arg} at index {i} was of unexpected Python type {type(arg)}" @@ -420,7 +420,7 @@ def handle_arg(arg: Expr | ScratchVar | abi.BaseType) -> Expr: elif isinstance(arg, Expr): return arg elif isinstance(arg, abi.BaseType): - return arg._data_storage.load() + return arg.stored_value.load() else: raise TealInputError( f"cannot handle current arg: {arg} to put it on stack" @@ -791,8 +791,6 @@ def evaluate_subroutine(subroutine: SubroutineDefinition) -> SubroutineDeclarati def var_n_loaded( param: str, ) -> tuple[ScratchVar, ScratchVar | abi.BaseType | Expr]: - from pyteal.ast.abi.type import ScratchStorage - loaded_var: ScratchVar | abi.BaseType | Expr argument_var: ScratchVar @@ -801,11 +799,11 @@ def var_n_loaded( loaded_var = argument_var elif param in subroutine.abi_args: internal_abi_var = subroutine.abi_args[param].new_instance() - if not isinstance(internal_abi_var._data_storage, ScratchStorage): + if not isinstance(internal_abi_var.stored_value, ScratchVar): raise TealInternalError( "subroutine ABI args must have data schema being ScratchVarStorage" ) - argument_var = internal_abi_var._data_storage.scratchvar + argument_var = internal_abi_var.stored_value loaded_var = internal_abi_var else: argument_var = ScratchVar(TealType.anytype) @@ -853,7 +851,7 @@ def var_n_loaded( f"ABI returning subroutine definition should evaluate to TealType.none, " f"while evaluate to {subroutine_body.type_of()}." ) - deferred_expr = output_carrying_abi._data_storage.load() + deferred_expr = output_carrying_abi.stored_value.load() # Arg usage "A" to be pick up and store in scratch parameters that have been placed on the stack # need to reverse order of argumentVars because the last argument will be on top of the stack From f362b57542041162a3acb477687e8812e1c529c7 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 10:51:50 -0400 Subject: [PATCH 071/206] better type checking in scratch slot --- pyteal/ast/abi/type.py | 3 +-- pyteal/ast/scratchvar.py | 9 +++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index 2e9027c5d..f9368cbda 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -281,8 +281,7 @@ def store_into(self, output: BaseType) -> Expr: f"ABI return subroutine deferred_expr is expected to be typed {output.type_spec().storage_type()}, " f"but has type {declaration.deferred_expr.type_of()}." ) - assert isinstance(output.stored_value, ScratchVar) - return output.stored_value.slot.store(self.computation) + return output.stored_value.store(self.computation) ReturnedValue.__module__ = "pyteal.abi" diff --git a/pyteal/ast/scratchvar.py b/pyteal/ast/scratchvar.py index 44d422782..7b4962f97 100644 --- a/pyteal/ast/scratchvar.py +++ b/pyteal/ast/scratchvar.py @@ -1,7 +1,7 @@ from abc import ABC, abstractmethod from pyteal.errors import TealInputError -from pyteal.types import TealType, require_type +from pyteal.types import TealType, require_type, types_match from pyteal.ast.expr import Expr from pyteal.ast.scratch import ScratchSlot, ScratchLoad, ScratchStore @@ -61,7 +61,12 @@ def store(self, value: Expr) -> Expr: Args: value: The value to store. Must conform to this ScratchVar's type. """ - require_type(value, self.type) + from pyteal.ast.subroutine import SubroutineCall + + if not isinstance(value, SubroutineCall) or not value.output_kwarg: + require_type(value, self.type) + else: + assert types_match(value.output_kwarg.abi_type.storage_type(), self.type) return self.slot.store(value) def load(self) -> ScratchLoad: From a0f1a813eb435403120b88d8b832ebe8cf55714b Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 10:55:21 -0400 Subject: [PATCH 072/206] reformat imports and class decl for FrameVar and ScratchVar --- pyteal/__init__.pyi | 1 + pyteal/ast/__init__.py | 3 ++- pyteal/ast/abi/__init__.py | 11 +--------- pyteal/ast/abi/type.py | 41 -------------------------------------- pyteal/ast/frame.py | 1 + 5 files changed, 5 insertions(+), 52 deletions(-) diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index ed1d3c1e1..baf5ae050 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -122,6 +122,7 @@ __all__ = [ "For", "FrameBury", "FrameDig", + "FrameStorage", "Ge", "GeneratedID", "GetBit", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 3d2671068..0f2bcaa34 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -155,7 +155,7 @@ from pyteal.ast.for_ import For from pyteal.ast.break_ import Break from pyteal.ast.continue_ import Continue -from pyteal.ast.frame import Proto, FrameDig, FrameBury, PopN, DupN, Bury +from pyteal.ast.frame import Proto, FrameDig, FrameBury, PopN, DupN, Bury, FrameStorage # misc from pyteal.ast.scratch import ( @@ -344,6 +344,7 @@ "Bury", "DupN", "PopN", + "FrameStorage", "Router", "CallConfig", "MethodConfig", diff --git a/pyteal/ast/abi/__init__.py b/pyteal/ast/abi/__init__.py index bb2a0d1b2..f1cb3a58c 100644 --- a/pyteal/ast/abi/__init__.py +++ b/pyteal/ast/abi/__init__.py @@ -4,14 +4,7 @@ Address, AddressLength, ) -from pyteal.ast.abi.type import ( - TypeSpec, - BaseType, - ComputedValue, - ReturnedValue, - FrameStorage, - ScratchStorage, -) +from pyteal.ast.abi.type import TypeSpec, BaseType, ComputedValue, ReturnedValue from pyteal.ast.abi.bool import BoolTypeSpec, Bool from pyteal.ast.abi.uint import ( UintTypeSpec, @@ -173,8 +166,6 @@ "type_specs_from_signature", "make", "size_of", - "FrameStorage", - "ScratchStorage", "algosdk_from_annotation", "algosdk_from_type_spec", "contains_type_spec", diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index f9368cbda..b87fe1282 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -65,47 +65,6 @@ def __str__(self) -> str: TypeSpec.__module__ = "pyteal.abi" -class ScratchStorage(AbstractVar): - def __init__(self, storage_type: TealType) -> None: - super().__init__() - self.scratchvar: Final[ScratchVar] = ScratchVar(storage_type) - - def load(self) -> Expr: - return self.scratchvar.load() - - def store(self, value: Expr) -> Expr: - return self.scratchvar.slot.store(value) - - def storage_type(self) -> TealType: - return self.scratchvar.storage_type() - - -ScratchStorage.__module__ = "pyteal" - - -class FrameStorage(AbstractVar): - def __init__(self, storage_type: TealType, stack_depth: int) -> None: - super().__init__() - self.stack_type = storage_type - self.stack_depth = stack_depth - - def storage_type(self) -> TealType: - return self.stack_type - - def store(self, value: Expr) -> Expr: - from pyteal.ast import FrameBury - - return FrameBury(value, self.stack_depth) - - def load(self) -> Expr: - from pyteal.ast import FrameDig - - return FrameDig(self.stack_depth) - - -FrameStorage.__module__ = "pyteal" - - class BaseType(ABC): """The abstract base class for all ABI type instances. diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 8f5e24891..6b94cb2a3 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -1,6 +1,7 @@ from typing import TYPE_CHECKING from pyteal.ast.expr import Expr +from pyteal.ast.scratchvar import AbstractVar from pyteal.types import TealType, require_type from pyteal.errors import TealInputError, verifyProgramVersion from pyteal.ir import TealBlock, TealSimpleBlock, TealOp, Op From 46b886b021052d2b0e34f942f65661d6d7968b0c Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 11:27:24 -0400 Subject: [PATCH 073/206] still thinking about hiding the _stored value --- pyteal/ast/abi/address.py | 12 ++++++------ pyteal/ast/abi/address_test.py | 24 ++++++++++++------------ pyteal/ast/abi/array_base.py | 6 +++--- pyteal/ast/abi/array_dynamic.py | 8 ++++---- pyteal/ast/abi/array_dynamic_test.py | 24 ++++++++++++------------ pyteal/ast/abi/array_static.py | 10 +++++----- pyteal/ast/abi/array_static_test.py | 18 +++++++++--------- pyteal/ast/abi/bool.py | 8 ++++---- pyteal/ast/abi/bool_test.py | 20 ++++++++++---------- pyteal/ast/abi/reference_type.py | 8 ++++---- pyteal/ast/abi/reference_type_test.py | 10 +++++----- pyteal/ast/abi/string.py | 10 +++++----- pyteal/ast/abi/string_test.py | 22 +++++++++++----------- pyteal/ast/abi/transaction.py | 8 ++++---- pyteal/ast/abi/transaction_test.py | 2 +- pyteal/ast/abi/tuple.py | 6 +++--- pyteal/ast/abi/tuple_test.py | 10 ++++++---- pyteal/ast/abi/type.py | 10 +++++----- pyteal/ast/abi/type_test.py | 2 +- pyteal/ast/abi/uint.py | 8 ++++---- pyteal/ast/abi/uint_test.py | 20 ++++++++++---------- pyteal/ast/subroutine.py | 10 +++++----- 22 files changed, 129 insertions(+), 127 deletions(-) diff --git a/pyteal/ast/abi/address.py b/pyteal/ast/abi/address.py index d0413cf6c..d8ad3cbc2 100644 --- a/pyteal/ast/abi/address.py +++ b/pyteal/ast/abi/address.py @@ -56,7 +56,7 @@ def get(self) -> Expr: The expression will have the type TealType.bytes. """ - return self.stored_value.load() + return self._stored_value.load() def set( self, @@ -108,25 +108,25 @@ def set( or value.type_spec() == StaticArrayTypeSpec(ByteTypeSpec(), AddressLength.Bytes) ): - return self.stored_value.store(value.stored_value.load()) + return self._stored_value.store(value._stored_value.load()) raise TealInputError( f"Got {value} with type spec {value.type_spec()}, expected AddressTypeSpec" ) case str(): # Addr throws if value is invalid address - return self.stored_value.store(Addr(value)) + return self._stored_value.store(Addr(value)) case bytes(): if len(value) == AddressLength.Bytes: - return self.stored_value.store(Bytes(value)) + return self._stored_value.store(Bytes(value)) raise TealInputError( f"Got bytes with length {len(value)}, expected {AddressLength.Bytes}" ) case Expr(): return Seq( - self.stored_value.store(value), + self._stored_value.store(value), Assert( - Len(self.stored_value.load()) == Int(AddressLength.Bytes.value) + Len(self._stored_value.load()) == Int(AddressLength.Bytes.value) ), ) case CollectionSequence(): diff --git a/pyteal/ast/abi/address_test.py b/pyteal/ast/abi/address_test.py index d115082cd..c70cbe5ea 100644 --- a/pyteal/ast/abi/address_test.py +++ b/pyteal/ast/abi/address_test.py @@ -53,7 +53,7 @@ def test_Address_encode(): pt.TealOp( expr, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -86,7 +86,7 @@ def test_Address_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expectedExpr = value.stored_value.store( + expectedExpr = value._stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -117,7 +117,7 @@ def test_Address_get(): pt.TealOp( expr, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -139,12 +139,12 @@ def test_Address_set_StaticArray(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value_to_set.stored_value).slot, + cast(pt.ScratchVar, value_to_set._stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -174,7 +174,7 @@ def test_Address_set_str(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -203,7 +203,7 @@ def test_Address_set_bytes(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -236,12 +236,12 @@ def test_Address_set_expr(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.int, AddressLength.Bytes.value), @@ -270,12 +270,12 @@ def test_Address_set_copy(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, other.stored_value).slot, + cast(pt.ScratchVar, other._stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -307,7 +307,7 @@ def test_Address_set_computed(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/array_base.py b/pyteal/ast/abi/array_base.py index aea164c81..8920637bc 100644 --- a/pyteal/ast/abi/array_base.py +++ b/pyteal/ast/abi/array_base.py @@ -104,7 +104,7 @@ def decode( extracted = substring_for_decoding( encoded, start_index=start_index, end_index=end_index, length=length ) - return self.stored_value.store(extracted) + return self._stored_value.store(extracted) def set(self, values: Sequence[T]) -> Expr: """Set the ABI array with a sequence of ABI type variables. @@ -142,7 +142,7 @@ def set(self, values: Sequence[T]) -> Expr: length_prefix = Seq(length_tmp.set(len(values)), length_tmp.encode()) encoded = Concat(length_prefix, encoded) - return self.stored_value.store(encoded) + return self._stored_value.store(encoded) def encode(self) -> Expr: """Encode the ABI array to be a byte string. @@ -150,7 +150,7 @@ def encode(self) -> Expr: Returns: A PyTeal expression that encodes this ABI array to a byte string. """ - return self.stored_value.load() + return self._stored_value.load() @abstractmethod def length(self) -> Expr: diff --git a/pyteal/ast/abi/array_dynamic.py b/pyteal/ast/abi/array_dynamic.py index 9d53e0559..ecbeeb49c 100644 --- a/pyteal/ast/abi/array_dynamic.py +++ b/pyteal/ast/abi/array_dynamic.py @@ -79,7 +79,7 @@ def set( raise TealInputError( f"Cannot assign type {values.type_spec()} to {self.type_spec()}" ) - return self.stored_value.store(values.encode()) + return self._stored_value.store(values.encode()) return super().set(values) def length(self) -> Expr: @@ -165,10 +165,10 @@ def set( match values: case bytes() | bytearray(): - return self.stored_value.store(_encoded_byte_string(values)) + return self._stored_value.store(_encoded_byte_string(values)) case Expr(): return _store_encoded_expr_byte_string_into_var( - values, self.stored_value + values, self._stored_value ) return super().set(values) @@ -181,7 +181,7 @@ def get(self) -> Expr: Returns: A Pyteal expression that loads byte encoding of this DynamicBytes, and drop the first uint16 DynamicArray length encoding. """ - return Suffix(self.stored_value.load(), Int(2)) + return Suffix(self._stored_value.load(), Int(2)) DynamicBytes.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/array_dynamic_test.py b/pyteal/ast/abi/array_dynamic_test.py index e8e930787..91497500a 100644 --- a/pyteal/ast/abi/array_dynamic_test.py +++ b/pyteal/ast/abi/array_dynamic_test.py @@ -106,7 +106,7 @@ def test_DynamicArray_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value.stored_value.store( + expectedExpr = value._stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -141,7 +141,7 @@ def test_DynamicArray_set_values(): assert not expr.has_return() length_tmp = abi.Uint16() - expectedExpr = value.stored_value.store( + expectedExpr = value._stored_value.store( pt.Concat( pt.Seq(length_tmp.set(len(values)), length_tmp.encode()), _encode_tuple(values), @@ -185,12 +185,12 @@ def test_DynamicArray_set_copy(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, otherArray.stored_value).slot, + cast(pt.ScratchVar, otherArray._stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -218,7 +218,7 @@ def test_DynamicArray_set_computed(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -268,7 +268,7 @@ def test_DynamicBytes_set_py_bytes(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -299,12 +299,12 @@ def test_DynamicBytes_set_expr(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.itob), @@ -312,13 +312,13 @@ def test_DynamicBytes_set_expr(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.concat), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -343,7 +343,7 @@ def test_DynamicBytes_get(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.extract, 2, 0), ] @@ -365,7 +365,7 @@ def test_DynamicArray_encode(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/array_static.py b/pyteal/ast/abi/array_static.py index 7744a6edb..3d9d56557 100644 --- a/pyteal/ast/abi/array_static.py +++ b/pyteal/ast/abi/array_static.py @@ -109,7 +109,7 @@ def set( raise TealInputError( f"Cannot assign type {values.type_spec()} to {self.type_spec()}" ) - return self.stored_value.store(values.encode()) + return self._stored_value.store(values.encode()) if self.type_spec().length_static() != len(values): raise TealInputError( @@ -207,11 +207,11 @@ def set( raise TealInputError( f"Got bytes with length {len(values)}, expect {self.type_spec().length_static()}" ) - return self.stored_value.store(Bytes(values)) + return self._stored_value.store(Bytes(values)) case Expr(): return Seq( - self.stored_value.store(values), - Assert(self.length() == Len(self.stored_value.load())), + self._stored_value.store(values), + Assert(self.length() == Len(self._stored_value.load())), ) return super().set(values) @@ -222,7 +222,7 @@ def get(self) -> Expr: Returns: A Pyteal expression that loads byte encoding of this StaticBytes. """ - return self.stored_value.load() + return self._stored_value.load() StaticBytes.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/array_static_test.py b/pyteal/ast/abi/array_static_test.py index 7c2e914ec..7a61e2b65 100644 --- a/pyteal/ast/abi/array_static_test.py +++ b/pyteal/ast/abi/array_static_test.py @@ -159,7 +159,7 @@ def test_StaticArray_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value.stored_value.store( + expectedExpr = value._stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -202,7 +202,7 @@ def test_StaticArray_set_values(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = value.stored_value.store(_encode_tuple(values)) + expectedExpr = value._stored_value.store(_encode_tuple(values)) expected, _ = expectedExpr.__teal__(options) expected.addIncoming() expected = pt.TealBlock.NormalizeBlocks(expected) @@ -237,12 +237,12 @@ def test_StaticArray_set_copy(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, otherArray.stored_value).slot, + cast(pt.ScratchVar, otherArray._stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -270,7 +270,7 @@ def test_StaticArray_set_computed(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -317,7 +317,7 @@ def test_StaticBytes_set_py_bytes(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -352,13 +352,13 @@ def test_StaticBytes_expr(test_case: bytes | bytearray): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.int, 32), pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.eq), @@ -381,7 +381,7 @@ def test_StaticArray_encode(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/bool.py b/pyteal/ast/abi/bool.py index 13552b6db..6fa6d72a3 100644 --- a/pyteal/ast/abi/bool.py +++ b/pyteal/ast/abi/bool.py @@ -50,7 +50,7 @@ def get(self) -> Expr: expression that evaluates to 0 will be returned. In either case, the expression will have the type TealType.uint64. """ - return self.stored_value.load() + return self._stored_value.load() def set(self, value: Union[bool, Expr, "Bool", ComputedValue["Bool"]]) -> Expr: """Set the value of this Bool to the input value. @@ -85,10 +85,10 @@ def set(self, value: Union[bool, Expr, "Bool", ComputedValue["Bool"]]) -> Expr: checked = True if checked: - return self.stored_value.store(value) + return self._stored_value.store(value) # Not(Not(value)) coerces all values greater than 0 to 1 - return self.stored_value.store(Not(Not(value))) + return self._stored_value.store(Not(Not(value))) def decode( self, @@ -103,7 +103,7 @@ def decode( return self.decode_bit(encoded, start_index * Int(NUM_BITS_IN_BYTE)) def decode_bit(self, encoded, bit_index: Expr) -> Expr: - return self.stored_value.store(GetBit(encoded, bit_index)) + return self._stored_value.store(GetBit(encoded, bit_index)) def encode(self) -> Expr: return SetBit(Bytes(b"\x00"), Int(0), self.get()) diff --git a/pyteal/ast/abi/bool_test.py b/pyteal/ast/abi/bool_test.py index 1cf881d55..7dfb5c684 100644 --- a/pyteal/ast/abi/bool_test.py +++ b/pyteal/ast/abi/bool_test.py @@ -56,7 +56,7 @@ def test_Bool_set_static(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -85,7 +85,7 @@ def test_Bool_set_expr(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -110,12 +110,12 @@ def test_Bool_set_copy(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, other.stored_value).slot, + cast(pt.ScratchVar, other._stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -144,7 +144,7 @@ def test_Bool_set_computed(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -171,7 +171,7 @@ def test_Bool_get(): pt.TealOp( expr, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -203,7 +203,7 @@ def test_Bool_decode(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -232,7 +232,7 @@ def test_Bool_decode_bit(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -258,7 +258,7 @@ def test_Bool_encode(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.setbit), ] @@ -442,7 +442,7 @@ class EncodeSeqTest(NamedTuple): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, testType.stored_value).slot, + cast(pt.ScratchVar, testType._stored_value).slot, ), pt.TealOp(None, pt.Op.setbit), ] diff --git a/pyteal/ast/abi/reference_type.py b/pyteal/ast/abi/reference_type.py index f4882fc97..e1a228245 100644 --- a/pyteal/ast/abi/reference_type.py +++ b/pyteal/ast/abi/reference_type.py @@ -58,7 +58,7 @@ def referenced_index(self) -> Expr: If this reference type is an application or asset, note that this DOES NOT return the application or asset ID. See :code:`application_id()` or :code:`asset_id()` for that. """ - return self.stored_value.load() + return self._stored_value.load() def decode( self, @@ -70,7 +70,7 @@ def decode( ) -> Expr: return uint_decode( self.type_spec().bit_size(), - self.stored_value, + self._stored_value, encoded, start_index, end_index, @@ -107,7 +107,7 @@ def __init__(self) -> None: def address(self) -> Expr: """Get the address of the account.""" - return Txn.accounts[self.stored_value.load()] + return Txn.accounts[self._stored_value.load()] def params(self) -> AccountParamObject: """Get information about the account.""" @@ -205,7 +205,7 @@ def __init__(self) -> None: def application_id(self) -> Expr: """Get the ID of the application.""" - return Txn.applications[self.stored_value.load()] + return Txn.applications[self._stored_value.load()] def params(self) -> AppParamObject: """Get information about the application's parameters.""" diff --git a/pyteal/ast/abi/reference_type_test.py b/pyteal/ast/abi/reference_type_test.py index 4ec862e66..cbbc45d34 100644 --- a/pyteal/ast/abi/reference_type_test.py +++ b/pyteal/ast/abi/reference_type_test.py @@ -26,7 +26,7 @@ def test_ReferenceType_referenced_index(): pt.TealOp( expr, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -61,7 +61,7 @@ def test_ReferenceType_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expected_decoding = value.stored_value.store( + expected_decoding = value._stored_value.store( pt.GetByte( encoded, start_index if start_index is not None else pt.Int(0), @@ -117,7 +117,7 @@ def test_Account_address(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.txnas, "Accounts"), ] @@ -204,7 +204,7 @@ def test_Asset_asset_id(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.txnas, "Assets"), ] @@ -298,7 +298,7 @@ def test_Application_application_id(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.txnas, "Applications"), ] diff --git a/pyteal/ast/abi/string.py b/pyteal/ast/abi/string.py index ac5866cb2..f142eaa55 100644 --- a/pyteal/ast/abi/string.py +++ b/pyteal/ast/abi/string.py @@ -68,7 +68,7 @@ def get(self) -> Expr: The expression will have the type TealType.bytes. """ return Suffix( - self.stored_value.load(), Int(Uint16TypeSpec().byte_length_static()) + self._stored_value.load(), Int(Uint16TypeSpec().byte_length_static()) ) def set( @@ -111,18 +111,18 @@ def set( if value.type_spec() == StringTypeSpec() or ( value.type_spec() == DynamicArrayTypeSpec(ByteTypeSpec()) ): - return self.stored_value.store(value.stored_value.load()) + return self._stored_value.store(value._stored_value.load()) raise TealInputError( f"Got {value} with type spec {value.type_spec()}, expected {StringTypeSpec}" ) case bytes() | bytearray(): - return self.stored_value.store(_encoded_byte_string(value)) + return self._stored_value.store(_encoded_byte_string(value)) case str(): - return self.stored_value.store(_encoded_byte_string(value.encode())) + return self._stored_value.store(_encoded_byte_string(value.encode())) case Expr(): return _store_encoded_expr_byte_string_into_var( - value, self.stored_value + value, self._stored_value ) case CollectionSequence(): return super().set(cast(Sequence[Byte], value)) diff --git a/pyteal/ast/abi/string_test.py b/pyteal/ast/abi/string_test.py index c60ac52f4..9ebcbfadd 100644 --- a/pyteal/ast/abi/string_test.py +++ b/pyteal/ast/abi/string_test.py @@ -44,7 +44,7 @@ def test_String_encode(): pt.TealOp( expr, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -76,7 +76,7 @@ def test_DynamicArray_decode(): assert expr.type_of() == pt.TealType.none assert expr.has_return() is False - expectedExpr = value.stored_value.store( + expectedExpr = value._stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -107,7 +107,7 @@ def test_String_get(): pt.TealOp( expr, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.extract, 2, 0), ] @@ -143,7 +143,7 @@ def test_String_set_static(value_to_set, value_encoded): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -174,12 +174,12 @@ def test_String_set_expr(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.len), pt.TealOp(None, pt.Op.itob), @@ -187,13 +187,13 @@ def test_String_set_expr(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.concat), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -222,12 +222,12 @@ def test_String_set_copy(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, other.stored_value).slot, + cast(pt.ScratchVar, other._stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -259,7 +259,7 @@ def test_String_set_computed(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/transaction.py b/pyteal/ast/abi/transaction.py index aeb5c7a33..69de7ea29 100644 --- a/pyteal/ast/abi/transaction.py +++ b/pyteal/ast/abi/transaction.py @@ -82,16 +82,16 @@ def _set_index( case ComputedValue(): return self._set_with_computed_type(value) case BaseType(): - return self.stored_value.store(self.stored_value.load()) + return self._stored_value.store(self._stored_value.load()) case int(): - return self.stored_value.store(Int(value)) + return self._stored_value.store(Int(value)) case Expr(): - return self.stored_value.store(value) + return self._stored_value.store(value) case _: raise TealInputError(f"Cant store a {type(value)} in a Transaction") def index(self) -> Expr: - return self.stored_value.load() + return self._stored_value.load() def decode( self, diff --git a/pyteal/ast/abi/transaction_test.py b/pyteal/ast/abi/transaction_test.py index b4c27a97c..3b0cdeae1 100644 --- a/pyteal/ast/abi/transaction_test.py +++ b/pyteal/ast/abi/transaction_test.py @@ -134,7 +134,7 @@ def test_Transaction__set_index(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, tv.t.stored_value).slot, + cast(pt.ScratchVar, tv.t._stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/tuple.py b/pyteal/ast/abi/tuple.py index bc1966414..3149250a6 100644 --- a/pyteal/ast/abi/tuple.py +++ b/pyteal/ast/abi/tuple.py @@ -309,7 +309,7 @@ def decode( extracted = substring_for_decoding( encoded, start_index=start_index, end_index=end_index, length=length ) - return self.stored_value.store(extracted) + return self._stored_value.store(extracted) @overload def set(self, *values: BaseType) -> Expr: @@ -352,10 +352,10 @@ def set(self, *values): ) if not all(myTypes[i] == values[i].type_spec() for i in range(len(myTypes))): raise TealInputError("Input values do not match type") - return self.stored_value.store(_encode_tuple(values)) + return self._stored_value.store(_encode_tuple(values)) def encode(self) -> Expr: - return self.stored_value.load() + return self._stored_value.load() def length(self) -> Expr: """Get the number of values this tuple holds as an Expr.""" diff --git a/pyteal/ast/abi/tuple_test.py b/pyteal/ast/abi/tuple_test.py index a761d88af..b175ce7bd 100644 --- a/pyteal/ast/abi/tuple_test.py +++ b/pyteal/ast/abi/tuple_test.py @@ -623,7 +623,7 @@ def test_Tuple_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = tupleValue.stored_value.store( + expectedExpr = tupleValue._stored_value.store( substring_for_decoding( encoded, start_index=start_index, @@ -672,7 +672,9 @@ def test_Tuple_set(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedExpr = tupleValue.stored_value.store(_encode_tuple([uint8, uint16, uint32])) + expectedExpr = tupleValue._stored_value.store( + _encode_tuple([uint8, uint16, uint32]) + ) expected, _ = expectedExpr.__teal__(options) expected.addIncoming() expected = pt.TealBlock.NormalizeBlocks(expected) @@ -704,7 +706,7 @@ def test_Tuple_set_Computed(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, tupleValue.stored_value).slot, + cast(pt.ScratchVar, tupleValue._stored_value).slot, ), ] ) @@ -735,7 +737,7 @@ def test_Tuple_encode(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, tupleValue.stored_value).slot, + cast(pt.ScratchVar, tupleValue._stored_value).slot, ), ] ) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index b87fe1282..adb76ecf3 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -77,16 +77,16 @@ def __init__(self, spec: TypeSpec) -> None: """Create a new BaseType.""" super().__init__() self._type_spec: Final[TypeSpec] = spec - self.stored_value: AbstractVar = ScratchVar(spec.storage_type()) + self._stored_value: AbstractVar = ScratchVar(spec.storage_type()) def _set_data_source(self, storage: AbstractVar) -> None: - self.stored_value = storage + self._stored_value = storage def _load_value(self) -> Expr: - return self.stored_value.load() + return self._stored_value.load() def _store_value(self, value: Expr) -> Expr: - return self.stored_value.store(value) + return self._stored_value.store(value) def type_spec(self) -> TypeSpec: """Get the TypeSpec for this ABI type instance.""" @@ -240,7 +240,7 @@ def store_into(self, output: BaseType) -> Expr: f"ABI return subroutine deferred_expr is expected to be typed {output.type_spec().storage_type()}, " f"but has type {declaration.deferred_expr.type_of()}." ) - return output.stored_value.store(self.computation) + return output._stored_value.store(self.computation) ReturnedValue.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/type_test.py b/pyteal/ast/abi/type_test.py index 56a9e6c76..568ebf94c 100644 --- a/pyteal/ast/abi/type_test.py +++ b/pyteal/ast/abi/type_test.py @@ -17,7 +17,7 @@ def store_into(self, output: abi.BaseType) -> pt.Expr: raise pt.TealInputError( f"expected type_spec {self.type_spec} but get {output.type_spec()}" ) - return output.stored_value.store(self.encodings) + return output._stored_value.store(self.encodings) def test_ComputedType_use(): diff --git a/pyteal/ast/abi/uint.py b/pyteal/ast/abi/uint.py index 0a99eb27f..c3f7c7f98 100644 --- a/pyteal/ast/abi/uint.py +++ b/pyteal/ast/abi/uint.py @@ -239,7 +239,7 @@ def get(self) -> Expr: The expression will have the type TealType.uint64. """ - return self.stored_value.load() + return self._stored_value.load() def set(self, value: Union[int, Expr, "Uint", ComputedValue["Uint"]]) -> Expr: """Set the value of this Uint to the input value. @@ -274,7 +274,7 @@ def set(self, value: Union[int, Expr, "Uint", ComputedValue["Uint"]]) -> Expr: value.type_spec(), self.type_spec() ) ) - return uint_set(self.type_spec().bit_size(), self.stored_value, value) + return uint_set(self.type_spec().bit_size(), self._stored_value, value) def decode( self, @@ -286,7 +286,7 @@ def decode( ) -> Expr: return uint_decode( self.type_spec().bit_size(), - self.stored_value, + self._stored_value, encoded, start_index, end_index, @@ -294,7 +294,7 @@ def decode( ) def encode(self) -> Expr: - return uint_encode(self.type_spec().bit_size(), self.stored_value) + return uint_encode(self.type_spec().bit_size(), self._stored_value) Uint.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abi/uint_test.py b/pyteal/ast/abi/uint_test.py index 26ba3541f..b9a74b64d 100644 --- a/pyteal/ast/abi/uint_test.py +++ b/pyteal/ast/abi/uint_test.py @@ -142,7 +142,7 @@ def test_Uint_set_static(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -174,7 +174,7 @@ def test_Uint_set_expr(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), pt.TealOp(None, pt.Op.int, test.maxValue + 1), pt.TealOp(None, pt.Op.lt), @@ -189,7 +189,7 @@ def test_Uint_set_expr(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] + upperBoundCheck @@ -216,12 +216,12 @@ def test_Uint_set_copy(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, other.stored_value).slot, + cast(pt.ScratchVar, other._stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -253,7 +253,7 @@ def test_Uint_set_computed(): pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -281,7 +281,7 @@ def test_Uint_get(): pt.TealOp( expr, pt.Op.load, - cast(pt.ScratchVar, value.stored_value).slot, + cast(pt.ScratchVar, value._stored_value).slot, ), ] ) @@ -307,7 +307,7 @@ def test_Uint_decode(): assert expr.type_of() == pt.TealType.none assert not expr.has_return() - expectedDecoding = value.stored_value.store( + expectedDecoding = value._stored_value.store( test.expectedDecoding(encoded, start_index, end_index, length) ) expected, _ = expectedDecoding.__teal__(options) @@ -359,12 +359,12 @@ def test_ByteUint8_mutual_conversion(): pt.TealOp( None, pt.Op.load, - cast(pt.ScratchVar, other.stored_value).slot, + cast(pt.ScratchVar, other._stored_value).slot, ), pt.TealOp( None, pt.Op.store, - cast(pt.ScratchVar, type_b_instance.stored_value).slot, + cast(pt.ScratchVar, type_b_instance._stored_value).slot, ), ] ) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 437c9535d..f3bf83a2c 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -378,7 +378,7 @@ def __init__( elif isinstance(arg, ScratchVar): arg_type = arg.type elif isinstance(arg, abi.BaseType): - arg_type = cast(abi.BaseType, arg).stored_value.storage_type() + arg_type = cast(abi.BaseType, arg)._stored_value.storage_type() else: raise TealInputError( f"Subroutine argument {arg} at index {i} was of unexpected Python type {type(arg)}" @@ -420,7 +420,7 @@ def handle_arg(arg: Expr | ScratchVar | abi.BaseType) -> Expr: elif isinstance(arg, Expr): return arg elif isinstance(arg, abi.BaseType): - return arg.stored_value.load() + return arg._stored_value.load() else: raise TealInputError( f"cannot handle current arg: {arg} to put it on stack" @@ -799,11 +799,11 @@ def var_n_loaded( loaded_var = argument_var elif param in subroutine.abi_args: internal_abi_var = subroutine.abi_args[param].new_instance() - if not isinstance(internal_abi_var.stored_value, ScratchVar): + if not isinstance(internal_abi_var._stored_value, ScratchVar): raise TealInternalError( "subroutine ABI args must have data schema being ScratchVarStorage" ) - argument_var = internal_abi_var.stored_value + argument_var = internal_abi_var._stored_value loaded_var = internal_abi_var else: argument_var = ScratchVar(TealType.anytype) @@ -851,7 +851,7 @@ def var_n_loaded( f"ABI returning subroutine definition should evaluate to TealType.none, " f"while evaluate to {subroutine_body.type_of()}." ) - deferred_expr = output_carrying_abi.stored_value.load() + deferred_expr = output_carrying_abi._stored_value.load() # Arg usage "A" to be pick up and store in scratch parameters that have been placed on the stack # need to reverse order of argumentVars because the last argument will be on top of the stack From 0d5eaf3410685f214ad9fe228a47a0d7afff1eab Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 12:06:10 -0400 Subject: [PATCH 074/206] per pr comment, rename to FrameVar --- pyteal/__init__.pyi | 2 +- pyteal/ast/__init__.py | 4 ++-- pyteal/ast/frame.py | 23 +++++++++++++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index baf5ae050..2e03200b2 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -122,7 +122,7 @@ __all__ = [ "For", "FrameBury", "FrameDig", - "FrameStorage", + "FrameVar", "Ge", "GeneratedID", "GetBit", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 0f2bcaa34..f4ebd5f88 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -155,7 +155,7 @@ from pyteal.ast.for_ import For from pyteal.ast.break_ import Break from pyteal.ast.continue_ import Continue -from pyteal.ast.frame import Proto, FrameDig, FrameBury, PopN, DupN, Bury, FrameStorage +from pyteal.ast.frame import Proto, FrameDig, FrameBury, PopN, DupN, Bury, FrameVar # misc from pyteal.ast.scratch import ( @@ -344,7 +344,7 @@ "Bury", "DupN", "PopN", - "FrameStorage", + "FrameVar", "Router", "CallConfig", "MethodConfig", diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 6b94cb2a3..c8fb29d53 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -102,6 +102,29 @@ def has_return(self) -> bool: FrameBury.__module__ = "pyteal" +class FrameVar(AbstractVar): + def __init__(self, storage_type: TealType, stack_depth: int) -> None: + super().__init__() + self.stack_type = storage_type + self.stack_depth = stack_depth + + def storage_type(self) -> TealType: + return self.stack_type + + def store(self, value: Expr) -> Expr: + from pyteal.ast import FrameBury + + return FrameBury(value, self.stack_depth) + + def load(self) -> Expr: + from pyteal.ast import FrameDig + + return FrameDig(self.stack_depth) + + +FrameVar.__module__ = "pyteal" + + class DupN(Expr): def __init__(self, value: Expr, repetition: int): super().__init__() From d02d73b888105c62e5194450d36f19db6166a564 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 12:11:45 -0400 Subject: [PATCH 075/206] take bury out --- pyteal/__init__.pyi | 2 -- pyteal/ast/__init__.py | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index 2e03200b2..56c22a572 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -72,7 +72,6 @@ __all__ = [ "BoxReplace", "Break", "Btoi", - "Bury", "Bytes", "BytesAdd", "BytesAnd", @@ -181,7 +180,6 @@ __all__ = [ "OptimizeOptions", "Or", "Pop", - "PopN", "Pragma", "Proto", "RETURN_HASH_PREFIX", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index f4ebd5f88..1721ce522 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -155,7 +155,7 @@ from pyteal.ast.for_ import For from pyteal.ast.break_ import Break from pyteal.ast.continue_ import Continue -from pyteal.ast.frame import Proto, FrameDig, FrameBury, PopN, DupN, Bury, FrameVar +from pyteal.ast.frame import Proto, FrameDig, FrameBury, DupN, FrameVar # misc from pyteal.ast.scratch import ( @@ -341,9 +341,7 @@ "Proto", "FrameDig", "FrameBury", - "Bury", "DupN", - "PopN", "FrameVar", "Router", "CallConfig", From 25a98a494523cbd2efbe47f3ddf873b50724b845 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 12:53:59 -0400 Subject: [PATCH 076/206] abstractvar.py --- pyteal/ast/__init__.py | 3 ++- pyteal/ast/abstractvar.py | 20 ++++++++++++++++++++ pyteal/ast/scratchvar.py | 20 +------------------- 3 files changed, 23 insertions(+), 20 deletions(-) create mode 100644 pyteal/ast/abstractvar.py diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 1721ce522..7de5e044a 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -165,7 +165,8 @@ ScratchStackStore, ScratchStore, ) -from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar, AbstractVar +from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar +from pyteal.ast.abstractvar import AbstractVar from pyteal.ast.maybe import MaybeValue from pyteal.ast.multi import MultiValue from pyteal.ast.opup import OpUp, OpUpMode, OpUpFeeSource diff --git a/pyteal/ast/abstractvar.py b/pyteal/ast/abstractvar.py new file mode 100644 index 000000000..59788e001 --- /dev/null +++ b/pyteal/ast/abstractvar.py @@ -0,0 +1,20 @@ +from abc import ABC, abstractmethod +from pyteal.types import TealType +from pyteal.ast.expr import Expr + + +class AbstractVar(ABC): + @abstractmethod + def store(self, value: Expr) -> Expr: + pass + + @abstractmethod + def load(self) -> Expr: + pass + + @abstractmethod + def storage_type(self) -> TealType: + pass + + +AbstractVar.__module__ = "pyteal" diff --git a/pyteal/ast/scratchvar.py b/pyteal/ast/scratchvar.py index 7b4962f97..e97b5d1ef 100644 --- a/pyteal/ast/scratchvar.py +++ b/pyteal/ast/scratchvar.py @@ -1,29 +1,11 @@ -from abc import ABC, abstractmethod - from pyteal.errors import TealInputError from pyteal.types import TealType, require_type, types_match +from pyteal.ast.abstractvar import AbstractVar from pyteal.ast.expr import Expr from pyteal.ast.scratch import ScratchSlot, ScratchLoad, ScratchStore -class AbstractVar(ABC): - @abstractmethod - def store(self, value: Expr) -> Expr: - pass - - @abstractmethod - def load(self) -> Expr: - pass - - @abstractmethod - def storage_type(self) -> TealType: - pass - - -AbstractVar.__module__ = "pyteal" - - class ScratchVar(AbstractVar): """ Interface around Scratch space, similar to get/put local/global state From 2704c5a478318bccfeb0ede4a9059476597935f1 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 14:00:46 -0400 Subject: [PATCH 077/206] unexport FrameVar and AbstractVar --- pyteal/__init__.pyi | 2 -- pyteal/ast/__init__.py | 5 +---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index 56c22a572..19dcc01fb 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -35,7 +35,6 @@ from pyteal.config import ( __all__ = [ "ABIReturnSubroutine", - "AbstractVar", "AccountParam", "AccountParamObject", "Add", @@ -121,7 +120,6 @@ __all__ = [ "For", "FrameBury", "FrameDig", - "FrameVar", "Ge", "GeneratedID", "GetBit", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 7de5e044a..4a0b4e181 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -155,7 +155,7 @@ from pyteal.ast.for_ import For from pyteal.ast.break_ import Break from pyteal.ast.continue_ import Continue -from pyteal.ast.frame import Proto, FrameDig, FrameBury, DupN, FrameVar +from pyteal.ast.frame import Proto, FrameDig, FrameBury, DupN # misc from pyteal.ast.scratch import ( @@ -166,7 +166,6 @@ ScratchStore, ) from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar -from pyteal.ast.abstractvar import AbstractVar from pyteal.ast.maybe import MaybeValue from pyteal.ast.multi import MultiValue from pyteal.ast.opup import OpUp, OpUpMode, OpUpFeeSource @@ -306,7 +305,6 @@ "ScratchStore", "DynamicScratchVar", "ScratchVar", - "AbstractVar", "MaybeValue", "MultiValue", "OpUp", @@ -343,7 +341,6 @@ "FrameDig", "FrameBury", "DupN", - "FrameVar", "Router", "CallConfig", "MethodConfig", From 92c46f0d0e74ffacf7754aa93dd8c2f4dbc1405f Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 14:04:58 -0400 Subject: [PATCH 078/206] unexport use of frame ops --- pyteal/__init__.pyi | 4 ---- pyteal/ast/__init__.py | 5 ----- 2 files changed, 9 deletions(-) diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index 19dcc01fb..3f69e10bd 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -99,7 +99,6 @@ __all__ = [ "DEFAULT_TEAL_VERSION", "Div", "Divw", - "DupN", "DynamicScratchVar", "EcdsaCurve", "EcdsaDecompress", @@ -118,8 +117,6 @@ __all__ = [ "ExtractUint64", "FRAME_POINTER_VERSION", "For", - "FrameBury", - "FrameDig", "Ge", "GeneratedID", "GetBit", @@ -179,7 +176,6 @@ __all__ = [ "Or", "Pop", "Pragma", - "Proto", "RETURN_HASH_PREFIX", "Reject", "Replace", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 4a0b4e181..9efe807c5 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -155,7 +155,6 @@ from pyteal.ast.for_ import For from pyteal.ast.break_ import Break from pyteal.ast.continue_ import Continue -from pyteal.ast.frame import Proto, FrameDig, FrameBury, DupN # misc from pyteal.ast.scratch import ( @@ -337,10 +336,6 @@ "For", "Break", "Continue", - "Proto", - "FrameDig", - "FrameBury", - "DupN", "Router", "CallConfig", "MethodConfig", From 5e256f80f29ca8bfb58bf2c2fe485916b527c7ba Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 14:49:48 -0400 Subject: [PATCH 079/206] remove _set_data_storage --- pyteal/ast/abi/type.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index adb76ecf3..24f396cf3 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -79,9 +79,6 @@ def __init__(self, spec: TypeSpec) -> None: self._type_spec: Final[TypeSpec] = spec self._stored_value: AbstractVar = ScratchVar(spec.storage_type()) - def _set_data_source(self, storage: AbstractVar) -> None: - self._stored_value = storage - def _load_value(self) -> Expr: return self._stored_value.load() From 296f6cf3c12ab136fc677173289555cef838a714 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 15:19:04 -0400 Subject: [PATCH 080/206] rename from stack_depth to frame_index --- pyteal/ast/frame.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index c8fb29d53..9ddcf237a 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -103,23 +103,19 @@ def has_return(self) -> bool: class FrameVar(AbstractVar): - def __init__(self, storage_type: TealType, stack_depth: int) -> None: + def __init__(self, storage_type: TealType, frame_index: int) -> None: super().__init__() self.stack_type = storage_type - self.stack_depth = stack_depth + self.frame_index = frame_index def storage_type(self) -> TealType: return self.stack_type def store(self, value: Expr) -> Expr: - from pyteal.ast import FrameBury - - return FrameBury(value, self.stack_depth) + return FrameBury(value, self.frame_index) def load(self) -> Expr: - from pyteal.ast import FrameDig - - return FrameDig(self.stack_depth) + return FrameDig(self.frame_index) FrameVar.__module__ = "pyteal" From bca1868e71ae5472691762bfed432ac179d902fc Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 17:28:29 -0400 Subject: [PATCH 081/206] hide FRAME_POINTER_VERISON --- pyteal/__init__.py | 2 -- pyteal/__init__.pyi | 2 -- pyteal/compiler/__init__.py | 2 -- 3 files changed, 6 deletions(-) diff --git a/pyteal/__init__.py b/pyteal/__init__.py index ba6e8eead..ac28dd641 100644 --- a/pyteal/__init__.py +++ b/pyteal/__init__.py @@ -8,7 +8,6 @@ MIN_TEAL_VERSION, DEFAULT_TEAL_VERSION, MAX_PROGRAM_VERSION, - FRAME_POINTER_VERSION, MIN_PROGRAM_VERSION, DEFAULT_PROGRAM_VERSION, CompileOptions, @@ -39,7 +38,6 @@ "MIN_TEAL_VERSION", "DEFAULT_TEAL_VERSION", "MAX_PROGRAM_VERSION", - "FRAME_POINTER_VERSION", "MIN_PROGRAM_VERSION", "DEFAULT_PROGRAM_VERSION", "CompileOptions", diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index 3f69e10bd..ce347b0eb 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -11,7 +11,6 @@ from pyteal.compiler import ( MIN_TEAL_VERSION, DEFAULT_TEAL_VERSION, MAX_PROGRAM_VERSION, - FRAME_POINTER_VERSION, MIN_PROGRAM_VERSION, DEFAULT_PROGRAM_VERSION, CompileOptions, @@ -115,7 +114,6 @@ __all__ = [ "ExtractUint16", "ExtractUint32", "ExtractUint64", - "FRAME_POINTER_VERSION", "For", "Ge", "GeneratedID", diff --git a/pyteal/compiler/__init__.py b/pyteal/compiler/__init__.py index 9755ead4f..e0d29450d 100644 --- a/pyteal/compiler/__init__.py +++ b/pyteal/compiler/__init__.py @@ -3,7 +3,6 @@ MIN_TEAL_VERSION, DEFAULT_TEAL_VERSION, MAX_PROGRAM_VERSION, - FRAME_POINTER_VERSION, MIN_PROGRAM_VERSION, DEFAULT_PROGRAM_VERSION, CompileOptions, @@ -17,7 +16,6 @@ "MIN_TEAL_VERSION", "DEFAULT_TEAL_VERSION", "MAX_PROGRAM_VERSION", - "FRAME_POINTER_VERSION", "MIN_PROGRAM_VERSION", "DEFAULT_PROGRAM_VERSION", "CompileOptions", From 40ebb8cc0df151a4829be275fee5436c2cad85a5 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 2 Nov 2022 17:37:42 -0400 Subject: [PATCH 082/206] hide FRAME_POINTER_VERISON --- pyteal/__init__.py | 2 -- pyteal/__init__.pyi | 2 -- pyteal/compiler/__init__.py | 2 -- 3 files changed, 6 deletions(-) diff --git a/pyteal/__init__.py b/pyteal/__init__.py index ba6e8eead..ac28dd641 100644 --- a/pyteal/__init__.py +++ b/pyteal/__init__.py @@ -8,7 +8,6 @@ MIN_TEAL_VERSION, DEFAULT_TEAL_VERSION, MAX_PROGRAM_VERSION, - FRAME_POINTER_VERSION, MIN_PROGRAM_VERSION, DEFAULT_PROGRAM_VERSION, CompileOptions, @@ -39,7 +38,6 @@ "MIN_TEAL_VERSION", "DEFAULT_TEAL_VERSION", "MAX_PROGRAM_VERSION", - "FRAME_POINTER_VERSION", "MIN_PROGRAM_VERSION", "DEFAULT_PROGRAM_VERSION", "CompileOptions", diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index 3f69e10bd..ce347b0eb 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -11,7 +11,6 @@ from pyteal.compiler import ( MIN_TEAL_VERSION, DEFAULT_TEAL_VERSION, MAX_PROGRAM_VERSION, - FRAME_POINTER_VERSION, MIN_PROGRAM_VERSION, DEFAULT_PROGRAM_VERSION, CompileOptions, @@ -115,7 +114,6 @@ __all__ = [ "ExtractUint16", "ExtractUint32", "ExtractUint64", - "FRAME_POINTER_VERSION", "For", "Ge", "GeneratedID", diff --git a/pyteal/compiler/__init__.py b/pyteal/compiler/__init__.py index 9755ead4f..e0d29450d 100644 --- a/pyteal/compiler/__init__.py +++ b/pyteal/compiler/__init__.py @@ -3,7 +3,6 @@ MIN_TEAL_VERSION, DEFAULT_TEAL_VERSION, MAX_PROGRAM_VERSION, - FRAME_POINTER_VERSION, MIN_PROGRAM_VERSION, DEFAULT_PROGRAM_VERSION, CompileOptions, @@ -17,7 +16,6 @@ "MIN_TEAL_VERSION", "DEFAULT_TEAL_VERSION", "MAX_PROGRAM_VERSION", - "FRAME_POINTER_VERSION", "MIN_PROGRAM_VERSION", "DEFAULT_PROGRAM_VERSION", "CompileOptions", From a1770c4b74b03975742c39d835315325e3a3906b Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 3 Nov 2022 09:03:59 -0500 Subject: [PATCH 083/206] Validate types option (#590) * experiment with external type validation * revert * passing unit tests * revert --- pyteal/ast/abi/type.py | 19 ++++++++++++++++--- pyteal/ast/abstractvar.py | 2 +- pyteal/ast/frame.py | 10 ++++++++-- pyteal/ast/scratchvar.py | 19 ++++++++++--------- 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index 24f396cf3..1f4fff6d9 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -1,11 +1,11 @@ from typing import TypeVar, Generic, Callable, Final, cast from abc import ABC, abstractmethod -from pyteal.errors import TealInputError -from pyteal.types import TealType from pyteal.ast.expr import Expr from pyteal.ast.scratchvar import ScratchVar, AbstractVar from pyteal.ast.seq import Seq +from pyteal.errors import TealInputError +from pyteal.types import TealType, require_type, types_match class TypeSpec(ABC): @@ -221,6 +221,8 @@ def produced_type_spec(self) -> TypeSpec: return self.type_spec def store_into(self, output: BaseType) -> Expr: + from pyteal.ast.subroutine import SubroutineCall + if output.type_spec() != self.produced_type_spec(): raise TealInputError( f"expected type_spec {self.produced_type_spec()} but get {output.type_spec()}" @@ -237,7 +239,18 @@ def store_into(self, output: BaseType) -> Expr: f"ABI return subroutine deferred_expr is expected to be typed {output.type_spec().storage_type()}, " f"but has type {declaration.deferred_expr.type_of()}." ) - return output._stored_value.store(self.computation) + if ( + isinstance(self.computation, SubroutineCall) + and self.computation.output_kwarg + ): + assert types_match( + self.computation.output_kwarg.abi_type.storage_type(), + output._stored_value.storage_type(), + ) + else: + require_type(self.computation, output._stored_value.storage_type()) + + return output._stored_value.store(self.computation, validate_types=False) ReturnedValue.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abstractvar.py b/pyteal/ast/abstractvar.py index 59788e001..d18a98d70 100644 --- a/pyteal/ast/abstractvar.py +++ b/pyteal/ast/abstractvar.py @@ -5,7 +5,7 @@ class AbstractVar(ABC): @abstractmethod - def store(self, value: Expr) -> Expr: + def store(self, value: Expr, validate_types: bool = True) -> Expr: pass @abstractmethod diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 9ddcf237a..652709fee 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -3,7 +3,7 @@ from pyteal.ast.expr import Expr from pyteal.ast.scratchvar import AbstractVar from pyteal.types import TealType, require_type -from pyteal.errors import TealInputError, verifyProgramVersion +from pyteal.errors import TealInputError, TealInternalError, verifyProgramVersion from pyteal.ir import TealBlock, TealSimpleBlock, TealOp, Op if TYPE_CHECKING: @@ -111,7 +111,13 @@ def __init__(self, storage_type: TealType, frame_index: int) -> None: def storage_type(self) -> TealType: return self.stack_type - def store(self, value: Expr) -> Expr: + def store(self, value: Expr, validate_types: bool = True) -> Expr: + if not validate_types: + # validation always happens inside of FramBury's initializer + raise TealInternalError( + f"DynamicScratchVar's must validate_types but {validate_types=}" + ) + return FrameBury(value, self.frame_index) def load(self) -> Expr: diff --git a/pyteal/ast/scratchvar.py b/pyteal/ast/scratchvar.py index e97b5d1ef..29a938e33 100644 --- a/pyteal/ast/scratchvar.py +++ b/pyteal/ast/scratchvar.py @@ -1,5 +1,5 @@ -from pyteal.errors import TealInputError -from pyteal.types import TealType, require_type, types_match +from pyteal.errors import TealInputError, TealInternalError +from pyteal.types import TealType, require_type from pyteal.ast.abstractvar import AbstractVar from pyteal.ast.expr import Expr @@ -37,18 +37,14 @@ def storage_type(self) -> TealType: """Get the type of expressions that can be stored in this ScratchVar.""" return self.type - def store(self, value: Expr) -> Expr: + def store(self, value: Expr, validate_types: bool = True) -> Expr: """Store value in Scratch Space Args: value: The value to store. Must conform to this ScratchVar's type. """ - from pyteal.ast.subroutine import SubroutineCall - - if not isinstance(value, SubroutineCall) or not value.output_kwarg: + if validate_types: require_type(value, self.type) - else: - assert types_match(value.output_kwarg.abi_type.storage_type(), self.type) return self.slot.store(value) def load(self) -> ScratchLoad: @@ -121,8 +117,13 @@ def storage_type(self) -> TealType: """Get the type of expressions that can be stored in this ScratchVar.""" return self.dynamic_type - def store(self, value: Expr) -> Expr: + def store(self, value: Expr, validate_types: bool = True) -> Expr: """Store the value in the referenced ScratchVar.""" + if not validate_types: + raise TealInternalError( + f"DynamicScratchVar's must validate_types but {validate_types=}" + ) + require_type(value, self.dynamic_type) return ScratchStore(slot=None, value=value, index_expression=self.index()) From 5193635a4d671cb9aac06039fdd65c17f2685546 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Thu, 3 Nov 2022 10:51:51 -0400 Subject: [PATCH 084/206] wrong import, blame my lsp --- pyteal/ast/abi/string.py | 3 ++- pyteal/ast/abi/type.py | 3 ++- pyteal/ast/abi/uint.py | 3 ++- pyteal/ast/frame.py | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/pyteal/ast/abi/string.py b/pyteal/ast/abi/string.py index f142eaa55..890e7e149 100644 --- a/pyteal/ast/abi/string.py +++ b/pyteal/ast/abi/string.py @@ -4,10 +4,11 @@ from algosdk.abi import ABIType from pyteal.ast.abi.uint import Byte -from pyteal.ast.abi.type import ComputedValue, BaseType, AbstractVar +from pyteal.ast.abi.type import ComputedValue, BaseType from pyteal.ast.abi.array_dynamic import DynamicArray, DynamicArrayTypeSpec from pyteal.ast.abi.uint import ByteTypeSpec, Uint16TypeSpec +from pyteal.ast.abstractvar import AbstractVar from pyteal.ast.int import Int from pyteal.ast.expr import Expr from pyteal.ast.bytes import Bytes diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index 1f4fff6d9..fcdef3c2a 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -2,7 +2,8 @@ from abc import ABC, abstractmethod from pyteal.ast.expr import Expr -from pyteal.ast.scratchvar import ScratchVar, AbstractVar +from pyteal.ast.abstractvar import AbstractVar +from pyteal.ast.scratchvar import ScratchVar from pyteal.ast.seq import Seq from pyteal.errors import TealInputError from pyteal.types import TealType, require_type, types_match diff --git a/pyteal/ast/abi/uint.py b/pyteal/ast/abi/uint.py index c3f7c7f98..949eb7c40 100644 --- a/pyteal/ast/abi/uint.py +++ b/pyteal/ast/abi/uint.py @@ -8,6 +8,7 @@ from pyteal.types import TealType from pyteal.errors import TealInputError +from pyteal.ast.abstractvar import AbstractVar from pyteal.ast.expr import Expr from pyteal.ast.seq import Seq from pyteal.ast.assert_ import Assert @@ -17,7 +18,7 @@ from pyteal.ast.unaryexpr import Itob, Btoi from pyteal.ast.binaryexpr import GetByte, ExtractUint16, ExtractUint32, ExtractUint64 from pyteal.ast.ternaryexpr import SetByte -from pyteal.ast.abi.type import ComputedValue, TypeSpec, BaseType, AbstractVar +from pyteal.ast.abi.type import ComputedValue, TypeSpec, BaseType NUM_BITS_IN_BYTE = 8 diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 652709fee..5b964ac93 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -1,7 +1,7 @@ from typing import TYPE_CHECKING from pyteal.ast.expr import Expr -from pyteal.ast.scratchvar import AbstractVar +from pyteal.ast.abstractvar import AbstractVar from pyteal.types import TealType, require_type from pyteal.errors import TealInputError, TealInternalError, verifyProgramVersion from pyteal.ir import TealBlock, TealSimpleBlock, TealOp, Op From 2a57388ef28d780fefd5c78395da4357e172d7dd Mon Sep 17 00:00:00 2001 From: Hang Su <87964331+ahangsu@users.noreply.github.com> Date: Thu, 3 Nov 2022 10:52:52 -0400 Subject: [PATCH 085/206] FrameVar error msg fix Co-authored-by: Zeph Grunschlag --- pyteal/ast/frame.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 5b964ac93..e768021f0 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -115,7 +115,7 @@ def store(self, value: Expr, validate_types: bool = True) -> Expr: if not validate_types: # validation always happens inside of FramBury's initializer raise TealInternalError( - f"DynamicScratchVar's must validate_types but {validate_types=}" + f"FrameVar's must validate_types but {validate_types=}" ) return FrameBury(value, self.frame_index) From a895cb9480215e3df9af99fe7498387f801d0a98 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Thu, 3 Nov 2022 14:10:31 -0400 Subject: [PATCH 086/206] scrape down the change of frame pointer from feature/fp-subroutine --- pyteal/ast/frame.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index e768021f0..71277a7ed 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -1,8 +1,9 @@ from typing import TYPE_CHECKING from pyteal.ast.expr import Expr +from pyteal.ast.int import Int from pyteal.ast.abstractvar import AbstractVar -from pyteal.types import TealType, require_type +from pyteal.types import TealType, require_type, types_match from pyteal.errors import TealInputError, TealInternalError, verifyProgramVersion from pyteal.ir import TealBlock, TealSimpleBlock, TealOp, Op @@ -11,7 +12,7 @@ class Proto(Expr): - def __init__(self, num_args: int, num_returns: int): + def __init__(self, num_args: int, num_returns: int, /, *, num_allocs: int = 0): super().__init__() if num_args < 0: raise TealInputError( @@ -23,6 +24,7 @@ def __init__(self, num_args: int, num_returns: int): ) self.num_args = num_args self.num_returns = num_returns + self.num_allocs = num_allocs def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: verifyProgramVersion( @@ -31,10 +33,20 @@ def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBloc "Program version too low to use op proto", ) op = TealOp(self, Op.proto, self.num_args, self.num_returns) - return TealBlock.FromOp(options, op) + proto_srt, proto_end = TealBlock.FromOp(options, op) + if self.num_allocs == 0: + return proto_srt, proto_end + elif self.num_allocs == 1: + int_srt, int_end = Int(0).__teal__(options) + proto_end.setNextBlock(int_srt) + return proto_srt, int_end + else: + dupn_srt, dupn_end = DupN(Int(0), self.num_allocs).__teal__(options) + proto_end.setNextBlock(dupn_srt) + return proto_srt, dupn_end def __str__(self) -> str: - return f"(proto: num_args = {self.num_args}, num_returns = {self.num_returns})" + return f"(proto: num_args = {self.num_args}, num_rets = {self.num_returns}, num_allocs = {self.num_allocs})" def type_of(self) -> TealType: return TealType.none @@ -75,8 +87,16 @@ def has_return(self) -> bool: class FrameBury(Expr): def __init__(self, value: Expr, frame_index: int): + from pyteal.ast.subroutine import SubroutineCall + super().__init__() - require_type(value, TealType.anytype) + if not isinstance(value, SubroutineCall) or not value.output_kwarg: + require_type(value, TealType.anytype) + else: + assert types_match( + value.output_kwarg.abi_type.storage_type(), TealType.anytype + ) + self.value = value self.frame_index = frame_index From 630e04673a358c6f06ae72040d5f50ff91dd5950 Mon Sep 17 00:00:00 2001 From: Hang Su <87964331+ahangsu@users.noreply.github.com> Date: Mon, 7 Nov 2022 15:07:43 -0500 Subject: [PATCH 087/206] Memory layout for frame var and frame ops (#593) * memory layout structure in frame var and frame related ops * validate type * minor, error msg * testing for memory layout, need test frame var * kwarg/posarg * simpler condition in check frame mem layout args Co-authored-by: Zeph Grunschlag * Better type check in `__getitem__` return var Co-authored-by: Zeph Grunschlag * vanilla flavored class decl * take away output index * good testcase for succinct repr * better assert for type checking * better error checking in proto, inherit layouts from expr not seq * tie for local type segment invalid none type * take out confusing algorithm * better tie error msg check * super Co-authored-by: Zeph Grunschlag --- pyteal/ast/frame.py | 192 +++++++++++++++++++++++++++++------- pyteal/ast/frame_test.py | 204 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 358 insertions(+), 38 deletions(-) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 71277a7ed..7962d349b 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -1,9 +1,11 @@ -from typing import TYPE_CHECKING +from itertools import groupby +from typing import TYPE_CHECKING, Optional from pyteal.ast.expr import Expr from pyteal.ast.int import Int +from pyteal.ast.bytes import Bytes from pyteal.ast.abstractvar import AbstractVar -from pyteal.types import TealType, require_type, types_match +from pyteal.types import TealType, require_type from pyteal.errors import TealInputError, TealInternalError, verifyProgramVersion from pyteal.ir import TealBlock, TealSimpleBlock, TealOp, Op @@ -11,20 +13,133 @@ from pyteal.compiler import CompileOptions +class LocalTypeSegment(Expr): + def __init__(self, local_type: TealType, count: int): + super().__init__() + self.local_type = local_type + self.count = count + self.auto_instance: Expr + + if self.count <= 0: + raise TealInternalError( + "LocalTypeSegment initialization error: segment length must be strictly greater than 0." + ) + match self.local_type: + case TealType.uint64 | TealType.anytype: + self.auto_instance = Int(0) + case TealType.bytes: + self.auto_instance = Bytes("") + case TealType.none: + raise TealInternalError( + "Local variable in subroutine initialization must be typed." + ) + + def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: + if self.count == 1: + inst_srt, inst_end = self.auto_instance.__teal__(options) + return inst_srt, inst_end + else: + dupn_srt, dupn_end = DupN(self.auto_instance, self.count).__teal__(options) + return dupn_srt, dupn_end + + def __str__(self) -> str: + return f"(LocalTypeSegment: (type: {self.local_type}) (count: {self.count}))" + + def has_return(self) -> bool: + return False + + def type_of(self) -> TealType: + return TealType.none + + +LocalTypeSegment.__module__ = "pyteal" + + +class ProtoStackLayout(Expr): + def __init__( + self, + arg_stack_types: list[TealType], + local_stack_types: list[TealType], + num_returns: int, + ): + super().__init__() + if num_returns < 0: + raise TealInternalError("Return number should be non-negative.") + elif num_returns > len(local_stack_types): + raise TealInternalError( + "ProtoStackLayout initialization error:" + f"return number {num_returns} should not be greater than local allocations {len(local_stack_types)}." + ) + + if not all(map(lambda t: t != TealType.none, arg_stack_types)): + raise TealInternalError("Variables in frame memory layout must be typed.") + + self.num_returns: int = num_returns + self.arg_stack_types: list[TealType] = arg_stack_types + self.local_stack_types: list[TealType] = local_stack_types + + # Type check of local variables are performed over LocalTypeSegments + self.succinct_repr: list[LocalTypeSegment] = [ + LocalTypeSegment(t_type, len(list(dup_seg))) + for t_type, dup_seg in groupby(self.local_stack_types) + ] + + def __getitem__(self, index: int) -> TealType: + if index < 0: + return self.arg_stack_types[len(self.arg_stack_types) + index] + return self.local_stack_types[index] + + def __str__(self) -> str: + return f"(ProtoStackLayout: (args: {self.arg_stack_types}) (locals: {self.local_stack_types}))" + + def has_return(self) -> bool: + return False + + def type_of(self) -> TealType: + return TealType.none + + def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: + seg_srt, seg_end = self.succinct_repr[0].__teal__(options) + for iter_seg in self.succinct_repr[1:]: + srt, end = iter_seg.__teal__(options) + seg_end.setNextBlock(srt) + seg_end = end + return seg_srt, seg_end + + +ProtoStackLayout.__module__ = "pyteal" + + class Proto(Expr): - def __init__(self, num_args: int, num_returns: int, /, *, num_allocs: int = 0): + def __init__( + self, + num_args: int, + num_returns: int, + *, + mem_layout: Optional[ProtoStackLayout] = None, + ): super().__init__() if num_args < 0: raise TealInputError( - f"the number of arguments provided to Proto must be >= 0 but {num_args=}" + f"The number of arguments provided to Proto must be >= 0 but {num_args=}." ) if num_returns < 0: raise TealInputError( - f"the number of return values provided to Proto must be >= 0 but {num_returns=}" + f"The number of returns provided to Proto must be >= 0 but {num_returns=}." ) + if mem_layout: + if mem_layout.num_returns != num_returns: + raise TealInternalError( + f"The number of returns {num_returns} should match with memory layout's number of returns {mem_layout.num_returns}" + ) + if len(mem_layout.arg_stack_types) != num_args: + raise TealInternalError( + f"The number of arguments {num_args} should match with memory layout's number of arguments {len(mem_layout.arg_stack_types)}" + ) + self.num_args = num_args self.num_returns = num_returns - self.num_allocs = num_allocs + self.mem_layout: Optional[ProtoStackLayout] = mem_layout def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: verifyProgramVersion( @@ -34,19 +149,14 @@ def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBloc ) op = TealOp(self, Op.proto, self.num_args, self.num_returns) proto_srt, proto_end = TealBlock.FromOp(options, op) - if self.num_allocs == 0: + if not self.mem_layout: return proto_srt, proto_end - elif self.num_allocs == 1: - int_srt, int_end = Int(0).__teal__(options) - proto_end.setNextBlock(int_srt) - return proto_srt, int_end - else: - dupn_srt, dupn_end = DupN(Int(0), self.num_allocs).__teal__(options) - proto_end.setNextBlock(dupn_srt) - return proto_srt, dupn_end + local_srt, local_end = self.mem_layout.__teal__(options) + proto_end.setNextBlock(local_srt) + return proto_srt, local_end def __str__(self) -> str: - return f"(proto: num_args = {self.num_args}, num_rets = {self.num_returns}, num_allocs = {self.num_allocs})" + return f"(proto: num_args = {self.num_args}, num_rets = {self.num_returns})" def type_of(self) -> TealType: return TealType.none @@ -59,9 +169,10 @@ def has_return(self) -> bool: class FrameDig(Expr): - def __init__(self, frame_index: int): + def __init__(self, frame_index: int, *, inferred_type: Optional[TealType] = None): super().__init__() self.frame_index = frame_index + self.dig_type = inferred_type if inferred_type else TealType.anytype def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: verifyProgramVersion( @@ -76,7 +187,7 @@ def __str__(self) -> str: return f"(frame_dig: dig_from = {self.frame_index})" def type_of(self) -> TealType: - return TealType.anytype + return self.dig_type def has_return(self) -> bool: return False @@ -86,16 +197,19 @@ def has_return(self) -> bool: class FrameBury(Expr): - def __init__(self, value: Expr, frame_index: int): - from pyteal.ast.subroutine import SubroutineCall - + def __init__( + self, + value: Expr, + frame_index: int, + *, + validate_types: bool = True, + inferred_type: Optional[TealType] = None, + ): super().__init__() - if not isinstance(value, SubroutineCall) or not value.output_kwarg: - require_type(value, TealType.anytype) - else: - assert types_match( - value.output_kwarg.abi_type.storage_type(), TealType.anytype - ) + + if validate_types: + target_type = inferred_type if inferred_type else TealType.anytype + require_type(value, target_type) self.value = value self.frame_index = frame_index @@ -123,25 +237,29 @@ def has_return(self) -> bool: class FrameVar(AbstractVar): - def __init__(self, storage_type: TealType, frame_index: int) -> None: + def __init__(self, under_proto: Proto, frame_index: int) -> None: super().__init__() - self.stack_type = storage_type + self.proto = under_proto self.frame_index = frame_index + self.stack_type = ( + self.proto.mem_layout[frame_index] + if self.proto.mem_layout + else TealType.anytype + ) def storage_type(self) -> TealType: return self.stack_type def store(self, value: Expr, validate_types: bool = True) -> Expr: - if not validate_types: - # validation always happens inside of FramBury's initializer - raise TealInternalError( - f"FrameVar's must validate_types but {validate_types=}" - ) - - return FrameBury(value, self.frame_index) + return FrameBury( + value, + self.frame_index, + validate_types=validate_types, + inferred_type=self.stack_type, + ) def load(self) -> Expr: - return FrameDig(self.frame_index) + return FrameDig(self.frame_index, inferred_type=self.stack_type) FrameVar.__module__ = "pyteal" diff --git a/pyteal/ast/frame_test.py b/pyteal/ast/frame_test.py index e4cde2aa4..2182c35b9 100644 --- a/pyteal/ast/frame_test.py +++ b/pyteal/ast/frame_test.py @@ -1,6 +1,14 @@ import pytest import pyteal as pt -from pyteal.ast.frame import FrameBury, FrameDig, Proto, DupN +from dataclasses import dataclass +from pyteal.ast.frame import ( + FrameBury, + FrameDig, + Proto, + DupN, + LocalTypeSegment, + ProtoStackLayout, +) avm7Options = pt.CompileOptions(version=7) avm8Options = pt.CompileOptions(version=8) @@ -105,3 +113,197 @@ def test_dupn_invalid(): with pytest.raises(pt.TealInputError): DupN(pt.Int(1), 1).__teal__(avm7Options) + + +def test_local_type_segment_invalid(): + with pytest.raises(pt.TealInternalError) as tie: + LocalTypeSegment(pt.TealType.anytype, 0) + + assert "segment length must be strictly greater than 0" in str(tie) + + with pytest.raises(pt.TealInternalError) as tie: + LocalTypeSegment(pt.TealType.anytype, -1) + + assert "segment length must be strictly greater than 0" in str(tie) + + with pytest.raises(pt.TealInternalError) as tie: + LocalTypeSegment(pt.TealType.none, 2) + + assert "Local variable in subroutine initialization must be typed." in str(tie) + + +@dataclass +class LocalTypeSegmentTestCase: + local_type_segment: LocalTypeSegment + expected: pt.TealSimpleBlock + + +@pytest.mark.parametrize( + "testcase", + [ + LocalTypeSegmentTestCase( + LocalTypeSegment(pt.TealType.anytype, 1), + pt.TealSimpleBlock([pt.TealOp(None, pt.Op.int, 0)]), + ), + LocalTypeSegmentTestCase( + LocalTypeSegment(pt.TealType.anytype, 5), + pt.TealSimpleBlock( + [ + pt.TealOp(None, pt.Op.int, 0), + pt.TealOp(None, pt.Op.dupn, 5), + ] + ), + ), + LocalTypeSegmentTestCase( + LocalTypeSegment(pt.TealType.uint64, 1), + pt.TealSimpleBlock([pt.TealOp(None, pt.Op.int, 0)]), + ), + LocalTypeSegmentTestCase( + LocalTypeSegment(pt.TealType.uint64, 5), + pt.TealSimpleBlock( + [ + pt.TealOp(None, pt.Op.int, 0), + pt.TealOp(None, pt.Op.dupn, 5), + ] + ), + ), + LocalTypeSegmentTestCase( + LocalTypeSegment(pt.TealType.bytes, 1), + pt.TealSimpleBlock([pt.TealOp(None, pt.Op.byte, '""')]), + ), + LocalTypeSegmentTestCase( + LocalTypeSegment(pt.TealType.bytes, 5), + pt.TealSimpleBlock( + [ + pt.TealOp(None, pt.Op.byte, '""'), + pt.TealOp(None, pt.Op.dupn, 5), + ] + ), + ), + ], +) +def test_local_type_segment_compilation(testcase: LocalTypeSegmentTestCase): + actual, _ = testcase.local_type_segment.__teal__(avm8Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + with pt.TealComponent.Context.ignoreExprEquality(): + assert actual == testcase.expected + + +def test_proto_stack_layout_invalid(): + with pytest.raises(pt.TealInternalError) as bad_local_alloc: + ProtoStackLayout([pt.TealType.uint64, pt.TealType.bytes], [], -1) + + assert "Return number should be non-negative." == str(bad_local_alloc.value) + + with pytest.raises(pt.TealInternalError) as bad_local_alloc: + ProtoStackLayout([pt.TealType.uint64, pt.TealType.bytes], [], 1) + + assert "should not be greater than local allocations" in str(bad_local_alloc.value) + + with pytest.raises(pt.TealInternalError) as bad_type_on_stack: + ProtoStackLayout([pt.TealType.bytes, pt.TealType.none], [], 0) + + assert "must be typed" in str(bad_type_on_stack.value) + + with pytest.raises(pt.TealInternalError) as bad_type_on_stack: + ProtoStackLayout( + [pt.TealType.bytes, pt.TealType.uint64], + [pt.TealType.uint64, pt.TealType.none], + 0, + ) + + assert "must be typed" in str(bad_type_on_stack.value) + + +@dataclass +class SuccinctReprTestCase: + local_types: list[pt.TealType] + expected: list[LocalTypeSegment] + + +@pytest.mark.parametrize( + "testcase", + [ + SuccinctReprTestCase([], []), + SuccinctReprTestCase( + [pt.TealType.anytype], [LocalTypeSegment(pt.TealType.anytype, 1)] + ), + SuccinctReprTestCase( + [pt.TealType.anytype, pt.TealType.uint64], + [ + LocalTypeSegment(pt.TealType.anytype, 1), + LocalTypeSegment(pt.TealType.uint64, 1), + ], + ), + SuccinctReprTestCase( + [pt.TealType.bytes, pt.TealType.anytype, pt.TealType.uint64], + [ + LocalTypeSegment(pt.TealType.bytes, 1), + LocalTypeSegment(pt.TealType.anytype, 1), + LocalTypeSegment(pt.TealType.uint64, 1), + ], + ), + SuccinctReprTestCase( + [ + pt.TealType.anytype, + pt.TealType.bytes, + pt.TealType.anytype, + pt.TealType.uint64, + ], + [ + LocalTypeSegment(pt.TealType.anytype, 1), + LocalTypeSegment(pt.TealType.bytes, 1), + LocalTypeSegment(pt.TealType.anytype, 1), + LocalTypeSegment(pt.TealType.uint64, 1), + ], + ), + SuccinctReprTestCase( + [ + pt.TealType.anytype, + pt.TealType.bytes, + pt.TealType.anytype, + pt.TealType.uint64, + pt.TealType.anytype, + ], + [ + LocalTypeSegment(pt.TealType.anytype, 1), + LocalTypeSegment(pt.TealType.bytes, 1), + LocalTypeSegment(pt.TealType.anytype, 1), + LocalTypeSegment(pt.TealType.uint64, 1), + LocalTypeSegment(pt.TealType.anytype, 1), + ], + ), + SuccinctReprTestCase( + [ + pt.TealType.anytype, + pt.TealType.bytes, + pt.TealType.bytes, + pt.TealType.uint64, + pt.TealType.uint64, + pt.TealType.uint64, + pt.TealType.anytype, + pt.TealType.anytype, + pt.TealType.anytype, + pt.TealType.anytype, + pt.TealType.bytes, + pt.TealType.bytes, + pt.TealType.uint64, + pt.TealType.uint64, + pt.TealType.uint64, + ], + [ + LocalTypeSegment(pt.TealType.anytype, 1), + LocalTypeSegment(pt.TealType.bytes, 2), + LocalTypeSegment(pt.TealType.uint64, 3), + LocalTypeSegment(pt.TealType.anytype, 4), + LocalTypeSegment(pt.TealType.bytes, 2), + LocalTypeSegment(pt.TealType.uint64, 3), + ], + ), + ], +) +def test_proto_stack_layout_succinct_repr(testcase: SuccinctReprTestCase): + actual = ProtoStackLayout([], testcase.local_types, False).succinct_repr + assert actual == testcase.expected From e399e09d240c4e5bea80af3e150829919cbeac45 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Mon, 7 Nov 2022 15:24:56 -0500 Subject: [PATCH 088/206] rename arg for mem layout, on return alloc number --- pyteal/ast/frame.py | 20 +++++++++++--------- pyteal/ast/frame_test.py | 16 ++++++++-------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 7962d349b..329922c5c 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -60,21 +60,21 @@ def __init__( self, arg_stack_types: list[TealType], local_stack_types: list[TealType], - num_returns: int, + num_return_allocs: int, ): super().__init__() - if num_returns < 0: - raise TealInternalError("Return number should be non-negative.") - elif num_returns > len(local_stack_types): + if num_return_allocs < 0: + raise TealInternalError("Return allocation number should be non-negative.") + elif num_return_allocs > len(local_stack_types): raise TealInternalError( "ProtoStackLayout initialization error:" - f"return number {num_returns} should not be greater than local allocations {len(local_stack_types)}." + f"return allocation number {num_return_allocs} should not be greater than local allocations {len(local_stack_types)}." ) if not all(map(lambda t: t != TealType.none, arg_stack_types)): raise TealInternalError("Variables in frame memory layout must be typed.") - self.num_returns: int = num_returns + self.num_return_allocs: int = num_return_allocs self.arg_stack_types: list[TealType] = arg_stack_types self.local_stack_types: list[TealType] = local_stack_types @@ -128,13 +128,15 @@ def __init__( f"The number of returns provided to Proto must be >= 0 but {num_returns=}." ) if mem_layout: - if mem_layout.num_returns != num_returns: + if mem_layout.num_return_allocs > num_returns: raise TealInternalError( - f"The number of returns {num_returns} should match with memory layout's number of returns {mem_layout.num_returns}" + f"The number of returns {num_returns} should be greater equal to " + f"memory layout's number of allocations for returns {mem_layout.num_return_allocs}" ) if len(mem_layout.arg_stack_types) != num_args: raise TealInternalError( - f"The number of arguments {num_args} should match with memory layout's number of arguments {len(mem_layout.arg_stack_types)}" + f"The number of arguments {num_args} should match with " + f"memory layout's number of arguments {len(mem_layout.arg_stack_types)}" ) self.num_args = num_args diff --git a/pyteal/ast/frame_test.py b/pyteal/ast/frame_test.py index 2182c35b9..3f62ca35b 100644 --- a/pyteal/ast/frame_test.py +++ b/pyteal/ast/frame_test.py @@ -192,29 +192,29 @@ def test_local_type_segment_compilation(testcase: LocalTypeSegmentTestCase): def test_proto_stack_layout_invalid(): - with pytest.raises(pt.TealInternalError) as bad_local_alloc: + with pytest.raises(pt.TealInternalError) as tie: ProtoStackLayout([pt.TealType.uint64, pt.TealType.bytes], [], -1) - assert "Return number should be non-negative." == str(bad_local_alloc.value) + assert "Return allocation number should be non-negative." == str(tie.value) - with pytest.raises(pt.TealInternalError) as bad_local_alloc: + with pytest.raises(pt.TealInternalError) as tie: ProtoStackLayout([pt.TealType.uint64, pt.TealType.bytes], [], 1) - assert "should not be greater than local allocations" in str(bad_local_alloc.value) + assert "should not be greater than local allocations" in str(tie.value) - with pytest.raises(pt.TealInternalError) as bad_type_on_stack: + with pytest.raises(pt.TealInternalError) as tie: ProtoStackLayout([pt.TealType.bytes, pt.TealType.none], [], 0) - assert "must be typed" in str(bad_type_on_stack.value) + assert "must be typed" in str(tie.value) - with pytest.raises(pt.TealInternalError) as bad_type_on_stack: + with pytest.raises(pt.TealInternalError) as tie: ProtoStackLayout( [pt.TealType.bytes, pt.TealType.uint64], [pt.TealType.uint64, pt.TealType.none], 0, ) - assert "must be typed" in str(bad_type_on_stack.value) + assert "must be typed" in str(tie.value) @dataclass From 0a5b570c55cf50e7ffe49483239bdc8fc04d58f3 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Mon, 7 Nov 2022 16:53:00 -0500 Subject: [PATCH 089/206] if there's nothing to initialize for local... --- pyteal/ast/frame.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 329922c5c..d299b2db0 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -99,12 +99,13 @@ def type_of(self) -> TealType: return TealType.none def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBlock]: - seg_srt, seg_end = self.succinct_repr[0].__teal__(options) - for iter_seg in self.succinct_repr[1:]: - srt, end = iter_seg.__teal__(options) - seg_end.setNextBlock(srt) - seg_end = end - return seg_srt, seg_end + srt = TealSimpleBlock([]) + end = srt + for iter_seg in self.succinct_repr: + seg_srt, seg_end = iter_seg.__teal__(options) + end.setNextBlock(seg_srt) + end = seg_end + return srt, end ProtoStackLayout.__module__ = "pyteal" From b8b6f32a804664787ab4c87251fc2231a97ab6ca Mon Sep 17 00:00:00 2001 From: Hang Su Date: Mon, 7 Nov 2022 18:45:42 -0500 Subject: [PATCH 090/206] update changes from mem layout --- pyteal/ast/abi/type.py | 5 +- pyteal/ast/subroutine.py | 74 ++++++++++++------- .../teal/roundtrip/app_roundtrip_()_v8.teal | 4 +- .../app_roundtrip_(bool)[10]_v8.teal | 6 +- .../roundtrip/app_roundtrip_(bool)_v8.teal | 4 +- ...t64,bool),byte[10],bool[4],uint64)_v8.teal | 12 +-- .../app_roundtrip_(bool,byte)_v8.teal | 4 +- ...undtrip_(bool,byte,address,string)_v8.teal | 8 +- ...yte),uint8)[2],string,bool[]))[]_2_v8.teal | 30 ++++---- ..._(bool,byte,address,string,uint64)_v8.teal | 8 +- ...app_roundtrip_(bool,uint64,uint32)_v8.teal | 4 +- .../roundtrip/app_roundtrip_(byte)_v8.teal | 4 +- .../app_roundtrip_(byte,bool,uint64)_v8.teal | 4 +- ...4],(bool,bool),uint64,address)[]_7_v8.teal | 12 +-- .../roundtrip/app_roundtrip_(uint16)_v8.teal | 4 +- .../app_roundtrip_(uint16,uint8,byte)_v8.teal | 4 +- .../roundtrip/app_roundtrip_(uint32)_v8.teal | 4 +- ...pp_roundtrip_(uint32,uint16,uint8)_v8.teal | 4 +- .../roundtrip/app_roundtrip_(uint64)_v8.teal | 4 +- ...p_roundtrip_(uint64,uint32,uint16)_v8.teal | 4 +- .../roundtrip/app_roundtrip_(uint8)_v8.teal | 4 +- .../app_roundtrip_(uint8,byte,bool)_v8.teal | 4 +- .../app_roundtrip_address[]_10_v8.teal | 6 +- .../roundtrip/app_roundtrip_address_v8.teal | 4 +- .../roundtrip/app_roundtrip_bool[1]_v8.teal | 4 +- .../app_roundtrip_bool[3][]_11_v8.teal | 6 +- .../roundtrip/app_roundtrip_bool[42]_v8.teal | 4 +- .../roundtrip/app_roundtrip_bool[]_0_v8.teal | 4 +- .../roundtrip/app_roundtrip_bool[]_1_v8.teal | 4 +- .../roundtrip/app_roundtrip_bool[]_42_v8.teal | 4 +- .../teal/roundtrip/app_roundtrip_bool_v8.teal | 2 +- .../roundtrip/app_roundtrip_byte[16]_v8.teal | 4 +- .../roundtrip/app_roundtrip_byte[]_36_v8.teal | 4 +- .../teal/roundtrip/app_roundtrip_byte_v8.teal | 2 +- .../roundtrip/app_roundtrip_string_0_v8.teal | 4 +- .../roundtrip/app_roundtrip_string_13_v8.teal | 4 +- .../roundtrip/app_roundtrip_string_1_v8.teal | 4 +- .../roundtrip/app_roundtrip_uint16_v8.teal | 2 +- .../roundtrip/app_roundtrip_uint32_v8.teal | 2 +- .../roundtrip/app_roundtrip_uint64[1]_v8.teal | 4 +- .../app_roundtrip_uint64[42]_v8.teal | 4 +- .../app_roundtrip_uint64[]_0_v8.teal | 4 +- .../app_roundtrip_uint64[]_1_v8.teal | 4 +- .../app_roundtrip_uint64[]_42_v8.teal | 4 +- .../roundtrip/app_roundtrip_uint64_v8.teal | 2 +- .../roundtrip/app_roundtrip_uint8_v8.teal | 2 +- 46 files changed, 159 insertions(+), 140 deletions(-) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index 03a23fe1a..fcdef3c2a 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -251,10 +251,7 @@ def store_into(self, output: BaseType) -> Expr: else: require_type(self.computation, output._stored_value.storage_type()) - return output._stored_value.store( - self.computation, - validate_types=not isinstance(output._stored_value, ScratchVar), - ) + return output._stored_value.store(self.computation, validate_types=False) ReturnedValue.__module__ = "pyteal.abi" diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 31978ad17..50ad7f1e2 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -9,7 +9,7 @@ from pyteal.ast.expr import Expr from pyteal.ast.seq import Seq from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar, ScratchSlot -from pyteal.ast.frame import FrameDig, Proto +from pyteal.ast.frame import FrameDig, Proto, FrameVar, ProtoStackLayout from pyteal.errors import TealInputError, TealInternalError, verifyProgramVersion from pyteal.ir import TealOp, Op, TealBlock from pyteal.types import TealType @@ -914,7 +914,7 @@ class SubroutineEval: """ var_n_loaded: Callable[ - [SubroutineDefinition, str], + [SubroutineDefinition, str, Optional[Proto]], tuple[Optional[ScratchVar], ScratchVar | abi.BaseType | Expr], ] use_frame_pt: bool = False @@ -923,6 +923,7 @@ class SubroutineEval: def __var_n_loaded( subroutine: SubroutineDefinition, param: str, + _: Optional[Proto] = None, ) -> tuple[ScratchVar, ScratchVar | abi.BaseType | Expr]: loaded_var: ScratchVar | abi.BaseType | Expr argument_var: ScratchVar @@ -948,8 +949,12 @@ def __var_n_loaded( def __var_n_loaded_fp( subroutine: SubroutineDefinition, param: str, + proto: Optional[Proto], ) -> tuple[Optional[ScratchVar], ScratchVar | abi.BaseType | Expr]: - from pyteal.ast.frame import FrameVar + if not proto: + raise TealInternalError( + "proto should be available for frame pointer based subroutine." + ) loaded_var: ScratchVar | abi.BaseType | Expr argument_var: Optional[ScratchVar] @@ -962,7 +967,7 @@ def __var_n_loaded_fp( dig_index = ( subroutine.arguments().index(param) - subroutine.argument_count() ) - internal_abi_var._stored_value = FrameVar(TealType.anytype, dig_index) + internal_abi_var._stored_value = FrameVar(proto, dig_index) argument_var = None loaded_var = internal_abi_var else: @@ -974,14 +979,49 @@ def __var_n_loaded_fp( return argument_var, loaded_var + @staticmethod + def __proto(subroutine: SubroutineDefinition) -> Proto: + arg_stack_types: list[TealType] = [] + for t in subroutine.expected_arg_types: + if t is Expr: + arg_stack_types.append(TealType.anytype) + elif t is ScratchVar: + arg_stack_types.append(TealType.uint64) + else: + arg_stack_types.append(cast(abi.TypeSpec, t).storage_type()) + + num_return_allocs: int = int(subroutine.has_abi_output) + + local_stack_types: list[TealType] = [] + if subroutine.has_abi_output: + output_info = cast( + OutputKwArgInfo, OutputKwArgInfo.from_dict(subroutine.output_kwarg) + ) + local_stack_types = [output_info.abi_type.storage_type()] + + layout: ProtoStackLayout = ProtoStackLayout( + arg_stack_types, local_stack_types, num_return_allocs + ) + + # if subroutine do not have abi output, then only two cases happen: + # - subroutine is a normal subroutine, then check subroutine body evaluates to something, rather than none + # - subroutine is an ABIReturnSubroutine, the type is void, and its subroutine body type of is always none + num_stack_outputs: int = ( + 1 + if subroutine.has_abi_output + else int(subroutine.return_type != TealType.none) + ) + + return Proto(subroutine.argument_count(), num_stack_outputs, mem_layout=layout) + def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: - from pyteal.ast.frame import FrameVar + proto = self.__proto(subroutine) args = subroutine.arguments() arg_vars: list[ScratchVar] = [] loaded_args: list[ScratchVar | Expr | abi.BaseType] = [] for arg in args: - arg_var, loaded_arg = self.var_n_loaded(subroutine, arg) + arg_var, loaded_arg = self.var_n_loaded(subroutine, arg, proto) if arg_var: arg_vars.append(arg_var) loaded_args.append(loaded_arg) @@ -993,7 +1033,7 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: if output_kwarg_info: output_carrying_abi = output_kwarg_info.abi_type.new_instance() if self.use_frame_pt: - output_carrying_abi._stored_value = FrameVar(TealType.anytype, 0) + output_carrying_abi._stored_value = FrameVar(proto, 0) abi_output_kwargs[output_kwarg_info.name] = output_carrying_abi # Arg usage "B" supplied to build an AST from the user-defined PyTEAL function: @@ -1016,25 +1056,7 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: # Arg usage "A" to be pick up and store in scratch parameters that have been placed on the stack # need to reverse order of argumentVars because the last argument will be on top of the stack - body_ops: list[Expr] = [] - - stack_output_cnt: int - if not subroutine.has_abi_output: - # if subroutine do not have abi output, then only two cases happen: - # - subroutine is a normal subroutine, then check subroutine body evaluates to something, rather than none - # - subroutine is an ABIReturnSubroutine, the type is void, and its subroutine body type of is always none - stack_output_cnt = int(subroutine.return_type != TealType.none) - else: - stack_output_cnt = len(abi_output_kwargs) - - if self.use_frame_pt: - body_ops = [ - Proto( - subroutine.argument_count(), - stack_output_cnt, - num_allocs=int(subroutine.has_abi_output), - ) - ] + body_ops: list[Expr] = [] if not self.use_frame_pt else [proto] body_ops += [var.slot.store() for var in arg_vars[::-1]] body_ops.append(subroutine_body) diff --git a/tests/integration/teal/roundtrip/app_roundtrip_()_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_()_v8.teal index a15a4fc89..6fc43d729 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_()_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_()_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" byte "" frame_bury 0 frame_dig 0 @@ -23,7 +23,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub tuplecomplement_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10]_v8.teal index 3fd706e70..01f03a3df 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10]_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10]_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 getbit @@ -33,7 +33,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 @@ -160,7 +160,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 0 +byte "" frame_dig -1 callsub arraycomplement_1 store 3 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool)_v8.teal index 007dc02ea..4545cae71 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 getbit @@ -33,7 +33,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub tuplecomplement_0 store 3 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64)_v8.teal index 6f72201c2..500bd48f0 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 getbit @@ -75,7 +75,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub tuplecomplement_0 store 8 @@ -121,7 +121,7 @@ retsub // array_complement arraycomplement_4: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 @@ -576,7 +576,7 @@ retsub // tuple_complement tuplecomplement_5: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 extract_uint64 @@ -620,7 +620,7 @@ retsub // array_complement arraycomplement_7: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 @@ -779,7 +779,7 @@ retsub // array_complement arraycomplement_9: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 getbit diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte)_v8.teal index 7de062794..93a6c2c3b 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 getbit @@ -45,7 +45,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub tuplecomplement_0 store 4 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string)_v8.teal index c015db7d2..5d4d405aa 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 getbit @@ -76,7 +76,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub tuplecomplement_0 store 6 @@ -185,7 +185,7 @@ retsub // array_complement arraycomplement_5: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 @@ -640,7 +640,7 @@ retsub // string_reverse stringreverse_6: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_2_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_2_v8.teal index c7436e670..196bf904e 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_2_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_2_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 getbit @@ -109,7 +109,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 0 +byte "" frame_dig -1 frame_dig -1 int 2 @@ -238,7 +238,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 0 +byte "" frame_dig -1 callsub arraycomplement_1 store 7 @@ -347,7 +347,7 @@ retsub // array_complement arraycomplement_6: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 @@ -802,7 +802,7 @@ retsub // string_reverse stringreverse_7: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 @@ -854,7 +854,7 @@ retsub // tuple_complement tuplecomplement_8: proto 1 1 -int 0 +byte "" frame_dig -1 extract 0 32 store 22 @@ -973,7 +973,7 @@ retsub // array_complement arraycomplement_10: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 @@ -1428,7 +1428,7 @@ retsub // tuple_complement tuplecomplement_11: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 extract_uint32 @@ -1497,7 +1497,7 @@ retsub // array_complement arraycomplement_12: proto 1 1 -int 0 +byte "" frame_dig -1 frame_dig -1 int 2 @@ -1596,7 +1596,7 @@ retsub // string_reverse stringreverse_13: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 @@ -1660,7 +1660,7 @@ retsub // array_complement arraycomplement_15: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 int 16 @@ -1726,7 +1726,7 @@ retsub // string_reverse stringreverse_17: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 @@ -1778,7 +1778,7 @@ retsub // array_complement arraycomplement_18: proto 1 1 -int 0 +byte "" frame_dig -1 frame_dig -1 int 2 @@ -1981,7 +1981,7 @@ retsub // array_complement arraycomplement_20: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 getbit @@ -2010,7 +2010,7 @@ retsub // tuple_complement tuplecomplement_21: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 getbyte diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64)_v8.teal index b20a2929e..31c7c3c33 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 getbit @@ -86,7 +86,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub tuplecomplement_0 store 7 @@ -195,7 +195,7 @@ retsub // array_complement arraycomplement_5: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 @@ -650,7 +650,7 @@ retsub // string_reverse stringreverse_6: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32)_v8.teal index c6cb8d92a..0fd41ab36 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 getbit @@ -54,7 +54,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub tuplecomplement_0 store 5 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(byte)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(byte)_v8.teal index ed37a3f74..58b13c2a9 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(byte)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(byte)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 getbyte @@ -33,7 +33,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub tuplecomplement_0 store 3 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64)_v8.teal index 328541097..833bcf2f8 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 getbyte @@ -55,7 +55,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub tuplecomplement_0 store 5 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7_v8.teal index 12e8535c4..a353ed873 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" frame_dig -1 extract 0 4 store 0 @@ -55,7 +55,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 0 +byte "" frame_dig -1 int 45 int 0 @@ -166,7 +166,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 0 +byte "" frame_dig -1 callsub arraycomplement_1 store 6 @@ -248,7 +248,7 @@ retsub // array_complement arraycomplement_4: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 @@ -311,7 +311,7 @@ retsub // tuple_complement tuplecomplement_5: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 getbit @@ -366,7 +366,7 @@ retsub // array_complement arraycomplement_8: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint16)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint16)_v8.teal index ce75f2421..b20aff3b8 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint16)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint16)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 extract_uint16 @@ -32,7 +32,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub tuplecomplement_0 store 3 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte)_v8.teal index b2cde5b27..a04b815e8 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 extract_uint16 @@ -56,7 +56,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub tuplecomplement_0 store 5 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint32)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint32)_v8.teal index 4e9b98403..608ed547c 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint32)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint32)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 extract_uint32 @@ -32,7 +32,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub tuplecomplement_0 store 3 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8)_v8.teal index fe6043f2f..f520db71c 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 extract_uint32 @@ -55,7 +55,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub tuplecomplement_0 store 5 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint64)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint64)_v8.teal index 64e19a464..417770e21 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint64)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint64)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" frame_dig -1 btoi store 0 @@ -30,7 +30,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub tuplecomplement_0 store 3 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16)_v8.teal index cdbd5954b..8f2803270 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 extract_uint64 @@ -53,7 +53,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub tuplecomplement_0 store 5 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint8)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint8)_v8.teal index ed37a3f74..58b13c2a9 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint8)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint8)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 getbyte @@ -33,7 +33,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub tuplecomplement_0 store 3 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v8.teal index 689248d79..dedc08a8d 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v8.teal @@ -14,7 +14,7 @@ return // tuple_complement tuplecomplement_0: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 getbyte @@ -57,7 +57,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub tuplecomplement_0 store 5 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_address[]_10_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_address[]_10_v8.teal index 280f65569..05dff5111 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_address[]_10_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_address[]_10_v8.teal @@ -29,7 +29,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 @@ -484,7 +484,7 @@ retsub // array_complement arraycomplement_2: proto 1 1 -int 0 +byte "" frame_dig -1 int 32 int 0 @@ -637,7 +637,7 @@ retsub // round_tripper roundtripper_3: proto 1 1 -int 0 +byte "" frame_dig -1 callsub arraycomplement_2 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_address_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_address_v8.teal index 33347e57b..f71989611 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_address_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_address_v8.teal @@ -29,7 +29,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 @@ -484,7 +484,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 0 +byte "" frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[1]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[1]_v8.teal index 35258686a..3acd9d712 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool[1]_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[1]_v8.teal @@ -26,7 +26,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 getbit @@ -45,7 +45,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 0 +byte "" frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11_v8.teal index 07faee81c..2fc9c7774 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11_v8.teal @@ -26,7 +26,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 getbit @@ -65,7 +65,7 @@ retsub // array_complement arraycomplement_2: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 @@ -232,7 +232,7 @@ retsub // round_tripper roundtripper_3: proto 1 1 -int 0 +byte "" frame_dig -1 callsub arraycomplement_2 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[42]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[42]_v8.teal index 31fa09e84..5787f99f9 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool[42]_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[42]_v8.teal @@ -26,7 +26,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 getbit @@ -455,7 +455,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 0 +byte "" frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_0_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_0_v8.teal index 67050ca70..89f595322 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_0_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_0_v8.teal @@ -14,7 +14,7 @@ return // array_complement arraycomplement_0: proto 1 1 -int 0 +byte "" int 0 store 8 load 8 @@ -29,7 +29,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub arraycomplement_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_1_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_1_v8.teal index 61b164f60..61a4806b2 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_1_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_1_v8.teal @@ -26,7 +26,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 int 16 @@ -53,7 +53,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 0 +byte "" frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_42_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_42_v8.teal index a5c7c3d9f..56931159c 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_42_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_42_v8.teal @@ -26,7 +26,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 0 +byte "" frame_dig -1 int 0 int 16 @@ -545,7 +545,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 0 +byte "" frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool_v8.teal index b241c509d..23e0c659a 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool_v8.teal @@ -30,7 +30,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub boolcomp_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_byte[16]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_byte[16]_v8.teal index 4d3b6e7c2..a8ca32f63 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_byte[16]_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_byte[16]_v8.teal @@ -29,7 +29,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 @@ -260,7 +260,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 0 +byte "" frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_byte[]_36_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_byte[]_36_v8.teal index 731fb06d0..7aa6b4aad 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_byte[]_36_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_byte[]_36_v8.teal @@ -29,7 +29,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 @@ -618,7 +618,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 0 +byte "" frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_byte_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_byte_v8.teal index b1ec9822c..91cc0024a 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_byte_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_byte_v8.teal @@ -31,7 +31,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub numericalcomp_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_string_0_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_string_0_v8.teal index fb6e4bfeb..c0d9a212c 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_string_0_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_string_0_v8.teal @@ -14,7 +14,7 @@ return // string_reverse stringreverse_0: proto 1 1 -int 0 +byte "" int 0 store 8 load 8 @@ -29,7 +29,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub stringreverse_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_string_13_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_string_13_v8.teal index 6b9d3620f..742afe0a0 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_string_13_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_string_13_v8.teal @@ -14,7 +14,7 @@ return // string_reverse stringreverse_0: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 @@ -196,7 +196,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub stringreverse_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_string_1_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_string_1_v8.teal index 15bec0ea9..3e6f669d6 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_string_1_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_string_1_v8.teal @@ -14,7 +14,7 @@ return // string_reverse stringreverse_0: proto 1 1 -int 0 +byte "" frame_dig -1 int 1 int 0 @@ -40,7 +40,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub stringreverse_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint16_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint16_v8.teal index 4204c502b..700f8bead 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint16_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint16_v8.teal @@ -31,7 +31,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub numericalcomp_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint32_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint32_v8.teal index 2ed29b2ee..00be1ca95 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint32_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint32_v8.teal @@ -31,7 +31,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub numericalcomp_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[1]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[1]_v8.teal index fb6a67b3a..6aa863ad2 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint64[1]_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[1]_v8.teal @@ -25,7 +25,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 0 +byte "" frame_dig -1 int 8 int 0 @@ -44,7 +44,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 0 +byte "" frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[42]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[42]_v8.teal index e82c27443..b995008af 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint64[42]_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[42]_v8.teal @@ -25,7 +25,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 0 +byte "" frame_dig -1 int 8 int 0 @@ -536,7 +536,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 0 +byte "" frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0_v8.teal index 67050ca70..89f595322 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0_v8.teal @@ -14,7 +14,7 @@ return // array_complement arraycomplement_0: proto 1 1 -int 0 +byte "" int 0 store 8 load 8 @@ -29,7 +29,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub arraycomplement_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1_v8.teal index cd6867a22..ce54ebdb6 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1_v8.teal @@ -25,7 +25,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 0 +byte "" frame_dig -1 int 8 int 0 @@ -52,7 +52,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 0 +byte "" frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42_v8.teal index 0b2bddb45..24dd3f3ff 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42_v8.teal @@ -25,7 +25,7 @@ retsub // array_complement arraycomplement_1: proto 1 1 -int 0 +byte "" frame_dig -1 int 8 int 0 @@ -626,7 +626,7 @@ retsub // round_tripper roundtripper_2: proto 1 1 -int 0 +byte "" frame_dig -1 callsub arraycomplement_1 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64_v8.teal index 4f6069984..165bcb347 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint64_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64_v8.teal @@ -26,7 +26,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub numericalcomp_0 store 2 diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint8_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint8_v8.teal index b1ec9822c..91cc0024a 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint8_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint8_v8.teal @@ -31,7 +31,7 @@ retsub // round_tripper roundtripper_1: proto 1 1 -int 0 +byte "" frame_dig -1 callsub numericalcomp_0 store 2 From f6994ae0f4f37c7d24b0ae696e7fb7447951ca14 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Tue, 8 Nov 2022 10:50:40 -0500 Subject: [PATCH 091/206] minor change in type-check in computed-type --- pyteal/ast/abi/type.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index fcdef3c2a..34351590a 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -6,7 +6,7 @@ from pyteal.ast.scratchvar import ScratchVar from pyteal.ast.seq import Seq from pyteal.errors import TealInputError -from pyteal.types import TealType, require_type, types_match +from pyteal.types import TealType, types_match class TypeSpec(ABC): @@ -240,6 +240,9 @@ def store_into(self, output: BaseType) -> Expr: f"ABI return subroutine deferred_expr is expected to be typed {output.type_spec().storage_type()}, " f"but has type {declaration.deferred_expr.type_of()}." ) + + validate_in_store: bool = True + if ( isinstance(self.computation, SubroutineCall) and self.computation.output_kwarg @@ -248,10 +251,9 @@ def store_into(self, output: BaseType) -> Expr: self.computation.output_kwarg.abi_type.storage_type(), output._stored_value.storage_type(), ) - else: - require_type(self.computation, output._stored_value.storage_type()) + validate_in_store = False - return output._stored_value.store(self.computation, validate_types=False) + return output._stored_value.store(self.computation, validate_types=validate_in_store) ReturnedValue.__module__ = "pyteal.abi" From 21e9350f74c17dc9dbd3b683c350670e2145613e Mon Sep 17 00:00:00 2001 From: Hang Su Date: Tue, 8 Nov 2022 10:50:40 -0500 Subject: [PATCH 092/206] minor change in type-check in computed-type --- pyteal/ast/abi/type.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index fcdef3c2a..4afef8a70 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -6,7 +6,7 @@ from pyteal.ast.scratchvar import ScratchVar from pyteal.ast.seq import Seq from pyteal.errors import TealInputError -from pyteal.types import TealType, require_type, types_match +from pyteal.types import TealType, types_match class TypeSpec(ABC): @@ -240,6 +240,9 @@ def store_into(self, output: BaseType) -> Expr: f"ABI return subroutine deferred_expr is expected to be typed {output.type_spec().storage_type()}, " f"but has type {declaration.deferred_expr.type_of()}." ) + + validate_in_store: bool = True + if ( isinstance(self.computation, SubroutineCall) and self.computation.output_kwarg @@ -248,10 +251,11 @@ def store_into(self, output: BaseType) -> Expr: self.computation.output_kwarg.abi_type.storage_type(), output._stored_value.storage_type(), ) - else: - require_type(self.computation, output._stored_value.storage_type()) + validate_in_store = False - return output._stored_value.store(self.computation, validate_types=False) + return output._stored_value.store( + self.computation, validate_types=validate_in_store + ) ReturnedValue.__module__ = "pyteal.abi" From b0045ec7fa61eff0569b91bdfc1904d5007aad45 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Tue, 8 Nov 2022 11:28:59 -0500 Subject: [PATCH 093/206] linewidth --- pyteal/ast/frame.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index d299b2db0..04d829286 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -67,8 +67,9 @@ def __init__( raise TealInternalError("Return allocation number should be non-negative.") elif num_return_allocs > len(local_stack_types): raise TealInternalError( - "ProtoStackLayout initialization error:" - f"return allocation number {num_return_allocs} should not be greater than local allocations {len(local_stack_types)}." + "ProtoStackLayout initialization error: " + f"return allocation number {num_return_allocs} should not " + f"be greater than local allocations {len(local_stack_types)}." ) if not all(map(lambda t: t != TealType.none, arg_stack_types)): From 9daee52491ee43908a6c11b323c40174b0e0ba42 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Tue, 8 Nov 2022 13:26:42 -0500 Subject: [PATCH 094/206] some minor comments --- pyteal/ast/abstractvar.py | 14 +++++++++++++ pyteal/ast/frame.py | 44 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/pyteal/ast/abstractvar.py b/pyteal/ast/abstractvar.py index d18a98d70..956d4735f 100644 --- a/pyteal/ast/abstractvar.py +++ b/pyteal/ast/abstractvar.py @@ -4,6 +4,20 @@ class AbstractVar(ABC): + """AbstractVar is an abstract class that captures properties of a variable. + + A variable, on an abstract perspective, has following properties: + + * Storing: can be stored to a certain position. + * Loading: can be loaded from a certain position. + * (Strong) Typed: can indicate its own type. + + ScratchVar and FrameVar inherits from this class, representing the load and storage of value + against scratch slots or stack based on frame pointer. + + This class is intentionally hidden because it's too basic to directly expose. + """ + @abstractmethod def store(self, value: Expr, validate_types: bool = True) -> Expr: pass diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 04d829286..8fd972981 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -14,6 +14,12 @@ class LocalTypeSegment(Expr): + """An expression that allocates stack spaces for local variable. + + This class is intentionally hidden because it's too basic to directly expose. + This is only used in ProtoStackLayout internally. + """ + def __init__(self, local_type: TealType, count: int): super().__init__() self.local_type = local_type @@ -56,6 +62,12 @@ def type_of(self) -> TealType: class ProtoStackLayout(Expr): + """An expression that carrys arg types and local types for a subroutine. + + This class is intentionally hidden because it's too basic to directly expose. + This is only used in Proto internally. + """ + def __init__( self, arg_stack_types: list[TealType], @@ -113,6 +125,12 @@ def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBloc class Proto(Expr): + """An expression that prepare top call frame for a retsub that will assume A args and R return values. + + This class is intentionally hidden because it's too basic to directly expose. + It is only used in subroutine, for subrouine declaration computation. + """ + def __init__( self, num_args: int, @@ -173,6 +191,12 @@ def has_return(self) -> bool: class FrameDig(Expr): + """An expression that digs a value from a position around frame pointer. + + This class is intentionally hidden because it's too basic to directly expose. + his is used only internally by FrameVar. + """ + def __init__(self, frame_index: int, *, inferred_type: Optional[TealType] = None): super().__init__() self.frame_index = frame_index @@ -201,6 +225,12 @@ def has_return(self) -> bool: class FrameBury(Expr): + """An expression that burys a value to a position around frame pointer. + + This class is intentionally hidden because it's too basic to directly expose. + his is used only internally by FrameVar. + """ + def __init__( self, value: Expr, @@ -241,6 +271,14 @@ def has_return(self) -> bool: class FrameVar(AbstractVar): + """An instantiation for AbstractVar based on frame pointer. + + FrameVar captures loading, storing and type of variable over stack by frame pointer. + + This class is intentionally hidden because it's too basic to directly expose. + This is used only internally by SubroutineEval in subroutine declaration computation. + """ + def __init__(self, under_proto: Proto, frame_index: int) -> None: super().__init__() self.proto = under_proto @@ -270,6 +308,12 @@ def load(self) -> Expr: class DupN(Expr): + """Duplicate an expression N times. + + This class is intentionally hidden because it's too basic to directly expose. + This is used only by Proto and LocalTypeSegment. + """ + def __init__(self, value: Expr, repetition: int): super().__init__() require_type(value, TealType.anytype) From 6ef76dd88bbc5d75ff706c41f074ab889bfe0799 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Tue, 8 Nov 2022 15:13:16 -0500 Subject: [PATCH 095/206] revert to framevar version --- pyteal/ast/subroutine.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 50ad7f1e2..c562f7a96 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -9,7 +9,7 @@ from pyteal.ast.expr import Expr from pyteal.ast.seq import Seq from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar, ScratchSlot -from pyteal.ast.frame import FrameDig, Proto, FrameVar, ProtoStackLayout +from pyteal.ast.frame import Proto, FrameVar, ProtoStackLayout from pyteal.errors import TealInputError, TealInternalError, verifyProgramVersion from pyteal.ir import TealOp, Op, TealBlock from pyteal.types import TealType @@ -975,7 +975,7 @@ def __var_n_loaded_fp( subroutine.arguments().index(param) - subroutine.argument_count() ) argument_var = None - loaded_var = FrameDig(dig_index) + loaded_var = FrameVar(proto, dig_index).load() return argument_var, loaded_var From 19a1fe2ae68f845a76c3ae704baefb87bf44a5f7 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Tue, 8 Nov 2022 15:59:18 -0500 Subject: [PATCH 096/206] use deferred only on scratch slot --- pyteal/ast/subroutine.py | 3 ++- .../teal/roundtrip/app_roundtrip_()_v8.teal | 2 -- .../app_roundtrip_(bool)[10]_v8.teal | 4 ---- .../roundtrip/app_roundtrip_(bool)_v8.teal | 3 --- ...t64,bool),byte[10],bool[4],uint64)_v8.teal | 13 ---------- .../app_roundtrip_(bool,byte)_v8.teal | 4 ---- ...undtrip_(bool,byte,address,string)_v8.teal | 7 ------ ...yte),uint8)[2],string,bool[]))[]_2_v8.teal | 24 ------------------- ..._(bool,byte,address,string,uint64)_v8.teal | 8 ------- ...app_roundtrip_(bool,uint64,uint32)_v8.teal | 5 ---- .../roundtrip/app_roundtrip_(byte)_v8.teal | 3 --- .../app_roundtrip_(byte,bool,uint64)_v8.teal | 5 ---- ...4],(bool,bool),uint64,address)[]_7_v8.teal | 11 --------- .../roundtrip/app_roundtrip_(uint16)_v8.teal | 3 --- .../app_roundtrip_(uint16,uint8,byte)_v8.teal | 5 ---- .../roundtrip/app_roundtrip_(uint32)_v8.teal | 3 --- ...pp_roundtrip_(uint32,uint16,uint8)_v8.teal | 5 ---- .../roundtrip/app_roundtrip_(uint64)_v8.teal | 3 --- ...p_roundtrip_(uint64,uint32,uint16)_v8.teal | 5 ---- .../roundtrip/app_roundtrip_(uint8)_v8.teal | 3 --- .../app_roundtrip_(uint8,byte,bool)_v8.teal | 5 ---- .../app_roundtrip_address[]_10_v8.teal | 4 ---- .../roundtrip/app_roundtrip_address_v8.teal | 3 --- .../roundtrip/app_roundtrip_bool[1]_v8.teal | 3 --- .../app_roundtrip_bool[3][]_11_v8.teal | 4 ---- .../roundtrip/app_roundtrip_bool[42]_v8.teal | 3 --- .../roundtrip/app_roundtrip_bool[]_0_v8.teal | 2 -- .../roundtrip/app_roundtrip_bool[]_1_v8.teal | 3 --- .../roundtrip/app_roundtrip_bool[]_42_v8.teal | 3 --- .../teal/roundtrip/app_roundtrip_bool_v8.teal | 2 -- .../roundtrip/app_roundtrip_byte[16]_v8.teal | 3 --- .../roundtrip/app_roundtrip_byte[]_36_v8.teal | 3 --- .../teal/roundtrip/app_roundtrip_byte_v8.teal | 2 -- .../roundtrip/app_roundtrip_string_0_v8.teal | 2 -- .../roundtrip/app_roundtrip_string_13_v8.teal | 2 -- .../roundtrip/app_roundtrip_string_1_v8.teal | 2 -- .../roundtrip/app_roundtrip_uint16_v8.teal | 2 -- .../roundtrip/app_roundtrip_uint32_v8.teal | 2 -- .../roundtrip/app_roundtrip_uint64[1]_v8.teal | 3 --- .../app_roundtrip_uint64[42]_v8.teal | 3 --- .../app_roundtrip_uint64[]_0_v8.teal | 2 -- .../app_roundtrip_uint64[]_1_v8.teal | 3 --- .../app_roundtrip_uint64[]_42_v8.teal | 3 --- .../roundtrip/app_roundtrip_uint64_v8.teal | 2 -- .../roundtrip/app_roundtrip_uint8_v8.teal | 2 -- 45 files changed, 2 insertions(+), 185 deletions(-) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index c562f7a96..0b5f03337 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -1052,7 +1052,8 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: f"ABI returning subroutine definition should evaluate to TealType.none, " f"while evaluate to {subroutine_body.type_of()}." ) - deferred_expr = output_carrying_abi._stored_value.load() + if not self.use_frame_pt: + deferred_expr = output_carrying_abi._stored_value.load() # Arg usage "A" to be pick up and store in scratch parameters that have been placed on the stack # need to reverse order of argumentVars because the last argument will be on top of the stack diff --git a/tests/integration/teal/roundtrip/app_roundtrip_()_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_()_v8.teal index 6fc43d729..d0ddb9ccf 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_()_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_()_v8.teal @@ -17,7 +17,6 @@ proto 1 1 byte "" byte "" frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -36,5 +35,4 @@ concat load 3 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10]_v8.teal index 01f03a3df..13296df67 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10]_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool)[10]_v8.teal @@ -27,7 +27,6 @@ int 0 load 0 setbit frame_bury 0 -frame_dig 0 retsub // array_complement @@ -154,7 +153,6 @@ concat load 14 concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -173,7 +171,6 @@ concat load 4 concat frame_bury 0 -frame_dig 0 retsub // bool_comp @@ -185,5 +182,4 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool)_v8.teal index 4545cae71..72411884c 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool)_v8.teal @@ -27,7 +27,6 @@ int 0 load 0 setbit frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -46,7 +45,6 @@ concat load 4 concat frame_bury 0 -frame_dig 0 retsub // bool_comp @@ -58,5 +56,4 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64)_v8.teal index 500bd48f0..1875b356a 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,address,(uint64,bool),byte[10],bool[4],uint64)_v8.teal @@ -69,7 +69,6 @@ load 5 itob concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -88,7 +87,6 @@ concat load 9 concat frame_bury 0 -frame_dig 0 retsub // bool_comp @@ -100,7 +98,6 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -115,7 +112,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // array_complement @@ -570,7 +566,6 @@ load 43 setbyte concat frame_bury 0 -frame_dig 0 retsub // tuple_complement @@ -599,7 +594,6 @@ load 11 setbit concat frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -614,7 +608,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // array_complement @@ -761,7 +754,6 @@ load 53 setbyte concat frame_bury 0 -frame_dig 0 retsub // bool_comp @@ -773,7 +765,6 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub // array_complement @@ -822,7 +813,6 @@ int 3 load 57 setbit frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -833,7 +823,6 @@ int 18446744073709551615 frame_dig -1 - frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -844,7 +833,6 @@ int 18446744073709551615 frame_dig -1 - frame_bury 0 -frame_dig 0 retsub // bool_comp @@ -856,5 +844,4 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte)_v8.teal index 93a6c2c3b..c91fe2871 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte)_v8.teal @@ -39,7 +39,6 @@ load 1 setbyte concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -58,7 +57,6 @@ concat load 5 concat frame_bury 0 -frame_dig 0 retsub // bool_comp @@ -70,7 +68,6 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -85,5 +82,4 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string)_v8.teal index 5d4d405aa..dbb2b1b5e 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string)_v8.teal @@ -70,7 +70,6 @@ concat load 13 concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -137,7 +136,6 @@ concat load 10 concat frame_bury 0 -frame_dig 0 retsub // bool_comp @@ -149,7 +147,6 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -164,7 +161,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // numerical_comp @@ -179,7 +175,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // array_complement @@ -634,7 +629,6 @@ load 46 setbyte concat frame_bury 0 -frame_dig 0 retsub // string_reverse @@ -686,5 +680,4 @@ setbyte concat concat frame_bury 0 -frame_dig 0 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_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_2_v8.teal index 196bf904e..ac2ca105f 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_2_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,(address,(uint32,string[],bool[2],(byte),uint8)[2],string,bool[]))[]_2_v8.teal @@ -103,7 +103,6 @@ concat load 28 concat frame_bury 0 -frame_dig 0 retsub // array_complement @@ -232,7 +231,6 @@ load 19 concat concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -299,7 +297,6 @@ concat load 11 concat frame_bury 0 -frame_dig 0 retsub // bool_comp @@ -311,7 +308,6 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -326,7 +322,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // numerical_comp @@ -341,7 +336,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // array_complement @@ -796,7 +790,6 @@ load 61 setbyte concat frame_bury 0 -frame_dig 0 retsub // string_reverse @@ -848,7 +841,6 @@ setbyte concat concat frame_bury 0 -frame_dig 0 retsub // tuple_complement @@ -952,7 +944,6 @@ concat load 73 concat frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -967,7 +958,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // array_complement @@ -1422,7 +1412,6 @@ load 106 setbyte concat frame_bury 0 -frame_dig 0 retsub // tuple_complement @@ -1491,7 +1480,6 @@ concat load 115 concat frame_bury 0 -frame_dig 0 retsub // array_complement @@ -1590,7 +1578,6 @@ concat load 111 concat frame_bury 0 -frame_dig 0 retsub // string_reverse @@ -1642,7 +1629,6 @@ setbyte concat concat frame_bury 0 -frame_dig 0 retsub // bool_comp @@ -1654,7 +1640,6 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub // array_complement @@ -1705,7 +1690,6 @@ load 140 setbit concat frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -1720,7 +1704,6 @@ frame_dig 0 int 4294967296 < assert -frame_dig 0 retsub // string_reverse @@ -1772,7 +1755,6 @@ setbyte concat concat frame_bury 0 -frame_dig 0 retsub // array_complement @@ -1963,7 +1945,6 @@ load 125 concat concat frame_bury 0 -frame_dig 0 retsub // bool_comp @@ -1975,7 +1956,6 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub // array_complement @@ -2004,7 +1984,6 @@ int 1 load 133 setbit frame_bury 0 -frame_dig 0 retsub // tuple_complement @@ -2023,7 +2002,6 @@ int 0 load 113 setbyte frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -2038,7 +2016,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // numerical_comp @@ -2053,5 +2030,4 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64)_v8.teal index 31c7c3c33..ac3980f9e 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,byte,address,string,uint64)_v8.teal @@ -80,7 +80,6 @@ concat load 14 concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -147,7 +146,6 @@ concat load 11 concat frame_bury 0 -frame_dig 0 retsub // bool_comp @@ -159,7 +157,6 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -174,7 +171,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // numerical_comp @@ -189,7 +185,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // array_complement @@ -644,7 +639,6 @@ load 47 setbyte concat frame_bury 0 -frame_dig 0 retsub // string_reverse @@ -696,7 +690,6 @@ setbyte concat concat frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -707,5 +700,4 @@ int 18446744073709551615 frame_dig -1 - frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32)_v8.teal index 0fd41ab36..8f04b8ad0 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(bool,uint64,uint32)_v8.teal @@ -48,7 +48,6 @@ itob extract 4 0 concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -67,7 +66,6 @@ concat load 6 concat frame_bury 0 -frame_dig 0 retsub // bool_comp @@ -79,7 +77,6 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -90,7 +87,6 @@ int 18446744073709551615 frame_dig -1 - frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -105,5 +101,4 @@ frame_dig 0 int 4294967296 < assert -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(byte)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(byte)_v8.teal index 58b13c2a9..4a8d567ff 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(byte)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(byte)_v8.teal @@ -27,7 +27,6 @@ int 0 load 0 setbyte frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -46,7 +45,6 @@ concat load 4 concat frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -61,5 +59,4 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64)_v8.teal index 833bcf2f8..a5fb0355f 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(byte,bool,uint64)_v8.teal @@ -49,7 +49,6 @@ load 2 itob concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -68,7 +67,6 @@ concat load 6 concat frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -83,7 +81,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // bool_comp @@ -95,7 +92,6 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -106,5 +102,4 @@ int 18446744073709551615 frame_dig -1 - frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7_v8.teal index a353ed873..064b29fc8 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(byte[4],(bool,bool),uint64,address)[]_7_v8.teal @@ -49,7 +49,6 @@ concat load 3 concat frame_bury 0 -frame_dig 0 retsub // array_complement @@ -160,7 +159,6 @@ load 18 concat concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -227,7 +225,6 @@ concat load 10 concat frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -242,7 +239,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // array_complement @@ -305,7 +301,6 @@ load 25 setbyte concat frame_bury 0 -frame_dig 0 retsub // tuple_complement @@ -334,7 +329,6 @@ int 1 load 21 setbit frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -345,7 +339,6 @@ int 18446744073709551615 frame_dig -1 - frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -360,7 +353,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // array_complement @@ -815,7 +807,6 @@ load 57 setbyte concat frame_bury 0 -frame_dig 0 retsub // bool_comp @@ -827,7 +818,6 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub // bool_comp @@ -839,5 +829,4 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint16)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint16)_v8.teal index b20aff3b8..3a683e4cf 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint16)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint16)_v8.teal @@ -26,7 +26,6 @@ load 0 itob extract 6 0 frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -45,7 +44,6 @@ concat load 4 concat frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -60,5 +58,4 @@ frame_dig 0 int 65536 < assert -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte)_v8.teal index a04b815e8..47ddf0b4c 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint16,uint8,byte)_v8.teal @@ -50,7 +50,6 @@ load 2 setbyte concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -69,7 +68,6 @@ concat load 6 concat frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -84,7 +82,6 @@ frame_dig 0 int 65536 < assert -frame_dig 0 retsub // numerical_comp @@ -99,7 +96,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // numerical_comp @@ -114,5 +110,4 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint32)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint32)_v8.teal index 608ed547c..a4b6b04a2 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint32)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint32)_v8.teal @@ -26,7 +26,6 @@ load 0 itob extract 4 0 frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -45,7 +44,6 @@ concat load 4 concat frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -60,5 +58,4 @@ frame_dig 0 int 4294967296 < assert -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8)_v8.teal index f520db71c..8a165cddc 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint32,uint16,uint8)_v8.teal @@ -49,7 +49,6 @@ load 2 setbyte concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -68,7 +67,6 @@ concat load 6 concat frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -83,7 +81,6 @@ frame_dig 0 int 4294967296 < assert -frame_dig 0 retsub // numerical_comp @@ -98,7 +95,6 @@ frame_dig 0 int 65536 < assert -frame_dig 0 retsub // numerical_comp @@ -113,5 +109,4 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint64)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint64)_v8.teal index 417770e21..5ba9c63c6 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint64)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint64)_v8.teal @@ -24,7 +24,6 @@ store 0 load 0 itob frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -43,7 +42,6 @@ concat load 4 concat frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -54,5 +52,4 @@ int 18446744073709551615 frame_dig -1 - frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16)_v8.teal index 8f2803270..33a5fb36c 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint64,uint32,uint16)_v8.teal @@ -47,7 +47,6 @@ itob extract 6 0 concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -66,7 +65,6 @@ concat load 6 concat frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -77,7 +75,6 @@ int 18446744073709551615 frame_dig -1 - frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -92,7 +89,6 @@ frame_dig 0 int 4294967296 < assert -frame_dig 0 retsub // numerical_comp @@ -107,5 +103,4 @@ frame_dig 0 int 65536 < assert -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint8)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint8)_v8.teal index 58b13c2a9..4a8d567ff 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint8)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint8)_v8.teal @@ -27,7 +27,6 @@ int 0 load 0 setbyte frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -46,7 +45,6 @@ concat load 4 concat frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -61,5 +59,4 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v8.teal index dedc08a8d..853a8b269 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_(uint8,byte,bool)_v8.teal @@ -51,7 +51,6 @@ load 2 setbit concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -70,7 +69,6 @@ concat load 6 concat frame_bury 0 -frame_dig 0 retsub // numerical_comp @@ -85,7 +83,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // numerical_comp @@ -100,7 +97,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // bool_comp @@ -112,5 +108,4 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_address[]_10_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_address[]_10_v8.teal index 05dff5111..d58d71f84 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_address[]_10_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_address[]_10_v8.teal @@ -23,7 +23,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // array_complement @@ -478,7 +477,6 @@ load 50 setbyte concat frame_bury 0 -frame_dig 0 retsub // array_complement @@ -631,7 +629,6 @@ load 17 concat concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -698,5 +695,4 @@ concat load 6 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_address_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_address_v8.teal index f71989611..0ebe72b72 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_address_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_address_v8.teal @@ -23,7 +23,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // array_complement @@ -478,7 +477,6 @@ load 35 setbyte concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -497,5 +495,4 @@ concat load 3 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[1]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[1]_v8.teal index 3acd9d712..3458bde41 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool[1]_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[1]_v8.teal @@ -20,7 +20,6 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub // array_complement @@ -39,7 +38,6 @@ int 0 load 4 setbit frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -58,5 +56,4 @@ concat load 3 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11_v8.teal index 2fc9c7774..64bd1f049 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[3][]_11_v8.teal @@ -20,7 +20,6 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub // array_complement @@ -59,7 +58,6 @@ int 2 load 22 setbit frame_bury 0 -frame_dig 0 retsub // array_complement @@ -226,7 +224,6 @@ load 18 concat concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -293,5 +290,4 @@ concat load 6 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[42]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[42]_v8.teal index 5787f99f9..a215df488 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool[42]_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[42]_v8.teal @@ -20,7 +20,6 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub // array_complement @@ -449,7 +448,6 @@ int 41 load 45 setbit frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -468,5 +466,4 @@ concat load 3 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_0_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_0_v8.teal index 89f595322..87f935c92 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_0_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_0_v8.teal @@ -23,7 +23,6 @@ extract 6 0 byte "" concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -90,5 +89,4 @@ concat load 6 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_1_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_1_v8.teal index 61a4806b2..9b403483f 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_1_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_1_v8.teal @@ -20,7 +20,6 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub // array_complement @@ -47,7 +46,6 @@ load 8 setbit concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -114,5 +112,4 @@ concat load 6 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_42_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_42_v8.teal index 56931159c..a2a6821c4 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool[]_42_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool[]_42_v8.teal @@ -20,7 +20,6 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub // array_complement @@ -539,7 +538,6 @@ load 49 setbit concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -606,5 +604,4 @@ concat load 6 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_bool_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_bool_v8.teal index 23e0c659a..5e08ac3d2 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_bool_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_bool_v8.teal @@ -24,7 +24,6 @@ frame_dig -1 ! ! frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -48,5 +47,4 @@ int 2 load 3 setbit frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_byte[16]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_byte[16]_v8.teal index a8ca32f63..86fa73f5a 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_byte[16]_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_byte[16]_v8.teal @@ -23,7 +23,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // array_complement @@ -254,7 +253,6 @@ load 19 setbyte concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -273,5 +271,4 @@ concat load 3 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_byte[]_36_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_byte[]_36_v8.teal index 7aa6b4aad..3b92e3e84 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_byte[]_36_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_byte[]_36_v8.teal @@ -23,7 +23,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // array_complement @@ -612,7 +611,6 @@ setbyte concat concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -679,5 +677,4 @@ concat load 6 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_byte_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_byte_v8.teal index 91cc0024a..c7dfcc09f 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_byte_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_byte_v8.teal @@ -25,7 +25,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // round_tripper @@ -53,5 +52,4 @@ load 3 setbyte concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_string_0_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_string_0_v8.teal index c0d9a212c..f6742b7c1 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_string_0_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_string_0_v8.teal @@ -23,7 +23,6 @@ extract 6 0 byte "" concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -90,5 +89,4 @@ concat load 6 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_string_13_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_string_13_v8.teal index 742afe0a0..4e608a404 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_string_13_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_string_13_v8.teal @@ -190,7 +190,6 @@ setbyte concat concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -257,5 +256,4 @@ concat load 6 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_string_1_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_string_1_v8.teal index 3e6f669d6..8a72badb8 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_string_1_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_string_1_v8.teal @@ -34,7 +34,6 @@ load 8 setbyte concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -101,5 +100,4 @@ concat load 6 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint16_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint16_v8.teal index 700f8bead..2baecd50a 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint16_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint16_v8.teal @@ -25,7 +25,6 @@ frame_dig 0 int 65536 < assert -frame_dig 0 retsub // round_tripper @@ -50,5 +49,4 @@ itob extract 6 0 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint32_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint32_v8.teal index 00be1ca95..d495dae9d 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint32_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint32_v8.teal @@ -25,7 +25,6 @@ frame_dig 0 int 4294967296 < assert -frame_dig 0 retsub // round_tripper @@ -50,5 +49,4 @@ itob extract 4 0 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[1]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[1]_v8.teal index 6aa863ad2..48d881ec6 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint64[1]_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[1]_v8.teal @@ -19,7 +19,6 @@ int 18446744073709551615 frame_dig -1 - frame_bury 0 -frame_dig 0 retsub // array_complement @@ -38,7 +37,6 @@ store 4 load 4 itob frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -57,5 +55,4 @@ concat load 3 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[42]_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[42]_v8.teal index b995008af..9126983f1 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint64[42]_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[42]_v8.teal @@ -19,7 +19,6 @@ int 18446744073709551615 frame_dig -1 - frame_bury 0 -frame_dig 0 retsub // array_complement @@ -530,7 +529,6 @@ load 45 itob concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -549,5 +547,4 @@ concat load 3 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0_v8.teal index 89f595322..87f935c92 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_0_v8.teal @@ -23,7 +23,6 @@ extract 6 0 byte "" concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -90,5 +89,4 @@ concat load 6 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1_v8.teal index ce54ebdb6..fb4caf8bd 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_1_v8.teal @@ -19,7 +19,6 @@ int 18446744073709551615 frame_dig -1 - frame_bury 0 -frame_dig 0 retsub // array_complement @@ -46,7 +45,6 @@ load 8 itob concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -113,5 +111,4 @@ concat load 6 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42_v8.teal index 24dd3f3ff..cf61ff80f 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64[]_42_v8.teal @@ -19,7 +19,6 @@ int 18446744073709551615 frame_dig -1 - frame_bury 0 -frame_dig 0 retsub // array_complement @@ -620,7 +619,6 @@ itob concat concat frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -687,5 +685,4 @@ concat load 6 concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint64_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint64_v8.teal index 165bcb347..ce11171f2 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint64_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint64_v8.teal @@ -20,7 +20,6 @@ int 18446744073709551615 frame_dig -1 - frame_bury 0 -frame_dig 0 retsub // round_tripper @@ -42,5 +41,4 @@ load 3 itob concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file diff --git a/tests/integration/teal/roundtrip/app_roundtrip_uint8_v8.teal b/tests/integration/teal/roundtrip/app_roundtrip_uint8_v8.teal index 91cc0024a..c7dfcc09f 100644 --- a/tests/integration/teal/roundtrip/app_roundtrip_uint8_v8.teal +++ b/tests/integration/teal/roundtrip/app_roundtrip_uint8_v8.teal @@ -25,7 +25,6 @@ frame_dig 0 int 256 < assert -frame_dig 0 retsub // round_tripper @@ -53,5 +52,4 @@ load 3 setbyte concat frame_bury 0 -frame_dig 0 retsub \ No newline at end of file From 431026b7b35401c4fa021a123150cca0c513acf9 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Tue, 8 Nov 2022 17:27:55 -0500 Subject: [PATCH 097/206] use deferred only on scratch slot, comments --- pyteal/ast/subroutine.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 0b5f03337..d4a890f26 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -1045,7 +1045,8 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: deferred_expr: Optional[Expr] = None - # if there is an output keyword argument for ABI, place the storing on the stack + # if there is an output keyword argument for ABI + # place the storing on the stack with deferred expr only when compile to scratch var if output_carrying_abi: if subroutine_body.type_of() != TealType.none: raise TealInputError( From 66a6416a06cc89b1abed278a35ef4855a9c6a1d9 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 9 Nov 2022 21:18:40 -0500 Subject: [PATCH 098/206] spellings --- pyteal/ast/frame.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 8fd972981..32436345c 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -62,7 +62,7 @@ def type_of(self) -> TealType: class ProtoStackLayout(Expr): - """An expression that carrys arg types and local types for a subroutine. + """An expression that carries arg types and local types for a subroutine. This class is intentionally hidden because it's too basic to directly expose. This is only used in Proto internally. @@ -128,7 +128,7 @@ class Proto(Expr): """An expression that prepare top call frame for a retsub that will assume A args and R return values. This class is intentionally hidden because it's too basic to directly expose. - It is only used in subroutine, for subrouine declaration computation. + It is only used in subroutine, for subroutine declaration computation. """ def __init__( @@ -225,7 +225,7 @@ def has_return(self) -> bool: class FrameBury(Expr): - """An expression that burys a value to a position around frame pointer. + """An expression that buries a value to a position around frame pointer. This class is intentionally hidden because it's too basic to directly expose. his is used only internally by FrameVar. From 3bd25faab68b312b0d26a47b6136a67b6a60069e Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 9 Nov 2022 21:23:23 -0500 Subject: [PATCH 099/206] remove unused class methods --- pyteal/ast/abi/type.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index 4afef8a70..c686b705c 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -80,12 +80,6 @@ def __init__(self, spec: TypeSpec) -> None: self._type_spec: Final[TypeSpec] = spec self._stored_value: AbstractVar = ScratchVar(spec.storage_type()) - def _load_value(self) -> Expr: - return self._stored_value.load() - - def _store_value(self, value: Expr) -> Expr: - return self._stored_value.store(value) - def type_spec(self) -> TypeSpec: """Get the TypeSpec for this ABI type instance.""" return self._type_spec From 39f6f6b7e94e099d70243d0cf30e6a50cda3da76 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 9 Nov 2022 21:37:52 -0500 Subject: [PATCH 100/206] remove scratchvar type check in var_n_load --- pyteal/ast/subroutine.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index f3bf83a2c..0a3f200d3 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -9,7 +9,7 @@ from pyteal.ast.expr import Expr from pyteal.ast.seq import Seq from pyteal.ast.scratchvar import DynamicScratchVar, ScratchVar -from pyteal.errors import TealInputError, TealInternalError, verifyProgramVersion +from pyteal.errors import TealInputError, verifyProgramVersion from pyteal.ir import TealOp, Op, TealBlock from pyteal.types import TealType @@ -799,11 +799,7 @@ def var_n_loaded( loaded_var = argument_var elif param in subroutine.abi_args: internal_abi_var = subroutine.abi_args[param].new_instance() - if not isinstance(internal_abi_var._stored_value, ScratchVar): - raise TealInternalError( - "subroutine ABI args must have data schema being ScratchVarStorage" - ) - argument_var = internal_abi_var._stored_value + argument_var = cast(ScratchVar, internal_abi_var._stored_value) loaded_var = internal_abi_var else: argument_var = ScratchVar(TealType.anytype) From bb8f9e560758e9057ff20c6d004f2c65fe6d49c4 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 9 Nov 2022 22:08:51 -0500 Subject: [PATCH 101/206] docstring explanation of validate type --- pyteal/ast/abi/type.py | 2 +- pyteal/ast/abstractvar.py | 21 ++++++++++++++++++++- pyteal/ast/scratchvar.py | 4 ++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index c686b705c..75760015d 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -248,7 +248,7 @@ def store_into(self, output: BaseType) -> Expr: validate_in_store = False return output._stored_value.store( - self.computation, validate_types=validate_in_store + self.computation, validate_type=validate_in_store ) diff --git a/pyteal/ast/abstractvar.py b/pyteal/ast/abstractvar.py index 956d4735f..2c4a6d2df 100644 --- a/pyteal/ast/abstractvar.py +++ b/pyteal/ast/abstractvar.py @@ -19,11 +19,30 @@ class AbstractVar(ABC): """ @abstractmethod - def store(self, value: Expr, validate_types: bool = True) -> Expr: + def store(self, value: Expr, validate_type: bool = True) -> Expr: + """Store value in AbstractVar. + + In most cases, we validate the type of the value to store against the type of the :any:`AbstractVar`. + The *only* case we skip type validation is: + we store a :any:`ReturnValue` of an :code:`ABIReturnSubroutine` into an :any:`AbstractVar`. + An :any:`ABIReturnSubroutine` evaluates to :code:`TealType.none`, + while an :any:`AbstractVar` has any concrete type other than :code:`TealType.none`. + A direct type check against :any:`ABIReturnSubroutine` will incur a type error, + while we apply type check against output keyword argument of :any:`ABIReturnSubroutine`, + which is applied and enforced inside of :any:`ReturnedValue`. + + In short, in most scenarios, it is not recommended to let validate_type to be False, + unless one is very clear about the expected behavior. + + Args: + value: An expression that represents the value to store. + validate_type: A bool variable that activate type check in value storage. + """ pass @abstractmethod def load(self) -> Expr: + """Load value from AbstractVar""" pass @abstractmethod diff --git a/pyteal/ast/scratchvar.py b/pyteal/ast/scratchvar.py index 29a938e33..971b717b0 100644 --- a/pyteal/ast/scratchvar.py +++ b/pyteal/ast/scratchvar.py @@ -37,13 +37,13 @@ def storage_type(self) -> TealType: """Get the type of expressions that can be stored in this ScratchVar.""" return self.type - def store(self, value: Expr, validate_types: bool = True) -> Expr: + def store(self, value: Expr, validate_type: bool = True) -> Expr: """Store value in Scratch Space Args: value: The value to store. Must conform to this ScratchVar's type. """ - if validate_types: + if validate_type: require_type(value, self.type) return self.slot.store(value) From 411c57020e34c641c68494ffef08e9a3ba279936 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Wed, 9 Nov 2022 22:33:21 -0500 Subject: [PATCH 102/206] docstring --- pyteal/ast/frame.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 32436345c..a44711259 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -64,6 +64,9 @@ def type_of(self) -> TealType: class ProtoStackLayout(Expr): """An expression that carries arg types and local types for a subroutine. + Proto return value is placed on frame index 0 against frame pointer, + and return type is included in local_stack_types, which is the first element. + This class is intentionally hidden because it's too basic to directly expose. This is only used in Proto internally. """ @@ -127,6 +130,8 @@ def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBloc class Proto(Expr): """An expression that prepare top call frame for a retsub that will assume A args and R return values. + Proto return value is placed from frame index 0 against frame pointer. + This class is intentionally hidden because it's too basic to directly expose. It is only used in subroutine, for subroutine declaration computation. """ From daf877d8ac5a62f38755d811917d2d0be5fffb16 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Thu, 10 Nov 2022 11:21:17 -0500 Subject: [PATCH 103/206] docstring --- pyteal/ast/abstractvar.py | 4 ++-- pyteal/ast/scratchvar.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pyteal/ast/abstractvar.py b/pyteal/ast/abstractvar.py index 2c4a6d2df..1d3220f11 100644 --- a/pyteal/ast/abstractvar.py +++ b/pyteal/ast/abstractvar.py @@ -29,9 +29,9 @@ def store(self, value: Expr, validate_type: bool = True) -> Expr: while an :any:`AbstractVar` has any concrete type other than :code:`TealType.none`. A direct type check against :any:`ABIReturnSubroutine` will incur a type error, while we apply type check against output keyword argument of :any:`ABIReturnSubroutine`, - which is applied and enforced inside of :any:`ReturnedValue`. + which is applied and enforced inside :any:`ReturnedValue`. - In short, in most scenarios, it is not recommended to let validate_type to be False, + In short, in most scenarios, we do not recommended to let validate_type to be False, unless one is very clear about the expected behavior. Args: diff --git a/pyteal/ast/scratchvar.py b/pyteal/ast/scratchvar.py index 971b717b0..79a5258e9 100644 --- a/pyteal/ast/scratchvar.py +++ b/pyteal/ast/scratchvar.py @@ -42,6 +42,7 @@ def store(self, value: Expr, validate_type: bool = True) -> Expr: Args: value: The value to store. Must conform to this ScratchVar's type. + validate_type: A bool variable that activate type check in value storage. """ if validate_type: require_type(value, self.type) From d8b5eb6b18ed4cdfc48f8ceec2f7da1d67591242 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Thu, 10 Nov 2022 14:55:50 -0500 Subject: [PATCH 104/206] collect changes to basis pr --- pyteal/ast/frame.py | 8 ++++---- pyteal/ast/scratchvar.py | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index a44711259..9145b55b7 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -241,12 +241,12 @@ def __init__( value: Expr, frame_index: int, *, - validate_types: bool = True, + validate_type: bool = True, inferred_type: Optional[TealType] = None, ): super().__init__() - if validate_types: + if validate_type: target_type = inferred_type if inferred_type else TealType.anytype require_type(value, target_type) @@ -297,11 +297,11 @@ def __init__(self, under_proto: Proto, frame_index: int) -> None: def storage_type(self) -> TealType: return self.stack_type - def store(self, value: Expr, validate_types: bool = True) -> Expr: + def store(self, value: Expr, validate_type: bool = True) -> Expr: return FrameBury( value, self.frame_index, - validate_types=validate_types, + validate_type=validate_type, inferred_type=self.stack_type, ) diff --git a/pyteal/ast/scratchvar.py b/pyteal/ast/scratchvar.py index 79a5258e9..c5a6bf9be 100644 --- a/pyteal/ast/scratchvar.py +++ b/pyteal/ast/scratchvar.py @@ -118,11 +118,11 @@ def storage_type(self) -> TealType: """Get the type of expressions that can be stored in this ScratchVar.""" return self.dynamic_type - def store(self, value: Expr, validate_types: bool = True) -> Expr: + def store(self, value: Expr, validate_type: bool = True) -> Expr: """Store the value in the referenced ScratchVar.""" - if not validate_types: + if not validate_type: raise TealInternalError( - f"DynamicScratchVar's must validate_types but {validate_types=}" + f"DynamicScratchVar's must validate_type but {validate_type=}" ) require_type(value, self.dynamic_type) From 935cc0c373279b78fff073f77757d21abde9016d Mon Sep 17 00:00:00 2001 From: Hang Su Date: Thu, 10 Nov 2022 15:00:33 -0500 Subject: [PATCH 105/206] wording check --- pyteal/ast/abstractvar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyteal/ast/abstractvar.py b/pyteal/ast/abstractvar.py index 1d3220f11..962e0366e 100644 --- a/pyteal/ast/abstractvar.py +++ b/pyteal/ast/abstractvar.py @@ -6,7 +6,7 @@ class AbstractVar(ABC): """AbstractVar is an abstract class that captures properties of a variable. - A variable, on an abstract perspective, has following properties: + A variable, on an abstract perspective, has the following properties: * Storing: can be stored to a certain position. * Loading: can be loaded from a certain position. From fe3b60dc139c54850f21ab00ee6dd56378f895ea Mon Sep 17 00:00:00 2001 From: Hang Su Date: Sun, 13 Nov 2022 03:21:39 -0500 Subject: [PATCH 106/206] good find on one more dupped stuff --- pyteal/ast/frame.py | 4 +++- pyteal/ast/frame_test.py | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index 9145b55b7..dc6a0c5f4 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -45,7 +45,9 @@ def __teal__(self, options: "CompileOptions") -> tuple[TealBlock, TealSimpleBloc inst_srt, inst_end = self.auto_instance.__teal__(options) return inst_srt, inst_end else: - dupn_srt, dupn_end = DupN(self.auto_instance, self.count).__teal__(options) + dupn_srt, dupn_end = DupN(self.auto_instance, self.count - 1).__teal__( + options + ) return dupn_srt, dupn_end def __str__(self) -> str: diff --git a/pyteal/ast/frame_test.py b/pyteal/ast/frame_test.py index 3f62ca35b..b5fd1e183 100644 --- a/pyteal/ast/frame_test.py +++ b/pyteal/ast/frame_test.py @@ -150,7 +150,7 @@ class LocalTypeSegmentTestCase: pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.int, 0), - pt.TealOp(None, pt.Op.dupn, 5), + pt.TealOp(None, pt.Op.dupn, 4), ] ), ), @@ -163,7 +163,7 @@ class LocalTypeSegmentTestCase: pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.int, 0), - pt.TealOp(None, pt.Op.dupn, 5), + pt.TealOp(None, pt.Op.dupn, 4), ] ), ), @@ -176,7 +176,7 @@ class LocalTypeSegmentTestCase: pt.TealSimpleBlock( [ pt.TealOp(None, pt.Op.byte, '""'), - pt.TealOp(None, pt.Op.dupn, 5), + pt.TealOp(None, pt.Op.dupn, 4), ] ), ), From 55a838a6bccb2ab3a3a726d5cc6c592941bed6c9 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Mon, 14 Nov 2022 12:13:21 -0500 Subject: [PATCH 107/206] per Zeph's PR comments --- pyteal/ast/subroutine.py | 146 +++-------------------------- pyteal/ast/subroutine_test.py | 9 +- tests/abi_roundtrip.py | 7 -- tests/integration/graviton_test.py | 12 +-- 4 files changed, 27 insertions(+), 147 deletions(-) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 312df87e7..ce1d5e129 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -39,7 +39,6 @@ def __init__(self, subroutine_def: "SubroutineDefinition") -> None: self.type_of: Optional[TealType] = None def get_declaration(self) -> "SubroutineDeclaration": - # XXX MARK THIS METHOD TO BE DEPRECATED LATER I GUESS return self.get_declaration_by_version(Op.callsub.min_version) def get_declaration_by_version(self, version: int) -> "SubroutineDeclaration": @@ -337,7 +336,6 @@ def _validate_annotation( ) def get_declaration(self) -> "SubroutineDeclaration": - # XXX MARK THIS METHOD TO BE DEPRECATED LATER I GUESS return self.declarations.get_declaration() def get_declaration_by_version(self, version: int) -> "SubroutineDeclaration": @@ -896,31 +894,30 @@ class SubroutineEval: -------------- --- ------------ ----- ------- - ----------------------- Usage (A) "argumentVars" - Storing pre-placed stack variables with frame pointer: - Type 1. (by-value) use None for we can load from stack with FrameDig() - Type 2. (by-reference) ALSO use FrameDig to pick up from the stack + Type 1. (by-value) use None for we can load from stack with FrameDig() from FrameVar abstraction + Type 2. (by-reference) ALSO use FrameDig() from FrameVar abstraction to pick up from the stack NOTE: SubroutineCall.__teal__() has placed the _SLOT INDEX_ on the stack so this is stored into the local scratch space - Type 3. (ABI) use None for we can load from stack with FrameDig() + Type 3. (ABI) use None for we can load from stack with FrameDig() from FrameVar abstraction NOTE: SubroutineCall.__teal__() has placed the ABI encoding on the stack, so ABI set and get methods are working over stack Type 4. (ABI-output-arg) it is not really used here, but we use FrameDig/Bury to interact with it - TODO need to repolish later after merge and rebase Usage (B) "loadedArgs" - Passing through to an invoked PyTEAL subroutine AST: - Type 1. (by-value) use FrameDig() to have an Expr that can be compiled in python by the PyTEAL subroutine + Type 1. (by-value) use FrameDig() from FrameVar absrraction, to have an Expr that can be compiled in python by the PyTEAL subroutine. Type 2. (by-reference) use a DynamicScratchVar as the user will have written the PyTEAL in a way that satisfies the ScratchVar API. I.e., the user will write `x.load()` and `x.store(val)` as opposed to just `x`. - Type 3. (ABI) use abi_value that interface with stack data through FrameDig/FrameBury - Type 4. (ABI-output-arg) generates a new instance of the ABI value, - and appends a return expression of stored value of the ABI keyword value. + Type 3. (ABI) use abi_value that interface with stack data through FrameVar abstraction. + Type 4. (ABI-output-arg) Prepare a FrameVar over the stack with frame-index 0 against current frame pointer, + and set the ABI value's _stored_value to be using FrameVar. """ - var_n_loaded: Callable[ + var_n_loaded_method: Callable[ [SubroutineDefinition, str, Optional[Proto]], tuple[Optional[ScratchVar], ScratchVar | abi.BaseType | Expr], ] use_frame_pt: bool = False @staticmethod - def __var_n_loaded( + def var_n_loaded_scratch( subroutine: SubroutineDefinition, param: str, _: Optional[Proto] = None, @@ -946,7 +943,7 @@ def __var_n_loaded( return argument_var, loaded_var @staticmethod - def __var_n_loaded_fp( + def var_n_loaded_fp( subroutine: SubroutineDefinition, param: str, proto: Optional[Proto], @@ -1021,7 +1018,7 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: arg_vars: list[ScratchVar] = [] loaded_args: list[ScratchVar | Expr | abi.BaseType] = [] for arg in args: - arg_var, loaded_arg = self.var_n_loaded(subroutine, arg, proto) + arg_var, loaded_arg = self.var_n_loaded_method(subroutine, arg, proto) if arg_var: arg_vars.append(arg_var) loaded_args.append(loaded_arg) @@ -1068,128 +1065,11 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: @classmethod def normal_evaluator(cls) -> "SubroutineEval": - return cls(SubroutineEval.__var_n_loaded, False) + return cls(SubroutineEval.var_n_loaded_scratch, False) @classmethod def fp_evaluator(cls) -> "SubroutineEval": - return cls(SubroutineEval.__var_n_loaded_fp, True) + return cls(SubroutineEval.var_n_loaded_fp, True) SubroutineEval.__module__ = "pyteal" - - -def evaluate_subroutine(subroutine: SubroutineDefinition) -> SubroutineDeclaration: - """ - NOTE: THIS METHOD IS DEPRECATED, USE CLASS `SubroutineEval` INSTEAD FOR SUBROUTINE EVALUATOR - - Puts together the data necessary to define the code for a subroutine. - "evaluate" is used here to connote evaluating the PyTEAL AST into a SubroutineDeclaration, - but not actually placing it at call locations. The trickiest part here is managing the subroutine's arguments. - The arguments are needed for two different code-paths, and there are 2 different argument types to consider - for each of the code-paths: - - 2 Argument Usages / Code-Paths - - -------- ------ ---------- - Usage (A) for run-time: "argumentVars" --reverse--> "body_ops" - These are "store" expressions that pick up parameters that have been pre-placed on the stack prior to subroutine invocation. - The argumentVars are stored into local scratch space to be used by the TEAL subroutine. - - Usage (B) for compile-time: "loadedArgs" - These are expressions supplied to the user-defined PyTEAL function. - The loadedArgs are invoked to by the subroutine to create a self-contained AST which will translate into a TEAL subroutine. - - In both usage cases, we need to handle - - 2 Argument Types - - -------- ----- - Type 1 (by-value): these have python type Expr - Type 2 (by-reference): these have python type ScratchVar - Type 3 (ABI): these are ABI typed variables with scratch space storage, and still pass by value - Type 4 (ABI-output-arg): ABI typed variables with scratch space, a new ABI instance is generated inside function body, - not one of the cases in the previous three options - - Usage (A) "argumentVars" - Storing pre-placed stack variables into local scratch space: - Type 1. (by-value) use ScratchVar.store() to pick the actual value into a local scratch space - Type 2. (by-reference) ALSO use ScratchVar.store() to pick up from the stack - NOTE: SubroutineCall.__teal__() has placed the _SLOT INDEX_ on the stack so this is stored into the local scratch space - Type 3. (ABI) abi_value.stored_value.store() to pick from the stack - Type 4. (ABI-output-arg) it is not really used here, since it is only generated internal of the subroutine - - Usage (B) "loadedArgs" - Passing through to an invoked PyTEAL subroutine AST: - Type 1. (by-value) use ScratchVar.load() to have an Expr that can be compiled in python by the PyTEAL subroutine - Type 2. (by-reference) use a DynamicScratchVar as the user will have written the PyTEAL in a way that satisfies - the ScratchVar API. I.e., the user will write `x.load()` and `x.store(val)` as opposed to just `x`. - Type 3. (ABI) use abi_value itself after storing stack value into scratch space. - Type 4. (ABI-output-arg) generates a new instance of the ABI value, - and appends a return expression of stored value of the ABI keyword value. - """ - - def var_n_loaded( - param: str, - ) -> tuple[ScratchVar, ScratchVar | abi.BaseType | Expr]: - loaded_var: ScratchVar | abi.BaseType | Expr - argument_var: ScratchVar - - if param in subroutine.by_ref_args: - argument_var = DynamicScratchVar(TealType.anytype) - loaded_var = argument_var - elif param in subroutine.abi_args: - internal_abi_var = subroutine.abi_args[param].new_instance() - argument_var = cast(ScratchVar, internal_abi_var._stored_value) - loaded_var = internal_abi_var - else: - argument_var = ScratchVar(TealType.anytype) - loaded_var = argument_var.load() - - return argument_var, loaded_var - - if len(subroutine.output_kwarg) > 1: - raise TealInputError( - f"ABI keyword argument num: {len(subroutine.output_kwarg)}. " - f"Exceeding abi output keyword argument max number 1." - ) - - args = subroutine.arguments() - - arg_vars: list[ScratchVar] = [] - loaded_args: list[ScratchVar | Expr | abi.BaseType] = [] - for arg in args: - arg_var, loaded_arg = var_n_loaded(arg) - arg_vars.append(arg_var) - loaded_args.append(loaded_arg) - - abi_output_kwargs: dict[str, abi.BaseType] = {} - output_kwarg_info = OutputKwArgInfo.from_dict(subroutine.output_kwarg) - output_carrying_abi: Optional[abi.BaseType] = None - - if output_kwarg_info: - output_carrying_abi = output_kwarg_info.abi_type.new_instance() - abi_output_kwargs[output_kwarg_info.name] = output_carrying_abi - - # Arg usage "B" supplied to build an AST from the user-defined PyTEAL function: - subroutine_body = subroutine.implementation(*loaded_args, **abi_output_kwargs) - - if not isinstance(subroutine_body, Expr): - raise TealInputError( - f"Subroutine function does not return a PyTeal expression. Got type {type(subroutine_body)}." - ) - - deferred_expr: Optional[Expr] = None - - # if there is an output keyword argument for ABI, place the storing on the stack - if output_carrying_abi: - if subroutine_body.type_of() != TealType.none: - raise TealInputError( - f"ABI returning subroutine definition should evaluate to TealType.none, " - f"while evaluate to {subroutine_body.type_of()}." - ) - deferred_expr = output_carrying_abi._stored_value.load() - - # Arg usage "A" to be pick up and store in scratch parameters that have been placed on the stack - # need to reverse order of argumentVars because the last argument will be on top of the stack - body_ops = [var.slot.store() for var in arg_vars[::-1]] - body_ops.append(subroutine_body) - - sd = SubroutineDeclaration(subroutine, Seq(body_ops), deferred_expr) - sd.trace = subroutine_body.trace - return sd diff --git a/pyteal/ast/subroutine_test.py b/pyteal/ast/subroutine_test.py index c7b7df03a..935657105 100644 --- a/pyteal/ast/subroutine_test.py +++ b/pyteal/ast/subroutine_test.py @@ -5,7 +5,7 @@ from dataclasses import dataclass import pyteal as pt -from pyteal.ast.subroutine import ABIReturnSubroutine, evaluate_subroutine +from pyteal.ast.subroutine import ABIReturnSubroutine, SubroutineEval options = pt.CompileOptions(version=5) @@ -1153,6 +1153,8 @@ def mySubroutine(): return returnValue definition = pt.SubroutineDefinition(mySubroutine, returnType) + evaluate_subroutine = SubroutineEval.normal_evaluator() + declaration = evaluate_subroutine(definition) assert isinstance(declaration, pt.SubroutineDeclaration) @@ -1187,6 +1189,8 @@ def mySubroutine(a1): return returnValue definition = pt.SubroutineDefinition(mySubroutine, returnType) + + evaluate_subroutine = SubroutineEval.normal_evaluator() declaration = evaluate_subroutine(definition) assert isinstance(declaration, pt.SubroutineDeclaration) @@ -1231,6 +1235,7 @@ def mySubroutine(a1, a2): definition = pt.SubroutineDefinition(mySubroutine, returnType) + evaluate_subroutine = SubroutineEval.normal_evaluator() declaration = evaluate_subroutine(definition) assert isinstance(declaration, pt.SubroutineDeclaration) @@ -1277,6 +1282,8 @@ def mySubroutine(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10): return returnValue definition = pt.SubroutineDefinition(mySubroutine, returnType) + + evaluate_subroutine = SubroutineEval.normal_evaluator() declaration = evaluate_subroutine(definition) assert isinstance(declaration, pt.SubroutineDeclaration) diff --git a/tests/abi_roundtrip.py b/tests/abi_roundtrip.py index ba0f4d8c0..5a2f624dc 100644 --- a/tests/abi_roundtrip.py +++ b/tests/abi_roundtrip.py @@ -128,13 +128,6 @@ def array_comp_factory(self) -> pt.ABIReturnSubroutine: elif self.length is None: self.length = 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() diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index 8dd141180..d49332214 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -579,13 +579,13 @@ def square(x): x = 9 args = [x] - def evaluate_and_check(_version: int): + def evaluate_and_check(version: int): # evaluate the programs app_result = PyTealDryRunExecutor(square, Mode.Application).dryrun( - args, compiler_version=_version + args, compiler_version=version ) lsig_result = PyTealDryRunExecutor(square, Mode.Signature).dryrun( - args, compiler_version=_version + args, compiler_version=version ) # check to see that x^2 is at the top of the stack as expected @@ -651,10 +651,10 @@ def euclid(x, y): ) ) - def test_and_report(_verison: int): + def test_and_report(version: int): # assert that each result is that same as what Python's math.gcd() computes inspectors = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_on_sequence( - inputs, compiler_version=_verison + inputs, compiler_version=version ) for i, result in enumerate(inspectors): args = inputs[i] @@ -664,7 +664,7 @@ def test_and_report(_verison: int): # save the CSV to ...current working directory.../euclid_v{version}.csv euclid_csv = DryRunInspector.csv_report(inputs, inspectors) - with open(Path.cwd() / f"euclid_v{_verison}.csv", "w") as f: + with open(Path.cwd() / f"euclid_v{version}.csv", "w") as f: f.write(euclid_csv) test_and_report(6) From f1de3ec553d3133f2556a4ce2aa7d5e76111d852 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Mon, 14 Nov 2022 12:35:13 -0500 Subject: [PATCH 108/206] no overshadowing version param --- tests/integration/abi_roundtrip_test.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/integration/abi_roundtrip_test.py b/tests/integration/abi_roundtrip_test.py index ef611f385..fee247b78 100644 --- a/tests/integration/abi_roundtrip_test.py +++ b/tests/integration/abi_roundtrip_test.py @@ -209,13 +209,13 @@ def test_pure_compilation(abi_type): assert [sdk_abi_type] == abi_arg_types assert algosdk.abi.TupleType([sdk_abi_type] * 3) == abi_ret_type - def compile_and_compare(_version: int): - teal = roundtripper.compile(_version) + def compile_and_compare(version: int): + teal = roundtripper.compile(version) filename = ( f"app_roundtrip_{sdk_abi_type}" + ("" if dynamic_length is None else f"_{dynamic_length}") - + f"_v{_version}.teal" + + f"_v{version}.teal" ) tealdir = GENERATED / "roundtrip" tealdir.mkdir(parents=True, exist_ok=True) @@ -256,8 +256,8 @@ def test_roundtrip(abi_type): rand_abi_instance = abi_strat.get_random() args = (rand_abi_instance,) - def dryrun_roundtrip(_version: int): - inspector = roundtripper.dryrun(args, compiler_version=_version) + def dryrun_roundtrip(version: int): + inspector = roundtripper.dryrun(args, compiler_version=version) cost = inspector.cost() passed = inspector.passed() @@ -265,7 +265,7 @@ def dryrun_roundtrip(_version: int): print( f""" -version={_version} +version={version} {abi_type=} {sdk_abi_str=} {dynamic_length=} From 5cf0cf5077ff4785f18b86db1cc36f31227b5543 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Mon, 14 Nov 2022 17:13:03 -0500 Subject: [PATCH 109/206] type_of subroutinecall --- pyteal/ast/abi/type.py | 20 ++------------------ pyteal/ast/abstractvar.py | 3 +-- pyteal/ast/frame.py | 9 +++------ pyteal/ast/subroutine.py | 3 +++ 4 files changed, 9 insertions(+), 26 deletions(-) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index 75760015d..6abed2d80 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -6,7 +6,7 @@ from pyteal.ast.scratchvar import ScratchVar from pyteal.ast.seq import Seq from pyteal.errors import TealInputError -from pyteal.types import TealType, types_match +from pyteal.types import TealType class TypeSpec(ABC): @@ -216,8 +216,6 @@ def produced_type_spec(self) -> TypeSpec: return self.type_spec def store_into(self, output: BaseType) -> Expr: - from pyteal.ast.subroutine import SubroutineCall - if output.type_spec() != self.produced_type_spec(): raise TealInputError( f"expected type_spec {self.produced_type_spec()} but get {output.type_spec()}" @@ -235,21 +233,7 @@ def store_into(self, output: BaseType) -> Expr: f"but has type {declaration.deferred_expr.type_of()}." ) - validate_in_store: bool = True - - if ( - isinstance(self.computation, SubroutineCall) - and self.computation.output_kwarg - ): - assert types_match( - self.computation.output_kwarg.abi_type.storage_type(), - output._stored_value.storage_type(), - ) - validate_in_store = False - - return output._stored_value.store( - self.computation, validate_type=validate_in_store - ) + return output._stored_value.store(self.computation) ReturnedValue.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abstractvar.py b/pyteal/ast/abstractvar.py index 962e0366e..1cc94b517 100644 --- a/pyteal/ast/abstractvar.py +++ b/pyteal/ast/abstractvar.py @@ -19,7 +19,7 @@ class AbstractVar(ABC): """ @abstractmethod - def store(self, value: Expr, validate_type: bool = True) -> Expr: + def store(self, value: Expr) -> Expr: """Store value in AbstractVar. In most cases, we validate the type of the value to store against the type of the :any:`AbstractVar`. @@ -36,7 +36,6 @@ def store(self, value: Expr, validate_type: bool = True) -> Expr: Args: value: An expression that represents the value to store. - validate_type: A bool variable that activate type check in value storage. """ pass diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index dc6a0c5f4..40c32d3cb 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -243,14 +243,12 @@ def __init__( value: Expr, frame_index: int, *, - validate_type: bool = True, inferred_type: Optional[TealType] = None, ): super().__init__() - if validate_type: - target_type = inferred_type if inferred_type else TealType.anytype - require_type(value, target_type) + target_type = inferred_type if inferred_type else TealType.anytype + require_type(value, target_type) self.value = value self.frame_index = frame_index @@ -299,11 +297,10 @@ def __init__(self, under_proto: Proto, frame_index: int) -> None: def storage_type(self) -> TealType: return self.stack_type - def store(self, value: Expr, validate_type: bool = True) -> Expr: + def store(self, value: Expr) -> Expr: return FrameBury( value, self.frame_index, - validate_type=validate_type, inferred_type=self.stack_type, ) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 0a3f200d3..1695d4547 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -438,6 +438,9 @@ def __str__(self): return f'(SubroutineCall {self.subroutine.name()} ({" ".join(arg_str_list)}))' def type_of(self): + output_info = OutputKwArgInfo.from_dict(self.subroutine.output_kwarg) + if output_info: + return output_info.abi_type.storage_type() return self.subroutine.return_type def has_return(self): From 29be7ff298ebf0ffabf11686beabe67eb528284e Mon Sep 17 00:00:00 2001 From: Hang Su Date: Mon, 14 Nov 2022 17:13:03 -0500 Subject: [PATCH 110/206] type_of subroutinecall --- pyteal/ast/abi/type.py | 20 ++------------------ pyteal/ast/abstractvar.py | 15 +-------------- pyteal/ast/frame.py | 9 +++------ pyteal/ast/subroutine.py | 3 +++ 4 files changed, 9 insertions(+), 38 deletions(-) diff --git a/pyteal/ast/abi/type.py b/pyteal/ast/abi/type.py index 75760015d..6abed2d80 100644 --- a/pyteal/ast/abi/type.py +++ b/pyteal/ast/abi/type.py @@ -6,7 +6,7 @@ from pyteal.ast.scratchvar import ScratchVar from pyteal.ast.seq import Seq from pyteal.errors import TealInputError -from pyteal.types import TealType, types_match +from pyteal.types import TealType class TypeSpec(ABC): @@ -216,8 +216,6 @@ def produced_type_spec(self) -> TypeSpec: return self.type_spec def store_into(self, output: BaseType) -> Expr: - from pyteal.ast.subroutine import SubroutineCall - if output.type_spec() != self.produced_type_spec(): raise TealInputError( f"expected type_spec {self.produced_type_spec()} but get {output.type_spec()}" @@ -235,21 +233,7 @@ def store_into(self, output: BaseType) -> Expr: f"but has type {declaration.deferred_expr.type_of()}." ) - validate_in_store: bool = True - - if ( - isinstance(self.computation, SubroutineCall) - and self.computation.output_kwarg - ): - assert types_match( - self.computation.output_kwarg.abi_type.storage_type(), - output._stored_value.storage_type(), - ) - validate_in_store = False - - return output._stored_value.store( - self.computation, validate_type=validate_in_store - ) + return output._stored_value.store(self.computation) ReturnedValue.__module__ = "pyteal.abi" diff --git a/pyteal/ast/abstractvar.py b/pyteal/ast/abstractvar.py index 962e0366e..0ed9bf9b2 100644 --- a/pyteal/ast/abstractvar.py +++ b/pyteal/ast/abstractvar.py @@ -19,24 +19,11 @@ class AbstractVar(ABC): """ @abstractmethod - def store(self, value: Expr, validate_type: bool = True) -> Expr: + def store(self, value: Expr) -> Expr: """Store value in AbstractVar. - In most cases, we validate the type of the value to store against the type of the :any:`AbstractVar`. - The *only* case we skip type validation is: - we store a :any:`ReturnValue` of an :code:`ABIReturnSubroutine` into an :any:`AbstractVar`. - An :any:`ABIReturnSubroutine` evaluates to :code:`TealType.none`, - while an :any:`AbstractVar` has any concrete type other than :code:`TealType.none`. - A direct type check against :any:`ABIReturnSubroutine` will incur a type error, - while we apply type check against output keyword argument of :any:`ABIReturnSubroutine`, - which is applied and enforced inside :any:`ReturnedValue`. - - In short, in most scenarios, we do not recommended to let validate_type to be False, - unless one is very clear about the expected behavior. - Args: value: An expression that represents the value to store. - validate_type: A bool variable that activate type check in value storage. """ pass diff --git a/pyteal/ast/frame.py b/pyteal/ast/frame.py index dc6a0c5f4..40c32d3cb 100644 --- a/pyteal/ast/frame.py +++ b/pyteal/ast/frame.py @@ -243,14 +243,12 @@ def __init__( value: Expr, frame_index: int, *, - validate_type: bool = True, inferred_type: Optional[TealType] = None, ): super().__init__() - if validate_type: - target_type = inferred_type if inferred_type else TealType.anytype - require_type(value, target_type) + target_type = inferred_type if inferred_type else TealType.anytype + require_type(value, target_type) self.value = value self.frame_index = frame_index @@ -299,11 +297,10 @@ def __init__(self, under_proto: Proto, frame_index: int) -> None: def storage_type(self) -> TealType: return self.stack_type - def store(self, value: Expr, validate_type: bool = True) -> Expr: + def store(self, value: Expr) -> Expr: return FrameBury( value, self.frame_index, - validate_type=validate_type, inferred_type=self.stack_type, ) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 0a3f200d3..1695d4547 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -438,6 +438,9 @@ def __str__(self): return f'(SubroutineCall {self.subroutine.name()} ({" ".join(arg_str_list)}))' def type_of(self): + output_info = OutputKwArgInfo.from_dict(self.subroutine.output_kwarg) + if output_info: + return output_info.abi_type.storage_type() return self.subroutine.return_type def has_return(self): From cd7d52c330136a4b2530160e71ac257cea8b2e82 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Mon, 14 Nov 2022 17:47:14 -0500 Subject: [PATCH 111/206] remove all validate_type --- pyteal/ast/scratchvar.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/pyteal/ast/scratchvar.py b/pyteal/ast/scratchvar.py index c5a6bf9be..a7d8a2dfa 100644 --- a/pyteal/ast/scratchvar.py +++ b/pyteal/ast/scratchvar.py @@ -1,4 +1,4 @@ -from pyteal.errors import TealInputError, TealInternalError +from pyteal.errors import TealInputError from pyteal.types import TealType, require_type from pyteal.ast.abstractvar import AbstractVar @@ -37,15 +37,13 @@ def storage_type(self) -> TealType: """Get the type of expressions that can be stored in this ScratchVar.""" return self.type - def store(self, value: Expr, validate_type: bool = True) -> Expr: + def store(self, value: Expr) -> Expr: """Store value in Scratch Space Args: value: The value to store. Must conform to this ScratchVar's type. - validate_type: A bool variable that activate type check in value storage. """ - if validate_type: - require_type(value, self.type) + require_type(value, self.type) return self.slot.store(value) def load(self) -> ScratchLoad: @@ -118,12 +116,8 @@ def storage_type(self) -> TealType: """Get the type of expressions that can be stored in this ScratchVar.""" return self.dynamic_type - def store(self, value: Expr, validate_type: bool = True) -> Expr: + def store(self, value: Expr) -> Expr: """Store the value in the referenced ScratchVar.""" - if not validate_type: - raise TealInternalError( - f"DynamicScratchVar's must validate_type but {validate_type=}" - ) require_type(value, self.dynamic_type) return ScratchStore(slot=None, value=value, index_expression=self.index()) From dcb90dc3c9021c9903b7074b4d3e6b994667273f Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 14 Nov 2022 19:51:10 -0600 Subject: [PATCH 112/206] Test identical functionality across versions - just a POC and too slow to merge --- requirements.txt | 2 +- tests/integration/graviton_abi_test.py | 58 +++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/requirements.txt b/requirements.txt index 158039a7b..b5e7cf4a9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/algorand/graviton@v0.5.0 +graviton@git+https://github.com/algorand/graviton@f6e9dfa965afd9588bfaf7325afe5f8c8edafae3 mypy==0.950 pytest==7.2.0 pytest-cov==3.0.0 diff --git a/tests/integration/graviton_abi_test.py b/tests/integration/graviton_abi_test.py index 0806ee96e..e178fbfdc 100644 --- a/tests/integration/graviton_abi_test.py +++ b/tests/integration/graviton_abi_test.py @@ -1,7 +1,9 @@ +from itertools import product import random import pytest -from graviton.blackbox import DryRunInspector +from graviton.blackbox import DryRunInspector, DryRunProperty as DRProp +from graviton.invariant import Invariant, PredicateKind as IQ import pyteal as pt from pyteal.ast.subroutine import ABIReturnSubroutine @@ -300,6 +302,10 @@ def conditional_factorial(_factor: pt.abi.Uint64, *, output: pt.abi.Uint64) -> p # ---- integration test functions ---- # +def pynum_to_int65tuple(n): + return (n >= 0, abs(n)) + + @pytest.mark.parametrize("version", [6, 8]) def test_integer65(version: int): bbpt_subtract_slick = PyTealDryRunExecutor(int65_sub, pt.Mode.Application) @@ -312,9 +318,6 @@ def test_integer65(version: int): 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 @@ -323,10 +326,10 @@ def pytuple_to_num(t): random.seed(42) choices = range(-9_999, 10_000) - unary_inputs = [(pynum_to_tuple(x),) for x in random.sample(choices, N)] + unary_inputs = [(pynum_to_int65tuple(x),) for x in random.sample(choices, N)] binary_inputs = [ - (pynum_to_tuple(x), pynum_to_tuple(y)) + (pynum_to_int65tuple(x), pynum_to_int65tuple(y)) for x, y in zip(random.sample(choices, N), random.sample(choices, N)) ] @@ -541,3 +544,46 @@ def test_conditional_factorial(version: int): assert inspector.error(), inspector.report( args, f"FAILED: should error for {n=}", row=n + 1 ) + + +xs = list(map(pynum_to_int65tuple, (-1, 1, 3, 5, 7))) +int65_unary_function_inputs = [(x,) for x in xs] +int65_binary_function_inputs = list(product(xs, xs)) +zs = int65_binary_function_inputs +complex130_unary_function_inputs = [(z,) for z in zs] +complex130_binary_function_inputs = list(product(zs, zs)) +VERSIONING_CASES = [ + (int65_minus_cond, int65_binary_function_inputs), + (int65_sub, int65_binary_function_inputs), + (int65_mult, int65_binary_function_inputs), + (int65_negate, int65_unary_function_inputs), + (int65_add, int65_binary_function_inputs), + (complex130_add, complex130_binary_function_inputs), + (complex130_mult, complex130_binary_function_inputs), + (complex130_real, complex130_unary_function_inputs), + (complex130_imag, complex130_unary_function_inputs), + (complex130_conjugate, complex130_unary_function_inputs), + (complex130_norm_squared, complex130_unary_function_inputs), +] + +IDENTITY_PREDICATES = { + DRProp.lastLog: IQ.IdenticalPair, + DRProp.status: IQ.IdenticalPair, + DRProp.error: IQ.IdenticalPair, + DRProp.lastMessage: IQ.IdenticalPair, +} + +min_version = 5 + + +@pytest.mark.parametrize("subroutine, inputs", VERSIONING_CASES) +@pytest.mark.parametrize("mode", pt.Mode) +@pytest.mark.parametrize("version", range(min_version + 1, pt.MAX_PROGRAM_VERSION + 1)) +def test_identical_functionality(subroutine, inputs, mode, version): + ptdre = PyTealDryRunExecutor(subroutine, mode) + inspectors2 = ptdre.dryrun_on_sequence(inputs, compiler_version=min_version) + inspectorsN = ptdre.dryrun_on_sequence(inputs, compiler_version=version) + + Invariant.full_validation( + IDENTITY_PREDICATES, inspectors=inspectors2, identities=inspectorsN + ) From f3476c56e2e79a365cda425398a1a1574d93f87c Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 14 Nov 2022 19:55:42 -0600 Subject: [PATCH 113/206] bad alias --- tests/integration/graviton_abi_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/integration/graviton_abi_test.py b/tests/integration/graviton_abi_test.py index e178fbfdc..7b33e4b56 100644 --- a/tests/integration/graviton_abi_test.py +++ b/tests/integration/graviton_abi_test.py @@ -3,7 +3,7 @@ import pytest from graviton.blackbox import DryRunInspector, DryRunProperty as DRProp -from graviton.invariant import Invariant, PredicateKind as IQ +from graviton.invariant import Invariant, PredicateKind import pyteal as pt from pyteal.ast.subroutine import ABIReturnSubroutine @@ -567,10 +567,10 @@ def test_conditional_factorial(version: int): ] IDENTITY_PREDICATES = { - DRProp.lastLog: IQ.IdenticalPair, - DRProp.status: IQ.IdenticalPair, - DRProp.error: IQ.IdenticalPair, - DRProp.lastMessage: IQ.IdenticalPair, + DRProp.lastLog: PredicateKind.IdenticalPair, + DRProp.status: PredicateKind.IdenticalPair, + DRProp.error: PredicateKind.IdenticalPair, + DRProp.lastMessage: PredicateKind.IdenticalPair, } min_version = 5 From c9d9aa2a4aef868a4f19328ba74709a6c533db20 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 14 Nov 2022 21:25:02 -0600 Subject: [PATCH 114/206] handle logic sigs and trace compiled teal in the pt dr executor --- tests/blackbox.py | 29 +++++++++++++++++++++----- tests/integration/graviton_abi_test.py | 20 ++++++++++++------ 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index db5eb97b3..e0b60813e 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -1,4 +1,4 @@ -from typing import Callable, Generic, Sequence, TypeVar, cast +from typing import Any, Callable, Generic, Optional, Sequence, TypeVar, cast from dataclasses import dataclass import algosdk.abi @@ -144,8 +144,14 @@ def decorator_blackbox(func: SubroutineFnWrapper | ABIReturnSubroutine): @dataclass(frozen=True) class _MatchMode(Generic[Output]): + runner: Optional["PyTealDryRunExecutor"] app_case: Lazy signature_case: Lazy + trace: Any = None + + def __post_init__(self): + if self.runner and self.trace: + self.runner.add_trace(self.trace) def __call__(self, mode: Mode, *args, **kwargs) -> Output: match mode: @@ -159,6 +165,7 @@ def __call__(self, mode: Mode, *args, **kwargs) -> Output: def mode_to_execution_mode(mode: Mode) -> blackbox.ExecutionMode: return _MatchMode( + runner=None, app_case=lambda: blackbox.ExecutionMode.Application, signature_case=lambda: blackbox.ExecutionMode.Signature, )(mode) @@ -192,6 +199,11 @@ def __init__(self, subr: BlackboxWrapper, mode: Mode): self._pyteal_lambda: Callable[..., Expr] = approval + self.traces: list = [] + + def add_trace(self, trace: Any) -> None: + self.traces.append(trace) + def is_abi(self) -> bool: return isinstance(self.subr.subroutine, ABIReturnSubroutine) @@ -389,6 +401,7 @@ def approval(): def compile(self, version: int, assemble_constants: bool = False) -> str: return _MatchMode( + runner=self, app_case=lambda: compileTeal( self.program(), self.mode, @@ -408,21 +421,24 @@ def dryrun_on_sequence( inputs: list[Sequence[PyTypes]], compiler_version=6, ) -> list[DryRunInspector]: + teal = self.compile(compiler_version) return _MatchMode( + self, app_case=lambda: DryRunExecutor.dryrun_app_on_sequence( algod=algod_with_assertion(), - teal=self.compile(compiler_version), + teal=teal, inputs=inputs, abi_argument_types=self.abi_argument_types(), abi_return_type=self.abi_return_type(), ), signature_case=lambda: DryRunExecutor.dryrun_logicsig_on_sequence( algod=algod_with_assertion(), - teal=self.compile(compiler_version), + teal=teal, inputs=inputs, abi_argument_types=self.abi_argument_types(), abi_return_type=self.abi_return_type(), ), + trace=teal, )(self.mode) def dryrun( @@ -430,19 +446,22 @@ def dryrun( args: Sequence[bytes | str | int], compiler_version=6, ) -> DryRunInspector: + teal = self.compile(compiler_version) return _MatchMode( + self, app_case=lambda: DryRunExecutor.dryrun_app( algod_with_assertion(), - self.compile(compiler_version), + teal, args, self.abi_argument_types(), self.abi_return_type(), ), signature_case=lambda: DryRunExecutor.dryrun_logicsig( algod_with_assertion(), - self.compile(compiler_version), + teal, args, self.abi_argument_types(), self.abi_return_type(), ), + trace=teal, )(self.mode) diff --git a/tests/integration/graviton_abi_test.py b/tests/integration/graviton_abi_test.py index 7b33e4b56..21c7ccb2e 100644 --- a/tests/integration/graviton_abi_test.py +++ b/tests/integration/graviton_abi_test.py @@ -566,13 +566,17 @@ def test_conditional_factorial(version: int): (complex130_norm_squared, complex130_unary_function_inputs), ] -IDENTITY_PREDICATES = { +APP_PREDICATES = { DRProp.lastLog: PredicateKind.IdenticalPair, DRProp.status: PredicateKind.IdenticalPair, DRProp.error: PredicateKind.IdenticalPair, DRProp.lastMessage: PredicateKind.IdenticalPair, } - +LSIG_PREDICATES = { + DRProp.status: PredicateKind.IdenticalPair, + DRProp.error: PredicateKind.IdenticalPair, + DRProp.lastMessage: PredicateKind.IdenticalPair, +} min_version = 5 @@ -581,9 +585,13 @@ def test_conditional_factorial(version: int): @pytest.mark.parametrize("version", range(min_version + 1, pt.MAX_PROGRAM_VERSION + 1)) def test_identical_functionality(subroutine, inputs, mode, version): ptdre = PyTealDryRunExecutor(subroutine, mode) - inspectors2 = ptdre.dryrun_on_sequence(inputs, compiler_version=min_version) + inspectors5 = ptdre.dryrun_on_sequence(inputs, compiler_version=min_version) + teal5 = ptdre.traces[-1] + assert teal5.startswith("#pragma version 5") + inspectorsN = ptdre.dryrun_on_sequence(inputs, compiler_version=version) + tealN = ptdre.traces[-1] + assert tealN.startswith(f"#pragma version {version}") - Invariant.full_validation( - IDENTITY_PREDICATES, inspectors=inspectors2, identities=inspectorsN - ) + preds = APP_PREDICATES if mode == pt.Mode.Application else LSIG_PREDICATES + Invariant.full_validation(preds, inspectors=inspectors5, identities=inspectorsN) From 34ec871c7ef4ad8844fdf9b73d38a23280648445 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 15 Nov 2022 13:38:00 -0600 Subject: [PATCH 115/206] port identity predicates to graviton_test.py --- requirements.txt | 2 +- tests/integration/graviton_abi_test.py | 1 + tests/integration/graviton_test.py | 139 ++++++++++++++++++++----- 3 files changed, 115 insertions(+), 27 deletions(-) diff --git a/requirements.txt b/requirements.txt index b5e7cf4a9..0a5d03d2f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/algorand/graviton@f6e9dfa965afd9588bfaf7325afe5f8c8edafae3 +graviton@git+https://github.com/algorand/graviton@19959cca5a4ca7aaf4736a21c7c23f2083a54233 mypy==0.950 pytest==7.2.0 pytest-cov==3.0.0 diff --git a/tests/integration/graviton_abi_test.py b/tests/integration/graviton_abi_test.py index 21c7ccb2e..a39310594 100644 --- a/tests/integration/graviton_abi_test.py +++ b/tests/integration/graviton_abi_test.py @@ -580,6 +580,7 @@ def test_conditional_factorial(version: int): min_version = 5 +@pytest.mark.skip("Nice test, but too slow. Good to know that it ran once and passed.") @pytest.mark.parametrize("subroutine, inputs", VERSIONING_CASES) @pytest.mark.parametrize("mode", pt.Mode) @pytest.mark.parametrize("version", range(min_version + 1, pt.MAX_PROGRAM_VERSION + 1)) diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index a9e90095f..6c66ea48d 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -23,7 +23,7 @@ mode_has_property, ) -from graviton.invariant import Invariant +from graviton.invariant import Invariant, PredicateKind PATH = Path.cwd() / "tests" / "integration" FIXTURES = PATH / "teal" @@ -487,6 +487,16 @@ def test_stable_teal_generation(subr, mode): }, } +APP_IDENTITICAL_PREDICATES = { + DRProp.lastLog: PredicateKind.IdenticalPair, + DRProp.status: PredicateKind.IdenticalPair, + DRProp.error: PredicateKind.IdenticalPair, +} +LSIG_IDENTICAL_PREDICATES = { + DRProp.status: PredicateKind.IdenticalPair, + DRProp.error: PredicateKind.IdenticalPair, +} + def blackbox_test_runner( subr: pt.SubroutineFnWrapper, @@ -494,7 +504,7 @@ def blackbox_test_runner( scenario: Dict[str, Any], version: int, assemble_constants: bool = True, -): +) -> list[DryRunInspector]: case_name = subr.name() print(f"blackbox test of {case_name} with mode {mode}") exec_mode = mode_to_execution_mode(mode) @@ -541,6 +551,8 @@ def blackbox_test_runner( print(f"{i+1}. Assertion for {case_name}-{mode}: {dr_prop} <<{predicate}>>") invariant.validates(dr_prop, inspectors) + return inspectors + # ---- Graviton / Blackbox tests ---- # @@ -550,8 +562,14 @@ def test_blackbox_subroutines_as_apps( subr: pt.SubroutineFnWrapper, scenario: Dict[str, Any], ): - blackbox_test_runner(subr, pt.Mode.Application, scenario, 6) - blackbox_test_runner(subr, pt.Mode.Application, scenario, 8) + inspectors6 = blackbox_test_runner(subr, pt.Mode.Application, scenario, 6) + inspectors8 = blackbox_test_runner(subr, pt.Mode.Application, scenario, 8) + Invariant.full_validation( + APP_IDENTITICAL_PREDICATES, + inspectors=inspectors6, + identities=inspectors8, + msg=f"{subr.name()=}", + ) @pytest.mark.parametrize("subr, scenario", LOGICSIG_SCENARIOS.items()) @@ -559,8 +577,14 @@ def test_blackbox_subroutines_as_logic_sigs( subr: pt.SubroutineFnWrapper, scenario: Dict[str, Any], ): - blackbox_test_runner(subr, pt.Mode.Signature, scenario, 6) - blackbox_test_runner(subr, pt.Mode.Signature, scenario, 8) + inspectors6 = blackbox_test_runner(subr, pt.Mode.Signature, scenario, 6) + inspectors8 = blackbox_test_runner(subr, pt.Mode.Signature, scenario, 8) + Invariant.full_validation( + LSIG_IDENTICAL_PREDICATES, + inspectors=inspectors6, + identities=inspectors8, + msg=f"{subr.name()=}", + ) def blackbox_pyteal_example1(): @@ -601,8 +625,22 @@ def evaluate_and_check(version: int): args, "last_log() gave unexpected results from app" ) - evaluate_and_check(6) - evaluate_and_check(8) + return (app_result, lsig_result) + + app6, lsig6 = evaluate_and_check(6) + app8, lsig8 = evaluate_and_check(8) + Invariant.full_validation( + APP_IDENTITICAL_PREDICATES, + inspectors=[app6], + identities=[app8], + msg="Mode.Application example 1", + ) + Invariant.full_validation( + LSIG_IDENTICAL_PREDICATES, + inspectors=[lsig6], + identities=[lsig8], + msg="Mode.Signature example 1", + ) def blackbox_pyteal_example2(): @@ -667,8 +705,16 @@ def test_and_report(version: int): with open(Path.cwd() / f"euclid_v{version}.csv", "w") as f: f.write(euclid_csv) - test_and_report(6) - test_and_report(8) + return inspectors + + inspectors6 = test_and_report(6) + inspectors8 = test_and_report(8) + Invariant.full_validation( + APP_IDENTITICAL_PREDICATES, + inspectors=inspectors6, + identities=inspectors8, + msg="example 2", + ) def blackbox_pyteal_example3(): @@ -739,22 +785,29 @@ def euclid(x, y): ) # Execute on the input sequence to get a dry-run inspectors: - inspectors = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_on_sequence( - inputs + inspectors6 = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_on_sequence( + inputs, compiler_version=6 ) # Assert that each invariant holds on the sequences of inputs and dry-runs: for property, predicate in predicates.items(): - Invariant(predicate).validates(property, inspectors) + Invariant(predicate).validates(property, inspectors6) # Execute on the input sequence to get a dry-run inspectors: - inspectors = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_on_sequence( + inspectors8 = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_on_sequence( inputs, compiler_version=8 ) # Assert that each invariant holds on the sequences of inputs and dry-runs: for property, predicate in predicates.items(): - Invariant(predicate).validates(property, inspectors) + Invariant(predicate).validates(property, inspectors8) + + Invariant.full_validation( + APP_IDENTITICAL_PREDICATES, + inspectors=inspectors6, + identities=inspectors8, + msg="Mode.Application example 3", + ) def blackbox_pyteal_example4(): @@ -856,8 +909,22 @@ def report(kind): report("app") report("lsig") - test_and_report_for_app_and_lsig(6) - test_and_report_for_app_and_lsig(8) + return app_inspectors, lsig_inspectors + + app_inspectors6, lsig_inspectors6 = test_and_report_for_app_and_lsig(6) + app_inspectors8, lsig_inspectors8 = test_and_report_for_app_and_lsig(8) + Invariant.full_validation( + APP_IDENTITICAL_PREDICATES, + inspectors=app_inspectors6, + identities=app_inspectors8, + msg=f"Mode.Application example 4 {abi_sum.name()=}", + ) + Invariant.full_validation( + LSIG_IDENTICAL_PREDICATES, + inspectors=lsig_inspectors6, + identities=lsig_inspectors8, + msg=f"Mode.Signature example 4 {abi_sum.name()=}", + ) def blackbox_pyteal_example5(): @@ -898,9 +965,22 @@ def test_app_and_lsig(_version: int): assert inspect.stack_top() == input_var**3, inspect.report( args=inputs[index], msg="stack_top() gave unexpected results from app" ) - - test_app_and_lsig(6) - test_app_and_lsig(8) + return app_inspect, lsig_inspect + + app6, lsig6 = test_app_and_lsig(6) + app8, lsig8 = test_app_and_lsig(8) + Invariant.full_validation( + APP_IDENTITICAL_PREDICATES, + inspectors=[app6], + identities=[app8], + msg="Mode.Application example 5", + ) + Invariant.full_validation( + LSIG_IDENTICAL_PREDICATES, + inspectors=[lsig6], + identities=[lsig8], + msg="Mode.Application example 5", + ) def blackbox_pyteal_while_continue_test(): @@ -1011,14 +1091,21 @@ def named_tuple_field_access( lsig_pytealer = PyTealDryRunExecutor(named_tuple_field_access, Mode.Signature) args = (False, b"1" * 32, (0, False), b"0" * 10, [True] * 4, 0) - inspector = lsig_pytealer.dryrun(args) + inspector6 = lsig_pytealer.dryrun(args, compiler_version=6) - assert inspector.stack_top() == 1 - assert inspector.passed() + assert inspector6.stack_top() == 1 + assert inspector6.passed() - inspector = lsig_pytealer.dryrun(args, compiler_version=8) - assert inspector.passed() - assert inspector.stack_top() == 1 + inspector8 = lsig_pytealer.dryrun(args, compiler_version=8) + assert inspector8.passed() + assert inspector8.stack_top() == 1 + + Invariant.full_validation( + LSIG_IDENTICAL_PREDICATES, + inspectors=inspector6, + identities=inspector8, + msg="Mode.Signature NamedTuple example", + ) @pytest.mark.parametrize( From 2d2666cef00b6d4bfebcaca0702ec5fd1884e4ae Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 15 Nov 2022 14:19:29 -0600 Subject: [PATCH 116/206] some examples failing. Might be a red herring, or might be related to how dynamic scratchvars are handled --- requirements.txt | 2 +- tests/integration/graviton_test.py | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/requirements.txt b/requirements.txt index 0a5d03d2f..63e086c3b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/algorand/graviton@19959cca5a4ca7aaf4736a21c7c23f2083a54233 +graviton@git+https://github.com/algorand/graviton@91fe1f6f82b2a75601cf28e94b8bb2b5c7186621 mypy==0.950 pytest==7.2.0 pytest-cov==3.0.0 diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index 6c66ea48d..c893250cc 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -967,19 +967,19 @@ def test_app_and_lsig(_version: int): ) return app_inspect, lsig_inspect - app6, lsig6 = test_app_and_lsig(6) - app8, lsig8 = test_app_and_lsig(8) + app_inspectors6, lsig_inspectors6 = test_app_and_lsig(6) + app_inspectors8, lsig_inspectors8 = test_app_and_lsig(8) Invariant.full_validation( APP_IDENTITICAL_PREDICATES, - inspectors=[app6], - identities=[app8], + inspectors=app_inspectors6, + identities=app_inspectors8, msg="Mode.Application example 5", ) Invariant.full_validation( LSIG_IDENTICAL_PREDICATES, - inspectors=[lsig6], - identities=[lsig8], - msg="Mode.Application example 5", + inspectors=lsig_inspectors6, + identities=lsig_inspectors8, + msg="Mode.Signature example 5", ) @@ -1102,8 +1102,8 @@ def named_tuple_field_access( Invariant.full_validation( LSIG_IDENTICAL_PREDICATES, - inspectors=inspector6, - identities=inspector8, + inspectors=[inspector6], + identities=[inspector8], msg="Mode.Signature NamedTuple example", ) From b7d77a2156fa8372dc6703e7d43c872c49ece253 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Tue, 15 Nov 2022 17:37:34 -0500 Subject: [PATCH 117/206] fixing wrong stack mechanism for dynamic scratch var --- pyteal/ast/subroutine.py | 18 +++++++++++++----- tests/integration/graviton_test.py | 4 ++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index b84be28db..9915d0760 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -1014,12 +1014,12 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: proto = self.__proto(subroutine) args = subroutine.arguments() - arg_vars: list[ScratchVar] = [] + arg_vars: list[tuple[ScratchVar, int]] = [] loaded_args: list[ScratchVar | Expr | abi.BaseType] = [] - for arg in args: + for index, arg in enumerate(args): arg_var, loaded_arg = self.var_n_loaded_method(subroutine, arg, proto) if arg_var: - arg_vars.append(arg_var) + arg_vars.append((arg_var, index - subroutine.argument_count())) loaded_args.append(loaded_arg) abi_output_kwargs: dict[str, abi.BaseType] = {} @@ -1054,9 +1054,17 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: # Arg usage "A" to be pick up and store in scratch parameters that have been placed on the stack # need to reverse order of argumentVars because the last argument will be on top of the stack - body_ops: list[Expr] = [] if not self.use_frame_pt else [proto] - body_ops += [var.slot.store() for var in arg_vars[::-1]] + body_ops: list[Expr] + if not self.use_frame_pt: + body_ops = [var.slot.store() for var, _ in arg_vars[::-1]] + else: + body_ops = [proto] + body_ops += [ + var.slot.store(FrameVar(proto, index).load()) + for var, index in arg_vars[::-1] + ] + body_ops.append(subroutine_body) sd = SubroutineDeclaration(subroutine, Seq(body_ops), deferred_expr) sd.trace = subroutine_body.trace diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index c893250cc..a5284e3f0 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -310,7 +310,7 @@ def test_stable_teal_generation(subr, mode): }, }, slow_fibonacci: { - "inputs": [(i,) for i in range(18)], + "inputs": [(i,) for i in range(17)], "assertions": { DRProp.cost: lambda args: (fib_cost(args) if args[0] < 17 else 70_000), DRProp.lastLog: lambda args: ( @@ -625,7 +625,7 @@ def evaluate_and_check(version: int): args, "last_log() gave unexpected results from app" ) - return (app_result, lsig_result) + return app_result, lsig_result app6, lsig6 = evaluate_and_check(6) app8, lsig8 = evaluate_and_check(8) From 273d304c65fa6fb52f9d3ac82b6a673a4de0792e Mon Sep 17 00:00:00 2001 From: Hang Su Date: Tue, 15 Nov 2022 17:47:32 -0500 Subject: [PATCH 118/206] fixing wrong stack mechanism for dynamic scratch var --- pyteal/ast/subroutine.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index b84be28db..9915d0760 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -1014,12 +1014,12 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: proto = self.__proto(subroutine) args = subroutine.arguments() - arg_vars: list[ScratchVar] = [] + arg_vars: list[tuple[ScratchVar, int]] = [] loaded_args: list[ScratchVar | Expr | abi.BaseType] = [] - for arg in args: + for index, arg in enumerate(args): arg_var, loaded_arg = self.var_n_loaded_method(subroutine, arg, proto) if arg_var: - arg_vars.append(arg_var) + arg_vars.append((arg_var, index - subroutine.argument_count())) loaded_args.append(loaded_arg) abi_output_kwargs: dict[str, abi.BaseType] = {} @@ -1054,9 +1054,17 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: # Arg usage "A" to be pick up and store in scratch parameters that have been placed on the stack # need to reverse order of argumentVars because the last argument will be on top of the stack - body_ops: list[Expr] = [] if not self.use_frame_pt else [proto] - body_ops += [var.slot.store() for var in arg_vars[::-1]] + body_ops: list[Expr] + if not self.use_frame_pt: + body_ops = [var.slot.store() for var, _ in arg_vars[::-1]] + else: + body_ops = [proto] + body_ops += [ + var.slot.store(FrameVar(proto, index).load()) + for var, index in arg_vars[::-1] + ] + body_ops.append(subroutine_body) sd = SubroutineDeclaration(subroutine, Seq(body_ops), deferred_expr) sd.trace = subroutine_body.trace From a55052d44e2394444617633dd26f554a0841c006 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Tue, 15 Nov 2022 19:44:30 -0500 Subject: [PATCH 119/206] rename --- pyteal/ast/subroutine.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pyteal/ast/subroutine.py b/pyteal/ast/subroutine.py index 9915d0760..b5cf797b7 100644 --- a/pyteal/ast/subroutine.py +++ b/pyteal/ast/subroutine.py @@ -1014,12 +1014,14 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: proto = self.__proto(subroutine) args = subroutine.arguments() - arg_vars: list[tuple[ScratchVar, int]] = [] + arg_var_n_frame_index_pairs: list[tuple[ScratchVar, int]] = [] loaded_args: list[ScratchVar | Expr | abi.BaseType] = [] for index, arg in enumerate(args): arg_var, loaded_arg = self.var_n_loaded_method(subroutine, arg, proto) if arg_var: - arg_vars.append((arg_var, index - subroutine.argument_count())) + arg_var_n_frame_index_pairs.append( + (arg_var, index - subroutine.argument_count()) + ) loaded_args.append(loaded_arg) abi_output_kwargs: dict[str, abi.BaseType] = {} @@ -1057,12 +1059,14 @@ def __call__(self, subroutine: SubroutineDefinition) -> SubroutineDeclaration: body_ops: list[Expr] if not self.use_frame_pt: - body_ops = [var.slot.store() for var, _ in arg_vars[::-1]] + body_ops = [ + var.slot.store() for var, _ in arg_var_n_frame_index_pairs[::-1] + ] else: body_ops = [proto] body_ops += [ var.slot.store(FrameVar(proto, index).load()) - for var, index in arg_vars[::-1] + for var, index in arg_var_n_frame_index_pairs[::-1] ] body_ops.append(subroutine_body) From 29cd5897b002259a6e434860a19f5c6965a9952a Mon Sep 17 00:00:00 2001 From: Hang Su Date: Tue, 15 Nov 2022 20:11:21 -0500 Subject: [PATCH 120/206] special case notes --- tests/integration/graviton_test.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index a5284e3f0..470adb1e2 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -310,7 +310,7 @@ def test_stable_teal_generation(subr, mode): }, }, slow_fibonacci: { - "inputs": [(i,) for i in range(17)], + "inputs": [(i,) for i in range(18)], "assertions": { DRProp.cost: lambda args: (fib_cost(args) if args[0] < 17 else 70_000), DRProp.lastLog: lambda args: ( @@ -564,6 +564,15 @@ def test_blackbox_subroutines_as_apps( ): inspectors6 = blackbox_test_runner(subr, pt.Mode.Application, scenario, 6) inspectors8 = blackbox_test_runner(subr, pt.Mode.Application, scenario, 8) + + if subr.name() == "slow_fibonacci": + assert len(inspectors6) == len(inspectors8) == 18 + # NOTE the last case of inspector 8 (compilation with frame pointer) + # does not blow up the 70k budget limit, so we skip specifically for this one. + + del inspectors6[-1] + del inspectors8[-1] + Invariant.full_validation( APP_IDENTITICAL_PREDICATES, inspectors=inspectors6, From e5865647c1fb3922cd73381bbcd06e0f9a004822 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Wed, 16 Nov 2022 12:11:35 -0600 Subject: [PATCH 121/206] fix embarassing spelling --- tests/integration/graviton_test.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index 470adb1e2..e92070f70 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -487,7 +487,7 @@ def test_stable_teal_generation(subr, mode): }, } -APP_IDENTITICAL_PREDICATES = { +APP_IDENTICAL_PREDICATES = { DRProp.lastLog: PredicateKind.IdenticalPair, DRProp.status: PredicateKind.IdenticalPair, DRProp.error: PredicateKind.IdenticalPair, @@ -574,7 +574,7 @@ def test_blackbox_subroutines_as_apps( del inspectors8[-1] Invariant.full_validation( - APP_IDENTITICAL_PREDICATES, + APP_IDENTICAL_PREDICATES, inspectors=inspectors6, identities=inspectors8, msg=f"{subr.name()=}", @@ -639,7 +639,7 @@ def evaluate_and_check(version: int): app6, lsig6 = evaluate_and_check(6) app8, lsig8 = evaluate_and_check(8) Invariant.full_validation( - APP_IDENTITICAL_PREDICATES, + APP_IDENTICAL_PREDICATES, inspectors=[app6], identities=[app8], msg="Mode.Application example 1", @@ -719,7 +719,7 @@ def test_and_report(version: int): inspectors6 = test_and_report(6) inspectors8 = test_and_report(8) Invariant.full_validation( - APP_IDENTITICAL_PREDICATES, + APP_IDENTICAL_PREDICATES, inspectors=inspectors6, identities=inspectors8, msg="example 2", @@ -812,7 +812,7 @@ def euclid(x, y): Invariant(predicate).validates(property, inspectors8) Invariant.full_validation( - APP_IDENTITICAL_PREDICATES, + APP_IDENTICAL_PREDICATES, inspectors=inspectors6, identities=inspectors8, msg="Mode.Application example 3", @@ -923,7 +923,7 @@ def report(kind): app_inspectors6, lsig_inspectors6 = test_and_report_for_app_and_lsig(6) app_inspectors8, lsig_inspectors8 = test_and_report_for_app_and_lsig(8) Invariant.full_validation( - APP_IDENTITICAL_PREDICATES, + APP_IDENTICAL_PREDICATES, inspectors=app_inspectors6, identities=app_inspectors8, msg=f"Mode.Application example 4 {abi_sum.name()=}", @@ -979,7 +979,7 @@ def test_app_and_lsig(_version: int): app_inspectors6, lsig_inspectors6 = test_app_and_lsig(6) app_inspectors8, lsig_inspectors8 = test_app_and_lsig(8) Invariant.full_validation( - APP_IDENTITICAL_PREDICATES, + APP_IDENTICAL_PREDICATES, inspectors=app_inspectors6, identities=app_inspectors8, msg="Mode.Application example 5", From 77ca4a588acf20069fe07d203e751ab8dff813a1 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Wed, 23 Nov 2022 17:49:53 -0600 Subject: [PATCH 122/206] remove run-once forever to be skipped slow test --- tests/integration/graviton_abi_test.py | 56 +------------------------- 1 file changed, 1 insertion(+), 55 deletions(-) diff --git a/tests/integration/graviton_abi_test.py b/tests/integration/graviton_abi_test.py index a39310594..6b2f8bbce 100644 --- a/tests/integration/graviton_abi_test.py +++ b/tests/integration/graviton_abi_test.py @@ -1,9 +1,7 @@ -from itertools import product import random import pytest -from graviton.blackbox import DryRunInspector, DryRunProperty as DRProp -from graviton.invariant import Invariant, PredicateKind +from graviton.blackbox import DryRunInspector import pyteal as pt from pyteal.ast.subroutine import ABIReturnSubroutine @@ -544,55 +542,3 @@ def test_conditional_factorial(version: int): assert inspector.error(), inspector.report( args, f"FAILED: should error for {n=}", row=n + 1 ) - - -xs = list(map(pynum_to_int65tuple, (-1, 1, 3, 5, 7))) -int65_unary_function_inputs = [(x,) for x in xs] -int65_binary_function_inputs = list(product(xs, xs)) -zs = int65_binary_function_inputs -complex130_unary_function_inputs = [(z,) for z in zs] -complex130_binary_function_inputs = list(product(zs, zs)) -VERSIONING_CASES = [ - (int65_minus_cond, int65_binary_function_inputs), - (int65_sub, int65_binary_function_inputs), - (int65_mult, int65_binary_function_inputs), - (int65_negate, int65_unary_function_inputs), - (int65_add, int65_binary_function_inputs), - (complex130_add, complex130_binary_function_inputs), - (complex130_mult, complex130_binary_function_inputs), - (complex130_real, complex130_unary_function_inputs), - (complex130_imag, complex130_unary_function_inputs), - (complex130_conjugate, complex130_unary_function_inputs), - (complex130_norm_squared, complex130_unary_function_inputs), -] - -APP_PREDICATES = { - DRProp.lastLog: PredicateKind.IdenticalPair, - DRProp.status: PredicateKind.IdenticalPair, - DRProp.error: PredicateKind.IdenticalPair, - DRProp.lastMessage: PredicateKind.IdenticalPair, -} -LSIG_PREDICATES = { - DRProp.status: PredicateKind.IdenticalPair, - DRProp.error: PredicateKind.IdenticalPair, - DRProp.lastMessage: PredicateKind.IdenticalPair, -} -min_version = 5 - - -@pytest.mark.skip("Nice test, but too slow. Good to know that it ran once and passed.") -@pytest.mark.parametrize("subroutine, inputs", VERSIONING_CASES) -@pytest.mark.parametrize("mode", pt.Mode) -@pytest.mark.parametrize("version", range(min_version + 1, pt.MAX_PROGRAM_VERSION + 1)) -def test_identical_functionality(subroutine, inputs, mode, version): - ptdre = PyTealDryRunExecutor(subroutine, mode) - inspectors5 = ptdre.dryrun_on_sequence(inputs, compiler_version=min_version) - teal5 = ptdre.traces[-1] - assert teal5.startswith("#pragma version 5") - - inspectorsN = ptdre.dryrun_on_sequence(inputs, compiler_version=version) - tealN = ptdre.traces[-1] - assert tealN.startswith(f"#pragma version {version}") - - preds = APP_PREDICATES if mode == pt.Mode.Application else LSIG_PREDICATES - Invariant.full_validation(preds, inspectors=inspectors5, identities=inspectorsN) From f5ef8194c1b3685b161bf2f0ece8ade2d5e1833f Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 14 Nov 2022 19:51:10 -0600 Subject: [PATCH 123/206] Test identical functionality across versions - just a POC and too slow to merge --- requirements.txt | 2 +- tests/integration/graviton_abi_test.py | 58 +++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/requirements.txt b/requirements.txt index 158039a7b..b5e7cf4a9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/algorand/graviton@v0.5.0 +graviton@git+https://github.com/algorand/graviton@f6e9dfa965afd9588bfaf7325afe5f8c8edafae3 mypy==0.950 pytest==7.2.0 pytest-cov==3.0.0 diff --git a/tests/integration/graviton_abi_test.py b/tests/integration/graviton_abi_test.py index 0806ee96e..e178fbfdc 100644 --- a/tests/integration/graviton_abi_test.py +++ b/tests/integration/graviton_abi_test.py @@ -1,7 +1,9 @@ +from itertools import product import random import pytest -from graviton.blackbox import DryRunInspector +from graviton.blackbox import DryRunInspector, DryRunProperty as DRProp +from graviton.invariant import Invariant, PredicateKind as IQ import pyteal as pt from pyteal.ast.subroutine import ABIReturnSubroutine @@ -300,6 +302,10 @@ def conditional_factorial(_factor: pt.abi.Uint64, *, output: pt.abi.Uint64) -> p # ---- integration test functions ---- # +def pynum_to_int65tuple(n): + return (n >= 0, abs(n)) + + @pytest.mark.parametrize("version", [6, 8]) def test_integer65(version: int): bbpt_subtract_slick = PyTealDryRunExecutor(int65_sub, pt.Mode.Application) @@ -312,9 +318,6 @@ def test_integer65(version: int): 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 @@ -323,10 +326,10 @@ def pytuple_to_num(t): random.seed(42) choices = range(-9_999, 10_000) - unary_inputs = [(pynum_to_tuple(x),) for x in random.sample(choices, N)] + unary_inputs = [(pynum_to_int65tuple(x),) for x in random.sample(choices, N)] binary_inputs = [ - (pynum_to_tuple(x), pynum_to_tuple(y)) + (pynum_to_int65tuple(x), pynum_to_int65tuple(y)) for x, y in zip(random.sample(choices, N), random.sample(choices, N)) ] @@ -541,3 +544,46 @@ def test_conditional_factorial(version: int): assert inspector.error(), inspector.report( args, f"FAILED: should error for {n=}", row=n + 1 ) + + +xs = list(map(pynum_to_int65tuple, (-1, 1, 3, 5, 7))) +int65_unary_function_inputs = [(x,) for x in xs] +int65_binary_function_inputs = list(product(xs, xs)) +zs = int65_binary_function_inputs +complex130_unary_function_inputs = [(z,) for z in zs] +complex130_binary_function_inputs = list(product(zs, zs)) +VERSIONING_CASES = [ + (int65_minus_cond, int65_binary_function_inputs), + (int65_sub, int65_binary_function_inputs), + (int65_mult, int65_binary_function_inputs), + (int65_negate, int65_unary_function_inputs), + (int65_add, int65_binary_function_inputs), + (complex130_add, complex130_binary_function_inputs), + (complex130_mult, complex130_binary_function_inputs), + (complex130_real, complex130_unary_function_inputs), + (complex130_imag, complex130_unary_function_inputs), + (complex130_conjugate, complex130_unary_function_inputs), + (complex130_norm_squared, complex130_unary_function_inputs), +] + +IDENTITY_PREDICATES = { + DRProp.lastLog: IQ.IdenticalPair, + DRProp.status: IQ.IdenticalPair, + DRProp.error: IQ.IdenticalPair, + DRProp.lastMessage: IQ.IdenticalPair, +} + +min_version = 5 + + +@pytest.mark.parametrize("subroutine, inputs", VERSIONING_CASES) +@pytest.mark.parametrize("mode", pt.Mode) +@pytest.mark.parametrize("version", range(min_version + 1, pt.MAX_PROGRAM_VERSION + 1)) +def test_identical_functionality(subroutine, inputs, mode, version): + ptdre = PyTealDryRunExecutor(subroutine, mode) + inspectors2 = ptdre.dryrun_on_sequence(inputs, compiler_version=min_version) + inspectorsN = ptdre.dryrun_on_sequence(inputs, compiler_version=version) + + Invariant.full_validation( + IDENTITY_PREDICATES, inspectors=inspectors2, identities=inspectorsN + ) From 7cddccd3f02a2f58907c06f731d15fae1b4fde1f Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 14 Nov 2022 19:55:42 -0600 Subject: [PATCH 124/206] bad alias --- tests/integration/graviton_abi_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/integration/graviton_abi_test.py b/tests/integration/graviton_abi_test.py index e178fbfdc..7b33e4b56 100644 --- a/tests/integration/graviton_abi_test.py +++ b/tests/integration/graviton_abi_test.py @@ -3,7 +3,7 @@ import pytest from graviton.blackbox import DryRunInspector, DryRunProperty as DRProp -from graviton.invariant import Invariant, PredicateKind as IQ +from graviton.invariant import Invariant, PredicateKind import pyteal as pt from pyteal.ast.subroutine import ABIReturnSubroutine @@ -567,10 +567,10 @@ def test_conditional_factorial(version: int): ] IDENTITY_PREDICATES = { - DRProp.lastLog: IQ.IdenticalPair, - DRProp.status: IQ.IdenticalPair, - DRProp.error: IQ.IdenticalPair, - DRProp.lastMessage: IQ.IdenticalPair, + DRProp.lastLog: PredicateKind.IdenticalPair, + DRProp.status: PredicateKind.IdenticalPair, + DRProp.error: PredicateKind.IdenticalPair, + DRProp.lastMessage: PredicateKind.IdenticalPair, } min_version = 5 From 08a51f29e2d897e5a8b2a4d19d10af42b3e588a0 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 14 Nov 2022 21:25:02 -0600 Subject: [PATCH 125/206] handle logic sigs and trace compiled teal in the pt dr executor --- tests/blackbox.py | 29 +++++++++++++++++++++----- tests/integration/graviton_abi_test.py | 20 ++++++++++++------ 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index db5eb97b3..e0b60813e 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -1,4 +1,4 @@ -from typing import Callable, Generic, Sequence, TypeVar, cast +from typing import Any, Callable, Generic, Optional, Sequence, TypeVar, cast from dataclasses import dataclass import algosdk.abi @@ -144,8 +144,14 @@ def decorator_blackbox(func: SubroutineFnWrapper | ABIReturnSubroutine): @dataclass(frozen=True) class _MatchMode(Generic[Output]): + runner: Optional["PyTealDryRunExecutor"] app_case: Lazy signature_case: Lazy + trace: Any = None + + def __post_init__(self): + if self.runner and self.trace: + self.runner.add_trace(self.trace) def __call__(self, mode: Mode, *args, **kwargs) -> Output: match mode: @@ -159,6 +165,7 @@ def __call__(self, mode: Mode, *args, **kwargs) -> Output: def mode_to_execution_mode(mode: Mode) -> blackbox.ExecutionMode: return _MatchMode( + runner=None, app_case=lambda: blackbox.ExecutionMode.Application, signature_case=lambda: blackbox.ExecutionMode.Signature, )(mode) @@ -192,6 +199,11 @@ def __init__(self, subr: BlackboxWrapper, mode: Mode): self._pyteal_lambda: Callable[..., Expr] = approval + self.traces: list = [] + + def add_trace(self, trace: Any) -> None: + self.traces.append(trace) + def is_abi(self) -> bool: return isinstance(self.subr.subroutine, ABIReturnSubroutine) @@ -389,6 +401,7 @@ def approval(): def compile(self, version: int, assemble_constants: bool = False) -> str: return _MatchMode( + runner=self, app_case=lambda: compileTeal( self.program(), self.mode, @@ -408,21 +421,24 @@ def dryrun_on_sequence( inputs: list[Sequence[PyTypes]], compiler_version=6, ) -> list[DryRunInspector]: + teal = self.compile(compiler_version) return _MatchMode( + self, app_case=lambda: DryRunExecutor.dryrun_app_on_sequence( algod=algod_with_assertion(), - teal=self.compile(compiler_version), + teal=teal, inputs=inputs, abi_argument_types=self.abi_argument_types(), abi_return_type=self.abi_return_type(), ), signature_case=lambda: DryRunExecutor.dryrun_logicsig_on_sequence( algod=algod_with_assertion(), - teal=self.compile(compiler_version), + teal=teal, inputs=inputs, abi_argument_types=self.abi_argument_types(), abi_return_type=self.abi_return_type(), ), + trace=teal, )(self.mode) def dryrun( @@ -430,19 +446,22 @@ def dryrun( args: Sequence[bytes | str | int], compiler_version=6, ) -> DryRunInspector: + teal = self.compile(compiler_version) return _MatchMode( + self, app_case=lambda: DryRunExecutor.dryrun_app( algod_with_assertion(), - self.compile(compiler_version), + teal, args, self.abi_argument_types(), self.abi_return_type(), ), signature_case=lambda: DryRunExecutor.dryrun_logicsig( algod_with_assertion(), - self.compile(compiler_version), + teal, args, self.abi_argument_types(), self.abi_return_type(), ), + trace=teal, )(self.mode) diff --git a/tests/integration/graviton_abi_test.py b/tests/integration/graviton_abi_test.py index 7b33e4b56..21c7ccb2e 100644 --- a/tests/integration/graviton_abi_test.py +++ b/tests/integration/graviton_abi_test.py @@ -566,13 +566,17 @@ def test_conditional_factorial(version: int): (complex130_norm_squared, complex130_unary_function_inputs), ] -IDENTITY_PREDICATES = { +APP_PREDICATES = { DRProp.lastLog: PredicateKind.IdenticalPair, DRProp.status: PredicateKind.IdenticalPair, DRProp.error: PredicateKind.IdenticalPair, DRProp.lastMessage: PredicateKind.IdenticalPair, } - +LSIG_PREDICATES = { + DRProp.status: PredicateKind.IdenticalPair, + DRProp.error: PredicateKind.IdenticalPair, + DRProp.lastMessage: PredicateKind.IdenticalPair, +} min_version = 5 @@ -581,9 +585,13 @@ def test_conditional_factorial(version: int): @pytest.mark.parametrize("version", range(min_version + 1, pt.MAX_PROGRAM_VERSION + 1)) def test_identical_functionality(subroutine, inputs, mode, version): ptdre = PyTealDryRunExecutor(subroutine, mode) - inspectors2 = ptdre.dryrun_on_sequence(inputs, compiler_version=min_version) + inspectors5 = ptdre.dryrun_on_sequence(inputs, compiler_version=min_version) + teal5 = ptdre.traces[-1] + assert teal5.startswith("#pragma version 5") + inspectorsN = ptdre.dryrun_on_sequence(inputs, compiler_version=version) + tealN = ptdre.traces[-1] + assert tealN.startswith(f"#pragma version {version}") - Invariant.full_validation( - IDENTITY_PREDICATES, inspectors=inspectors2, identities=inspectorsN - ) + preds = APP_PREDICATES if mode == pt.Mode.Application else LSIG_PREDICATES + Invariant.full_validation(preds, inspectors=inspectors5, identities=inspectorsN) From 8a84f7363631e49ae5e56ece2b39255a245e6cdb Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 15 Nov 2022 13:38:00 -0600 Subject: [PATCH 126/206] port identity predicates to graviton_test.py --- requirements.txt | 2 +- tests/integration/graviton_abi_test.py | 1 + tests/integration/graviton_test.py | 139 ++++++++++++++++++++----- 3 files changed, 115 insertions(+), 27 deletions(-) diff --git a/requirements.txt b/requirements.txt index b5e7cf4a9..0a5d03d2f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/algorand/graviton@f6e9dfa965afd9588bfaf7325afe5f8c8edafae3 +graviton@git+https://github.com/algorand/graviton@19959cca5a4ca7aaf4736a21c7c23f2083a54233 mypy==0.950 pytest==7.2.0 pytest-cov==3.0.0 diff --git a/tests/integration/graviton_abi_test.py b/tests/integration/graviton_abi_test.py index 21c7ccb2e..a39310594 100644 --- a/tests/integration/graviton_abi_test.py +++ b/tests/integration/graviton_abi_test.py @@ -580,6 +580,7 @@ def test_conditional_factorial(version: int): min_version = 5 +@pytest.mark.skip("Nice test, but too slow. Good to know that it ran once and passed.") @pytest.mark.parametrize("subroutine, inputs", VERSIONING_CASES) @pytest.mark.parametrize("mode", pt.Mode) @pytest.mark.parametrize("version", range(min_version + 1, pt.MAX_PROGRAM_VERSION + 1)) diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index 31f77bb04..cdd40bc15 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -23,7 +23,7 @@ mode_has_property, ) -from graviton.invariant import Invariant +from graviton.invariant import Invariant, PredicateKind PATH = Path.cwd() / "tests" / "integration" FIXTURES = PATH / "teal" @@ -485,6 +485,16 @@ def test_stable_teal_generation(subr, mode): }, } +APP_IDENTITICAL_PREDICATES = { + DRProp.lastLog: PredicateKind.IdenticalPair, + DRProp.status: PredicateKind.IdenticalPair, + DRProp.error: PredicateKind.IdenticalPair, +} +LSIG_IDENTICAL_PREDICATES = { + DRProp.status: PredicateKind.IdenticalPair, + DRProp.error: PredicateKind.IdenticalPair, +} + def blackbox_test_runner( subr: pt.SubroutineFnWrapper, @@ -492,7 +502,7 @@ def blackbox_test_runner( scenario: Dict[str, Any], version: int, assemble_constants: bool = True, -): +) -> list[DryRunInspector]: case_name = subr.name() print(f"blackbox test of {case_name} with mode {mode}") exec_mode = mode_to_execution_mode(mode) @@ -539,6 +549,8 @@ def blackbox_test_runner( print(f"{i+1}. Assertion for {case_name}-{mode}: {dr_prop} <<{predicate}>>") invariant.validates(dr_prop, inspectors) + return inspectors + # ---- Graviton / Blackbox tests ---- # @@ -548,8 +560,14 @@ def test_blackbox_subroutines_as_apps( subr: pt.SubroutineFnWrapper, scenario: Dict[str, Any], ): - blackbox_test_runner(subr, pt.Mode.Application, scenario, 6) - blackbox_test_runner(subr, pt.Mode.Application, scenario, 8) + inspectors6 = blackbox_test_runner(subr, pt.Mode.Application, scenario, 6) + inspectors8 = blackbox_test_runner(subr, pt.Mode.Application, scenario, 8) + Invariant.full_validation( + APP_IDENTITICAL_PREDICATES, + inspectors=inspectors6, + identities=inspectors8, + msg=f"{subr.name()=}", + ) @pytest.mark.parametrize("subr, scenario", LOGICSIG_SCENARIOS.items()) @@ -557,8 +575,14 @@ def test_blackbox_subroutines_as_logic_sigs( subr: pt.SubroutineFnWrapper, scenario: Dict[str, Any], ): - blackbox_test_runner(subr, pt.Mode.Signature, scenario, 6) - blackbox_test_runner(subr, pt.Mode.Signature, scenario, 8) + inspectors6 = blackbox_test_runner(subr, pt.Mode.Signature, scenario, 6) + inspectors8 = blackbox_test_runner(subr, pt.Mode.Signature, scenario, 8) + Invariant.full_validation( + LSIG_IDENTICAL_PREDICATES, + inspectors=inspectors6, + identities=inspectors8, + msg=f"{subr.name()=}", + ) def blackbox_pyteal_example1(): @@ -599,8 +623,22 @@ def evaluate_and_check(version: int): args, "last_log() gave unexpected results from app" ) - evaluate_and_check(6) - evaluate_and_check(8) + return (app_result, lsig_result) + + app6, lsig6 = evaluate_and_check(6) + app8, lsig8 = evaluate_and_check(8) + Invariant.full_validation( + APP_IDENTITICAL_PREDICATES, + inspectors=[app6], + identities=[app8], + msg="Mode.Application example 1", + ) + Invariant.full_validation( + LSIG_IDENTICAL_PREDICATES, + inspectors=[lsig6], + identities=[lsig8], + msg="Mode.Signature example 1", + ) def blackbox_pyteal_example2(): @@ -665,8 +703,16 @@ def test_and_report(version: int): with open(Path.cwd() / f"euclid_v{version}.csv", "w") as f: f.write(euclid_csv) - test_and_report(6) - test_and_report(8) + return inspectors + + inspectors6 = test_and_report(6) + inspectors8 = test_and_report(8) + Invariant.full_validation( + APP_IDENTITICAL_PREDICATES, + inspectors=inspectors6, + identities=inspectors8, + msg="example 2", + ) def blackbox_pyteal_example3(): @@ -737,22 +783,29 @@ def euclid(x, y): ) # Execute on the input sequence to get a dry-run inspectors: - inspectors = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_on_sequence( - inputs + inspectors6 = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_on_sequence( + inputs, compiler_version=6 ) # Assert that each invariant holds on the sequences of inputs and dry-runs: for property, predicate in predicates.items(): - Invariant(predicate).validates(property, inspectors) + Invariant(predicate).validates(property, inspectors6) # Execute on the input sequence to get a dry-run inspectors: - inspectors = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_on_sequence( + inspectors8 = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_on_sequence( inputs, compiler_version=8 ) # Assert that each invariant holds on the sequences of inputs and dry-runs: for property, predicate in predicates.items(): - Invariant(predicate).validates(property, inspectors) + Invariant(predicate).validates(property, inspectors8) + + Invariant.full_validation( + APP_IDENTITICAL_PREDICATES, + inspectors=inspectors6, + identities=inspectors8, + msg="Mode.Application example 3", + ) def blackbox_pyteal_example4(): @@ -854,8 +907,22 @@ def report(kind): report("app") report("lsig") - test_and_report_for_app_and_lsig(6) - test_and_report_for_app_and_lsig(8) + return app_inspectors, lsig_inspectors + + app_inspectors6, lsig_inspectors6 = test_and_report_for_app_and_lsig(6) + app_inspectors8, lsig_inspectors8 = test_and_report_for_app_and_lsig(8) + Invariant.full_validation( + APP_IDENTITICAL_PREDICATES, + inspectors=app_inspectors6, + identities=app_inspectors8, + msg=f"Mode.Application example 4 {abi_sum.name()=}", + ) + Invariant.full_validation( + LSIG_IDENTICAL_PREDICATES, + inspectors=lsig_inspectors6, + identities=lsig_inspectors8, + msg=f"Mode.Signature example 4 {abi_sum.name()=}", + ) def blackbox_pyteal_example5(): @@ -896,9 +963,22 @@ def test_app_and_lsig(_version: int): assert inspect.stack_top() == input_var**3, inspect.report( args=inputs[index], msg="stack_top() gave unexpected results from app" ) - - test_app_and_lsig(6) - test_app_and_lsig(8) + return app_inspect, lsig_inspect + + app6, lsig6 = test_app_and_lsig(6) + app8, lsig8 = test_app_and_lsig(8) + Invariant.full_validation( + APP_IDENTITICAL_PREDICATES, + inspectors=[app6], + identities=[app8], + msg="Mode.Application example 5", + ) + Invariant.full_validation( + LSIG_IDENTICAL_PREDICATES, + inspectors=[lsig6], + identities=[lsig8], + msg="Mode.Application example 5", + ) def blackbox_pyteal_while_continue_test(): @@ -1009,14 +1089,21 @@ def named_tuple_field_access( lsig_pytealer = PyTealDryRunExecutor(named_tuple_field_access, Mode.Signature) args = (False, b"1" * 32, (0, False), b"0" * 10, [True] * 4, 0) - inspector = lsig_pytealer.dryrun(args) + inspector6 = lsig_pytealer.dryrun(args, compiler_version=6) - assert inspector.stack_top() == 1 - assert inspector.passed() + assert inspector6.stack_top() == 1 + assert inspector6.passed() - inspector = lsig_pytealer.dryrun(args, compiler_version=8) - assert inspector.passed() - assert inspector.stack_top() == 1 + inspector8 = lsig_pytealer.dryrun(args, compiler_version=8) + assert inspector8.passed() + assert inspector8.stack_top() == 1 + + Invariant.full_validation( + LSIG_IDENTICAL_PREDICATES, + inspectors=inspector6, + identities=inspector8, + msg="Mode.Signature NamedTuple example", + ) @pytest.mark.parametrize( From 61d1cc69cebc992f8b81bf73104150d9cd1d2f80 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 15 Nov 2022 14:19:29 -0600 Subject: [PATCH 127/206] some examples failing. Might be a red herring, or might be related to how dynamic scratchvars are handled fixing wrong stack mechanism for dynamic scratch var fixing wrong stack mechanism for dynamic scratch var rename --- requirements.txt | 2 +- tests/integration/graviton_test.py | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/requirements.txt b/requirements.txt index 0a5d03d2f..63e086c3b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/algorand/graviton@19959cca5a4ca7aaf4736a21c7c23f2083a54233 +graviton@git+https://github.com/algorand/graviton@91fe1f6f82b2a75601cf28e94b8bb2b5c7186621 mypy==0.950 pytest==7.2.0 pytest-cov==3.0.0 diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index cdd40bc15..889343ce7 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -308,7 +308,7 @@ def test_stable_teal_generation(subr, mode): }, }, slow_fibonacci: { - "inputs": [(i,) for i in range(18)], + "inputs": [(i,) for i in range(17)], "assertions": { DRProp.cost: lambda args: (fib_cost(args) if args[0] < 17 else 70_000), DRProp.lastLog: lambda args: ( @@ -623,7 +623,7 @@ def evaluate_and_check(version: int): args, "last_log() gave unexpected results from app" ) - return (app_result, lsig_result) + return app_result, lsig_result app6, lsig6 = evaluate_and_check(6) app8, lsig8 = evaluate_and_check(8) @@ -965,19 +965,19 @@ def test_app_and_lsig(_version: int): ) return app_inspect, lsig_inspect - app6, lsig6 = test_app_and_lsig(6) - app8, lsig8 = test_app_and_lsig(8) + app_inspectors6, lsig_inspectors6 = test_app_and_lsig(6) + app_inspectors8, lsig_inspectors8 = test_app_and_lsig(8) Invariant.full_validation( APP_IDENTITICAL_PREDICATES, - inspectors=[app6], - identities=[app8], + inspectors=app_inspectors6, + identities=app_inspectors8, msg="Mode.Application example 5", ) Invariant.full_validation( LSIG_IDENTICAL_PREDICATES, - inspectors=[lsig6], - identities=[lsig8], - msg="Mode.Application example 5", + inspectors=lsig_inspectors6, + identities=lsig_inspectors8, + msg="Mode.Signature example 5", ) @@ -1100,8 +1100,8 @@ def named_tuple_field_access( Invariant.full_validation( LSIG_IDENTICAL_PREDICATES, - inspectors=inspector6, - identities=inspector8, + inspectors=[inspector6], + identities=[inspector8], msg="Mode.Signature NamedTuple example", ) From 6922ac1a504b9d34c9311735aac4e1231e775fd3 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Tue, 15 Nov 2022 20:11:21 -0500 Subject: [PATCH 128/206] special case notes --- tests/integration/graviton_test.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index 889343ce7..34bf8d86c 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -308,7 +308,7 @@ def test_stable_teal_generation(subr, mode): }, }, slow_fibonacci: { - "inputs": [(i,) for i in range(17)], + "inputs": [(i,) for i in range(18)], "assertions": { DRProp.cost: lambda args: (fib_cost(args) if args[0] < 17 else 70_000), DRProp.lastLog: lambda args: ( @@ -562,6 +562,15 @@ def test_blackbox_subroutines_as_apps( ): inspectors6 = blackbox_test_runner(subr, pt.Mode.Application, scenario, 6) inspectors8 = blackbox_test_runner(subr, pt.Mode.Application, scenario, 8) + + if subr.name() == "slow_fibonacci": + assert len(inspectors6) == len(inspectors8) == 18 + # NOTE the last case of inspector 8 (compilation with frame pointer) + # does not blow up the 70k budget limit, so we skip specifically for this one. + + del inspectors6[-1] + del inspectors8[-1] + Invariant.full_validation( APP_IDENTITICAL_PREDICATES, inspectors=inspectors6, From 64172651e13d8d831fc435bca3c2b77f4345b3ab Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Wed, 16 Nov 2022 12:11:35 -0600 Subject: [PATCH 129/206] fix embarassing spelling --- tests/integration/graviton_test.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index 34bf8d86c..3831e3e7d 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -485,7 +485,7 @@ def test_stable_teal_generation(subr, mode): }, } -APP_IDENTITICAL_PREDICATES = { +APP_IDENTICAL_PREDICATES = { DRProp.lastLog: PredicateKind.IdenticalPair, DRProp.status: PredicateKind.IdenticalPair, DRProp.error: PredicateKind.IdenticalPair, @@ -572,7 +572,7 @@ def test_blackbox_subroutines_as_apps( del inspectors8[-1] Invariant.full_validation( - APP_IDENTITICAL_PREDICATES, + APP_IDENTICAL_PREDICATES, inspectors=inspectors6, identities=inspectors8, msg=f"{subr.name()=}", @@ -637,7 +637,7 @@ def evaluate_and_check(version: int): app6, lsig6 = evaluate_and_check(6) app8, lsig8 = evaluate_and_check(8) Invariant.full_validation( - APP_IDENTITICAL_PREDICATES, + APP_IDENTICAL_PREDICATES, inspectors=[app6], identities=[app8], msg="Mode.Application example 1", @@ -717,7 +717,7 @@ def test_and_report(version: int): inspectors6 = test_and_report(6) inspectors8 = test_and_report(8) Invariant.full_validation( - APP_IDENTITICAL_PREDICATES, + APP_IDENTICAL_PREDICATES, inspectors=inspectors6, identities=inspectors8, msg="example 2", @@ -810,7 +810,7 @@ def euclid(x, y): Invariant(predicate).validates(property, inspectors8) Invariant.full_validation( - APP_IDENTITICAL_PREDICATES, + APP_IDENTICAL_PREDICATES, inspectors=inspectors6, identities=inspectors8, msg="Mode.Application example 3", @@ -921,7 +921,7 @@ def report(kind): app_inspectors6, lsig_inspectors6 = test_and_report_for_app_and_lsig(6) app_inspectors8, lsig_inspectors8 = test_and_report_for_app_and_lsig(8) Invariant.full_validation( - APP_IDENTITICAL_PREDICATES, + APP_IDENTICAL_PREDICATES, inspectors=app_inspectors6, identities=app_inspectors8, msg=f"Mode.Application example 4 {abi_sum.name()=}", @@ -977,7 +977,7 @@ def test_app_and_lsig(_version: int): app_inspectors6, lsig_inspectors6 = test_app_and_lsig(6) app_inspectors8, lsig_inspectors8 = test_app_and_lsig(8) Invariant.full_validation( - APP_IDENTITICAL_PREDICATES, + APP_IDENTICAL_PREDICATES, inspectors=app_inspectors6, identities=app_inspectors8, msg="Mode.Application example 5", From b4d930064b294db6c74d450e2e501ce685335bea Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Wed, 23 Nov 2022 17:49:53 -0600 Subject: [PATCH 130/206] remove run-once forever to be skipped slow test --- tests/integration/graviton_abi_test.py | 56 +------------------------- 1 file changed, 1 insertion(+), 55 deletions(-) diff --git a/tests/integration/graviton_abi_test.py b/tests/integration/graviton_abi_test.py index a39310594..6b2f8bbce 100644 --- a/tests/integration/graviton_abi_test.py +++ b/tests/integration/graviton_abi_test.py @@ -1,9 +1,7 @@ -from itertools import product import random import pytest -from graviton.blackbox import DryRunInspector, DryRunProperty as DRProp -from graviton.invariant import Invariant, PredicateKind +from graviton.blackbox import DryRunInspector import pyteal as pt from pyteal.ast.subroutine import ABIReturnSubroutine @@ -544,55 +542,3 @@ def test_conditional_factorial(version: int): assert inspector.error(), inspector.report( args, f"FAILED: should error for {n=}", row=n + 1 ) - - -xs = list(map(pynum_to_int65tuple, (-1, 1, 3, 5, 7))) -int65_unary_function_inputs = [(x,) for x in xs] -int65_binary_function_inputs = list(product(xs, xs)) -zs = int65_binary_function_inputs -complex130_unary_function_inputs = [(z,) for z in zs] -complex130_binary_function_inputs = list(product(zs, zs)) -VERSIONING_CASES = [ - (int65_minus_cond, int65_binary_function_inputs), - (int65_sub, int65_binary_function_inputs), - (int65_mult, int65_binary_function_inputs), - (int65_negate, int65_unary_function_inputs), - (int65_add, int65_binary_function_inputs), - (complex130_add, complex130_binary_function_inputs), - (complex130_mult, complex130_binary_function_inputs), - (complex130_real, complex130_unary_function_inputs), - (complex130_imag, complex130_unary_function_inputs), - (complex130_conjugate, complex130_unary_function_inputs), - (complex130_norm_squared, complex130_unary_function_inputs), -] - -APP_PREDICATES = { - DRProp.lastLog: PredicateKind.IdenticalPair, - DRProp.status: PredicateKind.IdenticalPair, - DRProp.error: PredicateKind.IdenticalPair, - DRProp.lastMessage: PredicateKind.IdenticalPair, -} -LSIG_PREDICATES = { - DRProp.status: PredicateKind.IdenticalPair, - DRProp.error: PredicateKind.IdenticalPair, - DRProp.lastMessage: PredicateKind.IdenticalPair, -} -min_version = 5 - - -@pytest.mark.skip("Nice test, but too slow. Good to know that it ran once and passed.") -@pytest.mark.parametrize("subroutine, inputs", VERSIONING_CASES) -@pytest.mark.parametrize("mode", pt.Mode) -@pytest.mark.parametrize("version", range(min_version + 1, pt.MAX_PROGRAM_VERSION + 1)) -def test_identical_functionality(subroutine, inputs, mode, version): - ptdre = PyTealDryRunExecutor(subroutine, mode) - inspectors5 = ptdre.dryrun_on_sequence(inputs, compiler_version=min_version) - teal5 = ptdre.traces[-1] - assert teal5.startswith("#pragma version 5") - - inspectorsN = ptdre.dryrun_on_sequence(inputs, compiler_version=version) - tealN = ptdre.traces[-1] - assert tealN.startswith(f"#pragma version {version}") - - preds = APP_PREDICATES if mode == pt.Mode.Application else LSIG_PREDICATES - Invariant.full_validation(preds, inspectors=inspectors5, identities=inspectorsN) From 72a749025241f231ef21710129d71d0f5b0a98f4 Mon Sep 17 00:00:00 2001 From: Hang Su <87964331+ahangsu@users.noreply.github.com> Date: Fri, 2 Dec 2022 22:18:05 -0500 Subject: [PATCH 131/206] update test comment --- tests/integration/graviton_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index 3831e3e7d..823e1cb7a 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -565,7 +565,7 @@ def test_blackbox_subroutines_as_apps( if subr.name() == "slow_fibonacci": assert len(inspectors6) == len(inspectors8) == 18 - # NOTE the last case of inspector 8 (compilation with frame pointer) + # NOTE! the last case of inspector 8 (slow_fibonacci compilation with frame pointer) # does not blow up the 70k budget limit, so we skip specifically for this one. del inspectors6[-1] From 9df2c7bebf1a3a7e0c5aace091bd58978fcf5f9a Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 6 Dec 2022 11:07:41 +0200 Subject: [PATCH 132/206] revert - except for better local function name --- tests/integration/graviton_abi_test.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/integration/graviton_abi_test.py b/tests/integration/graviton_abi_test.py index 6011ea26b..079bbafce 100644 --- a/tests/integration/graviton_abi_test.py +++ b/tests/integration/graviton_abi_test.py @@ -312,6 +312,9 @@ def test_integer65(version: int): bbpt_add = PyTealDryRunExecutor(int65_add, pt.Mode.Application) + def pynum_to_int65tuple(n): + return (n >= 0, abs(n)) + def pytuple_to_num(t): s, x = t return x if s else -x From 4451f3dbf8553512810b1b35710f457096a834c0 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 6 Dec 2022 11:18:19 +0200 Subject: [PATCH 133/206] Apply suggestions from code review --- tests/integration/graviton_abi_test.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/integration/graviton_abi_test.py b/tests/integration/graviton_abi_test.py index d613ad444..e827b545f 100644 --- a/tests/integration/graviton_abi_test.py +++ b/tests/integration/graviton_abi_test.py @@ -300,10 +300,6 @@ def conditional_factorial(_factor: pt.abi.Uint64, *, output: pt.abi.Uint64) -> p # ---- integration test functions ---- # -def pynum_to_int65tuple(n): - return (n >= 0, abs(n)) - - @pytest.mark.parametrize("version", [6, 8]) def test_integer65(version: int): bbpt_subtract_slick = PyTealDryRunExecutor(int65_sub, pt.Mode.Application) @@ -318,7 +314,6 @@ def test_integer65(version: int): def pynum_to_int65tuple(n): return (n >= 0, abs(n)) - def pytuple_to_num(t): s, x = t return x if s else -x From 2f7a7ac5edd6a7e1cdd07de069d04b347aad9726 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 6 Dec 2022 11:24:57 +0200 Subject: [PATCH 134/206] black --- tests/integration/graviton_abi_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integration/graviton_abi_test.py b/tests/integration/graviton_abi_test.py index e827b545f..cdd6d417b 100644 --- a/tests/integration/graviton_abi_test.py +++ b/tests/integration/graviton_abi_test.py @@ -314,6 +314,7 @@ def test_integer65(version: int): def pynum_to_int65tuple(n): return (n >= 0, abs(n)) + def pytuple_to_num(t): s, x = t return x if s else -x From f9aebde355627b0ff18b2ab8cb93f72d26be3fd7 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 6 Dec 2022 11:26:37 +0200 Subject: [PATCH 135/206] unused var --- tests/integration/graviton_test.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index c2ee65f45..e4350207b 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -818,11 +818,6 @@ def euclid(x, y): msg="Mode.Application example 3", ) - # Execute on the input sequence to get a dry-run inspectors: - inspectors = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_on_sequence( - inputs, compiler_version=8 - ) - # Assert that each invariant holds on the sequences of inputs and dry-runs: for property, predicate in predicates.items(): Invariant(predicate).validates(property, inspectors8) From 4d45f09af7c2067532485e038f11fb81ec6189b8 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Wed, 14 Dec 2022 12:40:32 +0200 Subject: [PATCH 136/206] Update requirements.txt Co-authored-by: Hang Su <87964331+ahangsu@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 63e086c3b..043a9cbf2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/algorand/graviton@91fe1f6f82b2a75601cf28e94b8bb2b5c7186621 +graviton@git+https://github.com/algorand/graviton@v0.6.0 mypy==0.950 pytest==7.2.0 pytest-cov==3.0.0 From 5b4ae3358da3790063dec40a8bb49fabbb79f2eb Mon Sep 17 00:00:00 2001 From: michaeldiamant Date: Thu, 22 Dec 2022 09:42:12 -0500 Subject: [PATCH 137/206] Prove no assertions tested --- tests/integration/graviton_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index 31f77bb04..472ef4ce9 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -513,6 +513,7 @@ def blackbox_test_runner( inputs, predicates = Invariant.inputs_and_invariants( scenario, exec_mode, raw_predicates=True ) + assert predicates, "Must configure >= 1 predicate" # 3. execute dry run sequence: execute = DryRunExecutor.execute_one_dryrun From 3b20a2102b71112bdf038d584b98c5344cf33f99 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 22 Dec 2022 20:00:37 -0600 Subject: [PATCH 138/206] get the tests to actually run, and nudge invariants to pass both with/out frame pointers --- requirements.txt | 2 +- tests/integration/graviton_test.py | 142 +++++++++++------------------ 2 files changed, 54 insertions(+), 90 deletions(-) diff --git a/requirements.txt b/requirements.txt index 61515780d..08815e16c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/algorand/graviton@v0.6.0 +graviton@git+https://github.com/algorand/graviton@f6f301a5da784cb7d6a38c59745879eb624fa622 mypy==0.991 pytest==7.2.0 pytest-cov==3.0.0 diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index 3a6c93e0e..d69a59037 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -137,13 +137,6 @@ def fib(n): return a -def fib_cost(args): - cost = 17 - for n in range(1, args[0] + 1): - cost += 31 * fib(n - 1) - return cost - - # ---- Blackbox pure unit tests (Skipping for now due to flakiness) ---- # @@ -176,7 +169,7 @@ def test_stable_teal_generation(subr, mode): "inputs": [()], # since only a single input, just assert a constant in each case "assertions": { - DRProp.cost: 11, + DRProp.cost: lambda _, actual: actual in {11, 12}, # int assertions on log outputs need encoding to varuint-hex: DRProp.lastLog: Encoder.hex(2**10), # dicts have a special meaning as assertions. So in the case of "finalScratch" @@ -193,7 +186,7 @@ def test_stable_teal_generation(subr, mode): square_byref: { "inputs": [(i,) for i in range(100)], "assertions": { - DRProp.cost: lambda _, actual: 20 < actual < 22, + DRProp.cost: lambda _, actual: 20 < actual < 24, DRProp.lastLog: Encoder.hex(1337), # due to dry-run artifact of not reporting 0-valued scratchvars, # we have a special case for n=0: @@ -201,7 +194,7 @@ def test_stable_teal_generation(subr, mode): {1, 1337, (args[0] ** 2 if args[0] else 1)} ).issubset(set(actual.values())), DRProp.stackTop: 1337, - DRProp.maxStackHeight: 3, + DRProp.maxStackHeight: lambda _, actual: actual in [3, 4], DRProp.status: "PASS", DRProp.passed: True, DRProp.rejected: False, @@ -214,14 +207,14 @@ def test_stable_teal_generation(subr, mode): DRProp.cost: 14, DRProp.lastLog: { # since execution REJECTS for 0, expect last log for this case to be None - (i,): Encoder.hex(i * i) if i else None + (i,): Encoder.hex(i * i) for i in range(100) }, DRProp.finalScratch: lambda args: ( {0: args[0] ** 2, 1: args[0]} if args[0] else {} ), DRProp.stackTop: lambda args: args[0] ** 2, - DRProp.maxStackHeight: 2, + DRProp.maxStackHeight: lambda _, actual: actual in range(2, 5), DRProp.status: lambda i: "PASS" if i[0] > 0 else "REJECT", DRProp.passed: lambda i: i[0] > 0, DRProp.rejected: lambda i: i[0] == 0, @@ -231,7 +224,7 @@ def test_stable_teal_generation(subr, mode): swap: { "inputs": [(1, 2), (1, "two"), ("one", 2), ("one", "two")], "assertions": { - DRProp.cost: 27, + DRProp.cost: lambda _, actual: actual in [27, 30], DRProp.lastLog: Encoder.hex(1337), DRProp.finalScratch: lambda args: { 0: 1337, @@ -242,7 +235,7 @@ def test_stable_teal_generation(subr, mode): 5: Encoder.hex0x(args[0]), }, DRProp.stackTop: 1337, - DRProp.maxStackHeight: 2, + DRProp.maxStackHeight: lambda _, actual: actual in [2, 4], DRProp.status: "PASS", DRProp.passed: True, DRProp.rejected: False, @@ -252,10 +245,7 @@ def test_stable_teal_generation(subr, mode): string_mult: { "inputs": [("xyzw", i) for i in range(100)], "assertions": { - DRProp.cost: lambda args: 30 + 15 * args[1], - DRProp.lastLog: ( - lambda args: Encoder.hex(args[0] * args[1]) if args[1] else None - ), + DRProp.lastLog: (lambda args: Encoder.hex(args[0] * args[1])), # due to dryrun 0-scratchvar artifact, special case for i == 0: DRProp.finalScratch: lambda args: ( { @@ -274,7 +264,6 @@ def test_stable_teal_generation(subr, mode): } ), DRProp.stackTop: lambda args: len(args[0] * args[1]), - DRProp.maxStackHeight: lambda args: 3 if args[1] else 2, DRProp.status: lambda args: ("PASS" if 0 < args[1] < 45 else "REJECT"), DRProp.passed: lambda args: 0 < args[1] < 45, DRProp.rejected: lambda args: 0 >= args[1] or args[1] >= 45, @@ -284,9 +273,6 @@ def test_stable_teal_generation(subr, mode): oldfac: { "inputs": [(i,) for i in range(25)], "assertions": { - DRProp.cost: lambda args, actual: ( - actual - 40 <= 17 * args[0] <= actual + 40 - ), DRProp.lastLog: lambda args: ( Encoder.hex(fac_with_overflow(args[0])) if args[0] < 21 else None ), @@ -300,7 +286,6 @@ def test_stable_teal_generation(subr, mode): ) ), DRProp.stackTop: lambda args: fac_with_overflow(args[0]), - DRProp.maxStackHeight: lambda args: max(2, 2 * args[0]), DRProp.status: lambda args: "PASS" if args[0] < 21 else "REJECT", DRProp.passed: lambda args: args[0] < 21, DRProp.rejected: lambda args: args[0] >= 21, @@ -310,11 +295,10 @@ def test_stable_teal_generation(subr, mode): }, }, slow_fibonacci: { - "inputs": [(i,) for i in range(18)], + "inputs": [(i,) for i in range(17)], "assertions": { - DRProp.cost: lambda args: (fib_cost(args) if args[0] < 17 else 70_000), - DRProp.lastLog: lambda args: ( - Encoder.hex(fib(args[0])) if 0 < args[0] < 17 else None + DRProp.lastLog: lambda args, actual: ( + Encoder.hex(fib(args[0])) == actual if 0 <= args[0] < 17 else True ), DRProp.finalScratch: lambda args, actual: ( actual == {1: args[0], 0: fib(args[0])} @@ -325,10 +309,6 @@ def test_stable_teal_generation(subr, mode): DRProp.stackTop: lambda args, actual: ( actual == fib(args[0]) if args[0] < 17 else True ), - # similarly, we don't care about max stack height for n >= 17 - DRProp.maxStackHeight: lambda args, actual: ( - actual == max(2, 2 * args[0]) if args[0] < 17 else True - ), DRProp.status: lambda args: "PASS" if 0 < args[0] < 8 else "REJECT", DRProp.passed: lambda args: 0 < args[0] < 8, DRProp.rejected: lambda args: 0 >= args[0] or args[0] >= 8, @@ -361,15 +341,13 @@ def test_stable_teal_generation(subr, mode): square_byref: { "inputs": [(i,) for i in range(100)], "assertions": { - # DRProp.cost: lambda _, actual: 20 < actual < 22, - # DRProp.lastLog: Encoder.hex(1337), # due to dry-run artifact of not reporting 0-valued scratchvars, # we have a special case for n=0: - DRProp.finalScratch: lambda args: ( - {0: 1, 1: args[0] ** 2} if args[0] else {0: 1} - ), + DRProp.finalScratch: lambda args, actual: ( + {1, 1337, (args[0] ** 2 if args[0] else 1)} + ).issubset(set(actual.values())), DRProp.stackTop: 1337, - DRProp.maxStackHeight: 3, + DRProp.maxStackHeight: lambda _, actual: actual in [3, 4], DRProp.status: "PASS", DRProp.passed: True, DRProp.rejected: False, @@ -379,11 +357,11 @@ def test_stable_teal_generation(subr, mode): square: { "inputs": [(i,) for i in range(100)], "assertions": { - # DRProp.cost: 14, - # DRProp.lastLog: {(i,): Encoder.hex(i * i) if i else None for i in range(100)}, - DRProp.finalScratch: lambda args: ({0: args[0]} if args[0] else {}), + DRProp.finalScratch: lambda args: ( + {0: args[0] ** 2, 1: args[0]} if args[0] else {} + ), DRProp.stackTop: lambda args: args[0] ** 2, - DRProp.maxStackHeight: 2, + DRProp.maxStackHeight: lambda _, actual: actual in range(2, 5), DRProp.status: lambda i: "PASS" if i[0] > 0 else "REJECT", DRProp.passed: lambda i: i[0] > 0, DRProp.rejected: lambda i: i[0] == 0, @@ -393,17 +371,16 @@ def test_stable_teal_generation(subr, mode): swap: { "inputs": [(1, 2), (1, "two"), ("one", 2), ("one", "two")], "assertions": { - # DRProp.cost: 27, - # DRProp.lastLog: Encoder.hex(1337), DRProp.finalScratch: lambda args: { - 0: 3, - 1: 4, + 0: 1337, + 1: Encoder.hex0x(args[1]), 2: Encoder.hex0x(args[0]), - 3: Encoder.hex0x(args[1]), - 4: Encoder.hex0x(args[0]), + 3: 1, + 4: 2, + 5: Encoder.hex0x(args[0]), }, DRProp.stackTop: 1337, - DRProp.maxStackHeight: 2, + DRProp.maxStackHeight: lambda _, actual: actual in [2, 4], DRProp.status: "PASS", DRProp.passed: True, DRProp.rejected: False, @@ -413,25 +390,24 @@ def test_stable_teal_generation(subr, mode): string_mult: { "inputs": [("xyzw", i) for i in range(100)], "assertions": { - # DRProp.cost: lambda args: 30 + 15 * args[1], - # DRProp.lastLog: lambda args: Encoder.hex(args[0] * args[1]) if args[1] else None, + # due to dryrun 0-scratchvar artifact, special case for i == 0: DRProp.finalScratch: lambda args: ( { - 0: len(args[0]), - 1: args[1], - 2: args[1] + 1, - 3: Encoder.hex0x(args[0]), - 4: Encoder.hex0x(args[0] * args[1]), + 0: Encoder.hex0x(args[0] * args[1]), + 1: Encoder.hex0x(args[0] * args[1]), + 2: 1, + 3: args[1], + 4: args[1] + 1, + 5: Encoder.hex0x(args[0]), } if args[1] else { - 0: len(args[0]), - 2: args[1] + 1, - 3: Encoder.hex0x(args[0]), + 2: 1, + 4: args[1] + 1, + 5: Encoder.hex0x(args[0]), } ), DRProp.stackTop: lambda args: len(args[0] * args[1]), - DRProp.maxStackHeight: lambda args: 3 if args[1] else 2, DRProp.status: lambda args: "PASS" if args[1] else "REJECT", DRProp.passed: lambda args: bool(args[1]), DRProp.rejected: lambda args: not bool(args[1]), @@ -441,40 +417,36 @@ def test_stable_teal_generation(subr, mode): oldfac: { "inputs": [(i,) for i in range(25)], "assertions": { - # DRProp.cost: lambda args, actual: actual - 40 <= 17 * args[0] <= actual + 40, - # DRProp.lastLog: lambda args, actual: (actual is None) or (int(actual, base=16) == fac_with_overflow(args[0])), DRProp.finalScratch: lambda args: ( - {0: min(args[0], 21)} if args[0] else {} + {1: args[0], 0: fac_with_overflow(args[0])} + if 0 < args[0] < 21 + else ( + {1: min(21, args[0])} + if args[0] + else {0: fac_with_overflow(args[0])} + ) ), DRProp.stackTop: lambda args: fac_with_overflow(args[0]), - DRProp.maxStackHeight: lambda args: max(2, 2 * args[0]), DRProp.status: lambda args: "PASS" if args[0] < 21 else "REJECT", DRProp.passed: lambda args: args[0] < 21, DRProp.rejected: lambda args: args[0] >= 21, DRProp.errorMessage: lambda args, actual: ( - actual is None - if args[0] < 21 - else "logic 0 failed at line 21: * overflowed" in actual + actual is None if args[0] < 21 else "overflowed" in actual ), }, }, slow_fibonacci: { - "inputs": [(i,) for i in range(18)], + "inputs": [(i,) for i in range(17)], "assertions": { - # DRProp.cost: fib_cost, - # DRProp.lastLog: fib_last_log, - # by returning True for n >= 15, we're declaring that we don't care about the scratchvar's for such cases: DRProp.finalScratch: lambda args, actual: ( - actual == {0: args[0]} - if 0 < args[0] < 15 - else (True if args[0] else actual == {}) + actual == {1: args[0], 0: fib(args[0])} + if 0 < args[0] < 17 + else (True if args[0] >= 17 else actual == {}) ), + # we declare to "not care" about the top of the stack for n >= 15 DRProp.stackTop: lambda args, actual: ( actual == fib(args[0]) if args[0] < 15 else True ), - DRProp.maxStackHeight: lambda args, actual: ( - actual == max(2, 2 * args[0]) if args[0] < 15 else True - ), DRProp.status: lambda args: "PASS" if 0 < args[0] < 15 else "REJECT", DRProp.passed: lambda args: 0 < args[0] < 15, DRProp.rejected: lambda args: not (0 < args[0] < 15), @@ -522,10 +494,11 @@ def blackbox_test_runner( algod = algod_with_assertion() # 2. validate dry run scenarios: - inputs, predicates = Invariant.inputs_and_invariants( - scenario, exec_mode, raw_predicates=True - ) + inputs = scenario["inputs"] + predicates = scenario["assertions"] + assert inputs and isinstance(inputs, list) assert predicates, "Must configure >= 1 predicate" + assert isinstance(predicates, dict) # 3. execute dry run sequence: execute = DryRunExecutor.execute_one_dryrun @@ -539,8 +512,7 @@ def blackbox_test_runner( print(f"Saved Dry Run CSV report to {csvpath}") # 5. Sequential assertions (if provided any) - for i, type_n_assertion in enumerate(predicates.items()): - dr_prop, predicate = type_n_assertion + for i, (dr_prop, predicate) in enumerate(predicates.items()): if SKIP_SCRATCH_ASSERTIONS and dr_prop == DRProp.finalScratch: print("skipping scratch assertions because unstable slots produced") @@ -566,14 +538,6 @@ def test_blackbox_subroutines_as_apps( inspectors6 = blackbox_test_runner(subr, pt.Mode.Application, scenario, 6) inspectors8 = blackbox_test_runner(subr, pt.Mode.Application, scenario, 8) - if subr.name() == "slow_fibonacci": - assert len(inspectors6) == len(inspectors8) == 18 - # NOTE! the last case of inspector 8 (slow_fibonacci compilation with frame pointer) - # does not blow up the 70k budget limit, so we skip specifically for this one. - - del inspectors6[-1] - del inspectors8[-1] - Invariant.full_validation( APP_IDENTICAL_PREDICATES, inspectors=inspectors6, From 6e7889d88af60e3bfed16b30b88750fdd7abb52e Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Fri, 23 Dec 2022 20:29:26 -0600 Subject: [PATCH 139/206] absorb the new graviton API --- requirements.txt | 2 +- tests/blackbox.py | 33 +++++++++++++++++++++++++-------- tests/integration/opup_test.py | 2 -- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/requirements.txt b/requirements.txt index 08815e16c..b7f11a0f7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/algorand/graviton@f6f301a5da784cb7d6a38c59745879eb624fa622 +graviton@git+https://github.com/algorand/graviton@6ed2789d6ff81489d2019fbc0840db7fc0233c6c mypy==0.991 pytest==7.2.0 pytest-cov==3.0.0 diff --git a/tests/blackbox.py b/tests/blackbox.py index e0b60813e..50e169342 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -207,6 +207,23 @@ def add_trace(self, trace: Any) -> None: def is_abi(self) -> bool: return isinstance(self.subr.subroutine, ABIReturnSubroutine) + def abi_method_signature(self) -> None | str: + if self.is_abi(): + abi_subr = cast(ABIReturnSubroutine, self.subr.subroutine) + return abi_subr.method_signature() + + # create an artificial method signature + # based on the `abi_argument_types()` and `abi_return_type()` + if arg_types := self.abi_argument_types(): + if all(t is None for t in arg_types): + return None + + ret_type = self.abi_return_type() + ret = str(ret_type) if ret_type else "void" + return f"ptdre_foo({','.join(map(str, arg_types))}){ret}" + + return None + def abi_argument_types(self) -> None | list[algosdk.abi.ABIType]: if not (self.input_types or self.is_abi()): return None @@ -428,15 +445,15 @@ def dryrun_on_sequence( algod=algod_with_assertion(), teal=teal, inputs=inputs, - abi_argument_types=self.abi_argument_types(), - abi_return_type=self.abi_return_type(), + abi_method_signature=self.abi_method_signature(), + omit_method_selector=True, ), signature_case=lambda: DryRunExecutor.dryrun_logicsig_on_sequence( algod=algod_with_assertion(), teal=teal, inputs=inputs, - abi_argument_types=self.abi_argument_types(), - abi_return_type=self.abi_return_type(), + abi_method_signature=self.abi_method_signature(), + omit_method_selector=True, ), trace=teal, )(self.mode) @@ -453,15 +470,15 @@ def dryrun( algod_with_assertion(), teal, args, - self.abi_argument_types(), - self.abi_return_type(), + abi_method_signature=self.abi_method_signature(), + omit_method_selector=True, ), signature_case=lambda: DryRunExecutor.dryrun_logicsig( algod_with_assertion(), teal, args, - self.abi_argument_types(), - self.abi_return_type(), + abi_method_signature=self.abi_method_signature(), + omit_method_selector=True, ), trace=teal, )(self.mode) diff --git a/tests/integration/opup_test.py b/tests/integration/opup_test.py index afdb82f1d..7c44cb5db 100644 --- a/tests/integration/opup_test.py +++ b/tests/integration/opup_test.py @@ -27,8 +27,6 @@ def _dryrun( e.compile(pt.compiler.MAX_PROGRAM_VERSION), [], ExecutionMode.Application, - e.abi_argument_types(), - e.abi_return_type(), txn_params=DryRunExecutor.transaction_params( sender=graviton.models.ZERO_ADDRESS, sp=sp, From d8bd2db0b5ac4eb438a897f5299bbafd061c0cc1 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 26 Dec 2022 17:50:29 -0600 Subject: [PATCH 140/206] update graviton's pin to latest branch commit --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b7f11a0f7..f697918f6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/algorand/graviton@6ed2789d6ff81489d2019fbc0840db7fc0233c6c +graviton@git+https://github.com/algorand/graviton@26d47e31c3ffb5132cd29251eefcb50db0723d03 mypy==0.991 pytest==7.2.0 pytest-cov==3.0.0 From 479006998b82a667382f48f10e1361cb36d15f2f Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Sat, 31 Dec 2022 10:06:03 -0600 Subject: [PATCH 141/206] Refactor graviton usage --- requirements.txt | 2 +- tests/blackbox.py | 119 +++++++----------------- tests/integration/abi_roundtrip_test.py | 2 +- tests/integration/ecdsa_test.py | 8 +- tests/integration/graviton_abi_test.py | 12 +-- tests/integration/graviton_test.py | 38 ++++---- tests/integration/opup_test.py | 16 +++- tests/integration/pure_logicsig_test.py | 8 +- 8 files changed, 80 insertions(+), 125 deletions(-) diff --git a/requirements.txt b/requirements.txt index f697918f6..b7ba8ca1a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/algorand/graviton@26d47e31c3ffb5132cd29251eefcb50db0723d03 +graviton@git+https://github.com/tzaffi/graviton@exec-multi-dispatch mypy==0.991 pytest==7.2.0 pytest-cov==3.0.0 diff --git a/tests/blackbox.py b/tests/blackbox.py index 50e169342..e1d2942b0 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -1,5 +1,4 @@ -from typing import Any, Callable, Generic, Optional, Sequence, TypeVar, cast -from dataclasses import dataclass +from typing import Any, Callable, Sequence, cast import algosdk.abi from algosdk.v2client import algod @@ -138,37 +137,13 @@ def decorator_blackbox(func: SubroutineFnWrapper | ABIReturnSubroutine): # ---- API ---- # -Output = TypeVar("Output") -Lazy = Callable[[], Output] - - -@dataclass(frozen=True) -class _MatchMode(Generic[Output]): - runner: Optional["PyTealDryRunExecutor"] - app_case: Lazy - signature_case: Lazy - trace: Any = None - - def __post_init__(self): - if self.runner and self.trace: - self.runner.add_trace(self.trace) - - 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 mode_to_execution_mode(mode: Mode) -> blackbox.ExecutionMode: - return _MatchMode( - runner=None, - app_case=lambda: blackbox.ExecutionMode.Application, - signature_case=lambda: blackbox.ExecutionMode.Signature, - )(mode) + if mode == Mode.Application: + return blackbox.ExecutionMode.Application + if mode == Mode.Signature: + return blackbox.ExecutionMode.Signature + + raise ValueError(f"Can't handle {mode=}") class PyTealDryRunExecutor: @@ -182,9 +157,11 @@ def __init__(self, subr: BlackboxWrapper, mode: Mode): 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)" + 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: @@ -417,68 +394,40 @@ def approval(): return approval def compile(self, version: int, assemble_constants: bool = False) -> str: - return _MatchMode( - runner=self, - 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( + return compileTeal( + self.program(), + self.mode, + version=version, + assembleConstants=assemble_constants, + ) + + def dryrun_sequence( self, inputs: list[Sequence[PyTypes]], compiler_version=6, ) -> list[DryRunInspector]: teal = self.compile(compiler_version) - return _MatchMode( - self, - app_case=lambda: DryRunExecutor.dryrun_app_on_sequence( + return cast( + list[DryRunInspector], + DryRunExecutor( algod=algod_with_assertion(), + mode=mode_to_execution_mode(self.mode), teal=teal, - inputs=inputs, abi_method_signature=self.abi_method_signature(), omit_method_selector=True, - ), - signature_case=lambda: DryRunExecutor.dryrun_logicsig_on_sequence( - algod=algod_with_assertion(), - teal=teal, - inputs=inputs, - abi_method_signature=self.abi_method_signature(), - omit_method_selector=True, - ), - trace=teal, - )(self.mode) + ).run_sequence(inputs), + ) - def dryrun( + def dryrun_one( self, args: Sequence[bytes | str | int], compiler_version=6, ) -> DryRunInspector: teal = self.compile(compiler_version) - return _MatchMode( - self, - app_case=lambda: DryRunExecutor.dryrun_app( - algod_with_assertion(), - teal, - args, - abi_method_signature=self.abi_method_signature(), - omit_method_selector=True, - ), - signature_case=lambda: DryRunExecutor.dryrun_logicsig( - algod_with_assertion(), - teal, - args, - abi_method_signature=self.abi_method_signature(), - omit_method_selector=True, - ), - trace=teal, - )(self.mode) + return DryRunExecutor( + algod=algod_with_assertion(), + mode=mode_to_execution_mode(self.mode), + teal=teal, + abi_method_signature=self.abi_method_signature(), + omit_method_selector=True, + ).run_one(args) diff --git a/tests/integration/abi_roundtrip_test.py b/tests/integration/abi_roundtrip_test.py index 849d632ed..feda75870 100644 --- a/tests/integration/abi_roundtrip_test.py +++ b/tests/integration/abi_roundtrip_test.py @@ -257,7 +257,7 @@ def test_roundtrip(abi_type): args = (rand_abi_instance,) def dryrun_roundtrip(version: int): - inspector = roundtripper.dryrun(args, compiler_version=version) + inspector = roundtripper.dryrun_one(args, compiler_version=version) cost = inspector.cost() passed = inspector.passed() diff --git a/tests/integration/ecdsa_test.py b/tests/integration/ecdsa_test.py index 4efceccb7..76572e2c8 100644 --- a/tests/integration/ecdsa_test.py +++ b/tests/integration/ecdsa_test.py @@ -46,7 +46,7 @@ def verify(): ) args = [] - app_result = PyTealDryRunExecutor(verify, Mode.Application).dryrun( + app_result = PyTealDryRunExecutor(verify, Mode.Application).dryrun_one( args, compiler_version=5 ) @@ -81,7 +81,7 @@ def verify_fail(): ) args = [] - app_result = PyTealDryRunExecutor(verify_fail, Mode.Application).dryrun( + app_result = PyTealDryRunExecutor(verify_fail, Mode.Application).dryrun_one( args, compiler_version=5 ) @@ -117,7 +117,7 @@ def decompress(): ) args = [] - app_result = PyTealDryRunExecutor(decompress, Mode.Application).dryrun( + app_result = PyTealDryRunExecutor(decompress, Mode.Application).dryrun_one( args, compiler_version=5 ) @@ -158,7 +158,7 @@ def recover(): ) args = [] - app_result = PyTealDryRunExecutor(recover, Mode.Application).dryrun( + app_result = PyTealDryRunExecutor(recover, Mode.Application).dryrun_one( args, compiler_version=5 ) diff --git a/tests/integration/graviton_abi_test.py b/tests/integration/graviton_abi_test.py index cdd6d417b..b5091f219 100644 --- a/tests/integration/graviton_abi_test.py +++ b/tests/integration/graviton_abi_test.py @@ -331,7 +331,7 @@ def pytuple_to_num(t): ] def binary_dryrun(p: PyTealDryRunExecutor) -> list[DryRunInspector]: - return p.dryrun_on_sequence(binary_inputs, compiler_version=version) # type: ignore + return p.dryrun_sequence(binary_inputs, compiler_version=version) # type: ignore # Binary: inspectors_subtract_slick = binary_dryrun(bbpt_subtract_slick) @@ -343,7 +343,7 @@ def binary_dryrun(p: PyTealDryRunExecutor) -> list[DryRunInspector]: inspectors_add = binary_dryrun(bbpt_add) # Unary: - inspectors_negate = bbpt_negate.dryrun_on_sequence( + inspectors_negate = bbpt_negate.dryrun_sequence( unary_inputs, compiler_version=version # type: ignore ) @@ -444,11 +444,11 @@ def pytuple_to_complex(tt): # Binary: def binary_dryrun(p: PyTealDryRunExecutor) -> list[DryRunInspector]: - return p.dryrun_on_sequence(binary_inputs, compiler_version=version) # type: ignore + return p.dryrun_sequence(binary_inputs, compiler_version=version) # type: ignore # Unary: def unary_dryrun(p: PyTealDryRunExecutor) -> list[DryRunInspector]: - return p.dryrun_on_sequence(unary_inputs, compiler_version=version) # type: ignore + return p.dryrun_sequence(unary_inputs, compiler_version=version) # type: ignore inspectors_cplx_add = binary_dryrun(bbpt_cplx_add) @@ -523,7 +523,7 @@ def test_conditional_factorial(version: int): ptdre = PyTealDryRunExecutor(conditional_factorial, pt.Mode.Application) inputs = [(n,) for n in range(20)] - inspectors = ptdre.dryrun_on_sequence(inputs, compiler_version=version) # type: ignore + inspectors = ptdre.dryrun_sequence(inputs, compiler_version=version) # type: ignore for i, args in enumerate(inputs): inspector = inspectors[i] n = args[0] @@ -534,7 +534,7 @@ def test_conditional_factorial(version: int): n = 21 args = (n,) - inspector = ptdre.dryrun(args) + inspector = ptdre.dryrun_one(args) assert inspector.rejected(), inspector.report( args, f"FAILED: should have rejected for {n=}", row=n + 1 ) diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index d69a59037..d947e5713 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -22,7 +22,6 @@ DryRunInspector, mode_has_property, ) - from graviton.invariant import Invariant, PredicateKind PATH = Path.cwd() / "tests" / "integration" @@ -501,8 +500,7 @@ def blackbox_test_runner( assert isinstance(predicates, dict) # 3. execute dry run sequence: - execute = DryRunExecutor.execute_one_dryrun - inspectors = list(map(lambda a: execute(algod, teal, a, exec_mode), inputs)) + inspectors = DryRunExecutor(algod, exec_mode, teal).run_sequence(inputs) # 4. Statistical report: csvpath = GENERATED / "blackbox" / f"{tealfile}_v{version}.csv" @@ -579,10 +577,10 @@ def square(x): def evaluate_and_check(version: int): # evaluate the programs - app_result = PyTealDryRunExecutor(square, Mode.Application).dryrun( + app_result = PyTealDryRunExecutor(square, Mode.Application).dryrun_one( args, compiler_version=version ) - lsig_result = PyTealDryRunExecutor(square, Mode.Signature).dryrun( + lsig_result = PyTealDryRunExecutor(square, Mode.Signature).dryrun_one( args, compiler_version=version ) @@ -665,7 +663,7 @@ def euclid(x, y): def test_and_report(version: int): # assert that each result is that same as what Python's math.gcd() computes - inspectors = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_on_sequence( + inspectors = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_sequence( inputs, compiler_version=version ) for i, result in enumerate(inspectors): @@ -759,7 +757,7 @@ def euclid(x, y): ) # Execute on the input sequence to get a dry-run inspectors: - inspectors6 = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_on_sequence( + inspectors6 = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_sequence( inputs, compiler_version=6 ) @@ -768,7 +766,7 @@ def euclid(x, y): Invariant(predicate).validates(property, inspectors6) # Execute on the input sequence to get a dry-run inspectors: - inspectors8 = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_on_sequence( + inspectors8 = PyTealDryRunExecutor(euclid, Mode.Application).dryrun_sequence( inputs, compiler_version=8 ) @@ -850,10 +848,8 @@ def abi_sum(toSum: abi.DynamicArray[abi.Uint64], *, output: abi.Uint64) -> Expr: inputs.append(tuple([random.sample(choices, n)])) def test_and_report_for_app_and_lsig(_version: int): - app_inspectors = app_pytealer.dryrun_on_sequence( - inputs, compiler_version=_version - ) - lsig_inspectors = lsig_pytealer.dryrun_on_sequence( + app_inspectors = app_pytealer.dryrun_sequence(inputs, compiler_version=_version) + lsig_inspectors = lsig_pytealer.dryrun_sequence( inputs, compiler_version=_version ) for i in range(N): @@ -926,13 +922,11 @@ def cubed(n: abi.Uint64): app_pytealer = PyTealDryRunExecutor(cubed, Mode.Application) lsig_pytealer = PyTealDryRunExecutor(cubed, Mode.Signature) - inputs = [[i] for i in range(1, 11)] + inputs = [(i,) for i in range(1, 11)] def test_app_and_lsig(_version: int): - app_inspect = app_pytealer.dryrun_on_sequence(inputs, compiler_version=_version) - lsig_inspect = lsig_pytealer.dryrun_on_sequence( - inputs, compiler_version=_version - ) + app_inspect = app_pytealer.dryrun_sequence(inputs, compiler_version=_version) + lsig_inspect = lsig_pytealer.dryrun_sequence(inputs, compiler_version=_version) for index, inspect in enumerate(app_inspect): input_var = inputs[index][0] @@ -1001,7 +995,7 @@ def while_continue_accumulation(n): for x in range(30): args = [x] - lsig_result = executor.dryrun(args) + lsig_result = executor.dryrun_one(args) if x == 0: assert not lsig_result.passed() else: @@ -1011,7 +1005,7 @@ def while_continue_accumulation(n): args, "stack_top() gave unexpected results for lsig" ) - lsig_result = executor.dryrun(args, compiler_version=8) + lsig_result = executor.dryrun_one(args, compiler_version=8) if x == 0: assert not lsig_result.passed() else: @@ -1076,12 +1070,12 @@ def named_tuple_field_access( lsig_pytealer = PyTealDryRunExecutor(named_tuple_field_access, Mode.Signature) args = (False, b"1" * 32, (0, False), b"0" * 10, [True] * 4, 0) - inspector6 = lsig_pytealer.dryrun(args, compiler_version=6) + inspector6 = lsig_pytealer.dryrun_one(args, compiler_version=6) assert inspector6.stack_top() == 1 assert inspector6.passed() - inspector8 = lsig_pytealer.dryrun(args, compiler_version=8) + inspector8 = lsig_pytealer.dryrun_one(args, compiler_version=8) assert inspector8.passed() assert inspector8.stack_top() == 1 @@ -1092,7 +1086,7 @@ def named_tuple_field_access( msg="Mode.Signature NamedTuple example", ) - inspector = lsig_pytealer.dryrun(args, compiler_version=8) + inspector = lsig_pytealer.dryrun_one(args, compiler_version=8) assert inspector.passed() assert inspector.stack_top() == 1 diff --git a/tests/integration/opup_test.py b/tests/integration/opup_test.py index 7c44cb5db..f779b7934 100644 --- a/tests/integration/opup_test.py +++ b/tests/integration/opup_test.py @@ -10,7 +10,12 @@ PyTealDryRunExecutor, ) import tests -from graviton.blackbox import DryRunExecutor, DryRunInspector, ExecutionMode +from graviton.blackbox import ( + DryRunExecutor, + DryRunInspector, + ExecutionMode, + DryRunTransactionParams as TxParams, +) from algosdk.v2client.models import Account import algosdk @@ -22,18 +27,19 @@ def _dryrun( accounts: list[Account], ) -> DryRunInspector: e = PyTealDryRunExecutor(bw, pt.Mode.Application) - return DryRunExecutor.execute_one_dryrun( + return DryRunExecutor( tests.blackbox.algod_with_assertion(), + ExecutionMode.Application, e.compile(pt.compiler.MAX_PROGRAM_VERSION), + ).run_one( [], - ExecutionMode.Application, - txn_params=DryRunExecutor.transaction_params( + txn_params=TxParams.for_app( sender=graviton.models.ZERO_ADDRESS, sp=sp, index=DryRunExecutor.EXISTING_APP_CALL, on_complete=algosdk.future.transaction.OnComplete.NoOpOC, + dryrun_accounts=accounts, ), - accounts=accounts, ) diff --git a/tests/integration/pure_logicsig_test.py b/tests/integration/pure_logicsig_test.py index 0fd8e52ff..ef1f4b74d 100644 --- a/tests/integration/pure_logicsig_test.py +++ b/tests/integration/pure_logicsig_test.py @@ -12,6 +12,8 @@ DryRunExecutor as Executor, DryRunInspector as Inspector, DryRunProperty as DRProp, + ExecutionMode, + DryRunTransactionParams as TxParams, ) from graviton.invariant import Invariant @@ -87,7 +89,11 @@ def payment_amount(x, y): for args, amt in zip(inputs, amts): txn = {"amt": amt} txns.append(txn) - inspectors.append(Executor.dryrun_logicsig(ALGOD, compiled, args, **txn)) + inspectors.append( + Executor(ALGOD, ExecutionMode.Signature, compiled).run_one( + args, txn_params=TxParams(**txn) + ), + ) print( f"generating a report for (a,p,q) = {a,p,q} with {M, N} dry-run calls and spreadsheet rows" From 7617c7a61ccb4679ae0df9eff57618f6d381a1bf Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Sat, 31 Dec 2022 20:08:17 -0600 Subject: [PATCH 142/206] new PyTealDryRunExecutor.executor() method --- requirements.txt | 2 +- tests/blackbox.py | 32 ++++++++++++-------------------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/requirements.txt b/requirements.txt index b7ba8ca1a..a7a9e0254 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/tzaffi/graviton@exec-multi-dispatch +graviton@git+https://github.com/tzaffi/graviton@403278bf4eaa71c45d810099ed2e9fdbd4d9276a mypy==0.991 pytest==7.2.0 pytest-cov==3.0.0 diff --git a/tests/blackbox.py b/tests/blackbox.py index e1d2942b0..5145e895a 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -401,33 +401,25 @@ def compile(self, version: int, assemble_constants: bool = False) -> str: assembleConstants=assemble_constants, ) + def executor(self, compiler_version: int = 6) -> DryRunExecutor: + return DryRunExecutor( + algod=algod_with_assertion(), + mode=mode_to_execution_mode(self.mode), + teal=self.compile(compiler_version), + abi_method_signature=self.abi_method_signature(), + omit_method_selector=True, + ) + def dryrun_sequence( self, inputs: list[Sequence[PyTypes]], - compiler_version=6, + compiler_version: int = 6, ) -> list[DryRunInspector]: - teal = self.compile(compiler_version) - return cast( - list[DryRunInspector], - DryRunExecutor( - algod=algod_with_assertion(), - mode=mode_to_execution_mode(self.mode), - teal=teal, - abi_method_signature=self.abi_method_signature(), - omit_method_selector=True, - ).run_sequence(inputs), - ) + return cast(list, self.executor(compiler_version).run_sequence(inputs)) def dryrun_one( self, args: Sequence[bytes | str | int], compiler_version=6, ) -> DryRunInspector: - teal = self.compile(compiler_version) - return DryRunExecutor( - algod=algod_with_assertion(), - mode=mode_to_execution_mode(self.mode), - teal=teal, - abi_method_signature=self.abi_method_signature(), - omit_method_selector=True, - ).run_one(args) + return self.executor(compiler_version).run_one(args) From 5f88771c7a155887187ce6fea550a2737c2418c6 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Sat, 31 Dec 2022 20:30:18 -0600 Subject: [PATCH 143/206] pass txn_params and verbose to graviton's runners --- tests/blackbox.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index 5145e895a..7fae92608 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -4,7 +4,11 @@ from algosdk.v2client import algod from graviton import blackbox -from graviton.blackbox import DryRunInspector, DryRunExecutor +from graviton.blackbox import ( + DryRunInspector, + DryRunExecutor, + DryRunTransactionParams as TxParams, +) from graviton.models import PyTypes from pyteal.ast.subroutine import OutputKwArgInfo @@ -413,13 +417,26 @@ def executor(self, compiler_version: int = 6) -> DryRunExecutor: def dryrun_sequence( self, inputs: list[Sequence[PyTypes]], - compiler_version: int = 6, + *, + compiler_version=6, + txn_params: TxParams | None = None, + verbose: bool = False, ) -> list[DryRunInspector]: - return cast(list, self.executor(compiler_version).run_sequence(inputs)) + return cast( + list, + self.executor(compiler_version).run_sequence( + inputs, txn_params=txn_params, verbose=verbose + ), + ) def dryrun_one( self, args: Sequence[bytes | str | int], + *, compiler_version=6, + txn_params: TxParams | None = None, + verbose: bool = False, ) -> DryRunInspector: - return self.executor(compiler_version).run_one(args) + return self.executor(compiler_version).run_one( + args, txn_params=txn_params, verbose=verbose + ) From 97aff37800f0b1217c7111c155e6b86cde16741a Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Sat, 31 Dec 2022 20:30:40 -0600 Subject: [PATCH 144/206] pass txn_params and verbose to graviton's runners --- tests/integration/opup_test.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tests/integration/opup_test.py b/tests/integration/opup_test.py index f779b7934..6b87661fb 100644 --- a/tests/integration/opup_test.py +++ b/tests/integration/opup_test.py @@ -9,11 +9,9 @@ BlackboxWrapper, PyTealDryRunExecutor, ) -import tests from graviton.blackbox import ( DryRunExecutor, DryRunInspector, - ExecutionMode, DryRunTransactionParams as TxParams, ) @@ -26,13 +24,9 @@ def _dryrun( sp: algosdk.future.transaction.SuggestedParams, accounts: list[Account], ) -> DryRunInspector: - e = PyTealDryRunExecutor(bw, pt.Mode.Application) - return DryRunExecutor( - tests.blackbox.algod_with_assertion(), - ExecutionMode.Application, - e.compile(pt.compiler.MAX_PROGRAM_VERSION), - ).run_one( + return PyTealDryRunExecutor(bw, pt.Mode.Application).dryrun_one( [], + compiler_version=pt.compiler.MAX_PROGRAM_VERSION, txn_params=TxParams.for_app( sender=graviton.models.ZERO_ADDRESS, sp=sp, From 1f97e303e909e0356038532bb145d71aa36c5468 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Sat, 31 Dec 2022 20:43:58 -0600 Subject: [PATCH 145/206] don't re-instantiate the executor at every iteration --- tests/integration/pure_logicsig_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/integration/pure_logicsig_test.py b/tests/integration/pure_logicsig_test.py index ef1f4b74d..3a67951de 100644 --- a/tests/integration/pure_logicsig_test.py +++ b/tests/integration/pure_logicsig_test.py @@ -9,7 +9,7 @@ from tests.blackbox import algod_with_assertion from graviton.blackbox import ( - DryRunExecutor as Executor, + DryRunExecutor, DryRunInspector as Inspector, DryRunProperty as DRProp, ExecutionMode, @@ -71,6 +71,8 @@ def factorizer_game_check(a: int, p: int, q: int, M: int, N: int): mode=Mode.Signature, assembleConstants=True, ) + executor = DryRunExecutor(ALGOD, ExecutionMode.Signature, compiled) + inputs = list(inputs_for_coefficients(a, p, q, M, N)) N = len(inputs) @@ -90,9 +92,7 @@ def payment_amount(x, y): txn = {"amt": amt} txns.append(txn) inspectors.append( - Executor(ALGOD, ExecutionMode.Signature, compiled).run_one( - args, txn_params=TxParams(**txn) - ), + executor.run_one(args, txn_params=TxParams(**txn)), ) print( From 315fc23a7708862c2773a8efdddb4e11a1c8914d Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Sun, 1 Jan 2023 11:40:12 -0600 Subject: [PATCH 146/206] remove now unused add_trace() --- tests/blackbox.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index 7fae92608..689068bf3 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -180,11 +180,6 @@ def __init__(self, subr: BlackboxWrapper, mode: Mode): self._pyteal_lambda: Callable[..., Expr] = approval - self.traces: list = [] - - def add_trace(self, trace: Any) -> None: - self.traces.append(trace) - def is_abi(self) -> bool: return isinstance(self.subr.subroutine, ABIReturnSubroutine) From 09261e88a9b20168fcd773e20e68d81cbf33dccd Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Sun, 1 Jan 2023 12:02:48 -0600 Subject: [PATCH 147/206] lint --- tests/blackbox.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index 689068bf3..3186f8dc9 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -1,4 +1,4 @@ -from typing import Any, Callable, Sequence, cast +from typing import Callable, Sequence, cast import algosdk.abi from algosdk.v2client import algod From 18150bc7a4fc97a8373a0e9def6b44e018d072f1 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Sun, 1 Jan 2023 14:40:58 -0600 Subject: [PATCH 148/206] Update to requirements.txt to latest graviton commit --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a7a9e0254..1d80f0cd5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/tzaffi/graviton@403278bf4eaa71c45d810099ed2e9fdbd4d9276a +graviton@git+https://github.com/tzaffi/graviton@a68208e694ee359bd98a504e849017a61c4b14dd mypy==0.991 pytest==7.2.0 pytest-cov==3.0.0 From 69519c59824662bda150acdb8f61acc240149a97 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 3 Jan 2023 16:24:46 -0600 Subject: [PATCH 149/206] pin to graviton 0.7.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1d80f0cd5..10b65a89e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/tzaffi/graviton@a68208e694ee359bd98a504e849017a61c4b14dd +graviton@git+https://github.com/tzaffi/graviton@v0.7.0 mypy==0.991 pytest==7.2.0 pytest-cov==3.0.0 From 3ad2f2ed4c0eec3cbd0f41f61d490fa746c9ad09 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 3 Jan 2023 16:26:29 -0600 Subject: [PATCH 150/206] fix gravition pin --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 10b65a89e..b7ba8ca1a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/tzaffi/graviton@v0.7.0 +graviton@git+https://github.com/tzaffi/graviton@exec-multi-dispatch mypy==0.991 pytest==7.2.0 pytest-cov==3.0.0 From 0ee255c8c88418183a2e7487a173fe81d1906712 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 3 Jan 2023 16:29:29 -0600 Subject: [PATCH 151/206] pin to v0.7.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index f697918f6..609ac6e51 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/algorand/graviton@26d47e31c3ffb5132cd29251eefcb50db0723d03 +graviton@git+https://github.com/algorand/graviton@v0.7.0 mypy==0.991 pytest==7.2.0 pytest-cov==3.0.0 From ed1baf46407f8e8812ce1cc9c03a5d23aaffb8ed Mon Sep 17 00:00:00 2001 From: Lemuel Solomon S <49029145+alvorithm@users.noreply.github.com> Date: Wed, 28 Dec 2022 18:35:16 +0200 Subject: [PATCH 152/206] Typo fix in docs (#625) --- docs/overview.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/overview.rst b/docs/overview.rst index b544623f1..54466c08d 100644 --- a/docs/overview.rst +++ b/docs/overview.rst @@ -9,7 +9,7 @@ Below is an example of writing a basic stateless smart contract that allows a sp .. literalinclude:: ../examples/signature/basic.py :language: python -As shown in this exmaple, the logic of smart contract is expressed using PyTeal expressions constructed in Python. PyTeal overloads Python's arithmetic operators +As shown in this example, the logic of smart contract is expressed using PyTeal expressions constructed in Python. PyTeal overloads Python's arithmetic operators such as :code:`<` and :code:`==` (more overloaded operators can be found in :ref:`arithmetic_expressions`), allowing Python developers express smart contract logic more naturally. Lastly, :any:`compileTeal` is called to convert an PyTeal expression From fc06c17afe7e3ce3ff13a6b9d3571a0467789c53 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 12 Jan 2023 19:32:09 -0600 Subject: [PATCH 153/206] flake8 --- tests/blackbox.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index 27f1026b4..7fae92608 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -1,5 +1,4 @@ -from typing import Any, Callable, Generic, Optional, Sequence, TypeVar, cast -from dataclasses import dataclass +from typing import Any, Callable, Sequence, cast import algosdk.abi from algosdk.v2client import algod From 3232a0905f26269210c76f09410a051bb87cc7db Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 12 Jan 2023 20:08:57 -0600 Subject: [PATCH 154/206] =?UTF-8?q?=F0=9F=A4=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/integration/graviton_abi_test.py | 2 +- tests/integration/graviton_test.py | 17 +++++------------ tests/integration/opup_test.py | 8 ++++---- tests/integration/pure_logicsig_test.py | 3 +-- 4 files changed, 11 insertions(+), 19 deletions(-) diff --git a/tests/integration/graviton_abi_test.py b/tests/integration/graviton_abi_test.py index b5091f219..b73132799 100644 --- a/tests/integration/graviton_abi_test.py +++ b/tests/integration/graviton_abi_test.py @@ -1,7 +1,7 @@ import random import pytest -from graviton.blackbox import DryRunInspector +from graviton.inspector import DryRunInspector import pyteal as pt from pyteal.ast.subroutine import ABIReturnSubroutine diff --git a/tests/integration/graviton_test.py b/tests/integration/graviton_test.py index d947e5713..7f80e70a3 100644 --- a/tests/integration/graviton_test.py +++ b/tests/integration/graviton_test.py @@ -15,14 +15,9 @@ PyTealDryRunExecutor, ) -from graviton.blackbox import ( - DryRunProperty as DRProp, - DryRunEncoder as Encoder, - DryRunExecutor, - DryRunInspector, - mode_has_property, -) -from graviton.invariant import Invariant, PredicateKind +from graviton.blackbox import DryRunEncoder as Encoder, DryRunExecutor +from graviton.inspector import DryRunProperty as DRProp, DryRunInspector +from graviton.invariant import Invariant, PredicateKind, mode_has_property PATH = Path.cwd() / "tests" / "integration" FIXTURES = PATH / "teal" @@ -695,10 +690,8 @@ def blackbox_pyteal_example3(): import math import random - from graviton.blackbox import ( - DryRunEncoder, - DryRunProperty as DRProp, - ) + from graviton.blackbox import DryRunEncoder + from graviton.inspector import DryRunProperty as DRProp from graviton.invariant import Invariant from pyteal import If, Int, Mod, Mode, Subroutine, TealType diff --git a/tests/integration/opup_test.py b/tests/integration/opup_test.py index f47a49b61..b1a02ad5e 100644 --- a/tests/integration/opup_test.py +++ b/tests/integration/opup_test.py @@ -22,7 +22,7 @@ def _dryrun( bw: BlackboxWrapper, sp: algosdk.transaction.SuggestedParams, - accounts: list[Account], + accounts: list[Account | str], ) -> DryRunInspector: return PyTealDryRunExecutor(bw, pt.Mode.Application).dryrun_one( [], @@ -31,7 +31,7 @@ def _dryrun( sender=graviton.models.ZERO_ADDRESS, sp=sp, index=DryRunExecutor.EXISTING_APP_CALL, - on_complete=algosdk.future.transaction.OnComplete.NoOpOC, + on_complete=algosdk.transaction.OnComplete.NoOpOC, dryrun_accounts=accounts, ), ) @@ -60,7 +60,7 @@ def maximize_budget(): ) if with_funding: - accounts = ( + accounts: list[Account | str] = ( [ Account( address=algosdk.logic.get_application_address( @@ -120,7 +120,7 @@ def ensure_budget(): ) if with_funding: - accounts = ( + accounts: list[Account | str] = ( [ Account( address=algosdk.logic.get_application_address( diff --git a/tests/integration/pure_logicsig_test.py b/tests/integration/pure_logicsig_test.py index 3a67951de..510f70f28 100644 --- a/tests/integration/pure_logicsig_test.py +++ b/tests/integration/pure_logicsig_test.py @@ -10,11 +10,10 @@ from tests.blackbox import algod_with_assertion from graviton.blackbox import ( DryRunExecutor, - DryRunInspector as Inspector, - DryRunProperty as DRProp, ExecutionMode, DryRunTransactionParams as TxParams, ) +from graviton.inspector import DryRunInspector as Inspector, DryRunProperty as DRProp from graviton.invariant import Invariant REPORTS_DIR = Path.cwd() / "tests" / "integration" / "reports" From d0331b0f14984c5ecd8884333675295dc15151bd Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 16 Jan 2023 22:32:45 -0600 Subject: [PATCH 155/206] Trigger a build against head of depending graviton branch --- tests/blackbox.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index 7fae92608..00e85e9ef 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -163,7 +163,7 @@ def __init__(self, subr: BlackboxWrapper, mode: Mode): input_types = subr.input_types assert input_types is not None, ( "please provide input_types in your @Subroutine or @ABIReturnSubroutine " - "annotation " + "annotation. " "(this is crucial for generating proper end-to-end testable PyTeal)" ) From df63e8c52c037a83e874926370b2a89e931044ca Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 16 Jan 2023 23:08:21 -0600 Subject: [PATCH 156/206] move the router part of the compile_test to new abi_router_test.py, and add fixtures for teal outputs --- pyteal/compiler/compiler_test.py | 2431 ----------------- tests/integration/abi_router_test.py | 240 ++ .../router/questionableFP_approval_v8.teal | 512 ++++ .../teal/router/questionableFP_clear_v8.teal | 92 + .../teal/router/questionable_approval_v6.teal | 460 ++++ .../teal/router/questionable_clear_v6.teal | 70 + .../teal/router/yaccFP_approval_v8.teal | 493 ++++ .../teal/router/yaccFP_clear_v8.teal | 85 + .../teal/router/yacc_approval_v6.teal | 441 +++ .../teal/router/yacc_clear_v6.teal | 63 + 10 files changed, 2456 insertions(+), 2431 deletions(-) create mode 100644 tests/integration/abi_router_test.py create mode 100644 tests/integration/teal/router/questionableFP_approval_v8.teal create mode 100644 tests/integration/teal/router/questionableFP_clear_v8.teal create mode 100644 tests/integration/teal/router/questionable_approval_v6.teal create mode 100644 tests/integration/teal/router/questionable_clear_v6.teal create mode 100644 tests/integration/teal/router/yaccFP_approval_v8.teal create mode 100644 tests/integration/teal/router/yaccFP_clear_v8.teal create mode 100644 tests/integration/teal/router/yacc_approval_v6.teal create mode 100644 tests/integration/teal/router/yacc_clear_v6.teal diff --git a/pyteal/compiler/compiler_test.py b/pyteal/compiler/compiler_test.py index 0fa3acf02..6909d3db1 100644 --- a/pyteal/compiler/compiler_test.py +++ b/pyteal/compiler/compiler_test.py @@ -2193,2434 +2193,3 @@ def access_b4_store(magic_num: pt.abi.Uint64, *, output: pt.abi.Uint64): with pytest.raises(pt.TealInternalError): pt.compileTeal(program_access_b4_store_broken, pt.Mode.Application, version=6) - - -def test_router_app(): - def add_methods_to_router(router: pt.Router): - @pt.ABIReturnSubroutine - def add( - a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 - ) -> pt.Expr: - return output.set(a.get() + b.get()) - - meth = router.add_method_handler(add) - assert meth.method_signature() == "add(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def sub( - a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 - ) -> pt.Expr: - return output.set(a.get() - b.get()) - - meth = router.add_method_handler(sub) - assert meth.method_signature() == "sub(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def mul( - a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 - ) -> pt.Expr: - return output.set(a.get() * b.get()) - - meth = router.add_method_handler(mul) - assert meth.method_signature() == "mul(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def div( - a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 - ) -> pt.Expr: - return output.set(a.get() / b.get()) - - meth = router.add_method_handler(div) - assert meth.method_signature() == "div(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def mod( - a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 - ) -> pt.Expr: - return output.set(a.get() % b.get()) - - meth = router.add_method_handler(mod) - assert meth.method_signature() == "mod(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def all_laid_to_args( - _a: pt.abi.Uint64, - _b: pt.abi.Uint64, - _c: pt.abi.Uint64, - _d: pt.abi.Uint64, - _e: pt.abi.Uint64, - _f: pt.abi.Uint64, - _g: pt.abi.Uint64, - _h: pt.abi.Uint64, - _i: pt.abi.Uint64, - _j: pt.abi.Uint64, - _k: pt.abi.Uint64, - _l: pt.abi.Uint64, - _m: pt.abi.Uint64, - _n: pt.abi.Uint64, - _o: pt.abi.Uint64, - _p: pt.abi.Uint64, - *, - output: pt.abi.Uint64, - ): - return output.set( - _a.get() - + _b.get() - + _c.get() - + _d.get() - + _e.get() - + _f.get() - + _g.get() - + _h.get() - + _i.get() - + _j.get() - + _k.get() - + _l.get() - + _m.get() - + _n.get() - + _o.get() - + _p.get() - ) - - meth = router.add_method_handler(all_laid_to_args) - assert ( - meth.method_signature() - == "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" - ) - - @pt.ABIReturnSubroutine - def empty_return_subroutine() -> pt.Expr: - return pt.Log(pt.Bytes("appear in both approval and clear state")) - - meth = router.add_method_handler( - empty_return_subroutine, - method_config=pt.MethodConfig( - no_op=pt.CallConfig.CALL, - opt_in=pt.CallConfig.ALL, - clear_state=pt.CallConfig.CALL, - ), - ) - assert meth.method_signature() == "empty_return_subroutine()void" - - @pt.ABIReturnSubroutine - def log_1(*, output: pt.abi.Uint64) -> pt.Expr: - return output.set(1) - - meth = router.add_method_handler( - log_1, - method_config=pt.MethodConfig( - no_op=pt.CallConfig.CALL, - opt_in=pt.CallConfig.CALL, - clear_state=pt.CallConfig.CALL, - ), - ) - - assert meth.method_signature() == "log_1()uint64" - - @pt.ABIReturnSubroutine - def log_creation(*, output: pt.abi.String) -> pt.Expr: - return output.set("logging creation") - - meth = router.add_method_handler( - log_creation, method_config=pt.MethodConfig(no_op=pt.CallConfig.CREATE) - ) - assert meth.method_signature() == "log_creation()string" - - @pt.ABIReturnSubroutine - def approve_if_odd(condition_encoding: pt.abi.Uint32) -> pt.Expr: - return ( - pt.If(condition_encoding.get() % pt.Int(2)) - .Then(pt.Approve()) - .Else(pt.Reject()) - ) - - meth = router.add_method_handler( - approve_if_odd, - method_config=pt.MethodConfig( - no_op=pt.CallConfig.NEVER, clear_state=pt.CallConfig.CALL - ), - ) - assert meth.method_signature() == "approve_if_odd(uint32)void" - - on_completion_actions = pt.BareCallActions( - opt_in=pt.OnCompleteAction.call_only(pt.Log(pt.Bytes("optin call"))), - clear_state=pt.OnCompleteAction.call_only(pt.Approve()), - ) - - with pytest.raises(pt.TealInputError) as e: - pt.Router("will-error", on_completion_actions).compile_program( - version=6, optimize=pt.OptimizeOptions(frame_pointers=True) - ) - - assert "Frame pointers aren't available" in str(e.value) - - _router_with_oc = pt.Router( - "ASimpleQuestionablyRobustContract", on_completion_actions - ) - add_methods_to_router(_router_with_oc) - ( - actual_ap_with_oc_compiled, - actual_csp_with_oc_compiled, - _, - ) = _router_with_oc.compile_program(version=6) - - expected_ap_with_oc = """#pragma version 6 -txn NumAppArgs -int 0 -== -bnz main_l20 -txna ApplicationArgs 0 -method "add(uint64,uint64)uint64" -== -bnz main_l19 -txna ApplicationArgs 0 -method "sub(uint64,uint64)uint64" -== -bnz main_l18 -txna ApplicationArgs 0 -method "mul(uint64,uint64)uint64" -== -bnz main_l17 -txna ApplicationArgs 0 -method "div(uint64,uint64)uint64" -== -bnz main_l16 -txna ApplicationArgs 0 -method "mod(uint64,uint64)uint64" -== -bnz main_l15 -txna ApplicationArgs 0 -method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" -== -bnz main_l14 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l13 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l12 -txna ApplicationArgs 0 -method "log_creation()string" -== -bnz main_l11 -err -main_l11: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -== -&& -assert -callsub logcreation_8 -store 67 -byte 0x151f7c75 -load 67 -concat -log -int 1 -return -main_l12: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -txn ApplicationID -int 0 -!= -&& -|| -assert -callsub log1_7 -store 65 -byte 0x151f7c75 -load 65 -itob -concat -log -int 1 -return -main_l13: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -|| -assert -callsub emptyreturnsubroutine_6 -int 1 -return -main_l14: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 30 -txna ApplicationArgs 2 -btoi -store 31 -txna ApplicationArgs 3 -btoi -store 32 -txna ApplicationArgs 4 -btoi -store 33 -txna ApplicationArgs 5 -btoi -store 34 -txna ApplicationArgs 6 -btoi -store 35 -txna ApplicationArgs 7 -btoi -store 36 -txna ApplicationArgs 8 -btoi -store 37 -txna ApplicationArgs 9 -btoi -store 38 -txna ApplicationArgs 10 -btoi -store 39 -txna ApplicationArgs 11 -btoi -store 40 -txna ApplicationArgs 12 -btoi -store 41 -txna ApplicationArgs 13 -btoi -store 42 -txna ApplicationArgs 14 -btoi -store 43 -txna ApplicationArgs 15 -store 46 -load 46 -int 0 -extract_uint64 -store 44 -load 46 -int 8 -extract_uint64 -store 45 -load 30 -load 31 -load 32 -load 33 -load 34 -load 35 -load 36 -load 37 -load 38 -load 39 -load 40 -load 41 -load 42 -load 43 -load 44 -load 45 -callsub alllaidtoargs_5 -store 47 -byte 0x151f7c75 -load 47 -itob -concat -log -int 1 -return -main_l15: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 24 -txna ApplicationArgs 2 -btoi -store 25 -load 24 -load 25 -callsub mod_4 -store 26 -byte 0x151f7c75 -load 26 -itob -concat -log -int 1 -return -main_l16: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 18 -txna ApplicationArgs 2 -btoi -store 19 -load 18 -load 19 -callsub div_3 -store 20 -byte 0x151f7c75 -load 20 -itob -concat -log -int 1 -return -main_l17: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 12 -txna ApplicationArgs 2 -btoi -store 13 -load 12 -load 13 -callsub mul_2 -store 14 -byte 0x151f7c75 -load 14 -itob -concat -log -int 1 -return -main_l18: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 6 -txna ApplicationArgs 2 -btoi -store 7 -load 6 -load 7 -callsub sub_1 -store 8 -byte 0x151f7c75 -load 8 -itob -concat -log -int 1 -return -main_l19: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 0 -txna ApplicationArgs 2 -btoi -store 1 -load 0 -load 1 -callsub add_0 -store 2 -byte 0x151f7c75 -load 2 -itob -concat -log -int 1 -return -main_l20: -txn OnCompletion -int OptIn -== -bnz main_l22 -err -main_l22: -txn ApplicationID -int 0 -!= -assert -byte "optin call" -log -int 1 -return - -// add -add_0: -store 4 -store 3 -load 3 -load 4 -+ -store 5 -load 5 -retsub - -// sub -sub_1: -store 10 -store 9 -load 9 -load 10 -- -store 11 -load 11 -retsub - -// mul -mul_2: -store 16 -store 15 -load 15 -load 16 -* -store 17 -load 17 -retsub - -// div -div_3: -store 22 -store 21 -load 21 -load 22 -/ -store 23 -load 23 -retsub - -// mod -mod_4: -store 28 -store 27 -load 27 -load 28 -% -store 29 -load 29 -retsub - -// all_laid_to_args -alllaidtoargs_5: -store 63 -store 62 -store 61 -store 60 -store 59 -store 58 -store 57 -store 56 -store 55 -store 54 -store 53 -store 52 -store 51 -store 50 -store 49 -store 48 -load 48 -load 49 -+ -load 50 -+ -load 51 -+ -load 52 -+ -load 53 -+ -load 54 -+ -load 55 -+ -load 56 -+ -load 57 -+ -load 58 -+ -load 59 -+ -load 60 -+ -load 61 -+ -load 62 -+ -load 63 -+ -store 64 -load 64 -retsub - -// empty_return_subroutine -emptyreturnsubroutine_6: -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_7: -int 1 -store 66 -load 66 -retsub - -// log_creation -logcreation_8: -byte 0x00106c6f6767696e67206372656174696f6e -store 68 -load 68 -retsub""".strip() - - assert expected_ap_with_oc == actual_ap_with_oc_compiled - - expected_csp_with_oc = """#pragma version 6 -txn NumAppArgs -int 0 -== -bnz main_l8 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l7 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l6 -txna ApplicationArgs 0 -method "approve_if_odd(uint32)void" -== -bnz main_l5 -err -main_l5: -txna ApplicationArgs 1 -int 0 -extract_uint32 -store 2 -load 2 -callsub approveifodd_2 -int 1 -return -main_l6: -callsub log1_1 -store 1 -byte 0x151f7c75 -load 1 -itob -concat -log -int 1 -return -main_l7: -callsub emptyreturnsubroutine_0 -int 1 -return -main_l8: -int 1 -return - -// empty_return_subroutine -emptyreturnsubroutine_0: -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_1: -int 1 -store 0 -load 0 -retsub - -// approve_if_odd -approveifodd_2: -store 3 -load 3 -int 2 -% -bnz approveifodd_2_l2 -int 0 -return -approveifodd_2_l2: -int 1 -return""".strip() - assert expected_csp_with_oc == actual_csp_with_oc_compiled - - _router_without_oc = pt.Router("yetAnotherContractConstructedFromRouter") - add_methods_to_router(_router_without_oc) - ( - actual_ap_without_oc_compiled, - actual_csp_without_oc_compiled, - _, - ) = _router_without_oc.compile_program(version=6) - expected_ap_without_oc = """#pragma version 6 -txna ApplicationArgs 0 -method "add(uint64,uint64)uint64" -== -bnz main_l18 -txna ApplicationArgs 0 -method "sub(uint64,uint64)uint64" -== -bnz main_l17 -txna ApplicationArgs 0 -method "mul(uint64,uint64)uint64" -== -bnz main_l16 -txna ApplicationArgs 0 -method "div(uint64,uint64)uint64" -== -bnz main_l15 -txna ApplicationArgs 0 -method "mod(uint64,uint64)uint64" -== -bnz main_l14 -txna ApplicationArgs 0 -method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" -== -bnz main_l13 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l12 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l11 -txna ApplicationArgs 0 -method "log_creation()string" -== -bnz main_l10 -err -main_l10: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -== -&& -assert -callsub logcreation_8 -store 67 -byte 0x151f7c75 -load 67 -concat -log -int 1 -return -main_l11: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -txn ApplicationID -int 0 -!= -&& -|| -assert -callsub log1_7 -store 65 -byte 0x151f7c75 -load 65 -itob -concat -log -int 1 -return -main_l12: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -|| -assert -callsub emptyreturnsubroutine_6 -int 1 -return -main_l13: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 30 -txna ApplicationArgs 2 -btoi -store 31 -txna ApplicationArgs 3 -btoi -store 32 -txna ApplicationArgs 4 -btoi -store 33 -txna ApplicationArgs 5 -btoi -store 34 -txna ApplicationArgs 6 -btoi -store 35 -txna ApplicationArgs 7 -btoi -store 36 -txna ApplicationArgs 8 -btoi -store 37 -txna ApplicationArgs 9 -btoi -store 38 -txna ApplicationArgs 10 -btoi -store 39 -txna ApplicationArgs 11 -btoi -store 40 -txna ApplicationArgs 12 -btoi -store 41 -txna ApplicationArgs 13 -btoi -store 42 -txna ApplicationArgs 14 -btoi -store 43 -txna ApplicationArgs 15 -store 46 -load 46 -int 0 -extract_uint64 -store 44 -load 46 -int 8 -extract_uint64 -store 45 -load 30 -load 31 -load 32 -load 33 -load 34 -load 35 -load 36 -load 37 -load 38 -load 39 -load 40 -load 41 -load 42 -load 43 -load 44 -load 45 -callsub alllaidtoargs_5 -store 47 -byte 0x151f7c75 -load 47 -itob -concat -log -int 1 -return -main_l14: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 24 -txna ApplicationArgs 2 -btoi -store 25 -load 24 -load 25 -callsub mod_4 -store 26 -byte 0x151f7c75 -load 26 -itob -concat -log -int 1 -return -main_l15: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 18 -txna ApplicationArgs 2 -btoi -store 19 -load 18 -load 19 -callsub div_3 -store 20 -byte 0x151f7c75 -load 20 -itob -concat -log -int 1 -return -main_l16: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 12 -txna ApplicationArgs 2 -btoi -store 13 -load 12 -load 13 -callsub mul_2 -store 14 -byte 0x151f7c75 -load 14 -itob -concat -log -int 1 -return -main_l17: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 6 -txna ApplicationArgs 2 -btoi -store 7 -load 6 -load 7 -callsub sub_1 -store 8 -byte 0x151f7c75 -load 8 -itob -concat -log -int 1 -return -main_l18: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 0 -txna ApplicationArgs 2 -btoi -store 1 -load 0 -load 1 -callsub add_0 -store 2 -byte 0x151f7c75 -load 2 -itob -concat -log -int 1 -return - -// add -add_0: -store 4 -store 3 -load 3 -load 4 -+ -store 5 -load 5 -retsub - -// sub -sub_1: -store 10 -store 9 -load 9 -load 10 -- -store 11 -load 11 -retsub - -// mul -mul_2: -store 16 -store 15 -load 15 -load 16 -* -store 17 -load 17 -retsub - -// div -div_3: -store 22 -store 21 -load 21 -load 22 -/ -store 23 -load 23 -retsub - -// mod -mod_4: -store 28 -store 27 -load 27 -load 28 -% -store 29 -load 29 -retsub - -// all_laid_to_args -alllaidtoargs_5: -store 63 -store 62 -store 61 -store 60 -store 59 -store 58 -store 57 -store 56 -store 55 -store 54 -store 53 -store 52 -store 51 -store 50 -store 49 -store 48 -load 48 -load 49 -+ -load 50 -+ -load 51 -+ -load 52 -+ -load 53 -+ -load 54 -+ -load 55 -+ -load 56 -+ -load 57 -+ -load 58 -+ -load 59 -+ -load 60 -+ -load 61 -+ -load 62 -+ -load 63 -+ -store 64 -load 64 -retsub - -// empty_return_subroutine -emptyreturnsubroutine_6: -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_7: -int 1 -store 66 -load 66 -retsub - -// log_creation -logcreation_8: -byte 0x00106c6f6767696e67206372656174696f6e -store 68 -load 68 -retsub""".strip() - assert actual_ap_without_oc_compiled == expected_ap_without_oc - - expected_csp_without_oc = """#pragma version 6 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l6 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l5 -txna ApplicationArgs 0 -method "approve_if_odd(uint32)void" -== -bnz main_l4 -err -main_l4: -txna ApplicationArgs 1 -int 0 -extract_uint32 -store 2 -load 2 -callsub approveifodd_2 -int 1 -return -main_l5: -callsub log1_1 -store 1 -byte 0x151f7c75 -load 1 -itob -concat -log -int 1 -return -main_l6: -callsub emptyreturnsubroutine_0 -int 1 -return - -// empty_return_subroutine -emptyreturnsubroutine_0: -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_1: -int 1 -store 0 -load 0 -retsub - -// approve_if_odd -approveifodd_2: -store 3 -load 3 -int 2 -% -bnz approveifodd_2_l2 -int 0 -return -approveifodd_2_l2: -int 1 -return""".strip() - assert actual_csp_without_oc_compiled == expected_csp_without_oc - - _router_with_oc = pt.Router( - "QuestionableRouterGenerateCodeWithFramePointer", on_completion_actions - ) - add_methods_to_router(_router_with_oc) - ( - actual_ap_with_oc_compiled, - actual_csp_with_oc_compiled, - _, - ) = _router_with_oc.compile_program(version=8) - - expected_ap_with_oc = """#pragma version 8 -txn NumAppArgs -int 0 -== -bnz main_l20 -txna ApplicationArgs 0 -method "add(uint64,uint64)uint64" -== -bnz main_l19 -txna ApplicationArgs 0 -method "sub(uint64,uint64)uint64" -== -bnz main_l18 -txna ApplicationArgs 0 -method "mul(uint64,uint64)uint64" -== -bnz main_l17 -txna ApplicationArgs 0 -method "div(uint64,uint64)uint64" -== -bnz main_l16 -txna ApplicationArgs 0 -method "mod(uint64,uint64)uint64" -== -bnz main_l15 -txna ApplicationArgs 0 -method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" -== -bnz main_l14 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l13 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l12 -txna ApplicationArgs 0 -method "log_creation()string" -== -bnz main_l11 -err -main_l11: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -== -&& -assert -callsub logcreationcaster_17 -int 1 -return -main_l12: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -txn ApplicationID -int 0 -!= -&& -|| -assert -callsub log1caster_16 -int 1 -return -main_l13: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -|| -assert -callsub emptyreturnsubroutinecaster_15 -int 1 -return -main_l14: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub alllaidtoargscaster_14 -int 1 -return -main_l15: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub modcaster_13 -int 1 -return -main_l16: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub divcaster_12 -int 1 -return -main_l17: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub mulcaster_11 -int 1 -return -main_l18: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub subcaster_10 -int 1 -return -main_l19: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub addcaster_9 -int 1 -return -main_l20: -txn OnCompletion -int OptIn -== -bnz main_l22 -err -main_l22: -txn ApplicationID -int 0 -!= -assert -byte "optin call" -log -int 1 -return - -// add -add_0: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -+ -frame_bury 0 -retsub - -// sub -sub_1: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -- -frame_bury 0 -retsub - -// mul -mul_2: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -* -frame_bury 0 -retsub - -// div -div_3: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -/ -frame_bury 0 -retsub - -// mod -mod_4: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -% -frame_bury 0 -retsub - -// all_laid_to_args -alllaidtoargs_5: -proto 16 1 -int 0 -frame_dig -16 -frame_dig -15 -+ -frame_dig -14 -+ -frame_dig -13 -+ -frame_dig -12 -+ -frame_dig -11 -+ -frame_dig -10 -+ -frame_dig -9 -+ -frame_dig -8 -+ -frame_dig -7 -+ -frame_dig -6 -+ -frame_dig -5 -+ -frame_dig -4 -+ -frame_dig -3 -+ -frame_dig -2 -+ -frame_dig -1 -+ -frame_bury 0 -retsub - -// empty_return_subroutine -emptyreturnsubroutine_6: -proto 0 0 -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_7: -proto 0 1 -int 0 -int 1 -frame_bury 0 -retsub - -// log_creation -logcreation_8: -proto 0 1 -byte "" -byte 0x00106c6f6767696e67206372656174696f6e -frame_bury 0 -retsub - -// add_caster -addcaster_9: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub add_0 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// sub_caster -subcaster_10: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub sub_1 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// mul_caster -mulcaster_11: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub mul_2 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// div_caster -divcaster_12: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub div_3 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// mod_caster -modcaster_13: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub mod_4 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// all_laid_to_args_caster -alllaidtoargscaster_14: -proto 0 0 -int 0 -dupn 16 -byte "" -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -txna ApplicationArgs 3 -btoi -frame_bury 3 -txna ApplicationArgs 4 -btoi -frame_bury 4 -txna ApplicationArgs 5 -btoi -frame_bury 5 -txna ApplicationArgs 6 -btoi -frame_bury 6 -txna ApplicationArgs 7 -btoi -frame_bury 7 -txna ApplicationArgs 8 -btoi -frame_bury 8 -txna ApplicationArgs 9 -btoi -frame_bury 9 -txna ApplicationArgs 10 -btoi -frame_bury 10 -txna ApplicationArgs 11 -btoi -frame_bury 11 -txna ApplicationArgs 12 -btoi -frame_bury 12 -txna ApplicationArgs 13 -btoi -frame_bury 13 -txna ApplicationArgs 14 -btoi -frame_bury 14 -txna ApplicationArgs 15 -frame_bury 17 -frame_dig 17 -int 0 -extract_uint64 -frame_bury 15 -frame_dig 17 -int 8 -extract_uint64 -frame_bury 16 -frame_dig 1 -frame_dig 2 -frame_dig 3 -frame_dig 4 -frame_dig 5 -frame_dig 6 -frame_dig 7 -frame_dig 8 -frame_dig 9 -frame_dig 10 -frame_dig 11 -frame_dig 12 -frame_dig 13 -frame_dig 14 -frame_dig 15 -frame_dig 16 -callsub alllaidtoargs_5 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// empty_return_subroutine_caster -emptyreturnsubroutinecaster_15: -proto 0 0 -callsub emptyreturnsubroutine_6 -retsub - -// log_1_caster -log1caster_16: -proto 0 0 -int 0 -callsub log1_7 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// log_creation_caster -logcreationcaster_17: -proto 0 0 -byte "" -callsub logcreation_8 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -concat -log -retsub""".strip() - assert actual_ap_with_oc_compiled == expected_ap_with_oc - - expected_csp_with_oc = """#pragma version 8 -txn NumAppArgs -int 0 -== -bnz main_l8 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l7 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l6 -txna ApplicationArgs 0 -method "approve_if_odd(uint32)void" -== -bnz main_l5 -err -main_l5: -callsub approveifoddcaster_5 -int 1 -return -main_l6: -callsub log1caster_4 -int 1 -return -main_l7: -callsub emptyreturnsubroutinecaster_3 -int 1 -return -main_l8: -int 1 -return - -// empty_return_subroutine -emptyreturnsubroutine_0: -proto 0 0 -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_1: -proto 0 1 -int 0 -int 1 -frame_bury 0 -retsub - -// approve_if_odd -approveifodd_2: -proto 1 0 -frame_dig -1 -int 2 -% -bnz approveifodd_2_l2 -int 0 -return -approveifodd_2_l2: -int 1 -return - -// empty_return_subroutine_caster -emptyreturnsubroutinecaster_3: -proto 0 0 -callsub emptyreturnsubroutine_0 -retsub - -// log_1_caster -log1caster_4: -proto 0 0 -int 0 -callsub log1_1 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// approve_if_odd_caster -approveifoddcaster_5: -proto 0 0 -int 0 -txna ApplicationArgs 1 -int 0 -extract_uint32 -frame_bury 0 -frame_dig 0 -callsub approveifodd_2 -retsub""".strip() - assert actual_csp_with_oc_compiled == expected_csp_with_oc - - _router_without_oc = pt.Router( - "yetAnotherContractConstructedFromRouterWithFramePointer" - ) - add_methods_to_router(_router_without_oc) - ( - actual_ap_without_oc_compiled, - actual_csp_without_oc_compiled, - _, - ) = _router_without_oc.compile_program(version=8) - - expected_ap_without_oc = """#pragma version 8 -txna ApplicationArgs 0 -method "add(uint64,uint64)uint64" -== -bnz main_l18 -txna ApplicationArgs 0 -method "sub(uint64,uint64)uint64" -== -bnz main_l17 -txna ApplicationArgs 0 -method "mul(uint64,uint64)uint64" -== -bnz main_l16 -txna ApplicationArgs 0 -method "div(uint64,uint64)uint64" -== -bnz main_l15 -txna ApplicationArgs 0 -method "mod(uint64,uint64)uint64" -== -bnz main_l14 -txna ApplicationArgs 0 -method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" -== -bnz main_l13 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l12 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l11 -txna ApplicationArgs 0 -method "log_creation()string" -== -bnz main_l10 -err -main_l10: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -== -&& -assert -callsub logcreationcaster_17 -int 1 -return -main_l11: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -txn ApplicationID -int 0 -!= -&& -|| -assert -callsub log1caster_16 -int 1 -return -main_l12: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -|| -assert -callsub emptyreturnsubroutinecaster_15 -int 1 -return -main_l13: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub alllaidtoargscaster_14 -int 1 -return -main_l14: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub modcaster_13 -int 1 -return -main_l15: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub divcaster_12 -int 1 -return -main_l16: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub mulcaster_11 -int 1 -return -main_l17: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub subcaster_10 -int 1 -return -main_l18: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub addcaster_9 -int 1 -return - -// add -add_0: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -+ -frame_bury 0 -retsub - -// sub -sub_1: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -- -frame_bury 0 -retsub - -// mul -mul_2: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -* -frame_bury 0 -retsub - -// div -div_3: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -/ -frame_bury 0 -retsub - -// mod -mod_4: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -% -frame_bury 0 -retsub - -// all_laid_to_args -alllaidtoargs_5: -proto 16 1 -int 0 -frame_dig -16 -frame_dig -15 -+ -frame_dig -14 -+ -frame_dig -13 -+ -frame_dig -12 -+ -frame_dig -11 -+ -frame_dig -10 -+ -frame_dig -9 -+ -frame_dig -8 -+ -frame_dig -7 -+ -frame_dig -6 -+ -frame_dig -5 -+ -frame_dig -4 -+ -frame_dig -3 -+ -frame_dig -2 -+ -frame_dig -1 -+ -frame_bury 0 -retsub - -// empty_return_subroutine -emptyreturnsubroutine_6: -proto 0 0 -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_7: -proto 0 1 -int 0 -int 1 -frame_bury 0 -retsub - -// log_creation -logcreation_8: -proto 0 1 -byte "" -byte 0x00106c6f6767696e67206372656174696f6e -frame_bury 0 -retsub - -// add_caster -addcaster_9: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub add_0 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// sub_caster -subcaster_10: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub sub_1 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// mul_caster -mulcaster_11: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub mul_2 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// div_caster -divcaster_12: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub div_3 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// mod_caster -modcaster_13: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub mod_4 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// all_laid_to_args_caster -alllaidtoargscaster_14: -proto 0 0 -int 0 -dupn 16 -byte "" -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -txna ApplicationArgs 3 -btoi -frame_bury 3 -txna ApplicationArgs 4 -btoi -frame_bury 4 -txna ApplicationArgs 5 -btoi -frame_bury 5 -txna ApplicationArgs 6 -btoi -frame_bury 6 -txna ApplicationArgs 7 -btoi -frame_bury 7 -txna ApplicationArgs 8 -btoi -frame_bury 8 -txna ApplicationArgs 9 -btoi -frame_bury 9 -txna ApplicationArgs 10 -btoi -frame_bury 10 -txna ApplicationArgs 11 -btoi -frame_bury 11 -txna ApplicationArgs 12 -btoi -frame_bury 12 -txna ApplicationArgs 13 -btoi -frame_bury 13 -txna ApplicationArgs 14 -btoi -frame_bury 14 -txna ApplicationArgs 15 -frame_bury 17 -frame_dig 17 -int 0 -extract_uint64 -frame_bury 15 -frame_dig 17 -int 8 -extract_uint64 -frame_bury 16 -frame_dig 1 -frame_dig 2 -frame_dig 3 -frame_dig 4 -frame_dig 5 -frame_dig 6 -frame_dig 7 -frame_dig 8 -frame_dig 9 -frame_dig 10 -frame_dig 11 -frame_dig 12 -frame_dig 13 -frame_dig 14 -frame_dig 15 -frame_dig 16 -callsub alllaidtoargs_5 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// empty_return_subroutine_caster -emptyreturnsubroutinecaster_15: -proto 0 0 -callsub emptyreturnsubroutine_6 -retsub - -// log_1_caster -log1caster_16: -proto 0 0 -int 0 -callsub log1_7 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// log_creation_caster -logcreationcaster_17: -proto 0 0 -byte "" -callsub logcreation_8 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -concat -log -retsub""".strip() - assert actual_ap_without_oc_compiled == expected_ap_without_oc - - expected_csp_without_oc = """#pragma version 8 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l6 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l5 -txna ApplicationArgs 0 -method "approve_if_odd(uint32)void" -== -bnz main_l4 -err -main_l4: -callsub approveifoddcaster_5 -int 1 -return -main_l5: -callsub log1caster_4 -int 1 -return -main_l6: -callsub emptyreturnsubroutinecaster_3 -int 1 -return - -// empty_return_subroutine -emptyreturnsubroutine_0: -proto 0 0 -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_1: -proto 0 1 -int 0 -int 1 -frame_bury 0 -retsub - -// approve_if_odd -approveifodd_2: -proto 1 0 -frame_dig -1 -int 2 -% -bnz approveifodd_2_l2 -int 0 -return -approveifodd_2_l2: -int 1 -return - -// empty_return_subroutine_caster -emptyreturnsubroutinecaster_3: -proto 0 0 -callsub emptyreturnsubroutine_0 -retsub - -// log_1_caster -log1caster_4: -proto 0 0 -int 0 -callsub log1_1 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// approve_if_odd_caster -approveifoddcaster_5: -proto 0 0 -int 0 -txna ApplicationArgs 1 -int 0 -extract_uint32 -frame_bury 0 -frame_dig 0 -callsub approveifodd_2 -retsub""".strip() - - assert actual_csp_without_oc_compiled == expected_csp_without_oc diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py new file mode 100644 index 000000000..13eabe714 --- /dev/null +++ b/tests/integration/abi_router_test.py @@ -0,0 +1,240 @@ + +from pathlib import Path +import pytest + +import pyteal as pt + +FIXTURES = Path.cwd() / "tests" / "integration" / "teal" / "router" + + +def test_router_app(): + def add_methods_to_router(router: pt.Router): + @pt.ABIReturnSubroutine + def add( + a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 + ) -> pt.Expr: + return output.set(a.get() + b.get()) + + meth = router.add_method_handler(add) + assert meth.method_signature() == "add(uint64,uint64)uint64" + + @pt.ABIReturnSubroutine + def sub( + a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 + ) -> pt.Expr: + return output.set(a.get() - b.get()) + + meth = router.add_method_handler(sub) + assert meth.method_signature() == "sub(uint64,uint64)uint64" + + @pt.ABIReturnSubroutine + def mul( + a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 + ) -> pt.Expr: + return output.set(a.get() * b.get()) + + meth = router.add_method_handler(mul) + assert meth.method_signature() == "mul(uint64,uint64)uint64" + + @pt.ABIReturnSubroutine + def div( + a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 + ) -> pt.Expr: + return output.set(a.get() / b.get()) + + meth = router.add_method_handler(div) + assert meth.method_signature() == "div(uint64,uint64)uint64" + + @pt.ABIReturnSubroutine + def mod( + a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 + ) -> pt.Expr: + return output.set(a.get() % b.get()) + + meth = router.add_method_handler(mod) + assert meth.method_signature() == "mod(uint64,uint64)uint64" + + @pt.ABIReturnSubroutine + def all_laid_to_args( + _a: pt.abi.Uint64, + _b: pt.abi.Uint64, + _c: pt.abi.Uint64, + _d: pt.abi.Uint64, + _e: pt.abi.Uint64, + _f: pt.abi.Uint64, + _g: pt.abi.Uint64, + _h: pt.abi.Uint64, + _i: pt.abi.Uint64, + _j: pt.abi.Uint64, + _k: pt.abi.Uint64, + _l: pt.abi.Uint64, + _m: pt.abi.Uint64, + _n: pt.abi.Uint64, + _o: pt.abi.Uint64, + _p: pt.abi.Uint64, + *, + output: pt.abi.Uint64, + ): + return output.set( + _a.get() + + _b.get() + + _c.get() + + _d.get() + + _e.get() + + _f.get() + + _g.get() + + _h.get() + + _i.get() + + _j.get() + + _k.get() + + _l.get() + + _m.get() + + _n.get() + + _o.get() + + _p.get() + ) + + meth = router.add_method_handler(all_laid_to_args) + assert ( + meth.method_signature() + == "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" + ) + + @pt.ABIReturnSubroutine + def empty_return_subroutine() -> pt.Expr: + return pt.Log(pt.Bytes("appear in both approval and clear state")) + + meth = router.add_method_handler( + empty_return_subroutine, + method_config=pt.MethodConfig( + no_op=pt.CallConfig.CALL, + opt_in=pt.CallConfig.ALL, + clear_state=pt.CallConfig.CALL, + ), + ) + assert meth.method_signature() == "empty_return_subroutine()void" + + @pt.ABIReturnSubroutine + def log_1(*, output: pt.abi.Uint64) -> pt.Expr: + return output.set(1) + + meth = router.add_method_handler( + log_1, + method_config=pt.MethodConfig( + no_op=pt.CallConfig.CALL, + opt_in=pt.CallConfig.CALL, + clear_state=pt.CallConfig.CALL, + ), + ) + + assert meth.method_signature() == "log_1()uint64" + + @pt.ABIReturnSubroutine + def log_creation(*, output: pt.abi.String) -> pt.Expr: + return output.set("logging creation") + + meth = router.add_method_handler( + log_creation, method_config=pt.MethodConfig(no_op=pt.CallConfig.CREATE) + ) + assert meth.method_signature() == "log_creation()string" + + @pt.ABIReturnSubroutine + def approve_if_odd(condition_encoding: pt.abi.Uint32) -> pt.Expr: + return ( + pt.If(condition_encoding.get() % pt.Int(2)) + .Then(pt.Approve()) + .Else(pt.Reject()) + ) + + meth = router.add_method_handler( + approve_if_odd, + method_config=pt.MethodConfig( + no_op=pt.CallConfig.NEVER, clear_state=pt.CallConfig.CALL + ), + ) + assert meth.method_signature() == "approve_if_odd(uint32)void" + + on_completion_actions = pt.BareCallActions( + opt_in=pt.OnCompleteAction.call_only(pt.Log(pt.Bytes("optin call"))), + clear_state=pt.OnCompleteAction.call_only(pt.Approve()), + ) + + with pytest.raises(pt.TealInputError) as e: + pt.Router("will-error", on_completion_actions).compile_program( + version=6, optimize=pt.OptimizeOptions(frame_pointers=True) + ) + + assert "Frame pointers aren't available" in str(e.value) + + _router_with_oc = pt.Router( + "ASimpleQuestionablyRobustContract", on_completion_actions + ) + add_methods_to_router(_router_with_oc) + ( + actual_ap_with_oc_compiled, + actual_csp_with_oc_compiled, + _, + ) = _router_with_oc.compile_program(version=6) + + with open(FIXTURES / "questionable_approval_v6.teal") as f: + expected_ap_with_oc = f.read() + + assert expected_ap_with_oc == actual_ap_with_oc_compiled + + with open(FIXTURES / "questionable_clear_v6.teal") as f: + expected_csp_with_oc = f.read() + + assert expected_csp_with_oc == actual_csp_with_oc_compiled + + _router_without_oc = pt.Router("yetAnotherContractConstructedFromRouter") + add_methods_to_router(_router_without_oc) + ( + actual_ap_without_oc_compiled, + actual_csp_without_oc_compiled, + _, + ) = _router_without_oc.compile_program(version=6) + + with open(FIXTURES / "yacc_approval_v6.teal") as f: + expected_ap_without_oc = f.read() + assert actual_ap_without_oc_compiled == expected_ap_without_oc + + with open(FIXTURES / "yacc_clear_v6.teal") as f: + expected_csp_without_oc = f.read() + assert actual_csp_without_oc_compiled == expected_csp_without_oc + + _router_with_oc = pt.Router( + "QuestionableRouterGenerateCodeWithFramePointer", on_completion_actions + ) + add_methods_to_router(_router_with_oc) + ( + actual_ap_with_oc_compiled, + actual_csp_with_oc_compiled, + _, + ) = _router_with_oc.compile_program(version=8) + + with open(FIXTURES / "questionableFP_approval_v8.teal") as f: + expected_ap_with_oc = f.read() + assert actual_ap_with_oc_compiled == expected_ap_with_oc + + with open(FIXTURES / "questionableFP_clear_v8.teal") as f: + expected_csp_with_oc = f.read() + assert actual_csp_with_oc_compiled == expected_csp_with_oc + + _router_without_oc = pt.Router( + "yetAnotherContractConstructedFromRouterWithFramePointer" + ) + add_methods_to_router(_router_without_oc) + ( + actual_ap_without_oc_compiled, + actual_csp_without_oc_compiled, + _, + ) = _router_without_oc.compile_program(version=8) + + with open(FIXTURES / "yaccFP_approval_v8.teal") as f: + expected_ap_without_oc = f.read() + assert actual_ap_without_oc_compiled == expected_ap_without_oc + + with open(FIXTURES / "yaccFP_clear_v8.teal") as f: + expected_csp_without_oc = f.read() + + assert actual_csp_without_oc_compiled == expected_csp_without_oc diff --git a/tests/integration/teal/router/questionableFP_approval_v8.teal b/tests/integration/teal/router/questionableFP_approval_v8.teal new file mode 100644 index 000000000..00a013082 --- /dev/null +++ b/tests/integration/teal/router/questionableFP_approval_v8.teal @@ -0,0 +1,512 @@ +#pragma version 8 +txn NumAppArgs +int 0 +== +bnz main_l20 +txna ApplicationArgs 0 +method "add(uint64,uint64)uint64" +== +bnz main_l19 +txna ApplicationArgs 0 +method "sub(uint64,uint64)uint64" +== +bnz main_l18 +txna ApplicationArgs 0 +method "mul(uint64,uint64)uint64" +== +bnz main_l17 +txna ApplicationArgs 0 +method "div(uint64,uint64)uint64" +== +bnz main_l16 +txna ApplicationArgs 0 +method "mod(uint64,uint64)uint64" +== +bnz main_l15 +txna ApplicationArgs 0 +method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" +== +bnz main_l14 +txna ApplicationArgs 0 +method "empty_return_subroutine()void" +== +bnz main_l13 +txna ApplicationArgs 0 +method "log_1()uint64" +== +bnz main_l12 +txna ApplicationArgs 0 +method "log_creation()string" +== +bnz main_l11 +err +main_l11: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +== +&& +assert +callsub logcreationcaster_17 +int 1 +return +main_l12: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +txn ApplicationID +int 0 +!= +&& +|| +assert +callsub log1caster_16 +int 1 +return +main_l13: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +|| +assert +callsub emptyreturnsubroutinecaster_15 +int 1 +return +main_l14: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub alllaidtoargscaster_14 +int 1 +return +main_l15: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub modcaster_13 +int 1 +return +main_l16: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub divcaster_12 +int 1 +return +main_l17: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub mulcaster_11 +int 1 +return +main_l18: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub subcaster_10 +int 1 +return +main_l19: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub addcaster_9 +int 1 +return +main_l20: +txn OnCompletion +int OptIn +== +bnz main_l22 +err +main_l22: +txn ApplicationID +int 0 +!= +assert +byte "optin call" +log +int 1 +return + +// add +add_0: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 ++ +frame_bury 0 +retsub + +// sub +sub_1: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +- +frame_bury 0 +retsub + +// mul +mul_2: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +* +frame_bury 0 +retsub + +// div +div_3: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +/ +frame_bury 0 +retsub + +// mod +mod_4: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +% +frame_bury 0 +retsub + +// all_laid_to_args +alllaidtoargs_5: +proto 16 1 +int 0 +frame_dig -16 +frame_dig -15 ++ +frame_dig -14 ++ +frame_dig -13 ++ +frame_dig -12 ++ +frame_dig -11 ++ +frame_dig -10 ++ +frame_dig -9 ++ +frame_dig -8 ++ +frame_dig -7 ++ +frame_dig -6 ++ +frame_dig -5 ++ +frame_dig -4 ++ +frame_dig -3 ++ +frame_dig -2 ++ +frame_dig -1 ++ +frame_bury 0 +retsub + +// empty_return_subroutine +emptyreturnsubroutine_6: +proto 0 0 +byte "appear in both approval and clear state" +log +retsub + +// log_1 +log1_7: +proto 0 1 +int 0 +int 1 +frame_bury 0 +retsub + +// log_creation +logcreation_8: +proto 0 1 +byte "" +byte 0x00106c6f6767696e67206372656174696f6e +frame_bury 0 +retsub + +// add_caster +addcaster_9: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub add_0 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// sub_caster +subcaster_10: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub sub_1 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// mul_caster +mulcaster_11: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub mul_2 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// div_caster +divcaster_12: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub div_3 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// mod_caster +modcaster_13: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub mod_4 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// all_laid_to_args_caster +alllaidtoargscaster_14: +proto 0 0 +int 0 +dupn 16 +byte "" +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +txna ApplicationArgs 3 +btoi +frame_bury 3 +txna ApplicationArgs 4 +btoi +frame_bury 4 +txna ApplicationArgs 5 +btoi +frame_bury 5 +txna ApplicationArgs 6 +btoi +frame_bury 6 +txna ApplicationArgs 7 +btoi +frame_bury 7 +txna ApplicationArgs 8 +btoi +frame_bury 8 +txna ApplicationArgs 9 +btoi +frame_bury 9 +txna ApplicationArgs 10 +btoi +frame_bury 10 +txna ApplicationArgs 11 +btoi +frame_bury 11 +txna ApplicationArgs 12 +btoi +frame_bury 12 +txna ApplicationArgs 13 +btoi +frame_bury 13 +txna ApplicationArgs 14 +btoi +frame_bury 14 +txna ApplicationArgs 15 +frame_bury 17 +frame_dig 17 +int 0 +extract_uint64 +frame_bury 15 +frame_dig 17 +int 8 +extract_uint64 +frame_bury 16 +frame_dig 1 +frame_dig 2 +frame_dig 3 +frame_dig 4 +frame_dig 5 +frame_dig 6 +frame_dig 7 +frame_dig 8 +frame_dig 9 +frame_dig 10 +frame_dig 11 +frame_dig 12 +frame_dig 13 +frame_dig 14 +frame_dig 15 +frame_dig 16 +callsub alllaidtoargs_5 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// empty_return_subroutine_caster +emptyreturnsubroutinecaster_15: +proto 0 0 +callsub emptyreturnsubroutine_6 +retsub + +// log_1_caster +log1caster_16: +proto 0 0 +int 0 +callsub log1_7 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// log_creation_caster +logcreationcaster_17: +proto 0 0 +byte "" +callsub logcreation_8 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +concat +log +retsub \ No newline at end of file diff --git a/tests/integration/teal/router/questionableFP_clear_v8.teal b/tests/integration/teal/router/questionableFP_clear_v8.teal new file mode 100644 index 000000000..5bb9f0213 --- /dev/null +++ b/tests/integration/teal/router/questionableFP_clear_v8.teal @@ -0,0 +1,92 @@ +#pragma version 8 +txn NumAppArgs +int 0 +== +bnz main_l8 +txna ApplicationArgs 0 +method "empty_return_subroutine()void" +== +bnz main_l7 +txna ApplicationArgs 0 +method "log_1()uint64" +== +bnz main_l6 +txna ApplicationArgs 0 +method "approve_if_odd(uint32)void" +== +bnz main_l5 +err +main_l5: +callsub approveifoddcaster_5 +int 1 +return +main_l6: +callsub log1caster_4 +int 1 +return +main_l7: +callsub emptyreturnsubroutinecaster_3 +int 1 +return +main_l8: +int 1 +return + +// empty_return_subroutine +emptyreturnsubroutine_0: +proto 0 0 +byte "appear in both approval and clear state" +log +retsub + +// log_1 +log1_1: +proto 0 1 +int 0 +int 1 +frame_bury 0 +retsub + +// approve_if_odd +approveifodd_2: +proto 1 0 +frame_dig -1 +int 2 +% +bnz approveifodd_2_l2 +int 0 +return +approveifodd_2_l2: +int 1 +return + +// empty_return_subroutine_caster +emptyreturnsubroutinecaster_3: +proto 0 0 +callsub emptyreturnsubroutine_0 +retsub + +// log_1_caster +log1caster_4: +proto 0 0 +int 0 +callsub log1_1 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// approve_if_odd_caster +approveifoddcaster_5: +proto 0 0 +int 0 +txna ApplicationArgs 1 +int 0 +extract_uint32 +frame_bury 0 +frame_dig 0 +callsub approveifodd_2 +retsub \ No newline at end of file diff --git a/tests/integration/teal/router/questionable_approval_v6.teal b/tests/integration/teal/router/questionable_approval_v6.teal new file mode 100644 index 000000000..51455774a --- /dev/null +++ b/tests/integration/teal/router/questionable_approval_v6.teal @@ -0,0 +1,460 @@ +#pragma version 6 +txn NumAppArgs +int 0 +== +bnz main_l20 +txna ApplicationArgs 0 +method "add(uint64,uint64)uint64" +== +bnz main_l19 +txna ApplicationArgs 0 +method "sub(uint64,uint64)uint64" +== +bnz main_l18 +txna ApplicationArgs 0 +method "mul(uint64,uint64)uint64" +== +bnz main_l17 +txna ApplicationArgs 0 +method "div(uint64,uint64)uint64" +== +bnz main_l16 +txna ApplicationArgs 0 +method "mod(uint64,uint64)uint64" +== +bnz main_l15 +txna ApplicationArgs 0 +method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" +== +bnz main_l14 +txna ApplicationArgs 0 +method "empty_return_subroutine()void" +== +bnz main_l13 +txna ApplicationArgs 0 +method "log_1()uint64" +== +bnz main_l12 +txna ApplicationArgs 0 +method "log_creation()string" +== +bnz main_l11 +err +main_l11: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +== +&& +assert +callsub logcreation_8 +store 67 +byte 0x151f7c75 +load 67 +concat +log +int 1 +return +main_l12: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +txn ApplicationID +int 0 +!= +&& +|| +assert +callsub log1_7 +store 65 +byte 0x151f7c75 +load 65 +itob +concat +log +int 1 +return +main_l13: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +|| +assert +callsub emptyreturnsubroutine_6 +int 1 +return +main_l14: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 30 +txna ApplicationArgs 2 +btoi +store 31 +txna ApplicationArgs 3 +btoi +store 32 +txna ApplicationArgs 4 +btoi +store 33 +txna ApplicationArgs 5 +btoi +store 34 +txna ApplicationArgs 6 +btoi +store 35 +txna ApplicationArgs 7 +btoi +store 36 +txna ApplicationArgs 8 +btoi +store 37 +txna ApplicationArgs 9 +btoi +store 38 +txna ApplicationArgs 10 +btoi +store 39 +txna ApplicationArgs 11 +btoi +store 40 +txna ApplicationArgs 12 +btoi +store 41 +txna ApplicationArgs 13 +btoi +store 42 +txna ApplicationArgs 14 +btoi +store 43 +txna ApplicationArgs 15 +store 46 +load 46 +int 0 +extract_uint64 +store 44 +load 46 +int 8 +extract_uint64 +store 45 +load 30 +load 31 +load 32 +load 33 +load 34 +load 35 +load 36 +load 37 +load 38 +load 39 +load 40 +load 41 +load 42 +load 43 +load 44 +load 45 +callsub alllaidtoargs_5 +store 47 +byte 0x151f7c75 +load 47 +itob +concat +log +int 1 +return +main_l15: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 24 +txna ApplicationArgs 2 +btoi +store 25 +load 24 +load 25 +callsub mod_4 +store 26 +byte 0x151f7c75 +load 26 +itob +concat +log +int 1 +return +main_l16: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 18 +txna ApplicationArgs 2 +btoi +store 19 +load 18 +load 19 +callsub div_3 +store 20 +byte 0x151f7c75 +load 20 +itob +concat +log +int 1 +return +main_l17: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 12 +txna ApplicationArgs 2 +btoi +store 13 +load 12 +load 13 +callsub mul_2 +store 14 +byte 0x151f7c75 +load 14 +itob +concat +log +int 1 +return +main_l18: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 6 +txna ApplicationArgs 2 +btoi +store 7 +load 6 +load 7 +callsub sub_1 +store 8 +byte 0x151f7c75 +load 8 +itob +concat +log +int 1 +return +main_l19: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 0 +txna ApplicationArgs 2 +btoi +store 1 +load 0 +load 1 +callsub add_0 +store 2 +byte 0x151f7c75 +load 2 +itob +concat +log +int 1 +return +main_l20: +txn OnCompletion +int OptIn +== +bnz main_l22 +err +main_l22: +txn ApplicationID +int 0 +!= +assert +byte "optin call" +log +int 1 +return + +// add +add_0: +store 4 +store 3 +load 3 +load 4 ++ +store 5 +load 5 +retsub + +// sub +sub_1: +store 10 +store 9 +load 9 +load 10 +- +store 11 +load 11 +retsub + +// mul +mul_2: +store 16 +store 15 +load 15 +load 16 +* +store 17 +load 17 +retsub + +// div +div_3: +store 22 +store 21 +load 21 +load 22 +/ +store 23 +load 23 +retsub + +// mod +mod_4: +store 28 +store 27 +load 27 +load 28 +% +store 29 +load 29 +retsub + +// all_laid_to_args +alllaidtoargs_5: +store 63 +store 62 +store 61 +store 60 +store 59 +store 58 +store 57 +store 56 +store 55 +store 54 +store 53 +store 52 +store 51 +store 50 +store 49 +store 48 +load 48 +load 49 ++ +load 50 ++ +load 51 ++ +load 52 ++ +load 53 ++ +load 54 ++ +load 55 ++ +load 56 ++ +load 57 ++ +load 58 ++ +load 59 ++ +load 60 ++ +load 61 ++ +load 62 ++ +load 63 ++ +store 64 +load 64 +retsub + +// empty_return_subroutine +emptyreturnsubroutine_6: +byte "appear in both approval and clear state" +log +retsub + +// log_1 +log1_7: +int 1 +store 66 +load 66 +retsub + +// log_creation +logcreation_8: +byte 0x00106c6f6767696e67206372656174696f6e +store 68 +load 68 +retsub \ No newline at end of file diff --git a/tests/integration/teal/router/questionable_clear_v6.teal b/tests/integration/teal/router/questionable_clear_v6.teal new file mode 100644 index 000000000..ad85ebc0d --- /dev/null +++ b/tests/integration/teal/router/questionable_clear_v6.teal @@ -0,0 +1,70 @@ +#pragma version 6 +txn NumAppArgs +int 0 +== +bnz main_l8 +txna ApplicationArgs 0 +method "empty_return_subroutine()void" +== +bnz main_l7 +txna ApplicationArgs 0 +method "log_1()uint64" +== +bnz main_l6 +txna ApplicationArgs 0 +method "approve_if_odd(uint32)void" +== +bnz main_l5 +err +main_l5: +txna ApplicationArgs 1 +int 0 +extract_uint32 +store 2 +load 2 +callsub approveifodd_2 +int 1 +return +main_l6: +callsub log1_1 +store 1 +byte 0x151f7c75 +load 1 +itob +concat +log +int 1 +return +main_l7: +callsub emptyreturnsubroutine_0 +int 1 +return +main_l8: +int 1 +return + +// empty_return_subroutine +emptyreturnsubroutine_0: +byte "appear in both approval and clear state" +log +retsub + +// log_1 +log1_1: +int 1 +store 0 +load 0 +retsub + +// approve_if_odd +approveifodd_2: +store 3 +load 3 +int 2 +% +bnz approveifodd_2_l2 +int 0 +return +approveifodd_2_l2: +int 1 +return \ No newline at end of file diff --git a/tests/integration/teal/router/yaccFP_approval_v8.teal b/tests/integration/teal/router/yaccFP_approval_v8.teal new file mode 100644 index 000000000..5c5bda6d0 --- /dev/null +++ b/tests/integration/teal/router/yaccFP_approval_v8.teal @@ -0,0 +1,493 @@ +#pragma version 8 +txna ApplicationArgs 0 +method "add(uint64,uint64)uint64" +== +bnz main_l18 +txna ApplicationArgs 0 +method "sub(uint64,uint64)uint64" +== +bnz main_l17 +txna ApplicationArgs 0 +method "mul(uint64,uint64)uint64" +== +bnz main_l16 +txna ApplicationArgs 0 +method "div(uint64,uint64)uint64" +== +bnz main_l15 +txna ApplicationArgs 0 +method "mod(uint64,uint64)uint64" +== +bnz main_l14 +txna ApplicationArgs 0 +method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" +== +bnz main_l13 +txna ApplicationArgs 0 +method "empty_return_subroutine()void" +== +bnz main_l12 +txna ApplicationArgs 0 +method "log_1()uint64" +== +bnz main_l11 +txna ApplicationArgs 0 +method "log_creation()string" +== +bnz main_l10 +err +main_l10: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +== +&& +assert +callsub logcreationcaster_17 +int 1 +return +main_l11: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +txn ApplicationID +int 0 +!= +&& +|| +assert +callsub log1caster_16 +int 1 +return +main_l12: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +|| +assert +callsub emptyreturnsubroutinecaster_15 +int 1 +return +main_l13: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub alllaidtoargscaster_14 +int 1 +return +main_l14: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub modcaster_13 +int 1 +return +main_l15: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub divcaster_12 +int 1 +return +main_l16: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub mulcaster_11 +int 1 +return +main_l17: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub subcaster_10 +int 1 +return +main_l18: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub addcaster_9 +int 1 +return + +// add +add_0: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 ++ +frame_bury 0 +retsub + +// sub +sub_1: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +- +frame_bury 0 +retsub + +// mul +mul_2: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +* +frame_bury 0 +retsub + +// div +div_3: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +/ +frame_bury 0 +retsub + +// mod +mod_4: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +% +frame_bury 0 +retsub + +// all_laid_to_args +alllaidtoargs_5: +proto 16 1 +int 0 +frame_dig -16 +frame_dig -15 ++ +frame_dig -14 ++ +frame_dig -13 ++ +frame_dig -12 ++ +frame_dig -11 ++ +frame_dig -10 ++ +frame_dig -9 ++ +frame_dig -8 ++ +frame_dig -7 ++ +frame_dig -6 ++ +frame_dig -5 ++ +frame_dig -4 ++ +frame_dig -3 ++ +frame_dig -2 ++ +frame_dig -1 ++ +frame_bury 0 +retsub + +// empty_return_subroutine +emptyreturnsubroutine_6: +proto 0 0 +byte "appear in both approval and clear state" +log +retsub + +// log_1 +log1_7: +proto 0 1 +int 0 +int 1 +frame_bury 0 +retsub + +// log_creation +logcreation_8: +proto 0 1 +byte "" +byte 0x00106c6f6767696e67206372656174696f6e +frame_bury 0 +retsub + +// add_caster +addcaster_9: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub add_0 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// sub_caster +subcaster_10: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub sub_1 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// mul_caster +mulcaster_11: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub mul_2 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// div_caster +divcaster_12: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub div_3 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// mod_caster +modcaster_13: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub mod_4 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// all_laid_to_args_caster +alllaidtoargscaster_14: +proto 0 0 +int 0 +dupn 16 +byte "" +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +txna ApplicationArgs 3 +btoi +frame_bury 3 +txna ApplicationArgs 4 +btoi +frame_bury 4 +txna ApplicationArgs 5 +btoi +frame_bury 5 +txna ApplicationArgs 6 +btoi +frame_bury 6 +txna ApplicationArgs 7 +btoi +frame_bury 7 +txna ApplicationArgs 8 +btoi +frame_bury 8 +txna ApplicationArgs 9 +btoi +frame_bury 9 +txna ApplicationArgs 10 +btoi +frame_bury 10 +txna ApplicationArgs 11 +btoi +frame_bury 11 +txna ApplicationArgs 12 +btoi +frame_bury 12 +txna ApplicationArgs 13 +btoi +frame_bury 13 +txna ApplicationArgs 14 +btoi +frame_bury 14 +txna ApplicationArgs 15 +frame_bury 17 +frame_dig 17 +int 0 +extract_uint64 +frame_bury 15 +frame_dig 17 +int 8 +extract_uint64 +frame_bury 16 +frame_dig 1 +frame_dig 2 +frame_dig 3 +frame_dig 4 +frame_dig 5 +frame_dig 6 +frame_dig 7 +frame_dig 8 +frame_dig 9 +frame_dig 10 +frame_dig 11 +frame_dig 12 +frame_dig 13 +frame_dig 14 +frame_dig 15 +frame_dig 16 +callsub alllaidtoargs_5 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// empty_return_subroutine_caster +emptyreturnsubroutinecaster_15: +proto 0 0 +callsub emptyreturnsubroutine_6 +retsub + +// log_1_caster +log1caster_16: +proto 0 0 +int 0 +callsub log1_7 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// log_creation_caster +logcreationcaster_17: +proto 0 0 +byte "" +callsub logcreation_8 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +concat +log +retsub \ No newline at end of file diff --git a/tests/integration/teal/router/yaccFP_clear_v8.teal b/tests/integration/teal/router/yaccFP_clear_v8.teal new file mode 100644 index 000000000..4be43a130 --- /dev/null +++ b/tests/integration/teal/router/yaccFP_clear_v8.teal @@ -0,0 +1,85 @@ +#pragma version 8 +txna ApplicationArgs 0 +method "empty_return_subroutine()void" +== +bnz main_l6 +txna ApplicationArgs 0 +method "log_1()uint64" +== +bnz main_l5 +txna ApplicationArgs 0 +method "approve_if_odd(uint32)void" +== +bnz main_l4 +err +main_l4: +callsub approveifoddcaster_5 +int 1 +return +main_l5: +callsub log1caster_4 +int 1 +return +main_l6: +callsub emptyreturnsubroutinecaster_3 +int 1 +return + +// empty_return_subroutine +emptyreturnsubroutine_0: +proto 0 0 +byte "appear in both approval and clear state" +log +retsub + +// log_1 +log1_1: +proto 0 1 +int 0 +int 1 +frame_bury 0 +retsub + +// approve_if_odd +approveifodd_2: +proto 1 0 +frame_dig -1 +int 2 +% +bnz approveifodd_2_l2 +int 0 +return +approveifodd_2_l2: +int 1 +return + +// empty_return_subroutine_caster +emptyreturnsubroutinecaster_3: +proto 0 0 +callsub emptyreturnsubroutine_0 +retsub + +// log_1_caster +log1caster_4: +proto 0 0 +int 0 +callsub log1_1 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// approve_if_odd_caster +approveifoddcaster_5: +proto 0 0 +int 0 +txna ApplicationArgs 1 +int 0 +extract_uint32 +frame_bury 0 +frame_dig 0 +callsub approveifodd_2 +retsub \ No newline at end of file diff --git a/tests/integration/teal/router/yacc_approval_v6.teal b/tests/integration/teal/router/yacc_approval_v6.teal new file mode 100644 index 000000000..b36bc397e --- /dev/null +++ b/tests/integration/teal/router/yacc_approval_v6.teal @@ -0,0 +1,441 @@ +#pragma version 6 +txna ApplicationArgs 0 +method "add(uint64,uint64)uint64" +== +bnz main_l18 +txna ApplicationArgs 0 +method "sub(uint64,uint64)uint64" +== +bnz main_l17 +txna ApplicationArgs 0 +method "mul(uint64,uint64)uint64" +== +bnz main_l16 +txna ApplicationArgs 0 +method "div(uint64,uint64)uint64" +== +bnz main_l15 +txna ApplicationArgs 0 +method "mod(uint64,uint64)uint64" +== +bnz main_l14 +txna ApplicationArgs 0 +method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" +== +bnz main_l13 +txna ApplicationArgs 0 +method "empty_return_subroutine()void" +== +bnz main_l12 +txna ApplicationArgs 0 +method "log_1()uint64" +== +bnz main_l11 +txna ApplicationArgs 0 +method "log_creation()string" +== +bnz main_l10 +err +main_l10: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +== +&& +assert +callsub logcreation_8 +store 67 +byte 0x151f7c75 +load 67 +concat +log +int 1 +return +main_l11: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +txn ApplicationID +int 0 +!= +&& +|| +assert +callsub log1_7 +store 65 +byte 0x151f7c75 +load 65 +itob +concat +log +int 1 +return +main_l12: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +|| +assert +callsub emptyreturnsubroutine_6 +int 1 +return +main_l13: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 30 +txna ApplicationArgs 2 +btoi +store 31 +txna ApplicationArgs 3 +btoi +store 32 +txna ApplicationArgs 4 +btoi +store 33 +txna ApplicationArgs 5 +btoi +store 34 +txna ApplicationArgs 6 +btoi +store 35 +txna ApplicationArgs 7 +btoi +store 36 +txna ApplicationArgs 8 +btoi +store 37 +txna ApplicationArgs 9 +btoi +store 38 +txna ApplicationArgs 10 +btoi +store 39 +txna ApplicationArgs 11 +btoi +store 40 +txna ApplicationArgs 12 +btoi +store 41 +txna ApplicationArgs 13 +btoi +store 42 +txna ApplicationArgs 14 +btoi +store 43 +txna ApplicationArgs 15 +store 46 +load 46 +int 0 +extract_uint64 +store 44 +load 46 +int 8 +extract_uint64 +store 45 +load 30 +load 31 +load 32 +load 33 +load 34 +load 35 +load 36 +load 37 +load 38 +load 39 +load 40 +load 41 +load 42 +load 43 +load 44 +load 45 +callsub alllaidtoargs_5 +store 47 +byte 0x151f7c75 +load 47 +itob +concat +log +int 1 +return +main_l14: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 24 +txna ApplicationArgs 2 +btoi +store 25 +load 24 +load 25 +callsub mod_4 +store 26 +byte 0x151f7c75 +load 26 +itob +concat +log +int 1 +return +main_l15: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 18 +txna ApplicationArgs 2 +btoi +store 19 +load 18 +load 19 +callsub div_3 +store 20 +byte 0x151f7c75 +load 20 +itob +concat +log +int 1 +return +main_l16: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 12 +txna ApplicationArgs 2 +btoi +store 13 +load 12 +load 13 +callsub mul_2 +store 14 +byte 0x151f7c75 +load 14 +itob +concat +log +int 1 +return +main_l17: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 6 +txna ApplicationArgs 2 +btoi +store 7 +load 6 +load 7 +callsub sub_1 +store 8 +byte 0x151f7c75 +load 8 +itob +concat +log +int 1 +return +main_l18: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 0 +txna ApplicationArgs 2 +btoi +store 1 +load 0 +load 1 +callsub add_0 +store 2 +byte 0x151f7c75 +load 2 +itob +concat +log +int 1 +return + +// add +add_0: +store 4 +store 3 +load 3 +load 4 ++ +store 5 +load 5 +retsub + +// sub +sub_1: +store 10 +store 9 +load 9 +load 10 +- +store 11 +load 11 +retsub + +// mul +mul_2: +store 16 +store 15 +load 15 +load 16 +* +store 17 +load 17 +retsub + +// div +div_3: +store 22 +store 21 +load 21 +load 22 +/ +store 23 +load 23 +retsub + +// mod +mod_4: +store 28 +store 27 +load 27 +load 28 +% +store 29 +load 29 +retsub + +// all_laid_to_args +alllaidtoargs_5: +store 63 +store 62 +store 61 +store 60 +store 59 +store 58 +store 57 +store 56 +store 55 +store 54 +store 53 +store 52 +store 51 +store 50 +store 49 +store 48 +load 48 +load 49 ++ +load 50 ++ +load 51 ++ +load 52 ++ +load 53 ++ +load 54 ++ +load 55 ++ +load 56 ++ +load 57 ++ +load 58 ++ +load 59 ++ +load 60 ++ +load 61 ++ +load 62 ++ +load 63 ++ +store 64 +load 64 +retsub + +// empty_return_subroutine +emptyreturnsubroutine_6: +byte "appear in both approval and clear state" +log +retsub + +// log_1 +log1_7: +int 1 +store 66 +load 66 +retsub + +// log_creation +logcreation_8: +byte 0x00106c6f6767696e67206372656174696f6e +store 68 +load 68 +retsub \ No newline at end of file diff --git a/tests/integration/teal/router/yacc_clear_v6.teal b/tests/integration/teal/router/yacc_clear_v6.teal new file mode 100644 index 000000000..8c4178605 --- /dev/null +++ b/tests/integration/teal/router/yacc_clear_v6.teal @@ -0,0 +1,63 @@ +#pragma version 6 +txna ApplicationArgs 0 +method "empty_return_subroutine()void" +== +bnz main_l6 +txna ApplicationArgs 0 +method "log_1()uint64" +== +bnz main_l5 +txna ApplicationArgs 0 +method "approve_if_odd(uint32)void" +== +bnz main_l4 +err +main_l4: +txna ApplicationArgs 1 +int 0 +extract_uint32 +store 2 +load 2 +callsub approveifodd_2 +int 1 +return +main_l5: +callsub log1_1 +store 1 +byte 0x151f7c75 +load 1 +itob +concat +log +int 1 +return +main_l6: +callsub emptyreturnsubroutine_0 +int 1 +return + +// empty_return_subroutine +emptyreturnsubroutine_0: +byte "appear in both approval and clear state" +log +retsub + +// log_1 +log1_1: +int 1 +store 0 +load 0 +retsub + +// approve_if_odd +approveifodd_2: +store 3 +load 3 +int 2 +% +bnz approveifodd_2_l2 +int 0 +return +approveifodd_2_l2: +int 1 +return \ No newline at end of file From 6d0fb42d260a376e0a8642ab18bc544d2a30dc98 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 16 Jan 2023 23:09:21 -0600 Subject: [PATCH 157/206] lint --- tests/integration/abi_router_test.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index 13eabe714..75c148feb 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -1,4 +1,3 @@ - from pathlib import Path import pytest @@ -178,7 +177,7 @@ def approve_if_odd(condition_encoding: pt.abi.Uint32) -> pt.Expr: with open(FIXTURES / "questionable_approval_v6.teal") as f: expected_ap_with_oc = f.read() - + assert expected_ap_with_oc == actual_ap_with_oc_compiled with open(FIXTURES / "questionable_clear_v6.teal") as f: @@ -199,7 +198,7 @@ def approve_if_odd(condition_encoding: pt.abi.Uint32) -> pt.Expr: assert actual_ap_without_oc_compiled == expected_ap_without_oc with open(FIXTURES / "yacc_clear_v6.teal") as f: - expected_csp_without_oc = f.read() + expected_csp_without_oc = f.read() assert actual_csp_without_oc_compiled == expected_csp_without_oc _router_with_oc = pt.Router( From 28687e59818d2ab883fbbce299dcda343a2b29a0 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Wed, 18 Jan 2023 22:04:16 -0600 Subject: [PATCH 158/206] pin to appropriate graviton --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b7ba8ca1a..816535eeb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/tzaffi/graviton@exec-multi-dispatch +graviton@git+https://github.com/tzaffi/graviton@ace-for-pyteal mypy==0.991 pytest==7.2.0 pytest-cov==3.0.0 From e17272e6be33951b881edb7d309395ca86d3c4f8 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Wed, 18 Jan 2023 22:05:31 -0600 Subject: [PATCH 159/206] adding to router's API: BareCallActions.get_method_config() + Router.method_configs --- pyteal/ast/router.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pyteal/ast/router.py b/pyteal/ast/router.py index d55db3a5c..bf2084e2a 100644 --- a/pyteal/ast/router.py +++ b/pyteal/ast/router.py @@ -267,6 +267,15 @@ def clear_state_construction(self) -> Optional[Expr]: ), ) + def get_method_config(self) -> MethodConfig: + return MethodConfig( + no_op=self.no_op.call_config, + opt_in=self.opt_in.call_config, + close_out=self.close_out.call_config, + clear_state=self.clear_state.call_config, + update_application=self.update_application.call_config, + delete_application=self.delete_application.call_config, + ) BareCallActions.__module__ = "pyteal" @@ -686,6 +695,8 @@ def __init__( self.method_sig_to_selector: dict[str, bytes] = dict() self.method_selector_to_sig: dict[bytes, str] = dict() + self.method_configs: dict[str | None, MethodConfig] = dict() + if bare_calls and not bare_calls.is_empty(): bare_call_approval = bare_calls.approval_construction() if bare_call_approval: @@ -703,6 +714,7 @@ def __init__( cast(Expr, bare_call_clear), ) ) + self.method_configs[None] = bare_calls.get_method_config() def add_method_handler( self, @@ -729,6 +741,7 @@ def add_method_handler( "for adding method handler, must be ABIReturnSubroutine" ) method_signature = method_call.method_signature(overriding_name) + final_name = overriding_name or method_call.name() if method_config is None: method_config = MethodConfig(no_op=CallConfig.CALL) if method_config.is_never(): @@ -761,6 +774,7 @@ def add_method_handler( self.clear_state_ast.add_method_to_ast( method_signature, method_clear_state_cond, method_call ) + self.method_configs[final_name] = method_config return method_call def method( From 6a5d9a0f684364722f34b011eb7f6ade217482e3 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Wed, 18 Jan 2023 22:07:39 -0600 Subject: [PATCH 160/206] TDD 2/3 done --- tests/blackbox.py | 298 +++++++++++++++++++++- tests/unit/blackbox_test.py | 490 +++++++++++++++++++++++++++++++++++- 2 files changed, 781 insertions(+), 7 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index 00e85e9ef..fb8b03b92 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -1,16 +1,23 @@ -from typing import Any, Callable, Sequence, cast +from dataclasses import dataclass +import json +from typing import Any, Callable, Sequence, Type, cast -import algosdk.abi +import algosdk.abi as sdk_abi +from algosdk.transaction import OnComplete from algosdk.v2client import algod from graviton import blackbox +from graviton.abi_strategy import ABIArgsMod, ABICallStrategy, ABIStrategy from graviton.blackbox import ( DryRunInspector, DryRunExecutor, DryRunTransactionParams as TxParams, ) -from graviton.models import PyTypes +from graviton.inspector import DryRunProperty as DRProp +from graviton.models import ExecutionMode, PyTypes +from graviton.sim import Simulation, SimulationResults +from pyteal.compiler.compiler import OptimizeOptions from pyteal.ast.subroutine import OutputKwArgInfo from pyteal import ( @@ -18,14 +25,17 @@ Arg, Btoi, Bytes, + CallConfig, compileTeal, Expr, Int, Itob, Len, Log, + MethodConfig, Mode, Pop, + Router, ScratchVar, Seq, SubroutineFnWrapper, @@ -35,6 +45,14 @@ from pyteal.ast.subroutine import ABIReturnSubroutine +# ---- Types ---- # + +Predicates = dict[DRProp, Any] # same as in graviton + +# key `method_config == None` indicates that the MethodConfig's +# should be picked up from the router +CallPredicates = dict[str | None, Predicates] + # ---- Clients ---- # @@ -205,7 +223,7 @@ def abi_method_signature(self) -> None | str: return None - def abi_argument_types(self) -> None | list[algosdk.abi.ABIType]: + def abi_argument_types(self) -> None | list[sdk_abi.ABIType]: if not (self.input_types or self.is_abi()): return None @@ -216,7 +234,7 @@ def handle_arg(arg): return [handle_arg(arg) for arg in self.input_types] - def abi_return_type(self) -> None | algosdk.abi.ABIType: + def abi_return_type(self) -> None | sdk_abi.ABIType: if not self.is_abi(): return None @@ -440,3 +458,273 @@ def dryrun_one( return self.executor(compiler_version).run_one( args, txn_params=txn_params, verbose=verbose ) + + +@dataclass(frozen=True) +class _SimConfig: + version: int + assemble_constants: bool + optimize: OptimizeOptions | None + ap_compiled: str + csp_compiled: str + contract: sdk_abi.Contract + method_configs: dict[str, MethodConfig] + call_strat: ABICallStrategy + txn_params: TxParams + model_version: int | None + model_assemble_constants: bool | None + model_optimize: OptimizeOptions | None + model_ap_compiled: str | None + model_csp_compiled: str | None + model_contract: sdk_abi.Contract | None + + +class RouterSimulation: + """ + Lifecycle of a RouterSimulation + + 1. Creation: + * router: Router (no version or other options specified) + * predicates: CallPredicates - the Router ought satisfy. Type has shape: + * method --> predicate ...> ... + * algod (optional) - if missing, just get one + * model_router: Router (optional) - in the case when the predicates provided + are of type PredicateKind.IdenticalPair, this parameter needs to be + provided for comparison. + NOTE: model_router may in fact be the same as router, and in this case + it is expected that something else such as version or optimization option + would differ between modeel_router and router during the simulation + + 2. Simulation: + * call_strat: ABICallStrategy - used for args generation + * version: int - for compiling router + * assemble_constants: bool (optional) - for compiling router + * optimize: OptimizeOptions (optional) - for compiling router + * method_configs: dict[str, MethodConfig] (optional) + - if missing, pick up from router.method_configs + * num_dryruns: int (default 1) - the number of input runs to generate + per method X config combination + * abi_args_mod: ABIArgsMod (default None) - used to specify any arg mutation + * txn_params: TxParams (optional) - other TxParams to append + -in addition to the (is_app_create, OnComplete) information + * msg: string (optional) - message to report when assert violation occurs + * model_version: int - for compiling model_router + * model_assemble_constants: bool (optional) - for compiling model_router + * model_optimize: OptimizeOptions (optional) - for compiling model_router + * TODO: consider adding -->strict: bool (default True) - when True ensure + that methods + call_config's to be tested are available in + `router` and `model_router` if it exists + * TODO: in this current version, there is no way to specify any other + other txn information that might accompany the arguments + * TODO: do we need to pass along `handle_selector: bool = True` + into ABICallStrategy's init ??? + + """ + + def __init__( + self, + router: Router, + predicates: dict[str, CallPredicates], + *, + model_router: Router | None = None, + algod: algod.AlgodClient | None = None, + ): + self.router: Router = router + self.predicates: dict[str, CallPredicates] = self._validate_predicates( + predicates + ) + self.model_router: Router | None = model_router + self.algod: algod.AlgodClient = algod or algod_with_assertion() + + @classmethod + def _validate_predicates(cls, predicates): + assert isinstance( + predicates, dict + ), f"Wrong type for predicates: {type(predicates)}. Please provide: dict[str | None, dict[graviton.DryRunProporty, Any]." + + assert ( + predicates + ), "Please provide at least one method to call and assert against." + + for method, preds in predicates.items(): + assert isinstance( + method, (str, type(None)) + ), f"Predicates method '{method}' has type {type(method)} but only 'str' and 'NoneType' are allowed." + assert ( + preds + ), f"Every method must provide at least one predicate for assertion but method '{method}' is missing predicates." + assert isinstance( + preds, dict + ), f"Method '{method}' is expected to have dict[graviton.DryRunProperty, Any] for its predicates value but the type is {type(preds)}." + for prop in preds: + assert isinstance( + prop, DRProp + ), f"Method '{method}' is expected to have dict[graviton.DryRunProperty, Any] for its predicates value but predicates['{method}'] has key '{prop}' of {type(prop)}." + + return predicates + + def _prep_simulation( + self, + arg_strat_type: Type[ABIStrategy], + abi_args_mod: ABIArgsMod | None, + version: int, + *, + assemble_constants: bool = False, + optimize: OptimizeOptions | None = None, + method_configs: dict[str, MethodConfig] | None = None, + num_dryruns: int = 1, + txn_params: TxParams | None = None, + model_version: int | None = None, + model_assemble_constants: bool = False, + model_optimize: OptimizeOptions | None = None, + # TODO: do I need to pass it on to ABICallStrategy() ??? + # handle_selector: bool = True, + ) -> _SimConfig: + assert isinstance(arg_strat_type, type) and issubclass( + arg_strat_type, ABIStrategy + ), f"arg_strat_type should _BE_ a subtype of ABIStrategy but we have {arg_strat_type} (its type is {type(arg_strat_type)})." + + assert isinstance( + abi_args_mod, (ABIArgsMod, type(None)) + ), f"abi_args_mod '{abi_args_mod}' has type {type(abi_args_mod)} but only 'ABIArgsMod' and 'NoneType' are allowed." + + ap_compiled, csp_compiled, contract = self.router.compile_program( + version=version, assemble_constants=assemble_constants, optimize=optimize + ) + assert ( + self.router.method_configs + ), f"Base router with name '{self.router.name}' is essentially empty, as compilation results in an empty method_configs." + + assert isinstance( + method_configs, (dict, type(None)) + ), f"method_configs '{method_configs}' has type {type(method_configs)} but only 'dict' and 'NoneType' are allowed." + + if method_configs is None: + method_configs = self.router.method_configs + assert ( + method_configs + ), "if providing explicit method_configs, make sure to give at least one" + + for meth, meth_config in method_configs.items(): + assert isinstance( + meth, (str, type(None)) + ), f"method_configs dict key '{meth}' has type {type(meth)} but only str and NoneType are allowed." + assert isinstance( + meth_config, MethodConfig + ), f"method_configs['{meth}'] = has type {type(meth_config)} but only MethodConfig is allowed." + assert ( + not meth_config.is_never() + ), f"method_configs['{meth}'] specifies NEVER to be called; for driving the test, each configured method should ACTUALLY be tested." + + assert ( + isinstance(num_dryruns, int) and num_dryruns >= 1 + ), f"num_dryruns must be a positive int but is {num_dryruns}." + call_strat: ABICallStrategy = ABICallStrategy( + json.dumps(contract.dictify()), + arg_strat_type, + num_dryruns=num_dryruns, + abi_args_mod=abi_args_mod, + ) + + assert isinstance( + txn_params, (TxParams, type(None)) + ), f"txn_params must have type DryRunTransactionParams or NoneType but has type {type(txn_params)}." + + if not self.model_router: + assert ( + model_version is None + ), f"model_version '{model_version}' was provided which is nonsensical because model_router was never provided for." + + model_ap_compiled: str | None = None + model_csp_compiled: str | None = None + model_contract: sdk_abi.Contract | None = None + if self.model_router: + ( + model_ap_compiled, + model_csp_compiled, + model_contract, + ) = self.router.compile_program( + version=model_version, + assemble_constants=model_assemble_constants, + optimize=model_optimize, + ) + assert ( + self.router.method_configs + ), f"Base router with name '{self.router.name}' is essentially empty, as compilation results in an empty method_configs." + + return _SimConfig( + version=version, + assemble_constants=assemble_constants, + optimize=optimize, + ap_compiled=ap_compiled, + csp_compiled=csp_compiled, + contract=contract, + method_configs=method_configs, + call_strat=call_strat, + txn_params=txn_params, + model_version=model_version, + model_assemble_constants=model_assemble_constants, + model_optimize=model_optimize, + model_ap_compiled=model_ap_compiled, + model_csp_compiled=model_csp_compiled, + model_contract=model_contract, + ) + + def simulate_and_assert( + self, + is_approval: bool, # False for clear + method: str | None, # None for bare app call + args_strategy: ABICallStrategy, + is_app_create: bool, + on_complete: OnComplete, + *, + txn_params: TxParams | None = None, + verbose: bool = False, + msg: str = "", + force_recompile: bool = False, + version: int = 6, + identities_version: int = 8, + assemble_constants: bool = False, + optimize: OptimizeOptions | None = None, + ) -> SimulationResults: + self._lazy_compile( + version=version, + assemble_constants=assemble_constants, + optimize=optimize, + force=force_recompile, + ) + + abi_method_sig: sdk_abi.Method | None = None + if method: + abi_method_sig = self.contract.get_method_by_name(method).get_signature() + + teal = self.approval_teal if is_approval else self.clear_teal + id_teal: str | None + if self.model_router: + id_ap, id_cl, id_con = self.model_router.compile_program( + version=identities_version, + assemble_constants=assemble_constants, + optimize=optimize, + ) + id_abi_method_sig = id_con.get_method_by_name(method).get_signature() + assert abi_method_sig == id_abi_method_sig, ( + f"To compare one router method against another, these " + f"must be identical. However, we have: " + f"{abi_method_sig=} vs. {id_abi_method_sig=}" + ) + id_teal = id_ap if is_approval else id_cl + + self.sim = Simulation( + self.algod, + ExecutionMode.Application, + teal, + self.predicates, + abi_method_signature=abi_method_sig, + identities_teal=id_teal + # omit_method_selector=False, + # validation=False, + ) + + return self.sim.run_and_assert( + args_strategy, + ) diff --git a/tests/unit/blackbox_test.py b/tests/unit/blackbox_test.py index 69ee59187..f59b58e93 100644 --- a/tests/unit/blackbox_test.py +++ b/tests/unit/blackbox_test.py @@ -2,11 +2,19 @@ from pathlib import Path import pytest from typing import Literal, Optional, Tuple +from unittest.mock import MagicMock +from algosdk.v2client.algod import AlgodClient +from graviton.abi_strategy import ABIArgsMod, ABICallStrategy, RandomABIStrategy +from graviton.inspector import DryRunProperty as DRProp import pyteal as pt -from tests.blackbox import Blackbox, BlackboxWrapper, PyTealDryRunExecutor - +from tests.blackbox import ( + Blackbox, + BlackboxWrapper, + PyTealDryRunExecutor, + RouterSimulation, +) from tests.compile_asserts import assert_teal_as_expected PATH = Path.cwd() / "tests" / "unit" @@ -254,3 +262,481 @@ def test_PyTealBlackboxExecutor_abi_return_type( assert PyTealDryRunExecutor(fn, mode).abi_return_type() is not None else: assert PyTealDryRunExecutor(fn, mode).abi_return_type() is None + + +def successful_RouterSimulation(router, model_router, predicates, algod): + rsim = RouterSimulation( + router, + predicates, + model_router=model_router, + algod=algod, + ) + assert rsim.router == router + assert rsim.predicates == predicates + assert rsim.model_router == model_router + assert rsim.algod == algod + + return rsim + + +def failing_RouterSimulation(router, model_router, predicates, algod, err_msg): + with pytest.raises(AssertionError) as ae: + RouterSimulation( + router, + predicates, + model_router=model_router, + algod=algod, + ) + assert err_msg == str(ae.value) + + +def test_RouterSimulation_init(): + router = MagicMock(spec=pt.Router) + model_router = MagicMock(spec=pt.Router) + assert router != model_router + + predicates = "totally unchecked at init" + algod = MagicMock(spec=AlgodClient) + + err_msg = "Wrong type for predicates: . Please provide: dict[str | None, dict[graviton.DryRunProporty, Any]." + failing_RouterSimulation(router, model_router, predicates, algod, err_msg) + + predicates = {} + err_msg = "Please provide at least one method to call and assert against." + failing_RouterSimulation(router, model_router, predicates, algod, err_msg) + + predicates = {3: "blah"} + err_msg = "Predicates method '3' has type but only 'str' and 'NoneType' are allowed." + failing_RouterSimulation(router, model_router, predicates, algod, err_msg) + + predicates = {"bar": {DRProp.passed: True}, "foo": {}} + err_msg = "Every method must provide at least one predicate for assertion but method 'foo' is missing predicates." + failing_RouterSimulation(router, model_router, predicates, algod, err_msg) + + predicates = {"bar": {DRProp.passed: True}, "foo": 42} + err_msg = "Method 'foo' is expected to have dict[graviton.DryRunProperty, Any] for its predicates value but the type is ." + failing_RouterSimulation(router, model_router, predicates, algod, err_msg) + + predicates = {"bar": {DRProp.passed: True}, "foo": {"blah": 45}} + err_msg = "Method 'foo' is expected to have dict[graviton.DryRunProperty, Any] for its predicates value but predicates['foo'] has key 'blah' of ." + failing_RouterSimulation(router, model_router, predicates, algod, err_msg) + + predicates = {"bar": {DRProp.passed: True}, "foo": {DRProp.budgetAdded: 45}} + successful_RouterSimulation(router, model_router, predicates, algod) + + +TYPICAL_IAC_OC = pt.MethodConfig(no_op=pt.CallConfig.CALL) + + +def failing_prep_simulate( + rsim, + arg_strat_type, + abi_args_mod, + version, + assemble_constants, + optimize, + method_configs, + num_dryruns, + txn_params, + model_version, + model_assemble_constants, + model_optimize, + err_msg, + err_type=AssertionError, +): + with pytest.raises(err_type) as ae: + rsim._prep_simulation( + arg_strat_type, + abi_args_mod, + version, + assemble_constants=assemble_constants, + optimize=optimize, + method_configs=method_configs, + num_dryruns=num_dryruns, + txn_params=txn_params, + model_version=model_version, + model_assemble_constants=model_assemble_constants, + model_optimize=model_optimize, + ) + assert err_msg == str(ae.value) + + +def get_2meth_router(): + router = pt.Router( + "router", + pt.BareCallActions( + clear_state=pt.OnCompleteAction( + action=pt.Approve(), call_config=pt.CallConfig.CALL + ), + opt_in=pt.OnCompleteAction( + action=pt.Reject(), call_config=pt.CallConfig.ALL + ), + ), + ) + + @router.method + def m1(): + return pt.Approve() + + @router.method + def m2(): + return pt.Reject() + + return router + + +def test_prep_simulation(): + # init params: + predicates = { + None: { + DRProp.rejected: True, + }, + "m1": { + DRProp.passed: True, + DRProp.cost: 42, + }, + "m2": { + DRProp.passed: True, + DRProp.lastLog: "blah blah blah", + }, + } + router = pt.Router("empty") + assert {} == router.method_configs + + model_router = None # starting out, just test using one router + algod = MagicMock(spec=AlgodClient) + rsim = successful_RouterSimulation(router, model_router, predicates, algod) + + # _prep_simulation params. Start with bad ones and fix one-by-one + arg_strat_type = 25 # WRONG TYPE + abi_args_mod = 17 # WRONG TYPE + version = -13 # ASSERTED BY Router.compile() + assemble_constants = False # this won't be asserted + optimize = None # this won't be asserted + method_configs = 55 # EITHER NONE OR OF TYPE dict[str, MethodConfig] + num_dryruns = -100 # MUST BE A POSITIVE NUMBER + txn_params = "foo foo" # EITHER NONE OR OF TYPE TxParams + model_version = -103 # EXISTENCE ASSERTED IN CASE OF model_router + model_assemble_constants = False # this won't be asserted + model_optimize = None # this won't be asserted + + err_msg = "arg_strat_type should _BE_ a subtype of ABIStrategy but we have 25 (its type is )." + failing_prep_simulate( + rsim, + arg_strat_type, + abi_args_mod, + version, + assemble_constants, + optimize, + method_configs, + num_dryruns, + txn_params, + model_version, + model_assemble_constants, + model_optimize, + err_msg, + ) + + arg_strat_type = int + err_msg = "arg_strat_type should _BE_ a subtype of ABIStrategy but we have (its type is )." + failing_prep_simulate( + rsim, + arg_strat_type, + abi_args_mod, + version, + assemble_constants, + optimize, + method_configs, + num_dryruns, + txn_params, + model_version, + model_assemble_constants, + model_optimize, + err_msg, + ) + + arg_strat_type = RandomABIStrategy # finally fixed + # but abi_args_mod is still wrong + err_msg = "abi_args_mod '17' has type but only 'ABIArgsMod' and 'NoneType' are allowed." + failing_prep_simulate( + rsim, + arg_strat_type, + abi_args_mod, + version, + assemble_constants, + optimize, + method_configs, + num_dryruns, + txn_params, + model_version, + model_assemble_constants, + model_optimize, + err_msg, + ) + + abi_args_mod = ABIArgsMod.selector_byte_insert # finally fixed + # but version is still wrong + err_msg = f"Unsupported program version: -13. Excepted an integer in the range [2, {pt.MAX_PROGRAM_VERSION}]" + failing_prep_simulate( + rsim, + arg_strat_type, + abi_args_mod, + version, + assemble_constants, + optimize, + method_configs, + num_dryruns, + txn_params, + model_version, + model_assemble_constants, + model_optimize, + err_msg, + err_type=pt.TealInputError, + ) + + version = 7 # finally fixed + err_msg = "Base router with name 'empty' is essentially empty, as compilation results in an empty method_configs." + failing_prep_simulate( + rsim, + arg_strat_type, + abi_args_mod, + version, + assemble_constants, + optimize, + method_configs, + num_dryruns, + txn_params, + model_version, + model_assemble_constants, + model_optimize, + err_msg, + ) + + router = get_2meth_router() + router_method_configs = { + None: pt.MethodConfig(opt_in=pt.CallConfig.ALL, clear_state=pt.CallConfig.CALL), + "m1": pt.MethodConfig(no_op=pt.CallConfig.CALL), + "m2": pt.MethodConfig(no_op=pt.CallConfig.CALL), + } + assert router_method_configs == router.method_configs + rsim = successful_RouterSimulation(router, model_router, predicates, algod) + + err_msg = "method_configs '55' has type but only 'dict' and 'NoneType' are allowed." + failing_prep_simulate( + rsim, + arg_strat_type, + abi_args_mod, + version, + assemble_constants, + optimize, + method_configs, + num_dryruns, + txn_params, + model_version, + model_assemble_constants, + model_optimize, + err_msg, + ) + + method_configs = {} + err_msg = "if providing explicit method_configs, make sure to give at least one" + failing_prep_simulate( + rsim, + arg_strat_type, + abi_args_mod, + version, + assemble_constants, + optimize, + method_configs, + num_dryruns, + txn_params, + model_version, + model_assemble_constants, + model_optimize, + err_msg, + ) + + method_configs = { + None: pt.MethodConfig(opt_in=pt.CallConfig.ALL, clear_state=pt.CallConfig.CALL), + 42: "foo", + "m2": pt.MethodConfig(no_op=pt.CallConfig.ALL), + } + err_msg = "method_configs dict key '42' has type but only str and NoneType are allowed." + failing_prep_simulate( + rsim, + arg_strat_type, + abi_args_mod, + version, + assemble_constants, + optimize, + method_configs, + num_dryruns, + txn_params, + model_version, + model_assemble_constants, + model_optimize, + err_msg, + ) + + method_configs = { + None: pt.MethodConfig(opt_in=pt.CallConfig.ALL, clear_state=pt.CallConfig.CALL), + "m1": "foo", + "m2": pt.MethodConfig(no_op=pt.CallConfig.ALL), + } + err_msg = f"method_configs['m1'] = has type but only MethodConfig is allowed." + failing_prep_simulate( + rsim, + arg_strat_type, + abi_args_mod, + version, + assemble_constants, + optimize, + method_configs, + num_dryruns, + txn_params, + model_version, + model_assemble_constants, + model_optimize, + err_msg, + ) + + method_configs = { + None: pt.MethodConfig(opt_in=pt.CallConfig.ALL, clear_state=pt.CallConfig.CALL), + "m1": pt.MethodConfig(no_op=pt.CallConfig.CALL), + "m2": pt.MethodConfig(no_op=pt.CallConfig.NEVER), + } + err_msg = "method_configs['m2'] specifies NEVER to be called; for driving the test, each configured method should ACTUALLY be tested." + failing_prep_simulate( + rsim, + arg_strat_type, + abi_args_mod, + version, + assemble_constants, + optimize, + method_configs, + num_dryruns, + txn_params, + model_version, + model_assemble_constants, + model_optimize, + err_msg, + ) + + method_configs = router_method_configs # finally fixed + # but num_dry_runs is still illegal + err_msg = "num_dryruns must be a positive int but is -100." + failing_prep_simulate( + rsim, + arg_strat_type, + abi_args_mod, + version, + assemble_constants, + optimize, + method_configs, + num_dryruns, + txn_params, + model_version, + model_assemble_constants, + model_optimize, + err_msg, + ) + + num_dryruns = 4 # finally fixed + # but txn_params is still messed up + err_msg = "txn_params must have type DryRunTransactionParams or NoneType but has type ." + failing_prep_simulate( + rsim, + arg_strat_type, + abi_args_mod, + version, + assemble_constants, + optimize, + method_configs, + num_dryruns, + txn_params, + model_version, + model_assemble_constants, + model_optimize, + err_msg, + ) + + txn_params = None # finally fixed + # but shoudn't provide `model_*` params when `model_router` wasn't provided + err_msg = "model_version '-103' was provided which is nonsensical because model_router was never provided for." + failing_prep_simulate( + rsim, + arg_strat_type, + abi_args_mod, + version, + assemble_constants, + optimize, + method_configs, + num_dryruns, + txn_params, + model_version, + model_assemble_constants, + model_optimize, + err_msg, + ) + + # -- NOW TRY model_router AS WELL -- # + model_router = router + algod = MagicMock(spec=AlgodClient) + rsim = successful_RouterSimulation(router, model_router, predicates, algod) + # but model_version is still wrong + err_msg = f"Unsupported program version: -103. Excepted an integer in the range [2, {pt.MAX_PROGRAM_VERSION}]" + failing_prep_simulate( + rsim, + arg_strat_type, + abi_args_mod, + version, + assemble_constants, + optimize, + method_configs, + num_dryruns, + txn_params, + model_version, + model_assemble_constants, + model_optimize, + err_msg, + err_type=pt.TealInputError, + ) + + model_version = 8 # FINALLY FINALLY FINALLY FIXED + # OK! we should be GTG + + sim_cfg = rsim._prep_simulation( + arg_strat_type, + abi_args_mod, + version, + assemble_constants=assemble_constants, + optimize=optimize, + method_configs=method_configs, + num_dryruns=num_dryruns, + txn_params=txn_params, + model_version=model_version, + model_assemble_constants=model_assemble_constants, + model_optimize=model_optimize, + ) + assert sim_cfg.version == version + assert sim_cfg.assemble_constants == assemble_constants + assert sim_cfg.optimize == optimize + + assert sim_cfg.ap_compiled + assert sim_cfg.csp_compiled + assert sim_cfg.contract + + assert sim_cfg.method_configs == method_configs + + assert sim_cfg.call_strat + assert sim_cfg.call_strat.abi_args_mod == abi_args_mod + + assert sim_cfg.txn_params == txn_params + + assert sim_cfg.model_version == model_version + assert sim_cfg.model_assemble_constants == model_assemble_constants + assert sim_cfg.model_optimize == model_optimize + + assert sim_cfg.model_ap_compiled + assert sim_cfg.model_csp_compiled + assert sim_cfg.model_contract From 8445c538ab1acc56f314a3bf5846b2d59ea54293 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 19 Jan 2023 00:34:29 -0600 Subject: [PATCH 161/206] RouterSimulation - code complete --- tests/blackbox.py | 186 ++++++++++++++++++++++++++---------- tests/unit/blackbox_test.py | 2 +- 2 files changed, 136 insertions(+), 52 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index fb8b03b92..cb56af5fe 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -1,4 +1,6 @@ -from dataclasses import dataclass +from copy import deepcopy +from collections import defaultdict +from dataclasses import dataclass, asdict import json from typing import Any, Callable, Sequence, Type, cast @@ -479,6 +481,29 @@ class _SimConfig: model_contract: sdk_abi.Contract | None +def as_on_complete(oc_str: str) -> OnComplete: + match oc_str: + case "no_op": + return OnComplete.NoOpOC + case "opt_in": + return OnComplete.OptInOC + case "close_out": + return OnComplete.CloseOutOC + case "clear_state": + return OnComplete.ClearStateOC + case "update_application": + return OnComplete.UpdateApplicationOC + case "delete_application": + return OnComplete.DeleteApplicationOC + + raise ValueError(f"unrecognized {oc_str=}") + + +# class _AutoDict(defaultdict): +# def __init__(self): +# super().__init__(lambda: _AutoDict()) + + class RouterSimulation: """ Lifecycle of a RouterSimulation @@ -536,6 +561,10 @@ def __init__( self.model_router: Router | None = model_router self.algod: algod.AlgodClient = algod or algod_with_assertion() + self.results: dict[ + str | None, dict[tuple[bool, OnComplete], SimulationResults] + ] = {} + @classmethod def _validate_predicates(cls, predicates): assert isinstance( @@ -672,59 +701,114 @@ def _prep_simulation( def simulate_and_assert( self, - is_approval: bool, # False for clear - method: str | None, # None for bare app call - args_strategy: ABICallStrategy, - is_app_create: bool, - on_complete: OnComplete, + arg_strat_type: Type[ABIStrategy], + abi_args_mod: ABIArgsMod | None, + version: int, *, - txn_params: TxParams | None = None, - verbose: bool = False, - msg: str = "", - force_recompile: bool = False, - version: int = 6, - identities_version: int = 8, assemble_constants: bool = False, optimize: OptimizeOptions | None = None, - ) -> SimulationResults: - self._lazy_compile( - version=version, + method_configs: dict[str, MethodConfig] | None = None, + num_dryruns: int = 1, + txn_params: TxParams | None = None, + model_version: int | None = None, + model_assemble_constants: bool = False, + model_optimize: OptimizeOptions | None = None, + # fail_on_first: bool = True, ??? future ??? + ) -> dict: + sim_cfg = self._prep_simulation( + arg_strat_type, + abi_args_mod, + version, assemble_constants=assemble_constants, optimize=optimize, - force=force_recompile, - ) - - abi_method_sig: sdk_abi.Method | None = None - if method: - abi_method_sig = self.contract.get_method_by_name(method).get_signature() - - teal = self.approval_teal if is_approval else self.clear_teal - id_teal: str | None - if self.model_router: - id_ap, id_cl, id_con = self.model_router.compile_program( - version=identities_version, - assemble_constants=assemble_constants, - optimize=optimize, - ) - id_abi_method_sig = id_con.get_method_by_name(method).get_signature() - assert abi_method_sig == id_abi_method_sig, ( - f"To compare one router method against another, these " - f"must be identical. However, we have: " - f"{abi_method_sig=} vs. {id_abi_method_sig=}" - ) - id_teal = id_ap if is_approval else id_cl - - self.sim = Simulation( - self.algod, - ExecutionMode.Application, - teal, - self.predicates, - abi_method_signature=abi_method_sig, - identities_teal=id_teal - # omit_method_selector=False, - # validation=False, - ) - - return self.sim.run_and_assert( - args_strategy, + method_configs=method_configs, + num_dryruns=num_dryruns, + txn_params=txn_params, + model_version=model_version, + model_assemble_constants=model_assemble_constants, + model_optimize=model_optimize, ) + if not txn_params: + txn_params = TxParams() + + method_combo_count = 0 + dryrun_count = 0 + assertions_count = 0 + + def msg() -> str: + return f"""{meth=} +{oc=} +{call_cfg=} +{is_app_create=} +{len(self.predicates[meth])=} +{method_combo_count=} +{dryrun_count=} +{assertions_count=} +""" + + for meth, meth_cfg in sim_cfg.method_configs.items(): + approve_sim: Simulation | None = None + clear_sim: Simulation | None = None + for oc_str, call_cfg in meth_cfg.items(): + oc = as_on_complete(oc_str) + sim: Simulation + if oc is OnComplete.ClearStateOC: + if not clear_sim: + clear_sim = Simulation( + algod, + ExecutionMode.Application, + sim_cfg.csp_compiled, + self.predicates[meth], + sim_cfg.call_strat.method_signature(), + # omit_method_selector=False ???? + # validation=True ??? + identities_teal=sim_cfg.model_csp_compiled, + ) + sim = clear_sim + else: + if not approve_sim: + approve_sim = Simulation( + algod, + ExecutionMode.Application, + sim_cfg.ap_compiled, + self.predicates[meth], + sim_cfg.call_strat.method_signature(), + # omit_method_selector=False ???? + # validation=True ??? + identities_teal=sim_cfg.model_ap_compiled, + ) + sim = approve_sim + + is_app_create: bool + + def simulate(): + tp: TxParams = deepcopy(txn_params) + tp.update( + TxParams.for_app(is_app_create=is_app_create, on_complete=oc) + ) + sim_results = sim.run_and_assert( + sim_cfg.call_strat, txn_params=tp, msg=msg() + ) + assert sim_results.succeeded + self.results[meth][(is_app_create, oc)] = sim_results + + method_combo_count += 1 + dryrun_count += sim_cfg.call_strat.num_dryruns + assertions_count += sim_cfg.call_strat.num_dryruns * len( + self.predicates[meth] + ) + + if call_cfg & CallConfig.CALL: + is_app_create = False + simulate() + + if call_cfg & CallConfig.CREATE: + is_app_create = True + simulate() + return { + "sim_cfg": sim_cfg, + "method_combo_count": method_combo_count, + "dryrun_count": dryrun_count, + "assertions_count": assertions_count, + "results": self.results, + } diff --git a/tests/unit/blackbox_test.py b/tests/unit/blackbox_test.py index f59b58e93..d01d9c1bb 100644 --- a/tests/unit/blackbox_test.py +++ b/tests/unit/blackbox_test.py @@ -721,7 +721,7 @@ def test_prep_simulation(): assert sim_cfg.version == version assert sim_cfg.assemble_constants == assemble_constants assert sim_cfg.optimize == optimize - + assert sim_cfg.ap_compiled assert sim_cfg.csp_compiled assert sim_cfg.contract From 8915b9fc3372c9196961af313e75619be14561f1 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 19 Jan 2023 00:35:27 -0600 Subject: [PATCH 162/206] save the work --- tests/integration/abi_router_test.py | 506 ++++++++++++++++++--------- 1 file changed, 350 insertions(+), 156 deletions(-) diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index 75c148feb..78c4ad468 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -1,170 +1,170 @@ from pathlib import Path import pytest +from typing import Any + +from algosdk.transaction import OnComplete +from graviton.abi_strategy import ABIArgsMod, ABICallStrategy, RandomABIStrategyHalfSized +from graviton.blackbox import DryRunEncoder +from graviton.invariant import DryRunProperty as DRProp import pyteal as pt +NUM_ROUTER_DRYRUNS = 7 FIXTURES = Path.cwd() / "tests" / "integration" / "teal" / "router" -def test_router_app(): - def add_methods_to_router(router: pt.Router): - @pt.ABIReturnSubroutine - def add( - a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 - ) -> pt.Expr: - return output.set(a.get() + b.get()) - - meth = router.add_method_handler(add) - assert meth.method_signature() == "add(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def sub( - a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 - ) -> pt.Expr: - return output.set(a.get() - b.get()) - - meth = router.add_method_handler(sub) - assert meth.method_signature() == "sub(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def mul( - a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 - ) -> pt.Expr: - return output.set(a.get() * b.get()) - - meth = router.add_method_handler(mul) - assert meth.method_signature() == "mul(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def div( - a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 - ) -> pt.Expr: - return output.set(a.get() / b.get()) - - meth = router.add_method_handler(div) - assert meth.method_signature() == "div(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def mod( - a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 - ) -> pt.Expr: - return output.set(a.get() % b.get()) - - meth = router.add_method_handler(mod) - assert meth.method_signature() == "mod(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def all_laid_to_args( - _a: pt.abi.Uint64, - _b: pt.abi.Uint64, - _c: pt.abi.Uint64, - _d: pt.abi.Uint64, - _e: pt.abi.Uint64, - _f: pt.abi.Uint64, - _g: pt.abi.Uint64, - _h: pt.abi.Uint64, - _i: pt.abi.Uint64, - _j: pt.abi.Uint64, - _k: pt.abi.Uint64, - _l: pt.abi.Uint64, - _m: pt.abi.Uint64, - _n: pt.abi.Uint64, - _o: pt.abi.Uint64, - _p: pt.abi.Uint64, - *, - output: pt.abi.Uint64, - ): - return output.set( - _a.get() - + _b.get() - + _c.get() - + _d.get() - + _e.get() - + _f.get() - + _g.get() - + _h.get() - + _i.get() - + _j.get() - + _k.get() - + _l.get() - + _m.get() - + _n.get() - + _o.get() - + _p.get() - ) - - meth = router.add_method_handler(all_laid_to_args) - assert ( - meth.method_signature() - == "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" +def add_methods_to_router(router: pt.Router): + @pt.ABIReturnSubroutine + def add(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr: + return output.set(a.get() + b.get()) + + meth = router.add_method_handler(add) + assert meth.method_signature() == "add(uint64,uint64)uint64" + + @pt.ABIReturnSubroutine + def sub(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr: + return output.set(a.get() - b.get()) + + meth = router.add_method_handler(sub) + assert meth.method_signature() == "sub(uint64,uint64)uint64" + + @pt.ABIReturnSubroutine + def mul(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr: + return output.set(a.get() * b.get()) + + meth = router.add_method_handler(mul) + assert meth.method_signature() == "mul(uint64,uint64)uint64" + + @pt.ABIReturnSubroutine + def div(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr: + return output.set(a.get() / b.get()) + + meth = router.add_method_handler(div) + assert meth.method_signature() == "div(uint64,uint64)uint64" + + @pt.ABIReturnSubroutine + def mod(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr: + return output.set(a.get() % b.get()) + + meth = router.add_method_handler(mod) + assert meth.method_signature() == "mod(uint64,uint64)uint64" + + @pt.ABIReturnSubroutine + def all_laid_to_args( + _a: pt.abi.Uint64, + _b: pt.abi.Uint64, + _c: pt.abi.Uint64, + _d: pt.abi.Uint64, + _e: pt.abi.Uint64, + _f: pt.abi.Uint64, + _g: pt.abi.Uint64, + _h: pt.abi.Uint64, + _i: pt.abi.Uint64, + _j: pt.abi.Uint64, + _k: pt.abi.Uint64, + _l: pt.abi.Uint64, + _m: pt.abi.Uint64, + _n: pt.abi.Uint64, + _o: pt.abi.Uint64, + _p: pt.abi.Uint64, + *, + output: pt.abi.Uint64, + ): + return output.set( + _a.get() + + _b.get() + + _c.get() + + _d.get() + + _e.get() + + _f.get() + + _g.get() + + _h.get() + + _i.get() + + _j.get() + + _k.get() + + _l.get() + + _m.get() + + _n.get() + + _o.get() + + _p.get() ) - @pt.ABIReturnSubroutine - def empty_return_subroutine() -> pt.Expr: - return pt.Log(pt.Bytes("appear in both approval and clear state")) + meth = router.add_method_handler(all_laid_to_args) + assert ( + meth.method_signature() + == "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" + ) - meth = router.add_method_handler( - empty_return_subroutine, - method_config=pt.MethodConfig( - no_op=pt.CallConfig.CALL, - opt_in=pt.CallConfig.ALL, - clear_state=pt.CallConfig.CALL, - ), - ) - assert meth.method_signature() == "empty_return_subroutine()void" - - @pt.ABIReturnSubroutine - def log_1(*, output: pt.abi.Uint64) -> pt.Expr: - return output.set(1) - - meth = router.add_method_handler( - log_1, - method_config=pt.MethodConfig( - no_op=pt.CallConfig.CALL, - opt_in=pt.CallConfig.CALL, - clear_state=pt.CallConfig.CALL, - ), - ) + @pt.ABIReturnSubroutine + def empty_return_subroutine() -> pt.Expr: + return pt.Log(pt.Bytes("appear in both approval and clear state")) + + meth = router.add_method_handler( + empty_return_subroutine, + method_config=pt.MethodConfig( + no_op=pt.CallConfig.CALL, + opt_in=pt.CallConfig.ALL, + clear_state=pt.CallConfig.CALL, + ), + ) + assert meth.method_signature() == "empty_return_subroutine()void" + + @pt.ABIReturnSubroutine + def log_1(*, output: pt.abi.Uint64) -> pt.Expr: + return output.set(1) + + meth = router.add_method_handler( + log_1, + method_config=pt.MethodConfig( + no_op=pt.CallConfig.CALL, + opt_in=pt.CallConfig.CALL, + clear_state=pt.CallConfig.CALL, + ), + ) - assert meth.method_signature() == "log_1()uint64" + assert meth.method_signature() == "log_1()uint64" - @pt.ABIReturnSubroutine - def log_creation(*, output: pt.abi.String) -> pt.Expr: - return output.set("logging creation") + @pt.ABIReturnSubroutine + def log_creation(*, output: pt.abi.String) -> pt.Expr: + return output.set("logging creation") - meth = router.add_method_handler( - log_creation, method_config=pt.MethodConfig(no_op=pt.CallConfig.CREATE) - ) - assert meth.method_signature() == "log_creation()string" - - @pt.ABIReturnSubroutine - def approve_if_odd(condition_encoding: pt.abi.Uint32) -> pt.Expr: - return ( - pt.If(condition_encoding.get() % pt.Int(2)) - .Then(pt.Approve()) - .Else(pt.Reject()) - ) - - meth = router.add_method_handler( - approve_if_odd, - method_config=pt.MethodConfig( - no_op=pt.CallConfig.NEVER, clear_state=pt.CallConfig.CALL - ), + meth = router.add_method_handler( + log_creation, method_config=pt.MethodConfig(no_op=pt.CallConfig.CREATE) + ) + assert meth.method_signature() == "log_creation()string" + + @pt.ABIReturnSubroutine + def approve_if_odd(condition_encoding: pt.abi.Uint32) -> pt.Expr: + return ( + pt.If(condition_encoding.get() % pt.Int(2)) + .Then(pt.Approve()) + .Else(pt.Reject()) ) - assert meth.method_signature() == "approve_if_odd(uint32)void" + meth = router.add_method_handler( + approve_if_odd, + method_config=pt.MethodConfig( + no_op=pt.CallConfig.NEVER, clear_state=pt.CallConfig.CALL + ), + ) + assert meth.method_signature() == "approve_if_odd(uint32)void" + + +def generate_and_test_routers(): + routers = [] + + # V6 not ready for Frame Pointers: on_completion_actions = pt.BareCallActions( opt_in=pt.OnCompleteAction.call_only(pt.Log(pt.Bytes("optin call"))), clear_state=pt.OnCompleteAction.call_only(pt.Approve()), ) - with pytest.raises(pt.TealInputError) as e: pt.Router("will-error", on_completion_actions).compile_program( version=6, optimize=pt.OptimizeOptions(frame_pointers=True) ) - assert "Frame pointers aren't available" in str(e.value) + # QUESTIONABLE V6: _router_with_oc = pt.Router( "ASimpleQuestionablyRobustContract", on_completion_actions ) @@ -174,17 +174,15 @@ def approve_if_odd(condition_encoding: pt.abi.Uint32) -> pt.Expr: actual_csp_with_oc_compiled, _, ) = _router_with_oc.compile_program(version=6) - with open(FIXTURES / "questionable_approval_v6.teal") as f: expected_ap_with_oc = f.read() - - assert expected_ap_with_oc == actual_ap_with_oc_compiled - with open(FIXTURES / "questionable_clear_v6.teal") as f: expected_csp_with_oc = f.read() - + assert expected_ap_with_oc == actual_ap_with_oc_compiled assert expected_csp_with_oc == actual_csp_with_oc_compiled + routers.append(("questionable", 6, _router_with_oc)) + # YACC V6: _router_without_oc = pt.Router("yetAnotherContractConstructedFromRouter") add_methods_to_router(_router_without_oc) ( @@ -192,15 +190,15 @@ def approve_if_odd(condition_encoding: pt.abi.Uint32) -> pt.Expr: actual_csp_without_oc_compiled, _, ) = _router_without_oc.compile_program(version=6) - with open(FIXTURES / "yacc_approval_v6.teal") as f: expected_ap_without_oc = f.read() - assert actual_ap_without_oc_compiled == expected_ap_without_oc - with open(FIXTURES / "yacc_clear_v6.teal") as f: expected_csp_without_oc = f.read() + assert actual_ap_without_oc_compiled == expected_ap_without_oc assert actual_csp_without_oc_compiled == expected_csp_without_oc + routers.append(("yacc", 6, _router_without_oc)) + # QUESTIONABLE FP V8: _router_with_oc = pt.Router( "QuestionableRouterGenerateCodeWithFramePointer", on_completion_actions ) @@ -210,15 +208,15 @@ def approve_if_odd(condition_encoding: pt.abi.Uint32) -> pt.Expr: actual_csp_with_oc_compiled, _, ) = _router_with_oc.compile_program(version=8) - with open(FIXTURES / "questionableFP_approval_v8.teal") as f: expected_ap_with_oc = f.read() - assert actual_ap_with_oc_compiled == expected_ap_with_oc - with open(FIXTURES / "questionableFP_clear_v8.teal") as f: expected_csp_with_oc = f.read() + assert actual_ap_with_oc_compiled == expected_ap_with_oc assert actual_csp_with_oc_compiled == expected_csp_with_oc + routers.append(("questionable", 8, _router_with_oc)) + # YACC FP V8: _router_without_oc = pt.Router( "yetAnotherContractConstructedFromRouterWithFramePointer" ) @@ -228,12 +226,208 @@ def approve_if_odd(condition_encoding: pt.abi.Uint32) -> pt.Expr: actual_csp_without_oc_compiled, _, ) = _router_without_oc.compile_program(version=8) - with open(FIXTURES / "yaccFP_approval_v8.teal") as f: expected_ap_without_oc = f.read() - assert actual_ap_without_oc_compiled == expected_ap_without_oc - with open(FIXTURES / "yaccFP_clear_v8.teal") as f: expected_csp_without_oc = f.read() - + assert actual_ap_without_oc_compiled == expected_ap_without_oc assert actual_csp_without_oc_compiled == expected_csp_without_oc + routers.append(("yacc", 8, _router_without_oc)) + + return routers + + +ROUTER_CASES = generate_and_test_routers() + +TYPICAL_IAC_OC = (False, OnComplete.NoOpOC) + +# LEGEND FOR TEST CASES: +# +# * @0 - method: str. method == `None` indicates bare app call +# +# * @1 - approval_call_types: list[tuple[bool, OncComplete]] +# [(is_app_create, `OnComplete`), ...] contexts expected for approval program +# +# * @2 - clear_call_types: list[tuple[bool, Oncomplete]] +# [(is_app_create, `OnComplete`), ...] contexts expected for clear program +# +# * @3 - predicates: dict[DRProp, Any] +# these are being asserted after being processed into Invariant's +# +# NOTE: the "yacc" routers will simply ignore the case with method `None` +# as they do not have any bare-app-calls +QUESTIONABLE_CASES: list[ + tuple[ + str, + list[tuple[bool, OnComplete]], + list[tuple[bool, OnComplete]], + dict[DRProp, Any], + ] +] = [ + ( + "add", + [TYPICAL_IAC_OC], + [], + {DRProp.passed: True, DRProp.lastLog: lambda args: args[1] + args[2]}, + ), + ( + "sub", + [TYPICAL_IAC_OC], + [], + { + DRProp.passed: lambda args: args[1] >= args[2], + DRProp.lastLog: ( + lambda args, actual: True + if args[1] < args[2] + else actual == args[1] - args[2] + ), + }, + ), + ( + "mul", + [TYPICAL_IAC_OC], + [], + {DRProp.passed: True, DRProp.lastLog: lambda args: args[1] * args[2]}, + ), + ( + "div", + [TYPICAL_IAC_OC], + [], + {DRProp.passed: True, DRProp.lastLog: lambda args: args[1] // args[2]}, + ), + ( + "mod", + [TYPICAL_IAC_OC], + [], + {DRProp.passed: True, DRProp.lastLog: lambda args: args[1] % args[2]}, + ), + ( + "all_laid_to_args", + [TYPICAL_IAC_OC], + [], + {DRProp.passed: True, DRProp.lastLog: lambda args: sum(args[1:])}, + ), + ( + "empty_return_subroutine", + [ + (False, OnComplete.NoOpOC), + (False, OnComplete.OptInOC), + (True, OnComplete.OptInOC), + ], + [ + (False, OnComplete.ClearStateOC), + ], + { + DRProp.passed: True, + DRProp.lastLog: DryRunEncoder.hex( + "appear in both approval and clear state" + ), + }, + ), + ( + "log_1", + [(False, OnComplete.NoOpOC), (False, OnComplete.OptInOC)], + [ + (False, OnComplete.ClearStateOC), + ], + {DRProp.passed: True, DRProp.lastLog: 1}, + ), + ( + "log_creation", + [(True, OnComplete.NoOpOC)], + [], + {DRProp.passed: True, DRProp.lastLog: "logging creation"}, + ), + ( + "approve_if_odd", # this should only appear in the clear-state program + [], + [ + (False, OnComplete.ClearStateOC), + ], + { + DRProp.passed: lambda args: args[1] % 2 == 1, + DRProp.lastLog: None, + }, + ), + ( + None, + [(False, OnComplete.OptInOC)], + [ + (False, OnComplete.ClearStateOC), + ], + { + DRProp.passed: True, + DRProp.lastLog: lambda _, actual: actual + in (None, DryRunEncoder.hex("optin call")), + }, + ), +] + + + + +@pytest.mark.parametrize("case, version, router", ROUTER_CASES) +@pytest.mark.parametrize( + "method, approval_call_types, clear_call_types, predicates", QUESTIONABLE_CASES +) +def test_abi_router_positive( + case, version, router, method, approval_call_types, clear_call_types, predicates +): + """ + Test the _positive_ version of a case. In other words, ensure that for the given: + * method or bare call + * OnComplete value + * number of arguments + that the app call succeeds according to the provided _invariants_ success definition + """ + def get_aa_strat(method_runner, abi_args_mod=None) -> ABICallStrategy: + return ABICallStrategy( + method_runner.teal, + method_runner.contract, + RandomABIStrategyHalfSized, + num_dryruns=NUM_ROUTER_DRYRUNS, + abi_args_mod=abi_args_mod, + ) + + + # def run_positive(is_approve, method_runner, call_types, invariants): + good_abi_args = get_aa_strat(method_runner) + + algod = get_algod() + + if not call_types: + return + + method = method_runner.method + sim = Simulation( + algod, + ExecutionMode.Application, + method_runner.teal, + invariants, + abi_method_signature=good_abi_args.method_signature(method), + omit_method_selector=False, + validation=False, + ) + + def msg(): + return f""" +TEST CASE [{method_runner}]({"APPROVAL" if is_approve else "CLEAR"}): +test_function={inspect.stack()[2][3]} +method={method} +is_app_create={is_app_create} +on_complete={on_complete!r}""" + + for is_app_create, on_complete in call_types: + sim_result = sim.run_and_assert( + good_abi_args, + method=method, + txn_params=TxParams.for_app( + is_app_create=is_app_create, + on_complete=on_complete, + ), + msg=msg(), + ) + assert sim_result.succeeded + + # run_positive(True, approval_runner, approval_call_types, invariants) + # run_positive(False, clear_runner, clear_call_types, invariants) From 139b26bf54e64861790e0e6add1fb5ca29ebd895 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 19 Jan 2023 06:54:42 -0600 Subject: [PATCH 163/206] positive cases --- tests/blackbox.py | 130 +++++++++---------- tests/integration/abi_router_test.py | 178 ++++++++++----------------- tests/unit/blackbox_test.py | 3 - 3 files changed, 130 insertions(+), 181 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index cb56af5fe..250efdb34 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -2,11 +2,11 @@ from collections import defaultdict from dataclasses import dataclass, asdict import json -from typing import Any, Callable, Sequence, Type, cast +from typing import Any, Callable, Dict, Sequence, Type, cast import algosdk.abi as sdk_abi from algosdk.transaction import OnComplete -from algosdk.v2client import algod +import algosdk.v2client as v2client from graviton import blackbox from graviton.abi_strategy import ABIArgsMod, ABICallStrategy, ABIStrategy @@ -66,9 +66,9 @@ def algod_with_assertion(): def _algod_client( algod_address="http://localhost:4001", algod_token="a" * 64 -) -> algod.AlgodClient: +) -> v2client.algod.AlgodClient: """Instantiate and return Algod client object.""" - return algod.AlgodClient(algod_token, algod_address) + return v2client.algod.AlgodClient(algod_token, algod_address) # ---- Decorator ---- # @@ -481,6 +481,11 @@ class _SimConfig: model_contract: sdk_abi.Contract | None +class _AutoPathDict(defaultdict): + def __init__(self): + super().__init__(lambda: _AutoPathDict()) + + def as_on_complete(oc_str: str) -> OnComplete: match oc_str: case "no_op": @@ -499,11 +504,6 @@ def as_on_complete(oc_str: str) -> OnComplete: raise ValueError(f"unrecognized {oc_str=}") -# class _AutoDict(defaultdict): -# def __init__(self): -# super().__init__(lambda: _AutoDict()) - - class RouterSimulation: """ Lifecycle of a RouterSimulation @@ -552,18 +552,18 @@ def __init__( predicates: dict[str, CallPredicates], *, model_router: Router | None = None, - algod: algod.AlgodClient | None = None, + algod: v2client.algod.AlgodClient | None = None, ): self.router: Router = router self.predicates: dict[str, CallPredicates] = self._validate_predicates( predicates ) self.model_router: Router | None = model_router - self.algod: algod.AlgodClient = algod or algod_with_assertion() + self.algod: v2client.algod.AlgodClient = algod or algod_with_assertion() - self.results: dict[ + self.results: Dict[ str | None, dict[tuple[bool, OnComplete], SimulationResults] - ] = {} + ] = _AutoPathDict() @classmethod def _validate_predicates(cls, predicates): @@ -672,14 +672,14 @@ def _prep_simulation( model_ap_compiled, model_csp_compiled, model_contract, - ) = self.router.compile_program( + ) = self.model_router.compile_program( version=model_version, assemble_constants=model_assemble_constants, optimize=model_optimize, ) assert ( - self.router.method_configs - ), f"Base router with name '{self.router.name}' is essentially empty, as compilation results in an empty method_configs." + self.model_router.method_configs + ), f"Model router with name '{self.model_router.name}' is essentially empty, as compilation results in an empty method_configs." return _SimConfig( version=version, @@ -731,9 +731,12 @@ def simulate_and_assert( if not txn_params: txn_params = TxParams() - method_combo_count = 0 - dryrun_count = 0 - assertions_count = 0 + stats = dict( + name=self.router.name, + method_combo_count=0, + dryrun_count=0, + assertions_count=0, + ) def msg() -> str: return f"""{meth=} @@ -741,74 +744,71 @@ def msg() -> str: {call_cfg=} {is_app_create=} {len(self.predicates[meth])=} -{method_combo_count=} -{dryrun_count=} -{assertions_count=} +{stats["method_combo_count"]=} +{stats["dryrun_count"]=} +{stats["assertions_count"]=} """ + def get_sim(): + return Simulation( + self.algod, + ExecutionMode.Application, + teal, + self.predicates[meth], + abi_method_signature=sim_cfg.call_strat.method_signature(meth), + # omit_method_selector=False ???? + # validation=True ??? + identities_teal=identities_teal, + ) + + def simulate(stats, is_app_create): + tp: TxParams = deepcopy(txn_params) + tp.update(TxParams.for_app(is_app_create=is_app_create, on_complete=oc)) + sim_results = sim.run_and_assert( + sim_cfg.call_strat, txn_params=tp, msg=msg() + ) + assert sim_results.succeeded + self.results[meth][(is_app_create, oc)] = sim_results + + stats["method_combo_count"] += 1 + stats["dryrun_count"] += sim_cfg.call_strat.num_dryruns + stats["assertions_count"] += sim_cfg.call_strat.num_dryruns * len( + self.predicates[meth] + ) + for meth, meth_cfg in sim_cfg.method_configs.items(): approve_sim: Simulation | None = None clear_sim: Simulation | None = None - for oc_str, call_cfg in meth_cfg.items(): + for oc_str, call_cfg in asdict(meth_cfg).items(): oc = as_on_complete(oc_str) sim: Simulation if oc is OnComplete.ClearStateOC: + teal: str + identities_teal: str | None + if not clear_sim: - clear_sim = Simulation( - algod, - ExecutionMode.Application, - sim_cfg.csp_compiled, - self.predicates[meth], - sim_cfg.call_strat.method_signature(), - # omit_method_selector=False ???? - # validation=True ??? - identities_teal=sim_cfg.model_csp_compiled, - ) + teal = sim_cfg.csp_compiled + identities_teal = sim_cfg.model_csp_compiled + clear_sim = get_sim() sim = clear_sim else: if not approve_sim: - approve_sim = Simulation( - algod, - ExecutionMode.Application, - sim_cfg.ap_compiled, - self.predicates[meth], - sim_cfg.call_strat.method_signature(), - # omit_method_selector=False ???? - # validation=True ??? - identities_teal=sim_cfg.model_ap_compiled, - ) + teal = sim_cfg.ap_compiled + identities_teal = sim_cfg.model_ap_compiled + approve_sim = get_sim() sim = approve_sim is_app_create: bool - def simulate(): - tp: TxParams = deepcopy(txn_params) - tp.update( - TxParams.for_app(is_app_create=is_app_create, on_complete=oc) - ) - sim_results = sim.run_and_assert( - sim_cfg.call_strat, txn_params=tp, msg=msg() - ) - assert sim_results.succeeded - self.results[meth][(is_app_create, oc)] = sim_results - - method_combo_count += 1 - dryrun_count += sim_cfg.call_strat.num_dryruns - assertions_count += sim_cfg.call_strat.num_dryruns * len( - self.predicates[meth] - ) - if call_cfg & CallConfig.CALL: is_app_create = False - simulate() + simulate(stats, is_app_create) if call_cfg & CallConfig.CREATE: is_app_create = True - simulate() + simulate(stats, is_app_create) return { "sim_cfg": sim_cfg, - "method_combo_count": method_combo_count, - "dryrun_count": dryrun_count, - "assertions_count": assertions_count, + "stats": stats, "results": self.results, } diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index 78c4ad468..d93c4f34a 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -1,14 +1,15 @@ +import json from pathlib import Path import pytest -from typing import Any -from algosdk.transaction import OnComplete -from graviton.abi_strategy import ABIArgsMod, ABICallStrategy, RandomABIStrategyHalfSized +from graviton.abi_strategy import RandomABIStrategyHalfSized from graviton.blackbox import DryRunEncoder from graviton.invariant import DryRunProperty as DRProp import pyteal as pt +from tests.blackbox import Predicates, RouterSimulation + NUM_ROUTER_DRYRUNS = 7 FIXTURES = Path.cwd() / "tests" / "integration" / "teal" / "router" @@ -239,41 +240,27 @@ def generate_and_test_routers(): ROUTER_CASES = generate_and_test_routers() -TYPICAL_IAC_OC = (False, OnComplete.NoOpOC) +TYPICAL_IAC_OC = pt.MethodConfig(no_op=pt.CallConfig.CALL) -# LEGEND FOR TEST CASES: -# +# TEST DRIVERS LEGEND - combines method_configs + predicates # * @0 - method: str. method == `None` indicates bare app call # -# * @1 - approval_call_types: list[tuple[bool, OncComplete]] -# [(is_app_create, `OnComplete`), ...] contexts expected for approval program +# * @1 - method_config: MethodConfig - defines how to call the method # -# * @2 - clear_call_types: list[tuple[bool, Oncomplete]] -# [(is_app_create, `OnComplete`), ...] contexts expected for clear program -# -# * @3 - predicates: dict[DRProp, Any] +# * @3 - predicates: Predicates ~ dict[DRProp, Any] # these are being asserted after being processed into Invariant's # # NOTE: the "yacc" routers will simply ignore the case with method `None` # as they do not have any bare-app-calls -QUESTIONABLE_CASES: list[ - tuple[ - str, - list[tuple[bool, OnComplete]], - list[tuple[bool, OnComplete]], - dict[DRProp, Any], - ] -] = [ +QUESTIONABLE_DRIVER: list[tuple[str, pt.MethodConfig, Predicates,]] = [ ( "add", - [TYPICAL_IAC_OC], - [], + TYPICAL_IAC_OC, {DRProp.passed: True, DRProp.lastLog: lambda args: args[1] + args[2]}, ), ( "sub", - [TYPICAL_IAC_OC], - [], + TYPICAL_IAC_OC, { DRProp.passed: lambda args: args[1] >= args[2], DRProp.lastLog: ( @@ -285,38 +272,31 @@ def generate_and_test_routers(): ), ( "mul", - [TYPICAL_IAC_OC], - [], + TYPICAL_IAC_OC, {DRProp.passed: True, DRProp.lastLog: lambda args: args[1] * args[2]}, ), ( "div", - [TYPICAL_IAC_OC], - [], + TYPICAL_IAC_OC, {DRProp.passed: True, DRProp.lastLog: lambda args: args[1] // args[2]}, ), ( "mod", - [TYPICAL_IAC_OC], - [], + TYPICAL_IAC_OC, {DRProp.passed: True, DRProp.lastLog: lambda args: args[1] % args[2]}, ), ( "all_laid_to_args", - [TYPICAL_IAC_OC], - [], + TYPICAL_IAC_OC, {DRProp.passed: True, DRProp.lastLog: lambda args: sum(args[1:])}, ), ( "empty_return_subroutine", - [ - (False, OnComplete.NoOpOC), - (False, OnComplete.OptInOC), - (True, OnComplete.OptInOC), - ], - [ - (False, OnComplete.ClearStateOC), - ], + pt.MethodConfig( + no_op=pt.CallConfig.CALL, + opt_in=pt.CallConfig.ALL, + clear_state=pt.CallConfig.CALL, + ), { DRProp.passed: True, DRProp.lastLog: DryRunEncoder.hex( @@ -326,24 +306,21 @@ def generate_and_test_routers(): ), ( "log_1", - [(False, OnComplete.NoOpOC), (False, OnComplete.OptInOC)], - [ - (False, OnComplete.ClearStateOC), - ], + pt.MethodConfig( + no_op=pt.CallConfig.CALL, + opt_in=pt.CallConfig.CALL, + clear_state=pt.CallConfig.CALL, + ), {DRProp.passed: True, DRProp.lastLog: 1}, ), ( "log_creation", - [(True, OnComplete.NoOpOC)], - [], + pt.MethodConfig(no_op=pt.CallConfig.CREATE), {DRProp.passed: True, DRProp.lastLog: "logging creation"}, ), ( "approve_if_odd", # this should only appear in the clear-state program - [], - [ - (False, OnComplete.ClearStateOC), - ], + pt.MethodConfig(clear_state=pt.CallConfig.CALL), { DRProp.passed: lambda args: args[1] % 2 == 1, DRProp.lastLog: None, @@ -351,10 +328,7 @@ def generate_and_test_routers(): ), ( None, - [(False, OnComplete.OptInOC)], - [ - (False, OnComplete.ClearStateOC), - ], + pt.MethodConfig(opt_in=pt.CallConfig.CALL, clear_state=pt.CallConfig.CALL), { DRProp.passed: True, DRProp.lastLog: lambda _, actual: actual @@ -363,71 +337,49 @@ def generate_and_test_routers(): ), ] +YACC_DRIVER = [case for case in QUESTIONABLE_DRIVER if case[0]] +DRIVERS = {"questionable": QUESTIONABLE_DRIVER, "yacc": YACC_DRIVER} -@pytest.mark.parametrize("case, version, router", ROUTER_CASES) -@pytest.mark.parametrize( - "method, approval_call_types, clear_call_types, predicates", QUESTIONABLE_CASES -) -def test_abi_router_positive( - case, version, router, method, approval_call_types, clear_call_types, predicates -): - """ - Test the _positive_ version of a case. In other words, ensure that for the given: - * method or bare call - * OnComplete value - * number of arguments - that the app call succeeds according to the provided _invariants_ success definition - """ - def get_aa_strat(method_runner, abi_args_mod=None) -> ABICallStrategy: - return ABICallStrategy( - method_runner.teal, - method_runner.contract, - RandomABIStrategyHalfSized, - num_dryruns=NUM_ROUTER_DRYRUNS, - abi_args_mod=abi_args_mod, - ) - +def split_driver2predicates_methconfigs(driver): + predicates = {} + methconfigs = {} + for meth, meth_config, predicate in driver: + predicates[meth] = predicate + methconfigs[meth] = meth_config - # def run_positive(is_approve, method_runner, call_types, invariants): - good_abi_args = get_aa_strat(method_runner) + return predicates, methconfigs - algod = get_algod() - if not call_types: - return - - method = method_runner.method - sim = Simulation( - algod, - ExecutionMode.Application, - method_runner.teal, - invariants, - abi_method_signature=good_abi_args.method_signature(method), - omit_method_selector=False, - validation=False, - ) +@pytest.mark.parametrize("case, version, router", ROUTER_CASES) +def test_abi_router_positive(case, version, router): + """ + Test the _positive_ version of a case. In other words, ensure that for each + router encountered and its driver, iterate through the driver as follows: + * consider each method or bare call + * consider each (OnComplete, CallConfig) combination + * assert that all predicates hold for this call + """ + driver = DRIVERS[case] + predicates, methconfigs = split_driver2predicates_methconfigs(driver) + assert methconfigs == router.method_configs + rsim = RouterSimulation(router, predicates) def msg(): - return f""" -TEST CASE [{method_runner}]({"APPROVAL" if is_approve else "CLEAR"}): -test_function={inspect.stack()[2][3]} -method={method} -is_app_create={is_app_create} -on_complete={on_complete!r}""" - - for is_app_create, on_complete in call_types: - sim_result = sim.run_and_assert( - good_abi_args, - method=method, - txn_params=TxParams.for_app( - is_app_create=is_app_create, - on_complete=on_complete, - ), - msg=msg(), - ) - assert sim_result.succeeded + return f"""test_abi_router_positive() +{case=} +{version=} +{router.name=}""" + + results = rsim.simulate_and_assert( + RandomABIStrategyHalfSized, + abi_args_mod=None, + version=version, + num_dryruns=NUM_ROUTER_DRYRUNS, + ) + assert all( + sim.succeeded for meth in results["results"].values() for sim in meth.values() + ) - # run_positive(True, approval_runner, approval_call_types, invariants) - # run_positive(False, clear_runner, clear_call_types, invariants) + print(json.dumps(results["stats"], indent=2)) diff --git a/tests/unit/blackbox_test.py b/tests/unit/blackbox_test.py index d01d9c1bb..59c9f5707 100644 --- a/tests/unit/blackbox_test.py +++ b/tests/unit/blackbox_test.py @@ -325,9 +325,6 @@ def test_RouterSimulation_init(): successful_RouterSimulation(router, model_router, predicates, algod) -TYPICAL_IAC_OC = pt.MethodConfig(no_op=pt.CallConfig.CALL) - - def failing_prep_simulate( rsim, arg_strat_type, From 34f6116e9218cdef1aae2a480c9ca68be8be2c5b Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 19 Jan 2023 07:12:05 -0600 Subject: [PATCH 164/206] lint --- pyteal/ast/router.py | 1 + tests/blackbox.py | 18 +++++++++--------- tests/integration/abi_router_test.py | 2 +- tests/unit/blackbox_test.py | 4 ++-- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/pyteal/ast/router.py b/pyteal/ast/router.py index bf2084e2a..7d76adf4d 100644 --- a/pyteal/ast/router.py +++ b/pyteal/ast/router.py @@ -277,6 +277,7 @@ def get_method_config(self) -> MethodConfig: delete_application=self.delete_application.call_config, ) + BareCallActions.__module__ = "pyteal" diff --git a/tests/blackbox.py b/tests/blackbox.py index 250efdb34..e1463e158 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -6,7 +6,7 @@ import algosdk.abi as sdk_abi from algosdk.transaction import OnComplete -import algosdk.v2client as v2client +from algosdk import v2client from graviton import blackbox from graviton.abi_strategy import ABIArgsMod, ABICallStrategy, ABIStrategy @@ -470,7 +470,7 @@ class _SimConfig: ap_compiled: str csp_compiled: str contract: sdk_abi.Contract - method_configs: dict[str, MethodConfig] + method_configs: dict[str | None, MethodConfig] call_strat: ABICallStrategy txn_params: TxParams model_version: int | None @@ -549,13 +549,13 @@ class RouterSimulation: def __init__( self, router: Router, - predicates: dict[str, CallPredicates], + predicates: dict[str, Predicates], *, model_router: Router | None = None, algod: v2client.algod.AlgodClient | None = None, ): self.router: Router = router - self.predicates: dict[str, CallPredicates] = self._validate_predicates( + self.predicates: dict[str | None, Predicates] = self._validate_predicates( predicates ) self.model_router: Router | None = model_router @@ -600,7 +600,7 @@ def _prep_simulation( *, assemble_constants: bool = False, optimize: OptimizeOptions | None = None, - method_configs: dict[str, MethodConfig] | None = None, + method_configs: dict[str | None, MethodConfig] | None = None, num_dryruns: int = 1, txn_params: TxParams | None = None, model_version: int | None = None, @@ -673,7 +673,7 @@ def _prep_simulation( model_csp_compiled, model_contract, ) = self.model_router.compile_program( - version=model_version, + version=cast(int, model_version), assemble_constants=model_assemble_constants, optimize=model_optimize, ) @@ -690,7 +690,7 @@ def _prep_simulation( contract=contract, method_configs=method_configs, call_strat=call_strat, - txn_params=txn_params, + txn_params=cast(TxParams, txn_params), model_version=model_version, model_assemble_constants=model_assemble_constants, model_optimize=model_optimize, @@ -707,7 +707,7 @@ def simulate_and_assert( *, assemble_constants: bool = False, optimize: OptimizeOptions | None = None, - method_configs: dict[str, MethodConfig] | None = None, + method_configs: dict[str | None, MethodConfig] | None = None, num_dryruns: int = 1, txn_params: TxParams | None = None, model_version: int | None = None, @@ -749,7 +749,7 @@ def msg() -> str: {stats["assertions_count"]=} """ - def get_sim(): + def get_sim() -> Simulation: return Simulation( self.algod, ExecutionMode.Application, diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index d93c4f34a..22d36a7ca 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -252,7 +252,7 @@ def generate_and_test_routers(): # # NOTE: the "yacc" routers will simply ignore the case with method `None` # as they do not have any bare-app-calls -QUESTIONABLE_DRIVER: list[tuple[str, pt.MethodConfig, Predicates,]] = [ +QUESTIONABLE_DRIVER: list[tuple[str | None, pt.MethodConfig, Predicates]] = [ ( "add", TYPICAL_IAC_OC, diff --git a/tests/unit/blackbox_test.py b/tests/unit/blackbox_test.py index 59c9f5707..db4f3b29f 100644 --- a/tests/unit/blackbox_test.py +++ b/tests/unit/blackbox_test.py @@ -5,7 +5,7 @@ from unittest.mock import MagicMock from algosdk.v2client.algod import AlgodClient -from graviton.abi_strategy import ABIArgsMod, ABICallStrategy, RandomABIStrategy +from graviton.abi_strategy import ABIArgsMod, RandomABIStrategy from graviton.inspector import DryRunProperty as DRProp import pyteal as pt @@ -580,7 +580,7 @@ def test_prep_simulation(): "m1": "foo", "m2": pt.MethodConfig(no_op=pt.CallConfig.ALL), } - err_msg = f"method_configs['m1'] = has type but only MethodConfig is allowed." + err_msg = "method_configs['m1'] = has type but only MethodConfig is allowed." failing_prep_simulate( rsim, arg_strat_type, From c9e88d8fa740fc8b23a2996e04280299d3cd2966 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 19 Jan 2023 16:49:09 -0600 Subject: [PATCH 165/206] wip --- tests/blackbox.py | 88 +++++++++++++++------------- tests/integration/abi_router_test.py | 82 ++++++++++++++++++++++---- 2 files changed, 119 insertions(+), 51 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index e1463e158..808ce6073 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -508,34 +508,36 @@ class RouterSimulation: """ Lifecycle of a RouterSimulation - 1. Creation: + 1. Creation (__init__ method): * router: Router (no version or other options specified) * predicates: CallPredicates - the Router ought satisfy. Type has shape: * method --> predicate ...> ... - * algod (optional) - if missing, just get one * model_router: Router (optional) - in the case when the predicates provided are of type PredicateKind.IdenticalPair, this parameter needs to be provided for comparison. NOTE: model_router may in fact be the same as router, and in this case it is expected that something else such as version or optimization option would differ between modeel_router and router during the simulation + * algod (optional) - if missing, just get one + + Artifacts from Step 1 are stored in self.results: _SimConfig - 2. Simulation: - * call_strat: ABICallStrategy - used for args generation - * version: int - for compiling router - * assemble_constants: bool (optional) - for compiling router - * optimize: OptimizeOptions (optional) - for compiling router - * method_configs: dict[str, MethodConfig] (optional) + 2. Simulation (simulate_and_assert method): - using self.results artifacts Step 1, also takes params: + * arg_strat_type: Type[ABICallStrategy] - strategy type to use for args generation + * abi_args_mod: ABIArgsMod (default None) - used to specify any arg mutation + * version: int - for compiling self.router + * assemble_constants: bool (optional) - for compiling self.router + * optimize: OptimizeOptions (optional) - for compiling self.router + * method_configs: dict[str | None, MethodConfig] (optional) - if missing, pick up from router.method_configs * num_dryruns: int (default 1) - the number of input runs to generate per method X config combination - * abi_args_mod: ABIArgsMod (default None) - used to specify any arg mutation * txn_params: TxParams (optional) - other TxParams to append -in addition to the (is_app_create, OnComplete) information * msg: string (optional) - message to report when assert violation occurs - * model_version: int - for compiling model_router - * model_assemble_constants: bool (optional) - for compiling model_router - * model_optimize: OptimizeOptions (optional) - for compiling model_router + * model_version: int - for compiling self.model_router + * model_assemble_constants: bool (optional) - for compiling self.model_router + * model_optimize: OptimizeOptions (optional) - for compiling self.model_router * TODO: consider adding -->strict: bool (default True) - when True ensure that methods + call_config's to be tested are available in `router` and `model_router` if it exists @@ -549,15 +551,13 @@ class RouterSimulation: def __init__( self, router: Router, - predicates: dict[str, Predicates], + predicates: CallPredicates, *, model_router: Router | None = None, algod: v2client.algod.AlgodClient | None = None, ): self.router: Router = router - self.predicates: dict[str | None, Predicates] = self._validate_predicates( - predicates - ) + self.predicates: CallPredicates = self._validate_predicates(predicates) self.model_router: Router | None = model_router self.algod: v2client.algod.AlgodClient = algod or algod_with_assertion() @@ -699,6 +699,18 @@ def _prep_simulation( model_contract=model_contract, ) + def _get_sim(self, teal, meth, sim_cfg, identities_teal) -> Simulation: + return Simulation( + self.algod, + ExecutionMode.Application, + teal, + self.predicates[meth], + abi_method_signature=sim_cfg.call_strat.method_signature(meth), + # omit_method_selector=False ???? + # validation=True ??? + identities_teal=identities_teal, + ) + def simulate_and_assert( self, arg_strat_type: Type[ABIStrategy], @@ -713,7 +725,7 @@ def simulate_and_assert( model_version: int | None = None, model_assemble_constants: bool = False, model_optimize: OptimizeOptions | None = None, - # fail_on_first: bool = True, ??? future ??? + msg: str = "", ) -> dict: sim_cfg = self._prep_simulation( arg_strat_type, @@ -738,8 +750,9 @@ def simulate_and_assert( assertions_count=0, ) - def msg() -> str: - return f"""{meth=} + def msg4simulate() -> str: + return f"""user proviede message={msg} +{meth=} {oc=} {call_cfg=} {is_app_create=} @@ -749,23 +762,11 @@ def msg() -> str: {stats["assertions_count"]=} """ - def get_sim() -> Simulation: - return Simulation( - self.algod, - ExecutionMode.Application, - teal, - self.predicates[meth], - abi_method_signature=sim_cfg.call_strat.method_signature(meth), - # omit_method_selector=False ???? - # validation=True ??? - identities_teal=identities_teal, - ) - def simulate(stats, is_app_create): tp: TxParams = deepcopy(txn_params) tp.update(TxParams.for_app(is_app_create=is_app_create, on_complete=oc)) sim_results = sim.run_and_assert( - sim_cfg.call_strat, txn_params=tp, msg=msg() + sim_cfg.call_strat, txn_params=tp, msg=msg4simulate() ) assert sim_results.succeeded self.results[meth][(is_app_create, oc)] = sim_results @@ -783,19 +784,22 @@ def simulate(stats, is_app_create): oc = as_on_complete(oc_str) sim: Simulation if oc is OnComplete.ClearStateOC: - teal: str - identities_teal: str | None - if not clear_sim: - teal = sim_cfg.csp_compiled - identities_teal = sim_cfg.model_csp_compiled - clear_sim = get_sim() + clear_sim = self._get_sim( + sim_cfg.csp_compiled, + meth, + sim_cfg, + sim_cfg.model_csp_compiled, + ) sim = clear_sim else: if not approve_sim: - teal = sim_cfg.ap_compiled - identities_teal = sim_cfg.model_ap_compiled - approve_sim = get_sim() + approve_sim = self._get_sim( + sim_cfg.ap_compiled, + meth, + sim_cfg, + sim_cfg.model_ap_compiled, + ) sim = approve_sim is_app_create: bool @@ -811,4 +815,6 @@ def simulate(stats, is_app_create): "sim_cfg": sim_cfg, "stats": stats, "results": self.results, + "approval_simulator": approve_sim, + "clear_simulator": clear_sim, } diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index 22d36a7ca..57caecdd8 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -151,8 +151,15 @@ def approve_if_odd(condition_encoding: pt.abi.Uint32) -> pt.Expr: assert meth.method_signature() == "approve_if_odd(uint32)void" -def generate_and_test_routers(): +def generate_and_test_routers() -> tuple[str, int, pt.Router, str, str]: routers = [] + sources = {} + + def append_router_info(rinfo, programs): + assert len(rinfo) == 3 + assert len(programs) == 2 + routers.append(rinfo) + sources[rinfo[:2]] = programs # V6 not ready for Frame Pointers: on_completion_actions = pt.BareCallActions( @@ -181,7 +188,17 @@ def generate_and_test_routers(): expected_csp_with_oc = f.read() assert expected_ap_with_oc == actual_ap_with_oc_compiled assert expected_csp_with_oc == actual_csp_with_oc_compiled - routers.append(("questionable", 6, _router_with_oc)) + append_router_info( + ( + "questionable", + 6, + _router_with_oc, + ), + ( + actual_ap_with_oc_compiled, + actual_csp_with_oc_compiled, + ), + ) # YACC V6: _router_without_oc = pt.Router("yetAnotherContractConstructedFromRouter") @@ -197,7 +214,17 @@ def generate_and_test_routers(): expected_csp_without_oc = f.read() assert actual_ap_without_oc_compiled == expected_ap_without_oc assert actual_csp_without_oc_compiled == expected_csp_without_oc - routers.append(("yacc", 6, _router_without_oc)) + append_router_info( + ( + "yacc", + 6, + _router_without_oc, + ), + ( + actual_ap_without_oc_compiled, + actual_csp_without_oc_compiled, + ), + ) # QUESTIONABLE FP V8: _router_with_oc = pt.Router( @@ -215,7 +242,17 @@ def generate_and_test_routers(): expected_csp_with_oc = f.read() assert actual_ap_with_oc_compiled == expected_ap_with_oc assert actual_csp_with_oc_compiled == expected_csp_with_oc - routers.append(("questionable", 8, _router_with_oc)) + append_router_info( + ( + "questionable", + 8, + _router_with_oc, + ), + ( + actual_ap_with_oc_compiled, + actual_csp_with_oc_compiled, + ), + ) # YACC FP V8: _router_without_oc = pt.Router( @@ -233,12 +270,22 @@ def generate_and_test_routers(): expected_csp_without_oc = f.read() assert actual_ap_without_oc_compiled == expected_ap_without_oc assert actual_csp_without_oc_compiled == expected_csp_without_oc - routers.append(("yacc", 8, _router_without_oc)) + append_router_info( + ( + "yacc", + 8, + _router_without_oc, + ), + ( + actual_ap_without_oc_compiled, + actual_csp_without_oc_compiled, + ), + ) - return routers + return routers, sources -ROUTER_CASES = generate_and_test_routers() +ROUTER_CASES, ROUTER_SOURCES = generate_and_test_routers() TYPICAL_IAC_OC = pt.MethodConfig(no_op=pt.CallConfig.CALL) @@ -361,6 +408,8 @@ def test_abi_router_positive(case, version, router): * consider each (OnComplete, CallConfig) combination * assert that all predicates hold for this call """ + pregen_approval, pregen_clear = ROUTER_SOURCES[(case, version)] + driver = DRIVERS[case] predicates, methconfigs = split_driver2predicates_methconfigs(driver) assert methconfigs == router.method_configs @@ -377,9 +426,22 @@ def msg(): abi_args_mod=None, version=version, num_dryruns=NUM_ROUTER_DRYRUNS, + msg=msg(), ) - assert all( - sim.succeeded for meth in results["results"].values() for sim in meth.values() + # won't even get here if there was an error, but some extra sanity checks: + + assert (sim_results := results["results"]) and all( + sim.succeeded for meth in sim_results.values() for sim in meth.values() ) - print(json.dumps(results["stats"], indent=2)) + print(json.dumps(stats := results["stats"], indent=2)) + assert stats and all(stats.values()) + + # wow!!! these fail because of label assignment non-determinism: + # assert pregen_approval == results["approval_simulator"].simulate_dre.program + # assert pregen_clear == results["clear_simulator"].simulate_dre.program + with open(FIXTURES / f"sim_approval_{case}_{version}.teal", "w") as f: + f.write(results["sim_cfg"].ap_compiled) + + with open(FIXTURES / f"sim_clear_{case}_{version}.teal", "w") as f: + f.write(results["sim_cfg"].csp_compiled) From c9a960bdf16b353f38ec9b692d439055ba7dcf97 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Mon, 23 Jan 2023 12:19:11 -0500 Subject: [PATCH 166/206] minor changes --- pyteal/ast/router.py | 1 - tests/integration/abi_router_test.py | 21 +-- .../router/questionableFP_approval_v8.teal | 121 ++++++++++++------ .../teal/router/questionableFP_clear_v8.teal | 91 +------------ .../teal/router/questionable_approval_v6.teal | 80 ++++++++---- .../teal/router/questionable_clear_v6.teal | 67 ---------- .../teal/router/yaccFP_approval_v8.teal | 113 ++++++++++------ .../teal/router/yaccFP_clear_v8.teal | 84 +----------- .../teal/router/yacc_approval_v6.teal | 72 ++++++++--- .../teal/router/yacc_clear_v6.teal | 60 --------- tests/unit/blackbox_test.py | 12 +- 11 files changed, 287 insertions(+), 435 deletions(-) diff --git a/pyteal/ast/router.py b/pyteal/ast/router.py index bdc32b6c5..14e2ed0c8 100644 --- a/pyteal/ast/router.py +++ b/pyteal/ast/router.py @@ -256,7 +256,6 @@ def get_method_config(self) -> MethodConfig: no_op=self.no_op.call_config, opt_in=self.opt_in.call_config, close_out=self.close_out.call_config, - clear_state=self.clear_state.call_config, update_application=self.update_application.call_config, delete_application=self.delete_application.call_config, ) diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index 57caecdd8..9cb04be08 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -105,7 +105,7 @@ def empty_return_subroutine() -> pt.Expr: method_config=pt.MethodConfig( no_op=pt.CallConfig.CALL, opt_in=pt.CallConfig.ALL, - clear_state=pt.CallConfig.CALL, + # clear_state=pt.CallConfig.CALL, ), ) assert meth.method_signature() == "empty_return_subroutine()void" @@ -119,7 +119,7 @@ def log_1(*, output: pt.abi.Uint64) -> pt.Expr: method_config=pt.MethodConfig( no_op=pt.CallConfig.CALL, opt_in=pt.CallConfig.CALL, - clear_state=pt.CallConfig.CALL, + # clear_state=pt.CallConfig.CALL, ), ) @@ -145,13 +145,14 @@ def approve_if_odd(condition_encoding: pt.abi.Uint32) -> pt.Expr: meth = router.add_method_handler( approve_if_odd, method_config=pt.MethodConfig( - no_op=pt.CallConfig.NEVER, clear_state=pt.CallConfig.CALL + no_op=pt.CallConfig.CALL, # clear_state=pt.CallConfig.CALL ), ) assert meth.method_signature() == "approve_if_odd(uint32)void" -def generate_and_test_routers() -> tuple[str, int, pt.Router, str, str]: +def generate_and_test_routers() -> tuple[list[pt.Router], dict[list, str]]: + # tuple[str, int, pt.Router, str, str]: routers = [] sources = {} @@ -164,7 +165,7 @@ def append_router_info(rinfo, programs): # V6 not ready for Frame Pointers: on_completion_actions = pt.BareCallActions( opt_in=pt.OnCompleteAction.call_only(pt.Log(pt.Bytes("optin call"))), - clear_state=pt.OnCompleteAction.call_only(pt.Approve()), + # clear_state=pt.OnCompleteAction.call_only(pt.Approve()), ) with pytest.raises(pt.TealInputError) as e: pt.Router("will-error", on_completion_actions).compile_program( @@ -342,7 +343,7 @@ def append_router_info(rinfo, programs): pt.MethodConfig( no_op=pt.CallConfig.CALL, opt_in=pt.CallConfig.ALL, - clear_state=pt.CallConfig.CALL, + # clear_state=pt.CallConfig.CALL, ), { DRProp.passed: True, @@ -356,7 +357,7 @@ def append_router_info(rinfo, programs): pt.MethodConfig( no_op=pt.CallConfig.CALL, opt_in=pt.CallConfig.CALL, - clear_state=pt.CallConfig.CALL, + # clear_state=pt.CallConfig.CALL, ), {DRProp.passed: True, DRProp.lastLog: 1}, ), @@ -367,7 +368,7 @@ def append_router_info(rinfo, programs): ), ( "approve_if_odd", # this should only appear in the clear-state program - pt.MethodConfig(clear_state=pt.CallConfig.CALL), + pt.MethodConfig(no_op=pt.CallConfig.CALL), { DRProp.passed: lambda args: args[1] % 2 == 1, DRProp.lastLog: None, @@ -375,7 +376,9 @@ def append_router_info(rinfo, programs): ), ( None, - pt.MethodConfig(opt_in=pt.CallConfig.CALL, clear_state=pt.CallConfig.CALL), + pt.MethodConfig( + opt_in=pt.CallConfig.CALL, # clear_state=pt.CallConfig.CALL + ), { DRProp.passed: True, DRProp.lastLog: lambda _, actual: actual diff --git a/tests/integration/teal/router/questionableFP_approval_v8.teal b/tests/integration/teal/router/questionableFP_approval_v8.teal index 00a013082..b0baf28fa 100644 --- a/tests/integration/teal/router/questionableFP_approval_v8.teal +++ b/tests/integration/teal/router/questionableFP_approval_v8.teal @@ -2,45 +2,61 @@ txn NumAppArgs int 0 == -bnz main_l20 +bnz main_l22 txna ApplicationArgs 0 method "add(uint64,uint64)uint64" == -bnz main_l19 +bnz main_l21 txna ApplicationArgs 0 method "sub(uint64,uint64)uint64" == -bnz main_l18 +bnz main_l20 txna ApplicationArgs 0 method "mul(uint64,uint64)uint64" == -bnz main_l17 +bnz main_l19 txna ApplicationArgs 0 method "div(uint64,uint64)uint64" == -bnz main_l16 +bnz main_l18 txna ApplicationArgs 0 method "mod(uint64,uint64)uint64" == -bnz main_l15 +bnz main_l17 txna ApplicationArgs 0 method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" == -bnz main_l14 +bnz main_l16 txna ApplicationArgs 0 method "empty_return_subroutine()void" == -bnz main_l13 +bnz main_l15 txna ApplicationArgs 0 method "log_1()uint64" == -bnz main_l12 +bnz main_l14 txna ApplicationArgs 0 method "log_creation()string" == -bnz main_l11 +bnz main_l13 +txna ApplicationArgs 0 +method "approve_if_odd(uint32)void" +== +bnz main_l12 err -main_l11: +main_l12: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub approveifoddcaster_19 +int 1 +return +main_l13: txn OnCompletion int NoOp == @@ -49,10 +65,10 @@ int 0 == && assert -callsub logcreationcaster_17 +callsub logcreationcaster_18 int 1 return -main_l12: +main_l14: txn OnCompletion int NoOp == @@ -69,10 +85,10 @@ int 0 && || assert -callsub log1caster_16 +callsub log1caster_17 int 1 return -main_l13: +main_l15: txn OnCompletion int NoOp == @@ -85,10 +101,10 @@ int OptIn == || assert -callsub emptyreturnsubroutinecaster_15 +callsub emptyreturnsubroutinecaster_16 int 1 return -main_l14: +main_l16: txn OnCompletion int NoOp == @@ -97,10 +113,10 @@ int 0 != && assert -callsub alllaidtoargscaster_14 +callsub alllaidtoargscaster_15 int 1 return -main_l15: +main_l17: txn OnCompletion int NoOp == @@ -109,10 +125,10 @@ int 0 != && assert -callsub modcaster_13 +callsub modcaster_14 int 1 return -main_l16: +main_l18: txn OnCompletion int NoOp == @@ -121,10 +137,10 @@ int 0 != && assert -callsub divcaster_12 +callsub divcaster_13 int 1 return -main_l17: +main_l19: txn OnCompletion int NoOp == @@ -133,10 +149,10 @@ int 0 != && assert -callsub mulcaster_11 +callsub mulcaster_12 int 1 return -main_l18: +main_l20: txn OnCompletion int NoOp == @@ -145,10 +161,10 @@ int 0 != && assert -callsub subcaster_10 +callsub subcaster_11 int 1 return -main_l19: +main_l21: txn OnCompletion int NoOp == @@ -157,16 +173,16 @@ int 0 != && assert -callsub addcaster_9 +callsub addcaster_10 int 1 return -main_l20: +main_l22: txn OnCompletion int OptIn == -bnz main_l22 +bnz main_l24 err -main_l22: +main_l24: txn ApplicationID int 0 != @@ -287,8 +303,21 @@ byte 0x00106c6f6767696e67206372656174696f6e frame_bury 0 retsub +// approve_if_odd +approveifodd_9: +proto 1 0 +frame_dig -1 +int 2 +% +bnz approveifodd_9_l2 +int 0 +return +approveifodd_9_l2: +int 1 +return + // add_caster -addcaster_9: +addcaster_10: proto 0 0 int 0 dupn 2 @@ -310,7 +339,7 @@ log retsub // sub_caster -subcaster_10: +subcaster_11: proto 0 0 int 0 dupn 2 @@ -332,7 +361,7 @@ log retsub // mul_caster -mulcaster_11: +mulcaster_12: proto 0 0 int 0 dupn 2 @@ -354,7 +383,7 @@ log retsub // div_caster -divcaster_12: +divcaster_13: proto 0 0 int 0 dupn 2 @@ -376,7 +405,7 @@ log retsub // mod_caster -modcaster_13: +modcaster_14: proto 0 0 int 0 dupn 2 @@ -398,7 +427,7 @@ log retsub // all_laid_to_args_caster -alllaidtoargscaster_14: +alllaidtoargscaster_15: proto 0 0 int 0 dupn 16 @@ -481,13 +510,13 @@ log retsub // empty_return_subroutine_caster -emptyreturnsubroutinecaster_15: +emptyreturnsubroutinecaster_16: proto 0 0 callsub emptyreturnsubroutine_6 retsub // log_1_caster -log1caster_16: +log1caster_17: proto 0 0 int 0 callsub log1_7 @@ -500,7 +529,7 @@ log retsub // log_creation_caster -logcreationcaster_17: +logcreationcaster_18: proto 0 0 byte "" callsub logcreation_8 @@ -509,4 +538,16 @@ byte 0x151f7c75 frame_dig 0 concat log +retsub + +// approve_if_odd_caster +approveifoddcaster_19: +proto 0 0 +int 0 +txna ApplicationArgs 1 +int 0 +extract_uint32 +frame_bury 0 +frame_dig 0 +callsub approveifodd_9 retsub \ No newline at end of file diff --git a/tests/integration/teal/router/questionableFP_clear_v8.teal b/tests/integration/teal/router/questionableFP_clear_v8.teal index 5bb9f0213..ba95445f2 100644 --- a/tests/integration/teal/router/questionableFP_clear_v8.teal +++ b/tests/integration/teal/router/questionableFP_clear_v8.teal @@ -1,92 +1,3 @@ #pragma version 8 -txn NumAppArgs int 0 -== -bnz main_l8 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l7 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l6 -txna ApplicationArgs 0 -method "approve_if_odd(uint32)void" -== -bnz main_l5 -err -main_l5: -callsub approveifoddcaster_5 -int 1 -return -main_l6: -callsub log1caster_4 -int 1 -return -main_l7: -callsub emptyreturnsubroutinecaster_3 -int 1 -return -main_l8: -int 1 -return - -// empty_return_subroutine -emptyreturnsubroutine_0: -proto 0 0 -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_1: -proto 0 1 -int 0 -int 1 -frame_bury 0 -retsub - -// approve_if_odd -approveifodd_2: -proto 1 0 -frame_dig -1 -int 2 -% -bnz approveifodd_2_l2 -int 0 -return -approveifodd_2_l2: -int 1 -return - -// empty_return_subroutine_caster -emptyreturnsubroutinecaster_3: -proto 0 0 -callsub emptyreturnsubroutine_0 -retsub - -// log_1_caster -log1caster_4: -proto 0 0 -int 0 -callsub log1_1 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// approve_if_odd_caster -approveifoddcaster_5: -proto 0 0 -int 0 -txna ApplicationArgs 1 -int 0 -extract_uint32 -frame_bury 0 -frame_dig 0 -callsub approveifodd_2 -retsub \ No newline at end of file +return \ No newline at end of file diff --git a/tests/integration/teal/router/questionable_approval_v6.teal b/tests/integration/teal/router/questionable_approval_v6.teal index 51455774a..36b68e6ae 100644 --- a/tests/integration/teal/router/questionable_approval_v6.teal +++ b/tests/integration/teal/router/questionable_approval_v6.teal @@ -2,45 +2,66 @@ txn NumAppArgs int 0 == -bnz main_l20 +bnz main_l22 txna ApplicationArgs 0 method "add(uint64,uint64)uint64" == -bnz main_l19 +bnz main_l21 txna ApplicationArgs 0 method "sub(uint64,uint64)uint64" == -bnz main_l18 +bnz main_l20 txna ApplicationArgs 0 method "mul(uint64,uint64)uint64" == -bnz main_l17 +bnz main_l19 txna ApplicationArgs 0 method "div(uint64,uint64)uint64" == -bnz main_l16 +bnz main_l18 txna ApplicationArgs 0 method "mod(uint64,uint64)uint64" == -bnz main_l15 +bnz main_l17 txna ApplicationArgs 0 method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" == -bnz main_l14 +bnz main_l16 txna ApplicationArgs 0 method "empty_return_subroutine()void" == -bnz main_l13 +bnz main_l15 txna ApplicationArgs 0 method "log_1()uint64" == -bnz main_l12 +bnz main_l14 txna ApplicationArgs 0 method "log_creation()string" == -bnz main_l11 +bnz main_l13 +txna ApplicationArgs 0 +method "approve_if_odd(uint32)void" +== +bnz main_l12 err -main_l11: +main_l12: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +int 0 +extract_uint32 +store 69 +load 69 +callsub approveifodd_9 +int 1 +return +main_l13: txn OnCompletion int NoOp == @@ -57,7 +78,7 @@ concat log int 1 return -main_l12: +main_l14: txn OnCompletion int NoOp == @@ -83,7 +104,7 @@ concat log int 1 return -main_l13: +main_l15: txn OnCompletion int NoOp == @@ -99,7 +120,7 @@ assert callsub emptyreturnsubroutine_6 int 1 return -main_l14: +main_l16: txn OnCompletion int NoOp == @@ -185,7 +206,7 @@ concat log int 1 return -main_l15: +main_l17: txn OnCompletion int NoOp == @@ -211,7 +232,7 @@ concat log int 1 return -main_l16: +main_l18: txn OnCompletion int NoOp == @@ -237,7 +258,7 @@ concat log int 1 return -main_l17: +main_l19: txn OnCompletion int NoOp == @@ -263,7 +284,7 @@ concat log int 1 return -main_l18: +main_l20: txn OnCompletion int NoOp == @@ -289,7 +310,7 @@ concat log int 1 return -main_l19: +main_l21: txn OnCompletion int NoOp == @@ -315,13 +336,13 @@ concat log int 1 return -main_l20: +main_l22: txn OnCompletion int OptIn == -bnz main_l22 +bnz main_l24 err -main_l22: +main_l24: txn ApplicationID int 0 != @@ -457,4 +478,17 @@ logcreation_8: byte 0x00106c6f6767696e67206372656174696f6e store 68 load 68 -retsub \ No newline at end of file +retsub + +// approve_if_odd +approveifodd_9: +store 70 +load 70 +int 2 +% +bnz approveifodd_9_l2 +int 0 +return +approveifodd_9_l2: +int 1 +return \ No newline at end of file diff --git a/tests/integration/teal/router/questionable_clear_v6.teal b/tests/integration/teal/router/questionable_clear_v6.teal index ad85ebc0d..e6cf44111 100644 --- a/tests/integration/teal/router/questionable_clear_v6.teal +++ b/tests/integration/teal/router/questionable_clear_v6.teal @@ -1,70 +1,3 @@ #pragma version 6 -txn NumAppArgs int 0 -== -bnz main_l8 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l7 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l6 -txna ApplicationArgs 0 -method "approve_if_odd(uint32)void" -== -bnz main_l5 -err -main_l5: -txna ApplicationArgs 1 -int 0 -extract_uint32 -store 2 -load 2 -callsub approveifodd_2 -int 1 -return -main_l6: -callsub log1_1 -store 1 -byte 0x151f7c75 -load 1 -itob -concat -log -int 1 -return -main_l7: -callsub emptyreturnsubroutine_0 -int 1 -return -main_l8: -int 1 -return - -// empty_return_subroutine -emptyreturnsubroutine_0: -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_1: -int 1 -store 0 -load 0 -retsub - -// approve_if_odd -approveifodd_2: -store 3 -load 3 -int 2 -% -bnz approveifodd_2_l2 -int 0 -return -approveifodd_2_l2: -int 1 return \ No newline at end of file diff --git a/tests/integration/teal/router/yaccFP_approval_v8.teal b/tests/integration/teal/router/yaccFP_approval_v8.teal index 5c5bda6d0..25af706c5 100644 --- a/tests/integration/teal/router/yaccFP_approval_v8.teal +++ b/tests/integration/teal/router/yaccFP_approval_v8.teal @@ -2,41 +2,57 @@ txna ApplicationArgs 0 method "add(uint64,uint64)uint64" == -bnz main_l18 +bnz main_l20 txna ApplicationArgs 0 method "sub(uint64,uint64)uint64" == -bnz main_l17 +bnz main_l19 txna ApplicationArgs 0 method "mul(uint64,uint64)uint64" == -bnz main_l16 +bnz main_l18 txna ApplicationArgs 0 method "div(uint64,uint64)uint64" == -bnz main_l15 +bnz main_l17 txna ApplicationArgs 0 method "mod(uint64,uint64)uint64" == -bnz main_l14 +bnz main_l16 txna ApplicationArgs 0 method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" == -bnz main_l13 +bnz main_l15 txna ApplicationArgs 0 method "empty_return_subroutine()void" == -bnz main_l12 +bnz main_l14 txna ApplicationArgs 0 method "log_1()uint64" == -bnz main_l11 +bnz main_l13 txna ApplicationArgs 0 method "log_creation()string" == -bnz main_l10 +bnz main_l12 +txna ApplicationArgs 0 +method "approve_if_odd(uint32)void" +== +bnz main_l11 err -main_l10: +main_l11: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub approveifoddcaster_19 +int 1 +return +main_l12: txn OnCompletion int NoOp == @@ -45,10 +61,10 @@ int 0 == && assert -callsub logcreationcaster_17 +callsub logcreationcaster_18 int 1 return -main_l11: +main_l13: txn OnCompletion int NoOp == @@ -65,10 +81,10 @@ int 0 && || assert -callsub log1caster_16 +callsub log1caster_17 int 1 return -main_l12: +main_l14: txn OnCompletion int NoOp == @@ -81,10 +97,10 @@ int OptIn == || assert -callsub emptyreturnsubroutinecaster_15 +callsub emptyreturnsubroutinecaster_16 int 1 return -main_l13: +main_l15: txn OnCompletion int NoOp == @@ -93,10 +109,10 @@ int 0 != && assert -callsub alllaidtoargscaster_14 +callsub alllaidtoargscaster_15 int 1 return -main_l14: +main_l16: txn OnCompletion int NoOp == @@ -105,10 +121,10 @@ int 0 != && assert -callsub modcaster_13 +callsub modcaster_14 int 1 return -main_l15: +main_l17: txn OnCompletion int NoOp == @@ -117,10 +133,10 @@ int 0 != && assert -callsub divcaster_12 +callsub divcaster_13 int 1 return -main_l16: +main_l18: txn OnCompletion int NoOp == @@ -129,10 +145,10 @@ int 0 != && assert -callsub mulcaster_11 +callsub mulcaster_12 int 1 return -main_l17: +main_l19: txn OnCompletion int NoOp == @@ -141,10 +157,10 @@ int 0 != && assert -callsub subcaster_10 +callsub subcaster_11 int 1 return -main_l18: +main_l20: txn OnCompletion int NoOp == @@ -153,7 +169,7 @@ int 0 != && assert -callsub addcaster_9 +callsub addcaster_10 int 1 return @@ -268,8 +284,21 @@ byte 0x00106c6f6767696e67206372656174696f6e frame_bury 0 retsub +// approve_if_odd +approveifodd_9: +proto 1 0 +frame_dig -1 +int 2 +% +bnz approveifodd_9_l2 +int 0 +return +approveifodd_9_l2: +int 1 +return + // add_caster -addcaster_9: +addcaster_10: proto 0 0 int 0 dupn 2 @@ -291,7 +320,7 @@ log retsub // sub_caster -subcaster_10: +subcaster_11: proto 0 0 int 0 dupn 2 @@ -313,7 +342,7 @@ log retsub // mul_caster -mulcaster_11: +mulcaster_12: proto 0 0 int 0 dupn 2 @@ -335,7 +364,7 @@ log retsub // div_caster -divcaster_12: +divcaster_13: proto 0 0 int 0 dupn 2 @@ -357,7 +386,7 @@ log retsub // mod_caster -modcaster_13: +modcaster_14: proto 0 0 int 0 dupn 2 @@ -379,7 +408,7 @@ log retsub // all_laid_to_args_caster -alllaidtoargscaster_14: +alllaidtoargscaster_15: proto 0 0 int 0 dupn 16 @@ -462,13 +491,13 @@ log retsub // empty_return_subroutine_caster -emptyreturnsubroutinecaster_15: +emptyreturnsubroutinecaster_16: proto 0 0 callsub emptyreturnsubroutine_6 retsub // log_1_caster -log1caster_16: +log1caster_17: proto 0 0 int 0 callsub log1_7 @@ -481,7 +510,7 @@ log retsub // log_creation_caster -logcreationcaster_17: +logcreationcaster_18: proto 0 0 byte "" callsub logcreation_8 @@ -490,4 +519,16 @@ byte 0x151f7c75 frame_dig 0 concat log +retsub + +// approve_if_odd_caster +approveifoddcaster_19: +proto 0 0 +int 0 +txna ApplicationArgs 1 +int 0 +extract_uint32 +frame_bury 0 +frame_dig 0 +callsub approveifodd_9 retsub \ No newline at end of file diff --git a/tests/integration/teal/router/yaccFP_clear_v8.teal b/tests/integration/teal/router/yaccFP_clear_v8.teal index 4be43a130..ba95445f2 100644 --- a/tests/integration/teal/router/yaccFP_clear_v8.teal +++ b/tests/integration/teal/router/yaccFP_clear_v8.teal @@ -1,85 +1,3 @@ #pragma version 8 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l6 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l5 -txna ApplicationArgs 0 -method "approve_if_odd(uint32)void" -== -bnz main_l4 -err -main_l4: -callsub approveifoddcaster_5 -int 1 -return -main_l5: -callsub log1caster_4 -int 1 -return -main_l6: -callsub emptyreturnsubroutinecaster_3 -int 1 -return - -// empty_return_subroutine -emptyreturnsubroutine_0: -proto 0 0 -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_1: -proto 0 1 int 0 -int 1 -frame_bury 0 -retsub - -// approve_if_odd -approveifodd_2: -proto 1 0 -frame_dig -1 -int 2 -% -bnz approveifodd_2_l2 -int 0 -return -approveifodd_2_l2: -int 1 -return - -// empty_return_subroutine_caster -emptyreturnsubroutinecaster_3: -proto 0 0 -callsub emptyreturnsubroutine_0 -retsub - -// log_1_caster -log1caster_4: -proto 0 0 -int 0 -callsub log1_1 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// approve_if_odd_caster -approveifoddcaster_5: -proto 0 0 -int 0 -txna ApplicationArgs 1 -int 0 -extract_uint32 -frame_bury 0 -frame_dig 0 -callsub approveifodd_2 -retsub \ No newline at end of file +return \ No newline at end of file diff --git a/tests/integration/teal/router/yacc_approval_v6.teal b/tests/integration/teal/router/yacc_approval_v6.teal index b36bc397e..a314f834a 100644 --- a/tests/integration/teal/router/yacc_approval_v6.teal +++ b/tests/integration/teal/router/yacc_approval_v6.teal @@ -2,41 +2,62 @@ txna ApplicationArgs 0 method "add(uint64,uint64)uint64" == -bnz main_l18 +bnz main_l20 txna ApplicationArgs 0 method "sub(uint64,uint64)uint64" == -bnz main_l17 +bnz main_l19 txna ApplicationArgs 0 method "mul(uint64,uint64)uint64" == -bnz main_l16 +bnz main_l18 txna ApplicationArgs 0 method "div(uint64,uint64)uint64" == -bnz main_l15 +bnz main_l17 txna ApplicationArgs 0 method "mod(uint64,uint64)uint64" == -bnz main_l14 +bnz main_l16 txna ApplicationArgs 0 method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" == -bnz main_l13 +bnz main_l15 txna ApplicationArgs 0 method "empty_return_subroutine()void" == -bnz main_l12 +bnz main_l14 txna ApplicationArgs 0 method "log_1()uint64" == -bnz main_l11 +bnz main_l13 txna ApplicationArgs 0 method "log_creation()string" == -bnz main_l10 +bnz main_l12 +txna ApplicationArgs 0 +method "approve_if_odd(uint32)void" +== +bnz main_l11 err -main_l10: +main_l11: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +int 0 +extract_uint32 +store 69 +load 69 +callsub approveifodd_9 +int 1 +return +main_l12: txn OnCompletion int NoOp == @@ -53,7 +74,7 @@ concat log int 1 return -main_l11: +main_l13: txn OnCompletion int NoOp == @@ -79,7 +100,7 @@ concat log int 1 return -main_l12: +main_l14: txn OnCompletion int NoOp == @@ -95,7 +116,7 @@ assert callsub emptyreturnsubroutine_6 int 1 return -main_l13: +main_l15: txn OnCompletion int NoOp == @@ -181,7 +202,7 @@ concat log int 1 return -main_l14: +main_l16: txn OnCompletion int NoOp == @@ -207,7 +228,7 @@ concat log int 1 return -main_l15: +main_l17: txn OnCompletion int NoOp == @@ -233,7 +254,7 @@ concat log int 1 return -main_l16: +main_l18: txn OnCompletion int NoOp == @@ -259,7 +280,7 @@ concat log int 1 return -main_l17: +main_l19: txn OnCompletion int NoOp == @@ -285,7 +306,7 @@ concat log int 1 return -main_l18: +main_l20: txn OnCompletion int NoOp == @@ -438,4 +459,17 @@ logcreation_8: byte 0x00106c6f6767696e67206372656174696f6e store 68 load 68 -retsub \ No newline at end of file +retsub + +// approve_if_odd +approveifodd_9: +store 70 +load 70 +int 2 +% +bnz approveifodd_9_l2 +int 0 +return +approveifodd_9_l2: +int 1 +return \ No newline at end of file diff --git a/tests/integration/teal/router/yacc_clear_v6.teal b/tests/integration/teal/router/yacc_clear_v6.teal index 8c4178605..e6cf44111 100644 --- a/tests/integration/teal/router/yacc_clear_v6.teal +++ b/tests/integration/teal/router/yacc_clear_v6.teal @@ -1,63 +1,3 @@ #pragma version 6 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l6 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l5 -txna ApplicationArgs 0 -method "approve_if_odd(uint32)void" -== -bnz main_l4 -err -main_l4: -txna ApplicationArgs 1 int 0 -extract_uint32 -store 2 -load 2 -callsub approveifodd_2 -int 1 -return -main_l5: -callsub log1_1 -store 1 -byte 0x151f7c75 -load 1 -itob -concat -log -int 1 -return -main_l6: -callsub emptyreturnsubroutine_0 -int 1 -return - -// empty_return_subroutine -emptyreturnsubroutine_0: -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_1: -int 1 -store 0 -load 0 -retsub - -// approve_if_odd -approveifodd_2: -store 3 -load 3 -int 2 -% -bnz approveifodd_2_l2 -int 0 -return -approveifodd_2_l2: -int 1 return \ No newline at end of file diff --git a/tests/unit/blackbox_test.py b/tests/unit/blackbox_test.py index db4f3b29f..646d2beb5 100644 --- a/tests/unit/blackbox_test.py +++ b/tests/unit/blackbox_test.py @@ -362,13 +362,11 @@ def get_2meth_router(): router = pt.Router( "router", pt.BareCallActions( - clear_state=pt.OnCompleteAction( - action=pt.Approve(), call_config=pt.CallConfig.CALL - ), opt_in=pt.OnCompleteAction( action=pt.Reject(), call_config=pt.CallConfig.ALL ), ), + clear_state=pt.Approve(), ) @router.method @@ -511,7 +509,7 @@ def test_prep_simulation(): router = get_2meth_router() router_method_configs = { - None: pt.MethodConfig(opt_in=pt.CallConfig.ALL, clear_state=pt.CallConfig.CALL), + None: pt.MethodConfig(opt_in=pt.CallConfig.ALL), "m1": pt.MethodConfig(no_op=pt.CallConfig.CALL), "m2": pt.MethodConfig(no_op=pt.CallConfig.CALL), } @@ -554,7 +552,7 @@ def test_prep_simulation(): ) method_configs = { - None: pt.MethodConfig(opt_in=pt.CallConfig.ALL, clear_state=pt.CallConfig.CALL), + None: pt.MethodConfig(opt_in=pt.CallConfig.ALL), 42: "foo", "m2": pt.MethodConfig(no_op=pt.CallConfig.ALL), } @@ -576,7 +574,7 @@ def test_prep_simulation(): ) method_configs = { - None: pt.MethodConfig(opt_in=pt.CallConfig.ALL, clear_state=pt.CallConfig.CALL), + None: pt.MethodConfig(opt_in=pt.CallConfig.ALL), "m1": "foo", "m2": pt.MethodConfig(no_op=pt.CallConfig.ALL), } @@ -598,7 +596,7 @@ def test_prep_simulation(): ) method_configs = { - None: pt.MethodConfig(opt_in=pt.CallConfig.ALL, clear_state=pt.CallConfig.CALL), + None: pt.MethodConfig(opt_in=pt.CallConfig.ALL), "m1": pt.MethodConfig(no_op=pt.CallConfig.CALL), "m2": pt.MethodConfig(no_op=pt.CallConfig.NEVER), } From e577bf316871cfed5aca6a78fee320d9a1555582 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 19 Jan 2023 18:32:17 -0600 Subject: [PATCH 167/206] test_router_build_idempotence --- pyteal/ast/router_test.py | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/pyteal/ast/router_test.py b/pyteal/ast/router_test.py index 312e1bf41..ca775a8e1 100644 --- a/pyteal/ast/router_test.py +++ b/pyteal/ast/router_test.py @@ -1,3 +1,4 @@ +from copy import deepcopy import pytest import secrets import typing @@ -908,18 +909,12 @@ def handle(deposit: pt.abi.PaymentTransaction): # noqa: F811 assert (ap1, cs1, c1) == (ap2, cs2, c2) -def test_router_compile_program_idempotence(): +def test_router_build_idempotence(): on_completion_actions = pt.BareCallActions( opt_in=pt.OnCompleteAction.call_only(pt.Log(pt.Bytes("optin call"))), + clear_state=pt.OnCompleteAction.call_only(pt.Approve()), ) - router = pt.Router("questionable", on_completion_actions, clear_state=pt.Approve()) - - approval1, clear1, contract1 = router.compile_program(version=6) - approval2, clear2, contract2 = router.compile_program(version=6) - - assert contract1.dictify() == contract2.dictify() - assert clear1 == clear2 - assert approval1 == approval2 + router = pt.Router("questionable", on_completion_actions) @pt.ABIReturnSubroutine def add(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr: @@ -928,20 +923,14 @@ def add(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr meth = router.add_method_handler(add) assert meth.method_signature() == "add(uint64,uint64)uint64" - # formerly nextSlotId: 256 --> 262: + # add_methods_to_router(router) + # method_configs0 = deepcopy(router.method_configs) approval1, clear1, contract1 = router.compile_program(version=6) - # formerly nextSlotId: 262 --> 265: + # method_configs1 = deepcopy(router.method_configs) approval2, clear2, contract2 = router.compile_program(version=6) - # formerly nextSlotId: 265 --> 268: - approval3, clear3, contract3 = router.compile_program(version=6) - - assert contract2.dictify() == contract3.dictify() - assert clear3 == clear2 - assert approval3 == approval3 - - assert contract2.dictify() == contract1.dictify() - assert clear2 == clear1 - assert ( - approval2 == approval1 - ), f"""{approval1=} -{approval2=}""" + # method_configs2 = deepcopy(router.method_configs) + + # assert method_configs0 == method_configs1 == method_configs2 + assert contract1.dictify() == contract2.dictify() + assert approval1 == approval2 + assert clear1 == clear2 From d4c16de7c571df515728153be0941bda3764d920 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 19 Jan 2023 19:05:09 -0600 Subject: [PATCH 168/206] wip --- pyteal/ast/router_test.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/pyteal/ast/router_test.py b/pyteal/ast/router_test.py index ca775a8e1..8f67d7498 100644 --- a/pyteal/ast/router_test.py +++ b/pyteal/ast/router_test.py @@ -916,6 +916,12 @@ def test_router_build_idempotence(): ) router = pt.Router("questionable", on_completion_actions) + approval1, clear1, contract1 = router.build_program(version=6) + approval2, clear2, contract2 = router.build_program(version=6) + + with pt.TealComponent.Context.ignoreExprEquality(): + assert approval1.__teal__(options)[0] == approval2.__teal__(options)[0] + @pt.ABIReturnSubroutine def add(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr: return output.set(a.get() + b.get()) @@ -923,14 +929,22 @@ def add(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr meth = router.add_method_handler(add) assert meth.method_signature() == "add(uint64,uint64)uint64" - # add_methods_to_router(router) + approval1, clear1, contract1 = router.build_program(version=6) + approval2, clear2, contract2 = router.build_program(version=6) + + with pt.TealComponent.Context.ignoreExprEquality(): + assert approval1.__teal__(options)[0] == approval2.__teal__(options)[0] + + + return + # for PR #634: # method_configs0 = deepcopy(router.method_configs) - approval1, clear1, contract1 = router.compile_program(version=6) # method_configs1 = deepcopy(router.method_configs) - approval2, clear2, contract2 = router.compile_program(version=6) # method_configs2 = deepcopy(router.method_configs) - # assert method_configs0 == method_configs1 == method_configs2 + + approval1, clear1, contract1 = router.compile_program(version=6) + approval2, clear2, contract2 = router.compile_program(version=6) assert contract1.dictify() == contract2.dictify() assert approval1 == approval2 assert clear1 == clear2 From 98c340f124c61590fca29d80ba3a08e91b380ae0 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 26 Jan 2023 11:29:08 -0600 Subject: [PATCH 169/206] tweak against local unmerged changes --- pyteal/ast/router_test.py | 47 +- .../router/sim_approval_questionable_6.teal | 494 ---------------- .../router/sim_approval_questionable_8.teal | 553 ------------------ .../teal/router/sim_approval_yacc_6.teal | 475 --------------- .../teal/router/sim_approval_yacc_8.teal | 534 ----------------- .../teal/router/sim_clear_questionable_6.teal | 3 - .../teal/router/sim_clear_questionable_8.teal | 3 - .../teal/router/sim_clear_yacc_6.teal | 3 - .../teal/router/sim_clear_yacc_8.teal | 3 - 9 files changed, 22 insertions(+), 2093 deletions(-) delete mode 100644 tests/integration/teal/router/sim_approval_questionable_6.teal delete mode 100644 tests/integration/teal/router/sim_approval_questionable_8.teal delete mode 100644 tests/integration/teal/router/sim_approval_yacc_6.teal delete mode 100644 tests/integration/teal/router/sim_approval_yacc_8.teal delete mode 100644 tests/integration/teal/router/sim_clear_questionable_6.teal delete mode 100644 tests/integration/teal/router/sim_clear_questionable_8.teal delete mode 100644 tests/integration/teal/router/sim_clear_yacc_6.teal delete mode 100644 tests/integration/teal/router/sim_clear_yacc_8.teal diff --git a/pyteal/ast/router_test.py b/pyteal/ast/router_test.py index 8f67d7498..312e1bf41 100644 --- a/pyteal/ast/router_test.py +++ b/pyteal/ast/router_test.py @@ -1,4 +1,3 @@ -from copy import deepcopy import pytest import secrets import typing @@ -909,18 +908,18 @@ def handle(deposit: pt.abi.PaymentTransaction): # noqa: F811 assert (ap1, cs1, c1) == (ap2, cs2, c2) -def test_router_build_idempotence(): +def test_router_compile_program_idempotence(): on_completion_actions = pt.BareCallActions( opt_in=pt.OnCompleteAction.call_only(pt.Log(pt.Bytes("optin call"))), - clear_state=pt.OnCompleteAction.call_only(pt.Approve()), ) - router = pt.Router("questionable", on_completion_actions) + router = pt.Router("questionable", on_completion_actions, clear_state=pt.Approve()) - approval1, clear1, contract1 = router.build_program(version=6) - approval2, clear2, contract2 = router.build_program(version=6) + approval1, clear1, contract1 = router.compile_program(version=6) + approval2, clear2, contract2 = router.compile_program(version=6) - with pt.TealComponent.Context.ignoreExprEquality(): - assert approval1.__teal__(options)[0] == approval2.__teal__(options)[0] + assert contract1.dictify() == contract2.dictify() + assert clear1 == clear2 + assert approval1 == approval2 @pt.ABIReturnSubroutine def add(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr: @@ -929,22 +928,20 @@ def add(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr meth = router.add_method_handler(add) assert meth.method_signature() == "add(uint64,uint64)uint64" - approval1, clear1, contract1 = router.build_program(version=6) - approval2, clear2, contract2 = router.build_program(version=6) - - with pt.TealComponent.Context.ignoreExprEquality(): - assert approval1.__teal__(options)[0] == approval2.__teal__(options)[0] - - - return - # for PR #634: - # method_configs0 = deepcopy(router.method_configs) - # method_configs1 = deepcopy(router.method_configs) - # method_configs2 = deepcopy(router.method_configs) - # assert method_configs0 == method_configs1 == method_configs2 - + # formerly nextSlotId: 256 --> 262: approval1, clear1, contract1 = router.compile_program(version=6) + # formerly nextSlotId: 262 --> 265: approval2, clear2, contract2 = router.compile_program(version=6) - assert contract1.dictify() == contract2.dictify() - assert approval1 == approval2 - assert clear1 == clear2 + # formerly nextSlotId: 265 --> 268: + approval3, clear3, contract3 = router.compile_program(version=6) + + assert contract2.dictify() == contract3.dictify() + assert clear3 == clear2 + assert approval3 == approval3 + + assert contract2.dictify() == contract1.dictify() + assert clear2 == clear1 + assert ( + approval2 == approval1 + ), f"""{approval1=} +{approval2=}""" diff --git a/tests/integration/teal/router/sim_approval_questionable_6.teal b/tests/integration/teal/router/sim_approval_questionable_6.teal deleted file mode 100644 index 8b1198407..000000000 --- a/tests/integration/teal/router/sim_approval_questionable_6.teal +++ /dev/null @@ -1,494 +0,0 @@ -#pragma version 6 -txn NumAppArgs -int 0 -== -bnz main_l22 -txna ApplicationArgs 0 -method "add(uint64,uint64)uint64" -== -bnz main_l21 -txna ApplicationArgs 0 -method "sub(uint64,uint64)uint64" -== -bnz main_l20 -txna ApplicationArgs 0 -method "mul(uint64,uint64)uint64" -== -bnz main_l19 -txna ApplicationArgs 0 -method "div(uint64,uint64)uint64" -== -bnz main_l18 -txna ApplicationArgs 0 -method "mod(uint64,uint64)uint64" -== -bnz main_l17 -txna ApplicationArgs 0 -method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" -== -bnz main_l16 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l15 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l14 -txna ApplicationArgs 0 -method "log_creation()string" -== -bnz main_l13 -txna ApplicationArgs 0 -method "approve_if_odd(uint32)void" -== -bnz main_l12 -err -main_l12: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -int 0 -extract_uint32 -store 70 -load 70 -callsub approveifodd_9 -int 1 -return -main_l13: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -== -&& -assert -callsub logcreation_8 -store 69 -byte 0x151f7c75 -load 69 -concat -log -int 1 -return -main_l14: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -txn ApplicationID -int 0 -!= -&& -|| -assert -callsub log1_7 -store 68 -byte 0x151f7c75 -load 68 -itob -concat -log -int 1 -return -main_l15: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -|| -assert -callsub emptyreturnsubroutine_6 -int 1 -return -main_l16: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 50 -txna ApplicationArgs 2 -btoi -store 51 -txna ApplicationArgs 3 -btoi -store 52 -txna ApplicationArgs 4 -btoi -store 53 -txna ApplicationArgs 5 -btoi -store 54 -txna ApplicationArgs 6 -btoi -store 55 -txna ApplicationArgs 7 -btoi -store 56 -txna ApplicationArgs 8 -btoi -store 57 -txna ApplicationArgs 9 -btoi -store 58 -txna ApplicationArgs 10 -btoi -store 59 -txna ApplicationArgs 11 -btoi -store 60 -txna ApplicationArgs 12 -btoi -store 61 -txna ApplicationArgs 13 -btoi -store 62 -txna ApplicationArgs 14 -btoi -store 63 -txna ApplicationArgs 15 -store 66 -load 66 -int 0 -extract_uint64 -store 64 -load 66 -int 8 -extract_uint64 -store 65 -load 50 -load 51 -load 52 -load 53 -load 54 -load 55 -load 56 -load 57 -load 58 -load 59 -load 60 -load 61 -load 62 -load 63 -load 64 -load 65 -callsub alllaidtoargs_5 -store 67 -byte 0x151f7c75 -load 67 -itob -concat -log -int 1 -return -main_l17: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 47 -txna ApplicationArgs 2 -btoi -store 48 -load 47 -load 48 -callsub mod_4 -store 49 -byte 0x151f7c75 -load 49 -itob -concat -log -int 1 -return -main_l18: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 44 -txna ApplicationArgs 2 -btoi -store 45 -load 44 -load 45 -callsub div_3 -store 46 -byte 0x151f7c75 -load 46 -itob -concat -log -int 1 -return -main_l19: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 41 -txna ApplicationArgs 2 -btoi -store 42 -load 41 -load 42 -callsub mul_2 -store 43 -byte 0x151f7c75 -load 43 -itob -concat -log -int 1 -return -main_l20: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 38 -txna ApplicationArgs 2 -btoi -store 39 -load 38 -load 39 -callsub sub_1 -store 40 -byte 0x151f7c75 -load 40 -itob -concat -log -int 1 -return -main_l21: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 35 -txna ApplicationArgs 2 -btoi -store 36 -load 35 -load 36 -callsub add_0 -store 37 -byte 0x151f7c75 -load 37 -itob -concat -log -int 1 -return -main_l22: -txn OnCompletion -int OptIn -== -bnz main_l24 -err -main_l24: -txn ApplicationID -int 0 -!= -assert -byte "optin call" -log -int 1 -return - -// add -add_0: -store 1 -store 0 -load 0 -load 1 -+ -store 2 -load 2 -retsub - -// sub -sub_1: -store 4 -store 3 -load 3 -load 4 -- -store 5 -load 5 -retsub - -// mul -mul_2: -store 7 -store 6 -load 6 -load 7 -* -store 8 -load 8 -retsub - -// div -div_3: -store 10 -store 9 -load 9 -load 10 -/ -store 11 -load 11 -retsub - -// mod -mod_4: -store 13 -store 12 -load 12 -load 13 -% -store 14 -load 14 -retsub - -// all_laid_to_args -alllaidtoargs_5: -store 30 -store 29 -store 28 -store 27 -store 26 -store 25 -store 24 -store 23 -store 22 -store 21 -store 20 -store 19 -store 18 -store 17 -store 16 -store 15 -load 15 -load 16 -+ -load 17 -+ -load 18 -+ -load 19 -+ -load 20 -+ -load 21 -+ -load 22 -+ -load 23 -+ -load 24 -+ -load 25 -+ -load 26 -+ -load 27 -+ -load 28 -+ -load 29 -+ -load 30 -+ -store 31 -load 31 -retsub - -// empty_return_subroutine -emptyreturnsubroutine_6: -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_7: -int 1 -store 32 -load 32 -retsub - -// log_creation -logcreation_8: -byte 0x00106c6f6767696e67206372656174696f6e -store 33 -load 33 -retsub - -// approve_if_odd -approveifodd_9: -store 34 -load 34 -int 2 -% -bnz approveifodd_9_l2 -int 0 -return -approveifodd_9_l2: -int 1 -return \ No newline at end of file diff --git a/tests/integration/teal/router/sim_approval_questionable_8.teal b/tests/integration/teal/router/sim_approval_questionable_8.teal deleted file mode 100644 index b0baf28fa..000000000 --- a/tests/integration/teal/router/sim_approval_questionable_8.teal +++ /dev/null @@ -1,553 +0,0 @@ -#pragma version 8 -txn NumAppArgs -int 0 -== -bnz main_l22 -txna ApplicationArgs 0 -method "add(uint64,uint64)uint64" -== -bnz main_l21 -txna ApplicationArgs 0 -method "sub(uint64,uint64)uint64" -== -bnz main_l20 -txna ApplicationArgs 0 -method "mul(uint64,uint64)uint64" -== -bnz main_l19 -txna ApplicationArgs 0 -method "div(uint64,uint64)uint64" -== -bnz main_l18 -txna ApplicationArgs 0 -method "mod(uint64,uint64)uint64" -== -bnz main_l17 -txna ApplicationArgs 0 -method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" -== -bnz main_l16 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l15 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l14 -txna ApplicationArgs 0 -method "log_creation()string" -== -bnz main_l13 -txna ApplicationArgs 0 -method "approve_if_odd(uint32)void" -== -bnz main_l12 -err -main_l12: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub approveifoddcaster_19 -int 1 -return -main_l13: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -== -&& -assert -callsub logcreationcaster_18 -int 1 -return -main_l14: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -txn ApplicationID -int 0 -!= -&& -|| -assert -callsub log1caster_17 -int 1 -return -main_l15: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -|| -assert -callsub emptyreturnsubroutinecaster_16 -int 1 -return -main_l16: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub alllaidtoargscaster_15 -int 1 -return -main_l17: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub modcaster_14 -int 1 -return -main_l18: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub divcaster_13 -int 1 -return -main_l19: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub mulcaster_12 -int 1 -return -main_l20: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub subcaster_11 -int 1 -return -main_l21: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub addcaster_10 -int 1 -return -main_l22: -txn OnCompletion -int OptIn -== -bnz main_l24 -err -main_l24: -txn ApplicationID -int 0 -!= -assert -byte "optin call" -log -int 1 -return - -// add -add_0: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -+ -frame_bury 0 -retsub - -// sub -sub_1: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -- -frame_bury 0 -retsub - -// mul -mul_2: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -* -frame_bury 0 -retsub - -// div -div_3: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -/ -frame_bury 0 -retsub - -// mod -mod_4: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -% -frame_bury 0 -retsub - -// all_laid_to_args -alllaidtoargs_5: -proto 16 1 -int 0 -frame_dig -16 -frame_dig -15 -+ -frame_dig -14 -+ -frame_dig -13 -+ -frame_dig -12 -+ -frame_dig -11 -+ -frame_dig -10 -+ -frame_dig -9 -+ -frame_dig -8 -+ -frame_dig -7 -+ -frame_dig -6 -+ -frame_dig -5 -+ -frame_dig -4 -+ -frame_dig -3 -+ -frame_dig -2 -+ -frame_dig -1 -+ -frame_bury 0 -retsub - -// empty_return_subroutine -emptyreturnsubroutine_6: -proto 0 0 -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_7: -proto 0 1 -int 0 -int 1 -frame_bury 0 -retsub - -// log_creation -logcreation_8: -proto 0 1 -byte "" -byte 0x00106c6f6767696e67206372656174696f6e -frame_bury 0 -retsub - -// approve_if_odd -approveifodd_9: -proto 1 0 -frame_dig -1 -int 2 -% -bnz approveifodd_9_l2 -int 0 -return -approveifodd_9_l2: -int 1 -return - -// add_caster -addcaster_10: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub add_0 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// sub_caster -subcaster_11: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub sub_1 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// mul_caster -mulcaster_12: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub mul_2 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// div_caster -divcaster_13: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub div_3 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// mod_caster -modcaster_14: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub mod_4 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// all_laid_to_args_caster -alllaidtoargscaster_15: -proto 0 0 -int 0 -dupn 16 -byte "" -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -txna ApplicationArgs 3 -btoi -frame_bury 3 -txna ApplicationArgs 4 -btoi -frame_bury 4 -txna ApplicationArgs 5 -btoi -frame_bury 5 -txna ApplicationArgs 6 -btoi -frame_bury 6 -txna ApplicationArgs 7 -btoi -frame_bury 7 -txna ApplicationArgs 8 -btoi -frame_bury 8 -txna ApplicationArgs 9 -btoi -frame_bury 9 -txna ApplicationArgs 10 -btoi -frame_bury 10 -txna ApplicationArgs 11 -btoi -frame_bury 11 -txna ApplicationArgs 12 -btoi -frame_bury 12 -txna ApplicationArgs 13 -btoi -frame_bury 13 -txna ApplicationArgs 14 -btoi -frame_bury 14 -txna ApplicationArgs 15 -frame_bury 17 -frame_dig 17 -int 0 -extract_uint64 -frame_bury 15 -frame_dig 17 -int 8 -extract_uint64 -frame_bury 16 -frame_dig 1 -frame_dig 2 -frame_dig 3 -frame_dig 4 -frame_dig 5 -frame_dig 6 -frame_dig 7 -frame_dig 8 -frame_dig 9 -frame_dig 10 -frame_dig 11 -frame_dig 12 -frame_dig 13 -frame_dig 14 -frame_dig 15 -frame_dig 16 -callsub alllaidtoargs_5 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// empty_return_subroutine_caster -emptyreturnsubroutinecaster_16: -proto 0 0 -callsub emptyreturnsubroutine_6 -retsub - -// log_1_caster -log1caster_17: -proto 0 0 -int 0 -callsub log1_7 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// log_creation_caster -logcreationcaster_18: -proto 0 0 -byte "" -callsub logcreation_8 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -concat -log -retsub - -// approve_if_odd_caster -approveifoddcaster_19: -proto 0 0 -int 0 -txna ApplicationArgs 1 -int 0 -extract_uint32 -frame_bury 0 -frame_dig 0 -callsub approveifodd_9 -retsub \ No newline at end of file diff --git a/tests/integration/teal/router/sim_approval_yacc_6.teal b/tests/integration/teal/router/sim_approval_yacc_6.teal deleted file mode 100644 index 74fd62797..000000000 --- a/tests/integration/teal/router/sim_approval_yacc_6.teal +++ /dev/null @@ -1,475 +0,0 @@ -#pragma version 6 -txna ApplicationArgs 0 -method "add(uint64,uint64)uint64" -== -bnz main_l20 -txna ApplicationArgs 0 -method "sub(uint64,uint64)uint64" -== -bnz main_l19 -txna ApplicationArgs 0 -method "mul(uint64,uint64)uint64" -== -bnz main_l18 -txna ApplicationArgs 0 -method "div(uint64,uint64)uint64" -== -bnz main_l17 -txna ApplicationArgs 0 -method "mod(uint64,uint64)uint64" -== -bnz main_l16 -txna ApplicationArgs 0 -method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" -== -bnz main_l15 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l14 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l13 -txna ApplicationArgs 0 -method "log_creation()string" -== -bnz main_l12 -txna ApplicationArgs 0 -method "approve_if_odd(uint32)void" -== -bnz main_l11 -err -main_l11: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -int 0 -extract_uint32 -store 70 -load 70 -callsub approveifodd_9 -int 1 -return -main_l12: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -== -&& -assert -callsub logcreation_8 -store 69 -byte 0x151f7c75 -load 69 -concat -log -int 1 -return -main_l13: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -txn ApplicationID -int 0 -!= -&& -|| -assert -callsub log1_7 -store 68 -byte 0x151f7c75 -load 68 -itob -concat -log -int 1 -return -main_l14: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -|| -assert -callsub emptyreturnsubroutine_6 -int 1 -return -main_l15: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 50 -txna ApplicationArgs 2 -btoi -store 51 -txna ApplicationArgs 3 -btoi -store 52 -txna ApplicationArgs 4 -btoi -store 53 -txna ApplicationArgs 5 -btoi -store 54 -txna ApplicationArgs 6 -btoi -store 55 -txna ApplicationArgs 7 -btoi -store 56 -txna ApplicationArgs 8 -btoi -store 57 -txna ApplicationArgs 9 -btoi -store 58 -txna ApplicationArgs 10 -btoi -store 59 -txna ApplicationArgs 11 -btoi -store 60 -txna ApplicationArgs 12 -btoi -store 61 -txna ApplicationArgs 13 -btoi -store 62 -txna ApplicationArgs 14 -btoi -store 63 -txna ApplicationArgs 15 -store 66 -load 66 -int 0 -extract_uint64 -store 64 -load 66 -int 8 -extract_uint64 -store 65 -load 50 -load 51 -load 52 -load 53 -load 54 -load 55 -load 56 -load 57 -load 58 -load 59 -load 60 -load 61 -load 62 -load 63 -load 64 -load 65 -callsub alllaidtoargs_5 -store 67 -byte 0x151f7c75 -load 67 -itob -concat -log -int 1 -return -main_l16: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 47 -txna ApplicationArgs 2 -btoi -store 48 -load 47 -load 48 -callsub mod_4 -store 49 -byte 0x151f7c75 -load 49 -itob -concat -log -int 1 -return -main_l17: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 44 -txna ApplicationArgs 2 -btoi -store 45 -load 44 -load 45 -callsub div_3 -store 46 -byte 0x151f7c75 -load 46 -itob -concat -log -int 1 -return -main_l18: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 41 -txna ApplicationArgs 2 -btoi -store 42 -load 41 -load 42 -callsub mul_2 -store 43 -byte 0x151f7c75 -load 43 -itob -concat -log -int 1 -return -main_l19: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 38 -txna ApplicationArgs 2 -btoi -store 39 -load 38 -load 39 -callsub sub_1 -store 40 -byte 0x151f7c75 -load 40 -itob -concat -log -int 1 -return -main_l20: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 35 -txna ApplicationArgs 2 -btoi -store 36 -load 35 -load 36 -callsub add_0 -store 37 -byte 0x151f7c75 -load 37 -itob -concat -log -int 1 -return - -// add -add_0: -store 1 -store 0 -load 0 -load 1 -+ -store 2 -load 2 -retsub - -// sub -sub_1: -store 4 -store 3 -load 3 -load 4 -- -store 5 -load 5 -retsub - -// mul -mul_2: -store 7 -store 6 -load 6 -load 7 -* -store 8 -load 8 -retsub - -// div -div_3: -store 10 -store 9 -load 9 -load 10 -/ -store 11 -load 11 -retsub - -// mod -mod_4: -store 13 -store 12 -load 12 -load 13 -% -store 14 -load 14 -retsub - -// all_laid_to_args -alllaidtoargs_5: -store 30 -store 29 -store 28 -store 27 -store 26 -store 25 -store 24 -store 23 -store 22 -store 21 -store 20 -store 19 -store 18 -store 17 -store 16 -store 15 -load 15 -load 16 -+ -load 17 -+ -load 18 -+ -load 19 -+ -load 20 -+ -load 21 -+ -load 22 -+ -load 23 -+ -load 24 -+ -load 25 -+ -load 26 -+ -load 27 -+ -load 28 -+ -load 29 -+ -load 30 -+ -store 31 -load 31 -retsub - -// empty_return_subroutine -emptyreturnsubroutine_6: -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_7: -int 1 -store 32 -load 32 -retsub - -// log_creation -logcreation_8: -byte 0x00106c6f6767696e67206372656174696f6e -store 33 -load 33 -retsub - -// approve_if_odd -approveifodd_9: -store 34 -load 34 -int 2 -% -bnz approveifodd_9_l2 -int 0 -return -approveifodd_9_l2: -int 1 -return \ No newline at end of file diff --git a/tests/integration/teal/router/sim_approval_yacc_8.teal b/tests/integration/teal/router/sim_approval_yacc_8.teal deleted file mode 100644 index 25af706c5..000000000 --- a/tests/integration/teal/router/sim_approval_yacc_8.teal +++ /dev/null @@ -1,534 +0,0 @@ -#pragma version 8 -txna ApplicationArgs 0 -method "add(uint64,uint64)uint64" -== -bnz main_l20 -txna ApplicationArgs 0 -method "sub(uint64,uint64)uint64" -== -bnz main_l19 -txna ApplicationArgs 0 -method "mul(uint64,uint64)uint64" -== -bnz main_l18 -txna ApplicationArgs 0 -method "div(uint64,uint64)uint64" -== -bnz main_l17 -txna ApplicationArgs 0 -method "mod(uint64,uint64)uint64" -== -bnz main_l16 -txna ApplicationArgs 0 -method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" -== -bnz main_l15 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l14 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l13 -txna ApplicationArgs 0 -method "log_creation()string" -== -bnz main_l12 -txna ApplicationArgs 0 -method "approve_if_odd(uint32)void" -== -bnz main_l11 -err -main_l11: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub approveifoddcaster_19 -int 1 -return -main_l12: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -== -&& -assert -callsub logcreationcaster_18 -int 1 -return -main_l13: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -txn ApplicationID -int 0 -!= -&& -|| -assert -callsub log1caster_17 -int 1 -return -main_l14: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -|| -assert -callsub emptyreturnsubroutinecaster_16 -int 1 -return -main_l15: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub alllaidtoargscaster_15 -int 1 -return -main_l16: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub modcaster_14 -int 1 -return -main_l17: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub divcaster_13 -int 1 -return -main_l18: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub mulcaster_12 -int 1 -return -main_l19: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub subcaster_11 -int 1 -return -main_l20: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub addcaster_10 -int 1 -return - -// add -add_0: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -+ -frame_bury 0 -retsub - -// sub -sub_1: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -- -frame_bury 0 -retsub - -// mul -mul_2: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -* -frame_bury 0 -retsub - -// div -div_3: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -/ -frame_bury 0 -retsub - -// mod -mod_4: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -% -frame_bury 0 -retsub - -// all_laid_to_args -alllaidtoargs_5: -proto 16 1 -int 0 -frame_dig -16 -frame_dig -15 -+ -frame_dig -14 -+ -frame_dig -13 -+ -frame_dig -12 -+ -frame_dig -11 -+ -frame_dig -10 -+ -frame_dig -9 -+ -frame_dig -8 -+ -frame_dig -7 -+ -frame_dig -6 -+ -frame_dig -5 -+ -frame_dig -4 -+ -frame_dig -3 -+ -frame_dig -2 -+ -frame_dig -1 -+ -frame_bury 0 -retsub - -// empty_return_subroutine -emptyreturnsubroutine_6: -proto 0 0 -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_7: -proto 0 1 -int 0 -int 1 -frame_bury 0 -retsub - -// log_creation -logcreation_8: -proto 0 1 -byte "" -byte 0x00106c6f6767696e67206372656174696f6e -frame_bury 0 -retsub - -// approve_if_odd -approveifodd_9: -proto 1 0 -frame_dig -1 -int 2 -% -bnz approveifodd_9_l2 -int 0 -return -approveifodd_9_l2: -int 1 -return - -// add_caster -addcaster_10: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub add_0 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// sub_caster -subcaster_11: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub sub_1 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// mul_caster -mulcaster_12: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub mul_2 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// div_caster -divcaster_13: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub div_3 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// mod_caster -modcaster_14: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub mod_4 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// all_laid_to_args_caster -alllaidtoargscaster_15: -proto 0 0 -int 0 -dupn 16 -byte "" -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -txna ApplicationArgs 3 -btoi -frame_bury 3 -txna ApplicationArgs 4 -btoi -frame_bury 4 -txna ApplicationArgs 5 -btoi -frame_bury 5 -txna ApplicationArgs 6 -btoi -frame_bury 6 -txna ApplicationArgs 7 -btoi -frame_bury 7 -txna ApplicationArgs 8 -btoi -frame_bury 8 -txna ApplicationArgs 9 -btoi -frame_bury 9 -txna ApplicationArgs 10 -btoi -frame_bury 10 -txna ApplicationArgs 11 -btoi -frame_bury 11 -txna ApplicationArgs 12 -btoi -frame_bury 12 -txna ApplicationArgs 13 -btoi -frame_bury 13 -txna ApplicationArgs 14 -btoi -frame_bury 14 -txna ApplicationArgs 15 -frame_bury 17 -frame_dig 17 -int 0 -extract_uint64 -frame_bury 15 -frame_dig 17 -int 8 -extract_uint64 -frame_bury 16 -frame_dig 1 -frame_dig 2 -frame_dig 3 -frame_dig 4 -frame_dig 5 -frame_dig 6 -frame_dig 7 -frame_dig 8 -frame_dig 9 -frame_dig 10 -frame_dig 11 -frame_dig 12 -frame_dig 13 -frame_dig 14 -frame_dig 15 -frame_dig 16 -callsub alllaidtoargs_5 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// empty_return_subroutine_caster -emptyreturnsubroutinecaster_16: -proto 0 0 -callsub emptyreturnsubroutine_6 -retsub - -// log_1_caster -log1caster_17: -proto 0 0 -int 0 -callsub log1_7 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// log_creation_caster -logcreationcaster_18: -proto 0 0 -byte "" -callsub logcreation_8 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -concat -log -retsub - -// approve_if_odd_caster -approveifoddcaster_19: -proto 0 0 -int 0 -txna ApplicationArgs 1 -int 0 -extract_uint32 -frame_bury 0 -frame_dig 0 -callsub approveifodd_9 -retsub \ No newline at end of file diff --git a/tests/integration/teal/router/sim_clear_questionable_6.teal b/tests/integration/teal/router/sim_clear_questionable_6.teal deleted file mode 100644 index e6cf44111..000000000 --- a/tests/integration/teal/router/sim_clear_questionable_6.teal +++ /dev/null @@ -1,3 +0,0 @@ -#pragma version 6 -int 0 -return \ No newline at end of file diff --git a/tests/integration/teal/router/sim_clear_questionable_8.teal b/tests/integration/teal/router/sim_clear_questionable_8.teal deleted file mode 100644 index ba95445f2..000000000 --- a/tests/integration/teal/router/sim_clear_questionable_8.teal +++ /dev/null @@ -1,3 +0,0 @@ -#pragma version 8 -int 0 -return \ No newline at end of file diff --git a/tests/integration/teal/router/sim_clear_yacc_6.teal b/tests/integration/teal/router/sim_clear_yacc_6.teal deleted file mode 100644 index e6cf44111..000000000 --- a/tests/integration/teal/router/sim_clear_yacc_6.teal +++ /dev/null @@ -1,3 +0,0 @@ -#pragma version 6 -int 0 -return \ No newline at end of file diff --git a/tests/integration/teal/router/sim_clear_yacc_8.teal b/tests/integration/teal/router/sim_clear_yacc_8.teal deleted file mode 100644 index ba95445f2..000000000 --- a/tests/integration/teal/router/sim_clear_yacc_8.teal +++ /dev/null @@ -1,3 +0,0 @@ -#pragma version 8 -int 0 -return \ No newline at end of file From 1e8ce99c4dc77cec310d0e9457d0c7fc3f715e7f Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 26 Jan 2023 11:57:04 -0600 Subject: [PATCH 170/206] small tweaks- main one is initializing `self.bare_calls` --- pyteal/ast/router.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/pyteal/ast/router.py b/pyteal/ast/router.py index f9385a970..1d707718d 100644 --- a/pyteal/ast/router.py +++ b/pyteal/ast/router.py @@ -35,6 +35,8 @@ from pyteal.ast.txn import Txn from pyteal.ast.return_ import Approve, Reject +ActionType = Expr | SubroutineFnWrapper | ABIReturnSubroutine + class CallConfig(IntFlag): """ @@ -132,12 +134,6 @@ def approval_cond(self) -> Expr | int: MethodConfig.__module__ = "pyteal" -ActionType = Expr | SubroutineFnWrapper | ABIReturnSubroutine - - -MethodConfig.__module__ = "pyteal" - - @dataclass(frozen=True) class OnCompleteAction: """ @@ -709,12 +705,11 @@ def __init__( self.method_sig_to_selector: dict[str, bytes] = dict() self.method_selector_to_sig: dict[bytes, str] = dict() - self.method_configs: dict[str | None, MethodConfig] = dict() + self.bare_calls: BareCallActions = bare_calls or BareCallActions() - self.bare_calls: BareCallActions | None = bare_calls - - if bare_calls and not bare_calls.is_empty(): - self.method_configs[None] = bare_calls.get_method_config() + self.method_configs: dict[str | None, MethodConfig] = dict() + if not self.bare_calls.is_empty(): + self.method_configs[None] = self.bare_calls.get_method_config() def _clean(self) -> None: self.approval_ast._clean_bare_calls() From 322c2d80a3877aa9b5581dafef007deb4d3b406c Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 26 Jan 2023 12:18:48 -0600 Subject: [PATCH 171/206] small refactoring around Router's `bare_call_actions` --- pyteal/ast/router.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pyteal/ast/router.py b/pyteal/ast/router.py index 1d707718d..0318e5721 100644 --- a/pyteal/ast/router.py +++ b/pyteal/ast/router.py @@ -705,11 +705,11 @@ def __init__( self.method_sig_to_selector: dict[str, bytes] = dict() self.method_selector_to_sig: dict[bytes, str] = dict() - self.bare_calls: BareCallActions = bare_calls or BareCallActions() + self.bare_call_actions: BareCallActions = bare_calls or BareCallActions() self.method_configs: dict[str | None, MethodConfig] = dict() - if not self.bare_calls.is_empty(): - self.method_configs[None] = self.bare_calls.get_method_config() + if not self.bare_call_actions.is_empty(): + self.method_configs[None] = self.bare_call_actions.get_method_config() def _clean(self) -> None: self.approval_ast._clean_bare_calls() @@ -889,8 +889,8 @@ def _build_program( * clear_state_program: an AST for clear-state program * contract: a Python SDK Contract object to allow clients to make off-chain calls """ - if self.bare_calls and not self.bare_calls.is_empty(): - bare_call_approval = self.bare_calls.approval_construction() + if not self.bare_call_actions.is_empty(): + bare_call_approval = self.bare_call_actions.approval_construction() if bare_call_approval: self.approval_ast.bare_calls = [ CondNode( From e893a204c9d912dff23e8635efc1366d9f055a8c Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Wed, 1 Feb 2023 22:42:25 -0600 Subject: [PATCH 172/206] mergin --- pyteal/compiler/compiler_test.py | 2282 ++--------------- tests/integration/abi_router_test.py | 297 +-- .../router/questionableFP_approval_v8.teal | 121 +- .../teal/router/questionableFP_clear_v8.teal | 2 +- .../teal/router/questionable_approval_v6.teal | 80 +- .../teal/router/questionable_clear_v6.teal | 2 +- .../router/sim_approval_questionable_6.teal | 460 ++++ .../router/sim_approval_questionable_8.teal | 512 ++++ tests/teal/router/sim_approval_yacc_6.teal | 441 ++++ tests/teal/router/sim_approval_yacc_8.teal | 493 ++++ .../teal/router/sim_clear_questionable_6.teal | 3 + .../teal/router/sim_clear_questionable_8.teal | 3 + tests/teal/router/sim_clear_yacc_6.teal | 3 + tests/teal/router/sim_clear_yacc_8.teal | 3 + .../teal/router/yaccFP_approval_v8.teal | 113 +- .../teal/router/yaccFP_clear_v8.teal | 2 +- .../teal/router/yacc_approval_v6.teal | 72 +- .../teal/router/yacc_clear_v6.teal | 2 +- 18 files changed, 2268 insertions(+), 2623 deletions(-) rename tests/{integration => }/teal/router/questionableFP_approval_v8.teal (85%) rename tests/{integration => }/teal/router/questionableFP_clear_v8.teal (80%) rename tests/{integration => }/teal/router/questionable_approval_v6.teal (91%) rename tests/{integration => }/teal/router/questionable_clear_v6.teal (80%) create mode 100644 tests/teal/router/sim_approval_questionable_6.teal create mode 100644 tests/teal/router/sim_approval_questionable_8.teal create mode 100644 tests/teal/router/sim_approval_yacc_6.teal create mode 100644 tests/teal/router/sim_approval_yacc_8.teal create mode 100644 tests/teal/router/sim_clear_questionable_6.teal create mode 100644 tests/teal/router/sim_clear_questionable_8.teal create mode 100644 tests/teal/router/sim_clear_yacc_6.teal create mode 100644 tests/teal/router/sim_clear_yacc_8.teal rename tests/{integration => }/teal/router/yaccFP_approval_v8.teal (85%) rename tests/{integration => }/teal/router/yaccFP_clear_v8.teal (80%) rename tests/{integration => }/teal/router/yacc_approval_v6.teal (91%) rename tests/{integration => }/teal/router/yacc_clear_v6.teal (80%) diff --git a/pyteal/compiler/compiler_test.py b/pyteal/compiler/compiler_test.py index 9f7de4ac8..c318129cf 100644 --- a/pyteal/compiler/compiler_test.py +++ b/pyteal/compiler/compiler_test.py @@ -1,7 +1,10 @@ +from pathlib import Path import pytest import pyteal as pt +FIXTURES = Path.cwd() / "tests" / "teal" / "router" + def test_compile_single(): expr = pt.Int(1) @@ -2195,626 +2198,180 @@ def access_b4_store(magic_num: pt.abi.Uint64, *, output: pt.abi.Uint64): pt.compileTeal(program_access_b4_store_broken, pt.Mode.Application, version=6) -def test_router_app(): - def add_methods_to_router(router: pt.Router): - @pt.ABIReturnSubroutine - def add( - a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 - ) -> pt.Expr: - return output.set(a.get() + b.get()) - - meth = router.add_method_handler(add) - assert meth.method_signature() == "add(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def sub( - a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 - ) -> pt.Expr: - return output.set(a.get() - b.get()) - - meth = router.add_method_handler(sub) - assert meth.method_signature() == "sub(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def mul( - a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 - ) -> pt.Expr: - return output.set(a.get() * b.get()) - - meth = router.add_method_handler(mul) - assert meth.method_signature() == "mul(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def div( - a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 - ) -> pt.Expr: - return output.set(a.get() / b.get()) - - meth = router.add_method_handler(div) - assert meth.method_signature() == "div(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def mod( - a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64 - ) -> pt.Expr: - return output.set(a.get() % b.get()) - - meth = router.add_method_handler(mod) - assert meth.method_signature() == "mod(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def all_laid_to_args( - _a: pt.abi.Uint64, - _b: pt.abi.Uint64, - _c: pt.abi.Uint64, - _d: pt.abi.Uint64, - _e: pt.abi.Uint64, - _f: pt.abi.Uint64, - _g: pt.abi.Uint64, - _h: pt.abi.Uint64, - _i: pt.abi.Uint64, - _j: pt.abi.Uint64, - _k: pt.abi.Uint64, - _l: pt.abi.Uint64, - _m: pt.abi.Uint64, - _n: pt.abi.Uint64, - _o: pt.abi.Uint64, - _p: pt.abi.Uint64, - *, - output: pt.abi.Uint64, - ): - return output.set( - _a.get() - + _b.get() - + _c.get() - + _d.get() - + _e.get() - + _f.get() - + _g.get() - + _h.get() - + _i.get() - + _j.get() - + _k.get() - + _l.get() - + _m.get() - + _n.get() - + _o.get() - + _p.get() - ) +def add_methods_to_router(router: pt.Router): + @pt.ABIReturnSubroutine + def add(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr: + return output.set(a.get() + b.get()) - meth = router.add_method_handler(all_laid_to_args) - assert ( - meth.method_signature() - == "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" - ) + meth = router.add_method_handler(add) + assert meth.method_signature() == "add(uint64,uint64)uint64" - @pt.ABIReturnSubroutine - def empty_return_subroutine() -> pt.Expr: - return pt.Log(pt.Bytes("appear in both approval and clear state")) + @pt.ABIReturnSubroutine + def sub(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr: + return output.set(a.get() - b.get()) - meth = router.add_method_handler( - empty_return_subroutine, - method_config=pt.MethodConfig( - no_op=pt.CallConfig.CALL, - opt_in=pt.CallConfig.ALL, - ), - ) - assert meth.method_signature() == "empty_return_subroutine()void" + meth = router.add_method_handler(sub) + assert meth.method_signature() == "sub(uint64,uint64)uint64" - @pt.ABIReturnSubroutine - def log_1(*, output: pt.abi.Uint64) -> pt.Expr: - return output.set(1) + @pt.ABIReturnSubroutine + def mul(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr: + return output.set(a.get() * b.get()) - meth = router.add_method_handler( - log_1, - method_config=pt.MethodConfig( - no_op=pt.CallConfig.CALL, - opt_in=pt.CallConfig.CALL, - ), - ) + meth = router.add_method_handler(mul) + assert meth.method_signature() == "mul(uint64,uint64)uint64" - assert meth.method_signature() == "log_1()uint64" + @pt.ABIReturnSubroutine + def div(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr: + return output.set(a.get() / b.get()) - @pt.ABIReturnSubroutine - def log_creation(*, output: pt.abi.String) -> pt.Expr: - return output.set("logging creation") + meth = router.add_method_handler(div) + assert meth.method_signature() == "div(uint64,uint64)uint64" - meth = router.add_method_handler( - log_creation, method_config=pt.MethodConfig(no_op=pt.CallConfig.CREATE) - ) - assert meth.method_signature() == "log_creation()string" + @pt.ABIReturnSubroutine + def mod(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr: + return output.set(a.get() % b.get()) - on_completion_actions = pt.BareCallActions( - opt_in=pt.OnCompleteAction.call_only(pt.Log(pt.Bytes("optin call"))), - ) + meth = router.add_method_handler(mod) + assert meth.method_signature() == "mod(uint64,uint64)uint64" - with pytest.raises(pt.TealInputError) as e: - pt.Router("will-error", on_completion_actions).compile_program( - version=6, optimize=pt.OptimizeOptions(frame_pointers=True) + @pt.ABIReturnSubroutine + def all_laid_to_args( + _a: pt.abi.Uint64, + _b: pt.abi.Uint64, + _c: pt.abi.Uint64, + _d: pt.abi.Uint64, + _e: pt.abi.Uint64, + _f: pt.abi.Uint64, + _g: pt.abi.Uint64, + _h: pt.abi.Uint64, + _i: pt.abi.Uint64, + _j: pt.abi.Uint64, + _k: pt.abi.Uint64, + _l: pt.abi.Uint64, + _m: pt.abi.Uint64, + _n: pt.abi.Uint64, + _o: pt.abi.Uint64, + _p: pt.abi.Uint64, + *, + output: pt.abi.Uint64, + ): + return output.set( + _a.get() + + _b.get() + + _c.get() + + _d.get() + + _e.get() + + _f.get() + + _g.get() + + _h.get() + + _i.get() + + _j.get() + + _k.get() + + _l.get() + + _m.get() + + _n.get() + + _o.get() + + _p.get() ) - assert "Frame pointers aren't available" in str(e.value) + meth = router.add_method_handler(all_laid_to_args) + assert ( + meth.method_signature() + == "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" + ) - _router_with_oc = pt.Router( - "ASimpleQuestionablyRobustContract", - on_completion_actions, - clear_state=pt.Approve(), + @pt.ABIReturnSubroutine + def empty_return_subroutine() -> pt.Expr: + return pt.Log(pt.Bytes("appear in both approval and clear state")) + + meth = router.add_method_handler( + empty_return_subroutine, + method_config=pt.MethodConfig( + no_op=pt.CallConfig.CALL, + opt_in=pt.CallConfig.ALL, + ), ) - add_methods_to_router(_router_with_oc) - ( - actual_ap_with_oc_compiled, - actual_csp_with_oc_compiled, - _, - ) = _router_with_oc.compile_program(version=6) + assert meth.method_signature() == "empty_return_subroutine()void" - expected_ap_with_oc = """#pragma version 6 -txn NumAppArgs -int 0 -== -bnz main_l20 -txna ApplicationArgs 0 -method "add(uint64,uint64)uint64" -== -bnz main_l19 -txna ApplicationArgs 0 -method "sub(uint64,uint64)uint64" -== -bnz main_l18 -txna ApplicationArgs 0 -method "mul(uint64,uint64)uint64" -== -bnz main_l17 -txna ApplicationArgs 0 -method "div(uint64,uint64)uint64" -== -bnz main_l16 -txna ApplicationArgs 0 -method "mod(uint64,uint64)uint64" -== -bnz main_l15 -txna ApplicationArgs 0 -method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" -== -bnz main_l14 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l13 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l12 -txna ApplicationArgs 0 -method "log_creation()string" -== -bnz main_l11 -err -main_l11: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -== -&& -assert -callsub logcreation_8 -store 67 -byte 0x151f7c75 -load 67 -concat -log -int 1 -return -main_l12: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -txn ApplicationID -int 0 -!= -&& -|| -assert -callsub log1_7 -store 65 -byte 0x151f7c75 -load 65 -itob -concat -log -int 1 -return -main_l13: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -|| -assert -callsub emptyreturnsubroutine_6 -int 1 -return -main_l14: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 30 -txna ApplicationArgs 2 -btoi -store 31 -txna ApplicationArgs 3 -btoi -store 32 -txna ApplicationArgs 4 -btoi -store 33 -txna ApplicationArgs 5 -btoi -store 34 -txna ApplicationArgs 6 -btoi -store 35 -txna ApplicationArgs 7 -btoi -store 36 -txna ApplicationArgs 8 -btoi -store 37 -txna ApplicationArgs 9 -btoi -store 38 -txna ApplicationArgs 10 -btoi -store 39 -txna ApplicationArgs 11 -btoi -store 40 -txna ApplicationArgs 12 -btoi -store 41 -txna ApplicationArgs 13 -btoi -store 42 -txna ApplicationArgs 14 -btoi -store 43 -txna ApplicationArgs 15 -store 46 -load 46 -int 0 -extract_uint64 -store 44 -load 46 -int 8 -extract_uint64 -store 45 -load 30 -load 31 -load 32 -load 33 -load 34 -load 35 -load 36 -load 37 -load 38 -load 39 -load 40 -load 41 -load 42 -load 43 -load 44 -load 45 -callsub alllaidtoargs_5 -store 47 -byte 0x151f7c75 -load 47 -itob -concat -log -int 1 -return -main_l15: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 24 -txna ApplicationArgs 2 -btoi -store 25 -load 24 -load 25 -callsub mod_4 -store 26 -byte 0x151f7c75 -load 26 -itob -concat -log -int 1 -return -main_l16: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 18 -txna ApplicationArgs 2 -btoi -store 19 -load 18 -load 19 -callsub div_3 -store 20 -byte 0x151f7c75 -load 20 -itob -concat -log -int 1 -return -main_l17: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 12 -txna ApplicationArgs 2 -btoi -store 13 -load 12 -load 13 -callsub mul_2 -store 14 -byte 0x151f7c75 -load 14 -itob -concat -log -int 1 -return -main_l18: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 6 -txna ApplicationArgs 2 -btoi -store 7 -load 6 -load 7 -callsub sub_1 -store 8 -byte 0x151f7c75 -load 8 -itob -concat -log -int 1 -return -main_l19: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 0 -txna ApplicationArgs 2 -btoi -store 1 -load 0 -load 1 -callsub add_0 -store 2 -byte 0x151f7c75 -load 2 -itob -concat -log -int 1 -return -main_l20: -txn OnCompletion -int OptIn -== -bnz main_l22 -err -main_l22: -txn ApplicationID -int 0 -!= -assert -byte "optin call" -log -int 1 -return + @pt.ABIReturnSubroutine + def log_1(*, output: pt.abi.Uint64) -> pt.Expr: + return output.set(1) + + meth = router.add_method_handler( + log_1, + method_config=pt.MethodConfig( + no_op=pt.CallConfig.CALL, + opt_in=pt.CallConfig.CALL, + ), + ) -// add -add_0: -store 4 -store 3 -load 3 -load 4 -+ -store 5 -load 5 -retsub + assert meth.method_signature() == "log_1()uint64" -// sub -sub_1: -store 10 -store 9 -load 9 -load 10 -- -store 11 -load 11 -retsub + @pt.ABIReturnSubroutine + def log_creation(*, output: pt.abi.String) -> pt.Expr: + return output.set("logging creation") -// mul -mul_2: -store 16 -store 15 -load 15 -load 16 -* -store 17 -load 17 -retsub + meth = router.add_method_handler( + log_creation, method_config=pt.MethodConfig(no_op=pt.CallConfig.CREATE) + ) + assert meth.method_signature() == "log_creation()string" -// div -div_3: -store 22 -store 21 -load 21 -load 22 -/ -store 23 -load 23 -retsub -// mod -mod_4: -store 28 -store 27 -load 27 -load 28 -% -store 29 -load 29 -retsub +ON_COMPLETION_ACTIONS = pt.BareCallActions( + opt_in=pt.OnCompleteAction.call_only(pt.Log(pt.Bytes("optin call"))), +) -// all_laid_to_args -alllaidtoargs_5: -store 63 -store 62 -store 61 -store 60 -store 59 -store 58 -store 57 -store 56 -store 55 -store 54 -store 53 -store 52 -store 51 -store 50 -store 49 -store 48 -load 48 -load 49 -+ -load 50 -+ -load 51 -+ -load 52 -+ -load 53 -+ -load 54 -+ -load 55 -+ -load 56 -+ -load 57 -+ -load 58 -+ -load 59 -+ -load 60 -+ -load 61 -+ -load 62 -+ -load 63 -+ -store 64 -load 64 -retsub +FIRST_ROUTER = pt.Router( + "ASimpleQuestionablyRobustContract", + ON_COMPLETION_ACTIONS, + clear_state=pt.Approve(), +) +add_methods_to_router(FIRST_ROUTER) -// empty_return_subroutine -emptyreturnsubroutine_6: -byte "appear in both approval and clear state" -log -retsub -// log_1 -log1_7: -int 1 -store 66 -load 66 -retsub +def router_app_tester() -> tuple[list[pt.Router], dict[str, str]]: + routers = [] + sources = {} -// log_creation -logcreation_8: -byte 0x00106c6f6767696e67206372656174696f6e -store 68 -load 68 -retsub""".strip() + def append_router_info(rinfo, programs): + assert len(rinfo) == 3 + assert len(programs) == 2 + routers.append(rinfo) + sources[rinfo[:2]] = programs - assert expected_ap_with_oc == actual_ap_with_oc_compiled + # V6 not ready for Frame Pointers: + with pytest.raises(pt.TealInputError) as e: + pt.Router("will-error", ON_COMPLETION_ACTIONS).compile_program( + version=6, optimize=pt.OptimizeOptions(frame_pointers=True) + ) + assert "Frame pointers aren't available" in str(e.value) - expected_csp_with_oc = """#pragma version 6 -int 1 -return""".strip() + # QUESTIONABLE V6: + _router_with_oc = FIRST_ROUTER + ( + actual_ap_with_oc_compiled, + actual_csp_with_oc_compiled, + _, + ) = _router_with_oc.compile_program(version=6) + with open(FIXTURES / "questionable_approval_v6.teal") as f: + expected_ap_with_oc = f.read() + with open(FIXTURES / "questionable_clear_v6.teal") as f: + expected_csp_with_oc = f.read() + assert expected_ap_with_oc == actual_ap_with_oc_compiled assert expected_csp_with_oc == actual_csp_with_oc_compiled + append_router_info( + ( + "questionable", + 6, + _router_with_oc, + ), + ( + actual_ap_with_oc_compiled, + actual_csp_with_oc_compiled, + ), + ) + # YACC V6: _router_without_oc = pt.Router( "yetAnotherContractConstructedFromRouter", clear_state=pt.Approve() ) @@ -2824,985 +2381,56 @@ def log_creation(*, output: pt.abi.String) -> pt.Expr: actual_csp_without_oc_compiled, _, ) = _router_without_oc.compile_program(version=6) - expected_ap_without_oc = """#pragma version 6 -txna ApplicationArgs 0 -method "add(uint64,uint64)uint64" -== -bnz main_l18 -txna ApplicationArgs 0 -method "sub(uint64,uint64)uint64" -== -bnz main_l17 -txna ApplicationArgs 0 -method "mul(uint64,uint64)uint64" -== -bnz main_l16 -txna ApplicationArgs 0 -method "div(uint64,uint64)uint64" -== -bnz main_l15 -txna ApplicationArgs 0 -method "mod(uint64,uint64)uint64" -== -bnz main_l14 -txna ApplicationArgs 0 -method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" -== -bnz main_l13 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l12 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l11 -txna ApplicationArgs 0 -method "log_creation()string" -== -bnz main_l10 -err -main_l10: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -== -&& -assert -callsub logcreation_8 -store 67 -byte 0x151f7c75 -load 67 -concat -log -int 1 -return -main_l11: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -txn ApplicationID -int 0 -!= -&& -|| -assert -callsub log1_7 -store 65 -byte 0x151f7c75 -load 65 -itob -concat -log -int 1 -return -main_l12: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -|| -assert -callsub emptyreturnsubroutine_6 -int 1 -return -main_l13: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 30 -txna ApplicationArgs 2 -btoi -store 31 -txna ApplicationArgs 3 -btoi -store 32 -txna ApplicationArgs 4 -btoi -store 33 -txna ApplicationArgs 5 -btoi -store 34 -txna ApplicationArgs 6 -btoi -store 35 -txna ApplicationArgs 7 -btoi -store 36 -txna ApplicationArgs 8 -btoi -store 37 -txna ApplicationArgs 9 -btoi -store 38 -txna ApplicationArgs 10 -btoi -store 39 -txna ApplicationArgs 11 -btoi -store 40 -txna ApplicationArgs 12 -btoi -store 41 -txna ApplicationArgs 13 -btoi -store 42 -txna ApplicationArgs 14 -btoi -store 43 -txna ApplicationArgs 15 -store 46 -load 46 -int 0 -extract_uint64 -store 44 -load 46 -int 8 -extract_uint64 -store 45 -load 30 -load 31 -load 32 -load 33 -load 34 -load 35 -load 36 -load 37 -load 38 -load 39 -load 40 -load 41 -load 42 -load 43 -load 44 -load 45 -callsub alllaidtoargs_5 -store 47 -byte 0x151f7c75 -load 47 -itob -concat -log -int 1 -return -main_l14: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 24 -txna ApplicationArgs 2 -btoi -store 25 -load 24 -load 25 -callsub mod_4 -store 26 -byte 0x151f7c75 -load 26 -itob -concat -log -int 1 -return -main_l15: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 18 -txna ApplicationArgs 2 -btoi -store 19 -load 18 -load 19 -callsub div_3 -store 20 -byte 0x151f7c75 -load 20 -itob -concat -log -int 1 -return -main_l16: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 12 -txna ApplicationArgs 2 -btoi -store 13 -load 12 -load 13 -callsub mul_2 -store 14 -byte 0x151f7c75 -load 14 -itob -concat -log -int 1 -return -main_l17: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 6 -txna ApplicationArgs 2 -btoi -store 7 -load 6 -load 7 -callsub sub_1 -store 8 -byte 0x151f7c75 -load 8 -itob -concat -log -int 1 -return -main_l18: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 0 -txna ApplicationArgs 2 -btoi -store 1 -load 0 -load 1 -callsub add_0 -store 2 -byte 0x151f7c75 -load 2 -itob -concat -log -int 1 -return - -// add -add_0: -store 4 -store 3 -load 3 -load 4 -+ -store 5 -load 5 -retsub - -// sub -sub_1: -store 10 -store 9 -load 9 -load 10 -- -store 11 -load 11 -retsub - -// mul -mul_2: -store 16 -store 15 -load 15 -load 16 -* -store 17 -load 17 -retsub - -// div -div_3: -store 22 -store 21 -load 21 -load 22 -/ -store 23 -load 23 -retsub - -// mod -mod_4: -store 28 -store 27 -load 27 -load 28 -% -store 29 -load 29 -retsub - -// all_laid_to_args -alllaidtoargs_5: -store 63 -store 62 -store 61 -store 60 -store 59 -store 58 -store 57 -store 56 -store 55 -store 54 -store 53 -store 52 -store 51 -store 50 -store 49 -store 48 -load 48 -load 49 -+ -load 50 -+ -load 51 -+ -load 52 -+ -load 53 -+ -load 54 -+ -load 55 -+ -load 56 -+ -load 57 -+ -load 58 -+ -load 59 -+ -load 60 -+ -load 61 -+ -load 62 -+ -load 63 -+ -store 64 -load 64 -retsub - -// empty_return_subroutine -emptyreturnsubroutine_6: -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_7: -int 1 -store 66 -load 66 -retsub - -// log_creation -logcreation_8: -byte 0x00106c6f6767696e67206372656174696f6e -store 68 -load 68 -retsub""".strip() - assert actual_ap_without_oc_compiled == expected_ap_without_oc - - expected_csp_without_oc = """#pragma version 6 -int 1 -return""".strip() - assert actual_csp_without_oc_compiled == expected_csp_without_oc - - _router_with_oc = pt.Router( - "QuestionableRouterGenerateCodeWithFramePointer", - on_completion_actions, - clear_state=pt.Approve(), - ) - add_methods_to_router(_router_with_oc) - ( - actual_ap_with_oc_compiled, - actual_csp_with_oc_compiled, - _, - ) = _router_with_oc.compile_program(version=8) - - expected_ap_with_oc = """#pragma version 8 -txn NumAppArgs -int 0 -== -bnz main_l20 -txna ApplicationArgs 0 -method "add(uint64,uint64)uint64" -== -bnz main_l19 -txna ApplicationArgs 0 -method "sub(uint64,uint64)uint64" -== -bnz main_l18 -txna ApplicationArgs 0 -method "mul(uint64,uint64)uint64" -== -bnz main_l17 -txna ApplicationArgs 0 -method "div(uint64,uint64)uint64" -== -bnz main_l16 -txna ApplicationArgs 0 -method "mod(uint64,uint64)uint64" -== -bnz main_l15 -txna ApplicationArgs 0 -method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" -== -bnz main_l14 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l13 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l12 -txna ApplicationArgs 0 -method "log_creation()string" -== -bnz main_l11 -err -main_l11: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -== -&& -assert -callsub logcreationcaster_17 -int 1 -return -main_l12: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -txn ApplicationID -int 0 -!= -&& -|| -assert -callsub log1caster_16 -int 1 -return -main_l13: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -|| -assert -callsub emptyreturnsubroutinecaster_15 -int 1 -return -main_l14: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub alllaidtoargscaster_14 -int 1 -return -main_l15: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub modcaster_13 -int 1 -return -main_l16: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub divcaster_12 -int 1 -return -main_l17: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub mulcaster_11 -int 1 -return -main_l18: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub subcaster_10 -int 1 -return -main_l19: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub addcaster_9 -int 1 -return -main_l20: -txn OnCompletion -int OptIn -== -bnz main_l22 -err -main_l22: -txn ApplicationID -int 0 -!= -assert -byte "optin call" -log -int 1 -return - -// add -add_0: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -+ -frame_bury 0 -retsub - -// sub -sub_1: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -- -frame_bury 0 -retsub - -// mul -mul_2: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -* -frame_bury 0 -retsub - -// div -div_3: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -/ -frame_bury 0 -retsub - -// mod -mod_4: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -% -frame_bury 0 -retsub - -// all_laid_to_args -alllaidtoargs_5: -proto 16 1 -int 0 -frame_dig -16 -frame_dig -15 -+ -frame_dig -14 -+ -frame_dig -13 -+ -frame_dig -12 -+ -frame_dig -11 -+ -frame_dig -10 -+ -frame_dig -9 -+ -frame_dig -8 -+ -frame_dig -7 -+ -frame_dig -6 -+ -frame_dig -5 -+ -frame_dig -4 -+ -frame_dig -3 -+ -frame_dig -2 -+ -frame_dig -1 -+ -frame_bury 0 -retsub - -// empty_return_subroutine -emptyreturnsubroutine_6: -proto 0 0 -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_7: -proto 0 1 -int 0 -int 1 -frame_bury 0 -retsub - -// log_creation -logcreation_8: -proto 0 1 -byte "" -byte 0x00106c6f6767696e67206372656174696f6e -frame_bury 0 -retsub - -// add_caster -addcaster_9: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub add_0 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// sub_caster -subcaster_10: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub sub_1 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// mul_caster -mulcaster_11: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub mul_2 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// div_caster -divcaster_12: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub div_3 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// mod_caster -modcaster_13: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub mod_4 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// all_laid_to_args_caster -alllaidtoargscaster_14: -proto 0 0 -int 0 -dupn 16 -byte "" -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -txna ApplicationArgs 3 -btoi -frame_bury 3 -txna ApplicationArgs 4 -btoi -frame_bury 4 -txna ApplicationArgs 5 -btoi -frame_bury 5 -txna ApplicationArgs 6 -btoi -frame_bury 6 -txna ApplicationArgs 7 -btoi -frame_bury 7 -txna ApplicationArgs 8 -btoi -frame_bury 8 -txna ApplicationArgs 9 -btoi -frame_bury 9 -txna ApplicationArgs 10 -btoi -frame_bury 10 -txna ApplicationArgs 11 -btoi -frame_bury 11 -txna ApplicationArgs 12 -btoi -frame_bury 12 -txna ApplicationArgs 13 -btoi -frame_bury 13 -txna ApplicationArgs 14 -btoi -frame_bury 14 -txna ApplicationArgs 15 -frame_bury 17 -frame_dig 17 -int 0 -extract_uint64 -frame_bury 15 -frame_dig 17 -int 8 -extract_uint64 -frame_bury 16 -frame_dig 1 -frame_dig 2 -frame_dig 3 -frame_dig 4 -frame_dig 5 -frame_dig 6 -frame_dig 7 -frame_dig 8 -frame_dig 9 -frame_dig 10 -frame_dig 11 -frame_dig 12 -frame_dig 13 -frame_dig 14 -frame_dig 15 -frame_dig 16 -callsub alllaidtoargs_5 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// empty_return_subroutine_caster -emptyreturnsubroutinecaster_15: -proto 0 0 -callsub emptyreturnsubroutine_6 -retsub - -// log_1_caster -log1caster_16: -proto 0 0 -int 0 -callsub log1_7 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub + with open(FIXTURES / "yacc_approval_v6.teal") as f: + expected_ap_without_oc = f.read() + with open(FIXTURES / "yacc_clear_v6.teal") as f: + expected_csp_without_oc = f.read() + assert actual_ap_without_oc_compiled == expected_ap_without_oc + assert actual_csp_without_oc_compiled == expected_csp_without_oc + append_router_info( + ( + "yacc", + 6, + _router_without_oc, + ), + ( + actual_ap_without_oc_compiled, + actual_csp_without_oc_compiled, + ), + ) -// log_creation_caster -logcreationcaster_17: -proto 0 0 -byte "" -callsub logcreation_8 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -concat -log -retsub""".strip() + # QUESTIONABLE FP V8: + _router_with_oc = pt.Router( + "QuestionableRouterGenerateCodeWithFramePointer", + ON_COMPLETION_ACTIONS, + clear_state=pt.Approve(), + ) + add_methods_to_router(_router_with_oc) + ( + actual_ap_with_oc_compiled, + actual_csp_with_oc_compiled, + _, + ) = _router_with_oc.compile_program(version=8) + with open(FIXTURES / "questionableFP_approval_v8.teal") as f: + expected_ap_with_oc = f.read() + with open(FIXTURES / "questionableFP_clear_v8.teal") as f: + expected_csp_with_oc = f.read() assert actual_ap_with_oc_compiled == expected_ap_with_oc - - expected_csp_with_oc = """#pragma version 8 -int 1 -return""".strip() + assert actual_csp_with_oc_compiled == expected_csp_with_oc + append_router_info( + ( + "questionable", + 8, + _router_with_oc, + ), + ( + actual_ap_with_oc_compiled, + actual_csp_with_oc_compiled, + ), + ) assert actual_csp_with_oc_compiled == expected_csp_with_oc + # YACC FP V8: _router_without_oc = pt.Router( "yetAnotherContractConstructedFromRouterWithFramePointer", clear_state=pt.Approve(), @@ -3813,504 +2441,28 @@ def log_creation(*, output: pt.abi.String) -> pt.Expr: actual_csp_without_oc_compiled, _, ) = _router_without_oc.compile_program(version=8) - - expected_ap_without_oc = """#pragma version 8 -txna ApplicationArgs 0 -method "add(uint64,uint64)uint64" -== -bnz main_l18 -txna ApplicationArgs 0 -method "sub(uint64,uint64)uint64" -== -bnz main_l17 -txna ApplicationArgs 0 -method "mul(uint64,uint64)uint64" -== -bnz main_l16 -txna ApplicationArgs 0 -method "div(uint64,uint64)uint64" -== -bnz main_l15 -txna ApplicationArgs 0 -method "mod(uint64,uint64)uint64" -== -bnz main_l14 -txna ApplicationArgs 0 -method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" -== -bnz main_l13 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l12 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l11 -txna ApplicationArgs 0 -method "log_creation()string" -== -bnz main_l10 -err -main_l10: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -== -&& -assert -callsub logcreationcaster_17 -int 1 -return -main_l11: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -txn ApplicationID -int 0 -!= -&& -|| -assert -callsub log1caster_16 -int 1 -return -main_l12: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -|| -assert -callsub emptyreturnsubroutinecaster_15 -int 1 -return -main_l13: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub alllaidtoargscaster_14 -int 1 -return -main_l14: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub modcaster_13 -int 1 -return -main_l15: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub divcaster_12 -int 1 -return -main_l16: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub mulcaster_11 -int 1 -return -main_l17: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub subcaster_10 -int 1 -return -main_l18: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub addcaster_9 -int 1 -return - -// add -add_0: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -+ -frame_bury 0 -retsub - -// sub -sub_1: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -- -frame_bury 0 -retsub - -// mul -mul_2: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -* -frame_bury 0 -retsub - -// div -div_3: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -/ -frame_bury 0 -retsub - -// mod -mod_4: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -% -frame_bury 0 -retsub - -// all_laid_to_args -alllaidtoargs_5: -proto 16 1 -int 0 -frame_dig -16 -frame_dig -15 -+ -frame_dig -14 -+ -frame_dig -13 -+ -frame_dig -12 -+ -frame_dig -11 -+ -frame_dig -10 -+ -frame_dig -9 -+ -frame_dig -8 -+ -frame_dig -7 -+ -frame_dig -6 -+ -frame_dig -5 -+ -frame_dig -4 -+ -frame_dig -3 -+ -frame_dig -2 -+ -frame_dig -1 -+ -frame_bury 0 -retsub - -// empty_return_subroutine -emptyreturnsubroutine_6: -proto 0 0 -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_7: -proto 0 1 -int 0 -int 1 -frame_bury 0 -retsub - -// log_creation -logcreation_8: -proto 0 1 -byte "" -byte 0x00106c6f6767696e67206372656174696f6e -frame_bury 0 -retsub - -// add_caster -addcaster_9: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub add_0 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// sub_caster -subcaster_10: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub sub_1 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// mul_caster -mulcaster_11: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub mul_2 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// div_caster -divcaster_12: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub div_3 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// mod_caster -modcaster_13: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub mod_4 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// all_laid_to_args_caster -alllaidtoargscaster_14: -proto 0 0 -int 0 -dupn 16 -byte "" -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -txna ApplicationArgs 3 -btoi -frame_bury 3 -txna ApplicationArgs 4 -btoi -frame_bury 4 -txna ApplicationArgs 5 -btoi -frame_bury 5 -txna ApplicationArgs 6 -btoi -frame_bury 6 -txna ApplicationArgs 7 -btoi -frame_bury 7 -txna ApplicationArgs 8 -btoi -frame_bury 8 -txna ApplicationArgs 9 -btoi -frame_bury 9 -txna ApplicationArgs 10 -btoi -frame_bury 10 -txna ApplicationArgs 11 -btoi -frame_bury 11 -txna ApplicationArgs 12 -btoi -frame_bury 12 -txna ApplicationArgs 13 -btoi -frame_bury 13 -txna ApplicationArgs 14 -btoi -frame_bury 14 -txna ApplicationArgs 15 -frame_bury 17 -frame_dig 17 -int 0 -extract_uint64 -frame_bury 15 -frame_dig 17 -int 8 -extract_uint64 -frame_bury 16 -frame_dig 1 -frame_dig 2 -frame_dig 3 -frame_dig 4 -frame_dig 5 -frame_dig 6 -frame_dig 7 -frame_dig 8 -frame_dig 9 -frame_dig 10 -frame_dig 11 -frame_dig 12 -frame_dig 13 -frame_dig 14 -frame_dig 15 -frame_dig 16 -callsub alllaidtoargs_5 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// empty_return_subroutine_caster -emptyreturnsubroutinecaster_15: -proto 0 0 -callsub emptyreturnsubroutine_6 -retsub - -// log_1_caster -log1caster_16: -proto 0 0 -int 0 -callsub log1_7 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// log_creation_caster -logcreationcaster_17: -proto 0 0 -byte "" -callsub logcreation_8 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -concat -log -retsub""".strip() + with open(FIXTURES / "yaccFP_approval_v8.teal") as f: + expected_ap_without_oc = f.read() + with open(FIXTURES / "yaccFP_clear_v8.teal") as f: + expected_csp_without_oc = f.read() assert actual_ap_without_oc_compiled == expected_ap_without_oc + assert actual_csp_without_oc_compiled == expected_csp_without_oc + append_router_info( + ( + "yacc", + 8, + _router_without_oc, + ), + ( + actual_ap_without_oc_compiled, + actual_csp_without_oc_compiled, + ), + ) + assert actual_csp_without_oc_compiled == expected_csp_without_oc - expected_csp_without_oc = """#pragma version 8 -int 1 -return""".strip() + return routers, sources - assert actual_csp_without_oc_compiled == expected_csp_without_oc +def test_router_app(): + # TODO: this test is redundant as router_app_tester is imported and run by + # tests/integration/abi_router_test.py's setup + router_app_tester() \ No newline at end of file diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index 9cb04be08..f54b2687d 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -6,287 +6,17 @@ from graviton.blackbox import DryRunEncoder from graviton.invariant import DryRunProperty as DRProp +from pyteal.compiler.compiler_test import router_app_tester import pyteal as pt from tests.blackbox import Predicates, RouterSimulation +BRUTE_FORCE_TERRIBLE_SKIPPING = True NUM_ROUTER_DRYRUNS = 7 -FIXTURES = Path.cwd() / "tests" / "integration" / "teal" / "router" +FIXTURES = Path.cwd() / "tests" / "teal" / "router" -def add_methods_to_router(router: pt.Router): - @pt.ABIReturnSubroutine - def add(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr: - return output.set(a.get() + b.get()) - - meth = router.add_method_handler(add) - assert meth.method_signature() == "add(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def sub(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr: - return output.set(a.get() - b.get()) - - meth = router.add_method_handler(sub) - assert meth.method_signature() == "sub(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def mul(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr: - return output.set(a.get() * b.get()) - - meth = router.add_method_handler(mul) - assert meth.method_signature() == "mul(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def div(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr: - return output.set(a.get() / b.get()) - - meth = router.add_method_handler(div) - assert meth.method_signature() == "div(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def mod(a: pt.abi.Uint64, b: pt.abi.Uint64, *, output: pt.abi.Uint64) -> pt.Expr: - return output.set(a.get() % b.get()) - - meth = router.add_method_handler(mod) - assert meth.method_signature() == "mod(uint64,uint64)uint64" - - @pt.ABIReturnSubroutine - def all_laid_to_args( - _a: pt.abi.Uint64, - _b: pt.abi.Uint64, - _c: pt.abi.Uint64, - _d: pt.abi.Uint64, - _e: pt.abi.Uint64, - _f: pt.abi.Uint64, - _g: pt.abi.Uint64, - _h: pt.abi.Uint64, - _i: pt.abi.Uint64, - _j: pt.abi.Uint64, - _k: pt.abi.Uint64, - _l: pt.abi.Uint64, - _m: pt.abi.Uint64, - _n: pt.abi.Uint64, - _o: pt.abi.Uint64, - _p: pt.abi.Uint64, - *, - output: pt.abi.Uint64, - ): - return output.set( - _a.get() - + _b.get() - + _c.get() - + _d.get() - + _e.get() - + _f.get() - + _g.get() - + _h.get() - + _i.get() - + _j.get() - + _k.get() - + _l.get() - + _m.get() - + _n.get() - + _o.get() - + _p.get() - ) - - meth = router.add_method_handler(all_laid_to_args) - assert ( - meth.method_signature() - == "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" - ) - - @pt.ABIReturnSubroutine - def empty_return_subroutine() -> pt.Expr: - return pt.Log(pt.Bytes("appear in both approval and clear state")) - - meth = router.add_method_handler( - empty_return_subroutine, - method_config=pt.MethodConfig( - no_op=pt.CallConfig.CALL, - opt_in=pt.CallConfig.ALL, - # clear_state=pt.CallConfig.CALL, - ), - ) - assert meth.method_signature() == "empty_return_subroutine()void" - - @pt.ABIReturnSubroutine - def log_1(*, output: pt.abi.Uint64) -> pt.Expr: - return output.set(1) - - meth = router.add_method_handler( - log_1, - method_config=pt.MethodConfig( - no_op=pt.CallConfig.CALL, - opt_in=pt.CallConfig.CALL, - # clear_state=pt.CallConfig.CALL, - ), - ) - - assert meth.method_signature() == "log_1()uint64" - - @pt.ABIReturnSubroutine - def log_creation(*, output: pt.abi.String) -> pt.Expr: - return output.set("logging creation") - - meth = router.add_method_handler( - log_creation, method_config=pt.MethodConfig(no_op=pt.CallConfig.CREATE) - ) - assert meth.method_signature() == "log_creation()string" - - @pt.ABIReturnSubroutine - def approve_if_odd(condition_encoding: pt.abi.Uint32) -> pt.Expr: - return ( - pt.If(condition_encoding.get() % pt.Int(2)) - .Then(pt.Approve()) - .Else(pt.Reject()) - ) - - meth = router.add_method_handler( - approve_if_odd, - method_config=pt.MethodConfig( - no_op=pt.CallConfig.CALL, # clear_state=pt.CallConfig.CALL - ), - ) - assert meth.method_signature() == "approve_if_odd(uint32)void" - - -def generate_and_test_routers() -> tuple[list[pt.Router], dict[list, str]]: - # tuple[str, int, pt.Router, str, str]: - routers = [] - sources = {} - - def append_router_info(rinfo, programs): - assert len(rinfo) == 3 - assert len(programs) == 2 - routers.append(rinfo) - sources[rinfo[:2]] = programs - - # V6 not ready for Frame Pointers: - on_completion_actions = pt.BareCallActions( - opt_in=pt.OnCompleteAction.call_only(pt.Log(pt.Bytes("optin call"))), - # clear_state=pt.OnCompleteAction.call_only(pt.Approve()), - ) - with pytest.raises(pt.TealInputError) as e: - pt.Router("will-error", on_completion_actions).compile_program( - version=6, optimize=pt.OptimizeOptions(frame_pointers=True) - ) - assert "Frame pointers aren't available" in str(e.value) - - # QUESTIONABLE V6: - _router_with_oc = pt.Router( - "ASimpleQuestionablyRobustContract", on_completion_actions - ) - add_methods_to_router(_router_with_oc) - ( - actual_ap_with_oc_compiled, - actual_csp_with_oc_compiled, - _, - ) = _router_with_oc.compile_program(version=6) - with open(FIXTURES / "questionable_approval_v6.teal") as f: - expected_ap_with_oc = f.read() - with open(FIXTURES / "questionable_clear_v6.teal") as f: - expected_csp_with_oc = f.read() - assert expected_ap_with_oc == actual_ap_with_oc_compiled - assert expected_csp_with_oc == actual_csp_with_oc_compiled - append_router_info( - ( - "questionable", - 6, - _router_with_oc, - ), - ( - actual_ap_with_oc_compiled, - actual_csp_with_oc_compiled, - ), - ) - - # YACC V6: - _router_without_oc = pt.Router("yetAnotherContractConstructedFromRouter") - add_methods_to_router(_router_without_oc) - ( - actual_ap_without_oc_compiled, - actual_csp_without_oc_compiled, - _, - ) = _router_without_oc.compile_program(version=6) - with open(FIXTURES / "yacc_approval_v6.teal") as f: - expected_ap_without_oc = f.read() - with open(FIXTURES / "yacc_clear_v6.teal") as f: - expected_csp_without_oc = f.read() - assert actual_ap_without_oc_compiled == expected_ap_without_oc - assert actual_csp_without_oc_compiled == expected_csp_without_oc - append_router_info( - ( - "yacc", - 6, - _router_without_oc, - ), - ( - actual_ap_without_oc_compiled, - actual_csp_without_oc_compiled, - ), - ) - - # QUESTIONABLE FP V8: - _router_with_oc = pt.Router( - "QuestionableRouterGenerateCodeWithFramePointer", on_completion_actions - ) - add_methods_to_router(_router_with_oc) - ( - actual_ap_with_oc_compiled, - actual_csp_with_oc_compiled, - _, - ) = _router_with_oc.compile_program(version=8) - with open(FIXTURES / "questionableFP_approval_v8.teal") as f: - expected_ap_with_oc = f.read() - with open(FIXTURES / "questionableFP_clear_v8.teal") as f: - expected_csp_with_oc = f.read() - assert actual_ap_with_oc_compiled == expected_ap_with_oc - assert actual_csp_with_oc_compiled == expected_csp_with_oc - append_router_info( - ( - "questionable", - 8, - _router_with_oc, - ), - ( - actual_ap_with_oc_compiled, - actual_csp_with_oc_compiled, - ), - ) - - # YACC FP V8: - _router_without_oc = pt.Router( - "yetAnotherContractConstructedFromRouterWithFramePointer" - ) - add_methods_to_router(_router_without_oc) - ( - actual_ap_without_oc_compiled, - actual_csp_without_oc_compiled, - _, - ) = _router_without_oc.compile_program(version=8) - with open(FIXTURES / "yaccFP_approval_v8.teal") as f: - expected_ap_without_oc = f.read() - with open(FIXTURES / "yaccFP_clear_v8.teal") as f: - expected_csp_without_oc = f.read() - assert actual_ap_without_oc_compiled == expected_ap_without_oc - assert actual_csp_without_oc_compiled == expected_csp_without_oc - append_router_info( - ( - "yacc", - 8, - _router_without_oc, - ), - ( - actual_ap_without_oc_compiled, - actual_csp_without_oc_compiled, - ), - ) - - return routers, sources - - -ROUTER_CASES, ROUTER_SOURCES = generate_and_test_routers() +ROUTER_CASES, ROUTER_SOURCES = router_app_tester() TYPICAL_IAC_OC = pt.MethodConfig(no_op=pt.CallConfig.CALL) @@ -366,14 +96,6 @@ def append_router_info(rinfo, programs): pt.MethodConfig(no_op=pt.CallConfig.CREATE), {DRProp.passed: True, DRProp.lastLog: "logging creation"}, ), - ( - "approve_if_odd", # this should only appear in the clear-state program - pt.MethodConfig(no_op=pt.CallConfig.CALL), - { - DRProp.passed: lambda args: args[1] % 2 == 1, - DRProp.lastLog: None, - }, - ), ( None, pt.MethodConfig( @@ -440,11 +162,14 @@ def msg(): print(json.dumps(stats := results["stats"], indent=2)) assert stats and all(stats.values()) - # wow!!! these fail because of label assignment non-determinism: - # assert pregen_approval == results["approval_simulator"].simulate_dre.program - # assert pregen_clear == results["clear_simulator"].simulate_dre.program + # wow!!! these fail because of differing scratch slot assignments + if BRUTE_FORCE_TERRIBLE_SKIPPING: + pass + else: + assert pregen_approval == results["approval_simulator"].simulate_dre.program + assert pregen_clear == results["clear_simulator"].simulate_dre.program + with open(FIXTURES / f"sim_approval_{case}_{version}.teal", "w") as f: f.write(results["sim_cfg"].ap_compiled) - with open(FIXTURES / f"sim_clear_{case}_{version}.teal", "w") as f: f.write(results["sim_cfg"].csp_compiled) diff --git a/tests/integration/teal/router/questionableFP_approval_v8.teal b/tests/teal/router/questionableFP_approval_v8.teal similarity index 85% rename from tests/integration/teal/router/questionableFP_approval_v8.teal rename to tests/teal/router/questionableFP_approval_v8.teal index b0baf28fa..00a013082 100644 --- a/tests/integration/teal/router/questionableFP_approval_v8.teal +++ b/tests/teal/router/questionableFP_approval_v8.teal @@ -2,61 +2,45 @@ txn NumAppArgs int 0 == -bnz main_l22 +bnz main_l20 txna ApplicationArgs 0 method "add(uint64,uint64)uint64" == -bnz main_l21 +bnz main_l19 txna ApplicationArgs 0 method "sub(uint64,uint64)uint64" == -bnz main_l20 +bnz main_l18 txna ApplicationArgs 0 method "mul(uint64,uint64)uint64" == -bnz main_l19 +bnz main_l17 txna ApplicationArgs 0 method "div(uint64,uint64)uint64" == -bnz main_l18 +bnz main_l16 txna ApplicationArgs 0 method "mod(uint64,uint64)uint64" == -bnz main_l17 +bnz main_l15 txna ApplicationArgs 0 method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" == -bnz main_l16 +bnz main_l14 txna ApplicationArgs 0 method "empty_return_subroutine()void" == -bnz main_l15 +bnz main_l13 txna ApplicationArgs 0 method "log_1()uint64" == -bnz main_l14 +bnz main_l12 txna ApplicationArgs 0 method "log_creation()string" == -bnz main_l13 -txna ApplicationArgs 0 -method "approve_if_odd(uint32)void" -== -bnz main_l12 +bnz main_l11 err -main_l12: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub approveifoddcaster_19 -int 1 -return -main_l13: +main_l11: txn OnCompletion int NoOp == @@ -65,10 +49,10 @@ int 0 == && assert -callsub logcreationcaster_18 +callsub logcreationcaster_17 int 1 return -main_l14: +main_l12: txn OnCompletion int NoOp == @@ -85,10 +69,10 @@ int 0 && || assert -callsub log1caster_17 +callsub log1caster_16 int 1 return -main_l15: +main_l13: txn OnCompletion int NoOp == @@ -101,10 +85,10 @@ int OptIn == || assert -callsub emptyreturnsubroutinecaster_16 +callsub emptyreturnsubroutinecaster_15 int 1 return -main_l16: +main_l14: txn OnCompletion int NoOp == @@ -113,10 +97,10 @@ int 0 != && assert -callsub alllaidtoargscaster_15 +callsub alllaidtoargscaster_14 int 1 return -main_l17: +main_l15: txn OnCompletion int NoOp == @@ -125,10 +109,10 @@ int 0 != && assert -callsub modcaster_14 +callsub modcaster_13 int 1 return -main_l18: +main_l16: txn OnCompletion int NoOp == @@ -137,10 +121,10 @@ int 0 != && assert -callsub divcaster_13 +callsub divcaster_12 int 1 return -main_l19: +main_l17: txn OnCompletion int NoOp == @@ -149,10 +133,10 @@ int 0 != && assert -callsub mulcaster_12 +callsub mulcaster_11 int 1 return -main_l20: +main_l18: txn OnCompletion int NoOp == @@ -161,10 +145,10 @@ int 0 != && assert -callsub subcaster_11 +callsub subcaster_10 int 1 return -main_l21: +main_l19: txn OnCompletion int NoOp == @@ -173,16 +157,16 @@ int 0 != && assert -callsub addcaster_10 +callsub addcaster_9 int 1 return -main_l22: +main_l20: txn OnCompletion int OptIn == -bnz main_l24 +bnz main_l22 err -main_l24: +main_l22: txn ApplicationID int 0 != @@ -303,21 +287,8 @@ byte 0x00106c6f6767696e67206372656174696f6e frame_bury 0 retsub -// approve_if_odd -approveifodd_9: -proto 1 0 -frame_dig -1 -int 2 -% -bnz approveifodd_9_l2 -int 0 -return -approveifodd_9_l2: -int 1 -return - // add_caster -addcaster_10: +addcaster_9: proto 0 0 int 0 dupn 2 @@ -339,7 +310,7 @@ log retsub // sub_caster -subcaster_11: +subcaster_10: proto 0 0 int 0 dupn 2 @@ -361,7 +332,7 @@ log retsub // mul_caster -mulcaster_12: +mulcaster_11: proto 0 0 int 0 dupn 2 @@ -383,7 +354,7 @@ log retsub // div_caster -divcaster_13: +divcaster_12: proto 0 0 int 0 dupn 2 @@ -405,7 +376,7 @@ log retsub // mod_caster -modcaster_14: +modcaster_13: proto 0 0 int 0 dupn 2 @@ -427,7 +398,7 @@ log retsub // all_laid_to_args_caster -alllaidtoargscaster_15: +alllaidtoargscaster_14: proto 0 0 int 0 dupn 16 @@ -510,13 +481,13 @@ log retsub // empty_return_subroutine_caster -emptyreturnsubroutinecaster_16: +emptyreturnsubroutinecaster_15: proto 0 0 callsub emptyreturnsubroutine_6 retsub // log_1_caster -log1caster_17: +log1caster_16: proto 0 0 int 0 callsub log1_7 @@ -529,7 +500,7 @@ log retsub // log_creation_caster -logcreationcaster_18: +logcreationcaster_17: proto 0 0 byte "" callsub logcreation_8 @@ -538,16 +509,4 @@ byte 0x151f7c75 frame_dig 0 concat log -retsub - -// approve_if_odd_caster -approveifoddcaster_19: -proto 0 0 -int 0 -txna ApplicationArgs 1 -int 0 -extract_uint32 -frame_bury 0 -frame_dig 0 -callsub approveifodd_9 retsub \ No newline at end of file diff --git a/tests/integration/teal/router/questionableFP_clear_v8.teal b/tests/teal/router/questionableFP_clear_v8.teal similarity index 80% rename from tests/integration/teal/router/questionableFP_clear_v8.teal rename to tests/teal/router/questionableFP_clear_v8.teal index ba95445f2..31588a8ec 100644 --- a/tests/integration/teal/router/questionableFP_clear_v8.teal +++ b/tests/teal/router/questionableFP_clear_v8.teal @@ -1,3 +1,3 @@ #pragma version 8 -int 0 +int 1 return \ No newline at end of file diff --git a/tests/integration/teal/router/questionable_approval_v6.teal b/tests/teal/router/questionable_approval_v6.teal similarity index 91% rename from tests/integration/teal/router/questionable_approval_v6.teal rename to tests/teal/router/questionable_approval_v6.teal index 36b68e6ae..51455774a 100644 --- a/tests/integration/teal/router/questionable_approval_v6.teal +++ b/tests/teal/router/questionable_approval_v6.teal @@ -2,66 +2,45 @@ txn NumAppArgs int 0 == -bnz main_l22 +bnz main_l20 txna ApplicationArgs 0 method "add(uint64,uint64)uint64" == -bnz main_l21 +bnz main_l19 txna ApplicationArgs 0 method "sub(uint64,uint64)uint64" == -bnz main_l20 +bnz main_l18 txna ApplicationArgs 0 method "mul(uint64,uint64)uint64" == -bnz main_l19 +bnz main_l17 txna ApplicationArgs 0 method "div(uint64,uint64)uint64" == -bnz main_l18 +bnz main_l16 txna ApplicationArgs 0 method "mod(uint64,uint64)uint64" == -bnz main_l17 +bnz main_l15 txna ApplicationArgs 0 method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" == -bnz main_l16 +bnz main_l14 txna ApplicationArgs 0 method "empty_return_subroutine()void" == -bnz main_l15 +bnz main_l13 txna ApplicationArgs 0 method "log_1()uint64" == -bnz main_l14 +bnz main_l12 txna ApplicationArgs 0 method "log_creation()string" == -bnz main_l13 -txna ApplicationArgs 0 -method "approve_if_odd(uint32)void" -== -bnz main_l12 +bnz main_l11 err -main_l12: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -int 0 -extract_uint32 -store 69 -load 69 -callsub approveifodd_9 -int 1 -return -main_l13: +main_l11: txn OnCompletion int NoOp == @@ -78,7 +57,7 @@ concat log int 1 return -main_l14: +main_l12: txn OnCompletion int NoOp == @@ -104,7 +83,7 @@ concat log int 1 return -main_l15: +main_l13: txn OnCompletion int NoOp == @@ -120,7 +99,7 @@ assert callsub emptyreturnsubroutine_6 int 1 return -main_l16: +main_l14: txn OnCompletion int NoOp == @@ -206,7 +185,7 @@ concat log int 1 return -main_l17: +main_l15: txn OnCompletion int NoOp == @@ -232,7 +211,7 @@ concat log int 1 return -main_l18: +main_l16: txn OnCompletion int NoOp == @@ -258,7 +237,7 @@ concat log int 1 return -main_l19: +main_l17: txn OnCompletion int NoOp == @@ -284,7 +263,7 @@ concat log int 1 return -main_l20: +main_l18: txn OnCompletion int NoOp == @@ -310,7 +289,7 @@ concat log int 1 return -main_l21: +main_l19: txn OnCompletion int NoOp == @@ -336,13 +315,13 @@ concat log int 1 return -main_l22: +main_l20: txn OnCompletion int OptIn == -bnz main_l24 +bnz main_l22 err -main_l24: +main_l22: txn ApplicationID int 0 != @@ -478,17 +457,4 @@ logcreation_8: byte 0x00106c6f6767696e67206372656174696f6e store 68 load 68 -retsub - -// approve_if_odd -approveifodd_9: -store 70 -load 70 -int 2 -% -bnz approveifodd_9_l2 -int 0 -return -approveifodd_9_l2: -int 1 -return \ No newline at end of file +retsub \ No newline at end of file diff --git a/tests/integration/teal/router/questionable_clear_v6.teal b/tests/teal/router/questionable_clear_v6.teal similarity index 80% rename from tests/integration/teal/router/questionable_clear_v6.teal rename to tests/teal/router/questionable_clear_v6.teal index e6cf44111..c7de51891 100644 --- a/tests/integration/teal/router/questionable_clear_v6.teal +++ b/tests/teal/router/questionable_clear_v6.teal @@ -1,3 +1,3 @@ #pragma version 6 -int 0 +int 1 return \ No newline at end of file diff --git a/tests/teal/router/sim_approval_questionable_6.teal b/tests/teal/router/sim_approval_questionable_6.teal new file mode 100644 index 000000000..21bf4e4d1 --- /dev/null +++ b/tests/teal/router/sim_approval_questionable_6.teal @@ -0,0 +1,460 @@ +#pragma version 6 +txn NumAppArgs +int 0 +== +bnz main_l20 +txna ApplicationArgs 0 +method "add(uint64,uint64)uint64" +== +bnz main_l19 +txna ApplicationArgs 0 +method "sub(uint64,uint64)uint64" +== +bnz main_l18 +txna ApplicationArgs 0 +method "mul(uint64,uint64)uint64" +== +bnz main_l17 +txna ApplicationArgs 0 +method "div(uint64,uint64)uint64" +== +bnz main_l16 +txna ApplicationArgs 0 +method "mod(uint64,uint64)uint64" +== +bnz main_l15 +txna ApplicationArgs 0 +method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" +== +bnz main_l14 +txna ApplicationArgs 0 +method "empty_return_subroutine()void" +== +bnz main_l13 +txna ApplicationArgs 0 +method "log_1()uint64" +== +bnz main_l12 +txna ApplicationArgs 0 +method "log_creation()string" +== +bnz main_l11 +err +main_l11: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +== +&& +assert +callsub logcreation_8 +store 49 +byte 0x151f7c75 +load 49 +concat +log +int 1 +return +main_l12: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +txn ApplicationID +int 0 +!= +&& +|| +assert +callsub log1_7 +store 48 +byte 0x151f7c75 +load 48 +itob +concat +log +int 1 +return +main_l13: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +|| +assert +callsub emptyreturnsubroutine_6 +int 1 +return +main_l14: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 22 +txna ApplicationArgs 2 +btoi +store 24 +txna ApplicationArgs 3 +btoi +store 25 +txna ApplicationArgs 4 +btoi +store 27 +txna ApplicationArgs 5 +btoi +store 28 +txna ApplicationArgs 6 +btoi +store 29 +txna ApplicationArgs 7 +btoi +store 30 +txna ApplicationArgs 8 +btoi +store 32 +txna ApplicationArgs 9 +btoi +store 35 +txna ApplicationArgs 10 +btoi +store 36 +txna ApplicationArgs 11 +btoi +store 37 +txna ApplicationArgs 12 +btoi +store 38 +txna ApplicationArgs 13 +btoi +store 40 +txna ApplicationArgs 14 +btoi +store 42 +txna ApplicationArgs 15 +store 46 +load 46 +int 0 +extract_uint64 +store 43 +load 46 +int 8 +extract_uint64 +store 45 +load 22 +load 24 +load 25 +load 27 +load 28 +load 29 +load 30 +load 32 +load 35 +load 36 +load 37 +load 38 +load 40 +load 42 +load 43 +load 45 +callsub alllaidtoargs_5 +store 47 +byte 0x151f7c75 +load 47 +itob +concat +log +int 1 +return +main_l15: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 18 +txna ApplicationArgs 2 +btoi +store 19 +load 18 +load 19 +callsub mod_4 +store 20 +byte 0x151f7c75 +load 20 +itob +concat +log +int 1 +return +main_l16: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 12 +txna ApplicationArgs 2 +btoi +store 15 +load 12 +load 15 +callsub div_3 +store 17 +byte 0x151f7c75 +load 17 +itob +concat +log +int 1 +return +main_l17: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 9 +txna ApplicationArgs 2 +btoi +store 10 +load 9 +load 10 +callsub mul_2 +store 11 +byte 0x151f7c75 +load 11 +itob +concat +log +int 1 +return +main_l18: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 4 +txna ApplicationArgs 2 +btoi +store 5 +load 4 +load 5 +callsub sub_1 +store 8 +byte 0x151f7c75 +load 8 +itob +concat +log +int 1 +return +main_l19: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 0 +txna ApplicationArgs 2 +btoi +store 1 +load 0 +load 1 +callsub add_0 +store 2 +byte 0x151f7c75 +load 2 +itob +concat +log +int 1 +return +main_l20: +txn OnCompletion +int OptIn +== +bnz main_l22 +err +main_l22: +txn ApplicationID +int 0 +!= +assert +byte "optin call" +log +int 1 +return + +// add +add_0: +store 6 +store 3 +load 3 +load 6 ++ +store 7 +load 7 +retsub + +// sub +sub_1: +store 14 +store 13 +load 13 +load 14 +- +store 16 +load 16 +retsub + +// mul +mul_2: +store 23 +store 21 +load 21 +load 23 +* +store 26 +load 26 +retsub + +// div +div_3: +store 33 +store 31 +load 31 +load 33 +/ +store 34 +load 34 +retsub + +// mod +mod_4: +store 41 +store 39 +load 39 +load 41 +% +store 44 +load 44 +retsub + +// all_laid_to_args +alllaidtoargs_5: +store 65 +store 64 +store 63 +store 62 +store 61 +store 60 +store 59 +store 58 +store 57 +store 56 +store 55 +store 54 +store 53 +store 52 +store 51 +store 50 +load 50 +load 51 ++ +load 52 ++ +load 53 ++ +load 54 ++ +load 55 ++ +load 56 ++ +load 57 ++ +load 58 ++ +load 59 ++ +load 60 ++ +load 61 ++ +load 62 ++ +load 63 ++ +load 64 ++ +load 65 ++ +store 66 +load 66 +retsub + +// empty_return_subroutine +emptyreturnsubroutine_6: +byte "appear in both approval and clear state" +log +retsub + +// log_1 +log1_7: +int 1 +store 67 +load 67 +retsub + +// log_creation +logcreation_8: +byte 0x00106c6f6767696e67206372656174696f6e +store 68 +load 68 +retsub \ No newline at end of file diff --git a/tests/teal/router/sim_approval_questionable_8.teal b/tests/teal/router/sim_approval_questionable_8.teal new file mode 100644 index 000000000..00a013082 --- /dev/null +++ b/tests/teal/router/sim_approval_questionable_8.teal @@ -0,0 +1,512 @@ +#pragma version 8 +txn NumAppArgs +int 0 +== +bnz main_l20 +txna ApplicationArgs 0 +method "add(uint64,uint64)uint64" +== +bnz main_l19 +txna ApplicationArgs 0 +method "sub(uint64,uint64)uint64" +== +bnz main_l18 +txna ApplicationArgs 0 +method "mul(uint64,uint64)uint64" +== +bnz main_l17 +txna ApplicationArgs 0 +method "div(uint64,uint64)uint64" +== +bnz main_l16 +txna ApplicationArgs 0 +method "mod(uint64,uint64)uint64" +== +bnz main_l15 +txna ApplicationArgs 0 +method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" +== +bnz main_l14 +txna ApplicationArgs 0 +method "empty_return_subroutine()void" +== +bnz main_l13 +txna ApplicationArgs 0 +method "log_1()uint64" +== +bnz main_l12 +txna ApplicationArgs 0 +method "log_creation()string" +== +bnz main_l11 +err +main_l11: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +== +&& +assert +callsub logcreationcaster_17 +int 1 +return +main_l12: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +txn ApplicationID +int 0 +!= +&& +|| +assert +callsub log1caster_16 +int 1 +return +main_l13: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +|| +assert +callsub emptyreturnsubroutinecaster_15 +int 1 +return +main_l14: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub alllaidtoargscaster_14 +int 1 +return +main_l15: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub modcaster_13 +int 1 +return +main_l16: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub divcaster_12 +int 1 +return +main_l17: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub mulcaster_11 +int 1 +return +main_l18: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub subcaster_10 +int 1 +return +main_l19: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub addcaster_9 +int 1 +return +main_l20: +txn OnCompletion +int OptIn +== +bnz main_l22 +err +main_l22: +txn ApplicationID +int 0 +!= +assert +byte "optin call" +log +int 1 +return + +// add +add_0: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 ++ +frame_bury 0 +retsub + +// sub +sub_1: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +- +frame_bury 0 +retsub + +// mul +mul_2: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +* +frame_bury 0 +retsub + +// div +div_3: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +/ +frame_bury 0 +retsub + +// mod +mod_4: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +% +frame_bury 0 +retsub + +// all_laid_to_args +alllaidtoargs_5: +proto 16 1 +int 0 +frame_dig -16 +frame_dig -15 ++ +frame_dig -14 ++ +frame_dig -13 ++ +frame_dig -12 ++ +frame_dig -11 ++ +frame_dig -10 ++ +frame_dig -9 ++ +frame_dig -8 ++ +frame_dig -7 ++ +frame_dig -6 ++ +frame_dig -5 ++ +frame_dig -4 ++ +frame_dig -3 ++ +frame_dig -2 ++ +frame_dig -1 ++ +frame_bury 0 +retsub + +// empty_return_subroutine +emptyreturnsubroutine_6: +proto 0 0 +byte "appear in both approval and clear state" +log +retsub + +// log_1 +log1_7: +proto 0 1 +int 0 +int 1 +frame_bury 0 +retsub + +// log_creation +logcreation_8: +proto 0 1 +byte "" +byte 0x00106c6f6767696e67206372656174696f6e +frame_bury 0 +retsub + +// add_caster +addcaster_9: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub add_0 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// sub_caster +subcaster_10: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub sub_1 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// mul_caster +mulcaster_11: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub mul_2 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// div_caster +divcaster_12: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub div_3 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// mod_caster +modcaster_13: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub mod_4 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// all_laid_to_args_caster +alllaidtoargscaster_14: +proto 0 0 +int 0 +dupn 16 +byte "" +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +txna ApplicationArgs 3 +btoi +frame_bury 3 +txna ApplicationArgs 4 +btoi +frame_bury 4 +txna ApplicationArgs 5 +btoi +frame_bury 5 +txna ApplicationArgs 6 +btoi +frame_bury 6 +txna ApplicationArgs 7 +btoi +frame_bury 7 +txna ApplicationArgs 8 +btoi +frame_bury 8 +txna ApplicationArgs 9 +btoi +frame_bury 9 +txna ApplicationArgs 10 +btoi +frame_bury 10 +txna ApplicationArgs 11 +btoi +frame_bury 11 +txna ApplicationArgs 12 +btoi +frame_bury 12 +txna ApplicationArgs 13 +btoi +frame_bury 13 +txna ApplicationArgs 14 +btoi +frame_bury 14 +txna ApplicationArgs 15 +frame_bury 17 +frame_dig 17 +int 0 +extract_uint64 +frame_bury 15 +frame_dig 17 +int 8 +extract_uint64 +frame_bury 16 +frame_dig 1 +frame_dig 2 +frame_dig 3 +frame_dig 4 +frame_dig 5 +frame_dig 6 +frame_dig 7 +frame_dig 8 +frame_dig 9 +frame_dig 10 +frame_dig 11 +frame_dig 12 +frame_dig 13 +frame_dig 14 +frame_dig 15 +frame_dig 16 +callsub alllaidtoargs_5 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// empty_return_subroutine_caster +emptyreturnsubroutinecaster_15: +proto 0 0 +callsub emptyreturnsubroutine_6 +retsub + +// log_1_caster +log1caster_16: +proto 0 0 +int 0 +callsub log1_7 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// log_creation_caster +logcreationcaster_17: +proto 0 0 +byte "" +callsub logcreation_8 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +concat +log +retsub \ No newline at end of file diff --git a/tests/teal/router/sim_approval_yacc_6.teal b/tests/teal/router/sim_approval_yacc_6.teal new file mode 100644 index 000000000..063bc1f51 --- /dev/null +++ b/tests/teal/router/sim_approval_yacc_6.teal @@ -0,0 +1,441 @@ +#pragma version 6 +txna ApplicationArgs 0 +method "add(uint64,uint64)uint64" +== +bnz main_l18 +txna ApplicationArgs 0 +method "sub(uint64,uint64)uint64" +== +bnz main_l17 +txna ApplicationArgs 0 +method "mul(uint64,uint64)uint64" +== +bnz main_l16 +txna ApplicationArgs 0 +method "div(uint64,uint64)uint64" +== +bnz main_l15 +txna ApplicationArgs 0 +method "mod(uint64,uint64)uint64" +== +bnz main_l14 +txna ApplicationArgs 0 +method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" +== +bnz main_l13 +txna ApplicationArgs 0 +method "empty_return_subroutine()void" +== +bnz main_l12 +txna ApplicationArgs 0 +method "log_1()uint64" +== +bnz main_l11 +txna ApplicationArgs 0 +method "log_creation()string" +== +bnz main_l10 +err +main_l10: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +== +&& +assert +callsub logcreation_8 +store 49 +byte 0x151f7c75 +load 49 +concat +log +int 1 +return +main_l11: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +txn ApplicationID +int 0 +!= +&& +|| +assert +callsub log1_7 +store 48 +byte 0x151f7c75 +load 48 +itob +concat +log +int 1 +return +main_l12: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +|| +assert +callsub emptyreturnsubroutine_6 +int 1 +return +main_l13: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 22 +txna ApplicationArgs 2 +btoi +store 23 +txna ApplicationArgs 3 +btoi +store 25 +txna ApplicationArgs 4 +btoi +store 27 +txna ApplicationArgs 5 +btoi +store 28 +txna ApplicationArgs 6 +btoi +store 29 +txna ApplicationArgs 7 +btoi +store 31 +txna ApplicationArgs 8 +btoi +store 33 +txna ApplicationArgs 9 +btoi +store 35 +txna ApplicationArgs 10 +btoi +store 36 +txna ApplicationArgs 11 +btoi +store 37 +txna ApplicationArgs 12 +btoi +store 38 +txna ApplicationArgs 13 +btoi +store 39 +txna ApplicationArgs 14 +btoi +store 41 +txna ApplicationArgs 15 +store 46 +load 46 +int 0 +extract_uint64 +store 44 +load 46 +int 8 +extract_uint64 +store 45 +load 22 +load 23 +load 25 +load 27 +load 28 +load 29 +load 31 +load 33 +load 35 +load 36 +load 37 +load 38 +load 39 +load 41 +load 44 +load 45 +callsub alllaidtoargs_5 +store 47 +byte 0x151f7c75 +load 47 +itob +concat +log +int 1 +return +main_l14: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 18 +txna ApplicationArgs 2 +btoi +store 19 +load 18 +load 19 +callsub mod_4 +store 20 +byte 0x151f7c75 +load 20 +itob +concat +log +int 1 +return +main_l15: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 13 +txna ApplicationArgs 2 +btoi +store 14 +load 13 +load 14 +callsub div_3 +store 16 +byte 0x151f7c75 +load 16 +itob +concat +log +int 1 +return +main_l16: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 9 +txna ApplicationArgs 2 +btoi +store 10 +load 9 +load 10 +callsub mul_2 +store 11 +byte 0x151f7c75 +load 11 +itob +concat +log +int 1 +return +main_l17: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 3 +txna ApplicationArgs 2 +btoi +store 6 +load 3 +load 6 +callsub sub_1 +store 8 +byte 0x151f7c75 +load 8 +itob +concat +log +int 1 +return +main_l18: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 0 +txna ApplicationArgs 2 +btoi +store 1 +load 0 +load 1 +callsub add_0 +store 2 +byte 0x151f7c75 +load 2 +itob +concat +log +int 1 +return + +// add +add_0: +store 5 +store 4 +load 4 +load 5 ++ +store 7 +load 7 +retsub + +// sub +sub_1: +store 15 +store 12 +load 12 +load 15 +- +store 17 +load 17 +retsub + +// mul +mul_2: +store 24 +store 21 +load 21 +load 24 +* +store 26 +load 26 +retsub + +// div +div_3: +store 32 +store 30 +load 30 +load 32 +/ +store 34 +load 34 +retsub + +// mod +mod_4: +store 42 +store 40 +load 40 +load 42 +% +store 43 +load 43 +retsub + +// all_laid_to_args +alllaidtoargs_5: +store 65 +store 64 +store 63 +store 62 +store 61 +store 60 +store 59 +store 58 +store 57 +store 56 +store 55 +store 54 +store 53 +store 52 +store 51 +store 50 +load 50 +load 51 ++ +load 52 ++ +load 53 ++ +load 54 ++ +load 55 ++ +load 56 ++ +load 57 ++ +load 58 ++ +load 59 ++ +load 60 ++ +load 61 ++ +load 62 ++ +load 63 ++ +load 64 ++ +load 65 ++ +store 66 +load 66 +retsub + +// empty_return_subroutine +emptyreturnsubroutine_6: +byte "appear in both approval and clear state" +log +retsub + +// log_1 +log1_7: +int 1 +store 67 +load 67 +retsub + +// log_creation +logcreation_8: +byte 0x00106c6f6767696e67206372656174696f6e +store 68 +load 68 +retsub \ No newline at end of file diff --git a/tests/teal/router/sim_approval_yacc_8.teal b/tests/teal/router/sim_approval_yacc_8.teal new file mode 100644 index 000000000..5c5bda6d0 --- /dev/null +++ b/tests/teal/router/sim_approval_yacc_8.teal @@ -0,0 +1,493 @@ +#pragma version 8 +txna ApplicationArgs 0 +method "add(uint64,uint64)uint64" +== +bnz main_l18 +txna ApplicationArgs 0 +method "sub(uint64,uint64)uint64" +== +bnz main_l17 +txna ApplicationArgs 0 +method "mul(uint64,uint64)uint64" +== +bnz main_l16 +txna ApplicationArgs 0 +method "div(uint64,uint64)uint64" +== +bnz main_l15 +txna ApplicationArgs 0 +method "mod(uint64,uint64)uint64" +== +bnz main_l14 +txna ApplicationArgs 0 +method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" +== +bnz main_l13 +txna ApplicationArgs 0 +method "empty_return_subroutine()void" +== +bnz main_l12 +txna ApplicationArgs 0 +method "log_1()uint64" +== +bnz main_l11 +txna ApplicationArgs 0 +method "log_creation()string" +== +bnz main_l10 +err +main_l10: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +== +&& +assert +callsub logcreationcaster_17 +int 1 +return +main_l11: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +txn ApplicationID +int 0 +!= +&& +|| +assert +callsub log1caster_16 +int 1 +return +main_l12: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +|| +assert +callsub emptyreturnsubroutinecaster_15 +int 1 +return +main_l13: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub alllaidtoargscaster_14 +int 1 +return +main_l14: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub modcaster_13 +int 1 +return +main_l15: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub divcaster_12 +int 1 +return +main_l16: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub mulcaster_11 +int 1 +return +main_l17: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub subcaster_10 +int 1 +return +main_l18: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub addcaster_9 +int 1 +return + +// add +add_0: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 ++ +frame_bury 0 +retsub + +// sub +sub_1: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +- +frame_bury 0 +retsub + +// mul +mul_2: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +* +frame_bury 0 +retsub + +// div +div_3: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +/ +frame_bury 0 +retsub + +// mod +mod_4: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +% +frame_bury 0 +retsub + +// all_laid_to_args +alllaidtoargs_5: +proto 16 1 +int 0 +frame_dig -16 +frame_dig -15 ++ +frame_dig -14 ++ +frame_dig -13 ++ +frame_dig -12 ++ +frame_dig -11 ++ +frame_dig -10 ++ +frame_dig -9 ++ +frame_dig -8 ++ +frame_dig -7 ++ +frame_dig -6 ++ +frame_dig -5 ++ +frame_dig -4 ++ +frame_dig -3 ++ +frame_dig -2 ++ +frame_dig -1 ++ +frame_bury 0 +retsub + +// empty_return_subroutine +emptyreturnsubroutine_6: +proto 0 0 +byte "appear in both approval and clear state" +log +retsub + +// log_1 +log1_7: +proto 0 1 +int 0 +int 1 +frame_bury 0 +retsub + +// log_creation +logcreation_8: +proto 0 1 +byte "" +byte 0x00106c6f6767696e67206372656174696f6e +frame_bury 0 +retsub + +// add_caster +addcaster_9: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub add_0 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// sub_caster +subcaster_10: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub sub_1 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// mul_caster +mulcaster_11: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub mul_2 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// div_caster +divcaster_12: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub div_3 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// mod_caster +modcaster_13: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub mod_4 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// all_laid_to_args_caster +alllaidtoargscaster_14: +proto 0 0 +int 0 +dupn 16 +byte "" +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +txna ApplicationArgs 3 +btoi +frame_bury 3 +txna ApplicationArgs 4 +btoi +frame_bury 4 +txna ApplicationArgs 5 +btoi +frame_bury 5 +txna ApplicationArgs 6 +btoi +frame_bury 6 +txna ApplicationArgs 7 +btoi +frame_bury 7 +txna ApplicationArgs 8 +btoi +frame_bury 8 +txna ApplicationArgs 9 +btoi +frame_bury 9 +txna ApplicationArgs 10 +btoi +frame_bury 10 +txna ApplicationArgs 11 +btoi +frame_bury 11 +txna ApplicationArgs 12 +btoi +frame_bury 12 +txna ApplicationArgs 13 +btoi +frame_bury 13 +txna ApplicationArgs 14 +btoi +frame_bury 14 +txna ApplicationArgs 15 +frame_bury 17 +frame_dig 17 +int 0 +extract_uint64 +frame_bury 15 +frame_dig 17 +int 8 +extract_uint64 +frame_bury 16 +frame_dig 1 +frame_dig 2 +frame_dig 3 +frame_dig 4 +frame_dig 5 +frame_dig 6 +frame_dig 7 +frame_dig 8 +frame_dig 9 +frame_dig 10 +frame_dig 11 +frame_dig 12 +frame_dig 13 +frame_dig 14 +frame_dig 15 +frame_dig 16 +callsub alllaidtoargs_5 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// empty_return_subroutine_caster +emptyreturnsubroutinecaster_15: +proto 0 0 +callsub emptyreturnsubroutine_6 +retsub + +// log_1_caster +log1caster_16: +proto 0 0 +int 0 +callsub log1_7 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// log_creation_caster +logcreationcaster_17: +proto 0 0 +byte "" +callsub logcreation_8 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +concat +log +retsub \ No newline at end of file diff --git a/tests/teal/router/sim_clear_questionable_6.teal b/tests/teal/router/sim_clear_questionable_6.teal new file mode 100644 index 000000000..c7de51891 --- /dev/null +++ b/tests/teal/router/sim_clear_questionable_6.teal @@ -0,0 +1,3 @@ +#pragma version 6 +int 1 +return \ No newline at end of file diff --git a/tests/teal/router/sim_clear_questionable_8.teal b/tests/teal/router/sim_clear_questionable_8.teal new file mode 100644 index 000000000..31588a8ec --- /dev/null +++ b/tests/teal/router/sim_clear_questionable_8.teal @@ -0,0 +1,3 @@ +#pragma version 8 +int 1 +return \ No newline at end of file diff --git a/tests/teal/router/sim_clear_yacc_6.teal b/tests/teal/router/sim_clear_yacc_6.teal new file mode 100644 index 000000000..c7de51891 --- /dev/null +++ b/tests/teal/router/sim_clear_yacc_6.teal @@ -0,0 +1,3 @@ +#pragma version 6 +int 1 +return \ No newline at end of file diff --git a/tests/teal/router/sim_clear_yacc_8.teal b/tests/teal/router/sim_clear_yacc_8.teal new file mode 100644 index 000000000..31588a8ec --- /dev/null +++ b/tests/teal/router/sim_clear_yacc_8.teal @@ -0,0 +1,3 @@ +#pragma version 8 +int 1 +return \ No newline at end of file diff --git a/tests/integration/teal/router/yaccFP_approval_v8.teal b/tests/teal/router/yaccFP_approval_v8.teal similarity index 85% rename from tests/integration/teal/router/yaccFP_approval_v8.teal rename to tests/teal/router/yaccFP_approval_v8.teal index 25af706c5..5c5bda6d0 100644 --- a/tests/integration/teal/router/yaccFP_approval_v8.teal +++ b/tests/teal/router/yaccFP_approval_v8.teal @@ -2,57 +2,41 @@ txna ApplicationArgs 0 method "add(uint64,uint64)uint64" == -bnz main_l20 +bnz main_l18 txna ApplicationArgs 0 method "sub(uint64,uint64)uint64" == -bnz main_l19 +bnz main_l17 txna ApplicationArgs 0 method "mul(uint64,uint64)uint64" == -bnz main_l18 +bnz main_l16 txna ApplicationArgs 0 method "div(uint64,uint64)uint64" == -bnz main_l17 +bnz main_l15 txna ApplicationArgs 0 method "mod(uint64,uint64)uint64" == -bnz main_l16 +bnz main_l14 txna ApplicationArgs 0 method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" == -bnz main_l15 +bnz main_l13 txna ApplicationArgs 0 method "empty_return_subroutine()void" == -bnz main_l14 +bnz main_l12 txna ApplicationArgs 0 method "log_1()uint64" == -bnz main_l13 +bnz main_l11 txna ApplicationArgs 0 method "log_creation()string" == -bnz main_l12 -txna ApplicationArgs 0 -method "approve_if_odd(uint32)void" -== -bnz main_l11 +bnz main_l10 err -main_l11: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub approveifoddcaster_19 -int 1 -return -main_l12: +main_l10: txn OnCompletion int NoOp == @@ -61,10 +45,10 @@ int 0 == && assert -callsub logcreationcaster_18 +callsub logcreationcaster_17 int 1 return -main_l13: +main_l11: txn OnCompletion int NoOp == @@ -81,10 +65,10 @@ int 0 && || assert -callsub log1caster_17 +callsub log1caster_16 int 1 return -main_l14: +main_l12: txn OnCompletion int NoOp == @@ -97,10 +81,10 @@ int OptIn == || assert -callsub emptyreturnsubroutinecaster_16 +callsub emptyreturnsubroutinecaster_15 int 1 return -main_l15: +main_l13: txn OnCompletion int NoOp == @@ -109,10 +93,10 @@ int 0 != && assert -callsub alllaidtoargscaster_15 +callsub alllaidtoargscaster_14 int 1 return -main_l16: +main_l14: txn OnCompletion int NoOp == @@ -121,10 +105,10 @@ int 0 != && assert -callsub modcaster_14 +callsub modcaster_13 int 1 return -main_l17: +main_l15: txn OnCompletion int NoOp == @@ -133,10 +117,10 @@ int 0 != && assert -callsub divcaster_13 +callsub divcaster_12 int 1 return -main_l18: +main_l16: txn OnCompletion int NoOp == @@ -145,10 +129,10 @@ int 0 != && assert -callsub mulcaster_12 +callsub mulcaster_11 int 1 return -main_l19: +main_l17: txn OnCompletion int NoOp == @@ -157,10 +141,10 @@ int 0 != && assert -callsub subcaster_11 +callsub subcaster_10 int 1 return -main_l20: +main_l18: txn OnCompletion int NoOp == @@ -169,7 +153,7 @@ int 0 != && assert -callsub addcaster_10 +callsub addcaster_9 int 1 return @@ -284,21 +268,8 @@ byte 0x00106c6f6767696e67206372656174696f6e frame_bury 0 retsub -// approve_if_odd -approveifodd_9: -proto 1 0 -frame_dig -1 -int 2 -% -bnz approveifodd_9_l2 -int 0 -return -approveifodd_9_l2: -int 1 -return - // add_caster -addcaster_10: +addcaster_9: proto 0 0 int 0 dupn 2 @@ -320,7 +291,7 @@ log retsub // sub_caster -subcaster_11: +subcaster_10: proto 0 0 int 0 dupn 2 @@ -342,7 +313,7 @@ log retsub // mul_caster -mulcaster_12: +mulcaster_11: proto 0 0 int 0 dupn 2 @@ -364,7 +335,7 @@ log retsub // div_caster -divcaster_13: +divcaster_12: proto 0 0 int 0 dupn 2 @@ -386,7 +357,7 @@ log retsub // mod_caster -modcaster_14: +modcaster_13: proto 0 0 int 0 dupn 2 @@ -408,7 +379,7 @@ log retsub // all_laid_to_args_caster -alllaidtoargscaster_15: +alllaidtoargscaster_14: proto 0 0 int 0 dupn 16 @@ -491,13 +462,13 @@ log retsub // empty_return_subroutine_caster -emptyreturnsubroutinecaster_16: +emptyreturnsubroutinecaster_15: proto 0 0 callsub emptyreturnsubroutine_6 retsub // log_1_caster -log1caster_17: +log1caster_16: proto 0 0 int 0 callsub log1_7 @@ -510,7 +481,7 @@ log retsub // log_creation_caster -logcreationcaster_18: +logcreationcaster_17: proto 0 0 byte "" callsub logcreation_8 @@ -519,16 +490,4 @@ byte 0x151f7c75 frame_dig 0 concat log -retsub - -// approve_if_odd_caster -approveifoddcaster_19: -proto 0 0 -int 0 -txna ApplicationArgs 1 -int 0 -extract_uint32 -frame_bury 0 -frame_dig 0 -callsub approveifodd_9 retsub \ No newline at end of file diff --git a/tests/integration/teal/router/yaccFP_clear_v8.teal b/tests/teal/router/yaccFP_clear_v8.teal similarity index 80% rename from tests/integration/teal/router/yaccFP_clear_v8.teal rename to tests/teal/router/yaccFP_clear_v8.teal index ba95445f2..31588a8ec 100644 --- a/tests/integration/teal/router/yaccFP_clear_v8.teal +++ b/tests/teal/router/yaccFP_clear_v8.teal @@ -1,3 +1,3 @@ #pragma version 8 -int 0 +int 1 return \ No newline at end of file diff --git a/tests/integration/teal/router/yacc_approval_v6.teal b/tests/teal/router/yacc_approval_v6.teal similarity index 91% rename from tests/integration/teal/router/yacc_approval_v6.teal rename to tests/teal/router/yacc_approval_v6.teal index a314f834a..b36bc397e 100644 --- a/tests/integration/teal/router/yacc_approval_v6.teal +++ b/tests/teal/router/yacc_approval_v6.teal @@ -2,62 +2,41 @@ txna ApplicationArgs 0 method "add(uint64,uint64)uint64" == -bnz main_l20 +bnz main_l18 txna ApplicationArgs 0 method "sub(uint64,uint64)uint64" == -bnz main_l19 +bnz main_l17 txna ApplicationArgs 0 method "mul(uint64,uint64)uint64" == -bnz main_l18 +bnz main_l16 txna ApplicationArgs 0 method "div(uint64,uint64)uint64" == -bnz main_l17 +bnz main_l15 txna ApplicationArgs 0 method "mod(uint64,uint64)uint64" == -bnz main_l16 +bnz main_l14 txna ApplicationArgs 0 method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" == -bnz main_l15 +bnz main_l13 txna ApplicationArgs 0 method "empty_return_subroutine()void" == -bnz main_l14 +bnz main_l12 txna ApplicationArgs 0 method "log_1()uint64" == -bnz main_l13 +bnz main_l11 txna ApplicationArgs 0 method "log_creation()string" == -bnz main_l12 -txna ApplicationArgs 0 -method "approve_if_odd(uint32)void" -== -bnz main_l11 +bnz main_l10 err -main_l11: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -int 0 -extract_uint32 -store 69 -load 69 -callsub approveifodd_9 -int 1 -return -main_l12: +main_l10: txn OnCompletion int NoOp == @@ -74,7 +53,7 @@ concat log int 1 return -main_l13: +main_l11: txn OnCompletion int NoOp == @@ -100,7 +79,7 @@ concat log int 1 return -main_l14: +main_l12: txn OnCompletion int NoOp == @@ -116,7 +95,7 @@ assert callsub emptyreturnsubroutine_6 int 1 return -main_l15: +main_l13: txn OnCompletion int NoOp == @@ -202,7 +181,7 @@ concat log int 1 return -main_l16: +main_l14: txn OnCompletion int NoOp == @@ -228,7 +207,7 @@ concat log int 1 return -main_l17: +main_l15: txn OnCompletion int NoOp == @@ -254,7 +233,7 @@ concat log int 1 return -main_l18: +main_l16: txn OnCompletion int NoOp == @@ -280,7 +259,7 @@ concat log int 1 return -main_l19: +main_l17: txn OnCompletion int NoOp == @@ -306,7 +285,7 @@ concat log int 1 return -main_l20: +main_l18: txn OnCompletion int NoOp == @@ -459,17 +438,4 @@ logcreation_8: byte 0x00106c6f6767696e67206372656174696f6e store 68 load 68 -retsub - -// approve_if_odd -approveifodd_9: -store 70 -load 70 -int 2 -% -bnz approveifodd_9_l2 -int 0 -return -approveifodd_9_l2: -int 1 -return \ No newline at end of file +retsub \ No newline at end of file diff --git a/tests/integration/teal/router/yacc_clear_v6.teal b/tests/teal/router/yacc_clear_v6.teal similarity index 80% rename from tests/integration/teal/router/yacc_clear_v6.teal rename to tests/teal/router/yacc_clear_v6.teal index e6cf44111..c7de51891 100644 --- a/tests/integration/teal/router/yacc_clear_v6.teal +++ b/tests/teal/router/yacc_clear_v6.teal @@ -1,3 +1,3 @@ #pragma version 6 -int 0 +int 1 return \ No newline at end of file From 5f6b798286d855ecb2f2538e0df8d060f1b1a773 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Wed, 1 Feb 2023 22:52:35 -0600 Subject: [PATCH 173/206] lint --- pyteal/compiler/compiler_test.py | 5 +- tests/integration/abi_router_test.py | 2 +- tests/teal/router/sim_approval_yacc_6.teal | 278 ++++++++++----------- 3 files changed, 143 insertions(+), 142 deletions(-) diff --git a/pyteal/compiler/compiler_test.py b/pyteal/compiler/compiler_test.py index c318129cf..202d25d11 100644 --- a/pyteal/compiler/compiler_test.py +++ b/pyteal/compiler/compiler_test.py @@ -2462,7 +2462,8 @@ def append_router_info(rinfo, programs): return routers, sources + def test_router_app(): - # TODO: this test is redundant as router_app_tester is imported and run by + # TODO: this test is redundant as router_app_tester is imported and run by # tests/integration/abi_router_test.py's setup - router_app_tester() \ No newline at end of file + router_app_tester() diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index f54b2687d..9a1892e34 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -13,7 +13,7 @@ BRUTE_FORCE_TERRIBLE_SKIPPING = True NUM_ROUTER_DRYRUNS = 7 -FIXTURES = Path.cwd() / "tests" / "teal" / "router" +FIXTURES = Path.cwd() / "tests" / "teal" / "router" ROUTER_CASES, ROUTER_SOURCES = router_app_tester() diff --git a/tests/teal/router/sim_approval_yacc_6.teal b/tests/teal/router/sim_approval_yacc_6.teal index 063bc1f51..121b3c146 100644 --- a/tests/teal/router/sim_approval_yacc_6.teal +++ b/tests/teal/router/sim_approval_yacc_6.teal @@ -46,9 +46,9 @@ int 0 && assert callsub logcreation_8 -store 49 +store 68 byte 0x151f7c75 -load 49 +load 68 concat log int 1 @@ -71,9 +71,9 @@ int 0 || assert callsub log1_7 -store 48 +store 67 byte 0x151f7c75 -load 48 +load 67 itob concat log @@ -106,76 +106,76 @@ int 0 assert txna ApplicationArgs 1 btoi -store 22 +store 49 txna ApplicationArgs 2 btoi -store 23 +store 50 txna ApplicationArgs 3 btoi -store 25 +store 51 txna ApplicationArgs 4 btoi -store 27 +store 52 txna ApplicationArgs 5 btoi -store 28 +store 53 txna ApplicationArgs 6 btoi -store 29 +store 54 txna ApplicationArgs 7 btoi -store 31 +store 55 txna ApplicationArgs 8 btoi -store 33 +store 56 txna ApplicationArgs 9 btoi -store 35 +store 57 txna ApplicationArgs 10 btoi -store 36 +store 58 txna ApplicationArgs 11 btoi -store 37 +store 59 txna ApplicationArgs 12 btoi -store 38 +store 60 txna ApplicationArgs 13 btoi -store 39 +store 61 txna ApplicationArgs 14 btoi -store 41 +store 62 txna ApplicationArgs 15 -store 46 -load 46 +store 65 +load 65 int 0 extract_uint64 -store 44 -load 46 +store 63 +load 65 int 8 extract_uint64 -store 45 -load 22 -load 23 -load 25 -load 27 -load 28 -load 29 -load 31 -load 33 -load 35 -load 36 -load 37 -load 38 -load 39 -load 41 -load 44 -load 45 +store 64 +load 49 +load 50 +load 51 +load 52 +load 53 +load 54 +load 55 +load 56 +load 57 +load 58 +load 59 +load 60 +load 61 +load 62 +load 63 +load 64 callsub alllaidtoargs_5 -store 47 +store 66 byte 0x151f7c75 -load 47 +load 66 itob concat log @@ -192,16 +192,16 @@ int 0 assert txna ApplicationArgs 1 btoi -store 18 +store 46 txna ApplicationArgs 2 btoi -store 19 -load 18 -load 19 +store 47 +load 46 +load 47 callsub mod_4 -store 20 +store 48 byte 0x151f7c75 -load 20 +load 48 itob concat log @@ -218,16 +218,16 @@ int 0 assert txna ApplicationArgs 1 btoi -store 13 +store 43 txna ApplicationArgs 2 btoi -store 14 -load 13 -load 14 +store 44 +load 43 +load 44 callsub div_3 -store 16 +store 45 byte 0x151f7c75 -load 16 +load 45 itob concat log @@ -244,16 +244,16 @@ int 0 assert txna ApplicationArgs 1 btoi -store 9 +store 40 txna ApplicationArgs 2 btoi -store 10 -load 9 -load 10 +store 41 +load 40 +load 41 callsub mul_2 -store 11 +store 42 byte 0x151f7c75 -load 11 +load 42 itob concat log @@ -270,16 +270,16 @@ int 0 assert txna ApplicationArgs 1 btoi -store 3 +store 37 txna ApplicationArgs 2 btoi -store 6 -load 3 -load 6 +store 38 +load 37 +load 38 callsub sub_1 -store 8 +store 39 byte 0x151f7c75 -load 8 +load 39 itob concat log @@ -296,16 +296,16 @@ int 0 assert txna ApplicationArgs 1 btoi -store 0 +store 34 txna ApplicationArgs 2 btoi -store 1 -load 0 -load 1 +store 35 +load 34 +load 35 callsub add_0 -store 2 +store 36 byte 0x151f7c75 -load 2 +load 36 itob concat log @@ -314,110 +314,110 @@ return // add add_0: -store 5 -store 4 -load 4 -load 5 +store 1 +store 0 +load 0 +load 1 + -store 7 -load 7 +store 2 +load 2 retsub // sub sub_1: -store 15 -store 12 -load 12 -load 15 +store 4 +store 3 +load 3 +load 4 - -store 17 -load 17 +store 5 +load 5 retsub // mul mul_2: -store 24 -store 21 -load 21 -load 24 +store 7 +store 6 +load 6 +load 7 * -store 26 -load 26 +store 8 +load 8 retsub // div div_3: -store 32 -store 30 -load 30 -load 32 +store 10 +store 9 +load 9 +load 10 / -store 34 -load 34 +store 11 +load 11 retsub // mod mod_4: -store 42 -store 40 -load 40 -load 42 +store 13 +store 12 +load 12 +load 13 % -store 43 -load 43 +store 14 +load 14 retsub // all_laid_to_args alllaidtoargs_5: -store 65 -store 64 -store 63 -store 62 -store 61 -store 60 -store 59 -store 58 -store 57 -store 56 -store 55 -store 54 -store 53 -store 52 -store 51 -store 50 -load 50 -load 51 +store 30 +store 29 +store 28 +store 27 +store 26 +store 25 +store 24 +store 23 +store 22 +store 21 +store 20 +store 19 +store 18 +store 17 +store 16 +store 15 +load 15 +load 16 + -load 52 +load 17 + -load 53 +load 18 + -load 54 +load 19 + -load 55 +load 20 + -load 56 +load 21 + -load 57 +load 22 + -load 58 +load 23 + -load 59 +load 24 + -load 60 +load 25 + -load 61 +load 26 + -load 62 +load 27 + -load 63 +load 28 + -load 64 +load 29 + -load 65 +load 30 + -store 66 -load 66 +store 31 +load 31 retsub // empty_return_subroutine @@ -429,13 +429,13 @@ retsub // log_1 log1_7: int 1 -store 67 -load 67 +store 32 +load 32 retsub // log_creation logcreation_8: byte 0x00106c6f6767696e67206372656174696f6e -store 68 -load 68 +store 33 +load 33 retsub \ No newline at end of file From 6090339f2182c61167d0d09dde6d12b3cc24081c Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 2 Feb 2023 20:04:29 -0600 Subject: [PATCH 174/206] unit test for BareCallActions.get_method_config --- pyteal/ast/router_test.py | 31 ++++++++++++++++++++++++++++++- tests/blackbox.py | 4 +++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/pyteal/ast/router_test.py b/pyteal/ast/router_test.py index 9df220edf..2eb1fb937 100644 --- a/pyteal/ast/router_test.py +++ b/pyteal/ast/router_test.py @@ -380,7 +380,7 @@ def test_bare_call_config_clear_state_failure(): assert "Attempt to construct clear state program from bare app call" in str(tie) -def test_bare_call_actions_asdict(): +def test_BareCallActions_asdict(): no_action = pt.OnCompleteAction() del_action = pt.OnCompleteAction(action=pt.Int(1), call_config=pt.CallConfig.ALL) close_action = pt.OnCompleteAction(action=pt.Int(2), call_config=pt.CallConfig.CALL) @@ -409,6 +409,35 @@ def test_bare_call_actions_asdict(): } +def test_BareCallActions_get_method_config(): + from pyteal.ast.router import MethodConfig, CallConfig + + cc_all, cc_call, cc_create = ( + pt.CallConfig.ALL, + pt.CallConfig.CALL, + pt.CallConfig.CREATE, + ) + optin_action = pt.OnCompleteAction(action=pt.Int(1), call_config=cc_all) + noop_action = pt.OnCompleteAction(action=pt.Int(2), call_config=cc_call) + update_action = pt.OnCompleteAction(action=pt.Int(3), call_config=cc_create) + + bca = pt.BareCallActions( + update_application=update_action, + opt_in=optin_action, + no_op=noop_action, + ) + + mc = bca.get_method_config() + assert mc == MethodConfig( + close_out=CallConfig.NEVER, + delete_application=CallConfig.NEVER, + no_op=cc_call, + opt_in=cc_all, + update_application=cc_create, + clear_state=CallConfig.NEVER, + ) + + def test_router_register_method_clear_state_failure(): router = pt.Router("doomedToFail") diff --git a/tests/blackbox.py b/tests/blackbox.py index 808ce6073..fc7b0723f 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -764,7 +764,9 @@ def msg4simulate() -> str: def simulate(stats, is_app_create): tp: TxParams = deepcopy(txn_params) - tp.update(TxParams.for_app(is_app_create=is_app_create, on_complete=oc)) + tp.update_fields( + TxParams.for_app(is_app_create=is_app_create, on_complete=oc) + ) sim_results = sim.run_and_assert( sim_cfg.call_strat, txn_params=tp, msg=msg4simulate() ) From 826b0b0385b513d3282a75537fce7fe3ba3e8224 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 2 Feb 2023 21:04:44 -0600 Subject: [PATCH 175/206] Clean up simulate_and_assert in preperation for negative cases --- tests/blackbox.py | 45 ++++++++++------------------ tests/integration/abi_router_test.py | 5 ++++ 2 files changed, 20 insertions(+), 30 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index fc7b0723f..d41360415 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -567,9 +567,10 @@ def __init__( @classmethod def _validate_predicates(cls, predicates): - assert isinstance( - predicates, dict - ), f"Wrong type for predicates: {type(predicates)}. Please provide: dict[str | None, dict[graviton.DryRunProporty, Any]." + assert isinstance(predicates, dict), ( + f"Wrong type for predicates: {type(predicates)}. Please provide: " + f"dict[str | None, dict[graviton.DryRunProporty, Any]." + ) assert ( predicates @@ -780,39 +781,23 @@ def simulate(stats, is_app_create): ) for meth, meth_cfg in sim_cfg.method_configs.items(): - approve_sim: Simulation | None = None - clear_sim: Simulation | None = None + + def sim_get(teal, model_teal): + return self._get_sim(teal, meth, sim_cfg, model_teal) + + approve_sim = sim_get(sim_cfg.ap_compiled, sim_cfg.model_ap_compiled) + clear_sim = sim_get(sim_cfg.csp_compiled, sim_cfg.model_csp_compiled) + for oc_str, call_cfg in asdict(meth_cfg).items(): oc = as_on_complete(oc_str) sim: Simulation - if oc is OnComplete.ClearStateOC: - if not clear_sim: - clear_sim = self._get_sim( - sim_cfg.csp_compiled, - meth, - sim_cfg, - sim_cfg.model_csp_compiled, - ) - sim = clear_sim - else: - if not approve_sim: - approve_sim = self._get_sim( - sim_cfg.ap_compiled, - meth, - sim_cfg, - sim_cfg.model_ap_compiled, - ) - sim = approve_sim - - is_app_create: bool + sim = clear_sim if oc is OnComplete.ClearStateOC else approve_sim + # weird walrus is_app_create := ... to fill closure of msg4simulate() if call_cfg & CallConfig.CALL: - is_app_create = False - simulate(stats, is_app_create) - + simulate(stats, is_app_create := False) if call_cfg & CallConfig.CREATE: - is_app_create = True - simulate(stats, is_app_create) + simulate(stats, is_app_create := True) return { "sim_cfg": sim_cfg, "stats": stats, diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index 9a1892e34..cef59a20b 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -173,3 +173,8 @@ def msg(): f.write(results["sim_cfg"].ap_compiled) with open(FIXTURES / f"sim_clear_{case}_{version}.teal", "w") as f: f.write(results["sim_cfg"].csp_compiled) + + +@pytest.mark.parametrize("case, version, router", ROUTER_CASES) +def test_abi_router_negative(case, version, router): + pass From 5d37e3912c9c688a57e9d3cd631085394e1e88ba Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Fri, 3 Feb 2023 23:48:24 -0600 Subject: [PATCH 176/206] back to square 2 --- pyteal/ast/router.py | 2 +- tests/blackbox.py | 322 ++++++++++++++------------- tests/integration/abi_router_test.py | 59 +++-- tests/unit/blackbox_test.py | 40 +++- 4 files changed, 239 insertions(+), 184 deletions(-) diff --git a/pyteal/ast/router.py b/pyteal/ast/router.py index e8ca03cbd..35aa275d3 100644 --- a/pyteal/ast/router.py +++ b/pyteal/ast/router.py @@ -844,7 +844,7 @@ def add_method_handler( """ if not isinstance(method_call, ABIReturnSubroutine): raise TealInputError( - "for adding method handler, must be ABIReturnSubroutine" + "for adding method handler, must be ABIReturnSubroutine but method_call is {type(method_call)}" ) method_signature = method_call.method_signature(overriding_name) final_name = overriding_name or method_call.name() diff --git a/tests/blackbox.py b/tests/blackbox.py index d41360415..bd9815b8c 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -1,15 +1,21 @@ -from copy import deepcopy from collections import defaultdict +from copy import deepcopy from dataclasses import dataclass, asdict import json -from typing import Any, Callable, Dict, Sequence, Type, cast +from typing import Any, Callable, Dict, Literal, Sequence, Type, cast import algosdk.abi as sdk_abi from algosdk.transaction import OnComplete from algosdk import v2client from graviton import blackbox -from graviton.abi_strategy import ABIArgsMod, ABICallStrategy, ABIStrategy +from graviton.abi_strategy import ( + ABIArgsMod, + ABICallStrategy, + ABIStrategy, + CallStrategy, + RandomArgLengthCallStrategy, +) from graviton.blackbox import ( DryRunInspector, DryRunExecutor, @@ -51,9 +57,20 @@ Predicates = dict[DRProp, Any] # same as in graviton + +ClearStateCall = Literal["ClearStateCall"] + +# str for methods, None for bare app calls: +CallType = str | None + +# CallType for app calls, ClearStateCall for clear state calls: +RouterCallType = CallType | ClearStateCall + +ABICallConfigs = dict[CallType, MethodConfig] + # key `method_config == None` indicates that the MethodConfig's # should be picked up from the router -CallPredicates = dict[str | None, Predicates] +CallPredicates = dict[RouterCallType, Predicates] # ---- Clients ---- # @@ -462,25 +479,6 @@ def dryrun_one( ) -@dataclass(frozen=True) -class _SimConfig: - version: int - assemble_constants: bool - optimize: OptimizeOptions | None - ap_compiled: str - csp_compiled: str - contract: sdk_abi.Contract - method_configs: dict[str | None, MethodConfig] - call_strat: ABICallStrategy - txn_params: TxParams - model_version: int | None - model_assemble_constants: bool | None - model_optimize: OptimizeOptions | None - model_ap_compiled: str | None - model_csp_compiled: str | None - model_contract: sdk_abi.Contract | None - - class _AutoPathDict(defaultdict): def __init__(self): super().__init__(lambda: _AutoPathDict()) @@ -556,15 +554,59 @@ def __init__( model_router: Router | None = None, algod: v2client.algod.AlgodClient | None = None, ): - self.router: Router = router + self.router: Router = self._validate_router(router) + self.predicates: CallPredicates = self._validate_predicates(predicates) - self.model_router: Router | None = model_router + + self.model_router: Router | None = None + if model_router: + self.model_router = self._validate_router(model_router, kind="Model") + self.algod: v2client.algod.AlgodClient = algod or algod_with_assertion() - self.results: Dict[ + self.auto_path_results: Dict[ str | None, dict[tuple[bool, OnComplete], SimulationResults] ] = _AutoPathDict() + # ---- Validation ---- # + + @classmethod + def _validate_router(cls, router: Router, kind: str = "Base") -> Router: + assert isinstance(router, Router), ( + f"Wrong type for {kind} Router: {type(router)}. Please provide: " f"Router." + ) + cls._validate_method_configs(router.method_configs) + + return router + + @classmethod + def _validate_method_configs(cls, method_configs): + assert isinstance( + method_configs, (dict) + ), f"method_configs '{method_configs}' has type {type(method_configs)} but only 'dict' and 'NoneType' are allowed." + + assert ( + method_configs + ), "make sure to give at least one key/value pair in method_configs" + + for call, meth_config in method_configs.items(): + assert isinstance( + call, CallType + ), f"method_configs dict key '{call}' has type {type(call)} but only str and NoneType are allowed." + cls._validate_single_method_config(call, meth_config) + + @classmethod + def _validate_single_method_config(cls, call, meth_config): + assert isinstance( + meth_config, MethodConfig + ), f"method_configs['{call}'] = has type {type(meth_config)} but only MethodConfig is allowed." + assert ( + not meth_config.is_never() + ), f"method_configs['{call}'] specifies NEVER to be called; for driving the test, each configured method should ACTUALLY be tested." + assert ( + meth_config.clear_state is CallConfig.NEVER + ), f"meth_config's clear_state must be None, but isn't" + @classmethod def _validate_predicates(cls, predicates): assert isinstance(predicates, dict), ( @@ -577,9 +619,17 @@ def _validate_predicates(cls, predicates): ), "Please provide at least one method to call and assert against." for method, preds in predicates.items(): - assert isinstance( - method, (str, type(None)) - ), f"Predicates method '{method}' has type {type(method)} but only 'str' and 'NoneType' are allowed." + assert isinstance(method, (str, type(None), type(ClearStateCall))), ( + f"Predicates method '{method}' has type {type(method)} but only " + "'str' and 'NoneType' and Literal['ClearStateCall'] (== ClearStateCall)" + " are allowed." + ) + if isinstance(method, type(ClearStateCall)): + assert method == ClearStateCall, ( + f"Predicates method '{method}' is not allowed. " + "Only Literal['ClearStateCall'] (== ClearStateCall) " + "is allowed for a Literal." + ) assert ( preds ), f"Every method must provide at least one predicate for assertion but method '{method}' is missing predicates." @@ -593,23 +643,15 @@ def _validate_predicates(cls, predicates): return predicates - def _prep_simulation( + def _validate_simulation( self, - arg_strat_type: Type[ABIStrategy], - abi_args_mod: ABIArgsMod | None, - version: int, - *, - assemble_constants: bool = False, - optimize: OptimizeOptions | None = None, - method_configs: dict[str | None, MethodConfig] | None = None, - num_dryruns: int = 1, - txn_params: TxParams | None = None, - model_version: int | None = None, - model_assemble_constants: bool = False, - model_optimize: OptimizeOptions | None = None, - # TODO: do I need to pass it on to ABICallStrategy() ??? - # handle_selector: bool = True, - ) -> _SimConfig: + arg_strat_type, + abi_args_mod, + method_configs, + num_dryruns, + txn_params, + model_version, + ): assert isinstance(arg_strat_type, type) and issubclass( arg_strat_type, ABIStrategy ), f"arg_strat_type should _BE_ a subtype of ABIStrategy but we have {arg_strat_type} (its type is {type(arg_strat_type)})." @@ -618,43 +660,11 @@ def _prep_simulation( abi_args_mod, (ABIArgsMod, type(None)) ), f"abi_args_mod '{abi_args_mod}' has type {type(abi_args_mod)} but only 'ABIArgsMod' and 'NoneType' are allowed." - ap_compiled, csp_compiled, contract = self.router.compile_program( - version=version, assemble_constants=assemble_constants, optimize=optimize - ) - assert ( - self.router.method_configs - ), f"Base router with name '{self.router.name}' is essentially empty, as compilation results in an empty method_configs." - - assert isinstance( - method_configs, (dict, type(None)) - ), f"method_configs '{method_configs}' has type {type(method_configs)} but only 'dict' and 'NoneType' are allowed." - - if method_configs is None: - method_configs = self.router.method_configs - assert ( - method_configs - ), "if providing explicit method_configs, make sure to give at least one" - - for meth, meth_config in method_configs.items(): - assert isinstance( - meth, (str, type(None)) - ), f"method_configs dict key '{meth}' has type {type(meth)} but only str and NoneType are allowed." - assert isinstance( - meth_config, MethodConfig - ), f"method_configs['{meth}'] = has type {type(meth_config)} but only MethodConfig is allowed." - assert ( - not meth_config.is_never() - ), f"method_configs['{meth}'] specifies NEVER to be called; for driving the test, each configured method should ACTUALLY be tested." + self._validate_method_configs(method_configs) assert ( isinstance(num_dryruns, int) and num_dryruns >= 1 ), f"num_dryruns must be a positive int but is {num_dryruns}." - call_strat: ABICallStrategy = ABICallStrategy( - json.dumps(contract.dictify()), - arg_strat_type, - num_dryruns=num_dryruns, - abi_args_mod=abi_args_mod, - ) assert isinstance( txn_params, (TxParams, type(None)) @@ -665,62 +675,22 @@ def _prep_simulation( model_version is None ), f"model_version '{model_version}' was provided which is nonsensical because model_router was never provided for." - model_ap_compiled: str | None = None - model_csp_compiled: str | None = None - model_contract: sdk_abi.Contract | None = None - if self.model_router: - ( - model_ap_compiled, - model_csp_compiled, - model_contract, - ) = self.model_router.compile_program( - version=cast(int, model_version), - assemble_constants=model_assemble_constants, - optimize=model_optimize, - ) - assert ( - self.model_router.method_configs - ), f"Model router with name '{self.model_router.name}' is essentially empty, as compilation results in an empty method_configs." - - return _SimConfig( - version=version, - assemble_constants=assemble_constants, - optimize=optimize, - ap_compiled=ap_compiled, - csp_compiled=csp_compiled, - contract=contract, - method_configs=method_configs, - call_strat=call_strat, - txn_params=cast(TxParams, txn_params), - model_version=model_version, - model_assemble_constants=model_assemble_constants, - model_optimize=model_optimize, - model_ap_compiled=model_ap_compiled, - model_csp_compiled=model_csp_compiled, - model_contract=model_contract, - ) - - def _get_sim(self, teal, meth, sim_cfg, identities_teal) -> Simulation: - return Simulation( - self.algod, - ExecutionMode.Application, - teal, - self.predicates[meth], - abi_method_signature=sim_cfg.call_strat.method_signature(meth), - # omit_method_selector=False ???? - # validation=True ??? - identities_teal=identities_teal, - ) + @dataclass(frozen=True) + class RouterSimulationResults: + stats: dict + results: dict + approval_simulator: Simulation + clear_simulator: Simulation def simulate_and_assert( self, arg_strat_type: Type[ABIStrategy], abi_args_mod: ABIArgsMod | None, version: int, + call_configs: ABICallConfigs, *, assemble_constants: bool = False, optimize: OptimizeOptions | None = None, - method_configs: dict[str | None, MethodConfig] | None = None, num_dryruns: int = 1, txn_params: TxParams | None = None, model_version: int | None = None, @@ -728,19 +698,46 @@ def simulate_and_assert( model_optimize: OptimizeOptions | None = None, msg: str = "", ) -> dict: - sim_cfg = self._prep_simulation( + # clear_call_config = MethodConfig(clear_state=CallConfig.CALL) + # del call_configs[ClearStateCall] + method_configs = call_configs + + # self._validate_single_method_config(ClearStateCall, clear_call_config) + # TODO: simulate the clear state call as well + + self._validate_simulation( arg_strat_type, abi_args_mod, - version, - assemble_constants=assemble_constants, - optimize=optimize, - method_configs=method_configs, + method_configs, + num_dryruns, + txn_params, + model_version, + ) + + approval_teal, _, contract = self.router.compile_program( + version=version, assemble_constants=assemble_constants, optimize=optimize + ) + + approval_strat = ABICallStrategy( + json.dumps(contract.dictify()), + arg_strat_type, num_dryruns=num_dryruns, - txn_params=txn_params, - model_version=model_version, - model_assemble_constants=model_assemble_constants, - model_optimize=model_optimize, + abi_args_mod=abi_args_mod, ) + + model_approval_teal: str | None = None + model_contract: sdk_abi.Contract | None = None + if self.model_router: + ( + model_approval_teal, + _, + model_contract, + ) = self.model_router.compile_program( + version=cast(int, model_version), + assemble_constants=model_assemble_constants, + optimize=model_optimize, + ) + if not txn_params: txn_params = TxParams() @@ -752,7 +749,8 @@ def simulate_and_assert( ) def msg4simulate() -> str: - return f"""user proviede message={msg} + return f"""user provide message={msg} +call_strat={type(approval_strat)} {meth=} {oc=} {call_cfg=} @@ -763,45 +761,51 @@ def msg4simulate() -> str: {stats["assertions_count"]=} """ - def simulate(stats, is_app_create): + def simulate(call_strat, stats, is_app_create): tp: TxParams = deepcopy(txn_params) tp.update_fields( TxParams.for_app(is_app_create=is_app_create, on_complete=oc) ) - sim_results = sim.run_and_assert( - sim_cfg.call_strat, txn_params=tp, msg=msg4simulate() + sim_results = approve_sim.run_and_assert( + call_strat, txn_params=tp, msg=msg4simulate() ) assert sim_results.succeeded - self.results[meth][(is_app_create, oc)] = sim_results + self.auto_path_results[meth][(is_app_create, oc)] = sim_results stats["method_combo_count"] += 1 - stats["dryrun_count"] += sim_cfg.call_strat.num_dryruns - stats["assertions_count"] += sim_cfg.call_strat.num_dryruns * len( + stats["dryrun_count"] += call_strat.num_dryruns + stats["assertions_count"] += call_strat.num_dryruns * len( self.predicates[meth] ) - for meth, meth_cfg in sim_cfg.method_configs.items(): - - def sim_get(teal, model_teal): - return self._get_sim(teal, meth, sim_cfg, model_teal) - - approve_sim = sim_get(sim_cfg.ap_compiled, sim_cfg.model_ap_compiled) - clear_sim = sim_get(sim_cfg.csp_compiled, sim_cfg.model_csp_compiled) + for meth, meth_cfg in method_configs.items(): + sig = approval_strat.method_signature(meth) + + approve_sim = Simulation( + self.algod, + ExecutionMode.Application, + approval_teal, + self.predicates[meth], + abi_method_signature=sig, + # omit_method_selector=False ???? + # validation=True ??? + identities_teal=model_approval_teal, + ) for oc_str, call_cfg in asdict(meth_cfg).items(): oc = as_on_complete(oc_str) - sim: Simulation - sim = clear_sim if oc is OnComplete.ClearStateOC else approve_sim + # sim: Simulation + # sim = clear_sim if oc is OnComplete.ClearStateOC else approve_sim # weird walrus is_app_create := ... to fill closure of msg4simulate() if call_cfg & CallConfig.CALL: - simulate(stats, is_app_create := False) + simulate(approval_strat, stats, is_app_create := False) if call_cfg & CallConfig.CREATE: - simulate(stats, is_app_create := True) - return { - "sim_cfg": sim_cfg, - "stats": stats, - "results": self.results, - "approval_simulator": approve_sim, - "clear_simulator": clear_sim, - } + simulate(approval_strat, stats, is_app_create := True) + + return self.RouterSimulationResults( + stats=stats, + results=self.auto_path_results, + approval_simulator=approve_sim, + clear_simulator=None, + ) diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index cef59a20b..26c3ad0af 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -1,15 +1,20 @@ import json from pathlib import Path -import pytest +import pytest from graviton.abi_strategy import RandomABIStrategyHalfSized from graviton.blackbox import DryRunEncoder from graviton.invariant import DryRunProperty as DRProp -from pyteal.compiler.compiler_test import router_app_tester import pyteal as pt - -from tests.blackbox import Predicates, RouterSimulation +from pyteal.compiler.compiler_test import router_app_tester +from tests.blackbox import ( + ABICallConfigs, + ClearStateCall, + Predicates, + RouterCallType, + RouterSimulation, +) BRUTE_FORCE_TERRIBLE_SKIPPING = True NUM_ROUTER_DRYRUNS = 7 @@ -30,7 +35,7 @@ # # NOTE: the "yacc" routers will simply ignore the case with method `None` # as they do not have any bare-app-calls -QUESTIONABLE_DRIVER: list[tuple[str | None, pt.MethodConfig, Predicates]] = [ +QUESTIONABLE_DRIVER: list[tuple[RouterCallType, pt.MethodConfig, Predicates]] = [ ( "add", TYPICAL_IAC_OC, @@ -73,7 +78,6 @@ pt.MethodConfig( no_op=pt.CallConfig.CALL, opt_in=pt.CallConfig.ALL, - # clear_state=pt.CallConfig.CALL, ), { DRProp.passed: True, @@ -99,7 +103,7 @@ ( None, pt.MethodConfig( - opt_in=pt.CallConfig.CALL, # clear_state=pt.CallConfig.CALL + opt_in=pt.CallConfig.CALL, ), { DRProp.passed: True, @@ -107,6 +111,14 @@ in (None, DryRunEncoder.hex("optin call")), }, ), + ( + ClearStateCall, + pt.MethodConfig(), # ignored in this case + { + DRProp.passed: True, + DRProp.cost: 1, + }, + ), ] YACC_DRIVER = [case for case in QUESTIONABLE_DRIVER if case[0]] @@ -114,12 +126,13 @@ DRIVERS = {"questionable": QUESTIONABLE_DRIVER, "yacc": YACC_DRIVER} -def split_driver2predicates_methconfigs(driver): +def split_driver2predicates_methconfigs(driver) -> tuple[Predicates, ABICallConfigs]: predicates = {} methconfigs = {} for meth, meth_config, predicate in driver: predicates[meth] = predicate - methconfigs[meth] = meth_config + if meth != ClearStateCall: + methconfigs[meth] = meth_config return predicates, methconfigs @@ -150,29 +163,43 @@ def msg(): RandomABIStrategyHalfSized, abi_args_mod=None, version=version, + call_configs=methconfigs, num_dryruns=NUM_ROUTER_DRYRUNS, msg=msg(), ) # won't even get here if there was an error, but some extra sanity checks: - assert (sim_results := results["results"]) and all( + assert (sim_results := results.results) and all( sim.succeeded for meth in sim_results.values() for sim in meth.values() ) - print(json.dumps(stats := results["stats"], indent=2)) + print("stats:", json.dumps(stats := results.stats, indent=2)) assert stats and all(stats.values()) + def deepstr(d): + if isinstance(d, dict): + return {str(k): deepstr(v) for k, v in d.items()} + return d + + print( + "results:", + json.dumps(deepstr(sim_results), indent=2, default=str), + ) + # wow!!! these fail because of differing scratch slot assignments if BRUTE_FORCE_TERRIBLE_SKIPPING: pass else: assert pregen_approval == results["approval_simulator"].simulate_dre.program - assert pregen_clear == results["clear_simulator"].simulate_dre.program - with open(FIXTURES / f"sim_approval_{case}_{version}.teal", "w") as f: - f.write(results["sim_cfg"].ap_compiled) - with open(FIXTURES / f"sim_clear_{case}_{version}.teal", "w") as f: - f.write(results["sim_cfg"].csp_compiled) + # TODO: uncomment the following when ready + # assert pregen_clear == results["clear_simulator"].simulate_dre.program + + # TODO: uncomment eventually ... + # with open(FIXTURES / f"sim_approval_{case}_{version}.teal", "w") as f: + # f.write(results["sim_cfg"].ap_compiled) + # with open(FIXTURES / f"sim_clear_{case}_{version}.teal", "w") as f: + # f.write(results["sim_cfg"].csp_compiled) @pytest.mark.parametrize("case, version, router", ROUTER_CASES) diff --git a/tests/unit/blackbox_test.py b/tests/unit/blackbox_test.py index f032c0b71..acd6680cd 100644 --- a/tests/unit/blackbox_test.py +++ b/tests/unit/blackbox_test.py @@ -293,13 +293,20 @@ def failing_RouterSimulation(router, model_router, predicates, algod, err_msg): def test_RouterSimulation_init(): - router = MagicMock(spec=pt.Router) - model_router = MagicMock(spec=pt.Router) - assert router != model_router - + router = "not a router" + model_router = "not a router either" predicates = "totally unchecked at init" algod = MagicMock(spec=AlgodClient) + # many paths to misery: + err_msg = "Wrong type for Base Router: . Please provide: Router." + failing_RouterSimulation(router, model_router, predicates, algod, err_msg) + + router = pt.Router("test_router") + err_msg = "make sure to give at least one key/value pair in method_configs" + failing_RouterSimulation(router, model_router, predicates, algod, err_msg) + + router.add_method_handler(pt.ABIReturnSubroutine(lambda : pt.Int(1)), overriding_name="foo") err_msg = "Wrong type for predicates: . Please provide: dict[str | None, dict[graviton.DryRunProporty, Any]." failing_RouterSimulation(router, model_router, predicates, algod, err_msg) @@ -308,7 +315,11 @@ def test_RouterSimulation_init(): failing_RouterSimulation(router, model_router, predicates, algod, err_msg) predicates = {3: "blah"} - err_msg = "Predicates method '3' has type but only 'str' and 'NoneType' are allowed." + err_msg = "Predicates method '3' has type but only 'str' and 'NoneType' and Literal['ClearStateCall'] (== ClearStateCall) are allowed." + failing_RouterSimulation(router, model_router, predicates, algod, err_msg) + + predicates = {Literal[42]: "blah"} + err_msg = "Predicates method 'typing.Literal[42]' is not allowed. Only Literal['ClearStateCall'] (== ClearStateCall) is allowed for a Literal." failing_RouterSimulation(router, model_router, predicates, algod, err_msg) predicates = {"bar": {DRProp.passed: True}, "foo": {}} @@ -324,8 +335,21 @@ def test_RouterSimulation_init(): failing_RouterSimulation(router, model_router, predicates, algod, err_msg) predicates = {"bar": {DRProp.passed: True}, "foo": {DRProp.budgetAdded: 45}} + err_msg = "Wrong type for Model Router: . Please provide: Router." + failing_RouterSimulation(router, model_router, predicates, algod, err_msg) + + model_router = pt.Router("test_router") + err_msg = "make sure to give at least one key/value pair in method_configs" + failing_RouterSimulation(router, model_router, predicates, algod, err_msg) + + # Finally, two happy paths + model_router.add_method_handler(pt.ABIReturnSubroutine(lambda : pt.Int(1)), overriding_name="foo") successful_RouterSimulation(router, model_router, predicates, algod) + model_router = None + successful_RouterSimulation(router, model_router, predicates, algod) + + def failing_prep_simulate( rsim, @@ -702,7 +726,7 @@ def test_prep_simulation(): model_version = 8 # FINALLY FINALLY FINALLY FIXED # OK! we should be GTG - sim_cfg = rsim._prep_simulation( + sim_cfg = rsim._prep_simulation_borked( arg_strat_type, abi_args_mod, version, @@ -719,7 +743,7 @@ def test_prep_simulation(): assert sim_cfg.assemble_constants == assemble_constants assert sim_cfg.optimize == optimize - assert sim_cfg.ap_compiled + assert sim_cfg.teal assert sim_cfg.csp_compiled assert sim_cfg.contract @@ -734,6 +758,6 @@ def test_prep_simulation(): assert sim_cfg.model_assemble_constants == model_assemble_constants assert sim_cfg.model_optimize == model_optimize - assert sim_cfg.model_ap_compiled + assert sim_cfg.model_teal assert sim_cfg.model_csp_compiled assert sim_cfg.model_contract From ed6ca7393e31db67de4233d8a1e4847ca3de8bbd Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Sat, 4 Feb 2023 10:12:09 -0600 Subject: [PATCH 177/206] better stats --- tests/blackbox.py | 17 ++++++++--------- tests/integration/abi_router_test.py | 21 ++++++++++++--------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index bd9815b8c..8e6bc45a0 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -741,12 +741,8 @@ def simulate_and_assert( if not txn_params: txn_params = TxParams() - stats = dict( - name=self.router.name, - method_combo_count=0, - dryrun_count=0, - assertions_count=0, - ) + stats = defaultdict(int) + stats["name"] = self.router.name def msg4simulate() -> str: return f"""user provide message={msg} @@ -761,7 +757,9 @@ def msg4simulate() -> str: {stats["assertions_count"]=} """ - def simulate(call_strat, stats, is_app_create): + def simulate( + meth: CallType, call_strat: ABICallStrategy, stats: defaultdict, is_app_create: bool + ) -> None: tp: TxParams = deepcopy(txn_params) tp.update_fields( TxParams.for_app(is_app_create=is_app_create, on_complete=oc) @@ -772,6 +770,7 @@ def simulate(call_strat, stats, is_app_create): assert sim_results.succeeded self.auto_path_results[meth][(is_app_create, oc)] = sim_results + stats[meth] += call_strat.num_dryruns stats["method_combo_count"] += 1 stats["dryrun_count"] += call_strat.num_dryruns stats["assertions_count"] += call_strat.num_dryruns * len( @@ -799,9 +798,9 @@ def simulate(call_strat, stats, is_app_create): # weird walrus is_app_create := ... to fill closure of msg4simulate() if call_cfg & CallConfig.CALL: - simulate(approval_strat, stats, is_app_create := False) + simulate(meth, approval_strat, stats, is_app_create := False) if call_cfg & CallConfig.CREATE: - simulate(approval_strat, stats, is_app_create := True) + simulate(meth, approval_strat, stats, is_app_create := True) return self.RouterSimulationResults( stats=stats, diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index 26c3ad0af..bf677da2f 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -173,18 +173,21 @@ def msg(): sim.succeeded for meth in sim_results.values() for sim in meth.values() ) - print("stats:", json.dumps(stats := results.stats, indent=2)) + print("\nstats:", json.dumps(stats := results.stats, indent=2)) assert stats and all(stats.values()) - def deepstr(d): - if isinstance(d, dict): - return {str(k): deepstr(v) for k, v in d.items()} - return d + if want_to_keep_annoying_details := False: - print( - "results:", - json.dumps(deepstr(sim_results), indent=2, default=str), - ) + def deepstr(d): + if isinstance(d, dict): + return {str(k): deepstr(v) for k, v in d.items()} + return d + + print( + "results:", + json.dumps(deepstr(sim_results), indent=2, default=str), + ) + print(f"{want_to_keep_annoying_details=}") # wow!!! these fail because of differing scratch slot assignments if BRUTE_FORCE_TERRIBLE_SKIPPING: From da8672a5e874def24b4eeb80bc24d52892511720 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Sat, 4 Feb 2023 23:24:15 -0600 Subject: [PATCH 178/206] passing positive with clear program --- tests/blackbox.py | 121 ++++++++++++++++++--------- tests/integration/abi_router_test.py | 17 ++-- 2 files changed, 89 insertions(+), 49 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index 8e6bc45a0..e2eb9f8e1 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -13,7 +13,6 @@ ABIArgsMod, ABICallStrategy, ABIStrategy, - CallStrategy, RandomArgLengthCallStrategy, ) from graviton.blackbox import ( @@ -504,6 +503,8 @@ def as_on_complete(oc_str: str) -> OnComplete: class RouterSimulation: """ + TODO: the following is out of date!!! + Lifecycle of a RouterSimulation 1. Creation (__init__ method): @@ -645,20 +646,24 @@ def _validate_predicates(cls, predicates): def _validate_simulation( self, - arg_strat_type, - abi_args_mod, + approval_args_strat_type, + clear_args_strat_type, + approval_abi_args_mod, method_configs, num_dryruns, txn_params, model_version, ): - assert isinstance(arg_strat_type, type) and issubclass( - arg_strat_type, ABIStrategy - ), f"arg_strat_type should _BE_ a subtype of ABIStrategy but we have {arg_strat_type} (its type is {type(arg_strat_type)})." + assert isinstance(approval_args_strat_type, type) and issubclass( + approval_args_strat_type, ABIStrategy + ), f"approval_args_strat_type should _BE_ a subtype of ABIStrategy but we have {approval_args_strat_type} (its type is {type(approval_args_strat_type)})." + assert isinstance(clear_args_strat_type, type) and issubclass( + clear_args_strat_type, ABIStrategy + ), f"clear_args_strat_type should _BE_ a subtype of ABIStrategy but we have {clear_args_strat_type} (its type is {type(clear_args_strat_type)})." assert isinstance( - abi_args_mod, (ABIArgsMod, type(None)) - ), f"abi_args_mod '{abi_args_mod}' has type {type(abi_args_mod)} but only 'ABIArgsMod' and 'NoneType' are allowed." + approval_abi_args_mod, (ABIArgsMod, type(None)) + ), f"approval_abi_args_mod '{approval_abi_args_mod}' has type {type(approval_abi_args_mod)} but only 'ABIArgsMod' and 'NoneType' are allowed." self._validate_method_configs(method_configs) @@ -684,10 +689,11 @@ class RouterSimulationResults: def simulate_and_assert( self, - arg_strat_type: Type[ABIStrategy], - abi_args_mod: ABIArgsMod | None, + approval_args_strat_type: Type[ABIStrategy], + clear_args_strat_type: Type[ABIStrategy], + approval_abi_args_mod: ABIArgsMod | None, version: int, - call_configs: ABICallConfigs, + method_configs: ABICallConfigs, *, assemble_constants: bool = False, optimize: OptimizeOptions | None = None, @@ -698,40 +704,27 @@ def simulate_and_assert( model_optimize: OptimizeOptions | None = None, msg: str = "", ) -> dict: - # clear_call_config = MethodConfig(clear_state=CallConfig.CALL) - # del call_configs[ClearStateCall] - method_configs = call_configs - - # self._validate_single_method_config(ClearStateCall, clear_call_config) - # TODO: simulate the clear state call as well - self._validate_simulation( - arg_strat_type, - abi_args_mod, + approval_args_strat_type, + clear_args_strat_type, + approval_abi_args_mod, method_configs, num_dryruns, txn_params, model_version, ) - approval_teal, _, contract = self.router.compile_program( + # --- Compile Programs --- # + approval_teal, clear_teal, contract = self.router.compile_program( version=version, assemble_constants=assemble_constants, optimize=optimize ) - - approval_strat = ABICallStrategy( - json.dumps(contract.dictify()), - arg_strat_type, - num_dryruns=num_dryruns, - abi_args_mod=abi_args_mod, - ) - model_approval_teal: str | None = None - model_contract: sdk_abi.Contract | None = None + model_clear_teal: str | None = None if self.model_router: ( model_approval_teal, + model_clear_teal, _, - model_contract, ) = self.model_router.compile_program( version=cast(int, model_version), assemble_constants=model_assemble_constants, @@ -744,6 +737,8 @@ def simulate_and_assert( stats = defaultdict(int) stats["name"] = self.router.name + # --- setup reporter --- # + def msg4simulate() -> str: return f"""user provide message={msg} call_strat={type(approval_strat)} @@ -757,8 +752,19 @@ def msg4simulate() -> str: {stats["assertions_count"]=} """ - def simulate( - meth: CallType, call_strat: ABICallStrategy, stats: defaultdict, is_app_create: bool + # ---- APPROVAL PROGRAM SIMULATION ---- # + approval_strat = ABICallStrategy( + json.dumps(contract.dictify()), + approval_args_strat_type, + num_dryruns=num_dryruns, + abi_args_mod=approval_abi_args_mod, + ) + + def simulate_approval( + meth: CallType, + call_strat: ABICallStrategy, + stats: defaultdict, + is_app_create: bool, ) -> None: tp: TxParams = deepcopy(txn_params) tp.update_fields( @@ -777,6 +783,7 @@ def simulate( self.predicates[meth] ) + double_check_at_least_one_method = False for meth, meth_cfg in method_configs.items(): sig = approval_strat.method_signature(meth) @@ -786,25 +793,59 @@ def simulate( approval_teal, self.predicates[meth], abi_method_signature=sig, - # omit_method_selector=False ???? - # validation=True ??? identities_teal=model_approval_teal, ) for oc_str, call_cfg in asdict(meth_cfg).items(): oc = as_on_complete(oc_str) - # sim: Simulation - # sim = clear_sim if oc is OnComplete.ClearStateOC else approve_sim # weird walrus is_app_create := ... to fill closure of msg4simulate() if call_cfg & CallConfig.CALL: - simulate(meth, approval_strat, stats, is_app_create := False) + double_check_at_least_one_method = True + simulate_approval( + meth, approval_strat, stats, is_app_create := False + ) if call_cfg & CallConfig.CREATE: - simulate(meth, approval_strat, stats, is_app_create := True) + double_check_at_least_one_method = True + simulate_approval( + meth, approval_strat, stats, is_app_create := True + ) + assert double_check_at_least_one_method, "no method was simulated" + + # ---- CLEAR PROGRAM SIMULATION ---- # + clear_strat = RandomArgLengthCallStrategy( + clear_args_strat_type, + max_args=2, + num_dryruns=num_dryruns, + min_args=0, + type_for_args=sdk_abi.ABIType.from_string("byte[8]"), + ) + + meth = ClearStateCall + is_app_create = False + oc = OnComplete.ClearStateOC + clear_sim = Simulation( + self.algod, + ExecutionMode.Application, + clear_teal, + self.predicates[meth], + identities_teal=model_clear_teal, + ) + + # ---- Summary Statistics ---- # + + sim_results = clear_sim.run_and_assert(clear_strat, msg=msg4simulate()) + assert sim_results.succeeded + self.auto_path_results[meth][(is_app_create, oc)] = sim_results + + stats[str(meth)] += num_dryruns + stats["method_combo_count"] += 1 + stats["dryrun_count"] += num_dryruns + stats["assertions_count"] += num_dryruns return self.RouterSimulationResults( stats=stats, results=self.auto_path_results, approval_simulator=approve_sim, - clear_simulator=None, + clear_simulator=clear_sim, ) diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index bf677da2f..f21892681 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -2,7 +2,7 @@ from pathlib import Path import pytest -from graviton.abi_strategy import RandomABIStrategyHalfSized +from graviton.abi_strategy import RandomABIStrategy, RandomABIStrategyHalfSized from graviton.blackbox import DryRunEncoder from graviton.invariant import DryRunProperty as DRProp @@ -116,7 +116,7 @@ pt.MethodConfig(), # ignored in this case { DRProp.passed: True, - DRProp.cost: 1, + DRProp.cost: 2, }, ), ] @@ -160,10 +160,11 @@ def msg(): {router.name=}""" results = rsim.simulate_and_assert( - RandomABIStrategyHalfSized, - abi_args_mod=None, + approval_args_strat_type=RandomABIStrategyHalfSized, + clear_args_strat_type=RandomABIStrategy, + approval_abi_args_mod=None, version=version, - call_configs=methconfigs, + method_configs=methconfigs, num_dryruns=NUM_ROUTER_DRYRUNS, msg=msg(), ) @@ -193,10 +194,8 @@ def deepstr(d): if BRUTE_FORCE_TERRIBLE_SKIPPING: pass else: - assert pregen_approval == results["approval_simulator"].simulate_dre.program - - # TODO: uncomment the following when ready - # assert pregen_clear == results["clear_simulator"].simulate_dre.program + assert pregen_clear == results.clear_simulator.simulate_dre.program + assert pregen_approval == results.approval_simulator.simulate_dre.program # TODO: uncomment eventually ... # with open(FIXTURES / f"sim_approval_{case}_{version}.teal", "w") as f: From a33f1deabbfcedecac034c19e5ff016c497a5d8c Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Sun, 5 Feb 2023 14:36:13 -0600 Subject: [PATCH 179/206] full validation coverage --- tests/blackbox.py | 50 +++++++++++++++++++++------- tests/integration/abi_router_test.py | 3 ++ 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index e2eb9f8e1..77ff840ee 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -649,10 +649,12 @@ def _validate_simulation( approval_args_strat_type, clear_args_strat_type, approval_abi_args_mod, - method_configs, num_dryruns, txn_params, model_version, + method_configs, + contract, + model_contract, ): assert isinstance(approval_args_strat_type, type) and issubclass( approval_args_strat_type, ABIStrategy @@ -667,6 +669,13 @@ def _validate_simulation( self._validate_method_configs(method_configs) + self._validate_meths_in_contract(method_configs, contract) + + if model_contract: + self._validate_meths_in_contract( + method_configs, model_contract, router_prefix="model" + ) + assert ( isinstance(num_dryruns, int) and num_dryruns >= 1 ), f"num_dryruns must be a positive int but is {num_dryruns}." @@ -680,6 +689,19 @@ def _validate_simulation( model_version is None ), f"model_version '{model_version}' was provided which is nonsensical because model_router was never provided for." + def _validate_meths_in_contract( + self, method_configs, contract, router_prefix="base" + ): + for meth in method_configs: + if meth is None: + continue + try: + contract.get_method_by_name(meth) + except KeyError: + raise ValueError( + f"method_configs has a method '{meth}' missing from {router_prefix}-Router's contract." + ) + @dataclass(frozen=True) class RouterSimulationResults: stats: dict @@ -704,33 +726,37 @@ def simulate_and_assert( model_optimize: OptimizeOptions | None = None, msg: str = "", ) -> dict: - self._validate_simulation( - approval_args_strat_type, - clear_args_strat_type, - approval_abi_args_mod, - method_configs, - num_dryruns, - txn_params, - model_version, - ) - # --- Compile Programs --- # approval_teal, clear_teal, contract = self.router.compile_program( version=version, assemble_constants=assemble_constants, optimize=optimize ) + model_approval_teal: str | None = None model_clear_teal: str | None = None + model_contract: sdk_abi.Contract | None = None if self.model_router: ( model_approval_teal, model_clear_teal, - _, + model_contract, ) = self.model_router.compile_program( version=cast(int, model_version), assemble_constants=model_assemble_constants, optimize=model_optimize, ) + self._validate_simulation( + approval_args_strat_type, + clear_args_strat_type, + approval_abi_args_mod, + num_dryruns, + txn_params, + model_version, + method_configs, + contract, + model_contract, + ) + if not txn_params: txn_params = TxParams() diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index f21892681..b740e9c62 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -150,7 +150,10 @@ def test_abi_router_positive(case, version, router): driver = DRIVERS[case] predicates, methconfigs = split_driver2predicates_methconfigs(driver) + + # assert FULL coverage: assert methconfigs == router.method_configs + rsim = RouterSimulation(router, predicates) def msg(): From 6ffe14b2f4c565670c09d70aaa43e09328644b15 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Sun, 5 Feb 2023 15:12:39 -0600 Subject: [PATCH 180/206] cleanup --- tests/blackbox.py | 61 +++++++++++++++---------------------- tests/unit/blackbox_test.py | 9 ++++-- 2 files changed, 30 insertions(+), 40 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index 77ff840ee..375e3f5ab 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -606,7 +606,7 @@ def _validate_single_method_config(cls, call, meth_config): ), f"method_configs['{call}'] specifies NEVER to be called; for driving the test, each configured method should ACTUALLY be tested." assert ( meth_config.clear_state is CallConfig.NEVER - ), f"meth_config's clear_state must be None, but isn't" + ), "meth_config's clear_state must be None, but isn't" @classmethod def _validate_predicates(cls, predicates): @@ -763,7 +763,7 @@ def simulate_and_assert( stats = defaultdict(int) stats["name"] = self.router.name - # --- setup reporter --- # + # --- setup reporter and stats --- # def msg4simulate() -> str: return f"""user provide message={msg} @@ -778,6 +778,12 @@ def msg4simulate() -> str: {stats["assertions_count"]=} """ + def update_stats(meth, num_preds): + stats[str(meth)] += num_dryruns + stats["method_combo_count"] += 1 + stats["dryrun_count"] += num_dryruns + stats["assertions_count"] += num_dryruns * num_preds + # ---- APPROVAL PROGRAM SIMULATION ---- # approval_strat = ABICallStrategy( json.dumps(contract.dictify()), @@ -785,30 +791,6 @@ def msg4simulate() -> str: num_dryruns=num_dryruns, abi_args_mod=approval_abi_args_mod, ) - - def simulate_approval( - meth: CallType, - call_strat: ABICallStrategy, - stats: defaultdict, - is_app_create: bool, - ) -> None: - tp: TxParams = deepcopy(txn_params) - tp.update_fields( - TxParams.for_app(is_app_create=is_app_create, on_complete=oc) - ) - sim_results = approve_sim.run_and_assert( - call_strat, txn_params=tp, msg=msg4simulate() - ) - assert sim_results.succeeded - self.auto_path_results[meth][(is_app_create, oc)] = sim_results - - stats[meth] += call_strat.num_dryruns - stats["method_combo_count"] += 1 - stats["dryrun_count"] += call_strat.num_dryruns - stats["assertions_count"] += call_strat.num_dryruns * len( - self.predicates[meth] - ) - double_check_at_least_one_method = False for meth, meth_cfg in method_configs.items(): sig = approval_strat.method_signature(meth) @@ -825,17 +807,26 @@ def simulate_approval( for oc_str, call_cfg in asdict(meth_cfg).items(): oc = as_on_complete(oc_str) + def simulate_approval(on_create): + tp: TxParams = deepcopy(txn_params) + tp.update_fields( + TxParams.for_app(is_app_create=on_create, on_complete=oc) + ) + sim_results = approve_sim.run_and_assert( + approval_strat, txn_params=tp, msg=msg4simulate() + ) + assert sim_results.succeeded + self.auto_path_results[meth][(on_create, oc)] = sim_results + update_stats(meth, len(self.predicates[meth])) + # weird walrus is_app_create := ... to fill closure of msg4simulate() if call_cfg & CallConfig.CALL: double_check_at_least_one_method = True - simulate_approval( - meth, approval_strat, stats, is_app_create := False - ) + simulate_approval(is_app_create := False) + if call_cfg & CallConfig.CREATE: double_check_at_least_one_method = True - simulate_approval( - meth, approval_strat, stats, is_app_create := True - ) + simulate_approval(is_app_create := True) assert double_check_at_least_one_method, "no method was simulated" # ---- CLEAR PROGRAM SIMULATION ---- # @@ -863,11 +854,7 @@ def simulate_approval( sim_results = clear_sim.run_and_assert(clear_strat, msg=msg4simulate()) assert sim_results.succeeded self.auto_path_results[meth][(is_app_create, oc)] = sim_results - - stats[str(meth)] += num_dryruns - stats["method_combo_count"] += 1 - stats["dryrun_count"] += num_dryruns - stats["assertions_count"] += num_dryruns + update_stats(meth, len(self.predicates[meth])) return self.RouterSimulationResults( stats=stats, diff --git a/tests/unit/blackbox_test.py b/tests/unit/blackbox_test.py index acd6680cd..978661a96 100644 --- a/tests/unit/blackbox_test.py +++ b/tests/unit/blackbox_test.py @@ -306,7 +306,9 @@ def test_RouterSimulation_init(): err_msg = "make sure to give at least one key/value pair in method_configs" failing_RouterSimulation(router, model_router, predicates, algod, err_msg) - router.add_method_handler(pt.ABIReturnSubroutine(lambda : pt.Int(1)), overriding_name="foo") + router.add_method_handler( + pt.ABIReturnSubroutine(lambda: pt.Int(1)), overriding_name="foo" + ) err_msg = "Wrong type for predicates: . Please provide: dict[str | None, dict[graviton.DryRunProporty, Any]." failing_RouterSimulation(router, model_router, predicates, algod, err_msg) @@ -343,14 +345,15 @@ def test_RouterSimulation_init(): failing_RouterSimulation(router, model_router, predicates, algod, err_msg) # Finally, two happy paths - model_router.add_method_handler(pt.ABIReturnSubroutine(lambda : pt.Int(1)), overriding_name="foo") + model_router.add_method_handler( + pt.ABIReturnSubroutine(lambda: pt.Int(1)), overriding_name="foo" + ) successful_RouterSimulation(router, model_router, predicates, algod) model_router = None successful_RouterSimulation(router, model_router, predicates, algod) - def failing_prep_simulate( rsim, arg_strat_type, From 628d49ffd7fa423e1c2eccde7868fde2f449224c Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Sun, 5 Feb 2023 15:53:04 -0600 Subject: [PATCH 181/206] lint --- tests/blackbox.py | 28 +++++++++++++++------------- tests/integration/abi_router_test.py | 6 +++--- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index 375e3f5ab..4a24a8c2d 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -2,7 +2,7 @@ from copy import deepcopy from dataclasses import dataclass, asdict import json -from typing import Any, Callable, Dict, Literal, Sequence, Type, cast +from typing import Any, Callable, Dict, Final, Literal, Sequence, Type, cast import algosdk.abi as sdk_abi from algosdk.transaction import OnComplete @@ -57,13 +57,14 @@ Predicates = dict[DRProp, Any] # same as in graviton -ClearStateCall = Literal["ClearStateCall"] +CLEAR_STATE_CALL: Final[str] = "ClearStateCall" +ClearStateCallType = Literal["ClearStateCall"] # str for methods, None for bare app calls: CallType = str | None -# CallType for app calls, ClearStateCall for clear state calls: -RouterCallType = CallType | ClearStateCall +# CallType for app calls, CLEAR_STATE_CALL for clear state calls: +RouterCallType = CallType | ClearStateCallType # type: ignore ABICallConfigs = dict[CallType, MethodConfig] @@ -591,7 +592,7 @@ def _validate_method_configs(cls, method_configs): ), "make sure to give at least one key/value pair in method_configs" for call, meth_config in method_configs.items(): - assert isinstance( + assert isinstance( # type: ignore call, CallType ), f"method_configs dict key '{call}' has type {type(call)} but only str and NoneType are allowed." cls._validate_single_method_config(call, meth_config) @@ -620,13 +621,13 @@ def _validate_predicates(cls, predicates): ), "Please provide at least one method to call and assert against." for method, preds in predicates.items(): - assert isinstance(method, (str, type(None), type(ClearStateCall))), ( + assert isinstance(method, (str, type(None), type(ClearStateCallType))), ( f"Predicates method '{method}' has type {type(method)} but only " "'str' and 'NoneType' and Literal['ClearStateCall'] (== ClearStateCall)" " are allowed." ) - if isinstance(method, type(ClearStateCall)): - assert method == ClearStateCall, ( + if isinstance(method, type(ClearStateCallType)): + assert method == ClearStateCallType, ( f"Predicates method '{method}' is not allowed. " "Only Literal['ClearStateCall'] (== ClearStateCall) " "is allowed for a Literal." @@ -704,7 +705,7 @@ def _validate_meths_in_contract( @dataclass(frozen=True) class RouterSimulationResults: - stats: dict + stats: dict[str, Any] results: dict approval_simulator: Simulation clear_simulator: Simulation @@ -725,7 +726,7 @@ def simulate_and_assert( model_assemble_constants: bool = False, model_optimize: OptimizeOptions | None = None, msg: str = "", - ) -> dict: + ) -> RouterSimulationResults: # --- Compile Programs --- # approval_teal, clear_teal, contract = self.router.compile_program( version=version, assemble_constants=assemble_constants, optimize=optimize @@ -760,11 +761,13 @@ def simulate_and_assert( if not txn_params: txn_params = TxParams() - stats = defaultdict(int) + stats: dict[str, int | str] = defaultdict(int) stats["name"] = self.router.name # --- setup reporter and stats --- # + meth: Any + def msg4simulate() -> str: return f"""user provide message={msg} call_strat={type(approval_strat)} @@ -794,7 +797,6 @@ def update_stats(meth, num_preds): double_check_at_least_one_method = False for meth, meth_cfg in method_configs.items(): sig = approval_strat.method_signature(meth) - approve_sim = Simulation( self.algod, ExecutionMode.Application, @@ -838,7 +840,7 @@ def simulate_approval(on_create): type_for_args=sdk_abi.ABIType.from_string("byte[8]"), ) - meth = ClearStateCall + meth = CLEAR_STATE_CALL is_app_create = False oc = OnComplete.ClearStateOC clear_sim = Simulation( diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index b740e9c62..a4c342aa1 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -9,8 +9,8 @@ import pyteal as pt from pyteal.compiler.compiler_test import router_app_tester from tests.blackbox import ( + CLEAR_STATE_CALL, ABICallConfigs, - ClearStateCall, Predicates, RouterCallType, RouterSimulation, @@ -112,7 +112,7 @@ }, ), ( - ClearStateCall, + CLEAR_STATE_CALL, pt.MethodConfig(), # ignored in this case { DRProp.passed: True, @@ -131,7 +131,7 @@ def split_driver2predicates_methconfigs(driver) -> tuple[Predicates, ABICallConf methconfigs = {} for meth, meth_config, predicate in driver: predicates[meth] = predicate - if meth != ClearStateCall: + if meth != CLEAR_STATE_CALL: methconfigs[meth] = meth_config return predicates, methconfigs From c11b115255b2b8a65c4e1bdd0f5c18f5137c8922 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 6 Feb 2023 00:14:30 -0600 Subject: [PATCH 182/206] tests seem to be failing for graviton, but here? --- tests/blackbox.py | 68 +++-- tests/integration/abi_router_test.py | 237 ++++++++++++++- tests/unit/blackbox_test.py | 417 +-------------------------- 3 files changed, 263 insertions(+), 459 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index 4a24a8c2d..be49de73c 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -502,6 +502,10 @@ def as_on_complete(oc_str: str) -> OnComplete: raise ValueError(f"unrecognized {oc_str=}") +def negate_cc(cc: CallConfig) -> CallConfig: + return CallConfig(3 - cc) + + class RouterSimulation: """ TODO: the following is out of date!!! @@ -656,13 +660,15 @@ def _validate_simulation( method_configs, contract, model_contract, + omit_clear_call, ): assert isinstance(approval_args_strat_type, type) and issubclass( approval_args_strat_type, ABIStrategy ), f"approval_args_strat_type should _BE_ a subtype of ABIStrategy but we have {approval_args_strat_type} (its type is {type(approval_args_strat_type)})." - assert isinstance(clear_args_strat_type, type) and issubclass( - clear_args_strat_type, ABIStrategy - ), f"clear_args_strat_type should _BE_ a subtype of ABIStrategy but we have {clear_args_strat_type} (its type is {type(clear_args_strat_type)})." + if not omit_clear_call: + assert isinstance(clear_args_strat_type, type) and issubclass( + clear_args_strat_type, ABIStrategy + ), f"clear_args_strat_type should _BE_ a subtype of ABIStrategy but we have {clear_args_strat_type} (its type is {type(clear_args_strat_type)})." assert isinstance( approval_abi_args_mod, (ABIArgsMod, type(None)) @@ -708,12 +714,12 @@ class RouterSimulationResults: stats: dict[str, Any] results: dict approval_simulator: Simulation - clear_simulator: Simulation + clear_simulator: Simulation | None def simulate_and_assert( self, approval_args_strat_type: Type[ABIStrategy], - clear_args_strat_type: Type[ABIStrategy], + clear_args_strat_type: Type[ABIStrategy] | None, approval_abi_args_mod: ABIArgsMod | None, version: int, method_configs: ABICallConfigs, @@ -721,7 +727,9 @@ def simulate_and_assert( assemble_constants: bool = False, optimize: OptimizeOptions | None = None, num_dryruns: int = 1, + omit_clear_call: bool = False, txn_params: TxParams | None = None, + executor_validation: bool = True, model_version: int | None = None, model_assemble_constants: bool = False, model_optimize: OptimizeOptions | None = None, @@ -756,6 +764,7 @@ def simulate_and_assert( method_configs, contract, model_contract, + omit_clear_call, ) if not txn_params: @@ -804,6 +813,7 @@ def update_stats(meth, num_preds): self.predicates[meth], abi_method_signature=sig, identities_teal=model_approval_teal, + validation=executor_validation, ) for oc_str, call_cfg in asdict(meth_cfg).items(): @@ -832,32 +842,34 @@ def simulate_approval(on_create): assert double_check_at_least_one_method, "no method was simulated" # ---- CLEAR PROGRAM SIMULATION ---- # - clear_strat = RandomArgLengthCallStrategy( - clear_args_strat_type, - max_args=2, - num_dryruns=num_dryruns, - min_args=0, - type_for_args=sdk_abi.ABIType.from_string("byte[8]"), - ) - - meth = CLEAR_STATE_CALL - is_app_create = False - oc = OnComplete.ClearStateOC - clear_sim = Simulation( - self.algod, - ExecutionMode.Application, - clear_teal, - self.predicates[meth], - identities_teal=model_clear_teal, - ) + clear_sim: Simulation | None = None + if not omit_clear_call: + clear_strat = RandomArgLengthCallStrategy( + cast(Type[ABIStrategy], clear_args_strat_type), + max_args=2, + num_dryruns=num_dryruns, + min_args=0, + type_for_args=sdk_abi.ABIType.from_string("byte[8]"), + ) - # ---- Summary Statistics ---- # + meth = CLEAR_STATE_CALL + is_app_create = False + oc = OnComplete.ClearStateOC + clear_sim = Simulation( + self.algod, + ExecutionMode.Application, + clear_teal, + self.predicates[meth], + identities_teal=model_clear_teal, + validation=executor_validation, + ) - sim_results = clear_sim.run_and_assert(clear_strat, msg=msg4simulate()) - assert sim_results.succeeded - self.auto_path_results[meth][(is_app_create, oc)] = sim_results - update_stats(meth, len(self.predicates[meth])) + sim_results = clear_sim.run_and_assert(clear_strat, msg=msg4simulate()) + assert sim_results.succeeded + self.auto_path_results[meth][(is_app_create, oc)] = sim_results + update_stats(meth, len(self.predicates[meth])) + # ---- Summary Statistics ---- # return self.RouterSimulationResults( stats=stats, results=self.auto_path_results, diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index a4c342aa1..8ac8ebd3a 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -1,8 +1,15 @@ import json +import re +from collections import defaultdict +from dataclasses import asdict from pathlib import Path import pytest -from graviton.abi_strategy import RandomABIStrategy, RandomABIStrategyHalfSized +from graviton.abi_strategy import ( + ABIArgsMod, + RandomABIStrategy, + RandomABIStrategyHalfSized, +) from graviton.blackbox import DryRunEncoder from graviton.invariant import DryRunProperty as DRProp @@ -14,6 +21,7 @@ Predicates, RouterCallType, RouterSimulation, + negate_cc, ) BRUTE_FORCE_TERRIBLE_SKIPPING = True @@ -172,7 +180,6 @@ def msg(): msg=msg(), ) # won't even get here if there was an error, but some extra sanity checks: - assert (sim_results := results.results) and all( sim.succeeded for meth in sim_results.values() for sim in meth.values() ) @@ -180,19 +187,6 @@ def msg(): print("\nstats:", json.dumps(stats := results.stats, indent=2)) assert stats and all(stats.values()) - if want_to_keep_annoying_details := False: - - def deepstr(d): - if isinstance(d, dict): - return {str(k): deepstr(v) for k, v in d.items()} - return d - - print( - "results:", - json.dumps(deepstr(sim_results), indent=2, default=str), - ) - print(f"{want_to_keep_annoying_details=}") - # wow!!! these fail because of differing scratch slot assignments if BRUTE_FORCE_TERRIBLE_SKIPPING: pass @@ -207,6 +201,217 @@ def deepstr(d): # f.write(results["sim_cfg"].csp_compiled) +# cf. https://death.andgravity.com/f-re for an explanation of verbose regex'es +EXPECTED_ERR_PATTERN = r""" + err\ opcode # pyteal generated err's ok +| assert\ failed\ pc= # pyteal generated assert's ok +| invalid\ ApplicationArgs\ index # failing because an app arg wasn't provided +| extract\ range\ beyond\ length\ of\ string # failing because couldn't extract when omitted final arg or jammed in tuple +""" + + +APPROVAL_NEGATIVE_PREDS = { + DRProp.rejected: True, + DRProp.error: True, + DRProp.errorMessage: lambda _, actual: ( + bool(re.search(EXPECTED_ERR_PATTERN, actual, re.VERBOSE)) + ), +} + +CLEAR_NEGATIVE_INVARIANTS_MUST_APPROVE = [ + inv for m, _, inv in QUESTIONABLE_DRIVER if m == CLEAR_STATE_CALL +][0] + + @pytest.mark.parametrize("case, version, router", ROUTER_CASES) def test_abi_router_negative(case, version, router): - pass + totals = defaultdict(int) + + def scenario_assert_stats(scenario, results): + part_a = f""" +SCENARIO: {scenario} +""" + if results: + part_b = json.dumps(stats := results.stats, indent=2) + assert stats and all(stats.values()) + for k, v in stats.items(): + if isinstance(v, int): + totals[k] += v + else: + part_b = "SKIPPED" + print(f"{part_a}stats:", part_b) + + contract = router.contract_construct() + + driver = DRIVERS[case] + pos_predicates, pos_mconfigs = split_driver2predicates_methconfigs(driver) + # assert FULL coverage (before modifying the dict): + assert pos_mconfigs == router.method_configs + + if None not in pos_mconfigs: + pos_mconfigs[None] = pt.MethodConfig() + pos_predicates[None] = APPROVAL_NEGATIVE_PREDS + + pure_meth_mconfigs = { + meth: methconfig + for meth, methconfig in pos_mconfigs.items() + if meth is not None + } + + neg_predicates = { + meth: ( + APPROVAL_NEGATIVE_PREDS + if meth != CLEAR_STATE_CALL + else CLEAR_NEGATIVE_INVARIANTS_MUST_APPROVE + ) + for meth in pos_predicates + } + + rsim = RouterSimulation(router, neg_predicates) + + def msg(): + return f"""test_abi_router_negative() +{scenario=} +{case=} +{version=} +{router.name=}""" + + scenario = "I. explore all UNEXPECTED (is_app_create, on_complete) combos" + + # NOTE: We're NOT including clear_state calls for the approval program + # as though they would never be applied. + # Also, we're ONLY including clear_state for the clear program. + # Finally, when no bare app calls are provided in method_configs, + # we still test the bare app call case. + neg_mconfigs = { + meth: pt.MethodConfig( + **{k: negate_cc(v) for k, v in asdict(mc).items() if k != "clear_state"} + ) + for meth, mc in pos_mconfigs.items() + } + + results = rsim.simulate_and_assert( + approval_args_strat_type=RandomABIStrategyHalfSized, + clear_args_strat_type=RandomABIStrategy, + approval_abi_args_mod=None, + version=version, + method_configs=neg_mconfigs, + num_dryruns=NUM_ROUTER_DRYRUNS, + executor_validation=False, + msg=msg(), + ) + # won't even get here if there was an error, but some extra sanity checks: + assert (sim_results := results.results) and all( + sim.succeeded for meth in sim_results.values() for sim in meth.values() + ) + scenario_assert_stats(scenario, results) + + # II. the case of bare-app-calls + scenario = "II. adding an argument to a bare app call" + if None in pos_mconfigs and not pos_mconfigs[None].is_never(): + bare_only_methconfigs = {None: pos_mconfigs[None]} + results = rsim.simulate_and_assert( + approval_args_strat_type=RandomABIStrategyHalfSized, + clear_args_strat_type=None, + approval_abi_args_mod=ABIArgsMod.parameter_append, + version=version, + method_configs=bare_only_methconfigs, + omit_clear_call=True, + num_dryruns=NUM_ROUTER_DRYRUNS, + executor_validation=False, + msg=msg(), + ) + assert (sim_results := results.results) and all( + sim.succeeded for meth in sim_results.values() for sim in meth.values() + ) + scenario_assert_stats(scenario, results) + else: + scenario_assert_stats(scenario, None) + + # For the rest, we may assume method calls (non bare-app-call) + # III. explore changing method selector arg[0] by edit distance 1 + + # NOTE: We don't test the case of adding an argument to method calls + # because the SDK's will guard against this case. + # However, we should re-think this assumption. + # Cf: https://github.com/algorand/go-algorand-internal/issues/2772 + # Cf. https://github.com/algorand/algorand-sdk-testing/issues/190 + + scenario = "III(a). inserting an extra random byte into method selector" + results = rsim.simulate_and_assert( + approval_args_strat_type=RandomABIStrategyHalfSized, + clear_args_strat_type=None, + approval_abi_args_mod=ABIArgsMod.selector_byte_insert, + version=version, + method_configs=pure_meth_mconfigs, + omit_clear_call=True, + num_dryruns=NUM_ROUTER_DRYRUNS, + executor_validation=False, + msg=msg(), + ) + assert (sim_results := results.results) and all( + sim.succeeded for meth in sim_results.values() for sim in meth.values() + ) + scenario_assert_stats(scenario, results) + + scenario = "III(b). removing a random byte from method selector" + results = rsim.simulate_and_assert( + approval_args_strat_type=RandomABIStrategyHalfSized, + clear_args_strat_type=None, + approval_abi_args_mod=ABIArgsMod.selector_byte_delete, + version=version, + method_configs=pure_meth_mconfigs, + omit_clear_call=True, + num_dryruns=NUM_ROUTER_DRYRUNS, + executor_validation=False, + msg=msg(), + ) + assert (sim_results := results.results) and all( + sim.succeeded for meth in sim_results.values() for sim in meth.values() + ) + scenario_assert_stats(scenario, results) + + scenario = "III(c). replacing a random byte in method selector" + results = rsim.simulate_and_assert( + approval_args_strat_type=RandomABIStrategyHalfSized, + clear_args_strat_type=None, + approval_abi_args_mod=ABIArgsMod.selector_byte_replace, + version=version, + method_configs=pure_meth_mconfigs, + omit_clear_call=True, + num_dryruns=NUM_ROUTER_DRYRUNS, + executor_validation=False, + msg=msg(), + ) + assert (sim_results := results.results) and all( + sim.succeeded for meth in sim_results.values() for sim in meth.values() + ) + scenario_assert_stats(scenario, results) + + # IV. explore changing the number of args over the 'good' call_types + # NOTE: We don't test the case of adding an argument to method calls + # We also remove methods with 0 arguments, as these degenerate to the + # already tested bare-app call case. + scenario = "IV. removing the final argument" + atleast_one_param_mconfigs = { + meth: mconfig + for meth, mconfig in pure_meth_mconfigs.items() + if len(contract.get_method_by_name(meth).args) > 0 + } + results = rsim.simulate_and_assert( + approval_args_strat_type=RandomABIStrategyHalfSized, + clear_args_strat_type=None, + approval_abi_args_mod=ABIArgsMod.parameter_delete, + version=version, + method_configs=atleast_one_param_mconfigs, + omit_clear_call=True, + num_dryruns=NUM_ROUTER_DRYRUNS, + executor_validation=False, + msg=msg(), + ) + assert (sim_results := results.results) and all( + sim.succeeded for meth in sim_results.values() for sim in meth.values() + ) + scenario_assert_stats(scenario, results) + + print("SUMMARY STATS: ", json.dumps(totals, indent=2)) diff --git a/tests/unit/blackbox_test.py b/tests/unit/blackbox_test.py index 978661a96..c9bfc0792 100644 --- a/tests/unit/blackbox_test.py +++ b/tests/unit/blackbox_test.py @@ -1,14 +1,13 @@ from itertools import product from pathlib import Path -import pytest from typing import Literal, Optional, Tuple from unittest.mock import MagicMock +import pytest from algosdk.v2client.algod import AlgodClient -from graviton.abi_strategy import ABIArgsMod, RandomABIStrategy from graviton.inspector import DryRunProperty as DRProp -import pyteal as pt +import pyteal as pt from tests.blackbox import ( Blackbox, BlackboxWrapper, @@ -352,415 +351,3 @@ def test_RouterSimulation_init(): model_router = None successful_RouterSimulation(router, model_router, predicates, algod) - - -def failing_prep_simulate( - rsim, - arg_strat_type, - abi_args_mod, - version, - assemble_constants, - optimize, - method_configs, - num_dryruns, - txn_params, - model_version, - model_assemble_constants, - model_optimize, - err_msg, - err_type=AssertionError, -): - with pytest.raises(err_type) as ae: - rsim._prep_simulation( - arg_strat_type, - abi_args_mod, - version, - assemble_constants=assemble_constants, - optimize=optimize, - method_configs=method_configs, - num_dryruns=num_dryruns, - txn_params=txn_params, - model_version=model_version, - model_assemble_constants=model_assemble_constants, - model_optimize=model_optimize, - ) - assert err_msg == str(ae.value) - - -def get_2meth_router(): - router = pt.Router( - "router", - pt.BareCallActions( - opt_in=pt.OnCompleteAction( - action=pt.Reject(), call_config=pt.CallConfig.ALL - ), - ), - clear_state=pt.Approve(), - ) - - @router.method - def m1(): - return pt.Approve() - - @router.method - def m2(): - return pt.Reject() - - return router - - -def test_prep_simulation(): - # init params: - predicates = { - None: { - DRProp.rejected: True, - }, - "m1": { - DRProp.passed: True, - DRProp.cost: 42, - }, - "m2": { - DRProp.passed: True, - DRProp.lastLog: "blah blah blah", - }, - } - router = pt.Router("empty") - assert {} == router.method_configs - - model_router = None # starting out, just test using one router - algod = MagicMock(spec=AlgodClient) - rsim = successful_RouterSimulation(router, model_router, predicates, algod) - - # _prep_simulation params. Start with bad ones and fix one-by-one - arg_strat_type = 25 # WRONG TYPE - abi_args_mod = 17 # WRONG TYPE - version = -13 # ASSERTED BY Router.compile() - assemble_constants = False # this won't be asserted - optimize = None # this won't be asserted - method_configs = 55 # EITHER NONE OR OF TYPE dict[str, MethodConfig] - num_dryruns = -100 # MUST BE A POSITIVE NUMBER - txn_params = "foo foo" # EITHER NONE OR OF TYPE TxParams - model_version = -103 # EXISTENCE ASSERTED IN CASE OF model_router - model_assemble_constants = False # this won't be asserted - model_optimize = None # this won't be asserted - - err_msg = "arg_strat_type should _BE_ a subtype of ABIStrategy but we have 25 (its type is )." - failing_prep_simulate( - rsim, - arg_strat_type, - abi_args_mod, - version, - assemble_constants, - optimize, - method_configs, - num_dryruns, - txn_params, - model_version, - model_assemble_constants, - model_optimize, - err_msg, - ) - - arg_strat_type = int - err_msg = "arg_strat_type should _BE_ a subtype of ABIStrategy but we have (its type is )." - failing_prep_simulate( - rsim, - arg_strat_type, - abi_args_mod, - version, - assemble_constants, - optimize, - method_configs, - num_dryruns, - txn_params, - model_version, - model_assemble_constants, - model_optimize, - err_msg, - ) - - arg_strat_type = RandomABIStrategy # finally fixed - # but abi_args_mod is still wrong - err_msg = "abi_args_mod '17' has type but only 'ABIArgsMod' and 'NoneType' are allowed." - failing_prep_simulate( - rsim, - arg_strat_type, - abi_args_mod, - version, - assemble_constants, - optimize, - method_configs, - num_dryruns, - txn_params, - model_version, - model_assemble_constants, - model_optimize, - err_msg, - ) - - abi_args_mod = ABIArgsMod.selector_byte_insert # finally fixed - # but version is still wrong - err_msg = f"Unsupported program version: -13. Excepted an integer in the range [2, {pt.MAX_PROGRAM_VERSION}]" - failing_prep_simulate( - rsim, - arg_strat_type, - abi_args_mod, - version, - assemble_constants, - optimize, - method_configs, - num_dryruns, - txn_params, - model_version, - model_assemble_constants, - model_optimize, - err_msg, - err_type=pt.TealInputError, - ) - - version = 7 # finally fixed - err_msg = "Base router with name 'empty' is essentially empty, as compilation results in an empty method_configs." - failing_prep_simulate( - rsim, - arg_strat_type, - abi_args_mod, - version, - assemble_constants, - optimize, - method_configs, - num_dryruns, - txn_params, - model_version, - model_assemble_constants, - model_optimize, - err_msg, - ) - - router = get_2meth_router() - router_method_configs = { - None: pt.MethodConfig(opt_in=pt.CallConfig.ALL), - "m1": pt.MethodConfig(no_op=pt.CallConfig.CALL), - "m2": pt.MethodConfig(no_op=pt.CallConfig.CALL), - } - assert router_method_configs == router.method_configs - rsim = successful_RouterSimulation(router, model_router, predicates, algod) - - err_msg = "method_configs '55' has type but only 'dict' and 'NoneType' are allowed." - failing_prep_simulate( - rsim, - arg_strat_type, - abi_args_mod, - version, - assemble_constants, - optimize, - method_configs, - num_dryruns, - txn_params, - model_version, - model_assemble_constants, - model_optimize, - err_msg, - ) - - method_configs = {} - err_msg = "if providing explicit method_configs, make sure to give at least one" - failing_prep_simulate( - rsim, - arg_strat_type, - abi_args_mod, - version, - assemble_constants, - optimize, - method_configs, - num_dryruns, - txn_params, - model_version, - model_assemble_constants, - model_optimize, - err_msg, - ) - - method_configs = { - None: pt.MethodConfig(opt_in=pt.CallConfig.ALL), - 42: "foo", - "m2": pt.MethodConfig(no_op=pt.CallConfig.ALL), - } - err_msg = "method_configs dict key '42' has type but only str and NoneType are allowed." - failing_prep_simulate( - rsim, - arg_strat_type, - abi_args_mod, - version, - assemble_constants, - optimize, - method_configs, - num_dryruns, - txn_params, - model_version, - model_assemble_constants, - model_optimize, - err_msg, - ) - - method_configs = { - None: pt.MethodConfig(opt_in=pt.CallConfig.ALL), - "m1": "foo", - "m2": pt.MethodConfig(no_op=pt.CallConfig.ALL), - } - err_msg = "method_configs['m1'] = has type but only MethodConfig is allowed." - failing_prep_simulate( - rsim, - arg_strat_type, - abi_args_mod, - version, - assemble_constants, - optimize, - method_configs, - num_dryruns, - txn_params, - model_version, - model_assemble_constants, - model_optimize, - err_msg, - ) - - method_configs = { - None: pt.MethodConfig(opt_in=pt.CallConfig.ALL), - "m1": pt.MethodConfig(no_op=pt.CallConfig.CALL), - "m2": pt.MethodConfig(no_op=pt.CallConfig.NEVER), - } - err_msg = "method_configs['m2'] specifies NEVER to be called; for driving the test, each configured method should ACTUALLY be tested." - failing_prep_simulate( - rsim, - arg_strat_type, - abi_args_mod, - version, - assemble_constants, - optimize, - method_configs, - num_dryruns, - txn_params, - model_version, - model_assemble_constants, - model_optimize, - err_msg, - ) - - method_configs = router_method_configs # finally fixed - # but num_dry_runs is still illegal - err_msg = "num_dryruns must be a positive int but is -100." - failing_prep_simulate( - rsim, - arg_strat_type, - abi_args_mod, - version, - assemble_constants, - optimize, - method_configs, - num_dryruns, - txn_params, - model_version, - model_assemble_constants, - model_optimize, - err_msg, - ) - - num_dryruns = 4 # finally fixed - # but txn_params is still messed up - err_msg = "txn_params must have type DryRunTransactionParams or NoneType but has type ." - failing_prep_simulate( - rsim, - arg_strat_type, - abi_args_mod, - version, - assemble_constants, - optimize, - method_configs, - num_dryruns, - txn_params, - model_version, - model_assemble_constants, - model_optimize, - err_msg, - ) - - txn_params = None # finally fixed - # but shoudn't provide `model_*` params when `model_router` wasn't provided - err_msg = "model_version '-103' was provided which is nonsensical because model_router was never provided for." - failing_prep_simulate( - rsim, - arg_strat_type, - abi_args_mod, - version, - assemble_constants, - optimize, - method_configs, - num_dryruns, - txn_params, - model_version, - model_assemble_constants, - model_optimize, - err_msg, - ) - - # -- NOW TRY model_router AS WELL -- # - model_router = router - algod = MagicMock(spec=AlgodClient) - rsim = successful_RouterSimulation(router, model_router, predicates, algod) - # but model_version is still wrong - err_msg = f"Unsupported program version: -103. Excepted an integer in the range [2, {pt.MAX_PROGRAM_VERSION}]" - failing_prep_simulate( - rsim, - arg_strat_type, - abi_args_mod, - version, - assemble_constants, - optimize, - method_configs, - num_dryruns, - txn_params, - model_version, - model_assemble_constants, - model_optimize, - err_msg, - err_type=pt.TealInputError, - ) - - model_version = 8 # FINALLY FINALLY FINALLY FIXED - # OK! we should be GTG - - sim_cfg = rsim._prep_simulation_borked( - arg_strat_type, - abi_args_mod, - version, - assemble_constants=assemble_constants, - optimize=optimize, - method_configs=method_configs, - num_dryruns=num_dryruns, - txn_params=txn_params, - model_version=model_version, - model_assemble_constants=model_assemble_constants, - model_optimize=model_optimize, - ) - assert sim_cfg.version == version - assert sim_cfg.assemble_constants == assemble_constants - assert sim_cfg.optimize == optimize - - assert sim_cfg.teal - assert sim_cfg.csp_compiled - assert sim_cfg.contract - - assert sim_cfg.method_configs == method_configs - - assert sim_cfg.call_strat - assert sim_cfg.call_strat.abi_args_mod == abi_args_mod - - assert sim_cfg.txn_params == txn_params - - assert sim_cfg.model_version == model_version - assert sim_cfg.model_assemble_constants == model_assemble_constants - assert sim_cfg.model_optimize == model_optimize - - assert sim_cfg.model_teal - assert sim_cfg.model_csp_compiled - assert sim_cfg.model_contract From 8199af3f397cf5c5a46d52873578578cb3ffb883 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 6 Feb 2023 01:30:28 -0600 Subject: [PATCH 183/206] report go-algrand commit hash when starting algod --- .github/workflows/build.yml | 2 +- Makefile | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ddc7da01b..f312a9289 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,7 +45,7 @@ jobs: echo $installed [[ $installed =~ "Python ${expected}" ]] && echo "Configured Python" || (echo "Failed to configure Python" && exit 1) - name: Start algod - run: make algod-start + run: make algod-start-version - name: Install python dependencies run: make setup-development - name: Integration Tests Only diff --git a/Makefile b/Makefile index 6a7708606..7fac71f0a 100644 --- a/Makefile +++ b/Makefile @@ -69,9 +69,14 @@ lint-and-test: check-generate-init lint test-unit algod-start: docker compose up -d algod --wait +algod-version: + docker compose exec algod goal --version + +algod-start-report: algod-start algod-version + algod-stop: docker compose stop algod - + integration-run: pytest -n $(NUM_PROCS) --durations=10 -sv tests/integration -m "not serial" pytest --durations=10 -sv tests/integration -m serial From 6a553e8e988ef76d49b981a5096df7f8c71b0bf7 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 6 Feb 2023 14:43:04 -0600 Subject: [PATCH 184/206] remove unused flakey fixtures + fix expected dry run error message --- tests/integration/abi_router_test.py | 18 +- .../router/sim_approval_questionable_6.teal | 460 ---------------- .../router/sim_approval_questionable_8.teal | 512 ------------------ tests/teal/router/sim_approval_yacc_6.teal | 441 --------------- tests/teal/router/sim_approval_yacc_8.teal | 493 ----------------- .../teal/router/sim_clear_questionable_6.teal | 3 - .../teal/router/sim_clear_questionable_8.teal | 3 - tests/teal/router/sim_clear_yacc_6.teal | 3 - tests/teal/router/sim_clear_yacc_8.teal | 3 - 9 files changed, 4 insertions(+), 1932 deletions(-) delete mode 100644 tests/teal/router/sim_approval_questionable_6.teal delete mode 100644 tests/teal/router/sim_approval_questionable_8.teal delete mode 100644 tests/teal/router/sim_approval_yacc_6.teal delete mode 100644 tests/teal/router/sim_approval_yacc_8.teal delete mode 100644 tests/teal/router/sim_clear_questionable_6.teal delete mode 100644 tests/teal/router/sim_clear_questionable_8.teal delete mode 100644 tests/teal/router/sim_clear_yacc_6.teal delete mode 100644 tests/teal/router/sim_clear_yacc_8.teal diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index 8ac8ebd3a..0829f9b11 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -24,7 +24,6 @@ negate_cc, ) -BRUTE_FORCE_TERRIBLE_SKIPPING = True NUM_ROUTER_DRYRUNS = 7 FIXTURES = Path.cwd() / "tests" / "teal" / "router" @@ -187,18 +186,9 @@ def msg(): print("\nstats:", json.dumps(stats := results.stats, indent=2)) assert stats and all(stats.values()) - # wow!!! these fail because of differing scratch slot assignments - if BRUTE_FORCE_TERRIBLE_SKIPPING: - pass - else: - assert pregen_clear == results.clear_simulator.simulate_dre.program - assert pregen_approval == results.approval_simulator.simulate_dre.program - - # TODO: uncomment eventually ... - # with open(FIXTURES / f"sim_approval_{case}_{version}.teal", "w") as f: - # f.write(results["sim_cfg"].ap_compiled) - # with open(FIXTURES / f"sim_clear_{case}_{version}.teal", "w") as f: - # f.write(results["sim_cfg"].csp_compiled) + # These fail because of differing scratch slot assignments + # assert pregen_clear == results.clear_simulator.simulate_dre.program + # assert pregen_approval == results.approval_simulator.simulate_dre.program # cf. https://death.andgravity.com/f-re for an explanation of verbose regex'es @@ -206,7 +196,7 @@ def msg(): err\ opcode # pyteal generated err's ok | assert\ failed\ pc= # pyteal generated assert's ok | invalid\ ApplicationArgs\ index # failing because an app arg wasn't provided -| extract\ range\ beyond\ length\ of\ string # failing because couldn't extract when omitted final arg or jammed in tuple +| extraction\ end\ 16\ is\ beyond\ length # failing because couldn't extract when omitted final arg or jammed in tuple """ diff --git a/tests/teal/router/sim_approval_questionable_6.teal b/tests/teal/router/sim_approval_questionable_6.teal deleted file mode 100644 index 21bf4e4d1..000000000 --- a/tests/teal/router/sim_approval_questionable_6.teal +++ /dev/null @@ -1,460 +0,0 @@ -#pragma version 6 -txn NumAppArgs -int 0 -== -bnz main_l20 -txna ApplicationArgs 0 -method "add(uint64,uint64)uint64" -== -bnz main_l19 -txna ApplicationArgs 0 -method "sub(uint64,uint64)uint64" -== -bnz main_l18 -txna ApplicationArgs 0 -method "mul(uint64,uint64)uint64" -== -bnz main_l17 -txna ApplicationArgs 0 -method "div(uint64,uint64)uint64" -== -bnz main_l16 -txna ApplicationArgs 0 -method "mod(uint64,uint64)uint64" -== -bnz main_l15 -txna ApplicationArgs 0 -method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" -== -bnz main_l14 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l13 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l12 -txna ApplicationArgs 0 -method "log_creation()string" -== -bnz main_l11 -err -main_l11: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -== -&& -assert -callsub logcreation_8 -store 49 -byte 0x151f7c75 -load 49 -concat -log -int 1 -return -main_l12: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -txn ApplicationID -int 0 -!= -&& -|| -assert -callsub log1_7 -store 48 -byte 0x151f7c75 -load 48 -itob -concat -log -int 1 -return -main_l13: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -|| -assert -callsub emptyreturnsubroutine_6 -int 1 -return -main_l14: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 22 -txna ApplicationArgs 2 -btoi -store 24 -txna ApplicationArgs 3 -btoi -store 25 -txna ApplicationArgs 4 -btoi -store 27 -txna ApplicationArgs 5 -btoi -store 28 -txna ApplicationArgs 6 -btoi -store 29 -txna ApplicationArgs 7 -btoi -store 30 -txna ApplicationArgs 8 -btoi -store 32 -txna ApplicationArgs 9 -btoi -store 35 -txna ApplicationArgs 10 -btoi -store 36 -txna ApplicationArgs 11 -btoi -store 37 -txna ApplicationArgs 12 -btoi -store 38 -txna ApplicationArgs 13 -btoi -store 40 -txna ApplicationArgs 14 -btoi -store 42 -txna ApplicationArgs 15 -store 46 -load 46 -int 0 -extract_uint64 -store 43 -load 46 -int 8 -extract_uint64 -store 45 -load 22 -load 24 -load 25 -load 27 -load 28 -load 29 -load 30 -load 32 -load 35 -load 36 -load 37 -load 38 -load 40 -load 42 -load 43 -load 45 -callsub alllaidtoargs_5 -store 47 -byte 0x151f7c75 -load 47 -itob -concat -log -int 1 -return -main_l15: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 18 -txna ApplicationArgs 2 -btoi -store 19 -load 18 -load 19 -callsub mod_4 -store 20 -byte 0x151f7c75 -load 20 -itob -concat -log -int 1 -return -main_l16: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 12 -txna ApplicationArgs 2 -btoi -store 15 -load 12 -load 15 -callsub div_3 -store 17 -byte 0x151f7c75 -load 17 -itob -concat -log -int 1 -return -main_l17: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 9 -txna ApplicationArgs 2 -btoi -store 10 -load 9 -load 10 -callsub mul_2 -store 11 -byte 0x151f7c75 -load 11 -itob -concat -log -int 1 -return -main_l18: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 4 -txna ApplicationArgs 2 -btoi -store 5 -load 4 -load 5 -callsub sub_1 -store 8 -byte 0x151f7c75 -load 8 -itob -concat -log -int 1 -return -main_l19: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 0 -txna ApplicationArgs 2 -btoi -store 1 -load 0 -load 1 -callsub add_0 -store 2 -byte 0x151f7c75 -load 2 -itob -concat -log -int 1 -return -main_l20: -txn OnCompletion -int OptIn -== -bnz main_l22 -err -main_l22: -txn ApplicationID -int 0 -!= -assert -byte "optin call" -log -int 1 -return - -// add -add_0: -store 6 -store 3 -load 3 -load 6 -+ -store 7 -load 7 -retsub - -// sub -sub_1: -store 14 -store 13 -load 13 -load 14 -- -store 16 -load 16 -retsub - -// mul -mul_2: -store 23 -store 21 -load 21 -load 23 -* -store 26 -load 26 -retsub - -// div -div_3: -store 33 -store 31 -load 31 -load 33 -/ -store 34 -load 34 -retsub - -// mod -mod_4: -store 41 -store 39 -load 39 -load 41 -% -store 44 -load 44 -retsub - -// all_laid_to_args -alllaidtoargs_5: -store 65 -store 64 -store 63 -store 62 -store 61 -store 60 -store 59 -store 58 -store 57 -store 56 -store 55 -store 54 -store 53 -store 52 -store 51 -store 50 -load 50 -load 51 -+ -load 52 -+ -load 53 -+ -load 54 -+ -load 55 -+ -load 56 -+ -load 57 -+ -load 58 -+ -load 59 -+ -load 60 -+ -load 61 -+ -load 62 -+ -load 63 -+ -load 64 -+ -load 65 -+ -store 66 -load 66 -retsub - -// empty_return_subroutine -emptyreturnsubroutine_6: -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_7: -int 1 -store 67 -load 67 -retsub - -// log_creation -logcreation_8: -byte 0x00106c6f6767696e67206372656174696f6e -store 68 -load 68 -retsub \ No newline at end of file diff --git a/tests/teal/router/sim_approval_questionable_8.teal b/tests/teal/router/sim_approval_questionable_8.teal deleted file mode 100644 index 00a013082..000000000 --- a/tests/teal/router/sim_approval_questionable_8.teal +++ /dev/null @@ -1,512 +0,0 @@ -#pragma version 8 -txn NumAppArgs -int 0 -== -bnz main_l20 -txna ApplicationArgs 0 -method "add(uint64,uint64)uint64" -== -bnz main_l19 -txna ApplicationArgs 0 -method "sub(uint64,uint64)uint64" -== -bnz main_l18 -txna ApplicationArgs 0 -method "mul(uint64,uint64)uint64" -== -bnz main_l17 -txna ApplicationArgs 0 -method "div(uint64,uint64)uint64" -== -bnz main_l16 -txna ApplicationArgs 0 -method "mod(uint64,uint64)uint64" -== -bnz main_l15 -txna ApplicationArgs 0 -method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" -== -bnz main_l14 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l13 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l12 -txna ApplicationArgs 0 -method "log_creation()string" -== -bnz main_l11 -err -main_l11: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -== -&& -assert -callsub logcreationcaster_17 -int 1 -return -main_l12: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -txn ApplicationID -int 0 -!= -&& -|| -assert -callsub log1caster_16 -int 1 -return -main_l13: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -|| -assert -callsub emptyreturnsubroutinecaster_15 -int 1 -return -main_l14: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub alllaidtoargscaster_14 -int 1 -return -main_l15: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub modcaster_13 -int 1 -return -main_l16: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub divcaster_12 -int 1 -return -main_l17: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub mulcaster_11 -int 1 -return -main_l18: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub subcaster_10 -int 1 -return -main_l19: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub addcaster_9 -int 1 -return -main_l20: -txn OnCompletion -int OptIn -== -bnz main_l22 -err -main_l22: -txn ApplicationID -int 0 -!= -assert -byte "optin call" -log -int 1 -return - -// add -add_0: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -+ -frame_bury 0 -retsub - -// sub -sub_1: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -- -frame_bury 0 -retsub - -// mul -mul_2: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -* -frame_bury 0 -retsub - -// div -div_3: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -/ -frame_bury 0 -retsub - -// mod -mod_4: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -% -frame_bury 0 -retsub - -// all_laid_to_args -alllaidtoargs_5: -proto 16 1 -int 0 -frame_dig -16 -frame_dig -15 -+ -frame_dig -14 -+ -frame_dig -13 -+ -frame_dig -12 -+ -frame_dig -11 -+ -frame_dig -10 -+ -frame_dig -9 -+ -frame_dig -8 -+ -frame_dig -7 -+ -frame_dig -6 -+ -frame_dig -5 -+ -frame_dig -4 -+ -frame_dig -3 -+ -frame_dig -2 -+ -frame_dig -1 -+ -frame_bury 0 -retsub - -// empty_return_subroutine -emptyreturnsubroutine_6: -proto 0 0 -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_7: -proto 0 1 -int 0 -int 1 -frame_bury 0 -retsub - -// log_creation -logcreation_8: -proto 0 1 -byte "" -byte 0x00106c6f6767696e67206372656174696f6e -frame_bury 0 -retsub - -// add_caster -addcaster_9: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub add_0 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// sub_caster -subcaster_10: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub sub_1 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// mul_caster -mulcaster_11: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub mul_2 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// div_caster -divcaster_12: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub div_3 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// mod_caster -modcaster_13: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub mod_4 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// all_laid_to_args_caster -alllaidtoargscaster_14: -proto 0 0 -int 0 -dupn 16 -byte "" -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -txna ApplicationArgs 3 -btoi -frame_bury 3 -txna ApplicationArgs 4 -btoi -frame_bury 4 -txna ApplicationArgs 5 -btoi -frame_bury 5 -txna ApplicationArgs 6 -btoi -frame_bury 6 -txna ApplicationArgs 7 -btoi -frame_bury 7 -txna ApplicationArgs 8 -btoi -frame_bury 8 -txna ApplicationArgs 9 -btoi -frame_bury 9 -txna ApplicationArgs 10 -btoi -frame_bury 10 -txna ApplicationArgs 11 -btoi -frame_bury 11 -txna ApplicationArgs 12 -btoi -frame_bury 12 -txna ApplicationArgs 13 -btoi -frame_bury 13 -txna ApplicationArgs 14 -btoi -frame_bury 14 -txna ApplicationArgs 15 -frame_bury 17 -frame_dig 17 -int 0 -extract_uint64 -frame_bury 15 -frame_dig 17 -int 8 -extract_uint64 -frame_bury 16 -frame_dig 1 -frame_dig 2 -frame_dig 3 -frame_dig 4 -frame_dig 5 -frame_dig 6 -frame_dig 7 -frame_dig 8 -frame_dig 9 -frame_dig 10 -frame_dig 11 -frame_dig 12 -frame_dig 13 -frame_dig 14 -frame_dig 15 -frame_dig 16 -callsub alllaidtoargs_5 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// empty_return_subroutine_caster -emptyreturnsubroutinecaster_15: -proto 0 0 -callsub emptyreturnsubroutine_6 -retsub - -// log_1_caster -log1caster_16: -proto 0 0 -int 0 -callsub log1_7 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// log_creation_caster -logcreationcaster_17: -proto 0 0 -byte "" -callsub logcreation_8 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -concat -log -retsub \ No newline at end of file diff --git a/tests/teal/router/sim_approval_yacc_6.teal b/tests/teal/router/sim_approval_yacc_6.teal deleted file mode 100644 index 121b3c146..000000000 --- a/tests/teal/router/sim_approval_yacc_6.teal +++ /dev/null @@ -1,441 +0,0 @@ -#pragma version 6 -txna ApplicationArgs 0 -method "add(uint64,uint64)uint64" -== -bnz main_l18 -txna ApplicationArgs 0 -method "sub(uint64,uint64)uint64" -== -bnz main_l17 -txna ApplicationArgs 0 -method "mul(uint64,uint64)uint64" -== -bnz main_l16 -txna ApplicationArgs 0 -method "div(uint64,uint64)uint64" -== -bnz main_l15 -txna ApplicationArgs 0 -method "mod(uint64,uint64)uint64" -== -bnz main_l14 -txna ApplicationArgs 0 -method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" -== -bnz main_l13 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l12 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l11 -txna ApplicationArgs 0 -method "log_creation()string" -== -bnz main_l10 -err -main_l10: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -== -&& -assert -callsub logcreation_8 -store 68 -byte 0x151f7c75 -load 68 -concat -log -int 1 -return -main_l11: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -txn ApplicationID -int 0 -!= -&& -|| -assert -callsub log1_7 -store 67 -byte 0x151f7c75 -load 67 -itob -concat -log -int 1 -return -main_l12: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -|| -assert -callsub emptyreturnsubroutine_6 -int 1 -return -main_l13: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 49 -txna ApplicationArgs 2 -btoi -store 50 -txna ApplicationArgs 3 -btoi -store 51 -txna ApplicationArgs 4 -btoi -store 52 -txna ApplicationArgs 5 -btoi -store 53 -txna ApplicationArgs 6 -btoi -store 54 -txna ApplicationArgs 7 -btoi -store 55 -txna ApplicationArgs 8 -btoi -store 56 -txna ApplicationArgs 9 -btoi -store 57 -txna ApplicationArgs 10 -btoi -store 58 -txna ApplicationArgs 11 -btoi -store 59 -txna ApplicationArgs 12 -btoi -store 60 -txna ApplicationArgs 13 -btoi -store 61 -txna ApplicationArgs 14 -btoi -store 62 -txna ApplicationArgs 15 -store 65 -load 65 -int 0 -extract_uint64 -store 63 -load 65 -int 8 -extract_uint64 -store 64 -load 49 -load 50 -load 51 -load 52 -load 53 -load 54 -load 55 -load 56 -load 57 -load 58 -load 59 -load 60 -load 61 -load 62 -load 63 -load 64 -callsub alllaidtoargs_5 -store 66 -byte 0x151f7c75 -load 66 -itob -concat -log -int 1 -return -main_l14: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 46 -txna ApplicationArgs 2 -btoi -store 47 -load 46 -load 47 -callsub mod_4 -store 48 -byte 0x151f7c75 -load 48 -itob -concat -log -int 1 -return -main_l15: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 43 -txna ApplicationArgs 2 -btoi -store 44 -load 43 -load 44 -callsub div_3 -store 45 -byte 0x151f7c75 -load 45 -itob -concat -log -int 1 -return -main_l16: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 40 -txna ApplicationArgs 2 -btoi -store 41 -load 40 -load 41 -callsub mul_2 -store 42 -byte 0x151f7c75 -load 42 -itob -concat -log -int 1 -return -main_l17: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 37 -txna ApplicationArgs 2 -btoi -store 38 -load 37 -load 38 -callsub sub_1 -store 39 -byte 0x151f7c75 -load 39 -itob -concat -log -int 1 -return -main_l18: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -txna ApplicationArgs 1 -btoi -store 34 -txna ApplicationArgs 2 -btoi -store 35 -load 34 -load 35 -callsub add_0 -store 36 -byte 0x151f7c75 -load 36 -itob -concat -log -int 1 -return - -// add -add_0: -store 1 -store 0 -load 0 -load 1 -+ -store 2 -load 2 -retsub - -// sub -sub_1: -store 4 -store 3 -load 3 -load 4 -- -store 5 -load 5 -retsub - -// mul -mul_2: -store 7 -store 6 -load 6 -load 7 -* -store 8 -load 8 -retsub - -// div -div_3: -store 10 -store 9 -load 9 -load 10 -/ -store 11 -load 11 -retsub - -// mod -mod_4: -store 13 -store 12 -load 12 -load 13 -% -store 14 -load 14 -retsub - -// all_laid_to_args -alllaidtoargs_5: -store 30 -store 29 -store 28 -store 27 -store 26 -store 25 -store 24 -store 23 -store 22 -store 21 -store 20 -store 19 -store 18 -store 17 -store 16 -store 15 -load 15 -load 16 -+ -load 17 -+ -load 18 -+ -load 19 -+ -load 20 -+ -load 21 -+ -load 22 -+ -load 23 -+ -load 24 -+ -load 25 -+ -load 26 -+ -load 27 -+ -load 28 -+ -load 29 -+ -load 30 -+ -store 31 -load 31 -retsub - -// empty_return_subroutine -emptyreturnsubroutine_6: -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_7: -int 1 -store 32 -load 32 -retsub - -// log_creation -logcreation_8: -byte 0x00106c6f6767696e67206372656174696f6e -store 33 -load 33 -retsub \ No newline at end of file diff --git a/tests/teal/router/sim_approval_yacc_8.teal b/tests/teal/router/sim_approval_yacc_8.teal deleted file mode 100644 index 5c5bda6d0..000000000 --- a/tests/teal/router/sim_approval_yacc_8.teal +++ /dev/null @@ -1,493 +0,0 @@ -#pragma version 8 -txna ApplicationArgs 0 -method "add(uint64,uint64)uint64" -== -bnz main_l18 -txna ApplicationArgs 0 -method "sub(uint64,uint64)uint64" -== -bnz main_l17 -txna ApplicationArgs 0 -method "mul(uint64,uint64)uint64" -== -bnz main_l16 -txna ApplicationArgs 0 -method "div(uint64,uint64)uint64" -== -bnz main_l15 -txna ApplicationArgs 0 -method "mod(uint64,uint64)uint64" -== -bnz main_l14 -txna ApplicationArgs 0 -method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" -== -bnz main_l13 -txna ApplicationArgs 0 -method "empty_return_subroutine()void" -== -bnz main_l12 -txna ApplicationArgs 0 -method "log_1()uint64" -== -bnz main_l11 -txna ApplicationArgs 0 -method "log_creation()string" -== -bnz main_l10 -err -main_l10: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -== -&& -assert -callsub logcreationcaster_17 -int 1 -return -main_l11: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -txn ApplicationID -int 0 -!= -&& -|| -assert -callsub log1caster_16 -int 1 -return -main_l12: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -txn OnCompletion -int OptIn -== -|| -assert -callsub emptyreturnsubroutinecaster_15 -int 1 -return -main_l13: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub alllaidtoargscaster_14 -int 1 -return -main_l14: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub modcaster_13 -int 1 -return -main_l15: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub divcaster_12 -int 1 -return -main_l16: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub mulcaster_11 -int 1 -return -main_l17: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub subcaster_10 -int 1 -return -main_l18: -txn OnCompletion -int NoOp -== -txn ApplicationID -int 0 -!= -&& -assert -callsub addcaster_9 -int 1 -return - -// add -add_0: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -+ -frame_bury 0 -retsub - -// sub -sub_1: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -- -frame_bury 0 -retsub - -// mul -mul_2: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -* -frame_bury 0 -retsub - -// div -div_3: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -/ -frame_bury 0 -retsub - -// mod -mod_4: -proto 2 1 -int 0 -frame_dig -2 -frame_dig -1 -% -frame_bury 0 -retsub - -// all_laid_to_args -alllaidtoargs_5: -proto 16 1 -int 0 -frame_dig -16 -frame_dig -15 -+ -frame_dig -14 -+ -frame_dig -13 -+ -frame_dig -12 -+ -frame_dig -11 -+ -frame_dig -10 -+ -frame_dig -9 -+ -frame_dig -8 -+ -frame_dig -7 -+ -frame_dig -6 -+ -frame_dig -5 -+ -frame_dig -4 -+ -frame_dig -3 -+ -frame_dig -2 -+ -frame_dig -1 -+ -frame_bury 0 -retsub - -// empty_return_subroutine -emptyreturnsubroutine_6: -proto 0 0 -byte "appear in both approval and clear state" -log -retsub - -// log_1 -log1_7: -proto 0 1 -int 0 -int 1 -frame_bury 0 -retsub - -// log_creation -logcreation_8: -proto 0 1 -byte "" -byte 0x00106c6f6767696e67206372656174696f6e -frame_bury 0 -retsub - -// add_caster -addcaster_9: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub add_0 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// sub_caster -subcaster_10: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub sub_1 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// mul_caster -mulcaster_11: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub mul_2 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// div_caster -divcaster_12: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub div_3 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// mod_caster -modcaster_13: -proto 0 0 -int 0 -dupn 2 -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -frame_dig 1 -frame_dig 2 -callsub mod_4 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// all_laid_to_args_caster -alllaidtoargscaster_14: -proto 0 0 -int 0 -dupn 16 -byte "" -txna ApplicationArgs 1 -btoi -frame_bury 1 -txna ApplicationArgs 2 -btoi -frame_bury 2 -txna ApplicationArgs 3 -btoi -frame_bury 3 -txna ApplicationArgs 4 -btoi -frame_bury 4 -txna ApplicationArgs 5 -btoi -frame_bury 5 -txna ApplicationArgs 6 -btoi -frame_bury 6 -txna ApplicationArgs 7 -btoi -frame_bury 7 -txna ApplicationArgs 8 -btoi -frame_bury 8 -txna ApplicationArgs 9 -btoi -frame_bury 9 -txna ApplicationArgs 10 -btoi -frame_bury 10 -txna ApplicationArgs 11 -btoi -frame_bury 11 -txna ApplicationArgs 12 -btoi -frame_bury 12 -txna ApplicationArgs 13 -btoi -frame_bury 13 -txna ApplicationArgs 14 -btoi -frame_bury 14 -txna ApplicationArgs 15 -frame_bury 17 -frame_dig 17 -int 0 -extract_uint64 -frame_bury 15 -frame_dig 17 -int 8 -extract_uint64 -frame_bury 16 -frame_dig 1 -frame_dig 2 -frame_dig 3 -frame_dig 4 -frame_dig 5 -frame_dig 6 -frame_dig 7 -frame_dig 8 -frame_dig 9 -frame_dig 10 -frame_dig 11 -frame_dig 12 -frame_dig 13 -frame_dig 14 -frame_dig 15 -frame_dig 16 -callsub alllaidtoargs_5 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// empty_return_subroutine_caster -emptyreturnsubroutinecaster_15: -proto 0 0 -callsub emptyreturnsubroutine_6 -retsub - -// log_1_caster -log1caster_16: -proto 0 0 -int 0 -callsub log1_7 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -itob -concat -log -retsub - -// log_creation_caster -logcreationcaster_17: -proto 0 0 -byte "" -callsub logcreation_8 -frame_bury 0 -byte 0x151f7c75 -frame_dig 0 -concat -log -retsub \ No newline at end of file diff --git a/tests/teal/router/sim_clear_questionable_6.teal b/tests/teal/router/sim_clear_questionable_6.teal deleted file mode 100644 index c7de51891..000000000 --- a/tests/teal/router/sim_clear_questionable_6.teal +++ /dev/null @@ -1,3 +0,0 @@ -#pragma version 6 -int 1 -return \ No newline at end of file diff --git a/tests/teal/router/sim_clear_questionable_8.teal b/tests/teal/router/sim_clear_questionable_8.teal deleted file mode 100644 index 31588a8ec..000000000 --- a/tests/teal/router/sim_clear_questionable_8.teal +++ /dev/null @@ -1,3 +0,0 @@ -#pragma version 8 -int 1 -return \ No newline at end of file diff --git a/tests/teal/router/sim_clear_yacc_6.teal b/tests/teal/router/sim_clear_yacc_6.teal deleted file mode 100644 index c7de51891..000000000 --- a/tests/teal/router/sim_clear_yacc_6.teal +++ /dev/null @@ -1,3 +0,0 @@ -#pragma version 6 -int 1 -return \ No newline at end of file diff --git a/tests/teal/router/sim_clear_yacc_8.teal b/tests/teal/router/sim_clear_yacc_8.teal deleted file mode 100644 index 31588a8ec..000000000 --- a/tests/teal/router/sim_clear_yacc_8.teal +++ /dev/null @@ -1,3 +0,0 @@ -#pragma version 8 -int 1 -return \ No newline at end of file From 2fbedc2baf93e39c39e58b19c092192042ef2dd6 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 6 Feb 2023 14:48:17 -0600 Subject: [PATCH 185/206] another to comment out --- tests/integration/abi_router_test.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index 0829f9b11..d17f6d661 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -153,8 +153,6 @@ def test_abi_router_positive(case, version, router): * consider each (OnComplete, CallConfig) combination * assert that all predicates hold for this call """ - pregen_approval, pregen_clear = ROUTER_SOURCES[(case, version)] - driver = DRIVERS[case] predicates, methconfigs = split_driver2predicates_methconfigs(driver) @@ -186,7 +184,8 @@ def msg(): print("\nstats:", json.dumps(stats := results.stats, indent=2)) assert stats and all(stats.values()) - # These fail because of differing scratch slot assignments + # These fail because of differing scratch slot assignments: + # pregen_approval, pregen_clear = ROUTER_SOURCES[(case, version)] # assert pregen_clear == results.clear_simulator.simulate_dre.program # assert pregen_approval == results.approval_simulator.simulate_dre.program From 1ca89449d79dcb9f96f9db23a96e759e3b974628 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 6 Feb 2023 14:50:41 -0600 Subject: [PATCH 186/206] fix wrong make ref --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f312a9289..6b203bd94 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,7 +45,7 @@ jobs: echo $installed [[ $installed =~ "Python ${expected}" ]] && echo "Configured Python" || (echo "Failed to configure Python" && exit 1) - name: Start algod - run: make algod-start-version + run: make algod-start-report - name: Install python dependencies run: make setup-development - name: Integration Tests Only From 5004dd9e9da4c04c0f9e6d2c4969b8560b64bb08 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 6 Feb 2023 14:52:16 -0600 Subject: [PATCH 187/206] Update Makefile --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 7fac71f0a..0439a6a4f 100644 --- a/Makefile +++ b/Makefile @@ -76,7 +76,6 @@ algod-start-report: algod-start algod-version algod-stop: docker compose stop algod - integration-run: pytest -n $(NUM_PROCS) --durations=10 -sv tests/integration -m "not serial" pytest --durations=10 -sv tests/integration -m serial From e5837622c284dca3696dfbfdd7d919ca84b4d687 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 6 Feb 2023 15:37:46 -0600 Subject: [PATCH 188/206] Apply suggestions from code review --- requirements.txt | 2 +- tests/blackbox.py | 21 +++++++-------------- tests/integration/abi_router_test.py | 8 +++++--- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/requirements.txt b/requirements.txt index 816535eeb..1e2f8b1c9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/tzaffi/graviton@ace-for-pyteal +graviton@git+https://github.com/tzaffi/graviton@v0.9.0 mypy==0.991 pytest==7.2.0 pytest-cov==3.0.0 diff --git a/tests/blackbox.py b/tests/blackbox.py index be49de73c..c3c193cbc 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -521,35 +521,28 @@ class RouterSimulation: provided for comparison. NOTE: model_router may in fact be the same as router, and in this case it is expected that something else such as version or optimization option - would differ between modeel_router and router during the simulation + would differ between model_router and router during the simulation * algod (optional) - if missing, just get one Artifacts from Step 1 are stored in self.results: _SimConfig 2. Simulation (simulate_and_assert method): - using self.results artifacts Step 1, also takes params: - * arg_strat_type: Type[ABICallStrategy] - strategy type to use for args generation - * abi_args_mod: ABIArgsMod (default None) - used to specify any arg mutation + * approval_arg_strat_type: Type[ABICallStrategy] - strategy type to use for approval program's arg generation + * clear_arg_strat_type: Type[ABICallStrategy] | None - strategy type to use for clear program's arg generation + * approval_abi_args_mod: ABIArgsMod (default None) - used to specify any arg mutation + # TODO: currently there aren't any clear_abi_args_mod, but we might need for testing non-trivial clear programs * version: int - for compiling self.router + * method_configs: ABICallConfigs - these drive all the test cases * assemble_constants: bool (optional) - for compiling self.router * optimize: OptimizeOptions (optional) - for compiling self.router - * method_configs: dict[str | None, MethodConfig] (optional) - - if missing, pick up from router.method_configs * num_dryruns: int (default 1) - the number of input runs to generate per method X config combination * txn_params: TxParams (optional) - other TxParams to append -in addition to the (is_app_create, OnComplete) information - * msg: string (optional) - message to report when assert violation occurs * model_version: int - for compiling self.model_router * model_assemble_constants: bool (optional) - for compiling self.model_router * model_optimize: OptimizeOptions (optional) - for compiling self.model_router - * TODO: consider adding -->strict: bool (default True) - when True ensure - that methods + call_config's to be tested are available in - `router` and `model_router` if it exists - * TODO: in this current version, there is no way to specify any other - other txn information that might accompany the arguments - * TODO: do we need to pass along `handle_selector: bool = True` - into ABICallStrategy's init ??? - + * msg: string (optional) - message to report when an assertion is violated """ def __init__( diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index d17f6d661..735c596fa 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -33,9 +33,11 @@ TYPICAL_IAC_OC = pt.MethodConfig(no_op=pt.CallConfig.CALL) # TEST DRIVERS LEGEND - combines method_configs + predicates -# * @0 - method: str. method == `None` indicates bare app call +# * @0 - method: str +# method == `None` indicates bare app call # -# * @1 - method_config: MethodConfig - defines how to call the method +# * @1 - method_config: MethodConfig +# defines how to call the method # # * @3 - predicates: Predicates ~ dict[DRProp, Any] # these are being asserted after being processed into Invariant's @@ -323,7 +325,7 @@ def msg(): # NOTE: We don't test the case of adding an argument to method calls # because the SDK's will guard against this case. # However, we should re-think this assumption. - # Cf: https://github.com/algorand/go-algorand-internal/issues/2772 + # Cf. https://github.com/algorand/go-algorand-internal/issues/2772 # Cf. https://github.com/algorand/algorand-sdk-testing/issues/190 scenario = "III(a). inserting an extra random byte into method selector" From 185f107898efcc4d5e2789ee504cf20f962096a2 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 6 Feb 2023 15:40:06 -0600 Subject: [PATCH 189/206] Update requirements.txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1e2f8b1c9..816535eeb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/tzaffi/graviton@v0.9.0 +graviton@git+https://github.com/tzaffi/graviton@ace-for-pyteal mypy==0.991 pytest==7.2.0 pytest-cov==3.0.0 From ed1b0813f243b1f2c2769fd039fc303803e5d8e6 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 6 Feb 2023 15:53:44 -0600 Subject: [PATCH 190/206] Update requirements.txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 816535eeb..5811b9870 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ black==22.3.0 flake8==5.0.4 flake8-tidy-imports==4.6.0 -graviton@git+https://github.com/tzaffi/graviton@ace-for-pyteal +graviton@git+https://github.com/algorand/graviton@v0.9.0 mypy==0.991 pytest==7.2.0 pytest-cov==3.0.0 From 869fb85fe255787d41a0d0ecc104e7accb00f19e Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 7 Feb 2023 00:29:56 -0600 Subject: [PATCH 191/206] non-trivial clear program --- pyteal/compiler/compiler_test.py | 162 +++--- tests/blackbox.py | 143 ++--- tests/integration/abi_router_test.py | 182 ++++++- .../router/nontriv_clear_approval_v6.teal | 460 ++++++++++++++++ .../router/nontriv_clear_approval_v8.teal | 512 ++++++++++++++++++ tests/teal/router/nontriv_clear_clear_v6.teal | 25 + tests/teal/router/nontriv_clear_clear_v8.teal | 25 + 7 files changed, 1331 insertions(+), 178 deletions(-) create mode 100644 tests/teal/router/nontriv_clear_approval_v6.teal create mode 100644 tests/teal/router/nontriv_clear_approval_v8.teal create mode 100644 tests/teal/router/nontriv_clear_clear_v6.teal create mode 100644 tests/teal/router/nontriv_clear_clear_v8.teal diff --git a/pyteal/compiler/compiler_test.py b/pyteal/compiler/compiler_test.py index 202d25d11..c7e8e0e89 100644 --- a/pyteal/compiler/compiler_test.py +++ b/pyteal/compiler/compiler_test.py @@ -2346,29 +2346,41 @@ def append_router_info(rinfo, programs): ) assert "Frame pointers aren't available" in str(e.value) + def router_compilarison(router, version, fixture_ap, fixture_csp, key, write=False): + (actual_ap, actual_csp, _) = router.compile_program(version=version) + + # if write: + # with open(FIXTURES / fixture_ap, "w") as f: + # f.write(actual_ap) + # with open(FIXTURES / fixture_csp, "w") as f: + # f.write(actual_csp) + + with open(FIXTURES / fixture_ap) as f: + expected_ap_with_oc = f.read() + with open(FIXTURES / fixture_csp) as f: + expected_csp_with_oc = f.read() + assert expected_ap_with_oc == actual_ap + assert expected_csp_with_oc == actual_csp + append_router_info( + ( + key, + version, + router, + ), + ( + actual_ap, + actual_csp, + ), + ) + # QUESTIONABLE V6: _router_with_oc = FIRST_ROUTER - ( - actual_ap_with_oc_compiled, - actual_csp_with_oc_compiled, - _, - ) = _router_with_oc.compile_program(version=6) - with open(FIXTURES / "questionable_approval_v6.teal") as f: - expected_ap_with_oc = f.read() - with open(FIXTURES / "questionable_clear_v6.teal") as f: - expected_csp_with_oc = f.read() - assert expected_ap_with_oc == actual_ap_with_oc_compiled - assert expected_csp_with_oc == actual_csp_with_oc_compiled - append_router_info( - ( - "questionable", - 6, - _router_with_oc, - ), - ( - actual_ap_with_oc_compiled, - actual_csp_with_oc_compiled, - ), + router_compilarison( + _router_with_oc, + 6, + "questionable_approval_v6.teal", + "questionable_clear_v6.teal", + "questionable", ) # YACC V6: @@ -2376,27 +2388,8 @@ def append_router_info(rinfo, programs): "yetAnotherContractConstructedFromRouter", clear_state=pt.Approve() ) add_methods_to_router(_router_without_oc) - ( - actual_ap_without_oc_compiled, - actual_csp_without_oc_compiled, - _, - ) = _router_without_oc.compile_program(version=6) - with open(FIXTURES / "yacc_approval_v6.teal") as f: - expected_ap_without_oc = f.read() - with open(FIXTURES / "yacc_clear_v6.teal") as f: - expected_csp_without_oc = f.read() - assert actual_ap_without_oc_compiled == expected_ap_without_oc - assert actual_csp_without_oc_compiled == expected_csp_without_oc - append_router_info( - ( - "yacc", - 6, - _router_without_oc, - ), - ( - actual_ap_without_oc_compiled, - actual_csp_without_oc_compiled, - ), + router_compilarison( + _router_without_oc, 6, "yacc_approval_v6.teal", "yacc_clear_v6.teal", "yacc" ) # QUESTIONABLE FP V8: @@ -2406,29 +2399,13 @@ def append_router_info(rinfo, programs): clear_state=pt.Approve(), ) add_methods_to_router(_router_with_oc) - ( - actual_ap_with_oc_compiled, - actual_csp_with_oc_compiled, - _, - ) = _router_with_oc.compile_program(version=8) - with open(FIXTURES / "questionableFP_approval_v8.teal") as f: - expected_ap_with_oc = f.read() - with open(FIXTURES / "questionableFP_clear_v8.teal") as f: - expected_csp_with_oc = f.read() - assert actual_ap_with_oc_compiled == expected_ap_with_oc - assert actual_csp_with_oc_compiled == expected_csp_with_oc - append_router_info( - ( - "questionable", - 8, - _router_with_oc, - ), - ( - actual_ap_with_oc_compiled, - actual_csp_with_oc_compiled, - ), + router_compilarison( + _router_with_oc, + 8, + "questionableFP_approval_v8.teal", + "questionableFP_clear_v8.teal", + "questionable", ) - assert actual_csp_with_oc_compiled == expected_csp_with_oc # YACC FP V8: _router_without_oc = pt.Router( @@ -2436,29 +2413,44 @@ def append_router_info(rinfo, programs): clear_state=pt.Approve(), ) add_methods_to_router(_router_without_oc) - ( - actual_ap_without_oc_compiled, - actual_csp_without_oc_compiled, - _, - ) = _router_without_oc.compile_program(version=8) - with open(FIXTURES / "yaccFP_approval_v8.teal") as f: - expected_ap_without_oc = f.read() - with open(FIXTURES / "yaccFP_clear_v8.teal") as f: - expected_csp_without_oc = f.read() - assert actual_ap_without_oc_compiled == expected_ap_without_oc - assert actual_csp_without_oc_compiled == expected_csp_without_oc - append_router_info( - ( - "yacc", - 8, - _router_without_oc, - ), - ( - actual_ap_without_oc_compiled, - actual_csp_without_oc_compiled, + router_compilarison( + _router_without_oc, + 8, + "yaccFP_approval_v8.teal", + "yaccFP_clear_v8.teal", + "yacc", + ) + + non_trivial = pt.Seq( + pt.Cond( + [pt.Txn.application_args.length() < pt.Int(2), pt.Approve()], + [pt.Txn.application_args[0] != pt.Bytes("CLEANUP"), pt.Approve()], + [pt.Txn.application_args[1] != pt.Bytes("ABORTING"), pt.Approve()], ), + pt.Reject(), + ) + _router_with_nontriv_clear = pt.Router( + "QuestionableRouterWithNontrivialClear", + bare_calls=ON_COMPLETION_ACTIONS, + clear_state=non_trivial, + ) + add_methods_to_router(_router_with_nontriv_clear) + + router_compilarison( + _router_with_nontriv_clear, + 6, + "nontriv_clear_approval_v6.teal", + "nontriv_clear_clear_v6.teal", + "nontriv_clear", + ) + + router_compilarison( + _router_with_nontriv_clear, + 8, + "nontriv_clear_approval_v8.teal", + "nontriv_clear_clear_v8.teal", + "nontriv_clear", ) - assert actual_csp_without_oc_compiled == expected_csp_without_oc return routers, sources diff --git a/tests/blackbox.py b/tests/blackbox.py index c3c193cbc..1458b3801 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -2,7 +2,7 @@ from copy import deepcopy from dataclasses import dataclass, asdict import json -from typing import Any, Callable, Dict, Final, Literal, Sequence, Type, cast +from typing import Any, Callable, Dict, Final, Iterable, Literal, Sequence, Type, cast import algosdk.abi as sdk_abi from algosdk.transaction import OnComplete @@ -706,13 +706,15 @@ def _validate_meths_in_contract( class RouterSimulationResults: stats: dict[str, Any] results: dict - approval_simulator: Simulation + approval_simulator: Simulation | None clear_simulator: Simulation | None def simulate_and_assert( self, approval_args_strat_type: Type[ABIStrategy], - clear_args_strat_type: Type[ABIStrategy] | None, + clear_args_strat_type_or_inputs: Type[ABIStrategy] + | Iterable[Sequence[PyTypes]] + | None, approval_abi_args_mod: ABIArgsMod | None, version: int, method_configs: ABICallConfigs, @@ -720,6 +722,7 @@ def simulate_and_assert( assemble_constants: bool = False, optimize: OptimizeOptions | None = None, num_dryruns: int = 1, + omit_approval_call: bool = False, omit_clear_call: bool = False, txn_params: TxParams | None = None, executor_validation: bool = True, @@ -727,7 +730,12 @@ def simulate_and_assert( model_assemble_constants: bool = False, model_optimize: OptimizeOptions | None = None, msg: str = "", + skip_validation: bool = False, ) -> RouterSimulationResults: + assert not ( + omit_approval_call and omit_approval_call + ), f"Aborting and failing as all tests are being omitted" + # --- Compile Programs --- # approval_teal, clear_teal, contract = self.router.compile_program( version=version, assemble_constants=assemble_constants, optimize=optimize @@ -747,18 +755,19 @@ def simulate_and_assert( optimize=model_optimize, ) - self._validate_simulation( - approval_args_strat_type, - clear_args_strat_type, - approval_abi_args_mod, - num_dryruns, - txn_params, - model_version, - method_configs, - contract, - model_contract, - omit_clear_call, - ) + if not skip_validation: + self._validate_simulation( + approval_args_strat_type, + clear_args_strat_type_or_inputs, + approval_abi_args_mod, + num_dryruns, + txn_params, + model_version, + method_configs, + contract, + model_contract, + omit_clear_call, + ) if not txn_params: txn_params = TxParams() @@ -790,60 +799,68 @@ def update_stats(meth, num_preds): stats["assertions_count"] += num_dryruns * num_preds # ---- APPROVAL PROGRAM SIMULATION ---- # - approval_strat = ABICallStrategy( - json.dumps(contract.dictify()), - approval_args_strat_type, - num_dryruns=num_dryruns, - abi_args_mod=approval_abi_args_mod, - ) - double_check_at_least_one_method = False - for meth, meth_cfg in method_configs.items(): - sig = approval_strat.method_signature(meth) - approve_sim = Simulation( - self.algod, - ExecutionMode.Application, - approval_teal, - self.predicates[meth], - abi_method_signature=sig, - identities_teal=model_approval_teal, - validation=executor_validation, + approval_strat = None + call_cfg = None + approve_sim = None + if not omit_approval_call: + approval_strat = ABICallStrategy( + json.dumps(contract.dictify()), + approval_args_strat_type, + num_dryruns=num_dryruns, + abi_args_mod=approval_abi_args_mod, ) + double_check_at_least_one_method = False + for meth, meth_cfg in method_configs.items(): + sig = approval_strat.method_signature(meth) + approve_sim = Simulation( + self.algod, + ExecutionMode.Application, + approval_teal, + self.predicates[meth], + abi_method_signature=sig, + identities_teal=model_approval_teal, + validation=executor_validation, + ) - for oc_str, call_cfg in asdict(meth_cfg).items(): - oc = as_on_complete(oc_str) - - def simulate_approval(on_create): - tp: TxParams = deepcopy(txn_params) - tp.update_fields( - TxParams.for_app(is_app_create=on_create, on_complete=oc) - ) - sim_results = approve_sim.run_and_assert( - approval_strat, txn_params=tp, msg=msg4simulate() - ) - assert sim_results.succeeded - self.auto_path_results[meth][(on_create, oc)] = sim_results - update_stats(meth, len(self.predicates[meth])) - - # weird walrus is_app_create := ... to fill closure of msg4simulate() - if call_cfg & CallConfig.CALL: - double_check_at_least_one_method = True - simulate_approval(is_app_create := False) - - if call_cfg & CallConfig.CREATE: - double_check_at_least_one_method = True - simulate_approval(is_app_create := True) - assert double_check_at_least_one_method, "no method was simulated" + for oc_str, call_cfg in asdict(meth_cfg).items(): + oc = as_on_complete(oc_str) + + def simulate_approval(on_create): + tp: TxParams = deepcopy(txn_params) + tp.update_fields( + TxParams.for_app(is_app_create=on_create, on_complete=oc) + ) + sim_results = approve_sim.run_and_assert( + approval_strat, txn_params=tp, msg=msg4simulate() + ) + assert sim_results.succeeded + self.auto_path_results[meth][(on_create, oc)] = sim_results + update_stats(meth, len(self.predicates[meth])) + + # weird walrus is_app_create := ... to fill closure of msg4simulate() + if call_cfg & CallConfig.CALL: + double_check_at_least_one_method = True + simulate_approval(is_app_create := False) + + if call_cfg & CallConfig.CREATE: + double_check_at_least_one_method = True + simulate_approval(is_app_create := True) + assert double_check_at_least_one_method, "no method was simulated" # ---- CLEAR PROGRAM SIMULATION ---- # clear_sim: Simulation | None = None if not omit_clear_call: - clear_strat = RandomArgLengthCallStrategy( - cast(Type[ABIStrategy], clear_args_strat_type), - max_args=2, - num_dryruns=num_dryruns, - min_args=0, - type_for_args=sdk_abi.ABIType.from_string("byte[8]"), - ) + if isinstance(clear_args_strat_type_or_inputs, list): + clear_strat = clear_args_strat_type_or_inputs + num_dryruns = len(clear_strat) + else: + clear_strat = RandomArgLengthCallStrategy( + cast(Type[ABIStrategy], clear_args_strat_type_or_inputs), + max_args=2, + num_dryruns=num_dryruns, + min_args=0, + type_for_args=sdk_abi.ABIType.from_string("byte[8]"), + ) # type: ignore meth = CLEAR_STATE_CALL is_app_create = False diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index 735c596fa..67dc2fa1d 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -12,6 +12,7 @@ ) from graviton.blackbox import DryRunEncoder from graviton.invariant import DryRunProperty as DRProp +from graviton.invariant import PredicateKind import pyteal as pt from pyteal.compiler.compiler_test import router_app_tester @@ -28,7 +29,9 @@ FIXTURES = Path.cwd() / "tests" / "teal" / "router" -ROUTER_CASES, ROUTER_SOURCES = router_app_tester() +ALL_ROUTER_CASES, ROUTER_SOURCES = router_app_tester() + +ROUTER_CASES, NONTRIV_CLEAR_ROUTER_CASES = ALL_ROUTER_CASES[:-2], ALL_ROUTER_CASES[-2:] TYPICAL_IAC_OC = pt.MethodConfig(no_op=pt.CallConfig.CALL) @@ -132,7 +135,11 @@ YACC_DRIVER = [case for case in QUESTIONABLE_DRIVER if case[0]] -DRIVERS = {"questionable": QUESTIONABLE_DRIVER, "yacc": YACC_DRIVER} +DRIVERS = { + "questionable": QUESTIONABLE_DRIVER, + "yacc": YACC_DRIVER, + "nontriv_clear": QUESTIONABLE_DRIVER, +} def split_driver2predicates_methconfigs(driver) -> tuple[Predicates, ABICallConfigs]: @@ -171,7 +178,7 @@ def msg(): results = rsim.simulate_and_assert( approval_args_strat_type=RandomABIStrategyHalfSized, - clear_args_strat_type=RandomABIStrategy, + clear_args_strat_type_or_inputs=RandomABIStrategy, approval_abi_args_mod=None, version=version, method_configs=methconfigs, @@ -214,24 +221,25 @@ def msg(): ][0] +def scenario_assert_stats(scenario, results, totals): + part_a = f""" +SCENARIO: {scenario} +""" + if results: + part_b = json.dumps(stats := results.stats, indent=2) + assert stats and all(stats.values()) + for k, v in stats.items(): + if isinstance(v, int): + totals[k] += v + else: + part_b = "SKIPPED" + print(f"{part_a}stats:", part_b) + + @pytest.mark.parametrize("case, version, router", ROUTER_CASES) def test_abi_router_negative(case, version, router): totals = defaultdict(int) - def scenario_assert_stats(scenario, results): - part_a = f""" -SCENARIO: {scenario} -""" - if results: - part_b = json.dumps(stats := results.stats, indent=2) - assert stats and all(stats.values()) - for k, v in stats.items(): - if isinstance(v, int): - totals[k] += v - else: - part_b = "SKIPPED" - print(f"{part_a}stats:", part_b) - contract = router.contract_construct() driver = DRIVERS[case] @@ -283,7 +291,7 @@ def msg(): results = rsim.simulate_and_assert( approval_args_strat_type=RandomABIStrategyHalfSized, - clear_args_strat_type=RandomABIStrategy, + clear_args_strat_type_or_inputs=RandomABIStrategy, approval_abi_args_mod=None, version=version, method_configs=neg_mconfigs, @@ -295,7 +303,7 @@ def msg(): assert (sim_results := results.results) and all( sim.succeeded for meth in sim_results.values() for sim in meth.values() ) - scenario_assert_stats(scenario, results) + scenario_assert_stats(scenario, results, totals) # II. the case of bare-app-calls scenario = "II. adding an argument to a bare app call" @@ -303,7 +311,7 @@ def msg(): bare_only_methconfigs = {None: pos_mconfigs[None]} results = rsim.simulate_and_assert( approval_args_strat_type=RandomABIStrategyHalfSized, - clear_args_strat_type=None, + clear_args_strat_type_or_inputs=None, approval_abi_args_mod=ABIArgsMod.parameter_append, version=version, method_configs=bare_only_methconfigs, @@ -315,9 +323,9 @@ def msg(): assert (sim_results := results.results) and all( sim.succeeded for meth in sim_results.values() for sim in meth.values() ) - scenario_assert_stats(scenario, results) + scenario_assert_stats(scenario, results, totals) else: - scenario_assert_stats(scenario, None) + scenario_assert_stats(scenario, None, totals) # For the rest, we may assume method calls (non bare-app-call) # III. explore changing method selector arg[0] by edit distance 1 @@ -331,7 +339,7 @@ def msg(): scenario = "III(a). inserting an extra random byte into method selector" results = rsim.simulate_and_assert( approval_args_strat_type=RandomABIStrategyHalfSized, - clear_args_strat_type=None, + clear_args_strat_type_or_inputs=None, approval_abi_args_mod=ABIArgsMod.selector_byte_insert, version=version, method_configs=pure_meth_mconfigs, @@ -343,12 +351,12 @@ def msg(): assert (sim_results := results.results) and all( sim.succeeded for meth in sim_results.values() for sim in meth.values() ) - scenario_assert_stats(scenario, results) + scenario_assert_stats(scenario, results, totals) scenario = "III(b). removing a random byte from method selector" results = rsim.simulate_and_assert( approval_args_strat_type=RandomABIStrategyHalfSized, - clear_args_strat_type=None, + clear_args_strat_type_or_inputs=None, approval_abi_args_mod=ABIArgsMod.selector_byte_delete, version=version, method_configs=pure_meth_mconfigs, @@ -360,12 +368,12 @@ def msg(): assert (sim_results := results.results) and all( sim.succeeded for meth in sim_results.values() for sim in meth.values() ) - scenario_assert_stats(scenario, results) + scenario_assert_stats(scenario, results, totals) scenario = "III(c). replacing a random byte in method selector" results = rsim.simulate_and_assert( approval_args_strat_type=RandomABIStrategyHalfSized, - clear_args_strat_type=None, + clear_args_strat_type_or_inputs=None, approval_abi_args_mod=ABIArgsMod.selector_byte_replace, version=version, method_configs=pure_meth_mconfigs, @@ -377,7 +385,7 @@ def msg(): assert (sim_results := results.results) and all( sim.succeeded for meth in sim_results.values() for sim in meth.values() ) - scenario_assert_stats(scenario, results) + scenario_assert_stats(scenario, results, totals) # IV. explore changing the number of args over the 'good' call_types # NOTE: We don't test the case of adding an argument to method calls @@ -391,7 +399,7 @@ def msg(): } results = rsim.simulate_and_assert( approval_args_strat_type=RandomABIStrategyHalfSized, - clear_args_strat_type=None, + clear_args_strat_type_or_inputs=None, approval_abi_args_mod=ABIArgsMod.parameter_delete, version=version, method_configs=atleast_one_param_mconfigs, @@ -403,6 +411,120 @@ def msg(): assert (sim_results := results.results) and all( sim.succeeded for meth in sim_results.values() for sim in meth.values() ) - scenario_assert_stats(scenario, results) + scenario_assert_stats(scenario, results, totals) print("SUMMARY STATS: ", json.dumps(totals, indent=2)) + + +IDENTITY_PREDICATES = { + DRProp.lastLog: PredicateKind.IdenticalPair, + DRProp.status: PredicateKind.IdenticalPair, + DRProp.error: PredicateKind.IdenticalPair, +} + + +def test_nontriv_clear(): + totals = defaultdict(int) + + questionable = [ + r for name, ver, r in ALL_ROUTER_CASES if name == "questionable" and ver == 6 + ][0] + nontriv_clear = [ + r for name, ver, r in ALL_ROUTER_CASES if name == "nontriv_clear" and ver == 6 + ][0] + + _, mconfigs = split_driver2predicates_methconfigs(DRIVERS["nontriv_clear"]) + predicates = {meth: IDENTITY_PREDICATES for meth in mconfigs} + + rsim_nt_vs_q = RouterSimulation( + nontriv_clear, predicates, model_router=questionable + ) + + # Sanity check the approval programs (POSITIVE CASES): + msg = "APPROVAL nontriv@v6 vs. questionable@v8" + version = 6 + results = rsim_nt_vs_q.simulate_and_assert( + approval_args_strat_type=RandomABIStrategyHalfSized, + clear_args_strat_type_or_inputs=None, + approval_abi_args_mod=None, + version=version, + method_configs=mconfigs, + num_dryruns=7, + omit_clear_call=True, + model_version=8, + msg=msg, + ) + assert (sim_results := results.results) and all( + sim.succeeded for meth in sim_results.values() for sim in meth.values() + ) + scenario_assert_stats(msg, results, totals) + + msg = "APPROVAL nontriv@v8 vs. questionable@v8" + version = 8 + results = rsim_nt_vs_q.simulate_and_assert( + approval_args_strat_type=RandomABIStrategyHalfSized, + clear_args_strat_type_or_inputs=None, + approval_abi_args_mod=None, + version=version, + method_configs=mconfigs, + num_dryruns=7, + omit_clear_call=True, + model_version=8, + msg=msg, + ) + assert (sim_results := results.results) and all( + sim.succeeded for meth in sim_results.values() for sim in meth.values() + ) + scenario_assert_stats(msg, results, totals) + + print("PARTIAL SUMMARY STATS: ", json.dumps(totals, indent=2)) + + # Finally, a bespoke test for the non-trivial clear program: + bespoke = { + DRProp.passed: { + (): True, + (b"random bytes",): True, + (b"CLEANUP",): True, + (b"CLEANUP", b"random bytes"): True, + (b"CLEANUP", b"ABORTING"): False, + (b"CLEANUP", b"ABORTING", b"random bytes"): False, + } + } + inputs = list(bespoke[DRProp.passed].keys()) + clear_preds = {CLEAR_STATE_CALL: bespoke} + + msg = "CLEAR nontriv@v6" + version = 6 + clear_rsim = RouterSimulation(nontriv_clear, clear_preds) + results = clear_rsim.simulate_and_assert( + approval_args_strat_type=None, + clear_args_strat_type_or_inputs=inputs, + approval_abi_args_mod=None, + version=version, + method_configs=None, + msg=msg, + omit_approval_call=True, + skip_validation=True, + ) + assert (sim_results := results.results) and all( + sim.succeeded for meth in sim_results.values() for sim in meth.values() + ) + scenario_assert_stats(msg, results, totals) + + msg = "CLEAR nontriv@v8" + version = 8 + clear_rsim = RouterSimulation(nontriv_clear, clear_preds) + results = clear_rsim.simulate_and_assert( + approval_args_strat_type=None, + clear_args_strat_type_or_inputs=inputs, + approval_abi_args_mod=None, + version=version, + method_configs=None, + msg=msg, + omit_approval_call=True, + skip_validation=True, + ) + assert (sim_results := results.results) and all( + sim.succeeded for meth in sim_results.values() for sim in meth.values() + ) + scenario_assert_stats(msg, results, totals) diff --git a/tests/teal/router/nontriv_clear_approval_v6.teal b/tests/teal/router/nontriv_clear_approval_v6.teal new file mode 100644 index 000000000..51455774a --- /dev/null +++ b/tests/teal/router/nontriv_clear_approval_v6.teal @@ -0,0 +1,460 @@ +#pragma version 6 +txn NumAppArgs +int 0 +== +bnz main_l20 +txna ApplicationArgs 0 +method "add(uint64,uint64)uint64" +== +bnz main_l19 +txna ApplicationArgs 0 +method "sub(uint64,uint64)uint64" +== +bnz main_l18 +txna ApplicationArgs 0 +method "mul(uint64,uint64)uint64" +== +bnz main_l17 +txna ApplicationArgs 0 +method "div(uint64,uint64)uint64" +== +bnz main_l16 +txna ApplicationArgs 0 +method "mod(uint64,uint64)uint64" +== +bnz main_l15 +txna ApplicationArgs 0 +method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" +== +bnz main_l14 +txna ApplicationArgs 0 +method "empty_return_subroutine()void" +== +bnz main_l13 +txna ApplicationArgs 0 +method "log_1()uint64" +== +bnz main_l12 +txna ApplicationArgs 0 +method "log_creation()string" +== +bnz main_l11 +err +main_l11: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +== +&& +assert +callsub logcreation_8 +store 67 +byte 0x151f7c75 +load 67 +concat +log +int 1 +return +main_l12: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +txn ApplicationID +int 0 +!= +&& +|| +assert +callsub log1_7 +store 65 +byte 0x151f7c75 +load 65 +itob +concat +log +int 1 +return +main_l13: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +|| +assert +callsub emptyreturnsubroutine_6 +int 1 +return +main_l14: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 30 +txna ApplicationArgs 2 +btoi +store 31 +txna ApplicationArgs 3 +btoi +store 32 +txna ApplicationArgs 4 +btoi +store 33 +txna ApplicationArgs 5 +btoi +store 34 +txna ApplicationArgs 6 +btoi +store 35 +txna ApplicationArgs 7 +btoi +store 36 +txna ApplicationArgs 8 +btoi +store 37 +txna ApplicationArgs 9 +btoi +store 38 +txna ApplicationArgs 10 +btoi +store 39 +txna ApplicationArgs 11 +btoi +store 40 +txna ApplicationArgs 12 +btoi +store 41 +txna ApplicationArgs 13 +btoi +store 42 +txna ApplicationArgs 14 +btoi +store 43 +txna ApplicationArgs 15 +store 46 +load 46 +int 0 +extract_uint64 +store 44 +load 46 +int 8 +extract_uint64 +store 45 +load 30 +load 31 +load 32 +load 33 +load 34 +load 35 +load 36 +load 37 +load 38 +load 39 +load 40 +load 41 +load 42 +load 43 +load 44 +load 45 +callsub alllaidtoargs_5 +store 47 +byte 0x151f7c75 +load 47 +itob +concat +log +int 1 +return +main_l15: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 24 +txna ApplicationArgs 2 +btoi +store 25 +load 24 +load 25 +callsub mod_4 +store 26 +byte 0x151f7c75 +load 26 +itob +concat +log +int 1 +return +main_l16: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 18 +txna ApplicationArgs 2 +btoi +store 19 +load 18 +load 19 +callsub div_3 +store 20 +byte 0x151f7c75 +load 20 +itob +concat +log +int 1 +return +main_l17: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 12 +txna ApplicationArgs 2 +btoi +store 13 +load 12 +load 13 +callsub mul_2 +store 14 +byte 0x151f7c75 +load 14 +itob +concat +log +int 1 +return +main_l18: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 6 +txna ApplicationArgs 2 +btoi +store 7 +load 6 +load 7 +callsub sub_1 +store 8 +byte 0x151f7c75 +load 8 +itob +concat +log +int 1 +return +main_l19: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +txna ApplicationArgs 1 +btoi +store 0 +txna ApplicationArgs 2 +btoi +store 1 +load 0 +load 1 +callsub add_0 +store 2 +byte 0x151f7c75 +load 2 +itob +concat +log +int 1 +return +main_l20: +txn OnCompletion +int OptIn +== +bnz main_l22 +err +main_l22: +txn ApplicationID +int 0 +!= +assert +byte "optin call" +log +int 1 +return + +// add +add_0: +store 4 +store 3 +load 3 +load 4 ++ +store 5 +load 5 +retsub + +// sub +sub_1: +store 10 +store 9 +load 9 +load 10 +- +store 11 +load 11 +retsub + +// mul +mul_2: +store 16 +store 15 +load 15 +load 16 +* +store 17 +load 17 +retsub + +// div +div_3: +store 22 +store 21 +load 21 +load 22 +/ +store 23 +load 23 +retsub + +// mod +mod_4: +store 28 +store 27 +load 27 +load 28 +% +store 29 +load 29 +retsub + +// all_laid_to_args +alllaidtoargs_5: +store 63 +store 62 +store 61 +store 60 +store 59 +store 58 +store 57 +store 56 +store 55 +store 54 +store 53 +store 52 +store 51 +store 50 +store 49 +store 48 +load 48 +load 49 ++ +load 50 ++ +load 51 ++ +load 52 ++ +load 53 ++ +load 54 ++ +load 55 ++ +load 56 ++ +load 57 ++ +load 58 ++ +load 59 ++ +load 60 ++ +load 61 ++ +load 62 ++ +load 63 ++ +store 64 +load 64 +retsub + +// empty_return_subroutine +emptyreturnsubroutine_6: +byte "appear in both approval and clear state" +log +retsub + +// log_1 +log1_7: +int 1 +store 66 +load 66 +retsub + +// log_creation +logcreation_8: +byte 0x00106c6f6767696e67206372656174696f6e +store 68 +load 68 +retsub \ No newline at end of file diff --git a/tests/teal/router/nontriv_clear_approval_v8.teal b/tests/teal/router/nontriv_clear_approval_v8.teal new file mode 100644 index 000000000..00a013082 --- /dev/null +++ b/tests/teal/router/nontriv_clear_approval_v8.teal @@ -0,0 +1,512 @@ +#pragma version 8 +txn NumAppArgs +int 0 +== +bnz main_l20 +txna ApplicationArgs 0 +method "add(uint64,uint64)uint64" +== +bnz main_l19 +txna ApplicationArgs 0 +method "sub(uint64,uint64)uint64" +== +bnz main_l18 +txna ApplicationArgs 0 +method "mul(uint64,uint64)uint64" +== +bnz main_l17 +txna ApplicationArgs 0 +method "div(uint64,uint64)uint64" +== +bnz main_l16 +txna ApplicationArgs 0 +method "mod(uint64,uint64)uint64" +== +bnz main_l15 +txna ApplicationArgs 0 +method "all_laid_to_args(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)uint64" +== +bnz main_l14 +txna ApplicationArgs 0 +method "empty_return_subroutine()void" +== +bnz main_l13 +txna ApplicationArgs 0 +method "log_1()uint64" +== +bnz main_l12 +txna ApplicationArgs 0 +method "log_creation()string" +== +bnz main_l11 +err +main_l11: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +== +&& +assert +callsub logcreationcaster_17 +int 1 +return +main_l12: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +txn ApplicationID +int 0 +!= +&& +|| +assert +callsub log1caster_16 +int 1 +return +main_l13: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +txn OnCompletion +int OptIn +== +|| +assert +callsub emptyreturnsubroutinecaster_15 +int 1 +return +main_l14: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub alllaidtoargscaster_14 +int 1 +return +main_l15: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub modcaster_13 +int 1 +return +main_l16: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub divcaster_12 +int 1 +return +main_l17: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub mulcaster_11 +int 1 +return +main_l18: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub subcaster_10 +int 1 +return +main_l19: +txn OnCompletion +int NoOp +== +txn ApplicationID +int 0 +!= +&& +assert +callsub addcaster_9 +int 1 +return +main_l20: +txn OnCompletion +int OptIn +== +bnz main_l22 +err +main_l22: +txn ApplicationID +int 0 +!= +assert +byte "optin call" +log +int 1 +return + +// add +add_0: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 ++ +frame_bury 0 +retsub + +// sub +sub_1: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +- +frame_bury 0 +retsub + +// mul +mul_2: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +* +frame_bury 0 +retsub + +// div +div_3: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +/ +frame_bury 0 +retsub + +// mod +mod_4: +proto 2 1 +int 0 +frame_dig -2 +frame_dig -1 +% +frame_bury 0 +retsub + +// all_laid_to_args +alllaidtoargs_5: +proto 16 1 +int 0 +frame_dig -16 +frame_dig -15 ++ +frame_dig -14 ++ +frame_dig -13 ++ +frame_dig -12 ++ +frame_dig -11 ++ +frame_dig -10 ++ +frame_dig -9 ++ +frame_dig -8 ++ +frame_dig -7 ++ +frame_dig -6 ++ +frame_dig -5 ++ +frame_dig -4 ++ +frame_dig -3 ++ +frame_dig -2 ++ +frame_dig -1 ++ +frame_bury 0 +retsub + +// empty_return_subroutine +emptyreturnsubroutine_6: +proto 0 0 +byte "appear in both approval and clear state" +log +retsub + +// log_1 +log1_7: +proto 0 1 +int 0 +int 1 +frame_bury 0 +retsub + +// log_creation +logcreation_8: +proto 0 1 +byte "" +byte 0x00106c6f6767696e67206372656174696f6e +frame_bury 0 +retsub + +// add_caster +addcaster_9: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub add_0 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// sub_caster +subcaster_10: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub sub_1 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// mul_caster +mulcaster_11: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub mul_2 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// div_caster +divcaster_12: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub div_3 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// mod_caster +modcaster_13: +proto 0 0 +int 0 +dupn 2 +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +frame_dig 1 +frame_dig 2 +callsub mod_4 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// all_laid_to_args_caster +alllaidtoargscaster_14: +proto 0 0 +int 0 +dupn 16 +byte "" +txna ApplicationArgs 1 +btoi +frame_bury 1 +txna ApplicationArgs 2 +btoi +frame_bury 2 +txna ApplicationArgs 3 +btoi +frame_bury 3 +txna ApplicationArgs 4 +btoi +frame_bury 4 +txna ApplicationArgs 5 +btoi +frame_bury 5 +txna ApplicationArgs 6 +btoi +frame_bury 6 +txna ApplicationArgs 7 +btoi +frame_bury 7 +txna ApplicationArgs 8 +btoi +frame_bury 8 +txna ApplicationArgs 9 +btoi +frame_bury 9 +txna ApplicationArgs 10 +btoi +frame_bury 10 +txna ApplicationArgs 11 +btoi +frame_bury 11 +txna ApplicationArgs 12 +btoi +frame_bury 12 +txna ApplicationArgs 13 +btoi +frame_bury 13 +txna ApplicationArgs 14 +btoi +frame_bury 14 +txna ApplicationArgs 15 +frame_bury 17 +frame_dig 17 +int 0 +extract_uint64 +frame_bury 15 +frame_dig 17 +int 8 +extract_uint64 +frame_bury 16 +frame_dig 1 +frame_dig 2 +frame_dig 3 +frame_dig 4 +frame_dig 5 +frame_dig 6 +frame_dig 7 +frame_dig 8 +frame_dig 9 +frame_dig 10 +frame_dig 11 +frame_dig 12 +frame_dig 13 +frame_dig 14 +frame_dig 15 +frame_dig 16 +callsub alllaidtoargs_5 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// empty_return_subroutine_caster +emptyreturnsubroutinecaster_15: +proto 0 0 +callsub emptyreturnsubroutine_6 +retsub + +// log_1_caster +log1caster_16: +proto 0 0 +int 0 +callsub log1_7 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +itob +concat +log +retsub + +// log_creation_caster +logcreationcaster_17: +proto 0 0 +byte "" +callsub logcreation_8 +frame_bury 0 +byte 0x151f7c75 +frame_dig 0 +concat +log +retsub \ No newline at end of file diff --git a/tests/teal/router/nontriv_clear_clear_v6.teal b/tests/teal/router/nontriv_clear_clear_v6.teal new file mode 100644 index 000000000..df52f53e8 --- /dev/null +++ b/tests/teal/router/nontriv_clear_clear_v6.teal @@ -0,0 +1,25 @@ +#pragma version 6 +txn NumAppArgs +int 2 +< +bnz main_l6 +txna ApplicationArgs 0 +byte "CLEANUP" +!= +bnz main_l5 +txna ApplicationArgs 1 +byte "ABORTING" +!= +bnz main_l4 +err +main_l4: +int 1 +return +main_l5: +int 1 +return +main_l6: +int 1 +return +int 0 +return \ No newline at end of file diff --git a/tests/teal/router/nontriv_clear_clear_v8.teal b/tests/teal/router/nontriv_clear_clear_v8.teal new file mode 100644 index 000000000..e65de3931 --- /dev/null +++ b/tests/teal/router/nontriv_clear_clear_v8.teal @@ -0,0 +1,25 @@ +#pragma version 8 +txn NumAppArgs +int 2 +< +bnz main_l6 +txna ApplicationArgs 0 +byte "CLEANUP" +!= +bnz main_l5 +txna ApplicationArgs 1 +byte "ABORTING" +!= +bnz main_l4 +err +main_l4: +int 1 +return +main_l5: +int 1 +return +main_l6: +int 1 +return +int 0 +return \ No newline at end of file From 33b8c2be07d06f4fcc569b575d0daadccd4b9aa5 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 7 Feb 2023 00:38:12 -0600 Subject: [PATCH 192/206] lint and rename variable --- pyteal/compiler/compiler_test.py | 11 ++++++----- tests/blackbox.py | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pyteal/compiler/compiler_test.py b/pyteal/compiler/compiler_test.py index c7e8e0e89..7b668587d 100644 --- a/pyteal/compiler/compiler_test.py +++ b/pyteal/compiler/compiler_test.py @@ -1,9 +1,10 @@ from pathlib import Path + import pytest import pyteal as pt -FIXTURES = Path.cwd() / "tests" / "teal" / "router" +ROUTER_FIXTURES = Path.cwd() / "tests" / "teal" / "router" def test_compile_single(): @@ -2350,14 +2351,14 @@ def router_compilarison(router, version, fixture_ap, fixture_csp, key, write=Fal (actual_ap, actual_csp, _) = router.compile_program(version=version) # if write: - # with open(FIXTURES / fixture_ap, "w") as f: + # with open(ROUTER_FIXTURES / fixture_ap, "w") as f: # f.write(actual_ap) - # with open(FIXTURES / fixture_csp, "w") as f: + # with open(ROUTER_FIXTURES / fixture_csp, "w") as f: # f.write(actual_csp) - with open(FIXTURES / fixture_ap) as f: + with open(ROUTER_FIXTURES / fixture_ap) as f: expected_ap_with_oc = f.read() - with open(FIXTURES / fixture_csp) as f: + with open(ROUTER_FIXTURES / fixture_csp) as f: expected_csp_with_oc = f.read() assert expected_ap_with_oc == actual_ap assert expected_csp_with_oc == actual_csp diff --git a/tests/blackbox.py b/tests/blackbox.py index 1458b3801..e9bc6eebb 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -734,7 +734,7 @@ def simulate_and_assert( ) -> RouterSimulationResults: assert not ( omit_approval_call and omit_approval_call - ), f"Aborting and failing as all tests are being omitted" + ), "Aborting and failing as all tests are being omitted" # --- Compile Programs --- # approval_teal, clear_teal, contract = self.router.compile_program( From 835d37eed38ee79eecf41045552333602b123005 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 7 Feb 2023 00:47:32 -0600 Subject: [PATCH 193/206] the_same and the_same bug --- tests/blackbox.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index e9bc6eebb..41a46699a 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -733,7 +733,7 @@ def simulate_and_assert( skip_validation: bool = False, ) -> RouterSimulationResults: assert not ( - omit_approval_call and omit_approval_call + omit_approval_call and omit_clear_call ), "Aborting and failing as all tests are being omitted" # --- Compile Programs --- # From d881a14ad5f90ea608da9cc10af21497fefad46b Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 7 Feb 2023 09:53:00 -0600 Subject: [PATCH 194/206] Update pyteal/ast/router.py Co-authored-by: Hang Su <87964331+ahangsu@users.noreply.github.com> --- pyteal/ast/router.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyteal/ast/router.py b/pyteal/ast/router.py index 35aa275d3..5cb5d0712 100644 --- a/pyteal/ast/router.py +++ b/pyteal/ast/router.py @@ -844,7 +844,7 @@ def add_method_handler( """ if not isinstance(method_call, ABIReturnSubroutine): raise TealInputError( - "for adding method handler, must be ABIReturnSubroutine but method_call is {type(method_call)}" + f"for adding method handler, must be ABIReturnSubroutine but method_call is {type(method_call)}" ) method_signature = method_call.method_signature(overriding_name) final_name = overriding_name or method_call.name() From 5dd9b8e0caf5663e2b124ad7ba3a282594c568d4 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 7 Feb 2023 09:53:20 -0600 Subject: [PATCH 195/206] Update pyteal/compiler/compiler_test.py Co-authored-by: Hang Su <87964331+ahangsu@users.noreply.github.com> --- pyteal/compiler/compiler_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyteal/compiler/compiler_test.py b/pyteal/compiler/compiler_test.py index 7b668587d..01509fe1c 100644 --- a/pyteal/compiler/compiler_test.py +++ b/pyteal/compiler/compiler_test.py @@ -2348,7 +2348,7 @@ def append_router_info(rinfo, programs): assert "Frame pointers aren't available" in str(e.value) def router_compilarison(router, version, fixture_ap, fixture_csp, key, write=False): - (actual_ap, actual_csp, _) = router.compile_program(version=version) + actual_ap, actual_csp, _ = router.compile_program(version=version) # if write: # with open(ROUTER_FIXTURES / fixture_ap, "w") as f: From 87f281eecee511bb71588e821273cb8d2b0287e9 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 7 Feb 2023 11:01:25 -0600 Subject: [PATCH 196/206] per CR suggstion - better non_triv clear program expression --- pyteal/compiler/compiler_test.py | 2 +- tests/teal/router/nontriv_clear_clear_v6.teal | 19 +++++++++++-------- tests/teal/router/nontriv_clear_clear_v8.teal | 19 +++++++++++-------- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/pyteal/compiler/compiler_test.py b/pyteal/compiler/compiler_test.py index 01509fe1c..6e93e80d0 100644 --- a/pyteal/compiler/compiler_test.py +++ b/pyteal/compiler/compiler_test.py @@ -2427,8 +2427,8 @@ def router_compilarison(router, version, fixture_ap, fixture_csp, key, write=Fal [pt.Txn.application_args.length() < pt.Int(2), pt.Approve()], [pt.Txn.application_args[0] != pt.Bytes("CLEANUP"), pt.Approve()], [pt.Txn.application_args[1] != pt.Bytes("ABORTING"), pt.Approve()], + [pt.Int(1), pt.Reject()], ), - pt.Reject(), ) _router_with_nontriv_clear = pt.Router( "QuestionableRouterWithNontrivialClear", diff --git a/tests/teal/router/nontriv_clear_clear_v6.teal b/tests/teal/router/nontriv_clear_clear_v6.teal index df52f53e8..22f69de3e 100644 --- a/tests/teal/router/nontriv_clear_clear_v6.teal +++ b/tests/teal/router/nontriv_clear_clear_v6.teal @@ -2,24 +2,27 @@ txn NumAppArgs int 2 < -bnz main_l6 +bnz main_l8 txna ApplicationArgs 0 byte "CLEANUP" != -bnz main_l5 +bnz main_l7 txna ApplicationArgs 1 byte "ABORTING" != -bnz main_l4 -err -main_l4: +bnz main_l6 int 1 -return +bnz main_l5 +err main_l5: -int 1 +int 0 return main_l6: int 1 return -int 0 +main_l7: +int 1 +return +main_l8: +int 1 return \ No newline at end of file diff --git a/tests/teal/router/nontriv_clear_clear_v8.teal b/tests/teal/router/nontriv_clear_clear_v8.teal index e65de3931..f9a349e0b 100644 --- a/tests/teal/router/nontriv_clear_clear_v8.teal +++ b/tests/teal/router/nontriv_clear_clear_v8.teal @@ -2,24 +2,27 @@ txn NumAppArgs int 2 < -bnz main_l6 +bnz main_l8 txna ApplicationArgs 0 byte "CLEANUP" != -bnz main_l5 +bnz main_l7 txna ApplicationArgs 1 byte "ABORTING" != -bnz main_l4 -err -main_l4: +bnz main_l6 int 1 -return +bnz main_l5 +err main_l5: -int 1 +int 0 return main_l6: int 1 return -int 0 +main_l7: +int 1 +return +main_l8: +int 1 return \ No newline at end of file From da6c2de4568c16f47716bd07ed82e0b841a2cee7 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 7 Feb 2023 12:17:34 -0600 Subject: [PATCH 197/206] per CR suggestion: method configs should be keyed of signature not name. But the tester remains keyed by name. --- pyteal/ast/router.py | 5 +++-- tests/blackbox.py | 24 ++++++++++++------------ tests/integration/abi_router_test.py | 16 +++++++++++++--- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/pyteal/ast/router.py b/pyteal/ast/router.py index 5cb5d0712..465223c04 100644 --- a/pyteal/ast/router.py +++ b/pyteal/ast/router.py @@ -815,7 +815,9 @@ def __init__( self.bare_call_actions: BareCallActions = bare_calls or BareCallActions() + # maps method signature (or None for bare call) to MethodConfig: self.method_configs: dict[str | None, MethodConfig] = dict() + if not self.bare_call_actions.is_empty(): self.method_configs[None] = self.bare_call_actions.get_method_config() @@ -847,7 +849,6 @@ def add_method_handler( f"for adding method handler, must be ABIReturnSubroutine but method_call is {type(method_call)}" ) method_signature = method_call.method_signature(overriding_name) - final_name = overriding_name or method_call.name() if method_config is None: method_config = MethodConfig(no_op=CallConfig.CALL) if method_config.is_never(): @@ -876,7 +877,7 @@ def add_method_handler( self.approval_ast.add_method_to_ast( method_signature, method_approval_cond, method_call ) - self.method_configs[final_name] = method_config + self.method_configs[method_signature] = method_config return method_call def method( diff --git a/tests/blackbox.py b/tests/blackbox.py index 41a46699a..5f80bd7e4 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -777,16 +777,16 @@ def simulate_and_assert( # --- setup reporter and stats --- # - meth: Any + meth_name: Any def msg4simulate() -> str: return f"""user provide message={msg} call_strat={type(approval_strat)} -{meth=} +{meth_name=} {oc=} {call_cfg=} {is_app_create=} -{len(self.predicates[meth])=} +{len(self.predicates[meth_name])=} {stats["method_combo_count"]=} {stats["dryrun_count"]=} {stats["assertions_count"]=} @@ -810,13 +810,13 @@ def update_stats(meth, num_preds): abi_args_mod=approval_abi_args_mod, ) double_check_at_least_one_method = False - for meth, meth_cfg in method_configs.items(): - sig = approval_strat.method_signature(meth) + for meth_name, meth_cfg in method_configs.items(): + sig = approval_strat.method_signature(meth_name) approve_sim = Simulation( self.algod, ExecutionMode.Application, approval_teal, - self.predicates[meth], + self.predicates[meth_name], abi_method_signature=sig, identities_teal=model_approval_teal, validation=executor_validation, @@ -834,8 +834,8 @@ def simulate_approval(on_create): approval_strat, txn_params=tp, msg=msg4simulate() ) assert sim_results.succeeded - self.auto_path_results[meth][(on_create, oc)] = sim_results - update_stats(meth, len(self.predicates[meth])) + self.auto_path_results[meth_name][(on_create, oc)] = sim_results + update_stats(meth_name, len(self.predicates[meth_name])) # weird walrus is_app_create := ... to fill closure of msg4simulate() if call_cfg & CallConfig.CALL: @@ -862,22 +862,22 @@ def simulate_approval(on_create): type_for_args=sdk_abi.ABIType.from_string("byte[8]"), ) # type: ignore - meth = CLEAR_STATE_CALL + meth_name = CLEAR_STATE_CALL is_app_create = False oc = OnComplete.ClearStateOC clear_sim = Simulation( self.algod, ExecutionMode.Application, clear_teal, - self.predicates[meth], + self.predicates[meth_name], identities_teal=model_clear_teal, validation=executor_validation, ) sim_results = clear_sim.run_and_assert(clear_strat, msg=msg4simulate()) assert sim_results.succeeded - self.auto_path_results[meth][(is_app_create, oc)] = sim_results - update_stats(meth, len(self.predicates[meth])) + self.auto_path_results[meth_name][(is_app_create, oc)] = sim_results + update_stats(meth_name, len(self.predicates[meth_name])) # ---- Summary Statistics ---- # return self.RouterSimulationResults( diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index 67dc2fa1d..850131bd9 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -153,6 +153,16 @@ def split_driver2predicates_methconfigs(driver) -> tuple[Predicates, ABICallConf return predicates, methconfigs +def assert_full_method_coverage(router, methconfigs): + assert len(methconfigs) == len(rmc := router.method_configs) + for meth_sig, meth_config in rmc.items(): + k = meth_sig + if k: + k = meth_sig.split("(")[0] + assert k in methconfigs, f"{k=} (derived from {meth_sig=} not in methconfigs" + assert meth_config == methconfigs[k] + + @pytest.mark.parametrize("case, version, router", ROUTER_CASES) def test_abi_router_positive(case, version, router): """ @@ -165,8 +175,7 @@ def test_abi_router_positive(case, version, router): driver = DRIVERS[case] predicates, methconfigs = split_driver2predicates_methconfigs(driver) - # assert FULL coverage: - assert methconfigs == router.method_configs + assert_full_method_coverage(router, methconfigs) rsim = RouterSimulation(router, predicates) @@ -244,8 +253,9 @@ def test_abi_router_negative(case, version, router): driver = DRIVERS[case] pos_predicates, pos_mconfigs = split_driver2predicates_methconfigs(driver) + # assert FULL coverage (before modifying the dict): - assert pos_mconfigs == router.method_configs + assert_full_method_coverage(router, pos_mconfigs) if None not in pos_mconfigs: pos_mconfigs[None] = pt.MethodConfig() From 5b98699bd363e8290219c57fff41942fb7ca60dc Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 7 Feb 2023 13:46:02 -0600 Subject: [PATCH 198/206] per CR suggestions --- tests/blackbox.py | 40 +++++++++++++++++++++---------------- tests/unit/blackbox_test.py | 4 ++-- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index 5f80bd7e4..63e90303a 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -508,8 +508,6 @@ def negate_cc(cc: CallConfig) -> CallConfig: class RouterSimulation: """ - TODO: the following is out of date!!! - Lifecycle of a RouterSimulation 1. Creation (__init__ method): @@ -527,22 +525,30 @@ class RouterSimulation: Artifacts from Step 1 are stored in self.results: _SimConfig 2. Simulation (simulate_and_assert method): - using self.results artifacts Step 1, also takes params: - * approval_arg_strat_type: Type[ABICallStrategy] - strategy type to use for approval program's arg generation - * clear_arg_strat_type: Type[ABICallStrategy] | None - strategy type to use for clear program's arg generation - * approval_abi_args_mod: ABIArgsMod (default None) - used to specify any arg mutation - # TODO: currently there aren't any clear_abi_args_mod, but we might need for testing non-trivial clear programs + * approval_arg_strat_type: Type[ABICallStrategy] + - strategy type to use for approval program's arg generation + * clear_arg_strat_type_or_inputs: Type[ABICallStrategy] | Iterable[Sequence[PyTypes]] | None + - strategy type to use for clear program's arg generation + * approval_abi_args_mod: ABIArgsMod (default None) + - used to specify any arg mutation + # TODO: currently there aren't any clear_abi_args_mod, but we might need these for testing non-trivial clear programs * version: int - for compiling self.router * method_configs: ABICallConfigs - these drive all the test cases * assemble_constants: bool (optional) - for compiling self.router * optimize: OptimizeOptions (optional) - for compiling self.router - * num_dryruns: int (default 1) - the number of input runs to generate - per method X config combination - * txn_params: TxParams (optional) - other TxParams to append - -in addition to the (is_app_create, OnComplete) information + * num_dryruns: int (default 1) + - the number of input runs to generate per method X config combination + * txn_params: TxParams (optional) + - other TxParams to append in addition to the (is_app_create, OnComplete) information * model_version: int - for compiling self.model_router * model_assemble_constants: bool (optional) - for compiling self.model_router * model_optimize: OptimizeOptions (optional) - for compiling self.model_router * msg: string (optional) - message to report when an assertion is violated + * omit_approval_call: bool (default False) - allow purely testing the clear program + * omit_clear_call: bool (default False) - allow purely testing the approval program + NOTE: one of omit_approval_call or omit_clear_call must remain False + * executor_validation (default True) - when False, skip the DryRunExecutor's validation + * skip_validation (default False) - when False, skip the Router's validation """ def __init__( @@ -571,9 +577,9 @@ def __init__( @classmethod def _validate_router(cls, router: Router, kind: str = "Base") -> Router: - assert isinstance(router, Router), ( - f"Wrong type for {kind} Router: {type(router)}. Please provide: " f"Router." - ) + assert isinstance( + router, Router + ), f"Wrong type for {kind} Router: {type(router)}" cls._validate_method_configs(router.method_configs) return router @@ -604,7 +610,7 @@ def _validate_single_method_config(cls, call, meth_config): ), f"method_configs['{call}'] specifies NEVER to be called; for driving the test, each configured method should ACTUALLY be tested." assert ( meth_config.clear_state is CallConfig.NEVER - ), "meth_config's clear_state must be None, but isn't" + ), "unexpected value for method_config's clear_state" @classmethod def _validate_predicates(cls, predicates): @@ -722,14 +728,14 @@ def simulate_and_assert( assemble_constants: bool = False, optimize: OptimizeOptions | None = None, num_dryruns: int = 1, - omit_approval_call: bool = False, - omit_clear_call: bool = False, txn_params: TxParams | None = None, - executor_validation: bool = True, model_version: int | None = None, model_assemble_constants: bool = False, model_optimize: OptimizeOptions | None = None, msg: str = "", + omit_approval_call: bool = False, + omit_clear_call: bool = False, + executor_validation: bool = True, skip_validation: bool = False, ) -> RouterSimulationResults: assert not ( diff --git a/tests/unit/blackbox_test.py b/tests/unit/blackbox_test.py index c9bfc0792..b12b63e5f 100644 --- a/tests/unit/blackbox_test.py +++ b/tests/unit/blackbox_test.py @@ -298,7 +298,7 @@ def test_RouterSimulation_init(): algod = MagicMock(spec=AlgodClient) # many paths to misery: - err_msg = "Wrong type for Base Router: . Please provide: Router." + err_msg = "Wrong type for Base Router: " failing_RouterSimulation(router, model_router, predicates, algod, err_msg) router = pt.Router("test_router") @@ -336,7 +336,7 @@ def test_RouterSimulation_init(): failing_RouterSimulation(router, model_router, predicates, algod, err_msg) predicates = {"bar": {DRProp.passed: True}, "foo": {DRProp.budgetAdded: 45}} - err_msg = "Wrong type for Model Router: . Please provide: Router." + err_msg = "Wrong type for Model Router: " failing_RouterSimulation(router, model_router, predicates, algod, err_msg) model_router = pt.Router("test_router") From 98c6d5ebd15d882f698aaba4a490b784b30863ce Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 7 Feb 2023 14:01:59 -0600 Subject: [PATCH 199/206] per CR suggestions --- tests/blackbox.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index 63e90303a..c1689de2e 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -506,6 +506,14 @@ def negate_cc(cc: CallConfig) -> CallConfig: return CallConfig(3 - cc) +@dataclass(frozen=True) +class RouterSimulationResults: + stats: dict[str, Any] + results: dict + approval_simulator: Simulation | None + clear_simulator: Simulation | None + + class RouterSimulation: """ Lifecycle of a RouterSimulation @@ -620,7 +628,7 @@ def _validate_predicates(cls, predicates): ) assert ( - predicates + len(predicates) > 0 ), "Please provide at least one method to call and assert against." for method, preds in predicates.items(): @@ -708,13 +716,6 @@ def _validate_meths_in_contract( f"method_configs has a method '{meth}' missing from {router_prefix}-Router's contract." ) - @dataclass(frozen=True) - class RouterSimulationResults: - stats: dict[str, Any] - results: dict - approval_simulator: Simulation | None - clear_simulator: Simulation | None - def simulate_and_assert( self, approval_args_strat_type: Type[ABIStrategy], @@ -886,7 +887,7 @@ def simulate_approval(on_create): update_stats(meth_name, len(self.predicates[meth_name])) # ---- Summary Statistics ---- # - return self.RouterSimulationResults( + return RouterSimulationResults( stats=stats, results=self.auto_path_results, approval_simulator=approve_sim, From 2e8e06f1b8b79b4bf14f4e1199895b5205198e04 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 7 Feb 2023 16:00:16 -0600 Subject: [PATCH 200/206] per CR suggestions --- tests/blackbox.py | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index c1689de2e..e05044f39 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -2,7 +2,7 @@ from copy import deepcopy from dataclasses import dataclass, asdict import json -from typing import Any, Callable, Dict, Final, Iterable, Literal, Sequence, Type, cast +from typing import Any, Callable, Final, Literal, Sequence, Type, cast import algosdk.abi as sdk_abi from algosdk.transaction import OnComplete @@ -22,7 +22,7 @@ ) from graviton.inspector import DryRunProperty as DRProp from graviton.models import ExecutionMode, PyTypes -from graviton.sim import Simulation, SimulationResults +from graviton.sim import InputStrategy, Simulation, SimulationResults from pyteal.compiler.compiler import OptimizeOptions from pyteal.ast.subroutine import OutputKwArgInfo @@ -479,11 +479,6 @@ def dryrun_one( ) -class _AutoPathDict(defaultdict): - def __init__(self): - super().__init__(lambda: _AutoPathDict()) - - def as_on_complete(oc_str: str) -> OnComplete: match oc_str: case "no_op": @@ -577,9 +572,9 @@ def __init__( self.algod: v2client.algod.AlgodClient = algod or algod_with_assertion() - self.auto_path_results: Dict[ + self.results: dict[ str | None, dict[tuple[bool, OnComplete], SimulationResults] - ] = _AutoPathDict() + ] = {} # ---- Validation ---- # @@ -720,7 +715,7 @@ def simulate_and_assert( self, approval_args_strat_type: Type[ABIStrategy], clear_args_strat_type_or_inputs: Type[ABIStrategy] - | Iterable[Sequence[PyTypes]] + | list[Sequence[PyTypes]] | None, approval_abi_args_mod: ABIArgsMod | None, version: int, @@ -841,7 +836,9 @@ def simulate_approval(on_create): approval_strat, txn_params=tp, msg=msg4simulate() ) assert sim_results.succeeded - self.auto_path_results[meth_name][(on_create, oc)] = sim_results + if meth_name not in self.results: + self.results[meth_name] = {} + self.results[meth_name][(on_create, oc)] = sim_results update_stats(meth_name, len(self.predicates[meth_name])) # weird walrus is_app_create := ... to fill closure of msg4simulate() @@ -855,19 +852,24 @@ def simulate_approval(on_create): assert double_check_at_least_one_method, "no method was simulated" # ---- CLEAR PROGRAM SIMULATION ---- # + clear_strat_or_inputs: InputStrategy # CallStrategy | Iterable[Sequence[PyTypes]] clear_sim: Simulation | None = None if not omit_clear_call: + assert clear_args_strat_type_or_inputs # therefore Type[ABIStrategy] | list[Sequence[PyTypes]] if isinstance(clear_args_strat_type_or_inputs, list): - clear_strat = clear_args_strat_type_or_inputs - num_dryruns = len(clear_strat) + clear_strat_or_inputs = cast( + list[Sequence[PyTypes]], clear_args_strat_type_or_inputs + ) + # for the closure of local update_stats(): + num_dryruns = len(clear_strat_or_inputs) else: - clear_strat = RandomArgLengthCallStrategy( + clear_strat_or_inputs = RandomArgLengthCallStrategy( cast(Type[ABIStrategy], clear_args_strat_type_or_inputs), max_args=2, num_dryruns=num_dryruns, min_args=0, type_for_args=sdk_abi.ABIType.from_string("byte[8]"), - ) # type: ignore + ) meth_name = CLEAR_STATE_CALL is_app_create = False @@ -881,15 +883,19 @@ def simulate_approval(on_create): validation=executor_validation, ) - sim_results = clear_sim.run_and_assert(clear_strat, msg=msg4simulate()) + sim_results = clear_sim.run_and_assert( + clear_strat_or_inputs, msg=msg4simulate() + ) assert sim_results.succeeded - self.auto_path_results[meth_name][(is_app_create, oc)] = sim_results + if meth_name not in self.results: + self.results[meth_name] = {} + self.results[meth_name][(is_app_create, oc)] = sim_results update_stats(meth_name, len(self.predicates[meth_name])) # ---- Summary Statistics ---- # return RouterSimulationResults( stats=stats, - results=self.auto_path_results, + results=self.results, approval_simulator=approve_sim, clear_simulator=clear_sim, ) From 510dde8f0ebdb7213711e1a989fb5b304e6f56ef Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Wed, 8 Feb 2023 08:54:20 -0600 Subject: [PATCH 201/206] Update tests/blackbox.py Co-authored-by: Hang Su <87964331+ahangsu@users.noreply.github.com> --- tests/blackbox.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index e05044f39..ce4370cff 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -590,7 +590,7 @@ def _validate_router(cls, router: Router, kind: str = "Base") -> Router: @classmethod def _validate_method_configs(cls, method_configs): assert isinstance( - method_configs, (dict) + method_configs, dict ), f"method_configs '{method_configs}' has type {type(method_configs)} but only 'dict' and 'NoneType' are allowed." assert ( From deca0acba00c971c10dbe1e7c7a78a60cf7c641d Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Wed, 8 Feb 2023 12:44:18 -0600 Subject: [PATCH 202/206] per CR suggestion: tighten up local functions and closure declarations --- tests/blackbox.py | 101 ++++++++++++++++++++++++++-------------------- 1 file changed, 58 insertions(+), 43 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index ce4370cff..5a71463bf 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -738,6 +738,59 @@ def simulate_and_assert( omit_approval_call and omit_clear_call ), "Aborting and failing as all tests are being omitted" + # --- setup local functions including reporter and stats. Also declare closure vars --- # + + # for purposes of clarity, defining all the variables for closures before each function: + approve_sim: Simulation | None # required for return RouterResults + + # msg4simulate: + + # msg - cf. parameters + approval_strat: ABICallStrategy | None + meth_name: str | None # simulate_approval's closure as well + call_cfg: CallConfig | None + is_app_create: bool + stats: dict[str, int | str] = defaultdict(int) + + def msg4simulate() -> str: + return f"""user provide message={msg} +call_strat={type(approval_strat)} +{meth_name=} +{oc=} +{call_cfg=} +{is_app_create=} +{len(self.predicates[meth_name])=} +{stats["method_combo_count"]=} +{stats["dryrun_count"]=} +{stats["assertions_count"]=} +""" + + # update_stats: + # num_dryruns - cf. parameters + # stats - cf. above + def update_stats(meth, num_preds): + stats[str(meth)] += num_dryruns + stats["method_combo_count"] += 1 + stats["dryrun_count"] += num_dryruns + stats["assertions_count"] += num_dryruns * num_preds + + # simulate_approval: + # txn_params - cf. parameters + oc: OnComplete + # approval_strat - cf. above + + def simulate_approval(on_create): + tp: TxParams = deepcopy(txn_params) + tp.update_fields(TxParams.for_app(is_app_create=on_create, on_complete=oc)) + sim_results = approve_sim.run_and_assert( + approval_strat, txn_params=tp, msg=msg4simulate() + ) + assert sim_results.succeeded + if meth_name not in self.results: + self.results[meth_name] = {} + self.results[meth_name][(on_create, oc)] = sim_results + update_stats(meth_name, len(self.predicates[meth_name])) + # --- Compile Programs --- # approval_teal, clear_teal, contract = self.router.compile_program( version=version, assemble_constants=assemble_constants, optimize=optimize @@ -774,36 +827,9 @@ def simulate_and_assert( if not txn_params: txn_params = TxParams() - stats: dict[str, int | str] = defaultdict(int) stats["name"] = self.router.name - # --- setup reporter and stats --- # - - meth_name: Any - - def msg4simulate() -> str: - return f"""user provide message={msg} -call_strat={type(approval_strat)} -{meth_name=} -{oc=} -{call_cfg=} -{is_app_create=} -{len(self.predicates[meth_name])=} -{stats["method_combo_count"]=} -{stats["dryrun_count"]=} -{stats["assertions_count"]=} -""" - - def update_stats(meth, num_preds): - stats[str(meth)] += num_dryruns - stats["method_combo_count"] += 1 - stats["dryrun_count"] += num_dryruns - stats["assertions_count"] += num_dryruns * num_preds - # ---- APPROVAL PROGRAM SIMULATION ---- # - approval_strat = None - call_cfg = None - approve_sim = None if not omit_approval_call: approval_strat = ABICallStrategy( json.dumps(contract.dictify()), @@ -827,31 +853,20 @@ def update_stats(meth, num_preds): for oc_str, call_cfg in asdict(meth_cfg).items(): oc = as_on_complete(oc_str) - def simulate_approval(on_create): - tp: TxParams = deepcopy(txn_params) - tp.update_fields( - TxParams.for_app(is_app_create=on_create, on_complete=oc) - ) - sim_results = approve_sim.run_and_assert( - approval_strat, txn_params=tp, msg=msg4simulate() - ) - assert sim_results.succeeded - if meth_name not in self.results: - self.results[meth_name] = {} - self.results[meth_name][(on_create, oc)] = sim_results - update_stats(meth_name, len(self.predicates[meth_name])) - # weird walrus is_app_create := ... to fill closure of msg4simulate() - if call_cfg & CallConfig.CALL: + if cast(CallConfig, call_cfg) & CallConfig.CALL: double_check_at_least_one_method = True simulate_approval(is_app_create := False) - if call_cfg & CallConfig.CREATE: + if cast(CallConfig, call_cfg) & CallConfig.CREATE: double_check_at_least_one_method = True simulate_approval(is_app_create := True) assert double_check_at_least_one_method, "no method was simulated" # ---- CLEAR PROGRAM SIMULATION ---- # + approval_strat = None + call_cfg = None + approve_sim = None clear_strat_or_inputs: InputStrategy # CallStrategy | Iterable[Sequence[PyTypes]] clear_sim: Simulation | None = None if not omit_clear_call: From ac8ad40f04e10ef1aea8042bae6de2710326fa98 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Wed, 8 Feb 2023 12:59:15 -0600 Subject: [PATCH 203/206] Apply suggestions from code review --- tests/blackbox.py | 2 +- tests/integration/abi_router_test.py | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/blackbox.py b/tests/blackbox.py index 5a71463bf..0b0aafc9d 100644 --- a/tests/blackbox.py +++ b/tests/blackbox.py @@ -740,7 +740,7 @@ def simulate_and_assert( # --- setup local functions including reporter and stats. Also declare closure vars --- # - # for purposes of clarity, defining all the variables for closures before each function: + # for purposes of clarity, declare all the variables for closures before each function: approve_sim: Simulation | None # required for return RouterResults # msg4simulate: diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index 850131bd9..3da6457f9 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -36,8 +36,8 @@ TYPICAL_IAC_OC = pt.MethodConfig(no_op=pt.CallConfig.CALL) # TEST DRIVERS LEGEND - combines method_configs + predicates -# * @0 - method: str -# method == `None` indicates bare app call +# * @0 - method: RouterCallType +# method == None indicates bare app call # # * @1 - method_config: MethodConfig # defines how to call the method @@ -202,6 +202,7 @@ def msg(): print("\nstats:", json.dumps(stats := results.stats, indent=2)) assert stats and all(stats.values()) + # TODO: add these assertions after the flakiness of issue #199 is fixed for good # These fail because of differing scratch slot assignments: # pregen_approval, pregen_clear = ROUTER_SOURCES[(case, version)] # assert pregen_clear == results.clear_simulator.simulate_dre.program @@ -288,10 +289,8 @@ def msg(): scenario = "I. explore all UNEXPECTED (is_app_create, on_complete) combos" # NOTE: We're NOT including clear_state calls for the approval program - # as though they would never be applied. + # as they would never be applied. # Also, we're ONLY including clear_state for the clear program. - # Finally, when no bare app calls are provided in method_configs, - # we still test the bare app call case. neg_mconfigs = { meth: pt.MethodConfig( **{k: negate_cc(v) for k, v in asdict(mc).items() if k != "clear_state"} @@ -337,7 +336,7 @@ def msg(): else: scenario_assert_stats(scenario, None, totals) - # For the rest, we may assume method calls (non bare-app-call) + # For the rest, we may assume method calls (i.e. non bare-app calls) # III. explore changing method selector arg[0] by edit distance 1 # NOTE: We don't test the case of adding an argument to method calls @@ -450,7 +449,7 @@ def test_nontriv_clear(): nontriv_clear, predicates, model_router=questionable ) - # Sanity check the approval programs (POSITIVE CASES): + # Sanity check the approval programs (_POSITIVE_ cases only): msg = "APPROVAL nontriv@v6 vs. questionable@v8" version = 6 results = rsim_nt_vs_q.simulate_and_assert( From 122879b20c992baff9eabc50e1ee5b058539b756 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Wed, 8 Feb 2023 15:42:49 -0600 Subject: [PATCH 204/206] Update tests/integration/abi_router_test.py Co-authored-by: Hang Su <87964331+ahangsu@users.noreply.github.com> --- tests/integration/abi_router_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index 3da6457f9..1282435f1 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -42,7 +42,7 @@ # * @1 - method_config: MethodConfig # defines how to call the method # -# * @3 - predicates: Predicates ~ dict[DRProp, Any] +# * @2 - predicates: Predicates ~ dict[DRProp, Any] # these are being asserted after being processed into Invariant's # # NOTE: the "yacc" routers will simply ignore the case with method `None` From 7dcb5c026f0c636d13bddaaa859bf39f776c9a48 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Wed, 8 Feb 2023 15:43:10 -0600 Subject: [PATCH 205/206] Update tests/integration/abi_router_test.py Co-authored-by: Hang Su <87964331+ahangsu@users.noreply.github.com> --- tests/integration/abi_router_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index 1282435f1..1b13afa69 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -38,6 +38,7 @@ # TEST DRIVERS LEGEND - combines method_configs + predicates # * @0 - method: RouterCallType # method == None indicates bare app call +# method == CLEAR_STATE_CALL indicates clear state app call # # * @1 - method_config: MethodConfig # defines how to call the method From 89abe752b55355a337a4cbd40f64f72f0a0ea267 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Wed, 8 Feb 2023 16:00:47 -0600 Subject: [PATCH 206/206] per CR suggestions --- pyteal/compiler/compiler_test.py | 8 +------- tests/integration/abi_router_test.py | 4 ++-- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/pyteal/compiler/compiler_test.py b/pyteal/compiler/compiler_test.py index 6e93e80d0..5e855944f 100644 --- a/pyteal/compiler/compiler_test.py +++ b/pyteal/compiler/compiler_test.py @@ -2347,15 +2347,9 @@ def append_router_info(rinfo, programs): ) assert "Frame pointers aren't available" in str(e.value) - def router_compilarison(router, version, fixture_ap, fixture_csp, key, write=False): + def router_compilarison(router, version, fixture_ap, fixture_csp, key): actual_ap, actual_csp, _ = router.compile_program(version=version) - # if write: - # with open(ROUTER_FIXTURES / fixture_ap, "w") as f: - # f.write(actual_ap) - # with open(ROUTER_FIXTURES / fixture_csp, "w") as f: - # f.write(actual_csp) - with open(ROUTER_FIXTURES / fixture_ap) as f: expected_ap_with_oc = f.read() with open(ROUTER_FIXTURES / fixture_csp) as f: diff --git a/tests/integration/abi_router_test.py b/tests/integration/abi_router_test.py index 1b13afa69..8f53db916 100644 --- a/tests/integration/abi_router_test.py +++ b/tests/integration/abi_router_test.py @@ -459,7 +459,7 @@ def test_nontriv_clear(): approval_abi_args_mod=None, version=version, method_configs=mconfigs, - num_dryruns=7, + num_dryruns=NUM_ROUTER_DRYRUNS, omit_clear_call=True, model_version=8, msg=msg, @@ -477,7 +477,7 @@ def test_nontriv_clear(): approval_abi_args_mod=None, version=version, method_configs=mconfigs, - num_dryruns=7, + num_dryruns=NUM_ROUTER_DRYRUNS, omit_clear_call=True, model_version=8, msg=msg,