示例#1
0
def test_open_channel_bad_type(runner: Runner, with_proposal: Any) -> None:
    """Tests for https://github.com/lightningnetwork/lightning-rfc/pull/880"""
    with_proposal(channel_type_csv)

    # This is not a feature bit, so use support_ to mark it.
    if runner.has_option('supports_open_accept_channel_types') is None:
        pytest.skip('Needs supports_open_accept_channel_types')

    local_funding_privkey = '20'

    local_keyset = KeySet(revocation_base_secret='21',
                          payment_base_secret='22',
                          htlc_base_secret='24',
                          delayed_payment_base_secret='23',
                          shachain_seed='00' * 32)

    test = [
        Block(blockheight=102, txs=[tx_spendable]),
        Connect(connprivkey='02'),
        ExpectMsg('init'),
        TryAll(
            # BOLT-a12da24dd0102c170365124782b46d9710950ac1 #9:
            # | 20/21 | `option_anchor_outputs`          | Anchor outputs
            Msg('init', globalfeatures='', features=bitfield(13, 21)),
            # BOLT #9:
            # | 12/13 | `option_static_remotekey`        | Static key for remote output
            Msg('init', globalfeatures='', features=bitfield(13)),
            # And not.
            Msg('init', globalfeatures='', features='')),
        Msg(
            'open_channel',
            chain_hash=regtest_hash,
            temporary_channel_id='00' * 32,
            funding_satoshis=funding_amount_for_utxo(0),
            push_msat=0,
            dust_limit_satoshis=546,
            max_htlc_value_in_flight_msat=4294967295,
            channel_reserve_satoshis=9998,
            htlc_minimum_msat=0,
            feerate_per_kw=253,
            # We use 5, because c-lightning runner uses 6, so this is different.
            to_self_delay=5,
            max_accepted_htlcs=483,
            funding_pubkey=pubkey_of(local_funding_privkey),
            revocation_basepoint=local_keyset.revocation_basepoint(),
            payment_basepoint=local_keyset.payment_basepoint(),
            delayed_payment_basepoint=local_keyset.delayed_payment_basepoint(),
            htlc_basepoint=local_keyset.htlc_basepoint(),
            first_per_commitment_point=local_keyset.per_commit_point(0),
            channel_flags=1,
            tlvs='{channel_types={types=[{features=' + bitfield(1) + '}]}}'),

        # BOLT #2
        # The receiving node MUST fail the channel if:
        #   - It supports `channel_types` and none of the `channel_types`
        #     are suitable.
        ExpectError()
    ]

    runner.run(test)
示例#2
0
def test_unknowns(runner: Runner, namespaceoverride: Any) -> None:
    # We override default namespace since we only need BOLT1
    namespaceoverride(pyln.spec.bolt1.namespace)
    test = [
        Connect(connprivkey='03'),
        ExpectMsg('init'),
        Msg('init', globalfeatures='', features=''),
        TryAll(
            [],
            # BOLT #1:
            # A receiving node:
            #   - upon receiving a message of _odd_, unknown type:
            #     - MUST ignore the received message.
            [RawMsg(bytes.fromhex('270F'))],

            # BOLT #1:
            # A receiving node:...
            #   - upon receiving a message of _even_, unknown type:
            #     - MUST close the connection.
            #     - MAY fail the channels.
            [RawMsg(bytes.fromhex('2710')),
             ExpectError()])
    ]

    runner.run(test)
示例#3
0
def test_open_channel(runner: Runner) -> None:
    local_funding_privkey = '20'

    local_keyset = KeySet(revocation_base_secret='21',
                          payment_base_secret='22',
                          htlc_base_secret='24',
                          delayed_payment_base_secret='23',
                          shachain_seed='00' * 32)

    test = [Block(blockheight=102, txs=[tx_spendable]),
            Connect(connprivkey='02'),
            ExpectMsg('init'),

            TryAll(
                # BOLT #9:
                # | 12/13 | `option_static_remotekey`        | Static key for remote output
                Msg('init', globalfeatures='', features=bitfield(13)),
                # And not.
                Msg('init', globalfeatures='', features='')),

            TryAll(
                # Accepter side: we initiate a new channel.
                [Msg('open_channel',
                     chain_hash=regtest_hash,
                     temporary_channel_id='00' * 32,
                     funding_satoshis=funding_amount_for_utxo(0),
                     push_msat=0,
                     dust_limit_satoshis=546,
                     max_htlc_value_in_flight_msat=4294967295,
                     channel_reserve_satoshis=9998,
                     htlc_minimum_msat=0,
                     feerate_per_kw=253,
                     # We use 5, because c-lightning runner uses 6, so this is different.
                     to_self_delay=5,
                     max_accepted_htlcs=483,
                     funding_pubkey=pubkey_of(local_funding_privkey),
                     revocation_basepoint=local_keyset.revocation_basepoint(),
                     payment_basepoint=local_keyset.payment_basepoint(),
                     delayed_payment_basepoint=local_keyset.delayed_payment_basepoint(),
                     htlc_basepoint=local_keyset.htlc_basepoint(),
                     first_per_commitment_point=local_keyset.per_commit_point(0),
                     channel_flags=1),

                 # Ignore unknown odd messages
                 TryAll([], RawMsg(bytes.fromhex('270F'))),

                 ExpectMsg('accept_channel',
                           temporary_channel_id=sent(),
                           funding_pubkey=remote_funding_pubkey(),
                           revocation_basepoint=remote_revocation_basepoint(),
                           payment_basepoint=remote_payment_basepoint(),
                           delayed_payment_basepoint=remote_delayed_payment_basepoint(),
                           htlc_basepoint=remote_htlc_basepoint(),
                           first_per_commitment_point=remote_per_commitment_point(0),
                           minimum_depth=3,
                           channel_reserve_satoshis=9998),

                 # Ignore unknown odd messages
                 TryAll([], RawMsg(bytes.fromhex('270F'))),

                 # Create and stash Funding object and FundingTx
                 CreateFunding(*utxo(0),
                               local_node_privkey='02',
                               local_funding_privkey=local_funding_privkey,
                               remote_node_privkey=runner.get_node_privkey(),
                               remote_funding_privkey=remote_funding_privkey()),

                 Commit(funding=funding(),
                        opener=Side.local,
                        local_keyset=local_keyset,
                        local_to_self_delay=rcvd('to_self_delay', int),
                        remote_to_self_delay=sent('to_self_delay', int),
                        local_amount=msat(sent('funding_satoshis', int)),
                        remote_amount=0,
                        local_dust_limit=546,
                        remote_dust_limit=546,
                        feerate=253,
                        local_features=sent('init.features'),
                        remote_features=rcvd('init.features')),

                 Msg('funding_created',
                     temporary_channel_id=rcvd(),
                     funding_txid=funding_txid(),
                     funding_output_index=0,
                     signature=commitsig_to_send()),

                 ExpectMsg('funding_signed',
                           channel_id=channel_id(),
                           signature=commitsig_to_recv()),

                 # Mine it and get it deep enough to confirm channel.
                 Block(blockheight=103, number=3, txs=[funding_tx()]),

                 ExpectMsg('funding_locked',
                           channel_id=channel_id(),
                           next_per_commitment_point='032405cbd0f41225d5f203fe4adac8401321a9e05767c5f8af97d51d2e81fbb206'),

                 Msg('funding_locked',
                     channel_id=channel_id(),
                     next_per_commitment_point='027eed8389cf8eb715d73111b73d94d2c2d04bf96dc43dfd5b0970d80b3617009d'),

                 # Ignore unknown odd messages
                 TryAll([], RawMsg(bytes.fromhex('270F')))],

                # Now we test the 'opener' side of an open_channel (node initiates)
                [FundChannel(amount=999877),

                 # This gives a channel of 999877sat
                 ExpectMsg('open_channel',
                           chain_hash=regtest_hash,
                           funding_satoshis=999877,
                           push_msat=0,
                           dust_limit_satoshis=546,
                           htlc_minimum_msat=0,
                           channel_reserve_satoshis=9998,
                           to_self_delay=6,
                           funding_pubkey=remote_funding_pubkey(),
                           revocation_basepoint=remote_revocation_basepoint(),
                           payment_basepoint=remote_payment_basepoint(),
                           delayed_payment_basepoint=remote_delayed_payment_basepoint(),
                           htlc_basepoint=remote_htlc_basepoint(),
                           first_per_commitment_point=remote_per_commitment_point(0),
                           # FIXME: Check more fields!
                           channel_flags='01'),

                 Msg('accept_channel',
                     temporary_channel_id=rcvd(),
                     dust_limit_satoshis=546,
                     max_htlc_value_in_flight_msat=4294967295,
                     channel_reserve_satoshis=9998,
                     htlc_minimum_msat=0,
                     minimum_depth=3,
                     max_accepted_htlcs=483,
                     # We use 5, because c-lightning runner uses 6, so this is different.
                     to_self_delay=5,
                     funding_pubkey=pubkey_of(local_funding_privkey),
                     revocation_basepoint=local_keyset.revocation_basepoint(),
                     payment_basepoint=local_keyset.payment_basepoint(),
                     delayed_payment_basepoint=local_keyset.delayed_payment_basepoint(),
                     htlc_basepoint=local_keyset.htlc_basepoint(),
                     first_per_commitment_point=local_keyset.per_commit_point(0)),

                 # Ignore unknown odd messages
                 TryAll([], RawMsg(bytes.fromhex('270F'))),

                 ExpectMsg('funding_created',
                           temporary_channel_id=rcvd('temporary_channel_id')),

                 # Now we can finally stash the funding information.
                 AcceptFunding(rcvd('funding_created.funding_txid'),
                               funding_output_index=rcvd('funding_created.funding_output_index', int),
                               funding_amount=rcvd('open_channel.funding_satoshis', int),
                               local_node_privkey='02',
                               local_funding_privkey=local_funding_privkey,
                               remote_node_privkey=runner.get_node_privkey(),
                               remote_funding_privkey=remote_funding_privkey()),

                 Commit(funding=funding(),
                        opener=Side.remote,
                        local_keyset=local_keyset,
                        local_to_self_delay=rcvd('open_channel.to_self_delay', int),
                        remote_to_self_delay=sent('accept_channel.to_self_delay', int),
                        local_amount=0,
                        remote_amount=msat(rcvd('open_channel.funding_satoshis', int)),
                        local_dust_limit=sent('accept_channel.dust_limit_satoshis', int),
                        remote_dust_limit=rcvd('open_channel.dust_limit_satoshis', int),
                        feerate=rcvd('open_channel.feerate_per_kw', int),
                        local_features=sent('init.features'),
                        remote_features=rcvd('init.features')),

                 # Now we've created commit, we can check sig is valid!
                 CheckEq(rcvd('funding_created.signature'), commitsig_to_recv()),

                 Msg('funding_signed',
                     channel_id=channel_id(),
                     signature=commitsig_to_send()),

                 # It will broadcast tx
                 ExpectTx(rcvd('funding_created.funding_txid')),

                 # Mine three blocks to confirm channel.
                 Block(blockheight=103, number=3),

                 Msg('funding_locked',
                     channel_id=sent(),
                     next_per_commitment_point=local_keyset.per_commit_point(1)),

                 ExpectMsg('funding_locked',
                           channel_id=sent(),
                           next_per_commitment_point=remote_per_commitment_point(1)),

                 # Ignore unknown odd messages
                 TryAll([], RawMsg(bytes.fromhex('270F'))),
                 ])]

    runner.run(test)
