Ejemplo n.º 1
0
def test_channelstate_get_unlock_proof():
    number_of_transfers = 100
    lock_amounts = cycle([1, 3, 5, 7, 11])
    lock_secrets = [
        make_secret(i)
        for i in range(number_of_transfers)
    ]

    block_number = 1000
    locked_amount = 0
    settle_timeout = 8
    merkletree_leaves = []
    locked_locks = {}
    unlocked_locks = {}

    for lock_amount, lock_secret in zip(lock_amounts, lock_secrets):
        block_number += 1
        locked_amount += lock_amount

        lock_expiration = block_number + settle_timeout
        lock_secrethash = sha3(lock_secret)
        lock = HashTimeLockState(
            lock_amount,
            lock_expiration,
            lock_secrethash,
        )

        merkletree_leaves.append(lock.lockhash)
        if random.randint(0, 1) == 0:
            locked_locks[lock_secrethash] = lock
        else:
            unlocked_locks[lock_secrethash] = UnlockPartialProofState(lock, lock_secret)

    end_state = NettingChannelEndState(HOP1, 300)
    end_state.secrethashes_to_lockedlocks = locked_locks
    end_state.secrethashes_to_unlockedlocks = unlocked_locks
    end_state.merkletree = MerkleTreeState(compute_layers(merkletree_leaves))

    unlock_proof = channel.get_batch_unlock(end_state)
    assert len(unlock_proof) == len(end_state.merkletree.layers[LEAVES])
    leaves_packed = b''.join(lock.encoded for lock in unlock_proof)

    recomputed_merkle_tree = MerkleTreeState(compute_layers(
        merkle_leaves_from_packed_data(leaves_packed),
    ))
    assert len(recomputed_merkle_tree.layers[LEAVES]) == len(end_state.merkletree.layers[LEAVES])

    computed_merkleroot = merkleroot(recomputed_merkle_tree)
    assert merkleroot(end_state.merkletree) == computed_merkleroot
Ejemplo n.º 2
0
def unlock(
    raiden: "RaidenService",
    payment_channel: PaymentChannel,
    end_state: NettingChannelEndState,
    participant: Address,
    partner: Address,
) -> None:
    merkle_tree_leaves = get_batch_unlock(end_state)

    try:
        payment_channel.unlock(
            participant=participant, partner=partner, merkle_tree_leaves=merkle_tree_leaves
        )
    except ChannelOutdatedError as e:
        log.error(str(e), node=pex(raiden.address))
Ejemplo n.º 3
0
def unlock(
    payment_channel: PaymentChannel,
    end_state: NettingChannelEndState,
    sender: Address,
    receiver: Address,
    given_block_identifier: BlockSpecification,
) -> None:  # pragma: no unittest
    pending_locks = get_batch_unlock(end_state)
    assert pending_locks, "pending lock set is missing"

    payment_channel.unlock(
        sender=sender,
        receiver=receiver,
        pending_locks=pending_locks,
        given_block_identifier=given_block_identifier,
    )
