-
Notifications
You must be signed in to change notification settings - Fork 21
feat(fraud-proofs): Implement RegisterOperator #197
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
8 commits
Select commit
Hold shift + click to select a range
280b3ee
feat(fraud-proofs): Implement RegisterOperator
snawaz 052a1cc
Use layout views for RegisterOperator
snawaz 1bfe89e
Dispatch RegisterOperator without program id
snawaz 5e63272
Use fresh blockhash for duplicate operator test
snawaz 2d87a3e
Use one-byte tag offset for operator args
snawaz 2fea7ba
Drop trivial RegisterOperator instruction data test
snawaz 51b6647
Rename protocol config test helpers
snawaz 3c180a5
dev review
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,7 @@ | ||
| use wheels::variable_offset_layout; | ||
|
|
||
| #[derive(Clone, Debug, PartialEq, Eq)] | ||
| #[variable_offset_layout(buffer_offset = 1)] | ||
| pub struct RegisterOperatorArgs { | ||
| pub stake_lamports: u64, | ||
| } |
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,3 +1,5 @@ | ||
| mod init_protocol_config; | ||
| mod register_operator; | ||
|
|
||
| pub use init_protocol_config::*; | ||
| pub use register_operator::*; |
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::{operator_bond_pda, protocol_config_pda}, | ||
| DlpV2Instruction, RegisterOperatorArgs, | ||
| }, | ||
| }; | ||
|
|
||
| /// Builds the instruction that registers one operator for v2 commitments. | ||
| pub fn register_operator( | ||
| operator: Pubkey, | ||
| authority: Pubkey, | ||
| args: RegisterOperatorArgs, | ||
| ) -> Instruction { | ||
| Instruction { | ||
| program_id: crate::id().modernize(), | ||
| accounts: vec![ | ||
| AccountMeta::new(operator, true), | ||
| AccountMeta::new_readonly(authority, true), | ||
| AccountMeta::new( | ||
| operator_bond_pda(&operator.compatize()).modernize(), | ||
| false, | ||
| ), | ||
| AccountMeta::new_readonly(protocol_config_pda().modernize(), false), | ||
| AccountMeta::new_readonly(system_program::id(), false), | ||
| ], | ||
| data: [ | ||
| DlpV2Instruction::RegisterOperator.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,5 +1,7 @@ | ||
| mod operator_bond; | ||
| mod protocol_config; | ||
| mod verifier_registry; | ||
|
|
||
| pub use operator_bond::*; | ||
| pub use protocol_config::*; | ||
| pub use 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,51 @@ | ||
| use wheels::fixed_offset_layout; | ||
|
|
||
| use crate::compat::Pubkey; | ||
|
|
||
| #[derive(Clone, Debug, PartialEq, Eq)] | ||
| #[fixed_offset_layout(buffer_offset = 0)] | ||
| pub struct OperatorBond { | ||
| /// Account type marker. | ||
| pub discriminator: [u8; 8], | ||
|
|
||
| /// Canonical PDA bump for this account. | ||
| pub bump: u8, | ||
|
|
||
| /// Operator identity allowed to post commitments through this bond. | ||
| pub operator_identity: Pubkey, | ||
|
|
||
| /// Slashable operator stake held in this account. | ||
| /// CHECKPOINT: the staking asset is SOL or BLOCK? | ||
| /// If this changes to BLOCK, this field will need to point at token-account | ||
| /// accounting instead of native lamports. | ||
| pub stake_lamports: u64, | ||
|
|
||
| /// Stake reserved by active commitments. | ||
| /// CHECKPOINT: the staking asset is SOL or BLOCK? | ||
| pub locked_lamports: u64, | ||
|
|
||
| /// Current operator lifecycle state, stored as `OperatorStatus::value()`. | ||
| pub status: u8, | ||
|
|
||
| /// Slot when withdrawal was requested, if the operator is exiting. | ||
| pub withdraw_requested_slot: Option<u64>, | ||
| } | ||
|
|
||
| impl OperatorBond { | ||
| pub const DISCRIMINATOR: [u8; 8] = *b"v2opbond"; | ||
| } | ||
|
|
||
| #[repr(u8)] | ||
| #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
| pub enum OperatorStatus { | ||
| Active = 1, | ||
| Exiting = 2, | ||
| Slashed = 3, | ||
| Jailed = 4, | ||
| } | ||
|
|
||
| impl OperatorStatus { | ||
| 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| mod init_protocol_config; | ||
| mod register_operator; | ||
|
|
||
| pub use init_protocol_config::*; | ||
| pub use register_operator::*; |
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,119 @@ | ||
| use dlp_api::{ | ||
| error::DlpError, | ||
| v2::{ | ||
| pda::{OPERATOR_BOND_SEED, PROTOCOL_CONFIG_SEED}, | ||
| OperatorBond, OperatorStatus, ProtocolConfig, RegisterOperatorArgs, | ||
| }, | ||
| }; | ||
| use pinocchio::{ | ||
| cpi::{Seed, Signer}, | ||
| error::ProgramError, | ||
| AccountView, ProgramResult, | ||
| }; | ||
| use pinocchio_system::instructions as system; | ||
| use wheels::{ | ||
| layout::{Decodable, Encodable}, | ||
| require, require_eq_keys, require_ge, require_n_accounts, require_signer, | ||
| }; | ||
|
|
||
| use crate::{ | ||
| processor::fast::utils::pda::create_pda, | ||
| requires::{ | ||
| require_initialized_pda, require_uninitialized_pda, StandardCtx, | ||
| }, | ||
| }; | ||
|
|
||
| /// Register one operator for v2 commitments. | ||
| /// | ||
| /// Accounts: | ||
| /// 0: `[signer, writable]` operator identity and stake payer | ||
| /// 1: `[signer]` protocol authority that admits the operator | ||
| /// 2: `[writable]` OperatorBond PDA | ||
| /// 3: `[]` ProtocolConfig PDA | ||
| /// 4: `[]` system program, required by system CPI | ||
| #[inline(never)] | ||
| pub fn process_register_operator( | ||
| accounts: &[AccountView], | ||
| data: &[u8], | ||
| ) -> ProgramResult { | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| let [ | ||
| operator, // force multi-line | ||
| authority, | ||
| operator_bond, | ||
| protocol_config, | ||
| _system_program, | ||
| ] = require_n_accounts!(accounts, 5); | ||
|
|
||
| require_signer!(operator); | ||
| require_signer!(authority); | ||
|
|
||
| let args = RegisterOperatorArgs::decode(data)?; | ||
|
|
||
| require_initialized_pda( | ||
| protocol_config, | ||
| &[PROTOCOL_CONFIG_SEED], | ||
| &crate::fast::ID, | ||
| false, | ||
| "protocol config", | ||
| )?; | ||
| let protocol_config_data = protocol_config.try_borrow()?; | ||
| let protocol_config_state = | ||
| ProtocolConfig::decode(protocol_config_data.as_ref())?; | ||
| require!( | ||
| protocol_config_state.discriminator() == ProtocolConfig::DISCRIMINATOR, | ||
| ProgramError::InvalidAccountData | ||
| ); | ||
|
|
||
| require_eq_keys!( | ||
| protocol_config_state.authority(), | ||
| authority.address(), | ||
| DlpError::InvalidAuthority | ||
| ); | ||
| require_ge!( | ||
| args.stake_lamports(), | ||
| protocol_config_state.min_operator_bond(), | ||
| ProgramError::InvalidInstructionData | ||
| ); | ||
|
|
||
| drop(protocol_config_data); | ||
|
|
||
| let operator_bond_bump = require_uninitialized_pda( | ||
| operator_bond, | ||
| &[OPERATOR_BOND_SEED, operator.address().as_ref()], | ||
| &crate::fast::ID, | ||
| true, | ||
| StandardCtx::new("operator bond"), | ||
| )?; | ||
|
|
||
| create_pda( | ||
| operator_bond, | ||
| &crate::fast::ID, | ||
| OperatorBond::DATA_LEN, | ||
| &[Signer::from(&[ | ||
| Seed::from(OPERATOR_BOND_SEED), | ||
| Seed::from(operator.address().as_ref()), | ||
| Seed::from(&[operator_bond_bump]), | ||
| ])], | ||
| operator, | ||
| )?; | ||
|
|
||
| system::Transfer { | ||
| from: operator, | ||
| to: operator_bond, | ||
| lamports: args.stake_lamports(), | ||
| } | ||
| .invoke()?; | ||
|
|
||
| OperatorBond { | ||
| discriminator: OperatorBond::DISCRIMINATOR, | ||
| bump: operator_bond_bump, | ||
| operator_identity: operator.address().to_bytes().into(), | ||
| stake_lamports: args.stake_lamports(), | ||
| locked_lamports: 0, | ||
| status: OperatorStatus::Active.value(), | ||
| withdraw_requested_slot: None, | ||
| } | ||
| .encode_to(operator_bond.try_borrow_mut()?.as_mut())?; | ||
|
|
||
| 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
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,4 +1,5 @@ | ||
| pub mod accounts; | ||
| pub mod v2; | ||
|
|
||
| #[allow(unused_imports)] | ||
| pub(crate) use accounts::*; |
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,69 @@ | ||
| use dlp_api::v2::{ | ||
| instruction_builder::init_protocol_config, InitProtocolConfigArgs, | ||
| }; | ||
| use solana_program::{ | ||
| hash::Hash, native_token::LAMPORTS_PER_SOL, pubkey::Pubkey, | ||
| }; | ||
| use solana_program_test::{BanksClient, ProgramTest}; | ||
| use solana_sdk::{ | ||
| account::Account, | ||
| signature::{Keypair, Signer}, | ||
| transaction::Transaction, | ||
| }; | ||
| use solana_sdk_ids::system_program; | ||
|
|
||
| pub fn valid_protocol_config_args() -> InitProtocolConfigArgs { | ||
| InitProtocolConfigArgs { | ||
| resolver: Pubkey::new_unique(), | ||
| min_operator_bond: 1, | ||
| min_verifier_bond: 1, | ||
| min_challenger_stake: 1, | ||
| challenge_window_slots: 10, | ||
| operator_response_timeout_slots: 10, | ||
| challenger_reveal_timeout_slots: 10, | ||
| payout_timelock_slots: 10, | ||
| verifiers_per_commitment: 1, | ||
| approval_threshold: 1, | ||
| max_window_extensions: 1, | ||
| match_penalty_bps: 500, | ||
| } | ||
| } | ||
|
|
||
| #[allow(dead_code)] | ||
| pub async fn initialize_protocol_config( | ||
| banks: &BanksClient, | ||
| payer: &Keypair, | ||
| authority: &Keypair, | ||
| blockhash: Hash, | ||
| args: InitProtocolConfigArgs, | ||
| ) { | ||
| let ix = init_protocol_config(authority.pubkey(), args); | ||
| let tx = Transaction::new_signed_with_payer( | ||
| &[ix], | ||
| Some(&payer.pubkey()), | ||
| &[payer, authority], | ||
| blockhash, | ||
| ); | ||
|
|
||
| banks.process_transaction(tx).await.unwrap(); | ||
| } | ||
|
|
||
| pub async fn setup_program_test_env() -> (BanksClient, Keypair, Keypair, Hash) { | ||
| let mut program_test = ProgramTest::new("dlp", dlp_api::ID, None); | ||
| program_test.prefer_bpf(true); | ||
|
|
||
| let authority = Keypair::new(); | ||
| program_test.add_account( | ||
| authority.pubkey(), | ||
| Account { | ||
| lamports: LAMPORTS_PER_SOL, | ||
| data: vec![], | ||
| owner: system_program::id(), | ||
| executable: false, | ||
| rent_epoch: 0, | ||
| }, | ||
| ); | ||
|
|
||
| let (banks, payer, blockhash) = program_test.start().await; | ||
| (banks, payer, authority, blockhash) | ||
| } |
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: 172
🏁 Script executed:
Repository: magicblock-labs/delegation-program
Length of output: 50391
🏁 Script executed:
Repository: magicblock-labs/delegation-program
Length of output: 7612
🌐 Web query:
wheels Rust crate layout Encodable encode LayoutError💡 Result:
There is no single Rust crate named "wheels" that standardly provides a trait called Encodable with methods like encode and a custom LayoutError. Based on your query, it is likely that you are encountering a combination of separate Rust concepts and crates: 1. LayoutError (Standard Library): The LayoutError struct is a standard component of the Rust standard library (std::alloc or alloc::alloc) [1][2]. It is returned when memory layout parameters, such as those provided to Layout::from_size_align, violate documented constraints (e.g., alignment must be a power of two) [3]. 2. Encodable and Encode (Crates): There is a crate named encode [4][5] that provides an Encodable trait for serialization purposes. However, it is a general-purpose library for building encoders and serializers [5]. It is common for different crates to define their own Encodable or Encode traits, so if you are seeing this in a specific project, it is likely defined within that crate or a dependency. 3. "Wheels" Crate: While there are crates with similar names, such as wheel [6], wheel-rs [7][8], bitwheel [9], and wheeltimer [10], none of these are standard, widely-recognized crates that centralize a "layout" system using an "Encodable" trait and "LayoutError." If you are working with a specific codebase and encountering these symbols, it is highly probable that: - LayoutError refers to the standard library's error type [1][2]. - Encodable/encode are either from the encode crate [5] or are custom traits defined within your specific project's "wheels" module (or a similar internal utility crate). To resolve this, check your Cargo.toml file to see which "wheel" or "encode" dependencies are included, and use your IDE's "Go to Definition" feature on the Encodable trait to find the source file where it is defined.
Citations:
Remove
.unwrap()from the instruction builder.Line 36 can panic when
args.encode()returns an error. Return the encoding error, or document and justify an explicit infallibility invariant before usingexpect.🤖 Prompt for AI Agents
Source: Path instructions