-
Notifications
You must be signed in to change notification settings - Fork 21
feat(fraud-proofs): Implement UpdateVerifierRegistry #199
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
7166d1b
feat(fraud-proofs): Implement UpdateVerifierRegistry
snawaz 3c19dcc
Use layout views for verifier registry updates
snawaz 235e929
Dispatch verifier registry update without program id
snawaz f873d41
Use one-byte tag offset for verifier registry args
snawaz e163ebb
Share PDA rent top-up helper
snawaz 50ba87b
Drop trivial UpdateVerifierRegistry instruction data test
snawaz 886eb45
Rename verifier registry update tests
snawaz d786428
dev review
snawaz 2d709b2
Remove verifier registry revision update
snawaz 9185361
dev review 2
snawaz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| use wheels::variable_offset_layout; | ||
|
|
||
| #[derive(Clone, Debug, PartialEq, Eq)] | ||
| #[variable_offset_layout(buffer_offset = 1)] | ||
| pub struct UpdateVerifierRegistryArgs { | ||
| pub action: u8, | ||
| pub weight: u64, | ||
| } | ||
|
|
||
| #[repr(u8)] | ||
| #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
| pub enum VerifierRegistryAction { | ||
| Add = 1, | ||
| Remove = 2, | ||
| } | ||
|
|
||
| impl VerifierRegistryAction { | ||
| pub const fn value(self) -> u8 { | ||
| self as u8 | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,9 @@ | ||
| mod init_protocol_config; | ||
| mod register_operator; | ||
| mod register_verifier; | ||
| mod update_verifier_registry; | ||
|
|
||
| pub use init_protocol_config::*; | ||
| pub use register_operator::*; | ||
| pub use register_verifier::*; | ||
| pub use update_verifier_registry::*; |
40 changes: 40 additions & 0 deletions
40
dlp-api/src/v2/instruction_builder/update_verifier_registry.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| use solana_program::{ | ||
| instruction::{AccountMeta, Instruction}, | ||
| pubkey::Pubkey, | ||
| }; | ||
| use solana_sdk_ids::system_program; | ||
| use wheels::layout::Encodable; | ||
|
|
||
| use crate::{ | ||
| compat::{Compatize, Modernize}, | ||
| v2::{ | ||
| pda::{protocol_config_pda, verifier_bond_pda, verifier_registry_pda}, | ||
| DlpV2Instruction, UpdateVerifierRegistryArgs, | ||
| }, | ||
| }; | ||
|
|
||
| /// Builds the instruction that updates the verifier selection registry. | ||
| pub fn update_verifier_registry( | ||
| authority: Pubkey, | ||
| verifier: Pubkey, | ||
| args: UpdateVerifierRegistryArgs, | ||
| ) -> Instruction { | ||
| Instruction { | ||
| program_id: crate::id().modernize(), | ||
| accounts: vec![ | ||
| AccountMeta::new(authority, true), | ||
| AccountMeta::new_readonly(protocol_config_pda().modernize(), false), | ||
| AccountMeta::new(verifier_registry_pda().modernize(), false), | ||
| AccountMeta::new_readonly( | ||
| verifier_bond_pda(&verifier.compatize()).modernize(), | ||
| false, | ||
| ), | ||
| AccountMeta::new_readonly(system_program::id(), false), | ||
| ], | ||
| data: [ | ||
| DlpV2Instruction::UpdateVerifierRegistry.to_vec(), | ||
| args.encode().unwrap(), | ||
| ] | ||
| .concat(), | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,9 @@ | ||
| mod init_protocol_config; | ||
| mod register_operator; | ||
| mod register_verifier; | ||
| mod update_verifier_registry; | ||
|
|
||
| pub use init_protocol_config::*; | ||
| pub use register_operator::*; | ||
| pub use register_verifier::*; | ||
| pub use update_verifier_registry::*; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,204 @@ | ||
| use dlp_api::{ | ||
| error::DlpError, | ||
| v2::{ | ||
| pda::{ | ||
| PROTOCOL_CONFIG_SEED, VERIFIER_BOND_SEED, VERIFIER_REGISTRY_SEED, | ||
| }, | ||
| ProtocolConfig, ProtocolConfigView, UpdateVerifierRegistryArgs, | ||
| UpdateVerifierRegistryArgsView, VerifierBond, VerifierBondView, | ||
| VerifierRegistry, VerifierRegistryAction, VerifierRegistryEntry, | ||
| VerifierStatus, | ||
| }, | ||
| }; | ||
| use pinocchio::{error::ProgramError, AccountView, ProgramResult}; | ||
| use wheels::{ | ||
| layout::Decodable, require, require_eq, require_eq_keys, require_ge, | ||
| require_n_accounts, require_signer, | ||
| }; | ||
|
|
||
| use crate::{ | ||
| processor::fast::utils::pda::top_up_pda_rent, | ||
| requires::{require_initialized_pda, require_owned_pda, require_pda}, | ||
| }; | ||
|
|
||
| /// Update the verifier registry used by v2 verifier selection. | ||
| /// | ||
| /// Accounts: | ||
| /// 0: `[signer, writable]` protocol authority and registry rent payer | ||
| /// 1: `[]` ProtocolConfig PDA | ||
| /// 2: `[writable]` VerifierRegistry PDA | ||
| /// 3: `[]` VerifierBond PDA | ||
| /// 4: `[]` system program, required by system CPI | ||
| #[inline(never)] | ||
| pub fn process_update_verifier_registry( | ||
| accounts: &[AccountView], | ||
| data: &[u8], | ||
| ) -> ProgramResult { | ||
| let [ | ||
| authority, // force multi-line | ||
| protocol_config, | ||
| verifier_registry, | ||
| verifier_bond, | ||
| _system_program, | ||
| ] = require_n_accounts!(accounts, 5); | ||
|
|
||
| require_signer!(authority); | ||
|
|
||
| let args = UpdateVerifierRegistryArgs::decode(data)?; | ||
| validate_update_args(&args)?; | ||
|
|
||
| require_initialized_pda( | ||
| protocol_config, | ||
| &[PROTOCOL_CONFIG_SEED], | ||
| &crate::fast::ID, | ||
| false, | ||
| "protocol config", | ||
| )?; | ||
| require_initialized_pda( | ||
| verifier_registry, | ||
| &[VERIFIER_REGISTRY_SEED], | ||
| &crate::fast::ID, | ||
| true, | ||
| "verifier registry", | ||
| )?; | ||
| require_owned_pda(verifier_bond, &crate::fast::ID, "verifier bond")?; | ||
|
|
||
| let verifier_bond_data = verifier_bond.try_borrow()?; | ||
| let verifier_bond_state = | ||
| VerifierBond::decode(verifier_bond_data.as_ref())?; | ||
| validate_verifier_bond(&verifier_bond_state, verifier_bond)?; | ||
|
|
||
| { | ||
| let protocol_config_data = protocol_config.try_borrow()?; | ||
| let protocol_config_state = | ||
| ProtocolConfig::decode(protocol_config_data.as_ref())?; | ||
| validate_protocol_config(&protocol_config_state, authority)?; | ||
| validate_verifier_can_be_added( | ||
| &protocol_config_state, | ||
| &verifier_bond_state, | ||
| )?; | ||
| } | ||
|
|
||
| let verifier_identity = verifier_bond_state.verifier_identity(); | ||
| let verifier_bond_key = verifier_bond.address(); | ||
|
|
||
| { | ||
| let verifier_registry_data = verifier_registry.try_borrow()?; | ||
| let verifier_registry_view = | ||
| VerifierRegistry::decode(verifier_registry_data.as_ref())?; | ||
| require!( | ||
| verifier_registry_view.discriminator() | ||
| == VerifierRegistry::DISCRIMINATOR, | ||
| ProgramError::InvalidAccountData | ||
| ); | ||
| // CHECKPOINT: this treats verifier identity and verifier bond as | ||
| // separate unique registry keys. Revisit if bond rotation should keep | ||
| // the same identity entry instead of rejecting either duplicate. | ||
| require!( | ||
| !verifier_registry_view.entries().iter().any(|entry| { | ||
| entry.verifier_identity() == verifier_identity | ||
| || entry.verifier_bond() == verifier_bond_key | ||
| }), | ||
| ProgramError::AccountAlreadyInitialized | ||
| ); | ||
| } | ||
|
|
||
| // CHECKPOINT: this single-PDA Vec is only suitable while the verifier set | ||
| // is small. Before allowing unbounded growth, cap the entry count or | ||
| // replace this with paged storage / Merkle-root based membership. | ||
| let old_registry_len = verifier_registry.data_len(); | ||
| let mut verifier_registry_state = | ||
| VerifierRegistry::decode_mut(verifier_registry)?; | ||
|
|
||
| verifier_registry_state | ||
| .entries_mut()? | ||
| .push(&VerifierRegistryEntry { | ||
| verifier_identity: *verifier_identity, | ||
| verifier_bond: *verifier_bond_key, | ||
| weight: args.weight(), | ||
| })?; | ||
|
|
||
| let new_registry_len = verifier_registry.data_len(); | ||
| if new_registry_len > old_registry_len { | ||
| top_up_pda_rent(authority, verifier_registry, new_registry_len)?; | ||
| } | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| fn validate_update_args( | ||
| args: &UpdateVerifierRegistryArgsView<'_>, | ||
| ) -> ProgramResult { | ||
| // CHECKPOINT: implement `VerifierRegistryAction::Remove` when | ||
| // withdrawal/removal rules are finalized. | ||
| require!( | ||
| args.action() == VerifierRegistryAction::Add.value(), | ||
| ProgramError::InvalidInstructionData | ||
| ); | ||
| // MVP verifier selection is equal-weight round-robin, so the only | ||
| // meaningful weight until weighted selection exists is 1. | ||
| require_eq!(args.weight(), 1_u64, ProgramError::InvalidInstructionData); | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| fn validate_protocol_config( | ||
| protocol_config: &ProtocolConfigView<'_>, | ||
| authority: &AccountView, | ||
| ) -> ProgramResult { | ||
| require!( | ||
| protocol_config.discriminator() == ProtocolConfig::DISCRIMINATOR, | ||
| ProgramError::InvalidAccountData | ||
| ); | ||
| require_eq_keys!( | ||
| protocol_config.authority(), | ||
| authority.address(), | ||
| DlpError::InvalidAuthority | ||
| ); | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| fn validate_verifier_bond( | ||
| verifier_bond: &VerifierBondView<'_>, | ||
| verifier_bond_account: &AccountView, | ||
| ) -> ProgramResult { | ||
| require!( | ||
| verifier_bond.discriminator() == VerifierBond::DISCRIMINATOR, | ||
| ProgramError::InvalidAccountData | ||
| ); | ||
| require_pda( | ||
| verifier_bond_account, | ||
| &[ | ||
| VERIFIER_BOND_SEED, | ||
| verifier_bond.verifier_identity().as_ref(), | ||
| ], | ||
| &crate::fast::ID, | ||
| false, | ||
| "verifier bond", | ||
| )?; | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| fn validate_verifier_can_be_added( | ||
| protocol_config: &ProtocolConfigView<'_>, | ||
| verifier_bond: &VerifierBondView<'_>, | ||
| ) -> ProgramResult { | ||
| require_eq!( | ||
| verifier_bond.status(), | ||
| VerifierStatus::Active.value(), | ||
| ProgramError::InvalidInstructionData | ||
| ); | ||
| require_ge!( | ||
| verifier_bond.stake_lamports(), | ||
| protocol_config.min_verifier_bond(), | ||
| ProgramError::InvalidInstructionData | ||
| ); | ||
| require!( | ||
| verifier_bond.withdraw_requested_slot().is_none(), | ||
| ProgramError::InvalidInstructionData | ||
| ); | ||
|
|
||
| Ok(()) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: magicblock-labs/delegation-program
Length of output: 4119
🏁 Script executed:
Repository: magicblock-labs/delegation-program
Length of output: 7911
🏁 Script executed:
Repository: magicblock-labs/delegation-program
Length of output: 633
🏁 Script executed:
Repository: magicblock-labs/delegation-program
Length of output: 1639
🌐 Web query:
wheels crate crates.io variable_offset_layout Encodable encode💡 Result:
There is no widely known Rust crate named "wheels" that features "variable_offset_layout" or the "Encodable::encode" pattern as its core definition. The terminology you are inquiring about appears to stem from separate, unrelated Rust libraries: 1. Encoding and Serialization: The "Encodable" trait and its "encode" method are core components of the "encode" crate [1][2][3]. This crate is a toolbox for building encoders and serializers, drawing inspiration from parsing libraries like "nom" and "winnow" [2][3]. Its Encodable trait is defined as: fn encode(&self, encoder: &mut E) -> Result<, Self::Error>; 2. Memory and Data Layout: The term "variable_offset_layout" is not a standard crate name, but the concept of explicit memory and field layout in Rust is addressed by several specialized crates, including: - "memory-layout" [4]: Allows defining struct layouts similar to C#'s [StructLayout(LayoutKind.Explicit)] [4]. - "struct_layout" [5]: Provides a similar mechanism with a focus on internal arrays and specific offset annotations [5]. - "binary_layout" [6]: Provides a type-safe, zero-copy way to access binary data structures [6]. 3. Crates named "wheel": Several unrelated crates exist with "wheel" in their name, such as "wheel-rs" (a general utility library) [7][8], "uwheel" (for stream aggregation) [9], "logs-wheel" (for rolling log files) [10], and "bitwheel" (for high-performance timers) [11]. None of these are primarily associated with the encoding or layout features mentioned. If you are following a specific tutorial or project, you may be conflating these distinct libraries. To use the encoding functionality, you should refer to the "encode" crate documentation [2], and for explicit memory layout, you should investigate "memory-layout" or "binary_layout" [4][6].
Citations:
Replace the fallible encoding unwrap.
args.encode()can return an error, andupdate_verifier_registry()currently panics by using.unwrap(). Return aResult<Instruction, ...>from this builder, or document and enforce an invariant that makes encoding failure impossible.🤖 Prompt for AI Agents
Source: Path instructions