Ejemplo n.º 4
0
    def handle_contract_send_channelunlock(
        self,
        raiden: RaidenService,
        channel_unlock_event: ContractSendChannelBatchUnlock,
    ):
        payment_channel: PaymentChannel = raiden.chain.payment_channel(
            channel_unlock_event.token_network_identifier,
            channel_unlock_event.channel_identifier,
        )
        token_network: TokenNetwork = payment_channel.token_network

        # Fetch on-chain balance hashes for both participants
        participants_details = token_network.detail_participants(
            raiden.address,
            channel_unlock_event.participant,
            channel_unlock_event.channel_identifier,
        )

        our_details = participants_details.our_details
        our_locksroot = our_details.locksroot

        partner_details = participants_details.partner_details
        partner_locksroot = partner_details.locksroot

        is_partner_unlock = (partner_details.address
                             == channel_unlock_event.participant
                             and partner_locksroot != EMPTY_HASH)
        is_our_unlock = (our_details.address
                         == channel_unlock_event.participant
                         and our_locksroot != EMPTY_HASH)

        if is_partner_unlock:
            record = raiden.wal.storage.get_latest_state_change_by_data_field({
                'balance_proof.chain_id':
                raiden.chain.network_id,
                'balance_proof.token_network_identifier':
                to_checksum_address(
                    channel_unlock_event.token_network_identifier, ),
                'balance_proof.channel_identifier':
                channel_unlock_event.channel_identifier,
                'balance_proof.sender':
                to_checksum_address(
                    participants_details.partner_details.address, ),
                'balance_proof.locksroot':
                serialize_bytes(partner_locksroot),
            })
        elif is_our_unlock:
            record = raiden.wal.storage.get_latest_event_by_data_field({
                'balance_proof.chain_id':
                raiden.chain.network_id,
                'balance_proof.token_network_identifier':
                to_checksum_address(
                    channel_unlock_event.token_network_identifier, ),
                'balance_proof.locksroot':
                serialize_bytes(our_locksroot),
                'channel_identifier':
                channel_unlock_event.channel_identifier,
            })
        else:
            raise RaidenUnrecoverableError(
                'Failed to find state/event that match current channel locksroots',
            )

        # Replay state changes until a channel state is reached where
        # this channel state has the participants balance hash.
        restored_channel_state = channel_state_until_state_change(
            raiden=raiden,
            payment_network_identifier=raiden.default_registry.address,
            token_address=channel_unlock_event.token_address,
            channel_identifier=channel_unlock_event.channel_identifier,
            state_change_identifier=record.state_change_identifier,
        )

        # Compute merkle tree leaves from partner state
        our_state = restored_channel_state.our_state
        partner_state = restored_channel_state.partner_state
        if partner_state.address == channel_unlock_event.participant:  # Partner account
            merkle_tree_leaves = get_batch_unlock(partner_state)
        elif our_state.address == channel_unlock_event.participant:  # Our account
            merkle_tree_leaves = get_batch_unlock(our_state)

        try:
            payment_channel.unlock(merkle_tree_leaves)
        except ChannelOutdatedError as e:
            log.error(
                str(e),
                node=pex(raiden.address),
            )
Ejemplo n.º 5
0
    def handle_contract_send_channelunlock(
            self,
            raiden: RaidenService,
            channel_unlock_event: ContractSendChannelBatchUnlock,
    ):
        token_network_identifier = channel_unlock_event.token_network_identifier
        channel_identifier = channel_unlock_event.channel_identifier
        participant = channel_unlock_event.participant
        token_address = channel_unlock_event.token_address

        payment_channel: PaymentChannel = raiden.chain.payment_channel(
            token_network_address=token_network_identifier,
            channel_id=channel_identifier,
        )
        token_network: TokenNetwork = payment_channel.token_network

        participants_details = token_network.detail_participants(
            participant1=raiden.address,
            participant2=participant,
            channel_identifier=channel_identifier,
        )

        our_details = participants_details.our_details
        our_locksroot = our_details.locksroot

        partner_details = participants_details.partner_details
        partner_locksroot = partner_details.locksroot

        is_partner_unlock = (
            partner_details.address == participant and
            partner_locksroot != EMPTY_HASH
        )
        is_our_unlock = (
            our_details.address == participant and
            our_locksroot != EMPTY_HASH
        )

        if is_partner_unlock:
            state_change_record = get_state_change_with_balance_proof(
                storage=raiden.wal.storage,
                chain_id=raiden.chain.network_id,
                token_network_identifier=token_network_identifier,
                channel_identifier=channel_identifier,
                balance_hash=partner_details.balance_hash,
                sender=participants_details.partner_details.address,
            )
            state_change_identifier = state_change_record.state_change_identifier
        elif is_our_unlock:
            event_record = get_event_with_balance_proof(
                storage=raiden.wal.storage,
                chain_id=raiden.chain.network_id,
                token_network_identifier=token_network_identifier,
                channel_identifier=channel_identifier,
                balance_hash=our_details.balance_hash,
            )
            state_change_identifier = event_record.state_change_identifier
        else:
            state_change_identifier = 0

        if not state_change_identifier:
            raise RaidenUnrecoverableError(
                f'Failed to find state/event that match current channel locksroots. '
                f'token:{to_checksum_address(token_address)} '
                f'token_network:{to_checksum_address(token_network_identifier)} '
                f'channel:{channel_identifier} '
                f'participant:{to_checksum_address(participant)} '
                f'our_locksroot:{to_hex(our_locksroot)} '
                f'partner_locksroot:{to_hex(partner_locksroot)} ',
            )

        # Replay state changes until a channel state is reached where
        # this channel state has the participants balance hash.
        restored_channel_state = channel_state_until_state_change(
            raiden=raiden,
            payment_network_identifier=raiden.default_registry.address,
            token_address=token_address,
            channel_identifier=channel_identifier,
            state_change_identifier=state_change_identifier,
        )

        our_state = restored_channel_state.our_state
        partner_state = restored_channel_state.partner_state
        if partner_state.address == participant:
            merkle_tree_leaves = get_batch_unlock(partner_state)
        elif our_state.address == participant:
            merkle_tree_leaves = get_batch_unlock(our_state)

        try:
            payment_channel.unlock(merkle_tree_leaves)
        except ChannelOutdatedError as e:
            log.error(
                str(e),
                node=pex(raiden.address),
            )
