mirror of
https://github.com/logos-blockchain/logos-blockchain-testing.git
synced 2026-01-02 05:13:09 +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",
|
||||
"serde",
|
||||
"subnetworks-assignations",
|
||||
"thiserror 2.0.17",
|
||||
"time",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
@ -41,6 +41,7 @@ num-bigint = { version = "0.4", default-features = false }
|
||||
rand = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
subnetworks-assignations = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
time = { version = "0.3", default-features = 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")
|
||||
}
|
||||
|
||||
#[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 = nomos_ledger::Config {
|
||||
fn build_ledger_config(consensus_params: &ConsensusParams) -> nomos_ledger::Config {
|
||||
nomos_ledger::Config {
|
||||
epoch_config: EpochConfig {
|
||||
epoch_stake_distribution_stabilization: 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
|
||||
.into_iter()
|
||||
@ -235,17 +239,6 @@ fn create_utxos_for_leader_and_services(
|
||||
blend_notes: &mut Vec<ServiceNote>,
|
||||
da_notes: &mut Vec<ServiceNote>,
|
||||
) -> Vec<Utxo> {
|
||||
let derive_key_material = |prefix: &[u8], id_bytes: &[u8]| -> [u8; 16] {
|
||||
let mut sk_data = [0; 16];
|
||||
let prefix_len = prefix.len();
|
||||
|
||||
sk_data[..prefix_len].copy_from_slice(prefix);
|
||||
let remaining_len = 16 - prefix_len;
|
||||
sk_data[prefix_len..].copy_from_slice(&id_bytes[..remaining_len]);
|
||||
|
||||
sk_data
|
||||
};
|
||||
|
||||
let mut utxos = Vec::new();
|
||||
|
||||
// Assume output index which will be set by the ledger tx.
|
||||
@ -253,55 +246,68 @@ fn create_utxos_for_leader_and_services(
|
||||
|
||||
// Create notes for leader, Blend and DA declarations.
|
||||
for &id in ids {
|
||||
let sk_leader_data = derive_key_material(b"ld", &id);
|
||||
let sk_leader = UnsecuredZkKey::from(BigUint::from_bytes_le(&sk_leader_data));
|
||||
let pk_leader = sk_leader.to_public_key();
|
||||
leader_keys.push((pk_leader, sk_leader));
|
||||
utxos.push(Utxo {
|
||||
note: Note::new(1_000, pk_leader),
|
||||
tx_hash: BigUint::from(0u8).into(),
|
||||
output_index: 0,
|
||||
});
|
||||
output_index += 1;
|
||||
|
||||
let sk_da_data = derive_key_material(b"da", &id);
|
||||
let sk_da = ZkKey::from(BigUint::from_bytes_le(&sk_da_data));
|
||||
let pk_da = sk_da.to_public_key();
|
||||
let note_da = Note::new(1, pk_da);
|
||||
da_notes.push(ServiceNote {
|
||||
pk: pk_da,
|
||||
sk: sk_da,
|
||||
note: note_da,
|
||||
output_index,
|
||||
});
|
||||
utxos.push(Utxo {
|
||||
note: note_da,
|
||||
tx_hash: BigUint::from(0u8).into(),
|
||||
output_index: 0,
|
||||
});
|
||||
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;
|
||||
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 prefix_len = prefix.len();
|
||||
|
||||
sk_data[..prefix_len].copy_from_slice(prefix);
|
||||
let remaining_len = 16 - prefix_len;
|
||||
sk_data[prefix_len..].copy_from_slice(&id_bytes[..remaining_len]);
|
||||
|
||||
sk_data
|
||||
}
|
||||
|
||||
fn push_leader_utxo(
|
||||
id: [u8; 32],
|
||||
leader_keys: &mut Vec<(ZkPublicKey, UnsecuredZkKey)>,
|
||||
utxos: &mut Vec<Utxo>,
|
||||
output_index: usize,
|
||||
) -> usize {
|
||||
let sk_data = derive_key_material(b"ld", &id);
|
||||
let sk = UnsecuredZkKey::from(BigUint::from_bytes_le(&sk_data));
|
||||
let pk = sk.to_public_key();
|
||||
leader_keys.push((pk, sk));
|
||||
utxos.push(Utxo {
|
||||
note: Note::new(1_000, pk),
|
||||
tx_hash: BigUint::from(0u8).into(),
|
||||
output_index: 0,
|
||||
});
|
||||
output_index + 1
|
||||
}
|
||||
|
||||
fn push_service_note(
|
||||
prefix: &[u8],
|
||||
id: [u8; 32],
|
||||
notes: &mut Vec<ServiceNote>,
|
||||
utxos: &mut Vec<Utxo>,
|
||||
output_index: usize,
|
||||
) -> usize {
|
||||
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,
|
||||
});
|
||||
utxos.push(Utxo {
|
||||
note,
|
||||
tx_hash: BigUint::from(0u8).into(),
|
||||
output_index: 0,
|
||||
});
|
||||
output_index + 1
|
||||
}
|
||||
|
||||
fn append_wallet_utxos(mut utxos: Vec<Utxo>, wallet: &WalletConfig) -> Vec<Utxo> {
|
||||
for account in &wallet.accounts {
|
||||
utxos.push(Utxo {
|
||||
|
||||
@ -18,6 +18,7 @@ use nomos_node::NomosDaMembership;
|
||||
use num_bigint::BigUint;
|
||||
use rand::random;
|
||||
use subnetworks_assignations::{MembershipCreator as _, MembershipHandler as _};
|
||||
use thiserror::Error;
|
||||
use tracing::warn;
|
||||
|
||||
use crate::secret_key_to_peer_id;
|
||||
@ -168,9 +169,43 @@ pub fn create_da_configs(
|
||||
da_params: &DaParams,
|
||||
ports: &[u16],
|
||||
) -> 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
|
||||
// can form a membership.
|
||||
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 peer_ids = vec![];
|
||||
let mut listening_addresses = vec![];
|
||||
@ -199,7 +234,7 @@ pub fn create_da_configs(
|
||||
let mut assignations: HashMap<u16, HashSet<PeerId>> = HashMap::new();
|
||||
if peer_ids.is_empty() {
|
||||
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 {
|
||||
let mut sorted_peers = peer_ids.clone();
|
||||
@ -214,14 +249,15 @@ pub fn create_da_configs(
|
||||
members.insert(*peer);
|
||||
}
|
||||
}
|
||||
assignations.insert(u16::try_from(id).unwrap_or_default(), members);
|
||||
assignations.insert(id as u16, members);
|
||||
}
|
||||
}
|
||||
|
||||
template.init(SessionNumber::default(), assignations)
|
||||
};
|
||||
|
||||
ids.iter()
|
||||
Ok(ids
|
||||
.iter()
|
||||
.zip(node_keys)
|
||||
.enumerate()
|
||||
.map(|(i, (id, node_key))| {
|
||||
@ -267,5 +303,31 @@ pub fn create_da_configs(
|
||||
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],
|
||||
network_params: &NetworkParams,
|
||||
) -> Vec<Vec<Multiaddr>> {
|
||||
if swarm_configs.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let mut all_initial_peers = vec![];
|
||||
|
||||
match network_params.libp2p_network_layout {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user