Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testgen external commands #549

Merged
merged 20 commits into from
Sep 11, 2020
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
3dcb316
#414: testgen tester -- utilities to run multiple tests with logs and…
andrey-kuprianov Sep 2, 2020
b5853ca
14: add testgen commands, in particular to call apalache and jsonatr
andrey-kuprianov Sep 2, 2020
29807a4
#547 add missing file updates from #529
andrey-kuprianov Sep 4, 2020
969ec0d
Merge branch 'master' into andrey/mbt-testgen-tester
andrey-kuprianov Sep 4, 2020
f95a8c9
fix merge typo
andrey-kuprianov Sep 4, 2020
d75346a
Merge branch 'andrey/mbt-testgen-tester' into andrey/mbt-testgen-comm…
andrey-kuprianov Sep 4, 2020
9d4531a
remove ref to time: it's in another PR
andrey-kuprianov Sep 4, 2020
4df1e28
fix clippy warning
andrey-kuprianov Sep 4, 2020
25bf098
TestEnv: change path parameters into AsRef<Path>
andrey-kuprianov Sep 10, 2020
7aed5a7
change TestEnv::full_path to return PathBuf
andrey-kuprianov Sep 10, 2020
45f4068
apply simplifications suggested by Romain
andrey-kuprianov Sep 10, 2020
be80b4c
apply simplification from Romain
andrey-kuprianov Sep 10, 2020
9e0c106
account for WOW Romain's suggestion on RefUnwindSafe
andrey-kuprianov Sep 10, 2020
429d8d9
address Romain's suggestion on TestEnv::cleanup
andrey-kuprianov Sep 10, 2020
4fae027
Merge branch 'master' into andrey/mbt-testgen-tester
andrey-kuprianov Sep 10, 2020
184bfd3
cargo clippy
andrey-kuprianov Sep 10, 2020
d8a55d9
update CHANGELOG.md
andrey-kuprianov Sep 10, 2020
85de97a
Merge branch 'andrey/mbt-testgen-tester' into andrey/mbt-testgen-comm…
andrey-kuprianov Sep 10, 2020
51dd975
Merge branch 'master' into andrey/mbt-testgen-commandds
andrey-kuprianov Sep 11, 2020
918b899
addressed Romains's suggestions
andrey-kuprianov Sep 11, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions light-client/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ use tendermint_rpc as rpc;

use crate::components::clock::Clock;
use crate::components::io::{AtHeight, Io, IoError};
use crate::components::verifier::{ProdVerifier, Verdict, Verifier};
use crate::errors::Error;
use crate::evidence::EvidenceReporter;
use crate::light_client::{LightClient, Options};
use crate::state::State;
use contracts::contract_trait;
use std::collections::HashMap;
use std::time::Duration;
use tendermint::block::Height as HeightStr;
use tendermint::evidence::{Duration as DurationStr, Evidence};

Expand Down Expand Up @@ -148,6 +153,47 @@ impl MockEvidenceReporter {
}
}

pub fn verify_single(
trusted_state: Trusted,
input: LightBlock,
trust_threshold: TrustThreshold,
trusting_period: Duration,
clock_drift: Duration,
now: Time,
) -> Result<LightBlock, Verdict> {
let verifier = ProdVerifier::default();

let trusted_state = LightBlock::new(
trusted_state.signed_header,
trusted_state.next_validators.clone(),
trusted_state.next_validators,
default_peer_id(),
);

let options = Options {
trust_threshold,
trusting_period,
clock_drift,
};

let result = verifier.verify(&input, &trusted_state, &options, now);

match result {
Verdict::Success => Ok(input),
error => Err(error),
}
}

pub fn verify_bisection(
untrusted_height: Height,
light_client: &mut LightClient,
state: &mut State,
) -> Result<Vec<LightBlock>, Error> {
light_client
.verify_to_target(untrusted_height, state)
.map(|_| state.get_trace(untrusted_height))
}

// -----------------------------------------------------------------------------
// Everything below is a temporary workaround for the lack of `provider` field
// in the light blocks serialized in the JSON fixtures.
Expand Down
53 changes: 6 additions & 47 deletions light-client/tests/light_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ use tendermint_light_client::{
components::{
io::{AtHeight, Io},
scheduler,
verifier::{ProdVerifier, Verdict, Verifier},
verifier::ProdVerifier,
},
errors::{Error, ErrorKind},
light_client::{LightClient, Options},
state::State,
store::{memory::MemoryStore, LightStore},
tests::{Trusted, *},
types::{Height, LightBlock, Status, Time, TrustThreshold},
types::{LightBlock, Status, TrustThreshold},
};

use tendermint_testgen::Tester;
Expand All @@ -21,47 +21,6 @@ use tendermint_testgen::Tester;
// https://github.com/informalsystems/conformance-tests
const TEST_FILES_PATH: &str = "./tests/support/";