示例#4
0
def test_init(runner: Runner, namespaceoverride: Any) -> None:
    # We override default namespace since we only need BOLT1
    namespaceoverride(pyln.spec.bolt1.namespace)
    test = [
        Connect(connprivkey='03'),
        ExpectMsg('init'),
        Msg('init', globalfeatures='', features=''),

        # optionally disconnect that first one
        TryAll([], Disconnect()),
        Connect(connprivkey='02'),
        TryAll(
            # Even if we don't send anything, it should send init.
            [ExpectMsg('init')],

            # Minimal possible init message.
            # BOLT #1:
            # The sending node:
            #  - MUST send `init` as the first Lightning message for any connection.
            [ExpectMsg('init'),
             Msg('init', globalfeatures='', features='')],

            # BOLT #1:
            # The sending node:...
            #  - SHOULD NOT set features greater than 13 in `globalfeatures`.
            [
                ExpectMsg('init', if_match=no_gf13),
                # BOLT #1:
                # The receiving node:...
                #  - upon receiving unknown _odd_ feature bits that are non-zero:
                #    - MUST ignore the bit.

                # init msg with unknown odd global bit (99): no error
                Msg('init', globalfeatures=bitfield(99), features='')
            ],

            # Sanity check that bits 34 and 35 are not used!
            [
                ExpectMsg('init',
                          if_match=functools.partial(no_feature, [34, 35])),
                # BOLT #1:
                # The receiving node:...
                #  - upon receiving unknown _odd_ feature bits that are non-zero:
                #    - MUST ignore the bit.

                # init msg with unknown odd local bit (99): no error
                Msg('init', globalfeatures='', features=bitfield(99))
            ],

            # BOLT #1:
            # The receiving node: ...
            #  - upon receiving unknown _even_ feature bits that are non-zero:
            #    - MUST fail the connection.
            [
                ExpectMsg('init'),
                Msg('init', globalfeatures='', features=bitfield(34)),
                ExpectError()
            ],

            # init msg with unknown even global bit (34): you will error
            [
                ExpectMsg('init'),
                Msg('init', globalfeatures=bitfield(34), features=''),
                ExpectError()
            ],

            # If you don't support `option_data_loss_protect`, you will be ok if
            # we ask for it.
            Sequence([
                ExpectMsg('init',
                          if_match=functools.partial(no_feature, [0, 1])),
                Msg('init', globalfeatures='', features=bitfield(1))
            ],
                     enable=not runner.has_option('option_data_loss_protect')),

            # If you don't support `option_data_loss_protect`, you will error if
            # we require it.
            Sequence([
                ExpectMsg('init',
                          if_match=functools.partial(no_feature, [0, 1])),
                Msg('init', globalfeatures='', features=bitfield(0)),
                ExpectError()
            ],
                     enable=not runner.has_option('option_data_loss_protect')),

            # If you support `option_data_loss_protect`, you will advertize it odd.
            Sequence(
                [
                    ExpectMsg('init',
                              if_match=functools.partial(has_feature, [1]))
                ],
                enable=(
                    runner.has_option('option_data_loss_protect') == 'odd')),

            # If you require `option_data_loss_protect`, you will advertize it even.
            Sequence(
                [
                    ExpectMsg('init',
                              if_match=functools.partial(has_feature, [0]))
                ],
                enable=(
                    runner.has_option('option_data_loss_protect') == 'even')),

            # If you don't support `option_anchor_outputs`, you will be ok if
            # we ask for it.
            Sequence([
                ExpectMsg('init',
                          if_match=functools.partial(no_feature, [20, 21])),
                Msg('init', globalfeatures='', features=bitfield(21))
            ],
                     enable=not runner.has_option('option_anchor_outputs')),

            # If you don't support `option_anchor_outputs`, you will error if
            # we require it.
            Sequence([
                ExpectMsg('init',
                          if_match=functools.partial(no_feature, [20, 21])),
                Msg('init', globalfeatures='', features=bitfield(20)),
                ExpectError()
            ],
                     enable=not runner.has_option('option_anchor_outputs')),

            # If you support `option_anchor_outputs`, you will advertize it odd.
            Sequence(
                [
                    ExpectMsg('init',
                              if_match=functools.partial(has_feature, [21]))
                ],
                enable=(runner.has_option('option_anchor_outputs') == 'odd')),

            # If you require `option_anchor_outputs`, you will advertize it even.
            Sequence(
                [
                    ExpectMsg('init',
                              if_match=functools.partial(has_feature, [20]))
                ],
                enable=(runner.has_option('option_anchor_outputs') == 'even')),

            # BOLT-a12da24dd0102c170365124782b46d9710950ac1 #9:
            # | Bits  | Name                    | ... | Dependencies
            # ...
            # | 12/13 | `option_static_remotekey` |
            # ...
            # | 20/21 | `option_anchor_outputs` | ... | `option_static_remotekey` |

            # If you support `option_anchor_outputs`, you will
            # advertize option_static_remotekey.
            Sequence([
                ExpectMsg('init',
                          if_match=functools.partial(has_one_feature,
                                                     [12, 13]))
            ],
                     enable=(runner.has_option('option_anchor_outputs')
                             is not None)),

            # You should always handle us echoing your own features back!
            [
                ExpectMsg('init'),
                Msg('init', globalfeatures=rcvd(), features=rcvd())
            ],
        )
    ]

    runner.run(test)
