Skip to content

Commit 16199ec

Browse files
authored
Method sig for router (#340)
* adding method_signature to ABIReturnSubroutine
1 parent b8e8d1f commit 16199ec

File tree

3 files changed

+57
-8
lines changed

3 files changed

+57
-8
lines changed

pyteal/ast/router.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def __init__(self, name: Optional[str] = None) -> None:
6868

6969
@staticmethod
7070
def __parse_conditions(
71+
method_signature: str,
7172
method_to_register: ABIReturnSubroutine | None,
7273
on_completes: list[EnumInt],
7374
creation: bool,
@@ -79,13 +80,18 @@ def __parse_conditions(
7980
)
8081
clear_state_conds: list[Expr] = []
8182

83+
if method_signature == "" and method_to_register is not None:
84+
raise TealInputError(
85+
"A method_signature must only be provided if method_to_register is not None"
86+
)
87+
8288
# Check:
8389
# - if current condition is for *ABI METHOD*
8490
# (method selector && numAppArg == 1 + min(METHOD_APP_ARG_NUM_LIMIT, subroutineSyntaxArgNum))
8591
# - or *BARE APP CALL* (numAppArg == 0)
8692
method_or_bare_condition = (
8793
And(
88-
Txn.application_args[0] == MethodSignature(method_to_register.name()),
94+
Txn.application_args[0] == MethodSignature(method_signature),
8995
Txn.application_args.length()
9096
== Int(
9197
1
@@ -281,23 +287,33 @@ def on_bare_app_call(
281287
else [cast(EnumInt, on_completes)]
282288
)
283289
approval_conds, clear_state_conds = Router.__parse_conditions(
284-
method_to_register=None, on_completes=ocList, creation=creation
290+
method_signature="",
291+
method_to_register=None,
292+
on_completes=ocList,
293+
creation=creation,
285294
)
286295
branch = Router.__wrap_handler(False, bare_app_call)
287296
self.__append_to_ast(approval_conds, clear_state_conds, branch, None)
288297

289298
def on_method_call(
290299
self,
291-
method_signature: str,
292300
method_app_call: ABIReturnSubroutine,
293301
*,
302+
method_signature: str = None,
294303
on_complete: EnumInt = OnComplete.NoOp,
295304
creation: bool = False,
296305
) -> None:
297306
""" """
298307
oc_list: list[EnumInt] = [cast(EnumInt, on_complete)]
308+
309+
if method_signature is None:
310+
method_signature = method_app_call.method_signature()
311+
299312
approval_conds, clear_state_conds = Router.__parse_conditions(
300-
method_to_register=method_app_call, on_completes=oc_list, creation=creation
313+
method_signature=method_signature,
314+
method_to_register=method_app_call,
315+
on_completes=oc_list,
316+
creation=creation,
301317
)
302318
branch = Router.__wrap_handler(True, method_app_call)
303319
self.__append_to_ast(

pyteal/ast/subroutine.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,15 @@ def __call__(
573573
def name(self) -> str:
574574
return self.subroutine.name()
575575

576+
def method_signature(self) -> str:
577+
if not self.is_registrable():
578+
raise TealInputError(
579+
"Only registrable methods may return a method signature"
580+
)
581+
582+
args = [str(v) for v in self.subroutine.abi_args.values()]
583+
return f"{self.name()}({','.join(args)}){self.type_of()}"
584+
576585
def type_of(self) -> str | abi.TypeSpec:
577586
return (
578587
"void"

pyteal/ast/subroutine_test.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ class ABISubroutineTC:
8686
arg_instances: list[pt.Expr | pt.abi.BaseType]
8787
name: str
8888
ret_type: str | pt.abi.TypeSpec
89+
signature: str
8990

9091

9192
def test_abi_subroutine_definition():
@@ -130,13 +131,27 @@ def fn_2arg_1ret_with_expr(
130131
return output.set(b[a % pt.Int(10)])
131132

132133
cases = (
133-
ABISubroutineTC(fn_0arg_0ret, [], "fn_0arg_0ret", "void"),
134+
ABISubroutineTC(fn_0arg_0ret, [], "fn_0arg_0ret", "void", "fn_0arg_0ret()void"),
134135
ABISubroutineTC(
135-
fn_0arg_uint64_ret, [], "fn_0arg_uint64_ret", pt.abi.Uint64TypeSpec()
136+
fn_0arg_uint64_ret,
137+
[],
138+
"fn_0arg_uint64_ret",
139+
pt.abi.Uint64TypeSpec(),
140+
"fn_0arg_uint64_ret()uint64",
136141
),
137-
ABISubroutineTC(fn_1arg_0ret, [pt.abi.Uint64()], "fn_1arg_0ret", "void"),
138142
ABISubroutineTC(
139-
fn_1arg_1ret, [pt.abi.Uint64()], "fn_1arg_1ret", pt.abi.Uint64TypeSpec()
143+
fn_1arg_0ret,
144+
[pt.abi.Uint64()],
145+
"fn_1arg_0ret",
146+
"void",
147+
"fn_1arg_0ret(uint64)void",
148+
),
149+
ABISubroutineTC(
150+
fn_1arg_1ret,
151+
[pt.abi.Uint64()],
152+
"fn_1arg_1ret",
153+
pt.abi.Uint64TypeSpec(),
154+
"fn_1arg_1ret(uint64)uint64",
140155
),
141156
ABISubroutineTC(
142157
fn_2arg_0ret,
@@ -148,6 +163,7 @@ def fn_2arg_1ret_with_expr(
148163
],
149164
"fn_2arg_0ret",
150165
"void",
166+
"fn_2arg_0ret(uint64,byte[10])void",
151167
),
152168
ABISubroutineTC(
153169
fn_2arg_1ret,
@@ -159,6 +175,7 @@ def fn_2arg_1ret_with_expr(
159175
],
160176
"fn_2arg_1ret",
161177
pt.abi.ByteTypeSpec(),
178+
"fn_2arg_1ret(uint64,byte[10])byte",
162179
),
163180
ABISubroutineTC(
164181
fn_2arg_1ret_with_expr,
@@ -170,6 +187,7 @@ def fn_2arg_1ret_with_expr(
170187
],
171188
"fn_2arg_1ret_with_expr",
172189
pt.abi.ByteTypeSpec(),
190+
None,
173191
),
174192
)
175193

@@ -193,6 +211,12 @@ def fn_2arg_1ret_with_expr(
193211
map(lambda x: isinstance(x, pt.abi.BaseType), case.arg_instances)
194212
)
195213

214+
if case.definition.is_registrable():
215+
assert case.definition.method_signature() == case.signature
216+
else:
217+
with pytest.raises(pt.TealInputError):
218+
case.definition.method_signature()
219+
196220

197221
def test_subroutine_definition_validate():
198222
"""

0 commit comments

Comments
 (0)