fn verify_single(
trusted_state: Trusted,
input: LightBlock,
trust_threshold: TrustThreshold,
trusting_period: Duration,
clock_drift: Duration,
now: Time,
) -> Result<LightBlock, Verdict> {
let verifier = ProdVerifier::default();

let trusted_state = LightBlock::new(
trusted_state.signed_header,
trusted_state.next_validators.clone(),
trusted_state.next_validators,
default_peer_id(),
);

let options = Options {
trust_threshold,
trusting_period,
clock_drift,
};

let result = verifier.verify(&input, &trusted_state, &options, now);

match result {
Verdict::Success => Ok(input),
error => Err(error),
}
}

fn verify_bisection(
untrusted_height: Height,
light_client: &mut LightClient,
state: &mut State,
) -> Result<Vec<LightBlock>, Error> {
light_client
.verify_to_target(untrusted_height, state)
.map(|_| state.get_trace(untrusted_height))
}

struct BisectionTestResult {
untrusted_light_block: LightBlock,
new_states: Result<Vec<LightBlock>, Error>,
Expand Down Expand Up @@ -229,17 +188,17 @@ fn bisection_lower_test(tc: TestBisection<AnonLightBlock>) {

#[test]
fn run_single_step_tests() {
let mut tester = Tester::new(TEST_FILES_PATH);
let mut tester = Tester::new("single_step", TEST_FILES_PATH);
tester.add_test("single-step test", single_step_test);
tester.run_foreach_in_dir("single_step");
tester.print_results();
tester.finalize();
}

#[test]
fn run_bisection_tests() {
let mut tester = Tester::new(TEST_FILES_PATH);
let mut tester = Tester::new("bisection", TEST_FILES_PATH);
tester.add_test("bisection test", bisection_test);
tester.add_test("bisection lower test", bisection_lower_test);
tester.run_foreach_in_dir("bisection/single_peer");
tester.print_results();
tester.finalize();
}
4 changes: 2 additions & 2 deletions light-client/tests/supervisor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ fn run_multipeer_test(tc: TestBisection<AnonLightBlock>) {

#[test]
fn run_multipeer_tests() {
let mut tester = Tester::new(TEST_FILES_PATH);
let mut tester = Tester::new("bisection_multi_peer", TEST_FILES_PATH);
tester.add_test("multipeer test", run_multipeer_test);
tester.run_foreach_in_dir("bisection/multi_peer");
tester.print_results();
tester.finalize();
}
1 change: 1 addition & 0 deletions testgen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ serde_json = "1"
ed25519-dalek = "1"
gumdrop = "0.8.0"
simple-error = "0.2.1"
tempfile = "3.1.0"

[[bin]]
name = "tendermint-testgen"
Expand Down
150 changes: 150 additions & 0 deletions testgen/jsonatr-lib/apalache-tendermint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
{
"description": "Transformers for Apalache counterexamples (CEs) with Tendermint blockchains",
"use": [
"tendermint.json"
],
"input": [
{
"name": "first_state",
"description": "extract the first state from Apalache CE",
"kind": "INLINE",
"source": "$.declarations[1].body.and | unwrap"
},
{
"name": "last_state",
"description": "extract the last state from Apalache CE",
"kind": "INLINE",
"source": "$.declarations[-2].body.and | unwrap"
},
{
"name": "history",
"description": "extract the history from the last state of Apalache CE",
"kind": "INLINE",
"source": "$last_state..[?(@.eq == 'history')].arg.atat..arg.record"
},
{
"name": "states",
"description": "extract all state from Apalache CE",
"kind": "INLINE",
"source": "$.declarations[1:-1].body.and"
},
{
"name": "lightblock_commits",
"description": "extract commits from a LightClient block of Apalache CE",
"kind": "INLINE",
"source": "$..[?(@.key.str == 'Commits')].value..str"
},
{
"name": "block_validators",
"description": "extract validators from a block of Apalache CE",
"kind": "INLINE",
"source": "$..[?(@.key.str == 'VS')].value..str"
},
{
"name": "block_next_validators",
"description": "extract next validators from a block of Apalache CE",
"kind": "INLINE",
"source": "$..[?(@.key.str == 'NextVS')].value..str"
},
{
"name": "block_height",
"description": "extract height from a block of Apalache CE",
"kind": "INLINE",
"source": "$..[?(@.key.str == 'height')].value | unwrap"
},
{
"name": "block_time",
"description": "extract time from a block of Apalache CE",
"kind": "INLINE",
"source": "$..[?(@.key.str == 'time')].value | unwrap"
},
{
"name": "id_to_validator",
"description": "transform an identifier into a validator expected by `tendermint-testgen validator`",
"kind": "INLINE",
"source": {
"id": "$",
"voting_power": 50
}
},
{
"name": "id_to_vote",
"description": "transform an identifier into a vote expected by `tendermint-testgen vote`",
"kind": "INLINE",
"source": {
"validator": "$ | id_to_validator",
"header": "$header"
}
},
{
"name": "block_to_header",
"description": "transform a block from Apalache CE into a header expected by `tendermint-testgen header`",
"kind": "INLINE",
"source": {
"validators": "$ | block_validators | map(id_to_validator)",
"next_validators": "$ | block_next_validators | map(id_to_validator)",
"height": "$ | block_height",
"time": "$ | block_time"
}
},
{
"name": "block_to_commit",
"description": "transform a block from Apalache CE into a commit expected by `tendermint-testgen commit`",
"kind": "INLINE",
"let": {
"header": "$ | block_to_header"
},
"source": {
"header": "$header",
"votes": "$ | lightblock_commits | map(id_to_vote)"
}
},
{
"name": "ids_to_validators",
"description": "transform a non-empty array of identifiers into Tendermint validators",
"kind": "INLINE",
"source": "$ | map(id_to_validator) | map(tendermint_validator)"
},
{
"name": "empty_array",
"description": "just an empty array",
"kind": "INLINE",
"source": []
},
{
"name": "first_validator",
"description": "extract first validator from a non-empty array of identifiers",
"kind": "INLINE",
"source": "$[0] | unwrap | id_to_validator | tendermint_validator"
},
{
"name": "const_id",
"description": "constant identifier",
"kind": "INLINE",
"source": "a"
}, {
"name": "fixed_validator",
"description": "extract first validator from a non-empty array of identifiers",
"kind": "INLINE",
"source": "$const_id | id_to_validator | tendermint_validator"
},
{
"name": "ids_to_validator_set",
"description": "transform an array of identifiers into a JSON-encoded Tendermint validator set",
"kind": "INLINE",
"source": {
"validators": "$ | ifelse(ids_to_validators,empty_array)",
"proposer": "$ | ifelse(first_validator,fixed_validator)"
}
},
{
"name": "block_to_signed_header",
"description": "transform a block from Apalache CE into a JSON-encoded Tendermint signed header",
"kind": "INLINE",
"source": {
"header": "$ | block_to_header | tendermint_header",
"commit": "$ | block_to_commit | tendermint_commit"
}
}
]
}
42 changes: 42 additions & 0 deletions testgen/jsonatr-lib/apalache_to_lite_test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"description": "Transform an Apalache counterexample into a Tendermint LightClient test",
"use": [
"unix.json",
"apalache-tendermint.json"
],
"input": [
{
"name": "block_to_initial_block",
"description": "transforms a block from Apalache CE into a JSON-encoded Tendermint initial light block",
"kind": "INLINE",
"source": {
"signed_header": "$ | block_to_signed_header",
"next_validator_set": "$ | block_next_validators | ids_to_validator_set",
"trusting_period": "1400000000000",
"now": "$utc_timestamp"
}
},
{
"name": "state_to_lite_block_verdict",
"description": "transforms a block from Apalache CE into a JSON-encoded Tendermint light block",
"kind": "INLINE",
"let": {
"block": "$..[?(@.key.str == 'current')].value"
},
"source": {
"block": {
"signed_header": "$block | block_to_signed_header",
"validator_set": "$block | block_validators | ids_to_validator_set",
"next_validator_set": "$block | block_next_validators | ids_to_validator_set"
},
"now": "$..[?(@.key.str == 'now')].value | unwrap | tendermint_time",
"verdict": "$..[?(@.key.str == 'verdict')].value.str | unwrap"
}
}
],
"output": {
"description": "auto-generated from Apalache counterexample",
"initial": "$history[0]..[?(@.key.str == 'current')].value | block_to_initial_block",
"input": "$history[1:] | map(state_to_lite_block_verdict)"
}
}
31 changes: 31 additions & 0 deletions testgen/jsonatr-lib/tendermint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"description": "Transformers for generating Tendermint datastructures",
"prerequisites": "add tendermint-testgen to your $PATH",
"input": [
{
"name": "tendermint_validator",
"kind": "COMMAND",
"source": "tendermint-testgen --stdin validator"
},
{
"name": "tendermint_header",
"kind": "COMMAND",
"source": "tendermint-testgen --stdin header"
},
{
"name": "tendermint_commit",
"kind": "COMMAND",
"source": "tendermint-testgen --stdin commit"
},
{
"name": "tendermint_vote",
"kind": "COMMAND",
"source": "tendermint-testgen --stdin vote"
},
{
"name": "tendermint_time",
"kind": "COMMAND",
"source": "tendermint-testgen --stdin time"
}
]
}
Loading