def test_get_channel_list(raiden_network, token_addresses):
    app0, app1, app2 = raiden_network  # pylint: disable=unbalanced-tuple-unpacking

    channel0 = channel(app0, app1, token_addresses[0])
    channel1 = channel(app1, app0, token_addresses[0])
    channel2 = channel(app0, app2, token_addresses[0])

    api0 = RaidenAPI(app0.raiden)
    api1 = RaidenAPI(app1.raiden)
    api2 = RaidenAPI(app2.raiden)

    assert channel0, channel2 in api0.get_channel_list()
    assert channel0 in api0.get_channel_list(partner_address=app1.raiden.address)
    assert channel1 in api1.get_channel_list(token_address=token_addresses[0])
    assert channel1 in api1.get_channel_list(token_addresses[0], app0.raiden.address)
    assert not api1.get_channel_list(partner_address=app2.raiden.address)

    assert not api1.get_channel_list(
        token_address=token_addresses[0],
        partner_address=app2.raiden.address,
    )

    assert not api2.get_channel_list(
        token_address=app2.raiden.address,
    )
Exemple #2
0
def test_fullnetwork(raiden_chain):
    app0, app1, app2 = raiden_chain  # pylint: disable=unbalanced-tuple-unpacking

    asset_address = app0.raiden.chain.default_registry.asset_addresses()[0]

    amount = 80
    random.seed(0)
    direct_transfer(app0, app1, asset_address, amount)
    # Assert default identifier is generated correctly
    fchannel = channel(app0, app1, asset_address)
    last_transfer = get_sent_transfer(fchannel, 0)
    random.seed(0)
    assert_identifier_correct(app0, asset_address, app1.raiden.address, last_transfer.identifier)

    amount = 50
    direct_transfer(app1, app2, asset_address, amount)

    amount = 30
    random.seed(0)
    mediated_transfer(
        app1,
        app2,
        asset_address,
        amount
    )
    # Assert default identifier is generated correctly
    fchannel = channel(app1, app2, asset_address)
    last_transfer = get_sent_transfer(fchannel, 1)
    random.seed(0)
    assert_identifier_correct(app1, asset_address, app2.raiden.address, last_transfer.identifier)
def test_direct_transfer_to_offline_node(raiden_network, token_addresses):
    token_address = token_addresses[0]
    app0, app1 = raiden_network

    # Wait until the initialization of the node is complete and then stop it
    gevent.wait([app1.raiden.start_event])
    app1.raiden.stop()

    amount = 10
    target = app1.raiden.address
    async_result = app0.raiden.direct_transfer_async(
        token_address,
        amount,
        target,
        identifier=1,
    )

    assert async_result.wait(5) is None

    app1.raiden.start()

    assert async_result.wait(5) is True

    assert_mirror(
        channel(app0, app1, token_address),
        channel(app1, app0, token_address),
    )
def test_transfer(raiden_network, assets_addresses):
    app0, app1 = raiden_network  # pylint: disable=unbalanced-tuple-unpacking

    channel0 = channel(app0, app1, assets_addresses[0])
    channel1 = channel(app1, app0, assets_addresses[0])

    contract_balance0 = channel0.contract_balance
    contract_balance1 = channel1.contract_balance

    # check agreement on addresses
    address0 = channel0.our_state.address
    address1 = channel1.our_state.address

    app0_asset = app0.raiden.managers_by_asset_address.keys()[0]
    app1_asset = app1.raiden.managers_by_asset_address.keys()[0]

    app0_partners = app0.raiden.managers_by_asset_address.values()[0].partneraddress_channel.keys()
    app1_partners = app1.raiden.managers_by_asset_address.values()[0].partneraddress_channel.keys()

    assert channel0.asset_address == channel1.asset_address
    assert app0_asset == app1_asset
    assert app1.raiden.address in app0_partners
    assert app0.raiden.address in app1_partners

    netting_address = channel0.external_state.netting_channel.address
    netting_channel = app0.raiden.chain.netting_channel(netting_address)

    # check balances of channel and contract are equal
    details0 = netting_channel.detail(address0)
    details1 = netting_channel.detail(address1)

    assert contract_balance0 == details0['our_balance']
    assert contract_balance1 == details1['our_balance']

    assert_synched_channels(
        channel0, contract_balance0, [],
        channel1, contract_balance1, [],
    )

    amount = 10

    direct_transfer = channel0.create_directtransfer(
        amount,
        1  # TODO: fill in identifier
    )
    app0.raiden.sign(direct_transfer)
    channel0.register_transfer(direct_transfer)
    channel1.register_transfer(direct_transfer)

    # check the contract is intact
    assert details0 == netting_channel.detail(address0)
    assert details1 == netting_channel.detail(address1)

    assert channel0.contract_balance == contract_balance0
    assert channel1.contract_balance == contract_balance1

    assert_synched_channels(
        channel0, contract_balance0 - amount, [],
        channel1, contract_balance1 + amount, [],
    )
def test_receive_direct_before_deposit(raiden_network):
    """Regression test that ensures we accept incoming direct transfers, even if we don't have
    any back channel balance.  """
    app0, app1, _ = raiden_network

    token_address = app0.raiden.default_registry.token_addresses()[0]
    channel_0_1 = channel(app0, app1, token_address)
    back_channel = channel(app1, app0, token_address)

    assert not channel_0_1.can_transfer
    assert not back_channel.can_transfer

    deposit_amount = 2
    transfer_amount = 1
    api0 = RaidenAPI(app0.raiden)
    api0.deposit(token_address, app1.raiden.address, deposit_amount)
    app0.raiden.chain.next_block()
    gevent.sleep(app0.raiden.alarm.wait_time)

    assert channel_0_1.can_transfer
    assert not back_channel.can_transfer
    assert back_channel.distributable == 0

    api0.transfer_and_wait(token_address, transfer_amount, app1.raiden.address)
    gevent.sleep(app1.raiden.alarm.wait_time)

    assert back_channel.can_transfer
    assert back_channel.distributable == transfer_amount
def test_settled_lock(token_addresses, raiden_network, settle_timeout, reveal_timeout):
    """ Any transfer following a secret revealed must update the locksroot, so
    that an attacker cannot reuse a secret to double claim a lock.
    """
    token = token_addresses[0]
    amount = 30

    app0, app1, app2, _ = raiden_network  # pylint: disable=unbalanced-tuple-unpacking

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

    forward_channel = channel(app0, app1, token)
    back_channel = channel(app1, app0, token)

    deposit0 = forward_channel.contract_balance
    deposit1 = back_channel.contract_balance

    token_contract = app0.raiden.chain.token(token)
    balance0 = token_contract.balance_of(address0)
    balance1 = token_contract.balance_of(address1)

    # A pending mediated transfer
    identifier = 1
    expiration = app0.raiden.chain.block_number() + settle_timeout - reveal_timeout
    secret = pending_mediated_transfer(
        raiden_network,
        token,
        amount,
        identifier,
        expiration,
    )
    hashlock = sha3(secret)

    # Get the proof to unlock the pending lock
    secret_transfer = get_received_transfer(back_channel, 0)
    lock = back_channel.partner_state.get_lock_by_hashlock(hashlock)
    unlock_proof = back_channel.partner_state.compute_proof_for_lock(secret, lock)

    # Update the hashlock
    claim_lock(raiden_network, identifier, token, secret)
    direct_transfer(app0, app1, token, amount, identifier=1)

    # The direct transfer locksroot must remove the unlocked lock and update
    # the transferred amount, the withdraw must fail.
    balance_proof = back_channel.partner_state.balance_proof
    back_channel.external_state.close(balance_proof)
    with pytest.raises(Exception):
        back_channel.external_state.netting_channel.withdraw(
            [(unlock_proof, secret_transfer.lock.as_bytes, secret)],
        )

    settle_expiration = app2.raiden.chain.block_number() + settle_timeout
    wait_until_block(app2.raiden.chain, settle_expiration)
    back_channel.external_state.netting_channel.settle()

    assert token_contract.balance_of(address0) == balance0 + deposit0 - amount * 2
    assert token_contract.balance_of(address1) == balance1 + deposit1 + amount * 2
def test_secret_revealed(raiden_chain, deposit, settle_timeout, events_poll_timeout):
    app0, app1, app2 = raiden_chain

    token_address = app0.raiden.default_registry.token_addresses()[0]
    amount = 10

    channel21 = channel(app2, app1, token_address)
    netting_channel = channel21.external_state.netting_channel

    identifier = 1
    expiration = app2.raiden.get_block_number() + settle_timeout - 3

    secret = pending_mediated_transfer(
        raiden_chain,
        token_address,
        amount,
        identifier,
        expiration,
    )
    hashlock = sha3(secret)

    gevent.sleep(.1)  # wait for the messages

    lock = channel21.our_state.get_lock_by_hashlock(hashlock)
    proof = channel21.our_state.compute_proof_for_lock(secret, lock)

    # the secret hasn't been revealed yet (through messages)
    assert len(channel21.our_state.hashlocks_to_pendinglocks) == 1
    proofs = list(channel21.our_state.get_known_unlocks())
    assert len(proofs) == 0

    netting_channel.close(channel21.our_state.balance_proof)

    # reveal it through the blockchain (this needs to emit the SecretRevealed event)
    netting_channel.withdraw(
        app2.raiden.address,
        [proof],
    )

    settle_expiration = app0.raiden.chain.block_number() + settle_timeout
    wait_until_block(app0.raiden.chain, settle_expiration)

    channel21.settle_event.wait(timeout=10)

    assert_synched_channels(
        channel(app1, app2, token_address), deposit - amount, [],
        channel(app2, app1, token_address), deposit + amount, [],
    )

    assert_synched_channels(
        channel(app0, app1, token_address), deposit - amount, [],
        channel(app1, app2, token_address), deposit + amount, [],
    )
def test_settled_lock(assets_addresses, raiden_network, settle_timeout):
    """ Any transfer following a secret revealed must update the locksroot, so
    that an attacker cannot reuse a secret to double claim a lock.
    """
    asset = assets_addresses[0]
    amount = 30

    app0, app1, app2, app3 = raiden_network  # pylint: disable=unbalanced-tuple-unpacking

    # mediated transfer
    secret = pending_mediated_transfer(raiden_network, asset, amount)

    # get a proof for the pending transfer
    back_channel = channel(app1, app0, asset)
    secret_transfer = get_received_transfer(back_channel, 0)
    merkle_proof = back_channel.our_state.locked.get_proof(secret_transfer)

    # reveal the secret
    register_secret(raiden_network, asset, secret)

    # a new transfer to update the hashlock
    direct_transfer(app0, app1, asset, amount)

    forward_channel = channel(app0, app1, asset)
    last_transfer = get_sent_transfer(forward_channel, 1)

    # call close giving the secret for a transfer that has being revealed
    back_channel.external_state.netting_channel.close(
        app1.raiden.address,
        last_transfer,
        None
    )

    # check that the double unlock will failed
    with pytest.raises(Exception):
        back_channel.external_state.netting_channel.unlock(
            app1.raiden.address,
            [(merkle_proof, secret_transfer.lock.as_bytes, secret)],
        )

    # forward the block number to allow settle
    for _ in range(settle_timeout):
        app2.raiden.chain.next_block()

    back_channel.external_state.netting_channel.settle()

    participant0 = back_channel.external_state.netting_channel.contract.participants[app0.raiden.address]
    participant1 = back_channel.external_state.netting_channel.contract.participants[app1.raiden.address]

    assert participant0.netted == participant0.deposit - amount * 2
    assert participant1.netted == participant1.deposit + amount * 2
Exemple #9
0
def test_secret_revealed(deployed_network, deposit):
    app0, app1, app2 = deployed_network

    asset_address = app0.raiden.chain.default_registry.asset_addresses()[0]
    amount = 10

    secret = pending_mediated_transfer(deployed_network, asset_address, amount)

    mediated_transfer = get_received_transfer(
        channel(app2, app1, asset_address),
        0,
    )

    merkle_proof = channel(app2, app1, asset_address).our_state.locked.get_proof(mediated_transfer)

    channel(app2, app1, asset_address).netting_contract.unlock(
        [(merkle_proof, mediated_transfer.lock, secret)],
    )

    gevent.sleep(0.1)  # let the task run

    assert_synched_channels(
        channel(app1, app2, asset_address), deposit - amount, [],
        channel(app2, app1, asset_address), deposit + amount, [],
    )

    assert_synched_channels(
        channel(app0, app1, asset_address), deposit - amount, [],
        channel(app1, app2, asset_address), deposit + amount, [],
    )
def test_mediated_transfer_with_entire_deposit(raiden_network, token_addresses, deposit):
    alice_app, bob_app, charlie_app = raiden_network
    token_address = token_addresses[0]

    result = alice_app.raiden.mediated_transfer_async(
        token_address,
        deposit,
        charlie_app.raiden.address,
        identifier=1,
    )

    channel_ab = channel(alice_app, bob_app, token_address)
    assert channel_ab.locked == deposit
    assert channel_ab.outstanding == 0
    assert channel_ab.distributable == 0

    assert result.wait(timeout=10)
    gevent.sleep(.1)  # wait for charlie to sync

    result = charlie_app.raiden.mediated_transfer_async(
        token_address,
        deposit * 2,
        alice_app.raiden.address,
        identifier=1,
    )
    assert result.wait(timeout=10)
def test_api_channel_events(raiden_chain):
    app0, app1 = raiden_chain  # pylint: disable=unbalanced-tuple-unpacking
    token_address = app0.raiden.default_registry.token_addresses()[0]
    channel_0_1 = channel(app0, app1, token_address)

    amount = 30
    direct_transfer(
        app0,
        app1,
        token_address,
        amount,
        identifier=1,
    )

    results = RaidenAPI(app0.raiden).get_channel_events(channel_0_1.channel_address, 0)
    assert len(results) == 3
    max_block = 0
    for idx, result in enumerate(results):
        if result['block_number'] > max_block:
            max_block = result['block_number']
            assert max_block != 0

        if idx == 2:
            assert result['_event_type'] == 'EventTransferSentSuccess'
            assert result['amount'] == amount
            assert result['target'] == app1.raiden.address
        else:
            assert result['_event_type'] == b'ChannelNewBalance'

    assert max_block != 0

    results = RaidenAPI(app0.raiden).get_channel_events(
        channel_0_1.channel_address, max_block + 1, max_block + 100
    )
    assert not results