Ejemplo n.º 6
0
def test_settled_lock(token_addresses, raiden_network, deposit):
    """ Any transfer following a secret revealed must update the locksroot, so
    hat an attacker cannot reuse a secret to double claim a lock."""
    app0, app1 = raiden_network
    registry_address = app0.raiden.default_registry.address
    token_address = token_addresses[0]
    amount = 30
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        views.state_from_app(app0),
        app0.raiden.default_registry.address,
        token_address,
    )

    address0 = app0.raiden.address
    address1 = app1.raiden.address

    deposit0 = deposit
    deposit1 = deposit

    token_proxy = app0.raiden.chain.token(token_address)
    initial_balance0 = token_proxy.balance_of(address0)
    initial_balance1 = token_proxy.balance_of(address1)

    # Using a pending mediated transfer because this allows us to compute the
    # merkle proof
    identifier = 1
    secret = pending_mediated_transfer(
        raiden_network,
        token_network_identifier,
        amount,
        identifier,
    )

    # Save the merkle tree leaves from the pending transfer, used to test the unlock
    channelstate_0_1 = get_channelstate(app0, app1, token_network_identifier)
    batch_unlock = channel.get_batch_unlock(channelstate_0_1.our_state)
    assert batch_unlock

    claim_lock(raiden_network, identifier, token_network_identifier, secret)

    # Make a new transfer
    direct_transfer(app0, app1, token_network_identifier, amount, identifier=1)
    RaidenAPI(app1.raiden).channel_close(
        registry_address,
        token_address,
        app0.raiden.address,
    )

    waiting.wait_for_settle(
        app1.raiden,
        app1.raiden.default_registry.address,
        token_address,
        [channelstate_0_1.identifier],
        app1.raiden.alarm.sleep_time,
    )

    netting_channel = app1.raiden.chain.payment_channel(
        token_network_identifier,
        channelstate_0_1.identifier,
    )

    # The direct transfer locksroot must not contain the unlocked lock, the
    # unlock must fail.
    with pytest.raises(Exception):
        netting_channel.unlock(
            channelstate_0_1.partner_state.address,
            batch_unlock,
        )

    expected_balance0 = initial_balance0 + deposit0 - amount * 2
    expected_balance1 = initial_balance1 + deposit1 + amount * 2

    assert token_proxy.balance_of(address0) == expected_balance0
    assert token_proxy.balance_of(address1) == expected_balance1
