algokit-utils 3.0.0b1__py3-none-any.whl → 3.0.0b2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of algokit-utils might be problematic. Click here for more details.

Files changed (70) hide show
  1. algokit_utils/__init__.py +23 -183
  2. algokit_utils/_debugging.py +123 -97
  3. algokit_utils/_legacy_v2/__init__.py +177 -0
  4. algokit_utils/{_ensure_funded.py → _legacy_v2/_ensure_funded.py} +19 -18
  5. algokit_utils/{_transfer.py → _legacy_v2/_transfer.py} +24 -23
  6. algokit_utils/_legacy_v2/account.py +203 -0
  7. algokit_utils/_legacy_v2/application_client.py +1471 -0
  8. algokit_utils/_legacy_v2/application_specification.py +21 -0
  9. algokit_utils/_legacy_v2/asset.py +168 -0
  10. algokit_utils/_legacy_v2/common.py +28 -0
  11. algokit_utils/_legacy_v2/deploy.py +822 -0
  12. algokit_utils/_legacy_v2/logic_error.py +14 -0
  13. algokit_utils/{models.py → _legacy_v2/models.py} +19 -142
  14. algokit_utils/_legacy_v2/network_clients.py +140 -0
  15. algokit_utils/account.py +12 -183
  16. algokit_utils/accounts/__init__.py +2 -0
  17. algokit_utils/accounts/account_manager.py +909 -0
  18. algokit_utils/accounts/kmd_account_manager.py +159 -0
  19. algokit_utils/algorand.py +265 -0
  20. algokit_utils/application_client.py +9 -1453
  21. algokit_utils/application_specification.py +39 -197
  22. algokit_utils/applications/__init__.py +7 -0
  23. algokit_utils/applications/abi.py +276 -0
  24. algokit_utils/applications/app_client.py +2056 -0
  25. algokit_utils/applications/app_deployer.py +600 -0
  26. algokit_utils/applications/app_factory.py +826 -0
  27. algokit_utils/applications/app_manager.py +470 -0
  28. algokit_utils/applications/app_spec/__init__.py +2 -0
  29. algokit_utils/applications/app_spec/arc32.py +207 -0
  30. algokit_utils/applications/app_spec/arc56.py +1023 -0
  31. algokit_utils/applications/enums.py +40 -0
  32. algokit_utils/asset.py +32 -168
  33. algokit_utils/assets/__init__.py +1 -0
  34. algokit_utils/assets/asset_manager.py +320 -0
  35. algokit_utils/beta/_utils.py +36 -0
  36. algokit_utils/beta/account_manager.py +4 -195
  37. algokit_utils/beta/algorand_client.py +4 -314
  38. algokit_utils/beta/client_manager.py +5 -74
  39. algokit_utils/beta/composer.py +5 -712
  40. algokit_utils/clients/__init__.py +2 -0
  41. algokit_utils/clients/client_manager.py +656 -0
  42. algokit_utils/clients/dispenser_api_client.py +192 -0
  43. algokit_utils/common.py +8 -26
  44. algokit_utils/config.py +71 -18
  45. algokit_utils/deploy.py +7 -892
  46. algokit_utils/dispenser_api.py +8 -176
  47. algokit_utils/errors/__init__.py +1 -0
  48. algokit_utils/errors/logic_error.py +121 -0
  49. algokit_utils/logic_error.py +7 -80
  50. algokit_utils/models/__init__.py +8 -0
  51. algokit_utils/models/account.py +193 -0
  52. algokit_utils/models/amount.py +198 -0
  53. algokit_utils/models/application.py +61 -0
  54. algokit_utils/models/network.py +25 -0
  55. algokit_utils/models/simulate.py +11 -0
  56. algokit_utils/models/state.py +59 -0
  57. algokit_utils/models/transaction.py +100 -0
  58. algokit_utils/network_clients.py +7 -152
  59. algokit_utils/protocols/__init__.py +2 -0
  60. algokit_utils/protocols/account.py +22 -0
  61. algokit_utils/protocols/typed_clients.py +108 -0
  62. algokit_utils/transactions/__init__.py +3 -0
  63. algokit_utils/transactions/transaction_composer.py +2293 -0
  64. algokit_utils/transactions/transaction_creator.py +156 -0
  65. algokit_utils/transactions/transaction_sender.py +574 -0
  66. {algokit_utils-3.0.0b1.dist-info → algokit_utils-3.0.0b2.dist-info}/METADATA +12 -7
  67. algokit_utils-3.0.0b2.dist-info/RECORD +70 -0
  68. {algokit_utils-3.0.0b1.dist-info → algokit_utils-3.0.0b2.dist-info}/WHEEL +1 -1
  69. algokit_utils-3.0.0b1.dist-info/RECORD +0 -24
  70. {algokit_utils-3.0.0b1.dist-info → algokit_utils-3.0.0b2.dist-info}/LICENSE +0 -0
