33//! High level APIs for creating C FFI compatible environment.
44//!
55
6+ use bitcoin:: taproot:: TAPROOT_ANNEX_PREFIX ;
67use hashes:: Hash ;
78use std:: os:: raw:: c_uchar;
89
@@ -33,7 +34,6 @@ struct RawOutputData {
3334/// passed to the C FFI.
3435#[ derive( Debug ) ]
3536struct RawInputData {
36- #[ allow( dead_code) ] // see FIXME below
3737 pub annex : Option < Vec < c_uchar > > ,
3838 // pegin
3939 pub genesis_hash : Option < [ c_uchar ; 32 ] > ,
@@ -75,8 +75,12 @@ fn new_raw_input<'raw>(
7575 inp_data : & ' raw RawInputData ,
7676) -> c_elements:: CRawInput < ' raw > {
7777 c_elements:: CRawInput {
78- // FIXME actually pass the annex in; see https://github.com/BlockstreamResearch/simplicity/issues/311 for some difficulty here.
79- annex : core:: ptr:: null ( ) ,
78+ annex : inp_data
79+ . annex
80+ . as_ref ( )
81+ . map ( |annex| c_elements:: CRawBuffer :: new ( annex) )
82+ . as_ref ( )
83+ . map_or ( core:: ptr:: null ( ) , |ptr| ptr as * const _ ) ,
8084 prev_txid : inp. previous_output . txid . as_ref ( ) ,
8185 pegin : inp_data. genesis_hash . as_ref ( ) ,
8286 issuance : if inp. has_issuance ( ) {
@@ -114,7 +118,7 @@ fn new_tx_data(tx: &elements::Transaction, in_utxos: &[ElementsUtxo]) -> RawTran
114118 } ;
115119 for ( inp, in_utxo) in tx. input . iter ( ) . zip ( in_utxos. iter ( ) ) {
116120 let inp_data = RawInputData {
117- annex : None , // Actually store annex
121+ annex : get_annex ( & inp . witness ) . map ( |s| s . to_vec ( ) ) ,
118122 genesis_hash : inp
119123 . pegin_data ( )
120124 . map ( |x| x. genesis_hash . to_raw_hash ( ) . to_byte_array ( ) ) ,
@@ -148,14 +152,29 @@ pub(super) fn new_tx(
148152) -> * mut c_elements:: CTransaction {
149153 let mut raw_inputs = Vec :: new ( ) ;
150154 let mut raw_outputs = Vec :: new ( ) ;
155+ // Allocate space for the raw annexes. This dumb `Vec::from_iter` construction is
156+ // equivalent to `vec![None; tx.input.len()]`, but that won't compile because it
157+ // requires Option::<CRawBuffer>::None to be cloneable, which it's not because
158+ // CRawBuffer isn't.
159+
160+ // SAFETY: this allocation *must* live until after the `simplicity_mallocTransaction`
161+ // at the bottom of this function. We convert the vector to a boxed slice to ensure
162+ // it cannot be resized, which would potentially trigger a reallocation.
163+ let mut raw_annexes = Vec :: from_iter ( ( 0 ..tx. input . len ( ) ) . map ( |_| None ) ) . into_boxed_slice ( ) ;
164+
151165 let txid = tx. txid ( ) ;
152166 let tx_data = new_tx_data ( tx, in_utxos) ;
153- for ( ( inp, in_utxo) , inp_data) in tx
167+ for ( ( ( n , inp) , in_utxo) , inp_data) in tx
154168 . input
155169 . iter ( )
170+ . enumerate ( )
156171 . zip ( in_utxos. iter ( ) )
157172 . zip ( tx_data. inputs . iter ( ) )
158173 {
174+ raw_annexes[ n] = inp_data
175+ . annex
176+ . as_ref ( )
177+ . map ( |annex| c_elements:: CRawBuffer :: new ( annex) ) ;
159178 let res = new_raw_input ( inp, in_utxo, inp_data) ;
160179 raw_inputs. push ( res) ;
161180 }
@@ -172,10 +191,17 @@ pub(super) fn new_tx(
172191 version : tx. version ,
173192 locktime : tx. lock_time . to_consensus_u32 ( ) ,
174193 } ;
175- unsafe {
194+ let ret = unsafe {
176195 // SAFETY: this is a FFI call and we constructed its argument correctly.
177196 c_elements:: simplicity_mallocTransaction ( & c_raw_tx)
178- }
197+ } ;
198+
199+ // Explicitly drop raw_annexes so Rust doesn't try any funny business dropping it early.
200+ // Drop raw_inputs first since it contains pointers into raw_annexes and we don't want
201+ // them to dangle. (It'd be safe since they're raw pointers, but still bad mojo.)
202+ drop ( raw_inputs) ;
203+ drop ( raw_annexes) ;
204+ ret
179205}
180206
181207pub ( super ) fn new_tap_env (
@@ -256,3 +282,13 @@ fn serialize_surjection_proof(surjection_proof: &Option<Box<SurjectionProof>>) -
256282 . map ( |x| x. serialize ( ) )
257283 . unwrap_or_default ( )
258284}
285+
286+ /// If the last item in the witness stack is an annex, return the data following the 0x50 byte.
287+ fn get_annex ( in_witness : & elements:: TxInWitness ) -> Option < & [ u8 ] > {
288+ let last_item = in_witness. script_witness . last ( ) ?;
289+ if * last_item. first ( ) ? == TAPROOT_ANNEX_PREFIX {
290+ Some ( & last_item[ 1 ..] )
291+ } else {
292+ None
293+ }
294+ }
0 commit comments