@@ -64,20 +64,6 @@ impl ScriptBuf {
64
64
/// Returns a mutable reference to unsized script.
65
65
pub fn as_mut_script ( & mut self ) -> & mut Script { Script :: from_bytes_mut ( & mut self . 0 ) }
66
66
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
-
81
67
/// Converts byte vector into script.
82
68
///
83
69
/// This method doesn't (re)allocate.
@@ -88,119 +74,151 @@ impl ScriptBuf {
88
74
/// This method doesn't (re)allocate.
89
75
pub fn into_bytes ( self ) -> Vec < u8 > { self . 0 }
90
76
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) }
99
89
}
90
+ }
100
91
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( )
125
101
}
126
- // Then push the raw bytes
127
- self . 0 . extend_from_slice ( data. as_bytes ( ) ) ;
128
- }
129
102
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) )
138
107
}
139
- }
140
108
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) ;
151
117
}
152
- }
153
118
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
+ }
159
138
}
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( ) ) ; }
160
155
}
156
+ }
161
157
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
+ }
177
167
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
+ }
187
193
}
188
- None => self . push_opcode ( OP_VERIFY ) ,
194
+ // Then push the raw bytes
195
+ this. extend_from_slice( data. as_bytes( ) ) ;
189
196
}
190
- }
191
197
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
+ }
204
222
}
205
223
}
206
224
@@ -250,3 +268,27 @@ impl<'a> Extend<Instruction<'a>> for ScriptBuf {
250
268
}
251
269
}
252
270
}
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