示例#5
0
def test_query_channel_range(runner: Runner) -> None:
    if runner.has_option('option_gossip_queries') is None:
        unittest.SkipTest('Needs option_gossip_queries')

    funding1, funding1_tx = Funding.from_utxo(*utxo(0),
                                              local_node_privkey='02',
                                              local_funding_privkey='10',
                                              remote_node_privkey='03',
                                              remote_funding_privkey='20')

    funding2, funding2_tx = Funding.from_utxo(*utxo(1),
                                              local_node_privkey='04',
                                              local_funding_privkey='30',
                                              remote_node_privkey='05',
                                              remote_funding_privkey='40')

    timestamp_103x1x0_LOCAL = int(time.time())
    timestamp_109x1x0_LOCAL = timestamp_103x1x0_LOCAL - 1
    timestamp_109x1x0_REMOTE = timestamp_109x1x0_LOCAL - 1

    ts_103x1x0 = encode_timestamps(
        *funding1.node_id_sort(timestamp_103x1x0_LOCAL, 0))
    ts_109x1x0 = encode_timestamps(*funding2.node_id_sort(
        timestamp_109x1x0_LOCAL, timestamp_109x1x0_REMOTE))

    update_103x1x0_LOCAL = funding1.channel_update(
        side=Side.local,
        short_channel_id='103x1x0',
        disable=False,
        cltv_expiry_delta=144,
        htlc_minimum_msat=0,
        fee_base_msat=1000,
        fee_proportional_millionths=10,
        timestamp=timestamp_103x1x0_LOCAL,
        htlc_maximum_msat=None)
    update_109x1x0_LOCAL = funding2.channel_update(
        side=Side.local,
        short_channel_id='109x1x0',
        disable=False,
        cltv_expiry_delta=144,
        htlc_minimum_msat=0,
        fee_base_msat=1000,
        fee_proportional_millionths=10,
        timestamp=timestamp_109x1x0_LOCAL,
        htlc_maximum_msat=None)
    update_109x1x0_REMOTE = funding2.channel_update(
        side=Side.remote,
        short_channel_id='109x1x0',
        disable=False,
        cltv_expiry_delta=144,
        htlc_minimum_msat=0,
        fee_base_msat=1000,
        fee_proportional_millionths=10,
        timestamp=timestamp_109x1x0_REMOTE,
        htlc_maximum_msat=None)

    csums_103x1x0 = update_checksums(
        *funding1.node_id_sort(update_103x1x0_LOCAL, None))
    csums_109x1x0 = update_checksums(
        *funding2.node_id_sort(update_109x1x0_LOCAL, update_109x1x0_REMOTE))

    test = [
        Block(blockheight=102, txs=[tx_spendable]),
        # Channel 103x1x0 (between 002 and 003)
        Block(blockheight=103, number=6, txs=[funding1_tx]),
        # Channel 109x1x0 (between 004 and 005)
        Block(blockheight=109, number=6, txs=[funding2_tx]),
        Connect(connprivkey='03'),
        ExpectMsg('init'),
        Msg('init', globalfeatures='', features=''),
        RawMsg(funding1.channel_announcement('103x1x0', '')),
        RawMsg(update_103x1x0_LOCAL),
        RawMsg(funding2.channel_announcement('109x1x0', '')),
        RawMsg(update_109x1x0_LOCAL),
        RawMsg(update_109x1x0_REMOTE),

        # c-lightning gets a race condition if we dont wait for
        # these updates to be added to the gossip store
        # FIXME: convert to explicit signal
        Wait(0.7),

        # New peer connects, with gossip_query option.
        Connect(connprivkey='05'),
        ExpectMsg('init'),
        # BOLT #9:
        # | 6/7   | `gossip_queries`                 | More sophisticated gossip control
        Msg('init', globalfeatures='', features=bitfield(7)),
        TryAll(
            # No queries?  Must not get anything.
            [
                MustNotMsg('channel_announcement'),
                MustNotMsg('channel_update'),
                MustNotMsg('node_announcement')
            ],

            # This should elicit an empty response
            [
                Msg('query_channel_range',
                    chain_hash=regtest_hash,
                    first_blocknum=0,
                    number_of_blocks=103),
                ExpectMsg('reply_channel_range',
                          chain_hash=regtest_hash,
                          first_blocknum=0,
                          number_of_blocks=103),
                CheckEq(decode_scids, '')
            ],

            # This should get the first one, not the second.
            [
                Msg('query_channel_range',
                    chain_hash=regtest_hash,
                    first_blocknum=103,
                    number_of_blocks=1),
                ExpectMsg('reply_channel_range',
                          chain_hash=regtest_hash,
                          first_blocknum=103,
                          number_of_blocks=1),
                CheckEq(decode_scids, '103x1x0')
            ],

            # This should get the second one, not the first.
            [
                Msg('query_channel_range',
                    chain_hash=regtest_hash,
                    first_blocknum=109,
                    number_of_blocks=4294967295),
                OneOf(
                    ExpectMsg('reply_channel_range',
                              chain_hash=regtest_hash,
                              first_blocknum=109,
                              number_of_blocks=4294967186),
                    # Could truncate number_of_blocks.
                    ExpectMsg('reply_channel_range',
                              chain_hash=regtest_hash,
                              first_blocknum=109,
                              number_of_blocks=1)),
                CheckEq(decode_scids, '109x1x0')
            ],

            # This should get both.
            [
                Msg('query_channel_range',
                    chain_hash=regtest_hash,
                    first_blocknum=103,
                    number_of_blocks=7),
                ExpectMsg('reply_channel_range',
                          chain_hash=regtest_hash,
                          first_blocknum=103,
                          number_of_blocks=7),
                CheckEq(decode_scids, '103x1x0,109x1x0')
            ],

            # This should get appended timestamp fields with option_gossip_queries_ex
            Sequence(enable=runner.has_option('option_gossip_queries_ex')
                     is not None,
                     events=[
                         Msg('query_channel_range',
                             chain_hash=regtest_hash,
                             first_blocknum=103,
                             number_of_blocks=7,
                             tlvs='{query_option={query_option_flags=1}}'),
                         ExpectMsg('reply_channel_range',
                                   chain_hash=regtest_hash,
                                   first_blocknum=103,
                                   number_of_blocks=7),
                         CheckEq(decode_timestamps, ts_103x1x0 + ts_109x1x0),
                         CheckEq(decode_scids, '103x1x0,109x1x0')
                     ]),

            # This should get appended checksum fields with option_gossip_queries_ex
            Sequence(enable=runner.has_option('option_gossip_queries_ex')
                     is not None,
                     events=[
                         Msg('query_channel_range',
                             chain_hash=regtest_hash,
                             first_blocknum=103,
                             number_of_blocks=7,
                             tlvs='{query_option={query_option_flags=2}}'),
                         ExpectMsg('reply_channel_range',
                                   chain_hash=regtest_hash,
                                   first_blocknum=103,
                                   number_of_blocks=7,
                                   tlvs='{checksums_tlv={checksums=[' +
                                   csums_103x1x0 + ',' + csums_109x1x0 +
                                   ']}}'),
                         CheckEq(decode_scids, '103x1x0,109x1x0')
                     ]),

            # This should append timestamps and checksums with option_gossip_queries_ex
            Sequence(enable=runner.has_option('option_gossip_queries_ex')
                     is not None,
                     events=[
                         Msg('query_channel_range',
                             chain_hash=regtest_hash,
                             first_blocknum=103,
                             number_of_blocks=7,
                             tlvs='{query_option={query_option_flags=3}}'),
                         ExpectMsg('reply_channel_range',
                                   chain_hash=regtest_hash,
                                   first_blocknum=103,
                                   number_of_blocks=7,
                                   tlvs='{checksums_tlv={checksums=[' +
                                   csums_103x1x0 + ',' + csums_109x1x0 +
                                   ']}}'),
                         CheckEq(decode_timestamps, ts_103x1x0 + ts_109x1x0),
                         CheckEq(decode_scids, '103x1x0,109x1x0')
                     ]))
    ]

    runner.run(test)
