Hi Community,
I am trying to save space by creating a subroutine. I have the same logic applicable to many fields.
Here my subroutine:
@Subroutine(TealType.bytes)
def update_contracts_fields(field):
saved_field = App.globalGet(Bytes(field))
saved_seller_pub = App.globalGet(Bytes(SELLER_PUB))
saved_buyer_pub = App.globalGet(Bytes(BUYER_PUB))
logic = Seq(
Assert(App.globalGet(Bytes(COMMITMENT_STATE)) != Bytes(COMM_STATE_EFFECTIVE)),
# Cond(
#
# ),
Cond(
[ # if currently set to nothing
saved_field == Bytes(""),
Seq( # first input provided by buyer
Assert(Txn.sender() == saved_buyer_pub),
App.globalPut(Bytes(field), Txn.application_args[1]),
)
], # if same value as existing, skips
[saved_field == Txn.application_args[1], Approve()],
[ # if currently set to something the change must be attested
saved_field != Txn.application_args[1],
Seq(
Cond( # if sender is the seller we remove the signature of the buyer, and vice versa
[Txn.sender() == saved_seller_pub, App.globalPut(Bytes(SIGNED_BY_BUYER), Bytes(""))],
[Txn.sender() == saved_buyer_pub, App.globalPut(Bytes(SIGNED_BY_SELLER), Bytes(""))]
), # then we can update the value
App.globalPut(Bytes(field), Txn.application_args[1])
)
]
),
)
return logic
I am trying then o use it as follows:
FIELD_TO_UPDATE = "my_field"
def noop_update_field():
return Seq(update_contracts_fields(FIELD_TO_UPDATE))
And then I get the error in the title.
What am I doing wrong?
Thanks in advance
The argument of a subroutine should by a PyTEAL type.
In your case, you should call
update_contracts_fields(Bytes(FIELD_TO_UPDATE))
and in your subroutine, you should use directly field
, instead of Bytes(field)
.
Thank you @fabrice, I did as you said and had another issue, it was expecting a TealType.none in the subroutine declaration.
I have fixed that and now it tells me that
pyteal.TealInputError: Subroutine function does not return a PyTeal expression. Got type <class 'tuple'>
I see examples of subroutines returning a logic like mine at Control Flow — PyTeal documentation
So what am i doing wrong now?
Thank you
Luca
Can you show a minimum example with the issue (that people can run with python
so they can see the exact issue)?
Can you compare with Control Flow — PyTeal documentation?
You need to return a PyTeal expression in the Python function. It looks like you are returning a Python tuple, something like return (aa, bb)
, which is not allowed.
Hi @fabrice,
The code has not changed apart from your recommendations above, the function returns a sequence like most examples at Control Flow — PyTeal documentation
I simplified the code now to try to narrow it to more simple logic but still:
@Subroutine(TealType.none)
def update_contracts_fields(field):
saved_field = App.globalGet(field)
logic = Seq(Cond(
[ # if currently set to nothing
saved_field == Bytes(""),
App.globalPut(field, Txn.application_args[1]),
],
[ # if currently set to something the change must be attested
saved_field != Txn.application_args[1],
App.globalPut(field, Txn.application_args[1])
]
), Approve())
return logic
I tried removing the Seq() and I have other subroutines that do work returning a Cond() but here is get this error that I am returning a tuple.
Here the full error if it is of any help
Traceback (most recent call last):
File "/Users/luca/Library/Mobile Documents/com~apple~CloudDocs/FDT VM/code/contractsvenv/lib/python3.9/site-packages/IPython/core/interactiveshell.py", line 3369, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-5-0f28285fdfe3>", line 1, in <cell line: 1>
approval_program_teal = approval_program()
File "/Users/luca/Library/Mobile Documents/com~apple~CloudDocs/FDT VM/code/algorand_src/contract.py", line 453, in approval_program
return compileTeal(program, Mode.Application, version=5)
File "/Users/luca/Library/Mobile Documents/com~apple~CloudDocs/FDT VM/code/contractsvenv/lib/python3.9/site-packages/pyteal/compiler/compiler.py", line 211, in compileTeal
compileSubroutine(
File "/Users/luca/Library/Mobile Documents/com~apple~CloudDocs/FDT VM/code/contractsvenv/lib/python3.9/site-packages/pyteal/compiler/compiler.py", line 158, in compileSubroutine
subroutine.getDeclaration(),
File "/Users/luca/Library/Mobile Documents/com~apple~CloudDocs/FDT VM/code/contractsvenv/lib/python3.9/site-packages/pyteal/ast/subroutine.py", line 60, in getDeclaration
self.declaration = evaluateSubroutine(self)
File "/Users/luca/Library/Mobile Documents/com~apple~CloudDocs/FDT VM/code/contractsvenv/lib/python3.9/site-packages/pyteal/ast/subroutine.py", line 219, in evaluateSubroutine
raise TealInputError(
pyteal.TealInputError: Subroutine function does not return a PyTeal expression. Got type <class 'tuple'>
I am starting to think that is because dynamic logic cannot be used in subroutines