Răsfoiți Sursa

Add `checked_create_program_address` helper (#30)

* Add unchecked helper

* Fix lint

* Add inline

* Rename to checked

* Cosmetics

* Fix sol log params
Fernando Otero 1 an în urmă
părinte
comite
2be6dc464d

+ 6 - 0
sdk/pinocchio/src/account_info.rs

@@ -139,6 +139,12 @@ impl AccountInfo {
         unsafe { (*self.raw).data_len as usize }
     }
 
+    /// Returns the lamports in the account.
+    #[inline(always)]
+    pub fn lamports(&self) -> u64 {
+        unsafe { (*self.raw).lamports }
+    }
+
     /// Indicates whether the account data is empty.
     ///
     /// An account is considered empty if the data length is zero.

+ 1 - 0
sdk/pinocchio/src/instruction.rs

@@ -121,6 +121,7 @@ pub struct AccountMeta<'a> {
 }
 
 impl<'a> AccountMeta<'a> {
+    #[inline(always)]
     pub fn new(pubkey: &'a Pubkey, is_writable: bool, is_signer: bool) -> Self {
         Self {
             pubkey,

+ 3 - 0
sdk/pinocchio/src/lazy_entrypoint.rs

@@ -14,6 +14,9 @@ use crate::{
 /// managing potential duplicated accounts and set up a `global allocator`
 /// and `panic handler`.
 ///
+/// The usual use-case for a `lazy_entrypoint` is small programs with a single instruction.
+/// For most use-cases, it is recommended to use the [`entrypoint`] macro instead.
+///
 /// This macro emits the boilerplate necessary to begin program execution, calling a
 /// provided function to process the program instruction supplied by the runtime, and reporting
 /// its result to the runtime.

+ 8 - 9
sdk/pinocchio/src/log.rs

@@ -33,6 +33,8 @@
 //! [`Pubkey`]: crate::pubkey::Pubkey
 //! [`Pubkey::log`]: crate::pubkey::Pubkey::log
 
+use crate::{account_info::AccountInfo, pubkey::log};
+
 #[macro_export]
 macro_rules! msg {
     ($msg:expr) => {
@@ -83,12 +85,10 @@ pub fn sol_log_slice(slice: &[u8]) {
     }
 }
 
-// Print the hexadecimal representation of the program's input parameters.
-//
-// - `accounts` - A slice of [`AccountInfo`].
-// - `data` - The instruction data.
-// TODO: This function is not yet implemented.
-/*
+/// Print the hexadecimal representation of the program's input parameters.
+///
+/// - `accounts` - A slice of [`AccountInfo`].
+/// - `data` - The instruction data.
 pub fn sol_log_params(accounts: &[AccountInfo], data: &[u8]) {
     for (i, account) in accounts.iter().enumerate() {
         msg!("AccountInfo");
@@ -96,18 +96,17 @@ pub fn sol_log_params(accounts: &[AccountInfo], data: &[u8]) {
         msg!("- Is signer");
         sol_log_64(0, 0, 0, 0, account.is_signer() as u64);
         msg!("- Key");
-        account.key().log();
+        log(account.key());
         msg!("- Lamports");
         sol_log_64(0, 0, 0, 0, account.lamports());
         msg!("- Account data length");
         sol_log_64(0, 0, 0, 0, account.data_len() as u64);
         msg!("- Owner");
-        account.owner().log();
+        log(account.owner());
     }
     msg!("Instruction data");
     sol_log_slice(data);
 }
-*/
 
 /// Print the remaining compute units available to the program.
 #[inline]

+ 43 - 8
sdk/pinocchio/src/pubkey.rs

@@ -17,7 +17,7 @@ pub const MAX_SEEDS: usize = 16;
 pub type Pubkey = [u8; PUBKEY_BYTES];
 
 /// Log a `Pubkey` from a program
-#[inline]
+#[inline(always)]
 pub fn log(pubkey: &Pubkey) {
     #[cfg(target_os = "solana")]
     unsafe {
@@ -116,6 +116,7 @@ pub fn find_program_address(seeds: &[&[u8]], program_id: &Pubkey) -> (Pubkey, u8
 /// See the documentation for [`find_program_address`] for a full description.
 ///
 /// [`find_program_address`]: #find_program_address
+#[inline]
 pub fn try_find_program_address(seeds: &[&[u8]], program_id: &Pubkey) -> Option<(Pubkey, u8)> {
     #[cfg(target_os = "solana")]
     {
@@ -158,22 +159,21 @@ pub fn try_find_program_address(seeds: &[&[u8]], program_id: &Pubkey) -> Option<
 /// See the documentation for [`find_program_address`] for a full description
 /// of program derived addresses and bump seeds.
 ///
+/// Note that this function does *not* validate whether the given `seeds` are within
+/// the valid length or not. It will return an error in case of invalid seeds length,
+/// incurring the cost of the syscall.
+///
 /// [`find_program_address`]: #find_program_address
+#[inline]
 pub fn create_program_address(
     seeds: &[&[u8]],
     program_id: &Pubkey,
 ) -> Result<Pubkey, ProgramError> {
-    if seeds.len() > MAX_SEEDS {
-        return Err(ProgramError::MaxSeedLengthExceeded);
-    }
-    if seeds.iter().any(|seed| seed.len() > MAX_SEED_LEN) {
-        return Err(ProgramError::MaxSeedLengthExceeded);
-    }
-
     // Call via a system call to perform the calculation
     #[cfg(target_os = "solana")]
     {
         let mut bytes = [0; 32];
+
         let result = unsafe {
             crate::syscalls::sol_create_program_address(
                 seeds as *const _ as *const u8,
@@ -182,6 +182,7 @@ pub fn create_program_address(
                 &mut bytes as *mut _ as *mut u8,
             )
         };
+
         match result {
             crate::SUCCESS => Ok(bytes),
             _ => Err(result.into()),
@@ -194,3 +195,37 @@ pub fn create_program_address(
         panic!("create_program_address is only available on target `solana`")
     }
 }
+
+/// Create a valid [program derived address][pda] without searching for a bump seed.
+///
+/// [pda]: https://solana.com/docs/core/cpi#program-derived-addresses
+///
+/// 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.
+///
+/// Note that this function validates whether the given `seeds` are within the valid
+/// length or not, returning an error without incurring the cost of the syscall.
+///
+/// [`find_program_address`]: #find_program_address
+#[inline(always)]
+pub fn checked_create_program_address(
+    seeds: &[&[u8]],
+    program_id: &Pubkey,
+) -> Result<Pubkey, ProgramError> {
+    if seeds.len() > MAX_SEEDS {
+        return Err(ProgramError::MaxSeedLengthExceeded);
+    }
+    if seeds.iter().any(|seed| seed.len() > MAX_SEED_LEN) {
+        return Err(ProgramError::MaxSeedLengthExceeded);
+    }
+
+    create_program_address(seeds, program_id)
+}