Esempio n. 1
0
def events_for_balanceproof(transfers_pair, block_number):
    """ Send the balance proof to nodes that know the secret. """

    events = list()
    for pair in reversed(transfers_pair):
        payee_knows_secret = pair.payee_state in STATE_SECRET_KNOWN
        payee_payed = pair.payee_state in STATE_TRANSFER_PAID
        payee_channel_open = pair.payee_route.state == CHANNEL_STATE_OPENED

        # XXX: All nodes must close the channel and withdraw on-chain if the
        # lock is nearing it's expiration block, what should be the strategy
        # for sending a balance proof to a node that knowns the secret but has
        # not gone on-chain while near the expiration? (The problem is how to
        # define the unsafe region, since that is a local configuration)
        lock_valid = is_lock_valid(pair.payee_transfer, block_number)

        if payee_channel_open and payee_knows_secret and not payee_payed and lock_valid:
            pair.payee_state = 'payee_balance_proof'
            balance_proof = SendBalanceProof(
                pair.payee_transfer.identifier,
                pair.payee_route.channel_address,
                pair.payee_transfer.token,
                pair.payee_route.node_address,
                pair.payee_transfer.secret,
            )
            events.append(balance_proof)

    return events
Esempio n. 2
0
def handle_secretreveal(state, state_change):
    """ Send a balance proof to the next hop with the current mediated transfer
    lock removed and the balance updated.
    """
    if state_change.sender == state.route.node_address:
        # next hop learned the secret, unlock the token locally and send the
        # withdraw message to next hop
        transfer = state.transfer
        unlock_lock = SendBalanceProof(
            transfer.identifier,
            state.route.channel_address,
            transfer.token,
            state.route.node_address,
            transfer.secret,
        )

        transfer_success = EventTransferSentSuccess(
            transfer.identifier,
            transfer.amount,
            transfer.target,
        )

        unlock_success = EventUnlockSuccess(
            transfer.identifier,
            transfer.hashlock,
        )

        iteration = TransitionResult(None, [unlock_lock, transfer_success, unlock_success])
    else:
        iteration = TransitionResult(state, list())

    return iteration
Esempio n. 3
0
def create_unlock(
    channel_state: NettingChannelState,
    message_identifier: typing.MessageID,
    payment_identifier: typing.PaymentID,
    secret: typing.Secret,
    lock: HashTimeLockState,
) -> SendUnlockAndMerkleTree:
    our_state = channel_state.our_state

    msg = 'caller must make sure the lock is known'
    assert is_lock_pending(our_state, lock.secrethash), msg

    msg = 'caller must make sure the channel is open'
    assert get_status(channel_state) == CHANNEL_STATE_OPENED, msg

    our_balance_proof = our_state.balance_proof
    if our_balance_proof:
        transferred_amount = lock.amount + our_balance_proof.transferred_amount
    else:
        transferred_amount = lock.amount

    merkletree = compute_merkletree_without(
        our_state.merkletree,
        lock.lockhash,
    )
    locksroot = merkleroot(merkletree)

    token = channel_state.token_address
    nonce = get_next_nonce(our_state)
    recipient = channel_state.partner_state.address
    locked_amount = get_amount_locked(
        our_state) - lock.amount  # the lock is still registered

    balance_proof = BalanceProofUnsignedState(
        nonce,
        transferred_amount,
        locked_amount,
        locksroot,
        channel_state.token_network_identifier,
        channel_state.identifier,
    )

    queue_name = channel_state.identifier
    unlock_lock = SendBalanceProof(
        recipient,
        queue_name,
        message_identifier,
        payment_identifier,
        token,
        secret,
        balance_proof,
    )

    return unlock_lock, merkletree
Esempio n. 4
0
def create_unlock(channel_state, message_identifier, payment_identifier,
                  secret, lock):
    msg = 'caller must make sure the lock is known'
    assert is_lock_pending(channel_state.our_state, lock.secrethash), msg

    msg = 'caller must make sure the channel is open'
    assert get_status(channel_state) == CHANNEL_STATE_OPENED, msg

    our_balance_proof = channel_state.our_state.balance_proof
    if our_balance_proof:
        transferred_amount = lock.amount + our_balance_proof.transferred_amount
    else:
        transferred_amount = lock.amount

    merkletree = compute_merkletree_without(
        channel_state.our_state.merkletree,
        lock.lockhash,
    )
    locksroot = merkleroot(merkletree)

    token = channel_state.token_address
    nonce = get_next_nonce(channel_state.our_state)
    recipient = channel_state.partner_state.address

    balance_proof = BalanceProofUnsignedState(
        nonce,
        transferred_amount,
        locksroot,
        channel_state.identifier,
    )

    queue_name = channel_state.identifier
    unlock_lock = SendBalanceProof(
        recipient,
        queue_name,
        message_identifier,
        payment_identifier,
        token,
        secret,
        balance_proof,
    )

    return unlock_lock, merkletree
