Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ members = [
"common/compare_fields_derive",
"common/deposit_contract",
"common/directory",
"common/eip_3076",
"common/eth2",
"common/eth2_config",
"common/eth2_interop_keypairs",
Expand Down Expand Up @@ -135,6 +136,7 @@ directory = { path = "common/directory" }
dirs = "3"
discv5 = { version = "0.10", features = ["libp2p"] }
doppelganger_service = { path = "validator_client/doppelganger_service" }
eip_3076 = { path = "common/eip_3076" }
either = "1.9"
environment = { path = "lighthouse/environment" }
eth2 = { path = "common/eth2" }
Expand Down
20 changes: 20 additions & 0 deletions common/eip_3076/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "eip_3076"
version = "0.1.0"
authors = ["Sigma Prime <contact@sigmaprime.io>"]
edition = { workspace = true }

[features]
default = []
arbitrary-fuzz = ["dep:arbitrary", "types/arbitrary"]
json = ["dep:serde_json"]

[dependencies]
arbitrary = { workspace = true, features = ["derive"], optional = true }
ethereum_serde_utils = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true, optional = true }
types = { workspace = true }

[dev-dependencies]
tempfile = { workspace = true }
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
use crate::InterchangeError;
use serde::{Deserialize, Serialize};
use std::cmp::max;
use std::collections::{HashMap, HashSet};
#[cfg(feature = "json")]
use std::io;
use types::{Epoch, Hash256, PublicKeyBytes, Slot};
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These types imports add a lot of bloat to this crate. It doesn't really matter much right now since eth2 needs types anyway but it might be worth considering some kind of core or primitives feature in types which only imports these basic types, especially if this crate gets used in contexts where the rest of the types aren't already required.


#[derive(Debug)]
pub enum Error {
MaxInconsistent,
}

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
Expand Down Expand Up @@ -53,10 +58,12 @@ pub struct Interchange {
}

impl Interchange {
#[cfg(feature = "json")]
pub fn from_json_str(json: &str) -> Result<Self, serde_json::Error> {
serde_json::from_str(json)
}

#[cfg(feature = "json")]
pub fn from_json_reader(mut reader: impl std::io::Read) -> Result<Self, io::Error> {
// We read the entire file into memory first, as this is *a lot* faster than using
// `serde_json::from_reader`. See https://github.com/serde-rs/json/issues/160
Expand All @@ -65,6 +72,7 @@ impl Interchange {
Ok(Interchange::from_json_str(&json_str)?)
}

#[cfg(feature = "json")]
pub fn write_to(&self, writer: impl std::io::Write) -> Result<(), serde_json::Error> {
serde_json::to_writer(writer, self)
}
Expand All @@ -87,7 +95,7 @@ impl Interchange {
}

/// Minify an interchange by constructing a synthetic block & attestation for each validator.
pub fn minify(&self) -> Result<Self, InterchangeError> {
pub fn minify(&self) -> Result<Self, Error> {
// Map from pubkey to optional max block and max attestation.
let mut validator_data =
HashMap::<PublicKeyBytes, (Option<SignedBlock>, Option<SignedAttestation>)>::new();
Expand Down Expand Up @@ -124,7 +132,7 @@ impl Interchange {
}
}
(None, None) => {}
_ => return Err(InterchangeError::MaxInconsistent),
_ => return Err(Error::MaxInconsistent),
};

// Find maximum block slot.
Expand Down Expand Up @@ -157,3 +165,96 @@ impl Interchange {
})
}
}

#[cfg(feature = "json")]
#[cfg(test)]
mod tests {
use super::*;
use std::fs::File;
use tempfile::tempdir;
use types::FixedBytesExtended;

fn get_interchange() -> Interchange {
Interchange {
metadata: InterchangeMetadata {
interchange_format_version: 5,
genesis_validators_root: Hash256::from_low_u64_be(555),
},
data: vec![
InterchangeData {
pubkey: PublicKeyBytes::deserialize(&[1u8; 48]).unwrap(),
signed_blocks: vec![SignedBlock {
slot: Slot::new(100),
signing_root: Some(Hash256::from_low_u64_be(1)),
}],
signed_attestations: vec![SignedAttestation {
source_epoch: Epoch::new(0),
target_epoch: Epoch::new(5),
signing_root: Some(Hash256::from_low_u64_be(2)),
}],
},
InterchangeData {
pubkey: PublicKeyBytes::deserialize(&[2u8; 48]).unwrap(),
signed_blocks: vec![],
signed_attestations: vec![],
},
],
}
}

#[test]
fn test_roundtrip() {
let temp_dir = tempdir().unwrap();
let file_path = temp_dir.path().join("interchange.json");

let interchange = get_interchange();

let mut file = File::create(&file_path).unwrap();
interchange.write_to(&mut file).unwrap();

let file = File::open(&file_path).unwrap();
let from_file = Interchange::from_json_reader(file).unwrap();

assert_eq!(interchange, from_file);
}

#[test]
fn test_empty_roundtrip() {
let temp_dir = tempdir().unwrap();
let file_path = temp_dir.path().join("empty.json");

let empty = Interchange {
metadata: InterchangeMetadata {
interchange_format_version: 5,
genesis_validators_root: Hash256::zero(),
},
data: vec![],
};

let mut file = File::create(&file_path).unwrap();
empty.write_to(&mut file).unwrap();

let file = File::open(&file_path).unwrap();
let from_file = Interchange::from_json_reader(file).unwrap();

assert_eq!(empty, from_file);
}

#[test]
fn test_minify_roundtrip() {
let interchange = get_interchange();

let minified = interchange.minify().unwrap();

let temp_dir = tempdir().unwrap();
let file_path = temp_dir.path().join("minified.json");

let mut file = File::create(&file_path).unwrap();
minified.write_to(&mut file).unwrap();

let file = File::open(&file_path).unwrap();
let from_file = Interchange::from_json_reader(file).unwrap();

assert_eq!(minified, from_file);
}
}
2 changes: 1 addition & 1 deletion common/eth2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ lighthouse = []

