Skip to content

Commit 91f2cb4

Browse files
committed
Merge branch 'main' into sigp-audit-fixes
2 parents 5935659 + 9feb4d2 commit 91f2cb4

File tree

29 files changed

+507
-3046
lines changed

29 files changed

+507
-3046
lines changed

.github/workflows/docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: Docs
33
on:
44
push:
55
branches:
6-
- main
6+
- stable
77
# Review gh actions docs if you want to further define triggers, paths, etc
88
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on
99

config.example.toml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Some fields are optional and can be omitted, in which case the default value, if present, will be used.
33

44
# Chain spec ID. Supported values:
5-
# A network ID. Supported values: Mainnet, Holesky, Sepolia, Helder, Hoodi.
5+
# A network ID. Supported values: Mainnet, Holesky, Sepolia, Helder, Hoodi. Lower case values e.g. "mainnet" are also accepted
66
# A custom object, e.g., chain = { genesis_time_secs = 1695902400, path = "/path/to/spec.json" }, with a path to a chain spec file, either in .json format (e.g., as returned by the beacon endpoint /eth/v1/config/spec), or in .yml format (see examples in tests/data).
77
# A custom object, e.g., chain = { genesis_time_secs = 1695902400, slot_time_secs = 12, genesis_fork_version = "0x01017000" }.
88
chain = "Holesky"
@@ -212,19 +212,21 @@ jwt_auth_fail_timeout_seconds = 300
212212
[signer.local.loader]
213213
# File: path to the keys file
214214
key_path = "./tests/data/keys.example.json"
215-
# ValidatorsDir: format of the keystore (lighthouse, prysm, teku or lodestar)
215+
# ValidatorsDir: format of the keystore (lighthouse, prysm, teku, lodestar, or nimbus)
216216
# format = "lighthouse"
217217
# ValidatorsDir: full path to the keys directory
218-
# For lighthouse, it's de path to the directory where the `<pubkey>/voting-keystore.json` directories are located.
218+
# For lighthouse, it's the path to the directory where the `<pubkey>` directories are located, under each of which is a `voting-keystore.json` file.
219219
# For prysm, it's the path to the `all-accounts.keystore.json` file.
220220
# For teku, it's the path to the directory where all `<pubkey>.json` files are located.
221221
# For lodestar, it's the path to the directory where all `<pubkey>.json` files are located.
222+
# For nimbus, it's the path to the directory where the `<pubkey>` directories are located, under each of which is a `keystore.json` file.
222223
# keys_path = ""
223224
# ValidatorsDir: full path to the secrets file/directory
224-
# For lighthouse, it's de path to the directory where the `<pubkey>.json` files are located.
225+
# For lighthouse, it's the path to the directory where the `<pubkey>` files are located.
225226
# For prysm, it's the path to the file containing the wallet decryption password.
226227
# For teku, it's the path to the directory where all `<pubkey>.txt` files are located.
227228
# For lodestar, it's the path to the file containing the decryption password.
229+
# For nimbus, it's the path to the directory where the `<pubkey>` files are located.
228230
# secrets_path = ""
229231
# Configuration for how the Signer module should store proxy delegations. Supported types of store are:
230232
# - File: store keys and delegations from a plain text file (unsafe, use only for testing purposes)

crates/cli/src/docker_init.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ pub async fn handle_docker_init(config_path: PathBuf, output_dir: PathBuf) -> Re
256256