Esempio n. 5
0
def create_unlock(channel_state, identifier, secret, lock):
    msg = 'caller must make sure the lock is known'
    assert is_known(channel_state.our_state, lock.hashlock), msg

    our_balance_proof = channel_state.our_state.balance_proof
    if our_balance_proof:
        transferred_amount = lock.amount + our_balance_proof.transferred_amount
    else:
        transferred_amount = lock.amount

    merkletree = compute_merkletree_without(
        channel_state.our_state.merkletree,
        lock.lockhash,
    )
    locksroot = merkleroot(merkletree)

    token = channel_state.token_address
    nonce = get_next_nonce(channel_state.our_state)
    recipient = channel_state.partner_state.address

    balance_proof = BalanceProofUnsignedState(
        nonce,
        transferred_amount,
        locksroot,
        channel_state.identifier,
    )

    unlock_lock = SendBalanceProof(
        identifier,
        token,
        recipient,
        secret,
        balance_proof,
    )

    return unlock_lock, merkletree
Esempio n. 6
0
def test_get_event_with_balance_proof():
    """ All events which contain a balance proof must be found by when
    querying the database.
    """
    serializer = JSONSerializer
    storage = SQLiteStorage(':memory:', serializer)
    counter = itertools.count()

    lock_expired = SendLockExpired(
        recipient=factories.make_address(),
        message_identifier=next(counter),
        balance_proof=make_balance_proof_from_counter(counter),
        secrethash=sha3(factories.make_secret(next(counter))),
    )
    locked_transfer = SendLockedTransfer(
        recipient=factories.make_address(),
        channel_identifier=factories.make_channel_identifier(),
        message_identifier=next(counter),
        transfer=make_transfer_from_counter(counter),
    )
    balance_proof = SendBalanceProof(
        recipient=factories.make_address(),
        channel_identifier=factories.make_channel_identifier(),
        message_identifier=next(counter),
        payment_identifier=next(counter),
        token_address=factories.make_address(),
        secret=factories.make_secret(next(counter)),
        balance_proof=make_balance_proof_from_counter(counter),
    )
    refund_transfer = SendRefundTransfer(
        recipient=factories.make_address(),
        channel_identifier=factories.make_channel_identifier(),
        message_identifier=next(counter),
        transfer=make_transfer_from_counter(counter),
    )

    events_balanceproofs = [
        (lock_expired, lock_expired.balance_proof),
        (locked_transfer, locked_transfer.balance_proof),
        (balance_proof, balance_proof.balance_proof),
        (refund_transfer, refund_transfer.transfer.balance_proof),
    ]

    timestamp = datetime.utcnow().isoformat(timespec='milliseconds')
    state_change = ''
    for event, _ in events_balanceproofs:
        state_change_identifier = storage.write_state_change(
            state_change,
            timestamp,
        )
        storage.write_events(
            state_change_identifier=state_change_identifier,
            events=[event],
            log_time=timestamp,
        )

    for event, balance_proof in events_balanceproofs:
        event_record = get_event_with_balance_proof(
            storage=storage,
            chain_id=balance_proof.chain_id,
            token_network_identifier=balance_proof.token_network_identifier,
            channel_identifier=balance_proof.channel_identifier,
            balance_hash=balance_proof.balance_hash,
        )
        assert event_record.data == event
