Skip to content

Commit 77a5ac5

Browse files
authored
chore: unify bls (#337)
1 parent 7d32afb commit 77a5ac5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1211
-765
lines changed

Cargo.lock

Lines changed: 541 additions & 66 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ axum-extra = { version = "0.10.0", features = ["typed-header"] }
2424
base64 = "0.22.1"
2525
bimap = { version = "0.6.3", features = ["serde"] }
2626
blsful = "2.5"
27-
blst = "0.3.11"
2827
bytes = "1.10.1"
2928
cb-cli = { path = "crates/cli" }
3029
cb-common = { path = "crates/common" }
@@ -38,7 +37,6 @@ ctr = "0.9.2"
3837
derive_more = { version = "2.0.1", features = ["deref", "display", "from", "into"] }
3938
docker-compose-types = "0.16.0"
4039
docker-image = "0.2.1"
41-
eth2_keystore = { git = "https://github.com/sigp/lighthouse", tag = "v7.0.1" }
4240
ethereum_serde_utils = "0.7.0"
4341
ethereum_ssz = "0.8"
4442
ethereum_ssz_derive = "0.8"
@@ -48,6 +46,8 @@ headers = "0.4.0"
4846
indexmap = "2.2.6"
4947
jsonwebtoken = { version = "9.3.1", default-features = false }
5048
lazy_static = "1.5.0"
49+
lh_eth2_keystore = { package = "eth2_keystore", git = "https://github.com/sigp/lighthouse", tag = "v7.1.0" }
50+
lh_types = { package = "types", git = "https://github.com/sigp/lighthouse", tag = "v7.1.0" }
5151
parking_lot = "0.12.3"
5252
pbkdf2 = "0.12.2"
5353
prometheus = "0.13.4"

benches/pbs/src/main.rs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
use std::time::{Duration, Instant};
22

3-
use alloy::{primitives::B256, rpc::types::beacon::BlsPublicKey};
3+
use alloy::primitives::B256;
44
use cb_common::{
55
config::RelayConfig,
66
pbs::{GetHeaderResponse, RelayClient, RelayEntry},
7-
signer::BlsSecretKey,
8-
types::Chain,
9-
utils::blst_pubkey_to_alloy,
7+
types::{BlsPublicKey, BlsSecretKey, Chain},
8+
utils::TestRandomSeed,
109
};
1110
use cb_tests::mock_relay::{start_mock_relay_service, MockRelayState};
1211
use comfy_table::Table;
@@ -18,9 +17,6 @@ mod config;
1817
fn get_random_hash() -> B256 {
1918
B256::from(rand::random::<[u8; 32]>())
2019
}
21-
fn get_random_pubkey() -> BlsPublicKey {
22-
BlsPublicKey::ZERO
23-
}
2420

2521
#[tokio::main]
2622
async fn main() {
@@ -46,8 +42,8 @@ async fn main() {
4642
// bench
4743
for slot in 0..config.benchmark.n_slots {
4844
let parent_hash = get_random_hash();
49-
let validator_pubkey = get_random_pubkey();
50-
let url = mock_validator.get_header_url(slot, parent_hash, validator_pubkey).unwrap();
45+
let validator_pubkey = BlsPublicKey::test_random();
46+
let url = mock_validator.get_header_url(slot, &parent_hash, &validator_pubkey).unwrap();
5147

5248
for _ in 0..config.benchmark.headers_per_slot {
5349
let url = url.clone();
@@ -138,8 +134,8 @@ const MOCK_RELAY_SECRET: [u8; 32] = [
138134
152, 98, 59, 240, 181, 131, 47, 1, 180, 255, 245,
139135
];
140136
async fn start_mock_relay(chain: Chain, relay_config: RelayConfig) {
141-
let signer = BlsSecretKey::key_gen(&MOCK_RELAY_SECRET, &[]).unwrap();
142-
let pubkey: BlsPublicKey = blst_pubkey_to_alloy(&signer.sk_to_pk());
137+
let signer = BlsSecretKey::deserialize(&MOCK_RELAY_SECRET).unwrap();
138+
let pubkey: BlsPublicKey = signer.public_key();
143139

144140
assert_eq!(relay_config.entry.pubkey, pubkey, "Expected relay pubkey to be 0xb060572f535ba5615b874ebfef757fbe6825352ad257e31d724e57fe25a067a13cfddd0f00cb17bf3a3d2e901a380c17");
145141

@@ -152,7 +148,7 @@ async fn start_mock_relay(chain: Chain, relay_config: RelayConfig) {
152148
}
153149

154150
fn get_mock_validator(bench: BenchConfig) -> RelayClient {
155-
let entry = RelayEntry { id: bench.id, pubkey: BlsPublicKey::default(), url: bench.url };
151+
let entry = RelayEntry { id: bench.id, pubkey: BlsPublicKey::test_random(), url: bench.url };
156152
let config = RelayConfig {
157153
entry,
158154
id: None,

bin/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ pub mod prelude {
1010
load_pbs_custom_config, LogsSettings, StartCommitModuleConfig, PBS_MODULE_NAME,
1111
},
1212
pbs::{BuilderEvent, BuilderEventClient, OnBuilderApiEvent},
13-
signer::{BlsPublicKey, BlsSignature, EcdsaSignature},
14-
types::Chain,
13+
signer::EcdsaSignature,
14+
types::{BlsPublicKey, BlsSignature, Chain},
1515
utils::{initialize_tracing_log, utcnow_ms, utcnow_ns, utcnow_sec, utcnow_us},
1616
};
1717
pub use cb_metrics::provider::MetricsProvider;

crates/common/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,19 @@ async-trait.workspace = true
1212
axum.workspace = true
1313
base64.workspace = true
1414
bimap.workspace = true
15-
blst.workspace = true
1615
bytes.workspace = true
1716
cipher.workspace = true
1817
ctr.workspace = true
1918
derive_more.workspace = true
2019
docker-image.workspace = true
21-
eth2_keystore.workspace = true
2220
ethereum_serde_utils.workspace = true
2321
ethereum_ssz.workspace = true
2422
ethereum_ssz_derive.workspace = true
2523
eyre.workspace = true
2624
futures.workspace = true
2725
jsonwebtoken.workspace = true
26+
lh_eth2_keystore.workspace = true
27+
lh_types.workspace = true
2828
pbkdf2.workspace = true
2929
rand.workspace = true
3030
rayon.workspace = true

crates/common/src/commit/client.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::time::{Duration, Instant};
22

3-
use alloy::{primitives::Address, rpc::types::beacon::BlsSignature};
3+
use alloy::primitives::Address;
44
use eyre::WrapErr;
55
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION};
66
use serde::Deserialize;
@@ -16,8 +16,8 @@ use super::{
1616
};
1717
use crate::{
1818
constants::SIGNER_JWT_EXPIRATION,
19-
signer::{BlsPublicKey, EcdsaSignature},
20-
types::{Jwt, ModuleId},
19+
signer::EcdsaSignature,
20+
types::{BlsPublicKey, BlsSignature, Jwt, ModuleId},
2121
utils::create_jwt,
2222
DEFAULT_REQUEST_TIMEOUT,
2323
};

crates/common/src/commit/request.rs

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,36 @@ use std::{
66
use alloy::{
77
hex,
88
primitives::{Address, B256},
9-
rpc::types::beacon::BlsSignature,
109
};
1110
use derive_more::derive::From;
1211
use serde::{Deserialize, Serialize};
1312
use tree_hash::TreeHash;
1413
use tree_hash_derive::TreeHash;
1514

1615
use crate::{
17-
constants::COMMIT_BOOST_DOMAIN, error::BlstErrorWrapper, signature::verify_signed_message,
18-
signer::BlsPublicKey, types::Chain,
16+
constants::COMMIT_BOOST_DOMAIN,
17+
signature::verify_signed_message,
18+
types::{BlsPublicKey, BlsSignature, Chain},
1919
};
2020

21-
pub trait ProxyId: AsRef<[u8]> + Debug + Clone + Copy + TreeHash + Display {}
21+
pub trait ProxyId: Debug + Clone + TreeHash + Display {
22+
fn to_bytes(&self) -> Vec<u8>;
23+
}
2224

23-
impl ProxyId for Address {}
25+
impl ProxyId for Address {
26+
fn to_bytes(&self) -> Vec<u8> {
27+
self.0.as_slice().to_vec()
28+
}
29+
}
2430

25-
impl ProxyId for BlsPublicKey {}
31+
impl ProxyId for BlsPublicKey {
32+
fn to_bytes(&self) -> Vec<u8> {
33+
self.serialize().to_vec()
34+
}
35+
}
2636

2737
// GENERIC PROXY DELEGATION
28-
#[derive(Debug, Clone, Copy, Serialize, Deserialize, TreeHash)]
38+
#[derive(Debug, Clone, Serialize, Deserialize, TreeHash)]
2939
pub struct ProxyDelegation<T: ProxyId> {
3040
pub delegator: BlsPublicKey,
3141
pub proxy: T,
@@ -40,7 +50,7 @@ impl<T: ProxyId> fmt::Display for ProxyDelegation<T> {
4050
}
4151
}
4252

43-
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
53+
#[derive(Debug, Clone, Serialize, Deserialize)]
4454
pub struct SignedProxyDelegation<T: ProxyId> {
4555
pub message: ProxyDelegation<T>,
4656
/// Signature of message with the delegator keypair
@@ -51,7 +61,7 @@ pub type SignedProxyDelegationBls = SignedProxyDelegation<BlsPublicKey>;
5161
pub type SignedProxyDelegationEcdsa = SignedProxyDelegation<Address>;
5262

5363
impl<T: ProxyId> SignedProxyDelegation<T> {
54-
pub fn validate(&self, chain: Chain) -> Result<(), BlstErrorWrapper> {
64+
pub fn validate(&self, chain: Chain) -> bool {
5565
verify_signed_message(
5666
chain,
5767
&self.message.delegator,
@@ -250,7 +260,7 @@ mod tests {
250260

251261
#[test]
252262
fn test_decode_response_signature() {
253-
let data = r#""0xa3ffa9241f78279f1af04644cb8c79c2d8f02bcf0e28e2f186f6dcccac0a869c2be441fda50f0dea895cfce2e53f0989a3ffa9241f78279f1af04644cb8c79c2d8f02bcf0e28e2f186f6dcccac0a869c2be441fda50f0dea895cfce2e53f0989""#;
263+
let data = r#""0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000""#;
254264
let _: BlsSignature = serde_json::from_str(data).unwrap();
255265

256266
let data = r#""0x985b495f49d1b96db3bba3f6c5dd1810950317c10d4c2042bd316f338cdbe74359072e209b85e56ac492092d7860063dd096ca31b4e164ef27e3f8d508e656801c""#;
@@ -283,7 +293,7 @@ mod tests {
283293
"delegator": "0xa3366b54f28e4bf1461926a3c70cdb0ec432b5c92554ecaae3742d33fb33873990cbed1761c68020e6d3c14d30a22050",
284294
"proxy": "0xa3366b54f28e4bf1461926a3c70cdb0ec432b5c92554ecaae3742d33fb33873990cbed1761c68020e6d3c14d30a22050"
285295
},
286-
"signature": "0xa3ffa9241f78279f1af04644cb8c79c2d8f02bcf0e28e2f186f6dcccac0a869c2be441fda50f0dea895cfce2e53f0989a3ffa9241f78279f1af04644cb8c79c2d8f02bcf0e28e2f186f6dcccac0a869c2be441fda50f0dea895cfce2e53f0989"
296+
"signature": "0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
287297
}"#;
288298

289299
let _: SignedProxyDelegationBls = serde_json::from_str(data).unwrap();
@@ -293,7 +303,7 @@ mod tests {
293303
"delegator": "0xa3366b54f28e4bf1461926a3c70cdb0ec432b5c92554ecaae3742d33fb33873990cbed1761c68020e6d3c14d30a22050",
294304
"proxy": "0x4ca9939a8311a7cab3dde201b70157285fa81a9d"
295305
},
296-
"signature": "0xa3ffa9241f78279f1af04644cb8c79c2d8f02bcf0e28e2f186f6dcccac0a869c2be441fda50f0dea895cfce2e53f0989a3ffa9241f78279f1af04644cb8c79c2d8f02bcf0e28e2f186f6dcccac0a869c2be441fda50f0dea895cfce2e53f0989"
306+
"signature": "0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
297307
}"#;
298308

299309
let _: SignedProxyDelegationEcdsa = serde_json::from_str(data).unwrap();

crates/common/src/config/mux.rs

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,21 @@ use std::{
88
use alloy::{
99
primitives::{address, Address, U256},
1010
providers::ProviderBuilder,
11-
rpc::{client::RpcClient, types::beacon::BlsPublicKey},
11+
rpc::{client::RpcClient, types::beacon::constants::BLS_PUBLIC_KEY_BYTES_LEN},
1212
sol,
1313
transports::http::Http,
1414
};
1515
use eyre::{bail, ensure, Context};
1616
use reqwest::Client;
17-
use serde::{Deserialize, Serialize};
17+
use serde::{Deserialize, Deserializer, Serialize};
1818
use tracing::{debug, info, warn};
1919
use url::Url;
2020

2121
use super::{load_optional_env_var, PbsConfig, RelayConfig, MUX_PATH_ENV};
2222
use crate::{
2323
config::{remove_duplicate_keys, safe_read_http_response},
2424
pbs::RelayClient,
25-
types::Chain,
25+
types::{BlsPublicKey, Chain},
2626
};
2727

2828
#[derive(Debug, Deserialize, Serialize)]
@@ -103,8 +103,8 @@ impl PbsMuxes {
103103
let config = Arc::new(config);
104104

105105
let runtime_config = RuntimeMuxConfig { id: mux.id, config, relays: relay_clients };
106-
for pubkey in mux.validator_pubkeys.iter() {
107-
configs.insert(*pubkey, runtime_config.clone());
106+
for pubkey in mux.validator_pubkeys.into_iter() {
107+
configs.insert(pubkey, runtime_config.clone());
108108
}
109109
}
110110

@@ -296,7 +296,6 @@ async fn fetch_lido_registry_keys(
296296
debug!("fetching {total_keys} total keys");
297297

298298
const CALL_BATCH_SIZE: u64 = 250u64;
299-
const BLS_PK_LEN: usize = BlsPublicKey::len_bytes();
300299

301300
let mut keys = vec![];
302301
let mut offset = 0;
@@ -311,13 +310,16 @@ async fn fetch_lido_registry_keys(
311310
.pubkeys;
312311

313312
ensure!(
314-
pubkeys.len() % BLS_PK_LEN == 0,
315-
"unexpected number of keys in batch, expected multiple of {BLS_PK_LEN}, got {}",
313+
pubkeys.len() % BLS_PUBLIC_KEY_BYTES_LEN == 0,
314+
"unexpected number of keys in batch, expected multiple of {BLS_PUBLIC_KEY_BYTES_LEN}, got {}",
316315
pubkeys.len()
317316
);
318317

319-
for chunk in pubkeys.chunks(BLS_PK_LEN) {
320-
keys.push(BlsPublicKey::try_from(chunk)?);
318+
for chunk in pubkeys.chunks(BLS_PUBLIC_KEY_BYTES_LEN) {
319+
keys.push(
320+
BlsPublicKey::deserialize(chunk)
321+
.map_err(|_| eyre::eyre!("invalid BLS public key"))?,
322+
);
321323
}
322324

323325
offset += limit;
@@ -356,10 +358,13 @@ async fn fetch_ssv_pubkeys(
356358
);
357359

358360
let response = fetch_ssv_pubkeys_from_url(&url, http_timeout).await?;
359-
pubkeys.extend(response.validators.iter().map(|v| v.pubkey).collect::<Vec<BlsPublicKey>>());
361+
let fetched = response.validators.len();
362+
pubkeys.extend(
363+
response.validators.into_iter().map(|v| v.pubkey).collect::<Vec<BlsPublicKey>>(),
364+
);
360365
page += 1;
361366

362-
if response.validators.len() < MAX_PER_PAGE {
367+
if fetched < MAX_PER_PAGE {
363368
ensure!(
364369
pubkeys.len() == response.pagination.total,
365370
"expected {} keys, got {}",
@@ -397,12 +402,29 @@ struct SSVResponse {
397402
pagination: SSVPagination,
398403
}
399404

400-
#[derive(Deserialize)]
401405
struct SSVValidator {
402-
#[serde(rename = "public_key")]
403406
pubkey: BlsPublicKey,
404407
}
405408

409+
impl<'de> Deserialize<'de> for SSVValidator {
410+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
411+
where
412+
D: Deserializer<'de>,
413+
{
414+
#[derive(Deserialize)]
415+
struct SSVValidator {
416+
public_key: String,
417+
}
418+
419+
let s = SSVValidator::deserialize(deserializer)?;
420+
let bytes = alloy::hex::decode(&s.public_key).map_err(serde::de::Error::custom)?;
421+
let pubkey = BlsPublicKey::deserialize(&bytes)
422+
.map_err(|e| serde::de::Error::custom(format!("invalid BLS public key: {e:?}")))?;
423+
424+
Ok(Self { pubkey })
425+
}
426+
}
427+
406428
#[derive(Deserialize)]
407429
struct SSVPagination {
408430
total: usize,
@@ -412,15 +434,15 @@ struct SSVPagination {
412434
mod tests {
413435
use std::net::SocketAddr;
414436

415-
use alloy::{hex::FromHex, primitives::U256, providers::ProviderBuilder};
437+
use alloy::{primitives::U256, providers::ProviderBuilder};
416438
use axum::{response::Response, routing::get};
417439
use tokio::{net::TcpListener, task::JoinHandle};
418440
use url::Url;
419441

420442
use super::*;
421443
use crate::{
422444
config::{HTTP_TIMEOUT_SECONDS_DEFAULT, MUXER_HTTP_MAX_LENGTH},
423-
utils::{set_ignore_content_length, ResponseReadError},
445+
utils::{bls_pubkey_from_hex_unchecked, set_ignore_content_length, ResponseReadError},
424446
};
425447

426448
const TEST_HTTP_TIMEOUT: u64 = 2;
@@ -448,8 +470,11 @@ mod tests {
448470
.pubkeys;
449471

450472
let mut vec = vec![];
451-
for chunk in pubkeys.chunks(BlsPublicKey::len_bytes()) {
452-
vec.push(BlsPublicKey::try_from(chunk)?);
473+
for chunk in pubkeys.chunks(BLS_PUBLIC_KEY_BYTES_LEN) {
474+
vec.push(
475+
BlsPublicKey::deserialize(chunk)
476+
.map_err(|_| eyre::eyre!("invalid BLS public key"))?,
477+
);
453478
}
454479

455480
assert_eq!(vec.len(), LIMIT);
@@ -472,15 +497,9 @@ mod tests {
472497
// NOTE: requires that ssv_data.json dpesn't change
473498
assert_eq!(response.validators.len(), 3);
474499
let expected_pubkeys = [
475-
BlsPublicKey::from_hex(
476-
"0x967ba17a3e7f82a25aa5350ec34d6923e28ad8237b5a41efe2c5e325240d74d87a015bf04634f21900963539c8229b2a",
477-
)?,
478-
BlsPublicKey::from_hex(
479-
"0xac769e8cec802e8ffee34de3253be8f438a0c17ee84bdff0b6730280d24b5ecb77ebc9c985281b41ee3bda8663b6658c",
480-
)?,
481-
BlsPublicKey::from_hex(
482-
"0x8c866a5a05f3d45c49b457e29365259021a509c5daa82e124f9701a960ee87b8902e87175315ab638a3d8b1115b23639",
483-
)?,
500+
bls_pubkey_from_hex_unchecked("967ba17a3e7f82a25aa5350ec34d6923e28ad8237b5a41efe2c5e325240d74d87a015bf04634f21900963539c8229b2a"),
501+
bls_pubkey_from_hex_unchecked("ac769e8cec802e8ffee34de3253be8f438a0c17ee84bdff0b6730280d24b5ecb77ebc9c985281b41ee3bda8663b6658c"),
502+
bls_pubkey_from_hex_unchecked("8c866a5a05f3d45c49b457e29365259021a509c5daa82e124f9701a960ee87b8902e87175315ab638a3d8b1115b23639"),
484503
];
485504
for (i, validator) in response.validators.iter().enumerate() {
486505
assert_eq!(validator.pubkey, expected_pubkeys[i]);

0 commit comments

Comments
 (0)