use crate::sys::{self, SysResult};
use core::mem::MaybeUninit;
use thruput_xdr::auth_claim::AuthClaim;
pub use thruput_xdr::auth_claim::BitMap;
pub use thruput_xdr::auth_claim::Weight;
use thruput_xdr::types::PublicKey;
mod layout {
use core::mem::{align_of, offset_of, size_of};
use thruput_xdr::auth_claim::{
AuthClaim, AuthClaim_source_address_claim, AuthClaimType,
PubkeyAccountPreimage,
};
use thruput_xdr::types::PublicKeyHash;
#[repr(C)]
struct PubkeyArm {
tag: AuthClaimType,
pubkey_preimage: PubkeyAccountPreimage,
}
#[repr(C)]
struct SourceArm {
tag: AuthClaimType,
source_address_claim: AuthClaim_source_address_claim,
}
pub(super) const AUTH_CLAIM_SIZE: usize = 48;
pub(super) const AUTH_CLAIM_ALIGN: usize = 8;
pub(super) const PUBKEY_HASH_OFFSET: usize = 8;
pub(super) const NONCE_OFFSET: usize = 40;
const _: () = {
assert!(size_of::<AuthClaimType>() == 4);
assert!(size_of::<AuthClaim>() == AUTH_CLAIM_SIZE);
assert!(align_of::<AuthClaim>() == AUTH_CLAIM_ALIGN);
assert!(size_of::<PublicKeyHash>() == 32);
assert!(align_of::<PublicKeyHash>() == 1);
assert!(size_of::<PubkeyAccountPreimage>() == 40);
assert!(align_of::<PubkeyAccountPreimage>() == 8);
assert!(offset_of!(PubkeyAccountPreimage, pubkey_hash) == 0);
assert!(offset_of!(PubkeyAccountPreimage, nonce) == 32);
assert!(offset_of!(PubkeyArm, tag) == 0);
assert!(offset_of!(PubkeyArm, pubkey_preimage) == PUBKEY_HASH_OFFSET);
assert!(
PUBKEY_HASH_OFFSET + offset_of!(PubkeyAccountPreimage, nonce)
== NONCE_OFFSET
);
assert!(size_of::<PubkeyArm>() == AUTH_CLAIM_SIZE);
assert!(size_of::<AuthClaim_source_address_claim>() == 8);
assert!(align_of::<AuthClaim_source_address_claim>() == 4);
assert!(offset_of!(AuthClaim_source_address_claim, allowed_keys) == 0);
assert!(
offset_of!(AuthClaim_source_address_claim, required_weight) == 4
);
assert!(offset_of!(SourceArm, source_address_claim) == 4);
assert!(size_of::<SourceArm>() == 12);
};
}
pub fn get_auth_claim() -> SysResult<AuthClaim> {
let mut auth_claim = MaybeUninit::uninit();
sys::uninit_GetAuthClaim(&mut auth_claim)?;
Ok(unsafe { auth_claim.assume_init() })
}
pub fn set_address_required_weight(required_weight: Weight) -> SysResult<()> {
sys::uninit_WriteAddressRequiredWeight(required_weight)
}
pub fn add_address_public_key(
pk_index: u32,
public_key: PublicKey,
key_weight: Weight,
) -> SysResult<()> {
let scheme = public_key.scheme();
sys::uninit_ChangePublicKeyRegistration(
pk_index,
Some(&scheme.0),
crate::crypto::public_key_bytes(&public_key),
Some(&key_weight),
)
}
pub fn remove_address_public_key(pk_index: u32) -> SysResult<()> {
sys::uninit_ChangePublicKeyRegistration(pk_index, None, &[], None)
}
#[cfg(test)]
mod tests {
use super::layout::*;
use thruput_xdr::auth_claim::{
AuthClaim, AuthClaim_source_address_claim, AuthClaimType,
PubkeyAccountPreimage,
};
use thruput_xdr::types::PublicKeyHash;
fn offset<T>(claim: &AuthClaim, field: &T) -> usize {
field as *const T as usize - claim as *const AuthClaim as usize
}
#[test]
fn pubkey_claim_field_offsets() {
let claim = AuthClaim::kPubkeySignature {
pubkey_preimage: PubkeyAccountPreimage {
pubkey_hash: PublicKeyHash::new([1; 32]),
nonce: 7,
},
};
assert_eq!(claim.claim_type(), AuthClaimType::kPubkeySignature);
let AuthClaim::kPubkeySignature { pubkey_preimage } = &claim else {
unreachable!()
};
assert_eq!(
offset(&claim, &pubkey_preimage.pubkey_hash),
PUBKEY_HASH_OFFSET
);
assert_eq!(offset(&claim, &pubkey_preimage.nonce), NONCE_OFFSET);
}
#[test]
fn source_claim_field_offsets() {
let claim = AuthClaim::kSourceAddressAuthData {
source_address_claim: AuthClaim_source_address_claim {
allowed_keys: 1,
required_weight: 2,
},
};
assert_eq!(claim.claim_type(), AuthClaimType::kSourceAddressAuthData);
let AuthClaim::kSourceAddressAuthData {
source_address_claim,
} = &claim
else {
unreachable!()
};
assert_eq!(offset(&claim, &source_address_claim.allowed_keys), 4);
assert_eq!(offset(&claim, &source_address_claim.required_weight), 8);
}
}