Esempio n. 7
0
def test_get_event_with_balance_proof():
    """ All events which contain a balance proof must be found by when
    querying the database.
    """
    serializer = JSONSerializer()
    storage = SerializedSQLiteStorage(":memory:", serializer)
    counter = itertools.count(1)
    partner_address = factories.make_address()

    balance_proof = make_balance_proof_from_counter(counter)
    lock_expired = SendLockExpired(
        recipient=partner_address,
        message_identifier=MessageID(next(counter)),
        balance_proof=balance_proof,
        secrethash=factories.make_secret_hash(next(counter)),
        canonical_identifier=balance_proof.canonical_identifier,
    )
    locked_transfer = SendLockedTransfer(
        recipient=partner_address,
        message_identifier=MessageID(next(counter)),
        transfer=make_transfer_from_counter(counter),
        canonical_identifier=factories.make_canonical_identifier(),
    )
    send_balance_proof = SendBalanceProof(
        recipient=partner_address,
        message_identifier=MessageID(next(counter)),
        payment_identifier=factories.make_payment_id(),
        token_address=factories.make_token_address(),
        secret=factories.make_secret(next(counter)),
        balance_proof=make_balance_proof_from_counter(counter),
        canonical_identifier=factories.make_canonical_identifier(),
    )

    refund_transfer = SendRefundTransfer(
        recipient=partner_address,
        message_identifier=MessageID(next(counter)),
        transfer=make_transfer_from_counter(counter),
        canonical_identifier=factories.make_canonical_identifier(),
    )

    events_balanceproofs = [
        (lock_expired, lock_expired.balance_proof),
        (locked_transfer, locked_transfer.balance_proof),
        (send_balance_proof, send_balance_proof.balance_proof),
        (refund_transfer, refund_transfer.transfer.balance_proof),
    ]

    state_change = Block(BlockNumber(1), BlockGasLimit(1),
                         factories.make_block_hash())
    for event, _ in events_balanceproofs:
        state_change_identifiers = storage.write_state_changes([state_change])
        storage.write_events(events=[(state_change_identifiers[0], event)])

    for event, balance_proof in events_balanceproofs:
        event_record = get_event_with_balance_proof_by_balance_hash(
            storage=storage,
            canonical_identifier=balance_proof.canonical_identifier,
            balance_hash=balance_proof.balance_hash,
            recipient=partner_address,
        )
        assert event_record
        assert event_record.data == event

        event_record = get_event_with_balance_proof_by_locksroot(
            storage=storage,
            canonical_identifier=balance_proof.canonical_identifier,
            recipient=event.recipient,
            locksroot=balance_proof.locksroot,
        )
        assert event_record
        assert event_record.data == event

        # Checking that balance proof attribute can be accessed for all events.
        # Issue https://github.com/raiden-network/raiden/issues/3179
        assert event_record.data.balance_proof == event.balance_proof

    storage.close()
Esempio n. 8
0
def test_pfs_global_messages(
    matrix_transports,
    monkeypatch,
):
    """
    Test that `update_pfs` from `RaidenEventHandler` sends balance proof updates to the global
    PATH_FINDING_BROADCASTING_ROOM room on Send($BalanceProof)* events, i.e. events, that send
    a new balance proof to the channel partner.
    """
    transport = matrix_transports[0]
    transport._client.api.retry_timeout = 0
    transport._send_raw = MagicMock()
    raiden_service = MockRaidenService(None)

    transport.start(
        raiden_service,
        raiden_service.message_handler,
        None,
    )

    pfs_room_name = make_room_alias(transport.network_id,
                                    PATH_FINDING_BROADCASTING_ROOM)
    pfs_room = transport._global_rooms.get(pfs_room_name)
    assert isinstance(pfs_room, Room)
    pfs_room.send_text = MagicMock(spec=pfs_room.send_text)

    raiden_service.transport = transport
    transport.log = MagicMock()

    # create mock events that should trigger a send
    lock = make_lock()
    hash_time_lock = HashTimeLockState(lock.amount, lock.expiration,
                                       lock.secrethash)

    def make_unsigned_balance_proof(nonce):
        return BalanceProofUnsignedState.from_dict(
            make_balance_proof(nonce=nonce,
                               signer=LocalSigner(HOP1_KEY),
                               amount=1).to_dict(), )

    transfer1 = LockedTransferUnsignedState(
        balance_proof=make_unsigned_balance_proof(nonce=1),
        payment_identifier=1,
        token=b'1',
        lock=hash_time_lock,
        target=HOP1,
        initiator=HOP1,
    )
    transfer2 = LockedTransferUnsignedState(
        balance_proof=make_unsigned_balance_proof(nonce=2),
        payment_identifier=1,
        token=b'1',
        lock=hash_time_lock,
        target=HOP1,
        initiator=HOP1,
    )

    send_balance_proof_events = [
        SendLockedTransfer(HOP1, 1, 1, transfer1),
        SendRefundTransfer(HOP1, 1, 1, transfer2),
        SendBalanceProof(HOP1, 1, 1, 1, b'1', b'x' * 32,
                         make_unsigned_balance_proof(nonce=3)),
        SendLockExpired(HOP1, 1, make_unsigned_balance_proof(nonce=4),
                        b'x' * 32),
    ]
    for num, event in enumerate(send_balance_proof_events):
        assert event.balance_proof.nonce == num + 1
    # make sure we cover all configured event types
    assert all(event in [type(event) for event in send_balance_proof_events]
               for event in SEND_BALANCE_PROOF_EVENTS)

    event_handler = raiden_event_handler.RaidenEventHandler()

    # let our mock objects pass validation
    channelstate_mock = Mock()
    channelstate_mock.reveal_timeout = 1

    monkeypatch.setattr(
        raiden_event_handler,
        'get_channelstate_by_token_network_and_partner',
        lambda *args, **kwargs: channelstate_mock,
    )
    monkeypatch.setattr(raiden_event_handler, 'state_from_raiden',
                        lambda *args, **kwargs: 1)
    monkeypatch.setattr(event_handler, 'handle_send_lockedtransfer',
                        lambda *args, **kwargs: 1)
    monkeypatch.setattr(event_handler, 'handle_send_refundtransfer',
                        lambda *args, **kwargs: 1)

    # handle the events
    for event in send_balance_proof_events:
        event_handler.on_raiden_event(
            raiden_service,
            event,
        )
    gevent.idle()

    # ensure all events triggered a send for their respective balance_proof
    # matrix transport may concatenate multiple messages send in one interval
    assert pfs_room.send_text.call_count >= 1
    concatenated_call_args = ' '.join(
        str(arg) for arg in pfs_room.send_text.call_args_list)
    assert all(f'"nonce": {i + 1}' in concatenated_call_args
               for i in range(len(SEND_BALANCE_PROOF_EVENTS)))
    transport.stop()
    transport.get()
