diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index 8f211ed3c25f80..4d7b77149ce337 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -3032,6 +3032,13 @@ dependencies = [ "solana-program 1.11.0", ] +[[package]] +name = "solana-bpf-rust-get-minimum-delegation-data" +version = "1.11.0" +dependencies = [ + "solana-program 1.11.0", +] + [[package]] name = "solana-bpf-rust-instruction-introspection" version = "1.11.0" diff --git a/programs/bpf/Cargo.toml b/programs/bpf/Cargo.toml index c8769088b828e6..d217788a0119ff 100644 --- a/programs/bpf/Cargo.toml +++ b/programs/bpf/Cargo.toml @@ -57,6 +57,7 @@ members = [ "rust/error_handling", "rust/log_data", "rust/external_spend", + "rust/get_minimum_delegation_data", "rust/finalize", "rust/instruction_introspection", "rust/invoke", diff --git a/programs/bpf/build.rs b/programs/bpf/build.rs index 30bef9df1ee189..489b702f08f73e 100644 --- a/programs/bpf/build.rs +++ b/programs/bpf/build.rs @@ -70,6 +70,7 @@ fn main() { "log_data", "external_spend", "finalize", + "get_minimum_delegation_data", "instruction_introspection", "invoke", "invoke_and_error", diff --git a/programs/bpf/rust/get_minimum_delegation_data/Cargo.toml b/programs/bpf/rust/get_minimum_delegation_data/Cargo.toml new file mode 100644 index 00000000000000..31538f576f9d06 --- /dev/null +++ b/programs/bpf/rust/get_minimum_delegation_data/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "solana-bpf-rust-get-minimum-delegation-data" +version = "1.11.0" +description = "Solana BPF test program written in Rust" +authors = ["Solana Maintainers "] +repository = "https://github.com/solana-labs/solana" +license = "Apache-2.0" +homepage = "https://solana.com/" +documentation = "https://docs.rs/solana-bpf-rust-get-minimum-delegation-data" +edition = "2021" + +[dependencies] +solana-program = { path = "../../../../sdk/program", version = "=1.11.0" } + +[lib] +crate-type = ["cdylib"] + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] diff --git a/programs/bpf/rust/get_minimum_delegation_data/src/lib.rs b/programs/bpf/rust/get_minimum_delegation_data/src/lib.rs new file mode 100644 index 00000000000000..65234cfb5960ab --- /dev/null +++ b/programs/bpf/rust/get_minimum_delegation_data/src/lib.rs @@ -0,0 +1,24 @@ +//! Example/test program for calling GetMinimumDelegation and then the +//! helper function to return the minimum delegation value. + +#![allow(unreachable_code)] + +extern crate solana_program; +use solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, program, pubkey::Pubkey, stake, +}; + +solana_program::entrypoint!(process_instruction); +#[allow(clippy::unnecessary_wraps)] +fn process_instruction( + _program_id: &Pubkey, + _accounts: &[AccountInfo], + _instruction_data: &[u8], +) -> ProgramResult { + let get_minimum_delegation_instruction = stake::instruction::get_minimum_delegation(); + program::invoke(&get_minimum_delegation_instruction, &[]).unwrap(); + + let minimum_delegation = stake::instruction::utils::get_minimum_delegation_data(); + assert!(minimum_delegation.is_some()); + Ok(()) +} diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 0df6803177ab46..50d58640be93a7 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -56,6 +56,7 @@ use { pubkey::Pubkey, rent::Rent, signature::{keypair_from_seed, Keypair, Signer}, + stake, system_instruction::{self, MAX_PERMITTED_DATA_LENGTH}, system_program, sysvar::{self, clock, rent}, @@ -3524,3 +3525,32 @@ fn test_program_fees() { let post_balance = bank_client.get_balance(&mint_keypair.pubkey()).unwrap(); assert_eq!(pre_balance - post_balance, expected_min_fee); } + +#[test] +#[cfg(feature = "bpf_rust")] +fn test_get_minimum_delegation_data() { + let GenesisConfigInfo { + genesis_config, + mint_keypair, + .. + } = create_genesis_config(100_123_456_789); + let mut bank = Bank::new_for_tests(&genesis_config); + bank.feature_set = Arc::new(FeatureSet::all_enabled()); + + let (name, id, entrypoint) = solana_bpf_loader_program!(); + bank.add_builtin(&name, &id, entrypoint); + let bank = Arc::new(bank); + let bank_client = BankClient::new_shared(&bank); + + let program_id = load_bpf_program( + &bank_client, + &bpf_loader::id(), + &mint_keypair, + "solana_bpf_rust_get_minimum_delegation_data", + ); + + let account_metas = vec![AccountMeta::new_readonly(stake::program::id(), false)]; + let instruction = Instruction::new_with_bytes(program_id, &[], account_metas); + let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction); + assert!(result.is_ok()); +} diff --git a/sdk/program/src/stake/instruction.rs b/sdk/program/src/stake/instruction.rs index 087407e226f3b1..5b4bc7660aba78 100644 --- a/sdk/program/src/stake/instruction.rs +++ b/sdk/program/src/stake/instruction.rs @@ -695,6 +695,21 @@ pub fn get_minimum_delegation() -> Instruction { ) } +pub mod utils { + /// Helper function for programs to get the actual data after calling GetMinimumDelegation + /// + /// This fn handles calling `get_return_data()`, ensures the result is from the correct + /// program, and returns the correct type. Returns `None` otherwise. + pub fn get_minimum_delegation_data() -> Option { + solana_program::program::get_return_data() + .and_then(|(program_id, return_data)| { + (program_id == crate::stake::program::id()).then(|| return_data) + }) + .and_then(|return_data| return_data.try_into().ok()) + .map(|return_data| u64::from_le_bytes(return_data)) + } +} + #[cfg(test)] mod tests { use {super::*, crate::instruction::InstructionError};