Program address generator (#8995)

This commit is contained in:
Jack May 2020-03-23 12:38:56 -07:00 committed by GitHub
parent d75a470ffa
commit fee002382e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,4 +1,7 @@
use crate::{hash::hashv, program_utils::DecodeError};
use crate::{
hash::{hashv, Hasher},
program_utils::DecodeError,
};
use num_derive::{FromPrimitive, ToPrimitive};
#[cfg(not(feature = "program"))]
use std::error;
@ -79,6 +82,22 @@ impl Pubkey {
))
}
pub fn create_program_address(
seeds: &[&str],
program_id: &Pubkey,
) -> Result<Pubkey, PubkeyError> {
let mut hasher = Hasher::default();
for seed in seeds.iter() {
if seed.len() > MAX_SEED_LEN {
return Err(PubkeyError::MaxSeedLengthExceeded);
}
hasher.hash(seed.as_ref());
}
hasher.hashv(&[program_id.as_ref(), "ProgramDerivedAddress".as_ref()]);
Ok(Pubkey::new(hashv(&[hasher.result().as_ref()]).as_ref()))
}
#[cfg(not(feature = "program"))]
pub fn new_rand() -> Self {
Self::new(&rand::random::<[u8; 32]>())
@ -220,6 +239,45 @@ mod tests {
);
}
#[test]
fn test_create_program_address() {
let exceeded_seed = from_utf8(&[127; MAX_SEED_LEN + 1]).unwrap();
let max_seed = from_utf8(&[0; MAX_SEED_LEN]).unwrap();
let program_id = Pubkey::new(b"BPFLoader11111111111111111111111");
assert_eq!(
Pubkey::create_program_address(&[exceeded_seed], &program_id),
Err(PubkeyError::MaxSeedLengthExceeded)
);
assert_eq!(
Pubkey::create_program_address(&["short_seed", exceeded_seed], &program_id),
Err(PubkeyError::MaxSeedLengthExceeded)
);
assert!(Pubkey::create_program_address(&[max_seed], &Pubkey::new_rand(),).is_ok());
assert_eq!(
Pubkey::create_program_address(&[""], &program_id),
Ok("FXjJsFsMXM8LFXynZvEkED7yECADnaEgAzWD6yyg91QG"
.parse()
.unwrap())
);
assert_eq!(
Pubkey::create_program_address(&[""], &program_id),
Ok("MAuKBzPvme5QmCNALp5iAEasZeazkpRyCZbwtJVkJEG"
.parse()
.unwrap())
);
assert_eq!(
Pubkey::create_program_address(&["Talking", "Squirrels"], &program_id),
Ok("3beXgJ9MfstiGfzav45bicJ7ygiwUEoCfsM4W94EuRii"
.parse()
.unwrap())
);
assert_ne!(
Pubkey::create_program_address(&["Talking", "Squirrels"], &program_id),
Pubkey::create_program_address(&["Talking"], &program_id),
);
}
#[test]
fn test_read_write_pubkey() -> Result<(), Box<dyn error::Error>> {
let filename = "test_pubkey.json";