def test_token_swap(raiden_network, deposit, settle_timeout):
    app0, app1 = raiden_network

    maker_address = app0.raiden.address
    taker_address = app1.raiden.address

    maker_token, taker_token = list(app0.raiden.token_to_channelgraph.keys())[:2]
    maker_amount = 70
    taker_amount = 30

    identifier = 313
    RaidenAPI(app1.raiden).expect_token_swap(
        identifier,
        maker_token,
        maker_amount,
        maker_address,
        taker_token,
        taker_amount,
        taker_address,
    )

    async_result = RaidenAPI(app0.raiden).token_swap_async(
        identifier,
        maker_token,
        maker_amount,
        maker_address,
        taker_token,
        taker_amount,
        taker_address,
    )

    assert async_result.wait()

    # wait for the taker to receive and process the messages
    gevent.sleep(0.5)

    assert_synched_channels(
        channel(app0, app1, maker_token), deposit - maker_amount, [],
        channel(app1, app0, maker_token), deposit + maker_amount, [],
    )

    assert_synched_channels(
        channel(app0, app1, taker_token), deposit + taker_amount, [],
        channel(app1, app0, taker_token), deposit - taker_amount, [],
    )
def test_setup(raiden_network, deposit, token_addresses):
    app0, app1 = raiden_network  # pylint: disable=unbalanced-tuple-unpacking

    tokens0 = list(app0.raiden.token_to_channelgraph.keys())
    tokens1 = list(app1.raiden.token_to_channelgraph.keys())

    assert len(tokens0) == 1
    assert len(tokens1) == 1
    assert tokens0 == tokens1
    assert tokens0[0] == token_addresses[0]

    token_address = tokens0[0]
    channel0 = channel(app0, app1, token_address)
    channel1 = channel(app1, app0, token_address)

    assert channel0 and channel1

    assert_synched_channels(
        channel0, deposit, [],
        channel1, deposit, [],
    )
Exemple #14
0
def test_setup(raiden_network, deposit, assets_addresses):
    app0, app1 = raiden_network  # pylint: disable=unbalanced-tuple-unpacking

    assets0 = app0.raiden.managers_by_asset_address.keys()
    assets1 = app1.raiden.managers_by_asset_address.keys()

    assert len(assets0) == 1
    assert len(assets1) == 1
    assert assets0 == assets1
    assert assets0[0] == assets_addresses[0]

    asset_address = assets0[0]
    channel0 = channel(app0, app1, asset_address)
    channel1 = channel(app1, app0, asset_address)

    assert channel0 and channel1

    assert_synched_channels(
        channel0, deposit, [],
        channel1, deposit, [],
    )
def test_deposit_updates_balance_immediately(raiden_chain, token_addresses):
    """Test that the balance of a channel gets updated by the deposit() call
    immediately and without having to wait for the `ContractReceiveBalance`
    message since the API needs to return the channel with the deposit balance
    updated"""
    app0, app1 = raiden_chain  # pylint: disable=unbalanced-tuple-unpacking

    api0 = RaidenAPI(app0.raiden)

    token_address = token_addresses[0]
    channel_0_1 = channel(app0, app1, token_address)
    old_balance = channel_0_1.contract_balance
    returned_channel = api0.deposit(token_address, app1.raiden.address, 10)
    assert returned_channel.contract_balance == old_balance + 10
def test_receive_mediatedtransfer_invalid_address(raiden_network, private_keys):
    alice_app = raiden_network[0]
    bob_app = raiden_network[1]

    graph = list(alice_app.raiden.token_to_channelgraph.values())[0]
    token_address = graph.token_address

    channel0 = channel(alice_app, bob_app, token_address)

    mt_helper = MediatedTransferTestHelper(raiden_network, graph)
    initiator_address = alice_app.raiden.address
    path = mt_helper.get_paths_of_length(initiator_address, 2)

    alice_address, bob_address, charlie_address = path
    amount = 10
    result = alice_app.raiden.mediated_transfer_async(
        token_address,
        amount,
        charlie_address,
        identifier=1,
    )

    assert result.wait(timeout=10)
    gevent.sleep(1.)

    # and now send one more mediated transfer with the same nonce, simulating
    # an out-of-order/resent message that arrives late
    lock = Lock(amount, 1, UNIT_HASHLOCK)
    identifier = create_default_identifier()
    mediated_transfer = MediatedTransfer(
        identifier=identifier,
        nonce=1,
        token=token_address,
        channel=channel0.channel_address,
        transferred_amount=amount,
        recipient=bob_address,
        locksroot=UNIT_HASHLOCK,
        lock=lock,
        target=charlie_address,
        initiator=initiator_address,
        fee=0
    )
    alice_key = PrivateKey(private_keys[0])
    target_app = None
    for app in raiden_network:
        if app.raiden.address not in path:
            target_app = app
            break
    sign_and_send(mediated_transfer, alice_key, alice_address, target_app)
def test_receive_mediatedtransfer_outoforder(raiden_network, private_keys):
    alice_app = raiden_network[0]
    bob_app = raiden_network[1]
    charlie_app = raiden_network[2]

    graph = list(alice_app.raiden.token_to_channelgraph.values())[0]
    token_address = graph.token_address

    channel0 = channel(
        alice_app,
        bob_app,
        token_address,
    )

    amount = 10
    result = alice_app.raiden.mediated_transfer_async(
        token_address,
        amount,
        charlie_app.raiden.address,
        identifier=1,
    )

    assert result.wait(timeout=10)

    lock = Lock(amount, 1, UNIT_HASHLOCK)
    identifier = create_default_identifier()
    mediated_transfer = MediatedTransfer(
        identifier=identifier,
        nonce=1,
        token=token_address,
        channel=channel0.channel_address,
        transferred_amount=amount,
        recipient=bob_app.raiden.address,
        locksroot=UNIT_HASHLOCK,
        lock=lock,
        target=charlie_app.raiden.address,
        initiator=alice_app.raiden.address,
        fee=0
    )
    alice_key = PrivateKey(private_keys[0])

    # send the invalid mediated transfer from alice to bob with the same nonce
    sign_and_send(
        mediated_transfer,
        alice_key,
        alice_app.raiden.address,
        bob_app,
    )
def test_close_channel_lack_of_balance_proof(
        raiden_chain,
        reveal_timeout,
        settle_timeout,
        token_addresses):

    app0, app1 = raiden_chain
    token_address = token_addresses[0]

    channel01 = channel(app0, app1, token_address)

    secret = sha3(b'test_close_channel_lack_of_balance_proof')
    hashlock = sha3(secret)

    fee = 0
    amount = 100
    identifier = 1
    expiration = app0.raiden.get_block_number() + reveal_timeout * 2
    transfer = channel01.create_mediatedtransfer(
        app0.raiden.address,
        app1.raiden.address,
        fee,
        amount,
        identifier,
        expiration,
        hashlock,
    )
    app0.raiden.sign(transfer)
    async_result = app0.raiden.send_async(app1.raiden.address, transfer)
    assert async_result.wait()

    reveal_secret = RevealSecret(secret)
    app0.raiden.sign(reveal_secret)
    async_result = app0.raiden.send_async(app1.raiden.address, reveal_secret)
    assert async_result.wait()

    wait_until = app0.raiden.get_block_number() + settle_timeout + 2
    wait_until_block(app0.raiden.chain, wait_until)

    # required for tester blockchain: let the alarm task run
    gevent.sleep(1)

    assert channel01.state != CHANNEL_STATE_OPENED
Exemple #19
0
def test_close_channel_lack_of_balance_proof(raiden_chain, reveal_timeout,
                                             settle_timeout, token_addresses):

    app0, app1 = raiden_chain
    token_address = token_addresses[0]

    channel01 = channel(app0, app1, token_address)

    secret = sha3('test_close_channel_lack_of_balance_proof')
    hashlock = sha3(secret)

    fee = 0
    amount = 100
    identifier = 1
    expiration = app0.raiden.get_block_number() + reveal_timeout * 2
    transfer = channel01.create_mediatedtransfer(
        app0.raiden.address,
        app1.raiden.address,
        fee,
        amount,
        identifier,
        expiration,
        hashlock,
    )
    app0.raiden.sign(transfer)
    async_result = app0.raiden.send_async(app1.raiden.address, transfer)
    assert async_result.wait()

    reveal_secret = RevealSecret(secret)
    app0.raiden.sign(reveal_secret)
    async_result = app0.raiden.send_async(app1.raiden.address, reveal_secret)
    assert async_result.wait()

    wait_until = app0.raiden.get_block_number() + settle_timeout + 2
    wait_until_block(app0.raiden.chain, wait_until)

    # required for tester blockchain: let the alarm task run
    gevent.sleep(1)

    assert channel01.state != CHANNEL_STATE_OPENED
def test_settled_lock():
    """ After a lock has it's secret revealed and a transfer happened, the lock
    cannot be used to net any value with the contract.
    """
    deposit = 100
    asset = sha3('test_settled_lock')[:20]
    amount = 30

    # pylint: disable=unbalanced-tuple-unpacking
    apps = create_sequential_network(num_nodes=4, deposit=deposit, asset=asset)

    # mediated transfer with the secret revealed
    transfer(apps[0], apps[3], asset, amount)

    # create the latest transfer
    direct_transfer(apps[0], apps[1], asset, amount)

    secret = ''  # need to get the secret
    attack_channel = channel(apps[2], apps[1], asset)
    secret_transfer = get_received_transfer(attack_channel, 0)
    last_transfer = get_received_transfer(attack_channel, 1)
    nettingcontract_address = attack_channel.nettingcontract_address

    # create a fake proof
    merkle_proof = attack_channel.our_state.locked.get_proof(secret_transfer)

    # call close giving the secret for a transfer that has being revealed
    apps[1].raiden.chain.close(
        asset,
        nettingcontract_address,
        apps[1].raiden.address,
        [last_transfer],
        [(merkle_proof, secret_transfer.lock, secret)],
    )

    # forward the block number to allow settle
    for _ in range(NettingChannelContract.locked_time):
        apps[2].raiden.chain.next_block()

    apps[1].raiden.chain.settle(asset, nettingcontract_address)
Exemple #21
0
def test_receive_mediatedtransfer_invalid_address(raiden_chain,
                                                  token_addresses):
    app0, app1, app2 = raiden_chain
    token_address = token_addresses[0]

    amount = 10
    result = app0.raiden.mediated_transfer_async(
        token_address,
        amount,
        app2.raiden.address,
        identifier=1,
    )
    assert result.wait(timeout=10)

    # and now send one more mediated transfer with the same nonce, simulating
    # an out-of-order/resent message that arrives late
    channel0 = channel(app0, app1, token_address)
    lock = Lock(amount, 1, UNIT_HASHLOCK)
    identifier = create_default_identifier()
    mediated_transfer = MediatedTransfer(identifier=identifier,
                                         nonce=1,
                                         token=token_address,
                                         channel=channel0.channel_address,
                                         transferred_amount=amount,
                                         recipient=app1.raiden.address,
                                         locksroot=UNIT_HASHLOCK,
                                         lock=lock,
                                         target=app2.raiden.address,
                                         initiator=app0.raiden.address,
                                         fee=0)

    sign_and_send(
        mediated_transfer,
        app0.raiden.private_key,
        app0.raiden.address,
        app1,
    )