def test_reestablish(runner: Runner) -> None:
    local_funding_privkey = '20'

    local_keyset = KeySet(revocation_base_secret='21',
                          payment_base_secret='22',
                          htlc_base_secret='24',
                          delayed_payment_base_secret='23',
                          shachain_seed='00' * 32)
    test = [
        Block(blockheight=102, txs=[tx_spendable]),
        Connect(connprivkey='02'),
        ExpectMsg('init'),
        TryAll(
            Msg('init',
                globalfeatures='',
                features=bitfield(data_loss_protect)),
            Msg('init', globalfeatures='',
                features=bitfield(static_remotekey)),
            # And nothing.
            Msg('init', globalfeatures='', features='')),
        Msg(
            'open_channel',
            chain_hash=regtest_hash,
            temporary_channel_id='00' * 32,
            funding_satoshis=funding_amount_for_utxo(0),
            push_msat=0,
            dust_limit_satoshis=546,
            max_htlc_value_in_flight_msat=4294967295,
            channel_reserve_satoshis=9998,
            htlc_minimum_msat=0,
            feerate_per_kw=253,
            # clightning uses to_self_delay=6; we use 5 to test differentiation
            to_self_delay=5,
            max_accepted_htlcs=483,
            funding_pubkey=pubkey_of(local_funding_privkey),
            revocation_basepoint=local_keyset.revocation_basepoint(),
            payment_basepoint=local_keyset.payment_basepoint(),
            delayed_payment_basepoint=local_keyset.delayed_payment_basepoint(),
            htlc_basepoint=local_keyset.htlc_basepoint(),
            first_per_commitment_point=local_keyset.per_commit_point(0),
            channel_flags=1),
        ExpectMsg('accept_channel',
                  funding_pubkey=remote_funding_pubkey(),
                  revocation_basepoint=remote_revocation_basepoint(),
                  payment_basepoint=remote_payment_basepoint(),
                  delayed_payment_basepoint=remote_delayed_payment_basepoint(),
                  htlc_basepoint=remote_htlc_basepoint(),
                  first_per_commitment_point=remote_per_commitment_point(0),
                  minimum_depth=3,
                  channel_reserve_satoshis=9998),

        # Create and stash Funding object and FundingTx
        CreateFunding(*utxo(0),
                      local_node_privkey='02',
                      local_funding_privkey=local_funding_privkey,
                      remote_node_privkey=runner.get_node_privkey(),
                      remote_funding_privkey=remote_funding_privkey()),
        Commit(funding=funding(),
               opener=Side.local,
               local_keyset=local_keyset,
               local_to_self_delay=rcvd('to_self_delay', int),
               remote_to_self_delay=sent('to_self_delay', int),
               local_amount=msat(sent('funding_satoshis', int)),
               remote_amount=0,
               local_dust_limit=546,
               remote_dust_limit=546,
               feerate=253,
               local_features=sent('init.features'),
               remote_features=rcvd('init.features')),
        Msg('funding_created',
            temporary_channel_id=rcvd(),
            funding_txid=funding_txid(),
            funding_output_index=0,
            signature=commitsig_to_send()),
        ExpectMsg('funding_signed',
                  channel_id=channel_id(),
                  signature=commitsig_to_recv()),

        # Mine it and get it deep enough to confirm channel.
        Block(blockheight=103, number=3, txs=[funding_tx()]),
        ExpectMsg('funding_locked',
                  channel_id=channel_id(),
                  next_per_commitment_point=remote_per_commitment_point(1)),
        Msg('funding_locked',
            channel_id=channel_id(),
            next_per_commitment_point=local_keyset.per_commit_point(1)),
        Disconnect(),
        Connect(connprivkey='02'),
        ExpectMsg('init'),

        # Reconnect with same features.
        Msg('init', globalfeatures='', features=sent('init.features')),

        # BOLT #2:
        #  - if `next_revocation_number` equals 0:
        #      - MUST set `your_last_per_commitment_secret` to all zeroes
        #    - otherwise:
        #      - MUST set `your_last_per_commitment_secret` to the last
        #        `per_commitment_secret` it received
        ExpectMsg('channel_reestablish',
                  channel_id=channel_id(),
                  next_commitment_number=1,
                  next_revocation_number=0,
                  your_last_per_commitment_secret='00' * 32),

        # BOLT #2:
        # The sending node:...
        # - if `option_static_remotekey` applies to the commitment
        #   transaction:
        #     - MUST set `my_current_per_commitment_point` to a valid point.
        # - otherwise:
        #   - MUST set `my_current_per_commitment_point` to its commitment
        #     point for the last signed commitment it received from its
        #     channel peer (i.e. the commitment_point corresponding to the
        #     commitment transaction the sender would use to unilaterally
        #     close).
        Sequence(CheckEq(rcvd('my_current_per_commitment_point'),
                         remote_per_commitment_point(0)),
                 enable=negotiated(sent('init.features'),
                                   rcvd('init.features'),
                                   excluded=[static_remotekey])),

        # Ignore unknown odd messages
        TryAll([], RawMsg(bytes.fromhex('270F'))),
        Msg('channel_reestablish',
            channel_id=channel_id(),
            next_commitment_number=1,
            next_revocation_number=0,
            your_last_per_commitment_secret='00' * 32,
            my_current_per_commitment_point=local_keyset.per_commit_point(0)),

        # FIXME: Check that they error and unilateral close if we give
        # the wrong info!
    ]

    runner.run(test)
