Skip to content

Commit

Permalink
Add convenience function for programs to get minimum delegation (#24175)
Browse files Browse the repository at this point in the history
  • Loading branch information
brooksprumo authored Apr 13, 2022
1 parent b4b2689 commit e146e86
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 2 deletions.
7 changes: 7 additions & 0 deletions programs/bpf/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions programs/bpf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ members = [
"rust/error_handling",
"rust/log_data",
"rust/external_spend",
"rust/get_minimum_delegation",
"rust/finalize",
"rust/instruction_introspection",
"rust/invoke",
Expand Down
1 change: 1 addition & 0 deletions programs/bpf/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ fn main() {
"log_data",
"external_spend",
"finalize",
"get_minimum_delegation",
"instruction_introspection",
"invoke",
"invoke_and_error",
Expand Down
19 changes: 19 additions & 0 deletions programs/bpf/rust/get_minimum_delegation/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "solana-bpf-rust-get-minimum-delegation"
version = "1.11.0"
description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <[email protected]>"]
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"
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"]
23 changes: 23 additions & 0 deletions programs/bpf/rust/get_minimum_delegation/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//! Example/test program to get the minimum stake delegation via the helper function
#![allow(unreachable_code)]

extern crate solana_program;
use solana_program::{
account_info::AccountInfo, entrypoint::ProgramResult, msg, 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 minimum_delegation = stake::tools::get_minimum_delegation()?;
msg!(
"The minimum stake delegation is {} lamports",
minimum_delegation
);
Ok(())
}
30 changes: 30 additions & 0 deletions programs/bpf/tests/programs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -3522,3 +3523,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() {
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",
);

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());
}
7 changes: 5 additions & 2 deletions sdk/program/src/stake/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,11 @@ pub enum StakeInstruction {
/// # Account references
/// None
///
/// The minimum delegation will be returned via the transaction context's returndata.
/// Use `get_return_data()` to retrieve the result.
/// Returns the minimum delegation as a little-endian encoded u64 value.
/// Programs can use the [`get_minimum_delegation()`] helper function to invoke and
/// retrieve the return value for this instruction.
///
/// [`get_minimum_delegation()`]: super::tools::get_minimum_delegation
GetMinimumDelegation,
}

Expand Down
1 change: 1 addition & 0 deletions sdk/program/src/stake/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod config;
pub mod instruction;
pub mod state;
pub mod tools;

pub mod program {
crate::declare_id!("Stake11111111111111111111111111111111111111");
Expand Down
38 changes: 38 additions & 0 deletions sdk/program/src/stake/tools.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//! Utility functions
use crate::program_error::ProgramError;

/// Helper function for programs to call [`GetMinimumDelegation`] and then fetch the return data
///
/// This fn handles performing the CPI to call the [`GetMinimumDelegation`] function, and then
/// calls [`get_return_data()`] to fetch the return data.
///
/// [`GetMinimumDelegation`]: super::instruction::StakeInstruction::GetMinimumDelegation
/// [`get_return_data()`]: crate::program::get_return_data
pub fn get_minimum_delegation() -> Result<u64, ProgramError> {
let instruction = super::instruction::get_minimum_delegation();
crate::program::invoke_unchecked(&instruction, &[])?;
get_minimum_delegation_return_data()
}

/// Helper function for programs to get the return data after calling [`GetMinimumDelegation`]
///
/// This fn handles calling [`get_return_data()`], ensures the result is from the correct
/// program, and returns the correct type.
///
/// [`GetMinimumDelegation`]: super::instruction::StakeInstruction::GetMinimumDelegation
/// [`get_return_data()`]: crate::program::get_return_data
fn get_minimum_delegation_return_data() -> Result<u64, ProgramError> {
crate::program::get_return_data()
.ok_or(ProgramError::InvalidInstructionData)
.and_then(|(program_id, return_data)| {
(program_id == super::program::id())
.then(|| return_data)
.ok_or(ProgramError::IncorrectProgramId)
})
.and_then(|return_data| {
return_data
.try_into()
.or(Err(ProgramError::InvalidInstructionData))
})
.map(u64::from_le_bytes)
}

0 comments on commit e146e86

Please sign in to comment.