1#![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
53pub const ADDRESS_BYTES: usize = 32;
55pub const MAX_SEED_LEN: usize = 32;
57pub const MAX_SEEDS: usize = 16;
59#[cfg(feature = "decode")]
60const MAX_BASE58_LEN: usize = 44;
62
63#[cfg(target_arch = "bpf")]
65pub static PDA_MARKER: &[u8; 21] = b"ProgramDerivedAddress";
66#[cfg(not(target_arch = "bpf"))]
68pub const PDA_MARKER: &[u8; 21] = b"ProgramDerivedAddress";
69
70#[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
125impl 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#[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 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 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 b[0..COUNTER_BYTES].copy_from_slice(&i.to_be_bytes());
221 #[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 #[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 #[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 #[inline(always)]
274 pub const fn as_array(&self) -> &[u8; 32] {
275 &self.0
276 }
277
278 #[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 #[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 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#[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#[macro_export]
368macro_rules! address {
369 ($input:literal) => {
370 $crate::Address::from_str_const($input)
371 };
372}
373
374#[cfg(feature = "decode")]
396#[macro_export]
397macro_rules! declare_id {
398 ($address:expr) => {
399 #[cfg(not(target_arch = "bpf"))]
400 pub const ID: $crate::Address = $crate::Address::from_str_const($address);
402 #[cfg(target_arch = "bpf")]
403 pub static ID: $crate::Address = $crate::Address::from_str_const($address);
405
406 pub fn check_id(id: &$crate::Address) -> bool {
410 id == &ID
411 }
412
413 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#[cfg(feature = "decode")]
433#[macro_export]
434macro_rules! declare_deprecated_id {
435 ($address:expr) => {
436 #[cfg(not(target_arch = "bpf"))]
437 pub const ID: $crate::Address = $crate::Address::from_str_const($address);
439 #[cfg(target_arch = "bpf")]
440 pub static ID: $crate::Address = $crate::Address::from_str_const($address);
442
443 #[deprecated()]
447 pub fn check_id(id: &$crate::Address) -> bool {
448 id == &ID
449 }
450
451 #[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 address_base58_str.replace_range(..1, "I");
513 assert_eq!(
514 address_base58_str.parse::<Address>(),
515 Err(ParseAddressError::Invalid)
516 );
517
518 let mut too_long = encode_address(&[255u8; ADDRESS_BYTES]);
521 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 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 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 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 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 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}