257257
if let Some(mux_config) = cb_config.muxes {
258258
for mux in mux_config.muxes.iter() {
259-
if let Some((env_name, actual_path, internal_path)) = mux.loader_env() {
259+
if let Some((env_name, actual_path, internal_path)) = mux.loader_env()? {
260260
let (key, val) = get_env_val(&env_name, &internal_path);
261261
pbs_envs.insert(key, val);
262262
pbs_volumes.push(Volumes::Simple(format!("{}:{}:ro", actual_path, internal_path)));

crates/common/src/config/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub use utils::*;
2626
#[derive(Debug, Deserialize, Serialize)]
2727
pub struct CommitBoostConfig {
2828
pub chain: Chain,
29+
#[serde(default)]
2930
pub relays: Vec<RelayConfig>,
3031
pub pbs: StaticPbsConfig,
3132
#[serde(flatten)]

crates/common/src/config/mux.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -130,19 +130,29 @@ pub struct MuxConfig {
130130

131131
impl MuxConfig {
132132
/// Returns the env, actual path, and internal path to use for the file
133-
/// loader
134-
pub fn loader_env(&self) -> Option<(String, String, String)> {
135-
self.loader.as_ref().and_then(|loader| match loader {
133+
/// loader. In File mode, validates the mux file prior to returning.
134+
pub fn loader_env(&self) -> eyre::Result<Option<(String, String, String)>> {
135+
let Some(loader) = self.loader.as_ref() else {
136+
return Ok(None);
137+
};
138+
139+
match loader {
136140
MuxKeysLoader::File(path_buf) => {
137-
let path =
138-
path_buf.to_str().unwrap_or_else(|| panic!("invalid path: {:?}", path_buf));
139-
let internal_path = get_mux_path(&self.id);
141+
let Some(path) = path_buf.to_str() else {
142+
bail!("invalid path: {:?}", path_buf);
143+
};
144+
145+
let file = load_file(path)?;
146+
// make sure we can load the pubkeys correctly
147+
let _: Vec<BlsPublicKey> =
148+
serde_json::from_str(&file).wrap_err("failed to parse mux keys file")?;
140149

141-
Some((get_mux_env(&self.id), path.to_owned(), internal_path))
150+
let internal_path = get_mux_path(&self.id);
151+
Ok(Some((get_mux_env(&self.id), path.to_owned(), internal_path)))
142152
}
143-
MuxKeysLoader::HTTP { .. } => None,
144-
MuxKeysLoader::Registry { .. } => None,
145-
})
153+
MuxKeysLoader::HTTP { .. } => Ok(None),
154+
MuxKeysLoader::Registry { .. } => Ok(None),
155+
}
146156
}
147157
}
148158

crates/common/src/config/pbs.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,14 @@ pub async fn load_pbs_config() -> Result<PbsModuleConfig> {
229229
let config = CommitBoostConfig::from_env_path()?;
230230
config.validate().await?;
231231

232+
// Make sure relays isn't empty - since the config is still technically valid if
233+
// there are no relays for things like Docker compose generation, this check
234+
// isn't in validate().
235+
ensure!(
236+
!config.relays.is_empty(),
237+
"At least one relay must be configured to run the PBS service"
238+
);
239+
232240
// use endpoint from env if set, otherwise use default host and port
233241
let endpoint = if let Some(endpoint) = load_optional_env_var(PBS_ENDPOINT_ENV) {
234242
endpoint.parse()?

crates/common/src/pbs/types/beacon_block.rs

Lines changed: 9 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,8 @@ use serde::{Deserialize, Serialize};
33
use ssz_derive::{Decode, Encode};
44

55
use super::{
6-
blinded_block_body::{BlindedBeaconBlockBodyDeneb, BlindedBeaconBlockBodyElectra},
7-
blobs_bundle::BlobsBundle,
8-
execution_payload::ExecutionPayload,
9-
spec::{DenebSpec, ElectraSpec},
10-
utils::VersionedResponse,
6+
blinded_block_body::BlindedBeaconBlockBodyElectra, blobs_bundle::BlobsBundle,
7+
execution_payload::ExecutionPayload, spec::ElectraSpec, utils::VersionedResponse,
118
};
129

1310
#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)]
@@ -21,28 +18,24 @@ impl SignedBlindedBeaconBlock {
2118
pub fn block_hash(&self) -> B256 {
2219
match &self.message {
2320
BlindedBeaconBlock::Electra(b) => b.body.execution_payload_header.block_hash,
24-
BlindedBeaconBlock::Deneb(b) => b.body.execution_payload_header.block_hash,
2521
}
2622
}
2723

2824
pub fn block_number(&self) -> u64 {
2925
match &self.message {
3026
BlindedBeaconBlock::Electra(b) => b.body.execution_payload_header.block_number,
31-
BlindedBeaconBlock::Deneb(b) => b.body.execution_payload_header.block_number,
3227
}
3328
}
3429

3530
pub fn parent_hash(&self) -> B256 {
3631
match &self.message {
3732
BlindedBeaconBlock::Electra(b) => b.body.execution_payload_header.parent_hash,
38-
BlindedBeaconBlock::Deneb(b) => b.body.execution_payload_header.parent_hash,
3933
}
4034
}
4135

4236
pub fn slot(&self) -> u64 {
4337
match &self.message {
4438
BlindedBeaconBlock::Electra(b) => b.slot,
45-
BlindedBeaconBlock::Deneb(b) => b.slot,
4639
}
4740
}
4841
}
@@ -51,27 +44,15 @@ impl SignedBlindedBeaconBlock {
5144
#[serde(untagged)]
5245
#[ssz(enum_behaviour = "transparent")]
5346
pub enum BlindedBeaconBlock {
54-
Deneb(BlindedBeaconBlockDeneb),
5547
Electra(BlindedBeaconBlockElectra),
5648
}
5749

5850
impl Default for BlindedBeaconBlock {
5951
fn default() -> Self {
60-
Self::Deneb(BlindedBeaconBlockDeneb::default())
52+
Self::Electra(BlindedBeaconBlockElectra::default())
6153
}
6254
}
6355

64-
#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)]
65-
pub struct BlindedBeaconBlockDeneb {
66-
#[serde(with = "serde_utils::quoted_u64")]
67-
pub slot: u64,
68-
#[serde(with = "serde_utils::quoted_u64")]
69-
pub proposer_index: u64,
70-
pub parent_root: B256,
71-
pub state_root: B256,
72-
pub body: BlindedBeaconBlockBodyDeneb<DenebSpec>,
73-
}
74-
7556
#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)]
7657
pub struct BlindedBeaconBlockElectra {
7758
#[serde(with = "serde_utils::quoted_u64")]
@@ -84,30 +65,16 @@ pub struct BlindedBeaconBlockElectra {
8465
}
8566

8667
/// Returned by relay in submit_block
87-
pub type SubmitBlindedBlockResponse =
88-
VersionedResponse<PayloadAndBlobsDeneb, PayloadAndBlobsElectra>;
68+
pub type SubmitBlindedBlockResponse = VersionedResponse<PayloadAndBlobsElectra>;
8969

9070
impl SubmitBlindedBlockResponse {
9171
pub fn block_hash(&self) -> B256 {
9272
match self {
93-
VersionedResponse::Deneb(d) => d.block_hash(),
9473
VersionedResponse::Electra(d) => d.block_hash(),
9574
}
9675
}
9776
}
9877

99-
#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)]
100-
pub struct PayloadAndBlobsDeneb {
101-
pub execution_payload: ExecutionPayload<DenebSpec>,
102-
pub blobs_bundle: BlobsBundle<DenebSpec>,
103-
}
104-
105-
impl PayloadAndBlobsDeneb {
106-
pub fn block_hash(&self) -> B256 {
107-
self.execution_payload.block_hash
108-
}
109-
}
110-
11178
#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)]
11279
pub struct PayloadAndBlobsElectra {
11380
pub execution_payload: ExecutionPayload<ElectraSpec>,
@@ -128,23 +95,6 @@ mod tests {
12895
use super::*;
12996
use crate::utils::{test_encode_decode, test_encode_decode_ssz};
13097

131-
#[test]
132-
// this is from the builder api spec, but with sync_committee_bits fixed to
133-
// deserialize correctly
134-
fn test_signed_blinded_block_deneb() {
135-
let data = include_str!("testdata/signed-blinded-beacon-block-deneb-2.json");
136-
let block = test_encode_decode::<SignedBlindedBeaconBlock>(&data);
137-
assert!(matches!(block.message, BlindedBeaconBlock::Deneb(_)));
138-
}
139-
140-
#[test]
141-
// this is from mev-boost test data
142-
fn test_signed_blinded_block_fb_deneb() {
143-
let data = include_str!("testdata/signed-blinded-beacon-block-deneb.json");
144-
let block = test_encode_decode::<SignedBlindedBeaconBlock>(&data);
145-
assert!(matches!(block.message, BlindedBeaconBlock::Deneb(_)));
146-
}
147-
14898
#[test]
14999
// this is from mev-boost test data
150100
fn test_signed_blinded_block_fb_electra() {
@@ -156,11 +106,11 @@ mod tests {
156106
#[test]
157107
// this is from the builder api spec, but with blobs fixed to deserialize
158108
// correctly
159-
fn test_submit_blinded_block_response_deneb() {
109+
fn test_submit_blinded_block_response_electra() {
160110
let blob = alloy::primitives::hex::encode_prefixed([1; 131072]);
161111

162112
let data = json!({
163-
"version": "deneb",
113+
"version": "electra",
164114
"data": {
165115
"execution_payload": {
166116
"parent_hash":
@@ -209,7 +159,7 @@ mod tests {
209159
}).to_string();
210160

211161
let block = test_encode_decode::<SubmitBlindedBlockResponse>(&data);
212-
assert!(matches!(block, SubmitBlindedBlockResponse::Deneb(_)));
162+
assert!(matches!(block, SubmitBlindedBlockResponse::Electra(_)));
213163
}
214164

215165
#[test]
@@ -230,21 +180,10 @@ mod tests {
230180
#[test]
231181
// this is dummy data generated with https://github.com/attestantio/go-builder-client
232182
fn test_execution_payload_block_ssz() {
233-
let data_json = include_str!("testdata/execution-payload-deneb.json");
234-
let block_json = test_encode_decode::<PayloadAndBlobsDeneb>(&data_json);
235-
236-
let data_ssz = include_bytes!("testdata/execution-payload-deneb.ssz");
237-
let data_ssz = alloy::primitives::hex::decode(data_ssz).unwrap();
238-
test_encode_decode_ssz::<PayloadAndBlobsDeneb>(&data_ssz);
239-
240-
assert_eq!(block_json.as_ssz_bytes(), data_ssz);
241-
242-
// electra and deneb have the same execution payload
243-
244-
let data_json = include_str!("testdata/execution-payload-deneb.json");
183+
let data_json = include_str!("testdata/execution-payload-electra.json");
245184
let block_json = test_encode_decode::<PayloadAndBlobsElectra>(&data_json);
246185

247-
let data_ssz = include_bytes!("testdata/execution-payload-deneb.ssz");
186+
let data_ssz = include_bytes!("testdata/execution-payload-electra.ssz");
248187
let data_ssz = alloy::primitives::hex::decode(data_ssz).unwrap();
249188
test_encode_decode_ssz::<PayloadAndBlobsElectra>(&data_ssz);
250189

crates/common/src/pbs/types/blinded_block_body.rs

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,6 @@ use super::{
1111
kzg::KzgCommitments, spec::EthSpec, utils::*,
1212
};
1313

14-
#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)]
15-
#[serde(deny_unknown_fields)]
16-
pub struct BlindedBeaconBlockBodyDeneb<T: EthSpec> {
17-
pub randao_reveal: BlsSignature,
18-
pub eth1_data: Eth1Data,
19-
pub graffiti: B256,
20-
pub proposer_slashings: VariableList<ProposerSlashing, T::MaxProposerSlashings>,
21-
pub attester_slashings: VariableList<AttesterSlashingDeneb<T>, T::MaxAttesterSlashings>,
22-
pub attestations: VariableList<AttestationDeneb<T>, T::MaxAttestations>,
23-
pub deposits: VariableList<Deposit, T::MaxDeposits>,
24-
pub voluntary_exits: VariableList<SignedVoluntaryExit, T::MaxVoluntaryExits>,
25-
pub sync_aggregate: SyncAggregate<T>,
26-
pub execution_payload_header: ExecutionPayloadHeader<T>,
27-
pub bls_to_execution_changes:
28-
VariableList<SignedBlsToExecutionChange, T::MaxBlsToExecutionChanges>,
29-
pub blob_kzg_commitments: KzgCommitments<T>,
30-
}
31-
3214
#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)]
3315
#[serde(deny_unknown_fields)]
3416
pub struct BlindedBeaconBlockBodyElectra<T: EthSpec> {
@@ -93,28 +75,12 @@ pub struct ProposerSlashing {
9375
pub signed_header_2: SignedBeaconBlockHeader,
9476
}
9577

96-
#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)]
97-
pub struct AttesterSlashingDeneb<T: EthSpec> {
98-
pub attestation_1: IndexedAttestationDeneb<T>,
99-
pub attestation_2: IndexedAttestationDeneb<T>,
100-
}
101-
10278
#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)]
10379
pub struct AttesterSlashingElectra<T: EthSpec> {
10480
pub attestation_1: IndexedAttestationElectra<T>,
10581
pub attestation_2: IndexedAttestationElectra<T>,
10682
}
10783

108-
#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)]
109-
#[serde(bound = "T: EthSpec")]
110-
pub struct IndexedAttestationDeneb<T: EthSpec> {
111-
/// Lists validator registry indices, not committee indices.
112-
#[serde(with = "quoted_variable_list_u64")]
113-
pub attesting_indices: VariableList<u64, T::MaxValidatorsPerCommittee>,
114-
pub data: AttestationData,
115-
pub signature: BlsSignature,
116-
}
117-
11884
#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)]
11985
#[serde(bound = "T: EthSpec")]
12086
pub struct IndexedAttestationElectra<T: EthSpec> {
@@ -145,14 +111,6 @@ pub struct Checkpoint {
145111
pub root: B256,
146112
}
147113

148-
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
149-
#[serde(bound = "T: EthSpec")]
150-
pub struct AttestationDeneb<T: EthSpec> {
151-
pub aggregation_bits: BitList<T::MaxValidatorsPerCommittee>,
152-
pub data: AttestationData,
153-
pub signature: BlsSignature,
154-
}
155-
156114
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
157115
#[serde(bound = "T: EthSpec")]
158116
pub struct AttestationElectra<T: EthSpec> {

crates/common/src/pbs/types/execution_payload.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,13 @@ mod tests {
9595

9696
use super::*;
9797
use crate::{
98-
pbs::types::{execution_payload::Transactions, spec::DenebSpec},
98+
pbs::{types::execution_payload::Transactions, ElectraSpec},
9999
utils::test_encode_decode,
100100
};
101101

102102
#[test]
103103
fn test_empty_tx_root_hash() {
104-
let txs: Transactions<DenebSpec> = VariableList::empty();
104+
let txs: Transactions<ElectraSpec> = VariableList::empty();
105105
let txs_root = txs.tree_hash_root();
106106

107107
assert_eq!(txs_root, EMPTY_TX_ROOT_HASH);
@@ -129,7 +129,7 @@ mod tests {
129129
"excess_blob_gas": "95158272"
130130
}"#;
131131

132-
let parsed = test_encode_decode::<ExecutionPayloadHeader<DenebSpec>>(&data);
132+
let parsed = test_encode_decode::<ExecutionPayloadHeader<ElectraSpec>>(&data);
133133

134134
assert_eq!(
135135
parsed.parent_hash,

0 commit comments

Comments
 (0)