URI: 
       tlnchannel: start using "latest" and "next" instead of "current" and "pending" - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit b1f606eaed10e6d6d3ead481301879ff065ee14a
   DIR parent e32807d29d0484b5bb834affc5fd163274991e13
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Sat,  3 Aug 2019 17:34:11 +0200
       
       lnchannel: start using "latest" and "next" instead of "current" and "pending"
       
       "current" used to be "oldest_unrevoked"; and pending was "oldest_unrevoked + 1"
       but this was very confusing...
       so now we have "oldest_unrevoked", "latest", and "next"
       where "next" is "latest + 1"
       "oldest_unrevoked" and "latest" are either the same or are offset by 1
       (but caller should know which one they need)
       
       rm "got_sig_for_next" - it was a redundant sanity check, that really
       just complicated things
       
       rm "local_commitment", "remote_commitment", "set_local_commitment",
       "set_remote_commitment" - just use "get_latest_commitment" instead
       
       Diffstat:
         M electrum/lnchannel.py               |      78 +++++++++++++------------------
         M electrum/lnpeer.py                  |      41 ++++++++++++++-----------------
         M electrum/lnsweep.py                 |      11 ++++++-----
         M electrum/lnutil.py                  |       1 -
         M electrum/lnworker.py                |       6 ++----
         M electrum/tests/test_lnchannel.py    |     143 ++++++++++++++-----------------
       
       6 files changed, 126 insertions(+), 154 deletions(-)
       ---
   DIR diff --git a/electrum/lnchannel.py b/electrum/lnchannel.py
       t@@ -146,8 +146,6 @@ class Channel(Logger):
                self._is_funding_txo_spent = None  # "don't know"
                self._state = None
                self.set_state('DISCONNECTED')
       -        self.local_commitment = None
       -        self.remote_commitment = None
                self.sweep_info = {}
        
            def get_feerate(self, subject, ctn):
       t@@ -175,14 +173,6 @@ class Channel(Logger):
                        out[rhash] = (self.channel_id, htlc, direction, status)
                return out
        
       -    def set_local_commitment(self, ctx):
       -        ctn = extract_ctn_from_tx_and_chan(ctx, self)
       -        assert self.signature_fits(ctx), (self.hm.log[LOCAL])
       -        self.local_commitment = ctx
       -
       -    def set_remote_commitment(self):
       -        self.remote_commitment = self.current_commitment(REMOTE)
       -
            def open_with_first_pcp(self, remote_pcp, remote_sig):
                self.config[REMOTE] = self.config[REMOTE]._replace(ctn=0, current_per_commitment_point=remote_pcp, next_per_commitment_point=None)
                self.config[LOCAL] = self.config[LOCAL]._replace(ctn=0, current_commitment_signature=remote_sig)
       t@@ -285,10 +275,10 @@ class Channel(Logger):
        
                This docstring was adapted from LND.
                """
       -        next_remote_ctn = self.get_current_ctn(REMOTE) + 1
       +        next_remote_ctn = self.get_next_ctn(REMOTE)
                self.logger.info(f"sign_next_commitment {next_remote_ctn}")
       -        self.hm.send_ctx()
       -        pending_remote_commitment = self.pending_commitment(REMOTE)
       +
       +        pending_remote_commitment = self.get_next_commitment(REMOTE)
                sig_64 = sign_and_get_sig_string(pending_remote_commitment, self.config[LOCAL], self.config[REMOTE])
        
                their_remote_htlc_privkey_number = derive_privkey(
       t@@ -317,8 +307,7 @@ class Channel(Logger):
                htlcsigs.sort()
                htlcsigs = [x[1] for x in htlcsigs]
        
       -        # TODO should add remote_commitment here and handle
       -        # both valid ctx'es in lnwatcher at the same time...
       +        self.hm.send_ctx()
        
                return sig_64, htlcsigs
        
       t@@ -335,22 +324,20 @@ class Channel(Logger):
        
                This docstring is from LND.
                """
       +        next_local_ctn = self.get_next_ctn(LOCAL)
                self.logger.info("receive_new_commitment")
        
       -        self.hm.recv_ctx()
       -
                assert len(htlc_sigs) == 0 or type(htlc_sigs[0]) is bytes
        
       -        pending_local_commitment = self.pending_commitment(LOCAL)
       +        pending_local_commitment = self.get_next_commitment(LOCAL)
                preimage_hex = pending_local_commitment.serialize_preimage(0)
                pre_hash = sha256d(bfh(preimage_hex))
                if not ecc.verify_signature(self.config[REMOTE].multisig_key.pubkey, sig, pre_hash):
       -            raise Exception('failed verifying signature of our updated commitment transaction: ' + bh2u(sig) + ' preimage is ' + preimage_hex)
       +            raise Exception(f'failed verifying signature of our updated commitment transaction: {bh2u(sig)} preimage is {preimage_hex}')
        
                htlc_sigs_string = b''.join(htlc_sigs)
        
                htlc_sigs = htlc_sigs[:] # copy cause we will delete now
       -        next_local_ctn = self.get_current_ctn(LOCAL) + 1
                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)]:
                    for htlc in htlcs:
       t@@ -359,12 +346,10 @@ class Channel(Logger):
                if len(htlc_sigs) != 0: # all sigs should have been popped above
                    raise Exception('failed verifying HTLC signatures: invalid amount of correct signatures')
        
       +        self.hm.recv_ctx()
                self.config[LOCAL]=self.config[LOCAL]._replace(
                    current_commitment_signature=sig,
       -            current_htlc_signatures=htlc_sigs_string,
       -            got_sig_for_next=True)
       -
       -        self.set_local_commitment(pending_local_commitment)
       +            current_htlc_signatures=htlc_sigs_string)
        
            def verify_htlc(self, htlc: UpdateAddHtlc, htlc_sigs: Sequence[bytes], we_receive: bool, ctx) -> int:
                ctn = extract_ctn_from_tx_and_chan(ctx, self)
       t@@ -394,15 +379,14 @@ class Channel(Logger):
        
            def revoke_current_commitment(self):
                self.logger.info("revoke_current_commitment")
       -        assert self.config[LOCAL].got_sig_for_next
                new_ctn = self.config[LOCAL].ctn + 1
       -        new_ctx = self.pending_commitment(LOCAL)
       -        assert self.signature_fits(new_ctx)
       -        self.set_local_commitment(new_ctx)
       +        new_ctx = self.get_latest_commitment(LOCAL)
       +        if not self.signature_fits(new_ctx):
       +            # this should never fail; as receive_new_commitment already did this test
       +            raise Exception("refusing to revoke as remote sig does not fit")
                self.hm.send_rev()
                self.config[LOCAL]=self.config[LOCAL]._replace(
                    ctn=new_ctn,
       -            got_sig_for_next=False,
                )
                received = self.hm.received_in_ctn(new_ctn)
                sent = self.hm.sent_in_ctn(new_ctn)
       t@@ -427,14 +411,12 @@ class Channel(Logger):
        
                self.config[REMOTE].revocation_store.add_next_entry(revocation.per_commitment_secret)
                ##### start applying fee/htlc changes
       -        next_point = self.config[REMOTE].next_per_commitment_point
                self.hm.recv_rev()
                self.config[REMOTE]=self.config[REMOTE]._replace(
                    ctn=self.config[REMOTE].ctn + 1,
       -            current_per_commitment_point=next_point,
       +            current_per_commitment_point=self.config[REMOTE].next_per_commitment_point,
                    next_per_commitment_point=revocation.next_per_commitment_point,
                )
       -        self.set_remote_commitment()
        
            def balance(self, whose, *, ctx_owner=HTLCOwner.LOCAL, ctn=None):
                """
       t@@ -512,7 +494,7 @@ class Channel(Logger):
        
            def get_secret_and_point(self, subject, ctn) -> Tuple[Optional[bytes], bytes]:
                assert type(subject) is HTLCOwner
       -        offset = ctn - self.get_current_ctn(subject)
       +        offset = ctn - self.get_oldest_unrevoked_ctn(subject)
                if subject == REMOTE:
                    if offset > 1:
                        raise RemoteCtnTooFarInFuture(f"offset: {offset}")
       t@@ -540,12 +522,16 @@ class Channel(Logger):
                secret, ctx = self.get_secret_and_commitment(subject, ctn)
                return ctx
        
       -    def pending_commitment(self, subject):
       -        ctn = self.get_current_ctn(subject)
       -        return self.get_commitment(subject, ctn + 1)
       +    def get_next_commitment(self, subject: HTLCOwner) -> Transaction:
       +        ctn = self.get_next_ctn(subject)
       +        return self.get_commitment(subject, ctn)
       +
       +    def get_latest_commitment(self, subject: HTLCOwner) -> Transaction:
       +        ctn = self.get_latest_ctn(subject)
       +        return self.get_commitment(subject, ctn)
        
       -    def current_commitment(self, subject):
       -        ctn = self.get_current_ctn(subject)
       +    def get_oldest_unrevoked_commitment(self, subject: HTLCOwner) -> Transaction:
       +        ctn = self.get_oldest_unrevoked_ctn(subject)
                return self.get_commitment(subject, ctn)
        
            def create_sweeptxs(self, ctn):
       t@@ -553,9 +539,15 @@ class Channel(Logger):
                secret, ctx = self.get_secret_and_commitment(REMOTE, ctn)
                return create_sweeptxs_for_watchtower(self, ctx, secret, self.sweep_address)
        
       -    def get_current_ctn(self, subject):
       +    def get_oldest_unrevoked_ctn(self, subject: HTLCOwner) -> int:
                return self.config[subject].ctn
        
       +    def get_latest_ctn(self, subject: HTLCOwner) -> int:
       +        return self.hm.ctn_latest(subject)
       +
       +    def get_next_ctn(self, subject: HTLCOwner) -> int:
       +        return self.hm.ctn_latest(subject) + 1
       +
            def total_msat(self, direction):
                """Return the cumulative total msat amount received/sent so far."""
                assert type(direction) is Direction
       t@@ -597,12 +589,8 @@ class Channel(Logger):
                self.logger.info("receive_fail_htlc")
                self.hm.recv_fail(htlc_id)
        
       -    @property
       -    def current_height(self):
       -        return {LOCAL: self.config[LOCAL].ctn, REMOTE: self.config[REMOTE].ctn}
       -
            def pending_local_fee(self):
       -        return self.constraints.capacity - sum(x[2] for x in self.pending_commitment(LOCAL).outputs())
       +        return self.constraints.capacity - sum(x[2] for x in self.get_next_commitment(LOCAL).outputs())
        
            def update_fee(self, feerate: int, from_us: bool):
                # feerate uses sat/kw
       t@@ -751,7 +739,7 @@ class Channel(Logger):
                return res
        
            def force_close_tx(self):
       -        tx = self.local_commitment
       +        tx = self.get_latest_commitment(LOCAL)
                assert self.signature_fits(tx)
                tx = Transaction(str(tx))
                tx.deserialize(True)
   DIR diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py
       t@@ -458,7 +458,6 @@ class Peer(Logger):
                    was_announced=False,
                    current_commitment_signature=None,
                    current_htlc_signatures=[],
       -            got_sig_for_next=False,
                )
                return local_config
        
       t@@ -577,8 +576,6 @@ class Peer(Logger):
                # broadcast funding tx
                await asyncio.wait_for(self.network.broadcast_transaction(funding_tx), 5)
                chan.open_with_first_pcp(remote_per_commitment_point, remote_sig)
       -        chan.set_remote_commitment()
       -        chan.set_local_commitment(chan.current_commitment(LOCAL))
                return chan
        
            async def on_open_channel(self, payload):
       t@@ -713,12 +710,12 @@ class Peer(Logger):
                # BOLT-02: "A node [...] upon disconnection [...] MUST reverse any uncommitted updates sent by the other side"
                chan.hm.discard_unsigned_remote_updates()
                # ctns
       -        oldest_unrevoked_local_ctn = chan.config[LOCAL].ctn
       -        latest_local_ctn = chan.hm.ctn_latest(LOCAL)
       -        next_local_ctn = latest_local_ctn + 1
       -        oldest_unrevoked_remote_ctn = chan.config[REMOTE].ctn
       -        latest_remote_ctn = chan.hm.ctn_latest(REMOTE)
       -        next_remote_ctn = latest_remote_ctn + 1
       +        oldest_unrevoked_local_ctn = chan.get_oldest_unrevoked_ctn(LOCAL)
       +        latest_local_ctn = chan.get_latest_ctn(LOCAL)
       +        next_local_ctn = chan.get_next_ctn(LOCAL)
       +        oldest_unrevoked_remote_ctn = chan.get_oldest_unrevoked_ctn(REMOTE)
       +        latest_remote_ctn = chan.get_latest_ctn(REMOTE)
       +        next_remote_ctn = chan.get_next_ctn(REMOTE)
                # send message
                dlp_enabled = self.localfeatures & LnLocalFeatures.OPTION_DATA_LOSS_PROTECT_OPT
                if dlp_enabled:
       t@@ -1016,7 +1013,7 @@ class Peer(Logger):
                htlc_id = int.from_bytes(payload["id"], "big")
                chan = self.channels[channel_id]
                chan.receive_fail_htlc(htlc_id)
       -        local_ctn = chan.get_current_ctn(LOCAL)
       +        local_ctn = chan.get_latest_ctn(LOCAL)
                asyncio.ensure_future(self._handle_error_code_from_failed_htlc(payload, channel_id, htlc_id))
                asyncio.ensure_future(self._on_update_fail_htlc(channel_id, htlc_id, local_ctn))
        
       t@@ -1087,7 +1084,7 @@ class Peer(Logger):
                        self.network.path_finder.add_to_blacklist(short_chan_id)
        
            def maybe_send_commitment(self, chan: Channel):
       -        ctn_to_sign = chan.get_current_ctn(REMOTE) + 1
       +        ctn_to_sign = chan.get_next_ctn(REMOTE)
                # if there are no changes, we will not (and must not) send a new commitment
                next_htlcs, latest_htlcs = chan.hm.get_htlcs_in_next_ctx(REMOTE), chan.hm.get_htlcs_in_latest_ctx(REMOTE)
                if (next_htlcs == latest_htlcs
       t@@ -1101,12 +1098,12 @@ class Peer(Logger):
        
            async def await_remote(self, chan: Channel, ctn: int):
                self.maybe_send_commitment(chan)
       -        while chan.get_current_ctn(REMOTE) <= ctn:
       +        while chan.get_latest_ctn(REMOTE) <= ctn:
                    await self._remote_changed_events[chan.channel_id].wait()
        
            async def await_local(self, chan: Channel, ctn: int):
                self.maybe_send_commitment(chan)
       -        while chan.get_current_ctn(LOCAL) <= ctn:
       +        while chan.get_latest_ctn(LOCAL) <= ctn:
                    await self._local_changed_events[chan.channel_id].wait()
        
            async def pay(self, route: List['RouteEdge'], chan: Channel, amount_msat: int,
       t@@ -1122,7 +1119,7 @@ class Peer(Logger):
                # create htlc
                htlc = UpdateAddHtlc(amount_msat=amount_msat, payment_hash=payment_hash, cltv_expiry=cltv, timestamp=int(time.time()))
                htlc = chan.add_htlc(htlc)
       -        remote_ctn = chan.get_current_ctn(REMOTE)
       +        remote_ctn = chan.get_latest_ctn(REMOTE)
                chan.onion_keys[htlc.htlc_id] = secret_key
                self.attempted_route[(chan.channel_id, htlc.htlc_id)] = route
                self.logger.info(f"starting payment. route: {route}. htlc: {htlc}")
       t@@ -1156,7 +1153,7 @@ class Peer(Logger):
                        and chan.get_next_feerate(LOCAL) == chan.get_latest_feerate(LOCAL)):
                    raise RemoteMisbehaving('received commitment_signed without pending changes')
                # make sure ctn is new
       -        ctn_to_recv = chan.get_current_ctn(LOCAL) + 1
       +        ctn_to_recv = chan.get_next_ctn(LOCAL)
                if ctn_to_recv == self.recv_commitment_for_ctn_last[chan]:
                    raise RemoteMisbehaving('received commitment_signed with same ctn')
                self.recv_commitment_for_ctn_last[chan] = ctn_to_recv
       t@@ -1172,7 +1169,7 @@ class Peer(Logger):
                preimage = update_fulfill_htlc_msg["payment_preimage"]
                htlc_id = int.from_bytes(update_fulfill_htlc_msg["id"], "big")
                chan.receive_htlc_settle(preimage, htlc_id)
       -        local_ctn = chan.get_current_ctn(LOCAL)
       +        local_ctn = chan.get_latest_ctn(LOCAL)
                asyncio.ensure_future(self._on_update_fulfill_htlc(chan, htlc_id, preimage, local_ctn))
        
            @log_exceptions
       t@@ -1206,8 +1203,8 @@ class Peer(Logger):
                                     timestamp=int(time.time()),
                                     htlc_id=htlc_id)
                htlc = chan.receive_htlc(htlc)
       -        local_ctn = chan.get_current_ctn(LOCAL)
       -        remote_ctn = chan.get_current_ctn(REMOTE)
       +        local_ctn = chan.get_latest_ctn(LOCAL)
       +        remote_ctn = chan.get_latest_ctn(REMOTE)
                if processed_onion.are_we_final:
                    asyncio.ensure_future(self._maybe_fulfill_htlc(chan=chan,
                                                                   htlc=htlc,
       t@@ -1243,7 +1240,7 @@ class Peer(Logger):
                next_amount_msat_htlc = int.from_bytes(dph.amt_to_forward, 'big')
                next_htlc = UpdateAddHtlc(amount_msat=next_amount_msat_htlc, payment_hash=htlc.payment_hash, cltv_expiry=next_cltv_expiry, timestamp=int(time.time()))
                next_htlc = next_chan.add_htlc(next_htlc)
       -        next_remote_ctn = next_chan.get_current_ctn(REMOTE)
       +        next_remote_ctn = next_chan.get_latest_ctn(REMOTE)
                next_peer.send_message(
                    "update_add_htlc",
                    channel_id=next_chan.channel_id,
       t@@ -1301,7 +1298,7 @@ class Peer(Logger):
        
            async def _fulfill_htlc(self, chan: Channel, htlc_id: int, preimage: bytes):
                chan.settle_htlc(preimage, htlc_id)
       -        remote_ctn = chan.get_current_ctn(REMOTE)
       +        remote_ctn = chan.get_latest_ctn(REMOTE)
                self.send_message("update_fulfill_htlc",
                                  channel_id=chan.channel_id,
                                  id=htlc_id,
       t@@ -1313,7 +1310,7 @@ class Peer(Logger):
                                reason: OnionRoutingFailureMessage):
                self.logger.info(f"failing received htlc {(bh2u(chan.channel_id), htlc_id)}. reason: {reason}")
                chan.fail_htlc(htlc_id)
       -        remote_ctn = chan.get_current_ctn(REMOTE)
       +        remote_ctn = chan.get_latest_ctn(REMOTE)
                error_packet = construct_onion_error(reason, onion_packet, our_onion_private_key=self.privkey)
                self.send_message("update_fail_htlc",
                                  channel_id=chan.channel_id,
       t@@ -1357,7 +1354,7 @@ class Peer(Logger):
                else:
                    return
                chan.update_fee(feerate_per_kw, True)
       -        remote_ctn = chan.get_current_ctn(REMOTE)
       +        remote_ctn = chan.get_latest_ctn(REMOTE)
                self.send_message("update_fee",
                                  channel_id=chan.channel_id,
                                  feerate_per_kw=feerate_per_kw)
   DIR diff --git a/electrum/lnsweep.py b/electrum/lnsweep.py
       t@@ -188,7 +188,7 @@ def create_sweeptxs_for_our_ctx(chan: 'Channel', ctx: Transaction, ctn: int,
            # other outputs are htlcs
            # if they are spent, we need to generate the script
            # so, second-stage htlc sweep should not be returned here
       -    if ctn != our_conf.ctn:
       +    if ctn < chan.get_oldest_unrevoked_ctn(LOCAL):
                _logger.info("we breached.")
                return {}
            txs = {}
       t@@ -247,17 +247,18 @@ def create_sweeptxs_for_our_ctx(chan: 'Channel', ctx: Transaction, ctn: int,
        
        def analyze_ctx(chan: 'Channel', ctx: Transaction):
            # note: the remote sometimes has two valid non-revoked commitment transactions,
       -    # either of which could be broadcast (their_conf.ctn, their_conf.ctn+1)
       +    # either of which could be broadcast
            our_conf, their_conf = get_ordered_channel_configs(chan=chan, for_us=True)
            ctn = extract_ctn_from_tx_and_chan(ctx, chan)
            per_commitment_secret = None
       -    if ctn == their_conf.ctn:
       +    oldest_unrevoked_remote_ctn = chan.get_oldest_unrevoked_ctn(REMOTE)
       +    if ctn == oldest_unrevoked_remote_ctn:
                their_pcp = their_conf.current_per_commitment_point
                is_revocation = False
       -    elif ctn == their_conf.ctn + 1:
       +    elif ctn == oldest_unrevoked_remote_ctn + 1:
                their_pcp = their_conf.next_per_commitment_point
                is_revocation = False
       -    elif ctn < their_conf.ctn:  # breach
       +    elif ctn < oldest_unrevoked_remote_ctn:  # breach
                try:
                    per_commitment_secret = their_conf.revocation_store.retrieve_secret(RevocationStore.START_INDEX - ctn)
                except UnableToDeriveSecret:
   DIR diff --git a/electrum/lnutil.py b/electrum/lnutil.py
       t@@ -52,7 +52,6 @@ class LocalConfig(NamedTuple):
            was_announced: bool
            current_commitment_signature: Optional[bytes]
            current_htlc_signatures: List[bytes]
       -    got_sig_for_next: bool
        
        
        class RemoteConfig(NamedTuple):
   DIR diff --git a/electrum/lnworker.py b/electrum/lnworker.py
       t@@ -311,8 +311,6 @@ class LNWallet(LNWorker):
                for x in wallet.storage.get("channels", []):
                    c = Channel(x, sweep_address=self.sweep_address, lnworker=self)
                    self.channels[c.channel_id] = c
       -            c.set_remote_commitment()
       -            c.set_local_commitment(c.current_commitment(LOCAL))
                # timestamps of opening and closing transactions
                self.channel_timestamps = self.storage.get('lightning_channel_timestamps', {})
                self.pending_payments = defaultdict(asyncio.Future)
       t@@ -348,10 +346,10 @@ class LNWallet(LNWorker):
                            self.logger.info(f'could not contact remote watchtower {watchtower_url}')
                    await asyncio.sleep(5)
        
       -    async def sync_channel_with_watchtower(self, chan, watchtower):
       +    async def sync_channel_with_watchtower(self, chan: Channel, watchtower):
                outpoint = chan.funding_outpoint.to_str()
                addr = chan.get_funding_address()
       -        current_ctn = chan.get_current_ctn(REMOTE)
       +        current_ctn = chan.get_oldest_unrevoked_ctn(REMOTE)
                watchtower_ctn = await watchtower.get_ctn(outpoint, addr)
                for ctn in range(watchtower_ctn + 1, current_ctn):
                    sweeptxs = chan.create_sweeptxs(ctn)
   DIR diff --git a/electrum/tests/test_lnchannel.py b/electrum/tests/test_lnchannel.py
       t@@ -85,7 +85,6 @@ def create_channel_state(funding_txid, funding_index, funding_sat, is_initiator,
                        was_announced=False,
                        current_commitment_signature=None,
                        current_htlc_signatures=None,
       -                got_sig_for_next=False,
                    ),
                    "constraints":lnpeer.ChannelConstraints(
                        capacity=funding_sat,
       t@@ -93,7 +92,6 @@ def create_channel_state(funding_txid, funding_index, funding_sat, is_initiator,
                        funding_txn_minimum_depth=3,
                    ),
                    "node_id":other_node_id,
       -            "remote_commitment_to_be_revoked": None,
                    'onion_keys': {},
            }
        
       t@@ -137,8 +135,8 @@ def create_test_channels(feerate=6000, local=None, remote=None):
            alice.set_state('OPEN')
            bob.set_state('OPEN')
        
       -    a_out = alice.current_commitment(LOCAL).outputs()
       -    b_out = bob.pending_commitment(REMOTE).outputs()
       +    a_out = alice.get_latest_commitment(LOCAL).outputs()
       +    b_out = bob.get_next_commitment(REMOTE).outputs()
            assert a_out == b_out, "\n" + pformat((a_out, b_out))
        
            sig_from_bob, a_htlc_sigs = bob.sign_next_commitment()
       t@@ -150,21 +148,12 @@ def create_test_channels(feerate=6000, local=None, remote=None):
            alice.config[LOCAL] = alice.config[LOCAL]._replace(current_commitment_signature=sig_from_bob)
            bob.config[LOCAL] = bob.config[LOCAL]._replace(current_commitment_signature=sig_from_alice)
        
       -    alice.set_local_commitment(alice.current_commitment(LOCAL))
       -    bob.set_local_commitment(bob.current_commitment(LOCAL))
       -
            alice_second = lnutil.secret_to_pubkey(int.from_bytes(lnutil.get_per_commitment_secret_from_seed(alice_seed, lnutil.RevocationStore.START_INDEX - 1), "big"))
            bob_second = lnutil.secret_to_pubkey(int.from_bytes(lnutil.get_per_commitment_secret_from_seed(bob_seed, lnutil.RevocationStore.START_INDEX - 1), "big"))
        
            alice.config[REMOTE] = alice.config[REMOTE]._replace(next_per_commitment_point=bob_second, current_per_commitment_point=bob_first)
            bob.config[REMOTE] = bob.config[REMOTE]._replace(next_per_commitment_point=alice_second, current_per_commitment_point=alice_first)
        
       -    alice.set_remote_commitment()
       -    bob.set_remote_commitment()
       -
       -    alice.remote_commitment_to_be_revoked = alice.remote_commitment
       -    bob.remote_commitment_to_be_revoked = bob.remote_commitment
       -
            alice.config[REMOTE] = alice.config[REMOTE]._replace(ctn=0)
            bob.config[REMOTE] = bob.config[REMOTE]._replace(ctn=0)
            alice.hm.channel_open_finished()
       t@@ -179,7 +168,7 @@ class TestFee(unittest.TestCase):
            """
            def test_fee(self):
                alice_channel, bob_channel = create_test_channels(253, 10000000000, 5000000000)
       -        self.assertIn(9999817, [x[2] for x in alice_channel.local_commitment.outputs()])
       +        self.assertIn(9999817, [x[2] for x in alice_channel.get_latest_commitment(LOCAL).outputs()])
        
        class TestChannel(unittest.TestCase):
            maxDiff = 999
       t@@ -228,31 +217,43 @@ class TestChannel(unittest.TestCase):
                self.htlc_dict['amount_msat'] += 1000
                self.bob_channel.add_htlc(self.htlc_dict)
                self.alice_channel.receive_htlc(self.htlc_dict)
       +
       +        self.assertEqual(len(self.alice_channel.get_latest_commitment(LOCAL).outputs()), 2)
       +        self.assertEqual(len(self.alice_channel.get_next_commitment(LOCAL).outputs()), 3)
       +        self.assertEqual(len(self.alice_channel.get_latest_commitment(REMOTE).outputs()), 2)
       +        self.assertEqual(len(self.alice_channel.get_next_commitment(REMOTE).outputs()), 3)
       +
                self.alice_channel.receive_new_commitment(*self.bob_channel.sign_next_commitment())
       -        self.assertEqual(len(self.alice_channel.pending_commitment(REMOTE).outputs()), 3)
       +
       +        self.assertEqual(len(self.alice_channel.get_latest_commitment(LOCAL).outputs()), 3)
       +        self.assertEqual(len(self.alice_channel.get_next_commitment(LOCAL).outputs()), 3)
       +        self.assertEqual(len(self.alice_channel.get_latest_commitment(REMOTE).outputs()), 2)
       +        self.assertEqual(len(self.alice_channel.get_next_commitment(REMOTE).outputs()), 3)
       +
                self.alice_channel.revoke_current_commitment()
       -        self.assertEqual(len(self.alice_channel.pending_commitment(REMOTE).outputs()), 4)
       +
       +        self.assertEqual(len(self.alice_channel.get_latest_commitment(LOCAL).outputs()), 3)
       +        self.assertEqual(len(self.alice_channel.get_next_commitment(LOCAL).outputs()), 3)
       +        self.assertEqual(len(self.alice_channel.get_latest_commitment(REMOTE).outputs()), 2)
       +        self.assertEqual(len(self.alice_channel.get_next_commitment(REMOTE).outputs()), 4)
        
            def test_SimpleAddSettleWorkflow(self):
                alice_channel, bob_channel = self.alice_channel, self.bob_channel
                htlc = self.htlc
        
       -        alice_out = alice_channel.current_commitment(LOCAL).outputs()
       +        alice_out = alice_channel.get_latest_commitment(LOCAL).outputs()
                short_idx, = [idx for idx, x in enumerate(alice_out) if len(x.address) == 42]
                long_idx,  = [idx for idx, x in enumerate(alice_out) if len(x.address) == 62]
                self.assertLess(alice_out[long_idx].value, 5 * 10**8, alice_out)
                self.assertEqual(alice_out[short_idx].value, 5 * 10**8, alice_out)
        
       -        alice_out = alice_channel.current_commitment(REMOTE).outputs()
       +        alice_out = alice_channel.get_latest_commitment(REMOTE).outputs()
                short_idx, = [idx for idx, x in enumerate(alice_out) if len(x.address) == 42]
                long_idx,  = [idx for idx, x in enumerate(alice_out) if len(x.address) == 62]
                self.assertLess(alice_out[short_idx].value, 5 * 10**8)
                self.assertEqual(alice_out[long_idx].value, 5 * 10**8)
        
       -        def com():
       -            return alice_channel.local_commitment
       -
       -        self.assertTrue(alice_channel.signature_fits(com()))
       +        self.assertTrue(alice_channel.signature_fits(alice_channel.get_latest_commitment(LOCAL)))
        
                self.assertNotEqual(alice_channel.included_htlcs(REMOTE, RECEIVED, 1), [])
        
       t@@ -270,9 +271,9 @@ class TestChannel(unittest.TestCase):
        
                from electrum.lnutil import extract_ctn_from_tx_and_chan
                tx0 = str(alice_channel.force_close_tx())
       -        self.assertEqual(alice_channel.config[LOCAL].ctn, 0)
       +        self.assertEqual(alice_channel.get_oldest_unrevoked_ctn(LOCAL), 0)
                self.assertEqual(extract_ctn_from_tx_and_chan(alice_channel.force_close_tx(), alice_channel), 0)
       -        self.assertTrue(alice_channel.signature_fits(alice_channel.current_commitment(LOCAL)))
       +        self.assertTrue(alice_channel.signature_fits(alice_channel.get_latest_commitment(LOCAL)))
        
                # Next alice commits this change by sending a signature message. Since
                # we expect the messages to be ordered, Bob will receive the HTLC we
       t@@ -281,21 +282,20 @@ class TestChannel(unittest.TestCase):
                aliceSig, aliceHtlcSigs = alice_channel.sign_next_commitment()
                self.assertEqual(len(aliceHtlcSigs), 1, "alice should generate one htlc signature")
        
       -        self.assertTrue(alice_channel.signature_fits(com()))
       -        self.assertEqual(str(alice_channel.current_commitment(LOCAL)), str(com()))
       +        self.assertTrue(alice_channel.signature_fits(alice_channel.get_latest_commitment(LOCAL)))
        
                self.assertEqual(next(iter(alice_channel.hm.get_htlcs_in_next_ctx(REMOTE)))[0], RECEIVED)
                self.assertEqual(alice_channel.hm.get_htlcs_in_next_ctx(REMOTE), bob_channel.hm.get_htlcs_in_next_ctx(LOCAL))
       -        self.assertEqual(alice_channel.pending_commitment(REMOTE).outputs(), bob_channel.pending_commitment(LOCAL).outputs())
       +        self.assertEqual(alice_channel.get_latest_commitment(REMOTE).outputs(), bob_channel.get_next_commitment(LOCAL).outputs())
        
                # Bob receives this signature message, and checks that this covers the
                # state he has in his remote log. This includes the HTLC just sent
                # from Alice.
       -        self.assertTrue(bob_channel.signature_fits(bob_channel.current_commitment(LOCAL)))
       +        self.assertTrue(bob_channel.signature_fits(bob_channel.get_latest_commitment(LOCAL)))
                bob_channel.receive_new_commitment(aliceSig, aliceHtlcSigs)
       -        self.assertTrue(bob_channel.signature_fits(bob_channel.pending_commitment(LOCAL)))
       +        self.assertTrue(bob_channel.signature_fits(bob_channel.get_latest_commitment(LOCAL)))
        
       -        self.assertEqual(bob_channel.config[REMOTE].ctn, 0)
       +        self.assertEqual(bob_channel.get_oldest_unrevoked_ctn(REMOTE), 0)
                self.assertEqual(bob_channel.included_htlcs(LOCAL, RECEIVED, 1), [htlc])#
        
                self.assertEqual(alice_channel.included_htlcs(REMOTE, RECEIVED, 0), [])
       t@@ -311,57 +311,50 @@ class TestChannel(unittest.TestCase):
                # has a valid signature for a newer commitment.
                bobRevocation, _ = bob_channel.revoke_current_commitment()
                bob_channel.serialize()
       -        self.assertTrue(bob_channel.signature_fits(bob_channel.current_commitment(LOCAL)))
       +        self.assertTrue(bob_channel.signature_fits(bob_channel.get_latest_commitment(LOCAL)))
        
                # Bob finally sends a signature for Alice's commitment transaction.
                # This signature will cover the HTLC, since Bob will first send the
                # revocation just created. The revocation also acks every received
                # HTLC up to the point where Alice sent her signature.
                bobSig, bobHtlcSigs = bob_channel.sign_next_commitment()
       -        self.assertTrue(bob_channel.signature_fits(bob_channel.current_commitment(LOCAL)))
       +        self.assertTrue(bob_channel.signature_fits(bob_channel.get_latest_commitment(LOCAL)))
        
                self.assertEqual(len(bobHtlcSigs), 1)
        
       -        self.assertTrue(alice_channel.signature_fits(com()))
       -        self.assertEqual(str(alice_channel.current_commitment(LOCAL)), str(com()))
       +        self.assertTrue(alice_channel.signature_fits(alice_channel.get_latest_commitment(LOCAL)))
        
                # so far: Alice added htlc, Alice signed.
       -        self.assertEqual(len(alice_channel.current_commitment(LOCAL).outputs()), 2)
       -        self.assertEqual(len(alice_channel.pending_commitment(LOCAL).outputs()), 2)
       -        self.assertEqual(len(alice_channel.current_commitment(REMOTE).outputs()), 2)  # oldest unrevoked
       -        self.assertEqual(len(alice_channel.pending_commitment(REMOTE).outputs()), 3)  # latest
       +        self.assertEqual(len(alice_channel.get_latest_commitment(LOCAL).outputs()), 2)
       +        self.assertEqual(len(alice_channel.get_next_commitment(LOCAL).outputs()), 2)
       +        self.assertEqual(len(alice_channel.get_oldest_unrevoked_commitment(REMOTE).outputs()), 2)
       +        self.assertEqual(len(alice_channel.get_latest_commitment(REMOTE).outputs()), 3)
        
                # Alice then processes this revocation, sending her own revocation for
                # her prior commitment transaction. Alice shouldn't have any HTLCs to
                # forward since she's sending an outgoing HTLC.
                alice_channel.receive_revocation(bobRevocation)
                alice_channel.serialize()
       -        self.assertEqual(alice_channel.remote_commitment.outputs(), alice_channel.current_commitment(REMOTE).outputs())
        
       -        self.assertTrue(alice_channel.signature_fits(com()))
       -        self.assertTrue(alice_channel.signature_fits(alice_channel.current_commitment(LOCAL)))
       +        self.assertTrue(alice_channel.signature_fits(alice_channel.get_latest_commitment(LOCAL)))
                alice_channel.serialize()
       -        self.assertEqual(str(alice_channel.current_commitment(LOCAL)), str(com()))
        
       -        self.assertEqual(len(alice_channel.current_commitment(LOCAL).outputs()), 2)
       -        self.assertEqual(len(alice_channel.current_commitment(REMOTE).outputs()), 3)
       -        self.assertEqual(len(com().outputs()), 2)
       +        self.assertEqual(len(alice_channel.get_latest_commitment(LOCAL).outputs()), 2)
       +        self.assertEqual(len(alice_channel.get_latest_commitment(REMOTE).outputs()), 3)
                self.assertEqual(len(alice_channel.force_close_tx().outputs()), 2)
        
                self.assertEqual(len(alice_channel.hm.log[LOCAL]['adds']), 1)
                alice_channel.serialize()
        
       -        self.assertEqual(alice_channel.pending_commitment(LOCAL).outputs(),
       -                         bob_channel.pending_commitment(REMOTE).outputs())
       +        self.assertEqual(alice_channel.get_next_commitment(LOCAL).outputs(),
       +                         bob_channel.get_latest_commitment(REMOTE).outputs())
        
                # Alice then processes bob's signature, and since she just received
                # the revocation, she expect this signature to cover everything up to
                # the point where she sent her signature, including the HTLC.
                alice_channel.receive_new_commitment(bobSig, bobHtlcSigs)
       -        self.assertEqual(alice_channel.remote_commitment.outputs(), alice_channel.current_commitment(REMOTE).outputs())
        
       -        self.assertEqual(len(alice_channel.current_commitment(REMOTE).outputs()), 3)
       -        self.assertEqual(len(com().outputs()), 3)
       +        self.assertEqual(len(alice_channel.get_latest_commitment(REMOTE).outputs()), 3)
                self.assertEqual(len(alice_channel.force_close_tx().outputs()), 3)
        
                self.assertEqual(len(alice_channel.hm.log[LOCAL]['adds']), 1)
       t@@ -371,10 +364,8 @@ class TestChannel(unittest.TestCase):
                self.assertNotEqual(tx0, tx1)
        
                # Alice then generates a revocation for bob.
       -        self.assertEqual(alice_channel.remote_commitment.outputs(), alice_channel.current_commitment(REMOTE).outputs())
                aliceRevocation, _ = alice_channel.revoke_current_commitment()
                alice_channel.serialize()
       -        #self.assertEqual(alice_channel.remote_commitment.outputs(), alice_channel.current_commitment(REMOTE).outputs())
        
                tx2 = str(alice_channel.force_close_tx())
                # since alice already has the signature for the next one, it doesn't change her force close tx (it was already the newer one)
       t@@ -384,7 +375,7 @@ class TestChannel(unittest.TestCase):
                # is fully locked in within both commitment transactions. Bob should
                # also be able to forward an HTLC now that the HTLC has been locked
                # into both commitment transactions.
       -        self.assertTrue(bob_channel.signature_fits(bob_channel.current_commitment(LOCAL)))
       +        self.assertTrue(bob_channel.signature_fits(bob_channel.get_latest_commitment(LOCAL)))
                bob_channel.receive_revocation(aliceRevocation)
                bob_channel.serialize()
        
       t@@ -398,13 +389,13 @@ class TestChannel(unittest.TestCase):
                self.assertEqual(alice_channel.total_msat(RECEIVED), bobSent, "alice has incorrect milli-satoshis received")
                self.assertEqual(bob_channel.total_msat(SENT), bobSent, "bob has incorrect milli-satoshis sent")
                self.assertEqual(bob_channel.total_msat(RECEIVED), aliceSent, "bob has incorrect milli-satoshis received")
       -        self.assertEqual(bob_channel.config[LOCAL].ctn, 1, "bob has incorrect commitment height")
       -        self.assertEqual(alice_channel.config[LOCAL].ctn, 1, "alice has incorrect commitment height")
       +        self.assertEqual(bob_channel.get_oldest_unrevoked_ctn(LOCAL), 1, "bob has incorrect commitment height")
       +        self.assertEqual(alice_channel.get_oldest_unrevoked_ctn(LOCAL), 1, "alice has incorrect commitment height")
        
                # Both commitment transactions should have three outputs, and one of
                # them should be exactly the amount of the HTLC.
       -        alice_ctx = alice_channel.pending_commitment(LOCAL)
       -        bob_ctx = bob_channel.pending_commitment(LOCAL)
       +        alice_ctx = alice_channel.get_next_commitment(LOCAL)
       +        bob_ctx = bob_channel.get_next_commitment(LOCAL)
                self.assertEqual(len(alice_ctx.outputs()), 3, "alice should have three commitment outputs, instead have %s"% len(alice_ctx.outputs()))
                self.assertEqual(len(bob_ctx.outputs()), 3, "bob should have three commitment outputs, instead have %s"% len(bob_ctx.outputs()))
                self.assertOutputExistsByValue(alice_ctx, htlc.amount_msat // 1000)
       t@@ -415,7 +406,6 @@ class TestChannel(unittest.TestCase):
                preimage = self.paymentPreimage
                bob_channel.settle_htlc(preimage, self.bobHtlcIndex)
        
       -        #self.assertEqual(alice_channel.remote_commitment.outputs(), alice_channel.current_commitment(REMOTE).outputs())
                alice_channel.receive_htlc_settle(preimage, self.aliceHtlcIndex)
        
                tx3 = str(alice_channel.force_close_tx())
       t@@ -426,7 +416,7 @@ class TestChannel(unittest.TestCase):
                self.assertEqual(len(bobHtlcSigs2), 0)
        
                self.assertEqual(alice_channel.hm.htlcs_by_direction(REMOTE, RECEIVED), [htlc])
       -        self.assertEqual(alice_channel.included_htlcs(REMOTE, RECEIVED, alice_channel.config[REMOTE].ctn), [htlc])
       +        self.assertEqual(alice_channel.included_htlcs(REMOTE, RECEIVED, alice_channel.get_oldest_unrevoked_ctn(REMOTE)), [htlc])
        
                self.assertEqual(alice_channel.included_htlcs(REMOTE, RECEIVED, 1), [htlc])
                self.assertEqual(alice_channel.included_htlcs(REMOTE, RECEIVED, 2), [htlc])
       t@@ -440,8 +430,8 @@ class TestChannel(unittest.TestCase):
                self.assertEqual(bob_channel.included_htlcs(REMOTE, RECEIVED, 1), [])
                self.assertEqual(bob_channel.included_htlcs(REMOTE, RECEIVED, 2), [])
        
       -        alice_ctx_bob_version = bob_channel.pending_commitment(REMOTE).outputs()
       -        alice_ctx_alice_version = alice_channel.pending_commitment(LOCAL).outputs()
       +        alice_ctx_bob_version = bob_channel.get_latest_commitment(REMOTE).outputs()
       +        alice_ctx_alice_version = alice_channel.get_next_commitment(LOCAL).outputs()
                self.assertEqual(alice_ctx_alice_version, alice_ctx_bob_version)
        
                alice_channel.receive_new_commitment(bobSig2, bobHtlcSigs2)
       t@@ -450,14 +440,13 @@ class TestChannel(unittest.TestCase):
                self.assertNotEqual(tx3, tx4)
        
                self.assertEqual(alice_channel.balance(LOCAL), 500000000000)
       -        self.assertEqual(1, alice_channel.config[LOCAL].ctn)
       +        self.assertEqual(1, alice_channel.get_oldest_unrevoked_ctn(LOCAL))
                self.assertEqual(len(alice_channel.included_htlcs(LOCAL, RECEIVED, ctn=2)), 0)
                aliceRevocation2, _ = alice_channel.revoke_current_commitment()
                alice_channel.serialize()
                aliceSig2, aliceHtlcSigs2 = alice_channel.sign_next_commitment()
                self.assertEqual(aliceHtlcSigs2, [], "alice should generate no htlc signatures")
       -        self.assertEqual(len(bob_channel.current_commitment(LOCAL).outputs()), 3)
       -        #self.assertEqual(len(bob_channel.pending_commitment(LOCAL).outputs()), 3)
       +        self.assertEqual(len(bob_channel.get_latest_commitment(LOCAL).outputs()), 3)
                bob_channel.receive_revocation(aliceRevocation2)
                bob_channel.serialize()
        
       t@@ -478,14 +467,14 @@ class TestChannel(unittest.TestCase):
                self.assertEqual(alice_channel.total_msat(RECEIVED), 0, "alice satoshis received incorrect")
                self.assertEqual(bob_channel.total_msat(RECEIVED), mSatTransferred, "bob satoshis received incorrect")
                self.assertEqual(bob_channel.total_msat(SENT), 0, "bob satoshis sent incorrect")
       -        self.assertEqual(bob_channel.current_height[LOCAL], 2, "bob has incorrect commitment height")
       -        self.assertEqual(alice_channel.current_height[LOCAL], 2, "alice has incorrect commitment height")
       +        self.assertEqual(bob_channel.get_latest_ctn(LOCAL), 2, "bob has incorrect commitment height")
       +        self.assertEqual(alice_channel.get_latest_ctn(LOCAL), 2, "alice has incorrect commitment height")
        
                alice_channel.update_fee(100000, True)
       -        alice_outputs = alice_channel.pending_commitment(REMOTE).outputs()
       -        old_outputs = bob_channel.pending_commitment(LOCAL).outputs()
       +        alice_outputs = alice_channel.get_next_commitment(REMOTE).outputs()
       +        old_outputs = bob_channel.get_next_commitment(LOCAL).outputs()
                bob_channel.update_fee(100000, False)
       -        new_outputs = bob_channel.pending_commitment(LOCAL).outputs()
       +        new_outputs = bob_channel.get_next_commitment(LOCAL).outputs()
                self.assertNotEqual(old_outputs, new_outputs)
                self.assertEqual(alice_outputs, new_outputs)
        
       t@@ -517,13 +506,13 @@ class TestChannel(unittest.TestCase):
        
        
            def alice_to_bob_fee_update(self, fee=111):
       -        aoldctx = self.alice_channel.pending_commitment(REMOTE).outputs()
       +        aoldctx = self.alice_channel.get_next_commitment(REMOTE).outputs()
                self.alice_channel.update_fee(fee, True)
       -        anewctx = self.alice_channel.pending_commitment(REMOTE).outputs()
       +        anewctx = self.alice_channel.get_next_commitment(REMOTE).outputs()
                self.assertNotEqual(aoldctx, anewctx)
       -        boldctx = self.bob_channel.pending_commitment(LOCAL).outputs()
       +        boldctx = self.bob_channel.get_next_commitment(LOCAL).outputs()
                self.bob_channel.update_fee(fee, False)
       -        bnewctx = self.bob_channel.pending_commitment(LOCAL).outputs()
       +        bnewctx = self.bob_channel.get_next_commitment(LOCAL).outputs()
                self.assertNotEqual(boldctx, bnewctx)
                self.assertEqual(anewctx, bnewctx)
                return fee
       t@@ -805,12 +794,12 @@ class TestDust(unittest.TestCase):
                    'timestamp'   :  0,
                }
        
       -        old_values = [x.value for x in bob_channel.current_commitment(LOCAL).outputs() ]
       +        old_values = [x.value for x in bob_channel.get_latest_commitment(LOCAL).outputs() ]
                aliceHtlcIndex = alice_channel.add_htlc(htlc).htlc_id
                bobHtlcIndex = bob_channel.receive_htlc(htlc).htlc_id
                force_state_transition(alice_channel, bob_channel)
       -        alice_ctx = alice_channel.current_commitment(LOCAL)
       -        bob_ctx = bob_channel.current_commitment(LOCAL)
       +        alice_ctx = alice_channel.get_latest_commitment(LOCAL)
       +        bob_ctx = bob_channel.get_latest_commitment(LOCAL)
                new_values = [x.value for x in bob_ctx.outputs() ]
                self.assertNotEqual(old_values, new_values)
                self.assertEqual(len(alice_ctx.outputs()), 3)
       t@@ -820,7 +809,7 @@ class TestDust(unittest.TestCase):
                bob_channel.settle_htlc(paymentPreimage, bobHtlcIndex)
                alice_channel.receive_htlc_settle(paymentPreimage, aliceHtlcIndex)
                force_state_transition(bob_channel, alice_channel)
       -        self.assertEqual(len(alice_channel.pending_commitment(LOCAL).outputs()), 2)
       +        self.assertEqual(len(alice_channel.get_next_commitment(LOCAL).outputs()), 2)
                self.assertEqual(alice_channel.total_msat(SENT) // 1000, htlcAmt)
        
        def force_state_transition(chanA, chanB):