Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions address/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ atomic = ["dep:solana-atomic-u64"]
borsh = ["dep:borsh", "alloc"]
bytemuck = ["copy", "dep:bytemuck", "dep:bytemuck_derive"]
copy = []
curve25519 = ["dep:curve25519-dalek", "error", "sha2"]
curve25519 = ["dep:curve25519-dalek", "sha2", "syscalls"]
Copy link
Contributor Author

@febo febo Oct 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enabling feature "curve25519" will enable the syscalls module, which will try to use solana-define-syscall dependency when target_os = "solana" or target_arch = "bpf", breaking the build. The fix here enables the "syscalls" feature so the dependency is found; it has no effect on other targets, it will only bring the required "error" feature.

Alternatively, we could improve the separation between the "curve25519" and "syscalls" features, but this does not seem necessary at the moment.

decode = ["dep:five8", "dep:five8_const", "error"]
dev-context-only-utils = ["dep:arbitrary", "rand"]
error = ["dep:solana-program-error"]
Expand Down Expand Up @@ -54,10 +54,14 @@ solana-frozen-abi-macro = { workspace = true, features = ["frozen-abi"], optiona
solana-program-error = { workspace = true, optional = true }
solana-sanitize = { workspace = true, optional = true }

[target.'cfg(not(target_os = "solana"))'.dependencies]
[target.'cfg(not(any(target_os = "solana", target_arch = "bpf")))'.dependencies]
curve25519-dalek = { workspace = true, optional = true }
solana-sha256-hasher = { workspace = true, features = ["sha2"], optional = true }

[target.'cfg(target_arch = "bpf")'.dependencies]
solana-define-syscall = { workspace = true, optional = true }
solana-sha256-hasher = { workspace = true, optional = true }

[target.'cfg(target_os = "solana")'.dependencies]
solana-define-syscall = { workspace = true, optional = true }
solana-sha256-hasher = { workspace = true, optional = true }
Expand Down
122 changes: 103 additions & 19 deletions address/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub mod syscalls;
use crate::error::AddressError;
#[cfg(feature = "decode")]
use crate::error::ParseAddressError;
#[cfg(all(feature = "rand", not(target_os = "solana")))]
#[cfg(all(feature = "rand", not(any(target_os = "solana", target_arch = "bpf"))))]
pub use crate::hasher::{AddressHasher, AddressHasherBuilder};

#[cfg(feature = "alloc")]
Expand Down Expand Up @@ -57,7 +57,12 @@ pub const MAX_SEEDS: usize = 16;
#[cfg(feature = "decode")]
/// Maximum string length of a base58 encoded address.
const MAX_BASE58_LEN: usize = 44;

/// Marker used to find program derived addresses (PDAs).
#[cfg(target_arch = "bpf")]
pub static PDA_MARKER: &[u8; 21] = b"ProgramDerivedAddress";
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

target_arch = "bpf" only supports scalar constants, so we need to switch this to be static instead.

/// Marker used to find program derived addresses (PDAs).
#[cfg(not(target_arch = "bpf"))]
pub const PDA_MARKER: &[u8; 21] = b"ProgramDerivedAddress";

/// The address of a [Solana account][acc].
Expand Down Expand Up @@ -164,13 +169,13 @@ impl TryFrom<&str> for Address {
}
}

// If target_os = "solana", then this panics so there are no dependencies.
// When target_os != "solana", this should be opt-in so users
// don't need the curve25519 dependency.
#[cfg(any(target_os = "solana", feature = "curve25519"))]
// If target_os = "solana" or target_arch = "bpf", then this panics so there
// are no dependencies; otherwise this should be opt-in so users don't need the
// curve25519 dependency.
#[cfg(any(target_os = "solana", target_arch = "bpf", feature = "curve25519"))]
#[allow(clippy::used_underscore_binding)]
pub fn bytes_are_curve_point<T: AsRef<[u8]>>(_bytes: T) -> bool {
#[cfg(not(target_os = "solana"))]
#[cfg(not(any(target_os = "solana", target_arch = "bpf")))]
{
let Ok(compressed_edwards_y) =
curve25519_dalek::edwards::CompressedEdwardsY::from_slice(_bytes.as_ref())
Expand All @@ -179,7 +184,7 @@ pub fn bytes_are_curve_point<T: AsRef<[u8]>>(_bytes: T) -> bool {
};
compressed_edwards_y.decompress().is_some()
}
#[cfg(target_os = "solana")]
#[cfg(any(target_os = "solana", target_arch = "bpf"))]
unimplemented!();
}

Expand Down Expand Up @@ -232,10 +237,10 @@ impl Address {
Self::from(b)
}

