11use {
2- crate :: api:: ChainId ,
2+ crate :: {
3+ api:: ChainId ,
4+ keeper:: keeper_metrics:: { AccountLabel , KeeperMetrics } ,
5+ } ,
36 anyhow:: { ensure, Result } ,
47 ethers:: types:: Address ,
58 sha3:: { Digest , Keccak256 } ,
9+ std:: sync:: Arc ,
610 tokio:: task:: spawn_blocking,
711} ;
812
@@ -127,11 +131,22 @@ impl PebbleHashChain {
127131/// which requires tracking multiple hash chains here.
128132pub struct HashChainState {
129133 // The sequence number where the hash chain starts. Must be stored in sorted order.
130- pub offsets : Vec < usize > ,
131- pub hash_chains : Vec < PebbleHashChain > ,
134+ offsets : Vec < usize > ,
135+ hash_chains : Vec < PebbleHashChain > ,
132136}
133137
134138impl HashChainState {
139+ pub fn new ( offsets : Vec < usize > , hash_chains : Vec < PebbleHashChain > ) -> Result < HashChainState > {
140+ if offsets. len ( ) != hash_chains. len ( ) {
141+ return Err ( anyhow:: anyhow!(
142+ "Offsets and hash chains must have the same length."
143+ ) ) ;
144+ }
145+ Ok ( HashChainState {
146+ offsets,
147+ hash_chains,
148+ } )
149+ }
135150 pub fn from_chain_at_offset ( offset : usize , chain : PebbleHashChain ) -> HashChainState {
136151 HashChainState {
137152 offsets : vec ! [ offset] ,
@@ -152,12 +167,54 @@ impl HashChainState {
152167 }
153168}
154169
170+ pub struct MonitoredHashChainState {
171+ hash_chain_state : Arc < HashChainState > ,
172+ metrics : Arc < KeeperMetrics > ,
173+ account_label : AccountLabel ,
174+ }
175+ impl MonitoredHashChainState {
176+ pub fn new (
177+ hash_chain_state : Arc < HashChainState > ,
178+ metrics : Arc < KeeperMetrics > ,
179+ chain_id : ChainId ,
180+ provider_address : Address ,
181+ ) -> Self {
182+ Self {
183+ hash_chain_state,
184+ metrics,
185+ account_label : AccountLabel {
186+ chain_id,
187+ address : provider_address. to_string ( ) ,
188+ } ,
189+ }
190+ }
191+
192+ pub fn reveal ( & self , sequence_number : u64 ) -> Result < [ u8 ; 32 ] > {
193+ let res = self . hash_chain_state . reveal ( sequence_number) ;
194+ if res. is_ok ( ) {
195+ let metric = self
196+ . metrics
197+ . highest_revealed_sequence_number
198+ . get_or_create ( & self . account_label ) ;
199+ if metric. get ( ) < sequence_number as i64 {
200+ metric. set ( sequence_number as i64 ) ;
201+ }
202+ }
203+ res
204+ }
205+ }
206+
155207#[ cfg( test) ]
156208mod test {
157209 use {
158- crate :: state:: { HashChainState , PebbleHashChain } ,
210+ crate :: {
211+ keeper:: keeper_metrics:: { AccountLabel , KeeperMetrics } ,
212+ state:: { HashChainState , MonitoredHashChainState , PebbleHashChain } ,
213+ } ,
159214 anyhow:: Result ,
215+ ethers:: types:: Address ,
160216 sha3:: { Digest , Keccak256 } ,
217+ std:: { sync:: Arc , vec} ,
161218 } ;
162219
163220 fn run_hash_chain_test ( secret : [ u8 ; 32 ] , length : usize , sample_interval : usize ) {
@@ -294,4 +351,65 @@ mod test {
294351
295352 Ok ( ( ) )
296353 }
354+ #[ test]
355+ fn test_inconsistent_lengths ( ) -> Result < ( ) > {
356+ let chain1 = PebbleHashChain :: new ( [ 0u8 ; 32 ] , 10 , 1 ) ;
357+ let chain2 = PebbleHashChain :: new ( [ 1u8 ; 32 ] , 10 , 1 ) ;
358+
359+ let hash_chain_state = HashChainState :: new ( vec ! [ 5 ] , vec ! [ chain1. clone( ) , chain2. clone( ) ] ) ;
360+ assert ! ( hash_chain_state. is_err( ) ) ;
361+ let hash_chain_state = HashChainState :: new ( vec ! [ 5 , 10 ] , vec ! [ chain1. clone( ) ] ) ;
362+ assert ! ( hash_chain_state. is_err( ) ) ;
363+ let hash_chain_state =
364+ HashChainState :: new ( vec ! [ 5 , 10 ] , vec ! [ chain1. clone( ) , chain2. clone( ) ] ) ;
365+ assert ! ( hash_chain_state. is_ok( ) ) ;
366+
367+ Ok ( ( ) )
368+ }
369+
370+ #[ test]
371+ fn test_highest_revealed_sequence_number ( ) {
372+ let chain = PebbleHashChain :: new ( [ 0u8 ; 32 ] , 100 , 1 ) ;
373+ let hash_chain_state = HashChainState :: new ( vec ! [ 0 ] , vec ! [ chain] ) . unwrap ( ) ;
374+ let metrics = Arc :: new ( KeeperMetrics :: default ( ) ) ;
375+ let provider = Address :: random ( ) ;
376+ let monitored = MonitoredHashChainState :: new (
377+ Arc :: new ( hash_chain_state) ,
378+ metrics. clone ( ) ,
379+ "ethereum" . to_string ( ) ,
380+ provider,
381+ ) ;
382+ let label = AccountLabel {
383+ chain_id : "ethereum" . to_string ( ) ,
384+ address : provider. to_string ( ) ,
385+ } ;
386+
387+ assert ! ( monitored. reveal( 5 ) . is_ok( ) ) ;
388+ let current = metrics
389+ . highest_revealed_sequence_number
390+ . get_or_create ( & label)
391+ . get ( ) ;
392+ assert_eq ! ( current, 5 ) ;
393+
394+ assert ! ( monitored. reveal( 15 ) . is_ok( ) ) ;
395+ let current = metrics
396+ . highest_revealed_sequence_number
397+ . get_or_create ( & label)
398+ . get ( ) ;
399+ assert_eq ! ( current, 15 ) ;
400+
401+ assert ! ( monitored. reveal( 10 ) . is_ok( ) ) ;
402+ let current = metrics
403+ . highest_revealed_sequence_number
404+ . get_or_create ( & label)
405+ . get ( ) ;
406+ assert_eq ! ( current, 15 ) ;
407+
408+ assert ! ( monitored. reveal( 1000 ) . is_err( ) ) ;
409+ let current = metrics
410+ . highest_revealed_sequence_number
411+ . get_or_create ( & label)
412+ . get ( ) ;
413+ assert_eq ! ( current, 15 ) ;
414+ }
297415}
0 commit comments