1515//! # Transactions
1616//!
1717
18+ mod pegin_witness;
1819mod witness;
1920
2021use std:: { io, fmt, str, cmp} ;
@@ -23,7 +24,6 @@ use std::convert::TryFrom;
2324
2425use bitcoin:: { self , VarInt } ;
2526use bitcoin:: hashes:: Hash as _;
26- use internals:: slice:: SliceExt ;
2727use crate :: hashes:: { sha256d, HashEngine as _} ;
2828
2929use crate :: { confidential, ContractHash } ;
@@ -37,6 +37,9 @@ use secp256k1_zkp::{
3737 Tweak , ZERO_TWEAK ,
3838} ;
3939
40+ pub use self :: pegin_witness:: {
41+ PeginData , PeginDataDecoder , PeginDataEncoder ,
42+ PeginWitness , PeginWitnessDecoder , PeginWitnessDecoderError , PeginWitnessEncoder } ;
4043pub use self :: witness:: { Witness , WitnessDecoder , WitnessDecoderError , WitnessEncoder } ;
4144
4245/// Description of an asset issuance in a transaction input
@@ -371,7 +374,7 @@ pub struct TxInWitness {
371374 /// Traditional script witness
372375 pub script_witness : Witness ,
373376 /// Pegin witness, basically the same thing
374- pub pegin_witness : Vec < Vec < u8 > > ,
377+ pub pegin_witness : PeginWitness ,
375378}
376379impl_consensus_encoding ! ( TxInWitness , amount_rangeproof, inflation_keys_rangeproof, script_witness, pegin_witness) ;
377380
@@ -382,7 +385,7 @@ impl TxInWitness {
382385 amount_rangeproof : RangeProof :: EMPTY ,
383386 inflation_keys_rangeproof : RangeProof :: EMPTY ,
384387 script_witness : Witness :: new ( ) ,
385- pegin_witness : Vec :: new ( ) ,
388+ pegin_witness : PeginWitness :: EMPTY ,
386389 }
387390 }
388391
@@ -401,84 +404,6 @@ impl Default for TxInWitness {
401404 }
402405}
403406
404-
405- /// Parsed data from a transaction input's pegin witness
406- #[ derive( Copy , Clone , PartialEq , Eq , Debug , Hash ) ]
407- pub struct PeginData < ' tx > {
408- /// Reference to the pegin output on the mainchain
409- pub outpoint : bitcoin:: OutPoint ,
410- /// The value, in satoshis, of the pegin
411- pub value : u64 ,
412- /// Asset type being pegged in
413- pub asset : AssetId ,
414- /// Hash of genesis block of originating blockchain
415- pub genesis_hash : bitcoin:: BlockHash ,
416- /// The claim script that we should hash to tweak our address. Unparsed
417- /// to avoid unnecessary allocation and copying. Typical use is simply
418- /// to feed it raw into a hash function.
419- pub claim_script : & ' tx [ u8 ] ,
420- /// Mainchain transaction; not parsed to save time/memory since the
421- /// parsed transaction is typically not useful without auxiliary
422- /// data (e.g. knowing how to compute pegin addresses for the
423- /// sidechain).
424- pub tx : & ' tx [ u8 ] ,
425- /// Merkle proof of transaction inclusion; also not parsed
426- pub merkle_proof : & ' tx [ u8 ] ,
427- /// The Bitcoin block that the pegin output appears in; scraped
428- /// from the transaction inclusion proof
429- pub referenced_block : bitcoin:: BlockHash ,
430- }
431-
432- impl < ' tx > PeginData < ' tx > {
433- /// Construct the pegin data from a pegin witness.
434- /// Returns None if not a valid pegin witness.
435- pub fn from_pegin_witness (
436- pegin_witness : & ' tx [ Vec < u8 > ] ,
437- prevout : bitcoin:: OutPoint ,
438- ) -> Result < PeginData < ' tx > , & ' static str > {
439- let Ok ( pegin_witness) = <& [ Vec < u8 > ; 6 ] >:: try_from ( pegin_witness) else {
440- return Err ( "size not 6" ) ;
441- } ;
442- let Some ( ( block_header, _) ) = SliceExt :: split_first_chunk :: < 80 > ( pegin_witness[ 5 ] . as_slice ( ) ) else {
443- return Err ( "merkle proof too short" ) ;
444- } ;
445-
446- Ok ( PeginData {
447- outpoint : prevout,
448- value : bitcoin:: consensus:: deserialize ( & pegin_witness[ 0 ] ) . map_err ( |_| "invalid value" ) ?,
449- asset : encode:: deserialize ( & pegin_witness[ 1 ] ) . map_err ( |_| "invalid asset" ) ?,
450- genesis_hash : bitcoin:: consensus:: deserialize ( & pegin_witness[ 2 ] )
451- . map_err ( |_| "invalid genesis hash" ) ?,
452- claim_script : & pegin_witness[ 3 ] ,
453- tx : & pegin_witness[ 4 ] ,
454- merkle_proof : & pegin_witness[ 5 ] ,
455- referenced_block : bitcoin:: BlockHash :: hash ( block_header) ,
456- } )
457- }
458-
459- /// Construct a pegin witness from the pegin data.
460- pub fn to_pegin_witness ( & self ) -> Vec < Vec < u8 > > {
461- vec ! [
462- bitcoin:: consensus:: serialize( & self . value) ,
463- encode:: serialize( & self . asset) ,
464- bitcoin:: consensus:: serialize( & self . genesis_hash) ,
465- self . claim_script. to_vec( ) ,
466- self . tx. to_vec( ) ,
467- self . merkle_proof. to_vec( ) ,
468- ]
469- }
470-
471- /// Parse the mainchain tx provided as pegin data.
472- pub fn parse_tx ( & self ) -> Result < bitcoin:: Transaction , bitcoin:: consensus:: encode:: Error > {
473- bitcoin:: consensus:: encode:: deserialize ( self . tx )
474- }
475-
476- /// Parse the merkle inclusion proof provided as pegin data.
477- pub fn parse_merkle_proof ( & self ) -> Result < bitcoin:: MerkleBlock , bitcoin:: consensus:: encode:: Error > {
478- bitcoin:: consensus:: encode:: deserialize ( self . merkle_proof )
479- }
480- }
481-
482407/// A transaction input, which defines old coins to be consumed
483408#[ derive( Clone , PartialEq , Eq , Debug , Hash , PartialOrd , Ord ) ]
484409pub struct TxIn {
@@ -603,10 +528,8 @@ impl TxIn {
603528 /// Extracts witness data from a pegin. Will return `None` if any data
604529 /// cannot be parsed. The combination of `is_pegin()` returning `true`
605530 /// and `pegin_data()` returning `None` indicates an invalid transaction.
606- pub fn pegin_data ( & self ) -> Option < PeginData < ' _ > > {
607- self . pegin_prevout ( ) . and_then ( |p| {
608- PeginData :: from_pegin_witness ( & self . witness . pegin_witness , p) . ok ( )
609- } )
531+ pub fn pegin_data ( & self ) -> Option < & PeginData > {
532+ self . witness . pegin_witness . data ( )
610533 }
611534
612535 /// Helper to determine whether an input has an asset issuance attached
@@ -961,11 +884,7 @@ impl Transaction {
961884 VarInt ( wit. len ( ) as u64 ) . size ( ) +
962885 wit. len ( )
963886 ) . sum :: < usize > ( ) +
964- VarInt ( input. witness . pegin_witness . len ( ) as u64 ) . size ( ) +
965- input. witness . pegin_witness . iter ( ) . map ( |wit|
966- VarInt ( wit. len ( ) as u64 ) . size ( ) +
967- wit. len ( )
968- ) . sum :: < usize > ( )
887+ input. witness . pegin_witness . encoded_size ( )
969888 } else {
970889 0
971890 }
@@ -1654,24 +1573,18 @@ mod tests {
16541573 assert_eq ! ( tx. input[ 0 ] . witness. pegin_witness. len( ) , 6 ) ;
16551574 assert_eq ! (
16561575 tx. input[ 0 ] . pegin_data( ) ,
1657- Some ( super :: PeginData {
1658- outpoint: bitcoin:: OutPoint {
1659- txid: bitcoin:: Txid :: from_str(
1660- "c9d88eb5130365deed045eab11cfd3eea5ba32ad45fa2e156ae6ead5f1fce93f" ,
1661- ) . unwrap( ) ,
1662- vout: 0 ,
1663- } ,
1576+ Some ( & super :: PeginData {
16641577 value: 100_000_000 ,
1665- asset : tx. output[ 0 ] . asset. explicit( ) . unwrap( ) ,
1578+ asset_id : tx. output[ 0 ] . asset. explicit( ) . unwrap( ) ,
16661579 genesis_hash: bitcoin:: BlockHash :: from_str(
16671580 "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"
16681581 ) . unwrap( ) ,
1669- claim_script: & [
1582+ claim_script: bitcoin :: ScriptBuf :: from ( vec! [
16701583 0x00 , 0x14 , 0x1a , 0xb7 , 0xf5 , 0x99 , 0x5c , 0xf0 ,
16711584 0xdf , 0xcb , 0x90 , 0xcb , 0xb0 , 0x2b , 0x63 , 0x39 ,
16721585 0x7e , 0x53 , 0x26 , 0xea , 0xe6 , 0xfe ,
1673- ] ,
1674- tx : & [
1586+ ] ) ,
1587+ transaction : vec! [
16751588 0x02 , 0x00 , 0x00 , 0x00 , 0x01 , 0x13 , 0x24 , 0x4f ,
16761589 0xa5 , 0x9f , 0xcb , 0x40 , 0x71 , 0x24 , 0x03 , 0x8f ,
16771590 0xf9 , 0x12 , 0x1e , 0xd5 , 0x46 , 0xf6 , 0xdc , 0x21 ,
@@ -1697,7 +1610,7 @@ mod tests {
16971610 0xfc , 0x1f , 0xc8 , 0xf1 , 0xa4 , 0x95 , 0xaf , 0xfa ,
16981611 0x88 , 0xac , 0xf4 , 0x01 , 0x00 , 0x00 ,
16991612 ] ,
1700- merkle_proof: & [
1613+ merkle_proof: vec! [
17011614 0x00 , 0x00 , 0x00 , 0x20 , 0xa0 , 0x60 , 0x08 , 0x6a ,
17021615 0xf9 , 0x2a , 0xc3 , 0x4d , 0xbb , 0xc8 , 0xbd , 0x89 ,
17031616 0xbb , 0xbe , 0x03 , 0xef , 0x7e , 0x00 , 0x16 , 0x93 ,
@@ -1729,7 +1642,7 @@ mod tests {
17291642 ) ;
17301643 assert_eq ! (
17311644 tx. input[ 0 ] . witness. pegin_witness,
1732- tx. input[ 0 ] . pegin_data( ) . unwrap( ) . to_pegin_witness ( ) ,
1645+ PeginWitness :: new ( tx. input[ 0 ] . pegin_data( ) . unwrap( ) . clone ( ) ) ,
17331646 ) ;
17341647
17351648 assert_eq ! ( tx. output. len( ) , 2 ) ;
@@ -2386,19 +2299,13 @@ mod tests {
23862299
23872300 #[ test]
23882301 fn malformed_pegin ( ) {
2389- let mut input: TxIn = hex_deserialize ! ( "\
2390- 0004000000000000ffffffff0000040000c0c0c0c0c0c0c0c0c0000000000000\
2391- 00805555555555555505c0c0c0c0c03fc0c0c0c0c0c0c0c0c0c0c0c00200ff01\
2392- 0000000000fd0000000000000000010000000000ffffffffffffffff00000000\
2393- 000000ff000000000000010000000000000000000001002d342d35313700\
2394- ") ;
2395- input. witness = hex_deserialize ! ( "\
2302+ let wit = hex:: decode_to_vec ( "\
23962303 0000000608202020202020202020202020202020202020202020202020202020\
23972304 2020202020202020202020202020202020202020202020202020202020202020\
23982305 2020202020202020202020202020202020202020202020202020202020200000\
23992306 00000000000000000000000000000002000400000000\
2400- ") ;
2401- assert ! ( input . pegin_data ( ) . is_none ( ) ) ;
2307+ ") . unwrap ( ) ;
2308+ assert ! ( TxInWitness :: consensus_decode ( & wit [ .. ] ) . is_err ( ) ) ;
24022309 }
24032310
24042311 #[ test]
0 commit comments