use crate::room_state::ChatRoomParametersV1;
use ed25519_dalek::VerifyingKey;
use freenet_stdlib::prelude::{ContractKey, Parameters};
mod generated {
include!(concat!(env!("OUT_DIR"), "/legacy_room_contracts.rs"));
}
pub use generated::LEGACY_ROOM_CONTRACT_CODE_HASHES;
fn encode_params(owner_vk: &VerifyingKey) -> Vec<u8> {
let params = ChatRoomParametersV1 { owner: *owner_vk };
let mut buf = Vec::new();
ciborium::ser::into_writer(¶ms, &mut buf)
.expect("CBOR serialization of ChatRoomParametersV1 cannot fail");
buf
}
pub fn contract_key_for_code_hash(owner_vk: &VerifyingKey, code_hash: &[u8; 32]) -> ContractKey {
let code_hash_b58 = bs58::encode(code_hash)
.with_alphabet(bs58::Alphabet::BITCOIN)
.into_string();
ContractKey::from_params(code_hash_b58, Parameters::from(encode_params(owner_vk)))
.expect("base58 encoding of a 32-byte array always decodes back to 32 bytes")
}
pub fn legacy_contract_keys_for_owner(owner_vk: &VerifyingKey) -> Vec<ContractKey> {
LEGACY_ROOM_CONTRACT_CODE_HASHES
.iter()
.rev()
.map(|code_hash| contract_key_for_code_hash(owner_vk, code_hash))
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
use ed25519_dalek::SigningKey;
use rand::rngs::OsRng;
#[test]
fn registry_is_non_empty_and_hashes_are_distinct() {
assert!(
!LEGACY_ROOM_CONTRACT_CODE_HASHES.is_empty(),
"legacy room-contract registry is empty"
);
let mut seen = std::collections::HashSet::new();
for hash in LEGACY_ROOM_CONTRACT_CODE_HASHES {
assert!(
seen.insert(*hash),
"duplicate code hash in legacy room-contract registry: {}",
hex::encode(hash)
);
}
}
#[test]
fn legacy_keys_are_newest_first_and_complete() {
let owner = SigningKey::generate(&mut OsRng).verifying_key();
let keys = legacy_contract_keys_for_owner(&owner);
assert_eq!(keys.len(), LEGACY_ROOM_CONTRACT_CODE_HASHES.len());
let newest = LEGACY_ROOM_CONTRACT_CODE_HASHES.last().unwrap();
assert_eq!(keys[0], contract_key_for_code_hash(&owner, newest));
}
#[test]
fn keys_are_owner_specific() {
let owner_a = SigningKey::generate(&mut OsRng).verifying_key();
let owner_b = SigningKey::generate(&mut OsRng).verifying_key();
let code_hash = LEGACY_ROOM_CONTRACT_CODE_HASHES[0];
assert_ne!(
contract_key_for_code_hash(&owner_a, &code_hash),
contract_key_for_code_hash(&owner_b, &code_hash),
);
}
#[test]
fn derivation_is_deterministic() {
let owner = SigningKey::generate(&mut OsRng).verifying_key();
let code_hash = LEGACY_ROOM_CONTRACT_CODE_HASHES[0];
assert_eq!(
contract_key_for_code_hash(&owner, &code_hash),
contract_key_for_code_hash(&owner, &code_hash),
);
}
}