def test_fullnetwork(
        raiden_chain,
        token_addresses,
        deposit,
        settle_timeout,
        reveal_timeout):
    # pylint: disable=too-many-locals,too-many-statements

    # The network has the following topology:
    #
    #   App0 <---> App1
    #    ^          ^
    #    |          |
    #    v          v
    #   App3 <---> App2

    token_address = token_addresses[0]

    app0, app1, app2, app3 = raiden_chain  # pylint: disable=unbalanced-tuple-unpacking
    channel_0_1 = channel(app0, app1, token_address)
    channel_3_2 = channel(app3, app2, token_address)
    channel_0_3 = channel(app0, app3, token_address)

    # Exhaust the channel deposit (to force the mediated transfer to go backwards)
    amount = deposit
    direct_transfer(app0, app1, token_address, amount, identifier=1)
    assert get_sent_transfer(channel_0_1, 0).transferred_amount == amount

    amount = int(deposit / 2.)
    mediated_transfer(
        app0,
        app2,
        token_address,
        amount
    )

    gevent.sleep(0.5)

    # This is the only possible path, the transfer must go backwards
    assert_path_mediated_transfer(
        get_sent_transfer(channel_0_3, 0),
        get_sent_transfer(channel_3_2, 0),
    )

    app0_state_changes = [
        change[1]
        for change in get_all_state_changes(app0.raiden.transaction_log)
    ]

    app0_events = [
        event.event_object
        for event in get_all_state_events(app0.raiden.transaction_log)
    ]

    secret = None
    for event in app0_events:
        if isinstance(event, SendRevealSecret):
            secret = event.secret

    assert secret is not None
    hashlock = sha3(secret)

    # app0 initiates the direct transfer and mediated_transfer
    assert must_contain_entry(app0_state_changes, ActionInitInitiator, {
        'our_address': app0.raiden.address,
        'transfer': {
            'amount': amount,
            'token': token_address,
            'initiator': app0.raiden.address,
            'target': app2.raiden.address,
            'expiration': None,
            'hashlock': None,
            'secret': None,
        }
    })

    # Of these 2 the state machine will in the future choose the one with the most
    # available balance
    not_taken_route = RouteState(
        state='opened',
        node_address=app1.raiden.address,
        channel_address=channel_0_1.channel_address,
        available_balance=deposit,
        settle_timeout=settle_timeout,
        reveal_timeout=reveal_timeout,
        closed_block=None,
    )

    taken_route = RouteState(
        state='opened',
        node_address=app3.raiden.address,
        channel_address=channel_0_3.channel_address,
        available_balance=deposit,
        settle_timeout=settle_timeout,
        reveal_timeout=reveal_timeout,
        closed_block=None,
    )

    for state_change in app0_state_changes:
        if isinstance(state_change, ActionInitMediator):
            assert taken_route in state_change.routes.available_routes
            assert not_taken_route not in state_change.routes.available_routes

    # app1 received one direct transfers
    app1_state_changes = [
        change[1]
        for change in get_all_state_changes(app1.raiden.transaction_log)
    ]
    assert must_contain_entry(app1_state_changes, ReceiveBalanceProof, {})
    assert must_contain_entry(app1_state_changes, ReceiveTransferDirect, {})

    app2_state_changes = [
        change[1]
        for change in get_all_state_changes(app2.raiden.transaction_log)
    ]

    assert must_contain_entry(app2_state_changes, ActionInitTarget, {
        'our_address': app2.raiden.address,
        'from_route': {
            'state': 'opened',
            'node_address': app3.raiden.address,
            'channel_address': channel_3_2.channel_address,
            'available_balance': deposit,
            'settle_timeout': settle_timeout,
            'reveal_timeout': reveal_timeout,
            'closed_block': None
        },
        'from_transfer': {
            'amount': amount,
            'hashlock': hashlock,
            'token': token_address,
            'initiator': app0.raiden.address,
            'target': app2.raiden.address,
        }
    })

    assert must_contain_entry(app2_state_changes, ReceiveSecretReveal, {
        'sender': app0.raiden.address,
        'secret': secret,
    })

    assert must_contain_entry(app2_state_changes, ReceiveSecretReveal, {
        'sender': app3.raiden.address,
        'secret': secret,
    })

    app2_events = [
        event.event_object
        for event in get_all_state_events(app2.raiden.transaction_log)
    ]

    assert must_contain_entry(app2_events, SendSecretRequest, {
        'amount': amount,
        'hashlock': hashlock,
        'receiver': app0.raiden.address,
    })

    assert must_contain_entry(app2_events, SendRevealSecret, {
        'token': token_address,
        'secret': secret,
        'receiver': app3.raiden.address,
        'sender': app2.raiden.address,
    })

    assert must_contain_entry(app0_state_changes, ReceiveSecretRequest, {
        'amount': amount,
        'sender': app2.raiden.address,
        'hashlock': hashlock,
    })

    assert must_contain_entry(app0_state_changes, ReceiveSecretReveal, {
        'sender': app3.raiden.address,
        'secret': secret,
    })

    assert must_contain_entry(app0_events, EventTransferSentSuccess, {})

    assert must_contain_entry(app0_events, SendMediatedTransfer, {
        'token': token_address,
        'amount': amount,
        'hashlock': hashlock,
        'initiator': app0.raiden.address,
        'target': app2.raiden.address,
        'receiver': app3.raiden.address,
    })

    assert must_contain_entry(app0_events, SendRevealSecret, {
        'secret': secret,
        'token': token_address,
        'receiver': app2.raiden.address,
        'sender': app0.raiden.address,
    })

    assert must_contain_entry(app0_events, SendBalanceProof, {
        'token': token_address,
        'channel_address': channel_0_3.channel_address,
        'receiver': app3.raiden.address,
        'secret': secret,
    })

    assert must_contain_entry(app0_events, EventTransferSentSuccess, {})
    assert must_contain_entry(app0_events, EventUnlockSuccess, {
        'hashlock': hashlock,
    })

    app3_state_changes = [
        change[1]
        for change in get_all_state_changes(app3.raiden.transaction_log)
    ]

    assert must_contain_entry(app3_state_changes, ActionInitMediator, {
        'our_address': app3.raiden.address,
        'from_route': {
            'state': 'opened',
            'node_address': app0.raiden.address,
            'channel_address': channel_0_3.channel_address,
            'available_balance': deposit,
            'settle_timeout': settle_timeout,
            'reveal_timeout': reveal_timeout,
            'closed_block': None,
        },
        'from_transfer': {
            'amount': amount,
            'hashlock': hashlock,
            'token': token_address,
            'initiator': app0.raiden.address,
            'target': app2.raiden.address,
        }
    })

    assert must_contain_entry(app3_state_changes, ReceiveSecretReveal, {
        'sender': app2.raiden.address,
        'secret': secret,
    })

    assert must_contain_entry(app3_state_changes, ReceiveSecretReveal, {
        'sender': app2.raiden.address,
        'secret': secret,
    })

    app3_events = [
        event.event_object
        for event in get_all_state_events(app3.raiden.transaction_log)
    ]

    assert must_contain_entry(app3_events, SendMediatedTransfer, {
        'token': token_address,
        'amount': amount,
        'hashlock': hashlock,
        'initiator': app0.raiden.address,
        'target': app2.raiden.address,
        'receiver': app2.raiden.address,
    })

    assert must_contain_entry(app3_events, SendRevealSecret, {
        'secret': secret,
        'token': token_address,
        'receiver': app0.raiden.address,
        'sender': app3.raiden.address,
    })

    assert must_contain_entry(app3_events, SendBalanceProof, {
        'token': token_address,
        'channel_address': channel_3_2.channel_address,
        'receiver': app2.raiden.address,
        'secret': secret,
    })
    assert must_contain_entry(app3_events, EventUnlockSuccess, {})
def test_cancel_transfer(raiden_chain, token_addresses, deposit):
    """ A failed transfer must send a refund back.

    TODO:
        - Unlock the token on refund #1091
        - Clear the merkletree and update the locked amount #193
        - Remove the refund message type #490
    """
    # Topology:
    #
    #  0 -> 1 -> 2
    #
    app0, app1, app2 = raiden_chain  # pylint: disable=unbalanced-tuple-unpacking

    token = token_addresses[0]

    assert_synched_channels(
        channel(app0, app1, token), deposit, [],
        channel(app1, app0, token), deposit, []
    )

    assert_synched_channels(
        channel(app1, app2, token), deposit, [],
        channel(app2, app1, token), deposit, []
    )

    # make a transfer to test the path app0 -> app1 -> app2
    identifier_path = 1
    amount_path = 1
    transfer(app0, app2, token, amount_path, identifier_path)

    # drain the channel app1 -> app2
    identifier_drain = 2
    amount_drain = int(deposit * 0.8)
    direct_transfer(app1, app2, token, amount_drain, identifier_drain)

    # wait for the nodes to sync
    gevent.sleep(0.2)

    assert_synched_channels(
        channel(app0, app1, token), deposit - amount_path, [],
        channel(app1, app0, token), deposit + amount_path, []
    )

    assert_synched_channels(
        channel(app1, app2, token), deposit - amount_path - amount_drain, [],
        channel(app2, app1, token), deposit + amount_path + amount_drain, []
    )

    # app0 -> app1 -> app2 is the only available path but the channel app1 ->
    # app2 doesnt have resources and needs to send a RefundTransfer down the
    # path
    identifier_refund = 3
    amount_refund = 50
    async_result = app0.raiden.mediated_transfer_async(
        token,
        amount_refund,
        app2.raiden.address,
        identifier_refund,
    )
    assert async_result.wait() is False, 'there is no path with capacity, the transfer must fail'

    gevent.sleep(0.2)

    # A lock structure with the correct amount
    app0_messages = app0.raiden.protocol.transport.get_sent_messages(app0.raiden.address)
    mediated_message = list(
        message
        for message in app0_messages
        if isinstance(message, MediatedTransfer) and message.target == app2.raiden.address
    )[-1]
    assert mediated_message

    app1_messages = app1.raiden.protocol.transport.get_sent_messages(app1.raiden.address)
    refund_message = next(
        message
        for message in app1_messages
        if isinstance(message, RefundTransfer) and message.recipient == app0.raiden.address
    )
    assert refund_message

    assert mediated_message.lock.amount == refund_message.lock.amount
    assert mediated_message.lock.hashlock == refund_message.lock.hashlock
    assert mediated_message.lock.expiration > refund_message.lock.expiration

    # Both channels have the amount locked because of the refund message
    assert_synched_channels(
        channel(app0, app1, token), deposit - amount_path, [refund_message.lock],
        channel(app1, app0, token), deposit + amount_path, [mediated_message.lock],
    )

    assert_synched_channels(
        channel(app1, app2, token), deposit - amount_path - amount_drain, [],
        channel(app2, app1, token), deposit + amount_path + amount_drain, []
    )
Exemple #24
0
def test_secret_revealed(raiden_chain, deposit, settle_timeout,
                         events_poll_timeout):
    app0, app1, app2 = raiden_chain

    token_address = app0.raiden.default_registry.token_addresses()[0]
    amount = 10

    channel21 = channel(app2, app1, token_address)
    netting_channel = channel21.external_state.netting_channel

    identifier = 1
    expiration = app2.raiden.get_block_number() + settle_timeout - 3

    secret = pending_mediated_transfer(
        raiden_chain,
        token_address,
        amount,
        identifier,
        expiration,
    )
    hashlock = sha3(secret)

    gevent.sleep(.1)  # wait for the messages

    lock = channel21.our_state.get_lock_by_hashlock(hashlock)
    proof = channel21.our_state.compute_proof_for_lock(secret, lock)

    # the secret hasn't been revealed yet (through messages)
    assert len(channel21.our_state.hashlocks_to_pendinglocks) == 1
    proofs = list(channel21.our_state.get_known_unlocks())
    assert len(proofs) == 0

    netting_channel.close(channel21.our_state.balance_proof)

    # reveal it through the blockchain (this needs to emit the SecretRevealed event)
    netting_channel.withdraw(
        app2.raiden.address,
        [proof],
    )

    settle_expiration = app0.raiden.chain.block_number() + settle_timeout
    wait_until_block(app0.raiden.chain, settle_expiration)

    channel21.settle_event.wait(timeout=10)

    assert_synched_channels(
        channel(app1, app2, token_address),
        deposit - amount,
        [],
        channel(app2, app1, token_address),
        deposit + amount,
        [],
    )

    assert_synched_channels(
        channel(app0, app1, token_address),
        deposit - amount,
        [],
        channel(app1, app2, token_address),
        deposit + amount,
        [],
    )
Exemple #25
0
def test_transfer(raiden_network, token_addresses):
    app0, app1 = raiden_network  # pylint: disable=unbalanced-tuple-unpacking

    channel0 = channel(app0, app1, token_addresses[0])
    channel1 = channel(app1, app0, token_addresses[0])

    contract_balance0 = channel0.contract_balance
    contract_balance1 = channel1.contract_balance

    app0_token = app0.raiden.token_to_channelgraph.keys()[0]
    app1_token = app1.raiden.token_to_channelgraph.keys()[0]

    graph0 = app0.raiden.token_to_channelgraph.values()[0]
    graph1 = app1.raiden.token_to_channelgraph.values()[0]

    app0_partners = graph0.partneraddress_to_channel.keys()
    app1_partners = graph1.partneraddress_to_channel.keys()

    assert channel0.token_address == channel1.token_address
    assert app0_token == app1_token
    assert app1.raiden.address in app0_partners
    assert app0.raiden.address in app1_partners

    netting_address = channel0.external_state.netting_channel.address
    netting_channel = app0.raiden.chain.netting_channel(netting_address)

    # check balances of channel and contract are equal
    details0 = netting_channel.detail()
    details1 = netting_channel.detail()

    assert contract_balance0 == details0['our_balance']
    assert contract_balance1 == details1['our_balance']

    assert_synched_channels(
        channel0, contract_balance0, [],
        channel1, contract_balance1, [],
    )

    amount = 10
    direct_transfer = channel0.create_directtransfer(
        amount,
        identifier=1,
    )
    app0.raiden.sign(direct_transfer)
    channel0.register_transfer(
        app0.raiden.get_block_number(),
        direct_transfer,
    )
    channel1.register_transfer(
        app1.raiden.get_block_number(),
        direct_transfer,
    )

    # check the contract is intact
    assert details0 == netting_channel.detail()
    assert details1 == netting_channel.detail()

    assert channel0.contract_balance == contract_balance0
    assert channel1.contract_balance == contract_balance1

    assert_synched_channels(
        channel0, contract_balance0 - amount, [],
        channel1, contract_balance1 + amount, [],
    )
def test_start_end_attack():
    """ An attacker can try to steal assets from a hub or the last node in a
    path.

    The attacker needs to use two addresses (A1 and A2) and connect both to the
    hub H, once connected a mediated transfer is initialized from A1 to A2
    through H, once the node A2 receives the mediated transfer the attacker
    uses the it's know secret and reveal to close and settles the channel H-A2,
    without revealing the secret to H's raiden node.

    The intention is to make the hub transfer the asset but for him to be
    unable to require the asset A1.
    """
    asset = sha3('test_two_attack')[:20]
    deposit = 100
    amount = 30
    apps = create_sequential_network(num_nodes=3, deposit=deposit, asset=asset)

    # The attacker creates a mediated transfer from it's account A1, to it's
    # account A2, throught the hub H
    secret = hidden_mediated_transfer(apps, asset, amount)

    attack_channel = channel(apps[2], apps[1], asset)
    attack_transfer = get_received_transfer(attack_channel, 0)
    attack_contract = attack_channel.nettingcontract_address
    hub_contract = channel(apps[1], apps[0], asset).nettingcontract_address

    # the attacker can create a merkle proof of the locked transfer
    merkle_proof = attack_channel.our_state.locked.get_proof(attack_transfer)

    # start the settle counter
    apps[2].raiden.chain.close(
        asset,
        attack_contract,
        apps[2].raiden.address,
        [attack_transfer],
        [],
    )

    # wait until the last block to reveal the secret
    for _ in range(attack_transfer.lock.expiration - 1):
        apps[2].raiden.chain.next_block()

    # since the attacker knows the secret he can net the lock
    apps[2].raiden.chain.close(
        asset,
        attack_contract,
        apps[2].raiden.address,
        [attack_transfer],
        [(merkle_proof, attack_transfer.lock, secret)],
    )
    # XXX: verify that the secret was publicized

    # at this point the hub might not know yet the secret, and won't be able to
    # claim the asset from the channel A1 - H

    # the attacker settle the contract
    apps[2].raiden.chain.next_block()
    apps[2].raiden.chain.settle(asset, attack_contract)

    # at this point the attack has the "stolen" funds
    attack_contract = apps[2].raiden.chain.asset_hashchannel[asset][attack_contract]
    assert attack_contract.participants[apps[2].raiden.address]['netted'] == deposit + amount
    assert attack_contract.participants[apps[1].raiden.address]['netted'] == deposit - amount

    # and the hub's channel A1-H doesn't
    hub_contract = apps[1].raiden.chain.asset_hashchannel[asset][hub_contract]
    assert hub_contract.participants[apps[0].raiden.address]['netted'] == deposit
    assert hub_contract.participants[apps[1].raiden.address]['netted'] == deposit

    # to mitigate the attack the Hub _needs_ to use a lower expiration for the
    # locked transfer between H-A2 than A1-H, since for A2 to acquire the asset
    # it needs to make the secret public in the block chain we publish the
    # secret through an event and the Hub will be able to require it's funds
    apps[1].raiden.chain.next_block()

    # XXX: verify that the Hub has found the secret, close and settle the channel

    # the hub has acquired it's asset
    hub_contract = apps[1].raiden.chain.asset_hashchannel[asset][hub_contract]
    assert hub_contract.participants[apps[0].raiden.address]['netted'] == deposit + amount
    assert hub_contract.participants[apps[1].raiden.address]['netted'] == deposit - amount
