feat: refactor subscription API with multi-filter support

- Support multiple transaction/account filters as vectors
- Add Token2022 extended state parsing
- Add pumpswap pool monitoring example
- Enhance AccountFilter with memcmp filters

BREAKING CHANGE: API signature changes for subscription methods
This commit is contained in:
ysq
2025-09-10 23:21:08 +08:00
parent 304c943d79
commit 5ea536bef6
13 changed files with 491 additions and 327 deletions
+39 -41
View File
@@ -13,6 +13,8 @@ use super::types::TransactionsFilterMap;
use crate::common::AnyResult;
use crate::streaming::common::StreamClientConfig as ClientConfig;
use crate::streaming::event_parser::common::filter::EventTypeFilter;
use crate::streaming::yellowstone_grpc::AccountFilter;
use crate::streaming::yellowstone_grpc::TransactionFilter;
/// Subscription manager
#[derive(Clone)]
@@ -51,15 +53,14 @@ impl SubscriptionManager {
impl Stream<Item = Result<SubscribeUpdate, Status>>,
SubscribeRequest,
)> {
let blocks_meta = if event_type_filter.is_some()
&& event_type_filter.unwrap().include_block_event()
{
hashmap! { "".to_owned() => SubscribeRequestFilterBlocksMeta {} }
} else if event_type_filter.is_none() {
hashmap! { "".to_owned() => SubscribeRequestFilterBlocksMeta {} }
} else {
hashmap! {}
};
let blocks_meta =
if event_type_filter.is_some() && event_type_filter.unwrap().include_block_event() {
hashmap! { "".to_owned() => SubscribeRequestFilterBlocksMeta {} }
} else if event_type_filter.is_none() {
hashmap! { "".to_owned() => SubscribeRequestFilterBlocksMeta {} }
} else {
hashmap! {}
};
let subscribe_request = SubscribeRequest {
accounts: accounts.unwrap_or_default(),
transactions: transactions.unwrap_or_default(),
@@ -79,56 +80,53 @@ impl SubscriptionManager {
/// Create account subscription request and return stream
pub fn subscribe_with_account_request(
&self,
account: Vec<String>,
owner: Vec<String>,
account_filter: Vec<AccountFilter>,
event_type_filter: Option<&EventTypeFilter>,
) -> Option<AccountsFilterMap> {
if account.len() == 0 && owner.len() == 0 {
if event_type_filter.is_some() && !event_type_filter.unwrap().include_account_event() {
return None;
}
if event_type_filter.is_some()
&& !event_type_filter.unwrap().include_account_event()
{
if account_filter.len() == 0 {
return None;
}
let mut accounts = HashMap::new();
accounts.insert(
"".to_owned(),
SubscribeRequestFilterAccounts {
account: account,
owner: owner,
filters: vec![],
nonempty_txn_signature: None,
},
);
for af in account_filter {
accounts.insert(
"".to_owned(),
SubscribeRequestFilterAccounts {
account: af.account,
owner: af.owner,
filters: af.filters,
nonempty_txn_signature: None,
},
);
}
Some(accounts)
}
/// Generate subscription request filter
pub fn get_subscribe_request_filter(
&self,
account_include: Vec<String>,
account_exclude: Vec<String>,
account_required: Vec<String>,
transaction_filter: Vec<TransactionFilter>,
event_type_filter: Option<&EventTypeFilter>,
) -> Option<TransactionsFilterMap> {
if event_type_filter.is_some()
&& !event_type_filter.unwrap().include_transaction_event()
{
if event_type_filter.is_some() && !event_type_filter.unwrap().include_transaction_event() {
return None;
}
let mut transactions = HashMap::new();
transactions.insert(
"client".to_string(),
SubscribeRequestFilterTransactions {
vote: Some(false),
failed: Some(false),
signature: None,
account_include,
account_exclude,
account_required,
},
);
for tf in transaction_filter {
transactions.insert(
"client".to_string(),
SubscribeRequestFilterTransactions {
vote: Some(false),
failed: Some(false),
signature: None,
account_include: tf.account_include,
account_exclude: tf.account_exclude,
account_required: tf.account_required,
},
);
}
Some(transactions)
}