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

Better Router Mapping #689

Merged
merged 367 commits into from
Mar 17, 2023
Merged
Show file tree
Hide file tree
Changes from 250 commits
Commits
Show all changes
367 commits
Select commit Hold shift + click to select a range
eb31b3a
dupn 1 -> dup (and misc)
Jan 12, 2023
1a9117e
const
ahangsu Jan 12, 2023
19f3bc2
Merge branch 'master' into source-map
Jan 12, 2023
90e423c
adding comments
ahangsu Jan 12, 2023
cb013c6
fix off-by-one-error
Jan 12, 2023
ef11042
passing CI 🤞
Jan 12, 2023
4a11335
line number assertion off-by-1
Jan 12, 2023
565661e
@pytest.mark.serial
Jan 13, 2023
b02135f
minor
ahangsu Jan 13, 2023
0e0df1c
Update pyteal/ast/router.py
ahangsu Jan 13, 2023
552f409
renaming i to something meaningful
ahangsu Jan 13, 2023
ba1afaf
build program API change
ahangsu Jan 13, 2023
23e4026
remove old comments
ahangsu Jan 13, 2023
dc20da4
or none
ahangsu Jan 14, 2023
6cf3b40
taking with minor mods
ahangsu Jan 14, 2023
60e559c
renaming and comments
ahangsu Jan 14, 2023
ac3172c
function bundle things
ahangsu Jan 14, 2023
fc854a0
type casting
ahangsu Jan 14, 2023
ed7e062
Merge branch 'master' into feature/fp-router
ahangsu Jan 17, 2023
e9282ff
test _failing_ on master
Jan 19, 2023
70efea9
Merge branch 'feature/fp-router' into bug-router-not-idempotent
Jan 20, 2023
a8b7e17
wip
Jan 20, 2023
6c49bb2
unit test done
Jan 20, 2023
4f79eba
stateful bug
Jan 20, 2023
6c8b12a
lint
Jan 20, 2023
58b68ce
is this the bug that's been bugging me for almost a year?
Jan 20, 2023
7857d81
Update pyteal/ast/router.py
tzaffi Jan 20, 2023
b3e2cf4
does finally finally fix the bug?
Jan 20, 2023
7f16efe
lint
Jan 20, 2023
a8f0755
i think this works...
Jan 20, 2023
5f3bb74
🤞
Jan 20, 2023
8ce19ac
lint and re-sort imports
Jan 20, 2023
a27e8e1
revert
Jan 20, 2023
b53e302
Update pyteal/ast/router_test.py
tzaffi Jan 20, 2023
d27e8b9
oops - remove integration tests that snuck into unit tests
Jan 20, 2023
987634e
Merge branch 'master' into feature/fp-router
ahangsu Jan 20, 2023
0fc291c
Merge branch 'feature/fp-router' into bug-router-not-idempotent
ahangsu Jan 20, 2023
e99e005
Merge branch 'master' into feature/fp-router
ahangsu Jan 21, 2023
03a8592
Merge branch 'feature/fp-router' into bug-router-not-idempotent
ahangsu Jan 21, 2023
90f1f4c
revive skipped tests in tests/unit/sourcemap_monkey_unit_test.py
Jan 21, 2023
576cfb0
Merge pull request #642 from algorand/merge-feature-router
tzaffi Jan 21, 2023
c76e18d
manual merge
Jan 21, 2023
0d5db9c
Merge remote-tracking branch 'algorand/feature/fp-router' into source…
Jan 21, 2023
b58c503
Merge branch 'feature/fp-router' into source-map
Jan 21, 2023
d0cf180
Update .gitignore
tzaffi Jan 21, 2023
bb7b0a4
reorder
Jan 21, 2023
0c9b7b3
wip
Jan 21, 2023
bf3a770
small improvments e.g. better PC column output
Jan 21, 2023
3033d3f
fine grained control over sync/asyn of unit and integration tests
Jan 22, 2023
9e48d86
finally all merged
Jan 22, 2023
d80f264
threading the synchronous tesst needle
Jan 23, 2023
5083a6d
don't need notebooks
Jan 23, 2023
706292e
remove mistakenly checked in files
Jan 23, 2023
2102a9a
Update .flake8
tzaffi Jan 23, 2023
2d39c6d
sort lines
Jan 23, 2023
f3787fa
Merge branch 'master' into merge-updates-fp-reouter
Jan 23, 2023
a9d1bed
Merge pull request #646 from algorand/merge-updates-fp-reouter
ahangsu Jan 23, 2023
96cdece
hide build program method in router
ahangsu Jan 23, 2023
4873b34
fix doc error
ahangsu Jan 23, 2023
9a8dcd3
Merge pull request #647 from algorand/hide-build-program
ahangsu Jan 23, 2023
6412626
Merge branch 'feature/fp-router' into bug-router-not-idempotent
ahangsu Jan 23, 2023
bac2e13
Merge branch 'feature/fp-router' into source-map
Jan 23, 2023
db6c8e5
Zeph's sick move
ahangsu Jan 23, 2023
b91dc7a
enforce "_root_expr" for members and "root_expr" everywhere else
Jan 23, 2023
2b4b213
Merge branch 'master' into feature/fp-router
ahangsu Jan 24, 2023
9c5a3ea
Merge branch 'feature/fp-router' into bug-router-not-idempotent
ahangsu Jan 24, 2023
b2f9100
Refactoring non-idempotent fix with contextmanager a bit (#649)
ahangsu Jan 24, 2023
eef19f7
Merge remote-tracking branch 'algorand/feature/fp-router' into source…
Jan 25, 2023
eadaa95
bring in `test_constructs()` passing in `source-mapper-that-works`
Jan 26, 2023
d3a7892
back to square 1.5
Jan 26, 2023
793c932
actions -> as_list
Jan 26, 2023
de188db
deleting obsolete test
Jan 26, 2023
45ce15b
mostly just formatting
Jan 26, 2023
d05070c
remove comments
Jan 26, 2023
5fc6ced
add 3rd case to test_build_program_clear_state_invalid_config
Jan 26, 2023
f9cee64
Update pyteal/ast/router.py
tzaffi Jan 26, 2023
eb853ab
minor refactoring
ahangsu Jan 26, 2023
cbed02e
Merge pull request #651 from algorand/minor-refactoring-on-non-idempo…
tzaffi Jan 26, 2023
459487f
Merge pull request #639 from algorand/bug-router-not-idempotent
tzaffi Jan 26, 2023
ed359d2
small changes to monkey unit test
Jan 26, 2023
a43cf2a
Merge remote-tracking branch 'algorand/feature/fp-router' into source…
Jan 26, 2023
4df29f6
passing tests hopefully (at least on 3.11)
Jan 26, 2023
7e13a94
Update pyteal/ast/router.py
tzaffi Jan 26, 2023
e41bd50
Apply suggestions from code review
tzaffi Jan 26, 2023
2d57ca4
should pass the docs build -even if haven't properly updated them
Jan 27, 2023
2c8285c
Update pyteal/stack_frame_test.py
tzaffi Jan 27, 2023
9aa4982
unskip the weak idempotence reliant tests
Jan 27, 2023
f3c8034
begone `source_inference` and `hybrid_source` params
Jan 27, 2023
ace910d
begone `source_inference` and `hybrid_source` params
Jan 27, 2023
0ba0c79
refactor part 1) CompileResults with safe data
Jan 27, 2023
4c318e5
refactor part 2) RouterResults with safe data
Jan 27, 2023
d3b9cf6
move SourceMapDisabledError up into errors.py
Jan 27, 2023
f2a945a
side-effectless infer method
Jan 27, 2023
da56f90
small cleanup
Jan 27, 2023
5944d88
unify source mapper outputs in `PyTealSourceMap` type
Jan 27, 2023
008fb61
make `Compilation.compile()` kw-only
Jan 27, 2023
b9a89b0
small cleanup/fixes
Jan 27, 2023
9a1a50c
remove comment
Jan 28, 2023
725a2e4
comment StackFrames + reorder params + reformat
Jan 30, 2023
eb8d1ed
more comments + remove unused method + reduce the chance of a false p…
Jan 30, 2023
6c0040e
remove StackFrames' `keep_one_frame_only` param and privatize the `_k…
Jan 30, 2023
8048f28
StackFrames ought not be subscriptable
Jan 30, 2023
44b3a8e
remove unused StackFrames.frame_infos method
Jan 30, 2023
7f3daa5
Privatizing StackFrames._frames
Jan 30, 2023
8a91c9d
StackFrames becomes NatalStackFrame
Jan 30, 2023
de4672c
pass the unit test
Jan 30, 2023
26f43ad
commentary
Jan 30, 2023
fe355b5
remove unused const _PYTEAL_FRAME
Jan 30, 2023
07846ba
R3SourceMap commentary
Jan 30, 2023
a21d6c3
fixture for source map integration tests
Jan 30, 2023
d539531
non-controversial changes
Jan 31, 2023
a545e04
rename to what the test expects
Jan 31, 2023
e2edde9
commentary
Jan 31, 2023
07706f6
Simplify NatalStackFrame's constructor while maintaining green tets
Jan 31, 2023
866b02c
hard code the logic and set last_drop_idx=1, but introduce unit test_…
Jan 31, 2023
8d034b4
fix unit test now that _keep_all init param is gone
Jan 31, 2023
df7f645
commentary
Jan 31, 2023
aa97b2b
commentary
Jan 31, 2023
21c60bb
make sourcemap-coverage
Jan 31, 2023
e8c4484
EOL
Jan 31, 2023
792168f
BareCallActions.asdict|list
Feb 1, 2023
6edc25c
algokit "ruff"s up sourcemap.py
Feb 1, 2023
e7296d9
Merge branch 'master' into feature/fp-router
ahangsu Feb 1, 2023
f601c88
bad merge
ahangsu Feb 1, 2023
9bcce00
removing ignoreExprEquality context
Feb 1, 2023
7ade42b
Merge branch 'master' into feature/fp-router
ahangsu Feb 1, 2023
ad43a5c
minor, index_start_from
ahangsu Feb 1, 2023
96f7787
Merge branch 'feature/fp-router' into source-map-b1
Feb 1, 2023
efd0ceb
remove dupe test_bare_call_actions_asdict
Feb 1, 2023
52a9cd6
documentation
ahangsu Feb 1, 2023
48004db
doc for de abify subroutine frame pointer
ahangsu Feb 1, 2023
2b6397f
doc for de abify subroutine frame pointer
ahangsu Feb 1, 2023
92ba2d6
Merge branch 'feature/fp-router' into source-map-b1
Feb 1, 2023
a98779c
doc for de abify subroutine vanilla
ahangsu Feb 1, 2023
943a3c9
explanatory coment
Feb 2, 2023
dca1f8e
Merge branch 'feature/fp-router' into source-map-b1
Feb 2, 2023
a9200bc
lint
Feb 2, 2023
721ff7a
unshadow `str`
Feb 2, 2023
f1ae6bf
Small tweaks of Router.bare_calls (#659)
tzaffi Feb 2, 2023
ccaf8bf
Merge branch 'feature/fp-router' into source-map-b1
Feb 2, 2023
c415375
commentary
Feb 8, 2023
a441a10
first stab at issue #658
Feb 8, 2023
f96ef86
_root_expr members renamed to more accurate _sframes_container
Feb 8, 2023
ec1e06c
remove obsolete comment
Feb 8, 2023
e153eae
Graviton 4 abi router (#634)
tzaffi Feb 9, 2023
4b5fd61
Merge branch 'feature/fp-router' into source-map-b1
Feb 9, 2023
3c9c009
try nightly
Feb 10, 2023
4711226
typo
Feb 10, 2023
2529c9d
try gin
Feb 10, 2023
430208a
and agin
Feb 10, 2023
aba8819
tg
Feb 10, 2023
d2e75f9
default `annotate_teal=False` in `compile()`
Feb 11, 2023
407d153
just look for startswith("def") instead of decorators AST property
Feb 12, 2023
ed299d7
fix and test hybrid_w_offset
Feb 12, 2023
86d90bc
mokey patched tests should be run serially
Feb 12, 2023
71588ea
temp todos
Feb 13, 2023
82feb4f
fix MethodReturn
Feb 13, 2023
c704fd9
no more BRUTE_FORCE_TERRIBLE_SKIP + improved interpretation of loadin…
Feb 13, 2023
483527b
pass the tests
Feb 13, 2023
78e0e2f
remove unneeded duplicates pyteal printouts in annotate()
Feb 13, 2023
bfc8b2e
Update pyteal/ast/router_test.py
tzaffi Feb 13, 2023
b1e9833
better import grouping
Feb 13, 2023
bc23cb4
working on nightly in separate branch
Feb 14, 2023
6e9bdea
Update pyteal/stack_frame.py
tzaffi Feb 15, 2023
f615c01
comment per CR suggestion
Feb 15, 2023
85a633e
remove a TODO
Feb 15, 2023
13bfc3b
per CR suggestion, add tests that assert no regressions against algob…
Feb 15, 2023
224f3e2
RPS fixture test to assert no regressions
Feb 15, 2023
469ddf2
Merge tag 'v0.23.0' into merge-v0.23.0
Feb 15, 2023
d8aee70
Merge pull request #670 from algorand/merge-v0.23.0
tzaffi Feb 15, 2023
a74cfbd
Merge remote-tracking branch 'algorand/feature/fp-router' into source…
Feb 15, 2023
c5fb967
Merge remote-tracking branch 'algorand/rps-fixture' into source-map-b1
Feb 15, 2023
4737ae1
unit tests with RPS; next up, integration tests
Feb 15, 2023
aa47f67
default Compilation.compile() to not calc sourcemap
Feb 15, 2023
bf0a76f
rps integration test
Feb 15, 2023
3a304c8
router improvements + break out slow test
Feb 16, 2023
8418e96
lint
Feb 16, 2023
a132f4a
register the custom pytest mark "slow"
Feb 16, 2023
1149b2a
bugfix, but don't fix the test cases just yet...
Feb 16, 2023
ddd9e4c
Tightening up types in 2 subroutine.py invokations (#672)
tzaffi Feb 17, 2023
91467fb
Merge branch 'master' into merge-master-fp-router
Feb 17, 2023
df19efe
Merge pull request #673 from algorand/merge-master-fp-router
tzaffi Feb 17, 2023
02840d5
Update pyteal/ast/router.py
ahangsu Feb 17, 2023
9261f3f
update comments
ahangsu Feb 17, 2023
477981b
default optimize object
ahangsu Feb 17, 2023
5864633
update comments and docs
ahangsu Feb 17, 2023
f3344bd
update comments and docs
ahangsu Feb 17, 2023
2b28442
update router comments
ahangsu Feb 17, 2023
2938ed0
default `wrap_to_name`
ahangsu Feb 17, 2023
a12f538
update comments
ahangsu Feb 17, 2023
4fa06fa
update comments
ahangsu Feb 17, 2023
57a8320
update comments
ahangsu Feb 17, 2023
90dbff1
update comments
ahangsu Feb 17, 2023
aeb8cd8
update comments
ahangsu Feb 17, 2023
1b44e79
update comments
ahangsu Feb 17, 2023
183de2c
update comments
ahangsu Feb 17, 2023
fb2b50e
update comments and docs
ahangsu Feb 17, 2023
0c64e56
update comments and docs
ahangsu Feb 17, 2023
ed9e95b
update comments and docs
ahangsu Feb 17, 2023
ef94354
update comments and docs
ahangsu Feb 17, 2023
6295dc2
update comments and docs
ahangsu Feb 17, 2023
a53c0b2
update comments and docs
ahangsu Feb 17, 2023
ef08bef
update comments and docs
ahangsu Feb 17, 2023
4ed640b
minor
ahangsu Feb 17, 2023
2912990
80% of the way towards complete router mapping
Feb 17, 2023
b4b407b
pass the tests
Feb 18, 2023
a98324e
Merge remote-tracking branch 'algorand/feature/fp-router' into better…
Feb 18, 2023
4d9f89b
85% of the way
Feb 18, 2023
70c89bc
90%
Feb 18, 2023
fac1fe6
92%
Feb 18, 2023
7c1732a
passing tests locally
Feb 18, 2023
540f65c
display only the mypy ERRORS, not the warnings
Feb 18, 2023
f251034
ci friendly grep
Feb 18, 2023
e55c1a2
revert grep
Feb 18, 2023
a73f4df
wip
Feb 21, 2023
6ce30e3
Merge branch 'master' into better-router-mapping
Mar 16, 2023
ec6ee5e
passing lint
Mar 16, 2023
a58f798
sort imports
Mar 16, 2023
1086ed2
get closer to passing unit tests
Mar 16, 2023
aedcfd3
pass more tests
Mar 16, 2023
e6a38d8
Merge branch 'master' into better-router-mapping-2
Mar 16, 2023
23e6ee7
fix test_r3sourcemap
Mar 16, 2023
5a70b58
Merge branch 'master' into better-router-mapping-2
Mar 16, 2023
9bc229d
improved RPS
Mar 16, 2023
ffd998c
skip flaky sub-test
Mar 16, 2023
93b877b
begone Method._sframes_container
Mar 16, 2023
9cc4545
lint
Mar 16, 2023
8133a9d
shd pass unit tests in CI
Mar 16, 2023
79ca368
more tests skipped due to unstable scratch slots
Mar 17, 2023
ec61f4d
don't need root_expr in Break()
Mar 17, 2023
678a045
don't need root_expr in Continue or TealSimpleBlock
Mar 17, 2023
6a49be7
EnumInt.clone wasn't needed
Mar 17, 2023
eb0d6a5
revert
Mar 17, 2023
6e4d0ae
cut NatalStackFrame._compiler_gen_DEPRECATED and follow through
Mar 17, 2023
8ab346a
improve test legibility
Mar 17, 2023
5faa030
improve test legibility
Mar 17, 2023
efcbaa6
remove unused pathway for detecting import
Mar 17, 2023
6e41e6b
lint
Mar 17, 2023
1aa0cbc
unused var
Mar 17, 2023
66a5621
simplify with instance method
Mar 17, 2023
868e822
clean up
Mar 17, 2023
0367176
compress and comment
Mar 17, 2023
f94fa7a
apply review suggestions and fix a couple more typos
Mar 17, 2023
622bb84
per CR nudge - clean up _walk_asts logic
Mar 17, 2023
50281ee
Update pyteal/ast/router.py
tzaffi Mar 17, 2023
048a231
Update pyteal/stack_frame.py
tzaffi Mar 17, 2023
89f5c4d
Update pyteal/stack_frame.py
tzaffi Mar 17, 2023
e4ce819
revert _debug_asts()
Mar 17, 2023
2c5f670
unify RPS so easier to run directly
Mar 17, 2023
dc203b3
Update .flake8
tzaffi Mar 17, 2023
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
3 changes: 1 addition & 2 deletions pyteal/ast/abi/method_return.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ def __init__(self, arg: BaseType):
if not isinstance(arg, BaseType):
raise TealInputError(f"Expecting an ABI type argument but get {arg}")
self.arg = arg
self._sframes_container: Expr | None = None

def __teal__(self, options: "CompileOptions") -> Tuple[TealBlock, TealSimpleBlock]:
if options.version < Op.log.min_version:
Expand All @@ -30,7 +29,7 @@ def __teal__(self, options: "CompileOptions") -> Tuple[TealBlock, TealSimpleBloc
start, end = Log(Concat(Bytes(RETURN_HASH_PREFIX), self.arg.encode())).__teal__(
options
)
NatalStackFrame.reframe_ops_in_blocks(self._sframes_container or self, start)
NatalStackFrame.reframe_ops_in_blocks(self, start)
tzaffi marked this conversation as resolved.
Show resolved Hide resolved
return start, end

def __str__(self) -> str:
Expand Down
156 changes: 100 additions & 56 deletions pyteal/ast/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
OutputKwArgInfo,
Subroutine,
SubroutineCall,
SubroutineDefinition,
SubroutineFnWrapper,
)
from pyteal.ast.txn import Txn
Expand Down Expand Up @@ -237,8 +238,7 @@ def approval_construction(self) -> Optional[Expr]:
if oca.is_empty():
continue
wrapped_handler = ASTBuilder.wrap_handler(
False,
cast(ActionType, oca.action),
False, cast(ActionType, oca.action)
)
match oca.call_config:
case CallConfig.ALL:
Expand All @@ -256,13 +256,12 @@ def approval_construction(self) -> Optional[Expr]:
raise TealInternalError(
f"Unexpected CallConfig: {oca.call_config!r}"
)
conditions_n_branches.append(
CondNode(
Txn.on_completion() == oc,
cond_body,
)
)
return Cond(*[[n.condition, n.branch] for n in conditions_n_branches])
cn = CondNode(Txn.on_completion() == oc, cond_body)
cn.reframe_asts(oca.stack_frames)
conditions_n_branches.append(cn)
tzaffi marked this conversation as resolved.
Show resolved Hide resolved
cond = Cond(*[[n.condition, n.branch] for n in conditions_n_branches])
cond.stack_frames = self.stack_frames
return cond

def get_method_config(self) -> MethodConfig:
return MethodConfig(
Expand All @@ -288,6 +287,9 @@ class CondNode:
condition: Expr
branch: Expr

def reframe_asts(self, stack_frames: NatalStackFrame) -> None:
bbroder-algo marked this conversation as resolved.
Show resolved Hide resolved
stack_frames.reframe(self.condition, self.branch)


CondNode.__module__ = "pyteal"

Expand Down Expand Up @@ -328,21 +330,27 @@ def to_cond_node(self, use_frame_pt: bool = False) -> CondNode:
if not (isinstance(self.condition, Expr) or self.condition == 1):
raise TealInputError("Invalid condition input for CondWithMethod")

res = ASTBuilder.wrap_handler(True, self.method, use_frame_pt=use_frame_pt)
user_frames_holder: list[NatalStackFrame] = []
res = ASTBuilder.wrap_handler(
True,
self.method,
use_frame_pt=use_frame_pt,
handler_stack_frames_container=user_frames_holder,
)
assert (
ufhlen := len(user_frames_holder)
) == 1, f"Unexpected length for user_frames_holder: {ufhlen}"
user_frames: NatalStackFrame = user_frames_holder[0]

if isinstance(self.condition, Expr):
res = Seq(Assert(self.condition), res)
NatalStackFrame.reframe_asts(self.condition.stack_frames, res)
return CondNode(walk_in_cond, res)


CondWithMethod.__module__ = "pyteal"
cn = CondNode(walk_in_cond, res)
cn.reframe_asts(user_frames)
return cn


def _smap_friendly_approve():
# TODO: Consider replacing _smap_friendly_approve() with a reframe_asts()
a = Approve()
a.stack_frames._compiler_gen = True
return a
CondWithMethod.__module__ = "pyteal"


@dataclass
Expand Down Expand Up @@ -513,6 +521,7 @@ def wrap_handler(
*,
wrap_to_name: str | None = None,
use_frame_pt: bool = False,
handler_stack_frames_container: list[NatalStackFrame] | None = None,
) -> Expr:
"""This is a helper function that handles transaction arguments passing in bare-app-call/abi-method handlers.
If `is_method_call` is True, then it can only be `ABIReturnSubroutine`,
Expand All @@ -531,6 +540,13 @@ def wrap_handler(
- for abi-method it returns the txn args correctly decomposed into ABI variables,
passed in ABIReturnSubroutine and logged, then approve.
"""

def scavenge(frames_holder) -> None:
bbroder-algo marked this conversation as resolved.
Show resolved Hide resolved
if handler_stack_frames_container is not None:
handler_stack_frames_container.append(frames_holder.stack_frames)

handler_evald: abi.ReturnedValue | SubroutineCall

if not is_method_call:
wrap_to_name = wrap_to_name or "bare appcall"

Expand All @@ -540,11 +556,8 @@ def wrap_handler(
raise TealInputError(
f"{wrap_to_name} handler should be TealType.none not {handler.type_of()}."
)
return (
handler
if handler.has_return()
else Seq(handler, _smap_friendly_approve())
)
scavenge(handler)
return handler if handler.has_return() else Seq(handler, Approve())
case SubroutineFnWrapper():
if handler.type_of() != TealType.none:
raise TealInputError(
Expand All @@ -555,7 +568,11 @@ def wrap_handler(
f"subroutine call should take 0 arg for {wrap_to_name}. "
f"this subroutine takes {handler.subroutine.argument_count()}."
)
return Seq(handler(), _smap_friendly_approve())
handler_evald = handler()
if isinstance(handler_evald, abi.ReturnedValue):
handler_evald = handler_evald.computation
scavenge(cast(SubroutineCall, handler_evald).subroutine)
return Seq(handler_evald, Approve())
case ABIReturnSubroutine():
if handler.type_of() != "void":
raise TealInputError(
Expand All @@ -566,7 +583,12 @@ def wrap_handler(
f"abi-returning subroutine call should take 0 arg for {wrap_to_name}. "
f"this abi-returning subroutine takes {handler.subroutine.argument_count()}."
)
return Seq(cast(Expr, handler()), _smap_friendly_approve())
handler_evald = handler()
if isinstance(handler_evald, abi.ReturnedValue):
handler_evald = handler_evald.computation

scavenge(handler_evald)
return Seq(cast(Expr, handler_evald), Approve())
case _:
raise TealInputError(
f"{wrap_to_name} can only accept: none type Expr, or Subroutine/ABIReturnSubroutine with none return and no arg"
Expand All @@ -583,13 +605,19 @@ def wrap_handler(
f"{wrap_to_name} ABIReturnSubroutine is not routable "
f"got {handler.subroutine.argument_count()} args with {len(handler.subroutine.abi_args)} ABI args."
)
if not use_frame_pt:
return ASTBuilder.__de_abify_subroutine_vanilla(handler)
else:
return ASTBuilder.__de_abify_subroutine_frame_pointers(handler)

ret_expr, subdef = (
ASTBuilder.__de_abify_subroutine_frame_pointers(handler)
if use_frame_pt
else ASTBuilder.__de_abify_subroutine_vanilla(handler)
)
scavenge(subdef)
ahangsu marked this conversation as resolved.
Show resolved Hide resolved
return ret_expr

@staticmethod
def __de_abify_subroutine_vanilla(handler: ActionType) -> Expr:
def __de_abify_subroutine_vanilla(
handler: ActionType,
) -> tuple[Expr, SubroutineDefinition]:
"""This private function retains the previous (pre-frame-pointer) logic of handling ABIReturnSubroutine method's IO.

This function can be roughly separated into following 4 parts:
Expand Down Expand Up @@ -638,28 +666,35 @@ def __de_abify_subroutine_vanilla(handler: ActionType) -> Expr:
arg_vals, app_arg_vals, txn_arg_vals, handler
)

ret_expr: Expr
handler_evald: abi.ReturnedValue | SubroutineCall
if handler.type_of() == sdk_abi.Returns.VOID:
return Seq(
ret_expr = Seq(
*decode_instructions,
cast(SubroutineCall, handler(*arg_vals)),
_smap_friendly_approve(),
cast(SubroutineCall, handler_evald := handler(*arg_vals)),
Approve(),
)
else:
output_temp: abi.BaseType = cast(
OutputKwArgInfo, handler.output_kwarg_info
).abi_type.new_instance()
returned_val: abi.ReturnedValue = cast(
abi.ReturnedValue, handler(*arg_vals)
)
return Seq(
handler_evald = cast(abi.ReturnedValue, handler(*arg_vals))
ret_expr = Seq(
*decode_instructions,
returned_val.store_into(output_temp),
handler_evald.store_into(output_temp),
abi.MethodReturn(output_temp),
_smap_friendly_approve(),
Approve(),
)

if isinstance(handler_evald, abi.ReturnedValue):
handler_evald = handler_evald.computation

return ret_expr, cast(SubroutineCall, handler_evald).subroutine

@staticmethod
def __de_abify_subroutine_frame_pointers(handler: ActionType) -> Expr:
def __de_abify_subroutine_frame_pointers(
handler: ActionType,
) -> tuple[Expr, SubroutineDefinition]:
"""This private function implements the frame-pointer-based logic of handling ABIReturnSubroutine method's IO.

This function can be roughly separated into following 4 parts:
Expand Down Expand Up @@ -737,15 +772,16 @@ def __de_abify_subroutine_frame_pointers(handler: ActionType) -> Expr:
]
returning_steps: list[Expr]

handler_evald: abi.ReturnedValue | SubroutineCall
if handler.type_of() == sdk_abi.Returns.VOID:
returning_steps = [cast(SubroutineCall, handler(*arg_vals))]
returning_steps = [cast(Expr, handler_evald := handler(*arg_vals))]
else:
output_temp: abi.BaseType = cast(
OutputKwArgInfo, handler.output_kwarg_info
).abi_type.new_instance()
output_temp._stored_value = FrameVar(proto, 0)
returned_val: abi.ReturnedValue = cast(
abi.ReturnedValue, handler(*arg_vals)
abi.ReturnedValue, handler_evald := handler(*arg_vals)
)
returning_steps = [
returned_val.store_into(output_temp),
Expand All @@ -755,7 +791,13 @@ def __de_abify_subroutine_frame_pointers(handler: ActionType) -> Expr:
def declaration():
return Seq(*decoding_steps, *returning_steps)

return Seq(subroutine_caster(declaration)(), _smap_friendly_approve())
if isinstance(handler_evald, abi.ReturnedValue):
handler_evald = handler_evald.computation

return (
Seq(subroutine_caster(declaration)(), Approve()),
cast(SubroutineCall, handler_evald).subroutine,
)

def add_method_to_ast(
self, method_signature: str, cond: Expr | int, handler: ABIReturnSubroutine
Expand Down Expand Up @@ -801,19 +843,21 @@ class _RouterBundle:
input: Optional["_RouterCompileInput"] = None

def get_results(self) -> RouterResults:
approval_sm: PyTealSourceMap | None = None
clear_sm: PyTealSourceMap | None = None
approval_sourcemap: PyTealSourceMap | None = None
clear_sourcemap: PyTealSourceMap | None = None
if self.approval_sourcemapper:
approval_sm = self.approval_sourcemapper.get_sourcemap(self.approval_teal)
approval_sourcemap = self.approval_sourcemapper.get_sourcemap(
self.approval_teal
)
if self.clear_sourcemapper:
clear_sm = self.clear_sourcemapper.get_sourcemap(self.clear_teal)
clear_sourcemap = self.clear_sourcemapper.get_sourcemap(self.clear_teal)

return RouterResults(
self.approval_teal,
self.clear_teal,
self.abi_contract,
approval_sm,
clear_sm,
approval_teal=self.approval_teal,
clear_teal=self.clear_teal,
abi_contract=self.abi_contract,
approval_sourcemap=approval_sourcemap,
clear_sourcemap=clear_sourcemap,
)


Expand Down Expand Up @@ -1106,7 +1150,7 @@ def _build_program(
act := cast(Expr, bare_call_approval),
)
]
NatalStackFrame.reframe_asts(bare_call_approval.stack_frames, cond)
bare_call_approval.stack_frames.reframe(cond)
act.stack_frames = bare_call_approval.stack_frames

optimize = optimize or OptimizeOptions()
Expand Down Expand Up @@ -1134,8 +1178,6 @@ def compile_program(
optimize: Optional[OptimizeOptions] = None,
) -> tuple[str, str, sdk_abi.Contract]:
"""
DEPRECATED BUT KEPT FOR BACKWARDS COMPATIBILITY. PREFER Router.compile().

Constructs and compiles approval and clear-state programs from the registered methods and
bare app calls in the router, and also generates a Contract object to allow client read and call
the methods easily.
Expand All @@ -1151,6 +1193,8 @@ def compile_program(
* approval_program: compiled approval program string
* clear_state_program: compiled clear-state program string
* contract: a Python SDK Contract object to allow clients to make off-chain calls

NOTE: For generating a source map, please refer to the `Router.compile` method.
"""
input = _RouterCompileInput(
version=version,
Expand Down
36 changes: 24 additions & 12 deletions pyteal/ast/router_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,17 @@ def test_bare_call_config_clear_state_failure():
)


def equal_ocas(oca1, oca2):
assert oca1.call_config == oca2.call_config
if oca1.action is None:
assert oca2.action is None
else:
assert isinstance(oca1.action, pt.Int)
assert isinstance(oca2.action, pt.Int)

return True


def test_BareCallActions_asdict():
no_action = pt.OnCompleteAction()
del_action = pt.OnCompleteAction(action=pt.Int(1), call_config=pt.CallConfig.ALL)
Expand All @@ -392,16 +403,7 @@ def test_BareCallActions_asdict():
close_out=close_action,
)

bcad = bca.asdict()
assert set(bcad.keys()) == {
"clear_state",
"close_out",
"delete_application",
"no_op",
"opt_in",
"update_application",
}
assert bcad == {
expected = {
"clear_state": no_action,
"close_out": close_action,
"delete_application": del_action,
Expand All @@ -410,6 +412,13 @@ def test_BareCallActions_asdict():
"update_application": no_action,
}

bcad = bca.asdict()
assert set(bcad.keys()) == set(expected.keys())

for k, oca1 in bcad.items():
oca2 = expected[k]
equal_ocas(oca1, oca2)


def test_BareCallActions_aslist():
no_action = pt.OnCompleteAction()
Expand All @@ -423,15 +432,18 @@ def test_BareCallActions_aslist():
opt_in=optin_action,
)

bcal = bca.aslist()
assert bcal == [
expected = [
no_action,
no_action,
no_action,
no_action,
optin_action,
update_action,
]
bcal = bca.aslist()
assert len(expected) == len(bcal)

assert all([equal_ocas(expected[i], actual) for i, actual in enumerate(bcal)])


def test_BareCallActions_get_method_config():
Expand Down
Loading