From a2a408f5d30e56a9ab77219f1111347f9d30c3ce Mon Sep 17 00:00:00 2001 From: frank <98238480+soundsonacid@users.noreply.github.com> Date: Mon, 29 Jan 2024 14:03:10 -0800 Subject: [PATCH] frank/fast tx sender (#93) * wip fast tx sender * feat: fast tx sender * fix: lazy load blockhash subscription --- src/driftpy/tx/fast_tx_sender.py | 45 ++++++++++++++++++++++++++++ src/driftpy/tx/standard_tx_sender.py | 7 +++-- 2 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 src/driftpy/tx/fast_tx_sender.py diff --git a/src/driftpy/tx/fast_tx_sender.py b/src/driftpy/tx/fast_tx_sender.py new file mode 100644 index 00000000..1ffc54da --- /dev/null +++ b/src/driftpy/tx/fast_tx_sender.py @@ -0,0 +1,45 @@ +import asyncio + +from solders.hash import Hash + +from solana.rpc.async_api import AsyncClient +from solana.rpc.types import TxOpts +from solana.rpc.commitment import Commitment, Confirmed + +from driftpy.tx.standard_tx_sender import StandardTxSender + + +class FastTxSender(StandardTxSender): + """ + The FastTxSender will refresh the latest blockhash in the background to save an RPC when building transactions. + """ + + def __init__( + self, + connection: AsyncClient, + opts: TxOpts, + blockhash_refresh_interval_secs: int, + blockhash_commitment: Commitment = Confirmed, + ): + super().__init__(connection, opts, blockhash_commitment) + self.blockhash_refresh_interval = blockhash_refresh_interval_secs + self.recent_blockhash = None + + async def subscribe_blockhash(self): + """ + Must be called with asyncio.create_task to prevent blocking + """ + while True: + try: + blockhash_info = await self.connection.get_latest_blockhash( + self.blockhash_commitment + ) + self.recent_blockhash = blockhash_info.value.blockhash + except Exception as e: + print(f"Error in subscribe_blockhash: {e}") + await asyncio.sleep(self.blockhash_refresh_interval) + + async def fetch_latest_blockhash(self) -> Hash: + if self.recent_blockhash is None: + await self.subscribe_blockhash() + return self.recent_blockhash diff --git a/src/driftpy/tx/standard_tx_sender.py b/src/driftpy/tx/standard_tx_sender.py index 43f3e0e6..cf7e255a 100644 --- a/src/driftpy/tx/standard_tx_sender.py +++ b/src/driftpy/tx/standard_tx_sender.py @@ -33,13 +33,16 @@ async def get_blockhash(self) -> Hash: await self.connection.get_latest_blockhash(self.blockhash_commitment) ).value.blockhash + async def fetch_latest_blockhash(self) -> Hash: + return await self.get_blockhash() + async def get_legacy_tx( self, ixs: Sequence[Instruction], payer: Keypair, additional_signers: Optional[Sequence[Keypair]], ) -> Transaction: - latest_blockhash = await self.get_blockhash() + latest_blockhash = await self.fetch_latest_blockhash() tx = Transaction( instructions=ixs, recent_blockhash=latest_blockhash, @@ -60,7 +63,7 @@ async def get_versioned_tx( lookup_tables: Sequence[AddressLookupTableAccount], additional_signers: Optional[Sequence[Keypair]], ) -> VersionedTransaction: - latest_blockhash = await self.get_blockhash() + latest_blockhash = await self.fetch_latest_blockhash() msg = MessageV0.try_compile( payer.pubkey(), ixs, lookup_tables, latest_blockhash )