0.7.27 +Refactor

This commit is contained in:
2026-05-10 00:33:01 +02:00
parent cb2e8e7096
commit 1f0137b9de
261 changed files with 12308 additions and 8928 deletions

View File

@@ -7,7 +7,7 @@
/// One transaction resolution request built from a WebSocket notification.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct KbTransactionResolutionRequest {
pub struct TransactionResolutionRequest {
/// Transaction signature to resolve.
pub signature: std::string::String,
/// Notification method that triggered the request.
@@ -22,20 +22,20 @@ pub struct KbTransactionResolutionRequest {
/// One forwarded WebSocket notification envelope for transaction resolution.
#[derive(Debug, Clone)]
pub struct KbWsTransactionResolutionEnvelope {
pub struct WsTransactionResolutionEnvelope {
/// Optional source endpoint logical name.
pub endpoint_name: std::option::Option<std::string::String>,
/// Raw JSON-RPC notification.
pub notification: crate::KbJsonRpcWsNotification,
pub notification: crate::JsonRpcWsNotification,
/// Optional matched subscription metadata.
pub subscription: std::option::Option<crate::WsSubscriptionInfo>,
}
impl KbWsTransactionResolutionEnvelope {
impl WsTransactionResolutionEnvelope {
/// Creates a new transaction-resolution envelope.
pub fn new(
endpoint_name: std::option::Option<std::string::String>,
notification: crate::KbJsonRpcWsNotification,
notification: crate::JsonRpcWsNotification,
subscription: std::option::Option<crate::WsSubscriptionInfo>,
) -> Self {
return Self {
@@ -48,7 +48,7 @@ impl KbWsTransactionResolutionEnvelope {
/// Result of one transaction resolution pass.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub enum KbTransactionResolutionOutcome {
pub enum TransactionResolutionOutcome {
/// The notification does not produce a transaction resolution request.
Ignored,
/// The transaction was successfully resolved and persisted.
@@ -80,7 +80,7 @@ pub enum KbTransactionResolutionOutcome {
/// Runtime statistics for one transaction resolution relay worker.
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
pub struct KbWsTransactionResolutionRelayStats {
pub struct WsTransactionResolutionRelayStats {
/// Number of received envelopes.
pub received_count: u64,
/// Number of ignored envelopes.
@@ -95,45 +95,44 @@ pub struct KbWsTransactionResolutionRelayStats {
/// Transaction resolution service.
#[derive(Debug, Clone)]
pub struct KbTransactionResolutionService {
pub struct TransactionResolutionService {
http_pool: std::sync::Arc<crate::HttpEndpointPool>,
persistence: crate::KbDetectionPersistenceService,
persistence: crate::DetectionPersistenceService,
http_role: std::string::String,
transaction_model: crate::KbTransactionModelService,
dex_decode_service: crate::KbDexDecodeService,
dex_detect_service: crate::KbDexDetectService,
launch_origin_service: crate::KbLaunchOriginService,
pool_origin_service: crate::KbPoolOriginService,
wallet_observation_service: crate::KbWalletObservationService,
trade_aggregation_service: crate::KbTradeAggregationService,
wallet_holding_observation_service: crate::KbWalletHoldingObservationService,
pair_candle_aggregation_service: crate::KbPairCandleAggregationService,
pair_analytic_signal_service: crate::KbPairAnalyticSignalService,
transaction_model: crate::TransactionModelService,
dex_decode_service: crate::DexDecodeService,
dex_detect_service: crate::DexDetectService,
launch_origin_service: crate::LaunchOriginService,
pool_origin_service: crate::PoolOriginService,
wallet_observation_service: crate::WalletObservationService,
trade_aggregation_service: crate::TradeAggregationService,
wallet_holding_observation_service: crate::WalletHoldingObservationService,
pair_candle_aggregation_service: crate::PairCandleAggregationService,
pair_analytic_signal_service: crate::PairAnalyticSignalService,
resolved_signatures:
std::sync::Arc<tokio::sync::Mutex<std::collections::HashSet<std::string::String>>>,
}
impl KbTransactionResolutionService {
impl TransactionResolutionService {
/// Creates a new transaction resolution service.
pub fn new(
http_pool: std::sync::Arc<crate::HttpEndpointPool>,
database: std::sync::Arc<crate::KbDatabase>,
database: std::sync::Arc<crate::Database>,
http_role: std::string::String,
) -> Self {
let persistence = crate::KbDetectionPersistenceService::new(database.clone());
let transaction_model = crate::KbTransactionModelService::new(database.clone());
let dex_decode_service = crate::KbDexDecodeService::new(database.clone());
let dex_detect_service = crate::KbDexDetectService::new(database.clone());
let launch_origin_service = crate::KbLaunchOriginService::new(database.clone());
let pool_origin_service = crate::KbPoolOriginService::new(database.clone());
let wallet_observation_service = crate::KbWalletObservationService::new(database.clone());
let trade_aggregation_service = crate::KbTradeAggregationService::new(database.clone());
let persistence = crate::DetectionPersistenceService::new(database.clone());
let transaction_model = crate::TransactionModelService::new(database.clone());
let dex_decode_service = crate::DexDecodeService::new(database.clone());
let dex_detect_service = crate::DexDetectService::new(database.clone());
let launch_origin_service = crate::LaunchOriginService::new(database.clone());
let pool_origin_service = crate::PoolOriginService::new(database.clone());
let wallet_observation_service = crate::WalletObservationService::new(database.clone());
let trade_aggregation_service = crate::TradeAggregationService::new(database.clone());
let wallet_holding_observation_service =
crate::KbWalletHoldingObservationService::new(database.clone());
crate::WalletHoldingObservationService::new(database.clone());
let pair_candle_aggregation_service =
crate::KbPairCandleAggregationService::new(database.clone());
let pair_analytic_signal_service =
crate::KbPairAnalyticSignalService::new(database.clone());
crate::PairCandleAggregationService::new(database.clone());
let pair_analytic_signal_service = crate::PairAnalyticSignalService::new(database.clone());
return Self {
http_pool,
persistence,
@@ -155,15 +154,15 @@ impl KbTransactionResolutionService {
}
/// Returns the persistence façade used by the resolver.
pub fn persistence(&self) -> &crate::KbDetectionPersistenceService {
pub fn persistence(&self) -> &crate::DetectionPersistenceService {
return &self.persistence;
}
/// Builds one transaction resolution request from one WS envelope.
pub fn try_build_request_from_ws_envelope(
&self,
envelope: &crate::KbWsTransactionResolutionEnvelope,
) -> std::option::Option<crate::KbTransactionResolutionRequest> {
envelope: &crate::WsTransactionResolutionEnvelope,
) -> std::option::Option<crate::TransactionResolutionRequest> {
let method = envelope.notification.method.as_str();
if method != "logsNotification"
&& method != "signatureNotification"
@@ -172,13 +171,13 @@ impl KbTransactionResolutionService {
return None;
}
let signature_option =
kb_extract_resolution_signature(&envelope.notification, envelope.subscription.as_ref());
extract_resolution_signature(&envelope.notification, envelope.subscription.as_ref());
let signature = match signature_option {
Some(signature) => signature,
None => return None,
};
let slot_hint = kb_extract_resolution_slot(&envelope.notification);
return Some(crate::KbTransactionResolutionRequest {
let slot_hint = extract_resolution_slot(&envelope.notification);
return Some(crate::TransactionResolutionRequest {
signature,
trigger_method: envelope.notification.method.clone(),
source_endpoint_name: envelope.endpoint_name.clone(),
@@ -195,17 +194,17 @@ impl KbTransactionResolutionService {
/// Processes one forwarded WS envelope.
pub async fn process_ws_envelope(
&self,
envelope: &crate::KbWsTransactionResolutionEnvelope,
) -> Result<crate::KbTransactionResolutionOutcome, crate::KbError> {
envelope: &crate::WsTransactionResolutionEnvelope,
) -> Result<crate::TransactionResolutionOutcome, crate::Error> {
let request_option = self.try_build_request_from_ws_envelope(envelope);
let request = match request_option {
Some(request) => request,
None => return Ok(crate::KbTransactionResolutionOutcome::Ignored),
None => return Ok(crate::TransactionResolutionOutcome::Ignored),
};
{
let resolved_guard = self.resolved_signatures.lock().await;
if resolved_guard.contains(request.signature.as_str()) {
return Ok(crate::KbTransactionResolutionOutcome::Ignored);
return Ok(crate::TransactionResolutionOutcome::Ignored);
}
}
let outcome_result = self.resolve_request(&request).await;
@@ -217,31 +216,31 @@ impl KbTransactionResolutionService {
Ok(signal_id) => signal_id,
Err(signal_error) => return Err(signal_error),
};
return Ok(crate::KbTransactionResolutionOutcome::ErrorSignaled {
return Ok(crate::TransactionResolutionOutcome::ErrorSignaled {
signature: request.signature.clone(),
signal_id,
});
},
};
match &outcome {
crate::KbTransactionResolutionOutcome::Resolved { signature, .. } => {
crate::TransactionResolutionOutcome::Resolved { signature, .. } => {
let mut resolved_guard = self.resolved_signatures.lock().await;
resolved_guard.insert(signature.clone());
},
crate::KbTransactionResolutionOutcome::Missing { signature, .. } => {
crate::TransactionResolutionOutcome::Missing { signature, .. } => {
let mut resolved_guard = self.resolved_signatures.lock().await;
resolved_guard.insert(signature.clone());
},
crate::KbTransactionResolutionOutcome::Ignored => {},
crate::KbTransactionResolutionOutcome::ErrorSignaled { .. } => {},
crate::TransactionResolutionOutcome::Ignored => {},
crate::TransactionResolutionOutcome::ErrorSignaled { .. } => {},
}
return Ok(outcome);
}
async fn resolve_request(
&self,
request: &crate::KbTransactionResolutionRequest,
) -> Result<crate::KbTransactionResolutionOutcome, crate::KbError> {
request: &crate::TransactionResolutionRequest,
) -> Result<crate::TransactionResolutionOutcome, crate::Error> {
let config = Some(serde_json::json!({
"encoding": "jsonParsed",
"maxSupportedTransactionVersion": 0
@@ -270,9 +269,9 @@ impl KbTransactionResolutionService {
});
let observation_id_result = self
.persistence
.record_observation(&crate::KbDetectionObservationInput::new(
.record_observation(&crate::DetectionObservationInput::new(
"http.transaction_resolution".to_string(),
crate::KbObservationSourceKind::HttpRpc,
crate::ObservationSourceKind::HttpRpc,
request.source_endpoint_name.clone(),
request.signature.clone(),
request.slot_hint,
@@ -285,9 +284,9 @@ impl KbTransactionResolutionService {
};
let signal_id_result = self
.persistence
.record_signal(&crate::KbDetectionSignalInput::new(
.record_signal(&crate::DetectionSignalInput::new(
"signal.transaction_resolution.missing".to_string(),
crate::KbAnalysisSignalSeverity::Medium,
crate::AnalysisSignalSeverity::Medium,
request.signature.clone(),
Some(observation_id),
None,
@@ -298,7 +297,7 @@ impl KbTransactionResolutionService {
Ok(signal_id) => signal_id,
Err(error) => return Err(error),
};
return Ok(crate::KbTransactionResolutionOutcome::Missing {
return Ok(crate::TransactionResolutionOutcome::Missing {
signature: request.signature.clone(),
observation_id,
signal_id,
@@ -422,9 +421,9 @@ impl KbTransactionResolutionService {
});
let observation_id_result = self
.persistence
.record_observation(&crate::KbDetectionObservationInput::new(
.record_observation(&crate::DetectionObservationInput::new(
"http.transaction_resolution".to_string(),
crate::KbObservationSourceKind::HttpRpc,
crate::ObservationSourceKind::HttpRpc,
request.source_endpoint_name.clone(),
request.signature.clone(),
resolved_slot,
@@ -437,9 +436,9 @@ impl KbTransactionResolutionService {
};
let signal_id_result = self
.persistence
.record_signal(&crate::KbDetectionSignalInput::new(
.record_signal(&crate::DetectionSignalInput::new(
"signal.transaction_resolution.resolved".to_string(),
crate::KbAnalysisSignalSeverity::Low,
crate::AnalysisSignalSeverity::Low,
request.signature.clone(),
Some(observation_id),
None,
@@ -450,7 +449,7 @@ impl KbTransactionResolutionService {
Ok(signal_id) => signal_id,
Err(error) => return Err(error),
};
return Ok(crate::KbTransactionResolutionOutcome::Resolved {
return Ok(crate::TransactionResolutionOutcome::Resolved {
signature: request.signature.clone(),
observation_id,
signal_id,
@@ -459,9 +458,9 @@ impl KbTransactionResolutionService {
async fn record_resolution_error_signal(
&self,
request: &crate::KbTransactionResolutionRequest,
error: &crate::KbError,
) -> Result<i64, crate::KbError> {
request: &crate::TransactionResolutionRequest,
error: &crate::Error,
) -> Result<i64, crate::Error> {
let payload = serde_json::json!({
"status": "error",
"signature": request.signature.clone(),
@@ -473,9 +472,9 @@ impl KbTransactionResolutionService {
});
return self
.persistence
.record_signal(&crate::KbDetectionSignalInput::new(
.record_signal(&crate::DetectionSignalInput::new(
"signal.transaction_resolution.error".to_string(),
crate::KbAnalysisSignalSeverity::High,
crate::AnalysisSignalSeverity::High,
request.signature.clone(),
None,
None,
@@ -488,13 +487,13 @@ impl KbTransactionResolutionService {
/// Relay that consumes forwarded WS notifications and resolves matching
/// signatures through HTTP `getTransaction`.
#[derive(Debug, Clone)]
pub struct KbWsTransactionResolutionRelay {
resolver: crate::KbTransactionResolutionService,
pub struct WsTransactionResolutionRelay {
resolver: crate::TransactionResolutionService,
}
impl KbWsTransactionResolutionRelay {
impl WsTransactionResolutionRelay {
/// Creates a new transaction resolution relay.
pub fn new(resolver: crate::KbTransactionResolutionService) -> Self {
pub fn new(resolver: crate::TransactionResolutionService) -> Self {
return Self { resolver };
}
@@ -502,8 +501,8 @@ impl KbWsTransactionResolutionRelay {
pub fn channel(
capacity: usize,
) -> (
tokio::sync::mpsc::Sender<crate::KbWsTransactionResolutionEnvelope>,
tokio::sync::mpsc::Receiver<crate::KbWsTransactionResolutionEnvelope>,
tokio::sync::mpsc::Sender<crate::WsTransactionResolutionEnvelope>,
tokio::sync::mpsc::Receiver<crate::WsTransactionResolutionEnvelope>,
) {
return tokio::sync::mpsc::channel(capacity);
}
@@ -511,18 +510,18 @@ impl KbWsTransactionResolutionRelay {
/// Processes one forwarded envelope.
pub async fn process_envelope(
&self,
envelope: &crate::KbWsTransactionResolutionEnvelope,
) -> Result<crate::KbTransactionResolutionOutcome, crate::KbError> {
envelope: &crate::WsTransactionResolutionEnvelope,
) -> Result<crate::TransactionResolutionOutcome, crate::Error> {
return self.resolver.process_ws_envelope(envelope).await;
}
/// Spawns one background relay worker.
pub fn spawn(
self,
mut receiver: tokio::sync::mpsc::Receiver<crate::KbWsTransactionResolutionEnvelope>,
) -> tokio::task::JoinHandle<crate::KbWsTransactionResolutionRelayStats> {
mut receiver: tokio::sync::mpsc::Receiver<crate::WsTransactionResolutionEnvelope>,
) -> tokio::task::JoinHandle<crate::WsTransactionResolutionRelayStats> {
return tokio::spawn(async move {
let mut stats = crate::KbWsTransactionResolutionRelayStats::default();
let mut stats = crate::WsTransactionResolutionRelayStats::default();
loop {
let recv_result = receiver.recv().await;
let envelope = match recv_result {
@@ -536,7 +535,7 @@ impl KbWsTransactionResolutionRelay {
Err(error) => {
stats.error_count += 1;
tracing::error!(
target: "kb_lib::tx_resolution",
target: "tx_resolution",
"transaction resolution relay failed endpoint_name={:?}: {}",
envelope.endpoint_name,
error
@@ -545,16 +544,16 @@ impl KbWsTransactionResolutionRelay {
},
};
match outcome {
crate::KbTransactionResolutionOutcome::Ignored => {
crate::TransactionResolutionOutcome::Ignored => {
stats.ignored_count += 1;
},
crate::KbTransactionResolutionOutcome::Resolved { .. } => {
crate::TransactionResolutionOutcome::Resolved { .. } => {
stats.resolved_count += 1;
},
crate::KbTransactionResolutionOutcome::Missing { .. } => {
crate::TransactionResolutionOutcome::Missing { .. } => {
stats.missing_count += 1;
},
crate::KbTransactionResolutionOutcome::ErrorSignaled { .. } => {
crate::TransactionResolutionOutcome::ErrorSignaled { .. } => {
stats.error_count += 1;
},
}
@@ -564,8 +563,8 @@ impl KbWsTransactionResolutionRelay {
}
}
fn kb_extract_resolution_signature(
notification: &crate::KbJsonRpcWsNotification,
fn extract_resolution_signature(
notification: &crate::JsonRpcWsNotification,
subscription: std::option::Option<&crate::WsSubscriptionInfo>,
) -> std::option::Option<std::string::String> {
let result = &notification.params.result;
@@ -589,8 +588,8 @@ fn kb_extract_resolution_signature(
return None;
}
fn kb_extract_resolution_slot(
notification: &crate::KbJsonRpcWsNotification,
fn extract_resolution_slot(
notification: &crate::JsonRpcWsNotification,
) -> std::option::Option<u64> {
let result = &notification.params.result;
if let Some(slot) = result.get("slot").and_then(serde_json::Value::as_u64) {