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"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "base64ct"
version = "1.6.0"
@@ -298,6 +304,7 @@ dependencies = [
"random_color",
"serde",
"serde_json",
"serde_with 3.8.1",
"sha2 0.10.8",
"time 0.1.45",
]
@@ -803,7 +810,7 @@ dependencies = [
"secp256k1",
"serde",
"serde_json",
"serde_with",
"serde_with 2.3.3",
"sha2 0.10.8",
"sha3",
"signature",
@@ -1177,6 +1184,7 @@ checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
"equivalent",
"hashbrown 0.14.5",
"serde",
]
[[package]]
@@ -1995,7 +2003,25 @@ dependencies = [
"indexmap 1.9.3",
"serde",
"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",
]
@@ -2011,6 +2037,18 @@ dependencies = [
"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]]
name = "sha-1"
version = "0.9.8"
@@ -2078,6 +2116,7 @@ dependencies = [
"clap",
"serde",
"serde_json",
"serde_with 3.8.1",
"tokio",
"websockets",
]

View File

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

View File

@@ -17,6 +17,8 @@ use fastcrypto::{
traits::{KeyPair, ToFromBytes},
// Verifier,
};
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, Bytes};
/// Anything that can be nested in a JSON CRDT
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
#[derive(Clone)]
#[serde_as]
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct SignedOp {
// 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
author: AuthorId,
/// 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 inner: Op<JsonValue>,
/// List of causal dependencies
#[serde_as(as = "Vec<Bytes>")]
pub depends_on: Vec<SignedDigest>,
}
@@ -244,7 +249,7 @@ impl<T: CrdtNode + DebugView> BaseCrdt<T> {
}
/// An enum representing a JSON value
#[derive(Clone, Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum JsonValue {
Null,
Bool(bool),

View File

@@ -81,7 +81,7 @@ pub fn parse_field(path: Vec<PathSegment>) -> Option<String> {
}
/// Represents a single node in a CRDT
#[derive(Clone, Serialize, Deserialize)]
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Op<T>
where
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 = { version = "1.0", features = ["derive"] }
serde_json = "1.0.117"
serde_with = "3.8.1"
[features]
default = ["bft", "logging-list", "logging-json"]

View File

@@ -1,4 +1,5 @@
use bft_crdt_derive::add_crdt_fields;
use bft_json_crdt::json_crdt::SignedOp;
use bft_json_crdt::keypair::KeyPair;
use bft_json_crdt::{
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/");
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
let keys = make_keypair();
let mut bft_crdt = BaseCrdt::<ListExample>::new(&keys);
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
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();
loop {
interval.tick().await;
println!("Sending: {}", json);
ws.send_text(json.clone()).await?;
println!("Sending: {:?}", signed_op);
ws.send_text(serde_json::to_string(&signed_op).unwrap())
.await?;
let msg = ws.receive().await?;
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
bft_crdt.apply(msg);
bft_crdt.apply(operation);
println!("New crdt state is: {}", bft_crdt.doc.view())
}
}
@@ -59,15 +71,17 @@ struct Transaction {
amount: f64,
}
fn generate_transaction() -> serde_json::Result<String> {
let transaction = Transaction {
fn generate_transaction() -> Transaction {
Transaction {
from: "Alice".to_string(),
to: "Bob".to_string(),
amount: 100.0,
path: vec![],
id: [0; ED25519_PUBLIC_KEY_LENGTH],
};
}
}
fn convert_to_json(transaction: &Transaction) -> serde_json::Result<String> {
let json = serde_json::to_string(&transaction).unwrap();
Ok(json)
}