use crate::tn_tools::Pubkey;
use sha2::{Digest, Sha256};
const TN_UPLOADER_PROGRAM_SEED_SIZE: usize = 32;
pub fn derive_uploader_program_accounts(
seed: &[u8],
program_id: &Pubkey,
) -> Result<(Pubkey, Pubkey), Box<dyn std::error::Error>> {
if seed.is_empty() {
return Err("Seed cannot be empty".into());
}
if seed.len() > TN_UPLOADER_PROGRAM_SEED_SIZE {
return Err("Seed cannot be greater than 32 bytes".into());
}
let mut padded_seed = [0u8; TN_UPLOADER_PROGRAM_SEED_SIZE];
padded_seed[..seed.len()].copy_from_slice(seed);
let meta_account = derive_program_address(&padded_seed, program_id, true)?;
let meta_bytes = meta_account.to_bytes()?;
let buffer_account = derive_program_address(&meta_bytes, program_id, true)?;
Ok((meta_account, buffer_account))
}
pub fn derive_manager_program_accounts(
seed: &[u8],
program_id: &Pubkey,
is_ephemeral: bool,
) -> Result<(Pubkey, Pubkey), Box<dyn std::error::Error>> {
if seed.is_empty() {
return Err("Seed cannot be empty".into());
}
if seed.len() > TN_UPLOADER_PROGRAM_SEED_SIZE {
return Err("Seed cannot be greater than 32 bytes".into());
}
let mut padded_seed = [0u8; TN_UPLOADER_PROGRAM_SEED_SIZE];
padded_seed[..seed.len()].copy_from_slice(seed);
let meta_account = derive_program_address(&padded_seed, program_id, is_ephemeral)?;
let meta_bytes = meta_account.to_bytes()?;
let program_account = derive_program_address(&meta_bytes, program_id, is_ephemeral)?;
Ok((meta_account, program_account))
}
pub fn derive_program_address(
seed: &[u8; 32],
program_id: &Pubkey,
is_ephemeral: bool,
) -> Result<Pubkey, Box<dyn std::error::Error>> {
let program_bytes = program_id
.to_bytes()
.map_err(|e| format!("Failed to convert program_id to bytes: {}", e))?;
let mut hasher = Sha256::new();
hasher.update(&program_bytes);
hasher.update(&[if is_ephemeral { 1u8 } else { 0u8 }]);
hasher.update(seed);
let hash = hasher.finalize();
let mut derived_bytes = [0u8; 32];
derived_bytes.copy_from_slice(&hash[..32]);
Ok(Pubkey::from_bytes(&derived_bytes))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_derive_uploader_program_accounts() {
let program_bytes = [1u8; 32];
let program_id = Pubkey::from_bytes(&program_bytes);
let seed = b"test_seed";
let result = derive_uploader_program_accounts(seed, &program_id);
assert!(result.is_ok());
let (meta_account, buffer_account) = result.unwrap();
assert_ne!(meta_account, buffer_account);
let result2 = derive_uploader_program_accounts(seed, &program_id);
let (meta_account2, buffer_account2) = result2.unwrap();
assert_eq!(meta_account, meta_account2);
assert_eq!(buffer_account, buffer_account2);
}
#[test]
fn test_derive_uploader_program_accounts_empty_seed() {
let program_bytes = [1u8; 32];
let program_id = Pubkey::from_bytes(&program_bytes);
let empty_seed = b"";
let result = derive_uploader_program_accounts(empty_seed, &program_id);
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "Seed cannot be empty");
}
#[test]
fn test_derive_program_address_different_seeds() {
let program_bytes = [1u8; 32];
let program_id = Pubkey::from_bytes(&program_bytes);
let mut seed1 = [0u8; 32];
seed1[..4].copy_from_slice(b"test");
let mut seed2 = [0u8; 32];
seed2[..4].copy_from_slice(b"seed");
let pubkey1 = derive_program_address(&seed1, &program_id, false).unwrap();
let pubkey2 = derive_program_address(&seed2, &program_id, false).unwrap();
assert_ne!(pubkey1, pubkey2);
}
}