@@ -8,10 +8,8 @@ use group::GroupEncoding;
8
8
use sapling:: { note_encryption:: SaplingDomain , SaplingVerificationContext } ;
9
9
use secp256k1:: { Secp256k1 , VerifyOnly } ;
10
10
11
- #[ allow( deprecated) ]
12
- use :: transparent:: keys:: pubkey_to_address;
13
11
use :: transparent:: {
14
- address:: { Script , TransparentAddress } ,
12
+ address:: TransparentAddress ,
15
13
bundle as transparent,
16
14
sighash:: { SighashType , TransparentAuthorizingContext } ,
17
15
} ;
@@ -33,6 +31,10 @@ use zcash_protocol::{
33
31
memo:: { Memo , MemoBytes } ,
34
32
value:: Zatoshis ,
35
33
} ;
34
+ use zcash_script:: {
35
+ opcode:: { Opcode , PushValue , SmallValue } ,
36
+ script,
37
+ } ;
36
38
37
39
use super :: {
38
40
context:: { Context , ZTxOut } ,
@@ -46,43 +48,45 @@ pub fn is_coinbase(tx: &Transaction) -> bool {
46
48
}
47
49
48
50
pub fn extract_height_from_coinbase ( tx : & Transaction ) -> Option < BlockHeight > {
49
- const OP_0 : u8 = 0x00 ;
50
- const OP_1NEGATE : u8 = 0x4f ;
51
- const OP_1 : u8 = 0x51 ;
52
- const OP_16 : u8 = 0x60 ;
53
-
54
51
tx. transparent_bundle ( )
55
52
. and_then ( |bundle| bundle. vin . first ( ) )
56
- . and_then ( |input| match input. script_sig . 0 . first ( ) . copied ( ) {
57
- // {0, -1} will never occur as the first byte of a coinbase scriptSig.
58
- Some ( OP_0 | OP_1NEGATE ) => None ,
59
- // Blocks 1 to 16.
60
- Some ( h @ OP_1 ..=OP_16 ) => Some ( BlockHeight :: from_u32 ( ( h - OP_1 + 1 ) . into ( ) ) ) ,
61
- // All other heights use CScriptNum encoding, which will never be longer
62
- // than 5 bytes for Zcash heights. These have the format
63
- // `[len(encoding)] || encoding`.
64
- Some ( h @ 1 ..=5 ) => {
65
- let rest = & input. script_sig . 0 [ 1 ..] ;
66
- let encoding_len = h as usize ;
67
- if rest. len ( ) < encoding_len {
68
- None
69
- } else {
70
- // Parse the encoding.
71
- let encoding = & rest[ ..encoding_len] ;
72
- if encoding. last ( ) . unwrap ( ) & 0x80 != 0 {
73
- // Height is never negative.
74
- None
75
- } else {
76
- let mut height: u64 = 0 ;
77
- for ( i, b) in encoding. iter ( ) . enumerate ( ) {
78
- height |= ( * b as u64 ) << ( 8 * i) ;
53
+ . and_then ( |input| {
54
+ input
55
+ . script_sig
56
+ . opcodes ( )
57
+ . first ( )
58
+ . and_then ( |opcode| match opcode {
59
+ Opcode :: PushValue ( PushValue :: SmallValue ( v) ) => match v {
60
+ // // {0, -1} will never occur as the first byte of a coinbase scriptSig.
61
+ SmallValue :: OP_0 | SmallValue :: OP_1NEGATE => None ,
62
+ // Invalid
63
+ SmallValue :: OP_RESERVED => None ,
64
+ // Blocks 1 to 16.
65
+ h => Some ( BlockHeight :: from_u32 ( u32:: from (
66
+ * h. value ( ) . expect ( "valid" ) . first ( ) . expect ( "valid" ) ,
67
+ ) ) ) ,
68
+ } ,
69
+ // All other heights use CScriptNum encoding, which will never be longer
70
+ // than 5 bytes for Zcash heights. These have the format
71
+ // `[len(encoding)] || encoding`.
72
+ // h @ 1..=5 =>
73
+ Opcode :: PushValue ( PushValue :: LargeValue ( v) ) => {
74
+ // Parse the encoding.
75
+ let encoding = v. value ( ) ;
76
+ if encoding. last ( ) . unwrap ( ) & 0x80 != 0 {
77
+ // Height is never negative.
78
+ None
79
+ } else {
80
+ let mut height: u64 = 0 ;
81
+ for ( i, b) in encoding. iter ( ) . enumerate ( ) {
82
+ height |= ( * b as u64 ) << ( 8 * i) ;
83
+ }
84
+ height. try_into ( ) . ok ( )
79
85
}
80
- height. try_into ( ) . ok ( )
81
86
}
82
- }
83
- }
84
- // Anything else is an invalid height encoding.
85
- _ => None ,
87
+ // Anything else is an invalid height encoding.
88
+ _ => None ,
89
+ } )
86
90
} )
87
91
}
88
92
@@ -109,7 +113,7 @@ pub(crate) struct TransparentAuth {
109
113
}
110
114
111
115
impl transparent:: Authorization for TransparentAuth {
112
- type ScriptSig = Script ;
116
+ type ScriptSig = script :: Sig < Opcode > ;
113
117
}
114
118
115
119
impl TransparentAuthorizingContext for TransparentAuth {
@@ -120,7 +124,7 @@ impl TransparentAuthorizingContext for TransparentAuth {
120
124
. collect ( )
121
125
}
122
126
123
- fn input_scriptpubkeys ( & self ) -> Vec < Script > {
127
+ fn input_scriptpubkeys ( & self ) -> Vec < script :: PubKey > {
124
128
self . all_prev_outputs
125
129
. iter ( )
126
130
. map ( |prevout| prevout. script_pubkey . clone ( ) )
@@ -246,39 +250,23 @@ pub(crate) fn inspect(
246
250
) ;
247
251
match coin. recipient_address ( ) {
248
252
Some ( addr @ TransparentAddress :: PublicKeyHash ( _) ) => {
249
- // Format is [sig_and_type_len] || sig || [hash_type] || [pubkey_len] || pubkey
253
+ // Format is PushData( sig || [hash_type]) || PushData( pubkey)
250
254
// where [x] encodes a single byte.
251
- let sig_and_type_len = txin. script_sig . 0 . first ( ) . map ( |l| * l as usize ) ;
252
- let pubkey_len = sig_and_type_len
253
- . and_then ( |sig_len| txin. script_sig . 0 . get ( 1 + sig_len) )
254
- . map ( |l| * l as usize ) ;
255
- let script_len = sig_and_type_len. zip ( pubkey_len) . map (
256
- |( sig_and_type_len, pubkey_len) | {
257
- 1 + sig_and_type_len + 1 + pubkey_len
258
- } ,
259
- ) ;
260
-
261
- if Some ( txin. script_sig . 0 . len ( ) ) != script_len {
262
- eprintln ! (
263
- " ⚠️ \" transparentcoins\" {} is P2PKH; txin {} scriptSig has length {} but data {}" ,
264
- i,
265
- i,
266
- txin. script_sig. 0 . len( ) ,
267
- if let Some ( l) = script_len {
268
- format!( "implies length {l}." )
269
- } else {
270
- "would cause an out-of-bounds read." . to_owned( )
271
- } ,
272
- ) ;
273
- } else {
274
- let sig_len = sig_and_type_len. unwrap ( ) - 1 ;
275
-
276
- let sig = secp256k1:: ecdsa:: Signature :: from_der (
277
- & txin. script_sig . 0 [ 1 ..1 + sig_len] ,
278
- ) ;
279
- let hash_type = SighashType :: parse ( txin. script_sig . 0 [ 1 + sig_len] ) ;
280
- let pubkey_bytes = & txin. script_sig . 0 [ 1 + sig_len + 2 ..] ;
281
- let pubkey = secp256k1:: PublicKey :: from_slice ( pubkey_bytes) ;
255
+ let ( sig_and_type, pubkey) = match txin. script_sig . opcodes ( ) {
256
+ [ Opcode :: PushValue ( sig_and_type) , Opcode :: PushValue ( pubkey) ] => {
257
+ ( sig_and_type. value ( ) , pubkey. value ( ) )
258
+ }
259
+ _ => ( None , None ) ,
260
+ } ;
261
+
262
+ if let Some ( ( ( & hash_type, sig) , pubkey_bytes) ) = sig_and_type
263
+ . as_ref ( )
264
+ . and_then ( |b| b. split_last ( ) )
265
+ . zip ( pubkey)
266
+ {
267
+ let sig = secp256k1:: ecdsa:: Signature :: from_der ( sig) ;
268
+ let hash_type = SighashType :: parse ( hash_type) ;
269
+ let pubkey = secp256k1:: PublicKey :: from_slice ( & pubkey_bytes) ;
282
270
283
271
if let Err ( e) = sig {
284
272
eprintln ! (
@@ -294,8 +282,7 @@ pub(crate) fn inspect(
294
282
if let ( Ok ( sig) , Some ( hash_type) , Ok ( pubkey) ) =
295
283
( sig, hash_type, pubkey)
296
284
{
297
- #[ allow( deprecated) ]
298
- if pubkey_to_address ( & pubkey) != addr {
285
+ if TransparentAddress :: from_pubkey ( & pubkey) != addr {
299
286
eprintln ! ( " ⚠️ Txin {i} pubkey does not match coin's script_pubkey" ) ;
300
287
}
301
288
0 commit comments