1
1
use crate :: utils:: convert_account;
2
+ use crate :: utils:: crossbar:: { CrossbarCache , SwbPullFeedMeta } ;
2
3
use crate :: utils:: metrics:: { LendingPoolBankMetrics , MarginfiAccountMetrics , MarginfiGroupMetrics } ;
3
- use crate :: utils:: snapshot:: Snapshot ;
4
4
use crate :: utils:: snapshot:: { AccountRoutingType , BankUpdateRoutingType } ;
5
+ use crate :: utils:: snapshot:: { OracleData , Snapshot } ;
6
+ use crate :: utils:: swb_pull:: overwrite_price_from_sim;
5
7
use anyhow:: Result ;
6
8
use chrono:: { DateTime , Utc } ;
7
9
use envconfig:: Envconfig ;
@@ -112,14 +114,16 @@ pub struct Context {
112
114
account_updates_queue : Arc < Mutex < BTreeMap < u64 , HashMap < Pubkey , AccountUpdate > > > > ,
113
115
latest_slots_with_commitment : Arc < Mutex < BTreeSet < u64 > > > ,
114
116
account_snapshot : Arc < Mutex < Snapshot > > ,
117
+ crossbar_store : Arc < CrossbarCache > ,
115
118
stream_disconnection_count : Arc < AtomicU64 > ,
116
119
update_processing_error_count : Arc < AtomicU64 > ,
117
120
}
118
121
119
122
impl Context {
120
123
pub async fn new ( config : & SnapshotAccountsConfig ) -> Self {
124
+ let rpc_endpoint = format ! ( "{}/{}" , config. rpc_endpoint, config. rpc_token) ;
121
125
let rpc_client = Arc :: new ( RpcClient :: new_with_commitment (
122
- format ! ( "{}/{}" , config . rpc_endpoint, config . rpc_token ) ,
126
+ rpc_endpoint,
123
127
CommitmentConfig {
124
128
commitment : solana_sdk:: commitment_config:: CommitmentLevel :: Finalized ,
125
129
} ,
@@ -132,6 +136,7 @@ impl Context {
132
136
account_updates_queue : Arc :: new ( Mutex :: new ( BTreeMap :: new ( ) ) ) ,
133
137
latest_slots_with_commitment : Arc :: new ( Mutex :: new ( BTreeSet :: new ( ) ) ) ,
134
138
account_snapshot : Arc :: new ( Mutex :: new ( Snapshot :: new ( config. program_id , rpc_client) ) ) ,
139
+ crossbar_store : Arc :: new ( CrossbarCache :: new ( ) ) ,
135
140
stream_disconnection_count : Arc :: new ( AtomicU64 :: new ( 0 ) ) ,
136
141
update_processing_error_count : Arc :: new ( AtomicU64 :: new ( 0 ) ) ,
137
142
}
@@ -188,6 +193,26 @@ pub async fn snapshot_accounts(config: SnapshotAccountsConfig) -> Result<()> {
188
193
snapshot. init ( ) . await . unwrap ( ) ;
189
194
info ! ( "Summary: {snapshot}" ) ;
190
195
196
+ let swb_feed_accounts_and_hashes = snapshot
197
+ . price_feeds
198
+ . iter ( )
199
+ . filter_map ( |( pk, od) | match od {
200
+ OracleData :: SwitchboardPull ( feed) => Some ( ( * pk, hex:: encode ( feed. feed . feed_hash ) ) ) ,
201
+ _ => None ,
202
+ } )
203
+ . collect :: < Vec < _ > > ( ) ;
204
+
205
+ context. crossbar_store . track_feeds (
206
+ swb_feed_accounts_and_hashes
207
+ . into_iter ( )
208
+ . map ( |( feed_address, feed_hash) | SwbPullFeedMeta {
209
+ feed_hash,
210
+ feed_address,
211
+ } )
212
+ . collect :: < Vec < _ > > ( ) ,
213
+ ) ;
214
+ context. crossbar_store . refresh_prices ( ) . await ;
215
+
191
216
snapshot
192
217
. routing_lookup
193
218
. iter ( )
@@ -207,6 +232,26 @@ pub async fn snapshot_accounts(config: SnapshotAccountsConfig) -> Result<()> {
207
232
let geyser_subscription_config = compute_geyser_config ( & config, & non_program_accounts) . await ;
208
233
* context. geyser_subscription_config . lock ( ) . await = ( false , geyser_subscription_config. clone ( ) ) ;
209
234
235
+ let update_crossbar_cache_handle = tokio:: spawn ( {
236
+ let context = context. clone ( ) ;
237
+ async move {
238
+ loop {
239
+ context. crossbar_store . refresh_prices ( ) . await ;
240
+ let mut snapshot = context. account_snapshot . lock ( ) . await ;
241
+ let feeds_per_address: HashMap < Pubkey , crate :: utils:: crossbar:: SimulatedPrice > =
242
+ context. crossbar_store . get_prices_per_address ( ) ;
243
+ for ( address, price) in feeds_per_address {
244
+ if let Some ( od) = snapshot. price_feeds . get_mut ( & address) {
245
+ if let OracleData :: SwitchboardPull ( feed) = od {
246
+ overwrite_price_from_sim ( feed, & price) ;
247
+ }
248
+ }
249
+ }
250
+ tokio:: time:: sleep ( std:: time:: Duration :: from_secs ( 20 ) ) . await ;
251
+ }
252
+ }
253
+ } ) ;
254
+
210
255
let listen_to_updates_handle = tokio:: spawn ( {
211
256
let context = context. clone ( ) ;
212
257
async move { listen_to_updates ( context) . await }
@@ -226,6 +271,7 @@ pub async fn snapshot_accounts(config: SnapshotAccountsConfig) -> Result<()> {
226
271
} ) ;
227
272
228
273
join_all ( [
274
+ update_crossbar_cache_handle,
229
275
listen_to_updates_handle,
230
276
process_account_updates_handle,
231
277
update_account_map_handle,
@@ -239,15 +285,14 @@ pub async fn snapshot_accounts(config: SnapshotAccountsConfig) -> Result<()> {
239
285
async fn listen_to_updates ( ctx : Arc < Context > ) {
240
286
loop {
241
287
info ! ( "Connecting geyser client" ) ;
242
- let geyser_client_connection_result = GeyserGrpcClient :: connect_with_timeout (
243
- ctx. config . rpc_endpoint . to_string ( ) ,
244
- Some ( ctx. config . rpc_token . to_string ( ) ) ,
245
- None ,
246
- Some ( Duration :: from_secs ( 10 ) ) ,
247
- Some ( Duration :: from_secs ( 10 ) ) ,
248
- false ,
249
- )
250
- . await ;
288
+ let geyser_client_connection_result =
289
+ GeyserGrpcClient :: build_from_shared ( ctx. config . rpc_endpoint . to_string ( ) )
290
+ . unwrap ( )
291
+ . x_token ( Some ( ctx. config . rpc_token . to_string ( ) ) )
292
+ . unwrap ( )
293
+ . connect ( )
294
+ . await ;
295
+
251
296
info ! ( "Connected" ) ;
252
297
253
298
let mut geyser_client = match geyser_client_connection_result {
0 commit comments