Skip to content
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
4e5ff19
fix(rust/signed-doc): add content type validation
saibatizoku Jan 27, 2025
15741c6
fix(rust/signed-doc): content encoding field is optional
saibatizoku Jan 27, 2025
3d34e47
fix(rust/signed-doc): add 'half' feature from minicbor crate
saibatizoku Jan 27, 2025
3a66559
wip(rust/signed_doc): implement verification method
saibatizoku Jan 28, 2025
70440b5
fix(rust/signed-doc): fix content-type verification
saibatizoku Jan 28, 2025
bd4561d
wip(rust/signed_doc): implement verification method
saibatizoku Jan 28, 2025
2392ed5
wip(rust/signed_doc): implement verification method
saibatizoku Jan 28, 2025
dd60045
Merge branch 'main' into feat/doc-signing-logic
saibatizoku Jan 28, 2025
22c46f0
feat(rust/signed-doc): add signatures to Catalyst Signed Document
saibatizoku Jan 28, 2025
0f85057
fix(rust/signed-doc): refactor cli tool to sign
saibatizoku Jan 29, 2025
ee0657c
fix(rust/signed-doc): add verify command to cli tool
saibatizoku Jan 29, 2025
262b1ad
fix(rust/catalyst-types): refactor sigining logic into builder
saibatizoku Jan 29, 2025
a1c11ea
Merge branch 'main' into feat/doc-signing-logic
saibatizoku Jan 29, 2025
56b0509
chore(docs): fix spelling
saibatizoku Jan 29, 2025
70cae9f
fix(rust/signed-doc): cleanup
saibatizoku Jan 31, 2025
0329541
fix content validation, add unit test
Mr-Leshiy Feb 2, 2025
3d1b044
remove clippy
Mr-Leshiy Feb 2, 2025
5b20cfd
remove redundant types
Mr-Leshiy Feb 2, 2025
5682dd5
fix
Mr-Leshiy Feb 2, 2025
d48d27b
Merge branch 'feat/doc-signing-logic' into feat/cat-sign-doc-validator
Mr-Leshiy Feb 2, 2025
84b891e
add DocumentType
Mr-Leshiy Feb 2, 2025
e199d8e
wip
Mr-Leshiy Feb 2, 2025
53deef7
add validator module
Mr-Leshiy Feb 2, 2025
830e4ef
add Proposal Document type
Mr-Leshiy Feb 2, 2025
1f02d57
wip
Mr-Leshiy Feb 2, 2025
9c40793
wip
Mr-Leshiy Feb 2, 2025
c303489
Merge branch 'main' into feat/cat-sign-doc-validator
Mr-Leshiy Feb 3, 2025
ebaa2f1
fix spelling
Mr-Leshiy Feb 3, 2025
367dab1
fix(rust/signed-doc): refactor doc type constant for proposals
saibatizoku Feb 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions rust/signed_doc/src/doc_types/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
//! An implementation of different defined document types
//! <https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/types/>

mod proposal_document;

use catalyst_types::uuid::UuidV4;
pub use proposal_document::ProposalDocument;

/// Represents different types of documents.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DocumentType {
/// A proposal document containing proposal details.
ProposalDocument,
/// A template for proposal documents, defining the expected structure.
ProposalTemplate,
/// A document representing a comment on a proposal.
CommentDocument,
/// A template for comment documents, defining the expected structure.
CommentTemplate,
/// A review document containing feedback on a proposal.
ReviewDocument,
/// A template for review documents, defining the expected structure.
ReviewTemplate,
/// A document defining parameters for a specific category.
CategoryParametersDocument,
/// A template for category parameter documents, defining the expected structure.
CategoryParametersTemplate,
/// A document containing parameters for a specific campaign.
CampaignParametersDocument,
/// A template for campaign parameter documents, defining the expected structure.
CampaignParametersTemplate,
/// A document containing brand-related parameters.
BrandParametersDocument,
/// A template for brand parameter documents, defining the expected structure.
BrandParametersTemplate,
/// A document representing an action related to a proposal.
ProposalActionDocument,
/// A public voting transaction version 2.
PublicVoteTxV2,
/// A private voting transaction version 2.
PrivateVoteTxV2,
/// A block in the immutable ledger.
ImmutableLedgerBlock,
}

