Add SignedRoot methods
This commit is contained in:
		
							parent
							
								
									4a57aec472
								
							
						
					
					
						commit
						94122a7334
					
				| @ -3,10 +3,11 @@ use crate::{Hash256, Slot}; | ||||
| use bls::Signature; | ||||
| use rand::RngCore; | ||||
| use serde_derive::Serialize; | ||||
| use ssz_derive::{Decode, Encode, TreeHash}; | ||||
| use ssz::TreeHash; | ||||
| use ssz_derive::{Decode, Encode, SignedRoot, TreeHash}; | ||||
| use test_random_derive::TestRandom; | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Clone, Serialize, Encode, Decode, TreeHash, TestRandom)] | ||||
| #[derive(Debug, PartialEq, Clone, Serialize, Encode, Decode, TreeHash, TestRandom, SignedRoot)] | ||||
| pub struct Proposal { | ||||
|     pub slot: Slot, | ||||
|     /// Shard number (spec.beacon_chain_shard_number for beacon chain)
 | ||||
| @ -19,7 +20,7 @@ pub struct Proposal { | ||||
| mod tests { | ||||
|     use super::*; | ||||
|     use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng}; | ||||
|     use ssz::{ssz_encode, Decodable, TreeHash}; | ||||
|     use ssz::{ssz_encode, Decodable, SignedRoot, TreeHash}; | ||||
| 
 | ||||
|     #[test] | ||||
|     pub fn test_ssz_round_trip() { | ||||
| @ -43,4 +44,32 @@ mod tests { | ||||
|         // TODO: Add further tests
 | ||||
|         // https://github.com/sigp/lighthouse/issues/170
 | ||||
|     } | ||||
| 
 | ||||
|     #[derive(TreeHash)] | ||||
|     struct SignedProposal { | ||||
|         pub slot: Slot, | ||||
|         pub shard: u64, | ||||
|         pub block_root: Hash256, | ||||
|     } | ||||
| 
 | ||||
|     impl Into<SignedProposal> for Proposal { | ||||
|         fn into(self) -> SignedProposal { | ||||
|             SignedProposal { | ||||
|                 slot: self.slot, | ||||
|                 shard: self.shard, | ||||
|                 block_root: self.block_root, | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     pub fn test_signed_root() { | ||||
|         let mut rng = XorShiftRng::from_seed([42; 16]); | ||||
|         let original = Proposal::random_for_test(&mut rng); | ||||
| 
 | ||||
|         let other: SignedProposal = original.clone().into(); | ||||
| 
 | ||||
|         assert_eq!(original.signed_root(), other.hash_tree_root()); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -12,6 +12,7 @@ extern crate ethereum_types; | ||||
| 
 | ||||
| pub mod decode; | ||||
| pub mod encode; | ||||
| mod signed_root; | ||||
| pub mod tree_hash; | ||||
| 
 | ||||
| mod impl_decode; | ||||
| @ -20,6 +21,7 @@ mod impl_tree_hash; | ||||
| 
 | ||||
| pub use crate::decode::{decode_ssz, decode_ssz_list, Decodable, DecodeError}; | ||||
| pub use crate::encode::{Encodable, SszStream}; | ||||
| pub use crate::signed_root::SignedRoot; | ||||
| pub use crate::tree_hash::{merkle_hash, TreeHash}; | ||||
| 
 | ||||
| pub use hashing::hash; | ||||
|  | ||||
							
								
								
									
										5
									
								
								eth2/utils/ssz/src/signed_root.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								eth2/utils/ssz/src/signed_root.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| use crate::TreeHash; | ||||
| 
 | ||||
| pub trait SignedRoot: TreeHash { | ||||
|     fn signed_root(&self) -> Vec<u8>; | ||||
| } | ||||
| @ -158,3 +158,78 @@ pub fn ssz_tree_hash_derive(input: TokenStream) -> TokenStream { | ||||
|     }; | ||||
|     output.into() | ||||
| } | ||||
| 
 | ||||
| /// Returns `true` if some `Ident` should be considered to be a signature type.
 | ||||
| fn type_ident_is_signature(ident: &syn::Ident) -> bool { | ||||
|     match ident.to_string().as_ref() { | ||||
|         "Signature" => true, | ||||
|         "AggregateSignature" => true, | ||||
|         _ => false, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Takes a `Field` where the type (`ty`) portion is a path (e.g., `types::Signature`) and returns
 | ||||
| /// the final `Ident` in that path.
 | ||||
| ///
 | ||||
| /// E.g., for `types::Signature` returns `Signature`.
 | ||||
| fn final_type_ident<'a>(field: &'a syn::Field) -> &'a syn::Ident { | ||||
|     match &field.ty { | ||||
|         syn::Type::Path(path) => &path.path.segments.last().unwrap().value().ident, | ||||
|         _ => panic!("ssz_derive only supports Path types."), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Implements `ssz::TreeHash` for some `struct`, whilst excluding any fields following and
 | ||||
| /// including a field that is of type "Signature" or "AggregateSignature".
 | ||||
| ///
 | ||||
| /// See:
 | ||||
| /// https://github.com/ethereum/eth2.0-specs/blob/master/specs/simple-serialize.md#signed-roots
 | ||||
| ///
 | ||||
| /// This is a rather horrendous macro, it will read the type of the object as a string and decide
 | ||||
| /// if it's a signature by matching that string against "Signature" or "AggregateSignature". So,
 | ||||
| /// it's important that you use those exact words as your type -- don't alias it to something else.
 | ||||
| ///
 | ||||
| /// If you can think of a better way to do this, please make an issue!
 | ||||
| ///
 | ||||
| /// Fields are processed in the order they are defined.
 | ||||
| #[proc_macro_derive(SignedRoot)] | ||||
| pub fn ssz_signed_root_derive(input: TokenStream) -> TokenStream { | ||||
|     let item = parse_macro_input!(input as DeriveInput); | ||||
| 
 | ||||
|     let name = &item.ident; | ||||
| 
 | ||||
|     let struct_data = match &item.data { | ||||
|         syn::Data::Struct(s) => s, | ||||
|         _ => panic!("ssz_derive only supports structs."), | ||||
|     }; | ||||
| 
 | ||||
|     let mut field_idents: Vec<&syn::Ident> = vec![]; | ||||
| 
 | ||||
|     for field in struct_data.fields.iter() { | ||||
|         let final_type_ident = final_type_ident(&field); | ||||
| 
 | ||||
|         if type_ident_is_signature(final_type_ident) { | ||||
|             break; | ||||
|         } else { | ||||
|             let ident = field | ||||
|                 .ident | ||||
|                 .as_ref() | ||||
|                 .expect("ssz_derive only supports named_struct fields."); | ||||
|             field_idents.push(ident); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     let output = quote! { | ||||
|         impl ssz::SignedRoot for #name { | ||||
|             fn signed_root(&self) -> Vec<u8> { | ||||
|                 let mut list: Vec<Vec<u8>> = Vec::new(); | ||||
|                 #( | ||||
|                     list.push(self.#field_idents.hash_tree_root_internal()); | ||||
|                 )* | ||||
| 
 | ||||
|                 ssz::merkle_hash(&mut list) | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
|     output.into() | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user