def test_settled_lock(assets_addresses, raiden_network, settle_timeout, reveal_timeout):
    """ Any transfer following a secret revealed must update the locksroot, so
    that an attacker cannot reuse a secret to double claim a lock.
    """
    asset = assets_addresses[0]
    amount = 30

    app0, app1, app2, _ = raiden_network  # pylint: disable=unbalanced-tuple-unpacking
    address0 = app0.raiden.address
    address1 = app1.raiden.address

    # mediated transfer
    identifier = 1
    expiration = app0.raiden.chain.block_number() + settle_timeout - reveal_timeout
    secret = pending_mediated_transfer(
        raiden_network,
        asset,
        amount,
        identifier,
        expiration,
    )
    hashlock = sha3(secret)

    # get a proof for the pending transfer
    back_channel = channel(app1, app0, asset)
    secret_transfer = get_received_transfer(back_channel, 0)
    lock = back_channel.our_state.balance_proof.get_lock_by_hashlock(hashlock)
    unlock_proof = back_channel.our_state.balance_proof.compute_proof_for_lock(secret, lock)

    # reveal the secret
    claim_lock(raiden_network, asset, secret)

    # a new transfer to update the hashlock
    direct_transfer(app0, app1, asset, amount)

    forward_channel = channel(app0, app1, asset)
    last_transfer = get_sent_transfer(forward_channel, 1)

    # call close giving the secret for a transfer that has being revealed
    back_channel.external_state.netting_channel.close(
        app1.raiden.address,
        last_transfer,
        None
    )

    # check that the double unlock will failed
    with pytest.raises(Exception):
        back_channel.external_state.netting_channel.unlock(
            app1.raiden.address,
            [(unlock_proof, secret_transfer.lock.as_bytes, secret)],
        )

    # forward the block number to allow settle
    settle_expiration = app2.raiden.chain.block_number() + settle_timeout
    wait_until_block(app2.raiden.chain, settle_expiration)

    back_channel.external_state.netting_channel.settle()

    participant0 = back_channel.external_state.netting_channel.contract.participants[address0]
    participant1 = back_channel.external_state.netting_channel.contract.participants[address1]

    assert participant0.netted == participant0.deposit - amount * 2
    assert participant1.netted == participant1.deposit + amount * 2
Exemple #28
0
def test_fullnetwork(raiden_chain, token_addresses, deposit, settle_timeout,
                     reveal_timeout):
    # pylint: disable=too-many-locals,too-many-statements

    # The network has the following topology:
    #
    #   App0 <---> App1
    #    ^          ^
    #    |          |
    #    v          v
    #   App3 <---> App2

    token_address = token_addresses[0]

    app0, app1, app2, app3 = raiden_chain  # pylint: disable=unbalanced-tuple-unpacking
    channel_0_1 = channel(app0, app1, token_address)
    channel_3_2 = channel(app3, app2, token_address)
    channel_0_3 = channel(app0, app3, token_address)

    # Exhaust the channel deposit (to force the mediated transfer to go backwards)
    amount = deposit
    direct_transfer(app0, app1, token_address, amount, identifier=1)
    assert get_sent_transfer(channel_0_1, 0).transferred_amount == amount

    amount = int(deposit / 2.)
    mediated_transfer(app0, app2, token_address, amount)

    gevent.sleep(0.5)

    # This is the only possible path, the transfer must go backwards
    assert_path_mediated_transfer(
        get_sent_transfer(channel_0_3, 0),
        get_sent_transfer(channel_3_2, 0),
    )

    app0_state_changes = [
        change[1]
        for change in get_all_state_changes(app0.raiden.transaction_log)
    ]

    app0_events = [
        event.event_object
        for event in get_all_state_events(app0.raiden.transaction_log)
    ]

    secret = None
    for event in app0_events:
        if isinstance(event, SendRevealSecret):
            secret = event.secret

    assert secret is not None
    hashlock = sha3(secret)

    # app0 initiates the direct transfer and mediated_transfer
    assert must_contain_entry(
        app0_state_changes, ActionInitInitiator, {
            'our_address': app0.raiden.address,
            'transfer': {
                'amount': amount,
                'token': token_address,
                'initiator': app0.raiden.address,
                'target': app2.raiden.address,
                'expiration': None,
                'hashlock': None,
                'secret': None,
            }
        })

    # Of these 2 the state machine will in the future choose the one with the most
    # available balance
    not_taken_route = RouteState(
        state='opened',
        node_address=app1.raiden.address,
        channel_address=channel_0_1.channel_address,
        available_balance=deposit,
        settle_timeout=settle_timeout,
        reveal_timeout=reveal_timeout,
        closed_block=None,
    )

    taken_route = RouteState(
        state='opened',
        node_address=app3.raiden.address,
        channel_address=channel_0_3.channel_address,
        available_balance=deposit,
        settle_timeout=settle_timeout,
        reveal_timeout=reveal_timeout,
        closed_block=None,
    )

    for state_change in app0_state_changes:
        if isinstance(state_change, ActionInitMediator):
            assert taken_route in state_change.routes.available_routes
            assert not_taken_route not in state_change.routes.available_routes

    # app1 received one direct transfers
    app1_state_changes = [
        change[1]
        for change in get_all_state_changes(app1.raiden.transaction_log)
    ]
    assert must_contain_entry(app1_state_changes, ReceiveBalanceProof, {})
    assert must_contain_entry(app1_state_changes, ReceiveTransferDirect, {})

    app2_state_changes = [
        change[1]
        for change in get_all_state_changes(app2.raiden.transaction_log)
    ]

    assert must_contain_entry(
        app2_state_changes, ActionInitTarget, {
            'our_address': app2.raiden.address,
            'from_route': {
                'state': 'opened',
                'node_address': app3.raiden.address,
                'channel_address': channel_3_2.channel_address,
                'available_balance': deposit,
                'settle_timeout': settle_timeout,
                'reveal_timeout': reveal_timeout,
                'closed_block': None
            },
            'from_transfer': {
                'amount': amount,
                'hashlock': hashlock,
                'token': token_address,
                'initiator': app0.raiden.address,
                'target': app2.raiden.address,
            }
        })

    assert must_contain_entry(app2_state_changes, ReceiveSecretReveal, {
        'sender': app0.raiden.address,
        'secret': secret,
    })

    assert must_contain_entry(app2_state_changes, ReceiveSecretReveal, {
        'sender': app3.raiden.address,
        'secret': secret,
    })

    app2_events = [
        event.event_object
        for event in get_all_state_events(app2.raiden.transaction_log)
    ]

    assert must_contain_entry(app2_events, SendSecretRequest, {
        'amount': amount,
        'hashlock': hashlock,
        'receiver': app0.raiden.address,
    })

    assert must_contain_entry(
        app2_events, SendRevealSecret, {
            'token': token_address,
            'secret': secret,
            'receiver': app3.raiden.address,
            'sender': app2.raiden.address,
        })

    assert must_contain_entry(app0_state_changes, ReceiveSecretRequest, {
        'amount': amount,
        'sender': app2.raiden.address,
        'hashlock': hashlock,
    })

    assert must_contain_entry(app0_state_changes, ReceiveSecretReveal, {
        'sender': app3.raiden.address,
        'secret': secret,
    })

    assert must_contain_entry(app0_events, EventTransferSentSuccess, {})

    assert must_contain_entry(
        app0_events, SendMediatedTransfer, {
            'token': token_address,
            'amount': amount,
            'hashlock': hashlock,
            'initiator': app0.raiden.address,
            'target': app2.raiden.address,
            'receiver': app3.raiden.address,
        })

    assert must_contain_entry(
        app0_events, SendRevealSecret, {
            'secret': secret,
            'token': token_address,
            'receiver': app2.raiden.address,
            'sender': app0.raiden.address,
        })

    assert must_contain_entry(
        app0_events, SendBalanceProof, {
            'token': token_address,
            'channel_address': channel_0_3.channel_address,
            'receiver': app3.raiden.address,
            'secret': secret,
        })

    assert must_contain_entry(app0_events, EventTransferSentSuccess, {})
    assert must_contain_entry(app0_events, EventUnlockSuccess, {
        'hashlock': hashlock,
    })

    app3_state_changes = [
        change[1]
        for change in get_all_state_changes(app3.raiden.transaction_log)
    ]

    assert must_contain_entry(
        app3_state_changes, ActionInitMediator, {
            'our_address': app3.raiden.address,
            'from_route': {
                'state': 'opened',
                'node_address': app0.raiden.address,
                'channel_address': channel_0_3.channel_address,
                'available_balance': deposit,
                'settle_timeout': settle_timeout,
                'reveal_timeout': reveal_timeout,
                'closed_block': None,
            },
            'from_transfer': {
                'amount': amount,
                'hashlock': hashlock,
                'token': token_address,
                'initiator': app0.raiden.address,
                'target': app2.raiden.address,
            }
        })

    assert must_contain_entry(app3_state_changes, ReceiveSecretReveal, {
        'sender': app2.raiden.address,
        'secret': secret,
    })

    assert must_contain_entry(app3_state_changes, ReceiveSecretReveal, {
        'sender': app2.raiden.address,
        'secret': secret,
    })

    app3_events = [
        event.event_object
        for event in get_all_state_events(app3.raiden.transaction_log)
    ]

    assert must_contain_entry(
        app3_events, SendMediatedTransfer, {
            'token': token_address,
            'amount': amount,
            'hashlock': hashlock,
            'initiator': app0.raiden.address,
            'target': app2.raiden.address,
            'receiver': app2.raiden.address,
        })

    assert must_contain_entry(
        app3_events, SendRevealSecret, {
            'secret': secret,
            'token': token_address,
            'receiver': app0.raiden.address,
            'sender': app3.raiden.address,
        })

    assert must_contain_entry(
        app3_events, SendBalanceProof, {
            'token': token_address,
            'channel_address': channel_3_2.channel_address,
            'receiver': app2.raiden.address,
            'secret': secret,
        })
    assert must_contain_entry(app3_events, EventUnlockSuccess, {})
Exemple #29
0
def test_regression_multiple_revealsecret(raiden_network, token_addresses):
    """ Multiple RevealSecret messages arriving at the same time must be
    handled properly.

    Secret handling followed these steps:

        The Secret message arrives
        The secret is registered
        The channel is updated and the correspoding lock is removed
        * A balance proof for the new channel state is created and sent to the
          payer
        The channel is unregistered for the given hashlock

    The step marked with an asterisk above introduced a context-switch, this
    allowed a second Reveal Secret message to be handled before the channel was
    unregistered, because the channel was already updated an exception was raised
    for an unknown secret.
    """
    app0, app1 = raiden_network
    token = token_addresses[0]

    identifier = 1
    secret = sha3(b'test_regression_multiple_revealsecret')
    hashlock = sha3(secret)
    expiration = app0.raiden.get_block_number() + 100
    amount = 10

    mediated_transfer = channel(app0, app1, token).create_mediatedtransfer(
        transfer_initiator=app0.raiden.address,
        transfer_target=app1.raiden.address,
        fee=0,
        amount=amount,
        identifier=identifier,
        expiration=expiration,
        hashlock=hashlock,
    )
    app0.raiden.sign(mediated_transfer)

    message_data = mediated_transfer.encode()
    app1.raiden.protocol.receive(message_data)

    reveal_secret = RevealSecret(secret)
    app0.raiden.sign(reveal_secret)
    reveal_secret_data = reveal_secret.encode()

    secret = Secret(
        identifier=identifier,
        nonce=mediated_transfer.nonce + 1,
        channel=channel(app0, app1, token).channel_address,
        transferred_amount=amount,
        locksroot=EMPTY_MERKLE_ROOT,
        secret=secret,
    )
    app0.raiden.sign(secret)
    secret_data = secret.encode()

    messages = [
        secret_data,
        reveal_secret_data,
    ]

    wait = [
        gevent.spawn_later(
            .1,
            app1.raiden.protocol.receive,
            data,
        ) for data in messages
    ]

    gevent.joinall(wait)
Exemple #30
0
def test_start_end_attack(asset_address, raiden_chain, deposit):
    """ An attacker can try to steal assets from a hub or the last node in a
    path.

    The attacker needs to use two addresses (A1 and A2) and connect both to the
    hub H, once connected a mediated transfer is initialized from A1 to A2
    through H, once the node A2 receives the mediated transfer the attacker
    uses the it's know secret and reveal to close and settles the channel H-A2,
    without revealing the secret to H's raiden node.

    The intention is to make the hub transfer the asset but for him to be
    unable to require the asset A1.
    """
    amount = 30

    asset = asset_address[0]
    app0, app1, app2 = raiden_chain  # pylint: disable=unbalanced-tuple-unpacking

    # The attacker creates a mediated transfer from it's account A1, to it's
    # account A2, throught the hub H
    secret = pending_mediated_transfer(raiden_chain, asset, amount)

    attack_channel = channel(app2, app1, asset)
    attack_transfer = get_received_transfer(attack_channel, 0)
    attack_contract = attack_channel.external_state.netting_channel.address
    hub_contract = channel(app1, app0, asset).external_state.netting_channel.address

    # the attacker can create a merkle proof of the locked transfer
    merkle_proof = attack_channel.our_state.locked.get_proof(attack_transfer)

    # start the settle counter
    attack_channel.netting_channel.close(
        app2.raiden.address,
        attack_transfer,
        None
    )

    # wait until the last block to reveal the secret
    for _ in range(attack_transfer.lock.expiration - 1):
        app2.raiden.chain.next_block()

    # since the attacker knows the secret he can net the lock
    attack_channel.netting_channel.unlock(
        [(merkle_proof, attack_transfer.lock, secret)],
    )
    # XXX: verify that the secret was publicized

    # at this point the hub might not know yet the secret, and won't be able to
    # claim the asset from the channel A1 - H

    # the attacker settle the contract
    app2.raiden.chain.next_block()

    attack_channel.netting_channel.settle(asset, attack_contract)

    # at this point the attack has the "stolen" funds
    attack_contract = app2.raiden.chain.asset_hashchannel[asset][attack_contract]
    assert attack_contract.participants[app2.raiden.address]['netted'] == deposit + amount
    assert attack_contract.participants[app1.raiden.address]['netted'] == deposit - amount

    # and the hub's channel A1-H doesn't
    hub_contract = app1.raiden.chain.asset_hashchannel[asset][hub_contract]
    assert hub_contract.participants[app0.raiden.address]['netted'] == deposit
    assert hub_contract.participants[app1.raiden.address]['netted'] == deposit

    # to mitigate the attack the Hub _needs_ to use a lower expiration for the
    # locked transfer between H-A2 than A1-H, since for A2 to acquire the asset
    # it needs to make the secret public in the block chain we publish the
    # secret through an event and the Hub will be able to require it's funds
    app1.raiden.chain.next_block()

    # XXX: verify that the Hub has found the secret, close and settle the channel

    # the hub has acquired it's asset
    hub_contract = app1.raiden.chain.asset_hashchannel[asset][hub_contract]
    assert hub_contract.participants[app0.raiden.address]['netted'] == deposit + amount
    assert hub_contract.participants[app1.raiden.address]['netted'] == deposit - amount
