Serialization of SignedOp now works; adding to the CRDT doesn't

This commit is contained in:
Dave Hrycyszyn
2024-06-05 16:50:28 +01:00
parent 4eac2ccf19
commit c866774612
6 changed files with 75 additions and 15 deletions

43
Cargo.lock generated
View File

@@ -264,6 +264,12 @@ version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]] [[package]]
name = "base64ct" name = "base64ct"
version = "1.6.0" version = "1.6.0"
@@ -298,6 +304,7 @@ dependencies = [
"random_color", "random_color",
"serde", "serde",
"serde_json", "serde_json",
"serde_with 3.8.1",
"sha2 0.10.8", "sha2 0.10.8",
"time 0.1.45", "time 0.1.45",
] ]
@@ -803,7 +810,7 @@ dependencies = [
"secp256k1", "secp256k1",
"serde", "serde",
"serde_json", "serde_json",
"serde_with", "serde_with 2.3.3",
"sha2 0.10.8", "sha2 0.10.8",
"sha3", "sha3",
"signature", "signature",
@@ -1177,6 +1184,7 @@ checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown 0.14.5", "hashbrown 0.14.5",
"serde",
] ]
[[package]] [[package]]
@@ -1995,7 +2003,25 @@ dependencies = [
"indexmap 1.9.3", "indexmap 1.9.3",
"serde", "serde",
"serde_json", "serde_json",
"serde_with_macros", "serde_with_macros 2.3.3",
"time 0.3.36",
]
[[package]]
name = "serde_with"
version = "3.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20"
dependencies = [
"base64 0.22.1",
"chrono",
"hex",
"indexmap 1.9.3",
"indexmap 2.2.6",
"serde",
"serde_derive",
"serde_json",
"serde_with_macros 3.8.1",
"time 0.3.36", "time 0.3.36",
] ]
@@ -2011,6 +2037,18 @@ dependencies = [
"syn 2.0.66", "syn 2.0.66",
] ]
[[package]]
name = "serde_with_macros"
version = "3.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.66",
]
[[package]] [[package]]
name = "sha-1" name = "sha-1"
version = "0.9.8" version = "0.9.8"
@@ -2078,6 +2116,7 @@ dependencies = [
"clap", "clap",
"serde", "serde",
"serde_json", "serde_json",
"serde_with 3.8.1",
"tokio", "tokio",
"websockets", "websockets",
] ]

View File

@@ -22,6 +22,7 @@ rand = "0.8.5"
random_color = "0.6.1" random_color = "0.6.1"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.85" serde_json = "1.0.85"
serde_with = "3.8.1"
sha2 = "0.10.6" sha2 = "0.10.6"
[dev-dependencies] [dev-dependencies]

View File

