Skip to content

[Low] build.rs artifact selection is non-deterministic #742

@Ollrogge

Description

@Ollrogge

Issue description

To locate the produced WASM runtime artifact, the custom build.rs recursively scans the target directory and picks the last filename matching the <pkg_name>.wasm format (link). This approach is non deterministic as stale build artifacts could be picked. Furthermore, fs::read_dir order can change between calls, causing different results over multiple runs.

Risk

This issue could result in different runtimes to be run by Serai nodes, potentially causing behavioral differences.

Mitigation

Determine the exact output path of the produced WASM runtime. We would recommend the second approach mentioned in the comments above the code. Pass --message-format=json to the build command and then parse the output, even if this would require a JSON parser build dependency.

Example code of how to deterministically find the WASM artifact:

let file = cargo_env("CARGO_PKG_NAME").replace('-', "_") + ".wasm";
let mut artifacts = HashSet::<PathBuf>::new();
for line in stdout.lines() {
  let line = line.expect("failed to read line from `cargo` JSON stdout");
  let Ok(json) = serde_json::from_str::<serde_json::Value>(&line) else {
    continue;
  };

  if json.get("reason").and_then(|r| r.as_str()) != Some("compiler-artifact") {
    continue;
  }

  let Some(filenames) = json.get("filenames").and_then(|f| f.as_array()) else {
    continue;
  };
  for filename in filenames {
    let Some(filename) = filename.as_str() else { continue };
    let path = PathBuf::from(filename);
    if path.file_name().and_then(|n| n.to_str()) == Some(file.as_str()) {
      artifacts.insert(path);
    }
  }
}

assert!(!artifacts.is_empty(), "nested build succeeded but did not emit a `{file}` artifact");
assert_eq!(
  artifacts.len(),
  1,
  "nested build emitted multiple `{file}` artifacts: {artifacts:?}"
);
let artifact = artifacts.into_iter().next().unwrap();

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions