Merge host-format-guard 5a89da23 into master (gate: green on 2a6aabd4, recorded by tools/ci/pre-push.sh; landed on the box mirror)
This commit is contained in:
commit
762391a305
4 changed files with 76 additions and 2 deletions
|
|
@ -286,9 +286,16 @@ bs_wt_lock() {
|
|||
local d="$BS_ROOT_REMOTE/_locks/wt-$BS_WT" t0 holder
|
||||
t0=$(date +%s)
|
||||
while :; do
|
||||
if bs_ssh "mkdir '$d' 2>/dev/null && printf 'pid %s since %sZ: %s\n' '$$' \"\$(date -u +%H:%M:%S)\" '${BS_TOOL:-build} $BS_CRATE_REL' > '$d/holder'"; then BS_WT_LOCKED="$d"; trap 'bs_wt_unlock' EXIT; return 0; fi
|
||||
if bs_ssh "mkdir '$d' 2>/dev/null && printf 'pid %s host %s since %sZ: %s\n' '$$' '$(hostname -s)' \"\$(date -u +%H:%M:%S)\" '${BS_TOOL:-build} $BS_CRATE_REL' > '$d/holder'"; then BS_WT_LOCKED="$d"; trap 'bs_wt_unlock' EXIT; return 0; fi
|
||||
holder=$(bs_ssh "cat '$d/holder' 2>/dev/null; find '$d' -maxdepth 0 -mmin +180 -print 2>/dev/null | grep -q . && echo STALE" 2>/dev/null || true)
|
||||
case "$holder" in *STALE*) bs_log "worktree lock $d is older than 3 h; taking it over"; bs_ssh "rm -rf '$d'"; continue ;; esac
|
||||
# the dead-holder class (8 October 2026, 21:11 to 22:11 UK): a build-remote killed by its pid never runs its EXIT trap, so the
|
||||
# box kept its lock for the 3 h rule and the next run on that worktree waited an hour. The holder line names the Mac and
|
||||
# the pid; a waiter on the same Mac whose pid is dead takes the lock over at once and says so.
|
||||
case "$holder" in
|
||||
"pid "*" host $(hostname -s) since "*) local hp; hp=$(printf '%s' "$holder" | sed -n 's/^pid \([0-9]*\) host .*/\1/p')
|
||||
if [ -n "$hp" ] && ! kill -0 "$hp" 2>/dev/null; then bs_log "worktree lock $d held by pid $hp of this Mac, which is dead; taking it over"; bs_ssh "rm -rf '$d'"; continue; fi ;;
|
||||
esac
|
||||
[ $(( $(date +%s) - t0 )) -lt 7200 ] || bs_die "gave up after 2 h waiting for the worktree lock $d (held: $holder)"
|
||||
[ $(( ($(date +%s) - t0) % 60 )) -lt 10 ] && bs_log "waiting for another run on worktree $BS_WT: ${holder:-?}"
|
||||
sleep 10
|
||||
|
|
|
|||
|
|
@ -19,5 +19,7 @@
|
|||
"vk_sha256": "0x8b4da5bff86d963f4210a78e5d800a1cd00ab41b158f6962f4ac009edc249d4c"
|
||||
},
|
||||
"sp1_circuit_version": "v6.1.0",
|
||||
"sp1_crate_version": "6.8.1"
|
||||
"sp1_crate_version": "6.8.1",
|
||||
"source_commit": "15bb6cdd43bf0e52fca0df0f1dd880e124d03acf",
|
||||
"guest_input_format": 1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,11 @@ fn run() -> Result<()> {
|
|||
println!("RESULT id: {}", pinned.describe());
|
||||
return Ok(());
|
||||
}
|
||||
// A host whose code writes a guest input layout the pinned pair does not read never builds an input for it: refused
|
||||
// here with the source commit to build from (aggregate, chain and every fixture mode build guest inputs; id and the verify modes do not).
|
||||
if !mode.starts_with("verify") {
|
||||
pinned.manifest.check_input_format(igneum_prove_core::shard::GUEST_INPUT_FORMAT)?;
|
||||
}
|
||||
if mode == "verify" {
|
||||
// proving v0 (spec 7.7): the node's proof pool verifies a submitted shard proof off the consensus path
|
||||
return run_verify(&pinned, &arg("--proof").context("--proof <file>")?, &arg("--statement").context("--statement 0x<keccak of the public values>")?);
|
||||
|
|
|
|||
|
|
@ -61,6 +61,36 @@ pub struct Manifest {
|
|||
/// from its object, never from here).
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub succession: Option<Succession>,
|
||||
/// V6-10 provenance (8 October 2026): the commit the pinned pair was built from; the host for this pair is built
|
||||
/// from it (the steward's release-manifest check reads it as an ancestor of the tree).
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub source_commit: Option<String>,
|
||||
/// The guest input layout the pinned pair reads (`igneum_prove_core::shard::GUEST_INPUT_FORMAT` of its source; absent
|
||||
/// on a pin from before the field, which is format 1). A host whose code writes another layout refuses to start
|
||||
/// (22:0x UK, 8 October 2026: a host from master wrote format 3 to the 5 October guests and read "public values are
|
||||
/// 0 bytes" on a 3060 and a 4060; the kit's prover is built from `source_commit`, never from a tree of another format).
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub guest_input_format: Option<u32>,
|
||||
}
|
||||
|
||||
impl Manifest {
|
||||
/// The input layout the pinned pair reads: the manifest's field, or 1 for a pin from before the field.
|
||||
pub fn input_format(&self) -> u32 {
|
||||
self.guest_input_format.unwrap_or(1)
|
||||
}
|
||||
/// Refuses a host whose code writes a layout the pinned pair does not read; the line names the source commit to
|
||||
/// build the prover from instead.
|
||||
pub fn check_input_format(&self, code_format: u32) -> Result<()> {
|
||||
let pinned = self.input_format();
|
||||
if pinned == code_format {
|
||||
return Ok(());
|
||||
}
|
||||
anyhow::bail!(
|
||||
"this host writes guest input format {code_format} and the pinned pair (shard {}) reads format {pinned}: the prover for this pair is built from the manifest's source commit {}, never from this tree (or the pin moves with the code: proving/igneum-prove/pin-guests.sh)",
|
||||
self.shard.program_id,
|
||||
self.source_commit.as_deref().unwrap_or("(absent: a pin from before provenance; its source is the commit that last changed elf/igneum-prove-program.elf)")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// The prior pair's block: the same per-program fields as the top level and the time it was pinned.
|
||||
|
|
@ -227,6 +257,36 @@ pub fn claimed_program_id(proof: &SP1ProofWithPublicValues) -> Option<B256> {
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// Known-failed first: a manifest naming another input layout refuses the host with the source commit to build from;
|
||||
/// a manifest naming none reads as format 1; the code's own format passes.
|
||||
#[test]
|
||||
fn a_pinned_pair_of_another_input_format_refuses_this_host_and_names_the_source_to_build() {
|
||||
let mut m = Manifest::embedded().unwrap();
|
||||
m.guest_input_format = Some(igneum_prove_core::shard::GUEST_INPUT_FORMAT + 1);
|
||||
m.source_commit = Some("abc123".into());
|
||||
let e = m.check_input_format(igneum_prove_core::shard::GUEST_INPUT_FORMAT).unwrap_err().to_string();
|
||||
assert!(e.contains("built from the manifest's source commit abc123"), "{e}");
|
||||
m.guest_input_format = None;
|
||||
assert_eq!(m.input_format(), 1, "a pin from before the field is format 1");
|
||||
if igneum_prove_core::shard::GUEST_INPUT_FORMAT != 1 {
|
||||
let e = m.check_input_format(igneum_prove_core::shard::GUEST_INPUT_FORMAT).unwrap_err().to_string();
|
||||
assert!(e.contains("reads format 1"), "{e}");
|
||||
}
|
||||
m.guest_input_format = Some(igneum_prove_core::shard::GUEST_INPUT_FORMAT);
|
||||
m.check_input_format(igneum_prove_core::shard::GUEST_INPUT_FORMAT).unwrap();
|
||||
// the embedded manifest itself: Pinned::load still answers (id and the verify modes work on a held pin), and the
|
||||
// input-format check either passes or names the source commit the prover is built from
|
||||
let embedded = Manifest::embedded().unwrap();
|
||||
Pinned::load().unwrap();
|
||||
match embedded.check_input_format(igneum_prove_core::shard::GUEST_INPUT_FORMAT) {
|
||||
Ok(()) => assert_eq!(embedded.input_format(), igneum_prove_core::shard::GUEST_INPUT_FORMAT),
|
||||
Err(e) => {
|
||||
assert!(e.to_string().contains("guest input format"), "{e}");
|
||||
assert!(embedded.source_commit.is_some(), "a held pin names the source commit its prover is built from");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn manifest_parses_and_names_both_programs() {
|
||||
let m = Manifest::embedded().unwrap();
|
||||
|
|
|
|||
Loading…
Reference in a new issue