Skip to content

Commit

Permalink
Deprecate transaction module (#442)
Browse files Browse the repository at this point in the history
Co-authored-by: Michael Huang <[email protected]>
  • Loading branch information
kevinheavey and michaelhly authored Oct 12, 2024
1 parent 0a57fd9 commit b34848c
Show file tree
Hide file tree
Showing 14 changed files with 569 additions and 395 deletions.
61 changes: 42 additions & 19 deletions src/solana/rpc/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from time import sleep, time
from typing import Dict, List, Optional, Sequence, Union
from warnings import warn

from solders.hash import Hash as Blockhash
from solders.keypair import Keypair
Expand Down Expand Up @@ -62,10 +63,10 @@
ValidatorExitResp,
)
from solders.signature import Signature
from solders.transaction import VersionedTransaction
from solders.transaction import Transaction, VersionedTransaction

from solana.rpc import types
from solana.transaction import Transaction
from solana.transaction import Transaction as LegacyTransaction

from .commitment import Commitment, Finalized
from .core import (
Expand Down Expand Up @@ -408,13 +409,13 @@ def get_fee_for_message(
Example:
>>> from solders.keypair import Keypair
>>> from solders.system_program import TransferParams, transfer
>>> from solana.transaction import Transaction
>>> from solders.message import Message
>>> leading_zeros = [0] * 31
>>> sender, receiver = Keypair.from_seed(leading_zeros + [1]), Keypair.from_seed(leading_zeros + [2])
>>> txn = Transaction().add(transfer(TransferParams(
... from_pubkey=sender.pubkey(), to_pubkey=receiver.pubkey(), lamports=1000)))
>>> msg = Message([transfer(TransferParams(
... from_pubkey=sender.pubkey(), to_pubkey=receiver.pubkey(), lamports=1000))])
>>> solana_client = Client("http://localhost:8899")
>>> solana_client.get_fee_for_message(txn.compile_message()).value # doctest: +SKIP
>>> solana_client.get_fee_for_message(msg).value # doctest: +SKIP
5000
"""
body = self._get_fee_for_message_body(message, commitment)
Expand Down Expand Up @@ -997,14 +998,14 @@ def send_raw_transaction(self, txn: bytes, opts: Optional[types.TxOpts] = None)
post_send_args = self._send_raw_transaction_post_send_args(resp, opts_to_use)
return self.__post_send_with_confirm(*post_send_args)

def send_transaction(
def send_legacy_transaction(
self,
txn: Union[VersionedTransaction, Transaction],
txn: LegacyTransaction,
*signers: Keypair,
opts: Optional[types.TxOpts] = None,
recent_blockhash: Optional[Blockhash] = None,
) -> SendTransactionResp:
"""Send a transaction.
"""Send a legacy transaction.
Args:
txn: transaction object.
Expand All @@ -1030,15 +1031,8 @@ def send_transaction(
1111111111111111111111111111111111111111111111111111111111111111,
)
"""
if isinstance(txn, VersionedTransaction):
if signers:
msg = "*signers args are not used when sending VersionedTransaction."
raise ValueError(msg)
if recent_blockhash is not None:
msg = "recent_blockhash arg is not used when sending VersionedTransaction."
raise ValueError(msg)
versioned_tx_opts = types.TxOpts(preflight_commitment=self._commitment) if opts is None else opts
return self.send_raw_transaction(bytes(txn), opts=versioned_tx_opts)
warn("send_legacy_transaction is deprecated. Use send_transaction instead.", DeprecationWarning)

last_valid_block_height = None
if recent_blockhash is None:
blockhash_resp = self.get_latest_blockhash(Finalized)
Expand All @@ -1060,6 +1054,34 @@ def send_transaction(
txn_resp = self.send_raw_transaction(txn.serialize(), opts=opts_to_use)
return txn_resp

def send_transaction(
self,
txn: Union[VersionedTransaction, Transaction],
opts: Optional[types.TxOpts] = None,
) -> SendTransactionResp:
"""Send a transaction.
Args:
txn: transaction object.
opts: (optional) Transaction options.
Example:
>>> from solders.keypair import Keypair
>>> from solders.pubkey import Pubkey
>>> from solana.rpc.api import Client
>>> from solders.system_program import TransferParams, transfer
>>> from solders.message import Message
>>> leading_zeros = [0] * 31
>>> sender, receiver = Keypair.from_seed(leading_zeros + [1]), Keypair.from_seed(leading_zeros + [2])
>>> ixns = [transfer(TransferParams(
... from_pubkey=sender.pubkey(), to_pubkey=receiver.pubkey(), lamports=1000))]
>>> msg = Message(ixns, sender.pubkey())
>>> client = Client("http://localhost:8899")
>>> client.send_transaction(Transaction([sender], msg, client.get_latest_blockhash()).value.blockhash) # doctest: +SKIP
""" # noqa: E501
tx_opts = types.TxOpts(preflight_commitment=self._commitment) if opts is None else opts
return self.send_raw_transaction(bytes(txn), opts=tx_opts)

def simulate_transaction(
self,
txn: Union[Transaction, VersionedTransaction],
Expand All @@ -1075,6 +1097,7 @@ def simulate_transaction(
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
Example:
>>> from solders.transaction import Transaction
>>> solana_client = Client("http://localhost:8899")
>>> full_signed_tx_hex = (
... '01b3795ccfaac3eee838bb05c3b8284122c18acedcd645c914fe8e178c3b62640d8616d061cc818b26cab8ecf3855ecc'
Expand All @@ -1083,7 +1106,7 @@ def simulate_transaction(
... '000000000000000000000000000000000000000000839618f701ba7e9ba27ae59825dd6d6bb66d14f6d5d0eae215161d7'
... '1851a106901020200010c0200000040420f0000000000'
... )
>>> tx = Transaction.deserialize(bytes.fromhex(full_signed_tx_hex))
>>> tx = Transaction.from_bytes(bytes.fromhex(full_signed_tx_hex))
>>> solana_client.simulate_transaction(tx).value.logs # doctest: +SKIP
['BPF program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri success']
"""
Expand Down
65 changes: 45 additions & 20 deletions src/solana/rpc/async_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import asyncio
from time import time
from typing import Dict, List, Optional, Sequence, Union
from warnings import warn

from solders.hash import Hash as Blockhash
from solders.keypair import Keypair
Expand Down Expand Up @@ -60,13 +61,18 @@
ValidatorExitResp,
)
from solders.signature import Signature
from solders.transaction import VersionedTransaction
from solders.transaction import Transaction, VersionedTransaction

from solana.rpc import types
from solana.transaction import Transaction
from solana.transaction import Transaction as LegacyTransaction

from .commitment import Commitment, Finalized
from .core import _COMMITMENT_TO_SOLDERS, TransactionExpiredBlockheightExceededError, UnconfirmedTxError, _ClientCore
from .core import (
_COMMITMENT_TO_SOLDERS,
TransactionExpiredBlockheightExceededError,
UnconfirmedTxError,
_ClientCore,
)
from .providers import async_http


Expand Down Expand Up @@ -415,13 +421,13 @@ async def get_fee_for_message(
Example:
>>> from solders.keypair import Keypair
>>> from solders.system_program import TransferParams, transfer
>>> from solana.transaction import Transaction
>>> from solders.message import Message
>>> leading_zeros = [0] * 31
>>> sender, receiver = Keypair.from_seed(leading_zeros + [1]), Keypair.from_seed(leading_zeros + [2])
>>> txn = Transaction().add(transfer(TransferParams(
... from_pubkey=sender.pubkey(), to_pubkey=receiver.pubkey(), lamports=1000)))
>>> msg = Message([transfer(TransferParams(
... from_pubkey=sender.pubkey(), to_pubkey=receiver.pubkey(), lamports=1000))])
>>> solana_client = AsyncClient("http://localhost:8899")
>>> (await solana_client.get_fee_for_message(txn.compile_message())).value # doctest: +SKIP
>>> (await solana_client.get_fee_for_message(msg)).value # doctest: +SKIP
5000
"""
body = self._get_fee_for_message_body(message, commitment)
Expand Down Expand Up @@ -1005,14 +1011,14 @@ async def send_raw_transaction(self, txn: bytes, opts: Optional[types.TxOpts] =
post_send_args = self._send_raw_transaction_post_send_args(resp, opts_to_use)
return await self.__post_send_with_confirm(*post_send_args)

async def send_transaction(
async def send_legacy_transaction(
self,
txn: Union[VersionedTransaction, Transaction],
txn: LegacyTransaction,
*signers: Keypair,
opts: Optional[types.TxOpts] = None,
recent_blockhash: Optional[Blockhash] = None,
) -> SendTransactionResp:
"""Send a transaction.
"""Send a legacy transaction.
Args:
txn: transaction object.
Expand All @@ -1036,15 +1042,8 @@ async def send_transaction(
1111111111111111111111111111111111111111111111111111111111111111,
)
"""
if isinstance(txn, VersionedTransaction):
if signers:
msg = "*signers args are not used when sending VersionedTransaction."
raise ValueError(msg)
if recent_blockhash is not None:
msg = "recent_blockhash arg is not used when sending VersionedTransaction."
raise ValueError(msg)
versioned_tx_opts = types.TxOpts(preflight_commitment=self._commitment) if opts is None else opts
return await self.send_raw_transaction(bytes(txn), opts=versioned_tx_opts)
warn("send_legacy_transaction is deprecated. Use send_transaction instead.", DeprecationWarning)

last_valid_block_height = None
if recent_blockhash is None:
blockhash_resp = await self.get_latest_blockhash(Finalized)
Expand All @@ -1065,6 +1064,32 @@ async def send_transaction(
txn_resp = await self.send_raw_transaction(txn.serialize(), opts=opts_to_use)
return txn_resp

async def send_transaction(
self,
txn: Union[VersionedTransaction, Transaction],
opts: Optional[types.TxOpts] = None,
) -> SendTransactionResp:
"""Send a transaction.
Args:
txn: transaction object.
opts: (optional) Transaction options.
Example:
>>> from solders.keypair import Keypair
>>> from solders.system_program import TransferParams, transfer
>>> from solders.message import Message
>>> from solders.transaction import Transaction
>>> leading_zeros = [0] * 31
>>> sender, receiver = Keypair.from_seed(leading_zeros + [1]), Keypair.from_seed(leading_zeros + [2])
>>> ixns = [transfer(TransferParams(
... from_pubkey=sender.pubkey(), to_pubkey=receiver.pubkey(), lamports=1000))]
>>> msg = Message(ixns, sender.pubkey())
>>> client = AsyncClient("http://localhost:8899")
>>> (await client.send_transaction(Transaction([sender], msg, (await client.get_latest_blockhash()).value.blockhash))) # doctest: +SKIP
""" # noqa: E501
return await self.send_raw_transaction(bytes(txn), opts=opts)

async def simulate_transaction(
self,
txn: Union[Transaction, VersionedTransaction],
Expand All @@ -1088,7 +1113,7 @@ async def simulate_transaction(
... '000000000000000000000000000000000000000000839618f701ba7e9ba27ae59825dd6d6bb66d14f6d5d0eae215161d7'
... '1851a106901020200010c0200000040420f0000000000'
... )
>>> tx = Transaction.deserialize(bytes.fromhex(full_signed_tx_hex))
>>> tx = Transaction.from_bytes(bytes.fromhex(full_signed_tx_hex))
>>> (await solana_client.simulate_transaction(tx)).value.logs # doctest: +SKIP
['BPF program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri success']
"""
Expand Down
6 changes: 2 additions & 4 deletions src/solana/rpc/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
from solders.transaction_status import UiTransactionEncoding

from solana.rpc import types
from solana.transaction import Transaction
from solders.transaction import Transaction

from .commitment import Commitment, Confirmed, Finalized, Processed

Expand Down Expand Up @@ -499,9 +499,7 @@ def _simulate_transaction_body(
commitment_to_use = _COMMITMENT_TO_SOLDERS[commitment or self._commitment]
config = RpcSimulateTransactionConfig(sig_verify=sig_verify, commitment=commitment_to_use)
if isinstance(txn, Transaction):
if txn.recent_blockhash is None:
raise ValueError("transaction must have a valid blockhash")
return SimulateLegacyTransaction(txn.to_solders(), config)
return SimulateLegacyTransaction(txn, config)
return SimulateVersionedTransaction(txn, config)

@staticmethod
Expand Down
10 changes: 7 additions & 3 deletions src/solana/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from __future__ import annotations

from typing import Any, List, NamedTuple, Optional, Sequence, Tuple, Union
from warnings import warn

from solders.hash import Hash as Blockhash
from solders.instruction import AccountMeta, Instruction
Expand Down Expand Up @@ -78,9 +79,6 @@ class Transaction:
instructions: The instructions to be executed in this transaction.
"""

# Default (empty) signature
__DEFAULT_SIG = bytes(64)

def __init__(
self,
recent_blockhash: Optional[Blockhash] = None,
Expand All @@ -89,6 +87,12 @@ def __init__(
instructions: Optional[Sequence[Instruction]] = None,
) -> None:
"""Init transaction object."""
warn(
"""Transaction is deprecated and will be removed in a later release.
Please use the Transaction module from solders.transaction instead.""",
DeprecationWarning,
)

self._solders = _build_solders_tx(
recent_blockhash=recent_blockhash,
nonce_info=nonce_info,
Expand Down
Loading

0 comments on commit b34848c

Please sign in to comment.