Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ All notable changes to this project will be documented in this file.
- Smartcontract
- Stop writing `InterfaceV3` from `CreateDeviceInterface` and `UpdateDeviceInterface`; `CurrentInterfaceVersion` is now `InterfaceV2`. `MigrateDeviceInterfaces` and `BackfillTopology` continue to write `InterfaceV3` since they are admin-controlled and need the `flex_algo_node_segments` field
- Add forward-compatible `NewInterface` struct in `state/interface.rs` with a `size: u16` + `version: u8` on-disk prefix, V3-shaped body, and `flex_algo_node_segments`. Older readers can use the size prefix to skip past unknown future versions in constant time. Additive only — no callers, processors, or SDKs change in this PR ([#3666](https://github.com/malbeclabs/doublezero/pull/3666))
- Append `new_interfaces: Vec<NewInterface>` to `Device` after `max_multicast_publishers`, behind a custom `BorshSerialize` that projects the on-disk legacy `interfaces` slot from `new_interfaces` (always `Interface::V2` per #3653) and writes `new_interfaces` at the end of the layout. Legacy accounts with no trailing bytes deserialize cleanly: `Device::try_from` rebuilds `new_interfaces` from the legacy enum vec via per-variant `TryFrom`. Older readers continue to parse the legacy slot at its existing offset; newer readers gain forward-compat via the trailing vec. Mutations now go through `Device::replace_interface` / `push_interface` / `remove_interface` so both vecs stay in sync; `find_interface` returns `&NewInterface` and `find_interface_legacy` is a temporary helper for unrelated callers ([#3665](https://github.com/malbeclabs/doublezero/pull/3665))

## [v0.21.0](https://github.com/malbeclabs/doublezero/compare/client/v0.20.0...client/v0.21.0) - 2026-05-01

Expand Down
1 change: 1 addition & 0 deletions client/doublezero/src/command/connect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1337,6 +1337,7 @@ mod tests {
dz_prefixes: format!("10.{}.0.0/24", device_number).parse().unwrap(),
mgmt_vrf: "default".to_string(),
interfaces: vec![],
new_interfaces: vec![],
max_users: 255,
users_count: 0,
device_health:
Expand Down
38 changes: 20 additions & 18 deletions client/doublezero/src/dzd_latency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,28 +255,29 @@ mod tests {
tunnel_endpoint_ips: Vec<Ipv4Addr>,
) -> (Pubkey, Device) {
let pubkey = Pubkey::new_unique();
let interfaces: Vec<Interface> = tunnel_endpoint_ips
let v2_ifaces: Vec<CurrentInterfaceVersion> = tunnel_endpoint_ips
.into_iter()
.enumerate()
.map(|(i, ip)| {
Interface::V2(CurrentInterfaceVersion {
status: InterfaceStatus::Activated,
name: format!("Loopback{}", i),
interface_type: InterfaceType::Loopback,
loopback_type: LoopbackType::None,
interface_cyoa: InterfaceCYOA::None,
interface_dia: InterfaceDIA::None,
bandwidth: 0,
cir: 0,
mtu: 1500,
routing_mode: RoutingMode::Static,
vlan_id: 0,
ip_net: NetworkV4::new(ip, 32).unwrap(),
node_segment_idx: 0,
user_tunnel_endpoint: true,
})
.map(|(i, ip)| CurrentInterfaceVersion {
status: InterfaceStatus::Activated,
name: format!("Loopback{}", i),
interface_type: InterfaceType::Loopback,
loopback_type: LoopbackType::None,
interface_cyoa: InterfaceCYOA::None,
interface_dia: InterfaceDIA::None,
bandwidth: 0,
cir: 0,
mtu: 1500,
routing_mode: RoutingMode::Static,
vlan_id: 0,
ip_net: NetworkV4::new(ip, 32).unwrap(),
node_segment_idx: 0,
user_tunnel_endpoint: true,
})
.collect();
let interfaces: Vec<Interface> =
v2_ifaces.iter().map(|v| Interface::V2(v.clone())).collect();
let new_interfaces = v2_ifaces.iter().map(|v| v.try_into().unwrap()).collect();
(
pubkey,
Device {
Expand All @@ -295,6 +296,7 @@ mod tests {
contributor_pk: Pubkey::default(),
mgmt_vrf: "default".to_string(),
interfaces,
new_interfaces,
reference_count: 0,
users_count,
max_users: 1,
Expand Down
1 change: 1 addition & 0 deletions controlplane/doublezero-admin/src/cli/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ mod tests {
dz_prefixes: "10.0.0.1/32".parse().unwrap(),
mgmt_vrf: "default".to_string(),
interfaces: vec![],
new_interfaces: vec![],
max_users: 255,
users_count: 0,
device_health: DeviceHealth::ReadyForUsers,
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -323,9 +323,14 @@ fn generate_device(dir: &Path) {
ip_net: "172.16.0.1/30".parse().unwrap(),
node_segment_idx: 200,
user_tunnel_endpoint: true,
flex_algo_node_segments: vec![],
}),
],
// Empty for now: regenerating with my custom Device serializer would
// V2-project the legacy slot from new_interfaces, dropping the V1 form
// and breaking SDK fixtures that pin Interface0 to V1. Existing
// device.bin remains in the legacy format and continues to pass SDK
// tests via the legacy fallback path in `Device::TryFrom`.
new_interfaces: vec![],
reference_count: 12,
users_count: 5,
max_users: 100,
Expand Down
1 change: 1 addition & 0 deletions smartcontract/cli/src/device/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ mod tests {
status: DeviceStatus::Activated,
mgmt_vrf: String::default(),
interfaces: vec![],
new_interfaces: vec![],
users_count: 0,
max_users: 100,
owner: Pubkey::default(),
Expand Down
1 change: 1 addition & 0 deletions smartcontract/cli/src/device/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ mod tests {
owner: pda_pubkey,
mgmt_vrf: "default".to_string(),
interfaces: vec![],
new_interfaces: vec![],
max_users: 255,
users_count: 0,
device_health: doublezero_serviceability::state::device::DeviceHealth::ReadyForUsers,
Expand Down
1 change: 1 addition & 0 deletions smartcontract/cli/src/device/get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ mod tests {
owner: device1_pubkey,
mgmt_vrf: "default".to_string(),
interfaces: vec![],
new_interfaces: vec![],
max_users: 255,
users_count: 0,
device_health: doublezero_serviceability::state::device::DeviceHealth::ReadyForUsers,
Expand Down
5 changes: 5 additions & 0 deletions smartcontract/cli/src/device/interface/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ mod tests {
owner: device1_pubkey,
mgmt_vrf: "default".to_string(),
interfaces: vec![],
new_interfaces: vec![],
max_users: 255,
users_count: 0,
device_health: doublezero_serviceability::state::device::DeviceHealth::ReadyForUsers,
Expand Down Expand Up @@ -225,6 +226,7 @@ mod tests {
user_tunnel_endpoint: false,
}
.to_interface()],
new_interfaces: vec![],
max_users: 255,
users_count: 0,
device_health: doublezero_serviceability::state::device::DeviceHealth::ReadyForUsers,
Expand Down Expand Up @@ -323,6 +325,7 @@ mod tests {
user_tunnel_endpoint: true,
}
.to_interface()],
new_interfaces: vec![],
max_users: 255,
users_count: 0,
device_health: doublezero_serviceability::state::device::DeviceHealth::ReadyForUsers,
Expand Down Expand Up @@ -411,6 +414,7 @@ mod tests {
owner: device1_pubkey,
mgmt_vrf: "default".to_string(),
interfaces: vec![],
new_interfaces: vec![],
max_users: 255,
users_count: 0,
device_health: doublezero_serviceability::state::device::DeviceHealth::ReadyForUsers,
Expand Down Expand Up @@ -482,6 +486,7 @@ mod tests {
owner: device1_pubkey,
mgmt_vrf: "default".to_string(),
interfaces: vec![],
new_interfaces: vec![],
max_users: 255,
users_count: 0,
device_health: doublezero_serviceability::state::device::DeviceHealth::ReadyForUsers,
Expand Down
3 changes: 2 additions & 1 deletion smartcontract/cli/src/device/interface/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl DeleteDeviceInterfaceCliCommand {
.map_err(|_| eyre::eyre!("Device not found"))?;

let (_, iface) = device
.find_interface(&self.name)
.find_interface_legacy(&self.name)
.map_err(|err| eyre::eyre!(err))?;

// if a physical interface is Activated, it's part of a link and shouldn't be deleted.
Expand Down Expand Up @@ -129,6 +129,7 @@ mod tests {
}
.to_interface(),
],
new_interfaces: vec![],
max_users: 255,
users_count: 0,
device_health: doublezero_serviceability::state::device::DeviceHealth::ReadyForUsers,
Expand Down
1 change: 1 addition & 0 deletions smartcontract/cli/src/device/interface/get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ mod tests {
user_tunnel_endpoint: true,
}
.to_interface()],
new_interfaces: vec![],
max_users: 255,
users_count: 0,
device_health: doublezero_serviceability::state::device::DeviceHealth::ReadyForUsers,
Expand Down
1 change: 1 addition & 0 deletions smartcontract/cli/src/device/interface/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ mod tests {
}
.to_interface(),
],
new_interfaces: vec![],
max_users: 255,
users_count: 0,
device_health: doublezero_serviceability::state::device::DeviceHealth::ReadyForUsers,
Expand Down
6 changes: 5 additions & 1 deletion smartcontract/cli/src/device/interface/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl UpdateDeviceInterfaceCliCommand {
})?;

let (_, interface) = device
.find_interface(&self.name)
.find_interface_legacy(&self.name)
.map_err(|e| eyre::eyre!(e.to_string()))?;

// Prevent setting a loopback type on physical interfaces
Expand Down Expand Up @@ -262,6 +262,7 @@ mod tests {
}
.to_interface(),
],
new_interfaces: vec![],
max_users: 255,
users_count: 0,
device_health: doublezero_serviceability::state::device::DeviceHealth::ReadyForUsers,
Expand Down Expand Up @@ -378,6 +379,7 @@ mod tests {
user_tunnel_endpoint: false,
}
.to_interface()],
new_interfaces: vec![],
max_users: 255,
users_count: 0,
device_health: doublezero_serviceability::state::device::DeviceHealth::ReadyForUsers,
Expand Down Expand Up @@ -426,6 +428,7 @@ mod tests {
user_tunnel_endpoint: false,
}
.to_interface()],
new_interfaces: vec![],
max_users: 255,
users_count: 0,
device_health: doublezero_serviceability::state::device::DeviceHealth::ReadyForUsers,
Expand Down Expand Up @@ -522,6 +525,7 @@ mod tests {
user_tunnel_endpoint: true,
}
.to_interface()],
new_interfaces: vec![],
max_users: 255,
users_count: 0,
device_health: doublezero_serviceability::state::device::DeviceHealth::ReadyForUsers,
Expand Down
Loading
Loading