Skip to main content

solana_address/
lib.rs

1//! Address representation for Solana.
2//!
3//! An address is a sequence of 32 bytes, often shown as a base58 encoded string
4//! (e.g. 14grJpemFaf88c8tiVb77W7TYg2W3ir6pfkKz3YjhhZ5).
5
6#![no_std]
7#![cfg_attr(docsrs, feature(doc_cfg))]
8#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
9#![allow(clippy::arithmetic_side_effects)]
10
11#[cfg(feature = "sha2")]
12mod derive;
13#[cfg(feature = "error")]
14pub mod error;
15#[cfg(feature = "rand")]
16mod hasher;
17#[cfg(any(feature = "curve25519", feature = "syscalls"))]
18pub mod syscalls;
19
20#[cfg(feature = "sha2")]
21use crate::error::AddressError;
22#[cfg(feature = "decode")]
23use crate::error::ParseAddressError;
24#[cfg(all(feature = "rand", not(any(target_os = "solana", target_arch = "bpf"))))]
25pub use crate::hasher::{AddressHasher, AddressHasherBuilder};
26
27#[cfg(feature = "alloc")]
28extern crate alloc;
29#[cfg(feature = "std")]
30extern crate std;
31#[cfg(feature = "alloc")]
32use alloc::vec::Vec;
33#[cfg(feature = "dev-context-only-utils")]
34use arbitrary::Arbitrary;
35#[cfg(feature = "bytemuck")]
36use bytemuck_derive::{Pod, Zeroable};
37#[cfg(feature = "decode")]
38use core::str::FromStr;
39use core::{
40    array,
41    convert::TryFrom,
42    hash::{Hash, Hasher},
43    ptr::read_unaligned,
44};
45#[cfg(feature = "serde")]
46use serde_derive::{Deserialize, Serialize};
47#[cfg(feature = "wincode")]
48use wincode::{SchemaRead, SchemaWrite};
49#[cfg(feature = "borsh")]
50use {
51    alloc::string::ToString,
52    borsh::{BorshDeserialize, BorshSchema, BorshSerialize},
53};
54
55/// Number of bytes in an address.
56pub const ADDRESS_BYTES: usize = 32;
57/// maximum length of derived `Address` seed
58pub const MAX_SEED_LEN: usize = 32;
59/// Maximum number of seeds
60pub const MAX_SEEDS: usize = 16;
61#[cfg(feature = "decode")]
62/// Maximum string length of a base58 encoded address.
63const MAX_BASE58_LEN: usize = 44;
64
65/// Marker used to find program derived addresses (PDAs).
66#[cfg(target_arch = "bpf")]
67pub static PDA_MARKER: &[u8; 21] = b"ProgramDerivedAddress";
68/// Marker used to find program derived addresses (PDAs).
69#[cfg(not(target_arch = "bpf"))]
70pub const PDA_MARKER: &[u8; 21] = b"ProgramDerivedAddress";
71
72/// The address of a [Solana account][acc].
73///
74/// Some account addresses are [ed25519] public keys, with corresponding secret
75/// keys that are managed off-chain. Often, though, account addresses do not
76/// have corresponding secret keys — as with [_program derived
77/// addresses_][pdas] — or the secret key is not relevant to the operation
78/// of a program, and may have even been disposed of. As running Solana programs
79/// can not safely create or manage secret keys, the full [`Keypair`] is not
80/// defined in `solana-program` but in `solana-sdk`.
81///
82/// [acc]: https://solana.com/docs/core/accounts
83/// [ed25519]: https://ed25519.cr.yp.to/
84/// [pdas]: https://solana.com/docs/core/cpi#program-derived-addresses
85/// [`Keypair`]: https://docs.rs/solana-sdk/latest/solana_sdk/signer/keypair/struct.Keypair.html
86#[repr(transparent)]
87#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))]
88#[cfg_attr(
89    feature = "borsh",
90    derive(BorshSerialize, BorshDeserialize),
91    borsh(crate = "borsh")
92)]
93#[cfg_attr(feature = "borsh", derive(BorshSchema))]
94#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
95#[cfg_attr(feature = "bytemuck", derive(Pod, Zeroable))]
96#[cfg_attr(feature = "wincode", derive(SchemaWrite, SchemaRead))]
97#[cfg_attr(feature = "dev-context-only-utils", derive(Arbitrary))]
98#[cfg_attr(not(feature = "decode"), derive(Debug))]
99#[cfg_attr(feature = "copy", derive(Copy))]
100#[derive(Clone, Default, Eq, Ord, PartialEq, PartialOrd)]
101pub struct Address(pub(crate) [u8; 32]);
102
103#[cfg(feature = "sanitize")]
104impl solana_sanitize::Sanitize for Address {}
105
106#[cfg(feature = "decode")]
107impl FromStr for Address {
108    type Err = ParseAddressError;
109
110    fn from_str(s: &str) -> Result<Self, Self::Err> {
111        use five8::DecodeError;
112        if s.len() > MAX_BASE58_LEN {
113            return Err(ParseAddressError::WrongSize);
114        }
115        let mut bytes = [0; ADDRESS_BYTES];
116        five8::decode_32(s, &mut bytes).map_err(|e| match e {
117            DecodeError::InvalidChar(_) => ParseAddressError::Invalid,
118            DecodeError::TooLong
119            | DecodeError::TooShort
120            | DecodeError::LargestTermTooHigh
121            | DecodeError::OutputTooLong => ParseAddressError::WrongSize,
122        })?;
123        Ok(Address(bytes))
124    }
125}
126
127/// Custom impl of Hash for Address.
128///
129/// This allows us to skip hashing the length of the address
130/// which is always the same anyway.
131impl Hash for Address {
132    fn hash<H: Hasher>(&self, state: &mut H) {
133        state.write(self.as_array());
134    }
135}
136
137impl From<&Address> for Address {
138    #[inline]
139    fn from(value: &Address) -> Self {
140        Self(value.0)
141    }
142}
143
144impl From<[u8; 32]> for Address {
145    #[inline]
146    fn from(from: [u8; 32]) -> Self {
147        Self(from)
148    }
149}
150
151impl TryFrom<&[u8]> for Address {
152    type Error = array::TryFromSliceError;
153
154    #[inline]
155    fn try_from(address: &[u8]) -> Result<Self, Self::Error> {
156        <[u8; 32]>::try_from(address).map(Self::from)
157    }
158}
159
160#[cfg(feature = "alloc")]
161impl TryFrom<Vec<u8>> for Address {
162    type Error = Vec<u8>;
163
164    #[inline]
165    fn try_from(address: Vec<u8>) -> Result<Self, Self::Error> {
166        <[u8; 32]>::try_from(address).map(Self::from)
167    }
168}
169
170#[cfg(feature = "decode")]
171impl TryFrom<&str> for Address {
172    type Error = ParseAddressError;
173    fn try_from(s: &str) -> Result<Self, Self::Error> {
174        Address::from_str(s)
175    }
176}
177
178/// Check whether the given bytes represent a valid curve point.
179#[cfg(any(feature = "curve25519", feature = "syscalls"))]
180#[inline(always)]
181pub fn bytes_are_curve_point<T: AsRef<[u8]>>(bytes: T) -> bool {
182    #[cfg(not(any(target_os = "solana", target_arch = "bpf")))]
183    {
184        #[cfg(feature = "curve25519")]
185        {
186            let Ok(compressed_edwards_y) =
187                curve25519_dalek::edwards::CompressedEdwardsY::from_slice(bytes.as_ref())
188            else {
189                return false;
190            };
191            compressed_edwards_y.decompress().is_some()
192        }
193
194        #[cfg(not(feature = "curve25519"))]
195        {
196            core::hint::black_box(bytes);
197            panic!("bytes_are_curve_point is only available with the `curve25519` feature enabled on this crate")
198        }
199    }
200
201    #[cfg(any(target_os = "solana", target_arch = "bpf"))]
202    {
203        // ID for the Ed25519 as defined in `solana-curve25519::CURVE25519_EDWARDS`.
204        const CURVE25519_EDWARDS: u64 = 0;
205
206        // The syscall return `0` when the point is valid – i.e., on the curve;
207        // otherwise it returns `1`
208        //
209        // SAFETY: The syscall validates the input.
210        let result = unsafe {
211            syscalls::sol_curve_validate_point(
212                CURVE25519_EDWARDS,
213                bytes.as_ref() as *const _ as *const u8,
214                core::ptr::null_mut(),
215            )
216        };
217
218        result == 0
219    }
220}
221
222impl Address {
223    pub const fn new_from_array(address_array: [u8; 32]) -> Self {
224        Self(address_array)
225    }
226
227    #[cfg(feature = "decode")]
228    /// Decode a string into an `Address`, usable in a const context
229    pub const fn from_str_const(s: &str) -> Self {
230        let id_array = five8_const::decode_32_const(s);
231        Address::new_from_array(id_array)
232    }
233
234    #[cfg(feature = "atomic")]
235    /// Create a unique `Address` for tests and benchmarks.
236    pub fn new_unique() -> Self {
237        use solana_atomic_u64::AtomicU64;
238        static I: AtomicU64 = AtomicU64::new(1);
239        type T = u32;
240        const COUNTER_BYTES: usize = core::mem::size_of::<T>();
241        let mut b = [0u8; ADDRESS_BYTES];
242        #[cfg(feature = "std")]
243        let mut i = I.fetch_add(1) as T;
244        #[cfg(not(feature = "std"))]
245        let i = I.fetch_add(1) as T;
246        // use big endian representation to ensure that recent unique addresses
247        // are always greater than less recent unique addresses.
248        b[0..COUNTER_BYTES].copy_from_slice(&i.to_be_bytes());
249        // fill the rest of the address with pseudorandom numbers to make
250        // data statistically similar to real addresses.
251        #[cfg(feature = "std")]
252        {
253            let mut hash = std::hash::DefaultHasher::new();
254            for slice in b[COUNTER_BYTES..].chunks_mut(COUNTER_BYTES) {
255                hash.write_u32(i);
256                i += 1;
257                slice.copy_from_slice(&hash.finish().to_ne_bytes()[0..COUNTER_BYTES]);
258            }
259        }
260        // if std is not available, just replicate last byte of the counter.
261        // this is not as good as a proper hash, but at least it is uniform
262        #[cfg(not(feature = "std"))]
263        {
264            for b in b[COUNTER_BYTES..].iter_mut() {
265                *b = (i & 0xFF) as u8;
266            }
267        }
268        Self::from(b)
269    }
270
271    // If target_os = "solana" or target_arch = "bpf", then the
272    // `solana_sha256_hasher` crate will use syscalls which bring no
273    // dependencies; otherwise, this should be opt-in so users don't
274    // need the sha2 dependency.
275    #[cfg(feature = "sha2")]
276    pub fn create_with_seed(
277        base: &Address,
278        seed: &str,
279        owner: &Address,
280    ) -> Result<Address, AddressError> {
281        if seed.len() > MAX_SEED_LEN {
282            return Err(AddressError::MaxSeedLengthExceeded);
283        }
284
285        let owner = owner.as_ref();
286        if owner.len() >= PDA_MARKER.len() {
287            let slice = &owner[owner.len() - PDA_MARKER.len()..];
288            if slice == PDA_MARKER {
289                return Err(AddressError::IllegalOwner);
290            }
291        }
292        let hash = solana_sha256_hasher::hashv(&[base.as_ref(), seed.as_ref(), owner]);
293        Ok(Address::from(hash.to_bytes()))
294    }
295
296    pub const fn to_bytes(&self) -> [u8; 32] {
297        self.0
298    }
299
300    /// Return a reference to the `Address`'s byte array.
301    #[inline(always)]
302    pub const fn as_array(&self) -> &[u8; 32] {
303        &self.0
304    }
305
306    /// Checks whether the given address lies on the Ed25519 curve.
307    ///
308    /// On-curve addresses correspond to valid Ed25519 public keys (and therefore
309    /// can have associated private keys). Off-curve addresses are typically used
310    /// for program-derived addresses (PDAs).
311    #[cfg(any(feature = "curve25519", feature = "syscalls"))]
312    #[inline(always)]
313    pub fn is_on_curve(&self) -> bool {
314        bytes_are_curve_point(self)
315    }
316
317    /// Log an `Address` value.
318    #[cfg(all(not(any(target_os = "solana", target_arch = "bpf")), feature = "std"))]
319    pub fn log(&self) {
320        std::println!("{}", std::string::ToString::to_string(&self));
321    }
322}
323
324impl AsRef<[u8]> for Address {
325    fn as_ref(&self) -> &[u8] {
326        &self.0[..]
327    }
328}
329
330impl AsMut<[u8]> for Address {
331    fn as_mut(&mut self) -> &mut [u8] {
332        &mut self.0[..]
333    }
334}
335
336#[cfg(feature = "decode")]
337fn write_as_base58(f: &mut core::fmt::Formatter, p: &Address) -> core::fmt::Result {
338    let mut out = [0u8; MAX_BASE58_LEN];
339    let len = five8::encode_32(&p.0, &mut out) as usize;
340    // any sequence of base58 chars is valid utf8
341    let as_str = unsafe { core::str::from_utf8_unchecked(&out[..len]) };
342    f.write_str(as_str)
343}
344
345#[cfg(feature = "decode")]
346impl core::fmt::Debug for Address {
347    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
348        write_as_base58(f, self)
349    }
350}
351
352#[cfg(feature = "decode")]
353impl core::fmt::Display for Address {
354    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
355        write_as_base58(f, self)
356    }
357}
358
359/// Custom implementation of equality for `Address`.
360///
361/// The implementation compares the address in 4 chunks of 8 bytes (`u64` values),
362/// which is currently more efficient (CU-wise) than the default implementation.
363///
364/// This isn't the implementation for the `PartialEq` trait because we can't do
365/// structural equality with a trait implementation.
366///
367/// [Issue #345](https://github.com/anza-xyz/solana-sdk/issues/345) contains
368/// more information about the problem.
369#[inline(always)]
370pub fn address_eq(a1: &Address, a2: &Address) -> bool {
371    let p1_ptr = a1.0.as_ptr().cast::<u64>();
372    let p2_ptr = a2.0.as_ptr().cast::<u64>();
373
374    unsafe {
375        read_unaligned(p1_ptr) == read_unaligned(p2_ptr)
376            && read_unaligned(p1_ptr.add(1)) == read_unaligned(p2_ptr.add(1))
377            && read_unaligned(p1_ptr.add(2)) == read_unaligned(p2_ptr.add(2))
378            && read_unaligned(p1_ptr.add(3)) == read_unaligned(p2_ptr.add(3))
379    }
380}
381
382/// Implementation of `Nullable` for `Address`.
383///
384/// The zero address (`[0u8; 32]`) is the `None` value.
385#[cfg(feature = "nullable")]
386impl solana_nullable::Nullable for Address {
387    const NONE: Self = Address::new_from_array([0u8; ADDRESS_BYTES]);
388}
389
390#[cfg(feature = "decode")]
391/// Convenience macro to define a static `Address` value.
392///
393/// Input: a single literal base58 string representation of an `Address`.
394///
395/// # Example
396///
397/// ```
398/// use std::str::FromStr;
399/// use solana_address::{address, Address};
400///
401/// static ID: Address = address!("My11111111111111111111111111111111111111111");
402///
403/// let my_id = Address::from_str("My11111111111111111111111111111111111111111").unwrap();
404/// assert_eq!(ID, my_id);
405/// ```
406#[macro_export]
407macro_rules! address {
408    ($input:literal) => {
409        $crate::Address::from_str_const($input)
410    };
411}
412
413/// Convenience macro to declare a static address and functions to interact with it.
414///
415/// Input: a single literal base58 string representation of a program's ID.
416///
417/// # Example
418///
419/// ```
420/// # // wrapper is used so that the macro invocation occurs in the item position
421/// # // rather than in the statement position which isn't allowed.
422/// use std::str::FromStr;
423/// use solana_address::{declare_id, Address};
424///
425/// # mod item_wrapper {
426/// #   use solana_address::declare_id;
427/// declare_id!("My11111111111111111111111111111111111111111");
428/// # }
429/// # use item_wrapper::id;
430///
431/// let my_id = Address::from_str("My11111111111111111111111111111111111111111").unwrap();
432/// assert_eq!(id(), my_id);
433/// ```
434#[cfg(feature = "decode")]
435#[macro_export]
436macro_rules! declare_id {
437    ($address:expr) => {
438        #[cfg(not(target_arch = "bpf"))]
439        /// The const program ID.
440        pub const ID: $crate::Address = $crate::Address::from_str_const($address);
441        #[cfg(target_arch = "bpf")]
442        /// The const program ID.
443        pub static ID: $crate::Address = $crate::Address::from_str_const($address);
444
445        /// Returns `true` if given address is the ID.
446        // TODO make this const once `derive_const` makes it out of nightly
447        // and we can `derive_const(PartialEq)` on `Address`.
448        pub fn check_id(id: &$crate::Address) -> bool {
449            id == &ID
450        }
451
452        /// Returns the ID.
453        pub const fn id() -> $crate::Address {
454            #[cfg(not(target_arch = "bpf"))]
455            {
456                ID
457            }
458            #[cfg(target_arch = "bpf")]
459            $crate::Address::from_str_const($address)
460        }
461
462        #[cfg(test)]
463        #[test]
464        fn test_id() {
465            assert!(check_id(&id()));
466        }
467    };
468}
469
470/// Same as [`declare_id`] except that it reports that this ID has been deprecated.
471#[cfg(feature = "decode")]
472#[macro_export]
473macro_rules! declare_deprecated_id {
474    ($address:expr) => {
475        #[cfg(not(target_arch = "bpf"))]
476        /// The const ID.
477        pub const ID: $crate::Address = $crate::Address::from_str_const($address);
478        #[cfg(target_arch = "bpf")]
479        /// The const ID.
480        pub static ID: $crate::Address = $crate::Address::from_str_const($address);
481
482        /// Returns `true` if given address is the ID.
483        // TODO make this const once `derive_const` makes it out of nightly
484        // and we can `derive_const(PartialEq)` on `Address`.
485        #[deprecated()]
486        pub fn check_id(id: &$crate::Address) -> bool {
487            id == &ID
488        }
489
490        /// Returns the ID.
491        #[deprecated()]
492        pub const fn id() -> $crate::Address {
493            #[cfg(not(target_arch = "bpf"))]
494            {
495                ID
496            }
497            #[cfg(target_arch = "bpf")]
498            $crate::Address::from_str_const($address)
499        }
500
501        #[cfg(test)]
502        #[test]
503        #[allow(deprecated)]
504        fn test_id() {
505            assert!(check_id(&id()));
506        }
507    };
508}
509
510#[cfg(test)]
511mod tests {
512    use {super::*, core::str::from_utf8, std::string::String};
513
514    fn encode_address(address: &[u8; 32]) -> String {
515        let mut buffer = [0u8; 44];
516        let count = five8::encode_32(address, &mut buffer);
517        from_utf8(&buffer[..count as usize]).unwrap().to_string()
518    }
519
520    #[test]
521    fn test_new_unique() {
522        assert!(Address::new_unique() != Address::new_unique());
523    }
524
525    #[test]
526    fn address_fromstr() {
527        let address = Address::new_unique();
528        let mut address_base58_str = encode_address(&address.0);
529
530        assert_eq!(address_base58_str.parse::<Address>(), Ok(address));
531
532        address_base58_str.push_str(&encode_address(&address.0));
533        assert_eq!(
534            address_base58_str.parse::<Address>(),
535            Err(ParseAddressError::WrongSize)
536        );
537
538        address_base58_str.truncate(address_base58_str.len() / 2);
539        assert_eq!(address_base58_str.parse::<Address>(), Ok(address));
540
541        address_base58_str.truncate(address_base58_str.len() / 2);
542        assert_eq!(
543            address_base58_str.parse::<Address>(),
544            Err(ParseAddressError::WrongSize)
545        );
546
547        let mut address_base58_str = encode_address(&address.0);
548        assert_eq!(address_base58_str.parse::<Address>(), Ok(address));
549
550        // throw some non-base58 stuff in there
551        address_base58_str.replace_range(..1, "I");
552        assert_eq!(
553            address_base58_str.parse::<Address>(),
554            Err(ParseAddressError::Invalid)
555        );
556
557        // too long input string
558        // longest valid encoding
559        let mut too_long = encode_address(&[255u8; ADDRESS_BYTES]);
560        // and one to grow on
561        too_long.push('1');
562        assert_eq!(
563            too_long.parse::<Address>(),
564            Err(ParseAddressError::WrongSize)
565        );
566    }
567
568    #[test]
569    fn test_create_with_seed() {
570        assert!(
571            Address::create_with_seed(&Address::new_unique(), "☉", &Address::new_unique()).is_ok()
572        );
573        assert_eq!(
574            Address::create_with_seed(
575                &Address::new_unique(),
576                from_utf8(&[127; MAX_SEED_LEN + 1]).unwrap(),
577                &Address::new_unique()
578            ),
579            Err(AddressError::MaxSeedLengthExceeded)
580        );
581        assert!(Address::create_with_seed(
582            &Address::new_unique(),
583            "\
584             \u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\
585             ",
586            &Address::new_unique()
587        )
588        .is_ok());
589        // utf-8 abuse ;)
590        assert_eq!(
591            Address::create_with_seed(
592                &Address::new_unique(),
593                "\
594                 x\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\
595                 ",
596                &Address::new_unique()
597            ),
598            Err(AddressError::MaxSeedLengthExceeded)
599        );
600
601        assert!(Address::create_with_seed(
602            &Address::new_unique(),
603            from_utf8(&[0; MAX_SEED_LEN]).unwrap(),
604            &Address::new_unique(),
605        )
606        .is_ok());
607
608        assert!(
609            Address::create_with_seed(&Address::new_unique(), "", &Address::new_unique(),).is_ok()
610        );
611
612        assert_eq!(
613            Address::create_with_seed(
614                &Address::default(),
615                "limber chicken: 4/45",
616                &Address::default(),
617            ),
618            Ok("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq"
619                .parse()
620                .unwrap())
621        );
622    }
623
624    #[test]
625    fn test_create_program_address() {
626        let exceeded_seed = &[127; MAX_SEED_LEN + 1];
627        let max_seed = &[0; MAX_SEED_LEN];
628        let exceeded_seeds: &[&[u8]] = &[
629            &[1],
630            &[2],
631            &[3],
632            &[4],
633            &[5],
634            &[6],
635            &[7],
636            &[8],
637            &[9],
638            &[10],
639            &[11],
640            &[12],
641            &[13],
642            &[14],
643            &[15],
644            &[16],
645            &[17],
646        ];
647        let max_seeds: &[&[u8]] = &[
648            &[1],
649            &[2],
650            &[3],
651            &[4],
652            &[5],
653            &[6],
654            &[7],
655            &[8],
656            &[9],
657            &[10],
658            &[11],
659            &[12],
660            &[13],
661            &[14],
662            &[15],
663            &[16],
664        ];
665        let program_id = Address::from_str("BPFLoaderUpgradeab1e11111111111111111111111").unwrap();
666        let public_key = Address::from_str("SeedPubey1111111111111111111111111111111111").unwrap();
667
668        assert_eq!(
669            Address::create_program_address(&[exceeded_seed], &program_id),
670            Err(AddressError::MaxSeedLengthExceeded)
671        );
672        assert_eq!(
673            Address::create_program_address(&[b"short_seed", exceeded_seed], &program_id),
674            Err(AddressError::MaxSeedLengthExceeded)
675        );
676        assert!(Address::create_program_address(&[max_seed], &program_id).is_ok());
677        assert_eq!(
678            Address::create_program_address(exceeded_seeds, &program_id),
679            Err(AddressError::MaxSeedLengthExceeded)
680        );
681        assert!(Address::create_program_address(max_seeds, &program_id).is_ok());
682        assert_eq!(
683            Address::create_program_address(&[b"", &[1]], &program_id),
684            Ok("BwqrghZA2htAcqq8dzP1WDAhTXYTYWj7CHxF5j7TDBAe"
685                .parse()
686                .unwrap())
687        );
688        assert_eq!(
689            Address::create_program_address(&["☉".as_ref(), &[0]], &program_id),
690            Ok("13yWmRpaTR4r5nAktwLqMpRNr28tnVUZw26rTvPSSB19"
691                .parse()
692                .unwrap())
693        );
694        assert_eq!(
695            Address::create_program_address(&[b"Talking", b"Squirrels"], &program_id),
696            Ok("2fnQrngrQT4SeLcdToJAD96phoEjNL2man2kfRLCASVk"
697                .parse()
698                .unwrap())
699        );
700        assert_eq!(
701            Address::create_program_address(&[public_key.as_ref(), &[1]], &program_id),
702            Ok("976ymqVnfE32QFe6NfGDctSvVa36LWnvYxhU6G2232YL"
703                .parse()
704                .unwrap())
705        );
706        assert_ne!(
707            Address::create_program_address(&[b"Talking", b"Squirrels"], &program_id).unwrap(),
708            Address::create_program_address(&[b"Talking"], &program_id).unwrap(),
709        );
710    }
711
712    #[test]
713    fn test_address_off_curve() {
714        // try a bunch of random input, all successful generated program
715        // addresses must land off the curve and be unique
716        let mut addresses = std::vec![];
717        for _ in 0..1_000 {
718            let program_id = Address::new_unique();
719            let bytes1 = rand::random::<[u8; 10]>();
720            let bytes2 = rand::random::<[u8; 32]>();
721            if let Ok(program_address) =
722                Address::create_program_address(&[&bytes1, &bytes2], &program_id)
723            {
724                assert!(!program_address.is_on_curve());
725                assert!(!addresses.contains(&program_address));
726                addresses.push(program_address);
727            }
728        }
729    }
730
731    #[test]
732    fn test_find_program_address() {
733        for _ in 0..1_000 {
734            let program_id = Address::new_unique();
735            let (address, bump_seed) =
736                Address::find_program_address(&[b"Lil'", b"Bits"], &program_id);
737            assert_eq!(
738                address,
739                Address::create_program_address(&[b"Lil'", b"Bits", &[bump_seed]], &program_id)
740                    .unwrap()
741            );
742        }
743    }
744
745    fn address_from_seed_by_marker(marker: &[u8]) -> Result<Address, AddressError> {
746        let key = Address::new_unique();
747        let owner = Address::default();
748
749        let mut to_fake = owner.to_bytes().to_vec();
750        to_fake.extend_from_slice(marker);
751
752        let seed = from_utf8(&to_fake[..to_fake.len() - 32]).expect("not utf8");
753        let base = &Address::try_from(&to_fake[to_fake.len() - 32..]).unwrap();
754
755        Address::create_with_seed(&key, seed, base)
756    }
757
758    #[test]
759    fn test_create_with_seed_rejects_illegal_owner() {
760        assert_eq!(
761            address_from_seed_by_marker(PDA_MARKER),
762            Err(AddressError::IllegalOwner)
763        );
764        assert!(address_from_seed_by_marker(&PDA_MARKER[1..]).is_ok());
765    }
766
767    #[test]
768    fn test_as_array() {
769        let bytes = [1u8; 32];
770        let key = Address::from(bytes);
771        assert_eq!(key.as_array(), &bytes);
772        assert_eq!(key.as_array(), &key.to_bytes());
773        // Sanity check: ensure the pointer is the same.
774        assert_eq!(key.as_array().as_ptr(), key.0.as_ptr());
775    }
776
777    #[test]
778    fn test_address_macro() {
779        const ADDRESS: Address =
780            Address::from_str_const("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq");
781        assert_eq!(
782            address!("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq"),
783            ADDRESS
784        );
785        assert_eq!(
786            Address::from_str("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq").unwrap(),
787            ADDRESS
788        );
789    }
790
791    #[test]
792    fn test_address_eq_matches_default_eq() {
793        for i in 0..u8::MAX {
794            let p1 = Address::from([i; ADDRESS_BYTES]);
795            let p2 = Address::from([i; ADDRESS_BYTES]);
796
797            // Identical addresses must be equal.
798            assert!(p1 == p2);
799            assert!(p1.eq(&p2));
800            assert_eq!(p1.eq(&p2), p1.0 == p2.0);
801            assert!(address_eq(&p1, &p2));
802
803            let p3 = Address::from([u8::MAX - i; ADDRESS_BYTES]);
804
805            // Different addresses must not be equal.
806            assert!(p1 != p3);
807            assert!(!p1.eq(&p3));
808            assert_eq!(!p1.eq(&p3), p1.0 != p3.0);
809            assert!(!address_eq(&p1, &p3));
810        }
811    }
812}