Implement tree hash caching (#584)

* Implement basic tree hash caching

* Use spaces to indent top-level Cargo.toml

* Optimize BLS tree hash by hashing bytes directly

* Implement tree hash caching for validator registry

* Persist BeaconState tree hash cache to disk

* Address Paul's review comments
This commit is contained in:
Michael Sproul
2019-11-05 15:46:52 +11:00
committed by GitHub
parent 4ef66a544a
commit c1a2238f1a
38 changed files with 1112 additions and 248 deletions

View File

@@ -1,19 +0,0 @@
// This build script is symlinked from each project that requires BLS's "fake crypto",
// so that the `fake_crypto` feature of every sub-crate can be turned on by running
// with FAKE_CRYPTO=1 from the top-level workspace.
// At some point in the future it might be possible to do:
// $ cargo test --all --release --features fake_crypto
// but at the present time this doesn't work.
// Related: https://github.com/rust-lang/cargo/issues/5364
fn main() {
if let Ok(fake_crypto) = std::env::var("FAKE_CRYPTO") {
if fake_crypto == "1" {
println!("cargo:rustc-cfg=feature=\"fake_crypto\"");
println!("cargo:rerun-if-env-changed=FAKE_CRYPTO");
println!(
"cargo:warning=[{}]: Compiled with fake BLS cryptography. DO NOT USE, TESTING ONLY",
std::env::var("CARGO_PKG_NAME").unwrap()
);
}
}
}

View File

@@ -155,7 +155,7 @@ impl_ssz!(
"AggregateSignature"
);
impl_tree_hash!(AggregateSignature, U96);
impl_tree_hash!(AggregateSignature, BLS_AGG_SIG_BYTE_SIZE);
impl Serialize for AggregateSignature {
/// Serde serialization is compliant the Ethereum YAML test format.

View File

@@ -93,7 +93,7 @@ impl_ssz!(
"FakeAggregateSignature"
);
impl_tree_hash!(FakeAggregateSignature, U96);
impl_tree_hash!(FakeAggregateSignature, BLS_AGG_SIG_BYTE_SIZE);
impl Serialize for FakeAggregateSignature {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>

View File

@@ -102,7 +102,7 @@ impl default::Default for FakePublicKey {
impl_ssz!(FakePublicKey, BLS_PUBLIC_KEY_BYTE_SIZE, "FakePublicKey");
impl_tree_hash!(FakePublicKey, U48);
impl_tree_hash!(FakePublicKey, BLS_PUBLIC_KEY_BYTE_SIZE);
impl Serialize for FakePublicKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>

View File

@@ -91,7 +91,7 @@ impl FakeSignature {
impl_ssz!(FakeSignature, BLS_SIG_BYTE_SIZE, "FakeSignature");
impl_tree_hash!(FakeSignature, U96);
impl_tree_hash!(FakeSignature, BLS_SIG_BYTE_SIZE);
impl Serialize for FakeSignature {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>

View File

@@ -42,7 +42,7 @@ macro_rules! impl_ssz {
}
macro_rules! impl_tree_hash {
($type: ty, $byte_size: ident) => {
($type: ty, $byte_size: expr) => {
impl tree_hash::TreeHash for $type {
fn tree_hash_type() -> tree_hash::TreeHashType {
tree_hash::TreeHashType::Vector
@@ -57,16 +57,19 @@ macro_rules! impl_tree_hash {
}
fn tree_hash_root(&self) -> Vec<u8> {
let vector: ssz_types::FixedVector<u8, ssz_types::typenum::$byte_size> =
ssz_types::FixedVector::from(self.as_ssz_bytes());
vector.tree_hash_root()
// We could use the tree hash implementation for `FixedVec<u8, $byte_size>`,
// but benchmarks have show that to be at least 15% slower because of the
// unnecessary copying and allocation (one Vec per byte)
let values_per_chunk = tree_hash::BYTES_PER_CHUNK;
let minimum_chunk_count = ($byte_size + values_per_chunk - 1) / values_per_chunk;
tree_hash::merkle_root(&self.as_ssz_bytes(), minimum_chunk_count)
}
}
};
}
macro_rules! bytes_struct {
($name: ident, $type: ty, $byte_size: expr, $small_name: expr, $ssz_type_size: ident,
($name: ident, $type: ty, $byte_size: expr, $small_name: expr,
$type_str: expr, $byte_size_str: expr) => {
#[doc = "Stores `"]
#[doc = $byte_size_str]
@@ -82,9 +85,9 @@ macro_rules! bytes_struct {
#[derive(Clone)]
pub struct $name([u8; $byte_size]);
};
($name: ident, $type: ty, $byte_size: expr, $small_name: expr, $ssz_type_size: ident) => {
bytes_struct!($name, $type, $byte_size, $small_name, $ssz_type_size, stringify!($type),
stringify!($byte_size));
($name: ident, $type: ty, $byte_size: expr, $small_name: expr) => {
bytes_struct!($name, $type, $byte_size, $small_name, stringify!($type),
stringify!($byte_size));
impl $name {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ssz::DecodeError> {
@@ -144,7 +147,7 @@ macro_rules! bytes_struct {
impl_ssz!($name, $byte_size, "$type");
impl_tree_hash!($name, $ssz_type_size);
impl_tree_hash!($name, $byte_size);
impl serde::ser::Serialize for $name {
/// Serde serialization is compliant the Ethereum YAML test format.

View File

@@ -94,7 +94,7 @@ impl default::Default for PublicKey {
impl_ssz!(PublicKey, BLS_PUBLIC_KEY_BYTE_SIZE, "PublicKey");
impl_tree_hash!(PublicKey, U48);
impl_tree_hash!(PublicKey, BLS_PUBLIC_KEY_BYTE_SIZE);
impl Serialize for PublicKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>

View File

@@ -6,8 +6,7 @@ bytes_struct!(
PublicKeyBytes,
PublicKey,
BLS_PUBLIC_KEY_BYTE_SIZE,
"public key",
U48
"public key"
);
#[cfg(test)]

View File

@@ -49,7 +49,7 @@ impl SecretKey {
impl_ssz!(SecretKey, BLS_SECRET_KEY_BYTE_SIZE, "SecretKey");
impl_tree_hash!(SecretKey, U48);
impl_tree_hash!(SecretKey, BLS_SECRET_KEY_BYTE_SIZE);
impl Serialize for SecretKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>

View File

@@ -108,7 +108,7 @@ impl Signature {
impl_ssz!(Signature, BLS_SIG_BYTE_SIZE, "Signature");
impl_tree_hash!(Signature, U96);
impl_tree_hash!(Signature, BLS_SIG_BYTE_SIZE);
impl Serialize for Signature {
/// Serde serialization is compliant the Ethereum YAML test format.

View File

@@ -2,13 +2,7 @@ use ssz::{Decode, DecodeError, Encode};
use super::{Signature, BLS_SIG_BYTE_SIZE};
bytes_struct!(
SignatureBytes,
Signature,
BLS_SIG_BYTE_SIZE,
"signature",
U96
);
bytes_struct!(SignatureBytes, Signature, BLS_SIG_BYTE_SIZE, "signature");
#[cfg(test)]
mod tests {