Skip to content

Commit

Permalink
ABI Router implementation and test (#170)
Browse files Browse the repository at this point in the history
* init commit

* minor

* minor

* rm decorator

* update ABI router design, seems we are still working on previous design

* minor

* update condition parser here

* skeleton for handler wrapping, need to tweak on subroutine to expose more message

* module

* use subroutine fn wrapper

* update dummy method return class

* unify ast construct way

* minor

* update notes for tasks and todos

* update handler wrapping for bare app call

* minor

* update redirecting args to method registered

* minor

* minor

* update router src

* update program node

* add questions in build prog

* update executing method branch

* minor

* minor

* minor

* hide other methods, set MethodAppArgNumLimit, keyword args on exposed register func, skeleton for arg de-tuple

* minor

* update notes

* update

* add a default for no registered ast gen

* update ast construction to conds

* need some documentations

* move abi-router in abi dir

* minor

* wtf

* update

* update to f-str

* define void type

* update instantiated computed type returnedType for ABI return in subroutine

* minor

* update stuffs to help infer type annotation of return ABI

* minor

* minor

* minor

* minor

* minor

* try my best to save stuffs

* simplify decorator to single function

* tear it down

* minor

* sheeeesh emacs

* update with latest abi impl

* minors

* minor

* updates

* minor, renaming something

* new design, start over

* updates

* abi fn wrapper for now

* minor

* minor update on subroutine def

* minor fixes

* minor fixes

* changes

* more constraint on void ret

* update comment examples

* import from abi

* update some error msg and comments

* testcases partial

* upgrade testscripts

* merging feature/abi to abi-router (#305)

* merging feature/abi

* missed one

* make router use absolute imports

* linter happy?

* Export Router (#306)

* Merge branch 'master' into feature/abi (#284)

* Move to pyteal as pt in ABI tests with concise  prefix (#286)

* ABI Strings (#278)

* Move to pyteal as pt in #278 (#287)

* Merge absolute imports into feature/abi (#288)

* Remove temporary I252 ignore on pyteal.ast.abi (#290)

* Fix abi import (#303)

* Fix abi import

* ignore flake8

* move router to ast

Co-authored-by: Michael Diamant <michaeldiamant@users.noreply.github.com>
Co-authored-by: Jason Paulos <jasonpaulos@users.noreply.github.com>

* fix spacing issue

* Bundle optional refactorings to subroutine.py (#308)

* Bundle optional refactorings to subroutine.py

* Refactor to remove branching

* storing local changes

* pr review partly

* pr review partly

* update test script

* Abi subroutine feature merge (#315)

* resolve conflicts

* lint

* minor reconstruct

* missing imports

* missing requirements from bad merge

* cooperate with typespec n var def change

* update comments

* some comments resolving?

* trim

* update some comments

* bring testcase back

* restriction on output kwarg name

* stop ci! i am reformatting

* squash merge abi subroutine atm, merge again after abi subroutine into feature/abi

* conform to pep8, reconstructing

* update json generator

* simplify name constrain

* resolving comments

* Use deferred subroutine expression for ABI returns (#328)

* Add subroutine deferred expr

* Allow multiple deferred blocks

* Remove error

* flake8

* Make test more realistic

* Add second test

* clean up code and comments

* remove deferred blocks function

* Add coverage for multiple ops in block error

* updating wrap handler

* change how to de-tuple args

* update checkbox

* minor

* bug fixes

* Method sig for router (#340)

* adding method_signature to ABIReturnSubroutine

* minor, renaming

* minor

* simplify

* compiler test adding...

* documentation

* start testcases

* update router testcase

* docstring tweak

* update testcases

* update testcases

* formatting

* branch cond testing

* router contract test

* subroutine branch wrapper bare call case tested

* more testcases to barecall

* minor, need to work on method call wrapper

* half done on method call wrapper

* update on abi method wrapper with return

* detuple testcase

* compiler test need to see csp

* rm redundant type annotation

* more error msg

* renaming

* renaming is_registrable -> is_abi_routable

* reording imports, eliminate anti patterns

* remove anti-pattern

* section it out

* non_empty_power_set -> power_set

* add conflict detection to protect AST from overshadowing

* error message

* shrinked commits on pr review

* add compile_program

* fixup subroutine testcase

* remove method signature specifying, directly infer from ABIReturnSubroutine

* remove method sign field, directly infer from ABIReturnSubroutine

* relaxation of bare app call arg num restriction

* add barecall class, api change following

* rename barecall to OnCompleteAction

* remove outdated comments

* start changing router api

* eliminate contradiction for oc and creation

* remove restriction on cond

* new interface: add bare-calls on init, register method-call more fine-grained

* documentation for new interface from last discussion

* Refactor #170 to reduce visibility and mutation (#362)

* Refactor to use partition

* Designate _oc_under_call_config as private

* hide wrap handler method

* adding comment changes

* pr review partly

* partition into two methods

* hide all these methods

* arc4 compliant CallConfigs classmethod

* arc4 compliant CallConfigs documentation

* disclaimer comments

* update new abi return hash prefix

* review comments partly

* OnCompleteActions -> BareCallActions

* disclaimer change, rename CallConfigs -> MethodConfig

* disclaimer move to docstring

* better naming for naming prefix

* new ast builder

* review comments

* An attempt to add decorator syntax to abi-router (#370)

* an attempt to use decorator

* no return, or we will have python-level issue?

* minor fix

* per pr comment on on-complete-action

* eliminate potential issue

* update call config testcase

* add testcase for on complete action

* per comments

* Add a check in `method_signature` to disallow reference return types (#368)

* new ast builder

* adding check in method_signature to raise error if its attempted to be called on method with reference type as return value

* use type spec instead of str

* adding recursive type checking method and using it in subroutine method signature

* Adding one more test case for extra nesting

* appease the linter

Co-authored-by: Hang Su <hang.su@algorand.com>

* add new compiler tests for router

* fix one test for wrapping bare calls

* comments fixing

* simplified oc-action post_init check

* naming variables

* comments

* comments

* testcase for method config update

* add router method only in clearstate prog

* closeout -> clearstate

* removing is_arc4_compliant

* update add method handler and method interface

* remove arc4_compliant

* Add manual test for 15+ args in abi router (#375)

Co-authored-by: Ben Guidarelli <ben.guidarelli@gmail.com>
Co-authored-by: Michael Diamant <michaeldiamant@users.noreply.github.com>
Co-authored-by: Jason Paulos <jasonpaulos@users.noreply.github.com>
Co-authored-by: Zeph Grunschlag <tzaffi@users.noreply.github.com>
Co-authored-by: Zeph Grunschlag <zeph@algorand.com>
  • Loading branch information
6 people authored Jun 1, 2022
1 parent c2bbd39 commit 7304e8f
Show file tree
Hide file tree
Showing 62 changed files with 2,643 additions and 85 deletions.
9 changes: 8 additions & 1 deletion pyteal/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@
TealInputError,
TealCompileError,
)
from pyteal.config import MAX_GROUP_SIZE, NUM_SLOTS
from pyteal.config import (
MAX_GROUP_SIZE,
NUM_SLOTS,
RETURN_HASH_PREFIX,
METHOD_ARG_NUM_CUTOFF,
)

# begin __all__
__all__ = (
Expand All @@ -37,6 +42,8 @@
"TealCompileError",
"MAX_GROUP_SIZE",
"NUM_SLOTS",
"RETURN_HASH_PREFIX",
"METHOD_ARG_NUM_CUTOFF",
]
)
# end __all__
14 changes: 13 additions & 1 deletion pyteal/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ from pyteal.errors import (
TealInputError,
TealCompileError,
)
from pyteal.config import MAX_GROUP_SIZE, NUM_SLOTS
from pyteal.config import (
MAX_GROUP_SIZE,
NUM_SLOTS,
RETURN_HASH_PREFIX,
METHOD_ARG_NUM_CUTOFF,
)

__all__ = [
"ABIReturnSubroutine",
Expand All @@ -38,6 +43,7 @@ __all__ = [
"AssetHolding",
"AssetParam",
"Balance",
"BareCallActions",
"BinaryExpr",
"BitLen",
"BitwiseAnd",
Expand All @@ -64,6 +70,7 @@ __all__ = [
"BytesSqrt",
"BytesXor",
"BytesZero",
"CallConfig",
"CompileOptions",
"Concat",
"Cond",
Expand Down Expand Up @@ -117,8 +124,10 @@ __all__ = [
"Lt",
"MAX_GROUP_SIZE",
"MAX_TEAL_VERSION",
"METHOD_ARG_NUM_CUTOFF",
"MIN_TEAL_VERSION",
"MaybeValue",
"MethodConfig",
"MethodSignature",
"MinBalance",
"Minus",
Expand All @@ -132,14 +141,17 @@ __all__ = [
"Nonce",
"Not",
"OnComplete",
"OnCompleteAction",
"Op",
"OpUp",
"OpUpMode",
"OptimizeOptions",
"Or",
"Pop",
"RETURN_HASH_PREFIX",
"Reject",
"Return",
"Router",
"ScratchIndex",
"ScratchLoad",
"ScratchSlot",
Expand Down
13 changes: 12 additions & 1 deletion pyteal/ast/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@
from pyteal.ast.break_ import Break
from pyteal.ast.continue_ import Continue


# misc
from pyteal.ast.scratch import (
ScratchIndex,
Expand All @@ -139,6 +138,13 @@
from pyteal.ast.multi import MultiValue
from pyteal.ast.opup import OpUp, OpUpMode
from pyteal.ast.ecdsa import EcdsaCurve, EcdsaVerify, EcdsaDecompress, EcdsaRecover
from pyteal.ast.router import (
Router,
CallConfig,
MethodConfig,
OnCompleteAction,
BareCallActions,
)

# abi
import pyteal.ast.abi as abi # noqa: I250
Expand Down Expand Up @@ -280,6 +286,11 @@
"For",
"Break",
"Continue",
"Router",
"CallConfig",
"MethodConfig",
"OnCompleteAction",
"BareCallActions",
"abi",
"EcdsaCurve",
"EcdsaVerify",
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 @@ -49,6 +49,7 @@
make,
size_of,
type_spec_from_annotation,
contains_type_spec,
)

__all__ = [
Expand Down Expand Up @@ -103,4 +104,5 @@
"size_of",
"algosdk_from_annotation",
"algosdk_from_type_spec",
"contains_type_spec",
]
8 changes: 4 additions & 4 deletions pyteal/ast/abi/method_return.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from pyteal.errors import TealInputError
from pyteal.ast import Expr, Log, Concat, Bytes
from pyteal.ir import TealBlock, TealSimpleBlock, Op
from pyteal.config import RETURN_METHOD_SELECTOR
from pyteal.config import RETURN_HASH_PREFIX

if TYPE_CHECKING:
from pyteal.compiler import CompileOptions
Expand All @@ -22,9 +22,9 @@ def __teal__(self, options: "CompileOptions") -> Tuple[TealBlock, TealSimpleBloc
raise TealInputError(
f"current version {options.version} is lower than log's min version {Op.log.min_version}"
)
return Log(
Concat(Bytes("base16", RETURN_METHOD_SELECTOR), self.arg.encode())
).__teal__(options)
return Log(Concat(Bytes(RETURN_HASH_PREFIX), self.arg.encode())).__teal__(
options
)

def __str__(self) -> str:
return f"(MethodReturn {self.arg.type_spec()})"
Expand Down
12 changes: 2 additions & 10 deletions pyteal/ast/abi/string.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Union, TypeVar, Sequence, cast
from typing import Union, Sequence, cast
from collections.abc import Sequence as CollectionSequence

from pyteal.ast.abi.uint import Byte
Expand All @@ -20,9 +20,6 @@ def encoded_string(s: Expr):
return Concat(Suffix(Itob(Len(s)), Int(6)), s)


T = TypeVar("T", bound=BaseType)


class StringTypeSpec(DynamicArrayTypeSpec):
def __init__(self) -> None:
super().__init__(ByteTypeSpec())
Expand Down Expand Up @@ -70,12 +67,7 @@ def set(

match value:
case ComputedValue():
if value.produced_type_spec() == StringTypeSpec():
return value.store_into(self)

raise TealInputError(
f"Got ComputedValue with type spec {value.produced_type_spec()}, expected StringTypeSpec"
)
return self._set_with_computed_type(value)
case BaseType():
if value.type_spec() == StringTypeSpec() or (
value.type_spec() == DynamicArrayTypeSpec(ByteTypeSpec())
Expand Down
25 changes: 24 additions & 1 deletion pyteal/ast/abi/util.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import TypeVar, Any, Literal, get_origin, get_args, cast
from typing import Sequence, TypeVar, Any, Literal, get_origin, get_args, cast

import algosdk.abi

Expand Down Expand Up @@ -235,6 +235,29 @@ def type_spec_from_annotation(annotation: Any) -> TypeSpec:
T = TypeVar("T", bound=BaseType)


def contains_type_spec(ts: TypeSpec, targets: Sequence[TypeSpec]) -> bool:
from pyteal.ast.abi.array_dynamic import DynamicArrayTypeSpec
from pyteal.ast.abi.array_static import StaticArrayTypeSpec
from pyteal.ast.abi.tuple import TupleTypeSpec

stack: list[TypeSpec] = [ts]

while stack:
current = stack.pop()
if current in targets:
return True

match current:
case TupleTypeSpec():
stack.extend(current.value_type_specs())
case DynamicArrayTypeSpec():
stack.append(current.value_type_spec())
case StaticArrayTypeSpec():
stack.append(current.value_type_spec())

return False


def size_of(t: type[T]) -> int:
"""Get the size in bytes of an ABI type. Must be a static type"""

Expand Down
5 changes: 1 addition & 4 deletions pyteal/ast/return_.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,7 @@ def __teal__(self, options: "CompileOptions"):
)
op = Op.return_

args = []
if self.value is not None:
args.append(self.value)

args = [] if self.value is None else [self.value]
return TealBlock.FromOp(options, TealOp(self, op), *args)

def __str__(self):
Expand Down
Loading

0 comments on commit 7304e8f

Please sign in to comment.