diff --git a/Cargo.lock b/Cargo.lock index 7a7ff95..cac9003 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -485,8 +485,10 @@ dependencies = [ "quick-protobuf", "rand", "serde", + "serde_arrays", "sqlx", "tokio", + "toml", "tracing", "tracing-subscriber", ] @@ -3055,6 +3057,15 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde_arrays" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38636132857f68ec3d5f3eb121166d2af33cb55174c4d5ff645db6165cbef0fd" +dependencies = [ + "serde", +] + [[package]] name = "serde_derive" version = "1.0.217" @@ -3078,6 +3089,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -3682,6 +3702,40 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower-service" version = "0.3.3" @@ -4204,6 +4258,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" diff --git a/Cargo.toml b/Cargo.toml index cb323cd..d6008b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,9 @@ owo-colors = "4.1.0" quick-protobuf = "0.8.1" rand = "0.8.5" serde = { version = "1.0.213", features = ["derive"] } +serde_arrays = "0.1.0" sqlx = { version = "0.8.2", features = ["sqlite", "macros", "runtime-tokio"] } tokio = { version = "1.40.0", features = ["full", "tracing"] } +toml = "0.8.20" tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } diff --git a/README.md b/README.md index 00be3ad..7835036 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,15 @@ # CL L2 V0 -This repo is a sandbox for the Cardano Lightning's L2 (V0). +## Aims -A key aim of this repo is to try and assess available libraries in order to -establish our key dependencies. +This is a demo of a CL node that is able to: + +- Manage channels via l1 interface (all l1 txs) +- Coordinate channels with other nodes (open, register) +- Send and receive cheques + +The repo is a sandbox for the Cardano Lightning's future work. Here we assess +available libraries and designs. ## Setup @@ -21,158 +27,35 @@ Run binary `x`: cargo run --bin ``` -There are three binaries: +## Current stack -- `admin` - admin controls: create, add, revoke ephemeral keys -- `server` - run the signing server -- `client` - run a client - -## Context - -CL depends on the use on signing/verification key pair cryptography. The signing -key may be used to handover all the participants funds. The signing key must be -handled with care. - -A router node must run their infrastructure on highly available machines, in -order to provide good service to their partners. The router might choose to use -an infrastructure provider to host their nodes. The router must produce the -signatures for cheques and snapshots in the course of standard channel -operations. A priori the machine will contain signing keys. What if the machine -is compromised? - -An attacker with access to the machine could send all funds to the partner of -the channel, or produce a tx that a partner signs, making it a valid mutual tx. -In either case, they are at the detriment of the router. - -Instead, we may outsource the signing process to a separate machine - the -signing server. This sever can: - -- serve requests to only whitelisted requesters. It can be more easily protected - from ddos type attacks and probing by an attacker. -- has minimal, relatively fixed, API. It will receive fewer updates each of - which can be reviewed more thoroughly, and have shorter/tighter software - supply chains, than might be true for the general service on the HA machine. - -In addition, the signing service could be split using, say, FROST. +- Comms stack : rust-libp2p +- Persistent storage : sqlx with sqlite ## Design -### Data +See the design docs. -#### Persistent keys +## TODO -These are the signing keys available to the machine and found at startup of the -service. - -#### Ephemeral keys - -Perhaps also called proxy keys. - -An ephemeral key consists of the following properties: - -1. Verification key -1. Persistent key -1. Expires at -1. Signature - -### Signing Server Actions - -#### Add - -An add is performed by "admin" to create new ephemeral keys. - -An `add` request has the following fields - -1. Verification key -2. Persistent key -3. Expires at -4. Signature - -The request is deemed valid - -1. The persistent key is in the database -1. The signature is valid wrt the persistent key, and the payload created by - `(verification_key, expires_at)` (with some prefix?) - -The result of a valid `add` request is the ephemeral key is added to the -database with the obvious fields. - -The response is either `Ok()` or `Error("help message!")` - -#### Sign - -A sign action is the "standard" action that will occur. - -A `sign` request has the following fields - -1. Verification key -2. Payload -3. Signature - -The request is deemed valid - -1. The verification key exists in the database -1. The verification key has not expired -1. The signature is valid wrt the payload and verification key -1. The payload is "sensible" (TBC) - this is context specific. - -The response to a valid request - -1. The signature produced by the persistent key associated to the verification - key for the same payload. - -#### Revoke - -A revoke is the opposite of add. It is also performed exclusively by admin. - -An `revoke` request has the following fields - -2. Verification key -3. Signature - -The request is deemed valid - -1. The verification key is in the database -1. The signature is valid wrt the associated persistent key, and the payload - created by `verification_key` (with some prefix?) - -The result of a valid `revoke` request is the ephemeral key is removed from the -database. - -The response is either `Ok()` or `Error("help message!")` - -#### SIMPLIFICATION - -The `add` and `revoke` endpoints are needed only by admin, and infrequently, or -in case of emergency. In contrast, `sign` is needed with relatively high -frequency, and called by less trusted machines. - -Thus, we assume that admin accesses the machine directly and simply adds the -ephemeral keys to the db. This does not require a valid signature - if the pub -key is registered, then a signature request is honored. - -### Client server actions - -#### Demo task - -Some way to trigger the client service to make a request to the server. - -## Notes - -### sqlx - -The sqlx tool has a cli (available via the flake). This can handle migrations -provided its opinionated design choices are adopted. See -[here](https://docs.rs/sqlx/latest/sqlx/migrate/trait.MigrationSource.html). - -```sh -export DATABASE_URL=sqlite:./db/cll2v0.db -sqlx database create -sqlx migration run -``` - -The database must be initialised before starting the application. - -### libp2p - -TODO +- [ ] api + - [ ] global + - [ ] terms + - [x] simple + - [ ] confer + - [x] simple + - [ ] watch + - [ ] register + - [ ] channel + - [ ] UNPACK +- [ ] config + - [ ] UNPACK +- [ ] storage + - [ ] ephemeral + - [ ] UNPACK + - [ ] persistent + - [ ] UNPACK +- [ ] l1 + - [ ] Mock + - [ ] UNPACK + - [ ] Via "kupmios" diff --git a/app/admin.rs b/app/admin.rs index 52ead95..aa33cde 100644 --- a/app/admin.rs +++ b/app/admin.rs @@ -1,9 +1,10 @@ use clap::{Parser, Subcommand}; -use ed25519_dalek::{Signature, SigningKey}; +// use ed25519_dalek::{Signature, SigningKey}; use cll2v0::{ - db, - keys::{self}, + // db, + config, + // keys::{self} }; /// cll2v0 is a playground for rust libraries. @@ -17,117 +18,122 @@ struct Args { #[derive(Subcommand)] enum Command { - /// Add new ephemeral key to an existing persistent key - Add { - ephemeral_key: String, - persistent_key: String, - expires_at: i64, - }, - /// Revoke an existing ephemeral key - Revoke { ephemeral_key: String }, - /// Check persistent keys are available and display - Check, - /// Gen from seed some sensible ephemeral key args to be used with `add` - Gen { seed: u8 }, - /// Sign a message - Sign { - signing_key: String, - message: String, - }, - /// Verify a message - Verify { - verifying_key: String, - message: String, - signature: String, - }, + /// Generate a default config + GenConfig, // /// Add new ephemeral key to an existing persistent key + // Add { + // ephemeral_key: String, + // persistent_key: String, + // expires_at: i64, + // }, + // /// Revoke an existing ephemeral key + // Revoke { ephemeral_key: String }, + // /// Check persistent keys are available and display + // Check, + // /// Gen from seed some sensible ephemeral key args to be used with `add` + // Gen { seed: u8 }, + // /// Sign a message + // Sign { + // signing_key: String, + // message: String, + // }, + // /// Verify a message + // Verify { + // verifying_key: String, + // message: String, + // signature: String, + // }, } #[tokio::main(flavor = "current_thread")] async fn main() -> anyhow::Result<()> { let args = Args::parse(); - let (_, pool) = db::start_db().await?; + // let (_, pool) = db::start_db().await?; match args.cmd { - Some(Command::Add { - ephemeral_key, - persistent_key, - expires_at, - }) => { - println!("Adding new ephemeral key '{ephemeral_key}'"); - let e = keys::from_hex(&ephemeral_key).expect("cannot parse key"); - let p = keys::from_hex(&persistent_key).expect("cannot parse key"); - let res = db::add_ephemeral_key(&pool, &e, &p, expires_at).await?; - println!("Added new ekey: {}", res); - } - Some(Command::Revoke { ephemeral_key }) => { - let e = keys::from_hex(&ephemeral_key).expect("cannot parse key"); - let res = db::revoke_ephemeral_key(&pool, &e).await?; - println!("Revoked key: {}", res); - } - Some(Command::Check) => { - eprintln!("!Check skipped"); - let res = db::list_persistent_keys(&pool).await?; - println!("Persistent keys:"); - res.into_iter() - .for_each(|key| println!("{}", keys::to_hex(&key))); - let res = db::list_ephemeral_keys(&pool).await?; - println!("ephemeral keys:"); - res.into_iter() - .for_each(|(e, p, t)| println!("{} {} {t}", keys::to_hex(&e), keys::to_hex(&p))) - } - Some(Command::Gen { seed }) => { - let ekey = SigningKey::from_bytes(&[ - seed, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - ]); - println!("Ephemeral signing key:"); - println!("{}", keys::signing_key_to_hex(&ekey)); - let res = db::list_persistent_keys(&pool).await?; - let idx = (seed as usize) % res.len(); - let pkey = res.get(idx); - match pkey { - None => eprintln!("No persistent keys found"), - Some(pkey) => { - let now: usize = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_millis() - .try_into() - .unwrap(); - let twenty_mins_from_now = 20usize * 60 * 1000 + now; - println!("Args"); - println!( - "{} {} {}", - keys::to_hex(&ekey.verifying_key()), - keys::to_hex(pkey), - twenty_mins_from_now - ) - } - } - } - Some(Command::Sign { - signing_key, - message, - }) => { - let mut skey = keys::signing_key_from_hex(&signing_key).unwrap(); - let msg = hex::decode(message).unwrap(); - let sig = keys::sign(&mut skey, msg); - println!("{}", hex::encode(sig.to_bytes())) - } - Some(Command::Verify { - verifying_key, - message, - signature, - }) => { - let vkey = keys::from_hex(&verifying_key).unwrap(); - let msg = hex::decode(message).unwrap(); - let sig = Signature::from_bytes( - &TryInto::<[u8; 64]>::try_into(hex::decode(signature).unwrap()).unwrap(), - ); - let res = keys::verify(&vkey, &msg, &sig).unwrap(); - println!("{:?}", res); + Some(Command::GenConfig) => { + let c = config::Config::default().to_string()?; + println!("{}", c); } + // Some(Command::Add { + // ephemeral_key, + // persistent_key, + // expires_at, + // }) => { + // println!("Adding new ephemeral key '{ephemeral_key}'"); + // let e = keys::from_hex(&ephemeral_key).expect("cannot parse key"); + // let p = keys::from_hex(&persistent_key).expect("cannot parse key"); + // let res = db::add_ephemeral_key(&pool, &e, &p, expires_at).await?; + // println!("Added new ekey: {}", res); + // } + // Some(Command::Revoke { ephemeral_key }) => { + // let e = keys::from_hex(&ephemeral_key).expect("cannot parse key"); + // let res = db::revoke_ephemeral_key(&pool, &e).await?; + // println!("Revoked key: {}", res); + // } + // Some(Command::Check) => { + // eprintln!("!Check skipped"); + // let res = db::list_persistent_keys(&pool).await?; + // println!("Persistent keys:"); + // res.into_iter() + // .for_each(|key| println!("{}", keys::to_hex(&key))); + // let res = db::list_ephemeral_keys(&pool).await?; + // println!("ephemeral keys:"); + // res.into_iter() + // .for_each(|(e, p, t)| println!("{} {} {t}", keys::to_hex(&e), keys::to_hex(&p))) + // } + // Some(Command::Gen { seed }) => { + // let ekey = SigningKey::from_bytes(&[ + // seed, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // 0, 0, 0, 0, 0, + // ]); + // println!("Ephemeral signing key:"); + // println!("{}", keys::signing_key_to_hex(&ekey)); + // let res = db::list_persistent_keys(&pool).await?; + // let idx = (seed as usize) % res.len(); + // let pkey = res.get(idx); + // match pkey { + // None => eprintln!("No persistent keys found"), + // Some(pkey) => { + // let now: usize = std::time::SystemTime::now() + // .duration_since(std::time::UNIX_EPOCH) + // .unwrap() + // .as_millis() + // .try_into() + // .unwrap(); + // let twenty_mins_from_now = 20usize * 60 * 1000 + now; + // println!("Args"); + // println!( + // "{} {} {}", + // keys::to_hex(&ekey.verifying_key()), + // keys::to_hex(pkey), + // twenty_mins_from_now + // ) + // } + // } + // } + // Some(Command::Sign { + // signing_key, + // message, + // }) => { + // let mut skey = keys::signing_key_from_hex(&signing_key).unwrap(); + // let msg = hex::decode(message).unwrap(); + // let sig = keys::sign(&mut skey, msg); + // println!("{}", hex::encode(sig.to_bytes())) + // } + // Some(Command::Verify { + // verifying_key, + // message, + // signature, + // }) => { + // let vkey = keys::from_hex(&verifying_key).unwrap(); + // let msg = hex::decode(message).unwrap(); + // let sig = Signature::from_bytes( + // &TryInto::<[u8; 64]>::try_into(hex::decode(signature).unwrap()).unwrap(), + // ); + // let res = keys::verify(&vkey, &msg, &sig).unwrap(); + // println!("{:?}", res); + // } None => { println!("See help"); } diff --git a/app/client.rs b/app/client.rs index 8ccfc97..6136fa9 100644 --- a/app/client.rs +++ b/app/client.rs @@ -10,15 +10,14 @@ use libp2p::{ use tracing_subscriber::EnvFilter; use cll2v0::{ - keys, - messages::{MyRequest, MyResult}, + api, keys, protocol::{mk_swarm, MyBehaviourEvent}, }; use clap::{Parser, Subcommand}; -/// cll2v0 is a playground for rust libraries. -/// This is signing service. +/// CLL2 client +/// Configured to act as a unpersistant node. #[derive(Parser)] #[command(arg_required_else_help(true), version, about)] struct Args { @@ -100,11 +99,7 @@ pub async fn start(params: ClientParams) -> Result<(), Box> { Ok(Some(line)) = stdin.next_line() => { println!("MESSAGE: {}", line); let bytes = line.into_bytes(); - let req = MyRequest { - key: keypair.clone().public().to_bytes(), - body: bytes.clone(), - sig: keys::sign(&mut key.clone(), bytes).to_vec(), - }; + let req = api::Req::Global(api::global::Req::Terms) ; println!("REQ : {:?}", req); swarm.behaviour_mut().req_res.send_request( &server_peer_id, @@ -147,11 +142,11 @@ pub async fn start(params: ClientParams) -> Result<(), Box> { })) => { // println!("response : {:?} {:?} {:?}", peer, request_id, "" ); match response { - MyResult::Okay(response) => { - println!("OKAY : {}", hex::encode(response.sig.clone()),); + api::Res::Global(api::global::Res::Terms(api::global::terms::Res::Okay(terms))) => { + println!("TERMS :: OKAY : {:?}", terms); } - MyResult::Fail(response) => { - println!("FAIL : {}", response); + res => { + println!("FAIL : {:?}", res); } } } diff --git a/app/server.rs b/app/server.rs index 6d1b2df..c5fb713 100644 --- a/app/server.rs +++ b/app/server.rs @@ -1,6 +1,5 @@ use std::error::Error; -use ed25519_dalek::{ed25519::signature::SignerMut, Signature}; use futures::prelude::*; use libp2p::{ mdns, @@ -10,8 +9,7 @@ use libp2p::{ use tracing_subscriber::EnvFilter; use cll2v0::{ - db, keys, - messages::{MyRequest, MyResponse, MyResult}, + api, config, keys, protocol::{mk_swarm, MyBehaviourEvent}, }; @@ -34,6 +32,9 @@ enum Command { #[derive(clap::Args, Debug)] pub struct ServerParams { + /// Config file + #[arg(long, default_value = "./config.toml")] + pub config: String, /// Server listening address #[arg(long, default_value = "/ip4/0.0.0.0/tcp/52321")] pub listen_on: String, @@ -60,9 +61,14 @@ fn main() -> Result<(), Box> { pub async fn start(params: ServerParams) -> Result<(), Box> { let ServerParams { + config: config_path, skey: skey_hex, listen_on, } = params; + + let c = config::Config::read(&config_path)?; + println!("CONFIG "); + println!("{:?}", c); if true { let _ = tracing_subscriber::fmt() .with_env_filter(EnvFilter::from_default_env()) @@ -72,7 +78,7 @@ pub async fn start(params: ServerParams) -> Result<(), Box> { let peer_id = libp2p_identity::PublicKey::from(keypair.public()).to_peer_id(); println!("PEER_ID : {}", peer_id); - let (keychain, pool) = db::start_db().await?; + // let (keychain, pool) = db::start_db().await?; let mut swarm = mk_swarm(&keypair.clone().into(), ProtocolSupport::Inbound)?; swarm.listen_on(listen_on.parse()?)?; @@ -93,33 +99,18 @@ pub async fn start(params: ServerParams) -> Result<(), Box> { request, channel, .. }, })) => { - // println!("Req : {:?} {:?} {:?}", peer, channel, hex::encode(request.body.clone()), ); - println!("REQSIG : {}", hex::encode(request.sig.clone()),); - let MyRequest { key, body, sig } = request; - - // FIXME :: MAP ERROR. - let sig_arr: [u8; 64] = sig.clone().try_into().unwrap(); - - if let Ok(ekey) = keys::from_bytes(key.into()) { - if let Ok(_) = ekey.verify_strict(&body, &Signature::from_bytes(&sig_arr)) { - if let Ok(pkey) = db::get_persistent_key(&pool, &ekey).await { - if let Some(skey) = keychain.get(&pkey.to_bytes()) { - let _ = swarm.behaviour_mut().req_res.send_response( - channel, - MyResult::Okay(MyResponse { - sig: skey.clone().sign(&body).to_bytes().into(), - }), - ); - } else { - println!("err0") - }; - } else { - println!("err1"); - } - } else { - println!("err2"); + let res = match request { + api::Req::Global(api::global::Req::Terms) => { + api::Res::Global(api::global::Res::Terms(api::global::terms::Res::Okay( + api::global::terms::Terms::default(), + ))) } - } + api::Req::Channel => todo!("Not yet implemented"), + _ => api::Res::Global(api::global::Res::Terms(api::global::terms::Res::Okay( + api::global::terms::Terms::default(), + ))), + }; + let _ = swarm.behaviour_mut().req_res.send_response(channel, res); } e => { println!("OTHER {:?}", e) diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..6e17e37 --- /dev/null +++ b/config.toml @@ -0,0 +1,22 @@ +keys = "" + +[api] +channel = false + +[api.global.terms.Static] +currencies = [[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], []]] +response_period = 86400000 +additional_terms = """ +There are no additional terms +""" + +[api.global.terms.Static.initial_amounts] +min_funds = 0 +min_gift = 0 + +[api.global.terms.Static.capacity] +max_count = 30 +max_locked = 30 +max_single = 1000000000 +max_total = 5000000000 + diff --git a/src/api.rs b/src/api.rs new file mode 100644 index 0000000..eac3f91 --- /dev/null +++ b/src/api.rs @@ -0,0 +1,21 @@ +use serde::{Deserialize, Serialize}; + +pub mod global; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum Req { + Global(global::Req), + Channel, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum Res { + Global(global::Res), + Channel, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] +pub struct Config { + global: global::Config, + channel: bool, +} diff --git a/src/api/global.rs b/src/api/global.rs new file mode 100644 index 0000000..a66b72d --- /dev/null +++ b/src/api/global.rs @@ -0,0 +1,28 @@ +use serde::{Deserialize, Serialize}; + +pub mod common; +pub mod confer; +pub mod register; +pub mod terms; +pub mod watch; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] +pub struct Config { + terms: terms::Config, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum Req { + Terms, + Confer(confer::Req), + Watch(watch::Req), + Register(register::Req), +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum Res { + Terms(terms::Res), + Confer(confer::Res), + Watch(watch::Res), + Register(register::Res), +} diff --git a/src/api/global/common.rs b/src/api/global/common.rs new file mode 100644 index 0000000..65a3e50 --- /dev/null +++ b/src/api/global/common.rs @@ -0,0 +1,51 @@ +use crate::prelude::*; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct InitialAmounts { + pub min_funds: Amount, + pub min_gift: Amount, +} + +impl Default for InitialAmounts { + fn default() -> Self { + InitialAmounts { + min_funds: 0, + min_gift: 0, + } + } +} + +impl InitialAmounts { + pub fn gte(&self, other: &Self) -> bool { + self.min_funds >= other.min_funds && self.min_gift >= other.min_gift + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct Capacity { + pub max_count: Natural, + pub max_locked: Natural, + pub max_single: Amount, + pub max_total: Amount, +} + +impl Default for Capacity { + fn default() -> Self { + Capacity { + max_count: 30, + max_locked: 30, + max_single: E9, + max_total: 5 * E9, + } + } +} + +impl Capacity { + pub fn gte(&self, other: &Self) -> bool { + self.max_count >= other.max_count + && self.max_locked >= other.max_locked + && self.max_single >= other.max_single + && self.max_total >= other.max_total + } +} diff --git a/src/api/global/confer.rs b/src/api/global/confer.rs new file mode 100644 index 0000000..9f8f69d --- /dev/null +++ b/src/api/global/confer.rs @@ -0,0 +1,71 @@ +use crate::prelude::*; +use serde::{Deserialize, Serialize}; + +use super::common::{Capacity, InitialAmounts}; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct Req { + pub currency: Currency, + pub initial_amounts: InitialAmounts, + pub response_period: Milliseconds, + pub capacity: Capacity, + pub key: VerificationKey, +} + +impl Req { + /// A channel adhering to `self` will necessarily adhere to other + pub fn is_stricter(&self, other: &Self) -> bool { + &self.currency == &other.currency + && self.initial_amounts.gte(&other.initial_amounts) + && other.capacity.gte(&self.capacity) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum Res { + Okay(VerificationKey), + Fail(Fail), +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum Fail { + Suggestion(Req), + Other(Option), +} + +pub fn basic_bounds(min_terms: Req, proposed_terms: Req) -> Res { + // FIXME :: this is all faff. + // + // // Bad currency + // if min_terms.currency != proposed_terms.currency { + // return Res::Fail(ConferFail::Suggestion(Req { + // currency: min_terms.currency, + // ..proposed_terms + // })); + // } + // // Bad initialAmount + // if !proposed_terms + // .initial_amounts + // .gte(&min_terms.initial_amounts) + // { + // return Res::Fail(Fail::Suggestion(Req { + // initial_amounts: min_terms.initial_amounts, + // ..proposed_terms + // })); + // } + // // Bad response period + // if !proposed_terms + // .initial_amounts + // .gte(&min_terms.initial_amounts) + // { + // return Res::Fail(Fail::Suggestion(Req { + // initial_amounts: min_terms.initial_amounts, + // ..proposed_terms + // })); + // } + if min_terms.is_stricter(&proposed_terms) { + Res::Okay(min_terms.key) + } else { + Res::Fail(Fail::Other(Some("See terms".to_string()))) + } +} diff --git a/src/api/global/register.rs b/src/api/global/register.rs new file mode 100644 index 0000000..fd793c0 --- /dev/null +++ b/src/api/global/register.rs @@ -0,0 +1,23 @@ +use serde::{Deserialize, Serialize}; + +use crate::prelude::*; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct KeyCert { + pub l2_key: VerificationKey, + pub channel_id: ChannelId, + pub expire: Timestamp, + pub rank: Index, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct Req { + pub my: Signed, + pub your: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum Res { + Okay(Option>), + Fail, +} diff --git a/src/api/global/terms.rs b/src/api/global/terms.rs new file mode 100644 index 0000000..a05462f --- /dev/null +++ b/src/api/global/terms.rs @@ -0,0 +1,68 @@ +use crate::prelude::*; +use serde::{Deserialize, Serialize}; + +use super::common::{Capacity, InitialAmounts}; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum Config { + Static(Terms), +} + +impl Default for Config { + fn default() -> Self { + Config::Static(Terms::default()) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum Res { + Okay(Terms), + Fail, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct Terms { + pub currencies: Vec, + pub initial_amounts: InitialAmounts, + pub response_period: Milliseconds, + pub capacity: Capacity, + pub additional_terms: Markdown, +} + +impl Default for Terms { + fn default() -> Self { + Terms { + currencies: vec![ada_currency()], + initial_amounts: InitialAmounts::default(), + response_period: DAY, + capacity: Capacity::default(), + additional_terms: "".to_string(), + } + } +} + +impl Terms { + /// A channel adhering to `self` will necessarily adhere to other + pub fn is_stricter(&self, other: &Self) -> bool { + is_sublist(&self.currencies, &other.currencies) + && self.initial_amounts.gte(&other.initial_amounts) + && other.capacity.gte(&self.capacity) + } +} + +fn is_sublist(a: &Vec, b: &Vec) -> bool +where + T: Eq, +{ + a.iter().all(|x| b.iter().any(|y| x == y)) +} + +pub fn static_handle(terms: Terms) -> impl Fn() -> Res { + move || Res::Okay(terms.clone()) +} + +pub fn handler(c: Config) -> impl Fn() -> Res { + match c { + Config::Static(terms) => static_handle(terms), + } +} diff --git a/src/api/global/watch.rs b/src/api/global/watch.rs new file mode 100644 index 0000000..5f0cfa2 --- /dev/null +++ b/src/api/global/watch.rs @@ -0,0 +1,31 @@ +use serde::{Deserialize, Serialize}; + +use crate::prelude::*; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct Req { + pub l1_key: VerificationKey, + pub transaction_id: TransactionId, + pub output_index: Natural, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum Res { + Watching, + Confirming, + Rejected(RejectedMessage), + Confirmed, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum RejectedMessage { + Timeout, + FailsTerms, + BadKey, + Other(String), +} + +/// Mock response +pub fn just_confirm(_req: Req) -> Res { + Res::Confirmed +} diff --git a/src/arr.rs b/src/arr.rs index 952a8c3..63fbc74 100644 --- a/src/arr.rs +++ b/src/arr.rs @@ -1,3 +1,5 @@ +// I do not know the idiomatic rust way to go from vectors to fixed length arrays + pub fn arr32(b: Vec) -> anyhow::Result<[u8; 32]> { println!("{}", b.len()); b.try_into().map_err(|_| anyhow::anyhow!("bad input")) diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..2b97709 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,28 @@ +use anyhow::Result; +use serde::{Deserialize, Serialize}; +use std::io::Read; +use toml; + +use crate::api; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] +pub struct Config { + pub keys: String, + pub api: api::Config, + // db: db::Config, +} + +impl Config { + pub fn read(fp: &str) -> Result { + let mut file = std::fs::File::open(fp)?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + let c: Config = toml::from_str(&contents)?; + Ok(c) + } + + pub fn to_string(&self) -> Result { + let x = toml::to_string(&self)?; + Ok(x) + } +} diff --git a/src/lib.rs b/src/lib.rs index 7338f89..811081a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,8 @@ pub mod arr; -pub mod db; +pub mod prelude; +// pub mod db; +pub mod api; +pub mod config; pub mod hash; pub mod keys; -pub mod messages; -//pub mod protobuf; pub mod protocol; diff --git a/src/messages.rs b/src/messages.rs deleted file mode 100644 index ab95faf..0000000 --- a/src/messages.rs +++ /dev/null @@ -1,77 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct MyRequest { - pub key: [u8; 32], - pub body: Vec, - pub sig: Vec, // FIXME :: fixed length array not supported by serde [u8; 64], -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub enum MyResult { - Okay(MyResponse), - Fail(i64), -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct MyResponse { - // sig: [u8; 64], - pub sig: Vec, // FIXME :: fixed length array not supported by serde [u8; 64], -} - -// type TestnetMagic = i64; -// -// pub enum NetworkId { -// Mainnet, -// Testnet(TestnetMagic), -// } -// -// type Version = i64; -// -// type Blake2b224Hash = [u8; 24]; -// type ScriptHash = Blake2b224Hash; -// -// type TokenName = Vec; -// type Currency = (ScriptHash, TokenName); -// -// pub struct Init { -// version: Version, -// network_id: NetworkId, -// currencies: Vec, -// routing: bool, -// htlc: bool, -// } -// -// type Positive = i64; -// type Natural = i64; -// type Amount = Natural; -// type Markdown = String; -// type Milliseconds = Natural; -// -// type ChannelId = Vec; -// -// // type ChannelMessage = (ChannelId, msg) -// -// type VerificationKey = [u8; 32]; -// -// pub struct Open { -// currency: Currency, -// funding_amount: Amount, -// gift_amount: Amount, -// respond_period: Milliseconds, -// minimum_depth: Positive, -// max_htlc_amount: Amount, -// max_total_htlc_amount: Amount, -// max_htlc_count: Positive, -// verification_key: VerificationKey, -// } -// -// pub struct Accept { -// respond_period: Milliseconds, -// minimum_depth: Positive, -// min_htlc_amount: Amount, -// max_htlc_amount: Amount, -// max_total_htlc_amount: Amount, -// max_htlc_count: Positive, -// verification_key: VerificationKey, -// } diff --git a/src/ping.rs b/src/ping.rs deleted file mode 100644 index 86221e6..0000000 --- a/src/ping.rs +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -//! Integration tests for the `Behaviour`. - -use std::{io, iter}; - -use futures::prelude::*; -use libp2p::identity::PeerId; -use libp2p::request_response; -use libp2p::request_response::ProtocolSupport; -use libp2p::swarm::{StreamProtocol, Swarm, SwarmEvent}; -// use libp2p::swarm_test::SwarmExt; -use rand::Rng; -use serde::{Deserialize, Serialize}; -use tracing_subscriber::EnvFilter; - -async fn is_response_outbound() { - let _ = tracing_subscriber::fmt() - .with_env_filter(EnvFilter::from_default_env()) - .try_init(); - let ping = Ping("ping".to_string().into_bytes()); - let offline_peer = PeerId::random(); - - let mut swarm1 = Swarm::new_ephemeral(|_| { - request_response::cbor::Behaviour::::new( - [( - StreamProtocol::new("/ping/1"), - request_response::ProtocolSupport::Full, - )], - request_response::Config::default(), - ) - }); - - let request_id1 = swarm1 - .behaviour_mut() - .send_request(&offline_peer, ping.clone()); - - match swarm1 - .next_swarm_event() - .await - .try_into_behaviour_event() - .unwrap() - { - request_response::Event::OutboundFailure { - peer, - request_id: req_id, - error: _error, - .. - } => { - assert_eq!(&offline_peer, &peer); - assert_eq!(req_id, request_id1); - } - e => panic!("Peer: Unexpected event: {e:?}"), - } - - let request_id2 = swarm1.behaviour_mut().send_request(&offline_peer, ping); - - assert!(!swarm1 - .behaviour() - .is_pending_outbound(&offline_peer, &request_id1)); - assert!(swarm1 - .behaviour() - .is_pending_outbound(&offline_peer, &request_id2)); -} - -async fn ping_protocol() { - let ping = Ping("ping".to_string().into_bytes()); - let pong = Pong("pong".to_string().into_bytes()); - - let protocols = iter::once((StreamProtocol::new("/ping/1"), ProtocolSupport::Full)); - let cfg = request_response::Config::default(); - - let mut swarm1 = Swarm::new_ephemeral(|_| { - request_response::cbor::Behaviour::::new(protocols.clone(), cfg.clone()) - }); - let peer1_id = *swarm1.local_peer_id(); - let mut swarm2 = Swarm::new_ephemeral(|_| { - request_response::cbor::Behaviour::::new(protocols, cfg) - }); - let peer2_id = *swarm2.local_peer_id(); - - swarm1.listen().with_memory_addr_external().await; - swarm2.connect(&mut swarm1).await; - - let expected_ping = ping.clone(); - let expected_pong = pong.clone(); - - let peer1 = async move { - loop { - match swarm1.next_swarm_event().await.try_into_behaviour_event() { - Ok(request_response::Event::Message { - peer, - message: - request_response::Message::Request { - request, channel, .. - }, - .. - }) => { - assert_eq!(&request, &expected_ping); - assert_eq!(&peer, &peer2_id); - swarm1 - .behaviour_mut() - .send_response(channel, pong.clone()) - .unwrap(); - } - Ok(request_response::Event::ResponseSent { peer, .. }) => { - assert_eq!(&peer, &peer2_id); - } - Ok(e) => { - panic!("Peer1: Unexpected event: {e:?}") - } - Err(..) => {} - } - } - }; - - let num_pings: u8 = rand::thread_rng().gen_range(1..100); - - let peer2 = async { - let mut count = 0; - - let mut req_id = swarm2.behaviour_mut().send_request(&peer1_id, ping.clone()); - assert!(swarm2.behaviour().is_pending_outbound(&peer1_id, &req_id)); - - loop { - match swarm2 - .next_swarm_event() - .await - .try_into_behaviour_event() - .unwrap() - { - request_response::Event::Message { - peer, - message: - request_response::Message::Response { - request_id, - response, - }, - .. - } => { - count += 1; - assert_eq!(&response, &expected_pong); - assert_eq!(&peer, &peer1_id); - assert_eq!(req_id, request_id); - if count >= num_pings { - return; - } else { - req_id = swarm2.behaviour_mut().send_request(&peer1_id, ping.clone()); - } - } - e => panic!("Peer2: Unexpected event: {e:?}"), - } - } - }; - - async_std::task::spawn(Box::pin(peer1)); - peer2.await; -} - -async fn emits_inbound_connection_closed_failure() { - let ping = Ping("ping".to_string().into_bytes()); - - let protocols = iter::once((StreamProtocol::new("/ping/1"), ProtocolSupport::Full)); - let cfg = request_response::Config::default(); - - let mut swarm1 = Swarm::new_ephemeral(|_| { - request_response::cbor::Behaviour::::new(protocols.clone(), cfg.clone()) - }); - let peer1_id = *swarm1.local_peer_id(); - let mut swarm2 = Swarm::new_ephemeral(|_| { - request_response::cbor::Behaviour::::new(protocols, cfg) - }); - let peer2_id = *swarm2.local_peer_id(); - - swarm1.listen().with_memory_addr_external().await; - swarm2.connect(&mut swarm1).await; - - swarm2.behaviour_mut().send_request(&peer1_id, ping.clone()); - - // Wait for swarm 1 to receive request by swarm 2. - let _channel = loop { - futures::select!( - event = swarm1.select_next_some() => match event { - SwarmEvent::Behaviour(request_response::Event::Message { - peer, - message: request_response::Message::Request { request, channel, .. }, - .. - }) => { - assert_eq!(&request, &ping); - assert_eq!(&peer, &peer2_id); - break channel; - }, - SwarmEvent::Behaviour(ev) => panic!("Peer1: Unexpected event: {ev:?}"), - _ => {} - }, - event = swarm2.select_next_some() => { - if let SwarmEvent::Behaviour(ev) = event { - panic!("Peer2: Unexpected event: {ev:?}"); - } - } - ) - }; - - // Drop swarm 2 in order for the connection between swarm 1 and 2 to close. - drop(swarm2); - - loop { - match swarm1.select_next_some().await { - SwarmEvent::Behaviour(request_response::Event::InboundFailure { - error: request_response::InboundFailure::ConnectionClosed, - .. - }) => break, - SwarmEvent::Behaviour(e) => panic!("Peer1: Unexpected event: {e:?}"), - _ => {} - } - } -} - -/// We expect the substream to be properly closed when response channel is dropped. -/// Since the ping protocol used here expects a response, the sender considers this -/// early close as a protocol violation which results in the connection being closed. -/// If the substream were not properly closed when dropped, the sender would instead -/// run into a timeout waiting for the response. -async fn emits_inbound_connection_closed_if_channel_is_dropped() { - let ping = Ping("ping".to_string().into_bytes()); - - let protocols = iter::once((StreamProtocol::new("/ping/1"), ProtocolSupport::Full)); - let cfg = request_response::Config::default(); - - let mut swarm1 = Swarm::new_ephemeral(|_| { - request_response::cbor::Behaviour::::new(protocols.clone(), cfg.clone()) - }); - let peer1_id = *swarm1.local_peer_id(); - let mut swarm2 = Swarm::new_ephemeral(|_| { - request_response::cbor::Behaviour::::new(protocols, cfg) - }); - let peer2_id = *swarm2.local_peer_id(); - - swarm1.listen().with_memory_addr_external().await; - swarm2.connect(&mut swarm1).await; - - swarm2.behaviour_mut().send_request(&peer1_id, ping.clone()); - - // Wait for swarm 1 to receive request by swarm 2. - let event = loop { - futures::select!( - event = swarm1.select_next_some() => { - if let SwarmEvent::Behaviour(request_response::Event::Message { - peer, - message: request_response::Message::Request { request, channel, .. }, - .. - }) = event { - assert_eq!(&request, &ping); - assert_eq!(&peer, &peer2_id); - - drop(channel); - continue; - } - }, - event = swarm2.select_next_some() => { - if let SwarmEvent::Behaviour(ev) = event { - break ev; - } - }, - ) - }; - - let error = match event { - request_response::Event::OutboundFailure { error, .. } => error, - e => panic!("unexpected event from peer 2: {e:?}"), - }; - - assert!(matches!( - error, - request_response::OutboundFailure::Io(e) if e.kind() == io::ErrorKind::UnexpectedEof, - )); -} - -// Simple Ping-Pong Protocol -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -struct Ping(Vec); -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -struct Pong(Vec); diff --git a/src/prelude.rs b/src/prelude.rs new file mode 100644 index 0000000..dab7f97 --- /dev/null +++ b/src/prelude.rs @@ -0,0 +1,66 @@ +use anyhow::Result; +use serde::{Deserialize, Serialize}; + +/// Use integer incase we switch to i128 or otherwise. +pub type Integer = i64; + +/// Non negative integer including 0 +pub type Natural = u64; + +/// Suggestive of a positive integer. Note that this is not enforced at a type level. +pub type Positive = u64; + +/// A natural representing and `amount of currency` +pub type Amount = Natural; + +/// A natural representing an index of, say, a cheque or utxo. +pub type Index = Natural; + +/// A time length in milliseconds +pub type Milliseconds = Integer; + +/// Milliseconds since Epoch +pub type Timestamp = Natural; + +// Alias for bytes +pub type Blake2b256Hash = [u8; 32]; +pub type Blake2b224Hash = [u8; 28]; +pub type KeyHash = Blake2b224Hash; +pub type ScriptHash = Blake2b224Hash; +pub type TransactionId = Blake2b256Hash; +pub type AssetName = Vec; +pub type VerificationKey = [u8; 32]; +pub type Signature = [u8; 64]; +pub type ChannelId = [u8; 28]; + +pub type Currency = (ScriptHash, AssetName); + +/// To keep types consistent we denote the script hash of ada as `[0;28]`. +pub fn ada_currency() -> Currency { + ([0; 28], [0_u8; 0].to_vec()) +} + +pub type Markdown = String; +pub type Text = String; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct Signed { + body: T, + #[serde(with = "serde_arrays")] + signature: [u8; 64], +} + +pub const E3: Natural = 1000 as Natural; +pub const E6: Natural = E3 * E3; +pub const E9: Natural = E6 * E3; +pub const E12: Natural = E9 * E3; + +pub const SECOND: Milliseconds = 1000; +pub const MINUTE: Milliseconds = 60 * SECOND; +pub const HOUR: Milliseconds = 60 * MINUTE; +pub const DAY: Milliseconds = 24 * HOUR; + +pub fn time_add(a: Timestamp, b: Milliseconds) -> Result { + let x = Timestamp::try_from(a as i64 + b)?; + Ok(x) +} diff --git a/src/protobuf/messages.proto b/src/protobuf/messages.proto deleted file mode 100644 index ebd4095..0000000 --- a/src/protobuf/messages.proto +++ /dev/null @@ -1,25 +0,0 @@ -syntax="proto3"; -package messages; - -message SignRequest { - bytes vkey = 1; - bytes body = 2; - bytes sig = 3; -} - -message SignResponse { - oneof result { - Okay okay = 1; - Fail fail = 2; - } -} - -message Okay { - bytes sig = 1; -} - -enum Fail { - UnrecognisedKey = 1; - ExpiredKey = 2; - Other = 3; -} diff --git a/src/protobuf/messages.rs b/src/protobuf/messages.rs deleted file mode 100644 index 9f3d011..0000000 --- a/src/protobuf/messages.rs +++ /dev/null @@ -1,180 +0,0 @@ -// Automatically generated rust module for 'messages.proto' file - -#![allow(non_snake_case)] -#![allow(non_upper_case_globals)] -#![allow(non_camel_case_types)] -#![allow(unused_imports)] -#![allow(unknown_lints)] -#![allow(clippy::all)] -#![cfg_attr(rustfmt, rustfmt_skip)] - - -use std::borrow::Cow; -use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result}; -use quick_protobuf::sizeofs::*; -use super::*; - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum Fail { - UnrecognisedKey = 1, - ExpiredKey = 2, - Other = 3, -} - -impl Default for Fail { - fn default() -> Self { - Fail::UnrecognisedKey - } -} - -impl From for Fail { - fn from(i: i32) -> Self { - match i { - 1 => Fail::UnrecognisedKey, - 2 => Fail::ExpiredKey, - 3 => Fail::Other, - _ => Self::default(), - } - } -} - -impl<'a> From<&'a str> for Fail { - fn from(s: &'a str) -> Self { - match s { - "UnrecognisedKey" => Fail::UnrecognisedKey, - "ExpiredKey" => Fail::ExpiredKey, - "Other" => Fail::Other, - _ => Self::default(), - } - } -} - -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Debug, Default, PartialEq, Clone)] -pub struct SignRequest<'a> { - pub vkey: Cow<'a, [u8]>, - pub body: Cow<'a, [u8]>, - pub sig: Cow<'a, [u8]>, -} - -impl<'a> MessageRead<'a> for SignRequest<'a> { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(10) => msg.vkey = r.read_bytes(bytes).map(Cow::Borrowed)?, - Ok(18) => msg.body = r.read_bytes(bytes).map(Cow::Borrowed)?, - Ok(26) => msg.sig = r.read_bytes(bytes).map(Cow::Borrowed)?, - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), - } - } - Ok(msg) - } -} - -impl<'a> MessageWrite for SignRequest<'a> { - fn get_size(&self) -> usize { - 0 - + if self.vkey == Cow::Borrowed(b"") { 0 } else { 1 + sizeof_len((&self.vkey).len()) } - + if self.body == Cow::Borrowed(b"") { 0 } else { 1 + sizeof_len((&self.body).len()) } - + if self.sig == Cow::Borrowed(b"") { 0 } else { 1 + sizeof_len((&self.sig).len()) } - } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - if self.vkey != Cow::Borrowed(b"") { w.write_with_tag(10, |w| w.write_bytes(&**&self.vkey))?; } - if self.body != Cow::Borrowed(b"") { w.write_with_tag(18, |w| w.write_bytes(&**&self.body))?; } - if self.sig != Cow::Borrowed(b"") { w.write_with_tag(26, |w| w.write_bytes(&**&self.sig))?; } - Ok(()) - } -} - -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Debug, Default, PartialEq, Clone)] -pub struct SignResponse<'a> { - pub result: messages::mod_SignResponse::OneOfresult<'a>, -} - -impl<'a> MessageRead<'a> for SignResponse<'a> { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(10) => msg.result = messages::mod_SignResponse::OneOfresult::okay(r.read_message::(bytes)?), - Ok(16) => msg.result = messages::mod_SignResponse::OneOfresult::fail(r.read_enum(bytes)?), - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), - } - } - Ok(msg) - } -} - -impl<'a> MessageWrite for SignResponse<'a> { - fn get_size(&self) -> usize { - 0 - + match self.result { - messages::mod_SignResponse::OneOfresult::okay(ref m) => 1 + sizeof_len((m).get_size()), - messages::mod_SignResponse::OneOfresult::fail(ref m) => 1 + sizeof_varint(*(m) as u64), - messages::mod_SignResponse::OneOfresult::None => 0, - } } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - match self.result { messages::mod_SignResponse::OneOfresult::okay(ref m) => { w.write_with_tag(10, |w| w.write_message(m))? }, - messages::mod_SignResponse::OneOfresult::fail(ref m) => { w.write_with_tag(16, |w| w.write_enum(*m as i32))? }, - messages::mod_SignResponse::OneOfresult::None => {}, - } Ok(()) - } -} - -pub mod mod_SignResponse { - -use super::*; - -#[derive(Debug, PartialEq, Clone)] -pub enum OneOfresult<'a> { - okay(messages::Okay<'a>), - fail(messages::Fail), - None, -} - -impl<'a> Default for OneOfresult<'a> { - fn default() -> Self { - OneOfresult::None - } -} - -} - -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Debug, Default, PartialEq, Clone)] -pub struct Okay<'a> { - pub sig: Cow<'a, [u8]>, -} - -impl<'a> MessageRead<'a> for Okay<'a> { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(10) => msg.sig = r.read_bytes(bytes).map(Cow::Borrowed)?, - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), - } - } - Ok(msg) - } -} - -impl<'a> MessageWrite for Okay<'a> { - fn get_size(&self) -> usize { - 0 - + if self.sig == Cow::Borrowed(b"") { 0 } else { 1 + sizeof_len((&self.sig).len()) } - } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - if self.sig != Cow::Borrowed(b"") { w.write_with_tag(10, |w| w.write_bytes(&**&self.sig))?; } - Ok(()) - } -} - diff --git a/src/protobuf/mod.rs b/src/protobuf/mod.rs deleted file mode 100644 index 49c19b6..0000000 --- a/src/protobuf/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -// Automatically generated mod.rs -pub mod messages; diff --git a/src/protocol.rs b/src/protocol.rs index 60e2a73..ba532a3 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -8,12 +8,12 @@ use libp2p::{ }; use libp2p_identity::ed25519::Keypair; -use crate::messages::{MyRequest, MyResult}; +use crate::api::{Req, Res}; #[derive(NetworkBehaviour)] pub struct MyBehaviour { pub mdns: mdns::tokio::Behaviour, - pub req_res: request_response::cbor::Behaviour, + pub req_res: request_response::cbor::Behaviour, } pub fn mk_swarm( @@ -30,10 +30,9 @@ pub fn mk_swarm( .with_behaviour(|key| { let mdns = mdns::tokio::Behaviour::new(mdns::Config::default(), key.public().to_peer_id())?; - let protocol = [(StreamProtocol::new("/sign-me/1"), protocol_support)]; + let protocol = [(StreamProtocol::new("/cll2p/1"), protocol_support)]; let config = request_response::Config::default(); - let req_res = - request_response::cbor::Behaviour::::new(protocol, config); + let req_res = request_response::cbor::Behaviour::::new(protocol, config); Ok(MyBehaviour { req_res, mdns }) })? .with_swarm_config(|cfg| cfg.with_idle_connection_timeout(Duration::from_secs(u64::MAX)))