Add SignedRoot methods
This commit is contained in:
parent
4a57aec472
commit
94122a7334
@ -3,10 +3,11 @@ use crate::{Hash256, Slot};
|
|||||||
use bls::Signature;
|
use bls::Signature;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
use serde_derive::Serialize;
|
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;
|
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 struct Proposal {
|
||||||
pub slot: Slot,
|
pub slot: Slot,
|
||||||
/// Shard number (spec.beacon_chain_shard_number for beacon chain)
|
/// Shard number (spec.beacon_chain_shard_number for beacon chain)
|
||||||
@ -19,7 +20,7 @@ pub struct Proposal {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
|
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
|
||||||
use ssz::{ssz_encode, Decodable, TreeHash};
|
use ssz::{ssz_encode, Decodable, SignedRoot, TreeHash};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_ssz_round_trip() {
|
pub fn test_ssz_round_trip() {
|
||||||
@ -43,4 +44,32 @@ mod tests {
|
|||||||
// TODO: Add further tests
|
// TODO: Add further tests
|
||||||
// https://github.com/sigp/lighthouse/issues/170
|
// 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 decode;
|
||||||
pub mod encode;
|
pub mod encode;
|
||||||
|
mod signed_root;
|
||||||
pub mod tree_hash;
|
pub mod tree_hash;
|
||||||
|
|
||||||
mod impl_decode;
|
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::decode::{decode_ssz, decode_ssz_list, Decodable, DecodeError};
|
||||||
pub use crate::encode::{Encodable, SszStream};
|
pub use crate::encode::{Encodable, SszStream};
|
||||||
|
pub use crate::signed_root::SignedRoot;
|
||||||
pub use crate::tree_hash::{merkle_hash, TreeHash};
|
pub use crate::tree_hash::{merkle_hash, TreeHash};
|
||||||
|
|
||||||
pub use hashing::hash;
|
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()
|
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