Serialization of SignedOp now works; adding to the CRDT doesn't
This commit is contained in:
43
Cargo.lock
generated
43
Cargo.lock
generated
@@ -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",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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"]
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user