From 1dc799d679258663de2bd7d2dc31e9f708ab61f4 Mon Sep 17 00:00:00 2001 From: Alexis Sellier Date: Thu, 13 Jul 2023 13:21:15 +0200 Subject: [PATCH] cob: Remove CRDTs from COB state It turns out that the CRDT formed by the union of Git DAGs is enough to guarantee everything we need for COBs. This changes the following things: * COB operations no longer need to be commutative * COB histories are traversed in the same deterministic order on all replicas * It's now possible to implement RSMs on top of COBs, eg. scripting * Lamport clocks have been removed * `radicle-crdt` is no longer a dependency of `radicle` * COBs are no longer instances of `Semilattice` * The `Ops` type was removed in favor of having `Op` contain multiple actions --- radicle-httpd/src/api/json.rs | 11 ++++++----- radicle-httpd/src/api/v1/projects.rs | 16 ++++++++-------- radicle-httpd/src/test.rs | 4 ++-- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/radicle-httpd/src/api/json.rs b/radicle-httpd/src/api/json.rs index 3fa310ccb..7408d7fa2 100644 --- a/radicle-httpd/src/api/json.rs +++ b/radicle-httpd/src/api/json.rs @@ -138,7 +138,7 @@ pub(crate) fn patch( "discussions": rev.discussion().comments() .map(|(id, comment)| Comment::new(id, comment, aliases)) .collect::>(), - "timestamp": rev.timestamp(), + "timestamp": rev.timestamp().as_secs().to_string(), "reviews": rev.reviews().map(|(nid, _review)| review(nid, aliases.alias(nid), _review)).collect::>(), }) }).collect::>(), @@ -165,7 +165,7 @@ fn merge(merge: &Merge, nid: &NodeId, alias: Option) -> Value { "alias": alias, }, "commit": merge.commit, - "timestamp": merge.timestamp, + "timestamp": merge.timestamp.as_secs().to_string(), "revision": merge.revision, }), None => json!({ @@ -173,7 +173,7 @@ fn merge(merge: &Merge, nid: &NodeId, alias: Option) -> Value { "id": nid, }, "commit": merge.commit, - "timestamp": merge.timestamp, + "timestamp": merge.timestamp.as_secs().to_string(), "revision": merge.revision, }), } @@ -190,7 +190,7 @@ fn review(nid: &NodeId, alias: Option, review: &Review) -> Value { "verdict": review.verdict(), "summary": review.summary(), "comments": review.comments().collect::>(), - "timestamp": review.timestamp(), + "timestamp": review.timestamp().as_secs().to_string(), }), None => json!({ "author": { @@ -199,7 +199,7 @@ fn review(nid: &NodeId, alias: Option, review: &Review) -> Value { "verdict": review.verdict(), "summary": review.summary(), "comments": review.comments().collect::>(), - "timestamp": review.timestamp(), + "timestamp": review.timestamp().as_secs().to_string(), }), } } @@ -240,6 +240,7 @@ struct Comment<'a> { author: Value, body: &'a str, reactions: Vec<(&'a ActorId, &'a Reaction)>, + #[serde(with = "radicle::serde_ext::localtime::time")] timestamp: Timestamp, reply_to: Option, } diff --git a/radicle-httpd/src/api/v1/projects.rs b/radicle-httpd/src/api/v1/projects.rs index 67e7bfd00..910d002ac 100644 --- a/radicle-httpd/src/api/v1/projects.rs +++ b/radicle-httpd/src/api/v1/projects.rs @@ -460,16 +460,16 @@ async fn issues_handler( let mut issues: Vec<_> = issues .all()? .filter_map(|r| { - let (id, issue, clock) = r.ok()?; - (state.matches(issue.state())).then_some((id, issue, clock)) + let (id, issue) = r.ok()?; + (state.matches(issue.state())).then_some((id, issue)) }) .collect::>(); - issues.sort_by(|(_, a, _), (_, b, _)| b.timestamp().cmp(&a.timestamp())); + issues.sort_by(|(_, a), (_, b)| b.timestamp().cmp(&a.timestamp())); let aliases = &ctx.profile.aliases(); let issues = issues .into_iter() - .map(|(id, issue, _)| api::json::issue(id, issue, aliases)) + .map(|(id, issue)| api::json::issue(id, issue, aliases)) .skip(page * per_page) .take(per_page) .collect::>(); @@ -739,15 +739,15 @@ async fn patches_handler( let mut patches = patches .all()? .filter_map(|r| { - let (id, patch, clock) = r.ok()?; - (state.matches(patch.state())).then_some((id, patch, clock)) + let (id, patch) = r.ok()?; + (state.matches(patch.state())).then_some((id, patch)) }) .collect::>(); - patches.sort_by(|(_, a, _), (_, b, _)| b.timestamp().cmp(&a.timestamp())); + patches.sort_by(|(_, a), (_, b)| b.timestamp().cmp(&a.timestamp())); let aliases = ctx.profile.aliases(); let patches = patches .into_iter() - .map(|(id, patch, _)| api::json::patch(id, patch, &repo, &aliases)) + .map(|(id, patch)| api::json::patch(id, patch, &repo, &aliases)) .skip(page * per_page) .take(per_page) .collect::>(); diff --git a/radicle-httpd/src/test.rs b/radicle-httpd/src/test.rs index 72b11e40f..5191520df 100644 --- a/radicle-httpd/src/test.rs +++ b/radicle-httpd/src/test.rs @@ -37,7 +37,7 @@ pub const ISSUE_ID: &str = "5ad77fa3f476beed9a26f49b2b3b844e61bef792"; pub const ISSUE_DISCUSSION_ID: &str = "f1dff128a22e8183a23516dd9812e72e80914c92"; pub const ISSUE_COMMENT_ID: &str = "845218041bf9eb8155bfa4aaa8f0c91ce18e5c13"; pub const SESSION_ID: &str = "u9MGAkkfkMOv0uDDB2WeUHBT7HbsO2Dy"; -pub const TIMESTAMP: u64 = 1671125284; +pub const TIMESTAMP: &str = "1671125284"; pub const CONTRIBUTOR_RID: &str = "rad:z4XaCmN3jLSeiMvW15YTDpNbDHFhG"; pub const CONTRIBUTOR_DID: &str = "did:key:z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8"; pub const CONTRIBUTOR_NID: &str = "z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8"; @@ -97,7 +97,7 @@ fn seed_with_signer(dir: &Path, profile: radicle::Profile, signer: &G let workdir = dir.join("hello-world"); - env::set_var("RAD_COMMIT_TIME", TIMESTAMP.to_string()); + env::set_var("RAD_COMMIT_TIME", TIMESTAMP); fs::create_dir_all(&workdir).unwrap();