Ejemplo n.º 7
0
def test_settled_lock(token_addresses, raiden_network, deposit):
    """ Any transfer following a secret reveal must update the locksroot, so
    that an attacker cannot reuse a secret to double claim a lock.
    """
    app0, app1 = raiden_network
    registry_address = app0.raiden.default_registry.address
    token_address = token_addresses[0]
    amount = 30
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        views.state_from_app(app0),
        app0.raiden.default_registry.address,
        token_address,
    )

    hold_event_handler = HoldOffChainSecretRequest()
    app1.raiden.raiden_event_handler = hold_event_handler

    address0 = app0.raiden.address
    address1 = app1.raiden.address

    deposit0 = deposit
    deposit1 = deposit

    token_proxy = app0.raiden.chain.token(token_address)
    initial_balance0 = token_proxy.balance_of(address0)
    initial_balance1 = token_proxy.balance_of(address1)
    identifier = 1
    target = app1.raiden.address
    secret = sha3(target)
    secrethash = sha3(secret)

    secret_available = hold_event_handler.hold_secretrequest_for(secrethash=secrethash)

    app0.raiden.start_mediated_transfer_with_secret(
        token_network_identifier,
        amount,
        target,
        identifier,
        secret,
    )

    secret_available.wait()  # wait for the messages to be exchanged

    # Save the merkle tree leaves from the pending transfer, used to test the unlock
    channelstate_0_1 = get_channelstate(app0, app1, token_network_identifier)
    batch_unlock = channel.get_batch_unlock(channelstate_0_1.our_state)
    assert batch_unlock

    hold_event_handler.release_secretrequest_for(
        app1.raiden,
        secrethash,
    )

    mediated_transfer(
        initiator_app=app0,
        target_app=app1,
        token_network_identifier=token_network_identifier,
        amount=amount,
        identifier=2,
    )

    RaidenAPI(app1.raiden).channel_close(
        registry_address,
        token_address,
        app0.raiden.address,
    )

    waiting.wait_for_settle(
        app1.raiden,
        app1.raiden.default_registry.address,
        token_address,
        [channelstate_0_1.identifier],
        app1.raiden.alarm.sleep_time,
    )

    netting_channel = app1.raiden.chain.payment_channel(
        token_network_identifier,
        channelstate_0_1.identifier,
    )

    # The transfer locksroot must not contain the unlocked lock, the
    # unlock must fail.
    with pytest.raises(Exception):
        netting_channel.unlock(
            channelstate_0_1.partner_state.address,
            batch_unlock,
        )

    expected_balance0 = initial_balance0 + deposit0 - amount * 2
    expected_balance1 = initial_balance1 + deposit1 + amount * 2

    assert token_proxy.balance_of(address0) == expected_balance0
    assert token_proxy.balance_of(address1) == expected_balance1
Ejemplo n.º 8
0
def test_settled_lock(token_addresses, raiden_network, deposit):
    """ Any transfer following a secret reveal must update the locksroot, so
    that an attacker cannot reuse a secret to double claim a lock.
    """
    app0, app1 = raiden_network
    registry_address = app0.raiden.default_registry.address
    token_address = token_addresses[0]
    amount = 30
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        views.state_from_app(app0),
        app0.raiden.default_registry.address,
        token_address,
    )

    hold_event_handler = HoldOffChainSecretRequest()
    app1.raiden.raiden_event_handler = hold_event_handler

    address0 = app0.raiden.address
    address1 = app1.raiden.address

    deposit0 = deposit
    deposit1 = deposit

    token_proxy = app0.raiden.chain.token(token_address)
    initial_balance0 = token_proxy.balance_of(address0)
    initial_balance1 = token_proxy.balance_of(address1)
    identifier = 1
    target = app1.raiden.address
    secret = sha3(target)
    secrethash = sha3(secret)

    secret_available = hold_event_handler.hold_secretrequest_for(
        secrethash=secrethash)

    app0.raiden.start_mediated_transfer_with_secret(
        token_network_identifier,
        amount,
        target,
        identifier,
        secret,
    )

    secret_available.wait()  # wait for the messages to be exchanged

    # Save the merkle tree leaves from the pending transfer, used to test the unlock
    channelstate_0_1 = get_channelstate(app0, app1, token_network_identifier)
    batch_unlock = channel.get_batch_unlock(channelstate_0_1.our_state)
    assert batch_unlock

    hold_event_handler.release_secretrequest_for(
        app1.raiden,
        secrethash,
    )

    mediated_transfer(
        initiator_app=app0,
        target_app=app1,
        token_network_identifier=token_network_identifier,
        amount=amount,
        identifier=2,
    )

    RaidenAPI(app1.raiden).channel_close(
        registry_address,
        token_address,
        app0.raiden.address,
    )

    waiting.wait_for_settle(
        app1.raiden,
        app1.raiden.default_registry.address,
        token_address,
        [channelstate_0_1.identifier],
        app1.raiden.alarm.sleep_time,
    )

    netting_channel = app1.raiden.chain.payment_channel(
        token_network_identifier,
        channelstate_0_1.identifier,
    )

    # The transfer locksroot must not contain the unlocked lock, the
    # unlock must fail.
    with pytest.raises(Exception):
        netting_channel.unlock(
            channelstate_0_1.partner_state.address,
            batch_unlock,
        )

    expected_balance0 = initial_balance0 + deposit0 - amount * 2
    expected_balance1 = initial_balance1 + deposit1 + amount * 2

    assert token_proxy.balance_of(address0) == expected_balance0
    assert token_proxy.balance_of(address1) == expected_balance1
