From a67c8f2c9fb94e4c3fe93b25c109d73dc4a5f41d Mon Sep 17 00:00:00 2001 From: "Andrew J. Stone" Date: Tue, 30 Sep 2025 19:46:32 +0000 Subject: [PATCH 1/3] TQ: Use BaseboardId instead of PlatformId PlatformId was used as an internal placeholder during trust quorum protocol development. In order to integrate the trust quorum protocol code into the rest of Omicron we need to use the proper `BaseboardId` type from `sled-agent-types`. The real `PlatformId` comes from the `dice-util-msgs` crate and we'll need to be able to compare that `PlatfromId` with `BaseboardId` and convert from `PlatformId` to `BaseboardId` in the future. --- Cargo.lock | 2 + sled-agent/types/Cargo.toml | 1 + sled-agent/types/src/sled.rs | 22 ++++++++++- trust-quorum/Cargo.toml | 1 + trust-quorum/src/alarm.rs | 2 +- trust-quorum/src/compute_key_share.rs | 8 ++-- trust-quorum/src/configuration.rs | 16 ++++---- trust-quorum/src/coordinator_state.rs | 26 ++++++------- trust-quorum/src/lib.rs | 50 ++----------------------- trust-quorum/src/messages.rs | 6 +-- trust-quorum/src/node.rs | 35 +++++++++-------- trust-quorum/src/node_ctx.rs | 34 ++++++++--------- trust-quorum/src/persistent_state.rs | 4 +- trust-quorum/src/rack_secret_loader.rs | 31 ++++++++------- trust-quorum/src/validators.rs | 44 +++++++++++----------- trust-quorum/test-utils/src/event.rs | 20 +++++----- trust-quorum/test-utils/src/lib.rs | 9 +++-- trust-quorum/test-utils/src/nexus.rs | 26 ++++++------- trust-quorum/test-utils/src/state.rs | 52 +++++++++++++------------- trust-quorum/tests/cluster.rs | 22 +++++------ 20 files changed, 201 insertions(+), 210 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a845d0d338..87d2e3010c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12574,6 +12574,7 @@ dependencies = [ "camino", "camino-tempfile", "chrono", + "daft", "iddqd", "nexus-sled-agent-shared", "omicron-common", @@ -14438,6 +14439,7 @@ dependencies = [ "serde_json", "serde_with", "sha3", + "sled-agent-types", "slog", "slog-error-chain", "static_assertions", diff --git a/sled-agent/types/Cargo.toml b/sled-agent/types/Cargo.toml index 10aab7af388..fb36c639ba1 100644 --- a/sled-agent/types/Cargo.toml +++ b/sled-agent/types/Cargo.toml @@ -13,6 +13,7 @@ async-trait.workspace = true bootstore.workspace = true camino.workspace = true chrono.workspace = true +daft.workspace = true iddqd.workspace = true nexus-sled-agent-shared.workspace = true # Note: we're trying to avoid a dependency from sled-agent-types to nexus-types diff --git a/sled-agent/types/src/sled.rs b/sled-agent/types/src/sled.rs index d63e418a062..0809e1d0690 100644 --- a/sled-agent/types/src/sled.rs +++ b/sled-agent/types/src/sled.rs @@ -7,6 +7,7 @@ use std::net::{IpAddr, Ipv6Addr, SocketAddrV6}; use async_trait::async_trait; +use daft::Diffable; use omicron_common::{ address::{self, Ipv6Subnet, SLED_PREFIX}, ledger::Ledgerable, @@ -22,7 +23,20 @@ pub const SWITCH_ZONE_BASEBOARD_FILE: &str = "/opt/oxide/baseboard.json"; /// A representation of a Baseboard ID as used in the inventory subsystem /// This type is essentially the same as a `Baseboard` except it doesn't have a /// revision or HW type (Gimlet, PC, Unknown). -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] +#[derive( + Clone, + Debug, + Serialize, + Deserialize, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + JsonSchema, + Diffable, +)] +#[daft(leaf)] pub struct BaseboardId { /// Oxide Part Number pub part_number: String, @@ -30,6 +44,12 @@ pub struct BaseboardId { pub serial_number: String, } +impl std::fmt::Display for BaseboardId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}:{}", self.part_number, self.serial_number) + } +} + /// A request to Add a given sled after rack initialization has occurred #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] pub struct AddSledRequest { diff --git a/trust-quorum/Cargo.toml b/trust-quorum/Cargo.toml index a358b625fb5..0b0dfefb0fe 100644 --- a/trust-quorum/Cargo.toml +++ b/trust-quorum/Cargo.toml @@ -25,6 +25,7 @@ secrecy.workspace = true serde.workspace = true serde_with.workspace = true sha3.workspace = true +sled-agent-types.workspace = true slog.workspace = true slog-error-chain.workspace = true static_assertions.workspace = true diff --git a/trust-quorum/src/alarm.rs b/trust-quorum/src/alarm.rs index c64446f8389..a7392184153 100644 --- a/trust-quorum/src/alarm.rs +++ b/trust-quorum/src/alarm.rs @@ -27,7 +27,7 @@ pub enum Alarm { MismatchedConfigurations { config1: Configuration, config2: Configuration, - // Either a stringified `PlatformId` or "Nexus" + // Either a stringified `BaseboardId` or "Nexus" from: String, }, diff --git a/trust-quorum/src/compute_key_share.rs b/trust-quorum/src/compute_key_share.rs index 648519733f5..9dbf43e3dc9 100644 --- a/trust-quorum/src/compute_key_share.rs +++ b/trust-quorum/src/compute_key_share.rs @@ -9,7 +9,7 @@ //! other nodes so that it can compute its own key share. use crate::{ - Alarm, Configuration, Epoch, NodeHandlerCtx, PeerMsgKind, PlatformId, + Alarm, Configuration, Epoch, NodeHandlerCtx, PeerMsgKind, BaseboardId, }; use gfss::gf256::Gf256; use gfss::shamir::{self, Share}; @@ -25,7 +25,7 @@ pub struct KeyShareComputer { // A copy of the configuration stored in persistent state config: Configuration, - collected_shares: BTreeMap, + collected_shares: BTreeMap, } #[cfg(feature = "danger_partial_eq_ct_wrapper")] @@ -63,7 +63,7 @@ impl KeyShareComputer { pub fn on_connect( &mut self, ctx: &mut impl NodeHandlerCtx, - peer: PlatformId, + peer: BaseboardId, ) { if self.config.members.contains_key(&peer) && !self.collected_shares.contains_key(&peer) @@ -79,7 +79,7 @@ impl KeyShareComputer { pub fn handle_share( &mut self, ctx: &mut impl NodeHandlerCtx, - from: PlatformId, + from: BaseboardId, epoch: Epoch, share: Share, ) -> bool { diff --git a/trust-quorum/src/configuration.rs b/trust-quorum/src/configuration.rs index 7e3568b5ad9..4373c076842 100644 --- a/trust-quorum/src/configuration.rs +++ b/trust-quorum/src/configuration.rs @@ -5,7 +5,7 @@ //! A configuration of a trust quroum at a given epoch use crate::crypto::{EncryptedRackSecrets, RackSecret, Sha3_256Digest}; -use crate::{Epoch, PlatformId, Threshold}; +use crate::{Epoch, BaseboardId, Threshold}; use daft::Diffable; use gfss::shamir::{Share, SplitError}; use iddqd::{IdOrdItem, id_upcast}; @@ -51,11 +51,11 @@ pub struct Configuration { pub epoch: Epoch, /// Who was the coordinator of this reconfiguration? - pub coordinator: PlatformId, + pub coordinator: BaseboardId, // All members of the current configuration and the hash of their key shares #[serde_as(as = "Vec<(_, _)>")] - pub members: BTreeMap, + pub members: BTreeMap, /// The number of sleds required to reconstruct the rack secret pub threshold: Threshold, @@ -77,9 +77,9 @@ impl IdOrdItem for Configuration { pub struct NewConfigParams<'a> { pub rack_id: RackUuid, pub epoch: Epoch, - pub members: &'a BTreeSet, + pub members: &'a BTreeSet, pub threshold: Threshold, - pub coordinator_id: &'a PlatformId, + pub coordinator_id: &'a BaseboardId, } impl Configuration { @@ -90,7 +90,7 @@ impl Configuration { /// the last committed epoch. pub fn new( params: NewConfigParams<'_>, - ) -> Result<(Configuration, BTreeMap), ConfigurationError> + ) -> Result<(Configuration, BTreeMap), ConfigurationError> { let coordinator = params.coordinator_id.clone(); let rack_secret = RackSecret::new(); @@ -110,8 +110,8 @@ impl Configuration { (s.clone(), digest) }); - let mut members: BTreeMap = BTreeMap::new(); - let mut shares: BTreeMap = BTreeMap::new(); + let mut members: BTreeMap = BTreeMap::new(); + let mut shares: BTreeMap = BTreeMap::new(); for (platform_id, (share, digest)) in params.members.iter().cloned().zip(shares_and_digests) { diff --git a/trust-quorum/src/coordinator_state.rs b/trust-quorum/src/coordinator_state.rs index 1a13240084a..82c9cffe205 100644 --- a/trust-quorum/src/coordinator_state.rs +++ b/trust-quorum/src/coordinator_state.rs @@ -10,7 +10,7 @@ use crate::crypto::{LrtqShare, PlaintextRackSecrets, ReconstructedRackSecret}; use crate::validators::{ ReconfigurationError, ValidatedLrtqUpgradeMsg, ValidatedReconfigureMsg, }; -use crate::{Configuration, Epoch, PeerMsgKind, PlatformId, RackSecret}; +use crate::{Configuration, Epoch, PeerMsgKind, BaseboardId, RackSecret}; use bootstore::trust_quorum::RackSecret as LrtqRackSecret; use daft::{Diffable, Leaf}; use gfss::shamir::Share; @@ -302,7 +302,7 @@ impl CoordinatorState { pub fn send_msgs_to( &mut self, ctx: &mut impl NodeHandlerCtx, - to: PlatformId, + to: BaseboardId, ) { match &self.op { CoordinatorOperation::CollectShares { @@ -349,7 +349,7 @@ impl CoordinatorState { /// Record a `PrepareAck` from another node as part of tracking /// quorum for the prepare phase of the trust quorum protocol. - pub fn ack_prepare(&mut self, from: PlatformId) { + pub fn ack_prepare(&mut self, from: BaseboardId) { match &mut self.op { CoordinatorOperation::Prepare { prepares, prepare_acks, .. @@ -384,7 +384,7 @@ impl CoordinatorState { pub fn handle_share( &mut self, ctx: &mut impl NodeHandlerCtx, - from: PlatformId, + from: BaseboardId, epoch: Epoch, share: Share, ) { @@ -501,7 +501,7 @@ impl CoordinatorState { pub fn handle_lrtq_share( &mut self, ctx: &mut impl NodeHandlerCtx, - from: PlatformId, + from: BaseboardId, share: LrtqShare, ) { match &mut self.op { @@ -627,7 +627,7 @@ impl CoordinatorState { &mut self, ctx: &mut impl NodeHandlerCtx, log: Logger, - mut new_shares: BTreeMap, + mut new_shares: BTreeMap, plaintext_secrets: PlaintextRackSecrets, ) { let new_epoch = self.configuration.epoch; @@ -714,25 +714,25 @@ impl CoordinatorState { pub enum CoordinatorOperation { CollectShares { old_epoch: Epoch, - old_collected_shares: BTreeMap, + old_collected_shares: BTreeMap, // These are new shares that the coordinator created that we carry along // until we get to `CoordinatorOperation::Prepare` - new_shares: BTreeMap, + new_shares: BTreeMap, }, CollectLrtqShares { - collected_lrtq_shares: BTreeMap, + collected_lrtq_shares: BTreeMap, // These are new shares that the coordinator created that we carry along // until we get to `CoordinatorOperation::Prepare` - new_shares: BTreeMap, + new_shares: BTreeMap, }, Prepare { /// The set of Prepares to send to each node - prepares: BTreeMap, + prepares: BTreeMap, /// Acknowledgements that the prepare has been received - prepare_acks: BTreeSet, + prepare_acks: BTreeSet, }, } @@ -749,7 +749,7 @@ impl CoordinatorOperation { /// Return the members that have acked prepares, if the current operation /// is `Prepare`. Otherwise return an empty set. - pub fn acked_prepares(&self) -> BTreeSet { + pub fn acked_prepares(&self) -> BTreeSet { if let CoordinatorOperation::Prepare { prepare_acks, .. } = self { prepare_acks.clone() } else { diff --git a/trust-quorum/src/lib.rs b/trust-quorum/src/lib.rs index d7259c6385a..b591c3c46c7 100644 --- a/trust-quorum/src/lib.rs +++ b/trust-quorum/src/lib.rs @@ -14,6 +14,7 @@ use daft::Diffable; use derive_more::Display; use gfss::shamir::Share; use serde::{Deserialize, Serialize}; +pub use sled_agent_types::sled::BaseboardId; use slog::{Logger, error, warn}; mod compute_key_share; @@ -91,57 +92,14 @@ impl Epoch { #[daft(leaf)] pub struct Threshold(pub u8); -/// A unique identifier for a given trust quorum member. -// -/// This data is derived from the subject common name in the platform identity -/// certificate that makes up part of the certificate chain used to establish -/// [sprockets](https://github.com/oxidecomputer/sprockets) connections. -/// -/// See RFDs 303 and 308 for more details. -#[derive( - Debug, - Clone, - PartialEq, - Eq, - PartialOrd, - Ord, - Serialize, - Deserialize, - Diffable, -)] -#[daft(leaf)] -pub struct PlatformId { - part_number: String, - serial_number: String, -} - -impl std::fmt::Display for PlatformId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}:{}", self.part_number, self.serial_number) - } -} - -impl PlatformId { - pub fn new(part_number: String, serial_number: String) -> PlatformId { - PlatformId { part_number, serial_number } - } - - pub fn part_number(&self) -> &str { - &self.part_number - } - - pub fn serial_number(&self) -> &str { - &self.serial_number - } -} /// A container to make messages between trust quorum nodes routable #[derive(Debug, Clone, Serialize, Deserialize, Diffable)] #[cfg_attr(feature = "danger_partial_eq_ct_wrapper", derive(PartialEq, Eq))] #[daft(leaf)] pub struct Envelope { - pub to: PlatformId, - pub from: PlatformId, + pub to: BaseboardId, + pub from: BaseboardId, pub msg: PeerMsg, } @@ -160,7 +118,7 @@ impl Envelope { pub fn validate_share( log: &Logger, config: &Configuration, - from: &PlatformId, + from: &BaseboardId, epoch: Epoch, share: &Share, ) -> bool { diff --git a/trust-quorum/src/messages.rs b/trust-quorum/src/messages.rs index fc8e3235255..1bd879d7fff 100644 --- a/trust-quorum/src/messages.rs +++ b/trust-quorum/src/messages.rs @@ -5,7 +5,7 @@ //! Messsages for the trust quorum protocol use crate::crypto::LrtqShare; -use crate::{Configuration, Epoch, PlatformId, Threshold}; +use crate::{Configuration, Epoch, BaseboardId, Threshold}; use gfss::shamir::Share; use omicron_uuid_kinds::RackUuid; use serde::{Deserialize, Serialize}; @@ -18,7 +18,7 @@ pub struct ReconfigureMsg { pub rack_id: RackUuid, pub epoch: Epoch, pub last_committed_epoch: Option, - pub members: BTreeSet, + pub members: BTreeSet, pub threshold: Threshold, } @@ -32,7 +32,7 @@ pub struct LrtqUpgradeMsg { // upgraded trust quorum cluster. This is implicit, as the membership of the // LRTQ cluster is computed based on the existing control plane sleds known // to Nexus. - pub members: BTreeSet, + pub members: BTreeSet, pub threshold: Threshold, } diff --git a/trust-quorum/src/node.rs b/trust-quorum/src/node.rs index 1ce2a4f22fd..bccec20596d 100644 --- a/trust-quorum/src/node.rs +++ b/trust-quorum/src/node.rs @@ -27,7 +27,7 @@ use crate::validators::{ }; use crate::{ Alarm, Configuration, CoordinatorState, Epoch, ExpungedMetadata, - NodeHandlerCtx, PlatformId, messages::*, + NodeHandlerCtx, BaseboardId, messages::*, }; use daft::{Diffable, Leaf}; use gfss::shamir::Share; @@ -368,7 +368,7 @@ impl Node { pub fn on_connect( &mut self, ctx: &mut impl NodeHandlerCtx, - peer: PlatformId, + peer: BaseboardId, ) { ctx.add_connection(peer.clone()); self.send_coordinator_msgs_to(ctx, peer.clone()); @@ -382,7 +382,7 @@ impl Node { pub fn on_disconnect( &mut self, ctx: &mut impl NodeHandlerCtx, - peer: PlatformId, + peer: BaseboardId, ) { ctx.remove_connection(&peer); } @@ -391,7 +391,7 @@ impl Node { pub fn handle( &mut self, ctx: &mut impl NodeHandlerCtx, - from: PlatformId, + from: BaseboardId, msg: PeerMsg, ) { if ctx.persistent_state().is_expunged() { @@ -451,7 +451,7 @@ impl Node { self.coordinator_state.as_ref() } - fn handle_prepare_ack(&mut self, from: PlatformId, epoch: Epoch) { + fn handle_prepare_ack(&mut self, from: BaseboardId, epoch: Epoch) { // Are we coordinating for this epoch? if let Some(cs) = &mut self.coordinator_state { let current_epoch = cs.msg().epoch(); @@ -482,7 +482,7 @@ impl Node { fn handle_expunged( &mut self, ctx: &mut impl NodeHandlerCtx, - from: PlatformId, + from: BaseboardId, epoch: Epoch, ) { if let Some(config) = ctx.persistent_state().latest_config() { @@ -730,7 +730,7 @@ impl Node { fn handle_get_share( &mut self, ctx: &mut impl NodeHandlerCtx, - from: PlatformId, + from: BaseboardId, epoch: Epoch, ) { if let Some(latest_committed_config) = @@ -822,7 +822,7 @@ impl Node { fn handle_share( &mut self, ctx: &mut impl NodeHandlerCtx, - from: PlatformId, + from: BaseboardId, epoch: Epoch, share: Share, ) { @@ -843,7 +843,7 @@ impl Node { fn handle_prepare( &mut self, ctx: &mut impl NodeHandlerCtx, - from: PlatformId, + from: BaseboardId, config: Configuration, share: Share, ) { @@ -928,7 +928,7 @@ impl Node { fn handle_get_lrtq_share( &mut self, ctx: &mut impl NodeHandlerCtx, - from: PlatformId, + from: BaseboardId, ) { // Have we already committed a TQ config? if let Some(latest_committed_config) = @@ -992,7 +992,7 @@ impl Node { fn handle_lrtq_share( &mut self, ctx: &mut impl NodeHandlerCtx, - from: PlatformId, + from: BaseboardId, share: LrtqShare, ) { if let Some(cs) = &mut self.coordinator_state { @@ -1014,7 +1014,7 @@ impl Node { fn send_coordinator_msgs_to( &mut self, ctx: &mut impl NodeHandlerCtx, - platform_id: PlatformId, + platform_id: BaseboardId, ) { // This function is called unconditionally in callbacks. We may not // actually be a coordinator. We ignore the call in that case. @@ -1074,7 +1074,7 @@ pub enum CommitError { #[error("cannot commit: not prepared for epoch {0}")] NotPrepared(Epoch), #[error("cannot commit: expunged at epoch {epoch} by {from}")] - Expunged { epoch: Epoch, from: PlatformId }, + Expunged { epoch: Epoch, from: BaseboardId }, } #[derive(Debug, Clone, thiserror::Error, PartialEq, Eq)] @@ -1086,7 +1086,7 @@ pub enum PrepareAndCommitError { MismatchedRackIdError, ), #[error("cannot commit: expunged at epoch {epoch} by {from}")] - Expunged { epoch: Epoch, from: PlatformId }, + Expunged { epoch: Epoch, from: BaseboardId }, } #[cfg(test)] @@ -1099,9 +1099,12 @@ mod tests { use proptest::prelude::*; use test_strategy::{Arbitrary, proptest}; - fn arb_member() -> impl Strategy { + fn arb_member() -> impl Strategy { (0..255u8).prop_map(|serial| { - PlatformId::new("test".into(), serial.to_string()) + BaseboardId { + part_number: "test".into(), + serial_number: serial.to_string(), + } }) } diff --git a/trust-quorum/src/node_ctx.rs b/trust-quorum/src/node_ctx.rs index 9e70063bc9f..57321bad317 100644 --- a/trust-quorum/src/node_ctx.rs +++ b/trust-quorum/src/node_ctx.rs @@ -5,7 +5,7 @@ //! Parameter to Node API calls that allows interaction with the system at large use crate::{ - Alarm, Envelope, PeerMsg, PeerMsgKind, PersistentState, PlatformId, + Alarm, Envelope, PeerMsg, PeerMsgKind, PersistentState, BaseboardId, persistent_state::PersistentStateDiff, }; use daft::{BTreeSetDiff, Diffable, Leaf}; @@ -13,9 +13,9 @@ use std::collections::BTreeSet; /// An API shared by [`NodeCallerCtx`] and [`NodeHandlerCtx`] pub trait NodeCommonCtx { - fn platform_id(&self) -> &PlatformId; + fn platform_id(&self) -> &BaseboardId; fn persistent_state(&self) -> &PersistentState; - fn connected(&self) -> &BTreeSet; + fn connected(&self) -> &BTreeSet; fn alarms(&self) -> &BTreeSet; } @@ -37,7 +37,7 @@ pub trait NodeCallerCtx: NodeCommonCtx { /// An API for an [`NodeCtx`] usable from inside FSM states pub trait NodeHandlerCtx: NodeCommonCtx { - fn send(&mut self, to: PlatformId, msg: PeerMsgKind); + fn send(&mut self, to: BaseboardId, msg: PeerMsgKind); /// Attempt to update the persistent state inside the callback `f`. If /// the state is updated, then `f` should return `true`, otherwise it should @@ -55,10 +55,10 @@ pub trait NodeHandlerCtx: NodeCommonCtx { F: FnOnce(&mut PersistentState) -> bool; /// Add a peer to the connected set - fn add_connection(&mut self, id: PlatformId); + fn add_connection(&mut self, id: BaseboardId); /// Remove a peer from the connected set - fn remove_connection(&mut self, id: &PlatformId); + fn remove_connection(&mut self, id: &BaseboardId); /// Record (in-memory) that an alarm has occurred fn raise_alarm(&mut self, alarm: Alarm); @@ -73,7 +73,7 @@ pub trait NodeHandlerCtx: NodeCommonCtx { #[cfg_attr(feature = "danger_partial_eq_ct_wrapper", derive(PartialEq, Eq))] pub struct NodeCtx { /// The unique hardware ID of a sled - platform_id: PlatformId, + platform_id: BaseboardId, /// State that gets persistenly stored in ledgers persistent_state: PersistentState, @@ -88,7 +88,7 @@ pub struct NodeCtx { outgoing: Vec, /// Connected peer nodes - connected: BTreeSet, + connected: BTreeSet, /// Any alarms that have occurred alarms: BTreeSet, @@ -97,7 +97,7 @@ pub struct NodeCtx { // For diffs we want to allow access to all fields, but not make them public in // the `NodeCtx` type itself. impl<'daft> NodeCtxDiff<'daft> { - pub fn platform_id(&self) -> Leaf<&PlatformId> { + pub fn platform_id(&self) -> Leaf<&BaseboardId> { self.platform_id } @@ -113,7 +113,7 @@ impl<'daft> NodeCtxDiff<'daft> { self.outgoing } - pub fn connected(&self) -> &BTreeSetDiff<'daft, PlatformId> { + pub fn connected(&self) -> &BTreeSetDiff<'daft, BaseboardId> { &self.connected } @@ -123,7 +123,7 @@ impl<'daft> NodeCtxDiff<'daft> { } impl NodeCtx { - pub fn new(platform_id: PlatformId) -> NodeCtx { + pub fn new(platform_id: BaseboardId) -> NodeCtx { NodeCtx { platform_id, persistent_state: PersistentState::empty(), @@ -135,7 +135,7 @@ impl NodeCtx { } pub fn new_with_persistent_state( - platform_id: PlatformId, + platform_id: BaseboardId, persistent_state: PersistentState, ) -> NodeCtx { NodeCtx { @@ -158,7 +158,7 @@ impl NodeCtx { } impl NodeCommonCtx for NodeCtx { - fn platform_id(&self) -> &PlatformId { + fn platform_id(&self) -> &BaseboardId { &self.platform_id } @@ -166,7 +166,7 @@ impl NodeCommonCtx for NodeCtx { &self.persistent_state } - fn connected(&self) -> &BTreeSet { + fn connected(&self) -> &BTreeSet { &self.connected } @@ -176,7 +176,7 @@ impl NodeCommonCtx for NodeCtx { } impl NodeHandlerCtx for NodeCtx { - fn send(&mut self, to: PlatformId, msg_kind: PeerMsgKind) { + fn send(&mut self, to: BaseboardId, msg_kind: PeerMsgKind) { let rack_id = self.persistent_state.rack_id().expect("rack id exists"); self.outgoing.push(Envelope { to, @@ -199,11 +199,11 @@ impl NodeHandlerCtx for NodeCtx { } } - fn add_connection(&mut self, id: PlatformId) { + fn add_connection(&mut self, id: BaseboardId) { self.connected.insert(id); } - fn remove_connection(&mut self, id: &PlatformId) { + fn remove_connection(&mut self, id: &BaseboardId) { self.connected.remove(id); } diff --git a/trust-quorum/src/persistent_state.rs b/trust-quorum/src/persistent_state.rs index ef63b5441aa..0af6c09a015 100644 --- a/trust-quorum/src/persistent_state.rs +++ b/trust-quorum/src/persistent_state.rs @@ -7,7 +7,7 @@ //! Note that this state is not necessarily directly serialized and saved. use crate::crypto::LrtqShare; -use crate::{Configuration, Epoch, PlatformId}; +use crate::{Configuration, Epoch, BaseboardId}; use bootstore::schemes::v0::SharePkgCommon as LrtqShareData; use daft::Diffable; use gfss::shamir::Share; @@ -134,7 +134,7 @@ pub struct ExpungedMetadata { pub epoch: Epoch, /// Which node this commit information was learned from - pub from: PlatformId, + pub from: BaseboardId, } /// A subset of information stored in [`PersistentState`] that is useful diff --git a/trust-quorum/src/rack_secret_loader.rs b/trust-quorum/src/rack_secret_loader.rs index a0a8b723cee..28f2f2062ef 100644 --- a/trust-quorum/src/rack_secret_loader.rs +++ b/trust-quorum/src/rack_secret_loader.rs @@ -9,7 +9,7 @@ use std::collections::BTreeMap; use crate::crypto::ReconstructedRackSecret; use crate::{ - Alarm, Configuration, Epoch, NodeHandlerCtx, PeerMsgKind, PlatformId, + Alarm, Configuration, Epoch, NodeHandlerCtx, PeerMsgKind, BaseboardId, RackSecret, Share, }; use daft::{BTreeMapDiff, Diffable, Leaf}; @@ -143,7 +143,7 @@ impl RackSecretLoader { pub fn handle_share( &mut self, ctx: &mut impl NodeHandlerCtx, - from: PlatformId, + from: BaseboardId, epoch: Epoch, share: Share, ) { @@ -174,7 +174,7 @@ impl RackSecretLoader { self.collector = None; } - pub fn on_connect(&self, ctx: &mut impl NodeHandlerCtx, peer: PlatformId) { + pub fn on_connect(&self, ctx: &mut impl NodeHandlerCtx, peer: BaseboardId) { if let Some(collector) = &self.collector { collector.on_connect(ctx, peer); } @@ -189,7 +189,7 @@ pub struct ShareCollector { // A copy of the configuration stored in persistent state #[daft(leaf)] config: Configuration, - shares: BTreeMap, + shares: BTreeMap, } #[cfg(feature = "danger_partial_eq_ct_wrapper")] @@ -207,7 +207,7 @@ impl<'daft> ShareCollectorDiff<'daft> { self.config } - pub fn shares(&self) -> &BTreeMapDiff<'daft, PlatformId, Share> { + pub fn shares(&self) -> &BTreeMapDiff<'daft, BaseboardId, Share> { &self.shares } } @@ -250,7 +250,7 @@ impl ShareCollector { pub fn handle_share( &mut self, ctx: &mut impl NodeHandlerCtx, - from: PlatformId, + from: BaseboardId, epoch: Epoch, share: Share, ) -> Option> { @@ -344,7 +344,7 @@ impl ShareCollector { } /// A peer node has connected to this one - pub fn on_connect(&self, ctx: &mut impl NodeHandlerCtx, peer: PlatformId) { + pub fn on_connect(&self, ctx: &mut impl NodeHandlerCtx, peer: BaseboardId) { if self.config.members.contains_key(&peer) { info!( self.log, @@ -374,10 +374,13 @@ mod tests { const NUM_INITIAL_MEMBERS: u8 = 5; pub fn initial_config() - -> (Configuration, RackSecret, BTreeMap) { + -> (Configuration, RackSecret, BTreeMap) { let threshold = Threshold(3); let initial_members: BTreeSet<_> = (0..NUM_INITIAL_MEMBERS) - .map(|serial| PlatformId::new("test".into(), serial.to_string())) + .map(|serial| BaseboardId { + part_number: "test".into(), + serial_number: serial.to_string(), + }) .collect(); let initial_rack_secret = RackSecret::new(); let shares: BTreeMap<_, _> = initial_members @@ -419,17 +422,17 @@ mod tests { new_member_serial: u8, old_config: &Configuration, old_rack_secret: ReconstructedRackSecret, - ) -> (Configuration, ReconstructedRackSecret, BTreeMap) + ) -> (Configuration, ReconstructedRackSecret, BTreeMap) { let threshold = Threshold(3); let rack_secret = RackSecret::new(); let mut new_members: BTreeSet<_> = old_config.members.keys().cloned().collect(); - new_members.insert(PlatformId::new( - "test".into(), - new_member_serial.to_string(), - )); + new_members.insert(BaseboardId { + part_number: "test".into(), + serial_number: new_member_serial.to_string(), + }); let num_members = new_members.len() as u8; let shares: BTreeMap<_, _> = new_members .into_iter() diff --git a/trust-quorum/src/validators.rs b/trust-quorum/src/validators.rs index 28bfa70b4d6..e7b3eeb0c12 100644 --- a/trust-quorum/src/validators.rs +++ b/trust-quorum/src/validators.rs @@ -7,7 +7,7 @@ use crate::configuration::{ConfigurationError, NewConfigParams}; use crate::messages::ReconfigureMsg; use crate::{ - Epoch, LrtqUpgradeMsg, NodeHandlerCtx, PersistentStateSummary, PlatformId, + Epoch, LrtqUpgradeMsg, NodeHandlerCtx, PersistentStateSummary, BaseboardId, Threshold, }; use daft::{BTreeSetDiff, Diffable, Leaf}; @@ -52,7 +52,7 @@ fn check_in_service( "sled was decommissioned on msg from {from:?} at epoch {epoch:?}: last prepared epoch = {last_prepared_epoch:?}" )] pub struct SledExpungedError { - from: PlatformId, + from: BaseboardId, epoch: Epoch, last_prepared_epoch: Option, } @@ -142,7 +142,7 @@ pub enum LrtqUpgradeError { ), #[error("cannot commit: expunged at epoch {epoch} by {from}")] - Expunged { epoch: Epoch, from: PlatformId }, + Expunged { epoch: Epoch, from: BaseboardId }, #[error("not an lrtq node - no lrtq key share")] NoLrtqShare, @@ -202,12 +202,12 @@ pub struct ValidatedReconfigureMsg { rack_id: RackUuid, epoch: Epoch, last_committed_epoch: Option, - members: BTreeSet, + members: BTreeSet, threshold: Threshold, // This is not included in the original `ReconfigureMsg`. It's implicit // in the node that Nexus sends the request to. - coordinator_id: PlatformId, + coordinator_id: BaseboardId, } // For diffs we want to allow access to all fields, but not make them public in @@ -225,7 +225,7 @@ impl<'daft> ValidatedReconfigureMsgDiff<'daft> { self.last_committed_epoch } - pub fn members(&self) -> &BTreeSetDiff<'daft, PlatformId> { + pub fn members(&self) -> &BTreeSetDiff<'daft, BaseboardId> { &self.members } @@ -233,7 +233,7 @@ impl<'daft> ValidatedReconfigureMsgDiff<'daft> { self.threshold } - pub fn coordinator_id(&self) -> Leaf<&PlatformId> { + pub fn coordinator_id(&self) -> Leaf<&BaseboardId> { self.coordinator_id } } @@ -281,7 +281,7 @@ impl ValidatedReconfigureMsg { /// that the ongoing coordination can continue. pub fn new( log: &Logger, - coordinator_id: &PlatformId, + coordinator_id: &BaseboardId, msg: ReconfigureMsg, persistent_state: PersistentStateSummary, last_reconfig_msg: Option<&ValidatedReconfigureMsg>, @@ -337,7 +337,7 @@ impl ValidatedReconfigureMsg { self.last_committed_epoch } - pub fn members(&self) -> &BTreeSet { + pub fn members(&self) -> &BTreeSet { &self.members } @@ -345,7 +345,7 @@ impl ValidatedReconfigureMsg { self.threshold } - pub fn coordinator_id(&self) -> &PlatformId { + pub fn coordinator_id(&self) -> &BaseboardId { &self.coordinator_id } @@ -477,12 +477,12 @@ impl<'a> From<&'a ValidatedLrtqUpgradeMsg> for NewConfigParams<'a> { pub struct ValidatedLrtqUpgradeMsg { rack_id: RackUuid, epoch: Epoch, - members: BTreeSet, + members: BTreeSet, threshold: Threshold, // This is not included in the original `LrtqUpgradeMsg`. It's implicit in // the node that Nexus sends the request to. - coordinator_id: PlatformId, + coordinator_id: BaseboardId, } impl ValidatedLrtqUpgradeMsg { @@ -567,7 +567,7 @@ impl ValidatedLrtqUpgradeMsg { self.epoch } - pub fn coordinator_id(&self) -> &PlatformId { + pub fn coordinator_id(&self) -> &BaseboardId { &self.coordinator_id } @@ -633,7 +633,7 @@ impl<'daft> ValidatedLrtqUpgradeMsgDiff<'daft> { self.epoch } - pub fn members(&self) -> &BTreeSetDiff<'daft, PlatformId> { + pub fn members(&self) -> &BTreeSetDiff<'daft, BaseboardId> { &self.members } @@ -641,7 +641,7 @@ impl<'daft> ValidatedLrtqUpgradeMsgDiff<'daft> { self.threshold } - pub fn coordinator_id(&self) -> Leaf<&PlatformId> { + pub fn coordinator_id(&self) -> Leaf<&BaseboardId> { self.coordinator_id } } @@ -656,13 +656,13 @@ mod tests { use test_strategy::{Arbitrary, proptest}; use uuid::Uuid; - fn arb_member() -> impl Strategy { + fn arb_member() -> impl Strategy { (0..255u8).prop_map(|serial| { - PlatformId::new("test".into(), serial.to_string()) + BaseboardId { part_number: "test".into(), serial_number: serial.to_string() } }) } - fn arb_members() -> impl Strategy> { + fn arb_members() -> impl Strategy> { proptest::collection::btree_set(arb_member(), 3..10) } @@ -686,7 +686,7 @@ mod tests { #[strategy(arb_rack_id())] rack_id: RackUuid, #[strategy(arb_members())] - members: BTreeSet, + members: BTreeSet, #[strategy((1..10u64).prop_map(|x| Epoch(x)))] epoch: Epoch, new_config: bool, @@ -733,7 +733,7 @@ mod tests { }; let mut members = input.members.clone(); members - .insert(PlatformId::new("test".into(), "removed_node".into())); + .insert(BaseboardId { part_number: "test".into(), serial_number: "removed_node".into() }); let last_reconfig_msg = ValidatedReconfigureMsg { rack_id: input.rack_id, epoch: msg.last_committed_epoch.unwrap(), @@ -803,7 +803,7 @@ mod tests { }; let mut members = input.members.clone(); members - .insert(PlatformId::new("test".into(), "removed_node".into())); + .insert(BaseboardId { part_number: "test".into(), serial_number: "removed_node".into() }); let last_reconfig_msg = ValidatedReconfigureMsg { rack_id: input.rack_id, epoch: msg.last_committed_epoch.unwrap(), @@ -838,7 +838,7 @@ mod tests { // Coordinator must be a member of the new group let msg = original_msg.clone(); - let bad_platform_id = PlatformId::new("bad".into(), "bad".into()); + let bad_platform_id = BaseboardId { part_number: "bad".into(), serial_number: "bad".into() }; let err = ValidatedReconfigureMsg::new( &logctx.log, &bad_platform_id, diff --git a/trust-quorum/test-utils/src/event.rs b/trust-quorum/test-utils/src/event.rs index 9748cc2f947..cc6e10a0b49 100644 --- a/trust-quorum/test-utils/src/event.rs +++ b/trust-quorum/test-utils/src/event.rs @@ -7,7 +7,7 @@ use crate::nexus::{NexusConfig, NexusReply}; use serde::{Deserialize, Serialize}; use std::collections::BTreeSet; -use trust_quorum::{Envelope, Epoch, PlatformId}; +use trust_quorum::{Envelope, Epoch, BaseboardId}; /// An event that can be fed into our system under test (SUT) /// @@ -18,7 +18,7 @@ pub enum Event { InitialSetup { member_universe_size: usize, config: NexusConfig, - crashed_nodes: BTreeSet, + crashed_nodes: BTreeSet, }, InitialSetupLrtq { member_universe_size: usize, @@ -31,24 +31,24 @@ pub enum Event { /// Since replay is deterministic, we actually know what this value is, /// even though a prior event may not have yet sent the message. DeliverEnvelope(Envelope), - LoadRackSecret(PlatformId, Epoch), - ClearSecrets(PlatformId), + LoadRackSecret(BaseboardId, Epoch), + ClearSecrets(BaseboardId), /// Pull a `NexusReply` off the underlay network and update the `NexusState` DeliverNexusReply(NexusReply), - CommitConfiguration(PlatformId), + CommitConfiguration(BaseboardId), Reconfigure(NexusConfig), LrtqUpgrade(NexusConfig), - CrashNode(PlatformId), + CrashNode(BaseboardId), RestartNode { - id: PlatformId, - connection_order: Vec, + id: BaseboardId, + connection_order: Vec, }, - PrepareAndCommit(PlatformId), + PrepareAndCommit(BaseboardId), } impl Event { /// Return which nodes the event may have mutated. - pub fn affected_nodes(&self) -> Vec { + pub fn affected_nodes(&self) -> Vec { match self { Self::InitialSetup { config, crashed_nodes, .. } => { config.members.union(&crashed_nodes).cloned().collect() diff --git a/trust-quorum/test-utils/src/lib.rs b/trust-quorum/test-utils/src/lib.rs index 7eccc64f5a9..6cc7d617f97 100644 --- a/trust-quorum/test-utils/src/lib.rs +++ b/trust-quorum/test-utils/src/lib.rs @@ -13,11 +13,14 @@ pub use event::Event; pub use event_log::EventLog; pub use state::TqState; -use trust_quorum::PlatformId; +use trust_quorum::BaseboardId; /// All possible members used in a test -pub fn member_universe(size: usize) -> Vec { +pub fn member_universe(size: usize) -> Vec { (0..size) - .map(|serial| PlatformId::new("test".into(), serial.to_string())) + .map(|serial| BaseboardId { + part_number: "test".into(), + serial_number: serial.to_string(), + }) .collect() } diff --git a/trust-quorum/test-utils/src/nexus.rs b/trust-quorum/test-utils/src/nexus.rs index da766049077..74ae738667b 100644 --- a/trust-quorum/test-utils/src/nexus.rs +++ b/trust-quorum/test-utils/src/nexus.rs @@ -11,7 +11,7 @@ use omicron_uuid_kinds::RackUuid; use serde::{Deserialize, Serialize}; use std::collections::BTreeSet; use trust_quorum::{ - Epoch, LrtqUpgradeMsg, PlatformId, ReconfigureMsg, Threshold, + Epoch, LrtqUpgradeMsg, BaseboardId, ReconfigureMsg, Threshold, }; // The operational state of nexus for a given configuration @@ -29,8 +29,8 @@ pub struct NexusConfig { pub op: NexusOp, pub epoch: Epoch, pub last_committed_epoch: Option, - pub coordinator: PlatformId, - pub members: BTreeSet, + pub coordinator: BaseboardId, + pub members: BTreeSet, // This is our `K` parameter pub threshold: Threshold, @@ -42,16 +42,16 @@ pub struct NexusConfig { // commit may occur. pub commit_crash_tolerance: u8, - pub prepared_members: BTreeSet, - pub committed_members: BTreeSet, + pub prepared_members: BTreeSet, + pub committed_members: BTreeSet, } impl NexusConfig { pub fn new( epoch: Epoch, last_committed_epoch: Option, - coordinator: PlatformId, - members: BTreeSet, + coordinator: BaseboardId, + members: BTreeSet, threshold: Threshold, ) -> NexusConfig { // We want a few extra nodes beyond `threshold` to ack before we commit. @@ -81,8 +81,8 @@ impl NexusConfig { // // We create it so that we can test upgrading out of it. pub fn new_lrtq( - coordinator: PlatformId, - members: BTreeSet, + coordinator: BaseboardId, + members: BTreeSet, ) -> NexusConfig { let threshold = Threshold((members.len() / 2 + 1) as u8); NexusConfig { @@ -155,7 +155,7 @@ impl NexusState { // Create a `ReconfigureMsg` for the latest nexus config pub fn reconfigure_msg_for_latest_config( &self, - ) -> (&PlatformId, ReconfigureMsg) { + ) -> (&BaseboardId, ReconfigureMsg) { let config = self.configs.iter().last().expect("at least one config"); (&config.coordinator, config.to_reconfigure_msg(self.rack_id)) } @@ -163,7 +163,7 @@ impl NexusState { // Create an `LrtqUpgradeMsg` for the latest nexus config pub fn lrtq_upgrade_msg_for_latest_config( &self, - ) -> (&PlatformId, LrtqUpgradeMsg) { + ) -> (&BaseboardId, LrtqUpgradeMsg) { let config = self.configs.iter().last().expect("at least one config"); (&config.coordinator, config.to_lrtq_upgrade_msg(self.rack_id)) } @@ -215,6 +215,6 @@ impl NexusState { Diffable, )] pub enum NexusReply { - AckedPreparesFromCoordinator { epoch: Epoch, acks: BTreeSet }, - CommitAck { from: PlatformId, epoch: Epoch }, + AckedPreparesFromCoordinator { epoch: Epoch, acks: BTreeSet }, + CommitAck { from: BaseboardId, epoch: Epoch }, } diff --git a/trust-quorum/test-utils/src/state.rs b/trust-quorum/test-utils/src/state.rs index 2479f9e60d7..ee2fe029b51 100644 --- a/trust-quorum/test-utils/src/state.rs +++ b/trust-quorum/test-utils/src/state.rs @@ -20,7 +20,7 @@ use std::fmt::Display; use trust_quorum::{ Configuration, CoordinatingMsg, CoordinatorOperation, CoordinatorStateDiff, Envelope, Epoch, LoadRackSecretError, Node, NodeCallerCtx, NodeCommonCtx, - NodeCtx, NodeCtxDiff, NodeDiff, PeerMsgKind, PersistentState, PlatformId, + NodeCtx, NodeCtxDiff, NodeDiff, PeerMsgKind, PersistentState, BaseboardId, ValidatedLrtqUpgradeMsgDiff, ValidatedReconfigureMsgDiff, }; @@ -36,7 +36,7 @@ pub struct TqState { pub sut: Sut, /// All in flight messages between nodes - pub bootstrap_network: BTreeMap>, + pub bootstrap_network: BTreeMap>, /// All in flight responses to nexus. We don't model the requests, as those /// are `Node` public method calls. But we don't want to synchronously @@ -54,10 +54,10 @@ pub struct TqState { pub nexus: NexusState, /// A cache of our member universe, so we only have to generate it once - pub member_universe: Vec, + pub member_universe: Vec, /// All possible system faults in our test - pub crashed_nodes: BTreeSet, + pub crashed_nodes: BTreeSet, /// All configurations ever generated by a coordinator. /// @@ -68,7 +68,7 @@ pub struct TqState { /// Expunged nodes cannot be added to a cluster. We never reuse nodes in /// this test. We include nodes here that may not know yet that they have /// been expunged in the `Sut`. - pub expunged: BTreeSet, + pub expunged: BTreeSet, } impl TqState { @@ -191,7 +191,7 @@ impl TqState { self.send_envelopes_from(&coordinator); } - pub fn send_envelopes_from(&mut self, id: &PlatformId) { + pub fn send_envelopes_from(&mut self, id: &BaseboardId) { let (_, ctx) = self.sut.nodes.get_mut(id).expect("node exists"); // Only send envelopes to alive nodes for envelope in ctx @@ -266,7 +266,7 @@ impl TqState { &mut self, member_universe_size: usize, config: NexusConfig, - crashed_nodes: BTreeSet, + crashed_nodes: BTreeSet, ) { // Generate the member universe self.member_universe = member_universe(member_universe_size); @@ -311,15 +311,15 @@ impl TqState { // Generate the member universe self.member_universe = member_universe(member_universe_size); - // Translate `PlatformId`s to `Baseboards`s for LRTQ membership + // Translate `BaseboardId`s to `Baseboards`s for LRTQ membership let baseboards: BTreeSet<_> = config .members .iter() .cloned() .map(|id| { Baseboard::new_pc( - id.serial_number().to_string(), - id.part_number().to_string(), + id.serial_number.clone(), + id.part_number.clone(), ) }) .collect(); @@ -357,7 +357,7 @@ impl TqState { } } - fn apply_event_commit(&mut self, id: PlatformId) { + fn apply_event_commit(&mut self, id: BaseboardId) { let rack_id = self.nexus.rack_id; let latest_config = self.nexus.latest_config(); let (node, ctx) = self.sut.nodes.get_mut(&id).expect("node exists"); @@ -378,7 +378,7 @@ impl TqState { // differences in rack secrets during test execution and tqdb playback. We // should fix this eventually, but it probably won't require changing this // method. - fn apply_event_prepare_and_commit(&mut self, id: PlatformId) { + fn apply_event_prepare_and_commit(&mut self, id: BaseboardId) { // Just grab the configuration from a prepared member here. In real code // Nexus will poll the coordinator for a configuration when it polls for // prepare acks. @@ -399,7 +399,7 @@ impl TqState { send_envelopes(ctx, &mut self.bootstrap_network, &self.crashed_nodes); } - fn apply_event_load_rack_secret(&mut self, id: PlatformId, epoch: Epoch) { + fn apply_event_load_rack_secret(&mut self, id: BaseboardId, epoch: Epoch) { let (node, ctx) = self.sut.nodes.get_mut(&id).expect("node exists"); // Postcondition checks @@ -457,7 +457,7 @@ impl TqState { } } - fn apply_event_clear_secrets(&mut self, id: PlatformId) { + fn apply_event_clear_secrets(&mut self, id: BaseboardId) { let (node, _) = self.sut.nodes.get_mut(&id).expect("node exists"); node.clear_secrets(); } @@ -466,7 +466,7 @@ impl TqState { self.underlay_network.push(reply); } - fn apply_event_crash_node(&mut self, id: PlatformId) { + fn apply_event_crash_node(&mut self, id: BaseboardId) { // We clear all the crashed node's destination messages self.bootstrap_network.remove(&id); @@ -495,8 +495,8 @@ impl TqState { fn apply_event_restart_node( &mut self, - id: PlatformId, - connection_order: Vec, + id: BaseboardId, + connection_order: Vec, ) { // The node is no longer crashed. self.crashed_nodes.remove(&id); @@ -677,8 +677,8 @@ impl TqState { /// Broken out of `TqState` to alleviate borrow checker woes fn send_envelopes( ctx: &mut NodeCtx, - bootstrap_network: &mut BTreeMap>, - crashed_nodes: &BTreeSet, + bootstrap_network: &mut BTreeMap>, + crashed_nodes: &BTreeSet, ) { for envelope in ctx.drain_envelopes().filter(|e| !crashed_nodes.contains(&e.to)) @@ -695,7 +695,7 @@ fn send_envelopes( #[derive(Debug, Clone, Diffable)] pub struct Sut { /// All nodes in the member universe - pub nodes: BTreeMap, + pub nodes: BTreeMap, } impl Sut { @@ -703,7 +703,7 @@ impl Sut { Sut { nodes: BTreeMap::new() } } - pub fn new(log: &Logger, universe: Vec) -> Sut { + pub fn new(log: &Logger, universe: Vec) -> Sut { let nodes = universe .into_iter() .map(|id| { @@ -717,8 +717,8 @@ impl Sut { pub fn new_lrtq( log: &Logger, - universe: Vec, - mut share_pkgs: BTreeMap, + universe: Vec, + mut share_pkgs: BTreeMap, ) -> Sut { // Populate the persistent state of each member in the LRTQ cluster // with a share pkg @@ -781,7 +781,7 @@ impl Display for TqStateDiff<'_> { } fn display_expunged_diff( - diff: &BTreeSetDiff<'_, PlatformId>, + diff: &BTreeSetDiff<'_, BaseboardId>, f: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { if !diff.added.is_empty() { @@ -794,7 +794,7 @@ fn display_expunged_diff( } fn display_faults_diff( - crashed_nodes: &BTreeSetDiff<'_, PlatformId>, + crashed_nodes: &BTreeSetDiff<'_, BaseboardId>, f: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { if !crashed_nodes.added.is_empty() { @@ -866,7 +866,7 @@ fn display_underlay_network_diff( } fn display_bootstrap_network_diff( - diff: &BTreeMapDiff<'_, PlatformId, Vec>, + diff: &BTreeMapDiff<'_, BaseboardId, Vec>, f: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { if !diff.added.is_empty() { diff --git a/trust-quorum/tests/cluster.rs b/trust-quorum/tests/cluster.rs index 1215e5b7eec..931e79a82c7 100644 --- a/trust-quorum/tests/cluster.rs +++ b/trust-quorum/tests/cluster.rs @@ -16,7 +16,7 @@ use slog::{Logger, info, o}; use std::collections::BTreeSet; use test_strategy::{Arbitrary, proptest}; use trust_quorum::{ - CoordinatorOperation, Epoch, NodeCallerCtx, NodeCommonCtx, PlatformId, + CoordinatorOperation, Epoch, NodeCallerCtx, NodeCommonCtx, BaseboardId, Threshold, }; use trust_quorum_test_utils::TqState; @@ -53,7 +53,7 @@ impl TestState { // event. let member_universe = trust_quorum_test_utils::member_universe(MEMBER_UNIVERSE_SIZE); - let members: BTreeSet = config + let members: BTreeSet = config .members .iter() .map(|index| member_universe[*index].clone()) @@ -77,7 +77,7 @@ impl TestState { // event. let member_universe = trust_quorum_test_utils::member_universe(MEMBER_UNIVERSE_SIZE); - let members: BTreeSet = config + let members: BTreeSet = config .members .iter() .map(|index| member_universe[*index].clone()) @@ -916,7 +916,7 @@ impl TestState { /// having to loop over all nodes when they haven't changed. fn check_invariants( &self, - affected_nodes: Vec, + affected_nodes: Vec, ) -> Result<(), TestCaseError> { self.invariant_all_nodes_have_same_configuration_per_epoch( &affected_nodes, @@ -939,7 +939,7 @@ impl TestState { /// * have no committed configurations fn invariant_expunged_nodes_have_actually_been_expunged( &self, - affected_nodes: &[PlatformId], + affected_nodes: &[BaseboardId], ) -> Result<(), TestCaseError> { for id in affected_nodes { if self.tq_state.expunged.contains(id) { @@ -975,7 +975,7 @@ impl TestState { /// Sometimes nodes may not have a configuration for a given epoch. fn invariant_all_nodes_have_same_configuration_per_epoch( &self, - affected_nodes: &[PlatformId], + affected_nodes: &[BaseboardId], ) -> Result<(), TestCaseError> { for id in affected_nodes { let (_, ctx) = @@ -1005,7 +1005,7 @@ impl TestState { /// only have acknowledgments from nodes that have seen the `Prepare`. fn invariant_nodes_have_prepared_if_coordinator_has_acks( &self, - affected_nodes: &[PlatformId], + affected_nodes: &[BaseboardId], ) -> Result<(), TestCaseError> { let (acked, epoch) = { let latest_config = self.tq_state.nexus.latest_config(); @@ -1056,7 +1056,7 @@ impl TestState { /// configuration and share for this epoch. fn invariant_nodes_have_committed_if_nexus_has_acks( &self, - affected_nodes: &[PlatformId], + affected_nodes: &[BaseboardId], ) -> Result<(), TestCaseError> { let latest_config = self.tq_state.nexus.latest_config(); if latest_config.op != NexusOp::Committed { @@ -1087,7 +1087,7 @@ impl TestState { // key share for the latest committed configuration that they know of. fn invariant_nodes_not_coordinating_and_computing_key_share_simultaneously( &self, - affected_nodes: &[PlatformId], + affected_nodes: &[BaseboardId], ) -> Result<(), TestCaseError> { for id in affected_nodes { let (node, _) = @@ -1106,7 +1106,7 @@ impl TestState { // Ensure there has been no alarm at any affected node fn invariant_no_alarms( &self, - affected_nodes: &[PlatformId], + affected_nodes: &[BaseboardId], ) -> Result<(), TestCaseError> { for id in affected_nodes { let (_, ctx) = @@ -1129,7 +1129,7 @@ impl TestState { pub enum Action { /// Deliver an in-flight bootstrap network msg if there is one. /// - /// The selector here is used to index into the `PlatformIds` of + /// The selector here is used to index into the `BaseboardIds` of /// `test_state.bootstrap_network`. #[weight(30)] DeliverEnvelope(Selector), From 0dd0f741148f2cc9096d14d797b69673f332b317 Mon Sep 17 00:00:00 2001 From: "Andrew J. Stone" Date: Tue, 30 Sep 2025 19:56:56 +0000 Subject: [PATCH 2/3] fmt --- trust-quorum/src/compute_key_share.rs | 2 +- trust-quorum/src/configuration.rs | 5 +++-- trust-quorum/src/coordinator_state.rs | 2 +- trust-quorum/src/lib.rs | 1 - trust-quorum/src/messages.rs | 2 +- trust-quorum/src/node.rs | 12 +++++------- trust-quorum/src/node_ctx.rs | 2 +- trust-quorum/src/persistent_state.rs | 2 +- trust-quorum/src/rack_secret_loader.rs | 2 +- trust-quorum/src/validators.rs | 24 ++++++++++++++++-------- trust-quorum/test-utils/src/event.rs | 2 +- trust-quorum/test-utils/src/nexus.rs | 2 +- trust-quorum/test-utils/src/state.rs | 8 ++++---- trust-quorum/tests/cluster.rs | 2 +- 14 files changed, 37 insertions(+), 31 deletions(-) diff --git a/trust-quorum/src/compute_key_share.rs b/trust-quorum/src/compute_key_share.rs index 9dbf43e3dc9..480a9108659 100644 --- a/trust-quorum/src/compute_key_share.rs +++ b/trust-quorum/src/compute_key_share.rs @@ -9,7 +9,7 @@ //! other nodes so that it can compute its own key share. use crate::{ - Alarm, Configuration, Epoch, NodeHandlerCtx, PeerMsgKind, BaseboardId, + Alarm, BaseboardId, Configuration, Epoch, NodeHandlerCtx, PeerMsgKind, }; use gfss::gf256::Gf256; use gfss::shamir::{self, Share}; diff --git a/trust-quorum/src/configuration.rs b/trust-quorum/src/configuration.rs index 4373c076842..2684a86da78 100644 --- a/trust-quorum/src/configuration.rs +++ b/trust-quorum/src/configuration.rs @@ -5,7 +5,7 @@ //! A configuration of a trust quroum at a given epoch use crate::crypto::{EncryptedRackSecrets, RackSecret, Sha3_256Digest}; -use crate::{Epoch, BaseboardId, Threshold}; +use crate::{BaseboardId, Epoch, Threshold}; use daft::Diffable; use gfss::shamir::{Share, SplitError}; use iddqd::{IdOrdItem, id_upcast}; @@ -110,7 +110,8 @@ impl Configuration { (s.clone(), digest) }); - let mut members: BTreeMap = BTreeMap::new(); + let mut members: BTreeMap = + BTreeMap::new(); let mut shares: BTreeMap = BTreeMap::new(); for (platform_id, (share, digest)) in params.members.iter().cloned().zip(shares_and_digests) diff --git a/trust-quorum/src/coordinator_state.rs b/trust-quorum/src/coordinator_state.rs index 82c9cffe205..5d8d394c32c 100644 --- a/trust-quorum/src/coordinator_state.rs +++ b/trust-quorum/src/coordinator_state.rs @@ -10,7 +10,7 @@ use crate::crypto::{LrtqShare, PlaintextRackSecrets, ReconstructedRackSecret}; use crate::validators::{ ReconfigurationError, ValidatedLrtqUpgradeMsg, ValidatedReconfigureMsg, }; -use crate::{Configuration, Epoch, PeerMsgKind, BaseboardId, RackSecret}; +use crate::{BaseboardId, Configuration, Epoch, PeerMsgKind, RackSecret}; use bootstore::trust_quorum::RackSecret as LrtqRackSecret; use daft::{Diffable, Leaf}; use gfss::shamir::Share; diff --git a/trust-quorum/src/lib.rs b/trust-quorum/src/lib.rs index b591c3c46c7..a389022af0f 100644 --- a/trust-quorum/src/lib.rs +++ b/trust-quorum/src/lib.rs @@ -92,7 +92,6 @@ impl Epoch { #[daft(leaf)] pub struct Threshold(pub u8); - /// A container to make messages between trust quorum nodes routable #[derive(Debug, Clone, Serialize, Deserialize, Diffable)] #[cfg_attr(feature = "danger_partial_eq_ct_wrapper", derive(PartialEq, Eq))] diff --git a/trust-quorum/src/messages.rs b/trust-quorum/src/messages.rs index 1bd879d7fff..af8c65424cd 100644 --- a/trust-quorum/src/messages.rs +++ b/trust-quorum/src/messages.rs @@ -5,7 +5,7 @@ //! Messsages for the trust quorum protocol use crate::crypto::LrtqShare; -use crate::{Configuration, Epoch, BaseboardId, Threshold}; +use crate::{BaseboardId, Configuration, Epoch, Threshold}; use gfss::shamir::Share; use omicron_uuid_kinds::RackUuid; use serde::{Deserialize, Serialize}; diff --git a/trust-quorum/src/node.rs b/trust-quorum/src/node.rs index bccec20596d..0571b58e35c 100644 --- a/trust-quorum/src/node.rs +++ b/trust-quorum/src/node.rs @@ -26,8 +26,8 @@ use crate::validators::{ ValidatedLrtqUpgradeMsg, ValidatedReconfigureMsg, }; use crate::{ - Alarm, Configuration, CoordinatorState, Epoch, ExpungedMetadata, - NodeHandlerCtx, BaseboardId, messages::*, + Alarm, BaseboardId, Configuration, CoordinatorState, Epoch, + ExpungedMetadata, NodeHandlerCtx, messages::*, }; use daft::{Diffable, Leaf}; use gfss::shamir::Share; @@ -1100,11 +1100,9 @@ mod tests { use test_strategy::{Arbitrary, proptest}; fn arb_member() -> impl Strategy { - (0..255u8).prop_map(|serial| { - BaseboardId { - part_number: "test".into(), - serial_number: serial.to_string(), - } + (0..255u8).prop_map(|serial| BaseboardId { + part_number: "test".into(), + serial_number: serial.to_string(), }) } diff --git a/trust-quorum/src/node_ctx.rs b/trust-quorum/src/node_ctx.rs index 57321bad317..9b46619bbc7 100644 --- a/trust-quorum/src/node_ctx.rs +++ b/trust-quorum/src/node_ctx.rs @@ -5,7 +5,7 @@ //! Parameter to Node API calls that allows interaction with the system at large use crate::{ - Alarm, Envelope, PeerMsg, PeerMsgKind, PersistentState, BaseboardId, + Alarm, BaseboardId, Envelope, PeerMsg, PeerMsgKind, PersistentState, persistent_state::PersistentStateDiff, }; use daft::{BTreeSetDiff, Diffable, Leaf}; diff --git a/trust-quorum/src/persistent_state.rs b/trust-quorum/src/persistent_state.rs index 0af6c09a015..ea450492ac4 100644 --- a/trust-quorum/src/persistent_state.rs +++ b/trust-quorum/src/persistent_state.rs @@ -7,7 +7,7 @@ //! Note that this state is not necessarily directly serialized and saved. use crate::crypto::LrtqShare; -use crate::{Configuration, Epoch, BaseboardId}; +use crate::{BaseboardId, Configuration, Epoch}; use bootstore::schemes::v0::SharePkgCommon as LrtqShareData; use daft::Diffable; use gfss::shamir::Share; diff --git a/trust-quorum/src/rack_secret_loader.rs b/trust-quorum/src/rack_secret_loader.rs index 28f2f2062ef..f355187fabb 100644 --- a/trust-quorum/src/rack_secret_loader.rs +++ b/trust-quorum/src/rack_secret_loader.rs @@ -9,7 +9,7 @@ use std::collections::BTreeMap; use crate::crypto::ReconstructedRackSecret; use crate::{ - Alarm, Configuration, Epoch, NodeHandlerCtx, PeerMsgKind, BaseboardId, + Alarm, BaseboardId, Configuration, Epoch, NodeHandlerCtx, PeerMsgKind, RackSecret, Share, }; use daft::{BTreeMapDiff, Diffable, Leaf}; diff --git a/trust-quorum/src/validators.rs b/trust-quorum/src/validators.rs index e7b3eeb0c12..9301e1cff01 100644 --- a/trust-quorum/src/validators.rs +++ b/trust-quorum/src/validators.rs @@ -7,7 +7,7 @@ use crate::configuration::{ConfigurationError, NewConfigParams}; use crate::messages::ReconfigureMsg; use crate::{ - Epoch, LrtqUpgradeMsg, NodeHandlerCtx, PersistentStateSummary, BaseboardId, + BaseboardId, Epoch, LrtqUpgradeMsg, NodeHandlerCtx, PersistentStateSummary, Threshold, }; use daft::{BTreeSetDiff, Diffable, Leaf}; @@ -657,8 +657,9 @@ mod tests { use uuid::Uuid; fn arb_member() -> impl Strategy { - (0..255u8).prop_map(|serial| { - BaseboardId { part_number: "test".into(), serial_number: serial.to_string() } + (0..255u8).prop_map(|serial| BaseboardId { + part_number: "test".into(), + serial_number: serial.to_string(), }) } @@ -732,8 +733,10 @@ mod tests { expunged: None, }; let mut members = input.members.clone(); - members - .insert(BaseboardId { part_number: "test".into(), serial_number: "removed_node".into() }); + members.insert(BaseboardId { + part_number: "test".into(), + serial_number: "removed_node".into(), + }); let last_reconfig_msg = ValidatedReconfigureMsg { rack_id: input.rack_id, epoch: msg.last_committed_epoch.unwrap(), @@ -802,8 +805,10 @@ mod tests { expunged: None, }; let mut members = input.members.clone(); - members - .insert(BaseboardId { part_number: "test".into(), serial_number: "removed_node".into() }); + members.insert(BaseboardId { + part_number: "test".into(), + serial_number: "removed_node".into(), + }); let last_reconfig_msg = ValidatedReconfigureMsg { rack_id: input.rack_id, epoch: msg.last_committed_epoch.unwrap(), @@ -838,7 +843,10 @@ mod tests { // Coordinator must be a member of the new group let msg = original_msg.clone(); - let bad_platform_id = BaseboardId { part_number: "bad".into(), serial_number: "bad".into() }; + let bad_platform_id = BaseboardId { + part_number: "bad".into(), + serial_number: "bad".into(), + }; let err = ValidatedReconfigureMsg::new( &logctx.log, &bad_platform_id, diff --git a/trust-quorum/test-utils/src/event.rs b/trust-quorum/test-utils/src/event.rs index cc6e10a0b49..3544456b3c3 100644 --- a/trust-quorum/test-utils/src/event.rs +++ b/trust-quorum/test-utils/src/event.rs @@ -7,7 +7,7 @@ use crate::nexus::{NexusConfig, NexusReply}; use serde::{Deserialize, Serialize}; use std::collections::BTreeSet; -use trust_quorum::{Envelope, Epoch, BaseboardId}; +use trust_quorum::{BaseboardId, Envelope, Epoch}; /// An event that can be fed into our system under test (SUT) /// diff --git a/trust-quorum/test-utils/src/nexus.rs b/trust-quorum/test-utils/src/nexus.rs index 74ae738667b..d59ec53cc9c 100644 --- a/trust-quorum/test-utils/src/nexus.rs +++ b/trust-quorum/test-utils/src/nexus.rs @@ -11,7 +11,7 @@ use omicron_uuid_kinds::RackUuid; use serde::{Deserialize, Serialize}; use std::collections::BTreeSet; use trust_quorum::{ - Epoch, LrtqUpgradeMsg, BaseboardId, ReconfigureMsg, Threshold, + BaseboardId, Epoch, LrtqUpgradeMsg, ReconfigureMsg, Threshold, }; // The operational state of nexus for a given configuration diff --git a/trust-quorum/test-utils/src/state.rs b/trust-quorum/test-utils/src/state.rs index ee2fe029b51..59b8524d8b7 100644 --- a/trust-quorum/test-utils/src/state.rs +++ b/trust-quorum/test-utils/src/state.rs @@ -18,10 +18,10 @@ use slog::{Logger, info}; use std::collections::{BTreeMap, BTreeSet}; use std::fmt::Display; use trust_quorum::{ - Configuration, CoordinatingMsg, CoordinatorOperation, CoordinatorStateDiff, - Envelope, Epoch, LoadRackSecretError, Node, NodeCallerCtx, NodeCommonCtx, - NodeCtx, NodeCtxDiff, NodeDiff, PeerMsgKind, PersistentState, BaseboardId, - ValidatedLrtqUpgradeMsgDiff, ValidatedReconfigureMsgDiff, + BaseboardId, Configuration, CoordinatingMsg, CoordinatorOperation, + CoordinatorStateDiff, Envelope, Epoch, LoadRackSecretError, Node, + NodeCallerCtx, NodeCommonCtx, NodeCtx, NodeCtxDiff, NodeDiff, PeerMsgKind, + PersistentState, ValidatedLrtqUpgradeMsgDiff, ValidatedReconfigureMsgDiff, }; // The state of our entire system including the system under test and diff --git a/trust-quorum/tests/cluster.rs b/trust-quorum/tests/cluster.rs index 931e79a82c7..39c1367661b 100644 --- a/trust-quorum/tests/cluster.rs +++ b/trust-quorum/tests/cluster.rs @@ -16,7 +16,7 @@ use slog::{Logger, info, o}; use std::collections::BTreeSet; use test_strategy::{Arbitrary, proptest}; use trust_quorum::{ - CoordinatorOperation, Epoch, NodeCallerCtx, NodeCommonCtx, BaseboardId, + BaseboardId, CoordinatorOperation, Epoch, NodeCallerCtx, NodeCommonCtx, Threshold, }; use trust_quorum_test_utils::TqState; From 7f83f7c7de564c23de9d0459e22cb38b20f57936 Mon Sep 17 00:00:00 2001 From: "Andrew J. Stone" Date: Tue, 30 Sep 2025 20:12:42 +0000 Subject: [PATCH 3/3] Use BaseboardId in tqdb --- trust-quorum/tqdb/src/bin/tqdb/main.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/trust-quorum/tqdb/src/bin/tqdb/main.rs b/trust-quorum/tqdb/src/bin/tqdb/main.rs index b7e44e590fe..a593e697e3b 100644 --- a/trust-quorum/tqdb/src/bin/tqdb/main.rs +++ b/trust-quorum/tqdb/src/bin/tqdb/main.rs @@ -24,7 +24,7 @@ use std::fmt::Write; use std::fs; use std::io::IsTerminal; use tabled::Tabled; -use trust_quorum::PlatformId; +use trust_quorum::BaseboardId; use trust_quorum_test_utils::{Event, TqState}; fn main() -> Result<(), anyhow::Error> { @@ -603,7 +603,10 @@ fn cmd_node_show( tqdb: &mut Tqdb, serial: usize, ) -> anyhow::Result> { - let id = PlatformId::new("test".into(), serial.to_string()); + let id = BaseboardId { + part_number: "test".into(), + serial_number: serial.to_string(), + }; let Some((node, ctx)) = tqdb.current_state.sut.nodes.get(&id) else { bail!("failed to load node: {id}"); }; @@ -691,7 +694,7 @@ fn cmd_summary(tqdb: &mut Tqdb) -> anyhow::Result> { writeln!( &mut s, " coordinator: {}", - latest_config.coordinator.serial_number() + latest_config.coordinator.serial_number )?; writeln!(&mut s, " total members: {}", latest_config.members.len())?; writeln!(