diff --git a/node/src/identity.rs b/node/src/identity.rs index ff77c961..521a6962 100644 --- a/node/src/identity.rs +++ b/node/src/identity.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; use thiserror::Error; use crate::crypto::{self, Verified}; -use crate::hash; +use crate::git; use crate::serde_ext; use crate::storage::Remotes; @@ -17,14 +17,14 @@ pub use doc::{Delegate, Doc}; #[derive(Error, Debug)] pub enum IdError { - #[error("invalid digest: {0}")] - InvalidDigest(#[from] hash::DecodeError), + #[error("invalid git object id: {0}")] + InvalidOid(#[from] git2::Error), #[error(transparent)] Multibase(#[from] multibase::Error), } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Id(hash::Digest); +pub struct Id(git::Oid); impl fmt::Display for Id { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -40,12 +40,12 @@ impl fmt::Debug for Id { impl Id { pub fn to_human(&self) -> String { - multibase::encode(multibase::Base::Base58Btc, &self.0.as_ref()) + multibase::encode(multibase::Base::Base58Btc, self.0.as_bytes()) } pub fn from_human(s: &str) -> Result { let (_, bytes) = multibase::decode(s)?; - let array: hash::Digest = bytes.as_slice().try_into()?; + let array: git::Oid = bytes.as_slice().try_into()?; Ok(Self(array)) } @@ -68,14 +68,20 @@ impl TryFrom for Id { } } -impl From for Id { - fn from(digest: hash::Digest) -> Self { - Self(digest) +impl From for Id { + fn from(oid: git::Oid) -> Self { + Self(oid) + } +} + +impl From for Id { + fn from(oid: git2::Oid) -> Self { + Self(oid.into()) } } impl Deref for Id { - type Target = hash::Digest; + type Target = git::Oid; fn deref(&self) -> &Self::Target { &self.0 diff --git a/node/src/identity/doc.rs b/node/src/identity/doc.rs index 1fc7cb91..443436f4 100644 --- a/node/src/identity/doc.rs +++ b/node/src/identity/doc.rs @@ -12,7 +12,6 @@ use thiserror::Error; use crate::crypto; use crate::crypto::{Signature, Unverified, Verified}; use crate::git; -use crate::hash; use crate::identity::{Did, Id}; use crate::storage::git::trailers; use crate::storage::{BranchName, ReadRepository, RemoteId}; @@ -79,22 +78,17 @@ pub struct Doc { } impl Doc { - pub fn write(&self, mut writer: W) -> Result { + pub fn encode(&self) -> Result<(Id, Vec), Error> { let mut buf = Vec::new(); - let mut ser = + let mut serializer = serde_json::Serializer::with_formatter(&mut buf, olpc_cjson::CanonicalFormatter::new()); - self.serialize(&mut ser)?; + self.serialize(&mut serializer)?; - let digest = hash::Digest::new(&buf); - let id = Id::from(digest); + let oid = git2::Oid::hash_object(git2::ObjectType::Blob, &buf)?; + let id = Id::from(oid); - // TODO: Currently, we serialize the document in canonical JSON. This isn't strictly - // necessary, as we could use CJSON just to get the hash, but then write a prettified - // version to disk to make it easier for users to edit. - writer.write_all(&buf)?; - - Ok(id) + Ok((id, buf)) } } @@ -367,9 +361,7 @@ mod test { #[quickcheck] fn prop_encode_decode(doc: Doc) { - let mut bytes = Vec::new(); - - doc.write(&mut bytes).unwrap(); + let (_, bytes) = doc.encode().unwrap(); assert_eq!(Doc::from_json(&bytes).unwrap().verified().unwrap(), doc); } } diff --git a/node/src/rad.rs b/node/src/rad.rs index d034e5e3..3ec53968 100644 --- a/node/src/rad.rs +++ b/node/src/rad.rs @@ -47,17 +47,15 @@ pub fn init<'r, G: Signer, S: storage::WriteStorage<'r>>( name: String::from("anonymous"), id: identity::Did::from(*pk), }; - let doc = identity::Doc::initial( + let (id, doc) = identity::Doc::initial( name.to_owned(), description.to_owned(), default_branch.clone(), delegate, ) - .verified()?; + .verified()? + .encode()?; - let filename = *identity::doc::PATH; - let mut doc_bytes = Vec::new(); - let id = doc.write(&mut doc_bytes)?; let project = storage.repository(&id)?; { @@ -70,11 +68,14 @@ pub fn init<'r, G: Signer, S: storage::WriteStorage<'r>>( // git fetch rad // git checkout -b radicle/id remotes/rad/radicle/id // + let filename = *identity::doc::PATH; let repo = project.raw(); let tree = { - let id_blob = repo.blob(&doc_bytes)?; + let doc_blob = repo.blob(&doc)?; let mut builder = repo.treebuilder(None)?; - builder.insert(filename, id_blob, 0o100_644)?; + builder.insert(filename, doc_blob, 0o100_644)?; + + assert_eq!(git::Oid::from(doc_blob), *id); let tree_id = builder.write()?; repo.find_tree(tree_id) diff --git a/node/src/test/arbitrary.rs b/node/src/test/arbitrary.rs index e1fcca03..efea335c 100644 --- a/node/src/test/arbitrary.rs +++ b/node/src/test/arbitrary.rs @@ -52,6 +52,10 @@ impl ByteArray { pub fn into_inner(self) -> [u8; N] { self.0 } + + pub fn as_slice(&self) -> &[u8] { + self.0.as_slice() + } } impl Arbitrary for ByteArray { @@ -174,9 +178,8 @@ impl Arbitrary for MockStorage { impl Arbitrary for Project { fn arbitrary(g: &mut quickcheck::Gen) -> Self { - let mut buf = Vec::new(); let doc = Doc::::arbitrary(g); - let id = doc.write(&mut buf).unwrap(); + let (id, _) = doc.encode().unwrap(); let remotes = storage::Remotes::arbitrary(g); let path = PathBuf::arbitrary(g); @@ -311,8 +314,10 @@ impl Arbitrary for MockSigner { impl Arbitrary for Id { fn arbitrary(g: &mut quickcheck::Gen) -> Self { - let digest = hash::Digest::arbitrary(g); - Id::from(digest) + let bytes = ByteArray::<20>::arbitrary(g); + let oid = git::Oid::try_from(bytes.as_slice()).unwrap(); + + Id::from(oid) } } diff --git a/node/src/wire.rs b/node/src/wire.rs index 90e2ff0f..8a307c79 100644 --- a/node/src/wire.rs +++ b/node/src/wire.rs @@ -375,9 +375,9 @@ impl Decode for git::Url { impl Decode for Id { fn decode(reader: &mut R) -> Result { - let digest: Digest = Decode::decode(reader)?; + let oid: git::Oid = Decode::decode(reader)?; - Ok(Self::from(digest)) + Ok(Self::from(oid)) } }