This commit is contained in:
waalge 2025-03-14 16:45:13 +00:00
parent 4183fe6ec8
commit aca2b9e8d5
24 changed files with 659 additions and 893 deletions

63
Cargo.lock generated
View File

@ -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"

View File

@ -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"] }

187
README.md
View File

@ -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 <x>
```
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"

View File

@ -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");
}

View File

@ -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<dyn Error>> {
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<dyn Error>> {
})) => {
// 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);
}
}
}

View File

@ -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<dyn Error>> {
pub async fn start(params: ServerParams) -> Result<(), Box<dyn Error>> {
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<dyn Error>> {
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<dyn Error>> {
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")
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(),
))),
};
} else {
println!("err1");
}
} else {
println!("err2");
}
}
let _ = swarm.behaviour_mut().req_res.send_response(channel, res);
}
e => {
println!("OTHER {:?}", e)

22
config.toml Normal file
View File

@ -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

21
src/api.rs Normal file
View File

@ -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,
}

28
src/api/global.rs Normal file
View File

@ -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),
}

51
src/api/global/common.rs Normal file
View File

@ -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
}
}

71
src/api/global/confer.rs Normal file
View File

@ -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<Text>),
}
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())))
}
}

View File

@ -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<KeyCert>,
pub your: Option<KeyCert>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Res {
Okay(Option<Signed<KeyCert>>),
Fail,
}

68
src/api/global/terms.rs Normal file
View File

@ -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<Currency>,
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<T>(a: &Vec<T>, b: &Vec<T>) -> 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),
}
}

31
src/api/global/watch.rs Normal file
View File

@ -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
}

View File

@ -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<u8>) -> anyhow::Result<[u8; 32]> {
println!("{}", b.len());
b.try_into().map_err(|_| anyhow::anyhow!("bad input"))

28
src/config.rs Normal file
View File

@ -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<Self> {
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<String> {
let x = toml::to_string(&self)?;
Ok(x)
}
}

View File

@ -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;

View File

@ -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<u8>,
pub sig: Vec<u8>, // 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<u8>, // 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<u8>;
// type Currency = (ScriptHash, TokenName);
//
// pub struct Init {
// version: Version,
// network_id: NetworkId,
// currencies: Vec<Currency>,
// routing: bool,
// htlc: bool,
// }
//
// type Positive = i64;
// type Natural = i64;
// type Amount = Natural;
// type Markdown = String;
// type Milliseconds = Natural;
//
// type ChannelId = Vec<u8>;
//
// // type ChannelMessage<msg> = (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,
// }

View File

@ -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::<Ping, Pong>::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::<Ping, Pong>::new(protocols.clone(), cfg.clone())
});
let peer1_id = *swarm1.local_peer_id();
let mut swarm2 = Swarm::new_ephemeral(|_| {
request_response::cbor::Behaviour::<Ping, Pong>::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::<Ping, Pong>::new(protocols.clone(), cfg.clone())
});
let peer1_id = *swarm1.local_peer_id();
let mut swarm2 = Swarm::new_ephemeral(|_| {
request_response::cbor::Behaviour::<Ping, Pong>::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::<Ping, Pong>::new(protocols.clone(), cfg.clone())
});
let peer1_id = *swarm1.local_peer_id();
let mut swarm2 = Swarm::new_ephemeral(|_| {
request_response::cbor::Behaviour::<Ping, Pong>::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<u8>);
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
struct Pong(Vec<u8>);

66
src/prelude.rs Normal file
View File

@ -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<u8>;
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<T> {
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<Timestamp> {
let x = Timestamp::try_from(a as i64 + b)?;
Ok(x)
}

View File

@ -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;
}

View File

@ -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<i32> 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<Self> {
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<W: WriterBackend>(&self, w: &mut Writer<W>) -> 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<Self> {
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::<messages::Okay>(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<W: WriterBackend>(&self, w: &mut Writer<W>) -> 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<Self> {
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<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if self.sig != Cow::Borrowed(b"") { w.write_with_tag(10, |w| w.write_bytes(&**&self.sig))?; }
Ok(())
}
}

View File

@ -1,2 +0,0 @@
// Automatically generated mod.rs
pub mod messages;

View File

@ -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<MyRequest, MyResult>,
pub req_res: request_response::cbor::Behaviour<Req, Res>,
}
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::<MyRequest, MyResult>::new(protocol, config);
let req_res = request_response::cbor::Behaviour::<Req, Res>::new(protocol, config);
Ok(MyBehaviour { req_res, mdns })
})?
.with_swarm_config(|cfg| cfg.with_idle_connection_timeout(Duration::from_secs(u64::MAX)))