Exemple #31
0
def test_fullnetwork(raiden_chain, token_addresses, deposit, settle_timeout,
                     reveal_timeout):

    # The network has the following topology:
    #
    #   App0 <---> App1
    #    ^          ^
    #    |          |
    #    v          v
    #   App3 <---> App2

    token_address = token_addresses[0]

    app0, app1, app2, app3 = raiden_chain  # pylint: disable=unbalanced-tuple-unpacking
    channel_0_1 = channel(app0, app1, token_address)
    channel_3_2 = channel(app3, app2, token_address)
    channel_0_3 = channel(app0, app3, token_address)

    # Exhaust the channel deposit (to force the mediated transfer to go backwards)
    amount = deposit
    direct_transfer(app0, app1, token_address, amount)
    assert get_sent_transfer(channel_0_1, 0).transferred_amount == amount

    amount = int(deposit / 2.)
    mediated_transfer(app0, app2, token_address, amount)

    # This is the only possible path, the transfer must go backwards
    assert_path_mediated_transfer(
        get_sent_transfer(channel_0_3, 0),
        get_sent_transfer(channel_3_2, 0),
    )

    # Now let's query the WAL to see if the state changes were logged as expected
    app0_state_changes = [
        change[1]
        for change in get_all_state_changes(app0.raiden.transaction_log)
        if not isinstance(change[1], Block)
    ]
    app0_events = [
        event.event_object
        for event in get_all_state_events(app0.raiden.transaction_log)
    ]
    app1_state_changes = [
        change[1]
        for change in get_all_state_changes(app1.raiden.transaction_log)
        if not isinstance(change[1], Block)
    ]
    app1_events = [
        event.event_object
        for event in get_all_state_events(app1.raiden.transaction_log)
    ]
    app2_state_changes = [
        change[1]
        for change in get_all_state_changes(app2.raiden.transaction_log)
        if not isinstance(change[1], Block)
    ]
    app2_events = [
        event.event_object
        for event in get_all_state_events(app2.raiden.transaction_log)
    ]
    app3_state_changes = [
        change[1]
        for change in get_all_state_changes(app3.raiden.transaction_log)
        if not isinstance(change[1], Block)
    ]
    app3_events = [
        event.event_object
        for event in get_all_state_events(app3.raiden.transaction_log)
    ]

    # app1 received one direct transfers
    assert len(app1_state_changes) == 1
    assert len(app1_events) == 1

    # app0 initiates the direct transfer and mediated_transfer
    assert len(app0_state_changes) == 4
    assert isinstance(app0_state_changes[1], ActionInitInitiator)
    assert app0_state_changes[1].our_address == app0.raiden.address
    assert app0_state_changes[1].transfer.amount == amount
    assert app0_state_changes[1].transfer.token == token_address
    assert app0_state_changes[1].transfer.initiator == app0.raiden.address
    assert app0_state_changes[1].transfer.target == app2.raiden.address
    # The ActionInitInitiator state change does not have the following fields populated.
    # They get populated via an event during the processing of the state change inside
    # this function: mediated_transfer.mediated_transfer.initiator.try_new_route()
    assert app0_state_changes[1].transfer.expiration is None
    assert app0_state_changes[1].transfer.hashlock is None
    assert app0_state_changes[1].transfer.secret is None
    # We should have one available route
    assert len(app0_state_changes[1].routes.available_routes) == 1
    assert len(app0_state_changes[1].routes.ignored_routes) == 0
    assert len(app0_state_changes[1].routes.refunded_routes) == 0
    assert len(app0_state_changes[1].routes.canceled_routes) == 0
    # Of these 2 the state machine will in the future choose the one with the most
    # available balance
    not_taken_route = RouteState(
        state='opened',
        node_address=app1.raiden.address,
        channel_address=channel_0_1.channel_address,
        available_balance=deposit,
        settle_timeout=settle_timeout,
        reveal_timeout=reveal_timeout,
        closed_block=None,
    )
    taken_route = RouteState(
        state='opened',
        node_address=app3.raiden.address,
        channel_address=channel_0_3.channel_address,
        available_balance=deposit,
        settle_timeout=settle_timeout,
        reveal_timeout=reveal_timeout,
        closed_block=None,
    )
    assert taken_route in app0_state_changes[1].routes.available_routes
    assert not_taken_route not in app0_state_changes[1].routes.available_routes

    # app0 will also receive a secret request from the target
    assert isinstance(app0_state_changes[2], ReceiveSecretRequest)
    assert app0_state_changes[2].amount == amount
    assert app0_state_changes[2].sender == app2.raiden.address
    hashlock = app0_state_changes[2].hashlock

    # app0 will also receive a secret reveal from the immediate neighbour
    assert isinstance(app0_state_changes[3], ReceiveSecretReveal)
    assert app0_state_changes[3].sender == app3.raiden.address
    secret = app0_state_changes[3].secret
    assert sha3(secret) == hashlock

    assert len(app0_events) == 6

    # Direct transfer
    assert isinstance(app0_events[0], EventTransferSentSuccess)

    # not checking the expiration and identifier
    assert isinstance(app0_events[1], SendMediatedTransfer)
    assert app0_events[1].token == token_address
    assert app0_events[1].amount == amount
    assert app0_events[1].hashlock == hashlock
    assert app0_events[1].initiator == app0.raiden.address
    assert app0_events[1].target == app2.raiden.address
    assert app0_events[1].receiver == app3.raiden.address

    #  not checking the identifier
    assert isinstance(app0_events[2], SendRevealSecret)
    assert app0_events[2].secret == secret
    assert app0_events[2].token == token_address
    assert app0_events[2].receiver == app2.raiden.address
    assert app0_events[2].sender == app0.raiden.address

    # not checking the identifier
    assert isinstance(app0_events[3], SendBalanceProof)
    assert app0_events[3].token == token_address
    assert app0_events[3].channel_address == channel_0_3.channel_address
    assert app0_events[3].receiver == app3.raiden.address
    assert app0_events[3].secret == secret

    assert isinstance(app0_events[4], EventTransferSentSuccess)

    # EventUnlockSuccess, not checking the identifier
    assert isinstance(app0_events[5], EventUnlockSuccess)
    assert app0_events[5].hashlock == hashlock

    # app3 is the mediator
    assert isinstance(app3_state_changes[0], ActionInitMediator)
    assert app3_state_changes[0].our_address == app3.raiden.address
    # We should have only 1 available route from mediator to target
    from_route = RouteState(
        state='opened',
        node_address=app0.raiden.address,
        channel_address=channel_0_3.channel_address,
        available_balance=deposit,
        settle_timeout=settle_timeout,
        reveal_timeout=reveal_timeout,
        closed_block=None,
    )
    to_route = RouteState(
        state='opened',
        node_address=app2.raiden.address,
        channel_address=channel_3_2.channel_address,
        available_balance=deposit,
        settle_timeout=settle_timeout,
        reveal_timeout=reveal_timeout,
        closed_block=None,
    )

    assert app3_state_changes[0].from_route == from_route
    assert len(app3_state_changes[0].routes.available_routes) == 1
    assert len(app3_state_changes[0].routes.ignored_routes) == 0
    assert len(app3_state_changes[0].routes.refunded_routes) == 0
    assert len(app3_state_changes[0].routes.canceled_routes) == 0
    assert app3_state_changes[0].routes.available_routes[0] == to_route
    # check the from_transfer is correct
    assert app3_state_changes[0].from_transfer.amount == amount
    assert app3_state_changes[0].from_transfer.hashlock == hashlock
    assert app3_state_changes[0].from_transfer.token == token_address
    assert app3_state_changes[0].from_transfer.initiator == app0.raiden.address
    assert app3_state_changes[0].from_transfer.target == app2.raiden.address

    # The mediator should have also received a SecretReveal from the target
    assert isinstance(app3_state_changes[1], ReceiveSecretReveal)
    assert app3_state_changes[1].sender == app2.raiden.address
    assert app3_state_changes[1].secret == secret

    # If the mediator received any more it is from the initiator
    # TODO: Figure out why we may get two times the secret reveal from the initiator
    for state_change in app3_state_changes[2:]:
        assert isinstance(state_change, ReceiveSecretReveal)
        assert state_change.sender == app0.raiden.address
        assert state_change.secret == secret

    # check app3 state events
    assert len(app3_events) == 4
    assert isinstance(app3_events[0], SendMediatedTransfer)
    assert app3_events[0].token == token_address
    assert app3_events[0].amount == amount
    assert app3_events[0].hashlock == hashlock
    assert app3_events[0].initiator == app0.raiden.address
    assert app3_events[0].target == app2.raiden.address
    assert app3_events[0].receiver == app2.raiden.address

    assert isinstance(app3_events[1], SendRevealSecret)
    assert app3_events[1].secret == secret
    assert app3_events[1].token == token_address
    assert app3_events[1].receiver == app0.raiden.address
    assert app3_events[1].sender == app3.raiden.address

    assert isinstance(app3_events[2], SendBalanceProof)
    assert app3_events[2].token == token_address
    assert app3_events[2].channel_address == channel_3_2.channel_address
    assert app3_events[2].receiver == app2.raiden.address
    assert app3_events[2].secret == secret

    assert isinstance(app3_events[3], EventUnlockSuccess)

    # app2 is the target of the mediated transfer
    assert len(app2_state_changes
               ) == 4  # We get 2 secret reveals from the mediator. WHY?
    assert isinstance(app2_state_changes[0], ActionInitTarget)
    assert app2_state_changes[0].our_address == app2.raiden.address
    # check the route the transfer came from
    from_route = RouteState(
        state='opened',
        node_address=app3.raiden.address,
        channel_address=channel_3_2.channel_address,
        available_balance=deposit,
        settle_timeout=settle_timeout,
        reveal_timeout=reveal_timeout,
        closed_block=None,
    )
    assert app2_state_changes[0].from_route == from_route
    # check the from_transfer is correct
    assert app2_state_changes[0].from_transfer.amount == amount
    assert app2_state_changes[0].from_transfer.hashlock == hashlock
    assert app2_state_changes[0].from_transfer.token == token_address
    assert app2_state_changes[0].from_transfer.initiator == app0.raiden.address
    assert app2_state_changes[0].from_transfer.target == app2.raiden.address

    # We also get secret reveals from the initiator and the mediator.
    assert isinstance(app2_state_changes[1], ReceiveSecretReveal)
    assert app2_state_changes[1].sender == app0.raiden.address
    assert app2_state_changes[1].secret == secret

    # TODO: Figure out why we get two times the Secret Reveal from the mediator
    assert isinstance(app2_state_changes[2], ReceiveSecretReveal)
    assert app2_state_changes[2].sender == app3.raiden.address
    assert app2_state_changes[2].secret == secret
    assert isinstance(app2_state_changes[3], ReceiveSecretReveal)
    assert app2_state_changes[3].sender == app3.raiden.address
    assert app2_state_changes[3].secret == secret

    # check app2 state events
    assert len(app2_events) == 2
    assert isinstance(app2_events[0], SendSecretRequest)
    assert app2_events[0].amount == amount
    assert app2_events[0].hashlock == hashlock
    assert app2_events[0].receiver == app0.raiden.address
    assert isinstance(app2_events[1], SendRevealSecret)
    assert app2_events[1].token == token_address
    assert app2_events[1].secret == secret
    assert app2_events[1].receiver == app3.raiden.address
    assert app2_events[1].sender == app2.raiden.address
def test_cancel_transfer(raiden_chain, asset, deposit):

    app0, app1, app2, app3 = raiden_chain  # pylint: disable=unbalanced-tuple-unpacking

    messages = setup_messages_cb()
    mlogger = MessageLogger()

    assert_synched_channels(
        channel(app0, app1, asset), deposit, [],
        channel(app1, app0, asset), deposit, []
    )

    assert_synched_channels(
        channel(app1, app2, asset), deposit, [],
        channel(app2, app1, asset), deposit, []
    )

    assert_synched_channels(
        channel(app2, app3, asset), deposit, [],
        channel(app3, app2, asset), deposit, []
    )

    assert_synched_channels(
        channel(app0, app1, asset), deposit, [],
        channel(app1, app0, asset), deposit, []
    )

    # drain the channel app1 -> app2
    amount12 = 50
    direct_transfer(app1, app2, asset, amount12)

    # drain the channel app2 -> app3
    amount23 = 80
    direct_transfer(app2, app3, asset, amount23)

    assert_synched_channels(
        channel(app1, app2, asset), deposit - amount12, [],
        channel(app2, app1, asset), deposit + amount12, []
    )

    assert_synched_channels(
        channel(app2, app3, asset), deposit - amount23, [],
        channel(app3, app2, asset), deposit + amount23, []
    )

    # app1 -> app3 is the only available path but app2 -> app3 doesnt have
    # resources and needs to send a RefundTransfer down the path
    transfer(app0, app3, asset, 50)

    assert_synched_channels(
        channel(app0, app1, asset), deposit, [],
        channel(app1, app0, asset), deposit, []
    )

    assert_synched_channels(
        channel(app1, app2, asset), deposit - amount12, [],
        channel(app2, app1, asset), deposit + amount12, []
    )

    assert_synched_channels(
        channel(app2, app3, asset), deposit - amount23, [],
        channel(app3, app2, asset), deposit + amount23, []
    )

    assert len(messages) == 12  # DT + DT + SMT + MT + RT + RT + ACKs

    app1_messages = mlogger.get_node_messages(pex(app1.raiden.address), only='sent')
    assert isinstance(app1_messages[-1], RefundTransfer)

    app2_messages = mlogger.get_node_messages(pex(app2.raiden.address), only='sent')
    assert isinstance(app2_messages[-1], RefundTransfer)
