1
1
//! Syncing committee info from the KeyManager contract
2
2
3
3
use std:: pin:: Pin ;
4
- use std:: task:: { Context , Poll } ;
5
4
6
5
use alloy:: {
7
6
eips:: BlockNumberOrTag ,
8
7
primitives:: Address ,
9
8
providers:: { Provider , ProviderBuilder } ,
10
- rpc:: types:: Filter ,
11
- sol_types:: SolEvent ,
12
- transports:: ws:: WsConnect ,
13
9
} ;
14
10
use anyhow:: { Context as AnyhowContext , Result } ;
15
11
use cliquenet:: AddressableCommittee ;
@@ -18,11 +14,15 @@ use itertools::{Itertools, izip};
18
14
use multisig:: { Committee , CommitteeId , x25519} ;
19
15
use timeboost_config:: { CERTIFIER_PORT_OFFSET , DECRYPTER_PORT_OFFSET , ParentChain } ;
20
16
use timeboost_contract:: KeyManager :: { self , CommitteeCreated } ;
17
+ use timeboost_contract:: provider:: PubSubProvider ;
21
18
use timeboost_crypto:: prelude:: DkgEncKey ;
22
19
use timeboost_types:: { KeyStore , Timestamp } ;
23
20
use tracing:: error;
24
21
use url:: Url ;
25
22
23
+ /// Type alias for the committee stream
24
+ pub type NewCommitteeStream = Pin < Box < dyn Stream < Item = CommitteeInfo > > > ;
25
+
26
26
/// The committee info stored on the KeyManager contract, a subset of [`CommitteeConfig`]
27
27
/// Keys and hosts are ordered in the same as they were registered (with KeyId from 0..n)
28
28
#[ derive( Debug , Clone ) ]
@@ -39,7 +39,14 @@ impl CommitteeInfo {
39
39
/// Fetch the committee info for `committee_id` from `key_manager_addr` on chain
40
40
pub async fn fetch ( rpc : Url , key_manager_addr : Address , committee_id : u64 ) -> Result < Self > {
41
41
let provider = ProviderBuilder :: new ( ) . connect_http ( rpc) ;
42
+ Self :: fetch_with ( provider, key_manager_addr, committee_id) . await
43
+ }
42
44
45
+ pub ( crate ) async fn fetch_with (
46
+ provider : impl Provider ,
47
+ key_manager_addr : Address ,
48
+ committee_id : u64 ,
49
+ ) -> Result < Self > {
43
50
let contract = KeyManager :: new ( key_manager_addr, & provider) ;
44
51
let c = contract. getCommitteeById ( committee_id) . call ( ) . await ?;
45
52
@@ -71,6 +78,10 @@ impl CommitteeInfo {
71
78
} )
72
79
}
73
80
81
+ pub fn id ( & self ) -> CommitteeId {
82
+ self . id
83
+ }
84
+
74
85
pub fn effective_timestamp ( & self ) -> Timestamp {
75
86
self . timestamp
76
87
}
@@ -138,64 +149,44 @@ impl CommitteeInfo {
138
149
. map ( |( i, k) | ( i as u8 , k. clone ( ) ) ) ,
139
150
)
140
151
}
141
- }
142
152
143
- /// An pubsub-provider-holding event stream. (the pubsub will close on drop)
144
- pub struct NewCommitteeStream {
145
- _provider : Box < dyn Provider > ,
146
- inner : Pin < Box < dyn Stream < Item = u64 > + Send > > ,
147
- }
148
-
149
- impl Stream for NewCommitteeStream {
150
- type Item = u64 ;
151
-
152
- fn poll_next ( mut self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Option < Self :: Item > > {
153
- self . inner . as_mut ( ) . poll_next ( cx)
154
- }
155
- }
156
-
157
- impl NewCommitteeStream {
158
- pub async fn create ( config : & ParentChain ) -> Result < Self > {
159
- // setup the websocket for contract event stream
160
- let ws = WsConnect :: new ( config. ws_url . clone ( ) ) ;
161
- // spawn the pubsub service (and backend) and the frontend is registered at the provider
162
- let provider = ProviderBuilder :: new ( )
163
- . connect_pubsub_with ( ws)
153
+ /// subscribe an event stream
154
+ pub async fn new_committee_stream (
155
+ provider : & PubSubProvider ,
156
+ start_ts : Timestamp ,
157
+ config : & ParentChain ,
158
+ ) -> Result < NewCommitteeStream > {
159
+ let from_block = provider
160
+ . get_block_number_by_timestamp ( start_ts. into ( ) )
161
+ . await ?
162
+ . unwrap_or_default ( ) ;
163
+ let events = provider
164
+ . event_stream :: < CommitteeCreated > (
165
+ config. key_manager_contract ,
166
+ BlockNumberOrTag :: Number ( from_block) ,
167
+ )
164
168
. await
165
- . map_err ( |err | {
166
- error ! ( ?err , "event pubsub failed to start" ) ;
167
- err
169
+ . map_err ( |e | {
170
+ error ! ( "Failed to create CommitteeCreated stream: {:?}" , e ) ;
171
+ e
168
172
} ) ?;
169
173
170
- let chain_id = config. id ;
171
- let tag = if chain_id == 31337 || chain_id == 1337 {
172
- // local test chain, we start scanning from the genesis
173
- BlockNumberOrTag :: Number ( 0 )
174
- } else {
175
- config. block_tag
176
- } ;
177
-
178
- let filter = Filter :: new ( )
179
- . address ( config. key_manager_contract )
180
- . event ( KeyManager :: CommitteeCreated :: SIGNATURE )
181
- . from_block ( tag) ;
182
- let events = provider
183
- . subscribe_logs ( & filter)
184
- . await
185
- . map_err ( |err| {
186
- error ! ( ?err, "pubsub subscription failed" ) ;
187
- err
188
- } ) ?
189
- . into_stream ( ) ;
190
-
191
- let validated = events. filter_map ( |log| async move {
192
- log. log_decode_validate :: < CommitteeCreated > ( )
193
- . ok ( )
194
- . map ( |v| v. data ( ) . id )
174
+ let provider = provider. clone ( ) ;
175
+ let key_manager_contract = config. key_manager_contract ;
176
+ let s = events. filter_map ( move |log| {
177
+ let provider = provider. clone ( ) ;
178
+ async move {
179
+ let id = log. data ( ) . id ;
180
+ match CommitteeInfo :: fetch_with ( provider. inner ( ) , key_manager_contract, id) . await {
181
+ Ok ( comm_info) => Some ( comm_info) ,
182
+ Err ( _) => {
183
+ error ! ( committee_id = %id, "fail to fetch new CommitteeInfo" ) ;
184
+ None
185
+ }
186
+ }
187
+ }
195
188
} ) ;
196
- Ok ( Self {
197
- _provider : Box :: new ( provider) ,
198
- inner : Box :: pin ( validated) ,
199
- } )
189
+
190
+ Ok ( Box :: pin ( s) )
200
191
}
201
192
}
0 commit comments