From 13a118aaf4678d456600d6d0829a56eae498fafa Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 26 Oct 2026 14:39:12 +0100 Subject: [PATCH 1/3] ci(lock): check out pinned consensus and primitives sources for the lock tests --- .github/workflows/ci.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2946e62..0710649 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,14 +26,36 @@ jobs: (!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[no ci]')) + defaults: + run: + working-directory: blvm-spec-lock steps: - uses: actions/checkout@v6 + with: + path: blvm-spec-lock + + # production_lock tests read ../blvm-consensus and ../blvm-primitives sources. + # Check them out at pinned commits so the locks always run against real code; + # bump these SHAs when the locks are re-checked against newer consensus. + - uses: actions/checkout@v6 + with: + repository: BTCDecoded/blvm-consensus + ref: 994480ddb6d03a828b4c00654521986d7551fcaf + path: blvm-consensus + + - uses: actions/checkout@v6 + with: + repository: BTCDecoded/blvm-primitives + ref: 9720541b8897c383cbdd0f3f6334d4bcc0af9485 + path: blvm-primitives - name: Install Rust uses: BTCDecoded/rust-ci/install-rust-toolchain@main - name: Cache uses: Swatinem/rust-cache@v2 + with: + workspaces: blvm-spec-lock # Single job + no incremental: avoids flaky "could not parse/generate dep info" (.d missing) # on self-hosted runners (NFS / high parallelism / cache races). From 567f36ce95be1502bfab015edc7f59cffed1dd79 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 26 Oct 2026 15:33:27 +0100 Subject: [PATCH 2/3] ci(lock): also check out pinned blvm-secp256k1 for the taproot hash locks --- .github/workflows/ci.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0710649..3e166e4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: with: path: blvm-spec-lock - # production_lock tests read ../blvm-consensus and ../blvm-primitives sources. + # production_lock tests read ../blvm-consensus, ../blvm-primitives and ../blvm-secp256k1 sources. # Check them out at pinned commits so the locks always run against real code; # bump these SHAs when the locks are re-checked against newer consensus. - uses: actions/checkout@v6 @@ -49,6 +49,12 @@ jobs: ref: 9720541b8897c383cbdd0f3f6334d4bcc0af9485 path: blvm-primitives + - uses: actions/checkout@v6 + with: + repository: BTCDecoded/blvm-secp256k1 + ref: 926f41588fce67f0d87cb5ae0b4ea62fc3f92d62 + path: blvm-secp256k1 + - name: Install Rust uses: BTCDecoded/rust-ci/install-rust-toolchain@main From f74ff82d277e0926b5a535670c4e5a8249c36b51 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 26 Oct 2026 15:38:43 +0100 Subject: [PATCH 3/3] fix(lock): clear clippy lints hidden behind the red Test step --- src/translator/production_lock.rs | 40 ++++++++++++------------------- src/translator/sample_eval.rs | 8 +++---- 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/src/translator/production_lock.rs b/src/translator/production_lock.rs index 4477f9b..7c2f5ca 100644 --- a/src/translator/production_lock.rs +++ b/src/translator/production_lock.rs @@ -271,7 +271,7 @@ pub fn facts_of(func: &syn::ItemFn) -> ProductionFacts { .cmps .iter() .all(|cmp| cmp.left.lit != Some(0x31) && cmp.right.lit != Some(0x31)); - v.facts.merkle_eq_present = scanned.marks.iter().any(|mark| *mark == "merkle-eq"); + v.facts.merkle_eq_present = scanned.marks.contains(&"merkle-eq"); v.facts.merkle_eq_before_pad = v.facts.merkle_eq_present && match ( scanned.marks.iter().position(|mark| *mark == "merkle-eq"), @@ -1485,10 +1485,7 @@ pub fn op_success_query(src: &str) -> SatResult { /// `vsize` is `ceil(weight / 4)`. pub fn vsize_query(src: &str, weight: u64) -> SatResult { - let got = sample_eval::eval_u64( - src, - &[("weight", Val::Int(i128::try_from(weight).expect("weight")))], - ); + let got = sample_eval::eval_u64(src, &[("weight", Val::Int(i128::from(weight)))]); let spec = weight.div_ceil(4); check(|ctx, solver| { let left = BV::from_u64(ctx, got, 64); @@ -2881,10 +2878,8 @@ fn has_nonempty_input_witness(src: &str, witnesses: Option<&[Vec>]>) -> witnesses.iter().all(|w| input_not_witness_empty(src, w)) } else if src.contains(".any(") { witnesses.iter().any(|w| input_not_witness_empty(src, w)) - } else if src.contains("\n true\n") { - true } else { - false + src.contains("\n true\n") } } @@ -2908,9 +2903,7 @@ fn reserved_nonce(src: &str, witnesses: &[Vec>]) -> Option<[u8; 32]> { if witnesses.is_empty() && src.contains("coinbase_witnesses.is_empty()") { return Some([0u8; 32]); } - let Some(stack) = witnesses.first() else { - return None; - }; + let stack = witnesses.first()?; if stack.is_empty() && src.contains("stack.is_empty()") { return Some([0u8; 32]); } @@ -4270,7 +4263,7 @@ fn bip54_stripped(src: &str, tx: &Val, size: u64) -> bool { /// Valid unless the transaction is not a coinbase and its witness-stripped size is 64. fn spec_bip54_stripped(coinbase: bool, size: u64) -> bool { - !(!coinbase && size == 64) + coinbase || size != 64 } pub fn bip54_stripped_query(src: &str, tx: &Val, coinbase: bool, size: u64) -> SatResult { @@ -4309,11 +4302,8 @@ pub fn transaction_size_query(src: &str, wire: &[u8]) -> SatResult { fn header_record(version: i128, prev: u8, merkle: u8, time: i128, bits: i128, nonce: i128) -> Val { Val::Rec(vec![ ("version".into(), Val::Int(version)), - ( - "prev_block_hash".into(), - sample_eval::bytes(&vec![prev; 32]), - ), - ("merkle_root".into(), sample_eval::bytes(&vec![merkle; 32])), + ("prev_block_hash".into(), sample_eval::bytes(&[prev; 32])), + ("merkle_root".into(), sample_eval::bytes(&[merkle; 32])), ("timestamp".into(), Val::Int(time)), ("bits".into(), Val::Int(bits)), ("nonce".into(), Val::Int(nonce)), @@ -6606,22 +6596,22 @@ mod tests { let key_src = extract_fn(&file, "extract_taproot_output_key"); let valid = { let mut script = vec![0x51, 0x20]; - script.extend(std::iter::repeat(0x11).take(32)); + script.extend(std::iter::repeat_n(0x11, 32)); script }; let short = { let mut script = vec![0x51, 0x20]; - script.extend(std::iter::repeat(0x11).take(31)); + script.extend(std::iter::repeat_n(0x11, 31)); script }; let bad_prefix = { let mut script = vec![0x00, 0x20]; - script.extend(std::iter::repeat(0x11).take(32)); + script.extend(std::iter::repeat_n(0x11, 32)); script }; let bad_push = { let mut script = vec![0x51, 0x00]; - script.extend(std::iter::repeat(0x11).take(32)); + script.extend(std::iter::repeat_n(0x11, 32)); script }; for script in [&valid, &short, &bad_prefix, &bad_push] { @@ -6689,12 +6679,12 @@ mod tests { ); let p2wpkh = { let mut program = vec![0x00, 0x14]; - program.extend(std::iter::repeat(0x11).take(20)); + program.extend(std::iter::repeat_n(0x11, 20)); program }; let p2wsh = { let mut program = vec![0x00, 0x20]; - program.extend(std::iter::repeat(0x22).take(32)); + program.extend(std::iter::repeat_n(0x22, 32)); program }; let witness = [0x51u8]; @@ -7038,7 +7028,7 @@ mod tests { let push = extract_fn(&file, "sigop_count_push_opcode"); let valid = { let mut script = vec![0xa9, 0x14]; - script.extend(std::iter::repeat(0x11).take(20)); + script.extend(std::iter::repeat_n(0x11, 20)); script.push(0x87); script }; @@ -7947,7 +7937,7 @@ mod tests { redeem_push_query(&src, &trailer, &redeem22), SatResult::Unsat ); - let wrong = direct(&vec![0u8; 22]); + let wrong = direct(&[0u8; 22]); assert_eq!(redeem_push_query(&src, &wrong, &redeem22), SatResult::Unsat); let mut bad_opcode = redeem22.clone(); bad_opcode.insert(0, 0x4c); diff --git a/src/translator/sample_eval.rs b/src/translator/sample_eval.rs index a5cb474..c1a7e82 100644 --- a/src/translator/sample_eval.rs +++ b/src/translator/sample_eval.rs @@ -1008,7 +1008,7 @@ fn call_func( .next() .cloned() .unwrap_or_else(|| panic!("sample eval missing argument {name}")); - ctx.bind(&name, value); + ctx.bind(name, value); } let flow = eval_block(&func.block, ctx); let refs = func @@ -1024,7 +1024,7 @@ fn call_func( } let name = pat_ident(&typed.pat); Some( - ctx.get(&name) + ctx.get(name) .unwrap_or_else(|| panic!("missing mut {name}")), ) }) @@ -1491,9 +1491,7 @@ fn u256_shift(bytes: &[u8], shift: i128, left: bool) -> Vec { } } } else if bit_shift == 0 { - for index in word_shift..4 { - result[index - word_shift] = limbs[index]; - } + result[..(4 - word_shift)].copy_from_slice(&limbs[word_shift..4]); } else { for index in word_shift..4 { let mut word = limbs[index] >> bit_shift;