Skip to content

Commit 303ca7d

Browse files
committed
feat: add support for populate-resources
See algorand/algorand-sdk-testing#319 for the test scenario
1 parent a2d610c commit 303ca7d

File tree

6 files changed

+113
-10
lines changed

6 files changed

+113
-10
lines changed

algosdk/abi/tuple_type.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,9 @@ def decode(self, bytestring: Union[bytes, bytearray]) -> list:
232232
"value string must be in bytes: {}".format(bytestring)
233233
)
234234
tuple_elements = self.child_types
235-
dynamic_segments: List[List[int]] = (
236-
list()
237-
) # Store the start and end of a dynamic element
235+
dynamic_segments: List[
236+
List[int]
237+
] = list() # Store the start and end of a dynamic element
238238
value_partitions: List[Optional[Union[bytes, bytearray]]] = list()
239239
i = 0
240240
array_index = 0

algosdk/atomic_transaction_composer.py

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from abc import ABC, abstractmethod
22
import base64
33
import copy
4+
from dataclasses import dataclass
45
from enum import IntEnum
56
from typing import (
67
Any,
@@ -25,6 +26,18 @@
2526
T = TypeVar("T")
2627

2728

29+
@dataclass(kw_only=True)
30+
class PopulatedResourceArrays:
31+
"""
32+
Contains the populated resource arrays when `populate_resources` is set to true on a simulate request
33+
"""
34+
35+
apps: list[int]
36+
accounts: list[str]
37+
assets: list[int]
38+
boxes: list[tuple[int, bytes]]
39+
40+
2841
def populate_foreign_array(
2942
value_to_add: T, foreign_array: List[T], zero_value: Optional[T] = None
3043
) -> int:
@@ -322,6 +335,8 @@ def __init__(
322335
results: List[SimulateABIResult],
323336
eval_overrides: Optional[SimulateEvalOverrides] = None,
324337
exec_trace_config: Optional[models.SimulateTraceConfig] = None,
338+
extra_resource_arrays: list[PopulatedResourceArrays] | None = None,
339+
populated_resource_arrays: list[PopulatedResourceArrays] | None = None,
325340
) -> None:
326341
self.version = version
327342
self.failure_message = failure_message
@@ -331,6 +346,8 @@ def __init__(
331346
self.abi_results = results
332347
self.eval_overrides = eval_overrides
333348
self.exec_trace_config = exec_trace_config
349+
self.extra_resource_arrays = extra_resource_arrays
350+
self.populated_resource_arrays = populated_resource_arrays
334351

335352

336353
class AtomicTransactionComposer:
@@ -679,9 +696,9 @@ def gather_signatures(self) -> List[GenericSignedTransaction]:
679696
stxn_list: List[Optional[GenericSignedTransaction]] = [None] * len(
680697
self.txn_list
681698
)
682-
signer_indexes: Dict[TransactionSigner, List[int]] = (
683-
{}
684-
) # Map a signer to a list of indices to sign
699+
signer_indexes: Dict[
700+
TransactionSigner, List[int]
701+
] = {} # Map a signer to a list of indices to sign
685702
txn_list = self.build_group()
686703
for i, txn_with_signer in enumerate(txn_list):
687704
if txn_with_signer.signer not in signer_indexes:
@@ -823,6 +840,40 @@ def simulate(
823840
)
824841
)
825842

843+
populated_resource_arrays = []
844+
for txn in txn_group["txn-results"]:
845+
if txn.get("populated-resource-arrays"):
846+
populated_resource_arrays.append(
847+
PopulatedResourceArrays(
848+
apps=txn["populated-resource-arrays"].get("apps", []),
849+
accounts=txn["populated-resource-arrays"].get(
850+
"accounts", []
851+
),
852+
assets=txn["populated-resource-arrays"].get(
853+
"assets", []
854+
),
855+
boxes=[
856+
(b["app"], base64.b64decode(b["name"]))
857+
for b in txn["populated-resource-arrays"].get(
858+
"boxes", []
859+
)
860+
],
861+
)
862+
)
863+
864+
extra_resource_arrays = []
865+
for arrays in txn_group.get("extra-resource-arrays", []):
866+
extra_resource_arrays.append(
867+
PopulatedResourceArrays(
868+
apps=arrays.get("apps", []),
869+
accounts=arrays.get("accounts", []),
870+
assets=arrays.get("assets", []),
871+
boxes=[
872+
(b["app"], base64.b64decode(b["name"]))
873+
for b in arrays.get("boxes", [])
874+
],
875+
)
876+
)
826877
return SimulateAtomicTransactionResponse(
827878
version=simulation_result.get("version", 0),
828879
failure_message=txn_group.get("failure-message", ""),
@@ -834,6 +885,8 @@ def simulate(
834885
simulation_result
835886
),
836887
exec_trace_config=exec_trace_config,
888+
extra_resource_arrays=extra_resource_arrays,
889+
populated_resource_arrays=populated_resource_arrays,
837890
)
838891

839892
def execute(

algosdk/transaction.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2308,9 +2308,9 @@ def merge(
23082308
for s in range(len(stx.multisig.subsigs)):
23092309
if stx.multisig.subsigs[s].signature:
23102310
if not msigstx.multisig.subsigs[s].signature:
2311-
msigstx.multisig.subsigs[s].signature = (
2312-
stx.multisig.subsigs[s].signature
2313-
)
2311+
msigstx.multisig.subsigs[
2312+
s
2313+
].signature = stx.multisig.subsigs[s].signature
23142314
elif (
23152315
not msigstx.multisig.subsigs[s].signature
23162316
== stx.multisig.subsigs[s].signature

algosdk/v2client/models/simulate_request.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ def __init__(
7272
allow_unnamed_resources: bool = False,
7373
extra_opcode_budget: int = 0,
7474
exec_trace_config: Optional[SimulateTraceConfig] = None,
75+
populate_resources: bool = False,
7576
) -> None:
7677
self.txn_groups = txn_groups
7778
self.round = round
@@ -82,6 +83,7 @@ def __init__(
8283
self.exec_trace_config = (
8384
exec_trace_config if exec_trace_config else SimulateTraceConfig()
8485
)
86+
self.populate_resources = populate_resources
8587

8688
def dictify(self) -> Dict[str, Any]:
8789
return {
@@ -94,4 +96,5 @@ def dictify(self) -> Dict[str, Any]:
9496
"allow-empty-signatures": self.allow_empty_signatures,
9597
"extra-opcode-budget": self.extra_opcode_budget,
9698
"exec-trace-config": self.exec_trace_config.dictify(),
99+
"populate-resources": self.populate_resources,
97100
}

tests/integration.tags

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@
1818
@simulate.lift_log_limits
1919
@simulate.extra_opcode_budget
2020
@simulate.exec_trace_with_stack_scratch
21-
@simulate.exec_trace_with_state_change_and_hash
21+
@simulate.exec_trace_with_state_change_and_hash
22+
@simulate.populate_resources

tests/steps/other_v2_steps.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import base64
22
import json
3+
from operator import truediv
34
import os
45
import unittest
56
import urllib
@@ -2036,3 +2037,48 @@ def get_ledger_state_delta_for_transaction_group(context, id):
20362037
@when("we make a GetBlockTxids call against block number {round}")
20372038
def get_block_txids_call(context, round):
20382039
context.response = context.acl.get_block_txids(round)
2040+
2041+
2042+
@when('I set unnamed-resources "{value}"')
2043+
def step_impl(context, value):
2044+
context.simulate_request.allow_unnamed_resources = value == "true"
2045+
2046+
2047+
@when('I set populate-resources "{value}"')
2048+
def step_impl(context, value):
2049+
context.simulate_request.populate_resources = value == "true"
2050+
2051+
2052+
@then(
2053+
"the response should include populated-resource-arrays for the transaction"
2054+
)
2055+
def step_impl(context):
2056+
resp: SimulateAtomicTransactionResponse = (
2057+
context.atomic_transaction_composer_return
2058+
)
2059+
assert len(resp.populated_resource_arrays) == 1
2060+
2061+
resources = resp.populated_resource_arrays[0]
2062+
assert resources.apps == [10000, 20000, 30000]
2063+
assert resources.accounts == [
2064+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ",
2065+
"AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKE3PRHE",
2066+
"AIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGFFWAF4",
2067+
"AMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANVWEXNA",
2068+
]
2069+
assert resources.boxes == [(context.current_application_id, b"box_key")]
2070+
assert resources.assets == []
2071+
2072+
2073+
@then("the response should include extra-resource-arrays for the group")
2074+
def step_impl(context):
2075+
resp: SimulateAtomicTransactionResponse = (
2076+
context.atomic_transaction_composer_return
2077+
)
2078+
assert len(resp.extra_resource_arrays) == 1
2079+
assert resp.extra_resource_arrays[0].apps == [40000]
2080+
assert resp.extra_resource_arrays[0].accounts == [
2081+
"AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJVBPJXY"
2082+
]
2083+
assert resp.extra_resource_arrays[0].assets == [10001]
2084+
assert resp.extra_resource_arrays[0].boxes == [(0, b"")]

0 commit comments

Comments
 (0)