|
@@ -5,18 +5,27 @@ use anchor_lang::solana_program::instruction::{AccountMeta, Instruction};
|
|
|
use anchor_lang::solana_program::program_error::ProgramError;
|
|
|
use anchor_lang::solana_program::pubkey::Pubkey;
|
|
|
use anchor_lang::solana_program::system_program;
|
|
|
-use anchor_lang::{AccountDeserialize, InstructionData, ToAccountMetas};
|
|
|
+use anchor_lang::{AccountDeserialize, Discriminator, InstructionData, ToAccountMetas};
|
|
|
use regex::Regex;
|
|
|
+use solana_account_decoder::UiAccountEncoding;
|
|
|
use solana_client::client_error::ClientError as SolanaClientError;
|
|
|
use solana_client::pubsub_client::{PubsubClient, PubsubClientError, PubsubClientSubscription};
|
|
|
use solana_client::rpc_client::RpcClient;
|
|
|
-use solana_client::rpc_config::{RpcTransactionLogsConfig, RpcTransactionLogsFilter};
|
|
|
+use solana_client::rpc_config::{
|
|
|
+ RpcAccountInfoConfig, RpcProgramAccountsConfig, RpcTransactionLogsConfig,
|
|
|
+ RpcTransactionLogsFilter,
|
|
|
+};
|
|
|
+use solana_client::rpc_filter::{Memcmp, MemcmpEncodedBytes, RpcFilterType};
|
|
|
use solana_client::rpc_response::{Response as RpcResponse, RpcLogsResponse};
|
|
|
+use solana_sdk::account::Account;
|
|
|
+use solana_sdk::bs58;
|
|
|
use solana_sdk::commitment_config::CommitmentConfig;
|
|
|
use solana_sdk::signature::{Signature, Signer};
|
|
|
use solana_sdk::transaction::Transaction;
|
|
|
use std::convert::Into;
|
|
|
+use std::iter::Map;
|
|
|
use std::rc::Rc;
|
|
|
+use std::vec::IntoIter;
|
|
|
use thiserror::Error;
|
|
|
|
|
|
pub use anchor_lang;
|
|
@@ -129,6 +138,45 @@ impl Program {
|
|
|
T::try_deserialize(&mut data).map_err(Into::into)
|
|
|
}
|
|
|
|
|
|
+ /// Returns all program accounts of the given type matching the given filters
|
|
|
+ pub fn accounts<T: AccountDeserialize + Discriminator>(
|
|
|
+ &self,
|
|
|
+ filters: Vec<RpcFilterType>,
|
|
|
+ ) -> Result<Vec<(Pubkey, T)>, ClientError> {
|
|
|
+ self.accounts_lazy(filters)?.collect()
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Returns all program accounts of the given type matching the given filters as an iterator
|
|
|
+ /// Deserialization is executed lazily
|
|
|
+ pub fn accounts_lazy<T: AccountDeserialize + Discriminator>(
|
|
|
+ &self,
|
|
|
+ filters: Vec<RpcFilterType>,
|
|
|
+ ) -> Result<ProgramAccountsIterator<T>, ClientError> {
|
|
|
+ let account_type_filter = RpcFilterType::Memcmp(Memcmp {
|
|
|
+ offset: 0,
|
|
|
+ bytes: MemcmpEncodedBytes::Base58(bs58::encode(T::discriminator()).into_string()),
|
|
|
+ encoding: None,
|
|
|
+ });
|
|
|
+ let config = RpcProgramAccountsConfig {
|
|
|
+ filters: Some([vec![account_type_filter], filters].concat()),
|
|
|
+ account_config: RpcAccountInfoConfig {
|
|
|
+ encoding: Some(UiAccountEncoding::Base64),
|
|
|
+ data_slice: None,
|
|
|
+ commitment: None,
|
|
|
+ },
|
|
|
+ with_context: None,
|
|
|
+ };
|
|
|
+ Ok(ProgramAccountsIterator {
|
|
|
+ inner: self
|
|
|
+ .rpc()
|
|
|
+ .get_program_accounts_with_config(&self.id(), config)?
|
|
|
+ .into_iter()
|
|
|
+ .map(|(key, account)| {
|
|
|
+ Ok((key, T::try_deserialize(&mut (&account.data as &[u8]))?))
|
|
|
+ }),
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
pub fn state<T: AccountDeserialize>(&self) -> Result<T, ClientError> {
|
|
|
self.account(anchor_lang::__private::state::address(&self.program_id))
|
|
|
}
|
|
@@ -209,6 +257,23 @@ impl Program {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/// Iterator with items of type (Pubkey, T). Used to lazily deserialize account structs.
|
|
|
+/// Wrapper type hides the inner type from usages so the implementation can be changed.
|
|
|
+pub struct ProgramAccountsIterator<T> {
|
|
|
+ inner: Map<IntoIter<(Pubkey, Account)>, AccountConverterFunction<T>>,
|
|
|
+}
|
|
|
+
|
|
|
+/// Function type that accepts solana accounts and returns deserialized anchor accounts
|
|
|
+type AccountConverterFunction<T> = fn((Pubkey, Account)) -> Result<(Pubkey, T), ClientError>;
|
|
|
+
|
|
|
+impl<T> Iterator for ProgramAccountsIterator<T> {
|
|
|
+ type Item = Result<(Pubkey, T), ClientError>;
|
|
|
+
|
|
|
+ fn next(&mut self) -> Option<Self::Item> {
|
|
|
+ self.inner.next()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
fn handle_program_log<T: anchor_lang::Event + anchor_lang::AnchorDeserialize>(
|
|
|
self_program_str: &str,
|
|
|
l: &str,
|