Optimization: reduce BLS decompression (#766)

* Add RwLock-style caching for BLS pubkeys

* Tidy docker ignore

* Remove RwLocks

* Merge in master
This commit is contained in:
Paul Hauner
2020-01-10 15:32:10 +11:00
committed by GitHub
parent 5a8f2dd961
commit 370c658c7c
7 changed files with 182 additions and 139 deletions

View File

@@ -248,10 +248,14 @@ fn validator_pubkey<'a, T: EthSpec>(
.ok_or_else(|| Error::ValidatorUnknown(validator_index as u64))?
.pubkey;
pubkey_bytes
.try_into()
.map(|pubkey: PublicKey| Cow::Owned(pubkey.as_raw().point.clone()))
.map_err(|_| Error::BadBlsBytes {
validator_index: validator_index as u64,
})
if let Some(pubkey) = pubkey_bytes.decompressed() {
Ok(Cow::Borrowed(&pubkey.as_raw().point))
} else {
pubkey_bytes
.try_into()
.map(|pubkey: PublicKey| Cow::Owned(pubkey.as_raw().point.clone()))
.map_err(|_| Error::BadBlsBytes {
validator_index: validator_index as u64,
})
}
}

View File

@@ -62,6 +62,7 @@ pub enum Error {
CommitteeCacheUninitialized(Option<RelativeEpoch>),
SszTypesError(ssz_types::Error),
CachedTreeHashError(cached_tree_hash::Error),
InvalidValidatorPubkey(ssz::DecodeError),
}
/// Control whether an epoch-indexed field can be indexed at the next epoch or not.
@@ -784,6 +785,7 @@ impl<T: EthSpec> BeaconState<T> {
self.update_pubkey_cache()?;
self.build_tree_hash_cache()?;
self.exit_cache.build(&self.validators, spec)?;
self.decompress_validator_pubkeys()?;
Ok(())
}
@@ -945,6 +947,23 @@ impl<T: EthSpec> BeaconState<T> {
self.tree_hash_cache = BeaconTreeHashCache::default();
}
/// Iterate through all validators and decompress their public key, unless it has already been
/// decompressed.
///
/// Does not check the validity of already decompressed keys.
pub fn decompress_validator_pubkeys(&mut self) -> Result<(), Error> {
self.validators.iter_mut().try_for_each(|validator| {
if validator.pubkey.decompressed().is_none() {
validator
.pubkey
.decompress()
.map_err(|e| Error::InvalidValidatorPubkey(e))
} else {
Ok(())
}
})
}
pub fn clone_without_caches(&self) -> Self {
BeaconState {
genesis_time: self.genesis_time,

View File

@@ -1,5 +1,4 @@
use crate::{test_utils::TestRandom, Epoch, Hash256, PublicKeyBytes};
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;

View File

@@ -83,7 +83,10 @@ macro_rules! bytes_struct {
#[doc = $small_name]
#[doc = " (e.g., from the deposit contract)."]
#[derive(Clone)]
pub struct $name([u8; $byte_size]);
pub struct $name {
bytes: [u8; $byte_size],
decompressed: Option<$type>
}
};
($name: ident, $type: ty, $byte_size: expr, $small_name: expr) => {
bytes_struct!($name, $type, $byte_size, $small_name, stringify!($type),
@@ -91,15 +94,21 @@ macro_rules! bytes_struct {
impl $name {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ssz::DecodeError> {
Ok(Self(Self::get_bytes(bytes)?))
Ok(Self {
bytes: Self::get_bytes(bytes)?,
decompressed: None
})
}
pub fn empty() -> Self {
Self([0; $byte_size])
Self {
bytes: [0; $byte_size],
decompressed: None
}
}
pub fn as_bytes(&self) -> Vec<u8> {
self.0.to_vec()
self.bytes.to_vec()
}
fn get_bytes(bytes: &[u8]) -> Result<[u8; $byte_size], ssz::DecodeError> {
@@ -114,23 +123,32 @@ macro_rules! bytes_struct {
Ok(result)
}
}
pub fn decompress(&mut self) -> Result<(), ssz::DecodeError> {
self.decompressed = Some(<&Self as std::convert::TryInto<$type>>::try_into(self)?);
Ok(())
}
pub fn decompressed(&self) -> &Option<$type> {
&self.decompressed
}
}
impl std::fmt::Debug for $name {
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
self.0[..].fmt(formatter)
self.bytes[..].fmt(formatter)
}
}
impl PartialEq for $name {
fn eq(&self, other: &Self) -> bool {
&self.0[..] == &other.0[..]
&self.bytes[..] == &other.bytes[..]
}
}
impl std::hash::Hash for $name {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state)
self.bytes.hash(state)
}
}
@@ -140,7 +158,7 @@ macro_rules! bytes_struct {
type Error = ssz::DecodeError;
fn try_into(self) -> Result<$type, Self::Error> {
<$type>::from_bytes(&self.0[..])
<$type>::from_bytes(&self.bytes[..])
}
}

View File

@@ -3,7 +3,7 @@ use super::*;
pub mod impls;
/// Returned when SSZ decoding fails.
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone)]
pub enum DecodeError {
/// The bytes supplied were too short to be decoded into the specified type.
InvalidByteLength { len: usize, expected: usize },