Skip to content

Commit

Permalink
Add handler for allowing Txna in InnerTxnBuilder (#384)
Browse files Browse the repository at this point in the history
Allow SetField(s) to accept the foreign reference array directly
  • Loading branch information
barnjamin committed Aug 3, 2022
1 parent 79df68b commit 338b1ee
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 21 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Unreleased
## Added
* Add the ability to pass foreign reference arrays directly into inner transactions ([#384](https://github.com/algorand/pyteal/pull/384))

## Fixed

Expand Down
2 changes: 2 additions & 0 deletions pyteal/ast/abi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
make,
size_of,
type_spec_from_annotation,
type_specs_from_signature,
contains_type_spec,
)

Expand Down Expand Up @@ -140,6 +141,7 @@
"KeyRegisterTransactionTypeSpec",
"TransactionTypeSpecs",
"type_spec_from_annotation",
"type_specs_from_signature",
"make",
"size_of",
"algosdk_from_annotation",
Expand Down
58 changes: 40 additions & 18 deletions pyteal/ast/itxn.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
from enum import Enum
from typing import TYPE_CHECKING, cast
import algosdk

from pyteal.ast.abi.util import type_specs_from_signature
from typing import TYPE_CHECKING, cast
from pyteal.ast.int import EnumInt
from pyteal.ast.for_ import For
from pyteal.ast.int import Int
from pyteal.ast.scratchvar import ScratchVar

from pyteal.ast.methodsig import MethodSignature
from pyteal.types import TealType, require_type
from pyteal.errors import TealInputError, TealTypeError, verifyProgramVersion
from pyteal.ir import TealOp, Op, TealBlock
from pyteal.ast.expr import Expr
from pyteal.ast.txn import TxnField, TxnExprBuilder, TxnType, TxnaExprBuilder, TxnObject
from pyteal.ast.txn import (
TxnType,
TxnArray,
TxnField,
TxnExprBuilder,
TxnaExprBuilder,
TxnObject,
)
from pyteal.ast.seq import Seq
from pyteal.ast.bytes import Bytes
from pyteal.ast import abi
Expand Down Expand Up @@ -149,6 +159,7 @@ def SetField(cls, field: TxnField, value: 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.
It is also possible to pass the entire array field if desired (e.g., Txn.accounts) to pass all the references.
Requires program version 5 or higher. This operation is only permitted in application mode.
Expand All @@ -158,33 +169,43 @@ def SetField(cls, field: TxnField, value: Expr | list[Expr]) -> Expr:
compatible with the field being set.
"""
if not field.is_array:
if type(value) is list:
if type(value) is list or isinstance(value, TxnArray):
raise TealInputError(
"inner transaction set field {} does not support array value".format(
field
)
)
return InnerTxnFieldExpr(field, cast(Expr, value))
else:
if type(value) is not list:
if type(value) is not list and not isinstance(value, TxnArray):
raise TealInputError(
"inner transaction set array field {} with non-array value".format(
field
)
)
for valueIter in value:
if not isinstance(valueIter, Expr):
raise TealInputError(
"inner transaction set array field {} with non PyTeal expression array element {}".format(
field, valueIter

if type(value) is list:
for valueIter in value:
if not isinstance(valueIter, Expr):
raise TealInputError(
"inner transaction set array field {} with non PyTeal expression array element {}".format(
field, valueIter
)
)
)
return Seq(
*[
InnerTxnFieldExpr(field, cast(Expr, valueIter))
for valueIter in value
]
)

return Seq(
*[
InnerTxnFieldExpr(field, cast(Expr, valueIter))
for valueIter in value
]
)
else:
arr = cast(TxnArray, value)
return For(
(i := ScratchVar()).store(Int(0)),
i.load() < arr.length(),
i.store(i.load() + Int(1)),
).Do(InnerTxnFieldExpr(field, arr[i.load()]))

@classmethod
def Execute(cls, fields: dict[TxnField, Expr | list[Expr]]) -> Expr:
Expand Down Expand Up @@ -216,6 +237,7 @@ def SetFields(cls, fields: dict[TxnField, 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.
It is also possible to pass the entire array field if desired (e.g., Txn.accounts) to pass all the references.
Requires program version 5 or higher. This operation is only permitted in application mode.
Expand Down Expand Up @@ -273,7 +295,7 @@ def MethodCall(

# We only care about the args
arg_type_specs: list[abi.TypeSpec]
arg_type_specs, _ = type_specs_from_signature(method_signature)
arg_type_specs, _ = abi.type_specs_from_signature(method_signature)

if len(args) != len(arg_type_specs):
raise TealInputError(
Expand Down
26 changes: 23 additions & 3 deletions pyteal/ast/itxn_test.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import pytest

import pyteal as pt
from pyteal.ast.txn import TxnField, TxnType
from pyteal.ast.txn import Txn, TxnField, TxnType
from pyteal.types import types_match

avm4Options = pt.CompileOptions(version=4)
Expand Down Expand Up @@ -111,6 +111,16 @@ def test_InnerTxnBuilder_SetField():
),
),
),
(
{pt.TxnField.accounts: pt.Txn.accounts},
pt.For(
(i := pt.ScratchVar()).store(pt.Int(0)),
i.load() < pt.Txn.accounts.length(),
i.store(i.load() + pt.Int(1)),
).Do(
pt.InnerTxnBuilder.SetField(pt.TxnField.accounts, [Txn.accounts[i.load()]])
),
),
]


Expand All @@ -128,9 +138,14 @@ def test_InnerTxnBuilder_SetFields():
actual.addIncoming()
actual = pt.TealBlock.NormalizeBlocks(actual)

with pt.TealComponent.Context.ignoreExprEquality():
with pt.TealComponent.Context.ignoreScratchSlotEquality(), pt.TealComponent.Context.ignoreExprEquality():
assert actual == expected

assert pt.TealBlock.MatchScratchSlotReferences(
pt.TealBlock.GetReferencedScratchSlots(actual),
pt.TealBlock.GetReferencedScratchSlots(expected),
)

if len(fields) != 0:
with pytest.raises(pt.TealInputError):
expr.__teal__(avm4Options)
Expand All @@ -152,9 +167,14 @@ def test_InnerTxnBuilder_Execute():
actual.addIncoming()
actual = pt.TealBlock.NormalizeBlocks(actual)

with pt.TealComponent.Context.ignoreExprEquality():
with pt.TealComponent.Context.ignoreScratchSlotEquality(), pt.TealComponent.Context.ignoreExprEquality():
assert actual == expected

assert pt.TealBlock.MatchScratchSlotReferences(
pt.TealBlock.GetReferencedScratchSlots(actual),
pt.TealBlock.GetReferencedScratchSlots(expected),
)

with pytest.raises(pt.TealInputError):
expr.__teal__(avm4Options)

Expand Down

0 comments on commit 338b1ee

Please sign in to comment.