示例#7
0
def test_htlc_add(runner: Runner) -> None:
    local_funding_privkey = '20'

    local_keyset = KeySet(revocation_base_secret='21',
                          payment_base_secret='22',
                          htlc_base_secret='24',
                          delayed_payment_base_secret='23',
                          shachain_seed='00' * 32)

    # FIXME: Generate onion routing packet!
    dust_htlc = HTLC(
        owner=Side.local,
        amount_msat=1000,
        payment_secret='00' * 32,
        cltv_expiry=200,
        # hop_data[0] = 00000000000000000000000000000003E8000000C8000000000000000000000000
        onion_routing_packet=
        '0002eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619b1153ae94698ea83a3298ab3c0ddd9f755853e4e5fbc5d4f3cb457bbb74a9b81d3b5bc9cf42d8617d1fe6966ffb66b8ec0eaa1188865957e26df123d11705395d339472bcc4920e428492f7822424eef8e6d903a768ec01959f3a1f2c1cd8725ba13329df3a932f641dee600dbb1a9f3bbe93a167410961f1777a7b48679d8a3041d57c0b8e795ed4884fbb33a2564d4cdafb528c7b63fc31cd2739e71d1d3b56f35ba7976a373b883eed8f1f263aedd540cce9b548e53e58c32ab604195f6004d8d92fe0a9a454229b9bc0795f3e4ccd54089075483afaa0ef3b32ee12cf321052f7b9e5ac1c28169e57d5628c3aee5c775d5fb33ba835fda195981b1e3a06792bdd0ecf85f8f6107fd830ca932e92c6713ea6d4d5129395f54aeabb54debccca130ad019a1f53a20c0c46dd8625ada068e2a13ea5373b60ecdf412728cc78192ae1a56bae26dfb450d2f6b4905e6bd9843fda7df63eb11fb77ce995b25d3076210eca527bb556b4ddc564fa4c6ccb43f1149163a4959ffe4178d653d35bdc052e4a46dd58b8f95fde83d114c4e35fd02e94a0dd2a9ae21594184808074a57d9de30c5105b53efe03aca192f8c518bc2b9e13211a9761c1948b31aa97f99da449968380005f96ff49a6e5fe833220a82f358eb94197584b2dfa5a1efee8918b5020f028748e5897bb694979f580ff58b8b1d865783340eaff2d1ce738409ec1c62c1bd7f632cf0730a5634a1a2d91244b865302339c1861655e11b264aeaf2feefbf2d1222bb13c6bd6b2d2379d9a548f93de4d2a044928458eafa745021e0a69796bb40f17c1ca53b895c76b53924faa886a4a19f07b50eda5f316e5f3b5422e984c59928144c275d4ae5e78634e16c6dafcfc92bb302c7d5eef1456250b0b8a41f0cabb55dd114d6b0bcaf53ef1ee2185d2383df57a0f1bc21d31f5d3ae395bab6e77370ee83ffe8995e9bfbe2f90b3ff0578720e0584e969479d40327415835579d7b8885037c02a611292c6bbffde25e86c184cc7c7481e8856ce6a3cf7109a6c001e51a2289c5ee3633936578d4dc3de82c18ebb787bf2c475e8fa0393727cbdbcd36849ee0b7411fba6fd5cb8459e63aaf3fba7a4cd4a04b266d8f416f0586e2093ea9c210140a6e6cb72759ae1dee7c24497f68389fb8d154f927cc4ab59b9137652eaf9c7cb56f0cce6c58616646c6fee836b07ce738a965b1ea725d9960c47e61086be053f3e9c48c08ce945404b060d9e699ad962c910208dda42d665f8eacf9865a64d2612ea62e0e2c0a4c731b35ae87b04e45739c34f4c972ce433a2094b10a9601e6711b95a6a226a85f4e4ed0e0417dbc9d737cd7d3513a82943de94ff8e4c9e91838506283f4878e3f41488fec47198b4a262b55d3691d275c6154d2a2ce9ee6ab97087e0f33654b01450869797c993dfca76cd732677bf1856f43d040d68022055987588f64af357bea80491b4bc42341dd6f81631d30fc28e8c5d7e3312655b30d277f10ce76c2525279ad53157b1c2c78b412107fc5f974ac7946bdc33ee54d71f3fc261530d50f20813e4e6aadf39e67573d5dc93a45023edf297b56def6b14ec5e19ca10fbfd1b807f17fa983bec363cf495c708a581db1bba1a23730ce22d0f925d764b04be014d662c3a36ac58b015317c9cf5ca6464f2ecef15e1769f2c91922968532bda66e9aaa2a7f120a9301f563fd33db8e90c940984b0a297e0c595544b7f687476325a07dbaba255c8461e98f069eea2246cfa50f1c2ef8d4c54f5fd509a9cc839548d7c252e60bb9c165d05f30bd525f6b53a4c8afc8fc31026686bcd5a48172593941b3113cbed88e6cfb566f7a693bb63c9a89925c1f5df0a115b4893128866a81c1b'
    )

    non_dust_htlc = HTLC(
        owner=Side.local,
        amount_msat=1000000,
        payment_secret='00' * 32,
        cltv_expiry=200,
        onion_routing_packet=
        '0002eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619b1153ae94698ea83a3298ab3c0ddd9f755853e4e5fbc5d4f3cb457bbb74a9b81d3b5bc9cf42d8617d1fe6966ffb66b8ec0eaa1188865957e26df123d11705395d339472bcc4920e428492f7822424eef8e6d903a768ec01959f3a1f2c1cd8725ba13329df3a932f641dee600dbb1a9f3bbe93a167410961f1777a7b48679d8a3041d57c0b8e795ed4884fbb33a2564d4cdafb528c7b63fc31cd2739e71d1d3b56f35ba7976a373b883eed8f1f263aedd540cce9b548e53e58c32ab604195f6004d8d92fe0a9a454229b9bc0795f3e4ccd54089075483afaa0ef3b32ee12cf321052f7b9e5ac1c28169e57d5628c3aee5c775d5fb33ba835fda195981b1e3a06792bdd0ecf85f8f6107fd830ca932e92c6713ea6d4d5129395f54aeabb54debccca130ad019a1f53a20c0c46dd8625ada068e2a13ea5373b60ecdf412728cc78192ae1a56bae26dfb450d2f6b4905e6bd9843fda7df63eb11fb77ce995b25d3076210eca527bb556b4ddc564fa4c6ccb43f1149163a4959ffe4178d653d35bdc052e4a46dd58b8f95fde83d114c4e35fd02e94a0dd2a9ae21594184808074a57d9de30c5105b53efe03aca192f8c518bc2b9e13211a9761c1948b31aa97f99da449968380005f96ff49a6e5fe833220a82f358eb94197584b2dfa5a1efee8918b5020f028748e5897bb694979f580ff58b8b1d865783340eaff2d1ce738409ec1c62c1bd7f632cf0730a5634a1a2d91244b865302339c1861655e11b264aeaf2feefbf2d1222bb13c6bd6b2d2379d9a548f93de4d2a044928458eafa745021e0a69796bb40f17c1ca53b895c76b53924faa886a4a19f07b50eda5f316e5f3b5422e984c59928144c275d4ae5e78634e16c6dafcfc92bb302c7d5eef1456250b0b8a41f0cabb55dd114d6b0bcaf53ef1ee2185d2383df57a0f1bc21d31f5d3ae395bab6e77370ee83ffe8995e9bfbe2f90b3ff0578720e0584e969479d40327415835579d7b8885037c02a611292c6bbffde25e86c184cc7c7481e8856ce6a3cf7109a6c001e51a2289c5ee3633936578d4dc3de82c18ebb787bf2c475e8fa0393727cbdbcd36849ee0b7411fba6fd5cb8459e63aaf3fba7a4cd4a04b266d8f416f0586e2093ea9c210140a6e6cb72759ae1dee7c24497f68389fb8d154f927cc4ab59b9137652eaf9c7cb56f0cce6c58616646c6fee836b07ce738a965b1ea725d9960c47e61086be053f3e9c48c08ce945404b060d9e699ad962c910208dda42d665f8eacf9865a64d2612ea62e0e2c0a4c731b35ae87b04e45739c34f4c972ce433a2094b10a9601e6711b95a6a226a85f4e4ed0e0417dbc9d737cd7d3513a82943de94ff8e4c9e91838506283f4878e3f41488fec47198b4a262b55d3691d275c6154d2a2ce9ee6ab97087e0f33654b01450869797c993dfca76cd732677bf1856f43d040d68022055987588f64af357bea80491b4bc42341dd6f81631d30fc28e8c5d7e3312655b30d277f10ce76c2525279ad53157b1c2c78b412107fc5f974ac7946bdc33ee54d71f3fc261530d50f20813e4e6aadf39e67573d5dc93a45023edf297b56def6b14ec5e19ca10fbfd1b807f17fa983bec363cf495c708a581db1bba1a23730ce22d0f925d764b04be014d662c3a36ac58b015317c9cf5ca6464f2ecef15e1769f2c91922968532bda66e9aaa2a7f120a9301f563fd33db8e90c940984b0a297e0c595544b7f687476325a07dbaba255c8461e98f069eea2246cfa50f1c2ef8d4c54f5fd509a9cc839548d7c252e60bb9c165d05f30bd525f6b53a4c8afc8fc31026686bcd5a48172593941b3113cbed88e6cfb566f7a693bb63c9a89925c1f5df0a115b4893128866a81c1b'
    )

    test = [
        Block(blockheight=102, txs=[tx_spendable]),
        Connect(connprivkey='02'),
        ExpectMsg('init'),
        TryAll(
            Msg('init',
                globalfeatures='',
                features=bitfield(data_loss_protect)),
            Msg('init', globalfeatures='',
                features=bitfield(static_remotekey)),
            Msg('init',
                globalfeatures='',
                features=bitfield(static_remotekey, anchor_outputs)),
            # And nothing.
            Msg('init', globalfeatures='', features='')),
        Msg(
            'open_channel',
            chain_hash=regtest_hash,
            temporary_channel_id='00' * 32,
            funding_satoshis=funding_amount_for_utxo(0),
            push_msat=0,
            dust_limit_satoshis=546,
            max_htlc_value_in_flight_msat=4294967295,
            channel_reserve_satoshis=9998,
            htlc_minimum_msat=0,
            feerate_per_kw=253,
            # clightning uses to_self_delay=6; we use 5 to test differentiation
            to_self_delay=5,
            max_accepted_htlcs=483,
            funding_pubkey=pubkey_of(local_funding_privkey),
            revocation_basepoint=local_keyset.revocation_basepoint(),
            payment_basepoint=local_keyset.payment_basepoint(),
            delayed_payment_basepoint=local_keyset.delayed_payment_basepoint(),
            htlc_basepoint=local_keyset.htlc_basepoint(),
            first_per_commitment_point=local_keyset.per_commit_point(0),
            channel_flags=1),
        ExpectMsg('accept_channel',
                  funding_pubkey=remote_funding_pubkey(),
                  revocation_basepoint=remote_revocation_basepoint(),
                  payment_basepoint=remote_payment_basepoint(),
                  delayed_payment_basepoint=remote_delayed_payment_basepoint(),
                  htlc_basepoint=remote_htlc_basepoint(),
                  first_per_commitment_point=remote_per_commitment_point(0),
                  minimum_depth=3,
                  channel_reserve_satoshis=9998),

        # Create and stash Funding object and FundingTx
        CreateFunding(*utxo(0),
                      local_node_privkey='02',
                      local_funding_privkey=local_funding_privkey,
                      remote_node_privkey=runner.get_node_privkey(),
                      remote_funding_privkey=remote_funding_privkey()),
        Commit(funding=funding(),
               opener=Side.local,
               local_keyset=local_keyset,
               local_to_self_delay=rcvd('to_self_delay', int),
               remote_to_self_delay=sent('to_self_delay', int),
               local_amount=msat(sent('funding_satoshis', int)),
               remote_amount=0,
               local_dust_limit=546,
               remote_dust_limit=546,
               feerate=253,
               local_features=sent('init.features'),
               remote_features=rcvd('init.features')),
        Msg('funding_created',
            temporary_channel_id=rcvd(),
            funding_txid=funding_txid(),
            funding_output_index=0,
            signature=commitsig_to_send()),
        ExpectMsg('funding_signed',
                  channel_id=channel_id(),
                  signature=commitsig_to_recv()),

        # Mine it and get it deep enough to confirm channel.
        Block(blockheight=103, number=3, txs=[funding_tx()]),
        ExpectMsg('funding_locked',
                  channel_id=channel_id(),
                  next_per_commitment_point=remote_per_commitment_point(1)),
        Msg('funding_locked',
            channel_id=channel_id(),
            next_per_commitment_point=local_keyset.per_commit_point(1)),

        # We try both a dust and a non-dust htlc.
        TryAll(
            Msg('update_add_htlc',
                channel_id=channel_id(),
                id=0,
                amount_msat=dust_htlc.amount_msat,
                payment_hash=dust_htlc.payment_hash(),
                cltv_expiry=dust_htlc.cltv_expiry,
                onion_routing_packet=dust_htlc.onion_routing_packet),
            Msg('update_add_htlc',
                channel_id=channel_id(),
                id=0,
                amount_msat=non_dust_htlc.amount_msat,
                payment_hash=non_dust_htlc.payment_hash(),
                cltv_expiry=non_dust_htlc.cltv_expiry,
                onion_routing_packet=non_dust_htlc.onion_routing_packet)),

        # Optional reconnect:
        TryAll(
            [],
            [
                Disconnect(),
                Connect(connprivkey='02'),
                ExpectMsg('init'),

                # Reconnect with same features.
                Msg('init', globalfeatures='', features=sent('init.features')),
                ExpectMsg('channel_reestablish',
                          channel_id=channel_id(),
                          next_commitment_number=1,
                          next_revocation_number=0,
                          your_last_per_commitment_secret='00' * 32),
                Msg('channel_reestablish',
                    channel_id=channel_id(),
                    next_commitment_number=1,
                    next_revocation_number=0,
                    your_last_per_commitment_secret='00' * 32,
                    my_current_per_commitment_point=local_keyset.
                    per_commit_point(0)),

                # BOLT #2:
                # A node:
                #   - if `next_commitment_number` is 1 in both the
                #     `channel_reestablish` it sent and received:
                #     - MUST retransmit `funding_locked`.
                #   - otherwise:
                #     - MUST NOT retransmit `funding_locked`.
                ExpectMsg(
                    'funding_locked',
                    channel_id=channel_id(),
                    next_per_commitment_point=remote_per_commitment_point(1),
                    ignore=ExpectMsg.ignore_all_gossip),

                # BOLT #2:
                # A node:
                # ...
                # - upon disconnection:
                #   - MUST reverse any uncommitted updates sent by the
                #   other side (i.e. all messages beginning with `update_`
                #   for which no `commitment_signed` has been received).

                # So this puts us back where we were.
                Msg('update_add_htlc',
                    channel_id=channel_id(),
                    id=0,
                    amount_msat=dust_htlc.amount_msat,
                    payment_hash=dust_htlc.payment_hash(),
                    cltv_expiry=dust_htlc.cltv_expiry,
                    onion_routing_packet=dust_htlc.onion_routing_packet)
            ]),
        UpdateCommit(new_htlcs=[(dust_htlc, 0)]),
        Msg('commitment_signed',
            channel_id=channel_id(),
            signature=commitsig_to_send(),
            htlc_signature=htlc_sigs_to_send()),
        ExpectMsg('revoke_and_ack',
                  channel_id=channel_id(),
                  per_commitment_secret=remote_per_commitment_secret(0),
                  next_per_commitment_point=remote_per_commitment_point(2),
                  ignore=ExpectMsg.ignore_all_gossip),
        ExpectMsg('commitment_signed',
                  signature=commitsig_to_recv(),
                  htlc_signature=htlc_sigs_to_recv(),
                  ignore=ExpectMsg.ignore_all_gossip),

        # Now try optionally reconnecting.
        TryAll(
            [],
            # Ignore unknown.
            [RawMsg(bytes.fromhex('270F'))],
            [
                Disconnect(),
                Connect(connprivkey='02'),
                ExpectMsg('init'),

                # Reconnect with same features.
                Msg('init', globalfeatures='', features=sent('init.features')),
                ExpectMsg('channel_reestablish',
                          channel_id=channel_id(),
                          next_commitment_number=2,
                          next_revocation_number=0,
                          your_last_per_commitment_secret='00' * 32,
                          ignore=ExpectMsg.ignore_all_gossip),

                # Depends on what we tell them we already received:
                TryAll(
                    # We didn't receive revoke_and_ack:
                    [
                        Msg('channel_reestablish',
                            channel_id=channel_id(),
                            next_commitment_number=1,
                            next_revocation_number=0,
                            your_last_per_commitment_secret='00' * 32,
                            my_current_per_commitment_point=local_keyset.
                            per_commit_point(0)),
                        ExpectMsg(
                            'revoke_and_ack',
                            channel_id=channel_id(),
                            per_commitment_secret=remote_per_commitment_secret(
                                0),
                            next_per_commitment_point=
                            remote_per_commitment_point(2),
                            ignore=ExpectMsg.ignore_all_gossip),
                        ExpectMsg('commitment_signed',
                                  signature=commitsig_to_recv(),
                                  htlc_signature=htlc_sigs_to_recv(),
                                  ignore=ExpectMsg.ignore_all_gossip)
                    ],

                    # We did receive revoke_and_ack, but not
                    # commitment_signed
                    [
                        Msg('channel_reestablish',
                            channel_id=channel_id(),
                            next_commitment_number=1,
                            next_revocation_number=1,
                            your_last_per_commitment_secret=
                            remote_per_commitment_secret(0),
                            my_current_per_commitment_point=local_keyset.
                            per_commit_point(0)),
                        ExpectMsg('commitment_signed',
                                  signature=commitsig_to_recv(),
                                  htlc_signature=htlc_sigs_to_recv(),
                                  ignore=ExpectMsg.ignore_all_gossip)
                    ],

                    # We received commitment_signed:
                    [
                        Msg('channel_reestablish',
                            channel_id=channel_id(),
                            next_commitment_number=2,
                            next_revocation_number=1,
                            your_last_per_commitment_secret=
                            remote_per_commitment_secret(0),
                            my_current_per_commitment_point=local_keyset.
                            per_commit_point(1))
                    ])
            ])
    ]

    runner.run(test)
