tln: avoid recursive dependencies, make new lnutil - electrum - Electrum Bitcoin wallet
 (HTM) git clone https://git.parazyd.org/electrum
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
       ---
 (DIR) commit fe973a5137ecb1ed9a8b63e042363b0c7792edef
 (DIR) parent 7a3551b5dfbc5643bb26add87cca8b0634d3dfb8
 (HTM) Author: Janus <ysangkok@gmail.com>
       Date:   Thu, 28 Jun 2018 15:50:45 +0200
       
       ln: avoid recursive dependencies, make new lnutil
       
       Diffstat:
         M lib/lnbase.py                       |     366 +------------------------------
         M lib/lnhtlc.py                       |      62 ++++++++++++++++++++-----------
         M lib/lnrouter.py                     |      10 ++++++----
         A lib/lnutil.py                       |     315 +++++++++++++++++++++++++++++++
         M lib/lnwatcher.py                    |       2 +-
         M lib/lnworker.py                     |      10 ++++------
         D lib/tests/test_lnbase.py            |     819 -------------------------------
         M lib/tests/test_lnhtlc.py            |      11 ++++++-----
         A lib/tests/test_lnrouter.py          |     150 +++++++++++++++++++++++++++++++
         A lib/tests/test_lnutil.py            |     670 +++++++++++++++++++++++++++++++
       
       10 files changed, 1205 insertions(+), 1210 deletions(-)
       ---
 (DIR) diff --git a/lib/lnbase.py b/lib/lnbase.py
       t@@ -5,49 +5,12 @@
        """
        
        from collections import namedtuple, defaultdict, OrderedDict, defaultdict
       -Keypair = namedtuple("Keypair", ["pubkey", "privkey"])
       -Outpoint = namedtuple("Outpoint", ["txid", "output_index"])
       -ChannelConfig = namedtuple("ChannelConfig", [
       -    "payment_basepoint", "multisig_key", "htlc_basepoint", "delayed_basepoint", "revocation_basepoint",
       -    "to_self_delay", "dust_limit_sat", "max_htlc_value_in_flight_msat", "max_accepted_htlcs"])
       -OnlyPubkeyKeypair = namedtuple("OnlyPubkeyKeypair", ["pubkey"])
       -RemoteState = namedtuple("RemoteState", ["ctn", "next_per_commitment_point", "amount_msat", "revocation_store", "current_per_commitment_point", "next_htlc_id"])
       -LocalState = namedtuple("LocalState", ["ctn", "per_commitment_secret_seed", "amount_msat", "next_htlc_id", "funding_locked_received", "was_announced", "current_commitment_signature"])
       -ChannelConstraints = namedtuple("ChannelConstraints", ["feerate", "capacity", "is_initiator", "funding_txn_minimum_depth"])
       -#OpenChannel = namedtuple("OpenChannel", ["channel_id", "short_channel_id", "funding_outpoint", "local_config", "remote_config", "remote_state", "local_state", "constraints", "node_id"])
       -
       -class RevocationStore:
       -    """ taken from lnd """
       -    def __init__(self):
       -        self.buckets = [None] * 48
       -        self.index = 2**48 - 1
       -    def add_next_entry(self, hsh):
       -        new_element = ShachainElement(index=self.index, secret=hsh)
       -        bucket = count_trailing_zeros(self.index)
       -        for i in range(0, bucket):
       -            this_bucket = self.buckets[i]
       -            e = shachain_derive(new_element, this_bucket.index)
       -
       -            if e != this_bucket:
       -                raise Exception("hash is not derivable: {} {} {}".format(bh2u(e.secret), bh2u(this_bucket.secret), this_bucket.index))
       -        self.buckets[bucket] = new_element
       -        self.index -= 1
       -    def serialize(self):
       -        return {"index": self.index, "buckets": [[bh2u(k.secret), k.index] if k is not None else None for k in self.buckets]}
       -    @staticmethod
       -    def from_json_obj(decoded_json_obj):
       -        store = RevocationStore()
       -        decode = lambda to_decode: ShachainElement(bfh(to_decode[0]), int(to_decode[1]))
       -        store.buckets = [k if k is None else decode(k) for k in decoded_json_obj["buckets"]]
       -        store.index = decoded_json_obj["index"]
       -        return store
       -    def __eq__(self, o):
       -        return type(o) is RevocationStore and self.serialize() == o.serialize()
       -    def __hash__(self):
       -        return hash(json.dumps(self.serialize(), sort_keys=True))
       +from .lnutil import Outpoint, ChannelConfig, LocalState, RemoteState, Keypair, OnlyPubkeyKeypair, ChannelConstraints, RevocationStore
       +from .lnutil import sign_and_get_sig_string, funding_output_script, get_ecdh, get_per_commitment_secret_from_seed
       +from .lnutil import secret_to_pubkey
       +from .bitcoin import COIN
        
        from ecdsa.util import sigdecode_der, sigencode_string_canonize, sigdecode_string
       -from ecdsa.curves import SECP256k1
        import queue
        import traceback
        import json
       t@@ -58,18 +21,8 @@ import time
        import binascii
        import hashlib
        import hmac
       -from typing import Sequence, Union, Tuple
        import cryptography.hazmat.primitives.ciphers.aead as AEAD
       -from cryptography.hazmat.primitives.ciphers import Cipher, algorithms
       -from cryptography.hazmat.backends import default_backend
        
       -HTLC_TIMEOUT_WEIGHT = 663
       -HTLC_SUCCESS_WEIGHT = 703
       -
       -from .ecc import ser_to_point, point_to_ser, string_to_number
       -from .bitcoin import (deserialize_privkey, rev_hex, int_to_hex,
       -                      push_script, script_num_to_hex,
       -                      add_number_to_script, var_int, COIN)
        from . import bitcoin
        from . import ecc
        from . import crypto
       t@@ -82,6 +35,8 @@ from .lnrouter import new_onion_packet, OnionHopsDataSingle, OnionPerHop, decode
        from .lightning_payencode.lnaddr import lndecode
        from .lnhtlc import UpdateAddHtlc, HTLCStateMachine, RevokeAndAck, SettleHtlc
        
       +REV_GENESIS = bytes.fromhex(bitcoin.rev_hex(constants.net.GENESIS))
       +
        def channel_id_from_funding_tx(funding_txid, funding_index):
            funding_txid_bytes = bytes.fromhex(funding_txid)[::-1]
            i = int.from_bytes(funding_txid_bytes, 'big') ^ funding_index
       t@@ -289,10 +244,6 @@ def get_bolt8_hkdf(salt, ikm):
            assert len(T1 + T2) == 64
            return T1, T2
        
       -def get_ecdh(priv: bytes, pub: bytes) -> bytes:
       -    pt = ecc.ECPubkey(pub) * string_to_number(priv)
       -    return sha256(pt.get_public_key_bytes())
       -
        def act1_initiator_message(hs, my_privkey):
            #Get a new ephemeral key
            epriv, epub = create_ephemeral_key(my_privkey)
       t@@ -328,290 +279,6 @@ def aiosafe(f):
                    traceback.print_exc()
            return f2
        
       -def get_obscured_ctn(ctn, local, remote):
       -    mask = int.from_bytes(sha256(local + remote)[-6:], 'big')
       -    return ctn ^ mask
       -
       -def secret_to_pubkey(secret):
       -    assert type(secret) is int
       -    return point_to_ser(SECP256k1.generator * secret)
       -
       -def derive_pubkey(basepoint, per_commitment_point):
       -    p = ecc.ECPubkey(basepoint) + ecc.generator() * ecc.string_to_number(sha256(per_commitment_point + basepoint))
       -    return p.get_public_key_bytes()
       -
       -def derive_privkey(secret, per_commitment_point):
       -    assert type(secret) is int
       -    basepoint = point_to_ser(SECP256k1.generator * secret)
       -    basepoint = secret + ecc.string_to_number(sha256(per_commitment_point + basepoint))
       -    basepoint %= SECP256k1.order
       -    return basepoint
       -
       -def derive_blinded_pubkey(basepoint, per_commitment_point):
       -    k1 = ecc.ECPubkey(basepoint) * ecc.string_to_number(sha256(basepoint + per_commitment_point))
       -    k2 = ecc.ECPubkey(per_commitment_point) * ecc.string_to_number(sha256(per_commitment_point + basepoint))
       -    return (k1 + k2).get_public_key_bytes()
       -
       -def shachain_derive(element, toIndex):
       -    return ShachainElement(get_per_commitment_secret_from_seed(element.secret, toIndex, count_trailing_zeros(element.index)), toIndex)
       -
       -
       -def get_per_commitment_secret_from_seed(seed: bytes, i: int, bits: int = 48) -> bytes:
       -    """Generate per commitment secret."""
       -    per_commitment_secret = bytearray(seed)
       -    for bitindex in range(bits - 1, -1, -1):
       -        mask = 1 << bitindex
       -        if i & mask:
       -            per_commitment_secret[bitindex // 8] ^= 1 << (bitindex % 8)
       -            per_commitment_secret = bytearray(sha256(per_commitment_secret))
       -    bajts = bytes(per_commitment_secret)
       -    return bajts
       -
       -
       -def overall_weight(num_htlc):
       -    return 500 + 172 * num_htlc + 224
       -
       -def make_htlc_tx_output(amount_msat, local_feerate, revocationpubkey, local_delayedpubkey, success, to_self_delay):
       -    assert type(amount_msat) is int
       -    assert type(local_feerate) is int
       -    assert type(revocationpubkey) is bytes
       -    assert type(local_delayedpubkey) is bytes
       -    script = bytes([opcodes.OP_IF]) \
       -        + bfh(push_script(bh2u(revocationpubkey))) \
       -        + bytes([opcodes.OP_ELSE]) \
       -        + bitcoin.add_number_to_script(to_self_delay) \
       -        + bytes([opcodes.OP_CSV, opcodes.OP_DROP]) \
       -        + bfh(push_script(bh2u(local_delayedpubkey))) \
       -        + bytes([opcodes.OP_ENDIF, opcodes.OP_CHECKSIG])
       -
       -    p2wsh = bitcoin.redeem_script_to_address('p2wsh', bh2u(script))
       -    weight = HTLC_SUCCESS_WEIGHT if success else HTLC_TIMEOUT_WEIGHT
       -    fee = local_feerate * weight
       -    final_amount_sat = (amount_msat - fee) // 1000
       -    assert final_amount_sat > 0, final_amount_sat
       -    output = (bitcoin.TYPE_ADDRESS, p2wsh, final_amount_sat)
       -    return output
       -
       -def make_htlc_tx_witness(remotehtlcsig, localhtlcsig, payment_preimage, witness_script):
       -    assert type(remotehtlcsig) is bytes
       -    assert type(localhtlcsig) is bytes
       -    assert type(payment_preimage) is bytes
       -    assert type(witness_script) is bytes
       -    return bfh(transaction.construct_witness([0, remotehtlcsig, localhtlcsig, payment_preimage, witness_script]))
       -
       -def make_htlc_tx_inputs(htlc_output_txid, htlc_output_index, revocationpubkey, local_delayedpubkey, amount_msat, witness_script):
       -    assert type(htlc_output_txid) is str
       -    assert type(htlc_output_index) is int
       -    assert type(revocationpubkey) is bytes
       -    assert type(local_delayedpubkey) is bytes
       -    assert type(amount_msat) is int
       -    assert type(witness_script) is str
       -    c_inputs = [{
       -        'scriptSig': '',
       -        'type': 'p2wsh',
       -        'signatures': [],
       -        'num_sig': 0,
       -        'prevout_n': htlc_output_index,
       -        'prevout_hash': htlc_output_txid,
       -        'value': amount_msat // 1000,
       -        'coinbase': False,
       -        'sequence': 0x0,
       -        'preimage_script': witness_script,
       -    }]
       -    return c_inputs
       -
       -def make_htlc_tx(cltv_timeout, inputs, output):
       -    assert type(cltv_timeout) is int
       -    c_outputs = [output]
       -    tx = Transaction.from_io(inputs, c_outputs, locktime=cltv_timeout, version=2)
       -    tx.BIP_LI01_sort()
       -    return tx
       -
       -def make_offered_htlc(revocation_pubkey, remote_htlcpubkey, local_htlcpubkey, payment_hash):
       -    assert type(revocation_pubkey) is bytes
       -    assert type(remote_htlcpubkey) is bytes
       -    assert type(local_htlcpubkey) is bytes
       -    assert type(payment_hash) is bytes
       -    return bytes([opcodes.OP_DUP, opcodes.OP_HASH160]) + bfh(push_script(bh2u(bitcoin.hash_160(revocation_pubkey))))\
       -        + bytes([opcodes.OP_EQUAL, opcodes.OP_IF, opcodes.OP_CHECKSIG, opcodes.OP_ELSE]) \
       -        + bfh(push_script(bh2u(remote_htlcpubkey)))\
       -        + bytes([opcodes.OP_SWAP, opcodes.OP_SIZE]) + bitcoin.add_number_to_script(32) + bytes([opcodes.OP_EQUAL, opcodes.OP_NOTIF, opcodes.OP_DROP])\
       -        + bitcoin.add_number_to_script(2) + bytes([opcodes.OP_SWAP]) + bfh(push_script(bh2u(local_htlcpubkey))) + bitcoin.add_number_to_script(2)\
       -        + bytes([opcodes.OP_CHECKMULTISIG, opcodes.OP_ELSE, opcodes.OP_HASH160])\
       -        + bfh(push_script(bh2u(crypto.ripemd(payment_hash)))) + bytes([opcodes.OP_EQUALVERIFY, opcodes.OP_CHECKSIG, opcodes.OP_ENDIF, opcodes.OP_ENDIF])
       -
       -def make_received_htlc(revocation_pubkey, remote_htlcpubkey, local_htlcpubkey, payment_hash, cltv_expiry):
       -    for i in [revocation_pubkey, remote_htlcpubkey, local_htlcpubkey, payment_hash]:
       -        assert type(i) is bytes
       -    assert type(cltv_expiry) is int
       -
       -    return bytes([opcodes.OP_DUP, opcodes.OP_HASH160]) \
       -        + bfh(push_script(bh2u(bitcoin.hash_160(revocation_pubkey)))) \
       -        + bytes([opcodes.OP_EQUAL, opcodes.OP_IF, opcodes.OP_CHECKSIG, opcodes.OP_ELSE]) \
       -        + bfh(push_script(bh2u(remote_htlcpubkey))) \
       -        + bytes([opcodes.OP_SWAP, opcodes.OP_SIZE]) \
       -        + bitcoin.add_number_to_script(32) \
       -        + bytes([opcodes.OP_EQUAL, opcodes.OP_IF, opcodes.OP_HASH160]) \
       -        + bfh(push_script(bh2u(crypto.ripemd(payment_hash)))) \
       -        + bytes([opcodes.OP_EQUALVERIFY]) \
       -        + bitcoin.add_number_to_script(2) \
       -        + bytes([opcodes.OP_SWAP]) \
       -        + bfh(push_script(bh2u(local_htlcpubkey))) \
       -        + bitcoin.add_number_to_script(2) \
       -        + bytes([opcodes.OP_CHECKMULTISIG, opcodes.OP_ELSE, opcodes.OP_DROP]) \
       -        + bitcoin.add_number_to_script(cltv_expiry) \
       -        + bytes([opcodes.OP_CLTV, opcodes.OP_DROP, opcodes.OP_CHECKSIG, opcodes.OP_ENDIF, opcodes.OP_ENDIF])
       -
       -def make_htlc_tx_with_open_channel(chan, pcp, for_us, we_receive, amount_msat, cltv_expiry, payment_hash, commit, original_htlc_output_index):
       -    conf = chan.local_config if for_us else chan.remote_config
       -    other_conf = chan.local_config if not for_us else chan.remote_config
       -
       -    revocation_pubkey = derive_blinded_pubkey(other_conf.revocation_basepoint.pubkey, pcp)
       -    delayedpubkey = derive_pubkey(conf.delayed_basepoint.pubkey, pcp)
       -    other_revocation_pubkey = derive_blinded_pubkey(other_conf.revocation_basepoint.pubkey, pcp)
       -    other_htlc_pubkey = derive_pubkey(other_conf.htlc_basepoint.pubkey, pcp)
       -    htlc_pubkey = derive_pubkey(conf.htlc_basepoint.pubkey, pcp)
       -    # HTLC-success for the HTLC spending from a received HTLC output
       -    # if we do not receive, and the commitment tx is not for us, they receive, so it is also an HTLC-success
       -    is_htlc_success = for_us == we_receive
       -    htlc_tx_output = make_htlc_tx_output(
       -        amount_msat = amount_msat,
       -        local_feerate = chan.constraints.feerate,
       -        revocationpubkey=revocation_pubkey,
       -        local_delayedpubkey=delayedpubkey,
       -        success = is_htlc_success,
       -        to_self_delay = other_conf.to_self_delay)
       -    if is_htlc_success:
       -        preimage_script = make_received_htlc(other_revocation_pubkey, other_htlc_pubkey, htlc_pubkey, payment_hash, cltv_expiry)
       -    else:
       -        preimage_script = make_offered_htlc(other_revocation_pubkey, other_htlc_pubkey, htlc_pubkey, payment_hash)
       -    htlc_tx_inputs = make_htlc_tx_inputs(
       -        commit.txid(), commit.htlc_output_indices[original_htlc_output_index],
       -        revocationpubkey=revocation_pubkey,
       -        local_delayedpubkey=delayedpubkey,
       -        amount_msat=amount_msat,
       -        witness_script=bh2u(preimage_script))
       -    if is_htlc_success:
       -        cltv_expiry = 0
       -    htlc_tx = make_htlc_tx(cltv_expiry, inputs=htlc_tx_inputs, output=htlc_tx_output)
       -    return htlc_tx
       -
       -def make_commitment_using_open_channel(chan, ctn, for_us, pcp, local_msat, remote_msat, htlcs=[], trimmed=0):
       -    conf = chan.local_config if for_us else chan.remote_config
       -    other_conf = chan.local_config if not for_us else chan.remote_config
       -    payment_pubkey = derive_pubkey(other_conf.payment_basepoint.pubkey, pcp)
       -    remote_revocation_pubkey = derive_blinded_pubkey(other_conf.revocation_basepoint.pubkey, pcp)
       -    return make_commitment(
       -        ctn,
       -        conf.multisig_key.pubkey,
       -        other_conf.multisig_key.pubkey,
       -        payment_pubkey,
       -        chan.local_config.payment_basepoint.pubkey,
       -        chan.remote_config.payment_basepoint.pubkey,
       -        remote_revocation_pubkey,
       -        derive_pubkey(conf.delayed_basepoint.pubkey, pcp),
       -        other_conf.to_self_delay,
       -        *chan.funding_outpoint,
       -        chan.constraints.capacity,
       -        local_msat,
       -        remote_msat,
       -        chan.local_config.dust_limit_sat,
       -        chan.constraints.feerate,
       -        for_us,
       -        chan.constraints.is_initiator,
       -        htlcs=htlcs,
       -        trimmed=trimmed)
       -
       -def make_commitment(ctn, local_funding_pubkey, remote_funding_pubkey,
       -                    remote_payment_pubkey, payment_basepoint,
       -                    remote_payment_basepoint, revocation_pubkey,
       -                    delayed_pubkey, to_self_delay, funding_txid,
       -                    funding_pos, funding_sat, local_amount, remote_amount,
       -                    dust_limit_sat, local_feerate, for_us, we_are_initiator,
       -                    htlcs, trimmed=0):
       -
       -    pubkeys = sorted([bh2u(local_funding_pubkey), bh2u(remote_funding_pubkey)])
       -    payments = [payment_basepoint, remote_payment_basepoint]
       -    if not we_are_initiator:
       -        payments.reverse()
       -    obs = get_obscured_ctn(ctn, *payments)
       -    locktime = (0x20 << 24) + (obs & 0xffffff)
       -    sequence = (0x80 << 24) + (obs >> 24)
       -    print_error('locktime', locktime, hex(locktime))
       -    # commitment tx input
       -    c_inputs = [{
       -        'type': 'p2wsh',
       -        'x_pubkeys': pubkeys,
       -        'signatures': [None, None],
       -        'num_sig': 2,
       -        'prevout_n': funding_pos,
       -        'prevout_hash': funding_txid,
       -        'value': funding_sat,
       -        'coinbase': False,
       -        'sequence': sequence
       -    }]
       -    # commitment tx outputs
       -    local_script = bytes([opcodes.OP_IF]) + bfh(push_script(bh2u(revocation_pubkey))) + bytes([opcodes.OP_ELSE]) + add_number_to_script(to_self_delay) \
       -                   + bytes([opcodes.OP_CSV, opcodes.OP_DROP]) + bfh(push_script(bh2u(delayed_pubkey))) + bytes([opcodes.OP_ENDIF, opcodes.OP_CHECKSIG])
       -    local_address = bitcoin.redeem_script_to_address('p2wsh', bh2u(local_script))
       -    remote_address = bitcoin.pubkey_to_address('p2wpkh', bh2u(remote_payment_pubkey))
       -    # TODO trim htlc outputs here while also considering 2nd stage htlc transactions
       -    fee = local_feerate * overall_weight(len(htlcs))
       -    fee -= trimmed * 1000
       -    assert type(fee) is int
       -    we_pay_fee = for_us == we_are_initiator
       -    to_local_amt = local_amount - (fee if we_pay_fee else 0)
       -    assert type(to_local_amt) is int
       -    to_local = (bitcoin.TYPE_ADDRESS, local_address, to_local_amt // 1000)
       -    to_remote_amt = remote_amount - (fee if not we_pay_fee else 0)
       -    assert type(to_remote_amt) is int
       -    to_remote = (bitcoin.TYPE_ADDRESS, remote_address, to_remote_amt // 1000)
       -    c_outputs = [to_local, to_remote]
       -    for script, msat_amount in htlcs:
       -        c_outputs += [(bitcoin.TYPE_ADDRESS, bitcoin.redeem_script_to_address('p2wsh', bh2u(script)), msat_amount // 1000)]
       -
       -    # trim outputs
       -    c_outputs_filtered = list(filter(lambda x:x[2]>= dust_limit_sat, c_outputs))
       -    assert sum(x[2] for x in c_outputs) <= funding_sat
       -
       -    # create commitment tx
       -    tx = Transaction.from_io(c_inputs, c_outputs_filtered, locktime=locktime, version=2)
       -    tx.BIP_LI01_sort()
       -
       -    tx.htlc_output_indices = {}
       -    for idx, output in enumerate(c_outputs):
       -        if output in tx.outputs():
       -            # minus the first two outputs (to_local, to_remote)
       -            tx.htlc_output_indices[idx - 2] = tx.outputs().index(output)
       -
       -    return tx
       -
       -
       -def calc_short_channel_id(block_height: int, tx_pos_in_block: int, output_index: int) -> bytes:
       -    bh = block_height.to_bytes(3, byteorder='big')
       -    tpos = tx_pos_in_block.to_bytes(3, byteorder='big')
       -    oi = output_index.to_bytes(2, byteorder='big')
       -    return bh + tpos + oi
       -
       -
       -def sign_and_get_sig_string(tx, local_config, remote_config):
       -    pubkeys = sorted([bh2u(local_config.multisig_key.pubkey), bh2u(remote_config.multisig_key.pubkey)])
       -    tx.sign({bh2u(local_config.multisig_key.pubkey): (local_config.multisig_key.privkey, True)})
       -    sig_index = pubkeys.index(bh2u(local_config.multisig_key.pubkey))
       -    sig = bytes.fromhex(tx.inputs()[0]["signatures"][sig_index])
       -    r, s = sigdecode_der(sig[:-1], SECP256k1.generator.order())
       -    sig_64 = sigencode_string_canonize(r, s, SECP256k1.generator.order())
       -    return sig_64
       -
       -def is_synced(network):
       -    local_height, server_height = network.get_status_value("updated")
       -    synced = server_height != 0 and network.is_up_to_date() and local_height >= server_height
       -    return synced
       -
       -def funding_output_script(local_config, remote_config):
       -    pubkeys = sorted([bh2u(local_config.multisig_key.pubkey), bh2u(remote_config.multisig_key.pubkey)])
       -    return transaction.multisig_script(pubkeys, 2)
       -
        class Peer(PrintError):
        
            def __init__(self, lnworker, host, port, pubkey, request_initial_sync=False):
       t@@ -864,7 +531,7 @@ class Peer(PrintError):
                msg = gen_msg(
                    "open_channel",
                    temporary_channel_id=temp_channel_id,
       -            chain_hash=bytes.fromhex(rev_hex(constants.net.GENESIS)),
       +            chain_hash=REV_GENESIS,
                    funding_satoshis=funding_sat,
                    push_msat=push_msat,
                    dust_limit_satoshis=local_config.dust_limit_sat,
       t@@ -1065,7 +732,7 @@ class Peer(PrintError):
                    bitcoin_signature_2=bitcoin_sigs[1],
                    len=0,
                    #features not set (defaults to zeros)
       -            chain_hash=bytes.fromhex(rev_hex(constants.net.GENESIS)),
       +            chain_hash=REV_GENESIS,
                    short_channel_id=chan.short_channel_id,
                    node_id_1=node_ids[0],
                    node_id_2=node_ids[1],
       t@@ -1107,7 +774,7 @@ class Peer(PrintError):
                chan_ann = gen_msg("channel_announcement",
                    len=0,
                    #features not set (defaults to zeros)
       -            chain_hash=bytes.fromhex(rev_hex(constants.net.GENESIS)),
       +            chain_hash=REV_GENESIS,
                    short_channel_id=chan.short_channel_id,
                    node_id_1=node_ids[0],
                    node_id_2=node_ids[1],
       t@@ -1217,7 +884,7 @@ class Peer(PrintError):
                    self.revoke(chan)
                # TODO process above commitment transactions
        
       -        bare_ctx = make_commitment_using_open_channel(chan, chan.remote_state.ctn + 1, False, chan.remote_state.next_per_commitment_point,
       +        bare_ctx = chan.make_commitment(chan.remote_state.ctn + 1, False, chan.remote_state.next_per_commitment_point,
                    msat_remote, msat_local)
        
                sig_64 = sign_and_get_sig_string(bare_ctx, chan.local_config, chan.remote_config)
       t@@ -1249,7 +916,7 @@ class Peer(PrintError):
            async def receive_commitment_revoke_ack(self, htlc, decoded, payment_preimage):
                chan = self.channels[htlc['channel_id']]
                channel_id = chan.channel_id
       -        expected_received_msat = int(decoded.amount * COIN * 1000)
       +        expected_received_msat = int(decoded.amount * bitcoin.COIN * 1000)
                htlc_id = int.from_bytes(htlc["id"], 'big')
                assert htlc_id == chan.remote_state.next_htlc_id, (htlc_id, chan.remote_state.next_htlc_id)
        
       t@@ -1279,7 +946,7 @@ class Peer(PrintError):
                self.send_message(gen_msg("update_fulfill_htlc", channel_id=channel_id, id=htlc_id, payment_preimage=payment_preimage))
        
                # remote commitment transaction without htlcs
       -        bare_ctx = make_commitment_using_open_channel(m, m.remote_state.ctn + 1, False, m.remote_state.next_per_commitment_point,
       +        bare_ctx = chan.make_commitment(m.remote_state.ctn + 1, False, m.remote_state.next_per_commitment_point,
                    m.remote_state.amount_msat - expected_received_msat, m.local_state.amount_msat + expected_received_msat)
                sig_64 = sign_and_get_sig_string(bare_ctx, m.local_config, m.remote_config)
                self.send_message(gen_msg("commitment_signed", channel_id=channel_id, signature=sig_64, num_htlcs=0))
       t@@ -1333,13 +1000,4 @@ class Peer(PrintError):
                self.channels[channel_id].update_fee(int.from_bytes(payload["feerate_per_kw"], "big"))
        
        
       -def count_trailing_zeros(index):
       -    """ BOLT-03 (where_to_put_secret) """
       -    try:
       -        return list(reversed(bin(index)[2:])).index("1")
       -    except ValueError:
       -        return 48
       -
       -ShachainElement = namedtuple("ShachainElement", ["secret", "index"])
       -ShachainElement.__str__ = lambda self: "ShachainElement(" + bh2u(self.secret) + "," + str(self.index) + ")"
        
 (DIR) diff --git a/lib/lnhtlc.py b/lib/lnhtlc.py
       t@@ -1,17 +1,17 @@
        # ported from lnd 42de4400bff5105352d0552155f73589166d162b
       +from collections import namedtuple
        import binascii
        import json
       -from ecdsa.util import sigencode_string_canonize, sigdecode_der
        from .util import bfh, PrintError
        from .bitcoin import Hash
       -from collections import namedtuple
       -from ecdsa.curves import SECP256k1
        from .crypto import sha256
        from . import ecc
       -from . import lnbase
       -from .lnbase import Outpoint, ChannelConfig, LocalState, RemoteState, Keypair, OnlyPubkeyKeypair, ChannelConstraints, RevocationStore
       -HTLC_TIMEOUT_WEIGHT = lnbase.HTLC_TIMEOUT_WEIGHT
       -HTLC_SUCCESS_WEIGHT = lnbase.HTLC_SUCCESS_WEIGHT
       +from .lnutil import Outpoint, ChannelConfig, LocalState, RemoteState, Keypair, OnlyPubkeyKeypair, ChannelConstraints, RevocationStore
       +from .lnutil import get_per_commitment_secret_from_seed
       +from .lnutil import secret_to_pubkey, derive_privkey, derive_pubkey, derive_blinded_pubkey
       +from .lnutil import sign_and_get_sig_string
       +from .lnutil import make_htlc_tx_with_open_channel, make_commitment, make_received_htlc, make_offered_htlc
       +from .lnutil import HTLC_TIMEOUT_WEIGHT, HTLC_SUCCESS_WEIGHT
        
        SettleHtlc = namedtuple("SettleHtlc", ["htlc_id"])
        RevokeAndAck = namedtuple("RevokeAndAck", ["per_commitment_secret", "next_per_commitment_point"])
       t@@ -149,7 +149,6 @@ class HTLCStateMachine(PrintError):
                any). The HTLC signatures are sorted according to the BIP 69 order of the
                HTLC's on the commitment transaction.
                """
       -        from .lnbase import sign_and_get_sig_string, derive_privkey, make_htlc_tx_with_open_channel
                for htlc in self.local_update_log:
                    if not type(htlc) is UpdateAddHtlc: continue
                    if htlc.l_locked_in is None: htlc.l_locked_in = self.local_state.ctn
       t@@ -168,15 +167,14 @@ class HTLCStateMachine(PrintError):
                for we_receive, htlcs in zip([True, False], [self.htlcs_in_remote, self.htlcs_in_local]):
                    assert len(htlcs) <= 1
                    for htlc in htlcs:
       -                weight = lnbase.HTLC_SUCCESS_WEIGHT if we_receive else lnbase.HTLC_TIMEOUT_WEIGHT
       +                weight = HTLC_SUCCESS_WEIGHT if we_receive else HTLC_TIMEOUT_WEIGHT
                        if htlc.amount_msat // 1000 - weight * (self.constraints.feerate // 1000) < self.remote_config.dust_limit_sat:
                            continue
                        original_htlc_output_index = 0
                        args = [self.remote_state.next_per_commitment_point, for_us, we_receive, htlc.amount_msat + htlc.total_fee, htlc.cltv_expiry, htlc.payment_hash, self.remote_commitment, original_htlc_output_index]
                        htlc_tx = make_htlc_tx_with_open_channel(self, *args)
                        sig = bfh(htlc_tx.sign_txin(0, their_remote_htlc_privkey))
       -                r, s = sigdecode_der(sig[:-1], SECP256k1.generator.order())
       -                htlc_sig = sigencode_string_canonize(r, s, SECP256k1.generator.order())
       +                htlc_sig = ecc.sig_string_from_der_sig(sig[:-1])
                        htlcsigs.append(htlc_sig)
        
                return sig_64, htlcsigs
       t@@ -192,7 +190,6 @@ class HTLCStateMachine(PrintError):
                state, then this newly added commitment becomes our current accepted channel
                state.
                """
       -        from .lnbase import make_htlc_tx_with_open_channel , derive_pubkey
        
                self.print_error("receive_new_commitment")
                for htlc in self.remote_update_log:
       t@@ -252,7 +249,6 @@ class HTLCStateMachine(PrintError):
        
            @property
            def points(self):
       -        from .lnbase import get_per_commitment_secret_from_seed, secret_to_pubkey
                last_small_num = self.local_state.ctn
                next_small_num = last_small_num + 2
                this_small_num = last_small_num + 1
       t@@ -356,7 +352,6 @@ class HTLCStateMachine(PrintError):
        
            @property
            def remote_commitment(self):
       -        from .lnbase import make_commitment_using_open_channel, make_received_htlc, make_offered_htlc, derive_pubkey, derive_blinded_pubkey
                remote_msat, total_fee_remote, local_msat, total_fee_local = self.amounts()
                assert local_msat >= 0
                assert remote_msat >= 0
       t@@ -371,7 +366,7 @@ class HTLCStateMachine(PrintError):
        
                htlcs_in_local = []
                for htlc in self.htlcs_in_local:
       -            if htlc.amount_msat // 1000 - lnbase.HTLC_SUCCESS_WEIGHT * (self.constraints.feerate // 1000) < self.remote_config.dust_limit_sat:
       +            if htlc.amount_msat // 1000 - HTLC_SUCCESS_WEIGHT * (self.constraints.feerate // 1000) < self.remote_config.dust_limit_sat:
                        trimmed += htlc.amount_msat // 1000
                        continue
                    htlcs_in_local.append(
       t@@ -379,20 +374,19 @@ class HTLCStateMachine(PrintError):
        
                htlcs_in_remote = []
                for htlc in self.htlcs_in_remote:
       -            if htlc.amount_msat // 1000 - lnbase.HTLC_TIMEOUT_WEIGHT * (self.constraints.feerate // 1000) < self.remote_config.dust_limit_sat:
       +            if htlc.amount_msat // 1000 - HTLC_TIMEOUT_WEIGHT * (self.constraints.feerate // 1000) < self.remote_config.dust_limit_sat:
                        trimmed += htlc.amount_msat // 1000
                        continue
                    htlcs_in_remote.append(
                        ( make_offered_htlc(local_revocation_pubkey, local_htlc_pubkey, remote_htlc_pubkey, htlc.payment_hash), htlc.amount_msat + htlc.total_fee))
        
       -        commit = make_commitment_using_open_channel(self, self.remote_state.ctn + 1,
       +        commit = self.make_commitment(self.remote_state.ctn + 1,
                    False, this_point,
                    remote_msat - total_fee_remote, local_msat - total_fee_local, htlcs_in_local + htlcs_in_remote, trimmed)
                return commit
        
            @property
            def local_commitment(self):
       -        from .lnbase import make_commitment_using_open_channel, make_received_htlc, make_offered_htlc, derive_pubkey, derive_blinded_pubkey, get_per_commitment_secret_from_seed, secret_to_pubkey
                remote_msat, total_fee_remote, local_msat, total_fee_local = self.amounts()
                assert local_msat >= 0
                assert remote_msat >= 0
       t@@ -407,7 +401,7 @@ class HTLCStateMachine(PrintError):
        
                htlcs_in_local = []
                for htlc in self.htlcs_in_local:
       -            if htlc.amount_msat // 1000 - lnbase.HTLC_TIMEOUT_WEIGHT * (self.constraints.feerate // 1000) < self.local_config.dust_limit_sat:
       +            if htlc.amount_msat // 1000 - HTLC_TIMEOUT_WEIGHT * (self.constraints.feerate // 1000) < self.local_config.dust_limit_sat:
                        trimmed += htlc.amount_msat // 1000
                        continue
                    htlcs_in_local.append(
       t@@ -415,13 +409,13 @@ class HTLCStateMachine(PrintError):
        
                htlcs_in_remote = []
                for htlc in self.htlcs_in_remote:
       -            if htlc.amount_msat // 1000 - lnbase.HTLC_SUCCESS_WEIGHT * (self.constraints.feerate // 1000) < self.local_config.dust_limit_sat:
       +            if htlc.amount_msat // 1000 - HTLC_SUCCESS_WEIGHT * (self.constraints.feerate // 1000) < self.local_config.dust_limit_sat:
                        trimmed += htlc.amount_msat // 1000
                        continue
                    htlcs_in_remote.append(
                        ( make_received_htlc(remote_revocation_pubkey, remote_htlc_pubkey, local_htlc_pubkey, htlc.payment_hash, htlc.cltv_expiry), htlc.amount_msat + htlc.total_fee))
        
       -        commit = make_commitment_using_open_channel(self, self.local_state.ctn + 1,
       +        commit = self.make_commitment(self.local_state.ctn + 1,
                    True, this_point,
                    local_msat - total_fee_local, remote_msat - total_fee_remote, htlcs_in_local + htlcs_in_remote, trimmed)
                return commit
       t@@ -523,3 +517,29 @@ class HTLCStateMachine(PrintError):
        
            def __str__(self):
                return self.serialize()
       +
       +    def make_commitment(chan, ctn, for_us, pcp, local_msat, remote_msat, htlcs=[], trimmed=0):
       +        conf = chan.local_config if for_us else chan.remote_config
       +        other_conf = chan.local_config if not for_us else chan.remote_config
       +        payment_pubkey = derive_pubkey(other_conf.payment_basepoint.pubkey, pcp)
       +        remote_revocation_pubkey = derive_blinded_pubkey(other_conf.revocation_basepoint.pubkey, pcp)
       +        return make_commitment(
       +            ctn,
       +            conf.multisig_key.pubkey,
       +            other_conf.multisig_key.pubkey,
       +            payment_pubkey,
       +            chan.local_config.payment_basepoint.pubkey,
       +            chan.remote_config.payment_basepoint.pubkey,
       +            remote_revocation_pubkey,
       +            derive_pubkey(conf.delayed_basepoint.pubkey, pcp),
       +            other_conf.to_self_delay,
       +            *chan.funding_outpoint,
       +            chan.constraints.capacity,
       +            local_msat,
       +            remote_msat,
       +            chan.local_config.dust_limit_sat,
       +            chan.constraints.feerate,
       +            for_us,
       +            chan.constraints.is_initiator,
       +            htlcs=htlcs,
       +            trimmed=trimmed)
 (DIR) diff --git a/lib/lnrouter.py b/lib/lnrouter.py
       t@@ -40,8 +40,8 @@ from . import bitcoin
        from . import ecc
        from . import crypto
        from .crypto import sha256
       -from .util import PrintError, bh2u, print_error, bfh, profiler, xor_bytes
       -from . import lnbase
       +from .util import PrintError, bh2u, profiler, xor_bytes
       +from .lnutil import get_ecdh
        
        
        class ChannelInfo(PrintError):
       t@@ -368,7 +368,7 @@ def get_shared_secrets_along_route(payment_path_pubkeys: Sequence[bytes],
            ephemeral_key = session_key
            # compute shared key for each hop
            for i in range(0, num_hops):
       -        hop_shared_secrets[i] = lnbase.get_ecdh(ephemeral_key, payment_path_pubkeys[i])
       +        hop_shared_secrets[i] = get_ecdh(ephemeral_key, payment_path_pubkeys[i])
                ephemeral_pubkey = ecc.ECPrivkey(ephemeral_key).get_public_key_bytes()
                blinding_factor = sha256(ephemeral_pubkey + hop_shared_secrets[i])
                blinding_factor_int = int.from_bytes(blinding_factor, byteorder="big")
       t@@ -435,7 +435,7 @@ ProcessedOnionPacket = namedtuple("ProcessedOnionPacket", ["are_we_final", "hop_
        # TODO replay protection
        def process_onion_packet(onion_packet: OnionPacket, associated_data: bytes,
                                 our_onion_private_key: bytes) -> ProcessedOnionPacket:
       -    shared_secret = lnbase.get_ecdh(our_onion_private_key, onion_packet.public_key)
       +    shared_secret = get_ecdh(our_onion_private_key, onion_packet.public_key)
        
            # check message integrity
            mu_key = get_bolt04_onion_key(b'mu', shared_secret)
       t@@ -519,5 +519,7 @@ def get_failure_msg_from_onion_error(decrypted_error_packet: bytes) -> OnionRout
            return OnionRoutingFailureMessage(failure_code, failure_data)
        
        
       +
       +
        # <----- bolt 04, "onion"
        
 (DIR) diff --git a/lib/lnutil.py b/lib/lnutil.py
       t@@ -0,0 +1,315 @@
       +from .util import bfh, bh2u
       +from .crypto import sha256
       +import json
       +from collections import namedtuple
       +from .transaction import Transaction
       +from .ecc import CURVE_ORDER, generator, sig_string_from_der_sig, ECPubkey, string_to_number
       +from . import ecc, bitcoin, crypto, transaction
       +from .transaction import opcodes
       +from .bitcoin import push_script
       +
       +HTLC_TIMEOUT_WEIGHT = 663
       +HTLC_SUCCESS_WEIGHT = 703
       +
       +Keypair = namedtuple("Keypair", ["pubkey", "privkey"])
       +Outpoint = namedtuple("Outpoint", ["txid", "output_index"])
       +ChannelConfig = namedtuple("ChannelConfig", [
       +    "payment_basepoint", "multisig_key", "htlc_basepoint", "delayed_basepoint", "revocation_basepoint",
       +    "to_self_delay", "dust_limit_sat", "max_htlc_value_in_flight_msat", "max_accepted_htlcs"])
       +OnlyPubkeyKeypair = namedtuple("OnlyPubkeyKeypair", ["pubkey"])
       +RemoteState = namedtuple("RemoteState", ["ctn", "next_per_commitment_point", "amount_msat", "revocation_store", "current_per_commitment_point", "next_htlc_id"])
       +LocalState = namedtuple("LocalState", ["ctn", "per_commitment_secret_seed", "amount_msat", "next_htlc_id", "funding_locked_received", "was_announced", "current_commitment_signature"])
       +ChannelConstraints = namedtuple("ChannelConstraints", ["feerate", "capacity", "is_initiator", "funding_txn_minimum_depth"])
       +#OpenChannel = namedtuple("OpenChannel", ["channel_id", "short_channel_id", "funding_outpoint", "local_config", "remote_config", "remote_state", "local_state", "constraints", "node_id"])
       +
       +class RevocationStore:
       +    """ taken from lnd """
       +    def __init__(self):
       +        self.buckets = [None] * 48
       +        self.index = 2**48 - 1
       +    def add_next_entry(self, hsh):
       +        new_element = ShachainElement(index=self.index, secret=hsh)
       +        bucket = count_trailing_zeros(self.index)
       +        for i in range(0, bucket):
       +            this_bucket = self.buckets[i]
       +            e = shachain_derive(new_element, this_bucket.index)
       +
       +            if e != this_bucket:
       +                raise Exception("hash is not derivable: {} {} {}".format(bh2u(e.secret), bh2u(this_bucket.secret), this_bucket.index))
       +        self.buckets[bucket] = new_element
       +        self.index -= 1
       +    def serialize(self):
       +        return {"index": self.index, "buckets": [[bh2u(k.secret), k.index] if k is not None else None for k in self.buckets]}
       +    @staticmethod
       +    def from_json_obj(decoded_json_obj):
       +        store = RevocationStore()
       +        decode = lambda to_decode: ShachainElement(bfh(to_decode[0]), int(to_decode[1]))
       +        store.buckets = [k if k is None else decode(k) for k in decoded_json_obj["buckets"]]
       +        store.index = decoded_json_obj["index"]
       +        return store
       +    def __eq__(self, o):
       +        return type(o) is RevocationStore and self.serialize() == o.serialize()
       +    def __hash__(self):
       +        return hash(json.dumps(self.serialize(), sort_keys=True))
       +
       +def count_trailing_zeros(index):
       +    """ BOLT-03 (where_to_put_secret) """
       +    try:
       +        return list(reversed(bin(index)[2:])).index("1")
       +    except ValueError:
       +        return 48
       +
       +def shachain_derive(element, toIndex):
       +    return ShachainElement(get_per_commitment_secret_from_seed(element.secret, toIndex, count_trailing_zeros(element.index)), toIndex)
       +
       +ShachainElement = namedtuple("ShachainElement", ["secret", "index"])
       +ShachainElement.__str__ = lambda self: "ShachainElement(" + bh2u(self.secret) + "," + str(self.index) + ")"
       +
       +def get_per_commitment_secret_from_seed(seed: bytes, i: int, bits: int = 48) -> bytes:
       +    """Generate per commitment secret."""
       +    per_commitment_secret = bytearray(seed)
       +    for bitindex in range(bits - 1, -1, -1):
       +        mask = 1 << bitindex
       +        if i & mask:
       +            per_commitment_secret[bitindex // 8] ^= 1 << (bitindex % 8)
       +            per_commitment_secret = bytearray(sha256(per_commitment_secret))
       +    bajts = bytes(per_commitment_secret)
       +    return bajts
       +
       +def secret_to_pubkey(secret):
       +    assert type(secret) is int
       +    return (ecc.generator() * secret).get_public_key_bytes()
       +
       +def derive_pubkey(basepoint, per_commitment_point):
       +    p = ecc.ECPubkey(basepoint) + ecc.generator() * ecc.string_to_number(sha256(per_commitment_point + basepoint))
       +    return p.get_public_key_bytes()
       +
       +def derive_privkey(secret, per_commitment_point):
       +    assert type(secret) is int
       +    basepoint = (ecc.generator() * secret).get_public_key_bytes()
       +    basepoint = secret + ecc.string_to_number(sha256(per_commitment_point + basepoint))
       +    basepoint %= CURVE_ORDER
       +    return basepoint
       +
       +def derive_blinded_pubkey(basepoint, per_commitment_point):
       +    k1 = ecc.ECPubkey(basepoint) * ecc.string_to_number(sha256(basepoint + per_commitment_point))
       +    k2 = ecc.ECPubkey(per_commitment_point) * ecc.string_to_number(sha256(per_commitment_point + basepoint))
       +    return (k1 + k2).get_public_key_bytes()
       +
       +def make_htlc_tx_output(amount_msat, local_feerate, revocationpubkey, local_delayedpubkey, success, to_self_delay):
       +    assert type(amount_msat) is int
       +    assert type(local_feerate) is int
       +    assert type(revocationpubkey) is bytes
       +    assert type(local_delayedpubkey) is bytes
       +    script = bytes([opcodes.OP_IF]) \
       +        + bfh(push_script(bh2u(revocationpubkey))) \
       +        + bytes([opcodes.OP_ELSE]) \
       +        + bitcoin.add_number_to_script(to_self_delay) \
       +        + bytes([opcodes.OP_CSV, opcodes.OP_DROP]) \
       +        + bfh(push_script(bh2u(local_delayedpubkey))) \
       +        + bytes([opcodes.OP_ENDIF, opcodes.OP_CHECKSIG])
       +
       +    p2wsh = bitcoin.redeem_script_to_address('p2wsh', bh2u(script))
       +    weight = HTLC_SUCCESS_WEIGHT if success else HTLC_TIMEOUT_WEIGHT
       +    fee = local_feerate * weight
       +    final_amount_sat = (amount_msat - fee) // 1000
       +    assert final_amount_sat > 0, final_amount_sat
       +    output = (bitcoin.TYPE_ADDRESS, p2wsh, final_amount_sat)
       +    return output
       +
       +def make_htlc_tx_witness(remotehtlcsig, localhtlcsig, payment_preimage, witness_script):
       +    assert type(remotehtlcsig) is bytes
       +    assert type(localhtlcsig) is bytes
       +    assert type(payment_preimage) is bytes
       +    assert type(witness_script) is bytes
       +    return bfh(transaction.construct_witness([0, remotehtlcsig, localhtlcsig, payment_preimage, witness_script]))
       +
       +def make_htlc_tx_inputs(htlc_output_txid, htlc_output_index, revocationpubkey, local_delayedpubkey, amount_msat, witness_script):
       +    assert type(htlc_output_txid) is str
       +    assert type(htlc_output_index) is int
       +    assert type(revocationpubkey) is bytes
       +    assert type(local_delayedpubkey) is bytes
       +    assert type(amount_msat) is int
       +    assert type(witness_script) is str
       +    c_inputs = [{
       +        'scriptSig': '',
       +        'type': 'p2wsh',
       +        'signatures': [],
       +        'num_sig': 0,
       +        'prevout_n': htlc_output_index,
       +        'prevout_hash': htlc_output_txid,
       +        'value': amount_msat // 1000,
       +        'coinbase': False,
       +        'sequence': 0x0,
       +        'preimage_script': witness_script,
       +    }]
       +    return c_inputs
       +
       +def make_htlc_tx(cltv_timeout, inputs, output):
       +    assert type(cltv_timeout) is int
       +    c_outputs = [output]
       +    tx = Transaction.from_io(inputs, c_outputs, locktime=cltv_timeout, version=2)
       +    tx.BIP_LI01_sort()
       +    return tx
       +
       +def make_offered_htlc(revocation_pubkey, remote_htlcpubkey, local_htlcpubkey, payment_hash):
       +    assert type(revocation_pubkey) is bytes
       +    assert type(remote_htlcpubkey) is bytes
       +    assert type(local_htlcpubkey) is bytes
       +    assert type(payment_hash) is bytes
       +    return bytes([opcodes.OP_DUP, opcodes.OP_HASH160]) + bfh(push_script(bh2u(bitcoin.hash_160(revocation_pubkey))))\
       +        + bytes([opcodes.OP_EQUAL, opcodes.OP_IF, opcodes.OP_CHECKSIG, opcodes.OP_ELSE]) \
       +        + bfh(push_script(bh2u(remote_htlcpubkey)))\
       +        + bytes([opcodes.OP_SWAP, opcodes.OP_SIZE]) + bitcoin.add_number_to_script(32) + bytes([opcodes.OP_EQUAL, opcodes.OP_NOTIF, opcodes.OP_DROP])\
       +        + bitcoin.add_number_to_script(2) + bytes([opcodes.OP_SWAP]) + bfh(push_script(bh2u(local_htlcpubkey))) + bitcoin.add_number_to_script(2)\
       +        + bytes([opcodes.OP_CHECKMULTISIG, opcodes.OP_ELSE, opcodes.OP_HASH160])\
       +        + bfh(push_script(bh2u(crypto.ripemd(payment_hash)))) + bytes([opcodes.OP_EQUALVERIFY, opcodes.OP_CHECKSIG, opcodes.OP_ENDIF, opcodes.OP_ENDIF])
       +
       +def make_received_htlc(revocation_pubkey, remote_htlcpubkey, local_htlcpubkey, payment_hash, cltv_expiry):
       +    for i in [revocation_pubkey, remote_htlcpubkey, local_htlcpubkey, payment_hash]:
       +        assert type(i) is bytes
       +    assert type(cltv_expiry) is int
       +
       +    return bytes([opcodes.OP_DUP, opcodes.OP_HASH160]) \
       +        + bfh(push_script(bh2u(bitcoin.hash_160(revocation_pubkey)))) \
       +        + bytes([opcodes.OP_EQUAL, opcodes.OP_IF, opcodes.OP_CHECKSIG, opcodes.OP_ELSE]) \
       +        + bfh(push_script(bh2u(remote_htlcpubkey))) \
       +        + bytes([opcodes.OP_SWAP, opcodes.OP_SIZE]) \
       +        + bitcoin.add_number_to_script(32) \
       +        + bytes([opcodes.OP_EQUAL, opcodes.OP_IF, opcodes.OP_HASH160]) \
       +        + bfh(push_script(bh2u(crypto.ripemd(payment_hash)))) \
       +        + bytes([opcodes.OP_EQUALVERIFY]) \
       +        + bitcoin.add_number_to_script(2) \
       +        + bytes([opcodes.OP_SWAP]) \
       +        + bfh(push_script(bh2u(local_htlcpubkey))) \
       +        + bitcoin.add_number_to_script(2) \
       +        + bytes([opcodes.OP_CHECKMULTISIG, opcodes.OP_ELSE, opcodes.OP_DROP]) \
       +        + bitcoin.add_number_to_script(cltv_expiry) \
       +        + bytes([opcodes.OP_CLTV, opcodes.OP_DROP, opcodes.OP_CHECKSIG, opcodes.OP_ENDIF, opcodes.OP_ENDIF])
       +
       +def make_htlc_tx_with_open_channel(chan, pcp, for_us, we_receive, amount_msat, cltv_expiry, payment_hash, commit, original_htlc_output_index):
       +    conf = chan.local_config if for_us else chan.remote_config
       +    other_conf = chan.local_config if not for_us else chan.remote_config
       +
       +    revocation_pubkey = derive_blinded_pubkey(other_conf.revocation_basepoint.pubkey, pcp)
       +    delayedpubkey = derive_pubkey(conf.delayed_basepoint.pubkey, pcp)
       +    other_revocation_pubkey = derive_blinded_pubkey(other_conf.revocation_basepoint.pubkey, pcp)
       +    other_htlc_pubkey = derive_pubkey(other_conf.htlc_basepoint.pubkey, pcp)
       +    htlc_pubkey = derive_pubkey(conf.htlc_basepoint.pubkey, pcp)
       +    # HTLC-success for the HTLC spending from a received HTLC output
       +    # if we do not receive, and the commitment tx is not for us, they receive, so it is also an HTLC-success
       +    is_htlc_success = for_us == we_receive
       +    htlc_tx_output = make_htlc_tx_output(
       +        amount_msat = amount_msat,
       +        local_feerate = chan.constraints.feerate,
       +        revocationpubkey=revocation_pubkey,
       +        local_delayedpubkey=delayedpubkey,
       +        success = is_htlc_success,
       +        to_self_delay = other_conf.to_self_delay)
       +    if is_htlc_success:
       +        preimage_script = make_received_htlc(other_revocation_pubkey, other_htlc_pubkey, htlc_pubkey, payment_hash, cltv_expiry)
       +    else:
       +        preimage_script = make_offered_htlc(other_revocation_pubkey, other_htlc_pubkey, htlc_pubkey, payment_hash)
       +    htlc_tx_inputs = make_htlc_tx_inputs(
       +        commit.txid(), commit.htlc_output_indices[original_htlc_output_index],
       +        revocationpubkey=revocation_pubkey,
       +        local_delayedpubkey=delayedpubkey,
       +        amount_msat=amount_msat,
       +        witness_script=bh2u(preimage_script))
       +    if is_htlc_success:
       +        cltv_expiry = 0
       +    htlc_tx = make_htlc_tx(cltv_expiry, inputs=htlc_tx_inputs, output=htlc_tx_output)
       +    return htlc_tx
       +
       +
       +def make_commitment(ctn, local_funding_pubkey, remote_funding_pubkey,
       +                    remote_payment_pubkey, payment_basepoint,
       +                    remote_payment_basepoint, revocation_pubkey,
       +                    delayed_pubkey, to_self_delay, funding_txid,
       +                    funding_pos, funding_sat, local_amount, remote_amount,
       +                    dust_limit_sat, local_feerate, for_us, we_are_initiator,
       +                    htlcs, trimmed=0):
       +
       +    pubkeys = sorted([bh2u(local_funding_pubkey), bh2u(remote_funding_pubkey)])
       +    payments = [payment_basepoint, remote_payment_basepoint]
       +    if not we_are_initiator:
       +        payments.reverse()
       +    obs = get_obscured_ctn(ctn, *payments)
       +    locktime = (0x20 << 24) + (obs & 0xffffff)
       +    sequence = (0x80 << 24) + (obs >> 24)
       +    # commitment tx input
       +    c_inputs = [{
       +        'type': 'p2wsh',
       +        'x_pubkeys': pubkeys,
       +        'signatures': [None, None],
       +        'num_sig': 2,
       +        'prevout_n': funding_pos,
       +        'prevout_hash': funding_txid,
       +        'value': funding_sat,
       +        'coinbase': False,
       +        'sequence': sequence
       +    }]
       +    # commitment tx outputs
       +    local_script = bytes([opcodes.OP_IF]) + bfh(push_script(bh2u(revocation_pubkey))) + bytes([opcodes.OP_ELSE]) + bitcoin.add_number_to_script(to_self_delay) \
       +                   + bytes([opcodes.OP_CSV, opcodes.OP_DROP]) + bfh(push_script(bh2u(delayed_pubkey))) + bytes([opcodes.OP_ENDIF, opcodes.OP_CHECKSIG])
       +    local_address = bitcoin.redeem_script_to_address('p2wsh', bh2u(local_script))
       +    remote_address = bitcoin.pubkey_to_address('p2wpkh', bh2u(remote_payment_pubkey))
       +    # TODO trim htlc outputs here while also considering 2nd stage htlc transactions
       +    fee = local_feerate * overall_weight(len(htlcs))
       +    fee -= trimmed * 1000
       +    assert type(fee) is int
       +    we_pay_fee = for_us == we_are_initiator
       +    to_local_amt = local_amount - (fee if we_pay_fee else 0)
       +    assert type(to_local_amt) is int
       +    to_local = (bitcoin.TYPE_ADDRESS, local_address, to_local_amt // 1000)
       +    to_remote_amt = remote_amount - (fee if not we_pay_fee else 0)
       +    assert type(to_remote_amt) is int
       +    to_remote = (bitcoin.TYPE_ADDRESS, remote_address, to_remote_amt // 1000)
       +    c_outputs = [to_local, to_remote]
       +    for script, msat_amount in htlcs:
       +        c_outputs += [(bitcoin.TYPE_ADDRESS, bitcoin.redeem_script_to_address('p2wsh', bh2u(script)), msat_amount // 1000)]
       +
       +    # trim outputs
       +    c_outputs_filtered = list(filter(lambda x:x[2]>= dust_limit_sat, c_outputs))
       +    assert sum(x[2] for x in c_outputs) <= funding_sat
       +
       +    # create commitment tx
       +    tx = Transaction.from_io(c_inputs, c_outputs_filtered, locktime=locktime, version=2)
       +    tx.BIP_LI01_sort()
       +
       +    tx.htlc_output_indices = {}
       +    for idx, output in enumerate(c_outputs):
       +        if output in tx.outputs():
       +            # minus the first two outputs (to_local, to_remote)
       +            tx.htlc_output_indices[idx - 2] = tx.outputs().index(output)
       +
       +    return tx
       +
       +def sign_and_get_sig_string(tx, local_config, remote_config):
       +    pubkeys = sorted([bh2u(local_config.multisig_key.pubkey), bh2u(remote_config.multisig_key.pubkey)])
       +    tx.sign({bh2u(local_config.multisig_key.pubkey): (local_config.multisig_key.privkey, True)})
       +    sig_index = pubkeys.index(bh2u(local_config.multisig_key.pubkey))
       +    sig = bytes.fromhex(tx.inputs()[0]["signatures"][sig_index])
       +    sig_64 = sig_string_from_der_sig(sig[:-1])
       +    return sig_64
       +
       +def funding_output_script(local_config, remote_config):
       +    pubkeys = sorted([bh2u(local_config.multisig_key.pubkey), bh2u(remote_config.multisig_key.pubkey)])
       +    return transaction.multisig_script(pubkeys, 2)
       +
       +def calc_short_channel_id(block_height: int, tx_pos_in_block: int, output_index: int) -> bytes:
       +    bh = block_height.to_bytes(3, byteorder='big')
       +    tpos = tx_pos_in_block.to_bytes(3, byteorder='big')
       +    oi = output_index.to_bytes(2, byteorder='big')
       +    return bh + tpos + oi
       +
       +def get_obscured_ctn(ctn, local, remote):
       +    mask = int.from_bytes(sha256(local + remote)[-6:], 'big')
       +    return ctn ^ mask
       +
       +def overall_weight(num_htlc):
       +    return 500 + 172 * num_htlc + 224
       +
       +def get_ecdh(priv: bytes, pub: bytes) -> bytes:
       +    pt = ECPubkey(pub) * string_to_number(priv)
       +    return sha256(pt.get_public_key_bytes())
 (DIR) diff --git a/lib/lnwatcher.py b/lib/lnwatcher.py
       t@@ -1,5 +1,5 @@
        from .util import PrintError
       -from .lnbase import funding_output_script
       +from .lnutil import funding_output_script
        from .bitcoin import redeem_script_to_address
        
        class LNWatcher(PrintError):
 (DIR) diff --git a/lib/lnworker.py b/lib/lnworker.py
       t@@ -10,12 +10,12 @@ from . import constants
        from .bitcoin import sha256, COIN
        from .util import bh2u, bfh, PrintError
        from .constants import set_testnet, set_simnet
       -from .lnbase import Peer, calc_short_channel_id, privkey_to_pubkey
       +from .lnbase import Peer, privkey_to_pubkey
        from .lightning_payencode.lnaddr import lnencode, LnAddr, lndecode
       -from .ecc import ECPrivkey, CURVE_ORDER, der_sig_from_sig_string
       +from .ecc import der_sig_from_sig_string
        from .transaction import Transaction
        from .lnhtlc import HTLCStateMachine
       -from .lnbase import Outpoint
       +from .lnutil import Outpoint, calc_short_channel_id
        
        # hardcoded nodes
        node_list = [
       t@@ -33,7 +33,7 @@ class LNWorker(PrintError):
                    wallet.storage.put('lightning_privkey', pk)
                    wallet.storage.write()
                self.privkey = bfh(pk)
       -        self.pubkey = ECPrivkey(self.privkey).get_public_key_bytes()
       +        self.pubkey = privkey_to_pubkey(self.privkey)
                self.config = network.config
                self.peers = {}
                self.channels = {x.channel_id: x for x in map(HTLCStateMachine, wallet.storage.get("channels", []))}
       t@@ -157,8 +157,6 @@ class LNWorker(PrintError):
                RHASH = sha256(payment_preimage)
                amount_btc = amount_sat/Decimal(COIN) if amount_sat else None
                pay_req = lnencode(LnAddr(RHASH, amount_btc, tags=[('d', message)]), self.privkey)
       -        decoded = lndecode(pay_req, expected_hrp=constants.net.SEGWIT_HRP)
       -        assert decoded.pubkey.serialize() == privkey_to_pubkey(self.privkey)
                self.invoices[bh2u(payment_preimage)] = pay_req
                self.wallet.storage.put('lightning_invoices', self.invoices)
                self.wallet.storage.write()
 (DIR) diff --git a/lib/tests/test_lnbase.py b/lib/tests/test_lnbase.py
       t@@ -1,819 +0,0 @@
       -import binascii
       -import json
       -import unittest
       -
       -from lib.util import bh2u, bfh
       -from lib.lnbase import make_commitment, get_obscured_ctn, Peer, make_offered_htlc, make_received_htlc, make_htlc_tx
       -from lib.lnbase import secret_to_pubkey, derive_pubkey, derive_privkey, derive_blinded_pubkey, overall_weight
       -from lib.lnbase import make_htlc_tx_output, make_htlc_tx_inputs, get_per_commitment_secret_from_seed, make_htlc_tx_witness
       -from lib.lnrouter import OnionHopsDataSingle, new_onion_packet, OnionPerHop
       -from lib.lnbase import RevocationStore
       -from lib.transaction import Transaction
       -from lib import bitcoin
       -import ecdsa.ellipticcurve
       -from ecdsa.curves import SECP256k1
       -from lib.util import bfh
       -from lib import bitcoin, lnbase, lnrouter
       -
       -funding_tx_id = '8984484a580b825b9972d7adb15050b3ab624ccd731946b3eeddb92f4e7ef6be'
       -funding_output_index = 0
       -funding_amount_satoshi = 10000000
       -commitment_number = 42
       -local_delay = 144
       -local_dust_limit_satoshi = 546
       -
       -local_payment_basepoint = bytes.fromhex('034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa')
       -remote_payment_basepoint = bytes.fromhex('032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991')
       -obs = get_obscured_ctn(42, local_payment_basepoint, remote_payment_basepoint)
       -local_funding_privkey = bytes.fromhex('30ff4956bbdd3222d44cc5e8a1261dab1e07957bdac5ae88fe3261ef321f374901')
       -local_funding_pubkey = bytes.fromhex('023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb')
       -remote_funding_pubkey = bytes.fromhex('030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c1')
       -local_privkey = bytes.fromhex('bb13b121cdc357cd2e608b0aea294afca36e2b34cf958e2e6451a2f27469449101')
       -localpubkey = bytes.fromhex('030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e7')
       -remotepubkey = bytes.fromhex('0394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b')
       -local_delayedpubkey = bytes.fromhex('03fd5960528dc152014952efdb702a88f71e3c1653b2314431701ec77e57fde83c')
       -local_revocation_pubkey = bytes.fromhex('0212a140cd0c6539d07cd08dfe09984dec3251ea808b892efeac3ede9402bf2b19')
       -# funding wscript = 5221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae
       -
       -class Test_LNBase(unittest.TestCase):
       -
       -    @staticmethod
       -    def parse_witness_list(witness_bytes):
       -        amount_witnesses = witness_bytes[0]
       -        witness_bytes = witness_bytes[1:]
       -        res = []
       -        for i in range(amount_witnesses):
       -            witness_length = witness_bytes[0]
       -            this_witness = witness_bytes[1:witness_length+1]
       -            assert len(this_witness) == witness_length
       -            witness_bytes = witness_bytes[witness_length+1:]
       -            res += [bytes(this_witness)]
       -        assert witness_bytes == b"", witness_bytes
       -        return res
       -
       -    def test_simple_commitment_tx_with_no_HTLCs(self):
       -        to_local_msat = 7000000000
       -        to_remote_msat = 3000000000
       -        local_feerate_per_kw = 15000
       -        # base commitment transaction fee = 10860
       -        # actual commitment transaction fee = 10860
       -        # to_local amount 6989140 wscript 63210212a140cd0c6539d07cd08dfe09984dec3251ea808b892efeac3ede9402bf2b1967029000b2752103fd5960528dc152014952efdb702a88f71e3c1653b2314431701ec77e57fde83c68ac
       -        # to_remote amount 3000000 P2WPKH(0394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b)
       -        remote_signature = "3045022100f51d2e566a70ba740fc5d8c0f07b9b93d2ed741c3c0860c613173de7d39e7968022041376d520e9c0e1ad52248ddf4b22e12be8763007df977253ef45a4ca3bdb7c0"
       -        # local_signature = 3044022051b75c73198c6deee1a875871c3961832909acd297c6b908d59e3319e5185a46022055c419379c5051a78d00dbbce11b5b664a0c22815fbcc6fcef6b1937c3836939
       -        htlcs=[]
       -        our_commit_tx = make_commitment(
       -            commitment_number,
       -            local_funding_pubkey, remote_funding_pubkey, remotepubkey,
       -            local_payment_basepoint, remote_payment_basepoint,
       -            local_revocation_pubkey, local_delayedpubkey, local_delay,
       -            funding_tx_id, funding_output_index, funding_amount_satoshi,
       -            to_local_msat, to_remote_msat, local_dust_limit_satoshi,
       -            local_feerate_per_kw, True, we_are_initiator=True, htlcs=[])
       -        self.sign_and_insert_remote_sig(our_commit_tx, remote_funding_pubkey, remote_signature, local_funding_pubkey, local_funding_privkey)
       -        ref_commit_tx_str = '02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8002c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de84311054a56a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400473044022051b75c73198c6deee1a875871c3961832909acd297c6b908d59e3319e5185a46022055c419379c5051a78d00dbbce11b5b664a0c22815fbcc6fcef6b1937c383693901483045022100f51d2e566a70ba740fc5d8c0f07b9b93d2ed741c3c0860c613173de7d39e7968022041376d520e9c0e1ad52248ddf4b22e12be8763007df977253ef45a4ca3bdb7c001475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220'
       -        self.assertEqual(str(our_commit_tx), ref_commit_tx_str)
       -
       -    def sign_and_insert_remote_sig(self, tx, remote_pubkey, remote_signature, pubkey, privkey):
       -        assert type(remote_pubkey) is bytes
       -        assert len(remote_pubkey) == 33
       -        assert type(remote_signature) is str
       -        assert type(pubkey) is bytes
       -        assert type(privkey) is bytes
       -        assert len(pubkey) == 33
       -        assert len(privkey) == 33
       -        tx.sign({bh2u(pubkey): (privkey[:-1], True)})
       -        pubkeys, _x_pubkeys = tx.get_sorted_pubkeys(tx.inputs()[0])
       -        index_of_pubkey = pubkeys.index(bh2u(remote_pubkey))
       -        tx._inputs[0]["signatures"][index_of_pubkey] = remote_signature + "01"
       -        tx.raw = None
       -
       -    def test_commitment_tx_with_all_five_HTLCs_untrimmed_minimum_feerate(self):
       -        to_local_msat = 6988000000
       -        to_remote_msat = 3000000000
       -        local_feerate_per_kw = 0
       -        # base commitment transaction fee = 0
       -        # actual commitment transaction fee = 0
       -
       -        per_commitment_secret = 0x1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100
       -        per_commitment_point = SECP256k1.generator * per_commitment_secret 
       -
       -        remote_htlcpubkey = remotepubkey
       -        local_htlcpubkey = localpubkey
       -
       -        htlc2_cltv_timeout = 502
       -        htlc2_payment_preimage = b"\x02" * 32
       -        htlc2 = make_offered_htlc(local_revocation_pubkey, remote_htlcpubkey, local_htlcpubkey, bitcoin.sha256(htlc2_payment_preimage))
       -        # HTLC 2 offered amount 2000
       -        ref_htlc2_wscript = "76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868"
       -        self.assertEqual(htlc2, bfh(ref_htlc2_wscript))
       -
       -        htlc3_cltv_timeout = 503
       -        htlc3_payment_preimage = b"\x03" * 32
       -        htlc3 = make_offered_htlc(local_revocation_pubkey, remote_htlcpubkey, local_htlcpubkey, bitcoin.sha256(htlc3_payment_preimage))
       -        # HTLC 3 offered amount 3000 
       -        ref_htlc3_wscript = "76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868"
       -        self.assertEqual(htlc3, bfh(ref_htlc3_wscript))
       -
       -        htlc0_cltv_timeout = 500
       -        htlc0_payment_preimage = b"\x00" * 32
       -        htlc0 = make_received_htlc(local_revocation_pubkey, remote_htlcpubkey, local_htlcpubkey, bitcoin.sha256(htlc0_payment_preimage), htlc0_cltv_timeout)
       -        # HTLC 0 received amount 1000
       -        ref_htlc0_wscript = "76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f401b175ac6868"
       -        self.assertEqual(htlc0, bfh(ref_htlc0_wscript))
       -
       -        htlc1_cltv_timeout = 501
       -        htlc1_payment_preimage = b"\x01" * 32
       -        htlc1 = make_received_htlc(local_revocation_pubkey, remote_htlcpubkey, local_htlcpubkey, bitcoin.sha256(htlc1_payment_preimage), htlc1_cltv_timeout)
       -        # HTLC 1 received amount 2000 
       -        ref_htlc1_wscript = "76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac6868"
       -        self.assertEqual(htlc1, bfh(ref_htlc1_wscript))
       -
       -        htlc4_cltv_timeout = 504
       -        htlc4_payment_preimage = b"\x04" * 32
       -        htlc4 = make_received_htlc(local_revocation_pubkey, remote_htlcpubkey, local_htlcpubkey, bitcoin.sha256(htlc4_payment_preimage), htlc4_cltv_timeout)
       -        # HTLC 4 received amount 4000 
       -        ref_htlc4_wscript = "76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6868"
       -        self.assertEqual(htlc4, bfh(ref_htlc4_wscript))
       -
       -        # to_local amount 6988000 wscript 63210212a140cd0c6539d07cd08dfe09984dec3251ea808b892efeac3ede9402bf2b1967029000b2752103fd5960528dc152014952efdb702a88f71e3c1653b2314431701ec77e57fde83c68ac
       -        # to_remote amount 3000000 P2WPKH(0394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b)
       -        remote_signature = "304402204fd4928835db1ccdfc40f5c78ce9bd65249b16348df81f0c44328dcdefc97d630220194d3869c38bc732dd87d13d2958015e2fc16829e74cd4377f84d215c0b70606"
       -        # local_signature = 30440220275b0c325a5e9355650dc30c0eccfbc7efb23987c24b556b9dfdd40effca18d202206caceb2c067836c51f296740c7ae807ffcbfbf1dd3a0d56b6de9a5b247985f06
       -        output_commit_tx = "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8007e80300000000000022002052bfef0479d7b293c27e0f1eb294bea154c63a3294ef092c19af51409bce0e2ad007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2db80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110e0a06a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e04004730440220275b0c325a5e9355650dc30c0eccfbc7efb23987c24b556b9dfdd40effca18d202206caceb2c067836c51f296740c7ae807ffcbfbf1dd3a0d56b6de9a5b247985f060147304402204fd4928835db1ccdfc40f5c78ce9bd65249b16348df81f0c44328dcdefc97d630220194d3869c38bc732dd87d13d2958015e2fc16829e74cd4377f84d215c0b7060601475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220"
       -
       -        htlc0_msat = 1000 * 1000
       -        htlc2_msat = 2000 * 1000
       -        htlc3_msat = 3000 * 1000
       -        htlc1_msat = 2000 * 1000
       -        htlc4_msat = 4000 * 1000
       -        htlcs = [(htlc2, htlc2_msat), (htlc3, htlc3_msat), (htlc0, htlc0_msat), (htlc1, htlc1_msat), (htlc4, htlc4_msat)]
       -
       -        our_commit_tx = make_commitment(
       -            commitment_number,
       -            local_funding_pubkey, remote_funding_pubkey, remotepubkey,
       -            local_payment_basepoint, remote_payment_basepoint,
       -            local_revocation_pubkey, local_delayedpubkey, local_delay,
       -            funding_tx_id, funding_output_index, funding_amount_satoshi,
       -            to_local_msat, to_remote_msat, local_dust_limit_satoshi,
       -            local_feerate_per_kw, True, we_are_initiator=True, htlcs=htlcs)
       -        self.sign_and_insert_remote_sig(our_commit_tx, remote_funding_pubkey, remote_signature, local_funding_pubkey, local_funding_privkey)
       -        self.assertEqual(str(our_commit_tx), output_commit_tx)
       -
       -        # (HTLC 0)
       -        signature_for_output_remote_htlc_0 = "304402206a6e59f18764a5bf8d4fa45eebc591566689441229c918b480fb2af8cc6a4aeb02205248f273be447684b33e3c8d1d85a8e0ca9fa0bae9ae33f0527ada9c162919a6"
       -        # (HTLC 2)
       -        signature_for_output_remote_htlc_2 = "3045022100d5275b3619953cb0c3b5aa577f04bc512380e60fa551762ce3d7a1bb7401cff9022037237ab0dac3fe100cde094e82e2bed9ba0ed1bb40154b48e56aa70f259e608b"
       -        # (HTLC 1)
       -        signature_for_output_remote_htlc_1 = "304402201b63ec807771baf4fdff523c644080de17f1da478989308ad13a58b51db91d360220568939d38c9ce295adba15665fa68f51d967e8ed14a007b751540a80b325f202"
       -        # (HTLC 3)
       -        signature_for_output_remote_htlc_3 = "3045022100daee1808f9861b6c3ecd14f7b707eca02dd6bdfc714ba2f33bc8cdba507bb182022026654bf8863af77d74f51f4e0b62d461a019561bb12acb120d3f7195d148a554"
       -        # (HTLC 4)
       -        signature_for_output_remote_htlc_4 = "304402207e0410e45454b0978a623f36a10626ef17b27d9ad44e2760f98cfa3efb37924f0220220bd8acd43ecaa916a80bd4f919c495a2c58982ce7c8625153f8596692a801d"
       -
       -
       -        local_signature_htlc0 = "304402207cb324fa0de88f452ffa9389678127ebcf4cabe1dd848b8e076c1a1962bf34720220116ed922b12311bd602d67e60d2529917f21c5b82f25ff6506c0f87886b4dfd5" # derive ourselves
       -        output_htlc_success_tx_0 = "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219700000000000000000001e8030000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402206a6e59f18764a5bf8d4fa45eebc591566689441229c918b480fb2af8cc6a4aeb02205248f273be447684b33e3c8d1d85a8e0ca9fa0bae9ae33f0527ada9c162919a60147304402207cb324fa0de88f452ffa9389678127ebcf4cabe1dd848b8e076c1a1962bf34720220116ed922b12311bd602d67e60d2529917f21c5b82f25ff6506c0f87886b4dfd5012000000000000000000000000000000000000000000000000000000000000000008a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f401b175ac686800000000"
       -
       -        local_signature_htlc2 = "3045022100c89172099507ff50f4c925e6c5150e871fb6e83dd73ff9fbb72f6ce829a9633f02203a63821d9162e99f9be712a68f9e589483994feae2661e4546cd5b6cec007be5"
       -        output_htlc_timeout_tx_2 = "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219701000000000000000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d5275b3619953cb0c3b5aa577f04bc512380e60fa551762ce3d7a1bb7401cff9022037237ab0dac3fe100cde094e82e2bed9ba0ed1bb40154b48e56aa70f259e608b01483045022100c89172099507ff50f4c925e6c5150e871fb6e83dd73ff9fbb72f6ce829a9633f02203a63821d9162e99f9be712a68f9e589483994feae2661e4546cd5b6cec007be501008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000"
       -
       -        local_signature_htlc1 = "3045022100def389deab09cee69eaa1ec14d9428770e45bcbe9feb46468ecf481371165c2f022015d2e3c46600b2ebba8dcc899768874cc6851fd1ecb3fffd15db1cc3de7e10da"
       -        output_htlc_success_tx_1 = "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219702000000000000000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402201b63ec807771baf4fdff523c644080de17f1da478989308ad13a58b51db91d360220568939d38c9ce295adba15665fa68f51d967e8ed14a007b751540a80b325f20201483045022100def389deab09cee69eaa1ec14d9428770e45bcbe9feb46468ecf481371165c2f022015d2e3c46600b2ebba8dcc899768874cc6851fd1ecb3fffd15db1cc3de7e10da012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000"
       -
       -        local_signature_htlc3 = "30440220643aacb19bbb72bd2b635bc3f7375481f5981bace78cdd8319b2988ffcc6704202203d27784ec8ad51ed3bd517a05525a5139bb0b755dd719e0054332d186ac08727"
       -        output_htlc_timeout_tx_3 = "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219703000000000000000001b80b0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100daee1808f9861b6c3ecd14f7b707eca02dd6bdfc714ba2f33bc8cdba507bb182022026654bf8863af77d74f51f4e0b62d461a019561bb12acb120d3f7195d148a554014730440220643aacb19bbb72bd2b635bc3f7375481f5981bace78cdd8319b2988ffcc6704202203d27784ec8ad51ed3bd517a05525a5139bb0b755dd719e0054332d186ac0872701008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000"
       -
       -        local_signature_htlc4 = "30440220549e80b4496803cbc4a1d09d46df50109f546d43fbbf86cd90b174b1484acd5402205f12a4f995cb9bded597eabfee195a285986aa6d93ae5bb72507ebc6a4e2349e"
       -        output_htlc_success_tx_4 = "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219704000000000000000001a00f0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402207e0410e45454b0978a623f36a10626ef17b27d9ad44e2760f98cfa3efb37924f0220220bd8acd43ecaa916a80bd4f919c495a2c58982ce7c8625153f8596692a801d014730440220549e80b4496803cbc4a1d09d46df50109f546d43fbbf86cd90b174b1484acd5402205f12a4f995cb9bded597eabfee195a285986aa6d93ae5bb72507ebc6a4e2349e012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000"
       -
       -        def test_htlc_tx(htlc, htlc_output_index, amount_msat, ref_local_sig, htlc_payment_preimage, remote_htlc_sig, ref_tx, success, cltv_timeout):
       -            our_htlc_tx_output = make_htlc_tx_output(
       -                amount_msat=amount_msat,
       -                local_feerate=local_feerate_per_kw,
       -                revocationpubkey=local_revocation_pubkey,
       -                local_delayedpubkey=local_delayedpubkey,
       -                success=success,
       -                to_self_delay=local_delay)
       -            our_htlc_tx_inputs = make_htlc_tx_inputs(
       -                htlc_output_txid=our_commit_tx.txid(),
       -                htlc_output_index=htlc_output_index,
       -                revocationpubkey=local_revocation_pubkey,
       -                local_delayedpubkey=local_delayedpubkey,
       -                amount_msat=amount_msat,
       -                witness_script=bh2u(htlc))
       -            our_htlc_tx = make_htlc_tx(cltv_timeout,
       -                inputs=our_htlc_tx_inputs,
       -                output=our_htlc_tx_output)
       -
       -            local_sig = our_htlc_tx.sign_txin(0, local_privkey[:-1])
       -            #self.assertEqual(ref_local_sig + "01", local_sig)  # commented out as it is sufficient to compare the serialized txn
       -
       -            our_htlc_tx_witness = make_htlc_tx_witness(  # FIXME only correct for success=True
       -                remotehtlcsig=bfh(remote_htlc_sig) + b"\x01",  # 0x01 is SIGHASH_ALL
       -                localhtlcsig=bfh(local_sig),
       -                payment_preimage=htlc_payment_preimage if success else b'',  # will put 00 on witness if timeout
       -                witness_script=htlc)
       -            our_htlc_tx._inputs[0]['witness'] = bh2u(our_htlc_tx_witness)
       -            self.assertEqual(ref_tx, str(our_htlc_tx))
       -
       -        test_htlc_tx(htlc=htlc0, htlc_output_index=0,
       -                     amount_msat=htlc0_msat,
       -                     ref_local_sig=local_signature_htlc0,
       -                     htlc_payment_preimage=htlc0_payment_preimage,
       -                     remote_htlc_sig=signature_for_output_remote_htlc_0,
       -                     ref_tx=output_htlc_success_tx_0,
       -                     success=True, cltv_timeout=0)
       -        test_htlc_tx(htlc=htlc1, htlc_output_index=2,
       -                     amount_msat=htlc1_msat,
       -                     ref_local_sig=local_signature_htlc1,
       -                     htlc_payment_preimage=htlc1_payment_preimage,
       -                     remote_htlc_sig=signature_for_output_remote_htlc_1,
       -                     ref_tx=output_htlc_success_tx_1,
       -                     success=True, cltv_timeout=0)
       -        test_htlc_tx(htlc=htlc2,  htlc_output_index=1,
       -                     amount_msat=htlc2_msat,
       -                     ref_local_sig=local_signature_htlc2,
       -                     htlc_payment_preimage=htlc2_payment_preimage,
       -                     remote_htlc_sig=signature_for_output_remote_htlc_2,
       -                     ref_tx=output_htlc_timeout_tx_2,
       -                     success=False, cltv_timeout=htlc2_cltv_timeout)
       -        test_htlc_tx(htlc=htlc3,  htlc_output_index=3,
       -                     amount_msat=htlc3_msat,
       -                     ref_local_sig=local_signature_htlc3,
       -                     htlc_payment_preimage=htlc3_payment_preimage,
       -                     remote_htlc_sig=signature_for_output_remote_htlc_3,
       -                     ref_tx=output_htlc_timeout_tx_3,
       -                     success=False, cltv_timeout=htlc3_cltv_timeout)
       -        test_htlc_tx(htlc=htlc4,  htlc_output_index=4,
       -                     amount_msat=htlc4_msat,
       -                     ref_local_sig=local_signature_htlc4,
       -                     htlc_payment_preimage=htlc4_payment_preimage,
       -                     remote_htlc_sig=signature_for_output_remote_htlc_4,
       -                     ref_tx=output_htlc_success_tx_4,
       -                     success=True, cltv_timeout=0)
       -
       -    def test_find_path_for_payment(self):
       -        class fake_ln_worker:
       -            channel_db = lnrouter.ChannelDB()
       -            path_finder = lnrouter.LNPathFinder(channel_db)
       -            privkey = bitcoin.sha256('privkeyseed')
       -            network = None
       -            channel_state = {}
       -            channels = []
       -            invoices = {}
       -        p = Peer(fake_ln_worker, '', 0, 'a')
       -        p.on_channel_announcement({'node_id_1': b'b', 'node_id_2': b'c', 'short_channel_id': bfh('0000000000000001')})
       -        p.on_channel_announcement({'node_id_1': b'b', 'node_id_2': b'e', 'short_channel_id': bfh('0000000000000002')})
       -        p.on_channel_announcement({'node_id_1': b'a', 'node_id_2': b'b', 'short_channel_id': bfh('0000000000000003')})
       -        p.on_channel_announcement({'node_id_1': b'c', 'node_id_2': b'd', 'short_channel_id': bfh('0000000000000004')})
       -        p.on_channel_announcement({'node_id_1': b'd', 'node_id_2': b'e', 'short_channel_id': bfh('0000000000000005')})
       -        p.on_channel_announcement({'node_id_1': b'a', 'node_id_2': b'd', 'short_channel_id': bfh('0000000000000006')})
       -        o = lambda i: i.to_bytes(8, "big")
       -        p.on_channel_update({'short_channel_id': bfh('0000000000000001'), 'flags': b'\x00', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       -        p.on_channel_update({'short_channel_id': bfh('0000000000000001'), 'flags': b'\x01', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       -        p.on_channel_update({'short_channel_id': bfh('0000000000000002'), 'flags': b'\x00', 'cltv_expiry_delta': o(99), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       -        p.on_channel_update({'short_channel_id': bfh('0000000000000002'), 'flags': b'\x01', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       -        p.on_channel_update({'short_channel_id': bfh('0000000000000003'), 'flags': b'\x01', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       -        p.on_channel_update({'short_channel_id': bfh('0000000000000003'), 'flags': b'\x00', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       -        p.on_channel_update({'short_channel_id': bfh('0000000000000004'), 'flags': b'\x01', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       -        p.on_channel_update({'short_channel_id': bfh('0000000000000004'), 'flags': b'\x00', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       -        p.on_channel_update({'short_channel_id': bfh('0000000000000005'), 'flags': b'\x01', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       -        p.on_channel_update({'short_channel_id': bfh('0000000000000005'), 'flags': b'\x00', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(999)})
       -        p.on_channel_update({'short_channel_id': bfh('0000000000000006'), 'flags': b'\x00', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(99999999)})
       -        p.on_channel_update({'short_channel_id': bfh('0000000000000006'), 'flags': b'\x01', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       -        self.assertNotEqual(None, fake_ln_worker.path_finder.find_path_for_payment(b'a', b'e', 100000))
       -
       -    def test_key_derivation(self):
       -        # BOLT3, Appendix E
       -        base_secret = 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
       -        per_commitment_secret = 0x1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100
       -        revocation_basepoint_secret = 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
       -        base_point = secret_to_pubkey(base_secret)
       -        self.assertEqual(base_point, bfh('036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2'))
       -        per_commitment_point = secret_to_pubkey(per_commitment_secret)
       -        self.assertEqual(per_commitment_point, bfh('025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486'))
       -        localpubkey = derive_pubkey(base_point, per_commitment_point)
       -        self.assertEqual(localpubkey, bfh('0235f2dbfaa89b57ec7b055afe29849ef7ddfeb1cefdb9ebdc43f5494984db29e5'))
       -        localprivkey = derive_privkey(base_secret, per_commitment_point)
       -        self.assertEqual(localprivkey, 0xcbced912d3b21bf196a766651e436aff192362621ce317704ea2f75d87e7be0f)
       -        revocation_basepoint = secret_to_pubkey(revocation_basepoint_secret)
       -        self.assertEqual(revocation_basepoint, bfh('036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2'))
       -        revocationpubkey = derive_blinded_pubkey(revocation_basepoint, per_commitment_point)
       -        self.assertEqual(revocationpubkey, bfh('02916e326636d19c33f13e8c0c3a03dd157f332f3e99c317c141dd865eb01f8ff0'))
       -
       -    def test_per_commitment_secret_from_seed(self):
       -        self.assertEqual(0x02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148.to_bytes(byteorder="big", length=32),
       -                         get_per_commitment_secret_from_seed(0x0000000000000000000000000000000000000000000000000000000000000000.to_bytes(byteorder="big", length=32), 281474976710655))
       -        self.assertEqual(0x7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc.to_bytes(byteorder="big", length=32),
       -                         get_per_commitment_secret_from_seed(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.to_bytes(byteorder="big", length=32), 281474976710655))
       -        self.assertEqual(0x56f4008fb007ca9acf0e15b054d5c9fd12ee06cea347914ddbaed70d1c13a528.to_bytes(byteorder="big", length=32),
       -                         get_per_commitment_secret_from_seed(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.to_bytes(byteorder="big", length=32), 0xaaaaaaaaaaa))
       -        self.assertEqual(0x9015daaeb06dba4ccc05b91b2f73bd54405f2be9f217fbacd3c5ac2e62327d31.to_bytes(byteorder="big", length=32),
       -                         get_per_commitment_secret_from_seed(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.to_bytes(byteorder="big", length=32), 0x555555555555))
       -        self.assertEqual(0x915c75942a26bb3a433a8ce2cb0427c29ec6c1775cfc78328b57f6ba7bfeaa9c.to_bytes(byteorder="big", length=32),
       -                         get_per_commitment_secret_from_seed(0x0101010101010101010101010101010101010101010101010101010101010101.to_bytes(byteorder="big", length=32), 1))
       -
       -    def test_new_onion_packet(self):
       -        # test vector from bolt-04
       -        payment_path_pubkeys = [
       -            bfh('02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619'),
       -            bfh('0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c'),
       -            bfh('027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007'),
       -            bfh('032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991'),
       -            bfh('02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145'),
       -        ]
       -        session_key = bfh('4141414141414141414141414141414141414141414141414141414141414141')
       -        associated_data = bfh('4242424242424242424242424242424242424242424242424242424242424242')
       -        hops_data = [
       -            OnionHopsDataSingle(OnionPerHop(
       -                bfh('0000000000000000'), bfh('0000000000000000'), bfh('00000000')
       -            )),
       -            OnionHopsDataSingle(OnionPerHop(
       -                bfh('0101010101010101'), bfh('0000000000000001'), bfh('00000001')
       -            )),
       -            OnionHopsDataSingle(OnionPerHop(
       -                bfh('0202020202020202'), bfh('0000000000000002'), bfh('00000002')
       -            )),
       -            OnionHopsDataSingle(OnionPerHop(
       -                bfh('0303030303030303'), bfh('0000000000000003'), bfh('00000003')
       -            )),
       -            OnionHopsDataSingle(OnionPerHop(
       -                bfh('0404040404040404'), bfh('0000000000000004'), bfh('00000004')
       -            )),
       -        ]
       -        packet = new_onion_packet(payment_path_pubkeys, session_key, hops_data, associated_data)
       -        self.assertEqual(bfh('0002eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619e5f14350c2a76fc232b5e46d421e9615471ab9e0bc887beff8c95fdb878f7b3a71da571226458c510bbadd1276f045c21c520a07d35da256ef75b4367962437b0dd10f7d61ab590531cf08000178a333a347f8b4072e216400406bdf3bf038659793a86cae5f52d32f3438527b47a1cfc54285a8afec3a4c9f3323db0c946f5d4cb2ce721caad69320c3a469a202f3e468c67eaf7a7cda226d0fd32f7b48084dca885d15222e60826d5d971f64172d98e0760154400958f00e86697aa1aa9d41bee8119a1ec866abe044a9ad635778ba61fc0776dc832b39451bd5d35072d2269cf9b040d6ba38b54ec35f81d7fc67678c3be47274f3c4cc472aff005c3469eb3bc140769ed4c7f0218ff8c6c7dd7221d189c65b3b9aaa71a01484b122846c7c7b57e02e679ea8469b70e14fe4f70fee4d87b910cf144be6fe48eef24da475c0b0bcc6565ae82cd3f4e3b24c76eaa5616c6111343306ab35c1fe5ca4a77c0e314ed7dba39d6f1e0de791719c241a939cc493bea2bae1c1e932679ea94d29084278513c77b899cc98059d06a27d171b0dbdf6bee13ddc4fc17a0c4d2827d488436b57baa167544138ca2e64a11b43ac8a06cd0c2fba2d4d900ed2d9205305e2d7383cc98dacb078133de5f6fb6bed2ef26ba92cea28aafc3b9948dd9ae5559e8bd6920b8cea462aa445ca6a95e0e7ba52961b181c79e73bd581821df2b10173727a810c92b83b5ba4a0403eb710d2ca10689a35bec6c3a708e9e92f7d78ff3c5d9989574b00c6736f84c199256e76e19e78f0c98a9d580b4a658c84fc8f2096c2fbea8f5f8c59d0fdacb3be2802ef802abbecb3aba4acaac69a0e965abd8981e9896b1f6ef9d60f7a164b371af869fd0e48073742825e9434fc54da837e120266d53302954843538ea7c6c3dbfb4ff3b2fdbe244437f2a153ccf7bdb4c92aa08102d4f3cff2ae5ef86fab4653595e6a5837fa2f3e29f27a9cde5966843fb847a4a61f1e76c281fe8bb2b0a181d096100db5a1a5ce7a910238251a43ca556712eaadea167fb4d7d75825e440f3ecd782036d7574df8bceacb397abefc5f5254d2722215c53ff54af8299aaaad642c6d72a14d27882d9bbd539e1cc7a527526ba89b8c037ad09120e98ab042d3e8652b31ae0e478516bfaf88efca9f3676ffe99d2819dcaeb7610a626695f53117665d267d3f7abebd6bbd6733f645c72c389f03855bdf1e4b8075b516569b118233a0f0971d24b83113c0b096f5216a207ca99a7cddc81c130923fe3d91e7508c9ac5f2e914ff5dccab9e558566fa14efb34ac98d878580814b94b73acbfde9072f30b881f7f0fff42d4045d1ace6322d86a97d164aa84d93a60498065cc7c20e636f5862dc81531a88c60305a2e59a985be327a6902e4bed986dbf4a0b50c217af0ea7fdf9ab37f9ea1a1aaa72f54cf40154ea9b269f1a7c09f9f43245109431a175d50e2db0132337baa0ef97eed0fcf20489da36b79a1172faccc2f7ded7c60e00694282d93359c4682135642bc81f433574aa8ef0c97b4ade7ca372c5ffc23c7eddd839bab4e0f14d6df15c9dbeab176bec8b5701cf054eb3072f6dadc98f88819042bf10c407516ee58bce33fbe3b3d86a54255e577db4598e30a135361528c101683a5fcde7e8ba53f3456254be8f45fe3a56120ae96ea3773631fcb3873aa3abd91bcff00bd38bd43697a2e789e00da6077482e7b1b1a677b5afae4c54e6cbdf7377b694eb7d7a5b913476a5be923322d3de06060fd5e819635232a2cf4f0731da13b8546d1d6d4f8d75b9fce6c2341a71b0ea6f780df54bfdb0dd5cd9855179f602f917265f21f9190c70217774a6fbaaa7d63ad64199f4664813b955cff954949076dcf'),
       -                         packet.to_bytes())
       -
       -    def test_process_onion_packet(self):
       -        # this test is not from bolt-04, but is based on the one there;
       -        # except here we have the privkeys for these pubkeys
       -        payment_path_pubkeys = [
       -            bfh('03d75c0ee70f68d73d7d13aeb6261d8ace11416800860c7e59407afe4e2e2d42bb'),
       -            bfh('03960a0b830c7b8e76de745b819f252c62508346196b916f5e813cdb0773283cce'),
       -            bfh('0385620e0a571cbc3552620f8bf1bdcdab2d1a4a59c36fa10b8249114ccbdda40d'),
       -            bfh('02ee242cf6c38b7285f0152c33804ff777f5c51fd352ca8132e845e2cf23b3d8ba'),
       -            bfh('025c585fd2e174bf8245b2b4a119e52a417688904228643ea3edaa1728bf2a258e'),
       -        ]
       -        payment_path_privkeys = [
       -            bfh('3463a278617b3dd83f79bda7f97673f12609c54386e1f0d2b67b1c6354fda14e'),
       -            bfh('7e1255fddb52db1729fc3ceb21a46f95b8d9fe94cc83425e936a6c5223bb679d'),
       -            bfh('c7ce8c1462c311eec24dff9e2532ac6241e50ae57e7d1833af21942136972f23'),
       -            bfh('3d885f374d79a5e777459b083f7818cdc9493e5c4994ac9c7b843de8b70be661'),
       -            bfh('dd72ab44729527b7942e195e7a835e7c71f9c0ff61844eb21274d9c26166a8f8'),
       -        ]
       -        session_key = bfh('4141414141414141414141414141414141414141414141414141414141414141')
       -        associated_data = bfh('4242424242424242424242424242424242424242424242424242424242424242')
       -        hops_data = [
       -            OnionHopsDataSingle(OnionPerHop(
       -                bfh('0000000000000000'), bfh('0000000000000000'), bfh('00000000')
       -            )),
       -            OnionHopsDataSingle(OnionPerHop(
       -                bfh('0101010101010101'), bfh('0000000000000001'), bfh('00000001')
       -            )),
       -            OnionHopsDataSingle(OnionPerHop(
       -                bfh('0202020202020202'), bfh('0000000000000002'), bfh('00000002')
       -            )),
       -            OnionHopsDataSingle(OnionPerHop(
       -                bfh('0303030303030303'), bfh('0000000000000003'), bfh('00000003')
       -            )),
       -            OnionHopsDataSingle(OnionPerHop(
       -                bfh('0404040404040404'), bfh('0000000000000004'), bfh('00000004')
       -            )),
       -        ]
       -        packet = new_onion_packet(payment_path_pubkeys, session_key, hops_data, associated_data)
       -        self.assertEqual(bfh('0002eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f28368661954176cd9869da33d713aa219fcef1e5c806fef11e696bcc66844de8271c27974a0fd57c2dbcb2c6dd4e8ef35d96db28d5a0e49b6ab3d6de31af65950723b8cddc108390bebf8d149002e31bdc283056477ba27c8054c248ad7306de31663a7c99ec659da15d0f6fbc7e1687485b39e9be0ec3b70164cb3618a9b546317e7c2d62ae9f0f840704535729262d30c6132d1b390f073edec8fa057176c6268b6ad06a82ff0d16d4c662194873e8b4ecf46eb2c9d4d58d2ee2021adb19840605ac5afd8bd942dd71e8244c83e28b2ed5a3b09e9e7df5c8c747e5765ba366a4f7407a6c6b0a32f74bc5e428f7fa4c3cf70e13ed91563177d94190d5149aa4b9c96d00e40d2ac35ab9c4a621ce0f6f5df7d64a9c8d435db19de192d9db522c7f7b4e201fc1b61a9bd3efd062ae24455d463818b01e2756c7d0691bc3ac4c017be34c9a8b2913bb1b937e31e0ae40f650a7cd820bcb4996825b1cbad1ff7ccc2b513b1104524c34f6573e1b59201c005a632ee5dccd3711a32e3ba1ff00fcffbe636e4b3a84bbe491b836a57ccec138b8cc2ec733846904d872f305d538d51db8e56232ec6e07877075328874cb7b09c7e799100a9ff085dead253886b174fc408a0ea7b48bce2c5d8992285011960af088f7e006ef60089d46ac9aa15acfac6c87c3cf6904764dd785419292fbafa9cca09c8ade24a6cd63f12d1cfc83fa35cf2f1cf503c39cbf78293f06c68a3cece7177169cd872bb49bf69d933a27a887dd9daefa9239fca9f0c3e309ec61d9df947211da98cf11a6e0fb77252629cdf9f2226dd69ca73fa51be4df224592f8d471b69a1aebbdaa2f3a798b3581253d97feb0a12e6606043ca0fc5efc0f49b8061d6796eff31cd8638499e2f25ffb96eec32837438ed7ebebbe587886648f63e35d80f41869f4c308f2e6970bd65fead5e8544e3239a6acc9d996b08d1546455bcafbe88ed3ed547714841946fe2e77180e4d7bf1452414e4b1745a7897184a2c4cbc3ac46f83342a55a48e29dc8f17cf595dd28f51e297ba89fd25ed0dbd1c0081a810beaab09758a36fbfd16fbdc3daa9fe05c8a73195f244ef2743a5df761f01ee6e693eb6c7f1a7834fab3671391e5ddebf611e119a2ae4456e2cee7a6d4f27a2246cdb1f8ef35f0b3d7044b3799d8d0ed0a6470557fd807c065d6d83acba07e96e10770ada8c0b4d4921522944188d5f30086a6ee0a4795331273f32beaaa43363fc58208a257e5c5c434c7325b583642219d81c7d67b908d5263b42ac1991edc69a777da60f38eff138c844af9e549374e8b29b166211bfded24587a29394e33828b784da7e7b62ab7e49ea2693fcdd17fa96186a5ef11ef1a8adffa50f93a3119e95e6c09014f3e3b0709183fa08a826ced6deb4608b7d986ebbcf99ad58e25451d4d9d38d0059734d8501467b97182cd11e0c07c91ca50f61cc31255a3147ade654976a5989097281892aafd8df595c63bd14f1e03f5955a9398d2dd6368bbcae833ae1cc2df31eb0980b4817dfd130020ffb275743fcc01df40e3ecda1c5988e8e1bde965353b0b1bf34ea05f095000c45b6249618d275905a24d3eb58c600aeab4fb552fbf1ccdb2a5c80ace220310f89829d7e53f78c126037b6d8d500220c7a118d9621b4d6bd5379edd7e24bcf540e87aba6b88862db16fa4ee00b009fda80577be67ab94910fd8a7807dfe4ebe66b8fdcd040aa2dc17ec22639298be56b2a2c9d8940647b75f2f6d81746df16e1cb2f05e23397a8c63baea0803441ff4b7d517ff172980a056726235e2f6af85e8aa9b91ba85f14532272d6170df3166b91169dc09d4f4a251610f57ff0885a93364cfaf650bdf436c89795efed5ca934bc7ffc0a4'),
       -                         packet.to_bytes())
       -        for i, privkey in enumerate(payment_path_privkeys):
       -            processed_packet = lnrouter.process_onion_packet(packet, associated_data, privkey)
       -            self.assertEqual(hops_data[i].per_hop.to_bytes(), processed_packet.hop_data.per_hop.to_bytes())
       -            packet = processed_packet.next_packet
       -
       -    def test_decode_onion_error(self):
       -        # test vector from bolt-04
       -        payment_path_pubkeys = [
       -            bfh('02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619'),
       -            bfh('0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c'),
       -            bfh('027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007'),
       -            bfh('032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991'),
       -            bfh('02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145'),
       -        ]
       -        session_key = bfh('4141414141414141414141414141414141414141414141414141414141414141')
       -        error_packet_for_node_0 = bfh('9c5add3963fc7f6ed7f148623c84134b5647e1306419dbe2174e523fa9e2fbed3a06a19f899145610741c83ad40b7712aefaddec8c6baf7325d92ea4ca4d1df8bce517f7e54554608bf2bd8071a4f52a7a2f7ffbb1413edad81eeea5785aa9d990f2865dc23b4bc3c301a94eec4eabebca66be5cf638f693ec256aec514620cc28ee4a94bd9565bc4d4962b9d3641d4278fb319ed2b84de5b665f307a2db0f7fbb757366067d88c50f7e829138fde4f78d39b5b5802f1b92a8a820865af5cc79f9f30bc3f461c66af95d13e5e1f0381c184572a91dee1c849048a647a1158cf884064deddbf1b0b88dfe2f791428d0ba0f6fb2f04e14081f69165ae66d9297c118f0907705c9c4954a199bae0bb96fad763d690e7daa6cfda59ba7f2c8d11448b604d12d')
       -        decoded_error, index_of_sender = lnrouter._decode_onion_error(error_packet_for_node_0, payment_path_pubkeys, session_key)
       -        self.assertEqual(bfh('4c2fc8bc08510334b6833ad9c3e79cd1b52ae59dfe5c2a4b23ead50f09f7ee0b0002200200fe0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'),
       -                             decoded_error)
       -        self.assertEqual(4, index_of_sender)
       -
       -    def test_shachain_store(self):
       -        tests = [
       -            {
       -                "name": "insert_secret correct sequence",
       -                "inserts": [
       -                    {
       -                        "index": 281474976710655,
       -                        "secret": "7cc854b54e3e0dcdb010d7a3fee464a9687b" +\
       -                            "e6e8db3be6854c475621e007a5dc",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710654,
       -                        "secret": "c7518c8ae4660ed02894df8976fa1a3659c1" +\
       -                            "a8b4b5bec0c4b872abeba4cb8964",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710653,
       -                        "secret": "2273e227a5b7449b6e70f1fb4652864038b1" +\
       -                            "cbf9cd7c043a7d6456b7fc275ad8",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710652,
       -                        "secret": "27cddaa5624534cb6cb9d7da077cf2b22ab2" +\
       -                            "1e9b506fd4998a51d54502e99116",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710651,
       -                        "secret": "c65716add7aa98ba7acb236352d665cab173" +\
       -                            "45fe45b55fb879ff80e6bd0c41dd",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710650,
       -                        "secret": "969660042a28f32d9be17344e09374b37996" +\
       -                            "2d03db1574df5a8a5a47e19ce3f2",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710649,
       -                        "secret": "a5a64476122ca0925fb344bdc1854c1c0a59" +\
       -                            "fc614298e50a33e331980a220f32",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710648,
       -                        "secret": "05cde6323d949933f7f7b78776bcc1ea6d9b" +\
       -                            "31447732e3802e1f7ac44b650e17",
       -                        "successful": True
       -                    }
       -                ]
       -            },
       -            {
       -                "name": "insert_secret #1 incorrect",
       -                "inserts": [
       -                    {
       -                        "index": 281474976710655,
       -                        "secret": "02a40c85b6f28da08dfdbe0926c53fab2d" +\
       -                            "e6d28c10301f8f7c4073d5e42e3148",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710654,
       -                        "secret": "c7518c8ae4660ed02894df8976fa1a3659" +\
       -                            "c1a8b4b5bec0c4b872abeba4cb8964",
       -                        "successful": False
       -                    }
       -                ]
       -            },
       -            {
       -                "name": "insert_secret #2 incorrect (#1 derived from incorrect)",
       -                "inserts": [
       -                    {
       -                        "index": 281474976710655,
       -                        "secret": "02a40c85b6f28da08dfdbe0926c53fab2de6" +\
       -                            "d28c10301f8f7c4073d5e42e3148",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710654,
       -                        "secret": "dddc3a8d14fddf2b68fa8c7fbad274827493" +\
       -                            "7479dd0f8930d5ebb4ab6bd866a3",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710653,
       -                        "secret": "2273e227a5b7449b6e70f1fb4652864038b1" +\
       -                            "cbf9cd7c043a7d6456b7fc275ad8",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710652,
       -                        "secret": "27cddaa5624534cb6cb9d7da077cf2b22a" +\
       -                            "b21e9b506fd4998a51d54502e99116",
       -                        "successful": False
       -                    }
       -                ]
       -            },
       -            {
       -                "name": "insert_secret #3 incorrect",
       -                "inserts": [
       -                    {
       -                        "index": 281474976710655,
       -                        "secret": "7cc854b54e3e0dcdb010d7a3fee464a9687b" +\
       -                            "e6e8db3be6854c475621e007a5dc",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710654,
       -                        "secret": "c7518c8ae4660ed02894df8976fa1a3659c1" +\
       -                            "a8b4b5bec0c4b872abeba4cb8964",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710653,
       -                        "secret": "c51a18b13e8527e579ec56365482c62f180b" +\
       -                            "7d5760b46e9477dae59e87ed423a",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710652,
       -                        "secret": "27cddaa5624534cb6cb9d7da077cf2b22ab2" +\
       -                            "1e9b506fd4998a51d54502e99116",
       -                        "successful": False
       -                    }
       -                ]
       -            },
       -            {
       -                "name": "insert_secret #4 incorrect (1,2,3 derived from incorrect)",
       -                "inserts": [
       -                    {
       -                        "index": 281474976710655,
       -                        "secret": "02a40c85b6f28da08dfdbe0926c53fab2de6" +\
       -                            "d28c10301f8f7c4073d5e42e3148",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710654,
       -                        "secret": "dddc3a8d14fddf2b68fa8c7fbad274827493" +\
       -                            "7479dd0f8930d5ebb4ab6bd866a3",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710653,
       -                        "secret": "c51a18b13e8527e579ec56365482c62f18" +\
       -                            "0b7d5760b46e9477dae59e87ed423a",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710652,
       -                        "secret": "ba65d7b0ef55a3ba300d4e87af29868f39" +\
       -                            "4f8f138d78a7011669c79b37b936f4",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710651,
       -                        "secret": "c65716add7aa98ba7acb236352d665cab1" +\
       -                            "7345fe45b55fb879ff80e6bd0c41dd",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710650,
       -                        "secret": "969660042a28f32d9be17344e09374b379" +\
       -                            "962d03db1574df5a8a5a47e19ce3f2",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710649,
       -                        "secret": "a5a64476122ca0925fb344bdc1854c1c0a" +\
       -                            "59fc614298e50a33e331980a220f32",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710649,
       -                        "secret": "05cde6323d949933f7f7b78776bcc1ea6d9b" +\
       -                            "31447732e3802e1f7ac44b650e17",
       -                        "successful": False
       -                    }
       -                ]
       -            },
       -            {
       -                "name": "insert_secret #5 incorrect",
       -                "inserts": [
       -                    {
       -                        "index": 281474976710655,
       -                        "secret": "7cc854b54e3e0dcdb010d7a3fee464a9687b" +\
       -                            "e6e8db3be6854c475621e007a5dc",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710654,
       -                        "secret": "c7518c8ae4660ed02894df8976fa1a3659c1a" +\
       -                            "8b4b5bec0c4b872abeba4cb8964",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710653,
       -                        "secret": "2273e227a5b7449b6e70f1fb4652864038b1" +\
       -                            "cbf9cd7c043a7d6456b7fc275ad8",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710652,
       -                        "secret": "27cddaa5624534cb6cb9d7da077cf2b22ab21" +\
       -                            "e9b506fd4998a51d54502e99116",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710651,
       -                        "secret": "631373ad5f9ef654bb3dade742d09504c567" +\
       -                            "edd24320d2fcd68e3cc47e2ff6a6",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710650,
       -                        "secret": "969660042a28f32d9be17344e09374b37996" +\
       -                            "2d03db1574df5a8a5a47e19ce3f2",
       -                        "successful": False
       -                    }
       -                ]
       -            },
       -            {
       -                "name": "insert_secret #6 incorrect (5 derived from incorrect)",
       -                "inserts": [
       -                    {
       -                        "index": 281474976710655,
       -                        "secret": "7cc854b54e3e0dcdb010d7a3fee464a9687b" +\
       -                            "e6e8db3be6854c475621e007a5dc",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710654,
       -                        "secret": "c7518c8ae4660ed02894df8976fa1a3659c1a" +\
       -                            "8b4b5bec0c4b872abeba4cb8964",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710653,
       -                        "secret": "2273e227a5b7449b6e70f1fb4652864038b1" +\
       -                            "cbf9cd7c043a7d6456b7fc275ad8",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710652,
       -                        "secret": "27cddaa5624534cb6cb9d7da077cf2b22ab21" +\
       -                            "e9b506fd4998a51d54502e99116",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710651,
       -                        "secret": "631373ad5f9ef654bb3dade742d09504c567" +\
       -                            "edd24320d2fcd68e3cc47e2ff6a6",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710650,
       -                        "secret": "b7e76a83668bde38b373970155c868a65330" +\
       -                            "4308f9896692f904a23731224bb1",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710649,
       -                        "secret": "a5a64476122ca0925fb344bdc1854c1c0a59f" +\
       -                            "c614298e50a33e331980a220f32",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710648,
       -                        "secret": "05cde6323d949933f7f7b78776bcc1ea6d9b" +\
       -                            "31447732e3802e1f7ac44b650e17",
       -                        "successful": False
       -                    }
       -                ]
       -            },
       -            {
       -                "name": "insert_secret #7 incorrect",
       -                "inserts": [
       -                    {
       -                        "index": 281474976710655,
       -                        "secret": "7cc854b54e3e0dcdb010d7a3fee464a9687b" +\
       -                            "e6e8db3be6854c475621e007a5dc",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710654,
       -                        "secret": "c7518c8ae4660ed02894df8976fa1a3659c1a" +\
       -                            "8b4b5bec0c4b872abeba4cb8964",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710653,
       -                        "secret": "2273e227a5b7449b6e70f1fb4652864038b1" +\
       -                            "cbf9cd7c043a7d6456b7fc275ad8",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710652,
       -                        "secret": "27cddaa5624534cb6cb9d7da077cf2b22ab21" +\
       -                            "e9b506fd4998a51d54502e99116",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710651,
       -                        "secret": "c65716add7aa98ba7acb236352d665cab173" +\
       -                            "45fe45b55fb879ff80e6bd0c41dd",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710650,
       -                        "secret": "969660042a28f32d9be17344e09374b37996" +\
       -                            "2d03db1574df5a8a5a47e19ce3f2",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710649,
       -                        "secret": "e7971de736e01da8ed58b94c2fc216cb1d" +\
       -                            "ca9e326f3a96e7194fe8ea8af6c0a3",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710648,
       -                        "secret": "05cde6323d949933f7f7b78776bcc1ea6d" +\
       -                            "9b31447732e3802e1f7ac44b650e17",
       -                        "successful": False
       -                    }
       -                ]
       -            },
       -            {
       -                "name": "insert_secret #8 incorrect",
       -                "inserts": [
       -                    {
       -                        "index": 281474976710655,
       -                        "secret": "7cc854b54e3e0dcdb010d7a3fee464a9687b" +\
       -                            "e6e8db3be6854c475621e007a5dc",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710654,
       -                        "secret": "c7518c8ae4660ed02894df8976fa1a3659c1a" +\
       -                            "8b4b5bec0c4b872abeba4cb8964",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710653,
       -                        "secret": "2273e227a5b7449b6e70f1fb4652864038b1" +\
       -                            "cbf9cd7c043a7d6456b7fc275ad8",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710652,
       -                        "secret": "27cddaa5624534cb6cb9d7da077cf2b22ab21" +\
       -                            "e9b506fd4998a51d54502e99116",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710651,
       -                        "secret": "c65716add7aa98ba7acb236352d665cab173" +\
       -                            "45fe45b55fb879ff80e6bd0c41dd",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710650,
       -                        "secret": "969660042a28f32d9be17344e09374b37996" +\
       -                            "2d03db1574df5a8a5a47e19ce3f2",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710649,
       -                        "secret": "a5a64476122ca0925fb344bdc1854c1c0a" +\
       -                            "59fc614298e50a33e331980a220f32",
       -                        "successful": True
       -                    },
       -                    {
       -                        "index": 281474976710648,
       -                        "secret": "a7efbc61aac46d34f77778bac22c8a20c6" +\
       -                            "a46ca460addc49009bda875ec88fa4",
       -                        "successful": False
       -                    }
       -                ]
       -            }
       -        ]
       -
       -        for test in tests:
       -            receiver = RevocationStore()
       -            for insert in test["inserts"]:
       -                secret = bytes.fromhex(insert["secret"])
       -
       -                try:
       -                    receiver.add_next_entry(secret)
       -                except Exception as e:
       -                    if insert["successful"]:
       -                        raise Exception("Failed ({}): error was received but it shouldn't: {}".format(test["name"], e))
       -                else:
       -                    if not insert["successful"]:
       -                        raise Exception("Failed ({}): error wasn't received".format(test["name"]))
       -
       -            print("Passed ({})".format(test["name"]))
       -
       -    def test_shachain_produce_consume(self):
       -        seed = bitcoin.sha256(b"shachaintest")
       -        consumer = RevocationStore()
       -        for i in range(10000):
       -            secret = get_per_commitment_secret_from_seed(seed, 2**48 - i - 1)
       -            try:
       -                consumer.add_next_entry(secret)
       -            except Exception as e:
       -                raise Exception("iteration " + str(i) + ": " + str(e))
       -            if i % 1000 == 0: self.assertEqual(consumer.serialize(), RevocationStore.from_json_obj(json.loads(json.dumps(consumer.serialize()))).serialize())
 (DIR) diff --git a/lib/tests/test_lnhtlc.py b/lib/tests/test_lnhtlc.py
       t@@ -4,6 +4,7 @@ import unittest
        import lib.bitcoin as bitcoin
        import lib.lnbase as lnbase
        import lib.lnhtlc as lnhtlc
       +import lib.lnutil as lnutil
        import lib.util as util
        import os
        import binascii
       t@@ -87,10 +88,10 @@ def create_test_channels():
            alice_seed = os.urandom(32)
            bob_seed = os.urandom(32)
        
       -    alice_cur = lnbase.secret_to_pubkey(int.from_bytes(lnbase.get_per_commitment_secret_from_seed(alice_seed, 2**48 - 1), "big"))
       -    alice_next = lnbase.secret_to_pubkey(int.from_bytes(lnbase.get_per_commitment_secret_from_seed(alice_seed, 2**48 - 2), "big"))
       -    bob_cur = lnbase.secret_to_pubkey(int.from_bytes(lnbase.get_per_commitment_secret_from_seed(bob_seed, 2**48 - 1), "big"))
       -    bob_next = lnbase.secret_to_pubkey(int.from_bytes(lnbase.get_per_commitment_secret_from_seed(bob_seed, 2**48 - 2), "big"))
       +    alice_cur = lnutil.secret_to_pubkey(int.from_bytes(lnutil.get_per_commitment_secret_from_seed(alice_seed, 2**48 - 1), "big"))
       +    alice_next = lnutil.secret_to_pubkey(int.from_bytes(lnutil.get_per_commitment_secret_from_seed(alice_seed, 2**48 - 2), "big"))
       +    bob_cur = lnutil.secret_to_pubkey(int.from_bytes(lnutil.get_per_commitment_secret_from_seed(bob_seed, 2**48 - 1), "big"))
       +    bob_next = lnutil.secret_to_pubkey(int.from_bytes(lnutil.get_per_commitment_secret_from_seed(bob_seed, 2**48 - 2), "big"))
        
            return \
                lnhtlc.HTLCStateMachine(
       t@@ -240,7 +241,7 @@ class TestLNBaseHTLCStateMachine(unittest.TestCase):
                paymentHash = bitcoin.sha256(paymentPreimage)
                fee_per_kw = alice_channel.constraints.feerate
                self.assertEqual(fee_per_kw, 6000)
       -        htlcAmt = 500 + lnbase.HTLC_TIMEOUT_WEIGHT * (fee_per_kw // 1000)
       +        htlcAmt = 500 + lnutil.HTLC_TIMEOUT_WEIGHT * (fee_per_kw // 1000)
                self.assertEqual(htlcAmt, 4478)
                htlc = lnhtlc.UpdateAddHtlc(
                    payment_hash = paymentHash,
 (DIR) diff --git a/lib/tests/test_lnrouter.py b/lib/tests/test_lnrouter.py
       t@@ -0,0 +1,150 @@
       +import unittest
       +
       +from lib.util import bh2u, bfh
       +from lib.lnbase import Peer
       +from lib.lnrouter import OnionHopsDataSingle, new_onion_packet, OnionPerHop
       +from lib import bitcoin, lnrouter
       +
       +class Test_LNRouter(unittest.TestCase):
       +
       +    #@staticmethod
       +    #def parse_witness_list(witness_bytes):
       +    #    amount_witnesses = witness_bytes[0]
       +    #    witness_bytes = witness_bytes[1:]
       +    #    res = []
       +    #    for i in range(amount_witnesses):
       +    #        witness_length = witness_bytes[0]
       +    #        this_witness = witness_bytes[1:witness_length+1]
       +    #        assert len(this_witness) == witness_length
       +    #        witness_bytes = witness_bytes[witness_length+1:]
       +    #        res += [bytes(this_witness)]
       +    #    assert witness_bytes == b"", witness_bytes
       +    #    return res
       +
       +
       +
       +    def test_find_path_for_payment(self):
       +        class fake_network:
       +            channel_db = lnrouter.ChannelDB()
       +        class fake_ln_worker:
       +            path_finder = lnrouter.LNPathFinder(fake_network.channel_db)
       +            privkey = bitcoin.sha256('privkeyseed')
       +            network = fake_network
       +            channel_state = {}
       +            channels = []
       +            invoices = {}
       +        p = Peer(fake_ln_worker, '', 0, 'a')
       +        p.on_channel_announcement({'node_id_1': b'b', 'node_id_2': b'c', 'short_channel_id': bfh('0000000000000001')})
       +        p.on_channel_announcement({'node_id_1': b'b', 'node_id_2': b'e', 'short_channel_id': bfh('0000000000000002')})
       +        p.on_channel_announcement({'node_id_1': b'a', 'node_id_2': b'b', 'short_channel_id': bfh('0000000000000003')})
       +        p.on_channel_announcement({'node_id_1': b'c', 'node_id_2': b'd', 'short_channel_id': bfh('0000000000000004')})
       +        p.on_channel_announcement({'node_id_1': b'd', 'node_id_2': b'e', 'short_channel_id': bfh('0000000000000005')})
       +        p.on_channel_announcement({'node_id_1': b'a', 'node_id_2': b'd', 'short_channel_id': bfh('0000000000000006')})
       +        o = lambda i: i.to_bytes(8, "big")
       +        p.on_channel_update({'short_channel_id': bfh('0000000000000001'), 'flags': b'\x00', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       +        p.on_channel_update({'short_channel_id': bfh('0000000000000001'), 'flags': b'\x01', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       +        p.on_channel_update({'short_channel_id': bfh('0000000000000002'), 'flags': b'\x00', 'cltv_expiry_delta': o(99), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       +        p.on_channel_update({'short_channel_id': bfh('0000000000000002'), 'flags': b'\x01', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       +        p.on_channel_update({'short_channel_id': bfh('0000000000000003'), 'flags': b'\x01', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       +        p.on_channel_update({'short_channel_id': bfh('0000000000000003'), 'flags': b'\x00', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       +        p.on_channel_update({'short_channel_id': bfh('0000000000000004'), 'flags': b'\x01', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       +        p.on_channel_update({'short_channel_id': bfh('0000000000000004'), 'flags': b'\x00', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       +        p.on_channel_update({'short_channel_id': bfh('0000000000000005'), 'flags': b'\x01', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       +        p.on_channel_update({'short_channel_id': bfh('0000000000000005'), 'flags': b'\x00', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(999)})
       +        p.on_channel_update({'short_channel_id': bfh('0000000000000006'), 'flags': b'\x00', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(99999999)})
       +        p.on_channel_update({'short_channel_id': bfh('0000000000000006'), 'flags': b'\x01', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150)})
       +        self.assertNotEqual(None, fake_ln_worker.path_finder.find_path_for_payment(b'a', b'e', 100000))
       +
       +
       +
       +    def test_new_onion_packet(self):
       +        # test vector from bolt-04
       +        payment_path_pubkeys = [
       +            bfh('02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619'),
       +            bfh('0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c'),
       +            bfh('027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007'),
       +            bfh('032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991'),
       +            bfh('02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145'),
       +        ]
       +        session_key = bfh('4141414141414141414141414141414141414141414141414141414141414141')
       +        associated_data = bfh('4242424242424242424242424242424242424242424242424242424242424242')
       +        hops_data = [
       +            OnionHopsDataSingle(OnionPerHop(
       +                bfh('0000000000000000'), bfh('0000000000000000'), bfh('00000000')
       +            )),
       +            OnionHopsDataSingle(OnionPerHop(
       +                bfh('0101010101010101'), bfh('0000000000000001'), bfh('00000001')
       +            )),
       +            OnionHopsDataSingle(OnionPerHop(
       +                bfh('0202020202020202'), bfh('0000000000000002'), bfh('00000002')
       +            )),
       +            OnionHopsDataSingle(OnionPerHop(
       +                bfh('0303030303030303'), bfh('0000000000000003'), bfh('00000003')
       +            )),
       +            OnionHopsDataSingle(OnionPerHop(
       +                bfh('0404040404040404'), bfh('0000000000000004'), bfh('00000004')
       +            )),
       +        ]
       +        packet = new_onion_packet(payment_path_pubkeys, session_key, hops_data, associated_data)
       +        self.assertEqual(bfh('0002eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619e5f14350c2a76fc232b5e46d421e9615471ab9e0bc887beff8c95fdb878f7b3a71da571226458c510bbadd1276f045c21c520a07d35da256ef75b4367962437b0dd10f7d61ab590531cf08000178a333a347f8b4072e216400406bdf3bf038659793a86cae5f52d32f3438527b47a1cfc54285a8afec3a4c9f3323db0c946f5d4cb2ce721caad69320c3a469a202f3e468c67eaf7a7cda226d0fd32f7b48084dca885d15222e60826d5d971f64172d98e0760154400958f00e86697aa1aa9d41bee8119a1ec866abe044a9ad635778ba61fc0776dc832b39451bd5d35072d2269cf9b040d6ba38b54ec35f81d7fc67678c3be47274f3c4cc472aff005c3469eb3bc140769ed4c7f0218ff8c6c7dd7221d189c65b3b9aaa71a01484b122846c7c7b57e02e679ea8469b70e14fe4f70fee4d87b910cf144be6fe48eef24da475c0b0bcc6565ae82cd3f4e3b24c76eaa5616c6111343306ab35c1fe5ca4a77c0e314ed7dba39d6f1e0de791719c241a939cc493bea2bae1c1e932679ea94d29084278513c77b899cc98059d06a27d171b0dbdf6bee13ddc4fc17a0c4d2827d488436b57baa167544138ca2e64a11b43ac8a06cd0c2fba2d4d900ed2d9205305e2d7383cc98dacb078133de5f6fb6bed2ef26ba92cea28aafc3b9948dd9ae5559e8bd6920b8cea462aa445ca6a95e0e7ba52961b181c79e73bd581821df2b10173727a810c92b83b5ba4a0403eb710d2ca10689a35bec6c3a708e9e92f7d78ff3c5d9989574b00c6736f84c199256e76e19e78f0c98a9d580b4a658c84fc8f2096c2fbea8f5f8c59d0fdacb3be2802ef802abbecb3aba4acaac69a0e965abd8981e9896b1f6ef9d60f7a164b371af869fd0e48073742825e9434fc54da837e120266d53302954843538ea7c6c3dbfb4ff3b2fdbe244437f2a153ccf7bdb4c92aa08102d4f3cff2ae5ef86fab4653595e6a5837fa2f3e29f27a9cde5966843fb847a4a61f1e76c281fe8bb2b0a181d096100db5a1a5ce7a910238251a43ca556712eaadea167fb4d7d75825e440f3ecd782036d7574df8bceacb397abefc5f5254d2722215c53ff54af8299aaaad642c6d72a14d27882d9bbd539e1cc7a527526ba89b8c037ad09120e98ab042d3e8652b31ae0e478516bfaf88efca9f3676ffe99d2819dcaeb7610a626695f53117665d267d3f7abebd6bbd6733f645c72c389f03855bdf1e4b8075b516569b118233a0f0971d24b83113c0b096f5216a207ca99a7cddc81c130923fe3d91e7508c9ac5f2e914ff5dccab9e558566fa14efb34ac98d878580814b94b73acbfde9072f30b881f7f0fff42d4045d1ace6322d86a97d164aa84d93a60498065cc7c20e636f5862dc81531a88c60305a2e59a985be327a6902e4bed986dbf4a0b50c217af0ea7fdf9ab37f9ea1a1aaa72f54cf40154ea9b269f1a7c09f9f43245109431a175d50e2db0132337baa0ef97eed0fcf20489da36b79a1172faccc2f7ded7c60e00694282d93359c4682135642bc81f433574aa8ef0c97b4ade7ca372c5ffc23c7eddd839bab4e0f14d6df15c9dbeab176bec8b5701cf054eb3072f6dadc98f88819042bf10c407516ee58bce33fbe3b3d86a54255e577db4598e30a135361528c101683a5fcde7e8ba53f3456254be8f45fe3a56120ae96ea3773631fcb3873aa3abd91bcff00bd38bd43697a2e789e00da6077482e7b1b1a677b5afae4c54e6cbdf7377b694eb7d7a5b913476a5be923322d3de06060fd5e819635232a2cf4f0731da13b8546d1d6d4f8d75b9fce6c2341a71b0ea6f780df54bfdb0dd5cd9855179f602f917265f21f9190c70217774a6fbaaa7d63ad64199f4664813b955cff954949076dcf'),
       +                         packet.to_bytes())
       +
       +    def test_process_onion_packet(self):
       +        # this test is not from bolt-04, but is based on the one there;
       +        # except here we have the privkeys for these pubkeys
       +        payment_path_pubkeys = [
       +            bfh('03d75c0ee70f68d73d7d13aeb6261d8ace11416800860c7e59407afe4e2e2d42bb'),
       +            bfh('03960a0b830c7b8e76de745b819f252c62508346196b916f5e813cdb0773283cce'),
       +            bfh('0385620e0a571cbc3552620f8bf1bdcdab2d1a4a59c36fa10b8249114ccbdda40d'),
       +            bfh('02ee242cf6c38b7285f0152c33804ff777f5c51fd352ca8132e845e2cf23b3d8ba'),
       +            bfh('025c585fd2e174bf8245b2b4a119e52a417688904228643ea3edaa1728bf2a258e'),
       +        ]
       +        payment_path_privkeys = [
       +            bfh('3463a278617b3dd83f79bda7f97673f12609c54386e1f0d2b67b1c6354fda14e'),
       +            bfh('7e1255fddb52db1729fc3ceb21a46f95b8d9fe94cc83425e936a6c5223bb679d'),
       +            bfh('c7ce8c1462c311eec24dff9e2532ac6241e50ae57e7d1833af21942136972f23'),
       +            bfh('3d885f374d79a5e777459b083f7818cdc9493e5c4994ac9c7b843de8b70be661'),
       +            bfh('dd72ab44729527b7942e195e7a835e7c71f9c0ff61844eb21274d9c26166a8f8'),
       +        ]
       +        session_key = bfh('4141414141414141414141414141414141414141414141414141414141414141')
       +        associated_data = bfh('4242424242424242424242424242424242424242424242424242424242424242')
       +        hops_data = [
       +            OnionHopsDataSingle(OnionPerHop(
       +                bfh('0000000000000000'), bfh('0000000000000000'), bfh('00000000')
       +            )),
       +            OnionHopsDataSingle(OnionPerHop(
       +                bfh('0101010101010101'), bfh('0000000000000001'), bfh('00000001')
       +            )),
       +            OnionHopsDataSingle(OnionPerHop(
       +                bfh('0202020202020202'), bfh('0000000000000002'), bfh('00000002')
       +            )),
       +            OnionHopsDataSingle(OnionPerHop(
       +                bfh('0303030303030303'), bfh('0000000000000003'), bfh('00000003')
       +            )),
       +            OnionHopsDataSingle(OnionPerHop(
       +                bfh('0404040404040404'), bfh('0000000000000004'), bfh('00000004')
       +            )),
       +        ]
       +        packet = new_onion_packet(payment_path_pubkeys, session_key, hops_data, associated_data)
       +        self.assertEqual(bfh('0002eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f28368661954176cd9869da33d713aa219fcef1e5c806fef11e696bcc66844de8271c27974a0fd57c2dbcb2c6dd4e8ef35d96db28d5a0e49b6ab3d6de31af65950723b8cddc108390bebf8d149002e31bdc283056477ba27c8054c248ad7306de31663a7c99ec659da15d0f6fbc7e1687485b39e9be0ec3b70164cb3618a9b546317e7c2d62ae9f0f840704535729262d30c6132d1b390f073edec8fa057176c6268b6ad06a82ff0d16d4c662194873e8b4ecf46eb2c9d4d58d2ee2021adb19840605ac5afd8bd942dd71e8244c83e28b2ed5a3b09e9e7df5c8c747e5765ba366a4f7407a6c6b0a32f74bc5e428f7fa4c3cf70e13ed91563177d94190d5149aa4b9c96d00e40d2ac35ab9c4a621ce0f6f5df7d64a9c8d435db19de192d9db522c7f7b4e201fc1b61a9bd3efd062ae24455d463818b01e2756c7d0691bc3ac4c017be34c9a8b2913bb1b937e31e0ae40f650a7cd820bcb4996825b1cbad1ff7ccc2b513b1104524c34f6573e1b59201c005a632ee5dccd3711a32e3ba1ff00fcffbe636e4b3a84bbe491b836a57ccec138b8cc2ec733846904d872f305d538d51db8e56232ec6e07877075328874cb7b09c7e799100a9ff085dead253886b174fc408a0ea7b48bce2c5d8992285011960af088f7e006ef60089d46ac9aa15acfac6c87c3cf6904764dd785419292fbafa9cca09c8ade24a6cd63f12d1cfc83fa35cf2f1cf503c39cbf78293f06c68a3cece7177169cd872bb49bf69d933a27a887dd9daefa9239fca9f0c3e309ec61d9df947211da98cf11a6e0fb77252629cdf9f2226dd69ca73fa51be4df224592f8d471b69a1aebbdaa2f3a798b3581253d97feb0a12e6606043ca0fc5efc0f49b8061d6796eff31cd8638499e2f25ffb96eec32837438ed7ebebbe587886648f63e35d80f41869f4c308f2e6970bd65fead5e8544e3239a6acc9d996b08d1546455bcafbe88ed3ed547714841946fe2e77180e4d7bf1452414e4b1745a7897184a2c4cbc3ac46f83342a55a48e29dc8f17cf595dd28f51e297ba89fd25ed0dbd1c0081a810beaab09758a36fbfd16fbdc3daa9fe05c8a73195f244ef2743a5df761f01ee6e693eb6c7f1a7834fab3671391e5ddebf611e119a2ae4456e2cee7a6d4f27a2246cdb1f8ef35f0b3d7044b3799d8d0ed0a6470557fd807c065d6d83acba07e96e10770ada8c0b4d4921522944188d5f30086a6ee0a4795331273f32beaaa43363fc58208a257e5c5c434c7325b583642219d81c7d67b908d5263b42ac1991edc69a777da60f38eff138c844af9e549374e8b29b166211bfded24587a29394e33828b784da7e7b62ab7e49ea2693fcdd17fa96186a5ef11ef1a8adffa50f93a3119e95e6c09014f3e3b0709183fa08a826ced6deb4608b7d986ebbcf99ad58e25451d4d9d38d0059734d8501467b97182cd11e0c07c91ca50f61cc31255a3147ade654976a5989097281892aafd8df595c63bd14f1e03f5955a9398d2dd6368bbcae833ae1cc2df31eb0980b4817dfd130020ffb275743fcc01df40e3ecda1c5988e8e1bde965353b0b1bf34ea05f095000c45b6249618d275905a24d3eb58c600aeab4fb552fbf1ccdb2a5c80ace220310f89829d7e53f78c126037b6d8d500220c7a118d9621b4d6bd5379edd7e24bcf540e87aba6b88862db16fa4ee00b009fda80577be67ab94910fd8a7807dfe4ebe66b8fdcd040aa2dc17ec22639298be56b2a2c9d8940647b75f2f6d81746df16e1cb2f05e23397a8c63baea0803441ff4b7d517ff172980a056726235e2f6af85e8aa9b91ba85f14532272d6170df3166b91169dc09d4f4a251610f57ff0885a93364cfaf650bdf436c89795efed5ca934bc7ffc0a4'),
       +                         packet.to_bytes())
       +        for i, privkey in enumerate(payment_path_privkeys):
       +            processed_packet = lnrouter.process_onion_packet(packet, associated_data, privkey)
       +            self.assertEqual(hops_data[i].per_hop.to_bytes(), processed_packet.hop_data.per_hop.to_bytes())
       +            packet = processed_packet.next_packet
       +
       +    def test_decode_onion_error(self):
       +        # test vector from bolt-04
       +        payment_path_pubkeys = [
       +            bfh('02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619'),
       +            bfh('0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c'),
       +            bfh('027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007'),
       +            bfh('032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991'),
       +            bfh('02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145'),
       +        ]
       +        session_key = bfh('4141414141414141414141414141414141414141414141414141414141414141')
       +        error_packet_for_node_0 = bfh('9c5add3963fc7f6ed7f148623c84134b5647e1306419dbe2174e523fa9e2fbed3a06a19f899145610741c83ad40b7712aefaddec8c6baf7325d92ea4ca4d1df8bce517f7e54554608bf2bd8071a4f52a7a2f7ffbb1413edad81eeea5785aa9d990f2865dc23b4bc3c301a94eec4eabebca66be5cf638f693ec256aec514620cc28ee4a94bd9565bc4d4962b9d3641d4278fb319ed2b84de5b665f307a2db0f7fbb757366067d88c50f7e829138fde4f78d39b5b5802f1b92a8a820865af5cc79f9f30bc3f461c66af95d13e5e1f0381c184572a91dee1c849048a647a1158cf884064deddbf1b0b88dfe2f791428d0ba0f6fb2f04e14081f69165ae66d9297c118f0907705c9c4954a199bae0bb96fad763d690e7daa6cfda59ba7f2c8d11448b604d12d')
       +        decoded_error, index_of_sender = lnrouter._decode_onion_error(error_packet_for_node_0, payment_path_pubkeys, session_key)
       +        self.assertEqual(bfh('4c2fc8bc08510334b6833ad9c3e79cd1b52ae59dfe5c2a4b23ead50f09f7ee0b0002200200fe0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'),
       +                             decoded_error)
       +        self.assertEqual(4, index_of_sender)
 (DIR) diff --git a/lib/tests/test_lnutil.py b/lib/tests/test_lnutil.py
       t@@ -0,0 +1,670 @@
       +import unittest
       +import json
       +from lib import bitcoin, ecc
       +from lib.lnutil import RevocationStore, get_per_commitment_secret_from_seed, make_offered_htlc, make_received_htlc, make_commitment, make_htlc_tx_witness, make_htlc_tx_output, make_htlc_tx_inputs, secret_to_pubkey, derive_blinded_pubkey, derive_privkey, derive_pubkey, make_htlc_tx
       +from lib.util import bh2u, bfh
       +
       +funding_tx_id = '8984484a580b825b9972d7adb15050b3ab624ccd731946b3eeddb92f4e7ef6be'
       +funding_output_index = 0
       +funding_amount_satoshi = 10000000
       +commitment_number = 42
       +local_delay = 144
       +local_dust_limit_satoshi = 546
       +
       +local_payment_basepoint = bytes.fromhex('034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa')
       +remote_payment_basepoint = bytes.fromhex('032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991')
       +# obs = get_obscured_ctn(42, local_payment_basepoint, remote_payment_basepoint)
       +local_funding_privkey = bytes.fromhex('30ff4956bbdd3222d44cc5e8a1261dab1e07957bdac5ae88fe3261ef321f374901')
       +local_funding_pubkey = bytes.fromhex('023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb')
       +remote_funding_pubkey = bytes.fromhex('030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c1')
       +local_privkey = bytes.fromhex('bb13b121cdc357cd2e608b0aea294afca36e2b34cf958e2e6451a2f27469449101')
       +localpubkey = bytes.fromhex('030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e7')
       +remotepubkey = bytes.fromhex('0394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b')
       +local_delayedpubkey = bytes.fromhex('03fd5960528dc152014952efdb702a88f71e3c1653b2314431701ec77e57fde83c')
       +local_revocation_pubkey = bytes.fromhex('0212a140cd0c6539d07cd08dfe09984dec3251ea808b892efeac3ede9402bf2b19')
       +# funding wscript = 5221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae
       +
       +class TestLNUtil(unittest.TestCase):
       +    def test_shachain_store(self):
       +        tests = [
       +            {
       +                "name": "insert_secret correct sequence",
       +                "inserts": [
       +                    {
       +                        "index": 281474976710655,
       +                        "secret": "7cc854b54e3e0dcdb010d7a3fee464a9687b" +\
       +                            "e6e8db3be6854c475621e007a5dc",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710654,
       +                        "secret": "c7518c8ae4660ed02894df8976fa1a3659c1" +\
       +                            "a8b4b5bec0c4b872abeba4cb8964",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710653,
       +                        "secret": "2273e227a5b7449b6e70f1fb4652864038b1" +\
       +                            "cbf9cd7c043a7d6456b7fc275ad8",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710652,
       +                        "secret": "27cddaa5624534cb6cb9d7da077cf2b22ab2" +\
       +                            "1e9b506fd4998a51d54502e99116",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710651,
       +                        "secret": "c65716add7aa98ba7acb236352d665cab173" +\
       +                            "45fe45b55fb879ff80e6bd0c41dd",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710650,
       +                        "secret": "969660042a28f32d9be17344e09374b37996" +\
       +                            "2d03db1574df5a8a5a47e19ce3f2",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710649,
       +                        "secret": "a5a64476122ca0925fb344bdc1854c1c0a59" +\
       +                            "fc614298e50a33e331980a220f32",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710648,
       +                        "secret": "05cde6323d949933f7f7b78776bcc1ea6d9b" +\
       +                            "31447732e3802e1f7ac44b650e17",
       +                        "successful": True
       +                    }
       +                ]
       +            },
       +            {
       +                "name": "insert_secret #1 incorrect",
       +                "inserts": [
       +                    {
       +                        "index": 281474976710655,
       +                        "secret": "02a40c85b6f28da08dfdbe0926c53fab2d" +\
       +                            "e6d28c10301f8f7c4073d5e42e3148",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710654,
       +                        "secret": "c7518c8ae4660ed02894df8976fa1a3659" +\
       +                            "c1a8b4b5bec0c4b872abeba4cb8964",
       +                        "successful": False
       +                    }
       +                ]
       +            },
       +            {
       +                "name": "insert_secret #2 incorrect (#1 derived from incorrect)",
       +                "inserts": [
       +                    {
       +                        "index": 281474976710655,
       +                        "secret": "02a40c85b6f28da08dfdbe0926c53fab2de6" +\
       +                            "d28c10301f8f7c4073d5e42e3148",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710654,
       +                        "secret": "dddc3a8d14fddf2b68fa8c7fbad274827493" +\
       +                            "7479dd0f8930d5ebb4ab6bd866a3",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710653,
       +                        "secret": "2273e227a5b7449b6e70f1fb4652864038b1" +\
       +                            "cbf9cd7c043a7d6456b7fc275ad8",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710652,
       +                        "secret": "27cddaa5624534cb6cb9d7da077cf2b22a" +\
       +                            "b21e9b506fd4998a51d54502e99116",
       +                        "successful": False
       +                    }
       +                ]
       +            },
       +            {
       +                "name": "insert_secret #3 incorrect",
       +                "inserts": [
       +                    {
       +                        "index": 281474976710655,
       +                        "secret": "7cc854b54e3e0dcdb010d7a3fee464a9687b" +\
       +                            "e6e8db3be6854c475621e007a5dc",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710654,
       +                        "secret": "c7518c8ae4660ed02894df8976fa1a3659c1" +\
       +                            "a8b4b5bec0c4b872abeba4cb8964",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710653,
       +                        "secret": "c51a18b13e8527e579ec56365482c62f180b" +\
       +                            "7d5760b46e9477dae59e87ed423a",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710652,
       +                        "secret": "27cddaa5624534cb6cb9d7da077cf2b22ab2" +\
       +                            "1e9b506fd4998a51d54502e99116",
       +                        "successful": False
       +                    }
       +                ]
       +            },
       +            {
       +                "name": "insert_secret #4 incorrect (1,2,3 derived from incorrect)",
       +                "inserts": [
       +                    {
       +                        "index": 281474976710655,
       +                        "secret": "02a40c85b6f28da08dfdbe0926c53fab2de6" +\
       +                            "d28c10301f8f7c4073d5e42e3148",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710654,
       +                        "secret": "dddc3a8d14fddf2b68fa8c7fbad274827493" +\
       +                            "7479dd0f8930d5ebb4ab6bd866a3",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710653,
       +                        "secret": "c51a18b13e8527e579ec56365482c62f18" +\
       +                            "0b7d5760b46e9477dae59e87ed423a",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710652,
       +                        "secret": "ba65d7b0ef55a3ba300d4e87af29868f39" +\
       +                            "4f8f138d78a7011669c79b37b936f4",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710651,
       +                        "secret": "c65716add7aa98ba7acb236352d665cab1" +\
       +                            "7345fe45b55fb879ff80e6bd0c41dd",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710650,
       +                        "secret": "969660042a28f32d9be17344e09374b379" +\
       +                            "962d03db1574df5a8a5a47e19ce3f2",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710649,
       +                        "secret": "a5a64476122ca0925fb344bdc1854c1c0a" +\
       +                            "59fc614298e50a33e331980a220f32",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710649,
       +                        "secret": "05cde6323d949933f7f7b78776bcc1ea6d9b" +\
       +                            "31447732e3802e1f7ac44b650e17",
       +                        "successful": False
       +                    }
       +                ]
       +            },
       +            {
       +                "name": "insert_secret #5 incorrect",
       +                "inserts": [
       +                    {
       +                        "index": 281474976710655,
       +                        "secret": "7cc854b54e3e0dcdb010d7a3fee464a9687b" +\
       +                            "e6e8db3be6854c475621e007a5dc",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710654,
       +                        "secret": "c7518c8ae4660ed02894df8976fa1a3659c1a" +\
       +                            "8b4b5bec0c4b872abeba4cb8964",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710653,
       +                        "secret": "2273e227a5b7449b6e70f1fb4652864038b1" +\
       +                            "cbf9cd7c043a7d6456b7fc275ad8",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710652,
       +                        "secret": "27cddaa5624534cb6cb9d7da077cf2b22ab21" +\
       +                            "e9b506fd4998a51d54502e99116",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710651,
       +                        "secret": "631373ad5f9ef654bb3dade742d09504c567" +\
       +                            "edd24320d2fcd68e3cc47e2ff6a6",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710650,
       +                        "secret": "969660042a28f32d9be17344e09374b37996" +\
       +                            "2d03db1574df5a8a5a47e19ce3f2",
       +                        "successful": False
       +                    }
       +                ]
       +            },
       +            {
       +                "name": "insert_secret #6 incorrect (5 derived from incorrect)",
       +                "inserts": [
       +                    {
       +                        "index": 281474976710655,
       +                        "secret": "7cc854b54e3e0dcdb010d7a3fee464a9687b" +\
       +                            "e6e8db3be6854c475621e007a5dc",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710654,
       +                        "secret": "c7518c8ae4660ed02894df8976fa1a3659c1a" +\
       +                            "8b4b5bec0c4b872abeba4cb8964",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710653,
       +                        "secret": "2273e227a5b7449b6e70f1fb4652864038b1" +\
       +                            "cbf9cd7c043a7d6456b7fc275ad8",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710652,
       +                        "secret": "27cddaa5624534cb6cb9d7da077cf2b22ab21" +\
       +                            "e9b506fd4998a51d54502e99116",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710651,
       +                        "secret": "631373ad5f9ef654bb3dade742d09504c567" +\
       +                            "edd24320d2fcd68e3cc47e2ff6a6",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710650,
       +                        "secret": "b7e76a83668bde38b373970155c868a65330" +\
       +                            "4308f9896692f904a23731224bb1",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710649,
       +                        "secret": "a5a64476122ca0925fb344bdc1854c1c0a59f" +\
       +                            "c614298e50a33e331980a220f32",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710648,
       +                        "secret": "05cde6323d949933f7f7b78776bcc1ea6d9b" +\
       +                            "31447732e3802e1f7ac44b650e17",
       +                        "successful": False
       +                    }
       +                ]
       +            },
       +            {
       +                "name": "insert_secret #7 incorrect",
       +                "inserts": [
       +                    {
       +                        "index": 281474976710655,
       +                        "secret": "7cc854b54e3e0dcdb010d7a3fee464a9687b" +\
       +                            "e6e8db3be6854c475621e007a5dc",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710654,
       +                        "secret": "c7518c8ae4660ed02894df8976fa1a3659c1a" +\
       +                            "8b4b5bec0c4b872abeba4cb8964",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710653,
       +                        "secret": "2273e227a5b7449b6e70f1fb4652864038b1" +\
       +                            "cbf9cd7c043a7d6456b7fc275ad8",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710652,
       +                        "secret": "27cddaa5624534cb6cb9d7da077cf2b22ab21" +\
       +                            "e9b506fd4998a51d54502e99116",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710651,
       +                        "secret": "c65716add7aa98ba7acb236352d665cab173" +\
       +                            "45fe45b55fb879ff80e6bd0c41dd",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710650,
       +                        "secret": "969660042a28f32d9be17344e09374b37996" +\
       +                            "2d03db1574df5a8a5a47e19ce3f2",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710649,
       +                        "secret": "e7971de736e01da8ed58b94c2fc216cb1d" +\
       +                            "ca9e326f3a96e7194fe8ea8af6c0a3",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710648,
       +                        "secret": "05cde6323d949933f7f7b78776bcc1ea6d" +\
       +                            "9b31447732e3802e1f7ac44b650e17",
       +                        "successful": False
       +                    }
       +                ]
       +            },
       +            {
       +                "name": "insert_secret #8 incorrect",
       +                "inserts": [
       +                    {
       +                        "index": 281474976710655,
       +                        "secret": "7cc854b54e3e0dcdb010d7a3fee464a9687b" +\
       +                            "e6e8db3be6854c475621e007a5dc",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710654,
       +                        "secret": "c7518c8ae4660ed02894df8976fa1a3659c1a" +\
       +                            "8b4b5bec0c4b872abeba4cb8964",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710653,
       +                        "secret": "2273e227a5b7449b6e70f1fb4652864038b1" +\
       +                            "cbf9cd7c043a7d6456b7fc275ad8",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710652,
       +                        "secret": "27cddaa5624534cb6cb9d7da077cf2b22ab21" +\
       +                            "e9b506fd4998a51d54502e99116",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710651,
       +                        "secret": "c65716add7aa98ba7acb236352d665cab173" +\
       +                            "45fe45b55fb879ff80e6bd0c41dd",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710650,
       +                        "secret": "969660042a28f32d9be17344e09374b37996" +\
       +                            "2d03db1574df5a8a5a47e19ce3f2",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710649,
       +                        "secret": "a5a64476122ca0925fb344bdc1854c1c0a" +\
       +                            "59fc614298e50a33e331980a220f32",
       +                        "successful": True
       +                    },
       +                    {
       +                        "index": 281474976710648,
       +                        "secret": "a7efbc61aac46d34f77778bac22c8a20c6" +\
       +                            "a46ca460addc49009bda875ec88fa4",
       +                        "successful": False
       +                    }
       +                ]
       +            }
       +        ]
       +
       +        for test in tests:
       +            receiver = RevocationStore()
       +            for insert in test["inserts"]:
       +                secret = bytes.fromhex(insert["secret"])
       +
       +                try:
       +                    receiver.add_next_entry(secret)
       +                except Exception as e:
       +                    if insert["successful"]:
       +                        raise Exception("Failed ({}): error was received but it shouldn't: {}".format(test["name"], e))
       +                else:
       +                    if not insert["successful"]:
       +                        raise Exception("Failed ({}): error wasn't received".format(test["name"]))
       +
       +            print("Passed ({})".format(test["name"]))
       +
       +    def test_shachain_produce_consume(self):
       +        seed = bitcoin.sha256(b"shachaintest")
       +        consumer = RevocationStore()
       +        for i in range(10000):
       +            secret = get_per_commitment_secret_from_seed(seed, 2**48 - i - 1)
       +            try:
       +                consumer.add_next_entry(secret)
       +            except Exception as e:
       +                raise Exception("iteration " + str(i) + ": " + str(e))
       +            if i % 1000 == 0: self.assertEqual(consumer.serialize(), RevocationStore.from_json_obj(json.loads(json.dumps(consumer.serialize()))).serialize())
       +
       +    def test_commitment_tx_with_all_five_HTLCs_untrimmed_minimum_feerate(self):
       +        to_local_msat = 6988000000
       +        to_remote_msat = 3000000000
       +        local_feerate_per_kw = 0
       +        # base commitment transaction fee = 0
       +        # actual commitment transaction fee = 0
       +
       +        per_commitment_secret = 0x1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100
       +        per_commitment_point = (ecc.generator() * per_commitment_secret).get_public_key_bytes()
       +
       +        remote_htlcpubkey = remotepubkey
       +        local_htlcpubkey = localpubkey
       +
       +        htlc2_cltv_timeout = 502
       +        htlc2_payment_preimage = b"\x02" * 32
       +        htlc2 = make_offered_htlc(local_revocation_pubkey, remote_htlcpubkey, local_htlcpubkey, bitcoin.sha256(htlc2_payment_preimage))
       +        # HTLC 2 offered amount 2000
       +        ref_htlc2_wscript = "76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868"
       +        self.assertEqual(htlc2, bfh(ref_htlc2_wscript))
       +
       +        htlc3_cltv_timeout = 503
       +        htlc3_payment_preimage = b"\x03" * 32
       +        htlc3 = make_offered_htlc(local_revocation_pubkey, remote_htlcpubkey, local_htlcpubkey, bitcoin.sha256(htlc3_payment_preimage))
       +        # HTLC 3 offered amount 3000
       +        ref_htlc3_wscript = "76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868"
       +        self.assertEqual(htlc3, bfh(ref_htlc3_wscript))
       +
       +        htlc0_cltv_timeout = 500
       +        htlc0_payment_preimage = b"\x00" * 32
       +        htlc0 = make_received_htlc(local_revocation_pubkey, remote_htlcpubkey, local_htlcpubkey, bitcoin.sha256(htlc0_payment_preimage), htlc0_cltv_timeout)
       +        # HTLC 0 received amount 1000
       +        ref_htlc0_wscript = "76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f401b175ac6868"
       +        self.assertEqual(htlc0, bfh(ref_htlc0_wscript))
       +
       +        htlc1_cltv_timeout = 501
       +        htlc1_payment_preimage = b"\x01" * 32
       +        htlc1 = make_received_htlc(local_revocation_pubkey, remote_htlcpubkey, local_htlcpubkey, bitcoin.sha256(htlc1_payment_preimage), htlc1_cltv_timeout)
       +        # HTLC 1 received amount 2000
       +        ref_htlc1_wscript = "76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac6868"
       +        self.assertEqual(htlc1, bfh(ref_htlc1_wscript))
       +
       +        htlc4_cltv_timeout = 504
       +        htlc4_payment_preimage = b"\x04" * 32
       +        htlc4 = make_received_htlc(local_revocation_pubkey, remote_htlcpubkey, local_htlcpubkey, bitcoin.sha256(htlc4_payment_preimage), htlc4_cltv_timeout)
       +        # HTLC 4 received amount 4000
       +        ref_htlc4_wscript = "76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6868"
       +        self.assertEqual(htlc4, bfh(ref_htlc4_wscript))
       +
       +        # to_local amount 6988000 wscript 63210212a140cd0c6539d07cd08dfe09984dec3251ea808b892efeac3ede9402bf2b1967029000b2752103fd5960528dc152014952efdb702a88f71e3c1653b2314431701ec77e57fde83c68ac
       +        # to_remote amount 3000000 P2WPKH(0394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b)
       +        remote_signature = "304402204fd4928835db1ccdfc40f5c78ce9bd65249b16348df81f0c44328dcdefc97d630220194d3869c38bc732dd87d13d2958015e2fc16829e74cd4377f84d215c0b70606"
       +        # local_signature = 30440220275b0c325a5e9355650dc30c0eccfbc7efb23987c24b556b9dfdd40effca18d202206caceb2c067836c51f296740c7ae807ffcbfbf1dd3a0d56b6de9a5b247985f06
       +        output_commit_tx = "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8007e80300000000000022002052bfef0479d7b293c27e0f1eb294bea154c63a3294ef092c19af51409bce0e2ad007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2db80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110e0a06a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e04004730440220275b0c325a5e9355650dc30c0eccfbc7efb23987c24b556b9dfdd40effca18d202206caceb2c067836c51f296740c7ae807ffcbfbf1dd3a0d56b6de9a5b247985f060147304402204fd4928835db1ccdfc40f5c78ce9bd65249b16348df81f0c44328dcdefc97d630220194d3869c38bc732dd87d13d2958015e2fc16829e74cd4377f84d215c0b7060601475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220"
       +
       +        htlc0_msat = 1000 * 1000
       +        htlc2_msat = 2000 * 1000
       +        htlc3_msat = 3000 * 1000
       +        htlc1_msat = 2000 * 1000
       +        htlc4_msat = 4000 * 1000
       +        htlcs = [(htlc2, htlc2_msat), (htlc3, htlc3_msat), (htlc0, htlc0_msat), (htlc1, htlc1_msat), (htlc4, htlc4_msat)]
       +
       +        our_commit_tx = make_commitment(
       +            commitment_number,
       +            local_funding_pubkey, remote_funding_pubkey, remotepubkey,
       +            local_payment_basepoint, remote_payment_basepoint,
       +            local_revocation_pubkey, local_delayedpubkey, local_delay,
       +            funding_tx_id, funding_output_index, funding_amount_satoshi,
       +            to_local_msat, to_remote_msat, local_dust_limit_satoshi,
       +            local_feerate_per_kw, True, we_are_initiator=True, htlcs=htlcs)
       +        self.sign_and_insert_remote_sig(our_commit_tx, remote_funding_pubkey, remote_signature, local_funding_pubkey, local_funding_privkey)
       +        self.assertEqual(str(our_commit_tx), output_commit_tx)
       +
       +        # (HTLC 0)
       +        signature_for_output_remote_htlc_0 = "304402206a6e59f18764a5bf8d4fa45eebc591566689441229c918b480fb2af8cc6a4aeb02205248f273be447684b33e3c8d1d85a8e0ca9fa0bae9ae33f0527ada9c162919a6"
       +        # (HTLC 2)
       +        signature_for_output_remote_htlc_2 = "3045022100d5275b3619953cb0c3b5aa577f04bc512380e60fa551762ce3d7a1bb7401cff9022037237ab0dac3fe100cde094e82e2bed9ba0ed1bb40154b48e56aa70f259e608b"
       +        # (HTLC 1)
       +        signature_for_output_remote_htlc_1 = "304402201b63ec807771baf4fdff523c644080de17f1da478989308ad13a58b51db91d360220568939d38c9ce295adba15665fa68f51d967e8ed14a007b751540a80b325f202"
       +        # (HTLC 3)
       +        signature_for_output_remote_htlc_3 = "3045022100daee1808f9861b6c3ecd14f7b707eca02dd6bdfc714ba2f33bc8cdba507bb182022026654bf8863af77d74f51f4e0b62d461a019561bb12acb120d3f7195d148a554"
       +        # (HTLC 4)
       +        signature_for_output_remote_htlc_4 = "304402207e0410e45454b0978a623f36a10626ef17b27d9ad44e2760f98cfa3efb37924f0220220bd8acd43ecaa916a80bd4f919c495a2c58982ce7c8625153f8596692a801d"
       +
       +
       +        local_signature_htlc0 = "304402207cb324fa0de88f452ffa9389678127ebcf4cabe1dd848b8e076c1a1962bf34720220116ed922b12311bd602d67e60d2529917f21c5b82f25ff6506c0f87886b4dfd5" # derive ourselves
       +        output_htlc_success_tx_0 = "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219700000000000000000001e8030000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402206a6e59f18764a5bf8d4fa45eebc591566689441229c918b480fb2af8cc6a4aeb02205248f273be447684b33e3c8d1d85a8e0ca9fa0bae9ae33f0527ada9c162919a60147304402207cb324fa0de88f452ffa9389678127ebcf4cabe1dd848b8e076c1a1962bf34720220116ed922b12311bd602d67e60d2529917f21c5b82f25ff6506c0f87886b4dfd5012000000000000000000000000000000000000000000000000000000000000000008a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f401b175ac686800000000"
       +
       +        local_signature_htlc2 = "3045022100c89172099507ff50f4c925e6c5150e871fb6e83dd73ff9fbb72f6ce829a9633f02203a63821d9162e99f9be712a68f9e589483994feae2661e4546cd5b6cec007be5"
       +        output_htlc_timeout_tx_2 = "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219701000000000000000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d5275b3619953cb0c3b5aa577f04bc512380e60fa551762ce3d7a1bb7401cff9022037237ab0dac3fe100cde094e82e2bed9ba0ed1bb40154b48e56aa70f259e608b01483045022100c89172099507ff50f4c925e6c5150e871fb6e83dd73ff9fbb72f6ce829a9633f02203a63821d9162e99f9be712a68f9e589483994feae2661e4546cd5b6cec007be501008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000"
       +
       +        local_signature_htlc1 = "3045022100def389deab09cee69eaa1ec14d9428770e45bcbe9feb46468ecf481371165c2f022015d2e3c46600b2ebba8dcc899768874cc6851fd1ecb3fffd15db1cc3de7e10da"
       +        output_htlc_success_tx_1 = "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219702000000000000000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402201b63ec807771baf4fdff523c644080de17f1da478989308ad13a58b51db91d360220568939d38c9ce295adba15665fa68f51d967e8ed14a007b751540a80b325f20201483045022100def389deab09cee69eaa1ec14d9428770e45bcbe9feb46468ecf481371165c2f022015d2e3c46600b2ebba8dcc899768874cc6851fd1ecb3fffd15db1cc3de7e10da012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000"
       +
       +        local_signature_htlc3 = "30440220643aacb19bbb72bd2b635bc3f7375481f5981bace78cdd8319b2988ffcc6704202203d27784ec8ad51ed3bd517a05525a5139bb0b755dd719e0054332d186ac08727"
       +        output_htlc_timeout_tx_3 = "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219703000000000000000001b80b0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100daee1808f9861b6c3ecd14f7b707eca02dd6bdfc714ba2f33bc8cdba507bb182022026654bf8863af77d74f51f4e0b62d461a019561bb12acb120d3f7195d148a554014730440220643aacb19bbb72bd2b635bc3f7375481f5981bace78cdd8319b2988ffcc6704202203d27784ec8ad51ed3bd517a05525a5139bb0b755dd719e0054332d186ac0872701008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000"
       +
       +        local_signature_htlc4 = "30440220549e80b4496803cbc4a1d09d46df50109f546d43fbbf86cd90b174b1484acd5402205f12a4f995cb9bded597eabfee195a285986aa6d93ae5bb72507ebc6a4e2349e"
       +        output_htlc_success_tx_4 = "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219704000000000000000001a00f0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402207e0410e45454b0978a623f36a10626ef17b27d9ad44e2760f98cfa3efb37924f0220220bd8acd43ecaa916a80bd4f919c495a2c58982ce7c8625153f8596692a801d014730440220549e80b4496803cbc4a1d09d46df50109f546d43fbbf86cd90b174b1484acd5402205f12a4f995cb9bded597eabfee195a285986aa6d93ae5bb72507ebc6a4e2349e012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000"
       +
       +        def test_htlc_tx(htlc, htlc_output_index, amount_msat, ref_local_sig, htlc_payment_preimage, remote_htlc_sig, ref_tx, success, cltv_timeout):
       +            our_htlc_tx_output = make_htlc_tx_output(
       +                amount_msat=amount_msat,
       +                local_feerate=local_feerate_per_kw,
       +                revocationpubkey=local_revocation_pubkey,
       +                local_delayedpubkey=local_delayedpubkey,
       +                success=success,
       +                to_self_delay=local_delay)
       +            our_htlc_tx_inputs = make_htlc_tx_inputs(
       +                htlc_output_txid=our_commit_tx.txid(),
       +                htlc_output_index=htlc_output_index,
       +                revocationpubkey=local_revocation_pubkey,
       +                local_delayedpubkey=local_delayedpubkey,
       +                amount_msat=amount_msat,
       +                witness_script=bh2u(htlc))
       +            our_htlc_tx = make_htlc_tx(cltv_timeout,
       +                inputs=our_htlc_tx_inputs,
       +                output=our_htlc_tx_output)
       +
       +            local_sig = our_htlc_tx.sign_txin(0, local_privkey[:-1])
       +            #self.assertEqual(ref_local_sig + "01", local_sig)  # commented out as it is sufficient to compare the serialized txn
       +
       +            our_htlc_tx_witness = make_htlc_tx_witness(  # FIXME only correct for success=True
       +                remotehtlcsig=bfh(remote_htlc_sig) + b"\x01",  # 0x01 is SIGHASH_ALL
       +                localhtlcsig=bfh(local_sig),
       +                payment_preimage=htlc_payment_preimage if success else b'',  # will put 00 on witness if timeout
       +                witness_script=htlc)
       +            our_htlc_tx._inputs[0]['witness'] = bh2u(our_htlc_tx_witness)
       +            self.assertEqual(ref_tx, str(our_htlc_tx))
       +
       +        test_htlc_tx(htlc=htlc0, htlc_output_index=0,
       +                     amount_msat=htlc0_msat,
       +                     ref_local_sig=local_signature_htlc0,
       +                     htlc_payment_preimage=htlc0_payment_preimage,
       +                     remote_htlc_sig=signature_for_output_remote_htlc_0,
       +                     ref_tx=output_htlc_success_tx_0,
       +                     success=True, cltv_timeout=0)
       +        test_htlc_tx(htlc=htlc1, htlc_output_index=2,
       +                     amount_msat=htlc1_msat,
       +                     ref_local_sig=local_signature_htlc1,
       +                     htlc_payment_preimage=htlc1_payment_preimage,
       +                     remote_htlc_sig=signature_for_output_remote_htlc_1,
       +                     ref_tx=output_htlc_success_tx_1,
       +                     success=True, cltv_timeout=0)
       +        test_htlc_tx(htlc=htlc2,  htlc_output_index=1,
       +                     amount_msat=htlc2_msat,
       +                     ref_local_sig=local_signature_htlc2,
       +                     htlc_payment_preimage=htlc2_payment_preimage,
       +                     remote_htlc_sig=signature_for_output_remote_htlc_2,
       +                     ref_tx=output_htlc_timeout_tx_2,
       +                     success=False, cltv_timeout=htlc2_cltv_timeout)
       +        test_htlc_tx(htlc=htlc3,  htlc_output_index=3,
       +                     amount_msat=htlc3_msat,
       +                     ref_local_sig=local_signature_htlc3,
       +                     htlc_payment_preimage=htlc3_payment_preimage,
       +                     remote_htlc_sig=signature_for_output_remote_htlc_3,
       +                     ref_tx=output_htlc_timeout_tx_3,
       +                     success=False, cltv_timeout=htlc3_cltv_timeout)
       +        test_htlc_tx(htlc=htlc4,  htlc_output_index=4,
       +                     amount_msat=htlc4_msat,
       +                     ref_local_sig=local_signature_htlc4,
       +                     htlc_payment_preimage=htlc4_payment_preimage,
       +                     remote_htlc_sig=signature_for_output_remote_htlc_4,
       +                     ref_tx=output_htlc_success_tx_4,
       +                     success=True, cltv_timeout=0)
       +
       +    def test_per_commitment_secret_from_seed(self):
       +        self.assertEqual(0x02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148.to_bytes(byteorder="big", length=32),
       +                         get_per_commitment_secret_from_seed(0x0000000000000000000000000000000000000000000000000000000000000000.to_bytes(byteorder="big", length=32), 281474976710655))
       +        self.assertEqual(0x7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc.to_bytes(byteorder="big", length=32),
       +                         get_per_commitment_secret_from_seed(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.to_bytes(byteorder="big", length=32), 281474976710655))
       +        self.assertEqual(0x56f4008fb007ca9acf0e15b054d5c9fd12ee06cea347914ddbaed70d1c13a528.to_bytes(byteorder="big", length=32),
       +                         get_per_commitment_secret_from_seed(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.to_bytes(byteorder="big", length=32), 0xaaaaaaaaaaa))
       +        self.assertEqual(0x9015daaeb06dba4ccc05b91b2f73bd54405f2be9f217fbacd3c5ac2e62327d31.to_bytes(byteorder="big", length=32),
       +                         get_per_commitment_secret_from_seed(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.to_bytes(byteorder="big", length=32), 0x555555555555))
       +        self.assertEqual(0x915c75942a26bb3a433a8ce2cb0427c29ec6c1775cfc78328b57f6ba7bfeaa9c.to_bytes(byteorder="big", length=32),
       +                         get_per_commitment_secret_from_seed(0x0101010101010101010101010101010101010101010101010101010101010101.to_bytes(byteorder="big", length=32), 1))
       +
       +    def test_key_derivation(self):
       +        # BOLT3, Appendix E
       +        base_secret = 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
       +        per_commitment_secret = 0x1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100
       +        revocation_basepoint_secret = 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
       +        base_point = secret_to_pubkey(base_secret)
       +        self.assertEqual(base_point, bfh('036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2'))
       +        per_commitment_point = secret_to_pubkey(per_commitment_secret)
       +        self.assertEqual(per_commitment_point, bfh('025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486'))
       +        localpubkey = derive_pubkey(base_point, per_commitment_point)
       +        self.assertEqual(localpubkey, bfh('0235f2dbfaa89b57ec7b055afe29849ef7ddfeb1cefdb9ebdc43f5494984db29e5'))
       +        localprivkey = derive_privkey(base_secret, per_commitment_point)
       +        self.assertEqual(localprivkey, 0xcbced912d3b21bf196a766651e436aff192362621ce317704ea2f75d87e7be0f)
       +        revocation_basepoint = secret_to_pubkey(revocation_basepoint_secret)
       +        self.assertEqual(revocation_basepoint, bfh('036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2'))
       +        revocationpubkey = derive_blinded_pubkey(revocation_basepoint, per_commitment_point)
       +        self.assertEqual(revocationpubkey, bfh('02916e326636d19c33f13e8c0c3a03dd157f332f3e99c317c141dd865eb01f8ff0'))
       +
       +    def test_simple_commitment_tx_with_no_HTLCs(self):
       +        to_local_msat = 7000000000
       +        to_remote_msat = 3000000000
       +        local_feerate_per_kw = 15000
       +        # base commitment transaction fee = 10860
       +        # actual commitment transaction fee = 10860
       +        # to_local amount 6989140 wscript 63210212a140cd0c6539d07cd08dfe09984dec3251ea808b892efeac3ede9402bf2b1967029000b2752103fd5960528dc152014952efdb702a88f71e3c1653b2314431701ec77e57fde83c68ac
       +        # to_remote amount 3000000 P2WPKH(0394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b)
       +        remote_signature = "3045022100f51d2e566a70ba740fc5d8c0f07b9b93d2ed741c3c0860c613173de7d39e7968022041376d520e9c0e1ad52248ddf4b22e12be8763007df977253ef45a4ca3bdb7c0"
       +        # local_signature = 3044022051b75c73198c6deee1a875871c3961832909acd297c6b908d59e3319e5185a46022055c419379c5051a78d00dbbce11b5b664a0c22815fbcc6fcef6b1937c3836939
       +        htlcs=[]
       +        our_commit_tx = make_commitment(
       +            commitment_number,
       +            local_funding_pubkey, remote_funding_pubkey, remotepubkey,
       +            local_payment_basepoint, remote_payment_basepoint,
       +            local_revocation_pubkey, local_delayedpubkey, local_delay,
       +            funding_tx_id, funding_output_index, funding_amount_satoshi,
       +            to_local_msat, to_remote_msat, local_dust_limit_satoshi,
       +            local_feerate_per_kw, True, we_are_initiator=True, htlcs=[])
       +        self.sign_and_insert_remote_sig(our_commit_tx, remote_funding_pubkey, remote_signature, local_funding_pubkey, local_funding_privkey)
       +        ref_commit_tx_str = '02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8002c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de84311054a56a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400473044022051b75c73198c6deee1a875871c3961832909acd297c6b908d59e3319e5185a46022055c419379c5051a78d00dbbce11b5b664a0c22815fbcc6fcef6b1937c383693901483045022100f51d2e566a70ba740fc5d8c0f07b9b93d2ed741c3c0860c613173de7d39e7968022041376d520e9c0e1ad52248ddf4b22e12be8763007df977253ef45a4ca3bdb7c001475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220'
       +        self.assertEqual(str(our_commit_tx), ref_commit_tx_str)
       +
       +    def sign_and_insert_remote_sig(self, tx, remote_pubkey, remote_signature, pubkey, privkey):
       +        assert type(remote_pubkey) is bytes
       +        assert len(remote_pubkey) == 33
       +        assert type(remote_signature) is str
       +        assert type(pubkey) is bytes
       +        assert type(privkey) is bytes
       +        assert len(pubkey) == 33
       +        assert len(privkey) == 33
       +        tx.sign({bh2u(pubkey): (privkey[:-1], True)})
       +        pubkeys, _x_pubkeys = tx.get_sorted_pubkeys(tx.inputs()[0])
       +        index_of_pubkey = pubkeys.index(bh2u(remote_pubkey))
       +        tx._inputs[0]["signatures"][index_of_pubkey] = remote_signature + "01"
       +        tx.raw = None