Compare commits
No commits in common. "aca2b9e8d5f086994ed75eb1e67c93ca7d738c4d" and "33b7dc5d8e76a6e8e762b003157e7dfe6062ec09" have entirely different histories.
aca2b9e8d5
...
33b7dc5d8e
|
@ -485,10 +485,8 @@ dependencies = [
|
||||||
"quick-protobuf",
|
"quick-protobuf",
|
||||||
"rand",
|
"rand",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_arrays",
|
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml",
|
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
]
|
]
|
||||||
|
@ -3057,15 +3055,6 @@ dependencies = [
|
||||||
"serde_derive",
|
"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]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.217"
|
version = "1.0.217"
|
||||||
|
@ -3089,15 +3078,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_spanned"
|
|
||||||
version = "0.6.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
|
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_urlencoded"
|
name = "serde_urlencoded"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
@ -3702,40 +3682,6 @@ dependencies = [
|
||||||
"tokio",
|
"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]]
|
[[package]]
|
||||||
name = "tower-service"
|
name = "tower-service"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
@ -4258,15 +4204,6 @@ version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winnow"
|
|
||||||
version = "0.7.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winreg"
|
name = "winreg"
|
||||||
version = "0.50.0"
|
version = "0.50.0"
|
||||||
|
|
|
@ -33,9 +33,7 @@ owo-colors = "4.1.0"
|
||||||
quick-protobuf = "0.8.1"
|
quick-protobuf = "0.8.1"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
serde = { version = "1.0.213", features = ["derive"] }
|
serde = { version = "1.0.213", features = ["derive"] }
|
||||||
serde_arrays = "0.1.0"
|
|
||||||
sqlx = { version = "0.8.2", features = ["sqlite", "macros", "runtime-tokio"] }
|
sqlx = { version = "0.8.2", features = ["sqlite", "macros", "runtime-tokio"] }
|
||||||
tokio = { version = "1.40.0", features = ["full", "tracing"] }
|
tokio = { version = "1.40.0", features = ["full", "tracing"] }
|
||||||
toml = "0.8.20"
|
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||||
|
|
187
README.md
187
README.md
|
@ -1,15 +1,9 @@
|
||||||
# CL L2 V0
|
# CL L2 V0
|
||||||
|
|
||||||
## Aims
|
This repo is a sandbox for the Cardano Lightning's L2 (V0).
|
||||||
|
|
||||||
This is a demo of a CL node that is able to:
|
A key aim of this repo is to try and assess available libraries in order to
|
||||||
|
establish our key dependencies.
|
||||||
- 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
|
## Setup
|
||||||
|
|
||||||
|
@ -27,35 +21,158 @@ Run binary `x`:
|
||||||
cargo run --bin <x>
|
cargo run --bin <x>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Current stack
|
There are three binaries:
|
||||||
|
|
||||||
- Comms stack : rust-libp2p
|
- `admin` - admin controls: create, add, revoke ephemeral keys
|
||||||
- Persistent storage : sqlx with sqlite
|
- `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.
|
||||||
|
|
||||||
## Design
|
## Design
|
||||||
|
|
||||||
See the design docs.
|
### Data
|
||||||
|
|
||||||
## TODO
|
#### Persistent keys
|
||||||
|
|
||||||
- [ ] api
|
These are the signing keys available to the machine and found at startup of the
|
||||||
- [ ] global
|
service.
|
||||||
- [ ] terms
|
|
||||||
- [x] simple
|
#### Ephemeral keys
|
||||||
- [ ] confer
|
|
||||||
- [x] simple
|
Perhaps also called proxy keys.
|
||||||
- [ ] watch
|
|
||||||
- [ ] register
|
An ephemeral key consists of the following properties:
|
||||||
- [ ] channel
|
|
||||||
- [ ] UNPACK
|
1. Verification key
|
||||||
- [ ] config
|
1. Persistent key
|
||||||
- [ ] UNPACK
|
1. Expires at
|
||||||
- [ ] storage
|
1. Signature
|
||||||
- [ ] ephemeral
|
|
||||||
- [ ] UNPACK
|
### Signing Server Actions
|
||||||
- [ ] persistent
|
|
||||||
- [ ] UNPACK
|
#### Add
|
||||||
- [ ] l1
|
|
||||||
- [ ] Mock
|
An add is performed by "admin" to create new ephemeral keys.
|
||||||
- [ ] UNPACK
|
|
||||||
- [ ] Via "kupmios"
|
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
|
||||||
|
|
216
app/admin.rs
216
app/admin.rs
|
@ -1,10 +1,9 @@
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
// use ed25519_dalek::{Signature, SigningKey};
|
use ed25519_dalek::{Signature, SigningKey};
|
||||||
|
|
||||||
use cll2v0::{
|
use cll2v0::{
|
||||||
// db,
|
db,
|
||||||
config,
|
keys::{self},
|
||||||
// keys::{self}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// cll2v0 is a playground for rust libraries.
|
/// cll2v0 is a playground for rust libraries.
|
||||||
|
@ -18,122 +17,117 @@ struct Args {
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
enum Command {
|
enum Command {
|
||||||
/// Generate a default config
|
/// Add new ephemeral key to an existing persistent key
|
||||||
GenConfig, // /// Add new ephemeral key to an existing persistent key
|
Add {
|
||||||
// Add {
|
ephemeral_key: String,
|
||||||
// ephemeral_key: String,
|
persistent_key: String,
|
||||||
// persistent_key: String,
|
expires_at: i64,
|
||||||
// expires_at: i64,
|
},
|
||||||
// },
|
/// Revoke an existing ephemeral key
|
||||||
// /// Revoke an existing ephemeral key
|
Revoke { ephemeral_key: String },
|
||||||
// Revoke { ephemeral_key: String },
|
/// Check persistent keys are available and display
|
||||||
// /// Check persistent keys are available and display
|
Check,
|
||||||
// Check,
|
/// Gen from seed some sensible ephemeral key args to be used with `add`
|
||||||
// /// Gen from seed some sensible ephemeral key args to be used with `add`
|
Gen { seed: u8 },
|
||||||
// Gen { seed: u8 },
|
/// Sign a message
|
||||||
// /// Sign a message
|
Sign {
|
||||||
// Sign {
|
signing_key: String,
|
||||||
// signing_key: String,
|
message: String,
|
||||||
// message: String,
|
},
|
||||||
// },
|
/// Verify a message
|
||||||
// /// Verify a message
|
Verify {
|
||||||
// Verify {
|
verifying_key: String,
|
||||||
// verifying_key: String,
|
message: String,
|
||||||
// message: String,
|
signature: String,
|
||||||
// signature: String,
|
},
|
||||||
// },
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main(flavor = "current_thread")]
|
#[tokio::main(flavor = "current_thread")]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
// let (_, pool) = db::start_db().await?;
|
let (_, pool) = db::start_db().await?;
|
||||||
|
|
||||||
match args.cmd {
|
match args.cmd {
|
||||||
Some(Command::GenConfig) => {
|
Some(Command::Add {
|
||||||
let c = config::Config::default().to_string()?;
|
ephemeral_key,
|
||||||
println!("{}", c);
|
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::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 => {
|
None => {
|
||||||
println!("See help");
|
println!("See help");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use ed25519_dalek::ed25519::signature::SignerMut;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use tokio::{io, io::AsyncBufReadExt, select};
|
use tokio::{io, io::AsyncBufReadExt, select};
|
||||||
|
|
||||||
|
@ -6,18 +7,20 @@ use libp2p::{
|
||||||
mdns,
|
mdns,
|
||||||
request_response::{self, ProtocolSupport},
|
request_response::{self, ProtocolSupport},
|
||||||
swarm::SwarmEvent,
|
swarm::SwarmEvent,
|
||||||
|
Multiaddr,
|
||||||
};
|
};
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
use cll2v0::{
|
use cll2v0::{
|
||||||
api, keys,
|
keys,
|
||||||
|
messages::MyRequest,
|
||||||
protocol::{mk_swarm, MyBehaviourEvent},
|
protocol::{mk_swarm, MyBehaviourEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
/// CLL2 client
|
/// cll2v0 is a playground for rust libraries.
|
||||||
/// Configured to act as a unpersistant node.
|
/// This is signing service.
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(arg_required_else_help(true), version, about)]
|
#[command(arg_required_else_help(true), version, about)]
|
||||||
struct Args {
|
struct Args {
|
||||||
|
@ -99,7 +102,11 @@ pub async fn start(params: ClientParams) -> Result<(), Box<dyn Error>> {
|
||||||
Ok(Some(line)) = stdin.next_line() => {
|
Ok(Some(line)) = stdin.next_line() => {
|
||||||
println!("MESSAGE: {}", line);
|
println!("MESSAGE: {}", line);
|
||||||
let bytes = line.into_bytes();
|
let bytes = line.into_bytes();
|
||||||
let req = api::Req::Global(api::global::Req::Terms) ;
|
let req = MyRequest {
|
||||||
|
key: keypair.clone().public().to_bytes(),
|
||||||
|
body: bytes.clone(),
|
||||||
|
sig: keys::sign(&mut key.clone(), bytes).to_vec(),
|
||||||
|
};
|
||||||
println!("REQ : {:?}", req);
|
println!("REQ : {:?}", req);
|
||||||
swarm.behaviour_mut().req_res.send_request(
|
swarm.behaviour_mut().req_res.send_request(
|
||||||
&server_peer_id,
|
&server_peer_id,
|
||||||
|
@ -141,14 +148,7 @@ pub async fn start(params: ClientParams) -> Result<(), Box<dyn Error>> {
|
||||||
message: libp2p::request_response::Message::Response { response, .. },
|
message: libp2p::request_response::Message::Response { response, .. },
|
||||||
})) => {
|
})) => {
|
||||||
// println!("response : {:?} {:?} {:?}", peer, request_id, "" );
|
// println!("response : {:?} {:?} {:?}", peer, request_id, "" );
|
||||||
match response {
|
println!("RESSIG : {}", hex::encode(response.sig.clone()),);
|
||||||
api::Res::Global(api::global::Res::Terms(api::global::terms::Res::Okay(terms))) => {
|
|
||||||
println!("TERMS :: OKAY : {:?}", terms);
|
|
||||||
}
|
|
||||||
res => {
|
|
||||||
println!("FAIL : {:?}", res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
e => {
|
e => {
|
||||||
println!("OTHER {:?}", e)
|
println!("OTHER {:?}", e)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
|
use ed25519_dalek::{ed25519::signature::SignerMut, Signature};
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use libp2p::{
|
use libp2p::{
|
||||||
mdns,
|
mdns,
|
||||||
|
@ -9,7 +10,8 @@ use libp2p::{
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
use cll2v0::{
|
use cll2v0::{
|
||||||
api, config, keys,
|
db, keys,
|
||||||
|
messages::{MyRequest, MyResponse},
|
||||||
protocol::{mk_swarm, MyBehaviourEvent},
|
protocol::{mk_swarm, MyBehaviourEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,9 +34,6 @@ enum Command {
|
||||||
|
|
||||||
#[derive(clap::Args, Debug)]
|
#[derive(clap::Args, Debug)]
|
||||||
pub struct ServerParams {
|
pub struct ServerParams {
|
||||||
/// Config file
|
|
||||||
#[arg(long, default_value = "./config.toml")]
|
|
||||||
pub config: String,
|
|
||||||
/// Server listening address
|
/// Server listening address
|
||||||
#[arg(long, default_value = "/ip4/0.0.0.0/tcp/52321")]
|
#[arg(long, default_value = "/ip4/0.0.0.0/tcp/52321")]
|
||||||
pub listen_on: String,
|
pub listen_on: String,
|
||||||
|
@ -61,14 +60,9 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
|
||||||
pub async fn start(params: ServerParams) -> Result<(), Box<dyn Error>> {
|
pub async fn start(params: ServerParams) -> Result<(), Box<dyn Error>> {
|
||||||
let ServerParams {
|
let ServerParams {
|
||||||
config: config_path,
|
|
||||||
skey: skey_hex,
|
skey: skey_hex,
|
||||||
listen_on,
|
listen_on,
|
||||||
} = params;
|
} = params;
|
||||||
|
|
||||||
let c = config::Config::read(&config_path)?;
|
|
||||||
println!("CONFIG ");
|
|
||||||
println!("{:?}", c);
|
|
||||||
if true {
|
if true {
|
||||||
let _ = tracing_subscriber::fmt()
|
let _ = tracing_subscriber::fmt()
|
||||||
.with_env_filter(EnvFilter::from_default_env())
|
.with_env_filter(EnvFilter::from_default_env())
|
||||||
|
@ -78,7 +72,7 @@ pub async fn start(params: ServerParams) -> Result<(), Box<dyn Error>> {
|
||||||
let peer_id = libp2p_identity::PublicKey::from(keypair.public()).to_peer_id();
|
let peer_id = libp2p_identity::PublicKey::from(keypair.public()).to_peer_id();
|
||||||
println!("PEER_ID : {}", 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)?;
|
let mut swarm = mk_swarm(&keypair.clone().into(), ProtocolSupport::Inbound)?;
|
||||||
swarm.listen_on(listen_on.parse()?)?;
|
swarm.listen_on(listen_on.parse()?)?;
|
||||||
|
@ -99,18 +93,33 @@ pub async fn start(params: ServerParams) -> Result<(), Box<dyn Error>> {
|
||||||
request, channel, ..
|
request, channel, ..
|
||||||
},
|
},
|
||||||
})) => {
|
})) => {
|
||||||
let res = match request {
|
// println!("Req : {:?} {:?} {:?}", peer, channel, hex::encode(request.body.clone()), );
|
||||||
api::Req::Global(api::global::Req::Terms) => {
|
println!("REQSIG : {}", hex::encode(request.sig.clone()),);
|
||||||
api::Res::Global(api::global::Res::Terms(api::global::terms::Res::Okay(
|
let MyRequest { key, body, sig } = request;
|
||||||
api::global::terms::Terms::default(),
|
|
||||||
)))
|
// FIXME :: MAP ERROR.
|
||||||
}
|
let sig_arr: [u8; 64] = sig.clone().try_into().unwrap();
|
||||||
api::Req::Channel => todo!("Not yet implemented"),
|
|
||||||
_ => api::Res::Global(api::global::Res::Terms(api::global::terms::Res::Okay(
|
if let Ok(ekey) = keys::from_bytes(key.into()) {
|
||||||
api::global::terms::Terms::default(),
|
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,
|
||||||
|
MyResponse {
|
||||||
|
sig: skey.clone().sign(&body).to_bytes().into(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!("err0")
|
||||||
};
|
};
|
||||||
let _ = swarm.behaviour_mut().req_res.send_response(channel, res);
|
} else {
|
||||||
|
println!("err1");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("err2");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
e => {
|
e => {
|
||||||
println!("OTHER {:?}", e)
|
println!("OTHER {:?}", e)
|
||||||
|
|
22
config.toml
22
config.toml
|
@ -1,22 +0,0 @@
|
||||||
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
21
src/api.rs
|
@ -1,21 +0,0 @@
|
||||||
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,
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
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),
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
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())))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
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,
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
|
@ -1,5 +1,3 @@
|
||||||
// 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]> {
|
pub fn arr32(b: Vec<u8>) -> anyhow::Result<[u8; 32]> {
|
||||||
println!("{}", b.len());
|
println!("{}", b.len());
|
||||||
b.try_into().map_err(|_| anyhow::anyhow!("bad input"))
|
b.try_into().map_err(|_| anyhow::anyhow!("bad input"))
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +1,7 @@
|
||||||
pub mod arr;
|
pub mod arr;
|
||||||
pub mod prelude;
|
pub mod db;
|
||||||
// pub mod db;
|
|
||||||
pub mod api;
|
|
||||||
pub mod config;
|
|
||||||
pub mod hash;
|
pub mod hash;
|
||||||
pub mod keys;
|
pub mod keys;
|
||||||
|
pub mod messages;
|
||||||
|
//pub mod protobuf;
|
||||||
pub mod protocol;
|
pub mod protocol;
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
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 struct MyResponse {
|
||||||
|
// sig: [u8; 64],
|
||||||
|
pub sig: Vec<u8>, // FIXME :: fixed length array not supported by serde [u8; 64],
|
||||||
|
}
|
|
@ -0,0 +1,301 @@
|
||||||
|
// 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>);
|
|
@ -1,66 +0,0 @@
|
||||||
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)
|
|
||||||
}
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
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;
|
||||||
|
}
|
|
@ -0,0 +1,180 @@
|
||||||
|
// 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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
// Automatically generated mod.rs
|
||||||
|
pub mod messages;
|
|
@ -8,12 +8,12 @@ use libp2p::{
|
||||||
};
|
};
|
||||||
use libp2p_identity::ed25519::Keypair;
|
use libp2p_identity::ed25519::Keypair;
|
||||||
|
|
||||||
use crate::api::{Req, Res};
|
use crate::messages::{MyRequest, MyResponse};
|
||||||
|
|
||||||
#[derive(NetworkBehaviour)]
|
#[derive(NetworkBehaviour)]
|
||||||
pub struct MyBehaviour {
|
pub struct MyBehaviour {
|
||||||
pub mdns: mdns::tokio::Behaviour,
|
pub mdns: mdns::tokio::Behaviour,
|
||||||
pub req_res: request_response::cbor::Behaviour<Req, Res>,
|
pub req_res: request_response::cbor::Behaviour<MyRequest, MyResponse>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mk_swarm(
|
pub fn mk_swarm(
|
||||||
|
@ -30,9 +30,10 @@ pub fn mk_swarm(
|
||||||
.with_behaviour(|key| {
|
.with_behaviour(|key| {
|
||||||
let mdns =
|
let mdns =
|
||||||
mdns::tokio::Behaviour::new(mdns::Config::default(), key.public().to_peer_id())?;
|
mdns::tokio::Behaviour::new(mdns::Config::default(), key.public().to_peer_id())?;
|
||||||
let protocol = [(StreamProtocol::new("/cll2p/1"), protocol_support)];
|
let protocol = [(StreamProtocol::new("/sign-me/1"), protocol_support)];
|
||||||
let config = request_response::Config::default();
|
let config = request_response::Config::default();
|
||||||
let req_res = request_response::cbor::Behaviour::<Req, Res>::new(protocol, config);
|
let req_res =
|
||||||
|
request_response::cbor::Behaviour::<MyRequest, MyResponse>::new(protocol, config);
|
||||||
Ok(MyBehaviour { req_res, mdns })
|
Ok(MyBehaviour { req_res, mdns })
|
||||||
})?
|
})?
|
||||||
.with_swarm_config(|cfg| cfg.with_idle_connection_timeout(Duration::from_secs(u64::MAX)))
|
.with_swarm_config(|cfg| cfg.with_idle_connection_timeout(Duration::from_secs(u64::MAX)))
|
||||||
|
|
Loading…
Reference in New Issue