@@ -17,6 +17,8 @@ use fastcrypto::{
traits::{KeyPair, ToFromBytes}, traits::{KeyPair, ToFromBytes},
// Verifier, // Verifier,
}; };
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, Bytes};
/// Anything that can be nested in a JSON CRDT /// Anything that can be nested in a JSON CRDT
pub trait CrdtNode: CrdtNodeFromValue + Hashable + Clone { pub trait CrdtNode: CrdtNodeFromValue + Hashable + Clone {
@@ -106,15 +108,18 @@ pub struct BaseCrdt<T: CrdtNode> {
} }
/// An [`Op<Value>`] with a few bits of extra metadata /// An [`Op<Value>`] with a few bits of extra metadata
#[derive(Clone)] #[serde_as]
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct SignedOp { pub struct SignedOp {
// Note that this can be different from the author of the inner op as the inner op could have been created // Note that this can be different from the author of the inner op as the inner op could have been created
// by a different person // by a different person
author: AuthorId, author: AuthorId,
/// Signed hash using priv key of author. Effectively [`OpID`] Use this as the ID to figure out what has been delivered already /// Signed hash using priv key of author. Effectively [`OpID`] Use this as the ID to figure out what has been delivered already
#[serde_as(as = "Bytes")]
pub signed_digest: SignedDigest, pub signed_digest: SignedDigest,
pub inner: Op<JsonValue>, pub inner: Op<JsonValue>,
/// List of causal dependencies /// List of causal dependencies
#[serde_as(as = "Vec<Bytes>")]
pub depends_on: Vec<SignedDigest>, pub depends_on: Vec<SignedDigest>,
} }
@@ -244,7 +249,7 @@ impl<T: CrdtNode + DebugView> BaseCrdt<T> {
} }
/// An enum representing a JSON value /// An enum representing a JSON value
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum JsonValue { pub enum JsonValue {
Null, Null,
Bool(bool), Bool(bool),

View File

@@ -81,7 +81,7 @@ pub fn parse_field(path: Vec<PathSegment>) -> Option<String> {
} }
/// Represents a single node in a CRDT /// Represents a single node in a CRDT
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Op<T> pub struct Op<T>
where where
T: CrdtNode, T: CrdtNode,

View File

@@ -14,6 +14,7 @@ bft-crdt-derive = { path = "../crates/bft-json-crdt/bft-crdt-derive" }
# serde_cbor = "0.11.2" # move to this once we need to pack things in CBOR # serde_cbor = "0.11.2" # move to this once we need to pack things in CBOR
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.117" serde_json = "1.0.117"
serde_with = "3.8.1"
[features] [features]
default = ["bft", "logging-list", "logging-json"] default = ["bft", "logging-list", "logging-json"]

View File

@@ -1,4 +1,5 @@
use bft_crdt_derive::add_crdt_fields; use bft_crdt_derive::add_crdt_fields;
use bft_json_crdt::json_crdt::SignedOp;
use bft_json_crdt::keypair::KeyPair; use bft_json_crdt::keypair::KeyPair;
use bft_json_crdt::{ use bft_json_crdt::{
json_crdt::{BaseCrdt, CrdtNode, IntoCrdtNode}, json_crdt::{BaseCrdt, CrdtNode, IntoCrdtNode},
@@ -15,27 +16,38 @@ pub(crate) async fn start() -> Result<(), websockets::WebSocketError> {
println!("connecting to websocket at ws://127.0.0.1:8080/"); println!("connecting to websocket at ws://127.0.0.1:8080/");
let mut ws = WebSocket::connect("ws://127.0.0.1:8080/").await?; let mut ws = WebSocket::connect("ws://127.0.0.1:8080/").await?;
// generate a placeholder transaction
let json = generate_transaction().unwrap();
// set up a new BFT-CRDT // set up a new BFT-CRDT
let keys = make_keypair(); let keys = make_keypair();
let mut bft_crdt = BaseCrdt::<ListExample>::new(&keys); let mut bft_crdt = BaseCrdt::<ListExample>::new(&keys);
println!("Generated a new CRDT with public key: {}", keys.public()); println!("Generated a new CRDT with public key: {}", keys.public());
// generate a placeholder transaction
let transaction = generate_transaction();
let json = convert_to_json(&transaction).unwrap();
// next job is to keep adding to this guy // next job is to keep adding to this guy
let _a = bft_crdt.doc.list.insert(ROOT_ID, 'a').sign(&keys); let signed_op = bft_crdt.doc.list.insert(ROOT_ID, json.clone()).sign(&keys);
println!("SignedOp before send is: {:?}", signed_op);
let mut interval = every_two_seconds(); let mut interval = every_two_seconds();
loop { loop {
interval.tick().await; interval.tick().await;
println!("Sending: {}", json); println!("Sending: {:?}", signed_op);
ws.send_text(json.clone()).await?; ws.send_text(serde_json::to_string(&signed_op).unwrap())
.await?;
let msg = ws.receive().await?; let msg = ws.receive().await?;
println!("Received: {:?}", msg); println!("Received: {:?}", msg);
// deserialize the received Frame into a string
let msg = msg.into_text().unwrap().0;
// deserialize the message into a Transaction struct
let operation: SignedOp = serde_json::from_str(&msg).unwrap();
// TODO: bft_crdt.apply() changes in here when we receive socket input from other nodes // TODO: bft_crdt.apply() changes in here when we receive socket input from other nodes
bft_crdt.apply(msg); bft_crdt.apply(operation);
println!("New crdt state is: {}", bft_crdt.doc.view()) println!("New crdt state is: {}", bft_crdt.doc.view())
} }
} }
@@ -59,15 +71,17 @@ struct Transaction {
amount: f64, amount: f64,
} }
fn generate_transaction() -> serde_json::Result<String> { fn generate_transaction() -> Transaction {
let transaction = Transaction { Transaction {
from: "Alice".to_string(), from: "Alice".to_string(),
to: "Bob".to_string(), to: "Bob".to_string(),
amount: 100.0, amount: 100.0,
path: vec![], path: vec![],
id: [0; ED25519_PUBLIC_KEY_LENGTH], id: [0; ED25519_PUBLIC_KEY_LENGTH],
}; }
}
fn convert_to_json(transaction: &Transaction) -> serde_json::Result<String> {
let json = serde_json::to_string(&transaction).unwrap(); let json = serde_json::to_string(&transaction).unwrap();
Ok(json) Ok(json)
} }