ab_contracts_common/
method.rs

1use crate::env::Blake3Hash;
2use crate::metadata::ContractMetadataKind;
3use ab_contracts_io_type::trivial_type::TrivialType;
4use const_sha1::sha1;
5use core::fmt;
6
7/// Hash of method's compact metadata, which uniquely represents method signature.
8///
9/// While nothing can be said about method implementation, matching method fingerprint means method
10/// name, inputs and outputs are what they are expected to be (struct and field names are ignored as
11/// explained in [`ContractMetadataKind::compact`].
12#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, TrivialType)]
13#[repr(C)]
14pub struct MethodFingerprint(Blake3Hash);
15
16impl fmt::Display for MethodFingerprint {
17    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18        for byte in self.0 {
19            write!(f, "{byte:02x}")?;
20        }
21        Ok(())
22    }
23}
24
25impl MethodFingerprint {
26    /// Create a new method fingerprint from its metadata.
27    ///
28    /// `None` is returned for invalid metadata (see
29    /// [`ContractMetadataKind::compact_external_args()`] for details).
30    pub const fn new(method_metadata: &[u8]) -> Option<Self> {
31        // `?` is not supported in `const` environment
32        let Some((compact_metadata_scratch, compact_metadata_size)) =
33            ContractMetadataKind::compact_external_args(method_metadata)
34        else {
35            return None;
36        };
37        // The same as `&compact_metadata_scratch[..compact_metadata_size]`, but it is not allowed
38        // in const environment yet
39        let compact_metadata = compact_metadata_scratch.split_at(compact_metadata_size).0;
40
41        let hash = sha1(compact_metadata).as_bytes();
42
43        Some(Self([
44            hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8],
45            hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15], hash[16],
46            hash[17], hash[18], hash[19], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
47        ]))
48    }
49
50    #[inline(always)]
51    pub const fn to_bytes(&self) -> &Blake3Hash {
52        &self.0
53    }
54}
55
56/// Marker trait for external arguments when calling methods.
57///
58/// # Safety
59/// Struct that implements this trait must be `#[repr(C)]` and valid `ExternalArgs` for the contract
60/// method being called.
61///
62/// **Do not implement this trait explicitly!** Implementation is automatically generated by the
63/// macro which generates contract implementation.
64pub unsafe trait ExternalArgs {
65    /// Fingerprint of the method being called
66    const FINGERPRINT: MethodFingerprint;
67    /// Metadata that corresponds to a method being called
68    const METADATA: &[u8];
69}