pub struct Pubkey(/* private fields */);
Expand description
The address of a Solana account.
Some account addresses are ed25519 public keys, with corresponding secret
keys that are managed off-chain. Often, though, account addresses do not
have corresponding secret keys — as with program derived
addresses — or the secret key is not relevant to the operation
of a program, and may have even been disposed of. As running Solana programs
can not safely create or manage secret keys, the full Keypair
is not
defined in solana-program
but in solana-sdk
.
Implementations§
source§impl Pubkey
impl Pubkey
pub fn new(pubkey_vec: &[u8]) -> Self
pub const fn new_from_array(pubkey_array: [u8; 32]) -> Self
pub fn new_rand() -> Self
sourcepub fn new_unique() -> Self
pub fn new_unique() -> Self
unique Pubkey for tests and benchmarks.
pub fn create_with_seed( base: &Pubkey, seed: &str, owner: &Pubkey, ) -> Result<Pubkey, PubkeyError>
sourcepub fn find_program_address(
seeds: &[&[u8]],
program_id: &Pubkey,
) -> (Pubkey, u8)
pub fn find_program_address( seeds: &[&[u8]], program_id: &Pubkey, ) -> (Pubkey, u8)
Find a valid program derived address and its corresponding bump seed.
Program derived addresses (PDAs) are account keys that only the program,
program_id
, has the authority to sign. The address is of the same form
as a Solana Pubkey
, except they are ensured to not be on the ed25519
curve and thus have no associated private key. When performing
cross-program invocations the program can “sign” for the key by calling
invoke_signed
and passing the same seeds used to generate the
address, along with the calculated bump seed, which this function
returns as the second tuple element. The runtime will verify that the
program associated with this address is the caller and thus authorized
to be the signer.
The seeds
are application-specific, and must be carefully selected to
uniquely derive accounts per application requirements. It is common to
use static strings and other pubkeys as seeds.
Because the program address must not lie on the ed25519 curve, there may
be seed and program id combinations that are invalid. For this reason,
an extra seed (the bump seed) is calculated that results in a
point off the curve. The bump seed must be passed as an additional seed
when calling invoke_signed
.
The processes of finding a valid program address is by trial and error, and even though it is deterministic given a set of inputs it can take a variable amount of time to succeed across different inputs. This means that when called from an on-chain program it may incur a variable amount of the program’s compute budget. Programs that are meant to be very performant may not want to use this function because it could take a considerable amount of time. Programs that are already at risk of exceeding their compute budget should call this with care since there is a chance that the program’s budget may be occasionally and unpredictably exceeded.
As all account addresses accessed by an on-chain Solana program must be
explicitly passed to the program, it is typical for the PDAs to be
derived in off-chain client programs, avoiding the compute cost of
generating the address on-chain. The address may or may not then be
verified by re-deriving it on-chain, depending on the requirements of
the program. This verification may be performed without the overhead of
re-searching for the bump key by using the create_program_address
function.
Warning: Because of the way the seeds are hashed there is a potential for program address collisions for the same program id. The seeds are hashed sequentially which means that seeds {“abcdef”}, {“abc”, “def”}, and {“ab”, “cd”, “ef”} will all result in the same program address given the same program id. Since the chance of collision is local to a given program id, the developer of that program must take care to choose seeds that do not collide with each other. For seed schemes that are susceptible to this type of hash collision, a common remedy is to insert separators between seeds, e.g. transforming {“abc”, “def”} into {“abc”, “-”, “def”}.
§Panics
Panics in the statistically improbable event that a bump seed could not be
found. Use try_find_program_address
to handle this case.
Panics if any of the following are true:
- the number of provided seeds is greater than, or equal to,
MAX_SEEDS
, - any individual seed’s length is greater than
MAX_SEED_LEN
.
§Examples
This example illustrates a simple case of creating a “vault” account which is derived from the payer account, but owned by an on-chain program. The program derived address is derived in an off-chain client program, which invokes an on-chain Solana program that uses the address to create a new account owned and controlled by the program itself.
By convention, the on-chain program will be compiled for use in two different contexts: both on-chain, to interpret a custom program instruction as a Solana transaction; and off-chain, as a library, so that clients can share the instruction data structure, constructors, and other common code.
First the on-chain Solana program:
// The custom instruction processed by our program. It includes the
// PDA's bump seed, which is derived by the client program. This
// definition is also imported into the off-chain client program.
// The computed address of the PDA will be passed to this program via
// the `accounts` vector of the `Instruction` type.
#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct InstructionData {
pub vault_bump_seed: u8,
pub lamports: u64,
}
// The size in bytes of a vault account. The client program needs
// this information to calculate the quantity of lamports necessary
// to pay for the account's rent.
pub static VAULT_ACCOUNT_SIZE: u64 = 1024;
// The entrypoint of the on-chain program, as provided to the
// `entrypoint!` macro.
fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
let account_info_iter = &mut accounts.iter();
let payer = next_account_info(account_info_iter)?;
// The vault PDA, derived from the payer's address
let vault = next_account_info(account_info_iter)?;
let mut instruction_data = instruction_data;
let instr = InstructionData::deserialize(&mut instruction_data)?;
let vault_bump_seed = instr.vault_bump_seed;
let lamports = instr.lamports;
let vault_size = VAULT_ACCOUNT_SIZE;
// Invoke the system program to create an account while virtually
// signing with the vault PDA, which is owned by this caller program.
invoke_signed(
&system_instruction::create_account(
&payer.key,
&vault.key,
lamports,
vault_size,
&program_id,
),
&[
payer.clone(),
vault.clone(),
],
// A slice of seed slices, each seed slice being the set
// of seeds used to generate one of the PDAs required by the
// callee program, the final seed being a single-element slice
// containing the `u8` bump seed.
&[
&[
b"vault",
payer.key.as_ref(),
&[vault_bump_seed],
],
]
)?;
Ok(())
}
The client program:
fn create_vault_account(
client: &RpcClient,
program_id: Pubkey,
payer: &Keypair,
) -> Result<()> {
// Derive the PDA from the payer account, a string representing the unique
// purpose of the account ("vault"), and the address of our on-chain program.
let (vault_pubkey, vault_bump_seed) = Pubkey::find_program_address(
&[b"vault", payer.pubkey().as_ref()],
&program_id
);
// Get the amount of lamports needed to pay for the vault's rent
let vault_account_size = usize::try_from(VAULT_ACCOUNT_SIZE)?;
let lamports = client.get_minimum_balance_for_rent_exemption(vault_account_size)?;
// The on-chain program's instruction data, imported from that program's crate.
let instr_data = InstructionData {
vault_bump_seed,
lamports,
};
// The accounts required by both our on-chain program and the system program's
// `create_account` instruction, including the vault's address.
let accounts = vec![
AccountMeta::new(payer.pubkey(), true),
AccountMeta::new(vault_pubkey, false),
AccountMeta::new(system_program::ID, false),
];
// Create the instruction by serializing our instruction data via borsh
let instruction = Instruction::new_with_borsh(
program_id,
&instr_data,
accounts,
);
let blockhash = client.get_latest_blockhash()?;
let transaction = Transaction::new_signed_with_payer(
&[instruction],
Some(&payer.pubkey()),
&[payer],
blockhash,
);
client.send_and_confirm_transaction(&transaction)?;
Ok(())
}
sourcepub fn try_find_program_address(
seeds: &[&[u8]],
program_id: &Pubkey,
) -> Option<(Pubkey, u8)>
pub fn try_find_program_address( seeds: &[&[u8]], program_id: &Pubkey, ) -> Option<(Pubkey, u8)>
Find a valid program derived address and its corresponding bump seed.
The only difference between this method and find_program_address
is that this one returns None
in the statistically improbable event
that a bump seed cannot be found; or if any of find_program_address
’s
preconditions are violated.
See the documentation for find_program_address
for a full description.
sourcepub fn create_program_address(
seeds: &[&[u8]],
program_id: &Pubkey,
) -> Result<Pubkey, PubkeyError>
pub fn create_program_address( seeds: &[&[u8]], program_id: &Pubkey, ) -> Result<Pubkey, PubkeyError>
Create a valid program derived address without searching for a bump seed.
Because this function does not create a bump seed, it may unpredictably return an error for any given set of seeds and is not generally suitable for creating program derived addresses.
However, it can be used for efficiently verifying that a set of seeds plus
bump seed generated by find_program_address
derives a particular
address as expected. See the example for details.
See the documentation for find_program_address
for a full description
of program derived addresses and bump seeds.
§Examples
Creating a program derived address involves iteratively searching for a
bump seed for which the derived Pubkey
does not lie on the ed25519
curve. This search process is generally performed off-chain, with the
find_program_address
function, after which the client passes the
bump seed to the program as instruction data.
Depending on the application requirements, a program may wish to verify that the set of seeds, plus the bump seed, do correctly generate an expected address.
The verification is performed by appending to the other seeds one
additional seed slice that contains the single u8
bump seed, calling
create_program_address
, checking that the return value is Ok
, and
that the returned Pubkey
has the expected value.
let (expected_pda, bump_seed) = Pubkey::find_program_address(&[b"vault"], &program_id);
let actual_pda = Pubkey::create_program_address(&[b"vault", &[bump_seed]], &program_id)?;
assert_eq!(expected_pda, actual_pda);
pub const fn to_bytes(self) -> [u8; 32]
pub fn is_on_curve(&self) -> bool
Trait Implementations§
source§impl BorshDeserialize for Pubkey
impl BorshDeserialize for Pubkey
fn deserialize_reader<__R: Read>(reader: &mut __R) -> Result<Self, Error>
source§fn deserialize(buf: &mut &[u8]) -> Result<Self, Error>
fn deserialize(buf: &mut &[u8]) -> Result<Self, Error>
source§fn try_from_slice(v: &[u8]) -> Result<Self, Error>
fn try_from_slice(v: &[u8]) -> Result<Self, Error>
fn try_from_reader<R>(reader: &mut R) -> Result<Self, Error>where
R: Read,
source§impl BorshDeserialize for Pubkey
impl BorshDeserialize for Pubkey
fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self, Error>
source§fn deserialize(buf: &mut &[u8]) -> Result<Self, Error>
fn deserialize(buf: &mut &[u8]) -> Result<Self, Error>
source§fn try_from_slice(v: &[u8]) -> Result<Self, Error>
fn try_from_slice(v: &[u8]) -> Result<Self, Error>
fn try_from_reader<R>(reader: &mut R) -> Result<Self, Error>where
R: Read,
source§impl BorshDeserialize for Pubkey
impl BorshDeserialize for Pubkey
source§impl BorshSchema for Pubkey
impl BorshSchema for Pubkey
source§fn declaration() -> Declaration
fn declaration() -> Declaration
source§fn add_definitions_recursively(
definitions: &mut BTreeMap<Declaration, Definition>,
)
fn add_definitions_recursively( definitions: &mut BTreeMap<Declaration, Definition>, )
source§impl BorshSchema for Pubkey
impl BorshSchema for Pubkey
source§fn declaration() -> Declaration
fn declaration() -> Declaration
source§fn add_definitions_recursively(
definitions: &mut HashMap<Declaration, Definition>,
)
fn add_definitions_recursively( definitions: &mut HashMap<Declaration, Definition>, )
source§fn add_definition(
declaration: String,
definition: Definition,
definitions: &mut HashMap<String, Definition>,
)
fn add_definition( declaration: String, definition: Definition, definitions: &mut HashMap<String, Definition>, )
fn schema_container() -> BorshSchemaContainer
source§impl BorshSchema for Pubkey
impl BorshSchema for Pubkey
source§fn declaration() -> Declaration
fn declaration() -> Declaration
source§fn add_definitions_recursively(
definitions: &mut HashMap<Declaration, Definition>,
)
fn add_definitions_recursively( definitions: &mut HashMap<Declaration, Definition>, )
source§fn add_definition(
declaration: String,
definition: Definition,
definitions: &mut HashMap<String, Definition>,
)
fn add_definition( declaration: String, definition: Definition, definitions: &mut HashMap<String, Definition>, )
fn schema_container() -> BorshSchemaContainer
source§impl BorshSerialize for Pubkey
impl BorshSerialize for Pubkey
source§impl BorshSerialize for Pubkey
impl BorshSerialize for Pubkey
source§impl BorshSerialize for Pubkey
impl BorshSerialize for Pubkey
source§impl<'de> Deserialize<'de> for Pubkey
impl<'de> Deserialize<'de> for Pubkey
source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
source§impl FromWasmAbi for Pubkey
impl FromWasmAbi for Pubkey
source§impl IntoWasmAbi for Pubkey
impl IntoWasmAbi for Pubkey
source§impl LongRefFromWasmAbi for Pubkey
impl LongRefFromWasmAbi for Pubkey
source§impl OptionFromWasmAbi for Pubkey
impl OptionFromWasmAbi for Pubkey
source§impl OptionIntoWasmAbi for Pubkey
impl OptionIntoWasmAbi for Pubkey
source§impl Ord for Pubkey
impl Ord for Pubkey
source§impl PartialOrd for Pubkey
impl PartialOrd for Pubkey
source§impl RefFromWasmAbi for Pubkey
impl RefFromWasmAbi for Pubkey
source§impl RefMutFromWasmAbi for Pubkey
impl RefMutFromWasmAbi for Pubkey
source§impl TryFromJsValue for Pubkey
impl TryFromJsValue for Pubkey
source§impl VectorFromWasmAbi for Pubkey
impl VectorFromWasmAbi for Pubkey
source§impl VectorIntoWasmAbi for Pubkey
impl VectorIntoWasmAbi for Pubkey
impl Copy for Pubkey
impl Eq for Pubkey
impl Pod for Pubkey
impl StructuralPartialEq for Pubkey
Auto Trait Implementations§
impl Freeze for Pubkey
impl RefUnwindSafe for Pubkey
impl Send for Pubkey
impl Sync for Pubkey
impl Unpin for Pubkey
impl UnwindSafe for Pubkey
Blanket Implementations§
source§impl<T> AbiEnumVisitor for T
impl<T> AbiEnumVisitor for T
default fn visit_for_abi( &self, _digester: &mut AbiDigester, ) -> Result<AbiDigester, DigestError>
source§impl<T> AbiEnumVisitor for T
impl<T> AbiEnumVisitor for T
default fn visit_for_abi( &self, digester: &mut AbiDigester, ) -> Result<AbiDigester, DigestError>
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> CheckedBitPattern for Twhere
T: AnyBitPattern,
impl<T> CheckedBitPattern for Twhere
T: AnyBitPattern,
source§type Bits = T
type Bits = T
Self
must have the same layout as the specified Bits
except for
the possible invalid bit patterns being checked during
is_valid_bit_pattern
.source§fn is_valid_bit_pattern(_bits: &T) -> bool
fn is_valid_bit_pattern(_bits: &T) -> bool
bits
as &Self
.source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
source§unsafe fn clone_to_uninit(&self, dst: *mut T)
unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit
)source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
source§impl<T> IntoEither for T
impl<T> IntoEither for T
source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§impl<T> Pointable for T
impl<T> Pointable for T
source§impl<T> ReturnWasmAbi for Twhere
T: IntoWasmAbi,
impl<T> ReturnWasmAbi for Twhere
T: IntoWasmAbi,
source§type Abi = <T as IntoWasmAbi>::Abi
type Abi = <T as IntoWasmAbi>::Abi
IntoWasmAbi::Abi
source§fn return_abi(self) -> <T as ReturnWasmAbi>::Abi
fn return_abi(self) -> <T as ReturnWasmAbi>::Abi
IntoWasmAbi::into_abi
, except that it may throw and never
return in the case of Err
.