0.5.5
This commit is contained in:
@@ -8,7 +8,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.5.4"
|
||||
version = "0.5.5"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-bobot"
|
||||
|
||||
215
khbb_lib/src/enriched_classifier.rs
Normal file
215
khbb_lib/src/enriched_classifier.rs
Normal file
@@ -0,0 +1,215 @@
|
||||
// file: khbb_lib/src/enriched_classifier.rs
|
||||
|
||||
//! Classification of enriched account snapshots into stronger domain signals.
|
||||
|
||||
/// Confirmed or refined event derived from an enriched account snapshot.
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub enum KhbbEnrichedConfirmedEvent {
|
||||
/// Confirmed token account activity.
|
||||
ConfirmedTokenAccountActivity(KhbbConfirmedTokenAccountActivityEvent),
|
||||
/// Confirmed mint account activity.
|
||||
ConfirmedMintAccountActivity(KhbbConfirmedMintAccountActivityEvent),
|
||||
/// Unknown token-program-owned account activity.
|
||||
UnknownTokenProgramAccountActivity(KhbbUnknownTokenProgramAccountActivityEvent),
|
||||
}
|
||||
|
||||
/// Confirmed token account activity.
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct KhbbConfirmedTokenAccountActivityEvent {
|
||||
/// Account pubkey.
|
||||
pub pubkey: std::string::String,
|
||||
/// Context slot from the enrichment response.
|
||||
pub context_slot: u64,
|
||||
/// Owner program if available.
|
||||
pub owner: std::option::Option<std::string::String>,
|
||||
/// Lamports if available.
|
||||
pub lamports: std::option::Option<u64>,
|
||||
}
|
||||
|
||||
/// Confirmed mint account activity.
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct KhbbConfirmedMintAccountActivityEvent {
|
||||
/// Account pubkey.
|
||||
pub pubkey: std::string::String,
|
||||
/// Context slot from the enrichment response.
|
||||
pub context_slot: u64,
|
||||
/// Owner program if available.
|
||||
pub owner: std::option::Option<std::string::String>,
|
||||
/// Lamports if available.
|
||||
pub lamports: std::option::Option<u64>,
|
||||
}
|
||||
|
||||
/// Unknown token-program-owned account activity.
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct KhbbUnknownTokenProgramAccountActivityEvent {
|
||||
/// Account pubkey.
|
||||
pub pubkey: std::string::String,
|
||||
/// Context slot from the enrichment response.
|
||||
pub context_slot: u64,
|
||||
/// Owner program if available.
|
||||
pub owner: std::option::Option<std::string::String>,
|
||||
/// Lamports if available.
|
||||
pub lamports: std::option::Option<u64>,
|
||||
}
|
||||
|
||||
/// Classifies an enriched account snapshot into a stronger confirmed event.
|
||||
pub(crate) fn classify_enriched_account_snapshot(
|
||||
snapshot: &crate::KhbbEnrichedAccountSnapshot,
|
||||
) -> core::result::Result<std::option::Option<KhbbEnrichedConfirmedEvent>, crate::KhbbError> {
|
||||
if !snapshot.exists {
|
||||
return Ok(None);
|
||||
}
|
||||
let kind = match &snapshot.kind {
|
||||
Some(value) => value,
|
||||
None => {
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
match kind {
|
||||
crate::KhbbEnrichedAccountKind::PotentialTokenAccount => {
|
||||
Ok(Some(
|
||||
KhbbEnrichedConfirmedEvent::ConfirmedTokenAccountActivity(
|
||||
KhbbConfirmedTokenAccountActivityEvent {
|
||||
pubkey: snapshot.pubkey.clone(),
|
||||
context_slot: snapshot.context_slot,
|
||||
owner: snapshot.owner.clone(),
|
||||
lamports: snapshot.lamports,
|
||||
},
|
||||
),
|
||||
))
|
||||
}
|
||||
crate::KhbbEnrichedAccountKind::PotentialMintAccount => {
|
||||
Ok(Some(
|
||||
KhbbEnrichedConfirmedEvent::ConfirmedMintAccountActivity(
|
||||
KhbbConfirmedMintAccountActivityEvent {
|
||||
pubkey: snapshot.pubkey.clone(),
|
||||
context_slot: snapshot.context_slot,
|
||||
owner: snapshot.owner.clone(),
|
||||
lamports: snapshot.lamports,
|
||||
},
|
||||
),
|
||||
))
|
||||
}
|
||||
crate::KhbbEnrichedAccountKind::UnknownAccount => {
|
||||
let owner = match snapshot.owner.as_deref() {
|
||||
Some(value) => value,
|
||||
None => {
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
let known_program =
|
||||
crate::program_registry::classify_known_program_id(owner);
|
||||
match known_program {
|
||||
Some(crate::KhbbKnownProgram::SplToken)
|
||||
| Some(crate::KhbbKnownProgram::SplToken2022) => {
|
||||
Ok(Some(
|
||||
KhbbEnrichedConfirmedEvent::UnknownTokenProgramAccountActivity(
|
||||
KhbbUnknownTokenProgramAccountActivityEvent {
|
||||
pubkey: snapshot.pubkey.clone(),
|
||||
context_slot: snapshot.context_slot,
|
||||
owner: snapshot.owner.clone(),
|
||||
lamports: snapshot.lamports,
|
||||
},
|
||||
),
|
||||
))
|
||||
}
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn classify_enriched_snapshot_returns_confirmed_token_account() {
|
||||
let snapshot = crate::KhbbEnrichedAccountSnapshot {
|
||||
pubkey: std::string::String::from("SomePubkey"),
|
||||
context_slot: 100,
|
||||
exists: true,
|
||||
owner: Some(crate::ids::SPL_TOKEN_PROGRAM_ID.to_string()),
|
||||
lamports: Some(123),
|
||||
kind: Some(crate::KhbbEnrichedAccountKind::PotentialTokenAccount),
|
||||
};
|
||||
let result = super::classify_enriched_account_snapshot(&snapshot);
|
||||
assert!(result.is_ok());
|
||||
let event_option = result.expect("classify token snapshot");
|
||||
assert!(event_option.is_some());
|
||||
match event_option.expect("confirmed token event") {
|
||||
super::KhbbEnrichedConfirmedEvent::ConfirmedTokenAccountActivity(inner) => {
|
||||
assert_eq!(inner.pubkey, "SomePubkey");
|
||||
assert_eq!(inner.context_slot, 100);
|
||||
assert_eq!(inner.lamports, Some(123));
|
||||
}
|
||||
_ => {
|
||||
panic!("expected confirmed token account activity");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn classify_enriched_snapshot_returns_confirmed_mint_account() {
|
||||
let snapshot = crate::KhbbEnrichedAccountSnapshot {
|
||||
pubkey: std::string::String::from("MintPubkey"),
|
||||
context_slot: 200,
|
||||
exists: true,
|
||||
owner: Some(crate::ids::SPL_TOKEN_PROGRAM_ID.to_string()),
|
||||
lamports: Some(456),
|
||||
kind: Some(crate::KhbbEnrichedAccountKind::PotentialMintAccount),
|
||||
};
|
||||
let result = super::classify_enriched_account_snapshot(&snapshot);
|
||||
assert!(result.is_ok());
|
||||
let event_option = result.expect("classify mint snapshot");
|
||||
assert!(event_option.is_some());
|
||||
match event_option.expect("confirmed mint event") {
|
||||
super::KhbbEnrichedConfirmedEvent::ConfirmedMintAccountActivity(inner) => {
|
||||
assert_eq!(inner.pubkey, "MintPubkey");
|
||||
assert_eq!(inner.context_slot, 200);
|
||||
assert_eq!(inner.lamports, Some(456));
|
||||
}
|
||||
_ => {
|
||||
panic!("expected confirmed mint account activity");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn classify_enriched_snapshot_returns_unknown_token_program_activity() {
|
||||
let snapshot = crate::KhbbEnrichedAccountSnapshot {
|
||||
pubkey: std::string::String::from("UnknownTokenOwnedPubkey"),
|
||||
context_slot: 300,
|
||||
exists: true,
|
||||
owner: Some(crate::ids::SPL_TOKEN_PROGRAM_ID.to_string()),
|
||||
lamports: Some(789),
|
||||
kind: Some(crate::KhbbEnrichedAccountKind::UnknownAccount),
|
||||
};
|
||||
let result = super::classify_enriched_account_snapshot(&snapshot);
|
||||
assert!(result.is_ok());
|
||||
let event_option = result.expect("classify unknown token owned snapshot");
|
||||
assert!(event_option.is_some());
|
||||
match event_option.expect("unknown token owned event") {
|
||||
super::KhbbEnrichedConfirmedEvent::UnknownTokenProgramAccountActivity(inner) => {
|
||||
assert_eq!(inner.pubkey, "UnknownTokenOwnedPubkey");
|
||||
assert_eq!(inner.context_slot, 300);
|
||||
}
|
||||
_ => {
|
||||
panic!("expected unknown token program account activity");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn classify_enriched_snapshot_returns_none_when_account_missing() {
|
||||
let snapshot = crate::KhbbEnrichedAccountSnapshot {
|
||||
pubkey: std::string::String::from("MissingPubkey"),
|
||||
context_slot: 400,
|
||||
exists: false,
|
||||
owner: None,
|
||||
lamports: None,
|
||||
kind: None,
|
||||
};
|
||||
let result = super::classify_enriched_account_snapshot(&snapshot);
|
||||
assert!(result.is_ok());
|
||||
assert!(result.expect("classify missing snapshot").is_none());
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ mod domain_classifier;
|
||||
mod ids;
|
||||
mod heuristics;
|
||||
mod account_enrichment;
|
||||
mod enriched_classifier;
|
||||
|
||||
/// Runs the listener application bootstrap workflow.
|
||||
pub use crate::app::run_listener_app;
|
||||
@@ -118,3 +119,11 @@ pub use crate::heuristics::KhbbPotentialTokenBootstrapActivitySignal;
|
||||
pub use crate::account_enrichment::KhbbEnrichedAccountKind;
|
||||
/// Minimal enriched account snapshot.
|
||||
pub use crate::account_enrichment::KhbbEnrichedAccountSnapshot;
|
||||
/// Confirmed or refined event derived from an enriched account snapshot.
|
||||
pub use crate::enriched_classifier::KhbbEnrichedConfirmedEvent;
|
||||
/// Confirmed token account activity.
|
||||
pub use crate::enriched_classifier::KhbbConfirmedTokenAccountActivityEvent;
|
||||
/// Confirmed mint account activity.
|
||||
pub use crate::enriched_classifier::KhbbConfirmedMintAccountActivityEvent;
|
||||
/// Unknown token-program-owned account activity.
|
||||
pub use crate::enriched_classifier::KhbbUnknownTokenProgramAccountActivityEvent;
|
||||
|
||||
@@ -645,7 +645,7 @@ pub async fn run_listener_runtime(
|
||||
&classified.pubkey,
|
||||
&response_value,
|
||||
);
|
||||
match enrichment_result {
|
||||
match enrichment_result {
|
||||
Ok(snapshot) => {
|
||||
tracing::trace!(
|
||||
listener_session_id = session.id,
|
||||
@@ -657,6 +657,51 @@ pub async fn run_listener_runtime(
|
||||
kind = ?snapshot.kind,
|
||||
"enriched token program account snapshot"
|
||||
);
|
||||
let confirmed_result =
|
||||
crate::enriched_classifier::classify_enriched_account_snapshot(
|
||||
&snapshot,
|
||||
);
|
||||
match confirmed_result {
|
||||
Ok(Some(crate::KhbbEnrichedConfirmedEvent::ConfirmedTokenAccountActivity(inner))) => {
|
||||
tracing::trace!(
|
||||
listener_session_id = session.id,
|
||||
pubkey = %inner.pubkey,
|
||||
context_slot = inner.context_slot,
|
||||
owner = ?inner.owner,
|
||||
lamports = ?inner.lamports,
|
||||
"confirmed token account activity event"
|
||||
);
|
||||
}
|
||||
Ok(Some(crate::KhbbEnrichedConfirmedEvent::ConfirmedMintAccountActivity(inner))) => {
|
||||
tracing::trace!(
|
||||
listener_session_id = session.id,
|
||||
pubkey = %inner.pubkey,
|
||||
context_slot = inner.context_slot,
|
||||
owner = ?inner.owner,
|
||||
lamports = ?inner.lamports,
|
||||
"confirmed mint account activity event"
|
||||
);
|
||||
}
|
||||
Ok(Some(crate::KhbbEnrichedConfirmedEvent::UnknownTokenProgramAccountActivity(inner))) => {
|
||||
tracing::trace!(
|
||||
listener_session_id = session.id,
|
||||
pubkey = %inner.pubkey,
|
||||
context_slot = inner.context_slot,
|
||||
owner = ?inner.owner,
|
||||
lamports = ?inner.lamports,
|
||||
"unknown token-program-owned account activity event"
|
||||
);
|
||||
}
|
||||
Ok(None) => {}
|
||||
Err(error) => {
|
||||
tracing::error!(
|
||||
listener_session_id = session.id,
|
||||
error = %error,
|
||||
pubkey = %classified.pubkey,
|
||||
"failed to classify enriched account snapshot"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::error!(
|
||||
@@ -798,6 +843,51 @@ pub async fn run_listener_runtime(
|
||||
kind = ?snapshot.kind,
|
||||
"enriched token program account snapshot"
|
||||
);
|
||||
let confirmed_result =
|
||||
crate::enriched_classifier::classify_enriched_account_snapshot(
|
||||
&snapshot,
|
||||
);
|
||||
match confirmed_result {
|
||||
Ok(Some(crate::KhbbEnrichedConfirmedEvent::ConfirmedTokenAccountActivity(inner))) => {
|
||||
tracing::trace!(
|
||||
listener_session_id = session.id,
|
||||
pubkey = %inner.pubkey,
|
||||
context_slot = inner.context_slot,
|
||||
owner = ?inner.owner,
|
||||
lamports = ?inner.lamports,
|
||||
"confirmed token account activity event"
|
||||
);
|
||||
}
|
||||
Ok(Some(crate::KhbbEnrichedConfirmedEvent::ConfirmedMintAccountActivity(inner))) => {
|
||||
tracing::trace!(
|
||||
listener_session_id = session.id,
|
||||
pubkey = %inner.pubkey,
|
||||
context_slot = inner.context_slot,
|
||||
owner = ?inner.owner,
|
||||
lamports = ?inner.lamports,
|
||||
"confirmed mint account activity event"
|
||||
);
|
||||
}
|
||||
Ok(Some(crate::KhbbEnrichedConfirmedEvent::UnknownTokenProgramAccountActivity(inner))) => {
|
||||
tracing::trace!(
|
||||
listener_session_id = session.id,
|
||||
pubkey = %inner.pubkey,
|
||||
context_slot = inner.context_slot,
|
||||
owner = ?inner.owner,
|
||||
lamports = ?inner.lamports,
|
||||
"unknown token-program-owned account activity event"
|
||||
);
|
||||
}
|
||||
Ok(None) => {}
|
||||
Err(error) => {
|
||||
tracing::error!(
|
||||
listener_session_id = session.id,
|
||||
error = %error,
|
||||
pubkey = %classified.pubkey,
|
||||
"failed to classify enriched account snapshot"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::error!(
|
||||
|
||||
Reference in New Issue
Block a user