Skip to content

Store pubkey cache decompressed on disk #3505

@michaelsproul

Description

@michaelsproul

Description

Currently Lighthouse takes a long time to start up while it reloads the public key cache from disk.

The fundamental reason for this is that it stores the BLS pubkeys in their compressed form and then has to decompress every one of them for the in-memory cache:

/// Wrapper for a public key stored in the database.
///
/// Keyed by the validator index as `Hash256::from_low_u64_be(index)`.
struct DatabasePubkey(PublicKeyBytes);

Just changing that PublicKeyBytes to PublicKey would not be sufficient, because the two types share the same compressed SSZ representation:

/// Contains the functions required for a `ssz::Encode` implementation.
///
/// Does not include the `Impl` section since it gets very complicated when it comes to generics.
macro_rules! impl_ssz_encode {
($byte_size: expr) => {
fn is_ssz_fixed_len() -> bool {
true
}
fn ssz_fixed_len() -> usize {
$byte_size
}
fn ssz_bytes_len(&self) -> usize {
$byte_size
}
fn ssz_append(&self, buf: &mut Vec<u8>) {
buf.extend_from_slice(&self.serialize())
}
};
}

impl TPublicKey for blst_core::PublicKey {
fn serialize(&self) -> [u8; PUBLIC_KEY_BYTES_LEN] {
self.compress()
}

So we would need to create new methods on bls::GenericPublicKey like serialize_uncompressed and deserialize_uncompressed which use the 96-byte serialization of the PublicKey rather than the 48-byte compressed serialization. For blst, we can use the PublicKey::serialize function. For milagro we can use PublicKey::as_uncompressed_bytes. Both libraries also include deserialisation functions acting on the uncompressed bytes.

Once these methods are in place in the bls wrapper lib, we can call them from the DatabasePubkey wrapper. We'll need two versions of DatabasePubkey in order to implement the schema migration from compressed keys to uncompressed keys.

By storing the bytes uncompressed we'll double the disk space required for the pubkey cache from 500k * 48 bytes = 24 MB to 48 MB. Given the overall size of the database I believe this is an acceptable trade-off. We could attempt to apply a faster compression algorithm like zstd to the data, but seeing as the input is pseudo-random bytes I suspect this naive compression would be ineffective.

Version

Lighthouse v3.0.0

Metadata

Metadata

Assignees

Labels

backwards-incompatBackwards-incompatible API changecryptoAn issue/PR that touches cryptography code.databaseoptimizationSomething to make Lighthouse run more efficiently.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions