Skip to content

Commit

Permalink
Changes to avm8 docs (#546)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonpaulos authored Sep 29, 2022
1 parent 5282726 commit 76010b2
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 55 deletions.
63 changes: 37 additions & 26 deletions docs/state.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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."))
Expand Down Expand Up @@ -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.
Expand All @@ -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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand All @@ -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::
Expand Down
42 changes: 23 additions & 19 deletions pyteal/ast/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -232,19 +238,21 @@ 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.
"""
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.
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -277,18 +283,16 @@ 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.
"""
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.
Expand Down
16 changes: 8 additions & 8 deletions pyteal/ast/box_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions pyteal/ast/maybe.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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]
Expand Down

0 comments on commit 76010b2

Please sign in to comment.