def test_transfer(raiden_network, token_addresses):
    app0, app1 = raiden_network  # pylint: disable=unbalanced-tuple-unpacking

    channel0 = channel(app0, app1, token_addresses[0])
    channel1 = channel(app1, app0, token_addresses[0])

    contract_balance0 = channel0.contract_balance
    contract_balance1 = channel1.contract_balance

    app0_token = list(app0.raiden.token_to_channelgraph.keys())[0]
    app1_token = list(app1.raiden.token_to_channelgraph.keys())[0]

    graph0 = list(app0.raiden.token_to_channelgraph.values())[0]
    graph1 = list(app1.raiden.token_to_channelgraph.values())[0]

    app0_partners = list(graph0.partneraddress_to_channel.keys())
    app1_partners = list(graph1.partneraddress_to_channel.keys())

    assert channel0.token_address == channel1.token_address
    assert app0_token == app1_token
    assert app1.raiden.address in app0_partners
    assert app0.raiden.address in app1_partners

    netting_address = channel0.external_state.netting_channel.address
    netting_channel = app0.raiden.chain.netting_channel(netting_address)

    # check balances of channel and contract are equal
    details0 = netting_channel.detail()
    details1 = netting_channel.detail()

    assert contract_balance0 == details0['our_balance']
    assert contract_balance1 == details1['our_balance']

    assert_synched_channels(
        channel0, contract_balance0, [],
        channel1, contract_balance1, [],
    )

    amount = 10
    direct_transfer = channel0.create_directtransfer(
        amount,
        identifier=1,
    )
    app0.raiden.sign(direct_transfer)
    channel0.register_transfer(
        app0.raiden.get_block_number(),
        direct_transfer,
    )
    channel1.register_transfer(
        app1.raiden.get_block_number(),
        direct_transfer,
    )

    # check the contract is intact
    assert details0 == netting_channel.detail()
    assert details1 == netting_channel.detail()

    assert channel0.contract_balance == contract_balance0
    assert channel1.contract_balance == contract_balance1

    assert_synched_channels(
        channel0, contract_balance0 - amount, [],
        channel1, contract_balance1 + amount, [],
    )
def test_receive_mediated_before_deposit(raiden_network, token_addresses):
    """Regression test that ensures we accept incoming mediated transfers, even if we don't have
    any back channel balance. """
    app_alice, app_bob, app_charlie = raiden_network
    token_address = token_addresses[0]

    # path alice -> bob -> charlie
    alice_bob = channel(app_alice, app_bob, token_address)
    bob_alice = channel(app_bob, app_alice, token_address)
    bob_charlie = channel(app_bob, app_charlie, token_address)
    charlie_bob = channel(app_charlie, app_bob, token_address)

    # ensure alice charlie is mediated
    with pytest.raises(KeyError):
        channel(app_alice, app_charlie, token_address)

    assert not alice_bob.can_transfer
    assert not bob_charlie.can_transfer
    assert not bob_alice.can_transfer

    deposit_amount = 3
    RaidenAPI(app_alice.raiden).deposit(
        token_address,
        app_bob.raiden.address,
        deposit_amount,
    )

    RaidenAPI(app_bob.raiden).deposit(
        token_address,
        app_charlie.raiden.address,
        deposit_amount,
    )

    # catch up with the Balance events
    for app in raiden_network:
        app.raiden.poll_blockchain_events()

    assert alice_bob.can_transfer
    assert bob_charlie.can_transfer
    assert not bob_alice.can_transfer

    assert alice_bob.distributable == deposit_amount
    assert bob_charlie.distributable == deposit_amount

    transfer_amount = 1
    async_result = app_alice.raiden.mediated_transfer_async(
        token_address,
        transfer_amount,
        app_charlie.raiden.address,
        1,
    )
    assert async_result.wait(10)

    # give extra time for the intermediaries to process the secret messages and
    # withdraw the tokens
    gevent.sleep(1)

    assert alice_bob.distributable == deposit_amount - transfer_amount
    assert bob_charlie.distributable == deposit_amount - transfer_amount
    assert bob_alice.distributable == transfer_amount
    assert charlie_bob.distributable == transfer_amount

    assert alice_bob.can_transfer
    assert bob_alice.can_transfer
    assert charlie_bob.can_transfer
Exemple #35
0
def test_cancel_transfer():
    deposit = 100
    asset = sha3('test_cancel_transfer')[:20]

    # pylint: disable=unbalanced-tuple-unpacking
    app0, app1, app2 = create_sequential_network(num_nodes=3, deposit=deposit, asset=asset)

    messages = setup_messages_cb()
    mlogger = MessageLogger()

    assert_synched_channels(
        channel(app0, app1, asset), deposit, [],
        channel(app1, app0, asset), deposit, []
    )

    assert_synched_channels(
        channel(app1, app2, asset), deposit, [],
        channel(app2, app1, asset), deposit, []
    )

    # drain the channel app1 -> app2
    amount = 80
    direct_transfer(app1, app2, asset, amount)

    assert_synched_channels(
        channel(app0, app1, asset), deposit, [],
        channel(app1, app0, asset), deposit, []
    )

    assert_synched_channels(
        channel(app1, app2, asset), deposit - amount, [],
        channel(app2, app1, asset), deposit + amount, []
    )

    # app1 -> app2 is the only available path and doens't have resource, app1
    # needs to send CancelTransfer to app0
    transfer(app0, app2, asset, 50)

    assert_synched_channels(
        channel(app0, app1, asset), deposit, [],
        channel(app1, app0, asset), deposit, []
    )

    assert_synched_channels(
        channel(app1, app2, asset), deposit - amount, [],
        channel(app2, app1, asset), deposit + amount, []
    )

    assert len(messages) == 6  # DirectTransfer + MediatedTransfer + CancelTransfer + a Ack for each

    app1_messages = mlogger.get_node_messages(pex(app1.raiden.address), only='sent')

    assert isinstance(app1_messages[-1], CancelTransfer)
Exemple #36
0
def test_transfer(raiden_network, tokens_addresses):
    app0, app1 = raiden_network  # pylint: disable=unbalanced-tuple-unpacking

    channel0 = channel(app0, app1, tokens_addresses[0])
    channel1 = channel(app1, app0, tokens_addresses[0])

    contract_balance0 = channel0.contract_balance
    contract_balance1 = channel1.contract_balance

    # check agreement on addresses
    address0 = channel0.our_state.address
    address1 = channel1.our_state.address

    app0_token = app0.raiden.managers_by_token_address.keys()[0]
    app1_token = app1.raiden.managers_by_token_address.keys()[0]

    app0_partners = app0.raiden.managers_by_token_address.values(
    )[0].partneraddress_channel.keys()
    app1_partners = app1.raiden.managers_by_token_address.values(
    )[0].partneraddress_channel.keys()

    assert channel0.token_address == channel1.token_address
    assert app0_token == app1_token
    assert app1.raiden.address in app0_partners
    assert app0.raiden.address in app1_partners

    netting_address = channel0.external_state.netting_channel.address
    netting_channel = app0.raiden.chain.netting_channel(netting_address)

    # check balances of channel and contract are equal
    details0 = netting_channel.detail(address0)
    details1 = netting_channel.detail(address1)

    assert contract_balance0 == details0['our_balance']
    assert contract_balance1 == details1['our_balance']

    assert_synched_channels(
        channel0,
        contract_balance0,
        [],
        channel1,
        contract_balance1,
        [],
    )

    amount = 10

    direct_transfer = channel0.create_directtransfer(
        amount,
        1  # TODO: fill in identifier
    )
    app0.raiden.sign(direct_transfer)
    channel0.register_transfer(direct_transfer)
    channel1.register_transfer(direct_transfer)

    # check the contract is intact
    assert details0 == netting_channel.detail(address0)
    assert details1 == netting_channel.detail(address1)

    assert channel0.contract_balance == contract_balance0
    assert channel1.contract_balance == contract_balance1

    assert_synched_channels(
        channel0,
        contract_balance0 - amount,
        [],
        channel1,
        contract_balance1 + amount,
        [],
    )
Exemple #37
0
def test_cancel_transfer(raiden_chain, asset, deposit):
    app0, app1, app2 = raiden_chain  # pylint: disable=unbalanced-tuple-unpacking

    messages = setup_messages_cb()
    mlogger = MessageLogger()

    assert_synched_channels(channel(app0, app1, asset), deposit, [],
                            channel(app1, app0, asset), deposit, [])

    assert_synched_channels(channel(app1, app2, asset), deposit, [],
                            channel(app2, app1, asset), deposit, [])

    # drain the channel app1 -> app2
    amount = 80
    direct_transfer(app1, app2, asset, amount)

    assert_synched_channels(channel(app0, app1, asset), deposit, [],
                            channel(app1, app0, asset), deposit, [])

    assert_synched_channels(channel(app1, app2, asset), deposit - amount, [],
                            channel(app2, app1, asset), deposit + amount, [])

    # app1 -> app2 is the only available path and doens't have resource, app1
    # needs to send RefundTransfer to app0
    transfer(app0, app2, asset, 50)

    assert_synched_channels(channel(app0, app1, asset), deposit, [],
                            channel(app1, app0, asset), deposit, [])

    assert_synched_channels(channel(app1, app2, asset), deposit - amount, [],
                            channel(app2, app1, asset), deposit + amount, [])

    assert len(
        messages
    ) == 6  # DirectTransfer + MediatedTransfer + RefundTransfer + a Ack for each

    app1_messages = mlogger.get_node_messages(pex(app1.raiden.address),
                                              only='sent')

    assert isinstance(app1_messages[-1], RefundTransfer)
Exemple #38
0
def test_cancel_transfer(raiden_chain, token_addresses, deposit):
    """ A failed transfer must send a refund back.

    TODO:
        - Unlock the token on refund #1091
        - Clear the merkletree and update the locked amount #193
        - Remove the refund message type #490
    """
    # Topology:
    #
    #  0 -> 1 -> 2
    #
    app0, app1, app2 = raiden_chain  # pylint: disable=unbalanced-tuple-unpacking

    token = token_addresses[0]

    assert_synched_channels(channel(app0, app1, token), deposit, [],
                            channel(app1, app0, token), deposit, [])

    assert_synched_channels(channel(app1, app2, token), deposit, [],
                            channel(app2, app1, token), deposit, [])

    # make a transfer to test the path app0 -> app1 -> app2
    identifier_path = 1
    amount_path = 1
    transfer(app0, app2, token, amount_path, identifier_path)

    # drain the channel app1 -> app2
    identifier_drain = 2
    amount_drain = int(deposit * 0.8)
    direct_transfer(app1, app2, token, amount_drain, identifier_drain)

    # wait for the nodes to sync
    gevent.sleep(0.2)

    assert_synched_channels(channel(app0, app1,
                                    token), deposit - amount_path, [],
                            channel(app1, app0, token), deposit + amount_path,
                            [])

    assert_synched_channels(channel(app1, app2, token),
                            deposit - amount_path - amount_drain, [],
                            channel(app2, app1, token),
                            deposit + amount_path + amount_drain, [])

    # app0 -> app1 -> app2 is the only available path but the channel app1 ->
    # app2 doesnt have resources and needs to send a RefundTransfer down the
    # path
    identifier_refund = 3
    amount_refund = 50
    async_result = app0.raiden.mediated_transfer_async(
        token,
        amount_refund,
        app2.raiden.address,
        identifier_refund,
    )
    assert async_result.wait(
    ) is False, 'there is no path with capacity, the transfer must fail'

    gevent.sleep(0.2)

    # A lock structure with the correct amount
    app0_messages = app0.raiden.protocol.transport.get_sent_messages(
        app0.raiden.address)
    mediated_message = list(message for message in app0_messages
                            if isinstance(message, MediatedTransfer)
                            and message.target == app2.raiden.address)[-1]
    assert mediated_message

    app1_messages = app1.raiden.protocol.transport.get_sent_messages(
        app1.raiden.address)
    refund_message = next(message for message in app1_messages
                          if isinstance(message, RefundTransfer)
                          and message.recipient == app0.raiden.address)
    assert refund_message

    assert mediated_message.lock.amount == refund_message.lock.amount
    assert mediated_message.lock.hashlock == refund_message.lock.hashlock
    assert mediated_message.lock.expiration > refund_message.lock.expiration

    # Both channels have the amount locked because of the refund message
    assert_synched_channels(
        channel(app0, app1, token),
        deposit - amount_path,
        [refund_message.lock],
        channel(app1, app0, token),
        deposit + amount_path,
        [mediated_message.lock],
    )

    assert_synched_channels(channel(app1, app2, token),
                            deposit - amount_path - amount_drain, [],
                            channel(app2, app1, token),
                            deposit + amount_path + amount_drain, [])
Exemple #39
0
def test_start_end_attack(token_addresses, raiden_chain, deposit,
                          reveal_timeout):
    """ An attacker can try to steal tokens from a hub or the last node in a
    path.

    The attacker needs to use two addresses (A1 and A2) and connect both to the
    hub H, once connected a mediated transfer is initialized from A1 to A2
    through H, once the node A2 receives the mediated transfer the attacker
    uses the known secret and reveal to close and settles the channel H-A2,
    without revealing the secret to H's raiden node.

    The intention is to make the hub transfer the token but for him to be
    unable to require the token A1.
    """
    amount = 30

    token = token_addresses[0]
    app0, app1, app2 = raiden_chain  # pylint: disable=unbalanced-tuple-unpacking

    # the attacker owns app0 and app2 and creates a transfer through app1
    identifier = 1
    expiration = reveal_timeout + 5
    secret = pending_mediated_transfer(raiden_chain, token, amount, identifier,
                                       expiration)
    hashlock = sha3(secret)

    attack_channel = channel(app2, app1, token)
    attack_transfer = get_received_transfer(attack_channel, 0)
    attack_contract = attack_channel.external_state.netting_channel.address
    hub_contract = channel(app1, app0,
                           token).external_state.netting_channel.address

    # the attacker can create a merkle proof of the locked transfer
    lock = attack_channel.our_state.balance_proof.get_lock_by_hashlock(
        hashlock)
    unlock_proof = attack_channel.our_state.balance_proof.compute_proof_for_lock(
        secret, lock)

    # start the settle counter
    attack_channel.netting_channel.close(attack_transfer)

    # wait until the last block to reveal the secret, hopefully we are not
    # missing a block during the test
    wait_until_block(app2.raiden.chain, attack_transfer.lock.expiration - 1)

    # since the attacker knows the secret he can net the lock
    attack_channel.netting_channel.withdraw(
        [(unlock_proof, attack_transfer.lock, secret)], )
    # XXX: verify that the secret was publicized

    # at this point the hub might not know yet the secret, and won't be able to
    # claim the token from the channel A1 - H

    # the attacker settle the contract
    app2.raiden.chain.next_block()

    attack_channel.netting_channel.settle(token, attack_contract)

    # at this point the attack has the "stolen" funds
    attack_contract = app2.raiden.chain.token_hashchannel[token][
        attack_contract]
    assert attack_contract.participants[
        app2.raiden.address]['netted'] == deposit + amount
    assert attack_contract.participants[
        app1.raiden.address]['netted'] == deposit - amount

    # and the hub's channel A1-H doesn't
    hub_contract = app1.raiden.chain.token_hashchannel[token][hub_contract]
    assert hub_contract.participants[app0.raiden.address]['netted'] == deposit
    assert hub_contract.participants[app1.raiden.address]['netted'] == deposit

    # to mitigate the attack the Hub _needs_ to use a lower expiration for the
    # locked transfer between H-A2 than A1-H, since for A2 to acquire the token
    # it needs to make the secret public in the block chain we publish the
    # secret through an event and the Hub will be able to require it's funds
    app1.raiden.chain.next_block()

    # XXX: verify that the Hub has found the secret, close and settle the channel

    # the hub has acquired its token
    hub_contract = app1.raiden.chain.token_hashchannel[token][hub_contract]
    assert hub_contract.participants[
        app0.raiden.address]['netted'] == deposit + amount
    assert hub_contract.participants[
        app1.raiden.address]['netted'] == deposit - amount
