Skip to content

Commit 956e143

Browse files
committed
add location support to device update functionality
update device location instruction for reference counter management
1 parent 863a060 commit 956e143

File tree

11 files changed

+558
-3
lines changed

11 files changed

+558
-3
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ All notable changes to this project will be documented in this file.
66

77
### Breaking
88

9+
- Updated the device update command to allow modifying a device’s location.
10+
911
### Changes
1012

1113
## [v0.6.11](https://github.com/malbeclabs/doublezero/compare/client/v0.6.10...client/v0.6.11) – 2025-11-13
@@ -59,6 +61,7 @@ All notable changes to this project will be documented in this file.
5961
- serviceability: prevent device interface name duplication
6062
- Update serviceability and telemetry program instruction args to use the `BorshDeserializeIncremental` derive macro incremental, backward-compatible, deserialization of structs.
6163
- Add explicit signer checks for payer accounts across various processors to improve security and ensure correct transaction authorization.
64+
- Add the ability to update a Device’s location, managing the reference counters accordingly.
6265
- CLI
6366
- Removed `--bgp-community` option from `doublezero exchange create` since these values are now assigned automatically
6467
- Add `--next-bgp-community` option to `doublezero global-config set` so authorized users can control which bgp_community will be assigned next

smartcontract/cli/src/device/update.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ pub struct UpdateDeviceCliCommand {
3535
/// Contributor Pubkey (optional)
3636
#[arg(long, value_parser = validate_pubkey)]
3737
pub contributor: Option<String>,
38+
/// Location Pubkey (optional)
39+
#[arg(long, value_parser = validate_pubkey)]
40+
pub location: Option<String>,
3841
/// Management VRF name (optional)
3942
#[arg(long)]
4043
pub mgmt_vrf: Option<String>,
@@ -113,6 +116,10 @@ impl UpdateDeviceCliCommand {
113116
dz_prefixes: self.dz_prefixes,
114117
metrics_publisher,
115118
contributor_pk: contributor,
119+
location_pk: match &self.location {
120+
Some(location) => Some(Pubkey::from_str(location)?),
121+
None => None,
122+
},
116123
mgmt_vrf: self.mgmt_vrf,
117124
interfaces: None,
118125
max_users: self.max_users,
@@ -258,6 +265,9 @@ mod tests {
258265
contributor_pk: Some(Pubkey::from_str_const(
259266
"HQ2UUt18uJqKaQFJhgV9zaTdQxUZjNrsKFgoEDquBkcx",
260267
)),
268+
location_pk: Some(Pubkey::from_str_const(
269+
"HQ2UUt18uJqKaQFJhgV9zaTdQxUZjNrsKFgoEDquBkcx",
270+
)),
261271
mgmt_vrf: Some("default".to_string()),
262272
interfaces: None,
263273
max_users: Some(1025),
@@ -275,6 +285,7 @@ mod tests {
275285
dz_prefixes: Some("1.2.3.4/32".parse().unwrap()),
276286
metrics_publisher: Some("HQ2UUt18uJqKaQFJhgV9zaTdQxUZjNrsKFgoEDquBkcx".to_string()),
277287
contributor: Some("HQ2UUt18uJqKaQFJhgV9zaTdQxUZjNrsKFgoEDquBkcx".to_string()),
288+
location: Some("HQ2UUt18uJqKaQFJhgV9zaTdQxUZjNrsKFgoEDquBkcx".to_string()),
278289
mgmt_vrf: Some("default".to_string()),
279290
max_users: Some(1025),
280291
users_count: Some(0),
@@ -364,6 +375,7 @@ mod tests {
364375
public_ip: None,
365376
dz_prefixes: None,
366377
metrics_publisher: None,
378+
location: None,
367379
contributor: None,
368380
mgmt_vrf: None,
369381
max_users: Some(255),
@@ -453,6 +465,7 @@ mod tests {
453465
public_ip: Some([10, 20, 30, 40].into()),
454466
dz_prefixes: None,
455467
metrics_publisher: None,
468+
location: None,
456469
contributor: None,
457470
mgmt_vrf: None,
458471
max_users: None,

smartcontract/programs/doublezero-serviceability/src/error.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ pub enum DoubleZeroError {
121121
InvalidInterfaceType, // variant 57
122122
#[error("Invalid Loopback Type")]
123123
InvalidLoopbackType, // variant 58
124+
#[error("Invalid Actual Location")]
125+
InvalidActualLocation, // variant 59
124126
}
125127

126128
impl From<DoubleZeroError> for ProgramError {
@@ -185,6 +187,7 @@ impl From<DoubleZeroError> for ProgramError {
185187
DoubleZeroError::InterfaceAlreadyExists => ProgramError::Custom(56),
186188
DoubleZeroError::InvalidInterfaceType => ProgramError::Custom(57),
187189
DoubleZeroError::InvalidLoopbackType => ProgramError::Custom(58),
190+
DoubleZeroError::InvalidActualLocation => ProgramError::Custom(59),
188191
}
189192
}
190193
}
@@ -250,6 +253,7 @@ impl From<u32> for DoubleZeroError {
250253
56 => DoubleZeroError::InterfaceAlreadyExists,
251254
57 => DoubleZeroError::InvalidInterfaceType,
252255
58 => DoubleZeroError::InvalidLoopbackType,
256+
59 => DoubleZeroError::InvalidActualLocation,
253257
_ => DoubleZeroError::Custom(e),
254258
}
255259
}
@@ -335,6 +339,7 @@ mod tests {
335339
InterfaceAlreadyExists,
336340
InvalidInterfaceType,
337341
InvalidLoopbackType,
342+
InvalidActualLocation,
338343
];
339344
for err in variants {
340345
let pe: ProgramError = err.clone().into();

smartcontract/programs/doublezero-serviceability/src/processors/device/update.rs

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,16 @@ use crate::{
22
error::DoubleZeroError,
33
globalstate::globalstate_get,
44
helper::*,
5-
state::{accounttype::AccountType, contributor::Contributor, device::*},
5+
state::{accounttype::AccountType, contributor::Contributor, device::*, location::Location},
66
};
77
use borsh::BorshSerialize;
88
use borsh_incremental::BorshDeserializeIncremental;
99
use core::fmt;
1010
use doublezero_program_common::{types::NetworkV4List, validate_account_code};
11-
#[cfg(test)]
12-
use solana_program::msg;
1311
use solana_program::{
1412
account_info::{next_account_info, AccountInfo},
1513
entrypoint::ProgramResult,
14+
msg,
1615
pubkey::Pubkey,
1716
};
1817

@@ -71,6 +70,17 @@ pub fn process_update_device(
7170

7271
let device_account = next_account_info(accounts_iter)?;
7372
let contributor_account = next_account_info(accounts_iter)?;
73+
// Update location accounts (old and new)
74+
75+
let (location_old_account, location_new_account) = if accounts.len() == 7 {
76+
(
77+
Some(next_account_info(accounts_iter)?),
78+
Some(next_account_info(accounts_iter)?),
79+
)
80+
} else {
81+
(None, None)
82+
};
83+
7484
let globalstate_account = next_account_info(accounts_iter)?;
7585
let payer_account = next_account_info(accounts_iter)?;
7686
let system_program = next_account_info(accounts_iter)?;
@@ -148,6 +158,43 @@ pub fn process_update_device(
148158
device.max_users = max_users;
149159
}
150160

161+
// Handle location update if both old and new location accounts are provided
162+
if let (Some(location_old_account), Some(location_new_account)) =
163+
(location_old_account, location_new_account)
164+
{
165+
if location_old_account.key != location_new_account.key {
166+
let mut location_old = Location::try_from(location_old_account)?;
167+
let mut location_new = Location::try_from(location_new_account)?;
168+
if device.location_pk != *location_old_account.key {
169+
msg!(
170+
"Invalid location account. Device location_pk: {}, location_old_account: {}",
171+
device.location_pk,
172+
location_old_account.key
173+
);
174+
return Err(DoubleZeroError::InvalidActualLocation.into());
175+
}
176+
177+
location_old.reference_count = location_old.reference_count.saturating_sub(1);
178+
location_new.reference_count = location_new.reference_count.saturating_add(1);
179+
180+
// Set new location pk in device
181+
device.location_pk = *location_new_account.key;
182+
183+
account_write(
184+
location_old_account,
185+
&location_old,
186+
payer_account,
187+
system_program,
188+
)?;
189+
account_write(
190+
location_new_account,
191+
&location_new,
192+
payer_account,
193+
system_program,
194+
)?;
195+
}
196+
}
197+
151198
account_write(device_account, &device, payer_account, system_program)?;
152199

153200
#[cfg(test)]

smartcontract/programs/doublezero-serviceability/tests/device_test.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ async fn test_device() {
208208
vec![
209209
AccountMeta::new(device_pubkey, false),
210210
AccountMeta::new(contributor_pubkey, false),
211+
AccountMeta::new(location_pubkey, false),
212+
AccountMeta::new(location_pubkey, false),
211213
AccountMeta::new(globalstate_pubkey, false),
212214
],
213215
&payer,
@@ -340,6 +342,8 @@ async fn test_device() {
340342
vec![
341343
AccountMeta::new(device_pubkey, false),
342344
AccountMeta::new(contributor_pubkey, false),
345+
AccountMeta::new(location_pubkey, false),
346+
AccountMeta::new(location_pubkey, false),
343347
AccountMeta::new(globalstate_pubkey, false),
344348
],
345349
&payer,
@@ -492,6 +496,8 @@ async fn test_device_update_metrics_publisher_by_foundation_allowlist_account()
492496
vec![
493497
AccountMeta::new(device_pubkey, false),
494498
AccountMeta::new(contributor_pubkey, false),
499+
AccountMeta::new(location_pubkey, false),
500+
AccountMeta::new(location_pubkey, false),
495501
AccountMeta::new(globalstate_pubkey, false),
496502
],
497503
&payer,
@@ -525,6 +531,8 @@ async fn test_device_update_metrics_publisher_by_foundation_allowlist_account()
525531
vec![
526532
AccountMeta::new(device_pubkey, false),
527533
AccountMeta::new(contributor_pubkey, false),
534+
AccountMeta::new(location_pubkey, false),
535+
AccountMeta::new(location_pubkey, false),
528536
AccountMeta::new(globalstate_pubkey, false),
529537
],
530538
&payer,

0 commit comments

Comments
 (0)