From 1cd673fa2b83f08dac69413aa479508cc68194d1 Mon Sep 17 00:00:00 2001 From: Hang Su Date: Tue, 12 Jul 2022 15:51:57 -0400 Subject: [PATCH] full support on ops --- pyteal/__init__.pyi | 3 ++ pyteal/ast/__init__.py | 5 ++- pyteal/ast/box.py | 78 ++++++++++++++++++++++++++++++++++++++++-- pyteal/ast/box_test.py | 5 +++ pyteal/ir/ops.py | 3 ++ 5 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 pyteal/ast/box_test.py diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index be21fb2df..374083dad 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -47,6 +47,9 @@ __all__ = [ "BoxCreate", "BoxDelete", "BoxExtract", + "BoxGet", + "BoxLen", + "BoxPut", "BoxReplace", "Break", "Btoi", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 52f254ae9..74c86ad2d 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -27,7 +27,7 @@ from pyteal.ast.app import App, AppField, OnComplete, AppParam from pyteal.ast.asset import AssetHolding, AssetParam from pyteal.ast.acct import AccountParam -from pyteal.ast.box import Box, BoxCreate, BoxDelete, BoxExtract, BoxReplace +from pyteal.ast.box import Box, BoxCreate, BoxDelete, BoxExtract, BoxReplace, BoxLen, BoxGet, BoxPut # inner txns @@ -153,6 +153,9 @@ "BoxDelete", "BoxReplace", "BoxExtract", + "BoxLen", + "BoxGet", + "BoxPut", "Int", "EnumInt", "MethodSignature", diff --git a/pyteal/ast/box.py b/pyteal/ast/box.py index c1accd849..fb9a0bc69 100644 --- a/pyteal/ast/box.py +++ b/pyteal/ast/box.py @@ -1,4 +1,5 @@ from typing import TYPE_CHECKING +from pyteal.ast.maybe import MaybeValue from pyteal.errors import TealInputError from pyteal.types import TealType, require_type @@ -26,6 +27,18 @@ def extract(name: Expr, start: Expr, stop: Expr) -> "BoxExtract": def replace(name: Expr, start: Expr, value: Expr) -> "BoxReplace": return BoxReplace(name, start, value) + @staticmethod + def length(name: Expr) -> "MaybeValue": + return BoxLen(name) + + @staticmethod + def get(name: Expr) -> "MaybeValue": + return BoxGet(name) + + @staticmethod + def put(name: Expr, value: Expr) -> "BoxPut": + return BoxPut(name, value) + class BoxCreate(Expr): """Create a box with a given name and size.""" @@ -54,7 +67,7 @@ def __teal__(self, options: "CompileOptions"): ) def __str__(self): - return "(box_create {} {})".format(self.name, self.size) + return f"(box_create {self.name} {self.size})" def type_of(self): return TealType.none @@ -87,7 +100,7 @@ def __teal__(self, options: "CompileOptions"): return TealBlock.FromOp(options, TealOp(self, Op.box_del), self.name) def __str__(self): - return "(box_del {})".format(self.name) + return f"(box_del {self.name})" def type_of(self): return TealType.none @@ -170,7 +183,7 @@ def __teal__(self, options: "CompileOptions"): ) def __str__(self): - return "(box_extract {} {} {})".format(self.name, self.start, self.stop) + return f"(box_extract {self.name} {self.start} {self.stop})" def type_of(self): return TealType.bytes @@ -180,3 +193,62 @@ def has_return(self): 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"): + if options.version < Op.box_put.min_version: + raise TealInputError( + f"BoxPut not available on teal version {options.version} (first available {Op.box_put.min_version})" + ) + + return TealBlock.FromOp(options, TealOp(self, Op.box_put), self.name) + + 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..2fd482436 --- /dev/null +++ b/pyteal/ast/box_test.py @@ -0,0 +1,5 @@ +import pytest +import pyteal as pt + +teal6Options = pt.CompileOptions(version=6) +teal7Options = pt.CompileOptions(version=7) diff --git a/pyteal/ir/ops.py b/pyteal/ir/ops.py index ff545191b..7d90ab8e2 100644 --- a/pyteal/ir/ops.py +++ b/pyteal/ir/ops.py @@ -183,6 +183,9 @@ def min_version(self) -> int: box_extract = OpType("box_extract", Mode.Application, 7) box_replace = OpType("box_replace", Mode.Application, 7) box_del = OpType("box_del", Mode.Application, 7) + box_len = OpType("box_len", Mode.Application, 7) + box_get = OpType("box_get", Mode.Application, 7) + box_put = OpType("box_put", Mode.Application, 7) # fmt: on