Exemple #40
0
def test_settled_lock(token_addresses, raiden_network, settle_timeout,
                      reveal_timeout):
    """ Any transfer following a secret revealed must update the locksroot, so
    that an attacker cannot reuse a secret to double claim a lock.
    """
    token = token_addresses[0]
    amount = 30

    app0, app1, app2, _ = raiden_network  # pylint: disable=unbalanced-tuple-unpacking

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

    forward_channel = channel(app0, app1, token)
    back_channel = channel(app1, app0, token)

    deposit0 = forward_channel.contract_balance
    deposit1 = back_channel.contract_balance

    token_contract = app0.raiden.chain.token(token)
    balance0 = token_contract.balance_of(address0)
    balance1 = token_contract.balance_of(address1)

    # mediated transfer
    identifier = 1
    expiration = app0.raiden.chain.block_number(
    ) + settle_timeout - reveal_timeout
    secret = pending_mediated_transfer(
        raiden_network,
        token,
        amount,
        identifier,
        expiration,
    )
    hashlock = sha3(secret)

    # get a proof for the pending transfer
    secret_transfer = get_received_transfer(back_channel, 0)
    lock = back_channel.our_state.balance_proof.get_lock_by_hashlock(hashlock)
    unlock_proof = back_channel.our_state.balance_proof.compute_proof_for_lock(
        secret, lock)

    # reveal the secret
    claim_lock(raiden_network, token, secret)

    # a new transfer to update the hashlock
    direct_transfer(app0, app1, token, amount)

    last_transfer = get_sent_transfer(forward_channel, 1)

    # call close giving the secret for a transfer that has being revealed
    back_channel.external_state.netting_channel.close(last_transfer)

    # check that the double unlock will fail
    with pytest.raises(Exception):
        back_channel.external_state.netting_channel.withdraw(
            [(unlock_proof, secret_transfer.lock.as_bytes, secret)], )

    # forward the block number to allow settle
    settle_expiration = app2.raiden.chain.block_number() + settle_timeout
    wait_until_block(app2.raiden.chain, settle_expiration)

    back_channel.external_state.netting_channel.settle()

    assert token_contract.balance_of(
        address0) == balance0 + deposit0 - amount * 2
    assert token_contract.balance_of(
        address1) == balance1 + deposit1 + amount * 2
Exemple #41
0
def test_settled_lock(token_addresses, raiden_network, settle_timeout,
                      reveal_timeout):
    """ Any transfer following a secret revealed must update the locksroot, so
    that an attacker cannot reuse a secret to double claim a lock.
    """
    token = token_addresses[0]
    amount = 30

    app0, app1, app2, _ = raiden_network  # pylint: disable=unbalanced-tuple-unpacking

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

    forward_channel = channel(app0, app1, token)
    back_channel = channel(app1, app0, token)

    deposit0 = forward_channel.contract_balance
    deposit1 = back_channel.contract_balance

    token_contract = app0.raiden.chain.token(token)
    balance0 = token_contract.balance_of(address0)
    balance1 = token_contract.balance_of(address1)

    # A pending mediated transfer
    identifier = 1
    expiration = app0.raiden.chain.block_number(
    ) + settle_timeout - reveal_timeout
    secret = pending_mediated_transfer(
        raiden_network,
        token,
        amount,
        identifier,
        expiration,
    )
    hashlock = sha3(secret)

    # Get the proof to unlock the pending lock
    secret_transfer = get_received_transfer(back_channel, 0)
    lock = back_channel.partner_state.balance_proof.get_lock_by_hashlock(
        hashlock)
    unlock_proof = back_channel.partner_state.balance_proof.compute_proof_for_lock(
        secret, lock)

    # Update the hashlock
    claim_lock(raiden_network, identifier, token, secret)
    direct_transfer(app0, app1, token, amount, identifier=1)

    # The direct transfer locksroot must remove the unlocked lock and update
    # the transferred amount, the withdraw must fail.
    balance_proof = back_channel.partner_state.balance_proof.balance_proof
    back_channel.external_state.close(balance_proof)
    with pytest.raises(Exception):
        back_channel.external_state.netting_channel.withdraw(
            [(unlock_proof, secret_transfer.lock.as_bytes, secret)], )

    settle_expiration = app2.raiden.chain.block_number() + settle_timeout
    wait_until_block(app2.raiden.chain, settle_expiration)
    back_channel.external_state.netting_channel.settle()

    assert token_contract.balance_of(
        address0) == balance0 + deposit0 - amount * 2
    assert token_contract.balance_of(
        address1) == balance1 + deposit1 + amount * 2
def test_cancel_transfer(raiden_chain, token, deposit):

    app0, app1, app2, app3 = raiden_chain  # pylint: disable=unbalanced-tuple-unpacking

    messages = setup_messages_cb()
    mlogger = MessageLogger()

    assert_synched_channels(
        channel(app0, app1, token), deposit, [],
        channel(app1, app0, token), deposit, []
    )

    assert_synched_channels(
        channel(app1, app2, token), deposit, [],
        channel(app2, app1, token), deposit, []
    )

    assert_synched_channels(
        channel(app2, app3, token), deposit, [],
        channel(app3, app2, token), deposit, []
    )

    assert_synched_channels(
        channel(app0, app1, token), deposit, [],
        channel(app1, app0, token), deposit, []
    )

    # drain the channel app1 -> app2
    amount12 = 50
    direct_transfer(app1, app2, token, amount12, identifier=1)

    # drain the channel app2 -> app3
    amount23 = 80
    direct_transfer(app2, app3, token, amount23, identifier=2)

    assert_synched_channels(
        channel(app1, app2, token), deposit - amount12, [],
        channel(app2, app1, token), deposit + amount12, []
    )

    assert_synched_channels(
        channel(app2, app3, token), deposit - amount23, [],
        channel(app3, app2, token), deposit + amount23, []
    )

    # app1 -> app3 is the only available path but app2 -> app3 doesnt have
    # resources and needs to send a RefundTransfer down the path
    transfer(app0, app3, token, amount=50, identifier=1)

    assert_synched_channels(
        channel(app0, app1, token), deposit, [],
        channel(app1, app0, token), deposit, []
    )

    assert_synched_channels(
        channel(app1, app2, token), deposit - amount12, [],
        channel(app2, app1, token), deposit + amount12, []
    )

    assert_synched_channels(
        channel(app2, app3, token), deposit - amount23, [],
        channel(app3, app2, token), deposit + amount23, []
    )

    assert len(unique(messages)) == 12  # DT + DT + SMT + MT + RT + RT + ACKs

    app1_messages = mlogger.get_node_messages(pex(app1.raiden.address), only='sent')
    assert isinstance(app1_messages[-1], RefundTransfer)

    app2_messages = mlogger.get_node_messages(pex(app2.raiden.address), only='sent')
    assert isinstance(app2_messages[-1], RefundTransfer)
Exemple #43
0
def test_fullnetwork(raiden_chain, settle_timeout, reveal_timeout):
    app0, app1, app2, app3 = raiden_chain  # pylint: disable=unbalanced-tuple-unpacking
    token_address = app0.raiden.chain.default_registry.token_addresses()[0]
    channel_0_1 = channel(app0, app1, token_address)
    channel_1_2 = channel(app1, app2, token_address)
    channel_3_2 = channel(app3, app2, token_address)
    channel_0_3 = channel(app0, app3, token_address)

    amount = 80
    direct_transfer(app0, app1, token_address, amount)
    last_transfer = get_sent_transfer(channel_0_1, 0)
    assert last_transfer.transferred_amount == 80

    amount = 50
    direct_transfer(app1, app2, token_address, amount)
    last_transfer = get_sent_transfer(channel_1_2, 0)
    assert last_transfer.transferred_amount == 50

    amount = 30
    mediated_transfer(app0, app2, token_address, amount)
    last_transfer = get_sent_transfer(channel_0_1, 0)
    assert isinstance(last_transfer, DirectTransfer)

    initiator_transfer = get_sent_transfer(channel_0_3, 0)
    mediator_transfer = get_sent_transfer(channel_3_2, 0)
    assert initiator_transfer.identifier == mediator_transfer.identifier
    assert initiator_transfer.lock.amount == amount
    assert mediator_transfer.lock.amount == amount

    # Now let's query the WAL to see if the state changes were logged as expected
    app0_state_changes = [
        change[1]
        for change in get_all_state_changes(app0.raiden.transaction_log)
        if not isinstance(change[1], Block)
    ]
    app0_events = [
        event[2] for event in get_all_state_events(app0.raiden.transaction_log)
    ]
    app1_state_changes = [
        change[1]
        for change in get_all_state_changes(app1.raiden.transaction_log)
        if not isinstance(change[1], Block)
    ]
    app1_events = [
        event[2] for event in get_all_state_events(app1.raiden.transaction_log)
    ]
    app2_state_changes = [
        change[1]
        for change in get_all_state_changes(app2.raiden.transaction_log)
        if not isinstance(change[1], Block)
    ]
    app2_events = [
        event[2] for event in get_all_state_events(app2.raiden.transaction_log)
    ]
    app3_state_changes = [
        change[1]
        for change in get_all_state_changes(app3.raiden.transaction_log)
        if not isinstance(change[1], Block)
    ]
    app3_events = [
        event[2] for event in get_all_state_events(app3.raiden.transaction_log)
    ]

    # app1 does not take part in the mediated transfer.
    assert len(app1_state_changes) == 0
    assert len(app1_events) == 0

    # app0 initiates the mediated_transfer
    assert len(app0_state_changes) == 3
    assert isinstance(app0_state_changes[0], ActionInitInitiator)
    assert app0_state_changes[0].our_address == app0.raiden.address
    assert app0_state_changes[0].transfer.amount == amount
    assert app0_state_changes[0].transfer.token == token_address
    assert app0_state_changes[0].transfer.initiator == app0.raiden.address
    assert app0_state_changes[0].transfer.target == app2.raiden.address
    # The ActionInitInitiator state change does not have the following fields populated.
    # They get populated via an event during the processing of the state change inside
    # this function: mediated_transfer.mediated_transfer.initiator.try_new_route()
    assert app0_state_changes[0].transfer.expiration is None
    assert app0_state_changes[0].transfer.hashlock is None
    assert app0_state_changes[0].transfer.secret is None
    # We should have two available routes
    assert len(app0_state_changes[0].routes.available_routes) == 2
    assert len(app0_state_changes[0].routes.ignored_routes) == 0
    assert len(app0_state_changes[0].routes.refunded_routes) == 0
    assert len(app0_state_changes[0].routes.canceled_routes) == 0
    # Of these 2 the state machine will in the future choose the one with the most
    # available balance
    not_taken_route = RouteState(
        state='opened',
        node_address=app1.raiden.address,
        channel_address=channel_0_1.channel_address,
        available_balance=1048496,
        settle_timeout=settle_timeout,
        reveal_timeout=reveal_timeout,
        closed_block=None,
    )
    taken_route = RouteState(
        state='opened',
        node_address=app3.raiden.address,
        channel_address=channel_0_3.channel_address,
        available_balance=1048576,
        settle_timeout=settle_timeout,
        reveal_timeout=reveal_timeout,
        closed_block=None,
    )
    assert taken_route in app0_state_changes[0].routes.available_routes
    assert not_taken_route in app0_state_changes[0].routes.available_routes

    # app0 will also receive a secret request from the target
    assert isinstance(app0_state_changes[1], ReceiveSecretRequest)
    assert app0_state_changes[1].amount == amount
    assert app0_state_changes[1].sender == app2.raiden.address
    hashlock = app0_state_changes[1].hashlock

    # app0 will also receive a secret reveal from the immediate neighbour
    assert isinstance(app0_state_changes[2], ReceiveSecretReveal)
    assert app0_state_changes[2].sender == app3.raiden.address
    secret = app0_state_changes[2].secret
    assert sha3(secret) == hashlock

    # check app0 state events
    assert len(app0_events) == 4
    assert isinstance(app0_events[0], SendMediatedTransfer)
    assert app0_events[0].token == token_address
    assert app0_events[0].amount == amount
    assert app0_events[0].hashlock == hashlock
    assert app0_events[0].initiator == app0.raiden.address
    assert app0_events[0].target == app2.raiden.address
    assert app0_events[0].receiver == app3.raiden.address
    assert isinstance(app0_events[1], SendRevealSecret)
    assert app0_events[1].secret == secret
    assert app0_events[1].token == token_address
    assert app0_events[1].receiver == app2.raiden.address
    assert app0_events[1].sender == app0.raiden.address
    assert isinstance(app0_events[2], SendBalanceProof)
    assert app0_events[2].token == token_address
    assert app0_events[2].channel_address == channel_0_3.channel_address
    assert app0_events[2].receiver == app3.raiden.address
    assert app0_events[2].secret == secret
    assert isinstance(app0_events[3], EventTransferCompleted)
    assert app0_events[3].secret == secret
    assert app0_events[3].hashlock == hashlock

    # app3 is the mediator
    assert isinstance(app3_state_changes[0], ActionInitMediator)
    assert app3_state_changes[0].our_address == app3.raiden.address
    # We should have only 1 available route from mediator to target
    from_route = RouteState(
        state='opened',
        node_address=app0.raiden.address,
        channel_address=channel_0_3.channel_address,
        available_balance=1048576,
        settle_timeout=settle_timeout,
        reveal_timeout=reveal_timeout,
        closed_block=None,
    )
    to_route = RouteState(
        state='opened',
        node_address=app2.raiden.address,
        channel_address=channel_3_2.channel_address,
        available_balance=1048576,
        settle_timeout=settle_timeout,
        reveal_timeout=reveal_timeout,
        closed_block=None,
    )
    assert app3_state_changes[0].from_route == from_route
    assert len(app3_state_changes[0].routes.available_routes) == 1
    assert len(app3_state_changes[0].routes.ignored_routes) == 0
    assert len(app3_state_changes[0].routes.refunded_routes) == 0
    assert len(app3_state_changes[0].routes.canceled_routes) == 0
    assert app3_state_changes[0].routes.available_routes[0] == to_route
    # check the from_transfer is correct
    assert app3_state_changes[0].from_transfer.amount == amount
    assert app3_state_changes[0].from_transfer.hashlock == hashlock
    assert app3_state_changes[0].from_transfer.token == token_address
    assert app3_state_changes[0].from_transfer.initiator == app0.raiden.address
    assert app3_state_changes[0].from_transfer.target == app2.raiden.address

    # The mediator should have also received a SecretReveal from the target
    assert isinstance(app3_state_changes[1], ReceiveSecretReveal)
    assert app3_state_changes[1].sender == app2.raiden.address
    assert app3_state_changes[1].secret == secret

    # If the mediator received any more it is from the initiator
    # TODO: Figure out why we may get two times the secret reveal from the initiator
    for state_change in app3_state_changes[2:]:
        assert isinstance(state_change, ReceiveSecretReveal)
        assert state_change.sender == app0.raiden.address
        assert state_change.secret == secret

    # check app3 state events
    assert len(app3_events) == 3
    assert isinstance(app3_events[0], SendMediatedTransfer)
    assert app3_events[0].token == token_address
    assert app3_events[0].amount == amount
    assert app3_events[0].hashlock == hashlock
    assert app3_events[0].initiator == app0.raiden.address
    assert app3_events[0].target == app2.raiden.address
    assert app3_events[0].receiver == app2.raiden.address
    assert isinstance(app3_events[1], SendRevealSecret)
    assert app3_events[1].secret == secret
    assert app3_events[1].token == token_address
    assert app3_events[1].receiver == app0.raiden.address
    assert app3_events[1].sender == app3.raiden.address
    assert isinstance(app3_events[2], SendBalanceProof)
    assert app3_events[2].token == token_address
    assert app3_events[2].channel_address == channel_3_2.channel_address
    assert app3_events[2].receiver == app2.raiden.address
    assert app3_events[2].secret == secret

    # app2 is the target of the mediated transfer
    assert len(app2_state_changes
               ) == 4  # We get 2 secret reveals from the mediator. WHY?
    assert isinstance(app2_state_changes[0], ActionInitTarget)
    assert app2_state_changes[0].our_address == app2.raiden.address
    # check the route the transfer came from
    from_route = RouteState(
        state='opened',
        node_address=app3.raiden.address,
        channel_address=channel_3_2.channel_address,
        available_balance=1048576,
        settle_timeout=settle_timeout,
        reveal_timeout=reveal_timeout,
        closed_block=None,
    )
    assert app2_state_changes[0].from_route == from_route
    # check the from_transfer is correct
    assert app2_state_changes[0].from_transfer.amount == amount
    assert app2_state_changes[0].from_transfer.hashlock == hashlock
    assert app2_state_changes[0].from_transfer.token == token_address
    assert app2_state_changes[0].from_transfer.initiator == app0.raiden.address
    assert app2_state_changes[0].from_transfer.target == app2.raiden.address

    # We also get secret reveals from the initiator and the mediator.
    assert isinstance(app2_state_changes[1], ReceiveSecretReveal)
    assert app2_state_changes[1].sender == app0.raiden.address
    assert app2_state_changes[1].secret == secret

    # TODO: Figure out why we get two times the Secret Reveal from the mediator
    assert isinstance(app2_state_changes[2], ReceiveSecretReveal)
    assert app2_state_changes[2].sender == app3.raiden.address
    assert app2_state_changes[2].secret == secret
    assert isinstance(app2_state_changes[3], ReceiveSecretReveal)
    assert app2_state_changes[3].sender == app3.raiden.address
    assert app2_state_changes[3].secret == secret

    # check app2 state events
    assert len(app2_events) == 2
    assert isinstance(app2_events[0], SendSecretRequest)
    assert app2_events[0].amount == amount
    assert app2_events[0].hashlock == hashlock
    assert app2_events[0].receiver == app0.raiden.address
    assert isinstance(app2_events[1], SendRevealSecret)
    assert app2_events[1].token == token_address
    assert app2_events[1].secret == secret
    assert app2_events[1].receiver == app3.raiden.address
    assert app2_events[1].sender == app2.raiden.address
