1373 lines
65 KiB
Python
1373 lines
65 KiB
Python
"""Async API client to interact with the Solana JSON RPC Endpoint.""" # pylint: disable=too-many-lines
|
|
import asyncio
|
|
from time import time
|
|
from typing import List, Optional, Union
|
|
|
|
from solana.blockhash import Blockhash, BlockhashCache
|
|
from solana.keypair import Keypair
|
|
from solana.publickey import PublicKey
|
|
from solana.rpc import types
|
|
from solana.transaction import Transaction
|
|
|
|
from .commitment import COMMITMENT_RANKS, Commitment, Finalized
|
|
from .core import RPCException, UnconfirmedTxError, _ClientCore
|
|
from .providers import async_http
|
|
|
|
|
|
class AsyncClient(_ClientCore): # pylint: disable=too-many-public-methods
|
|
"""Async client class.
|
|
|
|
Args:
|
|
endpoint: URL of the RPC endpoint.
|
|
commitment: Default bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
blockhash_cache: (Experimental) If True, keep a cache of recent blockhashes to make
|
|
`send_transaction` calls faster.
|
|
You can also pass your own BlockhashCache object to customize its parameters.
|
|
|
|
The cache works as follows:
|
|
|
|
1. Retrieve the oldest unused cached blockhash that is younger than `ttl` seconds,
|
|
where `ttl` is defined in the BlockhashCache (we prefer unused blockhashes because
|
|
reusing blockhashes can cause errors in some edge cases, and we prefer slightly
|
|
older blockhashes because they're more likely to be accepted by every validator).
|
|
2. If there are no unused blockhashes in the cache, take the oldest used
|
|
blockhash that is younger than `ttl` seconds.
|
|
3. Fetch a new recent blockhash *after* sending the transaction. This is to keep the cache up-to-date.
|
|
|
|
If you want something tailored to your use case, run your own loop that fetches the recent blockhash,
|
|
and pass that value in your `.send_transaction` calls.
|
|
timeout: HTTP request timeout in seconds.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
endpoint: Optional[str] = None,
|
|
commitment: Optional[Commitment] = None,
|
|
blockhash_cache: Union[BlockhashCache, bool] = False,
|
|
timeout: float = 10,
|
|
) -> None:
|
|
"""Init API client."""
|
|
super().__init__(commitment, blockhash_cache)
|
|
self._provider = async_http.AsyncHTTPProvider(endpoint, timeout=timeout)
|
|
|
|
async def __aenter__(self) -> "AsyncClient":
|
|
"""Use as a context manager."""
|
|
await self._provider.__aenter__()
|
|
return self
|
|
|
|
async def __aexit__(self, _exc_type, _exc, _tb):
|
|
"""Exits the context manager."""
|
|
await self.close()
|
|
|
|
async def close(self) -> None:
|
|
"""Use this when you are done with the client."""
|
|
await self._provider.close()
|
|
|
|
async def is_connected(self) -> bool:
|
|
"""Health check.
|
|
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.is_connected()) # doctest: +SKIP
|
|
True
|
|
|
|
Returns:
|
|
True if the client is connected.
|
|
"""
|
|
return await self._provider.is_connected()
|
|
|
|
async def get_balance(
|
|
self, pubkey: Union[PublicKey, str], commitment: Optional[Commitment] = None
|
|
) -> types.RPCResponse:
|
|
"""Returns the balance of the account of provided Pubkey.
|
|
|
|
Args:
|
|
pubkey: Pubkey of account to query, as base-58 encoded string or PublicKey object.
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> from solana.publickey import PublicKey
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_balance(PublicKey(1))) # doctest: +SKIP
|
|
{'jsonrpc': '2.0', 'result': {'context': {'slot': 228}, 'value': 0}, 'id': 1}
|
|
"""
|
|
args = self._get_balance_args(pubkey, commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_account_info(
|
|
self,
|
|
pubkey: Union[PublicKey, str],
|
|
commitment: Optional[Commitment] = None,
|
|
encoding: str = "base64",
|
|
data_slice: Optional[types.DataSliceOpts] = None,
|
|
) -> types.RPCResponse:
|
|
"""Returns all the account info for the specified public key.
|
|
|
|
Args:
|
|
pubkey: Pubkey of account to query, as base-58 encoded string or PublicKey object.
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
encoding: (optional) Encoding for Account data, either "base58" (slow), "base64", or
|
|
"jsonParsed". Default is "base64".
|
|
|
|
- "base58" is limited to Account data of less than 128 bytes.
|
|
- "base64" will return base64 encoded data for Account data of any size.
|
|
- "jsonParsed" encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data.
|
|
|
|
If jsonParsed is requested but a parser cannot be found, the field falls back to base64 encoding,
|
|
detectable when the data field is type. (jsonParsed encoding is UNSTABLE).
|
|
data_slice: (optional) Option to limit the returned account data using the provided `offset`: <usize> and
|
|
`length`: <usize> fields; only available for "base58" or "base64" encoding.
|
|
|
|
Example:
|
|
>>> from solana.publickey import PublicKey
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_account_info(PublicKey(1))) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'context': {'slot': 33265073},
|
|
'value': {'data': '',
|
|
'executable': False,
|
|
'lamports': 4459816188034584,
|
|
'owner': '11111111111111111111111111111111',
|
|
'rentEpoch': 90}},
|
|
'id': 1}
|
|
""" # noqa: E501 # pylint: disable=line-too-long
|
|
args = self._get_account_info_args(
|
|
pubkey=pubkey, commitment=commitment, encoding=encoding, data_slice=data_slice
|
|
)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_block_commitment(self, slot: int) -> types.RPCResponse:
|
|
"""Fetch the commitment for particular block.
|
|
|
|
Args:
|
|
slot: Block, identified by Slot.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_block_commitment(0)) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'commitment': [0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
497717120],
|
|
'totalStake': 497717120},
|
|
'id': 1}}
|
|
"""
|
|
args = self._get_block_commitment_args(slot)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_block_time(self, slot: int) -> types.RPCResponse:
|
|
"""Fetch the estimated production time of a block.
|
|
|
|
Args:
|
|
slot: Block, identified by Slot.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_block_time(5)) # doctest: +SKIP
|
|
{'jsonrpc': '2.0', 'result': 1598400007, 'id': 1}
|
|
"""
|
|
args = self._get_block_time_args(slot)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_cluster_nodes(self) -> types.RPCResponse:
|
|
"""Returns information about all the nodes participating in the cluster.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_cluster_nodes()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': [{'gossip': '127.0.0.1:8001',
|
|
'pubkey': 'LjvEBM78ufAikBfxqtj4RNiAECUi7Xqtz9k3QM3DzPk',
|
|
'rpc': '127.0.0.1:8899',
|
|
'tpu': '127.0.0.1:8003',
|
|
'version': '1.4.0 5332fcad'}],
|
|
'id': 1}
|
|
"""
|
|
return await self._provider.make_request(self._get_cluster_nodes)
|
|
|
|
async def get_confirmed_block(
|
|
self,
|
|
slot: int,
|
|
encoding: str = "json",
|
|
) -> types.RPCResponse:
|
|
"""Returns identity and transaction information about a confirmed block in the ledger.
|
|
|
|
Args:
|
|
slot: Slot, as u64 integer.
|
|
encoding: (optional) Encoding for the returned Transaction, either "json", "jsonParsed",
|
|
"base58" (slow), or "base64". If parameter not provided, the default encoding is JSON.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_confirmed_block(1)O # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'blockTime': None,
|
|
'blockhash': '39pJzWsPn59k2PuHqhB7xNYBNGFXcFVkXLertHPBV4Tj',
|
|
'parentSlot': 0,
|
|
'previousBlockhash': 'EwF9gtehrrvPUoNticgmiEadAWzn4XeN8bNaNVBkS6S2',
|
|
'rewards': [],
|
|
'transactions': [{'meta': {'err': None,
|
|
'fee': 0,
|
|
'postBalances': [500000000000, 26858640, 1, 1, 1],
|
|
'preBalances': [500000000000, 26858640, 1, 1, 1],
|
|
'status': {'Ok': None}},
|
|
'transaction': {'message': {'accountKeys': ['LjvEBM78ufAikBfxqtj4RNiAECUi7Xqtz9k3QM3DzPk',
|
|
'EKAar3bMQUZvGSonq7vcPF2nPaCYowbnat44FPafW8Po',
|
|
'SysvarS1otHashes111111111111111111111111111',
|
|
'SysvarC1ock11111111111111111111111111111111',
|
|
'Vote111111111111111111111111111111111111111'],
|
|
'header': {'numReadonlySignedAccounts': 0,
|
|
'numReadonlyUnsignedAccounts': 3,
|
|
'numRequiredSignatures': 1},
|
|
'instructions': [{'accounts': [1, 2, 3, 0],
|
|
'data': '37u9WtQpcm6ULa3VmTgTKEBCtYMxq84mk82tRvKdFEwj3rALiptAzuMJ1yoVSFAMARMZYp7q',
|
|
'programIdIndex': 4}],
|
|
'recentBlockhash': 'EwF9gtehrrvPUoNticgmiEadAWzn4XeN8bNaNVBkS6S2'},
|
|
'signatures': ['63jnpMCs7TNnCjnTqUrX7Mvqc5CbJMtVkLxBjPHUQkjXyZrQuZpfhjvzA7A29D9tMqVaiQC3UNP1NeaZKFFHJyQE']}}]},
|
|
'id': 9}
|
|
>>> asyncio.run(solana_client.get_confirmed_block(1, encoding="base64")) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'blockTime': None,
|
|
'blockhash': '39pJzWsPn59k2PuHqhB7xNYBNGFXcFVkXLertHPBV4Tj',
|
|
'parentSlot': 0,
|
|
'previousBlockhash': 'EwF9gtehrrvPUoNticgmiEadAWzn4XeN8bNaNVBkS6S2',
|
|
'rewards': [],
|
|
'transactions': [{'meta': {'err': None,
|
|
'fee': 0,
|
|
'postBalances': [500000000000, 26858640, 1, 1, 1],
|
|
'preBalances': [500000000000, 26858640, 1, 1, 1],
|
|
'status': {'Ok': None}},
|
|
'transaction': ['AfxyKHmHIjXWjkyHODGeAbVxmfQWPj1ydS9nF+ynJHo8I1vCPDp2P9Cj5aA6W1CAHEHCqY0B1FDKomCzRo3qrAsBAAMFBQ6QBWfhQF7rG02xhuEsmmrUtz3AUjBtJKkqaHPJEmvFzziDX0C0robPrl9RbOyXHoc9/Dxa0zoGL6cEjvCjLgan1RcZLwqvxvJl4/t3zHragsUp0L47E24tAFUgAAAABqfVFxjHdMkoVmOYaR1etoteuKObS21cc1VbIQAAAAAHYUgdNXR0u3xNdiTr072z2DVec9EQQ/wNo1OAAAAAAM8NSv7ISDPN9E9XNL9vX7h8LuJHWlopUcX39DxsDx23AQQEAQIDADUCAAAAAQAAAAAAAAAAAAAAAAAAAIWWp5Il3Kg312pzVk6Jt61iyFhTbtmkh/ORbj3JUQRbAA==',
|
|
'base64']}]},
|
|
'id': 10}
|
|
""" # noqa: E501 # pylint: disable=line-too-long
|
|
args = self._get_confirmed_block_args(slot, encoding)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_block(
|
|
self,
|
|
slot: int,
|
|
encoding: str = "json",
|
|
) -> types.RPCResponse:
|
|
"""Returns identity and transaction information about a confirmed block in the ledger.
|
|
|
|
Args:
|
|
slot: Slot, as u64 integer.
|
|
encoding: (optional) Encoding for the returned Transaction, either "json", "jsonParsed",
|
|
"base58" (slow), or "base64". If parameter not provided, the default encoding is JSON.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_block(1)O # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'blockTime': None, 'blockHeight': 0,
|
|
'blockhash': '39pJzWsPn59k2PuHqhB7xNYBNGFXcFVkXLertHPBV4Tj',
|
|
'parentSlot': 0,
|
|
'previousBlockhash': 'EwF9gtehrrvPUoNticgmiEadAWzn4XeN8bNaNVBkS6S2',
|
|
'rewards': [],
|
|
'transactions': [{'meta': {'err': None,
|
|
'fee': 0,
|
|
'postBalances': [500000000000, 26858640, 1, 1, 1],
|
|
'preBalances': [500000000000, 26858640, 1, 1, 1],
|
|
'status': {'Ok': None}},
|
|
'transaction': {'message': {'accountKeys': ['LjvEBM78ufAikBfxqtj4RNiAECUi7Xqtz9k3QM3DzPk',
|
|
'EKAar3bMQUZvGSonq7vcPF2nPaCYowbnat44FPafW8Po',
|
|
'SysvarS1otHashes111111111111111111111111111',
|
|
'SysvarC1ock11111111111111111111111111111111',
|
|
'Vote111111111111111111111111111111111111111'],
|
|
'header': {'numReadonlySignedAccounts': 0,
|
|
'numReadonlyUnsignedAccounts': 3,
|
|
'numRequiredSignatures': 1},
|
|
'instructions': [{'accounts': [1, 2, 3, 0],
|
|
'data': '37u9WtQpcm6ULa3VmTgTKEBCtYMxq84mk82tRvKdFEwj3rALiptAzuMJ1yoVSFAMARMZYp7q',
|
|
'programIdIndex': 4}],
|
|
'recentBlockhash': 'EwF9gtehrrvPUoNticgmiEadAWzn4XeN8bNaNVBkS6S2'},
|
|
'signatures': ['63jnpMCs7TNnCjnTqUrX7Mvqc5CbJMtVkLxBjPHUQkjXyZrQuZpfhjvzA7A29D9tMqVaiQC3UNP1NeaZKFFHJyQE']}}]},
|
|
'id': 9}
|
|
>>> asyncio.run(solana_client.get_block(1, encoding="base64")) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'blockTime': None, 'blockHeight': 0,
|
|
'blockhash': '39pJzWsPn59k2PuHqhB7xNYBNGFXcFVkXLertHPBV4Tj',
|
|
'parentSlot': 0,
|
|
'previousBlockhash': 'EwF9gtehrrvPUoNticgmiEadAWzn4XeN8bNaNVBkS6S2',
|
|
'rewards': [],
|
|
'transactions': [{'meta': {'err': None,
|
|
'fee': 0,
|
|
'postBalances': [500000000000, 26858640, 1, 1, 1],
|
|
'preBalances': [500000000000, 26858640, 1, 1, 1],
|
|
'status': {'Ok': None}},
|
|
'transaction': ['AfxyKHmHIjXWjkyHODGeAbVxmfQWPj1ydS9nF+ynJHo8I1vCPDp2P9Cj5aA6W1CAHEHCqY0B1FDKomCzRo3qrAsBAAMFBQ6QBWfhQF7rG02xhuEsmmrUtz3AUjBtJKkqaHPJEmvFzziDX0C0robPrl9RbOyXHoc9/Dxa0zoGL6cEjvCjLgan1RcZLwqvxvJl4/t3zHragsUp0L47E24tAFUgAAAABqfVFxjHdMkoVmOYaR1etoteuKObS21cc1VbIQAAAAAHYUgdNXR0u3xNdiTr072z2DVec9EQQ/wNo1OAAAAAAM8NSv7ISDPN9E9XNL9vX7h8LuJHWlopUcX39DxsDx23AQQEAQIDADUCAAAAAQAAAAAAAAAAAAAAAAAAAIWWp5Il3Kg312pzVk6Jt61iyFhTbtmkh/ORbj3JUQRbAA==',
|
|
'base64']}]},
|
|
'id': 10}
|
|
""" # noqa: E501 # pylint: disable=line-too-long
|
|
args = self._get_block_args(slot, encoding)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_block_height(self, commitment: Optional[Commitment] = None) -> types.RPCResponse:
|
|
"""Returns the current block height of the node.
|
|
|
|
Args:
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_block_height()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0', 'result': 1233, 'id': 1}
|
|
"""
|
|
args = self._get_block_height_args(commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_confirmed_blocks(self, start_slot: int, end_slot: Optional[int] = None) -> types.RPCResponse:
|
|
"""Returns a list of confirmed blocks.
|
|
|
|
Args:
|
|
start_slot: Start slot, as u64 integer.
|
|
end_slot: (optional) End slot, as u64 integer.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_confirmed_blocks(5, 10)) # doctest: +SKIP
|
|
{'jsonrpc': '2.0', 'result': [5, 6, 7, 8, 9, 10], 'id': 1}
|
|
"""
|
|
args = self._get_confirmed_blocks_args(start_slot, end_slot)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_blocks(self, start_slot: int, end_slot: Optional[int] = None) -> types.RPCResponse:
|
|
"""Returns a list of confirmed blocks.
|
|
|
|
Args:
|
|
start_slot: Start slot, as u64 integer.
|
|
end_slot: (optional) End slot, as u64 integer.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_blocks(5, 10)) # doctest: +SKIP
|
|
{'jsonrpc': '2.0', 'result': [5, 6, 7, 8, 9, 10], 'id': 1}
|
|
"""
|
|
args = self._get_blocks_args(start_slot, end_slot)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_confirmed_signature_for_address2(
|
|
self,
|
|
account: Union[str, Keypair, PublicKey],
|
|
before: Optional[str] = None,
|
|
until: Optional[str] = None,
|
|
limit: Optional[int] = None,
|
|
commitment: Optional[Commitment] = None,
|
|
) -> types.RPCResponse:
|
|
"""Returns confirmed signatures for transactions involving an address.
|
|
|
|
Signatures are returned backwards in time from the provided signature or
|
|
most recent confirmed block.
|
|
|
|
Args:
|
|
account: Account to be queried.
|
|
before: (optional) Start searching backwards from this transaction signature.
|
|
If not provided the search starts from the top of the highest max confirmed block.
|
|
until: (optional) Search until this transaction signature, if found before limit reached.
|
|
limit: (optoinal) Maximum transaction signatures to return (between 1 and 1,000, default: 1,000).
|
|
commitment: (optional) Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_confirmed_signature_for_address2("Vote111111111111111111111111111111111111111", limit=1)) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': [{'err': None,
|
|
'memo': None,
|
|
'signature': 'v1BK8XcaPBzAGd7TB1K53pMdi6TBGe5CLCgx8cmZ4Bj63ZNvA6ca2QaxFpBFdvmpoFQ51VorBjifkBGLTDhwpqN',
|
|
'slot': 4290}],
|
|
'id': 2}
|
|
""" # noqa: E501 # pylint: disable=line-too-long
|
|
args = self._get_confirmed_signature_for_address2_args(account, before, until, limit, commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_signatures_for_address(
|
|
self,
|
|
account: Union[str, Keypair, PublicKey],
|
|
before: Optional[str] = None,
|
|
until: Optional[str] = None,
|
|
limit: Optional[int] = None,
|
|
commitment: Optional[Commitment] = None,
|
|
) -> types.RPCResponse:
|
|
"""Returns confirmed signatures for transactions involving an address.
|
|
|
|
Signatures are returned backwards in time from the provided signature or
|
|
most recent confirmed block.
|
|
|
|
Args:
|
|
account: Account to be queried.
|
|
before: (optional) Start searching backwards from this transaction signature.
|
|
If not provided the search starts from the top of the highest max confirmed block.
|
|
until: (optional) Search until this transaction signature, if found before limit reached.
|
|
limit: (optional) Maximum transaction signatures to return (between 1 and 1,000, default: 1,000).
|
|
commitment: (optional) Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_signatures_for_address("Vote111111111111111111111111111111111111111", limit=1)) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': [{'err': None,
|
|
'memo': None,
|
|
'signature': 'v1BK8XcaPBzAGd7TB1K53pMdi6TBGe5CLCgx8cmZ4Bj63ZNvA6ca2QaxFpBFdvmpoFQ51VorBjifkBGLTDhwpqN',
|
|
'slot': 4290}],
|
|
'id': 2}
|
|
""" # noqa: E501 # pylint: disable=line-too-long
|
|
args = self._get_signatures_for_address_args(account, before, until, limit, commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_confirmed_transaction(self, tx_sig: str, encoding: str = "json") -> types.RPCResponse:
|
|
"""Returns transaction details for a confirmed transaction.
|
|
|
|
Args:
|
|
tx_sig: Transaction signature as base-58 encoded string N encoding attempts to use program-specific
|
|
instruction parsers to return more human-readable and explicit data in the
|
|
`transaction.message.instructions` list.
|
|
encoding: (optional) Encoding for the returned Transaction, either "json", "jsonParsed",
|
|
"base58" (slow), or "base64". If parameter not provided, the default encoding is JSON.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_confirmed_transaction("3PtGYH77LhhQqTXP4SmDVJ85hmDieWsgXCUbn14v7gYyVYPjZzygUQhTk3bSTYnfA48vCM1rmWY7zWL3j1EVKmEy")) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'meta': {'err': None,
|
|
'fee': 5000,
|
|
'postBalances': [498449233720610510, 1000001001987940, 1],
|
|
'preBalances': [498449233721615510, 1000001000987940, 1],
|
|
'status': {'Ok': None}},
|
|
'slot': 1659335,
|
|
'transaction': {'message': {'accountKeys': ['9B5XszUGdMaxCZ7uSQhPzdks5ZQSmWxrmzCSvtJ6Ns6g',
|
|
'2KW2XRd9kwqet15Aha2oK3tYvd3nWbTFH1MBiRAv1BE1',
|
|
'11111111111111111111111111111111'],
|
|
'header': {'numReadonlySignedAccounts': 0,
|
|
'numReadonlyUnsignedAccounts': 1,
|
|
'numRequiredSignatures': 1},
|
|
'instructions': [{'accounts': [0, 1],
|
|
'data': '3Bxs4Bc3VYuGVB19',
|
|
'programIdIndex': 2}],
|
|
'recentBlockhash': 'FwcsKNptGtMLccXAA9YgnivVFK95mKzECLT1DNPi3SDr'},
|
|
'signatures': ['3PtGYH77LhhQqTXP4SmDVJ85hmDieWsgXCUbn14v7gYyVYPjZzygUQhTk3bSTYnfA48vCM1rmWY7zWL3j1EVKmEy']}},
|
|
'id': 4}
|
|
""" # noqa: E501 # pylint: disable=line-too-long
|
|
args = self._get_confirmed_transaction_args(tx_sig, encoding)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_transaction(self, tx_sig: str, encoding: str = "json") -> types.RPCResponse:
|
|
"""Returns transaction details for a confirmed transaction.
|
|
|
|
Args:
|
|
tx_sig: Transaction signature as base-58 encoded string N encoding attempts to use program-specific
|
|
instruction parsers to return more human-readable and explicit data in the
|
|
`transaction.message.instructions` list.
|
|
encoding: (optional) Encoding for the returned Transaction, either "json", "jsonParsed",
|
|
"base58" (slow), or "base64". If parameter not provided, the default encoding is JSON.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_transaction("3PtGYH77LhhQqTXP4SmDVJ85hmDieWsgXCUbn14v7gYyVYPjZzygUQhTk3bSTYnfA48vCM1rmWY7zWL3j1EVKmEy")) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'meta': {'err': None,
|
|
'fee': 5000, 'rewards': [],
|
|
'postBalances': [498449233720610510, 1000001001987940, 1],
|
|
'preBalances': [498449233721615510, 1000001000987940, 1],
|
|
'status': {'Ok': None}},
|
|
'slot': 1659335,
|
|
'transaction': {'message': {'accountKeys': ['9B5XszUGdMaxCZ7uSQhPzdks5ZQSmWxrmzCSvtJ6Ns6g',
|
|
'2KW2XRd9kwqet15Aha2oK3tYvd3nWbTFH1MBiRAv1BE1',
|
|
'11111111111111111111111111111111'],
|
|
'header': {'numReadonlySignedAccounts': 0,
|
|
'numReadonlyUnsignedAccounts': 1,
|
|
'numRequiredSignatures': 1},
|
|
'instructions': [{'accounts': [0, 1],
|
|
'data': '3Bxs4Bc3VYuGVB19',
|
|
'programIdIndex': 2}],
|
|
'recentBlockhash': 'FwcsKNptGtMLccXAA9YgnivVFK95mKzECLT1DNPi3SDr'},
|
|
'signatures': ['3PtGYH77LhhQqTXP4SmDVJ85hmDieWsgXCUbn14v7gYyVYPjZzygUQhTk3bSTYnfA48vCM1rmWY7zWL3j1EVKmEy']}},
|
|
'id': 4}
|
|
""" # noqa: E501 # pylint: disable=line-too-long
|
|
args = self._get_transaction_args(tx_sig, encoding)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_epoch_info(self, commitment: Optional[Commitment] = None) -> types.RPCResponse:
|
|
"""Returns information about the current epoch.
|
|
|
|
Args:
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_epoch_info()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'absoluteSlot': 5150,
|
|
'blockHeight': 5150,
|
|
'epoch': 0,
|
|
'slotIndex': 5150,
|
|
'slotsInEpoch': 8192},
|
|
'id': 5}
|
|
"""
|
|
args = self._get_epoch_info_args(commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_epoch_schedule(self) -> types.RPCResponse:
|
|
"""Returns epoch schedule information from this cluster's genesis config.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_epoch_schedule()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'firstNormalEpoch': 0,
|
|
'firstNormalSlot': 0,
|
|
'leaderScheduleSlotOffset': 8192,
|
|
'slotsPerEpoch': 8192,
|
|
'warmup': False},
|
|
'id': 6}
|
|
"""
|
|
return await self._provider.make_request(self._get_epoch_schedule)
|
|
|
|
async def get_fee_calculator_for_blockhash(
|
|
self, blockhash: Union[str, Blockhash], commitment: Optional[Commitment] = None
|
|
) -> types.RPCResponse:
|
|
"""Returns the fee calculator associated with the query blockhash, or null if the blockhash has expired.
|
|
|
|
Args:
|
|
blockhash: Blockhash to query as a Base58 encoded string.
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_fee_calculator_for_blockhash("BaQSR194dC4dZaRxATtxYyEwDkk7VgqUY8NVNkub8HFZ")) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'context': {'slot': 7065},
|
|
'value': {'feeCalculator': {'lamportsPerSignature': 5000}}},
|
|
'id': 4}
|
|
""" # noqa: E501 # pylint: disable=line-too-long
|
|
args = self._get_fee_calculator_for_blockhash_args(blockhash, commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_fee_rate_governor(self) -> types.RPCResponse:
|
|
"""Return the fee rate governor information from the root bank.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_fee_rate_governor()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'context': {'slot': 7172},
|
|
'value': {'feeRateGovernor': {'burnPercent': 50,
|
|
'maxLamportsPerSignature': 100000,
|
|
'minLamportsPerSignature': 5000,
|
|
'targetLamportsPerSignature': 10000,
|
|
'targetSignaturesPerSlot': 20000}}},
|
|
'id': 5}
|
|
"""
|
|
return await self._provider.make_request(self._get_fee_rate_governor)
|
|
|
|
async def get_fees(self, commitment: Optional[Commitment] = None) -> types.RPCResponse:
|
|
"""Returns a recent block hash from the ledger, a fee schedule and the last slot the blockhash will be valid.
|
|
|
|
Args:
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_fees()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'context': {'slot': 7727},
|
|
'value': {'blockhash': 'GGS6AEDqjF5irU6D6VQNherEZ2hckGaeBiVdfSZKg4gd',
|
|
'feeCalculator': {'lamportsPerSignature': 5000},
|
|
'lastValidSlot': 8027}},
|
|
'id': 1}
|
|
"""
|
|
args = self._get_fees_args(commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_first_available_block(self) -> types.RPCResponse:
|
|
"""Returns the slot of the lowest confirmed block that has not been purged from the ledger.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_fees()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0', 'result': 1, 'id': 2}
|
|
"""
|
|
return await self._provider.make_request(self._get_first_available_block)
|
|
|
|
async def get_genesis_hash(self) -> types.RPCResponse:
|
|
"""Returns the genesis hash.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_genesis_hash()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': 'EwF9gtehrrvPUoNticgmiEadAWzn4XeN8bNaNVBkS6S2',
|
|
'id': 3}
|
|
"""
|
|
return await self._provider.make_request(self._get_genesis_hash)
|
|
|
|
async def get_identity(self) -> types.RPCResponse:
|
|
"""Returns the identity pubkey for the current node.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_identity()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'identity': 'LjvEBM78ufAikBfxqtj4RNiAECUi7Xqtz9k3QM3DzPk'},
|
|
'id': 4}
|
|
"""
|
|
return await self._provider.make_request(self._get_identity)
|
|
|
|
async def get_inflation_governor(self, commitment: Optional[Commitment] = None) -> types.RPCResponse:
|
|
"""Returns the current inflation governor.
|
|
|
|
Args:
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_inflation_governor()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'foundation': 0.05,
|
|
'foundationTerm': 7.0,
|
|
'initial': 0.15,
|
|
'taper': 0.15,
|
|
'terminal': 0.015},
|
|
'id': 5}
|
|
"""
|
|
args = self._get_inflation_governor_args(commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_inflation_rate(self) -> types.RPCResponse:
|
|
"""Returns the specific inflation values for the current epoch.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_inflation_rate()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'epoch': 1,
|
|
'foundation': 0.007499746885736559,
|
|
'total': 0.14999493771473116,
|
|
'validator': 0.1424951908289946},
|
|
'id': 1}
|
|
"""
|
|
return await self._provider.make_request(self._get_inflation_rate)
|
|
|
|
async def get_largest_accounts(
|
|
self, filter_opt: Optional[str] = None, commitment: Optional[Commitment] = None
|
|
) -> types.RPCResponse:
|
|
"""Returns the 20 largest accounts, by lamport balance.
|
|
|
|
Args:
|
|
filter_opt: Filter results by account type; currently supported: circulating|nonCirculating.
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_largest_accounts()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'context': {'slot': 8890},
|
|
'value': [{'address': '95L7AsBCLRsqghsi6ksZkzjNbs6rqDgHCzKaGZ7bJi75',
|
|
'lamports': 500000000000000000},
|
|
{'address': 'APnSR52EC1eH676m7qTBHUJ1nrGpHYpV7XKPxgRDD8gX',
|
|
'lamports': 164511033098290000},
|
|
{'address': '13LeFbG6m2EP1fqCj9k66fcXsoTHMMtgr7c78AivUrYD',
|
|
'lamports': 153333632446109120},
|
|
{'address': 'GK2zqSsXLA2rwVZk347RYhh6jJpRsCA69FjLW93ZGi3B',
|
|
'lamports': 57499999036109120},
|
|
{'address': '8HVqyX9jebh31Q9Hp8t5sMVJs665979ZeEr3eCfzitUe',
|
|
'lamports': 30301031036109120},
|
|
{'address': 'HbZ5FfmKWNHC7uwk6TF1hVi6TCs7dtYfdjEcuPGgzFAg',
|
|
'lamports': 14999999036109120},
|
|
{'address': '14FUT96s9swbmH7ZjpDvfEDywnAYy9zaNhv4xvezySGu',
|
|
'lamports': 4999999036109120},
|
|
{'address': '9huDUZfxoJ7wGMTffUE7vh1xePqef7gyrLJu9NApncqA',
|
|
'lamports': 4999999036109120},
|
|
{'address': 'C7C8odR8oashR5Feyrq2tJKaXL18id1dSj2zbkDGL2C2',
|
|
'lamports': 4999999036109120},
|
|
{'address': 'AYgECURrvuX6GtFe4tX7aAj87Xc5r5Znx96ntNk1nCv',
|
|
'lamports': 2499999518054560},
|
|
{'address': 'AogcwQ1ubM76EPMhSD5cw1ES4W5econvQCFmBL6nTW1',
|
|
'lamports': 2499999518054560},
|
|
{'address': 'gWgqQ4udVxE3uNxRHEwvftTHwpEmPHAd8JR9UzaHbR2',
|
|
'lamports': 2499999518054560},
|
|
{'address': '3D91zLQPRLamwJfGR5ZYMKQb4C18gsJNaSdmB6b2wLhw',
|
|
'lamports': 2499999518054560},
|
|
{'address': '3bHbMa5VW3np5AJazuacidrN4xPZgwhcXigmjwHmBg5e',
|
|
'lamports': 2499999518054560},
|
|
{'address': '4U3RFq7X5kLG6tZ9kcksFL8oXeGNjtuUN1YfkVKXbs5x',
|
|
'lamports': 2499999518054560},
|
|
{'address': '5cBVGBKY6kBaiTVmsQpxThJ2oqitBYuCAX9Zm2zMuV4y',
|
|
'lamports': 2499999518054560},
|
|
{'address': '8PjJTv657aeN9p5R2WoM6pPSz385chvTTytUWaEjSjkq',
|
|
'lamports': 2499999518054560},
|
|
{'address': 'AHB94zKUASftTdqgdfiDSdnPJHkEFp7zX3yMrcSxABsv',
|
|
'lamports': 2499999518054560},
|
|
{'address': 'Hc36Wh1ZqYGzGAnsJWNT9r2gY3h9n89uDpxZPsmEsiE3',
|
|
'lamports': 2499999518054560},
|
|
{'address': 'GxyRKP2eVKACaSSnso4VLSAjZKmHsFXHWUfS3A5CtiMA',
|
|
'lamports': 1940147018054560}]},
|
|
'id': 2}
|
|
"""
|
|
args = self._get_largest_accounts_args(filter_opt, commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_leader_schedule(
|
|
self, epoch: Optional[int] = None, commitment: Optional[Commitment] = None
|
|
) -> types.RPCResponse:
|
|
"""Returns the leader schedule for an epoch.
|
|
|
|
Args:
|
|
epoch: Fetch the leader schedule for the epoch that corresponds to the provided slot.
|
|
If unspecified, the leader schedule for the current epoch is fetched.
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_leader_schedule()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'EWj2cuEuVhi7RX81cnAY3TzpyFwnHzzVwvuTyfmxmhs3': [0,
|
|
1,
|
|
2,
|
|
3,
|
|
4,
|
|
5,
|
|
...]},
|
|
'id': 6}
|
|
"""
|
|
args = self._get_leader_schedule_args(epoch, commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_minimum_balance_for_rent_exemption(
|
|
self, usize: int, commitment: Optional[Commitment] = None
|
|
) -> types.RPCResponse:
|
|
"""Returns minimum balance required to make account rent exempt.
|
|
|
|
Args:
|
|
usize: Account data length.
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_minimum_balance_for_rent_exemption(50)) # doctest: +SKIP
|
|
{'jsonrpc': '2.0', 'result': 1238880, 'id': 7}
|
|
"""
|
|
args = self._get_minimum_balance_for_rent_exemption_args(usize, commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_multiple_accounts(
|
|
self,
|
|
pubkeys: List[Union[PublicKey, str]],
|
|
commitment: Optional[Commitment] = None,
|
|
encoding: str = "base64",
|
|
data_slice: Optional[types.DataSliceOpts] = None,
|
|
) -> types.RPCResponse:
|
|
"""Returns all the account info for a list of public keys.
|
|
|
|
Args:
|
|
pubkeys: list of Pubkeys to query, as base-58 encoded string or PublicKey object.
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
encoding: (optional) Encoding for Account data, either "base58" (slow), "base64", or
|
|
"jsonParsed". Default is "base64".
|
|
|
|
- "base58" is limited to Account data of less than 128 bytes.
|
|
- "base64" will return base64 encoded data for Account data of any size.
|
|
- "jsonParsed" encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data.
|
|
|
|
If jsonParsed is requested but a parser cannot be found, the field falls back to base64 encoding,
|
|
detectable when the data field is type. (jsonParsed encoding is UNSTABLE).
|
|
data_slice: (optional) Option to limit the returned account data using the provided `offset`: <usize> and
|
|
`length`: <usize> fields; only available for "base58" or "base64" encoding.
|
|
|
|
Example:
|
|
>>> from solana.publickey import PublicKey
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> pubkeys = [PublicKey("6ZWcsUiWJ63awprYmbZgBQSreqYZ4s6opowP4b7boUdh"), PublicKey("HkcE9sqQAnjJtECiFsqGMNmUho3ptXkapUPAqgZQbBSY")]
|
|
>>> asyncio.run(solana_client.get_multiple_accounts(pubkeys)) # doctest: +SKIP
|
|
{
|
|
"jsonrpc": "2.0",
|
|
"result": {
|
|
"context": {"slot": 97531946},
|
|
"value": [
|
|
{
|
|
"data": ["", "base64"],
|
|
"executable": False,
|
|
"lamports": 1,
|
|
"owner": "11111111111111111111111111111111",
|
|
"rentEpoch": 225,
|
|
},
|
|
{
|
|
"data": ["", "base64"],
|
|
"executable": False,
|
|
"lamports": 809441127,
|
|
"owner": "11111111111111111111111111111111",
|
|
"rentEpoch": 225,
|
|
},
|
|
],
|
|
},
|
|
"id": 1,
|
|
}
|
|
""" # noqa: E501 # pylint: disable=line-too-long
|
|
args = self._get_multiple_accounts_args(
|
|
pubkeys=pubkeys, commitment=commitment, encoding=encoding, data_slice=data_slice
|
|
)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_program_accounts( # pylint: disable=too-many-arguments
|
|
self,
|
|
pubkey: Union[str, PublicKey],
|
|
commitment: Optional[Commitment] = Finalized,
|
|
encoding: Optional[str] = None,
|
|
data_slice: Optional[types.DataSliceOpts] = None,
|
|
data_size: Optional[int] = None,
|
|
memcmp_opts: Optional[List[types.MemcmpOpts]] = None,
|
|
) -> types.RPCResponse:
|
|
"""Returns all accounts owned by the provided program Pubkey.
|
|
|
|
Args:
|
|
pubkey: Pubkey of program, as base-58 encoded string or PublicKey object.
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
encoding: (optional) Encoding for the returned Transaction, either jsonParsed",
|
|
"base58" (slow), or "base64". If parameter not provided, the default encoding is JSON.
|
|
data_slice: (optional) Limit the returned account data using the provided `offset`: <usize> and
|
|
`length`: <usize> fields; only available for "base58" or "base64" encoding.
|
|
data_size: (optional) Option to compare the program account data length with the provided data size.
|
|
memcmp_opts: (optional) Options to compare a provided series of bytes with program account data at a particular offset.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> memcmp_opts = [
|
|
... types.MemcmpOpts(offset=4, bytes="3Mc6vR"),
|
|
... ]
|
|
>>> asyncio.run(solana_client.get_program_accounts("4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T", data_size=17, memcmp_opts=memcmp_opts)) # doctest: +SKIP
|
|
{'jsonrpc': "2.0",
|
|
'result' :[{
|
|
'account' :{
|
|
'data' :'2R9jLfiAQ9bgdcw6h8s44439',
|
|
'executable' :false,
|
|
'lamports' :15298080,
|
|
'owner' :'4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T',
|
|
'rentEpoch' :28},
|
|
'pubkey' :'CxELquR1gPP8wHe33gZ4QxqGB3sZ9RSwsJ2KshVewkFY'}],
|
|
'id' :1}
|
|
""" # noqa: E501 # pylint: disable=line-too-long
|
|
args = self._get_program_accounts_args(
|
|
pubkey=pubkey,
|
|
commitment=commitment,
|
|
encoding=encoding,
|
|
data_slice=data_slice,
|
|
data_size=data_size,
|
|
memcmp_opts=memcmp_opts,
|
|
)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_recent_blockhash(self, commitment: Optional[Commitment] = None) -> types.RPCResponse:
|
|
"""Returns a recent block hash from the ledger.
|
|
|
|
Response also includes a fee schedule that can be used to compute the cost
|
|
of submitting a transaction using it.
|
|
|
|
Args:
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_recent_blockhash()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'context': {'slot': 1637},
|
|
'value': {'blockhash': 'EALChog1mXQ9nEgEUQpWAtmA5UueUZvZiL16ZivmR7eb',
|
|
'feeCalculator': {'lamportsPerSignature': 5000}}},
|
|
'id': 2}
|
|
"""
|
|
args = self._get_recent_blockhash_args(commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_signature_statuses(
|
|
self, signatures: List[Union[str, bytes]], search_transaction_history: bool = False
|
|
) -> types.RPCResponse:
|
|
"""Returns the statuses of a list of signatures.
|
|
|
|
Unless the `search_transaction_history` configuration parameter is included, this method only
|
|
searches the recent status cache of signatures, which retains statuses for all active slots plus
|
|
`MAX_RECENT_BLOCKHASHES` rooted slots.
|
|
|
|
Args:
|
|
signatures: An array of transaction signatures to confirm.
|
|
search_transaction_history: If true, a Solana node will search its ledger cache for
|
|
any signatures not found in the recent status cache.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> signatures = [
|
|
... "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW",
|
|
... "5j7s6NiJS3JAkvgkoc18WVAsiSaci2pxB2A6ueCJP4tprA2TFg9wSyTLeYouxPBJEMzJinENTkpA52YStRW5Dia7"]
|
|
>>> asyncio.run(solana_client.get_signature_statuses(signatures)) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {
|
|
'context': {'slot':82},
|
|
'value': [{
|
|
'slot': 72,
|
|
'confirmations': 10,
|
|
'err': null,
|
|
'status': {'Ok': null}}, null]},
|
|
'id': 1}
|
|
"""
|
|
args = self._get_signature_statuses_args(signatures, search_transaction_history)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_slot(self, commitment: Optional[Commitment] = None) -> types.RPCResponse:
|
|
"""Returns the current slot the node is processing.
|
|
|
|
Args:
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_slot()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0', 'result': 7515, 'id': 1}
|
|
"""
|
|
args = self._get_slot_args(commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_slot_leader(self, commitment: Optional[Commitment] = None) -> types.RPCResponse:
|
|
"""Returns the current slot leader.
|
|
|
|
Args:
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_slot_leader()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': 'EWj2cuEuVhi7RX81cnAY3TzpyFwnHzzVwvuTyfmxmhs3',
|
|
'id': 1}
|
|
"""
|
|
args = self._get_slot_leader_args(commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_stake_activation(
|
|
self, pubkey: Union[PublicKey, str], epoch: Optional[int] = None, commitment: Optional[Commitment] = None
|
|
) -> types.RPCResponse:
|
|
"""Returns epoch activation information for a stake account.
|
|
|
|
Args:
|
|
pubkey: Pubkey of stake account to query, as base-58 encoded string or PublicKey object.
|
|
epoch: (optional) Epoch for which to calculate activation details. If parameter not provided,
|
|
defaults to current epoch.
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_stake_activation()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0','result': {'active': 124429280, 'inactive': 73287840, 'state': 'activating'}, 'id': 1}}
|
|
"""
|
|
args = self._get_stake_activation_args(pubkey, epoch, commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_supply(self, commitment: Optional[Commitment] = None) -> types.RPCResponse:
|
|
"""Returns information about the current supply.
|
|
|
|
Args:
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_supply()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'context': {'slot': 3846},
|
|
'value': {'circulating': 683635192454157660,
|
|
'nonCirculating': 316364808037127120,
|
|
'nonCirculatingAccounts': ['ETfDYz7Cg5p9SDFmdpRerjBN5puKK7xydEBZZGM2V4Ay',
|
|
'7cKxv6UznFoWRuJkgw5bWj5rp5PiKTcXZeEaLqyd3Bbm',
|
|
'CV7qh8ZoqeUSTQagosGpkLptXoojf9yCszxkRx1jTD12',
|
|
'FZ9S7X9jMbCaMyJjRfSoBhFyarUMVwvx7HWRe4LnZHsg',
|
|
...]
|
|
'total': 1000000000491284780}},
|
|
'id': 1}
|
|
"""
|
|
args = self._get_supply_args(commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_token_account_balance(self, pubkey: Union[str, PublicKey], commitment: Optional[Commitment] = None):
|
|
"""Returns the token balance of an SPL Token account (UNSTABLE).
|
|
|
|
Args:
|
|
pubkey: Pubkey of Token account to query, as base-58 encoded string or PublicKey object.
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_token_account_balance("7fUAJdStEuGbc3sM84cKRL6yYaaSstyLSU4ve5oovLS7")) # noqa: E501 # pylint: disable=line-too-long # doctest: +SKIP
|
|
{'jsonrpc': '2.0','result': {
|
|
'context': {'slot':1114},
|
|
'value': {
|
|
'uiAmount': 98.64,
|
|
'amount': '9864',
|
|
'decimals': 2},
|
|
'id' :1}
|
|
"""
|
|
args = self._get_token_account_balance_args(pubkey, commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_token_accounts_by_delegate(
|
|
self,
|
|
delegate: PublicKey,
|
|
opts: types.TokenAccountOpts,
|
|
commitment: Optional[Commitment] = None,
|
|
) -> types.RPCResponse:
|
|
"""Returns all SPL Token accounts by approved Delegate (UNSTABLE).
|
|
|
|
Args:
|
|
delegate: Public key of the delegate owner to query.
|
|
opts: Token account option specifying at least one of `mint` or `program_id`.
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
"""
|
|
args = self._get_token_accounts_by_delegate_args(delegate, opts, commitment)
|
|
return await self.__get_token_accounts(*args)
|
|
|
|
async def get_token_accounts_by_owner(
|
|
self,
|
|
owner: PublicKey,
|
|
opts: types.TokenAccountOpts,
|
|
commitment: Optional[Commitment] = None,
|
|
) -> types.RPCResponse:
|
|
"""Returns all SPL Token accounts by token owner (UNSTABLE).
|
|
|
|
Args:
|
|
owner: Public key of the account owner to query.
|
|
opts: Token account option specifying at least one of `mint` or `program_id`.
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
"""
|
|
args = self._get_token_accounts_by_owner_args(owner, opts, commitment)
|
|
return await self.__get_token_accounts(*args)
|
|
|
|
async def __get_token_accounts(
|
|
self,
|
|
method: types.RPCMethod,
|
|
pubkey: str,
|
|
opts: types.TokenAccountOpts,
|
|
commitment: Commitment,
|
|
) -> types.RPCResponse:
|
|
args = self._get_token_accounts_args(method, pubkey, opts, commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_token_largest_accounts(
|
|
self, pubkey: Union[PublicKey, str], commitment: Optional[Commitment] = None
|
|
) -> types.RPCResponse:
|
|
"""Returns the 20 largest accounts of a particular SPL Token type."""
|
|
args = self._get_token_largest_account_args(pubkey, commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_token_supply(
|
|
self, pubkey: Union[PublicKey, str], commitment: Optional[Commitment] = None
|
|
) -> types.RPCResponse:
|
|
"""Returns the total supply of an SPL Token type."""
|
|
args = self._get_token_supply_args(pubkey, commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_transaction_count(self, commitment: Optional[Commitment] = None) -> types.RPCResponse:
|
|
"""Returns the current Transaction count from the ledger.
|
|
|
|
Args:
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_transaction_count()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0', 'result': 4554, 'id': 1}
|
|
"""
|
|
args = self._get_transaction_count_args(commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def get_minimum_ledger_slot(self) -> types.RPCResponse:
|
|
"""Returns the lowest slot that the node has information about in its ledger.
|
|
|
|
This value may increase over time if the node is configured to purge older ledger data.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_minimum_ledger_slot()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0', 'result': 1234, 'id': 1}
|
|
"""
|
|
return await self._provider.make_request(self._minimum_ledger_slot)
|
|
|
|
async def get_version(self) -> types.RPCResponse:
|
|
"""Returns the current solana versions running on the node.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_version()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0', 'result': {'solana-core': '1.4.0 5332fcad'}, 'id': 1}
|
|
"""
|
|
return await self._provider.make_request(self._get_version)
|
|
|
|
async def get_vote_accounts(self, commitment: Optional[Commitment] = None):
|
|
"""Returns the account info and associated stake for all the voting accounts in the current bank.
|
|
|
|
Args:
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.get_vote_accounts()) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': {'current': [{'activatedStake': 0,
|
|
'commission': 100,
|
|
'epochCredits': [[165, 714644, 707372],
|
|
[166, 722092, 714644],
|
|
[167, 730285, 722092],
|
|
[168, 738476, 730285],
|
|
...]
|
|
'epochVoteAccount': True,
|
|
'lastVote': 1872294,
|
|
'nodePubkey': 'J7v9ndmcoBuo9to2MnHegLnBkC9x3SAVbQBJo5MMJrN1',
|
|
'rootSlot': 1872263,
|
|
'votePubkey': 'HiFjzpR7e5Kv2tdU9jtE4FbH1X8Z9Syia3Uadadx18b5'},
|
|
{'activatedStake': 500029968930560,
|
|
'commission': 100,
|
|
'epochCredits': [[165, 1359689, 1351498],
|
|
[166, 1367881, 1359689],
|
|
[167, 1376073, 1367881],
|
|
[168, 1384265, 1376073],
|
|
...],
|
|
'epochVoteAccount': True,
|
|
'lastVote': 1872295,
|
|
'nodePubkey': 'dv1LfzJvDF7S1fBKpFgKoKXK5yoSosmkAdfbxBo1GqJ',
|
|
'rootSlot': 1872264,
|
|
'votePubkey': '5MMCR4NbTZqjthjLGywmeT66iwE9J9f7kjtxzJjwfUx2'},
|
|
{'activatedStake': 0,
|
|
'commission': 100,
|
|
'epochCredits': [[227, 2751, 0], [228, 7188, 2751]],
|
|
'epochVoteAccount': True,
|
|
'lastVote': 1872295,
|
|
'nodePubkey': 'H1wDvJ5HJc1SzhHoWtaycpzQpFbsL7g8peaRV3obKShs',
|
|
'rootSlot': 1872264,
|
|
'votePubkey': 'DPqpgoLQVU3aq72HEqSMsB9qh4KoXc9fGEpvgEuiwnp6'}],
|
|
'delinquent': []},
|
|
'id': 1}
|
|
"""
|
|
args = self._get_vote_accounts_args(commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def request_airdrop(
|
|
self, pubkey: Union[PublicKey, str], lamports: int, commitment: Optional[Commitment] = None
|
|
) -> types.RPCResponse:
|
|
"""Requests an airdrop of lamports to a Pubkey.
|
|
|
|
Args:
|
|
pubkey: Pubkey of account to receive lamports, as base-58 encoded string or public key object.
|
|
lamports: Amount of lamports.
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> from solana.publickey import PublicKey
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.request_airdrop(PublicKey(1), 10000)) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': 'uK6gbLbhnTEgjgmwn36D5BRTRkG4AT8r7Q162TLnJzQnHUZVL9r6BYZVfRttrhmkmno6Fp4VQELzL4AiriCo61U',
|
|
'id': 1}
|
|
"""
|
|
args = self._request_airdrop_args(pubkey, lamports, commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def send_raw_transaction(
|
|
self, txn: Union[bytes, str], opts: types.TxOpts = types.TxOpts()
|
|
) -> types.RPCResponse:
|
|
"""Send a transaction that has already been signed and serialized into the wire format.
|
|
|
|
Args:
|
|
txn: Fully-signed Transaction object, a fully sign transaction in wire format,
|
|
or a fully transaction as base-64 encoded string.
|
|
opts: (optional) Transaction options.
|
|
|
|
Before submitting, the following preflight checks are performed (unless disabled with the `skip_preflight` option):
|
|
|
|
- The transaction signatures are verified.
|
|
|
|
- The transaction is simulated against the latest max confirmed bank and on failure an error
|
|
will be returned. Preflight checks may be disabled if desired.
|
|
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> full_signed_tx_str = (
|
|
... "AbN5XM+qw+7oOLsFw7goQSLBis7c1kXJFP6OF4w7YmQNhhbQYcyBiybKuOzzhV7McvoRP3Mey9AhXojtwDCdbwoBAAEDE5j2"
|
|
... "LG0aRXxRumpLXz29L2n8qTIWIY3ImX5Ba9F9k8poq0Z3/7HyiU3QphU8Ix1F7ENq5TrmAUnb4V8y5LhwPwAAAAAAAAAAAAAA"
|
|
... "AAAAAAAAAAAAAAAAAAAAAAAAAAAAg5YY9wG6fpuieuWYJd1ta7ZtFPbV0OriFRYdcYUaEGkBAgIAAQwCAAAAQEIPAAAAAAA=")
|
|
>>> asyncio.run(solana_client.send_raw_transaction(full_signed_tx_str)) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': 'CMwyESM2NE74mghfbvsHJDERF7xMYKshwwm6VgH6GFqXzx8LfBFuP5ruccumfhTguha6seUHPpiHzzHUQXzq2kN',
|
|
'id': 1}
|
|
""" # noqa: E501 # pylint: disable=line-too-long
|
|
args = self._send_raw_transaction_args(txn, opts)
|
|
|
|
resp = await self._provider.make_request(*args)
|
|
if opts.skip_confirmation:
|
|
return self._post_send(resp)
|
|
post_send_args = self._send_raw_transaction_post_send_args(resp, opts)
|
|
return await self.__post_send_with_confirm(*post_send_args)
|
|
|
|
async def send_transaction(
|
|
self,
|
|
txn: Transaction,
|
|
*signers: Keypair,
|
|
opts: types.TxOpts = types.TxOpts(),
|
|
recent_blockhash: Optional[Blockhash] = None,
|
|
) -> types.RPCResponse:
|
|
"""Send a transaction.
|
|
|
|
Args:
|
|
txn: Transaction object.
|
|
signers: Signers to sign the transaction.
|
|
opts: (optional) Transaction options.
|
|
recent_blockhash: (optional) Pass a valid recent blockhash here if you want to
|
|
skip fetching the recent blockhash or relying on the cache.
|
|
|
|
Example:
|
|
>>> from solana.keypair import Keypair
|
|
>>> from solana.system_program import TransferParams, transfer
|
|
>>> from solana.transaction import Transaction
|
|
>>> sender, receiver = Keypair.from_seed(bytes(PublicKey(1))), Keypair.from_seed(bytes(PublicKey(2)))
|
|
>>> txn = Transaction().add(transfer(TransferParams(
|
|
... from_pubkey=sender.public_key, to_pubkey=receiver.public_key, lamports=1000)))
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.send_transaction(txn, sender)) # doctest: +SKIP
|
|
{'jsonrpc': '2.0',
|
|
'result': '236zSA5w4NaVuLXXHK1mqiBuBxkNBu84X6cfLBh1v6zjPrLfyECz4zdedofBaZFhs4gdwzSmij9VkaSo2tR5LTgG',
|
|
'id': 12}
|
|
"""
|
|
if recent_blockhash is None:
|
|
if self.blockhash_cache:
|
|
try:
|
|
recent_blockhash = self.blockhash_cache.get()
|
|
except ValueError:
|
|
blockhash_resp = await self.get_recent_blockhash(Finalized)
|
|
recent_blockhash = self._process_blockhash_resp(blockhash_resp, used_immediately=True)
|
|
else:
|
|
blockhash_resp = await self.get_recent_blockhash(Finalized)
|
|
recent_blockhash = self.parse_recent_blockhash(blockhash_resp)
|
|
txn.recent_blockhash = recent_blockhash
|
|
|
|
txn.sign(*signers)
|
|
txn_resp = await self.send_raw_transaction(txn.serialize(), opts=opts)
|
|
if self.blockhash_cache:
|
|
blockhash_resp = await self.get_recent_blockhash(Finalized)
|
|
self._process_blockhash_resp(blockhash_resp, used_immediately=False)
|
|
return txn_resp
|
|
|
|
async def simulate_transaction(
|
|
self, txn: Union[bytes, str, Transaction], sig_verify: bool = False, commitment: Optional[Commitment] = None
|
|
) -> types.RPCResponse:
|
|
"""Simulate sending a transaction.
|
|
|
|
Args:
|
|
txn: A Transaction object, a transaction in wire format, or a transaction as base-64 encoded string
|
|
The transaction must have a valid blockhash, but is not required to be signed.
|
|
sig_verify: If true the transaction signatures will be verified (default: false).
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> tx_str = (
|
|
... "4hXTCkRzt9WyecNzV1XPgCDfGAZzQKNxLXgynz5QDuWWPSAZBZSHptvWRL3BjCvzUXRdKvHL2b7yGrRQcWyaqsaBCncVG7BF"
|
|
... "ggS8w9snUts67BSh3EqKpXLUm5UMHfD7ZBe9GhARjbNQMLJ1QD3Spr6oMTBU6EhdB4RD8CP2xUxr2u3d6fos36PD98XS6oX8"
|
|
... "TQjLpsMwncs5DAMiD4nNnR8NBfyghGCWvCVifVwvA8B8TJxE1aiyiv2L429BCWfyzAme5sZW8rDb14NeCQHhZbtNqfXhcp2t"
|
|
... )
|
|
>>> asyncio.run(solana_client.simulate_transaction(tx_str)) # doctest: +SKIP
|
|
{'jsonrpc' :'2.0',
|
|
'result': {'context': {'slot': 218},
|
|
'value': {
|
|
'err': null,
|
|
'logs': ['BPF program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri success']},
|
|
'id':1}
|
|
""" # noqa: E501 # pylint: disable=line-too-long
|
|
args = self._simulate_transaction_args(txn, sig_verify, commitment)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def set_log_filter(self, log_filter: str) -> types.RPCResponse:
|
|
"""Sets the log filter on the validator.
|
|
|
|
Args:
|
|
log_filter: The new log filter to use.
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> asyncio.run(solana_client.set_log_filter("solana_core=debug")) # doctest: +SKIP
|
|
{'jsonrpc': '2.0', 'result': None, 'id': 1}
|
|
"""
|
|
args = self._set_log_filter_args(log_filter)
|
|
return await self._provider.make_request(*args)
|
|
|
|
async def validator_exit(self) -> types.RPCResponse:
|
|
"""Request to have the validator exit.
|
|
|
|
Validator must have booted with RPC exit enabled (`--enable-rpc-exit` parameter).
|
|
|
|
Example:
|
|
>>> solana_client = AsyncClient("http://localhost:8899")
|
|
>>> solana_client.validator_exit() # doctest: +SKIP
|
|
{'jsonrpc': '2.0', 'result': true, 'id': 1}
|
|
"""
|
|
return await self._provider.make_request(self._validator_exit)
|
|
|
|
async def __post_send_with_confirm(self, resp: types.RPCResponse, conf_comm: Commitment) -> types.RPCResponse:
|
|
resp = self._post_send(resp)
|
|
self._provider.logger.info(
|
|
"Transaction sent to %s. Signature %s: ", self._provider.endpoint_uri, resp["result"]
|
|
)
|
|
await self.confirm_transaction(resp["result"], conf_comm)
|
|
return resp
|
|
|
|
async def confirm_transaction(
|
|
self, tx_sig: str, commitment: Commitment = Finalized, sleep_seconds: float = 0.5
|
|
) -> types.RPCResponse:
|
|
"""Confirm the transaction identified by the specified signature.
|
|
|
|
Args:
|
|
tx_sig: the transaction signature to confirm.
|
|
commitment: Bank state to query. It can be either "finalized", "confirmed" or "processed".
|
|
sleep_seconds: The number of seconds to sleep when polling the signature status.
|
|
"""
|
|
timeout = time() + 30
|
|
while time() < timeout:
|
|
resp = await self.get_signature_statuses([tx_sig])
|
|
maybe_rpc_error = resp.get("error")
|
|
if maybe_rpc_error is not None:
|
|
raise RPCException(maybe_rpc_error)
|
|
resp_value = resp["result"]["value"][0]
|
|
if resp_value is not None:
|
|
confirmation_status = resp_value["confirmationStatus"]
|
|
confirmation_rank = COMMITMENT_RANKS[confirmation_status]
|
|
commitment_rank = COMMITMENT_RANKS[commitment]
|
|
if confirmation_rank >= commitment_rank:
|
|
break
|
|
await asyncio.sleep(sleep_seconds)
|
|
else:
|
|
maybe_rpc_error = resp.get("error")
|
|
if maybe_rpc_error is not None:
|
|
raise RPCException(maybe_rpc_error)
|
|
raise UnconfirmedTxError(f"Unable to confirm transaction {tx_sig}")
|
|
return resp
|