Skip to content

Commit 7080c53

Browse files
feat(rust/signed-doc): CatalystSignedDocument validator basic structure (#196)
* fix(rust/signed-doc): add content type validation * fix(rust/signed-doc): content encoding field is optional * fix(rust/signed-doc): add 'half' feature from minicbor crate * wip(rust/signed_doc): implement verification method * verify signatures with public (verification) key * todo: verify UUIDs * fix(rust/signed-doc): fix content-type verification * wip(rust/signed_doc): implement verification method * verify doc type, id and ver * wip(rust/signed_doc): implement verification method * verify extra fields * feat(rust/signed-doc): add signatures to Catalyst Signed Document * fix(rust/signed-doc): refactor cli tool to sign * fix(rust/signed-doc): add verify command to cli tool * fix(rust/catalyst-types): refactor sigining logic into builder * chore(docs): fix spelling * fix(rust/signed-doc): cleanup * fix content validation, add unit test * remove clippy * remove redundant types * fix * add DocumentType * wip * add validator module * add Proposal Document type * wip * wip * fix spelling * fix(rust/signed-doc): refactor doc type constant for proposals --------- Co-authored-by: Joaquín Rosales <[email protected]>
1 parent 85d3e41 commit 7080c53

File tree

9 files changed

+287
-158
lines changed

9 files changed

+287
-158
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
//! An implementation of different defined document types
2+
//! <https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/types/>
3+
4+
mod proposal_document;
5+
6+
use catalyst_types::uuid::UuidV4;
7+
pub use proposal_document::{ProposalDocument, PROPOSAL_DOCUMENT_UUID_TYPE};
8+
9+
/// Represents different types of documents.
10+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11+
pub enum DocumentType {
12+
/// A proposal document containing proposal details.
13+
ProposalDocument,
14+
/// A template for proposal documents, defining the expected structure.
15+
ProposalTemplate,
16+
/// A document representing a comment on a proposal.
17+
CommentDocument,
18+
/// A template for comment documents, defining the expected structure.
19+
CommentTemplate,
20+
/// A review document containing feedback on a proposal.
21+
ReviewDocument,
22+
/// A template for review documents, defining the expected structure.
23+
ReviewTemplate,
24+
/// A document defining parameters for a specific category.
25+
CategoryParametersDocument,
26+
/// A template for category parameter documents, defining the expected structure.
27+
CategoryParametersTemplate,
28+
/// A document containing parameters for a specific campaign.
29+
CampaignParametersDocument,
30+
/// A template for campaign parameter documents, defining the expected structure.
31+
CampaignParametersTemplate,
32+
/// A document containing brand-related parameters.
33+
BrandParametersDocument,
34+
/// A template for brand parameter documents, defining the expected structure.
35+
BrandParametersTemplate,
36+
/// A document representing an action related to a proposal.
37+
ProposalActionDocument,
38+
/// A public voting transaction version 2.
39+
PublicVoteTxV2,
40+
/// A private voting transaction version 2.
41+
PrivateVoteTxV2,
42+
/// A block in the immutable ledger.
43+
ImmutableLedgerBlock,
44+
}
45+
46+
/// Proposal template `UuidV4` type.
47+
const PROPOSAL_TEMPLATE_UUID_TYPE: uuid::Uuid =
48+
uuid::Uuid::from_u128(0x0CE8_AB38_9258_4FBC_A62E_7FAA_6E58_318F);
49+
/// Comment document `UuidV4` type.
50+
const COMMENT_DOCUMENT_UUID_TYPE: uuid::Uuid =
51+
uuid::Uuid::from_u128(0xB679_DED3_0E7C_41BA_89F8_DA62_A178_98EA);
52+
/// Comment template `UuidV4` type.
53+
const COMMENT_TEMPLATE_UUID_TYPE: uuid::Uuid =
54+
uuid::Uuid::from_u128(0x0B84_24D4_EBFD_46E3_9577_1775_A69D_290C);
55+
/// Review document `UuidV4` type.
56+
const REVIEW_DOCUMENT_UUID_TYPE: uuid::Uuid =
57+
uuid::Uuid::from_u128(0xE4CA_F5F0_098B_45FD_94F3_0702_A457_3DB5);
58+
/// Review template `UuidV4` type.
59+
const REVIEW_TEMPLATE_UUID_TYPE: uuid::Uuid =
60+
uuid::Uuid::from_u128(0xEBE5_D0BF_5D86_4577_AF4D_008F_DDBE_2EDC);
61+
/// Category parameters document `UuidV4` type.
62+
const CATEGORY_PARAMETERS_DOCUMENT_UUID_TYPE: uuid::Uuid =
63+
uuid::Uuid::from_u128(0x48C2_0109_362A_4D32_9BBA_E0A9_CF8B_45BE);
64+
/// Category parameters template `UuidV4` type.
65+
const CATEGORY_PARAMETERS_TEMPLATE_UUID_TYPE: uuid::Uuid =
66+
uuid::Uuid::from_u128(0x65B1_E8B0_51F1_46A5_9970_72CD_F268_84BE);
67+
/// Campaign parameters document `UuidV4` type.
68+
const CAMPAIGN_PARAMETERS_DOCUMENT_UUID_TYPE: uuid::Uuid =
69+
uuid::Uuid::from_u128(0x0110_EA96_A555_47CE_8408_36EF_E6ED_6F7C);
70+
/// Campaign parameters template `UuidV4` type.
71+
const CAMPAIGN_PARAMETERS_TEMPLATE_UUID_TYPE: uuid::Uuid =
72+
uuid::Uuid::from_u128(0x7E8F_5FA2_44CE_49C8_BFD5_02AF_42C1_79A3);
73+
/// Brand parameters document `UuidV4` type.
74+
const BRAND_PARAMETERS_DOCUMENT_UUID_TYPE: uuid::Uuid =
75+
uuid::Uuid::from_u128(0x3E48_08CC_C86E_467B_9702_D60B_AA9D_1FCA);
76+
/// Brand parameters template `UuidV4` type.
77+
const BRAND_PARAMETERS_TEMPLATE_UUID_TYPE: uuid::Uuid =
78+
uuid::Uuid::from_u128(0xFD3C_1735_80B1_4EEA_8D63_5F43_6D97_EA31);
79+
/// Proposal action document `UuidV4` type.
80+
const PROPOSAL_ACTION_DOCUMENT_UUID_TYPE: uuid::Uuid =
81+
uuid::Uuid::from_u128(0x5E60_E623_AD02_4A1B_A1AC_406D_B978_EE48);
82+
/// Public vote transaction v2 `UuidV4` type.
83+
const PUBLIC_VOTE_TX_V2_UUID_TYPE: uuid::Uuid =
84+
uuid::Uuid::from_u128(0x8DE5_586C_E998_4B95_8742_7BE3_C859_2803);
85+
/// Private vote transaction v2 `UuidV4` type.
86+
const PRIVATE_VOTE_TX_V2_UUID_TYPE: uuid::Uuid =
87+
uuid::Uuid::from_u128(0xE78E_E18D_F380_44C1_A852_80AA_6ECB_07FE);
88+
/// Immutable ledger block `UuidV4` type.
89+
const IMMUTABLE_LEDGER_BLOCK_UUID_TYPE: uuid::Uuid =
90+
uuid::Uuid::from_u128(0xD9E7_E6CE_2401_4D7D_9492_F4F7_C642_41C3);
91+
92+
impl TryFrom<UuidV4> for DocumentType {
93+
type Error = anyhow::Error;
94+
95+
fn try_from(uuid: UuidV4) -> Result<Self, Self::Error> {
96+
match uuid.uuid() {
97+
PROPOSAL_DOCUMENT_UUID_TYPE => Ok(DocumentType::ProposalDocument),
98+
PROPOSAL_TEMPLATE_UUID_TYPE => Ok(DocumentType::ProposalTemplate),
99+
COMMENT_DOCUMENT_UUID_TYPE => Ok(DocumentType::CommentDocument),
100+
COMMENT_TEMPLATE_UUID_TYPE => Ok(DocumentType::CommentTemplate),
101+
REVIEW_DOCUMENT_UUID_TYPE => Ok(DocumentType::ReviewDocument),
102+
REVIEW_TEMPLATE_UUID_TYPE => Ok(DocumentType::ReviewTemplate),
103+
CATEGORY_PARAMETERS_DOCUMENT_UUID_TYPE => Ok(DocumentType::CategoryParametersDocument),
104+
CATEGORY_PARAMETERS_TEMPLATE_UUID_TYPE => Ok(DocumentType::CategoryParametersTemplate),
105+
CAMPAIGN_PARAMETERS_DOCUMENT_UUID_TYPE => Ok(DocumentType::CampaignParametersDocument),
106+
CAMPAIGN_PARAMETERS_TEMPLATE_UUID_TYPE => Ok(DocumentType::CampaignParametersTemplate),
107+
BRAND_PARAMETERS_DOCUMENT_UUID_TYPE => Ok(DocumentType::BrandParametersDocument),
108+
BRAND_PARAMETERS_TEMPLATE_UUID_TYPE => Ok(DocumentType::BrandParametersTemplate),
109+
PROPOSAL_ACTION_DOCUMENT_UUID_TYPE => Ok(DocumentType::ProposalActionDocument),
110+
PUBLIC_VOTE_TX_V2_UUID_TYPE => Ok(DocumentType::PublicVoteTxV2),
111+
PRIVATE_VOTE_TX_V2_UUID_TYPE => Ok(DocumentType::PrivateVoteTxV2),
112+
IMMUTABLE_LEDGER_BLOCK_UUID_TYPE => Ok(DocumentType::ImmutableLedgerBlock),
113+
_ => anyhow::bail!("Unsupported document type"),
114+
}
115+
}
116+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//! Proposal Document object implementation
2+
//! <https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/catalyst_docs/proposal/#proposal-document>
3+
4+
use catalyst_types::problem_report::ProblemReport;
5+
6+
use crate::{error::CatalystSignedDocError, CatalystSignedDocument};
7+
8+
/// Proposal document `UuidV4` type.
9+
pub const PROPOSAL_DOCUMENT_UUID_TYPE: uuid::Uuid =
10+
uuid::Uuid::from_u128(0x7808_D2BA_D511_40AF_84E8_C0D1_625F_DFDC);
11+
12+
/// Proposal Document struct
13+
pub struct ProposalDocument {
14+
/// Proposal document content data
15+
/// TODO: change it to `serde_json::Value` type
16+
#[allow(dead_code)]
17+
content: Vec<u8>,
18+
}
19+
20+
impl ProposalDocument {
21+
/// Try to build `ProposalDocument` from `CatalystSignedDoc` doing all necessary
22+
/// stateless verifications,
23+
#[allow(dead_code)]
24+
pub(crate) fn from_signed_doc(
25+
doc: &CatalystSignedDocument, error_report: &ProblemReport,
26+
) -> anyhow::Result<Self> {
27+
/// Context for error messages.
28+
const CONTEXT: &str = "Catalyst Signed Document to Proposal Document";
29+
let mut failed = false;
30+
31+
if doc.doc_type().uuid() != PROPOSAL_DOCUMENT_UUID_TYPE {
32+
error_report.invalid_value(
33+
"`type`",
34+
&doc.doc_type().to_string(),
35+
&format!("Proposal Document type UUID value is {PROPOSAL_DOCUMENT_UUID_TYPE}"),
36+
CONTEXT,
37+
);
38+
failed = true;
39+
}
40+
41+
// TODO add other validation
42+
43+
if failed {
44+
anyhow::bail!("Failed to build `ProposalDocument` from `CatalystSignedDoc`");
45+
}
46+
47+
let content = doc.doc_content().decoded_bytes().to_vec();
48+
Ok(Self { content })
49+
}
50+
51+
/// A comprehensive validation of the `ProposalDocument` content.
52+
#[allow(clippy::unused_self)]
53+
pub(crate) fn validate_with_report<F>(&self, _doc_getter: F, _error_report: &ProblemReport)
54+
where F: FnMut() -> Option<CatalystSignedDocument> {
55+
// TODO: implement the rest of the validation
56+
}
57+
}
58+
59+
impl TryFrom<CatalystSignedDocument> for ProposalDocument {
60+
type Error = CatalystSignedDocError;
61+
62+
fn try_from(doc: CatalystSignedDocument) -> Result<Self, Self::Error> {
63+
let error_report = ProblemReport::new("Proposal Document");
64+
let res = Self::from_signed_doc(&doc, &error_report)
65+
.map_err(|e| CatalystSignedDocError::new(error_report, e))?;
66+
Ok(res)
67+
}
68+
}

rust/signed_doc/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
33
mod builder;
44
mod content;
5+
pub mod doc_types;
56
pub mod error;
67
mod metadata;
78
mod signature;
89
mod utils;
10+
pub mod validator;
911

1012
use std::{
1113
convert::TryFrom,
@@ -15,11 +17,12 @@ use std::{
1517

1618
pub use builder::Builder;
1719
use catalyst_types::problem_report::ProblemReport;
20+
pub use catalyst_types::uuid::{UuidV4, UuidV7};
1821
pub use content::Content;
1922
use coset::{CborSerializable, Header};
2023
use ed25519_dalek::VerifyingKey;
2124
use error::CatalystSignedDocError;
22-
pub use metadata::{DocumentRef, ExtraFields, Metadata, UuidV4, UuidV7};
25+
pub use metadata::{DocumentRef, ExtraFields, Metadata};
2326
pub use minicbor::{decode, encode, Decode, Decoder, Encode};
2427
pub use signature::{KidUri, Signatures};
2528
use utils::context::DecodeSignDocCtx;

rust/signed_doc/src/metadata/document_id.rs

Lines changed: 0 additions & 45 deletions
This file was deleted.

rust/signed_doc/src/metadata/document_ref.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@ pub struct DocumentRef {
1313
pub ver: Option<UuidV7>,
1414
}
1515

16+
impl DocumentRef {
17+
/// Determine if internal `UUID`s are valid.
18+
#[must_use]
19+
pub fn is_valid(&self) -> bool {
20+
match self.ver {
21+
Some(ver) => self.id.is_valid() && ver.is_valid() && ver >= self.id,
22+
None => self.id.is_valid(),
23+
}
24+
}
25+
}
26+
1627
impl TryFrom<DocumentRef> for Value {
1728
type Error = anyhow::Error;
1829

rust/signed_doc/src/metadata/document_type.rs

Lines changed: 0 additions & 45 deletions
This file was deleted.

rust/signed_doc/src/metadata/document_version.rs

Lines changed: 0 additions & 44 deletions
This file was deleted.

0 commit comments

Comments
 (0)