Exemple #44
0
def test_receive_mediated_before_deposit(raiden_network, token_addresses):
    """Regression test that ensures we accept incoming mediated transfers, even if we don't have
    any back channel balance. """
    app_alice, app_bob, app_charlie = raiden_network
    token_address = token_addresses[0]

    # path alice -> bob -> charlie
    alice_bob = channel(app_alice, app_bob, token_address)
    bob_alice = channel(app_bob, app_alice, token_address)
    bob_charlie = channel(app_bob, app_charlie, token_address)
    charlie_bob = channel(app_charlie, app_bob, token_address)

    # ensure alice charlie is mediated
    with pytest.raises(KeyError):
        channel(app_alice, app_charlie, token_address)

    assert not alice_bob.can_transfer
    assert not bob_charlie.can_transfer
    assert not bob_alice.can_transfer

    deposit_amount = 3
    RaidenAPI(app_alice.raiden).deposit(
        token_address,
        app_bob.raiden.address,
        deposit_amount,
    )

    RaidenAPI(app_bob.raiden).deposit(
        token_address,
        app_charlie.raiden.address,
        deposit_amount,
    )

    # catch up with the Balance events
    for app in raiden_network:
        app.raiden.poll_blockchain_events()

    assert alice_bob.can_transfer
    assert bob_charlie.can_transfer
    assert not bob_alice.can_transfer

    assert alice_bob.distributable == deposit_amount
    assert bob_charlie.distributable == deposit_amount

    transfer_amount = 1
    async_result = app_alice.raiden.mediated_transfer_async(
        token_address,
        transfer_amount,
        app_charlie.raiden.address,
        1,
    )
    assert async_result.wait(10)

    # give extra time for the intermediaries to process the secret messages and
    # withdraw the tokens
    gevent.sleep(1)

    assert alice_bob.distributable == deposit_amount - transfer_amount
    assert bob_charlie.distributable == deposit_amount - transfer_amount
    assert bob_alice.distributable == transfer_amount
    assert charlie_bob.distributable == transfer_amount

    assert alice_bob.can_transfer
    assert bob_alice.can_transfer
    assert charlie_bob.can_transfer
Exemple #45
0
def test_settled_lock(assets_addresses, raiden_network, settle_timeout,
                      reveal_timeout):
    """ Any transfer following a secret revealed must update the locksroot, so
    that an attacker cannot reuse a secret to double claim a lock.
    """
    asset = assets_addresses[0]
    amount = 30

    app0, app1, app2, _ = raiden_network  # pylint: disable=unbalanced-tuple-unpacking
    address0 = app0.raiden.address
    address1 = app1.raiden.address

    # mediated transfer
    identifier = 1
    expiration = app0.raiden.chain.block_number(
    ) + settle_timeout - reveal_timeout
    secret = pending_mediated_transfer(
        raiden_network,
        asset,
        amount,
        identifier,
        expiration,
    )
    hashlock = sha3(secret)

    # get a proof for the pending transfer
    back_channel = channel(app1, app0, asset)
    secret_transfer = get_received_transfer(back_channel, 0)
    lock = back_channel.our_state.balance_proof.get_lock_by_hashlock(hashlock)
    unlock_proof = back_channel.our_state.balance_proof.compute_proof_for_lock(
        secret, lock)

    # reveal the secret
    claim_lock(raiden_network, asset, secret)

    # a new transfer to update the hashlock
    direct_transfer(app0, app1, asset, amount)

    forward_channel = channel(app0, app1, asset)
    last_transfer = get_sent_transfer(forward_channel, 1)

    # call close giving the secret for a transfer that has being revealed
    back_channel.external_state.netting_channel.close(app1.raiden.address,
                                                      last_transfer, None)

    # check that the double unlock will failed
    with pytest.raises(Exception):
        back_channel.external_state.netting_channel.unlock(
            app1.raiden.address,
            [(unlock_proof, secret_transfer.lock.as_bytes, secret)],
        )

    # forward the block number to allow settle
    settle_expiration = app2.raiden.chain.block_number() + settle_timeout
    wait_until_block(app2.raiden.chain, settle_expiration)

    back_channel.external_state.netting_channel.settle()

    participant0 = back_channel.external_state.netting_channel.contract.participants[
        address0]
    participant1 = back_channel.external_state.netting_channel.contract.participants[
        address1]

    assert participant0.netted == participant0.deposit - amount * 2
    assert participant1.netted == participant1.deposit + amount * 2
def test_start_end_attack(asset_address, raiden_chain, deposit):
    """ An attacker can try to steal assets from a hub or the last node in a
    path.

    The attacker needs to use two addresses (A1 and A2) and connect both to the
    hub H, once connected a mediated transfer is initialized from A1 to A2
    through H, once the node A2 receives the mediated transfer the attacker
    uses the it's know secret and reveal to close and settles the channel H-A2,
    without revealing the secret to H's raiden node.

    The intention is to make the hub transfer the asset but for him to be
    unable to require the asset A1.
    """
    amount = 30

    asset = asset_address[0]
    app0, app1, app2 = raiden_chain  # pylint: disable=unbalanced-tuple-unpacking

    # the attacker owns app0 and app2 and creates a transfer throught app1
    secret = pending_mediated_transfer(
        raiden_chain,
        asset,
        amount,
        1  # TODO: fill in identifier
    )
    hashlock = sha3(secret)

    attack_channel = channel(app2, app1, asset)
    attack_transfer = get_received_transfer(attack_channel, 0)
    attack_contract = attack_channel.external_state.netting_channel.address
    hub_contract = channel(app1, app0, asset).external_state.netting_channel.address

    # the attacker can create a merkle proof of the locked transfer
    lock = attack_channel.our_state.balance_proof.get_lock_by_hashlock(hashlock)
    unlock_proof = attack_channel.our_state.balance_proof.compute_proof_for_lock(secret, lock)

    # start the settle counter
    attack_channel.netting_channel.close(
        app2.raiden.address,
        attack_transfer,
        None
    )

    # wait until the last block to reveal the secret, hopefully we are not
    # missing a block during the test
    wait_until_block(app2.raiden.chain, attack_transfer.lock.expiration - 1)

    # since the attacker knows the secret he can net the lock
    attack_channel.netting_channel.unlock(
        [(unlock_proof, attack_transfer.lock, secret)],
    )
    # XXX: verify that the secret was publicized

    # at this point the hub might not know yet the secret, and won't be able to
    # claim the asset from the channel A1 - H

    # the attacker settle the contract
    app2.raiden.chain.next_block()

    attack_channel.netting_channel.settle(asset, attack_contract)

    # at this point the attack has the "stolen" funds
    attack_contract = app2.raiden.chain.asset_hashchannel[asset][attack_contract]
    assert attack_contract.participants[app2.raiden.address]['netted'] == deposit + amount
    assert attack_contract.participants[app1.raiden.address]['netted'] == deposit - amount

    # and the hub's channel A1-H doesn't
    hub_contract = app1.raiden.chain.asset_hashchannel[asset][hub_contract]
    assert hub_contract.participants[app0.raiden.address]['netted'] == deposit
    assert hub_contract.participants[app1.raiden.address]['netted'] == deposit

    # to mitigate the attack the Hub _needs_ to use a lower expiration for the
    # locked transfer between H-A2 than A1-H, since for A2 to acquire the asset
    # it needs to make the secret public in the block chain we publish the
    # secret through an event and the Hub will be able to require it's funds
    app1.raiden.chain.next_block()

    # XXX: verify that the Hub has found the secret, close and settle the channel

    # the hub has acquired it's asset
    hub_contract = app1.raiden.chain.asset_hashchannel[asset][hub_contract]
    assert hub_contract.participants[app0.raiden.address]['netted'] == deposit + amount
    assert hub_contract.participants[app1.raiden.address]['netted'] == deposit - amount
def test_regression_multiple_revealsecret(raiden_network, token_addresses):
    """ Multiple RevealSecret messages arriving at the same time must be
    handled properly.

    Secret handling followed these steps:

        The Secret message arrives
        The secret is registered
        The channel is updated and the correspoding lock is removed
        * A balance proof for the new channel state is created and sent to the
          payer
        The channel is unregistered for the given hashlock

    The step marked with an asterisk above introduced a context-switch, this
    allowed a second Reveal Secret message to be handled before the channel was
    unregistered, because the channel was already updated an exception was raised
    for an unknown secret.
    """
    app0, app1 = raiden_network
    token = token_addresses[0]

    identifier = 1
    secret = sha3(b'test_regression_multiple_revealsecret')
    hashlock = sha3(secret)
    expiration = app0.raiden.get_block_number() + 100
    amount = 10

    mediated_transfer = channel(app0, app1, token).create_mediatedtransfer(
        transfer_initiator=app0.raiden.address,
        transfer_target=app1.raiden.address,
        fee=0,
        amount=amount,
        identifier=identifier,
        expiration=expiration,
        hashlock=hashlock,
    )
    app0.raiden.sign(mediated_transfer)

    message_data = mediated_transfer.encode()
    app1.raiden.protocol.receive(message_data)

    reveal_secret = RevealSecret(secret)
    app0.raiden.sign(reveal_secret)
    reveal_secret_data = reveal_secret.encode()

    secret = Secret(
        identifier=identifier,
        nonce=mediated_transfer.nonce + 1,
        channel=channel(app0, app1, token).channel_address,
        transferred_amount=amount,
        locksroot=EMPTY_MERKLE_ROOT,
        secret=secret,
    )
    app0.raiden.sign(secret)
    secret_data = secret.encode()

    messages = [
        secret_data,
        reveal_secret_data,
    ]

    wait = [
        gevent.spawn_later(
            .1,
            app1.raiden.protocol.receive,
            data,
        )
        for data in messages
    ]

    gevent.joinall(wait)