algokit_utils/__init__.py CHANGED
@@ -1,184 +1,24 @@
1
- from algokit_utils._debugging import PersistSourceMapInput, persist_sourcemaps, simulate_and_persist_response
2
- from algokit_utils._ensure_funded import EnsureBalanceParameters, EnsureFundedResponse, ensure_funded
3
- from algokit_utils._transfer import TransferAssetParameters, TransferParameters, transfer, transfer_asset
4
- from algokit_utils.account import (
5
- create_kmd_wallet_account,
6
- get_account,
7
- get_account_from_mnemonic,
8
- get_dispenser_account,
9
- get_kmd_wallet_account,
10
- get_localnet_default_account,
11
- get_or_create_kmd_wallet_account,
12
- )
13
- from algokit_utils.application_client import (
14
- ApplicationClient,
15
- execute_atc_with_logic_error,
16
- get_next_version,
17
- get_sender_from_signer,
18
- num_extra_program_pages,
19
- )
20
- from algokit_utils.application_specification import (
21
- ApplicationSpecification,
22
- AppSpecStateDict,
23
- CallConfig,
24
- DefaultArgumentDict,
25
- DefaultArgumentType,
26
- MethodConfigDict,
27
- MethodHints,
28
- OnCompleteActionName,
29
- )
30
- from algokit_utils.asset import opt_in, opt_out
31
- from algokit_utils.common import Program
32
- from algokit_utils.deploy import (
33
- DELETABLE_TEMPLATE_NAME,
34
- NOTE_PREFIX,
35
- UPDATABLE_TEMPLATE_NAME,
36
- ABICallArgs,
37
- ABICallArgsDict,
38
- ABICreateCallArgs,
39
- ABICreateCallArgsDict,
40
- AppDeployMetaData,
41
- AppLookup,
42
- AppMetaData,
43
- AppReference,
44
- DeployCallArgs,
45
- DeployCallArgsDict,
46
- DeployCreateCallArgs,
47
- DeployCreateCallArgsDict,
48
- DeploymentFailedError,
49
- DeployResponse,
50
- OnSchemaBreak,
51
- OnUpdate,
52
- OperationPerformed,
53
- TemplateValueDict,
54
- TemplateValueMapping,
55
- get_app_id_from_tx_id,
56
- get_creator_apps,
57
- replace_template_variables,
58
- )
59
- from algokit_utils.dispenser_api import (
60
- DISPENSER_ACCESS_TOKEN_KEY,
61
- DISPENSER_REQUEST_TIMEOUT,
62
- DispenserFundResponse,
63
- DispenserLimitResponse,
64
- TestNetDispenserApiClient,
65
- )
66
- from algokit_utils.logic_error import LogicError
67
- from algokit_utils.models import (
68
- ABIArgsDict,
69
- ABIMethod,
70
- ABITransactionResponse,
71
- Account,
72
- CommonCallParameters, # noqa: F401
73
- CommonCallParametersDict, # noqa: F401
74
- CreateCallParameters,
75
- CreateCallParametersDict,
76
- CreateTransactionParameters,
77
- OnCompleteCallParameters,
78
- OnCompleteCallParametersDict,
79
- RawTransactionParameters, # noqa: F401
80
- TransactionParameters,
81
- TransactionParametersDict,
82
- TransactionResponse,
83
- )
84
- from algokit_utils.network_clients import (
85
- AlgoClientConfig,
86
- get_algod_client,
87
- get_algonode_config,
88
- get_default_localnet_config,
89
- get_indexer_client,
90
- get_kmd_client_from_algod_client,
91
- get_purestake_config,
92
- is_localnet,
93
- is_mainnet,
94
- is_testnet,
95
- )
1
+ """AlgoKit Python Utilities - a set of utilities for building solutions on Algorand
96
2
 
97
- __all__ = [
98
- "create_kmd_wallet_account",
99
- "get_account_from_mnemonic",
100
- "get_or_create_kmd_wallet_account",
101
- "get_localnet_default_account",
102
- "get_dispenser_account",
103
- "get_kmd_wallet_account",
104
- "get_account",
105
- "UPDATABLE_TEMPLATE_NAME",
106
- "DELETABLE_TEMPLATE_NAME",
107
- "NOTE_PREFIX",
108
- "DeploymentFailedError",
109
- "AppReference",
110
- "AppDeployMetaData",
111
- "AppMetaData",
112
- "AppLookup",
113
- "get_creator_apps",
114
- "replace_template_variables",
115
- "ABIArgsDict",
116
- "ABICallArgs",
117
- "ABICallArgsDict",
118
- "ABICreateCallArgs",
119
- "ABICreateCallArgsDict",
120
- "ABIMethod",
121
- "CreateCallParameters",
122
- "CreateCallParametersDict",
123
- "CreateTransactionParameters",
124
- "DeployCallArgs",
125
- "DeployCreateCallArgs",
126
- "DeployCallArgsDict",
127
- "DeployCreateCallArgsDict",
128
- "OnCompleteCallParameters",
129
- "OnCompleteCallParametersDict",
130
- "TransactionParameters",
131
- "TransactionParametersDict",
132
- "ApplicationClient",
133
- "DeployResponse",
134
- "OnUpdate",
135
- "OnSchemaBreak",
136
- "OperationPerformed",
137
- "TemplateValueDict",
138
- "TemplateValueMapping",
139
- "Program",
140
- "execute_atc_with_logic_error",
141
- "get_app_id_from_tx_id",
142
- "get_next_version",
143
- "get_sender_from_signer",
144
- "num_extra_program_pages",
145
- "AppSpecStateDict",
146
- "ApplicationSpecification",
147
- "CallConfig",
148
- "DefaultArgumentDict",
149
- "DefaultArgumentType",
150
- "MethodConfigDict",
151
- "OnCompleteActionName",
152
- "MethodHints",
153
- "LogicError",
154
- "ABITransactionResponse",
155
- "Account",
156
- "TransactionResponse",
157
- "AlgoClientConfig",
158
- "get_algod_client",
159
- "get_algonode_config",
160
- "get_default_localnet_config",
161
- "get_indexer_client",
162
- "get_kmd_client_from_algod_client",
163
- "get_purestake_config",
164
- "is_localnet",
165
- "is_mainnet",
166
- "is_testnet",
167
- "TestNetDispenserApiClient",
168
- "DispenserFundResponse",
169
- "DispenserLimitResponse",
170
- "DISPENSER_ACCESS_TOKEN_KEY",
171
- "DISPENSER_REQUEST_TIMEOUT",
172
- "EnsureBalanceParameters",
173
- "EnsureFundedResponse",
174
- "TransferParameters",
175
- "ensure_funded",
176
- "transfer",
177
- "TransferAssetParameters",
178
- "transfer_asset",
179
- "opt_in",
180
- "opt_out",
181
- "persist_sourcemaps",
182
- "PersistSourceMapInput",
183
- "simulate_and_persist_response",
184
- ]
3
+ This module provides commonly used utilities and types at the root level for convenience.
4
+ For more specific functionality, import directly from the relevant submodules:
5
+
6
+ from algokit_utils.accounts import KmdAccountManager
7
+ from algokit_utils.applications import AppClient
8
+ from algokit_utils.applications.app_spec import Arc52Contract
9
+ etc.
10
+ """
11
+
12
+ # Core types and utilities that are commonly used
13
+ from algokit_utils.applications import * # noqa: F403
14
+ from algokit_utils.assets import * # noqa: F403
15
+ from algokit_utils.protocols import * # noqa: F403
16
+ from algokit_utils.models import * # noqa: F403
17
+ from algokit_utils.accounts import * # noqa: F403
18
+ from algokit_utils.clients import * # noqa: F403
19
+ from algokit_utils.transactions import * # noqa: F403
20
+ from algokit_utils.errors import * # noqa: F403
21
+ from algokit_utils.algorand import * # noqa: F403
22
+
23
+ # Legacy types and utilities
24
+ from algokit_utils._legacy_v2 import * # noqa: F403
@@ -14,7 +14,8 @@ from algosdk.atomic_transaction_composer import (
14
14
  from algosdk.encoding import checksum
15
15
  from algosdk.v2client.models import SimulateRequest, SimulateRequestTransactionGroup, SimulateTraceConfig
16
16
 
17
- from algokit_utils.common import Program
17
+ from algokit_utils._legacy_v2.common import Program
18
+ from algokit_utils.models.application import CompiledTeal
18
19
 
19
20
  if typing.TYPE_CHECKING:
20
21
  from algosdk.v2client.algod import AlgodClient
@@ -27,7 +28,7 @@ SOURCES_FILE = "sources.avm.json"
27
28
  TRACES_FILE_EXT = ".trace.avm.json"
28
29
  DEBUG_TRACES_DIR = "debug_traces"
29
30
  TEAL_FILE_EXT = ".teal"
30
- TEAL_SOURCEMAP_EXT = ".teal.tok.map"
31
+ TEAL_SOURCEMAP_EXT = ".teal.map"
31
32
 
32
33
 
33
34
  @dataclass
@@ -64,7 +65,11 @@ class AVMDebuggerSourceMap:
64
65
  @dataclass
65
66
  class PersistSourceMapInput:
66
67
  def __init__(
67
- self, app_name: str, file_name: str, raw_teal: str | None = None, compiled_teal: Program | None = None
68
+ self,
69
+ app_name: str,
70
+ file_name: str,
71
+ raw_teal: str | None = None,
72
+ compiled_teal: CompiledTeal | Program | None = None,
68
73
  ):
69
74
  self.compiled_teal = compiled_teal
70
75
  self.app_name = app_name
@@ -76,7 +81,9 @@ class PersistSourceMapInput:
76
81
  return cls(app_name, file_name, raw_teal=raw_teal)
77
82
 
78
83
  @classmethod
79
- def from_compiled_teal(cls, compiled_teal: Program, app_name: str, file_name: str) -> "PersistSourceMapInput":
84
+ def from_compiled_teal(
85
+ cls, compiled_teal: CompiledTeal | Program, app_name: str, file_name: str
86
+ ) -> "PersistSourceMapInput":
80
87
  return cls(app_name, file_name, compiled_teal=compiled_teal)
81
88
 
82
89
  @property
@@ -107,60 +114,40 @@ def _load_or_create_sources(sources_path: Path) -> AVMDebuggerSourceMap:
107
114
  return AVMDebuggerSourceMap.from_dict(json.load(f))
108
115
 
109
116
 
110
- def _upsert_debug_sourcemaps(sourcemaps: list[AVMDebuggerSourceMapEntry], project_root: Path) -> None:
111
- """
112
- This function updates or inserts debug sourcemaps. If path in the sourcemap during iteration leads to non
113
- existing file, removes it. Otherwise upserts.
114
-
115
- Args:
116
- sourcemaps (list[AVMDebuggerSourceMapEntry]): A list of AVMDebuggerSourceMapEntry objects.
117
- project_root (Path): The root directory of the project.
118
-
119
- Returns:
120
- None
121
- """
122
-
123
- sources_path = project_root / ALGOKIT_DIR / SOURCES_DIR / SOURCES_FILE
124
- sources = _load_or_create_sources(sources_path)
125
-
126
- for sourcemap in sourcemaps:
127
- source_file_path = Path(sourcemap.location)
128
- if not source_file_path.exists() and sourcemap in sources.txn_group_sources:
129
- sources.txn_group_sources.remove(sourcemap)
130
- elif source_file_path.exists():
131
- if sourcemap not in sources.txn_group_sources:
132
- sources.txn_group_sources.append(sourcemap)
133
- else:
134
- index = sources.txn_group_sources.index(sourcemap)
135
- sources.txn_group_sources[index] = sourcemap
136
-
137
- with sources_path.open("w") as f:
138
- json.dump(sources.to_dict(), f)
139
-
140
-
141
117
  def _write_to_file(path: Path, content: str) -> None:
142
118
  path.parent.mkdir(parents=True, exist_ok=True)
143
119
  path.write_text(content)
144
120
 
145
121
 
146
- def _build_avm_sourcemap( # noqa: PLR0913
122
+ def _build_avm_sourcemap(
147
123
  *,
148
124
  app_name: str,
149
125
  file_name: str,
150
126
  output_path: Path,
151
127
  client: "AlgodClient",
152
128
  raw_teal: str | None = None,
153
- compiled_teal: Program | None = None,
129
+ compiled_teal: CompiledTeal | Program | None = None,
154
130
  with_sources: bool = True,
155
131
  ) -> AVMDebuggerSourceMapEntry:
156
132
  if not raw_teal and not compiled_teal:
157
133
  raise ValueError("Either raw teal or compiled teal must be provided")
158
134
 
159
- result = compiled_teal if compiled_teal else Program(str(raw_teal), client=client)
160
- program_hash = base64.b64encode(
161
- checksum(result.raw_binary) # type: ignore[no-untyped-call]
162
- ).decode()
163
- source_map = result.source_map.__dict__
135
+ # Handle both legacy Program and new CompiledTeal
136
+ if isinstance(compiled_teal, Program):
137
+ program_hash = base64.b64encode(checksum(compiled_teal.raw_binary)).decode()
138
+ source_map = compiled_teal.source_map.__dict__
139
+ teal_content = compiled_teal.teal
140
+ elif isinstance(compiled_teal, CompiledTeal):
141
+ program_hash = base64.b64encode(checksum(compiled_teal.compiled_base64_to_bytes)).decode()
142
+ source_map = compiled_teal.source_map.__dict__ if compiled_teal.source_map else {}
143
+ teal_content = compiled_teal.teal
144
+ else:
145
+ # Handle raw TEAL case
146
+ result = Program(str(raw_teal), client=client)
147
+ program_hash = base64.b64encode(checksum(result.raw_binary)).decode()
148
+ source_map = result.source_map.__dict__
149
+ teal_content = result.teal
150
+
164
151
  source_map["sources"] = [f"{file_name}{TEAL_FILE_EXT}"] if with_sources else []
165
152
 
166
153
  output_dir_path = output_path / ALGOKIT_DIR / SOURCES_DIR / app_name
@@ -169,25 +156,45 @@ def _build_avm_sourcemap( # noqa: PLR0913
169
156
  _write_to_file(source_map_output_path, json.dumps(source_map))
170
157
 
171
158
  if with_sources:
172
- _write_to_file(teal_output_path, result.teal)
159
+ _write_to_file(teal_output_path, teal_content)
173
160
 
174
161
  return AVMDebuggerSourceMapEntry(str(source_map_output_path), program_hash)
175
162
 
176
163
 
164
+ def cleanup_old_trace_files(output_dir: Path, buffer_size_mb: float) -> None:
165
+ """
166
+ Cleanup old trace files if total size exceeds buffer size limit.
167
+
168
+ Args:
169
+ output_dir (Path): Directory containing trace files
170
+ buffer_size_mb (float): Maximum allowed size in megabytes
171
+ """
172
+ total_size = sum(f.stat().st_size for f in output_dir.glob("*") if f.is_file())
173
+ if total_size > buffer_size_mb * 1024 * 1024:
174
+ sorted_files = sorted(output_dir.glob("*"), key=lambda p: p.stat().st_mtime)
175
+ while total_size > buffer_size_mb * 1024 * 1024 and sorted_files:
176
+ oldest_file = sorted_files.pop(0)
177
+ total_size -= oldest_file.stat().st_size
178
+ oldest_file.unlink()
179
+
180
+
177
181
  def persist_sourcemaps(
178
- *, sources: list[PersistSourceMapInput], project_root: Path, client: "AlgodClient", with_sources: bool = True
182
+ *,
183
+ sources: list[PersistSourceMapInput],
184
+ project_root: Path,
185
+ client: "AlgodClient",
186
+ with_sources: bool = True,
179
187
  ) -> None:
180
188
  """
181
189
  Persist the sourcemaps for the given sources as an AlgoKit AVM Debugger compliant artifacts.
182
- Args:
183
- sources (list[PersistSourceMapInput]): A list of PersistSourceMapInput objects.
184
- project_root (Path): The root directory of the project.
185
- client (AlgodClient): An AlgodClient object for interacting with the Algorand blockchain.
186
- with_sources (bool): If True, it will dump teal source files along with sourcemaps.
187
- Default is True, as needed by an AlgoKit AVM debugger.
190
+
191
+ :param sources: A list of PersistSourceMapInput objects.
192
+ :param project_root: The root directory of the project.
193
+ :param client: An AlgodClient object for interacting with the Algorand blockchain.
194
+ :param with_sources: If True, it will dump teal source files along with sourcemaps.
188
195
  """
189
196
 
190
- sourcemaps = [
197
+ for source in sources:
191
198
  _build_avm_sourcemap(
192
199
  raw_teal=source.raw_teal,
193
200
  compiled_teal=source.compiled_teal,
@@ -197,54 +204,68 @@ def persist_sourcemaps(
197
204
  client=client,
198
205
  with_sources=with_sources,
199
206
  )
200
- for source in sources
201
- ]
202
-
203
- _upsert_debug_sourcemaps(sourcemaps, project_root)
204
207
 
205
208
 
206
- def simulate_response(atc: AtomicTransactionComposer, algod_client: "AlgodClient") -> SimulateAtomicTransactionResponse:
207
- """
208
- Simulate and fetch response for the given AtomicTransactionComposer and AlgodClient.
209
-
210
- Args:
211
- atc (AtomicTransactionComposer): An AtomicTransactionComposer object.
212
- algod_client (AlgodClient): An AlgodClient object for interacting with the Algorand blockchain.
213
-
214
- Returns:
215
- SimulateAtomicTransactionResponse: The simulated response.
216
- """
209
+ def simulate_response(
210
+ atc: AtomicTransactionComposer,
211
+ algod_client: "AlgodClient",
212
+ allow_more_logs: bool | None = None,
213
+ allow_empty_signatures: bool | None = None,
214
+ allow_unnamed_resources: bool | None = None,
215
+ extra_opcode_budget: int | None = None,
216
+ exec_trace_config: SimulateTraceConfig | None = None,
217
+ simulation_round: int | None = None,
218
+ ) -> SimulateAtomicTransactionResponse:
219
+ """Simulate atomic transaction group execution"""
217
220
 
218
221
  unsigned_txn_groups = atc.build_group()
219
222
  empty_signer = EmptySigner()
220
223
  txn_list = [txn_group.txn for txn_group in unsigned_txn_groups]
221
224
  fake_signed_transactions = empty_signer.sign_transactions(txn_list, [])
222
225
  txn_group = [SimulateRequestTransactionGroup(txns=fake_signed_transactions)]
223
- trace_config = SimulateTraceConfig(enable=True, stack_change=True, scratch_change=True)
226
+ trace_config = SimulateTraceConfig(enable=True, stack_change=True, scratch_change=True, state_change=True)
224
227
 
225
228
  simulate_request = SimulateRequest(
226
- txn_groups=txn_group, allow_more_logs=True, allow_empty_signatures=True, exec_trace_config=trace_config
229
+ txn_groups=txn_group,
230
+ allow_more_logs=allow_more_logs if allow_more_logs is not None else True,
231
+ round=simulation_round,
232
+ extra_opcode_budget=extra_opcode_budget if extra_opcode_budget is not None else 0,
233
+ allow_unnamed_resources=allow_unnamed_resources if allow_unnamed_resources is not None else True,
234
+ allow_empty_signatures=allow_empty_signatures if allow_empty_signatures is not None else True,
235
+ exec_trace_config=exec_trace_config if exec_trace_config is not None else trace_config,
227
236
  )
237
+
228
238
  return atc.simulate(algod_client, simulate_request)
229
239
 
230
240
 
231
241
  def simulate_and_persist_response(
232
- atc: AtomicTransactionComposer, project_root: Path, algod_client: "AlgodClient", buffer_size_mb: float = 256
242
+ atc: AtomicTransactionComposer,
243
+ project_root: Path,
244
+ algod_client: "AlgodClient",
245
+ buffer_size_mb: float = 256,
246
+ allow_more_logs: bool | None = None,
247
+ allow_empty_signatures: bool | None = None,
248
+ allow_unnamed_resources: bool | None = None,
249
+ extra_opcode_budget: int | None = None,
250
+ exec_trace_config: SimulateTraceConfig | None = None,
251
+ simulation_round: int | None = None,
233
252
  ) -> SimulateAtomicTransactionResponse:
234
- """
235
- Simulates the atomic transactions using the provided `AtomicTransactionComposer` object and `AlgodClient` object,
236
- and persists the simulation response to an AlgoKit AVM Debugger compliant JSON file.
237
-
238
- :param atc: An `AtomicTransactionComposer` object representing the atomic transactions to be
239
- simulated and persisted.
240
- :param project_root: A `Path` object representing the root directory of the project.
241
- :param algod_client: An `AlgodClient` object representing the Algorand client.
242
- :param buffer_size_mb: The size of the trace buffer in megabytes. Defaults to 256mb.
243
- :return: None
244
-
245
- Returns:
246
- SimulateAtomicTransactionResponse: The simulated response after persisting it
247
- for AlgoKit AVM Debugger consumption.
253
+ """Simulates atomic transactions and persists simulation response to a JSON file.
254
+
255
+ Simulates the atomic transactions using the provided AtomicTransactionComposer and AlgodClient,
256
+ then persists the simulation response to an AlgoKit AVM Debugger compliant JSON file.
257
+
258
+ :param atc: AtomicTransactionComposer containing transactions to simulate and persist
259
+ :param project_root: Root directory path of the project
260
+ :param algod_client: Algorand client instance
261
+ :param buffer_size_mb: Size of trace buffer in megabytes, defaults to 256
262
+ :param allow_more_logs: Flag to allow additional logs, defaults to None
263
+ :param allow_empty_signatures: Flag to allow empty signatures, defaults to None
264
+ :param allow_unnamed_resources: Flag to allow unnamed resources, defaults to None
265
+ :param extra_opcode_budget: Additional opcode budget, defaults to None
266
+ :param exec_trace_config: Execution trace configuration, defaults to None
267
+ :param simulation_round: Round number for simulation, defa ults to None
268
+ :return: Simulated response after persisting for AlgoKit AVM Debugger consumption
248
269
  """
249
270
  atc_to_simulate = atc.clone()
250
271
  sp = algod_client.suggested_params()
@@ -254,27 +275,32 @@ def simulate_and_persist_response(
254
275
  txn_with_sign.txn.last_valid_round = sp.last
255
276
  txn_with_sign.txn.genesis_hash = sp.gh
256
277
 
257
- response = simulate_response(atc_to_simulate, algod_client)
278
+ response = simulate_response(
279
+ atc_to_simulate,
280
+ algod_client,
281
+ allow_more_logs,
282
+ allow_empty_signatures,
283
+ allow_unnamed_resources,
284
+ extra_opcode_budget,
285
+ exec_trace_config,
286
+ simulation_round,
287
+ )
258
288
  txn_results = response.simulate_response["txn-groups"]
259
289
 
260
- txn_types = [txn_result["txn-results"][0]["txn-result"]["txn"]["txn"]["type"] for txn_result in txn_results]
261
- txn_types_count = {txn_type: txn_types.count(txn_type) for txn_type in set(txn_types)}
262
- txn_types_str = "_".join([f"{count}#{txn_type}" for txn_type, count in txn_types_count.items()])
290
+ txn_types = [
291
+ txn["txn-result"]["txn"]["txn"]["type"] for txn_result in txn_results for txn in txn_result["txn-results"]
292
+ ]
293
+ txn_types_count = {}
294
+ for txn_type in txn_types:
295
+ if txn_type not in txn_types_count:
296
+ txn_types_count[txn_type] = txn_types.count(txn_type)
297
+ txn_types_str = "_".join([f"{count}{txn_type}" for txn_type, count in txn_types_count.items()])
263
298
 
264
299
  last_round = response.simulate_response["last-round"]
265
300
  timestamp = datetime.now(tz=timezone.utc).strftime("%Y%m%d_%H%M%S")
266
301
  output_file = project_root / DEBUG_TRACES_DIR / f"{timestamp}_lr{last_round}_{txn_types_str}{TRACES_FILE_EXT}"
267
302
 
268
303
  output_file.parent.mkdir(parents=True, exist_ok=True)
269
-
270
- # cleanup old files if buffer size is exceeded
271
- total_size = sum(f.stat().st_size for f in output_file.parent.glob("*") if f.is_file())
272
- if total_size > buffer_size_mb * 1024 * 1024:
273
- sorted_files = sorted(output_file.parent.glob("*"), key=lambda p: p.stat().st_mtime)
274
- while total_size > buffer_size_mb * 1024 * 1024:
275
- oldest_file = sorted_files.pop(0)
276
- total_size -= oldest_file.stat().st_size
277
- oldest_file.unlink()
278
-
304
+ cleanup_old_trace_files(output_file.parent, buffer_size_mb)
279
305
  output_file.write_text(json.dumps(response.simulate_response, indent=2))
280
306
  return response