Add try_find_program_address syscall (#14118)
This commit is contained in:
@ -479,14 +479,31 @@ typedef struct {
|
||||
*
|
||||
* @param seeds Seed bytes used to sign program accounts
|
||||
* @param seeds_len Length of the seeds array
|
||||
* @param Progam id of the signer
|
||||
* @param Program address created, filled on return
|
||||
* @param program_id Program id of the signer
|
||||
* @param program_address Program address created, filled on return
|
||||
*/
|
||||
static uint64_t sol_create_program_address(
|
||||
const SolSignerSeed *seeds,
|
||||
int seeds_len,
|
||||
const SolPubkey *program_id,
|
||||
const SolPubkey *address
|
||||
const SolPubkey *program_address
|
||||
);
|
||||
|
||||
/**
|
||||
* Try to find a program address and return corresponding bump seed
|
||||
*
|
||||
* @param seeds Seed bytes used to sign program accounts
|
||||
* @param seeds_len Length of the seeds array
|
||||
* @param program_id Program id of the signer
|
||||
* @param program_address Program address created, filled on return
|
||||
* @param bump_seed Bump seed required to create a valid program address
|
||||
*/
|
||||
static uint64_t sol_try_find_program_address(
|
||||
const SolSignerSeed *seeds,
|
||||
int seeds_len,
|
||||
const SolPubkey *program_id,
|
||||
const SolPubkey *program_address,
|
||||
const uint8_t *bump_seed
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -194,31 +194,66 @@ impl Pubkey {
|
||||
}
|
||||
}
|
||||
|
||||
/// Find a valid program address and its corresponding bump seed which must be passed
|
||||
/// as an additional seed when calling `invoke_signed`.
|
||||
/// Find a valid program address and its corresponding bump seed which must
|
||||
/// be passed as an additional seed when calling `invoke_signed`.
|
||||
///
|
||||
/// Panics in the very unlikely event that the additional seed could not be found.
|
||||
/// Panics in the very unlikely event that the additional seed could not be
|
||||
/// found.
|
||||
pub fn find_program_address(seeds: &[&[u8]], program_id: &Pubkey) -> (Pubkey, u8) {
|
||||
Self::try_find_program_address(seeds, program_id)
|
||||
.unwrap_or_else(|| panic!("Unable to find a viable program address bump seed"))
|
||||
}
|
||||
|
||||
/// Find a valid program address and its corresponding bump seed which must be passed
|
||||
/// as an additional seed when calling `invoke_signed`
|
||||
/// Find a valid program address and its corresponding bump seed which must
|
||||
/// be passed as an additional seed when calling `invoke_signed`
|
||||
#[allow(clippy::same_item_push)]
|
||||
pub fn try_find_program_address(seeds: &[&[u8]], program_id: &Pubkey) -> Option<(Pubkey, u8)> {
|
||||
let mut bump_seed = [std::u8::MAX];
|
||||
for _ in 0..std::u8::MAX {
|
||||
{
|
||||
let mut seeds_with_bump = seeds.to_vec();
|
||||
seeds_with_bump.push(&bump_seed);
|
||||
if let Ok(address) = Self::create_program_address(&seeds_with_bump, program_id) {
|
||||
return Some((address, bump_seed[0]));
|
||||
// Perform the calculation inline, calling this from within a program is
|
||||
// not supported
|
||||
#[cfg(not(target_arch = "bpf"))]
|
||||
{
|
||||
let mut bump_seed = [std::u8::MAX];
|
||||
for _ in 0..std::u8::MAX {
|
||||
{
|
||||
let mut seeds_with_bump = seeds.to_vec();
|
||||
seeds_with_bump.push(&bump_seed);
|
||||
if let Ok(address) = Self::create_program_address(&seeds_with_bump, program_id)
|
||||
{
|
||||
return Some((address, bump_seed[0]));
|
||||
}
|
||||
}
|
||||
bump_seed[0] -= 1;
|
||||
}
|
||||
None
|
||||
}
|
||||
// Call via a system call to perform the calculation
|
||||
#[cfg(target_arch = "bpf")]
|
||||
{
|
||||
extern "C" {
|
||||
fn sol_try_find_program_address(
|
||||
seeds_addr: *const u8,
|
||||
seeds_len: u64,
|
||||
program_id_addr: *const u8,
|
||||
address_bytes_addr: *const u8,
|
||||
bump_seed_addr: *const u8,
|
||||
) -> u64;
|
||||
};
|
||||
let mut bytes = [0; 32];
|
||||
let mut bump_seed = std::u8::MAX;
|
||||
let result = unsafe {
|
||||
sol_try_find_program_address(
|
||||
seeds as *const _ as *const u8,
|
||||
seeds.len() as u64,
|
||||
program_id as *const _ as *const u8,
|
||||
&mut bytes as *mut _ as *mut u8,
|
||||
&mut bump_seed as *mut _ as *mut u8,
|
||||
)
|
||||
};
|
||||
match result {
|
||||
crate::entrypoint::SUCCESS => Some((Pubkey::new(&bytes), bump_seed)),
|
||||
_ => None,
|
||||
}
|
||||
bump_seed[0] -= 1;
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn to_bytes(self) -> [u8; 32] {
|
||||
|
@ -106,6 +106,10 @@ pub mod bpf_loader_upgradeable_program {
|
||||
solana_sdk::declare_id!("FbhK8HN9qvNHvJcoFVHAEUCNkagHvu7DTWzdnLuVQ5u4");
|
||||
}
|
||||
|
||||
pub mod try_find_program_address_syscall_enabled {
|
||||
solana_sdk::declare_id!("EMsMNadQNhCYDyGpYH5Tx6dGHxiUqKHk782PU5XaWfmi");
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// Map of feature identifiers to user-visible description
|
||||
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
||||
@ -134,6 +138,7 @@ lazy_static! {
|
||||
(filter_stake_delegation_accounts::id(), "filter stake_delegation_accounts #14062"),
|
||||
(simple_capitalization::id(), "simple capitalization"),
|
||||
(bpf_loader_upgradeable_program::id(), "upgradeable bpf loader"),
|
||||
(try_find_program_address_syscall_enabled::id(), "add try_find_program_address syscall"),
|
||||
/*************** ADD NEW FEATURES HERE ***************/
|
||||
]
|
||||
.iter()
|
||||
|
Reference in New Issue
Block a user