Ejemplo n.º 9
0
def test_settled_lock(token_addresses, raiden_network, deposit):
    """ Any transfer following a secret reveal must update the locksroot, so
    that an attacker cannot reuse a secret to double claim a lock.
    """
    app0, app1 = raiden_network
    registry_address = app0.raiden.default_registry.address
    token_address = token_addresses[0]
    amount = PaymentAmount(30)
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(app0), app0.raiden.default_registry.address, token_address
    )
    assert token_network_address
    hold_event_handler = app1.raiden.raiden_event_handler

    address0 = app0.raiden.address
    address1 = app1.raiden.address

    deposit0 = deposit
    deposit1 = deposit

    token_proxy = app0.raiden.proxy_manager.token(token_address)
    initial_balance0 = token_proxy.balance_of(address0)
    initial_balance1 = token_proxy.balance_of(address1)
    identifier = 1
    target = app1.raiden.address
    secret = Secret(sha3(target))
    secrethash = sha256_secrethash(secret)

    secret_available = hold_event_handler.hold_secretrequest_for(secrethash=secrethash)

    app0.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=amount,
        target=target,
        identifier=identifier,
        secret=secret,
    )

    secret_available.wait()  # wait for the messages to be exchanged

    # Save the pending locks from the pending transfer, used to test the unlock
    channelstate_0_1 = get_channelstate(app0, app1, token_network_address)
    batch_unlock = channel.get_batch_unlock(channelstate_0_1.our_state)
    assert batch_unlock

    hold_event_handler.release_secretrequest_for(app1.raiden, secrethash)

    transfer(
        initiator_app=app0,
        target_app=app1,
        token_address=token_address,
        amount=amount,
        identifier=PaymentID(2),
    )

    RaidenAPI(app1.raiden).channel_close(registry_address, token_address, app0.raiden.address)

    waiting.wait_for_settle(
        app1.raiden,
        app1.raiden.default_registry.address,
        token_address,
        [channelstate_0_1.identifier],
        app1.raiden.alarm.sleep_time,
    )
    current_block = app0.raiden.rpc_client.block_number()

    netting_channel = app1.raiden.proxy_manager.payment_channel(
        canonical_identifier=channelstate_0_1.canonical_identifier
    )

    # The transfer locksroot must not contain the unlocked lock, the
    # unlock must fail.
    with pytest.raises(RaidenUnrecoverableError):
        netting_channel.unlock(
            sender=channelstate_0_1.our_state.address,
            receiver=channelstate_0_1.partner_state.address,
            pending_locks=batch_unlock,
            given_block_identifier=current_block,
        )

    expected_balance0 = initial_balance0 + deposit0 - amount * 2
    expected_balance1 = initial_balance1 + deposit1 + amount * 2

    assert token_proxy.balance_of(address0) == expected_balance0
    assert token_proxy.balance_of(address1) == expected_balance1
