Skip to content
This repository has been archived by the owner on Nov 2, 2023. It is now read-only.

Latest commit

 

History

History

light-client

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

Crate Docs

See the repo root for build status, license, rust version, etc.

Light-Client

Implementation of the Light Client Verification and Fork Detection protocols.

Documentation

See documentation on crates.io.

Example

The code below demonstrates the main use case for the Tendermint Light Client: syncing to the latest block, verifying it, and performing fork detection.

Please refer to the light_client example for fully working code.

let primary_instance: Instance = make_instance(primary, primary_addr, primary_path);
let witness_instance: Instance = make_instance(witness, witness_addr, witness_path);

let mut peer_addr = HashMap::new();
peer_addr.insert(primary, primary_addr);
peer_addr.insert(witness, witness_addr);

let peer_list = PeerList::builder()
    .primary(primary, primary_instance)
    .witness(witness, witness_instance)
    .build();

let mut supervisor = Supervisor::new(
    peer_list,
    ProdForkDetector::default(),
    ProdEvidenceReporter::new(peer_addr),
);

let mut handle = supervisor.handle();

// Spawn the supervisor in its own thread.
std::thread::spawn(|| supervisor.run());

loop {
    // Synchronously query the supervisor via a handle
    let block = handle.verify_to_highest();

    match block {
        Ok(light_block) => {
            println!("[info] synced to block {}", light_block.height());
        }
        Err(e) => {
            println!("[error] sync failed: {}", e);
        }
    });

    std::thread::sleep(Duration::from_millis(800));
}

Testing

The Tendermint Light Client is primarily tested through unit tests.

Core Verification

The logic for the core verification of light blocks is entirely self-contained in the predicates module. This code is exercised in a family of tests called single_step via a set of JSON fixtures which encode an initial trusted state, a target block to verify, and the expected result of the core verification algorithm.

These tests come in two flavours:

  • skipping tests, where there is a gap between the initial trusted state and the target block.
  • sequential tests, where there the initial trusted state and the target block are adjacent.

The following command can be used to run only these tests:

$ cargo test -p tendermint-light-client --test light_client single_step

Model-based tests

We started to employ model-based testing (MBT), which is currently limited to the core verification. In MBT, the testing procedure is based on the Light Client formal model, and the tests themselves are simple assertions in the modeling language TLA+. The current set of TLA+ tests is translated automatically into the set of JSON fixtures. Please refer to the MBT Guide, and the MBT Abstract for further information.

The following command can be used to run only these tests:

$ cargo test -p tendermint-light-client --test model_based

Bisection

Similarly to the core verification logic, the algorithm for performing bisecting verification is exercised via a set of JSON fixtures which encode an initial trusted state, a target block to verify, a set of intermediary blocks, and the expected result of the bisection algorithm.

These tests target the light_client module, and can be found in the tests/light_client.rs file.

To run the tests:

$ cargo test -p tendermint-light-client --test light_client bisection

Fork Detection

Similarly to the bisection algorithm, the fork detection algorithm is tested via a set of JSON fixtures which encode an initial trusted state, a target block to verify, a set of intermediary blocks, and the expected result of the fork detection algorithm.

These tests target the supervisor module, and can be found in the tests/supervisor.rs file.

To run the tests:

$ cargo test -p tendermint-light-client --test supervisor

Voting Power Calculator

The voting power calculator is exercised through unit tests which rely on JSON fixtures to provide the calculator with various types of light blocks together with the expected result of the computation.

The following command can be used to run only these tests:

$ cargo test -p tendermint-light-client voting_power

Integration Tests

This project also includes simple integration test which spawns a light client instance against a single Tendermint full node which acts both as a primary peer and as its own witness.

Because this test requires a running Tendermint node, it is ignored by default. To run this test locally:

# In one terminal
$ mkdir -p /tmp/tendermint
$ docker run -it --rm -v "/tmp/tendermint:/tendermint" tendermint/tendermint init
$ docker run -it --rm -v "/tmp/tendermint:/tendermint" -p 26657:26657 tendermint/tendermint node --proxy_app=kvstore

# In another terminal
$ cargo test -p tendermint-light-client --test integration -- --ignored --nocapture

Other tests

A few core datastructures, such as the PeerList implementation, come with unit tests located in the same module as the implementation.

To run these tests together with all tests described above:

$ cargo test -p tendermint-light-client --all-features