This commit is contained in:
2026-04-18 22:59:32 +02:00
parent 6dab32d4c5
commit f08dfbd611
4 changed files with 316 additions and 2 deletions

View File

@@ -8,7 +8,7 @@ members = [
] ]
[workspace.package] [workspace.package]
version = "0.5.4" version = "0.5.5"
edition = "2024" edition = "2024"
license = "MIT" license = "MIT"
repository = "https://git.sasedev.com/Sasedev/khadhroony-bobot" repository = "https://git.sasedev.com/Sasedev/khadhroony-bobot"

View 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());
}
}

View File

@@ -25,6 +25,7 @@ mod domain_classifier;
mod ids; mod ids;
mod heuristics; mod heuristics;
mod account_enrichment; mod account_enrichment;
mod enriched_classifier;
/// Runs the listener application bootstrap workflow. /// Runs the listener application bootstrap workflow.
pub use crate::app::run_listener_app; pub use crate::app::run_listener_app;
@@ -118,3 +119,11 @@ pub use crate::heuristics::KhbbPotentialTokenBootstrapActivitySignal;
pub use crate::account_enrichment::KhbbEnrichedAccountKind; pub use crate::account_enrichment::KhbbEnrichedAccountKind;
/// Minimal enriched account snapshot. /// Minimal enriched account snapshot.
pub use crate::account_enrichment::KhbbEnrichedAccountSnapshot; 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;

View File

@@ -657,6 +657,51 @@ pub async fn run_listener_runtime(
kind = ?snapshot.kind, kind = ?snapshot.kind,
"enriched token program account snapshot" "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) => { Err(error) => {
tracing::error!( tracing::error!(
@@ -798,6 +843,51 @@ pub async fn run_listener_runtime(
kind = ?snapshot.kind, kind = ?snapshot.kind,
"enriched token program account snapshot" "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) => { Err(error) => {
tracing::error!( tracing::error!(