Ejemplo n.º 10
0
    def handle_contract_send_channelunlock(
        self,
        raiden: RaidenService,
        channel_unlock_event: ContractSendChannelBatchUnlock,
    ):
        token_network_identifier = channel_unlock_event.token_network_identifier
        channel_identifier = channel_unlock_event.channel_identifier
        participant = channel_unlock_event.participant
        token_address = channel_unlock_event.token_address

        payment_channel: PaymentChannel = raiden.chain.payment_channel(
            token_network_address=token_network_identifier,
            channel_id=channel_identifier,
        )
        token_network: TokenNetwork = payment_channel.token_network

        participants_details = token_network.detail_participants(
            participant1=raiden.address,
            participant2=participant,
            channel_identifier=channel_identifier,
        )

        our_details = participants_details.our_details
        our_locksroot = our_details.locksroot

        partner_details = participants_details.partner_details
        partner_locksroot = partner_details.locksroot

        is_partner_unlock = (partner_details.address == participant
                             and partner_locksroot != EMPTY_HASH)
        is_our_unlock = (our_details.address == participant
                         and our_locksroot != EMPTY_HASH)

        if not is_partner_unlock and not is_our_unlock:
            # In the case that someone else sent the unlock we do nothing
            # Check https://github.com/raiden-network/raiden/issues/3152
            # for more details
            log.warning(
                'Onchain unlock already mined',
                token_address=token_address,
                channel_identifier=channel_identifier,
                participant=participant,
            )
            return

        record = get_state_change_or_event_with_balance_proof(
            storage=raiden.wal.storage,
            chain_id=raiden.chain.network_id,
            token_network_identifier=token_network_identifier,
            channel_identifier=channel_identifier,
            is_our_unlock=is_our_unlock,
            is_partner_unlock=is_partner_unlock,
            our_balance_hash=our_details.balance_hash,
            partner_balance_hash=partner_details.balance_hash,
            sender=participants_details.partner_details.address,
        )

        if not record.state_change_identifier:
            log.warning(
                f'Unlock not done. '
                f'Failed to find state/event that match current channel locksroots. '
                f'token:{to_checksum_address(token_address)} '
                f'token_network:{to_checksum_address(token_network_identifier)} '
                f'channel:{channel_identifier} '
                f'participant:{to_checksum_address(participant)} '
                f'our_locksroot:{to_hex(our_locksroot)} '
                f'partner_locksroot:{to_hex(partner_locksroot)} ', )
            return

        # Replay state changes until a channel state is reached where
        # this channel state has the participants balance hash.
        restored_channel_state = channel_state_until_state_change(
            raiden=raiden,
            payment_network_identifier=raiden.default_registry.address,
            token_address=token_address,
            channel_identifier=channel_identifier,
            state_change_identifier=record.state_change_identifier,
        )

        our_state = restored_channel_state.our_state
        partner_state = restored_channel_state.partner_state
        if partner_state.address == participant:
            merkle_tree_leaves = get_batch_unlock(partner_state)
        elif our_state.address == participant:
            merkle_tree_leaves = get_batch_unlock(our_state)

        try:
            payment_channel.unlock(merkle_tree_leaves)
        except ChannelOutdatedError as e:
            log.error(
                str(e),
                node=pex(raiden.address),
            )
