Add duplicate publisher determinism proof
Some checks failed
deploy-cloudflare / checks (push) Failing after 3s
ci-gates / checks (push) Failing after 5s
deploy-cloudflare / deploy (push) Has been skipped

This commit is contained in:
every.channel 2026-06-10 03:28:55 -07:00
parent 5d0f3077d3
commit 91dad67fc2
No known key found for this signature in database
18 changed files with 21569 additions and 595 deletions

View file

@ -1,3 +1,4 @@
use std::collections::BTreeMap;
use std::io::{BufRead, BufReader};
use std::path::Path;
use std::process::{Command, Stdio};
@ -46,6 +47,15 @@ fn blake3_hex(path: &Path) -> anyhow::Result<String> {
Ok(blake3::hash(&bytes).to_hex().to_string())
}
fn command_available(name: &str) -> bool {
Command::new(name)
.arg("-version")
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.is_ok()
}
fn concat_init_and_segment(init: &Path, seg: &Path, out: &Path) -> anyhow::Result<()> {
let init_bytes = std::fs::read(init)?;
let seg_bytes = std::fs::read(seg)?;
@ -157,11 +167,15 @@ fn write_deterministic_ts(out_path: &Path) -> anyhow::Result<()> {
Ok(())
}
fn run_ladder(ec_node: &Path, input_ts: &Path, out_dir: &Path) -> anyhow::Result<()> {
fn run_ladder_with_identity(
ec_node: &Path,
input_ts: &Path,
out_dir: &Path,
stream_id: &str,
broadcast_name: &str,
) -> anyhow::Result<()> {
let signing_key = "11".repeat(32);
let network_secret = "22".repeat(32);
let stream_id = "every.channel/determinism/cmaf-ladder";
let broadcast_name = "every.channel/determinism/cmaf-ladder";
let mut cmd = Command::new(ec_node);
cmd.env("EVERY_CHANNEL_MANIFEST_SIGNING_KEY", &signing_key)
@ -210,6 +224,40 @@ fn run_ladder(ec_node: &Path, input_ts: &Path, out_dir: &Path) -> anyhow::Result
Ok(())
}
fn run_ladder(ec_node: &Path, input_ts: &Path, out_dir: &Path) -> anyhow::Result<()> {
run_ladder_with_identity(
ec_node,
input_ts,
out_dir,
"every.channel/determinism/cmaf-ladder",
"every.channel/determinism/cmaf-ladder",
)
}
fn ladder_artifact_hashes(root: &Path) -> BTreeMap<String, String> {
let mut hashes = BTreeMap::new();
for variant in ["1080p", "720p", "480p"] {
let variant_dir = root.join("cmaf-ladder").join(variant);
// `moq-publish --max-chunks 3` publishes init plus segments 0..=2.
// ffmpeg can race ahead and leave an unpublished tail segment before it is killed.
let init = variant_dir.join("init.mp4");
assert!(init.exists(), "missing init for {variant}");
hashes.insert(format!("{variant}/init.mp4"), blake3_hex(&init).unwrap());
for idx in 0..3 {
let name = format!("segment_{idx:06}.m4s");
let path = variant_dir.join(&name);
assert!(path.exists(), "missing {name} for {variant}");
hashes.insert(format!("{variant}/{name}"), blake3_hex(&path).unwrap());
}
}
hashes
}
fn assert_ladder_bytes_match(left: &Path, right: &Path) {
assert_eq!(ladder_artifact_hashes(left), ladder_artifact_hashes(right));
}
#[test]
#[ignore]
fn deterministic_cmaf_ladder_outputs_match_across_runs() {
@ -235,36 +283,53 @@ fn deterministic_cmaf_ladder_outputs_match_across_runs() {
run_ladder(&ec_node, &input_ts, &run1).expect("run ladder 1");
run_ladder(&ec_node, &input_ts, &run2).expect("run ladder 2");
for variant in ["1080p", "720p", "480p"] {
let v1 = run1.join("cmaf-ladder").join(variant);
let v2 = run2.join("cmaf-ladder").join(variant);
assert_ladder_bytes_match(&run1, &run2);
}
let init1 = v1.join("init.mp4");
let init2 = v2.join("init.mp4");
assert!(
init1.exists() && init2.exists(),
"missing init for {variant}"
);
assert_eq!(
blake3_hex(&init1).unwrap(),
blake3_hex(&init2).unwrap(),
"init differs for {variant}"
);
for idx in 0..3 {
let s1 = v1.join(format!("segment_{idx:06}.m4s"));
let s2 = v2.join(format!("segment_{idx:06}.m4s"));
assert!(
s1.exists() && s2.exists(),
"missing segment {idx} for {variant}"
);
assert_eq!(
blake3_hex(&s1).unwrap(),
blake3_hex(&s2).unwrap(),
"segment {idx} differs for {variant}"
);
}
#[test]
fn duplicate_publishers_same_input_produce_identical_cmaf_ladder_bytes() {
if !command_available("ffmpeg") {
eprintln!("skipping duplicate publisher CMAF ladder determinism test: ffmpeg unavailable");
return;
}
let ec_node = ec_node_path();
let ts = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_millis();
let tmp = std::env::temp_dir().join(format!("ec-duplicate-publisher-cmaf-ladder-{ts}"));
let _ = std::fs::create_dir_all(&tmp);
let input_ts = tmp.join("input.ts");
write_deterministic_ts(&input_ts).expect("write deterministic TS");
let publisher_a = tmp.join("publisher-a");
let publisher_b = tmp.join("publisher-b");
let _ = std::fs::remove_dir_all(&publisher_a);
let _ = std::fs::remove_dir_all(&publisher_b);
std::fs::create_dir_all(&publisher_a).unwrap();
std::fs::create_dir_all(&publisher_b).unwrap();
run_ladder_with_identity(
&ec_node,
&input_ts,
&publisher_a,
"every.channel/determinism/duplicate/publisher-a/la-kcop",
"publisher-a-la-kcop",
)
.expect("run duplicate publisher a");
run_ladder_with_identity(
&ec_node,
&input_ts,
&publisher_b,
"every.channel/determinism/duplicate/publisher-b/la-kcop",
"publisher-b-la-kcop",
)
.expect("run duplicate publisher b");
assert_ladder_bytes_match(&publisher_a, &publisher_b);
}
#[test]