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

PVF: Add test instructions #2058

Merged
merged 14 commits into from
Nov 28, 2023
71 changes: 59 additions & 12 deletions polkadot/doc/testing.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,65 @@
# Testing

Automated testing is an essential tool to assure correctness.
Testing is an essential tool to assure correctness. This document describes how we test the polkadot code, whether
locally, at scale, and/or automatically in CI.

## Scopes

The testing strategy for Polkadot is 4-fold:

### Unit testing (1)

Boring, small scale correctness tests of individual functions.
Boring, small scale correctness tests of individual functions. It is usually
enough to run `cargo test` in the crate you are testing.

For full coverage you may have to pass some additional features. For example:

```sh
cargo test --features ci-only-tests
```

### Integration tests

There are two variants of integration tests:
There are the following variants of integration tests:

#### Subsystem tests (2)

One particular subsystem (subsystem under test) interacts with a mocked overseer that is made to assert incoming and
outgoing messages of the subsystem under test. This is largely present today, but has some fragmentation in the evolved
integration test implementation. A `proc-macro`/`macro_rules` would allow for more consistent implementation and
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this feature-ask because it should be in an issue, not in user-facing documentation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this has been here for like three years, if it was an issue it would have been lost in the monorepo migration. So, I won't create it. :)

structure.
outgoing messages of the subsystem under test. See e.g. the `statement-distribution` tests.

#### Behavior tests (3)

Launching small scale networks, with multiple adversarial nodes without any further tooling required. This should
include tests around the thresholds in order to evaluate the error handling once certain assumed invariants fail.
Launching small scale networks, with multiple adversarial nodes. This should include tests around the thresholds in
order to evaluate the error handling once certain assumed invariants fail.

Currently, we commonly use **zombienet** to run mini test-networks, whether locally or in CI. To run on your machine:

- First, make sure you have [zombienet][zombienet] installed.

- Now, all the required binaries must be installed in your $PATH. You must run the following from the `polkadot/`
directory in order to test your changes. (Not `zombienet setup`, or you will get the released binaries without your
local changes!)

For this purpose based on `AllSubsystems` and `proc-macro` `AllSubsystemsGen`.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this stuff because I couldn't find any reference to AllSubsystems in the codebase.

```sh
cargo install --path . --locked
```

- You will also need to install whatever binaries are required for your specific tests. For example, to install
`undying-collator`, from `polkadot/`, run:

```sh
cargo install --path ./parachain/test-parachains/undying/collator --locked
```

This assumes a simplistic test runtime.
- Finally, run the zombienet test from the `polkadot` directory:

```sh
RUST_LOG=parachain::pvf=trace zombienet --provider=native spawn zombienet_tests/functional/0001-parachains-pvf.toml
```

- You can pick a validator node like `alice` from the output and view its logs
(`tail -f <log_file>`) or metrics. Make sure there is nothing funny in the logs
(try `grep WARN <log_file>`).

#### Testing at scale (4)

Expand All @@ -41,13 +72,27 @@ addition prometheus avoiding additional Polkadot source changes.
_Behavior tests_ and _testing at scale_ have naturally soft boundary. The most significant difference is the presence of
a real network and the number of nodes, since a single host often not capable to run multiple nodes at once.

---
## Observing Logs

To verify expected behavior it's often useful to observe logs. To avoid too many
logs at once, you can run one test at a time:

1. Add `sp_tracing::try_init_simple();` to the beginning of a test
2. Specify `RUST_LOG=<target>::<subtarget>=trace` before the cargo command.

For example:

```sh
RUST_LOG=parachain::pvf=trace cargo test execute_can_run_serially
```

For more info on how our logs work, check [the docs][logs].

## Coverage

Coverage gives a _hint_ of the actually covered source lines by tests and test applications.

The state of the art is currently [tarpaulin][tarpaulin] which unfortunately yields a lot of false negatives. Lines that
The state of the art is currently tarpaulin which unfortunately yields a lot of false negatives. Lines that
are in fact covered, marked as uncovered due to a mere linebreak in a statement can cause these artifacts. This leads to
lower coverage percentages than there actually is.

Expand Down Expand Up @@ -251,5 +296,7 @@ behavior_testcase!{
}
```

[zombienet]: https://github.com/paritytech/zombienet
[Gurke]: https://github.com/paritytech/gurke
[simnet]: https://github.com/paritytech/simnet_scripts
[logs]: https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/node/gum/src/lib.rs
47 changes: 47 additions & 0 deletions polkadot/node/core/pvf/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# PVF Host

This is the PVF host, responsible for responding to requests from Candidate
Validation and spawning worker tasks to fulfill those requests.

See also:

- for more information: [the Implementer's Guide][impl-guide]
- for an explanation of terminology: [the Glossary][glossary]

## Running basic tests

Running `cargo test` in the `pvf/` directory will run unit and integration
tests.

**Note:** some tests run only under Linux, amd64, and/or with the
`ci-only-tests` feature enabled.

See the general [Testing][testing] instructions for more information on
**running tests** and **observing logs**.

## Running a test-network with zombienet
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Wouldn't this steps be better at the top of this repo ? And if we already have them can we just reference them, since they might change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, there is a polkadot/doc/testing.md file. Looks much of this file can go there, and then this file can just reference that like you said.


Since this crate is consensus-critical, for major changes it is highly
recommended to run a test-network. See the "Behavior tests" section of the
[Testing][testing] docs for full instructions.

To run the PVF-specific zombienet test:

```sh
RUST_LOG=parachain::pvf=trace zombienet --provider=native spawn zombienet_tests/functional/0001-parachains-pvf.toml
```

## Testing on Linux

Some of the PVF functionality, especially related to security, is Linux-only,
and some is amd64-only. If you touch anything security-related, make sure to
test on Linux amd64! If you're on a Mac, you can either run a VM or you can hire
a VPS and use the open-source tool [EternalTerminal][et] to connect to it.[^et]

[^et]: Unlike ssh, ET preserves your session across disconnects, and unlike
another popular persistent shell, mosh, it allows scrollback.

[impl-guide]: https://paritytech.github.io/polkadot-sdk/book/pvf-prechecking.html#summary
[glossary]: https://paritytech.github.io/polkadot-sdk/book/glossary.html
[testing]: https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/doc/testing.md
[et]: https://github.com/MisterTea/EternalTerminal
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,9 @@ pub fn params_to_wasmtime_semantics(par: &ExecutorParams) -> Semantics {

/// Runs the prevalidation on the given code. Returns a [`RuntimeBlob`] if it succeeds.
pub fn prevalidate(code: &[u8]) -> Result<RuntimeBlob, sc_executor_common::error::WasmError> {
// Construct the runtime blob and do some basic checks for consistency.
let blob = RuntimeBlob::new(code)?;
// It's assumed this function will take care of any prevalidation logic
// that needs to be done.
//
// Do nothing for now.
// In the future this function should take care of any further prevalidation logic.
Ok(blob)
}

Expand Down
2 changes: 1 addition & 1 deletion polkadot/node/core/pvf/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

pub mod error;
pub mod execute;
pub mod executor_intf;
pub mod executor_interface;
pub mod prepare;
pub mod pvf;
pub mod worker;
Expand Down
4 changes: 2 additions & 2 deletions polkadot/node/core/pvf/execute-worker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
//! Contains the logic for executing PVFs. Used by the polkadot-execute-worker binary.

pub use polkadot_node_core_pvf_common::{
executor_intf::execute_artifact, worker_dir, SecurityStatus,
executor_interface::execute_artifact, worker_dir, SecurityStatus,
};

// NOTE: Initializing logging in e.g. tests will not have an effect in the workers, as they are
Expand Down Expand Up @@ -236,7 +236,7 @@ fn validate_using_artifact(
let descriptor_bytes = match unsafe {
// SAFETY: this should be safe since the compiled artifact passed here comes from the
// file created by the prepare workers. These files are obtained by calling
// [`executor_intf::prepare`].
// [`executor_interface::prepare`].
execute_artifact(compiled_artifact_blob, executor_params, params)
} {
Err(err) => return JobResponse::format_invalid("execute", &err),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

use criterion::{criterion_group, criterion_main, Criterion, SamplingMode};
use polkadot_node_core_pvf_common::{
executor_intf::{prepare, prevalidate},
executor_interface::{prepare, prevalidate},
prepare::PrepareJobKind,
pvf::PvfPrepData,
};
Expand Down
4 changes: 2 additions & 2 deletions polkadot/node/core/pvf/prepare-worker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

mod memory_stats;

use polkadot_node_core_pvf_common::executor_intf::{prepare, prevalidate};
use polkadot_node_core_pvf_common::executor_interface::{prepare, prevalidate};

// NOTE: Initializing logging in e.g. tests will not have an effect in the workers, as they are
// separate spawned processes. Run with e.g. `RUST_LOG=parachain::pvf-prepare-worker=trace`.
Expand All @@ -41,7 +41,7 @@ use os_pipe::{self, PipeReader, PipeWriter};
use parity_scale_codec::{Decode, Encode};
use polkadot_node_core_pvf_common::{
error::{PrepareError, PrepareWorkerResult},
executor_intf::create_runtime_from_artifact_bytes,
executor_interface::create_runtime_from_artifact_bytes,
framed_recv_blocking, framed_send_blocking,
prepare::{MemoryStats, PrepareJobKind, PrepareStats, PrepareWorkerSuccess},
pvf::PvfPrepData,
Expand Down
2 changes: 1 addition & 1 deletion polkadot/node/core/pvf/src/execute/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@
//! `polkadot_node_core_pvf_worker::execute_worker_entrypoint`.

mod queue;
mod worker_intf;
mod worker_interface;

pub use queue::{start, PendingExecutionRequest, ToQueue};
8 changes: 4 additions & 4 deletions polkadot/node/core/pvf/src/execute/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@

//! A queue that handles requests for PVF execution.

use super::worker_intf::Outcome;
use super::worker_interface::Outcome;
use crate::{
artifacts::{ArtifactId, ArtifactPathId},
host::ResultSender,
metrics::Metrics,
worker_intf::{IdleWorker, WorkerHandle},
worker_interface::{IdleWorker, WorkerHandle},
InvalidCandidate, PossiblyInvalidError, ValidationError, LOG_TARGET,
};
use futures::{
Expand Down Expand Up @@ -448,7 +448,7 @@ async fn spawn_worker_task(
use futures_timer::Delay;

loop {
match super::worker_intf::spawn(
match super::worker_interface::spawn(
&program_path,
&cache_path,
job.executor_params.clone(),
Expand Down Expand Up @@ -500,7 +500,7 @@ fn assign(queue: &mut Queue, worker: Worker, job: ExecuteJob) {
queue.mux.push(
async move {
let _timer = execution_timer;
let outcome = super::worker_intf::start_work(
let outcome = super::worker_interface::start_work(
idle,
job.artifact.clone(),
job.exec_timeout,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

use crate::{
artifacts::ArtifactPathId,
worker_intf::{
worker_interface::{
clear_worker_dir_path, framed_recv, framed_send, spawn_with_program_path, IdleWorker,
SpawnErr, WorkerDir, WorkerHandle, JOB_TIMEOUT_WALL_CLOCK_FACTOR,
},
Expand Down
4 changes: 2 additions & 2 deletions polkadot/node/core/pvf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ mod metrics;
mod prepare;
mod priority;
mod security;
mod worker_intf;
mod worker_interface;

#[cfg(feature = "test-utils")]
pub mod testing;
Expand All @@ -107,7 +107,7 @@ pub use error::{InvalidCandidate, PossiblyInvalidError, ValidationError};
pub use host::{start, Config, ValidationHost, EXECUTE_BINARY_NAME, PREPARE_BINARY_NAME};
pub use metrics::Metrics;
pub use priority::Priority;
pub use worker_intf::{framed_recv, framed_send, JOB_TIMEOUT_WALL_CLOCK_FACTOR};
pub use worker_interface::{framed_recv, framed_send, JOB_TIMEOUT_WALL_CLOCK_FACTOR};

// Re-export some common types.
pub use polkadot_node_core_pvf_common::{
Expand Down
2 changes: 1 addition & 1 deletion polkadot/node/core/pvf/src/prepare/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

mod pool;
mod queue;
mod worker_intf;
mod worker_interface;

pub use pool::start as start_pool;
pub use queue::{start as start_queue, FromQueue, ToQueue};
8 changes: 4 additions & 4 deletions polkadot/node/core/pvf/src/prepare/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

use super::worker_intf::{self, Outcome};
use super::worker_interface::{self, Outcome};
use crate::{
metrics::Metrics,
worker_intf::{IdleWorker, WorkerHandle},
worker_interface::{IdleWorker, WorkerHandle},
LOG_TARGET,
};
use always_assert::never;
Expand Down Expand Up @@ -278,7 +278,7 @@ async fn spawn_worker_task(
use futures_timer::Delay;

loop {
match worker_intf::spawn(
match worker_interface::spawn(
&program_path,
&cache_path,
spawn_timeout,
Expand Down Expand Up @@ -306,7 +306,7 @@ async fn start_work_task<Timer>(
cache_path: PathBuf,
_preparation_timer: Option<Timer>,
) -> PoolEvent {
let outcome = worker_intf::start_work(&metrics, idle, pvf, cache_path).await;
let outcome = worker_interface::start_work(&metrics, idle, pvf, cache_path).await;
PoolEvent::StartWork(worker, outcome)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
use crate::{
artifacts::ArtifactId,
metrics::Metrics,
worker_intf::{
worker_interface::{
clear_worker_dir_path, framed_recv, framed_send, spawn_with_program_path, IdleWorker,
SpawnErr, WorkerDir, WorkerHandle, JOB_TIMEOUT_WALL_CLOCK_FACTOR,
},
Expand Down
4 changes: 2 additions & 2 deletions polkadot/node/core/pvf/src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

pub use crate::{
host::{EXECUTE_BINARY_NAME, PREPARE_BINARY_NAME},
worker_intf::{spawn_with_program_path, SpawnErr},
worker_interface::{spawn_with_program_path, SpawnErr},
};

use crate::get_worker_version;
Expand All @@ -36,7 +36,7 @@ pub fn validate_candidate(
code: &[u8],
params: &[u8],
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
use polkadot_node_core_pvf_common::executor_intf::{prepare, prevalidate};
use polkadot_node_core_pvf_common::executor_interface::{prepare, prevalidate};
use polkadot_node_core_pvf_execute_worker::execute_artifact;

let code = sp_maybe_compressed_blob::decompress(code, 10 * 1024 * 1024)
Expand Down
9 changes: 0 additions & 9 deletions polkadot/node/core/pvf/tests/README.md
mrcnski marked this conversation as resolved.
Show resolved Hide resolved

This file was deleted.

9 changes: 6 additions & 3 deletions polkadot/roadmap/implementers-guide/src/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,13 @@ has exactly one downward message queue.
- **Proof-of-Validity (PoV):** A stateless-client proof that a parachain candidate is valid, with respect to some
validation function.
- **PVF:** Parachain Validation Function. The validation code that is run by validators on parachains.
- **PVF Prechecking:** This is the process of initially checking the PVF when it is first added. We attempt preparation
of the PVF and make sure it succeeds within a given timeout, plus some additional checks.
- **PVF Prechecking:** This is the process of checking a PVF when it appears
on-chain, either when the parachain is onboarded or when it signalled an
upgrade of its validation code. We attempt preparation of the PVF and make
sure it that succeeds within a given timeout, plus some additional checks.
- **PVF Preparation:** This is the process of preparing the WASM blob and includes both prevalidation and compilation.
As there is no prevalidation right now, preparation just consists of compilation.
- **PVF Prevalidation:** Some basic checks for correctness of the PVF blob. The
first step of PVF preparation, before compilation.
- **Relay Parent:** A block in the relay chain, referred to in a context where work is being done in the context of the
state at this block.
- **Runtime:** The relay-chain state machine.
Expand Down
Loading