Ejemplo n.º 11
0
    def handle_contract_send_channelunlock(
            self,
            raiden: RaidenService,
            channel_unlock_event: ContractSendChannelBatchUnlock,
    ):
        token_network_identifier = channel_unlock_event.token_network_identifier
        channel_identifier = channel_unlock_event.channel_identifier
        participant = channel_unlock_event.participant
        token_address = channel_unlock_event.token_address

        payment_channel: PaymentChannel = raiden.chain.payment_channel(
            token_network_address=token_network_identifier,
            channel_id=channel_identifier,
        )
        token_network: TokenNetwork = payment_channel.token_network

        participants_details = token_network.detail_participants(
            participant1=raiden.address,
            participant2=participant,
            channel_identifier=channel_identifier,
        )

        our_details = participants_details.our_details
        our_locksroot = our_details.locksroot

        partner_details = participants_details.partner_details
        partner_locksroot = partner_details.locksroot

        is_partner_unlock = (
            partner_details.address == participant and
            partner_locksroot != EMPTY_HASH
        )
        is_our_unlock = (
            our_details.address == participant and
            our_locksroot != EMPTY_HASH
        )

        if is_partner_unlock:
            state_change_record = get_state_change_with_balance_proof_by_locksroot(
                storage=raiden.wal.storage,
                chain_id=raiden.chain.network_id,
                token_network_identifier=token_network_identifier,
                channel_identifier=channel_identifier,
                locksroot=partner_locksroot,
                sender=participants_details.partner_details.address,
            )
            state_change_identifier = state_change_record.state_change_identifier
        elif is_our_unlock:
            event_record = get_event_with_balance_proof_by_locksroot(
                storage=raiden.wal.storage,
                chain_id=raiden.chain.network_id,
                token_network_identifier=token_network_identifier,
                channel_identifier=channel_identifier,
                locksroot=our_locksroot.balance_hash,
            )
            state_change_identifier = event_record.state_change_identifier
        else:
            # In the case that someone else sent the unlock we do nothing
            # Check https://github.com/raiden-network/raiden/issues/3152
            # for more details
            log.warning(
                'Onchain unlock already mined',
                token_address=token_address,
                channel_identifier=channel_identifier,
                participant=participant,
            )
            return

        if not state_change_identifier:
            raise RaidenUnrecoverableError(
                f'Failed to find state/event that match current channel locksroots. '
                f'chain_id:{raiden.chain.network_id} '
                f'token:{to_checksum_address(token_address)} '
                f'token_network:{to_checksum_address(token_network_identifier)} '
                f'channel:{channel_identifier} '
                f'participant:{to_checksum_address(participant)} '
                f'our_locksroot:{to_hex(our_locksroot)} '
                f'our_balance_hash:{to_hex(our_details.balance_hash)} '
                f'partner_locksroot:{to_hex(partner_locksroot)} '
                f'partner_balancehash:{to_hex(partner_details.balance_hash)} ',
            )

        # Replay state changes until a channel state is reached where
        # this channel state has the participants balance hash.
        restored_channel_state = channel_state_until_state_change(
            raiden=raiden,
            payment_network_identifier=raiden.default_registry.address,
            token_address=token_address,
            channel_identifier=channel_identifier,
            state_change_identifier=state_change_identifier,
        )

        our_state = restored_channel_state.our_state
        partner_state = restored_channel_state.partner_state
        if partner_state.address == participant:
            merkle_tree_leaves = get_batch_unlock(partner_state)
        elif our_state.address == participant:
            merkle_tree_leaves = get_batch_unlock(our_state)

        try:
            payment_channel.unlock(merkle_tree_leaves)
        except ChannelOutdatedError as e:
            log.error(
                str(e),
                node=pex(raiden.address),
            )
Ejemplo n.º 12
0
def test_settled_lock(token_addresses, raiden_network, deposit):
    """ Any transfer following a secret revealed must update the locksroot, so
    hat an attacker cannot reuse a secret to double claim a lock."""
    app0, app1 = raiden_network
    registry_address = app0.raiden.default_registry.address
    token_address = token_addresses[0]
    amount = 30
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        views.state_from_app(app0),
        app0.raiden.default_registry.address,
        token_address,
    )

    address0 = app0.raiden.address
    address1 = app1.raiden.address

    deposit0 = deposit
    deposit1 = deposit

    token_proxy = app0.raiden.chain.token(token_address)
    initial_balance0 = token_proxy.balance_of(address0)
    initial_balance1 = token_proxy.balance_of(address1)

    # Using a pending mediated transfer because this allows us to compute the
    # merkle proof
    identifier = 1
    secret = pending_mediated_transfer(
        raiden_network,
        token_network_identifier,
        amount,
        identifier,
    )

    # Save the merkle tree leaves from the pending transfer, used to test the unlock
    channelstate_0_1 = get_channelstate(app0, app1, token_network_identifier)
    batch_unlock = channel.get_batch_unlock(channelstate_0_1.our_state)
    assert batch_unlock

    claim_lock(raiden_network, identifier, token_network_identifier, secret)

    # Make a new transfer
    direct_transfer(app0, app1, token_network_identifier, amount, identifier=1)
    RaidenAPI(app1.raiden).channel_close(
        registry_address,
        token_address,
        app0.raiden.address,
    )

    waiting.wait_for_settle(
        app1.raiden,
        app1.raiden.default_registry.address,
        token_address,
        [channelstate_0_1.identifier],
        app1.raiden.alarm.sleep_time,
    )

    netting_channel = app1.raiden.chain.payment_channel(
        token_network_identifier,
        channelstate_0_1.identifier,
    )

    # The direct transfer locksroot must not contain the unlocked lock, the
    # unlock must fail.
    with pytest.raises(Exception):
        netting_channel.unlock(
            channelstate_0_1.partner_state.address,
            batch_unlock,
        )

    expected_balance0 = initial_balance0 + deposit0 - amount * 2
    expected_balance1 = initial_balance1 + deposit1 + amount * 2

    assert token_proxy.balance_of(address0) == expected_balance0
    assert token_proxy.balance_of(address1) == expected_balance1
