From 4c51ee2decdd709be9d38806e002d7f69bcd3ebd Mon Sep 17 00:00:00 2001 From: bryan newbold Date: Mon, 10 Apr 2023 00:19:13 -0700 Subject: repov2 commit node updates --- adenosine/src/mst.rs | 37 +++++---------- adenosine/src/repo.rs | 126 +++++++++++++++++--------------------------------- 2 files changed, 54 insertions(+), 109 deletions(-) diff --git a/adenosine/src/mst.rs b/adenosine/src/mst.rs index 7c9d4ee..ba86e4f 100644 --- a/adenosine/src/mst.rs +++ b/adenosine/src/mst.rs @@ -23,25 +23,20 @@ use std::collections::BTreeMap; use std::path::PathBuf; #[derive(Debug, DagCbor, PartialEq, Eq)] -pub struct CommitNode { - pub root: Cid, - pub sig: Box<[u8]>, -} - -#[derive(Debug, DagCbor, PartialEq, Eq)] -pub struct RootNode { - pub auth_token: Option, +pub struct SignedCommitNode { + pub did: String, + pub version: u8, pub prev: Option, - // TODO: not 'metadata'? - pub meta: Cid, pub data: Cid, + pub sig: Box<[u8]>, } #[derive(Debug, DagCbor, PartialEq, Eq)] -pub struct MetadataNode { - pub datastore: String, // "mst" +pub struct UnsignedCommitNode { pub did: String, - pub version: u8, // 1 + pub version: u8, + pub prev: Option, + pub data: Cid, } #[derive(Debug, DagCbor, PartialEq, Eq)] @@ -124,30 +119,20 @@ pub fn dump_mst_keys(db_path: &PathBuf) -> Result<()> { &db.get_block(&commit_cid)? .ok_or(anyhow!("expected commit block in store"))? ); - let commit: CommitNode = DagCborCodec.decode( + let commit: SignedCommitNode = DagCborCodec.decode( &db.get_block(&commit_cid)? .ok_or(anyhow!("expected commit block in store"))?, )?; debug!("Commit: {:?}", commit); - let root: RootNode = DagCborCodec.decode( - &db.get_block(&commit.root)? - .ok_or(anyhow!("expected root block in store"))?, - )?; - debug!("Root: {:?}", root); - let metadata: MetadataNode = DagCborCodec.decode( - &db.get_block(&root.meta)? - .ok_or(anyhow!("expected metadata block in store"))?, - )?; - debug!("Metadata: {:?}", metadata); let mst_node: MstNode = DagCborCodec.decode( - &db.get_block(&root.data)? + &db.get_block(&commit.data)? .ok_or(anyhow!("expected block in store"))?, )?; debug!("MST root node: {:?}", mst_node); debug!("============"); println!("{did}"); - print_mst_keys(&mut db, &root.data)?; + print_mst_keys(&mut db, &commit.data)?; Ok(()) } diff --git a/adenosine/src/repo.rs b/adenosine/src/repo.rs index a3a5a12..3fb3a40 100644 --- a/adenosine/src/repo.rs +++ b/adenosine/src/repo.rs @@ -3,7 +3,7 @@ use crate::car::{ }; use crate::crypto::KeyPair; use crate::identifiers::{Did, Nsid, Tid}; -use crate::mst::{collect_mst_keys, generate_mst, CommitNode, MetadataNode, RootNode}; +use crate::mst::{collect_mst_keys, generate_mst, SignedCommitNode, UnsignedCommitNode}; use anyhow::{anyhow, ensure, Context, Result}; use ipfs_sqlite_block_store::BlockStore; use libipld::cbor::DagCborCodec; @@ -20,13 +20,12 @@ use std::str::FromStr; #[derive(Debug, serde::Serialize)] pub struct RepoCommit { - pub sig: Box<[u8]>, - pub commit_cid: Cid, - pub root_cid: Cid, pub did: Did, + pub version: u8, pub prev: Option, - pub meta_cid: Cid, pub mst_cid: Cid, + pub sig: Box<[u8]>, + pub commit_cid: Cid, } impl RepoCommit { @@ -34,13 +33,12 @@ impl RepoCommit { /// (aka, CID as a string, not an array of bytes). pub fn to_pretty_json(&self) -> Value { json!({ - "sig": data_encoding::HEXUPPER.encode(&self.sig), - "commit_cid": self.commit_cid.to_string(), - "root_cid": self.root_cid.to_string(), "did": self.did.to_string(), + "version": self.version.to_string(), "prev": self.prev.map(|v| v.to_string()), - "meta_cid": self.meta_cid.to_string(), "mst_cid": self.mst_cid.to_string(), + "sig": data_encoding::HEXUPPER.encode(&self.sig), + "commit_cid": self.commit_cid.to_string(), }) } } @@ -115,7 +113,7 @@ impl RepoStore { pub fn get_commit(&mut self, commit_cid: &Cid) -> Result { // read records by CID: commit, root, meta - let commit_node: CommitNode = DagCborCodec + let commit_node: SignedCommitNode = DagCborCodec .decode( &self .db @@ -123,40 +121,18 @@ impl RepoStore { .ok_or(anyhow!("expected commit block in store"))?, ) .context("parsing commit IPLD node from blockstore")?; - let root_node: RootNode = DagCborCodec - .decode( - &self - .db - .get_block(&commit_node.root)? - .ok_or(anyhow!("expected root block in store"))?, - ) - .context("parsing root IPLD node from blockstore")?; - let metadata_node: MetadataNode = DagCborCodec - .decode( - &self - .db - .get_block(&root_node.meta)? - .ok_or(anyhow!("expected metadata block in store"))?, - ) - .context("parsing metadata IPLD node from blockstore")?; - ensure!( - metadata_node.datastore == "mst", - "unexpected repo metadata.datastore: {}", - metadata_node.datastore - ); ensure!( - metadata_node.version == 1, - "unexpected repo metadata.version: {}", - metadata_node.version + commit_node.version == 2, + "unexpected repo version: {}", + commit_node.version ); Ok(RepoCommit { + did: Did::from_str(&commit_node.did)?, + version: commit_node.version, + prev: commit_node.prev, + mst_cid: commit_node.data, sig: commit_node.sig, commit_cid: *commit_cid, - root_cid: commit_node.root, - meta_cid: root_node.meta, - did: Did::from_str(&metadata_node.did)?, - prev: root_node.prev, - mst_cid: root_node.data, }) } @@ -200,26 +176,28 @@ impl RepoStore { self.get_mst_record_by_key(&commit.mst_cid, &record_key) } - pub fn write_metadata(&mut self, did: &Did) -> Result { - self.put_ipld(&MetadataNode { - datastore: "mst".to_string(), + pub fn write_commit( + &mut self, + did: &Did, + prev: Option, + mst_cid: Cid, + signing_key: &KeyPair, + ) -> Result { + let unsigned_commit = UnsignedCommitNode { did: did.to_string(), - version: 1, - }) - } - - pub fn write_root(&mut self, meta_cid: Cid, prev: Option, mst_cid: Cid) -> Result { - self.put_ipld(&RootNode { - auth_token: None, + version: 2, prev, - meta: meta_cid, data: mst_cid, - }) - } + }; + let block = Block::::encode(DagCborCodec, Code::Sha2_256, &unsigned_commit)?; + let digest = sha256::digest(block.data()); + let sig = signing_key.sign_bytes(digest.as_bytes()); - pub fn write_commit(&mut self, did: &Did, root_cid: Cid, sig: &str) -> Result { - let commit_cid = self.put_ipld(&CommitNode { - root: root_cid, + let commit_cid = self.put_ipld(&SignedCommitNode { + did: did.to_string(), + version: 2, + prev, + data: mst_cid, sig: sig.as_bytes().to_vec().into_boxed_slice(), })?; self.db.alias(did.as_bytes().to_vec(), Some(&commit_cid))?; @@ -272,19 +250,11 @@ impl RepoStore { let new_mst_cid = self .update_mst(&last_commit.mst_cid, mutations) .context("updating MST in repo")?; - let new_root_cid = self.write_root( - last_commit.meta_cid, - Some(last_commit.commit_cid), - new_mst_cid, - )?; - // TODO: is this how signatures are supposed to work? - // TODO: no, CID in bytes and sign that? - let sig = signing_key.sign_bytes(new_root_cid.to_string().as_bytes()); - self.write_commit(did, new_root_cid, &sig) + self.write_commit(did, Some(last_commit.commit_cid), new_mst_cid, &signing_key) } /// Reads in a full MST tree starting at a repo commit, then re-builds and re-writes the tree - /// in to the repo, and verifies that both the MST root CIDs and the repo root CIDs are identical. + /// in to the repo, and verifies that both the MST root CIDs are identical. pub fn verify_repo_mst(&mut self, commit_cid: &Cid) -> Result<()> { // load existing commit and MST tree let existing_commit = self.get_commit(commit_cid)?; @@ -300,16 +270,6 @@ impl RepoStore { ))?; } - let new_root_cid = - self.write_root(existing_commit.meta_cid, existing_commit.prev, new_mst_cid)?; - if new_root_cid != existing_commit.root_cid { - Err(anyhow!( - "repo root CID did not verify: {} != {}", - existing_commit.root_cid, - new_root_cid - ))?; - } - Ok(()) } @@ -359,6 +319,7 @@ fn test_repo_mst() { let mut repo = RepoStore::open_ephemeral().unwrap(); let did = Did::from_str("did:plc:dummy").unwrap(); + let dummy_keypair = KeyPair::new_random(); // basic blob and IPLD record put/get let blob = b"beware the swamp thing"; @@ -387,10 +348,8 @@ fn test_repo_mst() { assert_eq!(map, repo.mst_to_map(&simple_map_cid).unwrap()); // create root and commit IPLD nodes - let meta_cid = repo.write_metadata(&did).unwrap(); - let simple_root_cid = repo.write_root(meta_cid, None, simple_map_cid).unwrap(); let simple_commit_cid = repo - .write_commit(&did, simple_root_cid, "dummy-sig") + .write_commit(&did, None, simple_map_cid, &dummy_keypair) .unwrap(); assert_eq!( Some(record.clone()), @@ -422,11 +381,13 @@ fn test_repo_mst() { map.insert("test.records/33333333333333".to_string(), record_cid); let simple3_map_cid = repo.mst_from_map(&map).unwrap(); - let simple3_root_cid = repo - .write_root(meta_cid, Some(simple_commit_cid), simple3_map_cid) - .unwrap(); let simple3_commit_cid = repo - .write_commit(&did, simple3_root_cid, "dummy-sig3") + .write_commit( + &did, + Some(simple_commit_cid), + simple3_map_cid, + &dummy_keypair, + ) .unwrap(); assert_eq!(map, repo.mst_to_map(&simple3_map_cid).unwrap()); assert_eq!( @@ -444,7 +405,6 @@ fn test_repo_mst() { .unwrap() ); let commit = repo.get_commit(&simple3_commit_cid).unwrap(); - assert_eq!(commit.sig.to_vec(), b"dummy-sig3".to_vec()); assert_eq!(commit.did, did); assert_eq!(commit.prev, Some(simple_commit_cid)); assert_eq!(commit.mst_cid, simple3_map_cid); -- cgit v1.2.3