示例#8
0
def test_gossip(runner: Runner) -> None:
    # Make up a channel between nodes 02 and 03, using bitcoin privkeys 10 and 20
    funding, funding_tx = Funding.from_utxo(*utxo(0),
                                            local_node_privkey='02',
                                            local_funding_privkey='10',
                                            remote_node_privkey='03',
                                            remote_funding_privkey='20')

    test = [Block(blockheight=102, txs=[tx_spendable]),
            Connect(connprivkey='03'),
            ExpectMsg('init'),
            Msg('init', globalfeatures='', features=''),

            Block(blockheight=103, number=6, txs=[funding_tx]),

            RawMsg(funding.channel_announcement('103x1x0', '')),

            # New peer connects, asking for initial_routing_sync.  We *won't* relay channel_announcement, as there is no channel_update.
            Connect(connprivkey='05'),
            ExpectMsg('init'),
            Msg('init', globalfeatures='', features='08'),
            MustNotMsg('channel_announcement'),
            Disconnect(),

            RawMsg(funding.channel_update('103x1x0',
                                          Side.local,
                                          disable=False,
                                          cltv_expiry_delta=144,
                                          htlc_minimum_msat=0,
                                          fee_base_msat=1000,
                                          fee_proportional_millionths=10,
                                          timestamp=int(time.time()),
                                          htlc_maximum_msat=None),
                   connprivkey='03'),

            # Now we'll relay to a new peer.
            Connect(connprivkey='05'),
            ExpectMsg('init'),
            Msg('init', globalfeatures='', features='08'),
            ExpectMsg('channel_announcement',
                      short_channel_id='103x1x0'),
            ExpectMsg('channel_update',
                      short_channel_id='103x1x0',
                      message_flags=0,
                      channel_flags=0),
            Disconnect(),

            # BOLT #7:
            # A node:
            #   - SHOULD monitor the funding transactions in the blockchain, to
            #   identify channels that are being closed.
            #  - if the funding output of a channel is being spent:
            #    - SHOULD be removed from the local network view AND be
            #      considered closed.
            Block(blockheight=109, txs=[funding.close_tx(200, '99')]),

            Connect(connprivkey='05'),
            ExpectMsg('init'),
            Msg('init', globalfeatures='', features='08'),
            MustNotMsg('channel_announcement'),
            MustNotMsg('channel_update')]

    runner.run(test)
