refactor: simplify GasFeeStrategy from singleton to static methods

- Replace OnceLock singleton pattern with LazyLock static storage
- Convert instance methods to static methods for better performance
- Remove enabled/disabled strategy type management complexity
- Update parallel execution to use new static API
This commit is contained in:
ysq
2025-09-19 11:35:13 +08:00
parent 006686e8a3
commit e8abb65e2e
2 changed files with 71 additions and 172 deletions
+65 -167
View File
@@ -1,7 +1,7 @@
use crate::swqos::{SwqosType, TradeType}; use crate::swqos::{SwqosType, TradeType};
use arc_swap::ArcSwap; use arc_swap::ArcSwap;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{Arc, OnceLock}; use std::sync::{Arc, LazyLock};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum GasFeeStrategyType { pub enum GasFeeStrategyType {
@@ -23,30 +23,15 @@ pub struct GasFeeStrategyValue {
pub tip: f64, pub tip: f64,
} }
#[derive(Debug)] // 静态存储策略数据
pub struct GasFeeStrategy { static STRATEGIES: LazyLock<
strategies: ArcSwap<HashMap<(SwqosType, TradeType, GasFeeStrategyType), GasFeeStrategyValue>>, ArcSwap<HashMap<(SwqosType, TradeType, GasFeeStrategyType), GasFeeStrategyValue>>,
enabled_types: ArcSwap<HashMap<TradeType, Vec<GasFeeStrategyType>>>, > = LazyLock::new(|| ArcSwap::from_pointee(HashMap::new()));
swqos_disabled_types: ArcSwap<HashMap<(SwqosType, TradeType), Vec<GasFeeStrategyType>>>,
}
static INSTANCE: OnceLock<Arc<GasFeeStrategy>> = OnceLock::new(); pub struct GasFeeStrategy;
impl GasFeeStrategy { impl GasFeeStrategy {
pub fn instance() -> Arc<GasFeeStrategy> {
INSTANCE.get_or_init(|| Arc::new(GasFeeStrategy::new())).clone()
}
fn new() -> Self {
Self {
strategies: ArcSwap::new(Arc::new(HashMap::new())),
enabled_types: ArcSwap::new(Arc::new(HashMap::new())),
swqos_disabled_types: ArcSwap::new(Arc::new(HashMap::new())),
}
}
pub fn add_high_low_fee_strategies( pub fn add_high_low_fee_strategies(
&self,
swqos_types: &[SwqosType], swqos_types: &[SwqosType],
trade_type: TradeType, trade_type: TradeType,
cu_limit: u32, cu_limit: u32,
@@ -54,8 +39,11 @@ impl GasFeeStrategy {
high_cu_price: u64, high_cu_price: u64,
low_tip: f64, low_tip: f64,
high_tip: f64, high_tip: f64,
) -> &Self { ) {
self.strategies.rcu(|current_map| { for swqos_type in swqos_types {
GasFeeStrategy::remove_strategy(*swqos_type, trade_type);
}
STRATEGIES.rcu(|current_map| {
let mut new_map = (**current_map).clone(); let mut new_map = (**current_map).clone();
for swqos_type in swqos_types { for swqos_type in swqos_types {
if swqos_type.eq(&SwqosType::Default) { if swqos_type.eq(&SwqosType::Default) {
@@ -72,11 +60,9 @@ impl GasFeeStrategy {
} }
Arc::new(new_map) Arc::new(new_map)
}); });
self
} }
pub fn add_high_low_fee_strategy( pub fn add_high_low_fee_strategy(
&self,
swqos_type: SwqosType, swqos_type: SwqosType,
trade_type: TradeType, trade_type: TradeType,
cu_limit: u32, cu_limit: u32,
@@ -84,11 +70,12 @@ impl GasFeeStrategy {
high_cu_price: u64, high_cu_price: u64,
low_tip: f64, low_tip: f64,
high_tip: f64, high_tip: f64,
) -> &Self { ) {
if swqos_type.eq(&SwqosType::Default) { if swqos_type.eq(&SwqosType::Default) {
return self; return;
} }
self.strategies.rcu(|current_map| { GasFeeStrategy::remove_strategy(swqos_type, trade_type);
STRATEGIES.rcu(|current_map| {
let mut new_map = (**current_map).clone(); let mut new_map = (**current_map).clone();
new_map.insert( new_map.insert(
(swqos_type, trade_type, GasFeeStrategyType::LowTipHighCuPrice), (swqos_type, trade_type, GasFeeStrategyType::LowTipHighCuPrice),
@@ -100,18 +87,19 @@ impl GasFeeStrategy {
); );
Arc::new(new_map) Arc::new(new_map)
}); });
self
} }
pub fn add_default_fee_strategies( pub fn add_default_fee_strategies(
&self,
swqos_types: &[SwqosType], swqos_types: &[SwqosType],
trade_type: TradeType, trade_type: TradeType,
cu_price: u64, cu_price: u64,
tip: f64, tip: f64,
cu_limit: u32, cu_limit: u32,
) -> &Self { ) {
self.strategies.rcu(|current_map| { for swqos_type in swqos_types {
GasFeeStrategy::remove_strategy(*swqos_type, trade_type);
}
STRATEGIES.rcu(|current_map| {
let mut new_map = (**current_map).clone(); let mut new_map = (**current_map).clone();
for swqos_type in swqos_types { for swqos_type in swqos_types {
new_map.insert( new_map.insert(
@@ -121,18 +109,17 @@ impl GasFeeStrategy {
} }
Arc::new(new_map) Arc::new(new_map)
}); });
self
} }
pub fn add_default_fee_strategy( pub fn add_default_fee_strategy(
&self,
swqos_type: SwqosType, swqos_type: SwqosType,
trade_type: TradeType, trade_type: TradeType,
cu_price: u64, cu_price: u64,
tip: f64, tip: f64,
cu_limit: u32, cu_limit: u32,
) -> &Self { ) {
self.strategies.rcu(|current_map| { GasFeeStrategy::remove_strategy(swqos_type, trade_type);
STRATEGIES.rcu(|current_map| {
let mut new_map = (**current_map).clone(); let mut new_map = (**current_map).clone();
new_map.insert( new_map.insert(
(swqos_type, trade_type, GasFeeStrategyType::Default), (swqos_type, trade_type, GasFeeStrategyType::Default),
@@ -140,47 +127,22 @@ impl GasFeeStrategy {
); );
Arc::new(new_map) Arc::new(new_map)
}); });
self
} }
pub fn remove_default_fee_strategy( pub fn remove_strategy(swqos_type: SwqosType, trade_type: TradeType) {
&self, STRATEGIES.rcu(|current_map| {
swqos_type: SwqosType,
trade_type: TradeType,
) -> &Self {
self.strategies.rcu(|current_map| {
let mut new_map = (**current_map).clone(); let mut new_map = (**current_map).clone();
new_map.remove(&(swqos_type, trade_type, GasFeeStrategyType::Default)); new_map.remove(&(swqos_type, trade_type, GasFeeStrategyType::Default));
Arc::new(new_map)
});
self
}
pub fn remove_high_low_fee_strategy(
&self,
swqos_type: SwqosType,
trade_type: TradeType,
) -> &Self {
self.strategies.rcu(|current_map| {
let mut new_map = (**current_map).clone();
new_map.remove(&(swqos_type, trade_type, GasFeeStrategyType::LowTipHighCuPrice)); new_map.remove(&(swqos_type, trade_type, GasFeeStrategyType::LowTipHighCuPrice));
new_map.remove(&(swqos_type, trade_type, GasFeeStrategyType::HighTipLowCuPrice)); new_map.remove(&(swqos_type, trade_type, GasFeeStrategyType::HighTipLowCuPrice));
Arc::new(new_map) Arc::new(new_map)
}); });
self
}
pub fn get_all_strategies(
&self,
) -> HashMap<(SwqosType, TradeType, GasFeeStrategyType), GasFeeStrategyValue> {
(**self.strategies.load()).clone()
} }
pub fn get_strategies( pub fn get_strategies(
&self,
trade_type: TradeType, trade_type: TradeType,
) -> Vec<(SwqosType, GasFeeStrategyType, GasFeeStrategyValue)> { ) -> Vec<(SwqosType, GasFeeStrategyType, GasFeeStrategyValue)> {
let strategies = self.strategies.load(); let strategies = STRATEGIES.load();
let mut result = Vec::new(); let mut result = Vec::new();
let mut swqos_types = std::collections::HashSet::new(); let mut swqos_types = std::collections::HashSet::new();
for (swqos_type, t_type, _) in strategies.keys() { for (swqos_type, t_type, _) in strategies.keys() {
@@ -200,81 +162,8 @@ impl GasFeeStrategy {
result result
} }
pub fn get_available_strategies( pub fn clear() {
&self, STRATEGIES.store(Arc::new(HashMap::new()));
trade_type: TradeType,
) -> Vec<(SwqosType, GasFeeStrategyType, GasFeeStrategyValue)> {
let strategies = self.strategies.load();
let enabled_types = self.get_enabled_strategy_types(trade_type);
let mut result = Vec::new();
let mut swqos_types = std::collections::HashSet::new();
for (swqos_type, t_type, _) in strategies.keys() {
if *t_type == trade_type {
swqos_types.insert(*swqos_type);
}
}
for swqos_type in swqos_types {
let disabled_types = self.get_swqos_disabled_strategy_types(swqos_type, trade_type);
for strategy_type in &enabled_types {
if disabled_types.contains(strategy_type) {
continue;
}
if let Some(strategy_value) =
strategies.get(&(swqos_type, trade_type, *strategy_type))
{
result.push((swqos_type, *strategy_type, *strategy_value));
}
}
}
result
}
pub fn set_enabled_strategy_types(
&self,
trade_type: TradeType,
types: &[GasFeeStrategyType],
) -> &Self {
self.enabled_types.rcu(|current_map| {
let mut new_map = (**current_map).clone();
new_map.insert(trade_type, types.to_vec());
Arc::new(new_map)
});
self
}
pub fn get_enabled_strategy_types(&self, trade_type: TradeType) -> Vec<GasFeeStrategyType> {
let strategies = self.enabled_types.load();
(**strategies).get(&trade_type).cloned().unwrap_or_default()
}
pub fn set_swqos_disabled_strategy_types(
&self,
swqos_type: SwqosType,
trade_type: TradeType,
types: &[GasFeeStrategyType],
) -> &Self {
self.swqos_disabled_types.rcu(|current_map| {
let mut new_map = (**current_map).clone();
new_map.insert((swqos_type, trade_type), types.to_vec());
Arc::new(new_map)
});
self
}
pub fn get_swqos_disabled_strategy_types(
&self,
swqos_type: SwqosType,
trade_type: TradeType,
) -> Vec<GasFeeStrategyType> {
let disabled_strategies = self.swqos_disabled_types.load();
(**disabled_strategies).get(&(swqos_type, trade_type)).cloned().unwrap_or_default()
}
pub fn clear(&self) -> &Self {
self.strategies.store(Arc::new(HashMap::new()));
self.enabled_types.store(Arc::new(HashMap::new()));
self.swqos_disabled_types.store(Arc::new(HashMap::new()));
self
} }
} }
@@ -284,33 +173,42 @@ mod tests {
#[test] #[test]
fn demo() { fn demo() {
GasFeeStrategy::instance() // 给SwqosType::Default 在 Buy 时添加默认策略
// 给SwqosType::Default在 Buy 时添加默认策略 GasFeeStrategy::add_default_fee_strategy(
.add_default_fee_strategy(SwqosType::Default, TradeType::Buy, 100, 0.0001, 10) SwqosType::Default,
// 给SwqosType::Jito在 Buy 时添加高低价策略 TradeType::Buy,
.add_high_low_fee_strategy(SwqosType::Jito, TradeType::Buy, 10, 100, 10000, 0.001, 0.1) 100,
// 给SwqosType::Jito在 Buy 时添加默认策略 0.0001,
.add_default_fee_strategy(SwqosType::Jito, TradeType::Buy, 100, 0.0001, 10) 10,
// 设置在 Buy 时启用策略 - 启用两个高低价策略、默认策略 );
.set_enabled_strategy_types( // 给SwqosType::Jito 在 Buy 时添加高低价策略
TradeType::Buy, GasFeeStrategy::add_high_low_fee_strategy(
&[ SwqosType::Jito,
GasFeeStrategyType::HighTipLowCuPrice, TradeType::Buy,
GasFeeStrategyType::LowTipHighCuPrice, 10,
GasFeeStrategyType::Default, 100,
], 10000,
) 0.001,
// 设置SwqosType::Jito在 Buy 时禁用策略 - 禁用 (默认策略) 0.1,
.set_swqos_disabled_strategy_types( );
SwqosType::Jito, // 获取所有 Buy 策略
TradeType::Buy, let all_strategies = GasFeeStrategy::get_strategies(TradeType::Buy);
&[GasFeeStrategyType::Default], for strategy in all_strategies {
); println!("strategy: {:?}", strategy);
// 获取在 Buy 时可用的策略 }
let strategies = GasFeeStrategy::instance().get_available_strategies(TradeType::Buy); println!("--------------------------------");
println!("strategies: {:?}", strategies); // 给SwqosType::Jito 在 Buy 时添加默认策略(会删除 jito 的高低价策略)
// 获取所有 Buy 策略(包括禁用的) GasFeeStrategy::add_default_fee_strategy(SwqosType::Jito, TradeType::Buy, 100, 0.0001, 10);
let all_strategies = GasFeeStrategy::instance().get_strategies(TradeType::Buy); // 获取所有 Buy 策略
println!("all_strategies: {:?}", all_strategies); let all_strategies = GasFeeStrategy::get_strategies(TradeType::Buy);
for strategy in all_strategies {
println!("strategy: {:?}", strategy);
}
// 删除SwqosType::Jito 在 Buy 时的策略
GasFeeStrategy::remove_strategy(SwqosType::Jito, TradeType::Buy);
// 清空策略
GasFeeStrategy::clear();
println!("--------------------------------");
println!("strategy {:?}", GasFeeStrategy::get_strategies(TradeType::Buy));
} }
} }
+6 -5
View File
@@ -10,9 +10,7 @@ use tokio::task::JoinHandle;
use crate::{ use crate::{
common::GasFeeStrategy, common::GasFeeStrategy,
swqos::{SwqosClient, SwqosType, TradeType}, swqos::{SwqosClient, SwqosType, TradeType},
trading::{ trading::{common::build_transaction, BuyParams, MiddlewareManager, SellParams},
common::build_transaction, BuyParams, SellParams, MiddlewareManager,
},
}; };
pub async fn buy_parallel_execute( pub async fn buy_parallel_execute(
@@ -95,8 +93,11 @@ async fn parallel_execute(
with_tip || matches!(swqos_client.get_swqos_type(), SwqosType::Default) with_tip || matches!(swqos_client.get_swqos_type(), SwqosType::Default)
}) })
.flat_map(|(i, swqos_client)| { .flat_map(|(i, swqos_client)| {
let gas_fee_strategy_configs = GasFeeStrategy::instance() let gas_fee_strategy_configs = GasFeeStrategy::get_strategies(if is_buy {
.get_available_strategies(if is_buy { TradeType::Buy } else { TradeType::Sell }); TradeType::Buy
} else {
TradeType::Sell
});
gas_fee_strategy_configs gas_fee_strategy_configs
.into_iter() .into_iter()
.filter(|config| config.0.eq(&swqos_client.get_swqos_type())) .filter(|config| config.0.eq(&swqos_client.get_swqos_type()))