mirror of
https://github.com/logos-blockchain/logos-blockchain-testing.git
synced 2026-01-02 13:23:13 +00:00
configs: validate DA subnet ids and handle empty network layouts
This commit is contained in:
parent
a582c00692
commit
540ef9f9c2
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -7215,6 +7215,7 @@ dependencies = [
|
|||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"serde",
|
"serde",
|
||||||
"subnetworks-assignations",
|
"subnetworks-assignations",
|
||||||
|
"thiserror 2.0.17",
|
||||||
"time",
|
"time",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -41,6 +41,7 @@ num-bigint = { version = "0.4", default-features = false }
|
|||||||
rand = { workspace = true }
|
rand = { workspace = true }
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
subnetworks-assignations = { workspace = true }
|
subnetworks-assignations = { workspace = true }
|
||||||
|
thiserror = { workspace = true }
|
||||||
time = { version = "0.3", default-features = true }
|
time = { version = "0.3", default-features = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
|
|
||||||
|
|||||||
@ -146,25 +146,8 @@ fn create_genesis_tx(utxos: &[Utxo]) -> GenesisTx {
|
|||||||
GenesisTx::from_tx(signed_mantle_tx).expect("Invalid genesis transaction")
|
GenesisTx::from_tx(signed_mantle_tx).expect("Invalid genesis transaction")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
fn build_ledger_config(consensus_params: &ConsensusParams) -> nomos_ledger::Config {
|
||||||
pub fn create_consensus_configs(
|
nomos_ledger::Config {
|
||||||
ids: &[[u8; 32]],
|
|
||||||
consensus_params: &ConsensusParams,
|
|
||||||
wallet: &WalletConfig,
|
|
||||||
) -> Vec<GeneralConsensusConfig> {
|
|
||||||
let mut leader_keys = Vec::new();
|
|
||||||
let mut blend_notes = Vec::new();
|
|
||||||
let mut da_notes = Vec::new();
|
|
||||||
|
|
||||||
let utxos = create_utxos_for_leader_and_services(
|
|
||||||
ids,
|
|
||||||
&mut leader_keys,
|
|
||||||
&mut blend_notes,
|
|
||||||
&mut da_notes,
|
|
||||||
);
|
|
||||||
let utxos = append_wallet_utxos(utxos, wallet);
|
|
||||||
let genesis_tx = create_genesis_tx(&utxos);
|
|
||||||
let ledger_config = nomos_ledger::Config {
|
|
||||||
epoch_config: EpochConfig {
|
epoch_config: EpochConfig {
|
||||||
epoch_stake_distribution_stabilization: NonZero::new(3).unwrap(),
|
epoch_stake_distribution_stabilization: NonZero::new(3).unwrap(),
|
||||||
epoch_period_nonce_buffer: NonZero::new(3).unwrap(),
|
epoch_period_nonce_buffer: NonZero::new(3).unwrap(),
|
||||||
@ -213,7 +196,28 @@ pub fn create_consensus_configs(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn create_consensus_configs(
|
||||||
|
ids: &[[u8; 32]],
|
||||||
|
consensus_params: &ConsensusParams,
|
||||||
|
wallet: &WalletConfig,
|
||||||
|
) -> Vec<GeneralConsensusConfig> {
|
||||||
|
let mut leader_keys = Vec::new();
|
||||||
|
let mut blend_notes = Vec::new();
|
||||||
|
let mut da_notes = Vec::new();
|
||||||
|
|
||||||
|
let utxos = create_utxos_for_leader_and_services(
|
||||||
|
ids,
|
||||||
|
&mut leader_keys,
|
||||||
|
&mut blend_notes,
|
||||||
|
&mut da_notes,
|
||||||
|
);
|
||||||
|
let utxos = append_wallet_utxos(utxos, wallet);
|
||||||
|
let genesis_tx = create_genesis_tx(&utxos);
|
||||||
|
let ledger_config = build_ledger_config(consensus_params);
|
||||||
|
|
||||||
leader_keys
|
leader_keys
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -235,7 +239,22 @@ fn create_utxos_for_leader_and_services(
|
|||||||
blend_notes: &mut Vec<ServiceNote>,
|
blend_notes: &mut Vec<ServiceNote>,
|
||||||
da_notes: &mut Vec<ServiceNote>,
|
da_notes: &mut Vec<ServiceNote>,
|
||||||
) -> Vec<Utxo> {
|
) -> Vec<Utxo> {
|
||||||
let derive_key_material = |prefix: &[u8], id_bytes: &[u8]| -> [u8; 16] {
|
let mut utxos = Vec::new();
|
||||||
|
|
||||||
|
// Assume output index which will be set by the ledger tx.
|
||||||
|
let mut output_index = 0;
|
||||||
|
|
||||||
|
// Create notes for leader, Blend and DA declarations.
|
||||||
|
for &id in ids {
|
||||||
|
output_index = push_leader_utxo(id, leader_keys, &mut utxos, output_index);
|
||||||
|
output_index = push_service_note(b"da", id, da_notes, &mut utxos, output_index);
|
||||||
|
output_index = push_service_note(b"bn", id, blend_notes, &mut utxos, output_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
utxos
|
||||||
|
}
|
||||||
|
|
||||||
|
fn derive_key_material(prefix: &[u8], id_bytes: &[u8; 32]) -> [u8; 16] {
|
||||||
let mut sk_data = [0; 16];
|
let mut sk_data = [0; 16];
|
||||||
let prefix_len = prefix.len();
|
let prefix_len = prefix.len();
|
||||||
|
|
||||||
@ -244,62 +263,49 @@ fn create_utxos_for_leader_and_services(
|
|||||||
sk_data[prefix_len..].copy_from_slice(&id_bytes[..remaining_len]);
|
sk_data[prefix_len..].copy_from_slice(&id_bytes[..remaining_len]);
|
||||||
|
|
||||||
sk_data
|
sk_data
|
||||||
};
|
}
|
||||||
|
|
||||||
let mut utxos = Vec::new();
|
fn push_leader_utxo(
|
||||||
|
id: [u8; 32],
|
||||||
// Assume output index which will be set by the ledger tx.
|
leader_keys: &mut Vec<(ZkPublicKey, UnsecuredZkKey)>,
|
||||||
let mut output_index = 0;
|
utxos: &mut Vec<Utxo>,
|
||||||
|
output_index: usize,
|
||||||
// Create notes for leader, Blend and DA declarations.
|
) -> usize {
|
||||||
for &id in ids {
|
let sk_data = derive_key_material(b"ld", &id);
|
||||||
let sk_leader_data = derive_key_material(b"ld", &id);
|
let sk = UnsecuredZkKey::from(BigUint::from_bytes_le(&sk_data));
|
||||||
let sk_leader = UnsecuredZkKey::from(BigUint::from_bytes_le(&sk_leader_data));
|
let pk = sk.to_public_key();
|
||||||
let pk_leader = sk_leader.to_public_key();
|
leader_keys.push((pk, sk));
|
||||||
leader_keys.push((pk_leader, sk_leader));
|
|
||||||
utxos.push(Utxo {
|
utxos.push(Utxo {
|
||||||
note: Note::new(1_000, pk_leader),
|
note: Note::new(1_000, pk),
|
||||||
tx_hash: BigUint::from(0u8).into(),
|
tx_hash: BigUint::from(0u8).into(),
|
||||||
output_index: 0,
|
output_index: 0,
|
||||||
});
|
});
|
||||||
output_index += 1;
|
output_index + 1
|
||||||
|
}
|
||||||
|
|
||||||
let sk_da_data = derive_key_material(b"da", &id);
|
fn push_service_note(
|
||||||
let sk_da = ZkKey::from(BigUint::from_bytes_le(&sk_da_data));
|
prefix: &[u8],
|
||||||
let pk_da = sk_da.to_public_key();
|
id: [u8; 32],
|
||||||
let note_da = Note::new(1, pk_da);
|
notes: &mut Vec<ServiceNote>,
|
||||||
da_notes.push(ServiceNote {
|
utxos: &mut Vec<Utxo>,
|
||||||
pk: pk_da,
|
output_index: usize,
|
||||||
sk: sk_da,
|
) -> usize {
|
||||||
note: note_da,
|
let sk_data = derive_key_material(prefix, &id);
|
||||||
|
let sk = ZkKey::from(BigUint::from_bytes_le(&sk_data));
|
||||||
|
let pk = sk.to_public_key();
|
||||||
|
let note = Note::new(1, pk);
|
||||||
|
notes.push(ServiceNote {
|
||||||
|
pk,
|
||||||
|
sk,
|
||||||
|
note,
|
||||||
output_index,
|
output_index,
|
||||||
});
|
});
|
||||||
utxos.push(Utxo {
|
utxos.push(Utxo {
|
||||||
note: note_da,
|
note,
|
||||||
tx_hash: BigUint::from(0u8).into(),
|
tx_hash: BigUint::from(0u8).into(),
|
||||||
output_index: 0,
|
output_index: 0,
|
||||||
});
|
});
|
||||||
output_index += 1;
|
output_index + 1
|
||||||
|
|
||||||
let sk_blend_data = derive_key_material(b"bn", &id);
|
|
||||||
let sk_blend = ZkKey::from(BigUint::from_bytes_le(&sk_blend_data));
|
|
||||||
let pk_blend = sk_blend.to_public_key();
|
|
||||||
let note_blend = Note::new(1, pk_blend);
|
|
||||||
blend_notes.push(ServiceNote {
|
|
||||||
pk: pk_blend,
|
|
||||||
sk: sk_blend,
|
|
||||||
note: note_blend,
|
|
||||||
output_index,
|
|
||||||
});
|
|
||||||
utxos.push(Utxo {
|
|
||||||
note: note_blend,
|
|
||||||
tx_hash: BigUint::from(0u8).into(),
|
|
||||||
output_index: 0,
|
|
||||||
});
|
|
||||||
output_index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
utxos
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append_wallet_utxos(mut utxos: Vec<Utxo>, wallet: &WalletConfig) -> Vec<Utxo> {
|
fn append_wallet_utxos(mut utxos: Vec<Utxo>, wallet: &WalletConfig) -> Vec<Utxo> {
|
||||||
|
|||||||
@ -18,6 +18,7 @@ use nomos_node::NomosDaMembership;
|
|||||||
use num_bigint::BigUint;
|
use num_bigint::BigUint;
|
||||||
use rand::random;
|
use rand::random;
|
||||||
use subnetworks_assignations::{MembershipCreator as _, MembershipHandler as _};
|
use subnetworks_assignations::{MembershipCreator as _, MembershipHandler as _};
|
||||||
|
use thiserror::Error;
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
use crate::secret_key_to_peer_id;
|
use crate::secret_key_to_peer_id;
|
||||||
@ -168,9 +169,43 @@ pub fn create_da_configs(
|
|||||||
da_params: &DaParams,
|
da_params: &DaParams,
|
||||||
ports: &[u16],
|
ports: &[u16],
|
||||||
) -> Vec<GeneralDaConfig> {
|
) -> Vec<GeneralDaConfig> {
|
||||||
|
try_create_da_configs(ids, da_params, ports).expect("failed to build DA configs")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum DaConfigError {
|
||||||
|
#[error("DA ports length mismatch (ids={ids}, ports={ports})")]
|
||||||
|
PortsLenMismatch { ids: usize, ports: usize },
|
||||||
|
#[error(
|
||||||
|
"DA subnetwork size too large for u16 subnetwork ids (effective_subnetwork_size={effective_subnetwork_size}, max={max})"
|
||||||
|
)]
|
||||||
|
SubnetworkTooLarge {
|
||||||
|
effective_subnetwork_size: usize,
|
||||||
|
max: usize,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_create_da_configs(
|
||||||
|
ids: &[[u8; 32]],
|
||||||
|
da_params: &DaParams,
|
||||||
|
ports: &[u16],
|
||||||
|
) -> Result<Vec<GeneralDaConfig>, DaConfigError> {
|
||||||
// Let the subnetwork size track the participant count so tiny local topologies
|
// Let the subnetwork size track the participant count so tiny local topologies
|
||||||
// can form a membership.
|
// can form a membership.
|
||||||
let effective_subnetwork_size = da_params.subnetwork_size.max(ids.len().max(1));
|
let effective_subnetwork_size = da_params.subnetwork_size.max(ids.len().max(1));
|
||||||
|
let max_subnetworks = u16::MAX as usize + 1;
|
||||||
|
if effective_subnetwork_size > max_subnetworks {
|
||||||
|
return Err(DaConfigError::SubnetworkTooLarge {
|
||||||
|
effective_subnetwork_size,
|
||||||
|
max: max_subnetworks,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if ports.len() < ids.len() {
|
||||||
|
return Err(DaConfigError::PortsLenMismatch {
|
||||||
|
ids: ids.len(),
|
||||||
|
ports: ports.len(),
|
||||||
|
});
|
||||||
|
}
|
||||||
let mut node_keys = vec![];
|
let mut node_keys = vec![];
|
||||||
let mut peer_ids = vec![];
|
let mut peer_ids = vec![];
|
||||||
let mut listening_addresses = vec![];
|
let mut listening_addresses = vec![];
|
||||||
@ -199,7 +234,7 @@ pub fn create_da_configs(
|
|||||||
let mut assignations: HashMap<u16, HashSet<PeerId>> = HashMap::new();
|
let mut assignations: HashMap<u16, HashSet<PeerId>> = HashMap::new();
|
||||||
if peer_ids.is_empty() {
|
if peer_ids.is_empty() {
|
||||||
for id in 0..effective_subnetwork_size {
|
for id in 0..effective_subnetwork_size {
|
||||||
assignations.insert(u16::try_from(id).unwrap_or_default(), HashSet::new());
|
assignations.insert(id as u16, HashSet::new());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut sorted_peers = peer_ids.clone();
|
let mut sorted_peers = peer_ids.clone();
|
||||||
@ -214,14 +249,15 @@ pub fn create_da_configs(
|
|||||||
members.insert(*peer);
|
members.insert(*peer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assignations.insert(u16::try_from(id).unwrap_or_default(), members);
|
assignations.insert(id as u16, members);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template.init(SessionNumber::default(), assignations)
|
template.init(SessionNumber::default(), assignations)
|
||||||
};
|
};
|
||||||
|
|
||||||
ids.iter()
|
Ok(ids
|
||||||
|
.iter()
|
||||||
.zip(node_keys)
|
.zip(node_keys)
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, (id, node_key))| {
|
.map(|(i, (id, node_key))| {
|
||||||
@ -267,5 +303,31 @@ pub fn create_da_configs(
|
|||||||
retry_commitments_limit: da_params.retry_commitments_limit,
|
retry_commitments_limit: da_params.retry_commitments_limit,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn try_create_da_configs_rejects_subnetwork_overflow() {
|
||||||
|
let ids = vec![[1u8; 32]];
|
||||||
|
let ports = vec![12345u16];
|
||||||
|
let mut params = DaParams::default();
|
||||||
|
params.subnetwork_size = u16::MAX as usize + 2;
|
||||||
|
|
||||||
|
let err = try_create_da_configs(&ids, ¶ms, &ports).unwrap_err();
|
||||||
|
assert!(matches!(err, DaConfigError::SubnetworkTooLarge { .. }));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn try_create_da_configs_rejects_port_mismatch() {
|
||||||
|
let ids = vec![[1u8; 32], [2u8; 32]];
|
||||||
|
let ports = vec![12345u16];
|
||||||
|
let params = DaParams::default();
|
||||||
|
|
||||||
|
let err = try_create_da_configs(&ids, ¶ms, &ports).unwrap_err();
|
||||||
|
assert!(matches!(err, DaConfigError::PortsLenMismatch { .. }));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -94,6 +94,10 @@ fn initial_peers_by_network_layout(
|
|||||||
swarm_configs: &[SwarmConfig],
|
swarm_configs: &[SwarmConfig],
|
||||||
network_params: &NetworkParams,
|
network_params: &NetworkParams,
|
||||||
) -> Vec<Vec<Multiaddr>> {
|
) -> Vec<Vec<Multiaddr>> {
|
||||||
|
if swarm_configs.is_empty() {
|
||||||
|
return Vec::new();
|
||||||
|
}
|
||||||
|
|
||||||
let mut all_initial_peers = vec![];
|
let mut all_initial_peers = vec![];
|
||||||
|
|
||||||
match network_params.libp2p_network_layout {
|
match network_params.libp2p_network_layout {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user