Ejemplo n.º 13
0
def test_settled_lock(
    token_addresses: List[TokenAddress], raiden_network: List[App], deposit: TokenAmount
) -> None:
    """ Any transfer following a secret reveal must update the locksroot, so
    that an attacker cannot reuse a secret to double claim a lock.
    """
    app0, app1 = raiden_network
    registry_address = app0.raiden.default_registry.address
    token_address = token_addresses[0]
    amount = PaymentAmount(30)
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(app0), app0.raiden.default_registry.address, token_address
    )
    assert token_network_address

    hold_event_handler = app1.raiden.raiden_event_handler

    msg = "hold event handler necessary to control messages"
    assert isinstance(hold_event_handler, HoldRaidenEventHandler), msg

    address0 = app0.raiden.address
    address1 = app1.raiden.address

    deposit0 = deposit
    deposit1 = deposit

    token_proxy = app0.raiden.proxy_manager.token(token_address, BLOCK_ID_LATEST)
    initial_balance0 = token_proxy.balance_of(address0)
    initial_balance1 = token_proxy.balance_of(address1)
    identifier = factories.make_payment_id()
    target = TargetAddress(app1.raiden.address)
    secret = factories.make_secret()
    secrethash = sha256_secrethash(secret)

    secret_available = hold_event_handler.hold_secretrequest_for(secrethash=secrethash)

    app0.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=amount,
        target=target,
        identifier=identifier,
        secret=secret,
    )

    secret_available.wait()  # wait for the messages to be exchanged

    # Save the pending locks from the pending transfer, used to test the unlock
    channelstate_0_1 = get_channelstate(app0, app1, token_network_address)
    batch_unlock = channel.get_batch_unlock(channelstate_0_1.our_state)
    assert batch_unlock

    hold_event_handler.release_secretrequest_for(app1.raiden, secrethash)

    transfer(
        initiator_app=app0,
        target_app=app1,
        token_address=token_address,
        amount=amount,
        identifier=PaymentID(2),
    )

    # The channel state has to be recovered before the settlement, otherwise
    # the object is cleared from the node's state.
    channelstate_1_0 = get_channelstate(app1, app0, token_network_address)

    RaidenAPI(app1.raiden).channel_close(registry_address, token_address, app0.raiden.address)

    waiting.wait_for_settle(
        app1.raiden,
        app1.raiden.default_registry.address,
        token_address,
        [channelstate_0_1.identifier],
        app1.raiden.alarm.sleep_time,
    )
    current_block = app0.raiden.rpc_client.block_number()

    netting_channel = app1.raiden.proxy_manager.payment_channel(
        channel_state=channelstate_1_0, block_identifier=BLOCK_ID_LATEST
    )

    # The transfer locksroot must not contain the unlocked lock, the
    # unlock must fail.
    with pytest.raises(RaidenUnrecoverableError):
        netting_channel.unlock(
            sender=channelstate_0_1.our_state.address,
            receiver=channelstate_0_1.partner_state.address,
            pending_locks=batch_unlock,
            given_block_identifier=current_block,
        )

    expected_balance0 = initial_balance0 + deposit0 - amount * 2
    expected_balance1 = initial_balance1 + deposit1 + amount * 2

    assert token_proxy.balance_of(address0) == expected_balance0
    assert token_proxy.balance_of(address1) == expected_balance1