// If target_os = "solana", then the solana_sha256_hasher crate will use
// syscalls which bring no dependencies.
// When target_os != "solana", this should be opt-in so users
// don't need the sha2 dependency.
// If target_os = "solana" or target_arch = "bpf", then the
// `solana_sha256_hasher` crate will use syscalls which bring no
// dependencies; otherwise, this should be opt-in so users don't
// need the sha2 dependency.
#[cfg(feature = "sha2")]
pub fn create_with_seed(
base: &Address,
Expand Down Expand Up @@ -267,16 +272,16 @@ impl Address {
&self.0
}

// If target_os = "solana", then this panics so there are no dependencies.
// When target_os != "solana", this should be opt-in so users
// don't need the curve25519 dependency.
#[cfg(any(target_os = "solana", feature = "curve25519"))]
// If target_os = "solana" or target_arch = "bpf", then this panics so there
// are no dependencies; otherwise, this should be opt-in so users don't need
// the curve25519 dependency.
#[cfg(any(target_os = "solana", target_arch = "bpf", feature = "curve25519"))]
pub fn is_on_curve(&self) -> bool {
bytes_are_curve_point(self)
}

#[cfg(all(not(target_os = "solana"), feature = "std"))]
/// Log a `Address` from a program
/// Log an `Address` value.
#[cfg(all(not(any(target_os = "solana", target_arch = "bpf")), feature = "std"))]
pub fn log(&self) {
std::println!("{}", std::string::ToString::to_string(&self));
}
Expand Down Expand Up @@ -384,7 +389,7 @@ macro_rules! address {
/// let my_id = Address::from_str("My11111111111111111111111111111111111111111").unwrap();
/// assert_eq!(id(), my_id);
/// ```
#[cfg(feature = "decode")]
#[cfg(all(feature = "decode", not(target_arch = "bpf")))]
#[macro_export]
macro_rules! declare_id {
($address:expr) => {
Expand All @@ -411,8 +416,56 @@ macro_rules! declare_id {
};
}

/// Convenience macro to declare a static address and functions to interact with it.
///
/// Input: a single literal base58 string representation of a program's ID.
///
/// # Example
///
/// ```
/// # // wrapper is used so that the macro invocation occurs in the item position
/// # // rather than in the statement position which isn't allowed.
/// use std::str::FromStr;
/// use solana_address::{declare_id, Address};
///
/// # mod item_wrapper {
/// # use solana_address::declare_id;
/// declare_id!("My11111111111111111111111111111111111111111");
/// # }
/// # use item_wrapper::id;
///
/// let my_id = Address::from_str("My11111111111111111111111111111111111111111").unwrap();
/// assert_eq!(id(), my_id);
/// ```
#[cfg(all(feature = "decode", target_arch = "bpf"))]
#[macro_export]
macro_rules! declare_id {
($address:expr) => {
/// The const program ID.
pub static ID: $crate::Address = $crate::Address::from_str_const($address);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, needs to be static for target_arch = "bpf".


/// Returns `true` if given address is the ID.
// TODO make this const once `derive_const` makes it out of nightly
// and we can `derive_const(PartialEq)` on `Address`.
pub fn check_id(id: &$crate::Address) -> bool {
id == &ID
}

/// Returns the ID.
pub const fn id() -> $crate::Address {
$crate::Address::from_str_const($address)
}

#[cfg(test)]
#[test]
fn test_id() {
assert!(check_id(&id()));
}
};
}

/// Same as [`declare_id`] except that it reports that this ID has been deprecated.
#[cfg(feature = "decode")]
#[cfg(all(feature = "decode", not(target_arch = "bpf")))]
#[macro_export]
macro_rules! declare_deprecated_id {
($address:expr) => {
Expand Down Expand Up @@ -442,6 +495,37 @@ macro_rules! declare_deprecated_id {
};
}

/// Same as [`declare_id`] except that it reports that this ID has been deprecated.
#[cfg(all(feature = "decode", target_arch = "bpf"))]
#[macro_export]
macro_rules! declare_deprecated_id {
($address:expr) => {
/// The const ID.
pub static ID: $crate::Address = $crate::Address::from_str_const($address);

/// Returns `true` if given address is the ID.
// TODO make this const once `derive_const` makes it out of nightly
// and we can `derive_const(PartialEq)` on `Address`.
#[deprecated()]
pub fn check_id(id: &$crate::Address) -> bool {
id == &ID
}

/// Returns the ID.
#[deprecated()]
pub const fn id() -> $crate::Address {
$crate::Address::from_str_const($address)
}

#[cfg(test)]
#[test]
#[allow(deprecated)]
fn test_id() {
assert!(check_id(&id()));
}
};
}

#[cfg(test)]
mod tests {
use {super::*, core::str::from_utf8, std::string::String};
Expand Down
50 changes: 25 additions & 25 deletions address/src/syscalls.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
#[cfg(all(not(target_os = "solana"), feature = "curve25519"))]
#[cfg(all(
not(any(target_os = "solana", target_arch = "bpf")),
feature = "curve25519"
))]
use crate::bytes_are_curve_point;
#[cfg(any(target_os = "solana", feature = "curve25519"))]
#[cfg(any(target_os = "solana", target_arch = "bpf", feature = "curve25519"))]
use crate::error::AddressError;
use crate::Address;
#[cfg(target_os = "solana")]
/// Syscall definitions used by `solana_address`.
#[cfg(any(target_os = "solana", target_arch = "bpf"))]
pub use solana_define_syscall::definitions::{
sol_create_program_address, sol_log_pubkey, sol_try_find_program_address,
};

/// Copied from `solana_program::entrypoint::SUCCESS`
/// to avoid a `solana_program` dependency
#[cfg(target_os = "solana")]
#[cfg(any(target_os = "solana", target_arch = "bpf"))]
const SUCCESS: u64 = 0;

impl Address {
#[cfg(target_os = "solana")]
/// Log a `Address` from a program
/// Log an `Address` value.
#[cfg(any(target_os = "solana", target_arch = "bpf"))]
pub fn log(&self) {
unsafe { sol_log_pubkey(self.as_ref() as *const _ as *const u8) };
}
Expand Down Expand Up @@ -265,11 +268,10 @@ impl Address {
/// #
/// # Ok::<(), anyhow::Error>(())
/// ```
// If target_os = "solana", then the function will use
// syscalls which bring no dependencies.
// When target_os != "solana", this should be opt-in so users
// don't need the curve25519 dependency.
#[cfg(any(target_os = "solana", feature = "curve25519"))]
// If target_os = "solana" or target_arch = "bpf", then the function
// will use syscalls which bring no dependencies; otherwise, this should
// be opt-in so users don't need the curve25519 dependency.
#[cfg(any(target_os = "solana", target_arch = "bpf", feature = "curve25519"))]
#[inline(always)]
pub fn find_program_address(seeds: &[&[u8]], program_id: &Address) -> (Address, u8) {
Self::try_find_program_address(seeds, program_id)
Expand All @@ -288,11 +290,10 @@ impl Address {
/// See the documentation for [`find_program_address`] for a full description.
///
/// [`find_program_address`]: Address::find_program_address
// If target_os = "solana", then the function will use
// syscalls which bring no dependencies.
// When target_os != "solana", this should be opt-in so users
// don't need the curve25519 dependency.
#[cfg(any(target_os = "solana", feature = "curve25519"))]
// If target_os = "solana" or target_arch = "bpf", then the function
// will use syscalls which bring no dependencies; otherwise, this should
// be opt-in so users don't need the curve25519 dependency.
#[cfg(any(target_os = "solana", target_arch = "bpf", feature = "curve25519"))]
#[allow(clippy::same_item_push)]
#[inline(always)]
pub fn try_find_program_address(
Expand All @@ -301,7 +302,7 @@ impl Address {
) -> Option<(Address, u8)> {
// Perform the calculation inline, calling this from within a program is
// not supported
#[cfg(not(target_os = "solana"))]
#[cfg(not(any(target_os = "solana", target_arch = "bpf")))]
{
let mut bump_seed = [u8::MAX];
for _ in 0..u8::MAX {
Expand All @@ -319,7 +320,7 @@ impl Address {
None
}
// Call via a system call to perform the calculation
#[cfg(target_os = "solana")]
#[cfg(any(target_os = "solana", target_arch = "bpf"))]
{
let mut bytes = core::mem::MaybeUninit::<Address>::uninit();
let mut bump_seed = u8::MAX;
Expand Down Expand Up @@ -382,11 +383,10 @@ impl Address {
/// assert_eq!(expected_pda, actual_pda);
/// # Ok::<(), anyhow::Error>(())
/// ```
// If target_os = "solana", then the function will use
// syscalls which bring no dependencies.
// When target_os != "solana", this should be opt-in so users
// don't need the curve225519 dep.
#[cfg(any(target_os = "solana", feature = "curve25519"))]
// If target_os = "solana" or target_arch = "bpf", then the function
// will use syscalls which bring no dependencies; otherwise, this should
// be opt-in so users don't need the curve25519 dependency.
#[cfg(any(target_os = "solana", target_arch = "bpf", feature = "curve25519"))]
#[inline(always)]
pub fn create_program_address(
seeds: &[&[u8]],
Expand All @@ -403,7 +403,7 @@ impl Address {

// Perform the calculation inline, calling this from within a program is
// not supported
#[cfg(not(target_os = "solana"))]
#[cfg(not(any(target_os = "solana", target_arch = "bpf")))]
{
use crate::PDA_MARKER;

Expand All @@ -421,7 +421,7 @@ impl Address {
Ok(Address::from(hash.to_bytes()))
}
// Call via a system call to perform the calculation
#[cfg(target_os = "solana")]
#[cfg(any(target_os = "solana", target_arch = "bpf"))]
{
let mut bytes = core::mem::MaybeUninit::<Address>::uninit();
let result = unsafe {
Expand Down