示例#9
0
def test_open_accepter_channel(runner: Runner) -> None:
    # Needs modified spec, so don't even try unless we have that!
    if not 'open_channel2' in pyln.spec.bolt2.__dict__:
        return

    local_funding_privkey = '20'

    local_keyset = KeySet(revocation_base_secret='21',
                          payment_base_secret='22',
                          htlc_base_secret='24',
                          delayed_payment_base_secret='23',
                          shachain_seed='00' * 32)

    input_index = 0

    test = [
        Block(blockheight=102, txs=[tx_spendable]),
        Connect(connprivkey='02'),
        ExpectMsg('init'),

        # BOLT-ff9a3470f5a0f475dc0909bf153620a73ca7b21e #9:
        # | 222/223 | `option_dual_fund`          | Use v2 channel open
        Msg('init', globalfeatures='', features=bitfield(12, 223)),

        # Accepter side: we initiate a new channel.
        Msg(
            'open_channel2',
            chain_hash=regtest_hash,
            funding_satoshis=funding_amount_for_utxo(input_index),
            dust_limit_satoshis=546,
            max_htlc_value_in_flight_msat=4294967295,
            htlc_minimum_msat=0,
            feerate_per_kw=253,
            feerate_per_kw_funding=253,
            # We use 5, because c-lightning runner uses 6, so this is different.
            to_self_delay=5,
            max_accepted_htlcs=483,
            locktime=0,
            podle_h2='00' * 32,
            funding_pubkey=pubkey_of(local_funding_privkey),
            revocation_basepoint=local_keyset.revocation_basepoint(),
            payment_basepoint=local_keyset.payment_basepoint(),
            delayed_payment_basepoint=local_keyset.delayed_payment_basepoint(),
            htlc_basepoint=local_keyset.htlc_basepoint(),
            first_per_commitment_point=local_keyset.per_commit_point(0),
            channel_flags=1),

        # Ignore unknown odd messages
        TryAll([], RawMsg(bytes.fromhex('270F'))),
        ExpectMsg('accept_channel2',
                  channel_id=channel_id_v2(local_keyset),
                  funding_satoshis=0,
                  funding_pubkey=remote_funding_pubkey(),
                  revocation_basepoint=remote_revocation_basepoint(),
                  payment_basepoint=remote_payment_basepoint(),
                  delayed_payment_basepoint=remote_delayed_payment_basepoint(),
                  htlc_basepoint=remote_htlc_basepoint(),
                  first_per_commitment_point=remote_per_commitment_point(0)),

        # Ignore unknown odd messages
        TryAll([], RawMsg(bytes.fromhex('270F'))),

        # Create and stash Funding object and FundingTx
        CreateFunding(*utxo(input_index),
                      local_node_privkey='02',
                      local_funding_privkey=local_funding_privkey,
                      remote_node_privkey=runner.get_node_privkey(),
                      remote_funding_privkey=remote_funding_privkey()),
        Commit(funding=funding(),
               opener=Side.local,
               local_keyset=local_keyset,
               local_to_self_delay=rcvd('accept_channel2.to_self_delay', int),
               remote_to_self_delay=sent('open_channel2.to_self_delay', int),
               local_amount=msat(sent('open_channel2.funding_satoshis', int)),
               remote_amount=0,
               local_dust_limit=546,
               remote_dust_limit=546,
               feerate=253,
               local_features=sent('init.features'),
               remote_features=rcvd('init.features')),
        Msg('tx_add_input',
            channel_id=rcvd('accept_channel2.channel_id'),
            serial_id=2,
            prevtx=tx_spendable,
            prevtx_vout=tx_out_for_index(input_index),
            max_witness_len=135,
            sequence=0xfffffffd,
            script=''),

        # Ignore unknown odd messages
        TryAll([], RawMsg(bytes.fromhex('270F'))),
        ExpectMsg('tx_complete',
                  channel_id=rcvd('accept_channel2.channel_id')),
        Msg('tx_add_output',
            channel_id=rcvd('accept_channel2.channel_id'),
            serial_id=2,
            sats=funding_amount_for_utxo(input_index),
            script=locking_script()),

        # Ignore unknown odd messages
        TryAll([], RawMsg(bytes.fromhex('270F'))),
        ExpectMsg('tx_complete',
                  channel_id=rcvd('accept_channel2.channel_id')),
        Msg('tx_complete', channel_id=rcvd('accept_channel2.channel_id')),

        # Ignore unknown odd messages
        TryAll([], RawMsg(bytes.fromhex('270F'))),
        Msg('commitment_signed',
            channel_id=rcvd('accept_channel2.channel_id'),
            signature=commitsig_to_send(),
            htlc_signature='[]'),

        # Ignore unknown odd messages
        TryAll([], RawMsg(bytes.fromhex('270F'))),
        ExpectMsg('commitment_signed',
                  channel_id=rcvd('accept_channel2.channel_id'),
                  signature=commitsig_to_recv()),
        ExpectMsg('tx_signatures',
                  channel_id=rcvd('accept_channel2.channel_id'),
                  txid=funding_txid(),
                  witness_stack='[]'),

        # Mine the block!
        Block(blockheight=103, number=3, txs=[funding_tx()]),
        Msg('funding_locked',
            channel_id=rcvd('accept_channel2.channel_id'),
            next_per_commitment_point=
            '027eed8389cf8eb715d73111b73d94d2c2d04bf96dc43dfd5b0970d80b3617009d'
            ),
        ExpectMsg(
            'funding_locked',
            channel_id=rcvd('accept_channel2.channel_id'),
            next_per_commitment_point=
            '032405cbd0f41225d5f203fe4adac8401321a9e05767c5f8af97d51d2e81fbb206'
        ),

        # Ignore unknown odd messages
        TryAll([], RawMsg(bytes.fromhex('270F')))
    ]

    runner.run(test)
示例#10
0
def test_open_dual_accepter_channel(runner: Runner) -> None:
    # Needs modified spec, so don't even try unless we have that!
    if not 'open_channel2' in pyln.spec.bolt2.__dict__:
        return

    local_funding_privkey = '20'

    local_keyset = KeySet(revocation_base_secret='21',
                          payment_base_secret='22',
                          htlc_base_secret='24',
                          delayed_payment_base_secret='23',
                          shachain_seed='00' * 32)

    input_index = 5

    # Since technically these can be sent in any order,
    # we must specify this as ok!
    expected_add_input = ExpectMsg(
        'tx_add_input',
        channel_id=rcvd('accept_channel2.channel_id'),
        max_witness_len=106,
        sequence=0xfffffffd,
        script='',
        if_match=odd_serial)

    expected_add_output = ExpectMsg(
        'tx_add_output',
        channel_id=rcvd('accept_channel2.channel_id'),
        if_match=odd_serial)

    test = [
        Block(blockheight=102, txs=[tx_spendable]),
        Connect(connprivkey='02'),
        ExpectMsg('init'),

        # BOLT-ff9a3470f5a0f475dc0909bf153620a73ca7b21e #9:
        # | 222/223 | `option_dual_fund`          | Use v2 channel open
        Msg('init', globalfeatures='', features=bitfield(12, 223)),
        DualFundAccept(),

        # Accepter side: we initiate a new channel.
        Msg(
            'open_channel2',
            chain_hash=regtest_hash,
            funding_satoshis=funding_amount_for_utxo(input_index),
            dust_limit_satoshis=546,
            max_htlc_value_in_flight_msat=4294967295,
            htlc_minimum_msat=0,
            feerate_per_kw=253,
            feerate_per_kw_funding=253,
            # We use 5, because c-lightning runner uses 6, so this is different.
            to_self_delay=5,
            max_accepted_htlcs=483,
            locktime=100,
            podle_h2='00' * 32,
            funding_pubkey=pubkey_of(local_funding_privkey),
            revocation_basepoint=local_keyset.revocation_basepoint(),
            payment_basepoint=local_keyset.payment_basepoint(),
            delayed_payment_basepoint=local_keyset.delayed_payment_basepoint(),
            htlc_basepoint=local_keyset.htlc_basepoint(),
            first_per_commitment_point=local_keyset.per_commit_point(0),
            channel_flags=1),

        # Ignore unknown odd messages
        TryAll([], RawMsg(bytes.fromhex('270F'))),
        ExpectMsg('accept_channel2',
                  channel_id=channel_id_v2(local_keyset),
                  funding_satoshis=funding_amount_for_utxo(input_index),
                  funding_pubkey=remote_funding_pubkey(),
                  revocation_basepoint=remote_revocation_basepoint(),
                  payment_basepoint=remote_payment_basepoint(),
                  delayed_payment_basepoint=remote_delayed_payment_basepoint(),
                  htlc_basepoint=remote_htlc_basepoint(),
                  first_per_commitment_point=remote_per_commitment_point(0)),

        # Create and stash Funding object and FundingTx
        CreateDualFunding(*utxo(input_index),
                          funding_sats=agreed_funding(),
                          locktime=sent('open_channel2.locktime', int),
                          local_node_privkey='02',
                          local_funding_privkey=local_funding_privkey,
                          remote_node_privkey=runner.get_node_privkey(),
                          remote_funding_privkey=remote_funding_privkey()),

        # Ignore unknown odd messages
        TryAll([], RawMsg(bytes.fromhex('270F'))),
        Msg('tx_add_input',
            channel_id=rcvd('accept_channel2.channel_id'),
            serial_id=0,
            sequence=0xfffffffd,
            prevtx=tx_spendable,
            prevtx_vout=tx_out_for_index(input_index),
            max_witness_len=135,
            script=''),
        AddInput(funding=funding(),
                 privkey=privkey_for_index(input_index),
                 serial_id=sent('tx_add_input.serial_id', int),
                 prevtx=sent(),
                 prevtx_vout=sent('tx_add_input.prevtx_vout', int),
                 max_witness_len=sent('tx_add_input.max_witness_len', int),
                 script=sent()),
        OneOf([
            expected_add_input,
            Msg('tx_add_output',
                channel_id=rcvd('accept_channel2.channel_id'),
                serial_id=0,
                sats=agreed_funding(),
                script=funding_lockscript(local_funding_privkey)),
            expected_add_output
        ], [
            expected_add_output,
            Msg('tx_add_output',
                channel_id=rcvd('accept_channel2.channel_id'),
                serial_id=2,
                sats=agreed_funding(),
                script=funding_lockscript(local_funding_privkey)),
            expected_add_input
        ]),
        AddInput(funding=funding(),
                 serial_id=rcvd('tx_add_input.serial_id', int),
                 prevtx=rcvd('tx_add_input.prevtx'),
                 prevtx_vout=rcvd('tx_add_input.prevtx_vout', int),
                 max_witness_len=rcvd('tx_add_input.max_witness_len', int),
                 script=rcvd('tx_add_input.script')),
        AddOutput(funding=funding(),
                  serial_id=rcvd('tx_add_output.serial_id', int),
                  sats=rcvd('tx_add_output.sats', int),
                  script=rcvd('tx_add_output.script')),
        AddOutput(funding=funding(),
                  serial_id=sent('tx_add_output.serial_id', int),
                  sats=sent('tx_add_output.sats', int),
                  script=sent('tx_add_output.script')),
        FinalizeFunding(funding=funding()),

        # Ignore unknown odd messages
        TryAll([], RawMsg(bytes.fromhex('270F'))),
        Msg('tx_complete', channel_id=rcvd('accept_channel2.channel_id')),
        ExpectMsg('tx_complete',
                  channel_id=rcvd('accept_channel2.channel_id')),
        Commit(funding=funding(),
               opener=Side.local,
               local_keyset=local_keyset,
               local_to_self_delay=rcvd('accept_channel2.to_self_delay', int),
               remote_to_self_delay=sent('open_channel2.to_self_delay', int),
               local_amount=msat(sent('open_channel2.funding_satoshis', int)),
               remote_amount=msat(rcvd('accept_channel2.funding_satoshis',
                                       int)),
               local_dust_limit=546,
               remote_dust_limit=546,
               feerate=253,
               local_features=sent('init.features'),
               remote_features=rcvd('init.features')),

        # Ignore unknown odd messages
        TryAll([], RawMsg(bytes.fromhex('270F'))),
        Msg('commitment_signed',
            channel_id=rcvd('accept_channel2.channel_id'),
            signature=commitsig_to_send(),
            htlc_signature='[]'),

        # Ignore unknown odd messages
        TryAll([], RawMsg(bytes.fromhex('270F'))),
        ExpectMsg('commitment_signed',
                  channel_id=rcvd('accept_channel2.channel_id'),
                  signature=commitsig_to_recv()),
        ExpectMsg('tx_signatures',
                  channel_id=rcvd('accept_channel2.channel_id'),
                  txid=funding_txid()),
        AddWitnesses(funding=funding(), witness_stack=rcvd('witness_stack')),

        # Mine the block!
        Block(blockheight=103, number=3, txs=[funding_tx()]),
        Msg('funding_locked',
            channel_id=rcvd('accept_channel2.channel_id'),
            next_per_commitment_point=local_keyset.per_commit_point(1)),
        ExpectMsg('funding_locked',
                  channel_id=rcvd('accept_channel2.channel_id'),
                  next_per_commitment_point=remote_per_commitment_point(1)),

        # Ignore unknown odd messages
        TryAll([], RawMsg(bytes.fromhex('270F')))
    ]

    runner.run(test)
