verification.rs (6986B)
1 #[cfg(not(feature = "std"))] 2 use alloc::string::{String, ToString}; 3 4 use core::fmt; 5 6 use radroots_event::contract::ContractValidationError; 7 use radroots_event::envelope::EventEnvelope; 8 use radroots_event::knowledge::{ 9 ContributionAttestation, EvidenceBounty, KnowledgeChangeProposal, KnowledgeClaim, 10 KnowledgeFieldReport, KnowledgeRelation, KnowledgeReview, KnowledgeSource, WikiArticle, 11 WikiMergeRequest, WikiRedirect, 12 }; 13 14 use crate::error::EventParseError; 15 use crate::knowledge::decode::{ 16 contribution_attestation_from_event, evidence_bounty_from_event, 17 knowledge_change_proposal_from_event, knowledge_claim_from_event, 18 knowledge_field_report_from_event, knowledge_relation_from_event, knowledge_review_from_event, 19 knowledge_source_from_event, wiki_article_from_event, wiki_merge_request_from_event, 20 wiki_redirect_from_event, 21 }; 22 use crate::parsed::RadrootsParsedEvent; 23 pub use crate::verification::{RadrootsContractValidatedEvent, validate_event_contract}; 24 use crate::verification::{RadrootsNip01VerificationError, verify_nip01_event}; 25 26 #[derive(Debug)] 27 pub enum RadrootsDecodeError { 28 Nip01Verification(RadrootsNip01VerificationError), 29 ContractValidation(ContractValidationError), 30 EventParse(EventParseError), 31 UnsupportedContract { contract_id: String }, 32 } 33 34 impl RadrootsDecodeError { 35 pub const fn code(&self) -> &'static str { 36 match self { 37 Self::Nip01Verification(_) => "nip01_verification", 38 Self::ContractValidation(_) => "contract_validation", 39 Self::EventParse(_) => "event_parse", 40 Self::UnsupportedContract { .. } => "unsupported_contract", 41 } 42 } 43 } 44 45 impl fmt::Display for RadrootsDecodeError { 46 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 47 match self { 48 Self::Nip01Verification(error) => write!(formatter, "{error}"), 49 Self::ContractValidation(error) => { 50 write!( 51 formatter, 52 "contract validation failed with code {}", 53 error.code() 54 ) 55 } 56 Self::EventParse(error) => write!(formatter, "{error}"), 57 Self::UnsupportedContract { contract_id } => { 58 write!(formatter, "unsupported event contract `{contract_id}`") 59 } 60 } 61 } 62 } 63 64 #[cfg(feature = "std")] 65 impl std::error::Error for RadrootsDecodeError {} 66 67 impl From<EventParseError> for RadrootsDecodeError { 68 fn from(value: EventParseError) -> Self { 69 Self::EventParse(value) 70 } 71 } 72 73 impl From<RadrootsNip01VerificationError> for RadrootsDecodeError { 74 fn from(value: RadrootsNip01VerificationError) -> Self { 75 Self::Nip01Verification(value) 76 } 77 } 78 79 impl From<ContractValidationError> for RadrootsDecodeError { 80 fn from(value: ContractValidationError) -> Self { 81 Self::ContractValidation(value) 82 } 83 } 84 85 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 86 #[derive(Clone, Debug)] 87 pub enum RadrootsDecodedEvent { 88 WikiArticle(RadrootsParsedEvent<WikiArticle>), 89 WikiRedirect(RadrootsParsedEvent<WikiRedirect>), 90 WikiMergeRequest(RadrootsParsedEvent<WikiMergeRequest>), 91 KnowledgeSource(RadrootsParsedEvent<KnowledgeSource>), 92 KnowledgeClaim(RadrootsParsedEvent<KnowledgeClaim>), 93 KnowledgeRelation(RadrootsParsedEvent<KnowledgeRelation>), 94 KnowledgeReview(RadrootsParsedEvent<KnowledgeReview>), 95 KnowledgeFieldReport(RadrootsParsedEvent<KnowledgeFieldReport>), 96 EvidenceBounty(RadrootsParsedEvent<EvidenceBounty>), 97 KnowledgeChangeProposal(RadrootsParsedEvent<KnowledgeChangeProposal>), 98 ContributionAttestation(RadrootsParsedEvent<ContributionAttestation>), 99 } 100 101 impl RadrootsDecodedEvent { 102 pub fn event(&self) -> &EventEnvelope { 103 match self { 104 Self::WikiArticle(parsed) => &parsed.event, 105 Self::WikiRedirect(parsed) => &parsed.event, 106 Self::WikiMergeRequest(parsed) => &parsed.event, 107 Self::KnowledgeSource(parsed) => &parsed.event, 108 Self::KnowledgeClaim(parsed) => &parsed.event, 109 Self::KnowledgeRelation(parsed) => &parsed.event, 110 Self::KnowledgeReview(parsed) => &parsed.event, 111 Self::KnowledgeFieldReport(parsed) => &parsed.event, 112 Self::EvidenceBounty(parsed) => &parsed.event, 113 Self::KnowledgeChangeProposal(parsed) => &parsed.event, 114 Self::ContributionAttestation(parsed) => &parsed.event, 115 } 116 } 117 } 118 119 pub fn decode_validated_event( 120 event: RadrootsContractValidatedEvent, 121 ) -> Result<RadrootsDecodedEvent, RadrootsDecodeError> { 122 let contract_id = event.contract_id(); 123 let event = event.into_event(); 124 match contract_id { 125 "radroots.wiki.article.v1" => Ok(RadrootsDecodedEvent::WikiArticle( 126 wiki_article_from_event(event)?, 127 )), 128 "radroots.wiki.redirect.v1" => Ok(RadrootsDecodedEvent::WikiRedirect( 129 wiki_redirect_from_event(event)?, 130 )), 131 "radroots.wiki.merge_request.v1" => Ok(RadrootsDecodedEvent::WikiMergeRequest( 132 wiki_merge_request_from_event(event)?, 133 )), 134 "radroots.knowledge.source.v1" => Ok(RadrootsDecodedEvent::KnowledgeSource( 135 knowledge_source_from_event(event)?, 136 )), 137 "radroots.knowledge.claim.v1" => Ok(RadrootsDecodedEvent::KnowledgeClaim( 138 knowledge_claim_from_event(event)?, 139 )), 140 "radroots.knowledge.relation.v1" => Ok(RadrootsDecodedEvent::KnowledgeRelation( 141 knowledge_relation_from_event(event)?, 142 )), 143 "radroots.knowledge.review.v1" => Ok(RadrootsDecodedEvent::KnowledgeReview( 144 knowledge_review_from_event(event)?, 145 )), 146 "radroots.knowledge.field_report.v1" => Ok(RadrootsDecodedEvent::KnowledgeFieldReport( 147 knowledge_field_report_from_event(event)?, 148 )), 149 "radroots.knowledge.evidence_bounty.v1" => Ok(RadrootsDecodedEvent::EvidenceBounty( 150 evidence_bounty_from_event(event)?, 151 )), 152 "radroots.knowledge.change_proposal.v1" => { 153 Ok(RadrootsDecodedEvent::KnowledgeChangeProposal( 154 knowledge_change_proposal_from_event(event)?, 155 )) 156 } 157 "radroots.knowledge.contribution_attestation.v1" => { 158 Ok(RadrootsDecodedEvent::ContributionAttestation( 159 contribution_attestation_from_event(event)?, 160 )) 161 } 162 contract_id => Err(RadrootsDecodeError::UnsupportedContract { 163 contract_id: contract_id.to_string(), 164 }), 165 } 166 } 167 168 /// Verifies NIP-01 identity before applying the knowledge contract and decoder. 169 pub fn verify_and_decode_radroots_event( 170 event: EventEnvelope, 171 ) -> Result<RadrootsDecodedEvent, RadrootsDecodeError> { 172 let verified = verify_nip01_event(event)?; 173 let contract_validated = validate_event_contract(verified)?; 174 decode_validated_event(contract_validated) 175 }