Repository navigation
Conversation
Don't actually build bitcoin yet; just refactor build.rs
For dumb "C polymorphism" reasons we have two structures in the C code named txEnv. We can call the corresponding Rust structures different things, but we need to access them from the C file env.c, which provides some C wrappers for FFI stuff. Since you can't have two different structs with the same name in one compilation unit, split it into two: add depend/bitcoin_env.c holding the Bitcoin txEnv wrappers, alongside the existing depend/env.c for Elements.
This is the more correct trait. When we update the Jet trait we will be forced to pick one, and we will pick Borrow.
Updates to BlockstreamResearch/simplicity#324 This PR does a couple things simultaneously: * Runs vendor-simplicity.sh and update-jets.sh * Updates the `Jet` trait to have associated transaction and environment types, and for the environment to be paramterized by the transaction type. * Changes the Core environment from () to CoreEnv::<Infallible> * Updates some fixed Core CMR/IHR vectors (this update to libsimplicity changes the benchmarks for the Core jets and thus changes these vectors) * Uncomments the commented-out symbols in simplicity-sys/src/c_jets/c_env/bitcoin.rs * Adds the "build bitcoin" lines to simplicity-sys/build.rs The update to the `Jet` trait is a bit noisy but ultimately mechanical: everywhere that we're generic over all J: Jet, we now also have to be generic over all T: Borrow<J::Transaction>, which leads to some extra line noise especially in unit tests where we have assert_* helper functions. The last four points are tiny diffs, thanks to the previous preparatory commits. The use of CoreEnv::<Infallible> as the core environment type is kinda fun. It means that it is impossible to execute any code which attempts to access the transaction in the environment. (No such code exists, since it would be nonsensical, but now we have some assurance that it won't exist by accident in the future.) Unfortunately this mixes mechanical and non-mechanical things in one commit. But the mechanical changes are exclusively in simplicity-sys/depend/ and src/jet/init/ and the non-mechanical changes are exclusively outside of those files, so it should be possible to review this.
Change the JetEnvironment impl for BitcoinEnv and ElementsEnv to be generic over T: Borrow<Transaction> instead of fixed to Arc<Transaction>. Update Policy::satisfy, get_satisfier, execute_successful, execute_unsuccessful, and serialize test helpers to accept ElementsEnv<impl Borrow<Transaction>>. This allows callers to construct environments without Arc overhead (for example, using a plain reference or owned value), and is required so that BitcoinEnv::c_jet_env can return a real CTxEnv from a borrowed transaction.
Now that we've updated the Jet trait to allow the transactions in environments to be arbitrary T: Borrow<Transaction>, we don't need to use Arc everywhere. In many cases we can use normal references.
This is a Rust type which can be used, among other things, to construct the transaction environment needed by C jets. Also provides accessors for the underlying transaction and input index, both of which are used (in the Elements version of this struct) in the policy satisfier.
rust-bitcoin 0.32 removed Witness::taproot_annex. Replace it with an inline BIP341 annex extraction: the last witness element that begins with 0x50 is the annex. This matches the Elements c_env helper and the BIP341 specification.
9c7f56c to
1f91d94
Compare
|
Force pushed to fix the MSRV job, which required splitting the shared files into their own RustSimplicityCommon static lib that both Bitcoin and Elements link against, instead of duplicating them. This is because MSRV 1.74.0 forces -Wl,--whole-archive on every native static lib rustc links, which pulls every object from both archives and hits "multiple definition of" for every shared symbol. |
| /// Extracts the annex from a taproot witness stack per BIP341: if there are at | ||
| /// least two witness elements and the last one starts with 0x50, it is the annex. | ||
| /// (rust-bitcoin 0.32 removed `Witness::taproot_annex`.) | ||
| fn get_annex(in_witness: &bitcoin::Witness) -> Option<&[u8]> { |
There was a problem hiding this comment.
This needs the same treatment as #384
Will do this together with any other review changes since the next 3 PRs will have to be rebased on top
| rustsimplicity_0_8_free(analysis); | ||
| } | ||
| if (IS_OK(*error)) { | ||
| txEnv env = rustsimplicity_0_8_bitcoin_build_txEnv(tx, taproot, ix); |
There was a problem hiding this comment.
Is it an intentional design that we do not include genesisHash to txEnv?
It is a difference I see with Elements case. I think genesisHash inclusion was preventing replay attacks
There was a problem hiding this comment.
The genesis hash for signatures is specific to elements. For bitcoin, the genesis hash is not traditionally included in the signatures. If we added it here, I think we would have to add it to libsimplicity as well.
There was a problem hiding this comment.
Double checked with AI:
Confirmed against the vendored libsimplicity: the Bitcoin txEnv has no genesis hash and sigAllHash commits only to txHash, tapEnvHash and ix. That matches Bitcoin's own sighashes, which have no chain ID. Adding one would change Bitcoin Simplicity's consensus semantics, so it would need to be decided upstream rather than here.
There was a problem hiding this comment.
I see, this is only Elements quirk
| [ | ||
| "bitcoin/exec.c", | ||
| "bitcoin/primitive.c", | ||
| // "bitcoin/checkSigHashAllTx1.c", // no sighashall test |
There was a problem hiding this comment.
Depending on the intention of this comment, we could remove it if this check is redundant. Or, we could add a TODO here to say that we will add the Bitcoin version later.
Either way, if somebody is even bored enough to do this, let's maybe do it in a follow-up, so we don't stall the review with small stuff.
There was a problem hiding this comment.
Do we need this empty file
|
ACK, ran tests on 1f91d94. Looks nice |
KyrylR
left a comment
There was a problem hiding this comment.
AI-generated code review, posted by Codex at the GitHub account holder's request. The four inline findings are based on independent read-only reviews by exact models Claude Opus 5.5 (claude-opus-5-5, High) and Claude Mythos 5.1 (claude-mythos-5-1, High), with local reproductions by Codex. The account holder did not author these findings. This is a comment-only review.
| fn get_annex(in_witness: &bitcoin::Witness) -> Option<&[u8]> { | ||
| let last_item = in_witness.last()?; | ||
| if *last_item.first()? == TAPROOT_ANNEX_PREFIX { | ||
| Some(last_item) |
There was a problem hiding this comment.
AI review finding. Based on independent read-only reviews by Claude Opus 5.5 (claude-opus-5-5, High) and Claude Mythos 5.1 (claude-mythos-5-1, High). Posted by Codex at the account holder's request; this is not the account holder's own authored review.
[P1] Strip the annex marker before passing it to libsimplicity. Some(last_item) includes the leading 0x50, but the pinned compatible Signet node passes data()+1 and size()-1 to the same C environment. The Elements wrapper strips the marker too. bitcoin/env.c hashes the supplied annex bytes into txHash and sigAllHash. A local exact-head probe found the PR's full-element digest 261ca392… versus 87308987… with the node's stripped annex. An annex-bearing signature generated from this environment will therefore disagree with that node. Please pass the payload after 0x50 and add an annex-bearing regression test. This concerns the Simplicity C environment interface; BIP341's separate TapSighash rule includes the marker.
| /// (rust-bitcoin 0.32 removed `Witness::taproot_annex`.) | ||
| fn get_annex(in_witness: &bitcoin::Witness) -> Option<&[u8]> { | ||
| let last_item = in_witness.last()?; | ||
| if *last_item.first()? == TAPROOT_ANNEX_PREFIX { |
There was a problem hiding this comment.
AI review finding. Based on independent read-only reviews by Claude Opus 5.5 (claude-opus-5-5, High) and Claude Mythos 5.1 (claude-mythos-5-1, High). Posted by Codex at the account holder's request; this is not the account holder's own authored review.
[P2] Require at least two witness items before recognizing an annex. This prefix check accepts a single witness item beginning 0x50, although BIP341 and the pinned node require at least two items. In the local exact-head probe, a one-item 0x50 witness changed the digest to the same value as a real two-item annex; a one-item ordinary witness did not. A key-path input in a mixed-input transaction can therefore change the Rust-side hash unexpectedly. Please guard on in_witness.len() >= 2 and test the one-item case. This expands the existing #384-related note on this helper.
| script_cmr: Cmr, | ||
| control_block: ControlBlock, | ||
| ) -> Self { | ||
| let c_tx = c_env::new_tx(tx.borrow(), utxos); |
There was a problem hiding this comment.
AI review finding. Based on independent read-only reviews by Claude Opus 5.5 (claude-opus-5-5, High) and Claude Mythos 5.1 (claude-mythos-5-1, High). Posted by Codex at the account holder's request; this is not the account holder's own authored review.
[P2] Validate UTXO count and the current input index before building the C environment. c_env::new_tx uses tx.input.iter().zip(in_utxos.iter()), which silently truncates the C input array when the UTXO slice is short. A local exact-head probe changed the omitted second input and found the same digest; with both UTXOs supplied, the digest changed. This safe constructor also accepts ix >= tx.input.len(), violating the C build_txEnv precondition. Please reject mismatched lengths and an out-of-range index before allocation. The hash is wrong with a short slice today; downstream jet use could index outside the C input array.
There was a problem hiding this comment.
Double check from GPT 6 Sol (Max effort) with Daybreak:
Short UTXO slice: confirmed; out-of-bounds consequence overstated. With two transaction inputs but one supplied UTXO, changing the omitted second input leaves the PR digest unchanged; with two UTXOs it changes. The safe BitcoinEnv::new also accepts ix=1 for a one-input transaction, despite the C build_txEnv precondition. However, the currently vendored build_txEnv does not dereference the indexed input, and every env->tx->input[env->ix] access found in bitcoinJets.c is preceded by a bounds check. The posted comment's statement that downstream jet use could index outside the C array is speculative and not supported by this revision. No out-of-bounds access was observed. The missing-UTXO hash defect and invalid-index acceptance remain valid.
| * unsigned char cmr[32] | ||
| * unsigned char program[program_len] | ||
| */ | ||
| bool rustsimplicity_0_6_computeCmr( simplicity_err* error, unsigned char* cmr, rustsimplicity_0_6_callback_decodeJet decodeJet |
There was a problem hiding this comment.
AI review finding. Based on independent read-only reviews by Claude Opus 5.5 (claude-opus-5-5, High) and Claude Mythos 5.1 (claude-mythos-5-1, High). Posted by Codex at the account holder's request; this is not the account holder's own authored review.
[P2] Reconcile the vendored C files with their recorded source revision and symbol version. simplicity-HEAD-revision.txt still names ba967b1a, but the newly added C/header files are absent from that revision. This file uses rustsimplicity_0_6_* names alongside the repository's 0_8_* declarations; bitcoin/cmr.c calls the 0_8 CMR symbol, and bitcoin/exec.h declares a 0_6 symbol while exec.c defines 0_8. Standalone syntax checks of both cmr.c files fail with unknown or undeclared symbols. Cargo passes because it does not compile these files today. Please re-vendor from the actual upstream revision or normalize the files and compile-check them before they are wired in.
There was a problem hiding this comment.
I wanted to ask the same question in the other PR, if vendor-simplicity.sh was called
|
Other than that that, I reviewed every commit manually, from a0b5435 to 1f91d94. LGTM! |
|
AI finding (Claude Opus 5.5, Extra High): We pass each input's real |
|
I also ran Claude Opus 5.5 Extra High on the entire PR, and it found the same problems as Kyrylo's AI review and marked them as blockers |
Redux of #331.
Covers the same ground: vendoring the bitcoin-env libsimplicity branch and adding the Rust
BitcoinEnv/JetEnvironmentplumbing.Why a new branch instead of updating #331:
ba967b1a(the rev shipped with simplicity-lang 0.9.0, already onmaster);rustsimplicity_0_8_*.CoreEnv::EMPTY(added inb0a25c2) is not needed or referenced by this series and is intentionally omitted.Three additional PRs stack on this one: #386 #387 #388