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