URI: 
       tlnchannel: ctx output-ordering: identical htlcs are ordered by CLTV - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 44761972cb16a7cf09e38d2bcea1de7630f93138
   DIR parent b1f606eaed10e6d6d3ead481301879ff065ee14a
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Sun,  4 Aug 2019 04:55:23 +0200
       
       lnchannel: ctx output-ordering: identical htlcs are ordered by CLTV
       
       Diffstat:
         M electrum/lnchannel.py               |       1 +
         M electrum/lnutil.py                  |      13 ++++++++++++-
         M electrum/tests/test_lnutil.py       |       2 +-
         M electrum/transaction.py             |       1 +
       
       4 files changed, 15 insertions(+), 2 deletions(-)
       ---
   DIR diff --git a/electrum/lnchannel.py b/electrum/lnchannel.py
       t@@ -340,6 +340,7 @@ class Channel(Logger):
                htlc_sigs = htlc_sigs[:] # copy cause we will delete now
                for htlcs, we_receive in [(self.included_htlcs(LOCAL, SENT, ctn=next_local_ctn), False),
                                          (self.included_htlcs(LOCAL, RECEIVED, ctn=next_local_ctn), True)]:
       +            # FIXME this is quadratic. BOLT-02: "corresponding to the ordering of the commitment transaction"
                    for htlc in htlcs:
                        idx = self.verify_htlc(htlc, htlc_sigs, we_receive, pending_local_commitment)
                        del htlc_sigs[idx]
   DIR diff --git a/electrum/lnutil.py b/electrum/lnutil.py
       t@@ -93,7 +93,11 @@ class FeeUpdate(NamedTuple):
        
        ChannelConstraints = namedtuple("ChannelConstraints", ["capacity", "is_initiator", "funding_txn_minimum_depth"])
        
       -ScriptHtlc = namedtuple('ScriptHtlc', ['redeem_script', 'htlc'])
       +
       +class ScriptHtlc(NamedTuple):
       +    redeem_script: bytes
       +    htlc: 'UpdateAddHtlc'
       +
        
        class Outpoint(NamedTuple("Outpoint", [('txid', str), ('output_index', int)])):
            def to_str(self):
       t@@ -475,6 +479,13 @@ def make_commitment(ctn, local_funding_pubkey, remote_funding_pubkey,
            remote_address = make_commitment_output_to_remote_address(remote_payment_pubkey)
            # TODO trim htlc outputs here while also considering 2nd stage htlc transactions
        
       +    # BOLT-03: "Transaction Input and Output Ordering
       +    #           Lexicographic ordering: see BIP69. In the case of identical HTLC outputs,
       +    #           the outputs are ordered in increasing cltv_expiry order."
       +    # so we sort by cltv_expiry now; and the later BIP69-sort is assumed to be *stable*
       +    htlcs = list(htlcs)
       +    htlcs.sort(key=lambda x: x.htlc.cltv_expiry)
       +
            htlc_outputs, c_outputs_filtered = make_commitment_outputs(fees_per_participant, local_amount, remote_amount,
                (bitcoin.TYPE_ADDRESS, local_address), (bitcoin.TYPE_ADDRESS, remote_address), htlcs, dust_limit_sat)
        
   DIR diff --git a/electrum/tests/test_lnutil.py b/electrum/tests/test_lnutil.py
       t@@ -495,7 +495,7 @@ class TestLNUtil(unittest.TestCase):
                    (1, 2000 * 1000),
                    (3, 3000 * 1000),
                    (4, 4000 * 1000)]:
       -            htlc_obj[num] = UpdateAddHtlc(amount_msat=msat, payment_hash=bitcoin.sha256(htlc_payment_preimage[num]), cltv_expiry=None, htlc_id=None, timestamp=0)
       +            htlc_obj[num] = UpdateAddHtlc(amount_msat=msat, payment_hash=bitcoin.sha256(htlc_payment_preimage[num]), cltv_expiry=0, htlc_id=None, timestamp=0)
                htlcs = [ScriptHtlc(htlc[x], htlc_obj[x]) for x in range(5)]
        
                our_commit_tx = make_commitment(
   DIR diff --git a/electrum/transaction.py b/electrum/transaction.py
       t@@ -958,6 +958,7 @@ class Transaction:
                    txin['sequence'] = nSequence
        
            def BIP69_sort(self, inputs=True, outputs=True):
       +        # NOTE: other parts of the code rely on these sorts being *stable* sorts
                if inputs:
                    self._inputs.sort(key = lambda i: (i['prevout_hash'], i['prevout_n']))
                if outputs: