@@ -1663,21 +1663,6 @@ where
16631663 }
16641664 NetworkActorCommand :: SettleMPPTlcSet ( payment_hash) => {
16651665 let hold_tlcs = self . store . get_payment_hold_tlcs ( payment_hash) ;
1666- // check all hold tlcs mpp_mode is same
1667- let mpp_modes: HashSet < _ > =
1668- hold_tlcs. iter ( ) . map ( |hold_tlc| hold_tlc. mpp_mode ) . collect ( ) ;
1669- if mpp_modes. len ( ) > 1 {
1670- error ! (
1671- "payment_hash {:?} have different mpp_mode, cannot settle" ,
1672- payment_hash
1673- ) ;
1674- return Ok ( ( ) ) ;
1675- }
1676- let Some ( mpp_mode) = mpp_modes. iter ( ) . next ( ) . cloned ( ) else {
1677- error ! ( "payment_hash {:?} have not hold tlcs" , payment_hash) ;
1678- return Ok ( ( ) ) ;
1679- } ;
1680-
16811666 // load hold tlcs
16821667 let tlcs: Vec < _ > = hold_tlcs
16831668 . iter ( )
@@ -1690,86 +1675,132 @@ where
16901675
16911676 let mut tlc_fail = None ;
16921677 let mut hash_algorithm = HashAlgorithm :: default ( ) ;
1678+ let mut tlc_preimage_map = HashMap :: new ( ) ;
1679+
1680+ // we generally set all validation error as IncorrectOrUnknownPaymentDetails, this failure
1681+ // is expected to be the scenarios malicious sender have sent a inconsistent data with MPP
1682+ ' validation: {
1683+ // check if all tlcs have the same total amount
1684+ if tlcs. len ( ) > 1
1685+ && !tlcs
1686+ . windows ( 2 )
1687+ . all ( |w| w[ 0 ] . total_amount == w[ 1 ] . total_amount )
1688+ {
1689+ error ! ( "TLCs have inconsistent total_amount: {:?}" , tlcs) ;
1690+ tlc_fail =
1691+ Some ( TlcErr :: new ( TlcErrorCode :: IncorrectOrUnknownPaymentDetails ) ) ;
1692+ break ' validation;
1693+ }
16931694
1694- // check if all tlcs have the same total amount
1695- if tlcs. len ( ) > 1
1696- && !tlcs
1697- . windows ( 2 )
1698- . all ( |w| w[ 0 ] . total_amount == w[ 1 ] . total_amount )
1699- {
1700- error ! ( "TLCs have inconsistent total_amount: {:?}" , tlcs) ;
1701- tlc_fail = Some ( TlcErr :: new ( TlcErrorCode :: IncorrectOrUnknownPaymentDetails ) ) ;
1702- } else {
17031695 // check if tlc set are fulfilled
1704- let Some ( invoice) = self . store . get_invoice ( & payment_hash) else {
1696+ let invoice = self . store . get_invoice ( & payment_hash) ;
1697+ let Some ( invoice) = invoice else {
17051698 error ! (
17061699 "Try to settle mpp tlc set, but invoice not found for payment hash {:?}" ,
17071700 payment_hash
17081701 ) ;
1709- return Ok ( ( ) ) ;
1702+ tlc_fail =
1703+ Some ( TlcErr :: new ( TlcErrorCode :: IncorrectOrUnknownPaymentDetails ) ) ;
1704+ break ' validation;
1705+ } ;
1706+
1707+ let Some ( mpp_mode) = invoice. mpp_mode ( ) else {
1708+ error ! ( "try to settle down mpp payment_hash: {:?} while the invoice does no support MPP" , payment_hash) ;
1709+ tlc_fail =
1710+ Some ( TlcErr :: new ( TlcErrorCode :: IncorrectOrUnknownPaymentDetails ) ) ;
1711+ break ' validation;
17101712 } ;
1711- // just return if invoice is not fulfilled
1713+
17121714 if !is_invoice_fulfilled ( & invoice, & tlcs) {
17131715 return Ok ( ( ) ) ;
17141716 }
1717+
17151718 hash_algorithm = invoice. hash_algorithm ( ) . cloned ( ) . unwrap_or ( hash_algorithm) ;
1716- }
1717- let mut tlc_preimages = HashMap :: new ( ) ;
1718- match mpp_mode {
1719- MppMode :: BasicMpp => {
1720- let Some ( preimage) = self . store . get_preimage ( & payment_hash) else {
1721- error ! (
1722- "basic MPP can not get preimage for payment: {:?}" ,
1723- payment_hash
1724- ) ;
1725- return Ok ( ( ) ) ;
1726- } ;
1727- for tlc in tlcs. iter ( ) {
1728- tlc_preimages. insert ( ( tlc. channel_id , tlc. id ( ) ) , preimage) ;
1729- }
1730- }
1731- MppMode :: AtomicMpp => {
1732- let mut atomic_mpp_data =
1733- self . store . get_atomic_mpp_payment_data ( & payment_hash) ;
1734- if atomic_mpp_data. len ( ) != tlcs. len ( ) {
1735- error ! (
1736- "atomic mpp don't have enough mpp data for payment_hash: {:?}" ,
1737- payment_hash
1738- ) ;
1719+ // Generate preimages based on MPP mode
1720+ match mpp_mode {
1721+ MppMode :: BasicMpp => {
1722+ let Some ( preimage) = self . store . get_preimage ( & payment_hash) else {
1723+ error ! (
1724+ "basic MPP can not get preimage for payment: {:?}" ,
1725+ payment_hash
1726+ ) ;
1727+ tlc_fail = Some ( TlcErr :: new (
1728+ TlcErrorCode :: IncorrectOrUnknownPaymentDetails ,
1729+ ) ) ;
1730+ break ' validation;
1731+ } ;
1732+
1733+ for tlc in tlcs. iter ( ) {
1734+ tlc_preimage_map. insert ( ( tlc. channel_id , tlc. id ( ) ) , preimage) ;
1735+ }
17391736 }
1740- atomic_mpp_data. sort_by ( |a, b| a. 1 . index . cmp ( & b. 1 . index ) ) ;
1741- let child_descs: Vec < ChildDesc > = atomic_mpp_data
1742- . iter ( )
1743- . map ( |( _, data) | ChildDesc :: new ( data. secret , data. index ) )
1744- . collect ( ) ;
1745- let children = reconstruct_children ( & child_descs, hash_algorithm) ;
1746- debug_assert_eq ! ( child_descs. len( ) , children. len( ) ) ;
1747- for ( ( ( channel_id, tlc_id) , _) , child) in
1748- atomic_mpp_data. iter ( ) . zip ( children. iter ( ) )
1749- {
1750- tlc_preimages. insert ( ( * channel_id, * tlc_id) , child. preimage ) ;
1737+ MppMode :: AtomicMpp => {
1738+ let mut atomic_mpp_data =
1739+ self . store . get_atomic_mpp_payment_data ( & payment_hash) ;
1740+
1741+ if atomic_mpp_data. len ( ) != tlcs. len ( ) {
1742+ error ! (
1743+ "atomic mpp don't have enough mpp data for payment_hash: {:?}" ,
1744+ payment_hash
1745+ ) ;
1746+ tlc_fail = Some ( TlcErr :: new (
1747+ TlcErrorCode :: IncorrectOrUnknownPaymentDetails ,
1748+ ) ) ;
1749+ break ' validation;
1750+ }
1751+
1752+ atomic_mpp_data. sort_by ( |a, b| a. 1 . index . cmp ( & b. 1 . index ) ) ;
1753+ let index: Vec < u16 > =
1754+ atomic_mpp_data. iter ( ) . map ( |a| a. 1 . index ) . collect ( ) ;
1755+ let expected_index: Vec < u16 > = ( 0 ..tlcs. len ( ) as u16 ) . collect ( ) ;
1756+
1757+ if index != expected_index {
1758+ error ! (
1759+ "atomic mpp index are not expected for payment_hash: {:?}" ,
1760+ payment_hash
1761+ ) ;
1762+ tlc_fail = Some ( TlcErr :: new (
1763+ TlcErrorCode :: IncorrectOrUnknownPaymentDetails ,
1764+ ) ) ;
1765+ break ' validation;
1766+ }
1767+
1768+ let child_descs: Vec < ChildDesc > = atomic_mpp_data
1769+ . iter ( )
1770+ . map ( |( _, data) | ChildDesc :: new ( data. secret , data. index ) )
1771+ . collect ( ) ;
1772+ let children = reconstruct_children ( & child_descs, hash_algorithm) ;
1773+ debug_assert_eq ! ( child_descs. len( ) , children. len( ) ) ;
1774+
1775+ for ( ( ( channel_id, tlc_id) , _) , child) in
1776+ atomic_mpp_data. iter ( ) . zip ( children. iter ( ) )
1777+ {
1778+ tlc_preimage_map. insert ( ( * channel_id, * tlc_id) , child. preimage ) ;
1779+ }
17511780 }
17521781 }
1753- }
1782+ } // end of 'validation block
17541783
17551784 // remove tlcs
17561785 for tlc in tlcs {
17571786 let ( send, _recv) = oneshot:: channel ( ) ;
17581787 let rpc_reply = RpcReplyPort :: from ( send) ;
1788+
17591789 let remove_reason = match tlc_fail. clone ( ) {
17601790 Some ( tlc_fail) => RemoveTlcReason :: RemoveTlcFail ( TlcErrPacket :: new (
17611791 tlc_fail,
17621792 & tlc. shared_secret ,
17631793 ) ) ,
17641794 None => {
1765- let preimage = * tlc_preimages
1795+ let preimage = * tlc_preimage_map
17661796 . get ( & ( tlc. channel_id , tlc. id ( ) ) )
17671797 . expect ( "must got preimage" ) ;
17681798 RemoveTlcReason :: RemoveTlcFulfill ( RemoveTlcFulfill {
17691799 payment_preimage : preimage,
17701800 } )
17711801 }
17721802 } ;
1803+
17731804 match state
17741805 . send_command_to_channel (
17751806 tlc. channel_id ,
0 commit comments