Skip to content

Commit ed66c38

Browse files
authored
Merge branch 'feat/new-cat-signed-doc' into feat/cbor-data-with-original-raw
2 parents 1982227 + 54294ce commit ed66c38

File tree

2 files changed

+215
-11
lines changed

2 files changed

+215
-11
lines changed

rust/cardano-blockchain-types/src/multi_era_block_data.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ impl MultiEraBlock {
163163
/// The decoded block data, which can easily be processed by a consumer.
164164
#[must_use]
165165
#[allow(clippy::missing_panics_doc)]
166-
pub fn decode(&self) -> &pallas::ledger::traverse::MultiEraBlock {
166+
pub fn decode(&self) -> &pallas::ledger::traverse::MultiEraBlock<'_> {
167167
self.inner.data.borrow_block()
168168
}
169169

@@ -275,12 +275,12 @@ impl MultiEraBlock {
275275

276276
/// Returns a list of transactions withing this block.
277277
#[must_use]
278-
pub fn txs(&self) -> Vec<MultiEraTx> {
278+
pub fn txs(&self) -> Vec<MultiEraTx<'_>> {
279279
self.decode().txs()
280280
}
281281

282282
/// Returns an iterator over `(TxnIndex, MultiEraTx)` pair.
283-
pub fn enumerate_txs(&self) -> impl Iterator<Item = (TxnIndex, MultiEraTx)> {
283+
pub fn enumerate_txs(&self) -> impl Iterator<Item = (TxnIndex, MultiEraTx<'_>)> {
284284
self.txs()
285285
.into_iter()
286286
.enumerate()

rust/signed_doc/tests/decoding.rs

Lines changed: 212 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ use catalyst_signed_doc::*;
44
use catalyst_types::catalyst_id::role_index::RoleId;
55
use common::create_dummy_key_pair;
66
use minicbor::{data::Tag, Encoder};
7+
use rand::Rng;
78

89
mod common;
910

1011
type PostCheck = dyn Fn(&CatalystSignedDocument) -> anyhow::Result<()>;
1112

1213
struct TestCase {
13-
name: &'static str,
14+
name: String,
1415
bytes_gen: Box<dyn Fn() -> anyhow::Result<Encoder<Vec<u8>>>>,
1516
// If the provided bytes can be even decoded without error (valid COSE or not).
1617
// If set to `false` all further checks will not even happen.
@@ -27,8 +28,7 @@ fn signed_doc_with_valid_alias_case(alias: &'static str) -> TestCase {
2728
let doc_ref_cloned = doc_ref.clone();
2829

2930
TestCase {
30-
name:
31-
"Provided category_id, brand_id, campaign_id field should be processed as parameters.",
31+
name: format!("Provided '{alias}' field should be processed as parameters."),
3232
bytes_gen: Box::new({
3333
move || {
3434
let mut e = Encoder::new(Vec::new());
@@ -78,14 +78,201 @@ fn signed_doc_with_valid_alias_case(alias: &'static str) -> TestCase {
7878
}
7979
}
8080

81+
fn signed_doc_with_missing_header_field_case(field: &'static str) -> TestCase {
82+
let uuid_v7 = UuidV7::new();
83+
let uuid_v4 = UuidV4::new();
84+
let doc_ref = DocumentRef::new(UuidV7::new(), UuidV7::new(), DocLocator::default());
85+
86+
TestCase {
87+
name: format!("Catalyst Signed Doc with missing '{field}' header."),
88+
bytes_gen: Box::new({
89+
move || {
90+
let mut e = Encoder::new(Vec::new());
91+
e.tag(Tag::new(98))?;
92+
e.array(4)?;
93+
94+
// protected headers (metadata fields)
95+
e.bytes({
96+
let mut p_headers = Encoder::new(Vec::new());
97+
p_headers.map(4)?;
98+
if field != "content-type" {
99+
p_headers.u8(3)?.encode(ContentType::Json)?;
100+
}
101+
if field != "type" {
102+
p_headers
103+
.str("type")?
104+
.encode_with(uuid_v4, &mut catalyst_types::uuid::CborContext::Tagged)?;
105+
}
106+
if field != "id" {
107+
p_headers
108+
.str("id")?
109+
.encode_with(uuid_v7, &mut catalyst_types::uuid::CborContext::Tagged)?;
110+
}
111+
if field != "ver" {
112+
p_headers
113+
.str("ver")?
114+
.encode_with(uuid_v7, &mut catalyst_types::uuid::CborContext::Tagged)?;
115+
}
116+
117+
p_headers
118+
.str("parameters")?
119+
.encode_with(doc_ref.clone(), &mut ())?;
120+
121+
p_headers.into_writer().as_slice()
122+
})?;
123+
124+
// empty unprotected headers
125+
e.map(0)?;
126+
// content
127+
e.bytes(serde_json::to_vec(&serde_json::Value::Null)?.as_slice())?;
128+
// zero signatures
129+
e.array(0)?;
130+
131+
Ok(e)
132+
}
133+
}),
134+
can_decode: true,
135+
valid_doc: false,
136+
post_checks: Some(Box::new({
137+
move |doc| {
138+
if field == "content-type" {
139+
anyhow::ensure!(doc.doc_meta().content_type().is_err());
140+
}
141+
if field == "type" {
142+
anyhow::ensure!(doc.doc_meta().doc_type().is_err());
143+
}
144+
if field == "id" {
145+
anyhow::ensure!(doc.doc_meta().doc_id().is_err());
146+
}
147+
if field == "ver" {
148+
anyhow::ensure!(doc.doc_meta().doc_ver().is_err());
149+
}
150+
151+
Ok(())
152+
}
153+
})),
154+
}
155+
}
156+
157+
fn signed_doc_with_random_header_field_case(field: &'static str) -> TestCase {
158+
let uuid_v7 = UuidV7::new();
159+
let uuid_v4 = UuidV4::new();
160+
let doc_ref = DocumentRef::new(UuidV7::new(), UuidV7::new(), DocLocator::default());
161+
162+
TestCase {
163+
name: format!("Catalyst Signed Doc with random bytes in '{field}' header field."),
164+
bytes_gen: Box::new({
165+
move || {
166+
let mut e = Encoder::new(Vec::new());
167+
e.tag(Tag::new(98))?;
168+
e.array(4)?;
169+
170+
// protected headers (metadata fields)
171+
e.bytes({
172+
let mut rng = rand::thread_rng();
173+
let mut rand_buf = [0u8; 128];
174+
rng.try_fill(&mut rand_buf)?;
175+
176+
let is_required_header = ["type", "id", "ver", "parameters"]
177+
.iter()
178+
.any(|v| v == &field);
179+
180+
let mut p_headers = Encoder::new(Vec::new());
181+
p_headers.map(if is_required_header { 5 } else { 6 })?;
182+
if field == "content-type" {
183+
p_headers.u8(3)?.encode_with(rand_buf, &mut ())?;
184+
} else {
185+
p_headers.u8(3)?.encode(ContentType::Json)?;
186+
}
187+
if field == "type" {
188+
p_headers.str("type")?.encode_with(rand_buf, &mut ())?;
189+
} else {
190+
p_headers
191+
.str("type")?
192+
.encode_with(uuid_v4, &mut catalyst_types::uuid::CborContext::Tagged)?;
193+
}
194+
if field == "id" {
195+
p_headers.str("id")?.encode_with(rand_buf, &mut ())?;
196+
} else {
197+
p_headers
198+
.str("id")?
199+
.encode_with(uuid_v7, &mut catalyst_types::uuid::CborContext::Tagged)?;
200+
}
201+
if field == "ver" {
202+
p_headers.str("ver")?.encode_with(rand_buf, &mut ())?;
203+
} else {
204+
p_headers
205+
.str("ver")?
206+
.encode_with(uuid_v7, &mut catalyst_types::uuid::CborContext::Tagged)?;
207+
}
208+
if field == "parameters" {
209+
p_headers
210+
.str("parameters")?
211+
.encode_with(rand_buf, &mut ())?;
212+
} else {
213+
p_headers
214+
.str("parameters")?
215+
.encode_with(doc_ref.clone(), &mut ())?;
216+
}
217+
218+
if !is_required_header {
219+
p_headers.str(field)?.encode_with(rand_buf, &mut ())?;
220+
}
221+
222+
p_headers.into_writer().as_slice()
223+
})?;
224+
225+
// empty unprotected headers
226+
e.map(0)?;
227+
// content
228+
e.bytes(serde_json::to_vec(&serde_json::Value::Null)?.as_slice())?;
229+
// zero signatures
230+
e.array(0)?;
231+
232+
Ok(e)
233+
}
234+
}),
235+
can_decode: true,
236+
valid_doc: false,
237+
post_checks: Some(Box::new({
238+
move |doc| {
239+
anyhow::ensure!(doc.doc_meta().content_encoding().is_none());
240+
anyhow::ensure!(doc.doc_meta().doc_ref().is_none());
241+
anyhow::ensure!(doc.doc_meta().template().is_none());
242+
anyhow::ensure!(doc.doc_meta().reply().is_none());
243+
anyhow::ensure!(doc.doc_meta().section().is_none());
244+
anyhow::ensure!(doc.doc_meta().collabs().is_empty());
245+
246+
if field == "content-type" {
247+
anyhow::ensure!(doc.doc_meta().content_type().is_err());
248+
}
249+
if field == "type" {
250+
anyhow::ensure!(doc.doc_meta().doc_type().is_err());
251+
}
252+
if field == "id" {
253+
anyhow::ensure!(doc.doc_meta().doc_id().is_err());
254+
}
255+
if field == "ver" {
256+
anyhow::ensure!(doc.doc_meta().doc_ver().is_err());
257+
}
258+
if field == "parameters" {
259+
anyhow::ensure!(doc.doc_meta().parameters().is_none());
260+
}
261+
262+
Ok(())
263+
}
264+
})),
265+
}
266+
}
267+
81268
// `parameters` value along with its aliases are not allowed to be presented
82269
fn signed_doc_with_parameters_and_aliases_case(aliases: &'static [&'static str]) -> TestCase {
83270
let uuid_v7 = UuidV7::new();
84271
let uuid_v4 = UuidV4::new();
85272
let doc_ref = DocumentRef::new(UuidV7::new(), UuidV7::new(), DocLocator::default());
86273

87274
TestCase {
88-
name: "Multiple definitions of campaign_id, brand_id, category_id and parameters at once.",
275+
name: format!("Multiple definitions of '{}' at once.", aliases.join(", ")),
89276
bytes_gen: Box::new({
90277
move || {
91278
let mut e = Encoder::new(Vec::new());
@@ -134,7 +321,7 @@ fn signed_doc_with_parameters_and_aliases_case(aliases: &'static [&'static str])
134321

135322
fn decoding_empty_bytes_case() -> TestCase {
136323
TestCase {
137-
name: "Decoding empty bytes",
324+
name: "Decoding empty bytes".to_string(),
138325
bytes_gen: Box::new(|| Ok(Encoder::new(Vec::new()))),
139326
can_decode: false,
140327
valid_doc: false,
@@ -147,7 +334,7 @@ fn signed_doc_with_all_fields_case() -> TestCase {
147334
let uuid_v4 = UuidV4::new();
148335

149336
TestCase {
150-
name: "Catalyst Signed Doc with minimally defined metadata fields, signed (one signature), CBOR tagged.",
337+
name: "Catalyst Signed Doc with minimally defined metadata fields, signed (one signature), CBOR tagged.".to_string(),
151338
bytes_gen: Box::new({
152339
move || {
153340
let (_, _, kid) = create_dummy_key_pair(RoleId::Role0)?;
@@ -203,7 +390,8 @@ fn minimally_valid_tagged_signed_doc() -> TestCase {
203390
let uuid_v7 = UuidV7::new();
204391
let uuid_v4 = UuidV4::new();
205392
TestCase {
206-
name: "Catalyst Signed Doc with minimally defined metadata fields, unsigned, CBOR tagged.",
393+
name: "Catalyst Signed Doc with minimally defined metadata fields, unsigned, CBOR tagged."
394+
.to_string(),
207395
bytes_gen: Box::new({
208396
move || {
209397
let mut e = Encoder::new(Vec::new());
@@ -260,7 +448,8 @@ fn minimally_valid_untagged_signed_doc() -> TestCase {
260448
let uuid_v7 = UuidV7::new();
261449
let uuid_v4 = UuidV4::new();
262450
TestCase {
263-
name: "Catalyst Signed Doc with minimally defined metadata fields, unsigned, CBOR tagged.",
451+
name: "Catalyst Signed Doc with minimally defined metadata fields, unsigned, CBOR tagged."
452+
.to_string(),
264453
bytes_gen: Box::new({
265454
move || {
266455
let mut e = Encoder::new(Vec::new());
@@ -319,6 +508,21 @@ fn catalyst_signed_doc_decoding_test() {
319508
signed_doc_with_valid_alias_case("category_id"),
320509
signed_doc_with_valid_alias_case("brand_id"),
321510
signed_doc_with_valid_alias_case("campaign_id"),
511+
signed_doc_with_missing_header_field_case("content-type"),
512+
signed_doc_with_missing_header_field_case("type"),
513+
signed_doc_with_missing_header_field_case("id"),
514+
signed_doc_with_missing_header_field_case("ver"),
515+
signed_doc_with_random_header_field_case("content-type"),
516+
signed_doc_with_random_header_field_case("type"),
517+
signed_doc_with_random_header_field_case("id"),
518+
signed_doc_with_random_header_field_case("ver"),
519+
signed_doc_with_random_header_field_case("ref"),
520+
signed_doc_with_random_header_field_case("template"),
521+
signed_doc_with_random_header_field_case("reply"),
522+
signed_doc_with_random_header_field_case("section"),
523+
signed_doc_with_random_header_field_case("collabs"),
524+
signed_doc_with_random_header_field_case("parameters"),
525+
signed_doc_with_random_header_field_case("content-encoding"),
322526
signed_doc_with_parameters_and_aliases_case(&["parameters", "category_id"]),
323527
signed_doc_with_parameters_and_aliases_case(&["parameters", "brand_id"]),
324528
signed_doc_with_parameters_and_aliases_case(&["parameters", "campaign_id"]),

0 commit comments

Comments
 (0)