Skip to content

Commit 100b267

Browse files
authored
Merge pull request #14 from LFDT-Lockness/impr-sim
Improve simulation UX
2 parents a7f14b2 + f6f44d3 commit 100b267

File tree

24 files changed

+1340
-679
lines changed

24 files changed

+1340
-679
lines changed

.github/workflows/rust.yml

+10
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ jobs:
3737
- name: cargo check
3838
run: cargo check -p round-based --all-features
3939

40+
test:
41+
runs-on: ubuntu-latest
42+
steps:
43+
- uses: actions/checkout@v3
44+
- uses: Swatinem/rust-cache@v2
45+
with:
46+
cache-on-failure: "true"
47+
- name: cargo test
48+
run: cargo test --all-features
49+
4050
check-fmt:
4151
runs-on: ubuntu-latest
4252
steps:

Cargo.lock

+25-29
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,12 @@ the documentation of the protocol you're using), but usually they are:
3535

3636
## Features
3737

38-
* `dev` enables development tools such as protocol simulation
38+
* `sim` enables protocol execution simulation, see `sim` module
39+
* `sim-async` enables protocol execution simulation with tokio runtime, see `sim::async_env`
40+
module
41+
* `state-machine` provides ability to carry out the protocol, defined as async function, via Sync
42+
API, see `state_machine` module
43+
* `derive` is needed to use `ProtocolMessage` proc macro
3944
* `runtime-tokio` enables tokio-specific implementation of async runtime
4045

4146
## Join us in Discord!

examples/random-generation-protocol/Cargo.toml

+2-6
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,15 @@ rand_core = { version = "0.6", default-features = false }
1313
sha2 = { version = "0.10", default-features = false }
1414
serde = { version = "1", default-features = false, features = ["derive"] }
1515

16-
displaydoc = { version = "0.2", default-features = false }
17-
thiserror = { version = "1", optional = true }
16+
thiserror = { version = "2", default-features = false }
1817

1918
# We don't use it directy, but we need to enable `serde` feature
2019
generic-array = { version = "0.14", features = ["serde"] }
2120

2221
[dev-dependencies]
23-
round-based = { path = "../../round-based", features = ["derive", "dev", "state-machine"] }
22+
round-based = { path = "../../round-based", features = ["derive", "sim", "state-machine"] }
2423
tokio = { version = "1.15", features = ["macros", "rt"] }
25-
futures = "0.3"
2624
hex = "0.4"
2725
rand_dev = "0.1"
2826
rand = "0.8"
2927

30-
[features]
31-
std = ["thiserror"]

examples/random-generation-protocol/src/lib.rs

+35-53
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
#![no_std]
44
#![forbid(unused_crate_dependencies, missing_docs)]
55

6-
#[cfg(any(feature = "std", test))]
6+
#[cfg(test)]
77
extern crate std;
88

99
extern crate alloc;
1010

1111
mod _unused_deps {
12-
// We don't use it directy, but we need to enable `serde` feature
12+
// We don't use it directly, but we need to enable `serde` feature
1313
use generic_array as _;
1414
}
1515

@@ -132,28 +132,23 @@ where
132132
}
133133

