admission.rs (5681B)
1 #[cfg(not(feature = "std"))] 2 use alloc::boxed::Box; 3 4 use core::fmt; 5 6 use radroots_event::{ 7 contract::EventContract, envelope::EventEnvelope, 8 food::availability::RADROOTS_FOOD_AVAILABILITY_CONTRACT_ID, 9 listing::classified::ClassifiedListingPartition, 10 }; 11 12 use crate::{ 13 food_availability::inbound::{ 14 RadrootsFoodAvailabilityProjectionError, RadrootsFoodAvailabilityProjectionOutcome, 15 RadrootsInboundFoodAvailabilityProjection, project_verified_food_availability_event, 16 }, 17 verification::{ 18 RadrootsNip01VerificationError, RadrootsSignatureVerifiedEvent, verify_nip01_event, 19 }, 20 }; 21 22 /// A verified focused FoodAvailability event bound to its tolerant projection. 23 #[derive(Clone, Debug, PartialEq, Eq)] 24 pub struct RadrootsAdmittedFoodAvailabilityEvent { 25 verified_event: RadrootsSignatureVerifiedEvent, 26 projection: RadrootsInboundFoodAvailabilityProjection, 27 } 28 29 impl RadrootsAdmittedFoodAvailabilityEvent { 30 pub fn verified_event(&self) -> &RadrootsSignatureVerifiedEvent { 31 &self.verified_event 32 } 33 34 pub fn event(&self) -> &EventEnvelope { 35 self.verified_event.event() 36 } 37 38 pub fn projection(&self) -> &RadrootsInboundFoodAvailabilityProjection { 39 &self.projection 40 } 41 42 pub fn contract(&self) -> &'static EventContract { 43 radroots_event::contract::event_contract(RADROOTS_FOOD_AVAILABILITY_CONTRACT_ID) 44 .expect("FoodAvailability contract ID is registry-owned") 45 } 46 47 pub fn into_parts( 48 self, 49 ) -> ( 50 RadrootsSignatureVerifiedEvent, 51 RadrootsInboundFoodAvailabilityProjection, 52 ) { 53 (self.verified_event, self.projection) 54 } 55 } 56 57 /// A verified kind-30402 event excluded from the focused Food profile. 58 #[derive(Clone, Debug, PartialEq, Eq)] 59 pub struct RadrootsExcludedClassifiedListingCandidate { 60 verified_event: RadrootsSignatureVerifiedEvent, 61 partition: ClassifiedListingPartition, 62 } 63 64 impl RadrootsExcludedClassifiedListingCandidate { 65 pub fn verified_event(&self) -> &RadrootsSignatureVerifiedEvent { 66 &self.verified_event 67 } 68 69 pub fn event(&self) -> &EventEnvelope { 70 self.verified_event.event() 71 } 72 73 pub const fn partition(&self) -> ClassifiedListingPartition { 74 self.partition 75 } 76 77 pub fn into_parts(self) -> (RadrootsSignatureVerifiedEvent, ClassifiedListingPartition) { 78 (self.verified_event, self.partition) 79 } 80 } 81 82 #[non_exhaustive] 83 #[derive(Clone, Debug, PartialEq, Eq)] 84 pub enum RadrootsFoodAvailabilityAdmissionOutcome { 85 Admitted(Box<RadrootsAdmittedFoodAvailabilityEvent>), 86 Excluded(RadrootsExcludedClassifiedListingCandidate), 87 } 88 89 #[non_exhaustive] 90 #[derive(Clone, Debug, PartialEq, Eq)] 91 pub enum RadrootsFoodAvailabilityAdmissionError { 92 Nip01Verification(RadrootsNip01VerificationError), 93 Projection(RadrootsFoodAvailabilityProjectionError), 94 } 95 96 impl RadrootsFoodAvailabilityAdmissionError { 97 pub const fn code(&self) -> &'static str { 98 match self { 99 Self::Nip01Verification(error) => error.code(), 100 Self::Projection(error) => error.code(), 101 } 102 } 103 } 104 105 impl fmt::Display for RadrootsFoodAvailabilityAdmissionError { 106 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 107 match self { 108 Self::Nip01Verification(error) => write!(formatter, "{error}"), 109 Self::Projection(error) => write!(formatter, "{error}"), 110 } 111 } 112 } 113 114 #[cfg(feature = "std")] 115 impl std::error::Error for RadrootsFoodAvailabilityAdmissionError { 116 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 117 match self { 118 Self::Nip01Verification(error) => Some(error), 119 Self::Projection(error) => Some(error), 120 } 121 } 122 } 123 124 impl From<RadrootsNip01VerificationError> for RadrootsFoodAvailabilityAdmissionError { 125 fn from(value: RadrootsNip01VerificationError) -> Self { 126 Self::Nip01Verification(value) 127 } 128 } 129 130 impl From<RadrootsFoodAvailabilityProjectionError> for RadrootsFoodAvailabilityAdmissionError { 131 fn from(value: RadrootsFoodAvailabilityProjectionError) -> Self { 132 Self::Projection(value) 133 } 134 } 135 136 /// Admits or explicitly excludes an already verified classified listing. 137 pub fn admit_verified_food_availability_event( 138 verified_event: RadrootsSignatureVerifiedEvent, 139 ) -> Result<RadrootsFoodAvailabilityAdmissionOutcome, RadrootsFoodAvailabilityAdmissionError> { 140 match project_verified_food_availability_event(&verified_event)? { 141 RadrootsFoodAvailabilityProjectionOutcome::Focused(projection) => { 142 Ok(RadrootsFoodAvailabilityAdmissionOutcome::Admitted( 143 Box::new(RadrootsAdmittedFoodAvailabilityEvent { 144 verified_event, 145 projection: *projection, 146 }), 147 )) 148 } 149 RadrootsFoodAvailabilityProjectionOutcome::Excluded(partition) => { 150 debug_assert!(matches!( 151 partition, 152 ClassifiedListingPartition::OperationalListing 153 | ClassifiedListingPartition::GenericNip99 154 )); 155 Ok(RadrootsFoodAvailabilityAdmissionOutcome::Excluded( 156 RadrootsExcludedClassifiedListingCandidate { 157 verified_event, 158 partition, 159 }, 160 )) 161 } 162 } 163 } 164 165 /// Verifies NIP-01 id and signature before focused Food admission. 166 pub fn verify_and_admit_food_availability_event( 167 event: EventEnvelope, 168 ) -> Result<RadrootsFoodAvailabilityAdmissionOutcome, RadrootsFoodAvailabilityAdmissionError> { 169 admit_verified_food_availability_event(verify_nip01_event(event)?) 170 }