Skip to content

Commit

Permalink
Release 0.74.0
Browse files Browse the repository at this point in the history
  • Loading branch information
FrankC01 committed Dec 24, 2024
1 parent fefb320 commit c4ba210
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 58 deletions.
54 changes: 52 additions & 2 deletions doc/source/graphql_serial_exc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,30 @@ the gas object used to pay for the transaction.

Note that all available gas objects will be smashed to one gas object during transaction build processing.

Here is a simple example:
Here is a simple sunny day example:

.. code-block:: python
:linenos:
import logging
logger = logging.getLogger()
logging.basicConfig(
filename="ser_txn.log",
filemode="w",
encoding="utf-8",
format="%(asctime)s %(module)s %(levelname)s %(message)s",
level=logging.INFO,
)
from pysui import PysuiConfiguration, AsyncGqlClient
from pysui.sui.sui_pgql.execute.caching_txn import CachingTransaction
from pysui.sui.sui_pgql.execute.serial_exec import (
SerialTransactionExecutor,
ser_txn_exc_logger,
)
async def test_splits():
"""."""
client = AsyncGqlClient(
Expand All @@ -31,6 +50,8 @@ Here is a simple example:
ser_txne = SerialTransactionExecutor(
client=client, signer=client.config.active_address, default_gas_budget=5000000
)
# Set logging level
ser_txn_exc_logger.setLevel(logging.DEBUG)
# Tx 1
ser_txn_1: CachingTransaction = await ser_txne.new_transaction()
scoin = await ser_txn_1.split_coin(coin=ser_txn_1.gas, amounts=[1000000000])
Expand All @@ -53,5 +74,34 @@ In this example the two transaction times are, respectivley:
.. code-block:: shell
:linenos:
serial_exec DEBUG tx execution 0.783149003982544
serial_exec DEBUG tx execution 0.9674050807952881
serial_exec DEBUG tx execution 0.1889028549194336
Note that the first transaction smashes and primes the gas object as well as resolving unresolved objects

Exceptions
----------

Use caution when evaluating the result of the execution. If the result is not an instance of ExecutionResultGQL then
it is some error returned from either building, signing or executing the transaction. So, if the result is a
tuple (vs. an instance of ExecutionResultGQL) then it contains:

`(ExecutorError,Exception)`


.. code-block:: python
:linenos:
from pysui.sui.sui_pgql.pgql_types import ExecutionResultGQL
async def test_splits():
"""."""
# All code omitted
gx = await ser_txne.execute_transactions([ser_txn_1, ser_txn_2])
for gres in gx:
if not isinstance(gres,tuple):
print(gres.to_json(indent=2))
else:
error_enum, exception = gres
print(f"Type error: {error_enum.name} exception: {exception}")
7 changes: 2 additions & 5 deletions pysui/sui/sui_pgql/execute/caching_exec.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ async def _smash_gas(
# If noting available, throw exception
if not coin_list:
logger.debug("_smash_gas has no available coins")
raise TypeError(
raise ValueError(
f"Signer {txn.signer_block.payer_address} has no available gas coins"
)
# If one return it
Expand Down Expand Up @@ -272,10 +272,7 @@ async def build_transaction(
)

async def execute_transaction(
self,
txn_str: str,
txn_sigs: list[str],
**kwargs,
self, txn_str: str, txn_sigs: list[str]
) -> ptypes.ExecutionResultGQL:
"""."""
result = await self._client.execute_query_node(
Expand Down
72 changes: 33 additions & 39 deletions pysui/sui/sui_pgql/execute/caching_txn.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,6 @@ async def _function_meta_args(
)
raise ValueError(f"Unresolvable target {target}")

async def target_function_summary(
self, target: str
) -> tuple[bcs.Address, str, str, int, pgql_type.MoveArgSummary]:
"""Returns the argument summary of a target sui move function."""
return await self._function_meta_args(target)

def _build_txn_data(
self,
gas_budget: int,
Expand Down Expand Up @@ -182,39 +176,39 @@ async def build(
)
return base64.b64encode(txn_data.serialize()).decode()

async def build_and_sign(
self,
*,
gas_budget: Optional[str] = None,
use_gas_objects: Optional[list[Union[str, pgql_type.SuiCoinObjectGQL]]] = None,
txn_expires_after: Optional[int] = None,
) -> dict:
"""build After creating the BCS TransactionKind, serialize to base64 string, create signatures and return.
:param gas_budget: Specify the amount of gas for the transaction budget, defaults to None
:type gas_budget: Optional[str], optional
:param use_gas_objects: Specify gas object(s) (by ID or SuiCoinObjectGQL), defaults to None
:type use_gas_objects: Optional[list[Union[str, pgql_type.SuiCoinObjectGQL]]], optional
:param txn_expires_after: Specify the transaction expiration epoch ID, defaults to None
:type txn_expires_after: Optional[int],optional
:return: Dict of
{
"tx_bytestr": base64 encoded transaction bytes,
"sig_array": array of base64 encoded signature bytes
}
:rtype: dict[str, str]
"""
txn_kind = await self.transaction_data(
gas_budget=gas_budget,
use_gas_objects=use_gas_objects,
txn_expires_after=txn_expires_after,
)
tx_bytes = base64.b64encode(txn_kind.serialize()).decode()
sigs = self.signer_block.get_signatures(
config=self.client.config, tx_bytes=tx_bytes
)
return {self._BUILD_BYTE_STR: tx_bytes, self._SIG_ARRAY: sigs}
# async def build_and_sign(
# self,
# *,
# gas_budget: Optional[str] = None,
# use_gas_objects: Optional[list[Union[str, pgql_type.SuiCoinObjectGQL]]] = None,
# txn_expires_after: Optional[int] = None,
# ) -> dict:
# """build After creating the BCS TransactionKind, serialize to base64 string, create signatures and return.

# :param gas_budget: Specify the amount of gas for the transaction budget, defaults to None
# :type gas_budget: Optional[str], optional
# :param use_gas_objects: Specify gas object(s) (by ID or SuiCoinObjectGQL), defaults to None
# :type use_gas_objects: Optional[list[Union[str, pgql_type.SuiCoinObjectGQL]]], optional
# :param txn_expires_after: Specify the transaction expiration epoch ID, defaults to None
# :type txn_expires_after: Optional[int],optional
# :return: Dict of
# {
# "tx_bytestr": base64 encoded transaction bytes,
# "sig_array": array of base64 encoded signature bytes

# }
# :rtype: dict[str, str]
# """
# txn_kind = await self.transaction_data(
# gas_budget=gas_budget,
# use_gas_objects=use_gas_objects,
# txn_expires_after=txn_expires_after,
# )
# tx_bytes = base64.b64encode(txn_kind.serialize()).decode()
# sigs = self.signer_block.get_signatures(
# config=self.client.config, tx_bytes=tx_bytes
# )
# return {self._BUILD_BYTE_STR: tx_bytes, self._SIG_ARRAY: sigs}

async def split_coin(
self,
Expand Down
41 changes: 29 additions & 12 deletions pysui/sui/sui_pgql/execute/serial_exec.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import base64
import logging
import time
from enum import IntEnum
from typing import Any, Coroutine, Optional, Union

ser_txn_exc_logger = logging.getLogger("serial_exec")
Expand All @@ -23,6 +24,12 @@
from .caching_txn import CachingTransaction


class ExecutorError(IntEnum):
BUILDING_ERROR = 1
SIGNING_ERROR = 2
EXECUTING_ERROR = 3


def _get_gascoin_from_effects(effects: bcst.TransactionEffects) -> bcs.ObjectReference:
"""."""
if effects.enum_name != "V2":
Expand Down Expand Up @@ -149,8 +156,7 @@ def _sign_transaction(self, tx_str: str) -> list[str]:
async def execute_transactions(
self,
transactions: list[CachingTransaction],
**kwargs,
) -> list[ptypes.ExecutionResultGQL]:
) -> list[Union[ptypes.ExecutionResultGQL, Exception]]:
"""Serially execute one or more transactions
:param transactions: The transactions to execute
Expand All @@ -164,24 +170,35 @@ async def execute_transactions(
for tx in transactions:
start_time = time.time()
ser_txn_exc_logger.debug("Building transaction")
tx_str = await self._build_transaction(tx)
ser_txn_exc_logger.debug(f"Signing {tx_str}")

# Buillding is non-recoverable
tx_str = await asyncio.gather(
self._build_transaction(tx), return_exceptions=True
)
if not isinstance(tx_str[0], str):
ser_txn_exc_logger.critical(f"tx build {tx_str[0].args}")
exe_res.append((ExecutorError.BUILDING_ERROR, tx_str[0]))
continue
tx_str: str = tx_str[0]
ser_txn_exc_logger.debug(f"Signing {tx_str}")
try:
ser_txn_exc_logger.debug("Cache transaction execution")
# Sign the transaction
sig_list = self._sign_transaction(tx_str)
results: ptypes.ExecutionResultGQL = (
await self._cache.execute_transaction(tx_str, sig_list, **kwargs)
results = await asyncio.gather(
self._cache.execute_transaction(tx_str, sig_list)
)
if not isinstance(results[0], ptypes.ExecutionResultGQL):
ser_txn_exc_logger.critical(f"tx execution {results[0].args}")
exe_res.append((ExecutorError.EXECUTING_ERROR, results[0]))
continue
results: ptypes.ExecutionResultGQL = results[0]
await self.apply_effects(results.bcs)
end_time = time.time()
ser_txn_exc_logger.info(f"tx execution {end_time-start_time}")
ser_txn_exc_logger.info(f"tx execution time {end_time-start_time}")
exe_res.append(results)

except ValueError as exc:
ser_txn_exc_logger.debug("Error callingi cache execute")
await self.reset_cache()
raise exc
except ValueError as ve:
ser_txn_exc_logger.critical(f"tx signing non-recoverable {ve.args}")
exe_res.append((ExecutorError.SIGNING_ERROR, ve))

return exe_res

0 comments on commit c4ba210

Please sign in to comment.