Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AVM Boxes Ops in Pyteal #438

Merged
merged 50 commits into from
Jul 20, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
5bb0d09
add box ops
barnjamin Jun 1, 2022
ff16945
full support on ops
ahangsu Jul 12, 2022
c6b4b91
first set of test, add versioning in multi
ahangsu Jul 12, 2022
9be38c3
remove some seemingly not necessary code?
ahangsu Jul 12, 2022
f6c63de
update testcase
ahangsu Jul 12, 2022
7389aeb
check invalid arguments
ahangsu Jul 13, 2022
8f41bad
finish testcase
ahangsu Jul 13, 2022
26aa362
move stuffs to app
ahangsu Jul 13, 2022
1305ea8
Merge remote-tracking branch 'origin/avm8' into feature/avm-box
ahangsu Jul 13, 2022
ec831e2
version check trick
ahangsu Jul 13, 2022
7dd22a6
Merge branch 'avm8' into feature/avm-box
ahangsu Jul 13, 2022
2944475
verifyTealVersion apply
ahangsu Jul 13, 2022
eec18ea
error message
ahangsu Jul 14, 2022
d6766d5
Merge branch 'avm8' into feature/avm-box
ahangsu Jul 14, 2022
949acd6
update docs structures
ahangsu Jul 14, 2022
ba77a22
period
ahangsu Jul 15, 2022
2767d12
update doc
ahangsu Jul 15, 2022
0a977b2
update doc
ahangsu Jul 18, 2022
28546dd
update doc
ahangsu Jul 18, 2022
3781fcb
per pr review on implementation
ahangsu Jul 19, 2022
75c08e3
Update docs/state.rst
ahangsu Jul 19, 2022
8a6738f
Update docs/state.rst
ahangsu Jul 19, 2022
abfffcf
Update docs/state.rst
ahangsu Jul 19, 2022
10c0730
Update docs/state.rst
ahangsu Jul 19, 2022
35d7e25
Update docs/state.rst
ahangsu Jul 19, 2022
1b95772
Update docs/state.rst
ahangsu Jul 19, 2022
198587e
Update docs/state.rst
ahangsu Jul 19, 2022
c819c78
Update docs/state.rst
ahangsu Jul 19, 2022
05d7b5c
Update docs/state.rst
ahangsu Jul 19, 2022
9285662
hex box size goes wild
ahangsu Jul 19, 2022
ae15c6f
Update docs/state.rst
ahangsu Jul 19, 2022
230894e
warning about MBR
ahangsu Jul 19, 2022
00767c2
Merge branch 'feature/avm-box' of github.com:algorand/pyteal into fea…
ahangsu Jul 19, 2022
eeb1b09
wording
ahangsu Jul 19, 2022
c1b2f15
Update docs/state.rst
ahangsu Jul 19, 2022
1aebe98
Merge branch 'feature/avm-box' of github.com:algorand/pyteal into fea…
ahangsu Jul 19, 2022
a5d6bf9
emphasize
ahangsu Jul 19, 2022
e384df6
Update docs/state.rst
ahangsu Jul 19, 2022
81e5f7a
Update docs/state.rst
ahangsu Jul 19, 2022
d4c3af8
Merge branch 'feature/avm-box' of github.com:algorand/pyteal into fea…
ahangsu Jul 19, 2022
65b404a
polishing
ahangsu Jul 19, 2022
a835be2
remove redundant box_put doc segment
ahangsu Jul 19, 2022
3d39d3f
per zeph pr review
ahangsu Jul 19, 2022
1185948
use note and warning
ahangsu Jul 19, 2022
16152ee
per zeph's pr review
ahangsu Jul 19, 2022
60439f6
Update docs/state.rst
ahangsu Jul 20, 2022
ef5e7f7
creating boxes
ahangsu Jul 20, 2022
ec5e8c4
Update docs/state.rst
ahangsu Jul 20, 2022
f4c581e
per pr review
ahangsu Jul 20, 2022
5481e8e
table for state types
ahangsu Jul 20, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions pyteal/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ __all__ = [
"BitwiseNot",
"BitwiseOr",
"BitwiseXor",
"BoxCreate",
michaeldiamant marked this conversation as resolved.
Show resolved Hide resolved
"BoxDelete",
"BoxExtract",
"BoxGet",
"BoxLen",
"BoxPut",
"BoxReplace",
"Break",
"Btoi",
"Bytes",
Expand Down
17 changes: 17 additions & 0 deletions pyteal/ast/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@
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 (
BoxCreate,
BoxDelete,
BoxExtract,
BoxReplace,
BoxLen,
BoxGet,
BoxPut,
)


# inner txns
from pyteal.ast.itxn import InnerTxnBuilder, InnerTxn, InnerTxnAction
Expand Down Expand Up @@ -146,6 +156,13 @@
"LeafExpr",
"Addr",
"Bytes",
"BoxCreate",
"BoxDelete",
"BoxReplace",
"BoxExtract",
"BoxLen",
"BoxGet",
"BoxPut",
"Int",
"EnumInt",
"MethodSignature",
Expand Down
87 changes: 86 additions & 1 deletion pyteal/ast/app.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
from typing import TYPE_CHECKING
from enum import Enum
from pyteal.ast.box import (
BoxCreate,
BoxDelete,
BoxExtract,
BoxReplace,
BoxLen,
BoxGet,
BoxPut,
)

from pyteal.types import TealType, require_type
from pyteal.ir import TealOp, Op, TealBlock
Expand Down Expand Up @@ -181,7 +190,7 @@ def globalPut(cls, key: Expr, value: Expr) -> "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)
Expand Down Expand Up @@ -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"

Expand Down
226 changes: 226 additions & 0 deletions pyteal/ast/box.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
from typing import TYPE_CHECKING
from pyteal.ast.maybe import MaybeValue
from pyteal.errors import TealInputError

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"):
if options.version < Op.box_create.min_version:
michaeldiamant marked this conversation as resolved.
Show resolved Hide resolved
raise TealInputError(
f"BoxCreate not available on teal version {options.version} (first available {Op.box_create.min_version})"
)

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 it's name"""
ahangsu marked this conversation as resolved.
Show resolved Hide resolved

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"):
if options.version < Op.box_del.min_version:
raise TealInputError(
f"BoxDelete not available on teal version {options.version} (first available {Op.box_del.min_version})"
)

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"):
if options.version < Op.box_replace.min_version:
raise TealInputError(
f"BoxReplace not available on teal version {options.version} (first available {Op.box_del.min_version})"
)

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"):
if options.version < Op.box_extract.min_version:
raise TealInputError(
f"BoxExtract not available on teal version {options.version} (first available {Op.box_extract.min_version})"
)

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"):
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, 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"
Loading