@@ -16,15 +16,59 @@ use eth2api::types::{
1616 GetPoolVoluntaryExitsResponseResponseDatum , Phase0SignedVoluntaryExitMessage ,
1717} ;
1818
19- /// Type alias for signed voluntary exit from eth2api.
20- pub type SignedVoluntaryExit = GetPoolVoluntaryExitsResponseResponseDatum ;
21-
2219use crate :: obolapi:: {
2320 client:: Client ,
2421 error:: { Error , Result } ,
2522 helper:: { bearer_string, from_0x, to_0x} ,
2623} ;
2724
25+ /// Type alias for signed voluntary exit from eth2api.
26+ pub type SignedVoluntaryExit = GetPoolVoluntaryExitsResponseResponseDatum ;
27+
28+ /// Trait for types that can be hashed using SSZ hash tree root.
29+ pub trait SszHashable {
30+ /// Hashes this value into the provided hasher.
31+ fn hash_with < H : HashWalker > ( & self , hh : & mut H ) -> Result < ( ) > ;
32+
33+ /// Computes the SSZ hash tree root of this value.
34+ fn hash_tree_root ( & self ) -> Result < [ u8 ; 32 ] > {
35+ let mut hh = Hasher :: default ( ) ;
36+ self . hash_with ( & mut hh) ?;
37+ hh. hash_root ( ) . map_err ( map_hasher_error)
38+ }
39+ }
40+
41+ impl SszHashable for SignedVoluntaryExit {
42+ fn hash_with < H : HashWalker > ( & self , hh : & mut H ) -> Result < ( ) > {
43+ let index = hh. index ( ) ;
44+
45+ self . message . hash_with ( hh) ?;
46+ let sig_bytes = from_0x ( & self . signature , SSZ_LEN_BLS_SIG ) ?;
47+ put_bytes_n ( hh, & sig_bytes, SSZ_LEN_BLS_SIG ) ?;
48+
49+ hh. merkleize ( index) . map_err ( map_walker_error) ?;
50+ Ok ( ( ) )
51+ }
52+ }
53+
54+ impl SszHashable for Phase0SignedVoluntaryExitMessage {
55+ fn hash_with < H : HashWalker > ( & self , hh : & mut H ) -> Result < ( ) > {
56+ let index = hh. index ( ) ;
57+
58+ let epoch = self . epoch . parse :: < u64 > ( ) . map_err ( Error :: EpochParse ) ?;
59+ let validator_index = self
60+ . validator_index
61+ . parse :: < u64 > ( )
62+ . map_err ( Error :: EpochParse ) ?;
63+
64+ hh. put_uint64 ( epoch) . map_err ( map_walker_error) ?;
65+ hh. put_uint64 ( validator_index) . map_err ( map_walker_error) ?;
66+
67+ hh. merkleize ( index) . map_err ( map_walker_error) ?;
68+ Ok ( ( ) )
69+ }
70+ }
71+
2872/// An exit message alongside its BLS12-381 hex-encoded signature.
2973#[ derive( Debug , Clone , Serialize , Deserialize ) ]
3074pub struct ExitBlob {
@@ -36,10 +80,23 @@ pub struct ExitBlob {
3680 pub signed_exit_message : SignedVoluntaryExit ,
3781}
3882
39- impl ExitBlob {
40- /// Computes the SSZ hash tree root of this ExitBlob.
41- pub fn hash_tree_root ( & self ) -> Result < [ u8 ; 32 ] > {
42- hash_exit_blob ( self )
83+ impl SszHashable for ExitBlob {
84+ fn hash_with < H : HashWalker > ( & self , hh : & mut H ) -> Result < ( ) > {
85+ let index = hh. index ( ) ;
86+
87+ let pk = self . public_key . as_ref ( ) . ok_or_else ( || {
88+ use charon_cluster:: ssz:: SSZError ;
89+ Error :: Ssz ( SSZError :: UnsupportedVersion (
90+ "missing public key" . to_string ( ) ,
91+ ) )
92+ } ) ?;
93+ let pk_bytes = from_0x ( pk, SSZ_LEN_PUB_KEY ) ?;
94+ hh. put_bytes ( & pk_bytes) . map_err ( map_walker_error) ?;
95+
96+ self . signed_exit_message . hash_with ( hh) ?;
97+
98+ hh. merkleize ( index) . map_err ( map_walker_error) ?;
99+ Ok ( ( ) )
43100 }
44101}
45102
@@ -48,24 +105,18 @@ impl ExitBlob {
48105#[ serde( transparent) ]
49106pub struct PartialExits ( pub Vec < ExitBlob > ) ;
50107
51- impl PartialExits {
52- /// Computes the SSZ hash tree root of the partial exits list.
53- pub fn hash_tree_root ( & self ) -> Result < [ u8 ; 32 ] > {
54- hash_partial_exits ( & self . 0 )
55- }
56- }
57-
58- impl std:: ops:: Deref for PartialExits {
59- type Target = Vec < ExitBlob > ;
108+ impl SszHashable for PartialExits {
109+ fn hash_with < H : HashWalker > ( & self , hh : & mut H ) -> Result < ( ) > {
110+ let index = hh. index ( ) ;
111+ let num = self . 0 . len ( ) ;
60112
61- fn deref ( & self ) -> & Self :: Target {
62- & self . 0
63- }
64- }
113+ for exit_blob in & self . 0 {
114+ exit_blob. hash_with ( hh) ?;
115+ }
65116
66- impl std :: ops :: DerefMut for PartialExits {
67- fn deref_mut ( & mut self ) -> & mut Self :: Target {
68- & mut self . 0
117+ hh . merkleize_with_mixin ( index , num , SSZ_MAX_EXITS )
118+ . map_err ( map_walker_error ) ? ;
119+ Ok ( ( ) )
69120 }
70121}
71122
@@ -75,12 +126,6 @@ impl From<Vec<ExitBlob>> for PartialExits {
75126 }
76127}
77128
78- impl From < PartialExits > for Vec < ExitBlob > {
79- fn from ( p : PartialExits ) -> Self {
80- p. 0
81- }
82- }
83-
84129/// An unsigned blob of data sent to the Obol API server, which is stored in the
85130/// backend awaiting aggregation.
86131#[ derive( Debug , Clone , Serialize , Deserialize ) ]
@@ -93,10 +138,15 @@ pub struct UnsignedPartialExitRequest {
93138 pub share_idx : u64 ,
94139}
95140
96- impl UnsignedPartialExitRequest {
97- /// Computes the SSZ hash tree root of this UnsignedPartialExitRequest.
98- pub fn hash_tree_root ( & self ) -> Result < [ u8 ; 32 ] > {
99- hash_unsigned_partial_exit_request ( self )
141+ impl SszHashable for UnsignedPartialExitRequest {
142+ fn hash_with < H : HashWalker > ( & self , hh : & mut H ) -> Result < ( ) > {
143+ let index = hh. index ( ) ;
144+
145+ self . partial_exits . hash_with ( hh) ?;
146+ hh. put_uint64 ( self . share_idx ) . map_err ( map_walker_error) ?;
147+
148+ hh. merkleize ( index) . map_err ( map_walker_error) ?;
149+ Ok ( ( ) )
100150 }
101151}
102152
@@ -181,10 +231,16 @@ pub struct FullExitAuthBlob {
181231 pub share_index : u64 ,
182232}
183233
184- impl FullExitAuthBlob {
185- /// Computes the SSZ hash tree root of this FullExitAuthBlob.
186- pub fn hash_tree_root ( & self ) -> Result < [ u8 ; 32 ] > {
187- hash_full_exit_auth_blob ( self )
234+ impl SszHashable for FullExitAuthBlob {
235+ fn hash_with < H : HashWalker > ( & self , hh : & mut H ) -> Result < ( ) > {
236+ let index = hh. index ( ) ;
237+
238+ hh. put_bytes ( & self . lock_hash ) . map_err ( map_walker_error) ?;
239+ put_bytes_n ( hh, & self . validator_pubkey , SSZ_LEN_PUB_KEY ) ?;
240+ hh. put_uint64 ( self . share_index ) . map_err ( map_walker_error) ?;
241+
242+ hh. merkleize ( index) . map_err ( map_walker_error) ?;
243+ Ok ( ( ) )
188244 }
189245}
190246const SSZ_MAX_EXITS : usize = 65536 ;
@@ -406,118 +462,6 @@ fn put_bytes_n<H: HashWalker>(hh: &mut H, bytes: &[u8], expected_len: usize) ->
406462 hh. put_bytes ( & padded) . map_err ( map_walker_error)
407463}
408464
409- fn hash_exit_blob ( blob : & ExitBlob ) -> Result < [ u8 ; 32 ] > {
410- let mut hh = Hasher :: default ( ) ;
411- hash_exit_blob_with ( blob, & mut hh) ?;
412- hh. hash_root ( ) . map_err ( map_hasher_error)
413- }
414-
415- fn hash_exit_blob_with < H : HashWalker > ( blob : & ExitBlob , hh : & mut H ) -> Result < ( ) > {
416- let index = hh. index ( ) ;
417-
418- let pk = blob. public_key . as_ref ( ) . ok_or_else ( || {
419- use charon_cluster:: ssz:: SSZError ;
420- Error :: Ssz ( SSZError :: UnsupportedVersion (
421- "missing public key" . to_string ( ) ,
422- ) )
423- } ) ?;
424- let pk_bytes = from_0x ( pk, SSZ_LEN_PUB_KEY ) ?;
425- hh. put_bytes ( & pk_bytes) . map_err ( map_walker_error) ?;
426-
427- hash_signed_voluntary_exit_with ( & blob. signed_exit_message , hh) ?;
428-
429- hh. merkleize ( index) . map_err ( map_walker_error) ?;
430- Ok ( ( ) )
431- }
432-
433- fn hash_partial_exits ( exits : & [ ExitBlob ] ) -> Result < [ u8 ; 32 ] > {
434- let mut hh = Hasher :: default ( ) ;
435- hash_partial_exits_with ( exits, & mut hh) ?;
436- hh. hash_root ( ) . map_err ( map_hasher_error)
437- }
438-
439- fn hash_unsigned_partial_exit_request ( req : & UnsignedPartialExitRequest ) -> Result < [ u8 ; 32 ] > {
440- let mut hh = Hasher :: default ( ) ;
441- hash_unsigned_partial_exit_request_with ( req, & mut hh) ?;
442- hh. hash_root ( ) . map_err ( map_hasher_error)
443- }
444-
445- fn hash_unsigned_partial_exit_request_with < H : HashWalker > (
446- req : & UnsignedPartialExitRequest ,
447- hh : & mut H ,
448- ) -> Result < ( ) > {
449- let index = hh. index ( ) ;
450-
451- hash_partial_exits_with ( & req. partial_exits , hh) ?;
452- hh. put_uint64 ( req. share_idx ) . map_err ( map_walker_error) ?;
453-
454- hh. merkleize ( index) . map_err ( map_walker_error) ?;
455- Ok ( ( ) )
456- }
457-
458- fn hash_partial_exits_with < H : HashWalker > ( exits : & [ ExitBlob ] , hh : & mut H ) -> Result < ( ) > {
459- let index = hh. index ( ) ;
460- let num = exits. len ( ) ;
461-
462- for exit_blob in exits {
463- hash_exit_blob_with ( exit_blob, hh) ?;
464- }
465-
466- hh. merkleize_with_mixin ( index, num, SSZ_MAX_EXITS )
467- . map_err ( map_walker_error) ?;
468- Ok ( ( ) )
469- }
470-
471- fn hash_full_exit_auth_blob ( blob : & FullExitAuthBlob ) -> Result < [ u8 ; 32 ] > {
472- let mut hh = Hasher :: default ( ) ;
473- hash_full_exit_auth_blob_with ( blob, & mut hh) ?;
474- hh. hash_root ( ) . map_err ( map_hasher_error)
475- }
476-
477- fn hash_full_exit_auth_blob_with < H : HashWalker > ( blob : & FullExitAuthBlob , hh : & mut H ) -> Result < ( ) > {
478- let index = hh. index ( ) ;
479-
480- hh. put_bytes ( & blob. lock_hash ) . map_err ( map_walker_error) ?;
481- put_bytes_n ( hh, & blob. validator_pubkey , SSZ_LEN_PUB_KEY ) ?;
482- hh. put_uint64 ( blob. share_index ) . map_err ( map_walker_error) ?;
483-
484- hh. merkleize ( index) . map_err ( map_walker_error) ?;
485- Ok ( ( ) )
486- }
487-
488- fn hash_signed_voluntary_exit_with < H : HashWalker > (
489- exit : & SignedVoluntaryExit ,
490- hh : & mut H ,
491- ) -> Result < ( ) > {
492- let index = hh. index ( ) ;
493-
494- hash_voluntary_exit_with ( & exit. message , hh) ?;
495- let sig_bytes = from_0x ( & exit. signature , SSZ_LEN_BLS_SIG ) ?;
496- put_bytes_n ( hh, & sig_bytes, SSZ_LEN_BLS_SIG ) ?;
497-
498- hh. merkleize ( index) . map_err ( map_walker_error) ?;
499- Ok ( ( ) )
500- }
501-
502- fn hash_voluntary_exit_with < H : HashWalker > (
503- message : & Phase0SignedVoluntaryExitMessage ,
504- hh : & mut H ,
505- ) -> Result < ( ) > {
506- let index = hh. index ( ) ;
507-
508- let epoch = message. epoch . parse :: < u64 > ( ) . map_err ( Error :: EpochParse ) ?;
509- let validator_index = message
510- . validator_index
511- . parse :: < u64 > ( )
512- . map_err ( Error :: EpochParse ) ?;
513-
514- hh. put_uint64 ( epoch) . map_err ( map_walker_error) ?;
515- hh. put_uint64 ( validator_index) . map_err ( map_walker_error) ?;
516-
517- hh. merkleize ( index) . map_err ( map_walker_error) ?;
518- Ok ( ( ) )
519- }
520-
521465#[ cfg( test) ]
522466mod tests {
523467 use super :: * ;
0 commit comments