Add convenience function for programs to get minimum delegation (#24175)

This commit is contained in:
Brooks Prumo 2022-04-13 14:41:52 -05:00 committed by GitHub
parent b4b26894cd
commit e146e860e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 125 additions and 2 deletions

View File

@ -3032,6 +3032,13 @@ dependencies = [
"solana-program 1.11.0",
]
[[package]]
name = "solana-bpf-rust-get-minimum-delegation"
version = "1.11.0"
dependencies = [
"solana-program 1.11.0",
]
[[package]]
name = "solana-bpf-rust-instruction-introspection"
version = "1.11.0"

View File

@ -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",

View File

@ -70,6 +70,7 @@ fn main() {
"log_data",
"external_spend",
"finalize",
"get_minimum_delegation",
"instruction_introspection",
"invoke",
"invoke_and_error",

View File

@ -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 <maintainers@solana.foundation>"]
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"]

View File

@ -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(())
}

View File

@ -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},
@ -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());
}

View File

@ -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,
}

View File

@ -1,6 +1,7 @@
pub mod config;
pub mod instruction;
pub mod state;
pub mod tools;
pub mod program {
crate::declare_id!("Stake11111111111111111111111111111111111111");

View File

@ -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)
}