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