From c843f07d75010508e41b1d26fd8e3df7652b6d89 Mon Sep 17 00:00:00 2001 From: Chris Joel Date: Tue, 25 Jan 2022 23:12:52 -0800 Subject: [PATCH 1/4] Strict ordering for DAG-CBOR-encoded map keys --- src/dag.rs | 22 +++++++++++++++++++++- src/ipld/dag_cbor.rs | 18 +++++++++++++++++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/dag.rs b/src/dag.rs index 3095c9878..21e111390 100644 --- a/src/dag.rs +++ b/src/dag.rs @@ -598,7 +598,7 @@ fn resolve_local_ipld<'a>( #[cfg(test)] mod tests { use super::*; - use crate::{make_ipld, Node}; + use crate::{ipld::dag_cbor::DagCborCodec, make_ipld, Node}; #[tokio::test] async fn test_resolve_root_cid() { @@ -996,4 +996,24 @@ mod tests { format!("no link named \"second-best-file\" under {}", cids[1]) ); } + + #[test] + fn observes_strict_order_of_map_keys() { + let map = make_ipld!({ + "omega": Ipld::Null, + "bar": Ipld::Null, + "alpha": Ipld::Null, + "foo": Ipld::Null, + }); + + let bytes = DagCborCodec::encode(&map).unwrap(); + + assert_eq!( + bytes.as_ref(), + &[ + 164, 99, 98, 97, 114, 246, 99, 102, 111, 111, 246, 101, 97, 108, 112, 104, 97, 246, + 101, 111, 109, 101, 103, 97, 246 + ] + ); + } } diff --git a/src/ipld/dag_cbor.rs b/src/ipld/dag_cbor.rs index 193457780..1e028f3a3 100644 --- a/src/ipld/dag_cbor.rs +++ b/src/ipld/dag_cbor.rs @@ -4,6 +4,7 @@ use crate::ipld::{BlockError, Ipld, IpldError}; use byteorder::{BigEndian, ByteOrder}; use cid::Cid; use std::{ + cmp::Ordering, collections::BTreeMap, convert::TryFrom, io::{Read, Write}, @@ -321,10 +322,25 @@ impl WriteCbor for BTreeMap { #[inline] fn write_cbor(&self, w: &mut W) -> CborResult<()> { write_u64(w, 5, self.len() as u64)?; - for (k, v) in self { + let mut keys: Vec<&String> = self.keys().collect(); + + // See: https://github.com/ipld/ipld/blob/master/specs/codecs/dag-cbor/spec.md#strictness + keys.sort_by(|l, r| { + if r.len() > l.len() { + Ordering::Less + } else if r.len() < l.len() { + Ordering::Greater + } else { + l.partial_cmp(r).or(Some(Ordering::Equal)).unwrap() + } + }); + + for k in keys { + let v = self.get(k).unwrap(); k.write_cbor(w)?; v.write_cbor(w)?; } + Ok(()) } } From 8e0d5d51924cece764e3f729c216afd7c1040084 Mon Sep 17 00:00:00 2001 From: Chris Joel Date: Tue, 25 Jan 2022 23:19:27 -0800 Subject: [PATCH 2/4] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index be9fc8f9f..175c37914 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ * perf: use hash_hasher where the key is Cid [#467] * chore: upgrade to libp2p 0.39.1, update most of the other deps with the notable exception of cid and multihash [#472] * refactor(swarm): swarm cleanup following libp2p upgrade to v0.39.1 [#473] +* fix: strict ordering for DAG-CBOR-encoded map keys [#493] [#429]: https://github.com/rs-ipfs/rust-ipfs/pull/429 [#428]: https://github.com/rs-ipfs/rust-ipfs/pull/428 @@ -27,6 +28,7 @@ [#467]: https://github.com/rs-ipfs/rust-ipfs/pull/467 [#472]: https://github.com/rs-ipfs/rust-ipfs/pull/472 [#473]: https://github.com/rs-ipfs/rust-ipfs/pull/473 +[#493]: https://github.com/rs-ipfs/rust-ipfs/pull/493 # 0.2.1 From 888776f2793f8872fcc89f00510d7fe8ed6bd128 Mon Sep 17 00:00:00 2001 From: Christopher Joel <240083+cdata@users.noreply.github.com> Date: Mon, 31 Jan 2022 14:50:27 -0800 Subject: [PATCH 3/4] Update src/ipld/dag_cbor.rs Co-authored-by: Joonas Koivunen --- src/ipld/dag_cbor.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/ipld/dag_cbor.rs b/src/ipld/dag_cbor.rs index 1e028f3a3..1cf30ecb8 100644 --- a/src/ipld/dag_cbor.rs +++ b/src/ipld/dag_cbor.rs @@ -325,15 +325,7 @@ impl WriteCbor for BTreeMap { let mut keys: Vec<&String> = self.keys().collect(); // See: https://github.com/ipld/ipld/blob/master/specs/codecs/dag-cbor/spec.md#strictness - keys.sort_by(|l, r| { - if r.len() > l.len() { - Ordering::Less - } else if r.len() < l.len() { - Ordering::Greater - } else { - l.partial_cmp(r).or(Some(Ordering::Equal)).unwrap() - } - }); + keys.sort_by(|l, r| l.len().cmp(&r.len()).then_with(|| l.cmp(r))); for k in keys { let v = self.get(k).unwrap(); From 80d2b79cb73a067981881dbdc04e4cf4fd0c8e00 Mon Sep 17 00:00:00 2001 From: Christopher Joel <240083+cdata@users.noreply.github.com> Date: Mon, 31 Jan 2022 14:50:42 -0800 Subject: [PATCH 4/4] Update src/ipld/dag_cbor.rs Co-authored-by: Joonas Koivunen --- src/ipld/dag_cbor.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ipld/dag_cbor.rs b/src/ipld/dag_cbor.rs index 1cf30ecb8..6b98aaeb7 100644 --- a/src/ipld/dag_cbor.rs +++ b/src/ipld/dag_cbor.rs @@ -4,7 +4,6 @@ use crate::ipld::{BlockError, Ipld, IpldError}; use byteorder::{BigEndian, ByteOrder}; use cid::Cid; use std::{ - cmp::Ordering, collections::BTreeMap, convert::TryFrom, io::{Read, Write},