[dependencies]
derivative = { workspace = true }
eip_3076 = { workspace = true }
either = { workspace = true }
enr = { version = "0.13.0", features = ["ed25519"] }
eth2_keystore = { workspace = true }
Expand All @@ -29,7 +30,6 @@ reqwest-eventsource = "0.5.0"
sensitive_url = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
slashing_protection = { workspace = true }
ssz_types = { workspace = true }
test_random_derive = { path = "../../common/test_random_derive" }
types = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion common/eth2/src/lighthouse_vc/std_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
use types::{Address, Graffiti, PublicKeyBytes};
use zeroize::Zeroizing;

pub use slashing_protection::interchange::Interchange;
pub use eip_3076::Interchange;

#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub struct GetFeeRecipientResponse {
Expand Down
1 change: 0 additions & 1 deletion consensus/types/src/contribution_and_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;

/// A Validators aggregate sync committee contribution and selection proof.

#[cfg_attr(
feature = "arbitrary",
derive(arbitrary::Arbitrary),
Expand Down
3 changes: 2 additions & 1 deletion validator_client/slashing_protection/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ edition = { workspace = true }
autotests = false

[features]
arbitrary-fuzz = ["types/arbitrary-fuzz"]
arbitrary-fuzz = ["types/arbitrary-fuzz", "eip_3076/arbitrary-fuzz"]
portable = ["types/portable"]

[dependencies]
arbitrary = { workspace = true, features = ["derive"] }
eip_3076 = { workspace = true, features = ["json"] }
ethereum_serde_utils = { workspace = true }
filesystem = { workspace = true }
r2d2 = { workspace = true }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use eip_3076::{Interchange, InterchangeData, InterchangeMetadata, SignedAttestation, SignedBlock};
use slashing_protection::SUPPORTED_INTERCHANGE_FORMAT_VERSION;
use slashing_protection::interchange::{
Interchange, InterchangeData, InterchangeMetadata, SignedAttestation, SignedBlock,
};
use slashing_protection::interchange_test::{MultiTestCase, TestCase};
use slashing_protection::test_utils::{DEFAULT_GENESIS_VALIDATORS_ROOT, pubkey};
use std::fs::{self, File};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::{
SigningRoot, SlashingDatabase,
interchange::{Interchange, SignedAttestation, SignedBlock},
test_utils::{DEFAULT_GENESIS_VALIDATORS_ROOT, pubkey},
};
use eip_3076::{Interchange, SignedAttestation, SignedBlock};
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use tempfile::tempdir;
Expand Down
5 changes: 4 additions & 1 deletion validator_client/slashing_protection/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
mod attestation_tests;
mod block_tests;
mod extra_interchange_tests;
pub mod interchange;
pub mod interchange_test;
mod parallel_tests;
mod registration_tests;
Expand All @@ -10,6 +9,10 @@ mod signed_block;
mod slashing_database;
pub mod test_utils;

pub mod interchange {
pub use eip_3076::{Interchange, InterchangeMetadata};
}

pub use crate::signed_attestation::{InvalidAttestation, SignedAttestation};
pub use crate::signed_block::{InvalidBlock, SignedBlock};
pub use crate::slashing_database::{
Expand Down
10 changes: 5 additions & 5 deletions validator_client/slashing_protection/src/slashing_database.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::interchange::{
Interchange, InterchangeData, InterchangeMetadata, SignedAttestation as InterchangeAttestation,
SignedBlock as InterchangeBlock,
};
use crate::signed_attestation::InvalidAttestation;
use crate::signed_block::InvalidBlock;
use crate::{NotSafe, Safe, SignedAttestation, SignedBlock, SigningRoot, signing_root_from_row};
use eip_3076::{
Interchange, InterchangeData, InterchangeMetadata, SignedAttestation as InterchangeAttestation,
SignedBlock as InterchangeBlock,
};
use filesystem::restrict_file_permissions;
use r2d2_sqlite::SqliteConnectionManager;
use rusqlite::{OptionalExtension, Transaction, TransactionBehavior, params};
Expand Down Expand Up @@ -1219,7 +1219,7 @@ pub enum InterchangeError {
interchange_file: Hash256,
client: Hash256,
},
MaxInconsistent,
Eip3076(eip_3076::Error),
SummaryInconsistent,
SQLError(String),
SQLPoolError(r2d2::Error),
Expand Down
Loading