示例#11
0
def test_gossip_timestamp_filter(runner: Runner) -> None:
    if runner.has_option('option_gossip_queries') is None:
        unittest.SkipTest('Needs option_gossip_queries')

    funding1, funding1_tx = Funding.from_utxo(*utxo(0),
                                              local_node_privkey='02',
                                              local_funding_privkey='10',
                                              remote_node_privkey='03',
                                              remote_funding_privkey='20')

    funding2, funding2_tx = Funding.from_utxo(*utxo(1),
                                              local_node_privkey='04',
                                              local_funding_privkey='30',
                                              remote_node_privkey='05',
                                              remote_funding_privkey='40')

    timestamp1 = int(time.time())
    timestamp2 = timestamp1 + 1

    test = [Block(blockheight=102, txs=[tx_spendable]),

            Connect(connprivkey='03'),
            ExpectMsg('init'),
            Msg('init', globalfeatures='', features=''),

            # txid 189c40b0728f382fe91c87270926584e48e0af3a6789f37454afee6c7560311d
            Block(blockheight=103, number=6, txs=[funding1_tx]),

            RawMsg(funding1.channel_announcement('103x1x0', '')),
            RawMsg(funding1.node_announcement(Side.local, '', (1, 2, 3), 'foobar', b'', timestamp1)),

            # New peer connects, asks for gossip_timestamp_filter=all.  We *won't* relay channel_announcement, as there is no channel_update.
            Connect(connprivkey='05'),
            ExpectMsg('init'),
            # BOLT #9:
            # | 6/7   | `gossip_queries`                 | More sophisticated gossip control
            Msg('init', globalfeatures='', features=bitfield(6)),
            Msg('gossip_timestamp_filter', chain_hash='06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f',
                first_timestamp=0, timestamp_range=4294967295),
            MustNotMsg('channel_announcement'),
            MustNotMsg('channel_update'),
            MustNotMsg('node_announcement'),
            Disconnect(),

            # Now, with channel update
            RawMsg(funding1.channel_update(side=Side.local,
                                           short_channel_id='103x1x0',
                                           disable=False,
                                           cltv_expiry_delta=144,
                                           htlc_minimum_msat=0,
                                           fee_base_msat=1000,
                                           fee_proportional_millionths=10,
                                           timestamp=timestamp1,
                                           htlc_maximum_msat=None),
                   connprivkey='03'),

            # New peer connects, asks for gossip_timestamp_filter=all.  update and node announcement will be relayed.
            Connect(connprivkey='05'),
            ExpectMsg('init'),
            Msg('init', globalfeatures='', features=bitfield(6)),
            Msg('gossip_timestamp_filter', chain_hash='06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f',
                first_timestamp=0, timestamp_range=4294967295),

            ExpectMsg('channel_announcement', short_channel_id='103x1x0'),
            AnyOrder(ExpectMsg('channel_update', short_channel_id='103x1x0'),
                     ExpectMsg('node_announcement')),
            Disconnect(),

            # BOLT #7:
            # The receiver:
            #  - SHOULD send all gossip messages whose `timestamp` is greater or
            #    equal to `first_timestamp`, and less than `first_timestamp` plus
            #    `timestamp_range`.
            Connect(connprivkey='05'),
            ExpectMsg('init'),
            Msg('init', globalfeatures='', features=bitfield(6)),
            Msg('gossip_timestamp_filter', chain_hash='06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f',
                first_timestamp=1000, timestamp_range=timestamp1 - 1000),

            MustNotMsg('channel_announcement'),
            MustNotMsg('channel_update'),
            MustNotMsg('node_announcement'),
            Disconnect(),

            Connect(connprivkey='05'),
            ExpectMsg('init'),
            Msg('init', globalfeatures='', features=bitfield(6)),
            Msg('gossip_timestamp_filter', chain_hash='06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f',
                first_timestamp=timestamp1 + 1, timestamp_range=4294967295),

            MustNotMsg('channel_announcement'),
            MustNotMsg('channel_update'),
            MustNotMsg('node_announcement'),
            Disconnect(),

            # These two succeed in getting the gossip, then stay connected for next test.
            Connect(connprivkey='05'),
            ExpectMsg('init'),
            Msg('init', globalfeatures='', features=bitfield(6)),
            Msg('gossip_timestamp_filter', chain_hash='06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f',
                first_timestamp=timestamp1, timestamp_range=4294967295),

            ExpectMsg('channel_announcement', short_channel_id='103x1x0'),
            AnyOrder(ExpectMsg('channel_update', short_channel_id='103x1x0'),
                     ExpectMsg('node_announcement')),

            Connect(connprivkey='06'),
            ExpectMsg('init'),
            Msg('init', globalfeatures='', features=bitfield(6)),
            Msg('gossip_timestamp_filter', chain_hash='06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f',
                first_timestamp=1000, timestamp_range=timestamp1 - 1000 + 1),

            ExpectMsg('channel_announcement', short_channel_id='103x1x0'),
            AnyOrder(ExpectMsg('channel_update', short_channel_id='103x1x0'),
                     ExpectMsg('node_announcement')),


            # BOLT #7:
            #  - SHOULD restrict future gossip messages to those whose `timestamp`
            #    is greater or equal to `first_timestamp`, and less than
            #    `first_timestamp` plus `timestamp_range`.
            Block(blockheight=109, number=6, txs=[funding2_tx]),

            RawMsg(funding2.channel_announcement('109x1x0', ''),
                   connprivkey='03'),
            RawMsg(funding2.channel_update(side=Side.local,
                                           short_channel_id='109x1x0',
                                           disable=False,
                                           cltv_expiry_delta=144,
                                           htlc_minimum_msat=0,
                                           fee_base_msat=1000,
                                           fee_proportional_millionths=10,
                                           timestamp=timestamp2,
                                           htlc_maximum_msat=None)),
            RawMsg(funding2.channel_update(side=Side.remote,
                                           short_channel_id='109x1x0',
                                           disable=False,
                                           cltv_expiry_delta=144,
                                           htlc_minimum_msat=0,
                                           fee_base_msat=1000,
                                           fee_proportional_millionths=10,
                                           timestamp=timestamp2,
                                           htlc_maximum_msat=None)),
            RawMsg(funding2.node_announcement(Side.local, '', (1, 2, 3), 'foobar2', b'', timestamp2)),

            # 005's filter covers this, 006's doesn't.
            ExpectMsg('channel_announcement', short_channel_id='109x1x0', connprivkey='05'),
            AnyOrder(ExpectMsg('channel_update', short_channel_id='109x1x0', channel_flags=0),
                     ExpectMsg('channel_update', short_channel_id='109x1x0', channel_flags=1),
                     ExpectMsg('node_announcement')),

            MustNotMsg('channel_announcement', connprivkey='06'),
            MustNotMsg('channel_update'),
            MustNotMsg('node_announcement')]

    runner.run(test)