134134
/// Protocol error
135-
#[derive(Debug, displaydoc::Display)]
136-
#[cfg_attr(feature = "std", derive(thiserror::Error))]
135+
#[derive(Debug, thiserror::Error)]
137136
pub enum Error<RecvErr, SendErr> {
138137
/// Couldn't send a message in the first round
139-
#[displaydoc("send a message at round 1")]
140-
Round1Send(#[cfg_attr(feature = "std", source)] SendErr),
138+
#[error("send a message at round 1")]
139+
Round1Send(#[source] SendErr),
141140
/// Couldn't receive a message in the first round
142-
#[displaydoc("receive messages at round 1")]
143-
Round1Receive(
144-
#[cfg_attr(feature = "std", source)] CompleteRoundError<RoundInputError, RecvErr>,
145-
),
141+
#[error("receive messages at round 1")]
142+
Round1Receive(#[source] CompleteRoundError<RoundInputError, RecvErr>),
146143
/// Couldn't send a message in the second round
147-
#[displaydoc("send a message at round 2")]
148-
Round2Send(#[cfg_attr(feature = "std", source)] SendErr),
144+
#[error("send a message at round 2")]
145+
Round2Send(#[source] SendErr),
149146
/// Couldn't receive a message in the second round
150-
#[displaydoc("receive messages at round 2")]
151-
Round2Receive(
152-
#[cfg_attr(feature = "std", source)] CompleteRoundError<RoundInputError, RecvErr>,
153-
),
147+
#[error("receive messages at round 2")]
148+
Round2Receive(#[source] CompleteRoundError<RoundInputError, RecvErr>),
154149

155150
/// Some of the parties cheated
156-
#[displaydoc("malicious parties: {guilty_parties:?}")]
151+
#[error("malicious parties: {guilty_parties:?}")]
157152
PartiesOpenedRandomnessDoesntMatchCommitment {
158153
/// List of cheated parties
159154
guilty_parties: Vec<Blame>,
@@ -173,56 +168,43 @@ pub struct Blame {
173168

174169
#[cfg(test)]
175170
mod tests {
176-
use alloc::{vec, vec::Vec};
177-
178171
use rand::Rng;
179-
use round_based::simulation::Simulation;
180172
use sha2::{Digest, Sha256};
181173

182-
use super::{protocol_of_random_generation, Msg};
174+
use super::protocol_of_random_generation;
183175

184-
#[tokio::test]
185-
async fn simulation_async() {
176+
#[test]
177+
fn simulation() {
186178
let mut rng = rand_dev::DevRng::new();
187179

188180
let n: u16 = 5;
189181

190-
let mut simulation = Simulation::<Msg>::new();
191-
let mut party_output = vec![];
192-
193-
for i in 0..n {
194-
let party = simulation.add_party();
195-
let output = protocol_of_random_generation(party, i, n, rng.fork());
196-
party_output.push(output);
197-
}
198-
199-
let output = futures::future::try_join_all(party_output).await.unwrap();
200-
201-
// Assert that all parties outputed the same randomness
202-
for i in 1..n {
203-
assert_eq!(output[0], output[usize::from(i)]);
204-
}
182+
let randomness = round_based::sim::run_with_setup(
183+
core::iter::repeat_with(|| rng.fork()).take(n.into()),
184+
|i, party, rng| protocol_of_random_generation(party, i, n, rng),
185+
)
186+
.unwrap()
187+
.expect_ok()
188+
.expect_eq();
205189

206-
std::println!("Output randomness: {}", hex::encode(output[0]));
190+
std::println!("Output randomness: {}", hex::encode(randomness));
207191
}
208192

209-
#[test]
210-
fn simulation_sync() {
193+
#[tokio::test]
194+
async fn simulation_async() {
211195
let mut rng = rand_dev::DevRng::new();
212196

213-
let simulation = round_based::simulation::SimulationSync::from_async_fn(5, |i, party| {
214-
protocol_of_random_generation(party, i, 5, rng.fork())
215-
});
197+
let n: u16 = 5;
216198

217-
let outputs = simulation
218-
.run()
219-
.unwrap()
220-
.into_iter()
221-
.collect::<Result<Vec<_>, _>>()
222-
.unwrap();
223-
for output_i in &outputs {
224-
assert_eq!(*output_i, outputs[0]);
225-
}
199+
let randomness = round_based::sim::async_env::run_with_setup(
200+
core::iter::repeat_with(|| rng.fork()).take(n.into()),
201+
|i, party, rng| protocol_of_random_generation(party, i, n, rng),
202+
)
203+
.await
204+
.expect_ok()
205+
.expect_eq();
206+
207+
std::println!("Output randomness: {}", hex::encode(randomness));
226208
}
227209

228210
// Emulate the protocol using the state machine interface

round-based/CHANGELOG.md

+31
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,34 @@
1+
## v0.4.0
2+
* BREAKING: Improve ergonomics of protocol simulation, which is used for writing tests [#14]
3+
* Remove `dev` feature, it's replaced with `sim` and `sim-async`
4+
* `round_based::simulation` module is renamed into `round_based::sim`
5+
* `round_based::simulation::Simulation` is renamed and moved to `round_based::sim::async_env::Network`
6+
* Other async simulated network related types are moved to `round_based::sim::async_env`
7+
* Added convenient `round_based::sim::{run, run_with_setup}` which make simulation very ergonomic
8+
* Simulation outputs `round_based::sim::SimResult`, which has convenient most-common methods:
9+
* `.expect_ok()` that unwraps all results, and if any party returned an error, panics with a verbose
10+
error message
11+
* `.expect_eq()` that checks that all outputs are equally the same
12+
* When `sim-async` feature is enabled, you can use `round_based::sim::async_env::{run, run_with_setup, ...}`,
13+
but typically you don't want to use them
14+
* `round_based::simulation::SimulationSync` has been renamed to `round_based::sim::Simulation`
15+
* Use `core::error::Error` trait which is now always implemented for all errors regardless whether `std` feature
16+
is enabled or not [#14]
17+
* Update `thiserror` dependency to v2
18+
* BREAKING: remove `std` feature, as the crate is fully no_std now
19+
20+
Migration guidelines:
21+
* Replace `dev` feature with `sim`
22+
* Instead of using `round_based::simulation::Simulation` from previous version, use
23+
`round_based::simulation::{run, run_with_setup}`
24+
* Take advantage of `SimResult::{expect_ok, expect_eq}` to reduce amount of the code
25+
in your tests
26+
* Remove `std` feature, if it was explicitly enabled
27+
28+
Other than simulation, there are no breaking changes in this release.
29+
30+
[#14]: https://github.com/LFDT-Lockness/round-based/pull/14
31+
132
## v0.3.2
233
* Update links in crate settings, update readme [#11]
334

0 commit comments

Comments
 (0)