/// Proposal document `UuidV4` type.
const PROPOSAL_DOCUMENT_UUID_TYPE: uuid::Uuid =
uuid::Uuid::from_u128(0x7808_D2BA_D511_40AF_84E8_C0D1_625F_DFDC);
/// Proposal template `UuidV4` type.
const PROPOSAL_TEMPLATE_UUID_TYPE: uuid::Uuid =
uuid::Uuid::from_u128(0x0CE8_AB38_9258_4FBC_A62E_7FAA_6E58_318F);
/// Comment document `UuidV4` type.
const COMMENT_DOCUMENT_UUID_TYPE: uuid::Uuid =
uuid::Uuid::from_u128(0xB679_DED3_0E7C_41BA_89F8_DA62_A178_98EA);
/// Comment template `UuidV4` type.
const COMMENT_TEMPLATE_UUID_TYPE: uuid::Uuid =
uuid::Uuid::from_u128(0x0B84_24D4_EBFD_46E3_9577_1775_A69D_290C);
/// Review document `UuidV4` type.
const REVIEW_DOCUMENT_UUID_TYPE: uuid::Uuid =
uuid::Uuid::from_u128(0xE4CA_F5F0_098B_45FD_94F3_0702_A457_3DB5);
/// Review template `UuidV4` type.
const REVIEW_TEMPLATE_UUID_TYPE: uuid::Uuid =
uuid::Uuid::from_u128(0xEBE5_D0BF_5D86_4577_AF4D_008F_DDBE_2EDC);
/// Category parameters document `UuidV4` type.
const CATEGORY_PARAMETERS_DOCUMENT_UUID_TYPE: uuid::Uuid =
uuid::Uuid::from_u128(0x48C2_0109_362A_4D32_9BBA_E0A9_CF8B_45BE);
/// Category parameters template `UuidV4` type.
const CATEGORY_PARAMETERS_TEMPLATE_UUID_TYPE: uuid::Uuid =
uuid::Uuid::from_u128(0x65B1_E8B0_51F1_46A5_9970_72CD_F268_84BE);
/// Campaign parameters document `UuidV4` type.
const CAMPAIGN_PARAMETERS_DOCUMENT_UUID_TYPE: uuid::Uuid =
uuid::Uuid::from_u128(0x0110_EA96_A555_47CE_8408_36EF_E6ED_6F7C);
/// Campaign parameters template `UuidV4` type.
const CAMPAIGN_PARAMETERS_TEMPLATE_UUID_TYPE: uuid::Uuid =
uuid::Uuid::from_u128(0x7E8F_5FA2_44CE_49C8_BFD5_02AF_42C1_79A3);
/// Brand parameters document `UuidV4` type.
const BRAND_PARAMETERS_DOCUMENT_UUID_TYPE: uuid::Uuid =
uuid::Uuid::from_u128(0x3E48_08CC_C86E_467B_9702_D60B_AA9D_1FCA);
/// Brand parameters template `UuidV4` type.
const BRAND_PARAMETERS_TEMPLATE_UUID_TYPE: uuid::Uuid =
uuid::Uuid::from_u128(0xFD3C_1735_80B1_4EEA_8D63_5F43_6D97_EA31);
/// Proposal action document `UuidV4` type.
const PROPOSAL_ACTION_DOCUMENT_UUID_TYPE: uuid::Uuid =
uuid::Uuid::from_u128(0x5E60_E623_AD02_4A1B_A1AC_406D_B978_EE48);
/// Public vote transaction v2 `UuidV4` type.
const PUBLIC_VOTE_TX_V2_UUID_TYPE: uuid::Uuid =
uuid::Uuid::from_u128(0x8DE5_586C_E998_4B95_8742_7BE3_C859_2803);
/// Private vote transaction v2 `UuidV4` type.
const PRIVATE_VOTE_TX_V2_UUID_TYPE: uuid::Uuid =
uuid::Uuid::from_u128(0xE78E_E18D_F380_44C1_A852_80AA_6ECB_07FE);
/// Immutable ledger block `UuidV4` type.
const IMMUTABLE_LEDGER_BLOCK_UUID_TYPE: uuid::Uuid =
uuid::Uuid::from_u128(0xD9E7_E6CE_2401_4D7D_9492_F4F7_C642_41C3);

impl TryFrom<UuidV4> for DocumentType {
type Error = anyhow::Error;

fn try_from(uuid: UuidV4) -> Result<Self, Self::Error> {
match uuid.uuid() {
PROPOSAL_DOCUMENT_UUID_TYPE => Ok(DocumentType::ProposalDocument),
PROPOSAL_TEMPLATE_UUID_TYPE => Ok(DocumentType::ProposalTemplate),
COMMENT_DOCUMENT_UUID_TYPE => Ok(DocumentType::CommentDocument),
COMMENT_TEMPLATE_UUID_TYPE => Ok(DocumentType::CommentTemplate),
REVIEW_DOCUMENT_UUID_TYPE => Ok(DocumentType::ReviewDocument),
REVIEW_TEMPLATE_UUID_TYPE => Ok(DocumentType::ReviewTemplate),
CATEGORY_PARAMETERS_DOCUMENT_UUID_TYPE => Ok(DocumentType::CategoryParametersDocument),
CATEGORY_PARAMETERS_TEMPLATE_UUID_TYPE => Ok(DocumentType::CategoryParametersTemplate),
CAMPAIGN_PARAMETERS_DOCUMENT_UUID_TYPE => Ok(DocumentType::CampaignParametersDocument),
CAMPAIGN_PARAMETERS_TEMPLATE_UUID_TYPE => Ok(DocumentType::CampaignParametersTemplate),
BRAND_PARAMETERS_DOCUMENT_UUID_TYPE => Ok(DocumentType::BrandParametersDocument),
BRAND_PARAMETERS_TEMPLATE_UUID_TYPE => Ok(DocumentType::BrandParametersTemplate),
PROPOSAL_ACTION_DOCUMENT_UUID_TYPE => Ok(DocumentType::ProposalActionDocument),
PUBLIC_VOTE_TX_V2_UUID_TYPE => Ok(DocumentType::PublicVoteTxV2),
PRIVATE_VOTE_TX_V2_UUID_TYPE => Ok(DocumentType::PrivateVoteTxV2),
IMMUTABLE_LEDGER_BLOCK_UUID_TYPE => Ok(DocumentType::ImmutableLedgerBlock),
_ => anyhow::bail!("Unsupported document type"),
}
}
}
68 changes: 68 additions & 0 deletions rust/signed_doc/src/doc_types/proposal_document.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//! Proposal Document object implementation
//! <https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/catalyst_docs/proposal/#proposal-document>

