@@ -23,6 +23,10 @@ use secp256k1::key::{SecretKey, PublicKey};
23
23
use secp256k1:: { Secp256k1 , Signature } ;
24
24
use secp256k1;
25
25
26
+ use std:: { cmp, mem} ;
27
+
28
+ const MAX_ALLOC_SIZE : usize = 64 * 1024 ;
29
+
26
30
pub ( super ) const HTLC_SUCCESS_TX_WEIGHT : u64 = 703 ;
27
31
pub ( super ) const HTLC_TIMEOUT_TX_WEIGHT : u64 = 663 ;
28
32
@@ -355,7 +359,7 @@ impl_writeable!(HTLCOutputInCommitment, 1 + 8 + 4 + 32 + 5, {
355
359
} ) ;
356
360
357
361
#[ inline]
358
- pub ( super ) fn get_htlc_redeemscript_with_explicit_keys ( htlc : & HTLCOutputInCommitment , a_htlc_key : & PublicKey , b_htlc_key : & PublicKey , revocation_key : & PublicKey ) -> Script {
362
+ pub ( crate ) fn get_htlc_redeemscript_with_explicit_keys ( htlc : & HTLCOutputInCommitment , a_htlc_key : & PublicKey , b_htlc_key : & PublicKey , revocation_key : & PublicKey ) -> Script {
359
363
let payment_hash160 = Ripemd160 :: hash ( & htlc. payment_hash . 0 [ ..] ) . into_inner ( ) ;
360
364
if htlc. offered {
361
365
Builder :: new ( ) . push_opcode ( opcodes:: all:: OP_DUP )
@@ -475,62 +479,44 @@ pub fn build_htlc_transaction(prev_hash: &Sha256dHash, feerate_per_kw: u64, to_s
475
479
}
476
480
}
477
481
478
- /// Signs a transaction created by build_htlc_transaction. If the transaction is an
479
- /// HTLC-Success transaction (ie htlc.offered is false), preimage must be set!
480
- pub ( crate ) fn sign_htlc_transaction < T : secp256k1:: Signing > ( tx : & mut Transaction , their_sig : & Signature , preimage : & Option < PaymentPreimage > , htlc : & HTLCOutputInCommitment , a_htlc_key : & PublicKey , b_htlc_key : & PublicKey , revocation_key : & PublicKey , per_commitment_point : & PublicKey , htlc_base_key : & SecretKey , secp_ctx : & Secp256k1 < T > ) -> Result < ( Signature , Script ) , ( ) > {
481
- if tx. input . len ( ) != 1 { return Err ( ( ) ) ; }
482
- if tx. input [ 0 ] . witness . len ( ) != 0 { return Err ( ( ) ) ; }
483
-
484
- let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys ( & htlc, a_htlc_key, b_htlc_key, revocation_key) ;
485
-
486
- let our_htlc_key = derive_private_key ( secp_ctx, per_commitment_point, htlc_base_key) . map_err ( |_| ( ) ) ?;
487
- let sighash = hash_to_message ! ( & bip143:: SighashComponents :: new( & tx) . sighash_all( & tx. input[ 0 ] , & htlc_redeemscript, htlc. amount_msat / 1000 ) [ ..] ) ;
488
- let local_tx = PublicKey :: from_secret_key ( & secp_ctx, & our_htlc_key) == * a_htlc_key;
489
- let our_sig = secp_ctx. sign ( & sighash, & our_htlc_key) ;
490
-
491
- tx. input [ 0 ] . witness . push ( Vec :: new ( ) ) ; // First is the multisig dummy
492
-
493
- if local_tx { // b, then a
494
- tx. input [ 0 ] . witness . push ( their_sig. serialize_der ( ) . to_vec ( ) ) ;
495
- tx. input [ 0 ] . witness . push ( our_sig. serialize_der ( ) . to_vec ( ) ) ;
496
- } else {
497
- tx. input [ 0 ] . witness . push ( our_sig. serialize_der ( ) . to_vec ( ) ) ;
498
- tx. input [ 0 ] . witness . push ( their_sig. serialize_der ( ) . to_vec ( ) ) ;
499
- }
500
- tx. input [ 0 ] . witness [ 1 ] . push ( SigHashType :: All as u8 ) ;
501
- tx. input [ 0 ] . witness [ 2 ] . push ( SigHashType :: All as u8 ) ;
502
-
503
- if htlc. offered {
504
- tx. input [ 0 ] . witness . push ( Vec :: new ( ) ) ;
505
- assert ! ( preimage. is_none( ) ) ;
506
- } else {
507
- tx. input [ 0 ] . witness . push ( preimage. unwrap ( ) . 0 . to_vec ( ) ) ;
508
- }
509
-
510
- tx. input [ 0 ] . witness . push ( htlc_redeemscript. as_bytes ( ) . to_vec ( ) ) ;
511
-
512
- Ok ( ( our_sig, htlc_redeemscript) )
513
- }
514
-
515
482
#[ derive( Clone ) ]
516
483
/// We use this to track local commitment transactions and put off signing them until we are ready
517
484
/// to broadcast. Eventually this will require a signer which is possibly external, but for now we
518
485
/// just pass in the SecretKeys required.
519
- pub ( crate ) struct LocalCommitmentTransaction {
520
- tx : Transaction
486
+ pub struct LocalCommitmentTransaction {
487
+ tx : Transaction ,
488
+ //TODO: modify Channel methods to integrate HTLC material at LocalCommitmentTransaction generation to drop Option here
489
+ local_keys : Option < TxCreationKeys > ,
490
+ feerate_per_kw : Option < u64 > ,
491
+ per_htlc : Vec < ( HTLCOutputInCommitment , Option < Signature > , Option < Transaction > ) >
521
492
}
522
493
impl LocalCommitmentTransaction {
523
494
#[ cfg( test) ]
524
495
pub fn dummy ( ) -> Self {
496
+ let dummy_input = TxIn {
497
+ previous_output : OutPoint {
498
+ txid : Default :: default ( ) ,
499
+ vout : 0 ,
500
+ } ,
501
+ script_sig : Default :: default ( ) ,
502
+ sequence : 0 ,
503
+ witness : vec ! [ vec![ ] , vec![ ] , vec![ ] ]
504
+ } ;
525
505
Self { tx : Transaction {
526
506
version : 2 ,
527
- input : Vec :: new ( ) ,
507
+ input : vec ! [ dummy_input ] ,
528
508
output : Vec :: new ( ) ,
529
509
lock_time : 0 ,
530
- } }
510
+ } ,
511
+ local_keys : None ,
512
+ feerate_per_kw : None ,
513
+ per_htlc : Vec :: new ( )
514
+ }
531
515
}
532
516
533
- pub fn new_missing_local_sig ( mut tx : Transaction , their_sig : & Signature , our_funding_key : & PublicKey , their_funding_key : & PublicKey ) -> LocalCommitmentTransaction {
517
+ /// Generate a new LocalCommitmentTransaction based on a raw commitment transaction,
518
+ /// remote signature and both parties keys
519
+ pub ( crate ) fn new_missing_local_sig ( mut tx : Transaction , their_sig : & Signature , our_funding_key : & PublicKey , their_funding_key : & PublicKey ) -> LocalCommitmentTransaction {
534
520
if tx. input . len ( ) != 1 { panic ! ( "Tried to store a commitment transaction that had input count != 1!" ) ; }
535
521
if tx. input [ 0 ] . witness . len ( ) != 0 { panic ! ( "Tried to store a signed commitment transaction?" ) ; }
536
522
@@ -546,13 +532,20 @@ impl LocalCommitmentTransaction {
546
532
tx. input [ 0 ] . witness . push ( Vec :: new ( ) ) ;
547
533
}
548
534
549
- Self { tx }
535
+ Self { tx,
536
+ local_keys : None ,
537
+ feerate_per_kw : None ,
538
+ per_htlc : Vec :: new ( )
539
+ }
550
540
}
551
541
542
+ /// Get the txid of the local commitment transaction contained in this
543
+ /// LocalCommitmentTransaction
552
544
pub fn txid ( & self ) -> Sha256dHash {
553
545
self . tx . txid ( )
554
546
}
555
547
548
+ /// Check if LocalCommitmentTransaction has already been signed by us
556
549
pub fn has_local_sig ( & self ) -> bool {
557
550
if self . tx . input . len ( ) != 1 { panic ! ( "Commitment transactions must have input count == 1!" ) ; }
558
551
if self . tx . input [ 0 ] . witness . len ( ) == 4 {
@@ -567,6 +560,15 @@ impl LocalCommitmentTransaction {
567
560
}
568
561
}
569
562
563
+ /// Add local signature for LocalCommitmentTransaction, do nothing if signature is already
564
+ /// present
565
+ ///
566
+ /// Funding key is your key included in the 2-2 funding_outpoint lock. Should be provided
567
+ /// by your ChannelKeys.
568
+ /// Funding redeemscript is script locking funding_outpoint. This is the mutlsig script
569
+ /// between your own funding key and your counterparty's. Currently, this is provided in
570
+ /// ChannelKeys::sign_local_commitment() calls directly.
571
+ /// Channel value is amount locked in funding_outpoint.
570
572
pub fn add_local_sig < T : secp256k1:: Signing > ( & mut self , funding_key : & SecretKey , funding_redeemscript : & Script , channel_value_satoshis : u64 , secp_ctx : & Secp256k1 < T > ) {
571
573
if self . has_local_sig ( ) { return ; }
572
574
let sighash = hash_to_message ! ( & bip143:: SighashComponents :: new( & self . tx)
@@ -584,11 +586,74 @@ impl LocalCommitmentTransaction {
584
586
self . tx . input [ 0 ] . witness . push ( funding_redeemscript. as_bytes ( ) . to_vec ( ) ) ;
585
587
}
586
588
587
- pub fn without_valid_witness ( & self ) -> & Transaction { & self . tx }
589
+ /// Get raw transaction without asserting if witness is complete
590
+ pub ( crate ) fn without_valid_witness ( & self ) -> & Transaction { & self . tx }
591
+ /// Get raw transaction with panics if witness is incomplete
588
592
pub fn with_valid_witness ( & self ) -> & Transaction {
589
593
assert ! ( self . has_local_sig( ) ) ;
590
594
& self . tx
591
595
}
596
+
597
+ /// Set HTLC cache to generate any local HTLC transaction spending one of htlc ouput
598
+ /// from this local commitment transaction
599
+ pub ( crate ) fn set_htlc_cache ( & mut self , local_keys : TxCreationKeys , feerate_per_kw : u64 , htlc_outputs : Vec < ( HTLCOutputInCommitment , Option < Signature > , Option < Transaction > ) > ) {
600
+ self . local_keys = Some ( local_keys) ;
601
+ self . feerate_per_kw = Some ( feerate_per_kw) ;
602
+ self . per_htlc = htlc_outputs;
603
+ }
604
+
605
+ /// Add local signature for a htlc transaction, do nothing if a cached signed transaction is
606
+ /// already present
607
+ pub fn add_htlc_sig < T : secp256k1:: Signing > ( & mut self , htlc_base_key : & SecretKey , htlc_index : u32 , preimage : Option < PaymentPreimage > , local_csv : u16 , secp_ctx : & Secp256k1 < T > ) {
608
+ if self . local_keys . is_none ( ) || self . feerate_per_kw . is_none ( ) { return ; }
609
+ let local_keys = self . local_keys . as_ref ( ) . unwrap ( ) ;
610
+ let txid = self . txid ( ) ;
611
+ for this_htlc in self . per_htlc . iter_mut ( ) {
612
+ if this_htlc. 0 . transaction_output_index . unwrap ( ) == htlc_index {
613
+ if this_htlc. 2 . is_some ( ) { return ; } // we already have a cached htlc transaction at provided index
614
+ let mut htlc_tx = build_htlc_transaction ( & txid, self . feerate_per_kw . unwrap ( ) , local_csv, & this_htlc. 0 , & local_keys. a_delayed_payment_key , & local_keys. revocation_key ) ;
615
+ if !this_htlc. 0 . offered && preimage. is_none ( ) { return ; } // if we don't have preimage for HTLC-Success, don't try to generate
616
+ let htlc_secret = if !this_htlc. 0 . offered { preimage } else { None } ; // if we have a preimage for HTLC-Timeout, don't use it that's likely a duplicate HTLC hash
617
+ if this_htlc. 1 . is_none ( ) { return ; } // we don't have any remote signature for this htlc
618
+ if htlc_tx. input . len ( ) != 1 { return ; }
619
+ if htlc_tx. input [ 0 ] . witness . len ( ) != 0 { return ; }
620
+
621
+ let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys ( & this_htlc. 0 , & local_keys. a_htlc_key , & local_keys. b_htlc_key , & local_keys. revocation_key ) ;
622
+
623
+ if let Ok ( our_htlc_key) = derive_private_key ( secp_ctx, & local_keys. per_commitment_point , htlc_base_key) {
624
+ let sighash = hash_to_message ! ( & bip143:: SighashComponents :: new( & htlc_tx) . sighash_all( & htlc_tx. input[ 0 ] , & htlc_redeemscript, this_htlc. 0 . amount_msat / 1000 ) [ ..] ) ;
625
+ let our_sig = secp_ctx. sign ( & sighash, & our_htlc_key) ;
626
+
627
+ htlc_tx. input [ 0 ] . witness . push ( Vec :: new ( ) ) ; // First is the multisig dummy
628
+
629
+ htlc_tx. input [ 0 ] . witness . push ( this_htlc. 1 . unwrap ( ) . serialize_der ( ) . to_vec ( ) ) ;
630
+ htlc_tx. input [ 0 ] . witness . push ( our_sig. serialize_der ( ) . to_vec ( ) ) ;
631
+ htlc_tx. input [ 0 ] . witness [ 1 ] . push ( SigHashType :: All as u8 ) ;
632
+ htlc_tx. input [ 0 ] . witness [ 2 ] . push ( SigHashType :: All as u8 ) ;
633
+
634
+ if this_htlc. 0 . offered {
635
+ htlc_tx. input [ 0 ] . witness . push ( Vec :: new ( ) ) ;
636
+ assert ! ( htlc_secret. is_none( ) ) ;
637
+ } else {
638
+ htlc_tx. input [ 0 ] . witness . push ( htlc_secret. unwrap ( ) . 0 . to_vec ( ) ) ;
639
+ }
640
+
641
+ htlc_tx. input [ 0 ] . witness . push ( htlc_redeemscript. as_bytes ( ) . to_vec ( ) ) ;
642
+
643
+ this_htlc. 2 = Some ( htlc_tx) ;
644
+ } else { return ; }
645
+ }
646
+ }
647
+ }
648
+ /// Expose raw htlc transaction, guarante witness is complete if non-empty
649
+ pub fn htlc_with_valid_witness ( & self , htlc_index : u32 ) -> & Option < Transaction > {
650
+ for this_htlc in self . per_htlc . iter ( ) {
651
+ if this_htlc. 0 . transaction_output_index . unwrap ( ) == htlc_index {
652
+ return & this_htlc. 2 ;
653
+ }
654
+ }
655
+ & None
656
+ }
592
657
}
593
658
impl PartialEq for LocalCommitmentTransaction {
594
659
// We dont care whether we are signed in equality comparison
@@ -604,6 +669,14 @@ impl Writeable for LocalCommitmentTransaction {
604
669
_ => panic ! ( "local tx must have been well-formed!" ) ,
605
670
}
606
671
}
672
+ self . local_keys . write ( writer) ?;
673
+ self . feerate_per_kw . write ( writer) ?;
674
+ writer. write_all ( & byte_utils:: be64_to_array ( self . per_htlc . len ( ) as u64 ) ) ?;
675
+ for & ( ref htlc, ref sig, ref htlc_tx) in self . per_htlc . iter ( ) {
676
+ htlc. write ( writer) ?;
677
+ sig. write ( writer) ?;
678
+ htlc_tx. write ( writer) ?;
679
+ }
607
680
Ok ( ( ) )
608
681
}
609
682
}
@@ -616,12 +689,27 @@ impl Readable for LocalCommitmentTransaction {
616
689
_ => return Err ( DecodeError :: InvalidValue ) ,
617
690
} ,
618
691
} ;
692
+ let local_keys = Readable :: read ( reader) ?;
693
+ let feerate_per_kw = Readable :: read ( reader) ?;
694
+ let htlcs_count: u64 = Readable :: read ( reader) ?;
695
+ let mut per_htlc = Vec :: with_capacity ( cmp:: min ( htlcs_count as usize , MAX_ALLOC_SIZE / mem:: size_of :: < ( HTLCOutputInCommitment , Option < Signature > , Option < Transaction > ) > ( ) ) ) ;
696
+ for _ in 0 ..htlcs_count {
697
+ let htlc: HTLCOutputInCommitment = Readable :: read ( reader) ?;
698
+ let sigs = Readable :: read ( reader) ?;
699
+ let htlc_tx = Readable :: read ( reader) ?;
700
+ per_htlc. push ( ( htlc, sigs, htlc_tx) ) ;
701
+ }
619
702
620
703
if tx. input . len ( ) != 1 {
621
704
// Ensure tx didn't hit the 0-input ambiguity case.
622
705
return Err ( DecodeError :: InvalidValue ) ;
623
706
}
624
- Ok ( Self { tx } )
707
+ Ok ( Self {
708
+ tx,
709
+ local_keys,
710
+ feerate_per_kw,
711
+ per_htlc,
712
+ } )
625
713
}
626
714
}
627
715
0 commit comments