diff --git a/algosdk/atomic_transaction_composer.py b/algosdk/atomic_transaction_composer.py index 926ec832..0ca9aaa3 100644 --- a/algosdk/atomic_transaction_composer.py +++ b/algosdk/atomic_transaction_composer.py @@ -714,7 +714,7 @@ def simulate( ) simulation_result = cast( - Dict[str, Any], client.simulate_transactions(self.signed_txns) + Dict[str, Any], client.simulate_raw_transactions(self.signed_txns) ) # Only take the first group in the simulate response txn_group: Dict[str, Any] = simulation_result["txn-groups"][0] diff --git a/algosdk/v2client/algod.py b/algosdk/v2client/algod.py index 01010026..586b780e 100644 --- a/algosdk/v2client/algod.py +++ b/algosdk/v2client/algod.py @@ -18,6 +18,7 @@ from urllib.request import Request, urlopen from algosdk import constants, encoding, error, transaction, util +from algosdk.v2client import models AlgodResponseType = Union[Dict[str, Any], bytes] @@ -598,48 +599,47 @@ def get_block_hash( def simulate_transactions( self, - txns: "Iterable[transaction.GenericSignedTransaction]", + request: models.SimulateRequest, **kwargs: Any, ) -> AlgodResponseType: """ - Simulate a list of a signed transaction objects being sent to the network. + Simulate transactions being sent to the network. Args: - txns (SignedTransaction[] or MultisigTransaction[]): - transactions to send - request_header (dict, optional): additional header for request + request (models.SimulateRequest): Simulation request object + headers (dict, optional): additional header for request Returns: - Dict[str, Any]: results from simulation of transaction group + Dict[str, Any]: results from simulation of transactions """ - serialized = [] - for txn in txns: - serialized.append(base64.b64decode(encoding.msgpack_encode(txn))) - - return self.simulate_raw_transaction( - base64.b64encode(b"".join(serialized)), **kwargs + body = base64.b64decode(encoding.msgpack_encode(request)) + req = "/transactions/simulate" + headers = util.build_headers_from( + kwargs.get("headers", False), + {"Content-Type": "application/msgpack"}, ) + kwargs["headers"] = headers + return self.algod_request("POST", req, data=body, **kwargs) - def simulate_raw_transaction(self, txn, **kwargs): + def simulate_raw_transactions( + self, txns: "Sequence[transaction.GenericSignedTransaction]", **kwargs + ): """ - Simulate a transaction group + Simulate a transaction group being sent to the network. Args: - txn (str): transaction to send, encoded in base64 - request_header (dict, optional): additional header for request + txns (Sequence[transaction.GenericSignedTransaction]): transaction group to simulate + headers (dict, optional): additional header for request Returns: - Dict[str, Any]: results from simulation of transaction group + Dict[str, Any]: results from simulation of transactions """ - txn = base64.b64decode(txn) - req = "/transactions/simulate" - headers = util.build_headers_from( - kwargs.get("headers", False), - {"Content-Type": "application/x-binary"}, + request = models.SimulateRequest( + txn_groups=[ + models.SimulateRequestTransactionGroup(txns=list(txns)) + ] ) - kwargs["headers"] = headers - - return self.algod_request("POST", req, data=txn, **kwargs) + return self.simulate_transactions(request, **kwargs) def _specify_round_string( diff --git a/algosdk/v2client/models/__init__.py b/algosdk/v2client/models/__init__.py index 025e7dea..c9625b4f 100644 --- a/algosdk/v2client/models/__init__.py +++ b/algosdk/v2client/models/__init__.py @@ -31,10 +31,15 @@ from algosdk.v2client.models.dryrun_source import DryrunSource from algosdk.v2client.models.teal_key_value import TealKeyValue from algosdk.v2client.models.teal_value import TealValue +from algosdk.v2client.models.simulate_request import ( + SimulateRequest, + SimulateRequestTransactionGroup, +) __all__ = [ "Account", "AccountParticipation", + "Application", "ApplicationLocalState", "ApplicationParams", "ApplicationStateSchema", @@ -45,4 +50,6 @@ "DryrunSource", "TealKeyValue", "TealValue", + "SimulateRequest", + "SimulateRequestTransactionGroup", ] diff --git a/algosdk/v2client/models/simulate_request.py b/algosdk/v2client/models/simulate_request.py new file mode 100644 index 00000000..51d7ed63 --- /dev/null +++ b/algosdk/v2client/models/simulate_request.py @@ -0,0 +1,32 @@ +from typing import List, Dict, Any, TYPE_CHECKING + +if TYPE_CHECKING: + from algosdk import transaction + + +class SimulateRequestTransactionGroup(object): + txns: "List[transaction.GenericSignedTransaction]" + + def __init__( + self, *, txns: "List[transaction.GenericSignedTransaction]" + ) -> None: + self.txns = txns + + def dictify(self) -> Dict[str, Any]: + return {"txns": [txn.dictify() for txn in self.txns]} + + +class SimulateRequest(object): + txn_groups: List[SimulateRequestTransactionGroup] + + def __init__( + self, *, txn_groups: List[SimulateRequestTransactionGroup] + ) -> None: + self.txn_groups = txn_groups + + def dictify(self) -> Dict[str, Any]: + return { + "txn-groups": [ + txn_group.dictify() for txn_group in self.txn_groups + ] + } diff --git a/tests/steps/other_v2_steps.py b/tests/steps/other_v2_steps.py index b6bd1b87..63d42b09 100644 --- a/tests/steps/other_v2_steps.py +++ b/tests/steps/other_v2_steps.py @@ -1433,7 +1433,7 @@ def get_block_hash(context, round): @when("I simulate the transaction") def simulate_transaction(context): - context.simulate_response = context.app_acl.simulate_transactions( + context.simulate_response = context.app_acl.simulate_raw_transactions( [context.stx] )