Compare commits

...

7 Commits

Author SHA1 Message Date
Omar Abdulla 87dd5edeb1 Update the format of the expectations file 2026-01-15 17:45:50 +03:00
Omar Abdulla 996a64d500 Fix CI issue with the paths 2026-01-15 16:34:28 +03:00
Omar Abdulla 2ce575bf72 Fix the path of the workdir in CI 2026-01-15 16:14:03 +03:00
Omar Abdulla 659263b8c5 Fix CI 2026-01-15 01:13:57 +03:00
Omar Abdulla e2d626d45b Fix an issue with CI 2026-01-15 00:30:38 +03:00
Omar Abdulla 1231a9b6c5 Add expectations tests to the CI action 2026-01-15 00:21:27 +03:00
Omar Abdulla 73ee78a01e Add a report processing tool 2026-01-14 23:01:04 +03:00
9 changed files with 492 additions and 47 deletions
@@ -41,6 +41,10 @@ inputs:
description: "The id of the parachain to spawn with the polkadot-omni-node. This is only required if the polkadot-omni-node is one of the selected platforms."
type: number
required: false
expectations-file-path:
description: "Path to the expectations file to use to compare against."
type: string
required: false
runs:
using: "composite"
@@ -79,6 +83,12 @@ runs:
run: |
${{ inputs['cargo-command'] }} build --locked --profile release -p pallet-revive-eth-rpc -p revive-dev-node --manifest-path ${{ inputs['polkadot-sdk-path'] }}/Cargo.toml
${{ inputs['cargo-command'] }} build --locked --profile release --bin polkadot-omni-node --manifest-path ${{ inputs['polkadot-sdk-path'] }}/Cargo.toml
- name: Installing retester
shell: bash
run: ${{ inputs['cargo-command'] }} install --path ./revive-differential-tests/crates/core
- name: Installing report-processor
shell: bash
run: ${{ inputs['cargo-command'] }} install --path ./revive-differential-tests/crates/report-processor
- name: Running the Differential Tests
shell: bash
run: |
@@ -96,11 +106,12 @@ runs:
)
fi
${{ inputs['cargo-command'] }} run --locked --manifest-path revive-differential-tests/Cargo.toml -- test \
retester test \
--test ./revive-differential-tests/resolc-compiler-tests/fixtures/solidity/simple \
--test ./revive-differential-tests/resolc-compiler-tests/fixtures/solidity/complex \
--test ./revive-differential-tests/resolc-compiler-tests/fixtures/solidity/translated_semantic_tests \
--platform ${{ inputs['platform'] }} \
--report.file-name report.json \
--concurrency.number-of-nodes 10 \
--concurrency.number-of-threads 10 \
--concurrency.number-of-concurrent-tasks 100 \
@@ -110,22 +121,21 @@ runs:
--eth-rpc.path ${{ inputs['polkadot-sdk-path'] }}/target/release/eth-rpc \
--polkadot-omni-node.path ${{ inputs['polkadot-sdk-path'] }}/target/release/polkadot-omni-node \
--resolc.path ./resolc \
"${OMNI_ARGS[@]}"
- name: Creating a markdown report of the test execution
"${OMNI_ARGS[@]}" || true
- name: Generate the expectation file
shell: bash
if: ${{ always() }}
run: |
mv ./workdir/*.json report.json
python3 revive-differential-tests/scripts/process-differential-tests-report.py report.json ${{ inputs['platform'] }}
run: report-processor generate-expectations-file --report-path ./workdir/report.json --output-path ./workdir/expectations.json --remove-prefix ./revive-differential-tests/resolc-compiler-tests
- name: Upload the Report to the CI
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f
if: ${{ always() }}
with:
name: report-${{ inputs['platform'] }}.md
path: report.md
- name: Posting the report as a comment on the PR
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405
if: ${{ always() }}
name: ${{ inputs['platform'] }}-report.json
path: ./workdir/report.json
- name: Upload the Report to the CI
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f
with:
header: diff-tests-report-${{ inputs['platform'] }}
path: report.md
name: ${{ inputs['platform'] }}.json
path: ./workdir/expectations.json
- name: Check Expectations
shell: bash
if: ${{ inputs['expectations-file-path'] != '' }}
run: report-processor compare-expectation-files --base-expectation-path ${{ inputs['expectations-file-path'] }} --other-expectation-path ./workdir/expectations.json
Generated
+12
View File
@@ -5910,6 +5910,18 @@ dependencies = [
"tracing",
]
[[package]]
name = "revive-dt-report-processor"
version = "0.1.0"
dependencies = [
"anyhow",
"clap",
"revive-dt-common",
"revive-dt-report",
"serde",
"serde_json",
]
[[package]]
name = "revive-dt-solc-binaries"
version = "0.1.0"
+7 -1
View File
@@ -21,6 +21,7 @@ revive-dt-node-interaction = { version = "0.1.0", path = "crates/node-interactio
revive-dt-node-pool = { version = "0.1.0", path = "crates/node-pool" }
revive-dt-report = { version = "0.1.0", path = "crates/report" }
revive-dt-solc-binaries = { version = "0.1.0", path = "crates/solc-binaries" }
revive-dt-report-processor = { version = "0.1.0", path = "crates/report-processor" }
alloy = { version = "1.4.1", features = ["full", "genesis", "json-rpc"] }
ansi_term = "0.12.1"
@@ -81,7 +82,12 @@ zombienet-sdk = { git = "https://github.com/paritytech/zombienet-sdk.git", rev =
[profile.bench]
inherits = "release"
lto = true
codegen-units = 1
lto = true
[profile.production]
inherits = "release"
codegen-units = 1
lto = true
[workspace.lints.clippy]
+12
View File
@@ -23,6 +23,18 @@ pub struct Mode {
pub version: Option<semver::VersionReq>,
}
impl Ord for Mode {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.to_string().cmp(&other.to_string())
}
}
impl PartialOrd for Mode {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Display for Mode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.pipeline.fmt(f)?;
@@ -1,10 +1,15 @@
use std::{fmt::Display, path::PathBuf, str::FromStr};
use std::{
fmt::Display,
path::{Path, PathBuf},
str::FromStr,
};
use anyhow::{Context as _, bail};
use serde::{Deserialize, Serialize};
use crate::types::Mode;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ParsedTestSpecifier {
/// All of the test cases in the file should be ran across all of the specified modes
FileOrDirectory {
@@ -34,6 +39,22 @@ pub enum ParsedTestSpecifier {
},
}
impl ParsedTestSpecifier {
pub fn metadata_path(&self) -> &Path {
match self {
ParsedTestSpecifier::FileOrDirectory {
metadata_or_directory_file_path: metadata_file_path,
}
| ParsedTestSpecifier::Case {
metadata_file_path, ..
}
| ParsedTestSpecifier::CaseWithMode {
metadata_file_path, ..
} => metadata_file_path,
}
}
}
impl Display for ParsedTestSpecifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
@@ -131,3 +152,22 @@ impl TryFrom<&str> for ParsedTestSpecifier {
value.parse()
}
}
impl Serialize for ParsedTestSpecifier {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.to_string().serialize(serializer)
}
}
impl<'de> Deserialize<'de> for ParsedTestSpecifier {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let string = String::deserialize(deserializer)?;
string.parse().map_err(serde::de::Error::custom)
}
}
+4
View File
@@ -1113,6 +1113,10 @@ pub struct ReportConfiguration {
/// Controls if the compiler output is included in the final report.
#[clap(long = "report.include-compiler-output")]
pub include_compiler_output: bool,
/// The filename to use for the report.
#[clap(long = "report.file-name")]
pub file_name: Option<String>,
}
#[derive(Clone, Debug, Parser, Serialize, Deserialize)]
+25
View File
@@ -0,0 +1,25 @@
[package]
name = "revive-dt-report-processor"
description = "revive differential testing report processor utility"
version.workspace = true
authors.workspace = true
license.workspace = true
edition.workspace = true
repository.workspace = true
rust-version.workspace = true
[[bin]]
name = "report-processor"
path = "src/main.rs"
[dependencies]
revive-dt-report = { workspace = true }
revive-dt-common = { workspace = true }
anyhow = { workspace = true }
clap = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
[lints]
workspace = true
+328
View File
@@ -0,0 +1,328 @@
use std::{
borrow::Cow,
collections::{BTreeMap, BTreeSet},
fmt::Display,
fs::{File, OpenOptions},
ops::{Deref, DerefMut},
path::{Path, PathBuf},
str::FromStr,
};
use anyhow::{Context as _, Error, Result, bail};
use clap::Parser;
use serde::{Deserialize, Serialize, de::DeserializeOwned};
use revive_dt_common::types::{Mode, ParsedTestSpecifier};
use revive_dt_report::{Report, TestCaseStatus};
fn main() -> Result<()> {
let cli = Cli::try_parse().context("Failed to parse the CLI arguments")?;
match cli {
Cli::GenerateExpectationsFile {
report_path,
output_path: output_file,
remove_prefix,
} => {
let remove_prefix = remove_prefix
.into_iter()
.map(|path| path.canonicalize().context("Failed to canonicalize path"))
.collect::<Result<Vec<_>>>()?;
let expectations = report_path
.execution_information
.iter()
.flat_map(|(metadata_file_path, metadata_file_report)| {
metadata_file_report
.case_reports
.iter()
.map(move |(case_idx, case_report)| {
(metadata_file_path, case_idx, case_report)
})
})
.flat_map(|(metadata_file_path, case_idx, case_report)| {
case_report.mode_execution_reports.iter().map(
move |(mode, execution_report)| {
(
metadata_file_path,
case_idx,
mode,
execution_report.status.as_ref(),
)
},
)
})
.filter_map(|(metadata_file_path, case_idx, mode, status)| {
status.map(|status| (metadata_file_path, case_idx, mode, status))
})
.map(|(metadata_file_path, case_idx, mode, status)| {
(
TestSpecifier {
metadata_file_path: Cow::Borrowed(
remove_prefix
.iter()
.filter_map(|prefix| {
metadata_file_path.as_inner().strip_prefix(prefix).ok()
})
.next()
.unwrap_or(metadata_file_path.as_inner()),
),
case_idx: case_idx.into_inner(),
mode: Cow::Borrowed(mode),
},
Status::from(status),
)
})
.collect::<Expectations>();
let output_file = OpenOptions::new()
.truncate(true)
.create(true)
.write(true)
.open(output_file)
.context("Failed to create the output file")?;
serde_json::to_writer_pretty(output_file, &expectations)
.context("Failed to write the expectations to file")?;
}
Cli::CompareExpectationFiles {
base_expectation_path,
other_expectation_path,
} => {
let keys = base_expectation_path
.keys()
.chain(other_expectation_path.keys())
.collect::<BTreeSet<_>>();
for key in keys {
let base_status = base_expectation_path.get(key).context(format!(
"Entry not found in the base expectations: \"{}\"",
key
))?;
let other_status = other_expectation_path.get(key).context(format!(
"Entry not found in the other expectations: \"{}\"",
key
))?;
if base_status != other_status {
bail!(
"Expectations for entry \"{}\" have changed. They were {:?} and now they are {:?}",
key,
base_status,
other_status
)
}
}
}
};
Ok(())
}
type Expectations<'a> = BTreeMap<TestSpecifier<'a>, Status>;
/// A tool that's used to process the reports generated by the retester binary in various ways.
#[derive(Clone, Debug, Parser)]
#[command(name = "retester", term_width = 100)]
pub enum Cli {
/// Generates an expectation file out of a given report.
GenerateExpectationsFile {
/// The path of the report's JSON file to generate the expectation's file for.
#[clap(long)]
report_path: JsonFile<Report>,
/// The path of the output file to generate.
///
/// Note that we expect that:
/// 1. The provided path points to a JSON file.
/// 1. The ancestor's of the provided path already exist such that no directory creations
/// are required.
#[clap(long)]
output_path: PathBuf,
/// Prefix paths to remove from the paths in the final expectations file.
#[clap(long)]
remove_prefix: Vec<PathBuf>,
},
/// Compares two expectation files to ensure that they match each other.
CompareExpectationFiles {
/// The path of the base expectation file.
#[clap(long)]
base_expectation_path: JsonFile<Expectations<'static>>,
/// The path of the other expectation file.
#[clap(long)]
other_expectation_path: JsonFile<Expectations<'static>>,
},
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum Status {
Succeeded,
Failed,
Ignored,
}
impl From<TestCaseStatus> for Status {
fn from(value: TestCaseStatus) -> Self {
match value {
TestCaseStatus::Succeeded { .. } => Self::Succeeded,
TestCaseStatus::Failed { .. } => Self::Failed,
TestCaseStatus::Ignored { .. } => Self::Ignored,
}
}
}
impl<'a> From<&'a TestCaseStatus> for Status {
fn from(value: &'a TestCaseStatus) -> Self {
match value {
TestCaseStatus::Succeeded { .. } => Self::Succeeded,
TestCaseStatus::Failed { .. } => Self::Failed,
TestCaseStatus::Ignored { .. } => Self::Ignored,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct JsonFile<T> {
path: PathBuf,
content: Box<T>,
}
impl<T> Deref for JsonFile<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.content
}
}
impl<T> DerefMut for JsonFile<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.content
}
}
impl<T> FromStr for JsonFile<T>
where
T: DeserializeOwned,
{
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let path = PathBuf::from(s);
let file = File::open(&path).context("Failed to open the file")?;
serde_json::from_reader(&file)
.map(|content| Self { path, content })
.context(format!(
"Failed to deserialize file's content as {}",
std::any::type_name::<T>()
))
}
}
impl<T> Display for JsonFile<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.path.display(), f)
}
}
impl<T> From<JsonFile<T>> for String {
fn from(value: JsonFile<T>) -> Self {
value.to_string()
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TestSpecifier<'a> {
pub metadata_file_path: Cow<'a, Path>,
pub case_idx: usize,
pub mode: Cow<'a, Mode>,
}
impl<'a> Display for TestSpecifier<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}::{}::{}",
self.metadata_file_path.display(),
self.case_idx,
self.mode
)
}
}
impl<'a> From<TestSpecifier<'a>> for ParsedTestSpecifier {
fn from(
TestSpecifier {
metadata_file_path,
case_idx,
mode,
}: TestSpecifier,
) -> Self {
Self::CaseWithMode {
metadata_file_path: metadata_file_path.to_path_buf(),
case_idx,
mode: mode.into_owned(),
}
}
}
impl TryFrom<ParsedTestSpecifier> for TestSpecifier<'static> {
type Error = Error;
fn try_from(value: ParsedTestSpecifier) -> Result<Self> {
let ParsedTestSpecifier::CaseWithMode {
metadata_file_path,
case_idx,
mode,
} = value
else {
bail!("Expected a full test case specifier")
};
Ok(Self {
metadata_file_path: Cow::Owned(metadata_file_path),
case_idx,
mode: Cow::Owned(mode),
})
}
}
impl<'a> Serialize for TestSpecifier<'a> {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.to_string().serialize(serializer)
}
}
impl<'d, 'a> Deserialize<'d> for TestSpecifier<'a> {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'d>,
{
let string = String::deserialize(deserializer)?;
let mut splitted = string.split("::");
let (Some(metadata_file_path), Some(case_idx), Some(mode), None) = (
splitted.next(),
splitted.next(),
splitted.next(),
splitted.next(),
) else {
return Err(serde::de::Error::custom(
"Test specifier doesn't contain the components required",
));
};
let metadata_file_path = PathBuf::from(metadata_file_path);
let case_idx = usize::from_str(case_idx)
.map_err(|_| serde::de::Error::custom("Case idx is not a usize"))?;
let mode = Mode::from_str(mode).map_err(|_| serde::de::Error::custom("Invalid mode"))?;
Ok(Self {
metadata_file_path: Cow::Owned(metadata_file_path),
case_idx,
mode: Cow::Owned(mode),
})
}
}
+37 -29
View File
@@ -36,6 +36,8 @@ pub struct ReportAggregator {
runner_tx: Option<UnboundedSender<RunnerEvent>>,
runner_rx: UnboundedReceiver<RunnerEvent>,
listener_tx: Sender<ReporterEvent>,
/* Context */
file_name: Option<String>,
}
impl ReportAggregator {
@@ -43,6 +45,11 @@ impl ReportAggregator {
let (runner_tx, runner_rx) = unbounded_channel::<RunnerEvent>();
let (listener_tx, _) = channel::<ReporterEvent>(0xFFFF);
Self {
file_name: match context {
Context::Test(ref context) => context.report_configuration.file_name.clone(),
Context::Benchmark(ref context) => context.report_configuration.file_name.clone(),
Context::ExportJsonSchema | Context::ExportGenesis(..) => None,
},
report: Report::new(context),
remaining_cases: Default::default(),
runner_tx: Some(runner_tx),
@@ -121,7 +128,7 @@ impl ReportAggregator {
self.handle_completion(CompletionEvent {});
debug!("Report aggregation completed");
let file_name = {
let default_file_name = {
let current_timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.context("System clock is before UNIX_EPOCH; cannot compute report timestamp")?
@@ -130,6 +137,7 @@ impl ReportAggregator {
file_name.push_str(".json");
file_name
};
let file_name = self.file_name.unwrap_or(default_file_name);
let file_path = self
.report
.context
@@ -562,7 +570,7 @@ pub struct Report {
/// The list of metadata files that were found by the tool.
pub metadata_files: BTreeSet<MetadataFilePath>,
/// Metrics from the execution.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metrics: Option<Metrics>,
/// Information relating to each test case.
pub execution_information: BTreeMap<MetadataFilePath, MetadataFileReport>,
@@ -582,7 +590,7 @@ impl Report {
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct MetadataFileReport {
/// Metrics from the execution.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metrics: Option<Metrics>,
/// The report of each case keyed by the case idx.
pub case_reports: BTreeMap<CaseIdx, CaseReport>,
@@ -592,7 +600,7 @@ pub struct MetadataFileReport {
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct CaseReport {
/// Metrics from the execution.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metrics: Option<Metrics>,
/// The [`ExecutionReport`] for each one of the [`Mode`]s.
#[serde_as(as = "HashMap<DisplayFromStr, _>")]
@@ -602,31 +610,31 @@ pub struct CaseReport {
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct ExecutionReport {
/// Information on the status of the test case and whether it succeeded, failed, or was ignored.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub status: Option<TestCaseStatus>,
/// Metrics from the execution.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metrics: Option<Metrics>,
/// Information related to the execution on one of the platforms.
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub platform_execution: PlatformKeyedInformation<Option<ExecutionInformation>>,
/// Information on the compiled contracts.
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub compiled_contracts: BTreeMap<PathBuf, BTreeMap<String, ContractInformation>>,
/// The addresses of the deployed contracts
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub contract_addresses: BTreeMap<ContractInstance, PlatformKeyedInformation<Vec<Address>>>,
/// Information on the mined blocks as part of this execution.
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub mined_block_information: PlatformKeyedInformation<Vec<MinedBlockInformation>>,
/// Information tracked for each step that was executed.
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub steps: BTreeMap<StepPath, StepReport>,
}
/// Information related to the status of the test. Could be that the test succeeded, failed, or that
/// it was ignored.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "status")]
pub enum TestCaseStatus {
/// The test case succeeded.
@@ -664,19 +672,19 @@ pub struct TestCaseNodeInformation {
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct ExecutionInformation {
/// Information related to the node assigned to this test case.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub node: Option<TestCaseNodeInformation>,
/// Information on the pre-link compiled contracts.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub pre_link_compilation_status: Option<CompilationStatus>,
/// Information on the post-link compiled contracts.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub post_link_compilation_status: Option<CompilationStatus>,
/// Information on the deployed libraries.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub deployed_libraries: Option<BTreeMap<ContractInstance, Address>>,
/// Information on the deployed contracts.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub deployed_contracts: Option<BTreeMap<ContractInstance, Address>>,
}
@@ -695,11 +703,11 @@ pub enum CompilationStatus {
/// The input provided to the compiler to compile the contracts. This is only included if
/// the appropriate flag is set in the CLI context and if the contracts were not cached and
/// the compiler was invoked.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
compiler_input: Option<CompilerInput>,
/// The output of the compiler. This is only included if the appropriate flag is set in the
/// CLI contexts.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
compiler_output: Option<CompilerOutput>,
},
/// The compilation failed.
@@ -707,15 +715,15 @@ pub enum CompilationStatus {
/// The failure reason.
reason: String,
/// The version of the compiler used to compile the contracts.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
compiler_version: Option<Version>,
/// The path of the compiler used to compile the contracts.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
compiler_path: Option<PathBuf>,
/// The input provided to the compiler to compile the contracts. This is only included if
/// the appropriate flag is set in the CLI context and if the contracts were not cached and
/// the compiler was invoked.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
compiler_input: Option<CompilerInput>,
},
}
@@ -743,24 +751,24 @@ pub struct Metrics {
pub gas_per_second: Metric<u64>,
/* Block Fullness */
pub gas_block_fullness: Metric<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ref_time_block_fullness: Option<Metric<u64>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub proof_size_block_fullness: Option<Metric<u64>>,
}
/// The data that we store for a given metric (e.g., TPS).
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Metric<T> {
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub minimum: Option<PlatformKeyedInformation<T>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub maximum: Option<PlatformKeyedInformation<T>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub mean: Option<PlatformKeyedInformation<T>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub median: Option<PlatformKeyedInformation<T>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub raw: Option<PlatformKeyedInformation<Vec<T>>>,
}