@@ -64,20 +64,6 @@ impl ScriptBuf {
6464 /// Returns a mutable reference to unsized script.
6565 pub fn as_mut_script ( & mut self ) -> & mut Script { Script :: from_bytes_mut ( & mut self . 0 ) }
6666
67- /// Creates a new script builder
68- pub fn builder ( ) -> Builder { Builder :: new ( ) }
69-
70- /// Generates OP_RETURN-type of scriptPubkey for the given data.
71- pub fn new_op_return < T : AsRef < PushBytes > > ( data : T ) -> Self {
72- Builder :: new ( ) . push_opcode ( OP_RETURN ) . push_slice ( data) . into_script ( )
73- }
74-
75- /// Creates a [`ScriptBuf`] from a hex string.
76- pub fn from_hex ( s : & str ) -> Result < Self , hex:: HexToBytesError > {
77- let v = Vec :: from_hex ( s) ?;
78- Ok ( ScriptBuf :: from_bytes ( v) )
79- }
80-
8167 /// Converts byte vector into script.
8268 ///
8369 /// This method doesn't (re)allocate.
@@ -88,119 +74,151 @@ impl ScriptBuf {
8874 /// This method doesn't (re)allocate.
8975 pub fn into_bytes ( self ) -> Vec < u8 > { self . 0 }
9076
91- /// Adds a single opcode to the script.
92- pub fn push_opcode ( & mut self , data : Opcode ) { self . 0 . push ( data. to_u8 ( ) ) ; }
93-
94- /// Adds instructions to push some arbitrary data onto the stack.
95- pub fn push_slice < T : AsRef < PushBytes > > ( & mut self , data : T ) {
96- let data = data. as_ref ( ) ;
97- self . reserve ( Self :: reserved_len_for_slice ( data. len ( ) ) ) ;
98- self . push_slice_no_opt ( data) ;
77+ /// Converts this `ScriptBuf` into a [boxed](Box) [`Script`].
78+ ///
79+ /// This method reallocates if the capacity is greater than length of the script but should not
80+ /// when they are equal. If you know beforehand that you need to create a script of exact size
81+ /// use [`reserve_exact`](Self::reserve_exact) before adding data to the script so that the
82+ /// reallocation can be avoided.
83+ #[ must_use = "`self` will be dropped if the result is not used" ]
84+ #[ inline]
85+ pub fn into_boxed_script ( self ) -> Box < Script > {
86+ // Copied from PathBuf::into_boxed_path
87+ let rw = Box :: into_raw ( self . 0 . into_boxed_slice ( ) ) as * mut Script ;
88+ unsafe { Box :: from_raw ( rw) }
9989 }
90+ }
10091
101- /// Pushes the slice without reserving
102- fn push_slice_no_opt ( & mut self , data : & PushBytes ) {
103- // Start with a PUSH opcode
104- match data. len ( ) . to_u64 ( ) {
105- n if n < opcodes:: Ordinary :: OP_PUSHDATA1 as u64 => {
106- self . 0 . push ( n as u8 ) ;
107- }
108- n if n < 0x100 => {
109- self . 0 . push ( opcodes:: Ordinary :: OP_PUSHDATA1 . to_u8 ( ) ) ;
110- self . 0 . push ( n as u8 ) ;
111- }
112- n if n < 0x10000 => {
113- self . 0 . push ( opcodes:: Ordinary :: OP_PUSHDATA2 . to_u8 ( ) ) ;
114- self . 0 . push ( ( n % 0x100 ) as u8 ) ;
115- self . 0 . push ( ( n / 0x100 ) as u8 ) ;
116- }
117- // `PushBytes` enforces len < 0x100000000
118- n => {
119- self . 0 . push ( opcodes:: Ordinary :: OP_PUSHDATA4 . to_u8 ( ) ) ;
120- self . 0 . push ( ( n % 0x100 ) as u8 ) ;
121- self . 0 . push ( ( ( n / 0x100 ) % 0x100 ) as u8 ) ;
122- self . 0 . push ( ( ( n / 0x10000 ) % 0x100 ) as u8 ) ;
123- self . 0 . push ( ( n / 0x1000000 ) as u8 ) ;
124- }
92+ crate :: internal_macros:: define_extension_trait! {
93+ /// Extension functionality for the [`ScriptBuf`] type.
94+ pub trait ScriptBufExt impl for ScriptBuf {
95+ /// Creates a new script builder
96+ fn builder( ) -> Builder { Builder :: new( ) }
97+
98+ /// Generates OP_RETURN-type of scriptPubkey for the given data.
99+ fn new_op_return<T : AsRef <PushBytes >>( data: T ) -> Self {
100+ Builder :: new( ) . push_opcode( OP_RETURN ) . push_slice( data) . into_script( )
125101 }
126- // Then push the raw bytes
127- self . 0 . extend_from_slice ( data. as_bytes ( ) ) ;
128- }
129102
130- /// Computes the sum of `len` and the length of an appropriate push opcode.
131- pub ( in crate :: blockdata:: script) fn reserved_len_for_slice ( len : usize ) -> usize {
132- len + match len {
133- 0 ..=0x4b => 1 ,
134- 0x4c ..=0xff => 2 ,
135- 0x100 ..=0xffff => 3 ,
136- // we don't care about oversized, the other fn will panic anyway
137- _ => 5 ,
103+ /// Creates a [`ScriptBuf`] from a hex string.
104+ fn from_hex( s: & str ) -> Result <ScriptBuf , hex:: HexToBytesError > {
105+ let v = Vec :: from_hex( s) ?;
106+ Ok ( ScriptBuf :: from_bytes( v) )
138107 }
139- }
140108
141- /// Add a single instruction to the script.
142- ///
143- /// # Panics
144- ///
145- /// The method panics if the instruction is a data push with length greater or equal to
146- /// 0x100000000.
147- pub fn push_instruction ( & mut self , instruction : Instruction < ' _ > ) {
148- match instruction {
149- Instruction :: Op ( opcode) => self . push_opcode ( opcode) ,
150- Instruction :: PushBytes ( bytes) => self . push_slice ( bytes) ,
109+ /// Adds a single opcode to the script.
110+ fn push_opcode( & mut self , data: Opcode ) { self . as_byte_vec( ) . push( data. to_u8( ) ) ; }
111+
112+ /// Adds instructions to push some arbitrary data onto the stack.
113+ fn push_slice<T : AsRef <PushBytes >>( & mut self , data: T ) {
114+ let data = data. as_ref( ) ;
115+ self . reserve( ScriptBuf :: reserved_len_for_slice( data. len( ) ) ) ;
116+ self . push_slice_no_opt( data) ;
151117 }
152- }
153118
154- /// Like push_instruction, but avoids calling `reserve` to not re-check the length.
155- pub fn push_instruction_no_opt ( & mut self , instruction : Instruction < ' _ > ) {
156- match instruction {
157- Instruction :: Op ( opcode) => self . push_opcode ( opcode) ,
158- Instruction :: PushBytes ( bytes) => self . push_slice_no_opt ( bytes) ,
119+ /// Add a single instruction to the script.
120+ ///
121+ /// # Panics
122+ ///
123+ /// The method panics if the instruction is a data push with length greater or equal to
124+ /// 0x100000000.
125+ fn push_instruction( & mut self , instruction: Instruction <' _>) {
126+ match instruction {
127+ Instruction :: Op ( opcode) => self . push_opcode( opcode) ,
128+ Instruction :: PushBytes ( bytes) => self . push_slice( bytes) ,
129+ }
130+ }
131+
132+ /// Like push_instruction, but avoids calling `reserve` to not re-check the length.
133+ fn push_instruction_no_opt( & mut self , instruction: Instruction <' _>) {
134+ match instruction {
135+ Instruction :: Op ( opcode) => self . push_opcode( opcode) ,
136+ Instruction :: PushBytes ( bytes) => self . push_slice_no_opt( bytes) ,
137+ }
159138 }
139+
140+ /// Adds an `OP_VERIFY` to the script or replaces the last opcode with VERIFY form.
141+ ///
142+ /// Some opcodes such as `OP_CHECKSIG` have a verify variant that works as if `VERIFY` was
143+ /// in the script right after. To save space this function appends `VERIFY` only if
144+ /// the most-recently-added opcode *does not* have an alternate `VERIFY` form. If it does
145+ /// the last opcode is replaced. E.g., `OP_CHECKSIG` will become `OP_CHECKSIGVERIFY`.
146+ ///
147+ /// Note that existing `OP_*VERIFY` opcodes do not lead to the instruction being ignored
148+ /// because `OP_VERIFY` consumes an item from the stack so ignoring them would change the
149+ /// semantics.
150+ ///
151+ /// This function needs to iterate over the script to find the last instruction. Prefer
152+ /// `Builder` if you're creating the script from scratch or if you want to push `OP_VERIFY`
153+ /// multiple times.
154+ fn scan_and_push_verify( & mut self ) { self . push_verify( self . last_opcode( ) ) ; }
160155 }
156+ }
161157
162- /// Adds an `OP_VERIFY` to the script or replaces the last opcode with VERIFY form.
163- ///
164- /// Some opcodes such as `OP_CHECKSIG` have a verify variant that works as if `VERIFY` was
165- /// in the script right after. To save space this function appends `VERIFY` only if
166- /// the most-recently-added opcode *does not* have an alternate `VERIFY` form. If it does
167- /// the last opcode is replaced. E.g., `OP_CHECKSIG` will become `OP_CHECKSIGVERIFY`.
168- ///
169- /// Note that existing `OP_*VERIFY` opcodes do not lead to the instruction being ignored
170- /// because `OP_VERIFY` consumes an item from the stack so ignoring them would change the
171- /// semantics.
172- ///
173- /// This function needs to iterate over the script to find the last instruction. Prefer
174- /// `Builder` if you're creating the script from scratch or if you want to push `OP_VERIFY`
175- /// multiple times.
176- pub fn scan_and_push_verify ( & mut self ) { self . push_verify ( self . last_opcode ( ) ) ; }
158+ crate :: internal_macros:: define_extension_trait! {
159+ pub ( crate ) trait ScriptBufExtPriv impl for ScriptBuf {
160+ /// Pretends to convert `&mut ScriptBuf` to `&mut Vec<u8>` so that it can be modified.
161+ ///
162+ /// Note: if the returned value leaks the original `ScriptBuf` will become empty.
163+ fn as_byte_vec( & mut self ) -> ScriptBufAsVec <' _> {
164+ let vec = core:: mem:: take( self ) . into_bytes( ) ;
165+ ScriptBufAsVec ( self , vec)
166+ }
177167
178- /// Adds an `OP_VERIFY` to the script or changes the most-recently-added opcode to `VERIFY`
179- /// alternative.
180- ///
181- /// See the public fn [`Self::scan_and_push_verify`] to learn more.
182- pub ( in crate :: blockdata:: script) fn push_verify ( & mut self , last_opcode : Option < Opcode > ) {
183- match opcode_to_verify ( last_opcode) {
184- Some ( opcode) => {
185- self . 0 . pop ( ) ;
186- self . push_opcode ( opcode) ;
168+ /// Pushes the slice without reserving
169+ fn push_slice_no_opt( & mut self , data: & PushBytes ) {
170+ let mut this = self . as_byte_vec( ) ;
171+ // Start with a PUSH opcode
172+ match data. len( ) . to_u64( ) {
173+ n if n < opcodes:: Ordinary :: OP_PUSHDATA1 as u64 => {
174+ this. push( n as u8 ) ;
175+ }
176+ n if n < 0x100 => {
177+ this. push( opcodes:: Ordinary :: OP_PUSHDATA1 . to_u8( ) ) ;
178+ this. push( n as u8 ) ;
179+ }
180+ n if n < 0x10000 => {
181+ this. push( opcodes:: Ordinary :: OP_PUSHDATA2 . to_u8( ) ) ;
182+ this. push( ( n % 0x100 ) as u8 ) ;
183+ this. push( ( n / 0x100 ) as u8 ) ;
184+ }
185+ // `PushBytes` enforces len < 0x100000000
186+ n => {
187+ this. push( opcodes:: Ordinary :: OP_PUSHDATA4 . to_u8( ) ) ;
188+ this. push( ( n % 0x100 ) as u8 ) ;
189+ this. push( ( ( n / 0x100 ) % 0x100 ) as u8 ) ;
190+ this. push( ( ( n / 0x10000 ) % 0x100 ) as u8 ) ;
191+ this. push( ( n / 0x1000000 ) as u8 ) ;
192+ }
187193 }
188- None => self . push_opcode ( OP_VERIFY ) ,
194+ // Then push the raw bytes
195+ this. extend_from_slice( data. as_bytes( ) ) ;
189196 }
190- }
191197
192- /// Converts this `ScriptBuf` into a [boxed](Box) [`Script`].
193- ///
194- /// This method reallocates if the capacity is greater than length of the script but should not
195- /// when they are equal. If you know beforehand that you need to create a script of exact size
196- /// use [`reserve_exact`](Self::reserve_exact) before adding data to the script so that the
197- /// reallocation can be avoided.
198- #[ must_use = "`self` will be dropped if the result is not used" ]
199- #[ inline]
200- pub fn into_boxed_script ( self ) -> Box < Script > {
201- // Copied from PathBuf::into_boxed_path
202- let rw = Box :: into_raw ( self . 0 . into_boxed_slice ( ) ) as * mut Script ;
203- unsafe { Box :: from_raw ( rw) }
198+ /// Computes the sum of `len` and the length of an appropriate push opcode.
199+ fn reserved_len_for_slice( len: usize ) -> usize {
200+ len + match len {
201+ 0 ..=0x4b => 1 ,
202+ 0x4c ..=0xff => 2 ,
203+ 0x100 ..=0xffff => 3 ,
204+ // we don't care about oversized, the other fn will panic anyway
205+ _ => 5 ,
206+ }
207+ }
208+
209+ /// Adds an `OP_VERIFY` to the script or changes the most-recently-added opcode to `VERIFY`
210+ /// alternative.
211+ ///
212+ /// See the public fn [`Self::scan_and_push_verify`] to learn more.
213+ fn push_verify( & mut self , last_opcode: Option <Opcode >) {
214+ match opcode_to_verify( last_opcode) {
215+ Some ( opcode) => {
216+ self . as_byte_vec( ) . pop( ) ;
217+ self . push_opcode( opcode) ;
218+ }
219+ None => self . push_opcode( OP_VERIFY ) ,
220+ }
221+ }
204222 }
205223}
206224
@@ -250,3 +268,27 @@ impl<'a> Extend<Instruction<'a>> for ScriptBuf {
250268 }
251269 }
252270}
271+
272+ /// Pretends that this is a mutable reference to [`ScriptBuf`]'s internal buffer.
273+ ///
274+ /// In reality the backing `Vec<u8>` is swapped with an empty one and this is holding both the
275+ /// reference and the vec. The vec is put back when this drops so it also covers paics. (But not
276+ /// leaks, which is OK since we never leak.)
277+ pub ( crate ) struct ScriptBufAsVec < ' a > ( & ' a mut ScriptBuf , Vec < u8 > ) ;
278+
279+ impl < ' a > core:: ops:: Deref for ScriptBufAsVec < ' a > {
280+ type Target = Vec < u8 > ;
281+
282+ fn deref ( & self ) -> & Self :: Target { & self . 1 }
283+ }
284+
285+ impl < ' a > core:: ops:: DerefMut for ScriptBufAsVec < ' a > {
286+ fn deref_mut ( & mut self ) -> & mut Self :: Target { & mut self . 1 }
287+ }
288+
289+ impl < ' a > Drop for ScriptBufAsVec < ' a > {
290+ fn drop ( & mut self ) {
291+ let vec = core:: mem:: take ( & mut self . 1 ) ;
292+ * ( self . 0 ) = ScriptBuf :: from_bytes ( vec) ;
293+ }
294+ }
0 commit comments