Esempio n. 9
0
def test_get_event_with_balance_proof():
    """ All events which contain a balance proof must be found by when
    querying the database.
    """
    serializer = JSONSerializer
    storage = SerializedSQLiteStorage(":memory:", serializer)
    counter = itertools.count()

    lock_expired = SendLockExpired(
        recipient=factories.make_address(),
        message_identifier=next(counter),
        balance_proof=make_balance_proof_from_counter(counter),
        secrethash=sha3(factories.make_secret(next(counter))),
    )
    locked_transfer = SendLockedTransfer(
        recipient=factories.make_address(),
        channel_identifier=factories.make_channel_identifier(),
        message_identifier=next(counter),
        transfer=make_transfer_from_counter(counter),
    )
    balance_proof = SendBalanceProof(
        recipient=factories.make_address(),
        channel_identifier=factories.make_channel_identifier(),
        message_identifier=next(counter),
        payment_identifier=next(counter),
        token_address=factories.make_address(),
        secret=factories.make_secret(next(counter)),
        balance_proof=make_balance_proof_from_counter(counter),
    )
    refund_transfer = SendRefundTransfer(
        recipient=factories.make_address(),
        channel_identifier=factories.make_channel_identifier(),
        message_identifier=next(counter),
        transfer=make_transfer_from_counter(counter),
    )

    events_balanceproofs = [
        (lock_expired, lock_expired.balance_proof),
        (locked_transfer, locked_transfer.balance_proof),
        (balance_proof, balance_proof.balance_proof),
        (refund_transfer, refund_transfer.transfer.balance_proof),
    ]

    timestamp = datetime.utcnow().isoformat(timespec="milliseconds")
    state_change = ""
    for event, _ in events_balanceproofs:
        state_change_identifier = storage.write_state_change(
            state_change, timestamp)
        storage.write_events(state_change_identifier=state_change_identifier,
                             events=[event],
                             log_time=timestamp)

    for event, balance_proof in events_balanceproofs:
        event_record = get_event_with_balance_proof_by_balance_hash(
            storage=storage,
            canonical_identifier=balance_proof.canonical_identifier,
            balance_hash=balance_proof.balance_hash,
        )
        assert event_record.data == event
        # Checking that balance proof attribute can be accessed for all events.
        # Issue https://github.com/raiden-network/raiden/issues/3179
        assert event_record.data.balance_proof == event.balance_proof