use catalyst_types::problem_report::ProblemReport;

use crate::{error::CatalystSignedDocError, CatalystSignedDocument};

/// Proposal document `UuidV4` type.
const PROPOSAL_DOCUMENT_UUID_TYPE: uuid::Uuid =
uuid::Uuid::from_u128(0x7808_D2BA_D511_40AF_84E8_C0D1_625F_DFDC);

/// Proposal Document struct
pub struct ProposalDocument {
/// Proposal document content data
/// TODO: change it to `serde_json::Value` type
#[allow(dead_code)]
content: Vec<u8>,
}

impl ProposalDocument {
/// Try to build `ProposalDocument` from `CatalystSignedDoc` doing all necessary
/// stateless verifications,
#[allow(dead_code)]
pub(crate) fn from_signed_doc(
doc: &CatalystSignedDocument, error_report: &ProblemReport,
) -> anyhow::Result<Self> {
/// Context for error messages.
const CONTEXT: &str = "Catalyst Signed Document to Proposal Document";
let mut failed = false;

if doc.doc_type().uuid() != PROPOSAL_DOCUMENT_UUID_TYPE {
error_report.invalid_value(
"`type`",
&doc.doc_type().to_string(),
&format!("Proposal Document type UUID value is {PROPOSAL_DOCUMENT_UUID_TYPE}"),
CONTEXT,
);
failed = true;
}

// TODO add other validation

if failed {
anyhow::bail!("Failed to build `ProposalDocument` from `CatalystSignedDoc`");
}

let content = doc.doc_content().decoded_bytes().to_vec();
Ok(Self { content })
}

/// A comprehensive validation of the `ProposalDocument` content.
#[allow(clippy::unused_self)]
pub(crate) fn validate_with_report<F>(&self, _doc_getter: F, _error_report: &ProblemReport)
where F: FnMut() -> Option<CatalystSignedDocument> {
// TODO: implement the rest of the validation
}
}

impl TryFrom<CatalystSignedDocument> for ProposalDocument {
type Error = CatalystSignedDocError;

fn try_from(doc: CatalystSignedDocument) -> Result<Self, Self::Error> {
let error_report = ProblemReport::new("Proposal Document");
let res = Self::from_signed_doc(&doc, &error_report)
.map_err(|e| CatalystSignedDocError::new(error_report, e))?;
Ok(res)
}
}
5 changes: 4 additions & 1 deletion rust/signed_doc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

mod builder;
mod content;
pub mod doc_types;
pub mod error;
mod metadata;
mod signature;
mod utils;
pub mod validator;

use std::{
convert::TryFrom,
Expand All @@ -15,11 +17,12 @@ use std::{

pub use builder::Builder;
use catalyst_types::problem_report::ProblemReport;
pub use catalyst_types::uuid::{UuidV4, UuidV7};
pub use content::Content;
use coset::{CborSerializable, Header};
use ed25519_dalek::VerifyingKey;
use error::CatalystSignedDocError;
pub use metadata::{DocumentRef, ExtraFields, Metadata, UuidV4, UuidV7};
pub use metadata::{DocumentRef, ExtraFields, Metadata};
pub use minicbor::{decode, encode, Decode, Decoder, Encode};
pub use signature::{KidUri, Signatures};
use utils::context::DecodeSignDocCtx;
Expand Down
45 changes: 0 additions & 45 deletions rust/signed_doc/src/metadata/document_id.rs

This file was deleted.

11 changes: 11 additions & 0 deletions rust/signed_doc/src/metadata/document_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@ pub struct DocumentRef {
pub ver: Option<UuidV7>,
}

impl DocumentRef {
/// Determine if internal `UUID`s are valid.
#[must_use]
pub fn is_valid(&self) -> bool {
match self.ver {
Some(ver) => self.id.is_valid() && ver.is_valid() && ver >= self.id,
None => self.id.is_valid(),
}
}
}

impl TryFrom<DocumentRef> for Value {
type Error = anyhow::Error;

Expand Down
45 changes: 0 additions & 45 deletions rust/signed_doc/src/metadata/document_type.rs

This file was deleted.

44 changes: 0 additions & 44 deletions rust/signed_doc/src/metadata/document_version.rs

This file was deleted.

Loading