Skip to content

Commit 7bde2d2

Browse files
address review claude
1 parent 6554fd0 commit 7bde2d2

16 files changed

Lines changed: 696 additions & 130 deletions

File tree

activator/src/process/multicastgroup.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ mod tests {
405405
predicate::eq(DoubleZeroInstruction::DeactivateMulticastGroup(
406406
MulticastGroupDeactivateArgs {
407407
use_onchain_deallocation: true,
408+
close_index: false,
408409
},
409410
)),
410411
predicate::always(),

sdk/serviceability/go/state.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const (
2525
ResourceExtensionType AccountType = 12
2626
TenantType AccountType = 13
2727
PermissionType AccountType = 15
28+
IndexType AccountType = 16
2829
)
2930

3031
type LocationStatus uint8

sdk/serviceability/python/serviceability/state.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class AccountTypeEnum(IntEnum):
4242
ACCESS_PASS = 11
4343
TENANT = 13
4444
PERMISSION = 15
45+
INDEX = 16
4546

4647

4748
# ---------------------------------------------------------------------------

sdk/serviceability/typescript/serviceability/state.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export const ACCOUNT_TYPE_CONTRIBUTOR = 10;
3232
export const ACCOUNT_TYPE_ACCESS_PASS = 11;
3333
export const ACCOUNT_TYPE_TENANT = 13;
3434
export const ACCOUNT_TYPE_PERMISSION = 15;
35+
export const ACCOUNT_TYPE_INDEX = 16;
3536

3637
// ---------------------------------------------------------------------------
3738
// Enum string mappings

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,7 @@ mod tests {
988988
publisher_count: None,
989989
subscriber_count: None,
990990
use_onchain_allocation: false,
991+
rename_index: false,
991992
}),
992993
"UpdateMulticastGroup",
993994
);
@@ -1005,13 +1006,15 @@ mod tests {
10051006
test_instruction(
10061007
DoubleZeroInstruction::DeleteMulticastGroup(MulticastGroupDeleteArgs {
10071008
use_onchain_deallocation: false,
1009+
close_index: false,
10081010
}),
10091011
"DeleteMulticastGroup",
10101012
);
10111013

10121014
test_instruction(
10131015
DoubleZeroInstruction::DeactivateMulticastGroup(MulticastGroupDeactivateArgs {
10141016
use_onchain_deallocation: false,
1017+
close_index: false,
10151018
}),
10161019
"DeactivateMulticastGroup",
10171020
);

smartcontract/programs/doublezero-serviceability/src/processors/index/create.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,13 @@ pub fn process_create_index(
8585
return Err(ProgramError::AccountAlreadyInitialized);
8686
}
8787

88-
// Verify the entity account is a valid program account
88+
// Verify the entity account is a valid, non-Index program account
8989
assert!(!entity_account.data_is_empty(), "Entity Account is empty");
90+
let entity_type = AccountType::from(entity_account.try_borrow_data()?[0]);
91+
assert!(
92+
entity_type != AccountType::None && entity_type != AccountType::Index,
93+
"Entity Account has invalid type for indexing: {entity_type}"
94+
);
9095

9196
let index = Index {
9297
account_type: AccountType::Index,

smartcontract/programs/doublezero-serviceability/src/processors/multicastgroup/closeaccount.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,17 @@ pub struct MulticastGroupDeactivateArgs {
2525
/// When false, legacy behavior is used (no deallocation).
2626
#[incremental(default = false)]
2727
pub use_onchain_deallocation: bool,
28+
/// When true, close the associated Index account alongside the multicast group.
29+
#[incremental(default = false)]
30+
pub close_index: bool,
2831
}
2932

3033
impl fmt::Debug for MulticastGroupDeactivateArgs {
3134
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3235
write!(
3336
f,
34-
"use_onchain_deallocation: {}",
35-
self.use_onchain_deallocation
37+
"use_onchain_deallocation: {}, close_index: {}",
38+
self.use_onchain_deallocation, self.close_index
3639
)
3740
}
3841
}
@@ -48,10 +51,12 @@ pub fn process_closeaccount_multicastgroup(
4851
let owner_account = next_account_info(accounts_iter)?;
4952
let globalstate_account = next_account_info(accounts_iter)?;
5053

51-
// Optional: ResourceExtension account for on-chain deallocation (before payer)
52-
// Account layout WITH ResourceExtension (use_onchain_deallocation = true):
53-
// [multicastgroup, owner, globalstate, multicast_group_block, payer, system]
54-
// Account layout WITHOUT (legacy, use_onchain_deallocation = false):
54+
// Optional accounts (before payer/system):
55+
// Account layout WITH deallocation + index:
56+
// [multicastgroup, owner, globalstate, multicast_group_block, index, payer, system]
57+
// Account layout WITHOUT deallocation, with index:
58+
// [multicastgroup, owner, globalstate, index, payer, system]
59+
// Legacy (no deallocation, no index):
5560
// [multicastgroup, owner, globalstate, payer, system]
5661
let resource_extension_account = if value.use_onchain_deallocation {
5762
let multicast_group_block_ext = next_account_info(accounts_iter)?;
@@ -60,12 +65,15 @@ pub fn process_closeaccount_multicastgroup(
6065
None
6166
};
6267

68+
let index_account = if value.close_index {
69+
Some(next_account_info(accounts_iter)?)
70+
} else {
71+
None
72+
};
73+
6374
let payer_account = next_account_info(accounts_iter)?;
6475
let system_program = next_account_info(accounts_iter)?;
6576

66-
// Optional: Index account to close alongside the multicast group
67-
let index_account = next_account_info(accounts_iter).ok();
68-
6977
#[cfg(test)]
7078
msg!("process_deactivate_multicastgroup({:?})", value);
7179

smartcontract/programs/doublezero-serviceability/src/processors/multicastgroup/delete.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,17 @@ pub struct MulticastGroupDeleteArgs {
3030
/// Requires ResourceExtension accounts and owner account.
3131
#[incremental(default = false)]
3232
pub use_onchain_deallocation: bool,
33+
/// When true, close the associated Index account alongside the multicast group.
34+
#[incremental(default = false)]
35+
pub close_index: bool,
3336
}
3437

3538
impl fmt::Debug for MulticastGroupDeleteArgs {
3639
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3740
write!(
3841
f,
39-
"use_onchain_deallocation: {}",
40-
self.use_onchain_deallocation
42+
"use_onchain_deallocation: {}, close_index: {}",
43+
self.use_onchain_deallocation, self.close_index
4144
)
4245
}
4346
}
@@ -52,10 +55,12 @@ pub fn process_delete_multicastgroup(
5255
let multicastgroup_account = next_account_info(accounts_iter)?;
5356
let globalstate_account = next_account_info(accounts_iter)?;
5457

55-
// Optional: additional accounts for atomic deallocation (before payer)
56-
// Account layout WITH deallocation (use_onchain_deallocation = true):
57-
// [mgroup, globalstate, multicast_group_block, owner, payer, system]
58-
// Account layout WITHOUT (legacy, use_onchain_deallocation = false):
58+
// Optional: additional accounts for atomic deallocation
59+
// Account layout WITH deallocation + index:
60+
// [mgroup, globalstate, multicast_group_block, owner, index, payer, system]
61+
// Account layout WITHOUT deallocation, with index:
62+
// [mgroup, globalstate, index, payer, system]
63+
// Legacy (no deallocation, no index):
5964
// [mgroup, globalstate, payer, system]
6065
let deallocation_accounts = if value.use_onchain_deallocation {
6166
let multicast_group_block_ext = next_account_info(accounts_iter)?;
@@ -65,12 +70,15 @@ pub fn process_delete_multicastgroup(
6570
None
6671
};
6772

73+
let index_account = if value.close_index {
74+
Some(next_account_info(accounts_iter)?)
75+
} else {
76+
None
77+
};
78+
6879
let payer_account = next_account_info(accounts_iter)?;
6980
let system_program = next_account_info(accounts_iter)?;
7081

71-
// Optional: Index account to close alongside the multicast group
72-
let index_account = next_account_info(accounts_iter).ok();
73-
7482
#[cfg(test)]
7583
msg!("process_delete_multicastgroup({:?})", value);
7684

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

Lines changed: 77 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,18 @@ pub struct MulticastGroupUpdateArgs {
4141
/// Requires ResourceExtension account (MulticastGroupBlock).
4242
#[incremental(default = false)]
4343
pub use_onchain_allocation: bool,
44+
/// When true, old and new Index accounts are included for an Index rename.
45+
/// Set to false when the code change doesn't affect the Index PDA (e.g. case-only rename).
46+
#[incremental(default = false)]
47+
pub rename_index: bool,
4448
}
4549

4650
impl fmt::Debug for MulticastGroupUpdateArgs {
4751
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4852
write!(
4953
f,
50-
"code: {:?}, multicast_ip: {:?}, max_bandwidth: {:?}, publisher_count: {:?}, subscriber_count: {:?}, use_onchain_allocation: {}",
51-
self.code, self.multicast_ip, self.max_bandwidth, self.publisher_count, self.subscriber_count, self.use_onchain_allocation
54+
"code: {:?}, multicast_ip: {:?}, max_bandwidth: {:?}, publisher_count: {:?}, subscriber_count: {:?}, use_onchain_allocation: {}, rename_index: {}",
55+
self.code, self.multicast_ip, self.max_bandwidth, self.publisher_count, self.subscriber_count, self.use_onchain_allocation, self.rename_index
5256
)
5357
}
5458
}
@@ -75,7 +79,7 @@ pub fn process_update_multicastgroup(
7579
};
7680

7781
// Optional: Index accounts for code rename (before payer/system)
78-
let index_accounts = if value.code.is_some() {
82+
let index_accounts = if value.rename_index {
7983
let old_index_account = next_account_info(accounts_iter)?;
8084
let new_index_account = next_account_info(accounts_iter)?;
8185
Some((old_index_account, new_index_account))
@@ -122,75 +126,77 @@ pub fn process_update_multicastgroup(
122126
if let Some(ref code) = value.code {
123127
let new_code =
124128
validate_account_code(code).map_err(|_| DoubleZeroError::InvalidAccountCode)?;
125-
let new_lowercase_code = new_code.to_ascii_lowercase();
126-
127-
let (old_index_account, new_index_account) =
128-
index_accounts.expect("Index accounts required for code change");
129-
130-
// Validate old Index PDA
131-
let (expected_old_index_pda, _) =
132-
get_index_pda(program_id, SEED_MULTICAST_GROUP, &multicastgroup.code);
133-
assert_eq!(
134-
old_index_account.key, &expected_old_index_pda,
135-
"Invalid old Index Pubkey"
136-
);
137-
assert_eq!(
138-
old_index_account.owner, program_id,
139-
"Invalid old Index Account Owner"
140-
);
141-
assert!(
142-
old_index_account.is_writable,
143-
"Old Index Account is not writable"
144-
);
145-
146-
// Validate new Index PDA
147-
let (expected_new_index_pda, new_index_bump_seed) =
148-
get_index_pda(program_id, SEED_MULTICAST_GROUP, &new_code);
149-
assert_eq!(
150-
new_index_account.key, &expected_new_index_pda,
151-
"Invalid new Index Pubkey"
152-
);
153-
assert!(
154-
new_index_account.is_writable,
155-
"New Index Account is not writable"
156-
);
157-
158-
// New index must not already exist (uniqueness)
159-
if !new_index_account.data_is_empty() {
160-
return Err(ProgramError::AccountAlreadyInitialized);
161-
}
162129

163-
// Verify old index points to this multicast group
164-
let old_index = Index::try_from(old_index_account)?;
165-
assert_eq!(
166-
old_index.pk, *multicastgroup_account.key,
167-
"Old Index does not point to this MulticastGroup"
168-
);
169-
170-
// Create new Index
171-
let new_index = Index {
172-
account_type: AccountType::Index,
173-
pk: *multicastgroup_account.key,
174-
bump_seed: new_index_bump_seed,
175-
};
176-
177-
try_acc_create(
178-
&new_index,
179-
new_index_account,
180-
payer_account,
181-
system_program,
182-
program_id,
183-
&[
184-
SEED_PREFIX,
185-
SEED_INDEX,
186-
SEED_MULTICAST_GROUP,
187-
new_lowercase_code.as_bytes(),
188-
&[new_index_bump_seed],
189-
],
190-
)?;
191-
192-
// Close old Index
193-
try_acc_close(old_index_account, payer_account)?;
130+
// Rename the Index if accounts are provided (skip for case-only renames
131+
// where the lowercased PDA is unchanged)
132+
if let Some((old_index_account, new_index_account)) = index_accounts {
133+
let new_lowercase_code = new_code.to_ascii_lowercase();
134+
135+
// Validate old Index PDA
136+
let (expected_old_index_pda, _) =
137+
get_index_pda(program_id, SEED_MULTICAST_GROUP, &multicastgroup.code);
138+
assert_eq!(
139+
old_index_account.key, &expected_old_index_pda,
140+
"Invalid old Index Pubkey"
141+
);
142+
assert_eq!(
143+
old_index_account.owner, program_id,
144+
"Invalid old Index Account Owner"
145+
);
146+
assert!(
147+
old_index_account.is_writable,
148+
"Old Index Account is not writable"
149+
);
150+
151+
// Validate new Index PDA
152+
let (expected_new_index_pda, new_index_bump_seed) =
153+
get_index_pda(program_id, SEED_MULTICAST_GROUP, &new_code);
154+
assert_eq!(
155+
new_index_account.key, &expected_new_index_pda,
156+
"Invalid new Index Pubkey"
157+
);
158+
assert!(
159+
new_index_account.is_writable,
160+
"New Index Account is not writable"
161+
);
162+
163+
// New index must not already exist (uniqueness)
164+
if !new_index_account.data_is_empty() {
165+
return Err(ProgramError::AccountAlreadyInitialized);
166+
}
167+
168+
// Verify old index points to this multicast group
169+
let old_index = Index::try_from(old_index_account)?;
170+
assert_eq!(
171+
old_index.pk, *multicastgroup_account.key,
172+
"Old Index does not point to this MulticastGroup"
173+
);
174+
175+
// Create new Index
176+
let new_index = Index {
177+
account_type: AccountType::Index,
178+
pk: *multicastgroup_account.key,
179+
bump_seed: new_index_bump_seed,
180+
};
181+
182+
try_acc_create(
183+
&new_index,
184+
new_index_account,
185+
payer_account,
186+
system_program,
187+
program_id,
188+
&[
189+
SEED_PREFIX,
190+
SEED_INDEX,
191+
SEED_MULTICAST_GROUP,
192+
new_lowercase_code.as_bytes(),
193+
&[new_index_bump_seed],
194+
],
195+
)?;
196+
197+
// Close old Index
198+
try_acc_close(old_index_account, payer_account)?;
199+
}
194200

195201
multicastgroup.code = new_code;
196202
}

0 commit comments

Comments
 (0)