• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

input-output-hk / catalyst-libs / 19403595944

16 Nov 2025 09:31AM UTC coverage: 68.206% (-0.09%) from 68.298%
19403595944

push

github

web-flow
feat(rust/signed-doc): CatalystSignedDocument has CIDv1 (#621)

* feat(rust/signed-doc): CatalystSignedDocument has CIDv1

* feat(rust/signed-doc): Cid newtype

* break(rust/signed-doc): DocLocator(Cid) must be valid

* Breaking change that removes compatibility with old versions

* fix(rust/signed-doc): fix unit tests to support DocLocator

* removes support for old version

* fix(rust/signed-doc): fix integration tests

* chore(rust/signed-doc): fmt fix

* chore(rust/signed-doc): fix spelling

* chore(rust/signed-doc): fix doc comment

* chore(rust/signed-doc): Add `doc_ref` method for `CatalystSignedDoc`. (#640)

* update API

* wip

* wip

* wip

* fix test

* wip

* wip

* fix fmt

* fix(rust/signed-doc): remove stale example

---------

Co-authored-by: JoaquĆ­n Rosales <joaquin.rosales@iohk.io>

---------

Co-authored-by: Alex Pozhylenkov <leshiy12345678@gmail.com>

525 of 561 new or added lines in 12 files covered. (93.58%)

10 existing lines in 5 files now uncovered.

13841 of 20293 relevant lines covered (68.21%)

2725.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

65.26
/rust/signed_doc/src/validator/rules/chain/mod.rs
1
//! `chain` rule type impl.
2

3
use catalyst_signed_doc_spec::{is_required::IsRequired, metadata::chain::Chain};
4

5
use crate::{CatalystSignedDocument, providers::CatalystSignedDocumentProvider};
6

7
#[cfg(test)]
8
mod tests;
9

10
/// `chain` field validation rule
11
#[derive(Debug)]
12
pub(crate) enum ChainRule {
13
    /// Is 'chain' specified
14
    Specified {
15
        /// optional flag for the `chain` field
16
        optional: bool,
17
    },
18
    /// 'chain' is not specified
19
    NotSpecified,
20
}
21

22
impl ChainRule {
23
    /// Generating `ChainRule` from specs
24
    pub(crate) fn new(spec: &Chain) -> Self {
1,425✔
25
        let optional = match spec.required {
1,425✔
26
            IsRequired::Yes => false,
×
27
            IsRequired::Optional => true,
×
28
            IsRequired::Excluded => {
29
                return Self::NotSpecified;
1,425✔
30
            },
31
        };
32

33
        Self::Specified { optional }
×
34
    }
1,425✔
35

36
    /// Field validation rule
37
    pub(crate) async fn check<Provider>(
82✔
38
        &self,
82✔
39
        doc: &CatalystSignedDocument,
82✔
40
        provider: &Provider,
82✔
41
    ) -> anyhow::Result<bool>
82✔
42
    where
82✔
43
        Provider: CatalystSignedDocumentProvider,
82✔
44
    {
82✔
45
        let chain = doc.doc_meta().chain();
82✔
46

47
        // TODO: the current implementation is only for the direct chained doc,
48
        // make it recursively checks the entire chain with the same `id` docs.
49

50
        if let Self::Specified { optional } = self {
82✔
51
            if chain.is_none() && !optional {
8✔
52
                doc.report()
1✔
53
                    .missing_field("chain", "Document must have 'chain' field");
1✔
54
                return Ok(false);
1✔
55
            }
7✔
56

57
            // perform integrity validation
58
            if let Some(doc_chain) = chain {
7✔
59
                if doc_chain.document_ref().is_none() && doc_chain.height() != 0 {
6✔
60
                    doc.report().functional_validation(
×
61
                        "The chain height must be zero when there is no chained doc",
×
62
                        "Chained Documents validation",
×
63
                    );
64
                    return Ok(false);
×
65
                }
6✔
66
                if doc_chain.height() == 0 && doc_chain.document_ref().is_some() {
6✔
67
                    doc.report().functional_validation(
×
68
                        "The next Chained Document must not exist while the height is zero",
×
69
                        "Chained Documents validation",
×
70
                    );
71
                    return Ok(false);
×
72
                }
6✔
73

74
                if let Some(chained_ref) = doc_chain.document_ref() {
6✔
75
                    let Some(chained_doc) = provider.try_get_doc(chained_ref).await? else {
6✔
76
                        doc.report().other(
×
77
                            &format!(
×
78
                                "Cannot find the Chained Document ({chained_ref}) from the provider"
×
79
                            ),
×
80
                            "Chained Documents validation",
×
81
                        );
82
                        return Ok(false);
×
83
                    };
84

85
                    // have the same id as the document being chained to.
86
                    if chained_doc.doc_id()? != doc.doc_id()? {
6✔
87
                        doc.report().functional_validation(
1✔
88
                            "Must have the same id as the document being chained to",
1✔
89
                            "Chained Documents validation",
1✔
90
                        );
91
                        return Ok(false);
1✔
92
                    }
5✔
93

94
                    // have a ver that is greater than the ver being chained to.
95
                    if chained_doc.doc_ver()? > doc.doc_ver()? {
5✔
96
                        doc.report().functional_validation(
1✔
97
                            "Must have a ver that is greater than the ver being chained to",
1✔
98
                            "Chained Documents validation",
1✔
99
                        );
100
                        return Ok(false);
1✔
101
                    }
4✔
102

103
                    // have the same type as the chained document.
104
                    if chained_doc.doc_type()? != doc.doc_type()? {
4✔
105
                        doc.report().functional_validation(
1✔
106
                            "Must have the same type as the chained document",
1✔
107
                            "Chained Documents validation",
1✔
108
                        );
109
                        return Ok(false);
1✔
110
                    }
3✔
111

112
                    if let Some(chained_height) =
3✔
113
                        chained_doc.doc_meta().chain().map(crate::Chain::height)
3✔
114
                    {
115
                        // chain doc must not be negative
116
                        if chained_height < 0 {
3✔
UNCOV
117
                            doc.report().functional_validation(
×
UNCOV
118
                                "The height of the document being chained to must be positive number",
×
UNCOV
119
                                "Chained Documents validation",
×
120
                            );
UNCOV
121
                            return Ok(false);
×
122
                        }
3✔
123

124
                        // have its absolute height exactly one more than the height of the
125
                        // document being chained to.
126
                        if !matches!(
1✔
127
                            i32::abs(doc_chain.height()).checked_sub(i32::abs(chained_height)),
3✔
128
                            Some(1)
129
                        ) {
130
                            doc.report().functional_validation(
1✔
131
                                "Must have its absolute height exactly one more than the height of the document being chained to",
1✔
132
                                "Chained Documents validation",
1✔
133
                            );
134
                            return Ok(false);
1✔
135
                        }
2✔
136
                    }
×
137
                }
×
138
            }
1✔
139
        }
74✔
140
        if let Self::NotSpecified = self
77✔
141
            && chain.is_some()
74✔
142
        {
143
            doc.report().unknown_field(
×
144
                "chain",
×
145
                &doc.doc_meta()
×
146
                    .chain()
×
147
                    .iter()
×
148
                    .map(ToString::to_string)
×
149
                    .reduce(|a, b| format!("{a}, {b}"))
×
150
                    .unwrap_or_default(),
×
151
                "Document does not expect to have 'chain' field",
×
152
            );
153
            return Ok(false);
×
154
        }
77✔
155

156
        Ok(true)
77✔
157
    }
82✔
158
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc