Skip to content

Commit f7a887b

Browse files
committed
fix: expose execute_atc_with_logic_error, allow specifying approval source map
1 parent 000612d commit f7a887b

File tree

1 file changed

+44
-41
lines changed

1 file changed

+44
-41
lines changed

src/algokit_utils/application_client.py

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ def __init__(
185185
self.app_spec = app_spec
186186
self._approval_program: Program | None = None
187187
self._clear_program: Program | None = None
188-
self._approval_source_map: SourceMap | None = None
188+
self.approval_source_map: SourceMap | None = None
189189
self.existing_deployments = existing_deployments
190190
self._indexer_client = indexer_client
191191
if creator is not None:
@@ -226,17 +226,12 @@ def __init__(
226226
def app_address(self) -> str:
227227
return get_application_address(self.app_id)
228228

229-
# TODO: source map changes
230229
@property
231-
def approval(self) -> Program:
232-
if not self._approval_program:
233-
self._approval_program = Program(self.app_spec.approval_program, self.algod_client)
230+
def approval(self) -> Program | None:
234231
return self._approval_program
235232

236233
@property
237-
def clear(self) -> Program:
238-
if not self._clear_program:
239-
self._clear_program = Program(self.app_spec.clear_program, self.algod_client)
234+
def clear(self) -> Program | None:
240235
return self._clear_program
241236

242237
def deploy(
@@ -502,7 +497,7 @@ def compose_create(
502497
extra_pages: int | None = None,
503498
note: bytes | str | None = None,
504499
lease: bytes | None = None,
505-
) -> None:
500+
) -> tuple[Program, Program]:
506501
"""Adds a signed transaction with application id == 0 and the schema and source of client's app_spec to atc"""
507502

508503
approval_program, clear_program = self._substitute_template_and_compile(template_values)
@@ -529,6 +524,8 @@ def compose_create(
529524
lease=lease,
530525
)
531526

527+
return approval_program, clear_program
528+
532529
def create(
533530
self,
534531
abi_method: Method | str | bool | None = None,
@@ -547,7 +544,7 @@ def create(
547544

548545
atc = AtomicTransactionComposer()
549546

550-
self.compose_create(
547+
self._approval_program, self._clear_program = self.compose_create(
551548
atc,
552549
abi_method,
553550
args,
@@ -576,7 +573,7 @@ def compose_update(
576573
template_values: TemplateValueDict | None = None,
577574
note: bytes | str | None = None,
578575
lease: bytes | None = None,
579-
) -> None:
576+
) -> tuple[Program, Program]:
580577
"""Adds a signed transaction with on_complete=UpdateApplication to atc"""
581578

582579
self._load_reference_and_check_app_id()
@@ -597,6 +594,8 @@ def compose_update(
597594
lease=lease,
598595
)
599596

597+
return approval_program, clear_program
598+
600599
def update(
601600
self,
602601
abi_method: Method | str | bool | None = None,
@@ -612,7 +611,7 @@ def update(
612611
"""Submits a signed transaction with on_complete=UpdateApplication"""
613612

614613
atc = AtomicTransactionComposer()
615-
self.compose_update(
614+
self._approval_program, self._clear_program = self.compose_update(
616615
atc,
617616
abi_method,
618617
args,
@@ -1069,21 +1068,11 @@ def _substitute_template_and_compile(
10691068
self._clear_program = Program(clear, self.algod_client)
10701069
return self._approval_program, self._clear_program
10711070

1072-
def _get_approval_source_map(self) -> SourceMap:
1073-
def _find_template_vars(program: str) -> list[str]:
1074-
pattern = re.compile(r"\bTMPL_(\w*)\b")
1075-
return pattern.findall(program)
1071+
def _get_approval_source_map(self) -> SourceMap | None:
1072+
if self.approval:
1073+
return self.approval.source_map
10761074

1077-
if not self._approval_source_map:
1078-
if self._approval_program:
1079-
self._approval_source_map = self._approval_program.source_map
1080-
else:
1081-
# TODO: this will produce an incorrect source map for bytes as their length is not fixed
1082-
template_values: TemplateValueDict = {k: 0 for k in _find_template_vars(self.app_spec.approval_program)}
1083-
approval_program = replace_template_variables(self.app_spec.approval_program, template_values)
1084-
approval = Program(approval_program, self.algod_client)
1085-
self._approval_source_map = approval.source_map
1086-
return self._approval_source_map
1075+
return self.approval_source_map
10871076

10881077
def _add_method_call(
10891078
self,
@@ -1254,21 +1243,13 @@ def _execute_atc_tr(self, atc: AtomicTransactionComposer) -> TransactionResponse
12541243
confirmed_round=result.confirmed_round,
12551244
)
12561245

1257-
def _execute_atc(self, atc: AtomicTransactionComposer, wait_rounds: int = 4) -> AtomicTransactionResponse:
1258-
try:
1259-
return atc.execute(self.algod_client, wait_rounds=wait_rounds)
1260-
except Exception as ex:
1261-
logic_error_data = parse_logic_error(str(ex))
1262-
if logic_error_data is not None:
1263-
source_map = self._get_approval_source_map()
1264-
if source_map:
1265-
raise LogicError(
1266-
logic_error=ex,
1267-
program=self.app_spec.approval_program,
1268-
source_map=source_map,
1269-
**logic_error_data,
1270-
) from ex
1271-
raise ex
1246+
def _execute_atc(self, atc: AtomicTransactionComposer) -> AtomicTransactionResponse:
1247+
return execute_atc_with_logic_error(
1248+
atc,
1249+
self.algod_client,
1250+
approval_program=self.approval.teal if self.approval else self.app_spec.approval_program,
1251+
approval_source_map=self._get_approval_source_map(),
1252+
)
12721253

12731254
def _set_app_id_from_tx_id(self, tx_id: str) -> None:
12741255
self.app_id = get_app_id_from_tx_id(self.algod_client, tx_id)
@@ -1455,3 +1436,25 @@ def _get_deploy_control(
14551436
return _get_call_config(app_spec.bare_call_config, on_complete) != CallConfig.NEVER or any(
14561437
h for h in app_spec.hints.values() if _get_call_config(h.call_config, on_complete) != CallConfig.NEVER
14571438
)
1439+
1440+
1441+
def execute_atc_with_logic_error(
1442+
atc: AtomicTransactionComposer,
1443+
algod_client: AlgodClient,
1444+
wait_rounds: int = 4,
1445+
approval_program: str | None = None,
1446+
approval_source_map: SourceMap | None = None,
1447+
) -> AtomicTransactionResponse:
1448+
try:
1449+
return atc.execute(algod_client, wait_rounds=wait_rounds)
1450+
except Exception as ex:
1451+
if approval_source_map and approval_program:
1452+
logic_error_data = parse_logic_error(str(ex))
1453+
if logic_error_data is not None:
1454+
raise LogicError(
1455+
logic_error=ex,
1456+
program=approval_program,
1457+
source_map=approval_source_map,
1458+
**logic_error_data,
1459+
) from ex
1460+
raise ex

0 commit comments

Comments
 (0)