def test_mediation(raiden_network, token_addresses, settle_timeout): # The network has the following topology: # # App1 <--> App0 <--> App2 token_address = token_addresses[0] app0, app1, app2 = raiden_network # pylint: disable=unbalanced-tuple-unpacking identifier = 1 amount = 1 async_result = app1.raiden.mediated_transfer_async( token_address, amount, app2.raiden.address, identifier, ) assert async_result.wait() mediator_chain = app0.raiden.chain settle_expiration = mediator_chain.block_number() + settle_timeout + 1 wait_until_block(mediator_chain, settle_expiration) # context switch needed for tester to process the EventWithdrawSuccess gevent.sleep(1) app0_events = [ event.event_object for event in get_all_state_events(app0.raiden.transaction_log) ] assert must_contain_entry(app0_events, EventWithdrawSuccess, {})
def test_channel_with_self(raiden_network, settle_timeout, token_addresses): app0, = raiden_network # pylint: disable=unbalanced-tuple-unpacking registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] current_chanels = views.list_channelstate_for_tokennetwork( views.state_from_app(app0), registry_address, token_address, ) assert not current_chanels graph0 = app0.raiden.default_registry.manager_by_token(token_address) with pytest.raises(SamePeerAddress) as excinfo: graph0.new_netting_channel( app0.raiden.address, settle_timeout, ) assert 'The other peer must not have the same address as the client.' in str(excinfo.value) transaction_hash = graph0.proxy.transact('newChannel', app0.raiden.address, settle_timeout) # wait to make sure we get the receipt wait_until_block(app0.raiden.chain, app0.raiden.chain.block_number() + 5) assert check_transaction_threw(app0.raiden.chain.client, transaction_hash)
def test_channel_with_self(raiden_network, settle_timeout): app0, = raiden_network # pylint: disable=unbalanced-tuple-unpacking token_address = app0.raiden.default_registry.token_addresses()[0] assert not app0.raiden.token_to_channelgraph[token_address].address_to_channel graph0 = app0.raiden.default_registry.manager_by_token(token_address) with pytest.raises(SamePeerAddress) as excinfo: graph0.new_netting_channel( app0.raiden.address, settle_timeout, ) assert 'The other peer must not have the same address as the client.' in str(excinfo.value) transaction_hash = graph0.proxy.transact( 'newChannel', app0.raiden.address, settle_timeout, ) # wait to make sure we get the receipt wait_until_block(app0.raiden.chain, app0.raiden.chain.block_number() + 5) assert check_transaction_threw(app0.raiden.chain.client, transaction_hash)
def test_channel_with_self(raiden_network, settle_timeout, blockchain_type): app0, = raiden_network # pylint: disable=unbalanced-tuple-unpacking token_address = app0.raiden.chain.default_registry.token_addresses()[0] assert len(app0.raiden.token_to_channelgraph[token_address].address_to_channel) == 0 graph0 = app0.raiden.chain.manager_by_token(token_address) with pytest.raises(SamePeerAddress) as excinfo: graph0.new_netting_channel( app0.raiden.address, app0.raiden.address, settle_timeout, ) assert 'Peer1 and peer2 must not be equal' in str(excinfo.value) if blockchain_type == 'tester': with pytest.raises(TransactionFailed): graph0.proxy.newChannel(app0.raiden.address, settle_timeout) else: tx = graph0.proxy.newChannel(app0.raiden.address, settle_timeout) # wait to make sure we get the receipt wait_until_block(app0.raiden.chain, app0.raiden.chain.block_number() + 5) assert check_transaction_threw(app0.raiden.chain.client, tx) is True
def test_transfer_from_outdated(raiden_network, settle_timeout): app0, app1 = raiden_network # pylint: disable=unbalanced-tuple-unpacking graph0 = app0.raiden.token_to_channelgraph.values()[0] graph1 = app1.raiden.token_to_channelgraph.values()[0] channel0 = graph0.partneraddress_to_channel[app1.raiden.address] channel1 = graph1.partneraddress_to_channel[app0.raiden.address] balance0 = channel0.balance balance1 = channel1.balance assert graph0.token_address == graph1.token_address assert app1.raiden.address in graph0.partneraddress_to_channel amount = 10 result = app0.raiden.transfer_async( graph0.token_address, amount, target=app1.raiden.address, ) assert result.wait(timeout=10) assert_synched_channels(channel0, balance0 - amount, [], channel1, balance1 + amount, []) channel1.external_state.close(channel1.received_transfers[-1], ) wait_until_block(app1.raiden.chain, app1.raiden.chain.block_number() + 1) assert channel0.external_state.close_event.wait(timeout=25) assert channel1.external_state.close_event.wait(timeout=25) assert channel0.external_state.closed_block != 0 assert channel1.external_state.closed_block != 0 wait_until_block( app0.raiden.chain, app0.raiden.chain.block_number() + settle_timeout, ) assert channel0.external_state.settle_event.wait(timeout=25) assert channel1.external_state.settle_event.wait(timeout=25) assert channel0.external_state.settled_block != 0 assert channel1.external_state.settled_block != 0 # and now receive one more transfer from the closed channel direct_transfer_message = DirectTransfer( identifier=1, nonce=1, token=graph0.token_address, channel=channel0.channel_address, transferred_amount=10, recipient=app0.raiden.address, locksroot=UNIT_HASHLOCK, ) sign_and_send(direct_transfer_message, app1.raiden.private_key, app1.raiden.address, app1)
def test_leaving(raiden_network, token_addresses, blockchain_type): token_address = token_addresses[0] connection_managers = [ app.raiden.connection_manager_for_token(token_address) for app in raiden_network ] all_channels = list( itertools.chain.from_iterable( connection_manager.receiving_channels for connection_manager in connection_managers)) leaving_async = [ app.raiden.leave_all_token_networks_async() for app in raiden_network[1:] ] with gevent.timeout.Timeout(30): # tester needs manual block progress if blockchain_type == 'tester': for app in raiden_network: connection_manager = app.raiden.connection_manager_for_token( token_address) wait_blocks = connection_manager.min_settle_blocks if wait_blocks > 0: wait_until_block( app.raiden.chain, app.raiden.chain.block_number() + wait_blocks) gevent.sleep(app.raiden.alarm.wait_time) gevent.wait(leaving_async, timeout=50) assert not connection_managers[0].receiving_channels assert all(channel.state == CHANNEL_STATE_SETTLED for channel in all_channels)
def test_secret_revealed(raiden_chain, deposit, settle_timeout, events_poll_timeout): app0, app1, app2 = raiden_chain asset_address = app0.raiden.chain.default_registry.asset_addresses()[0] amount = 10 channel21 = channel(app2, app1, asset_address) netting_channel = channel21.external_state.netting_channel secret = pending_mediated_transfer( raiden_chain, asset_address, amount, 1 # TODO: fill in identifier ) hashlock = sha3(secret) gevent.sleep(.1) # wait for the messages balance_proof = channel21.our_state.balance_proof lock = balance_proof.get_lock_by_hashlock(hashlock) proof = balance_proof.compute_proof_for_lock(secret, lock) # the secret hasn't been revealed yet (through messages) assert len(balance_proof.hashlock_pendinglocks) == 1 proofs = list(balance_proof.get_known_unlocks()) assert len(proofs) == 0 netting_channel.close(app2.raiden.address, balance_proof.transfer, None) # reveal it through the blockchain (this needs to emit the SecretRevealed event) netting_channel.unlock( 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, 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_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, token_addresses): app0, app1, app2 = raiden_chain registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) amount = 10 identifier = 1 secret = pending_mediated_transfer( raiden_chain, token_network_identifier, amount, identifier, ) secrethash = sha3(secret) gevent.sleep(.1) # wait for the messages channel_state2_1 = get_channelstate(app2, app1, token_network_identifier) # the secret hasn't been revealed yet (through messages) assert len(channel_state2_1.our_state.secrethashes_to_lockedlocks) == 1 proofs = list(channel.get_known_unlocks(channel_state2_1.our_state)) assert not proofs channel.register_secret(channel_state2_1, secret, secrethash) # Close the channel netting_channel_proxy = app2.raiden.chain.netting_channel(channel_state2_1.identifier) netting_channel_proxy.channel_close( registry_address, channel_state2_1.partner_state.balance_proof, ) # Reveal the secret through the blockchain (this needs to emit the # SecretRevealed event) for unlock_proof in channel.get_known_unlocks(channel_state2_1.partner_state): netting_channel_proxy.unlock(unlock_proof) settle_expiration = app0.raiden.chain.block_number() + settle_timeout wait_until_block(app0.raiden.chain, settle_expiration) assert_synched_channel_state( token_address, app1, deposit - amount, [], app2, deposit + amount, [], ) assert_synched_channel_state( token_address, app0, deposit - amount, [], app1, deposit + amount, [], )
def test_received_lockedtransfer_closedchannel(raiden_network, reveal_timeout, token_addresses, deposit): app0, app1 = raiden_network registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] channel0 = get_channelstate(app0, app1, token_address) RaidenAPI(app1.raiden).channel_close( registry_address, token_address, app0.raiden.address, ) wait_until_block( app0.raiden.chain, app0.raiden.chain.block_number() + 1, ) # Now receive one mediated transfer for the closed channel lock_amount = 10 payment_identifier = 1 expiration = reveal_timeout * 2 mediated_transfer_message = LockedTransfer( message_identifier=random.randint(0, UINT64_MAX), payment_identifier=payment_identifier, nonce=1, registry_address=app0.raiden.default_registry.address, token=token_address, channel=channel0.identifier, transferred_amount=0, locked_amount=lock_amount, recipient=app1.raiden.address, locksroot=UNIT_SECRETHASH, lock=Lock(lock_amount, expiration, UNIT_SECRETHASH), target=app1.raiden.address, initiator=app0.raiden.address, fee=0) sign_and_inject( mediated_transfer_message, app0.raiden.private_key, app0.raiden.address, app1, ) # The local state must not change since the channel is already closed assert_synched_channel_state( token_address, app0, deposit, [], app1, deposit, [], )
def test_received_directtransfer_closedchannel(raiden_network, token_addresses, deposit): app0, app1 = raiden_network token_address = token_addresses[0] registry_address = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), registry_address, token_address, ) channel0 = get_channelstate(app0, app1, token_network_identifier) RaidenAPI(app1.raiden).channel_close( registry_address, token_address, app0.raiden.address, ) wait_until_block( app0.raiden.chain, app0.raiden.chain.block_number() + 1, ) # Now receive one direct transfer for the closed channel message_identifier = random.randint(0, UINT64_MAX) direct_transfer_message = DirectTransfer( message_identifier=message_identifier, payment_identifier=1, nonce=1, token_network_address=token_network_identifier, token=token_address, channel=channel0.identifier, transferred_amount=10, locked_amount=0, recipient=app0.raiden.address, locksroot=EMPTY_MERKLE_ROOT, ) sign_and_inject( direct_transfer_message, app0.raiden.private_key, app0.raiden.address, app1, ) # The local state must not change since the channel is already closed assert_synched_channel_state( token_network_identifier, app0, deposit, [], app1, deposit, [], )
def test_transfer_from_outdated(raiden_network, settle_timeout): app0, app1 = raiden_network # pylint: disable=unbalanced-tuple-unpacking token_manager0 = app0.raiden.managers_by_token_address.values()[0] token_manager1 = app1.raiden.managers_by_token_address.values()[0] channel0 = token_manager0.partneraddress_channel[app1.raiden.address] channel1 = token_manager1.partneraddress_channel[app0.raiden.address] balance0 = channel0.balance balance1 = channel1.balance assert token_manager0.token_address == token_manager1.token_address assert app1.raiden.address in token_manager0.partneraddress_channel amount = 10 app0.raiden.api.transfer( token_manager0.token_address, amount, target=app1.raiden.address, ) assert_synched_channels(channel0, balance0 - amount, [], channel1, balance1 + amount, []) app1.raiden.api.close(token_manager0.token_address, app0.raiden.address) wait_until_block(app1.raiden.chain, app1.raiden.chain.block_number() + 1) assert channel0.close_event.wait(timeout=25) assert channel1.close_event.wait(timeout=25) assert channel0.external_state.closed_block != 0 assert channel1.external_state.closed_block != 0 wait_until_block( app0.raiden.chain, app0.raiden.chain.block_number() + settle_timeout, ) assert channel0.settle_event.wait(timeout=25) assert channel1.settle_event.wait(timeout=25) assert channel0.external_state.settled_block != 0 assert channel1.external_state.settled_block != 0 # and now receive one more transfer from the closed channel direct_transfer = DirectTransfer(identifier=1, nonce=1, token=token_manager0.token_address, transferred_amount=10, recipient=app0.raiden.address, locksroot=HASH) sign_and_send(direct_transfer, app1.raiden.private_key, app1.raiden.address, app1)
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) 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[ 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
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_close_regression(blockchain_type, raiden_network, token_addresses): """ The python api was using the wrong balance proof to close the channel, thus the close was failling if a transfer was made. """ if blockchain_type == 'tester': pytest.skip('event polling is not reliable') node1, node2 = raiden_network token_address = token_addresses[0] api1 = RaidenAPI(node1.raiden) api2 = RaidenAPI(node2.raiden) channel_list = api1.get_channel_list(token_address, node2.raiden.address) channel12 = channel_list[0] token_proxy = node1.raiden.chain.token(token_address) node1_balance_before = token_proxy.balance_of(api1.address) node2_balance_before = token_proxy.balance_of(api2.address) channel_balance = token_proxy.balance_of(channel12.channel_address) amount = 10 assert api1.transfer(token_address, amount, api2.address) api1.close(token_address, api2.address) node1.raiden.poll_blockchain_events() assert channel12.state == CHANNEL_STATE_CLOSED settlement_block = ( channel12.external_state.closed_block + channel12.settle_timeout + 5 # arbitrary number of additional blocks, used to wait for the settle() call ) wait_until_block(node1.raiden.chain, settlement_block) node1.raiden.poll_blockchain_events() assert channel12.state == CHANNEL_STATE_SETTLED node1_withdraw_amount = channel12.balance node2_withdraw_amount = channel_balance - node1_withdraw_amount assert token_proxy.balance_of( api1.address) == node1_balance_before + node1_withdraw_amount assert token_proxy.balance_of( api2.address) == node2_balance_before + node2_withdraw_amount
def test_received_directtransfer_closedchannel(raiden_network, token_addresses, deposit): app0, app1 = raiden_network token_address = token_addresses[0] channel0 = get_channelstate(app0, app1, token_address) RaidenAPI(app1.raiden).channel_close( token_address, app0.raiden.address, ) wait_until_block( app0.raiden.chain, app0.raiden.chain.block_number() + 1, ) # Now receive one direct transfer for the closed channel direct_transfer_message = DirectTransfer( identifier=1, nonce=1, token=token_address, channel=channel0.identifier, transferred_amount=10, recipient=app0.raiden.address, locksroot=EMPTY_MERKLE_ROOT, ) sign_and_inject( direct_transfer_message, app0.raiden.private_key, app0.raiden.address, app1, ) # The local state must not change since the channel is already closed assert_synched_channel_state( token_address, app0, deposit, [], app1, deposit, [], )
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
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_channel_lifecycle(raiden_network, token_addresses, deposit, transport_config): node1, node2 = raiden_network token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(node1), node1.raiden.default_registry.address, token_address, ) api1 = RaidenAPI(node1.raiden) api2 = RaidenAPI(node2.raiden) registry_address = node1.raiden.default_registry.address if transport_config.protocol == TransportProtocol.UDP: # nodes don't have a channel, so they are not healthchecking assert api1.get_node_network_state( api2.address) == NODE_NETWORK_UNKNOWN assert api2.get_node_network_state( api1.address) == NODE_NETWORK_UNKNOWN elif transport_config.protocol == TransportProtocol.MATRIX: # with Matrix nodes do not need a health check to know each others reachability assert api1.get_node_network_state( api2.address) == NODE_NETWORK_UNREACHABLE assert api2.get_node_network_state( api1.address) == NODE_NETWORK_UNREACHABLE assert not api1.get_channel_list(registry_address, token_address, api2.address) # open is a synchronous api api1.channel_open(node1.raiden.default_registry.address, token_address, api2.address) channels = api1.get_channel_list(registry_address, token_address, api2.address) assert len(channels) == 1 channel12 = get_channelstate(node1, node2, token_network_identifier) assert channel.get_status(channel12) == CHANNEL_STATE_OPENED event_list1 = api1.get_channel_events( channel12.identifier, channel12.open_transaction.finished_block_number, ) assert event_list1 == [] token_events = api1.get_token_network_events( token_address, channel12.open_transaction.finished_block_number, ) assert token_events[0]['event'] == EVENT_CHANNEL_NEW registry_address = api1.raiden.default_registry.address # Load the new state with the deposit api1.channel_deposit( registry_address, token_address, api2.address, deposit, ) channel12 = get_channelstate(node1, node2, token_network_identifier) assert channel.get_status(channel12) == CHANNEL_STATE_OPENED assert channel.get_balance(channel12.our_state, channel12.partner_state) == deposit assert channel12.our_state.contract_balance == deposit assert api1.get_channel_list(registry_address, token_address, api2.address) == [channel12] # there is a channel open, they must be healthchecking each other assert api1.get_node_network_state(api2.address) == NODE_NETWORK_REACHABLE assert api2.get_node_network_state(api1.address) == NODE_NETWORK_REACHABLE event_list2 = api1.get_channel_events( channel12.identifier, channel12.open_transaction.finished_block_number, ) assert any( (event['event'] == EVENT_CHANNEL_NEW_BALANCE and is_same_address( event['args']['registry_address'], to_normalized_address(registry_address), ) and is_same_address( event['args']['participant'], to_normalized_address(api1.address), )) for event in event_list2) api1.channel_close(registry_address, token_address, api2.address) # Load the new state with the channel closed channel12 = get_channelstate(node1, node2, token_network_identifier) event_list3 = api1.get_channel_events( channel12.identifier, channel12.open_transaction.finished_block_number, ) assert len(event_list3) > len(event_list2) assert any((event['event'] == EVENT_CHANNEL_CLOSED and is_same_address( event['args']['registry_address'], to_normalized_address(registry_address), ) and is_same_address( event['args']['closing_address'], to_normalized_address(api1.address), )) for event in event_list3) assert channel.get_status(channel12) == CHANNEL_STATE_CLOSED settlement_block = ( channel12.close_transaction.finished_block_number + channel12.settle_timeout + 10 # arbitrary number of additional blocks, used to wait for the settle() call ) wait_until_block(node1.raiden.chain, settlement_block) # Load the new state with the channel settled channel12 = get_channelstate(node1, node2, token_network_identifier) assert channel.get_status(channel12) == CHANNEL_STATE_SETTLED
def test_query_events(raiden_chain, deposit, settle_timeout, events_poll_timeout): app0, app1 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking token_address = app0.raiden.default_registry.token_addresses()[0] assert len(app0.raiden.token_to_channelgraph[token_address]. address_to_channel) == 0 assert len(app1.raiden.token_to_channelgraph[token_address]. address_to_channel) == 0 token0 = app0.raiden.chain.token(token_address) manager0 = app0.raiden.default_registry.manager_by_token(token_address) events = get_all_registry_events( app0.raiden.chain, app0.raiden.default_registry.address, events=ALL_EVENTS, from_block=0, to_block='latest', ) assert len(events) == 1 assert event_dicts_are_equal( events[0], { '_event_type': 'TokenAdded', 'channel_manager_address': address_encoder(manager0.address), 'token_address': address_encoder(token_address), 'block_number': 'ignore', }) events = get_all_registry_events( app0.raiden.chain, app0.raiden.default_registry.address, events=ALL_EVENTS, from_block=999999998, to_block=999999999, ) assert not events netcontract_address = manager0.new_netting_channel( app0.raiden.address, app1.raiden.address, settle_timeout, ) events = get_all_channel_manager_events( app0.raiden.chain, manager0.address, events=ALL_EVENTS, from_block=0, to_block='latest', ) assert len(events) == 1 assert event_dicts_are_equal( events[0], { '_event_type': 'ChannelNew', 'settle_timeout': settle_timeout, 'netting_channel': address_encoder(netcontract_address), 'participant1': address_encoder(app0.raiden.address), 'participant2': address_encoder(app1.raiden.address), 'block_number': 'ignore', }) events = get_all_channel_manager_events( app0.raiden.chain, manager0.address, events=ALL_EVENTS, from_block=999999998, to_block=999999999, ) assert not events netting_channel0 = app0.raiden.chain.netting_channel(netcontract_address) gevent.sleep(events_poll_timeout * 2) # channel is created but not opened and without funds assert len(app0.raiden.token_to_channelgraph[token_address]. address_to_channel) == 1 assert len(app1.raiden.token_to_channelgraph[token_address]. address_to_channel) == 1 channel0 = app0.raiden.token_to_channelgraph[ token_address].address_to_channel.values()[0] channel1 = app1.raiden.token_to_channelgraph[ token_address].address_to_channel.values()[0] assert_synched_channels( channel0, 0, [], channel1, 0, [], ) token0.approve(netcontract_address, deposit) netting_channel0.deposit(deposit) all_netting_channel_events = get_all_netting_channel_events( app0.raiden.chain, netting_channel_address=netcontract_address, from_block=0, to_block='latest', ) events = get_all_netting_channel_events( app0.raiden.chain, netcontract_address, events=[CONTRACT_MANAGER.get_event_id(EVENT_CHANNEL_NEW_BALANCE)], ) assert len(all_netting_channel_events) == 1 assert len(events) == 1 new_balance_event = { '_event_type': 'ChannelNewBalance', 'token_address': address_encoder(token_address), 'participant': address_encoder(app0.raiden.address), 'balance': deposit, 'block_number': 'ignore', } assert event_dicts_are_equal(all_netting_channel_events[-1], new_balance_event) assert event_dicts_are_equal(events[0], new_balance_event) channel0.external_state.close(None) all_netting_channel_events = get_all_netting_channel_events( app0.raiden.chain, netting_channel_address=netcontract_address, from_block=0, to_block='latest', ) events = get_all_netting_channel_events( app0.raiden.chain, netcontract_address, events=[CONTRACT_MANAGER.get_event_id(EVENT_CHANNEL_CLOSED)], ) assert len(all_netting_channel_events) == 2 assert len(events) == 1 closed_event = { '_event_type': 'ChannelClosed', 'closing_address': address_encoder(app0.raiden.address), 'block_number': 'ignore', } assert event_dicts_are_equal(all_netting_channel_events[-1], closed_event) assert event_dicts_are_equal(events[0], closed_event) settle_expiration = app0.raiden.chain.block_number() + settle_timeout + 1 wait_until_block(app0.raiden.chain, settle_expiration) channel1.external_state.settle() all_netting_channel_events = get_all_netting_channel_events( app0.raiden.chain, netting_channel_address=netcontract_address, from_block=0, to_block='latest', ) events = get_all_netting_channel_events( app0.raiden.chain, netcontract_address, events=[CONTRACT_MANAGER.get_event_id(EVENT_CHANNEL_SETTLED)], ) assert len(all_netting_channel_events) == 3 assert len(events) == 1 settled_event = { '_event_type': 'ChannelSettled', 'block_number': 'ignore', } assert event_dicts_are_equal(all_netting_channel_events[-1], settled_event) assert event_dicts_are_equal(events[0], settled_event)
def test_participant_selection(raiden_network, token_addresses): # pylint: disable=too-many-locals token_address = token_addresses[0] # connect the first node (will register the token if necessary) RaidenAPI(raiden_network[0].raiden).connect_token_network(token_address, 100) # connect the other nodes connect_greenlets = [ gevent.spawn(RaidenAPI(app.raiden).connect_token_network, token_address, 100) for app in raiden_network[1:] ] gevent.wait(connect_greenlets) # wait some blocks to let the network connect wait_blocks = 15 for _ in range(wait_blocks): for app in raiden_network: wait_until_block( app.raiden.chain, app.raiden.chain.block_number() + 1 ) connection_managers = [ app.raiden.connection_manager_for_token(token_address) for app in raiden_network ] def open_channels_count(connection_managers_): return [ connection_manager.open_channels for connection_manager in connection_managers_ ] assert all(open_channels_count(connection_managers)) def not_saturated(connection_managers_): return [ 1 for connection_manager_ in connection_managers_ if len(connection_manager_.open_channels) < connection_manager_.initial_channel_target ] chain = raiden_network[-1].raiden.chain max_wait = 12 while not_saturated(connection_managers) and max_wait > 0: wait_until_block(chain, chain.block_number() + 1) max_wait -= 1 assert not not_saturated(connection_managers) # Ensure unpartitioned network addresses = [app.raiden.address for app in raiden_network] for connection_manager in connection_managers: assert all( connection_manager.channelgraph.has_path( connection_manager.raiden.address, address ) for address in addresses ) # average channel count acc = ( sum(len(connection_manager.open_channels) for connection_manager in connection_managers) / len(connection_managers) ) try: # FIXME: depending on the number of channels, this will fail, due to weak # selection algorithm # https://github.com/raiden-network/raiden/issues/576 assert not any( len(connection_manager.open_channels) > 2 * acc for connection_manager in connection_managers ) except AssertionError: pass # create a transfer to the leaving node, so we have a channel to settle sender = raiden_network[-1].raiden receiver = raiden_network[0].raiden # assert there is a direct channel receiver -> sender (vv) receiver_channel = RaidenAPI(receiver).get_channel_list( token_address=token_address, partner_address=sender.address ) assert len(receiver_channel) == 1 receiver_channel = receiver_channel[0] assert receiver_channel.external_state.opened_block != 0 assert not receiver_channel.received_transfers # assert there is a direct channel sender -> receiver sender_channel = RaidenAPI(sender).get_channel_list( token_address=token_address, partner_address=receiver.address ) assert len(sender_channel) == 1 sender_channel = sender_channel[0] assert sender_channel.can_transfer assert sender_channel.external_state.opened_block != 0 RaidenAPI(sender).transfer_and_wait( token_address, 1, receiver.address ) # now receiver has a transfer assert len(receiver_channel.received_transfers) # test `leave()` method connection_manager = connection_managers[0] before = len(connection_manager.receiving_channels) timeout = ( connection_manager.min_settle_blocks * connection_manager.raiden.chain.estimate_blocktime() * 5 ) assert timeout > 0 with gevent.timeout.Timeout(timeout): try: RaidenAPI(raiden_network[0].raiden).leave_token_network(token_address) except gevent.timeout.Timeout: log.error('timeout while waiting for leave') before_block = connection_manager.raiden.chain.block_number() wait_blocks = connection_manager.min_settle_blocks + 10 wait_until_block( connection_manager.raiden.chain, before_block + wait_blocks ) assert connection_manager.raiden.chain.block_number >= before_block + wait_blocks wait_until_block( receiver.chain, before_block + wait_blocks ) while receiver_channel.state != CHANNEL_STATE_SETTLED: gevent.sleep(receiver.alarm.wait_time) after = len(connection_manager.receiving_channels) assert before > after assert after == 0
def test_new_netting_contract(raiden_network, token_amount, settle_timeout): # pylint: disable=line-too-long,too-many-statements,too-many-locals app0, app1, app2 = raiden_network peer0_address = app0.raiden.address peer1_address = app1.raiden.address peer2_address = app2.raiden.address blockchain_service0 = app0.raiden.chain token_address = blockchain_service0.deploy_and_register_token( contract_name='HumanStandardToken', contract_file='HumanStandardToken.sol', constructor_parameters=(token_amount, 'raiden', 2, 'Rd'), ) token0 = blockchain_service0.token(token_address) for transfer_to in raiden_network[1:]: token0.transfer( privatekey_to_address(transfer_to.raiden.privkey), token_amount // len(raiden_network), ) manager0 = blockchain_service0.manager_by_token(token_address) # sanity assert manager0.channels_addresses() == [] assert manager0.channels_by_participant(peer0_address) == [] assert manager0.channels_by_participant(peer1_address) == [] assert manager0.channels_by_participant(peer2_address) == [] # create one channel netting_address_01 = manager0.new_netting_channel( peer0_address, peer1_address, settle_timeout, ) # check contract state netting_channel_01 = blockchain_service0.netting_channel( netting_address_01) assert netting_channel_01.can_transfer() is False # check channels channel_list = manager0.channels_addresses() assert sorted(channel_list[0]) == sorted([peer0_address, peer1_address]) assert manager0.channels_by_participant(peer0_address) == [ netting_address_01 ] assert manager0.channels_by_participant(peer1_address) == [ netting_address_01 ] assert manager0.channels_by_participant(peer2_address) == [] # create a duplicated channel with same participants while previous channel # is still open should throw an exception with pytest.raises(Exception): manager0.new_netting_channel( peer0_address, peer1_address, settle_timeout, ) # create other channel netting_address_02 = manager0.new_netting_channel( peer0_address, peer2_address, settle_timeout, ) netting_channel_02 = blockchain_service0.netting_channel( netting_address_02) assert netting_channel_02.can_transfer() is False channel_list = manager0.channels_addresses() expected_channels = [ sorted([peer0_address, peer1_address]), sorted([peer0_address, peer2_address]), ] for channel in channel_list: assert sorted(channel) in expected_channels result0 = sorted(manager0.channels_by_participant(peer0_address)) result1 = sorted([netting_address_01, netting_address_02]) assert result0 == result1 assert manager0.channels_by_participant(peer1_address) == [ netting_address_01 ] assert manager0.channels_by_participant(peer2_address) == [ netting_address_02 ] # deposit without approve should fail netting_channel_01.deposit(100) assert netting_channel_01.can_transfer() is False assert netting_channel_02.can_transfer() is False assert netting_channel_01.detail(None)['our_balance'] == 0 assert netting_channel_02.detail(None)['our_balance'] == 0 # single-funded channel app0.raiden.chain.token(token_address).approve(netting_address_01, 100) netting_channel_01.deposit(100) assert netting_channel_01.can_transfer() is True assert netting_channel_02.can_transfer() is False assert netting_channel_01.detail(None)['our_balance'] == 100 assert netting_channel_02.detail(None)['our_balance'] == 0 # double-funded channel app0.raiden.chain.token(token_address).approve(netting_address_02, 70) netting_channel_02.deposit(70) assert netting_channel_01.can_transfer() is True assert netting_channel_02.can_transfer() is True assert netting_channel_02.detail(None)['our_balance'] == 70 assert netting_channel_02.detail(None)['partner_balance'] == 0 app2.raiden.chain.token(token_address).approve(netting_address_02, 130) app2.raiden.chain.netting_channel(netting_address_02).deposit(130) assert netting_channel_01.can_transfer() is True assert netting_channel_02.can_transfer() is True assert netting_channel_02.detail(None)['our_balance'] == 70 assert netting_channel_02.detail(None)['partner_balance'] == 130 # open channel with same peer again after settling netting_channel_01.close(None) wait_until_block(app0.raiden.chain, app0.raiden.chain.block_number() + settle_timeout + 1) netting_channel_01.settle() assert netting_channel_01.opened() is '' assert netting_channel_01.closed() != 0 # open channel with same peer again netting_address_01_reopened = manager0.new_netting_channel( peer0_address, peer1_address, settle_timeout, ) netting_channel_01_reopened = blockchain_service0.netting_channel( netting_address_01_reopened) assert netting_channel_01_reopened.opened() != 0 assert netting_address_01_reopened in manager0.channels_by_participant( peer0_address) assert netting_address_01 not in manager0.channels_by_participant( peer0_address) app0.raiden.chain.token(token_address).approve(netting_address_01_reopened, 100) netting_channel_01_reopened.deposit(100) assert netting_channel_01_reopened.opened() != 0
def test_automatic_dispute(raiden_network, deposit, settle_timeout): app0, app1 = raiden_network channel0 = app0.raiden.channelgraphs.values( )[0].partneraddress_channel.values()[0] channel1 = app1.raiden.channelgraphs.values( )[0].partneraddress_channel.values()[0] privatekey0 = app0.raiden.private_key privatekey1 = app1.raiden.private_key address0 = privatekey_to_address(privatekey0.secret) address1 = privatekey_to_address(privatekey1.secret) token = app0.raiden.chain.token(channel0.token_address) initial_balance0 = token.balance_of(address0) initial_balance1 = token.balance_of(address1) # Alice sends Bob 10 tokens amount_alice1 = 10 identifier_alice1 = 1 alice_first_transfer = channel0.create_directtransfer( amount_alice1, identifier_alice1, ) alice_first_transfer.sign(privatekey0, address0) channel0.register_transfer( app0.raiden.get_block_number(), alice_first_transfer, ) channel1.register_transfer( app1.raiden.get_block_number(), alice_first_transfer, ) # Bob sends Alice 50 tokens amount_bob1 = 50 identifier_bob1 = 1 bob_first_transfer = channel1.create_directtransfer( amount_bob1, identifier_bob1, ) bob_first_transfer.sign(privatekey1, address1) channel0.register_transfer( app0.raiden.get_block_number(), bob_first_transfer, ) channel1.register_transfer( app1.raiden.get_block_number(), bob_first_transfer, ) # Finally Alice sends Bob 60 tokens identifier_alice2 = 2 amount_alice2 = 60 alice_second_transfer = channel0.create_directtransfer( amount_alice2, identifier_alice2, ) alice_second_transfer.sign(privatekey0, address0) channel0.register_transfer( app0.raiden.get_block_number(), alice_second_transfer, ) channel1.register_transfer( app1.raiden.get_block_number(), alice_second_transfer, ) bob_last_transaction = bob_first_transfer # Alice can only provide one of Bob's transfer, so she is incetivized to # use the one with the largest transferred_amount. channel0.external_state.close(bob_last_transaction) chain0 = app0.raiden.chain wait_until_block(chain0, chain0.block_number() + 1) assert channel0.external_state.close_event.wait(timeout=25) assert channel1.external_state.close_event.wait(timeout=25) assert channel0.external_state.closed_block != 0 assert channel1.external_state.closed_block != 0 # Bob needs to provide a transfer otherwise it's netted balance will be # wrong, so he is incetivized to use Alice's transfer with the largest # transferred_amount. channel1.external_state.update_transfer(alice_second_transfer, ) # wait until the settle timeout has passed settle_expiration = chain0.block_number() + settle_timeout wait_until_block(chain0, settle_expiration) # the settle event must be set assert channel0.external_state.settle_event.wait(timeout=60) assert channel1.external_state.settle_event.wait(timeout=60) # check that the channel is properly settled and that Bob's client # automatically called updateTransfer() to reflect the actual transactions assert channel0.external_state.settled_block != 0 assert channel1.external_state.settled_block != 0 assert token.balance_of( channel0.external_state.netting_channel.address) == 0 total_alice = amount_alice1 + amount_alice2 total_bob = amount_bob1 assert token.balance_of( address0) == initial_balance0 + deposit - total_alice + total_bob assert token.balance_of( address1) == initial_balance1 + deposit + total_alice - total_bob
def test_transfer_from_outdated(raiden_network, settle_timeout): app0, app1 = raiden_network # pylint: disable=unbalanced-tuple-unpacking graph0 = list(app0.raiden.token_to_channelgraph.values())[0] graph1 = list(app1.raiden.token_to_channelgraph.values())[0] channel0 = graph0.partneraddress_to_channel[app1.raiden.address] channel1 = graph1.partneraddress_to_channel[app0.raiden.address] balance0 = channel0.balance balance1 = channel1.balance assert graph0.token_address == graph1.token_address assert app1.raiden.address in graph0.partneraddress_to_channel amount = 10 result = app0.raiden.direct_transfer_async( graph0.token_address, amount, target=app1.raiden.address, identifier=1, ) assert result.wait(timeout=10) assert_synched_channels( channel0, balance0 - amount, [], channel1, balance1 + amount, [] ) channel1.external_state.close(channel1.our_state.balance_proof) wait_until_block( app1.raiden.chain, app1.raiden.chain.block_number() + 1 ) assert channel0.external_state.close_event.wait(timeout=25) assert channel1.external_state.close_event.wait(timeout=25) assert channel0.external_state.closed_block != 0 assert channel1.external_state.closed_block != 0 wait_until_block( app0.raiden.chain, app0.raiden.chain.block_number() + settle_timeout, ) assert channel0.external_state.settle_event.wait(timeout=25) assert channel1.external_state.settle_event.wait(timeout=25) assert channel0.external_state.settled_block != 0 assert channel1.external_state.settled_block != 0 # and now receive one more transfer from the closed channel direct_transfer_message = DirectTransfer( identifier=1, nonce=1, token=graph0.token_address, channel=channel0.channel_address, transferred_amount=10, recipient=app0.raiden.address, locksroot=UNIT_HASHLOCK, ) sign_and_send( direct_transfer_message, app1.raiden.private_key, app1.raiden.address, app1, )
def test_participant_selection(raiden_network, token_addresses, blockchain_type): token_address = token_addresses[0] # connect the first node (will register the token if necessary) RaidenAPI(raiden_network[0].raiden).connect_token_network( token_address, 100) # connect the other nodes connect_greenlets = [ gevent.spawn( RaidenAPI(app.raiden).connect_token_network, token_address, 100) for app in raiden_network[1:] ] gevent.wait(connect_greenlets) # wait some blocks to let the network connect wait_blocks = 15 for i in range(wait_blocks): for app in raiden_network: wait_until_block(app.raiden.chain, app.raiden.chain.block_number() + 1) # tester needs an explicit context switch :( if blockchain_type == 'tester': gevent.sleep(1) connection_managers = [ app.raiden.connection_manager_for_token(token_address) for app in raiden_network ] def open_channels_count(connection_managers_): return [ connection_manager.open_channels for connection_manager in connection_managers_ ] assert all(open_channels_count(connection_managers)) def not_saturated(connection_managers): return [ 1 for connection_manager in connection_managers if connection_manager.open_channels < connection_manager.initial_channel_target ] chain = raiden_network[-1].raiden.chain max_wait = 12 while len(not_saturated(connection_managers)) > 0 and max_wait > 0: wait_until_block(chain, chain.block_number() + 1) max_wait -= 1 assert len(not_saturated(connection_managers)) == 0 # Ensure unpartitioned network addresses = [app.raiden.address for app in raiden_network] for connection_manager in connection_managers: assert all( connection_manager.channelgraph.has_path( connection_manager.raiden.address, address) for address in addresses) # average channel count acc = (sum( len(connection_manager.open_channels) for connection_manager in connection_managers) / float(len(connection_managers))) try: # FIXME: depending on the number of channels, this will fail, due to weak # selection algorithm # https://github.com/raiden-network/raiden/issues/576 assert not any( len(connection_manager.open_channels) > 2 * acc for connection_manager in connection_managers) except AssertionError: pass # test `leave()` method connection_manager = connection_managers[0] before = len(connection_manager.open_channels) RaidenAPI(raiden_network[0].raiden).leave_token_network( token_address, wait_for_settle=False) wait_until_block(connection_manager.raiden.chain, (connection_manager.raiden.chain.block_number() + connection_manager.raiden.config['settle_timeout'] + 1)) after = len(connection_manager.open_channels) assert before > after assert after == 0
def test_channel_lifecycle(raiden_network, token_addresses, deposit): node1, node2 = raiden_network token_address = token_addresses[0] api1 = RaidenAPI(node1.raiden) api2 = RaidenAPI(node2.raiden) # nodes don't have a channel, so they are not healthchecking assert api1.get_node_network_state(api2.address) == NODE_NETWORK_UNKNOWN assert api2.get_node_network_state(api1.address) == NODE_NETWORK_UNKNOWN assert not api1.get_channel_list(token_address, api2.address) # open is a synchronous api api1.channel_open(token_address, api2.address) channels = api1.get_channel_list(token_address, api2.address) assert len(channels) == 1 channel12 = get_channelstate(node1, node2, token_address) assert channel.get_status(channel12) == CHANNEL_STATE_OPENED event_list1 = api1.get_channel_events( channel12.identifier, channel12.open_transaction.finished_block_number, ) assert event_list1 == [] # Load the new state with the deposit api1.channel_deposit(token_address, api2.address, deposit) channel12 = get_channelstate(node1, node2, token_address) assert channel.get_status(channel12) == CHANNEL_STATE_OPENED assert channel.get_balance(channel12.our_state, channel12.partner_state) == deposit assert channel12.our_state.contract_balance == deposit assert api1.get_channel_list(token_address, api2.address) == [channel12] # there is a channel open, they must be healthchecking each other assert api1.get_node_network_state(api2.address) == NODE_NETWORK_REACHABLE assert api2.get_node_network_state(api1.address) == NODE_NETWORK_REACHABLE event_list2 = api1.get_channel_events( channel12.identifier, channel12.open_transaction.finished_block_number, ) assert any((event['_event_type'] == b'ChannelNewBalance' and event['participant'] == address_encoder(api1.address)) for event in event_list2) api1.channel_close(token_address, api2.address) node1.raiden.poll_blockchain_events() # Load the new state with the channel closed channel12 = get_channelstate(node1, node2, token_address) event_list3 = api1.get_channel_events( channel12.identifier, channel12.open_transaction.finished_block_number, ) assert len(event_list3) > len(event_list2) assert any((event['_event_type'] == b'ChannelClosed' and event['closing_address'] == address_encoder(api1.address)) for event in event_list3) assert channel.get_status(channel12) == CHANNEL_STATE_CLOSED settlement_block = ( channel12.close_transaction.finished_block_number + channel12.settle_timeout + 10 # arbitrary number of additional blocks, used to wait for the settle() call ) wait_until_block(node1.raiden.chain, settlement_block) # Load the new state with the channel settled channel12 = get_channelstate(node1, node2, token_address) node1.raiden.poll_blockchain_events() assert channel.get_status(channel12) == CHANNEL_STATE_SETTLED
def test_channel_lifecycle(blockchain_type, raiden_network, token_addresses, deposit): if blockchain_type == 'tester': pytest.skip( 'there is not support ATM for retrieving events from tester') node1, node2 = raiden_network token_address = token_addresses[0] api1 = RaidenAPI(node1.raiden) api2 = RaidenAPI(node2.raiden) # nodes don't have a channel, so they are not healthchecking assert api1.get_node_network_state(api2.address) == NODE_NETWORK_UNKNOWN assert api2.get_node_network_state(api1.address) == NODE_NETWORK_UNKNOWN assert api1.get_channel_list(token_address, api2.address) == [] # this is a synchronous api api1.open(token_address, api2.address) channels = api1.get_channel_list(token_address, api2.address) assert len(channels) == 1 channel12 = channels[0] event_list1 = api1.get_channel_events( channel12.channel_address, channel12.external_state.opened_block, ) assert event_list1 == [] # the channel has no deposit yet assert channel12.state == CHANNEL_STATE_OPENED api1.deposit(token_address, api2.address, deposit) assert channel12.state == CHANNEL_STATE_OPENED assert channel12.balance == deposit assert channel12.contract_balance == deposit assert api1.get_channel_list(token_address, api2.address) == [channel12] # there is a channel open, they must be healthchecking each other assert api1.get_node_network_state(api2.address) == NODE_NETWORK_REACHABLE assert api2.get_node_network_state(api1.address) == NODE_NETWORK_REACHABLE event_list2 = api1.get_channel_events( channel12.channel_address, channel12.external_state.opened_block, ) assert any((event['_event_type'] == 'ChannelNewBalance' and event['participant'] == hexlify(api1.address)) for event in event_list2) with pytest.raises(InvalidState): api1.settle(token_address, api2.address) api1.close(token_address, api2.address) node1.raiden.poll_blockchain_events() event_list3 = api1.get_channel_events( channel12.channel_address, channel12.external_state.opened_block, ) assert len(event_list3) > len(event_list2) assert any((event['_event_type'] == 'ChannelClosed' and event['closing_address'] == hexlify(api1.address)) for event in event_list3) assert channel12.state == CHANNEL_STATE_CLOSED settlement_block = ( channel12.external_state.closed_block + channel12.settle_timeout + 5 # arbitrary number of additional blocks, used to wait for the settle() call ) wait_until_block(node1.raiden.chain, settlement_block) node1.raiden.poll_blockchain_events() assert channel12.state == CHANNEL_STATE_SETTLED
def test_automatic_dispute(raiden_network, deposit, settle_timeout, reveal_timeout): app0, app1 = raiden_network channel0 = app0.raiden.managers_by_token_address.values( )[0].partneraddress_channel.values()[0] channel1 = app1.raiden.managers_by_token_address.values( )[0].partneraddress_channel.values()[0] privatekey0 = app0.raiden.private_key privatekey1 = app1.raiden.private_key address0 = privatekey_to_address(privatekey0.private_key) address1 = privatekey_to_address(privatekey1.private_key) token = app0.raiden.chain.token(channel0.token_address) initial_balance0 = token.balance_of(address0) initial_balance1 = token.balance_of(address1) # Alice sends Bob 10 tokens amount_alice1 = 10 direct_transfer = channel0.create_directtransfer( amount_alice1, 1 # TODO: fill in identifier ) direct_transfer.sign(privatekey0, address0) channel0.register_transfer(direct_transfer) channel1.register_transfer(direct_transfer) alice_old_transaction = direct_transfer # Bob sends Alice 50 tokens amount_bob1 = 50 direct_transfer = channel1.create_directtransfer( amount_bob1, 1 # TODO: fill in identifier ) direct_transfer.sign(privatekey1, address1) channel0.register_transfer(direct_transfer) channel1.register_transfer(direct_transfer) bob_last_transaction = direct_transfer # Finally Alice sends Bob 60 tokens amount_alice2 = 60 direct_transfer = channel0.create_directtransfer( amount_alice2, 1 # TODO: fill in identifier ) direct_transfer.sign(privatekey0, address0) channel0.register_transfer(direct_transfer) channel1.register_transfer(direct_transfer) # Then Alice attempts to close the channel with an older transfer of hers channel0.external_state.close( None, bob_last_transaction, ) chain0 = app0.raiden.chain wait_until_block(chain0, chain0.block_number() + 1) assert channel0.close_event.wait(timeout=25) assert channel1.close_event.wait(timeout=25) assert channel0.external_state.closed_block != 0 assert channel1.external_state.closed_block != 0 channel1.external_state.update_transfer( None, direct_transfer, ) # wait until the settle timeout has passed settle_expiration = chain0.block_number() + settle_timeout wait_until_block(chain0, settle_expiration) # the settle event must be set assert channel0.settle_event.wait(timeout=60) assert channel1.settle_event.wait(timeout=60) # check that the channel is properly settled and that Bob's client # automatically called updateTransfer() to reflect the actual transactions assert channel0.external_state.settled_block != 0 assert channel1.external_state.settled_block != 0 assert token.balance_of( channel0.external_state.netting_channel.address) == 0 total_alice = amount_alice1 + amount_alice2 total_bob = amount_bob1 assert token.balance_of( address0) == initial_balance0 + deposit - total_alice + total_bob assert token.balance_of( address1) == initial_balance1 + deposit + total_alice - total_bob
def test_settlement(raiden_network, settle_timeout, reveal_timeout): app0, app1 = raiden_network # pylint: disable=unbalanced-tuple-unpacking setup_messages_cb() asset_manager0 = app0.raiden.managers_by_asset_address.values()[0] asset_manager1 = app1.raiden.managers_by_asset_address.values()[0] chain0 = app0.raiden.chain channel0 = asset_manager0.partneraddress_channel[app1.raiden.address] channel1 = asset_manager1.partneraddress_channel[app0.raiden.address] balance0 = channel0.balance balance1 = channel1.balance amount = 10 expiration = app0.raiden.chain.block_number() + reveal_timeout + 1 secret = 'secret' hashlock = sha3(secret) assert app1.raiden.address in asset_manager0.partneraddress_channel assert asset_manager0.asset_address == asset_manager1.asset_address nettingaddress0 = channel0.external_state.netting_channel.address nettingaddress1 = channel1.external_state.netting_channel.address assert nettingaddress0 == nettingaddress1 identifier = 1 fee = 0 transfermessage = channel0.create_mediatedtransfer( app0.raiden.address, app1.raiden.address, fee, amount, identifier, expiration, hashlock, ) app0.raiden.sign(transfermessage) channel0.register_transfer(transfermessage) channel1.register_transfer(transfermessage) assert_synched_channels( channel0, balance0, [], channel1, balance1, [transfermessage.lock], ) # At this point we are assuming the following: # # A -> B MediatedTransfer # B -> A SecretRequest # A -> B RevealSecret # - protocol didn't continue # # B knowns the secret but doesn't have an updated balance proof, B needs to # call settle. # get proof, that locked transfermessage was in merkle tree, with locked.root lock = channel1.our_state.balance_proof.get_lock_by_hashlock(hashlock) unlock_proof = channel1.our_state.balance_proof.compute_proof_for_lock( secret, lock) root = channel1.our_state.balance_proof.merkleroot_for_unclaimed() assert check_proof( unlock_proof.merkle_proof, root, sha3(transfermessage.lock.as_bytes), ) assert unlock_proof.lock_encoded == transfermessage.lock.as_bytes assert unlock_proof.secret == secret # a ChannelClose event will be generated, this will be polled by both apps # and each must start a task for calling settle channel0.external_state.netting_channel.close( app0.raiden.address, transfermessage, None, ) # unlock will not be called by Channel.channel_closed because we did not # register the secret channel0.external_state.netting_channel.unlock( app0.raiden.address, [unlock_proof], ) settle_expiration = chain0.block_number() + settle_timeout wait_until_block(chain0, settle_expiration) # settle must be called by the apps triggered by the ChannelClose event, # and the channels must update it's state based on the ChannelSettled event assert channel0.external_state.settled_block != 0 assert channel1.external_state.settled_block != 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 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_start_end_attack(token_addresses, raiden_chain, deposit): """ 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 settle 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 token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token, ) # the attacker owns app0 and app2 and creates a transfer through app1 identifier = 1 secret = pending_mediated_transfer( raiden_chain, token_network_identifier, amount, identifier, ) secrethash = sha3(secret) attack_channel = get_channelstate(app2, app1, token_network_identifier) attack_transfer = None # TODO attack_contract = attack_channel.external_state.netting_channel.address hub_contract = ( get_channelstate(app1, app0, token_network_identifier) .external_state .netting_channel.address ) # the attacker can create a merkle proof of the locked transfer lock = attack_channel.partner_state.get_lock_by_secrethash(secrethash) unlock_proof = attack_channel.partner_state.compute_proof_for_lock(secret, lock) # start the settle counter attack_balance_proof = attack_transfer.to_balanceproof() attack_channel.netting_channel.channel_close(attack_balance_proof) # 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( UnlockProofState(unlock_proof, attack_transfer.lock, secret), ) # XXX: verify that the secret was publicized # at this point the hub might not know the secret yet, and won't be able to # claim the token from the channel A1 - H # the attacker settles the contract app2.raiden.chain.next_block() attack_channel.netting_channel.settle(token, attack_contract) # at this point the attacker 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. For A2 to acquire the token # it needs to make the secret public in the blockchain so it publishes the # secret through an event and the Hub is able to require its 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
def test_query_events(raiden_chain, token_addresses, deposit, settle_timeout, events_poll_timeout): app0, app1 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), registry_address, token_address, ) manager0 = app0.raiden.default_registry.manager_by_token(token_address) channelcount0 = views.total_token_network_channels( views.state_from_app(app0), registry_address, token_address, ) events = get_all_registry_events( app0.raiden.chain, registry_address, events=ALL_EVENTS, from_block=0, to_block='latest', ) assert len(events) == 1 assert events[0]['event'] == EVENT_TOKEN_ADDED assert event_dicts_are_equal( events[0]['args'], { 'registry_address': to_normalized_address(registry_address), 'channel_manager_address': to_normalized_address(manager0.address), 'token_address': to_normalized_address(token_address), 'block_number': 'ignore', }) events = get_all_registry_events( app0.raiden.chain, app0.raiden.default_registry.address, events=ALL_EVENTS, from_block=999999998, to_block=999999999, ) assert not events channel_address = RaidenAPI(app0.raiden).channel_open( registry_address, token_address, app1.raiden.address, ) gevent.sleep(events_poll_timeout * 2) events = get_all_channel_manager_events( app0.raiden.chain, manager0.address, events=ALL_EVENTS, from_block=0, to_block='latest', ) assert len(events) == 1 assert events[0]['event'] == EVENT_CHANNEL_NEW assert event_dicts_are_equal( events[0]['args'], { 'registry_address': to_normalized_address(registry_address), 'settle_timeout': settle_timeout, 'netting_channel': to_normalized_address(channel_address), 'participant1': to_normalized_address(app0.raiden.address), 'participant2': to_normalized_address(app1.raiden.address), 'block_number': 'ignore', }) events = get_all_channel_manager_events( app0.raiden.chain, manager0.address, events=ALL_EVENTS, from_block=999999998, to_block=999999999, ) assert not events # channel is created but not opened and without funds channelcount1 = views.total_token_network_channels( views.state_from_app(app0), registry_address, token_address, ) assert channelcount0 + 1 == channelcount1 assert_synched_channel_state( token_network_identifier, app0, 0, [], app1, 0, [], ) RaidenAPI(app0.raiden).set_total_channel_deposit( registry_address, token_address, app1.raiden.address, deposit, ) gevent.sleep(events_poll_timeout * 2) all_netting_channel_events = get_all_netting_channel_events( app0.raiden.chain, channel_address, from_block=0, to_block='latest', ) events = get_all_netting_channel_events( app0.raiden.chain, channel_address, events=[CONTRACT_MANAGER.get_event_id(EVENT_CHANNEL_NEW_BALANCE)], ) assert len(all_netting_channel_events) == 1 assert len(events) == 1 assert events[0]['event'] == EVENT_CHANNEL_NEW_BALANCE new_balance_event = { 'registry_address': to_normalized_address(registry_address), 'token_address': to_normalized_address(token_address), 'participant': to_normalized_address(app0.raiden.address), 'balance': deposit, 'block_number': 'ignore', } assert event_dicts_are_equal(all_netting_channel_events[-1]['args'], new_balance_event) assert event_dicts_are_equal(events[0]['args'], new_balance_event) RaidenAPI(app0.raiden).channel_close( registry_address, token_address, app1.raiden.address, ) gevent.sleep(events_poll_timeout * 2) all_netting_channel_events = get_all_netting_channel_events( app0.raiden.chain, netting_channel_address=channel_address, from_block=0, to_block='latest', ) events = get_all_netting_channel_events( app0.raiden.chain, channel_address, events=[CONTRACT_MANAGER.get_event_id(EVENT_CHANNEL_CLOSED)], ) assert len(all_netting_channel_events) == 2 assert len(events) == 1 assert events[0]['event'] == EVENT_CHANNEL_CLOSED closed_event = { 'registry_address': to_normalized_address(registry_address), 'closing_address': to_normalized_address(app0.raiden.address), 'block_number': 'ignore', } assert event_dicts_are_equal(all_netting_channel_events[-1]['args'], closed_event) assert event_dicts_are_equal(events[0]['args'], closed_event) settle_expiration = app0.raiden.chain.block_number() + settle_timeout + 5 wait_until_block(app0.raiden.chain, settle_expiration) all_netting_channel_events = get_all_netting_channel_events( app0.raiden.chain, netting_channel_address=channel_address, from_block=0, to_block='latest', ) events = get_all_netting_channel_events( app0.raiden.chain, channel_address, events=[CONTRACT_MANAGER.get_event_id(EVENT_CHANNEL_SETTLED)], ) assert len(all_netting_channel_events) == 3 assert len(events) == 1 assert events[0]['event'] == EVENT_CHANNEL_SETTLED settled_event = { 'registry_address': to_normalized_address(registry_address), 'block_number': 'ignore', } assert event_dicts_are_equal(all_netting_channel_events[-1]['args'], settled_event) assert event_dicts_are_equal(events[0]['args'], settled_event)
def test_new_netting_contract(raiden_network, token_amount, settle_timeout): # pylint: disable=line-too-long,too-many-statements,too-many-locals app0, app1, app2 = raiden_network peer0_address = app0.raiden.address peer1_address = app1.raiden.address peer2_address = app2.raiden.address blockchain_service0 = app0.raiden.chain registry = app0.raiden.default_registry humantoken_path = get_contract_path('HumanStandardToken.sol') token_address = blockchain_service0.deploy_and_register_token( registry, contract_name='HumanStandardToken', contract_path=humantoken_path, constructor_parameters=(token_amount, 'raiden', 2, 'Rd'), ) token0 = blockchain_service0.token(token_address) for transfer_to in raiden_network[1:]: token0.transfer( privatekey_to_address(transfer_to.raiden.privkey), token_amount // len(raiden_network), ) manager0 = registry.manager_by_token(token_address) # sanity assert manager0.channels_addresses() == [] assert manager0.channels_by_participant(peer0_address) == [] assert manager0.channels_by_participant(peer1_address) == [] assert manager0.channels_by_participant(peer2_address) == [] # create one channel netting_address_01 = manager0.new_netting_channel( peer1_address, settle_timeout, ) # check contract state netting_channel_01 = blockchain_service0.netting_channel(netting_address_01) assert netting_channel_01.can_transfer() is False # check channels channel_list = manager0.channels_addresses() assert sorted(channel_list[0]) == sorted([peer0_address, peer1_address]) assert manager0.channels_by_participant(peer0_address) == [netting_address_01] assert manager0.channels_by_participant(peer1_address) == [netting_address_01] assert manager0.channels_by_participant(peer2_address) == [] # create a duplicated channel with same participants while previous channel # is still open should throw an exception with pytest.raises(Exception): manager0.new_netting_channel( peer1_address, settle_timeout, ) # create other channel netting_address_02 = manager0.new_netting_channel( peer2_address, settle_timeout, ) netting_channel_02 = blockchain_service0.netting_channel(netting_address_02) assert netting_channel_02.can_transfer() is False channel_list = manager0.channels_addresses() expected_channels = [ sorted([peer0_address, peer1_address]), sorted([peer0_address, peer2_address]), ] for channel in channel_list: assert sorted(channel) in expected_channels result0 = sorted(manager0.channels_by_participant(peer0_address)) result1 = sorted([netting_address_01, netting_address_02]) assert result0 == result1 assert manager0.channels_by_participant(peer1_address) == [netting_address_01] assert manager0.channels_by_participant(peer2_address) == [netting_address_02] # deposit without approve should fail netting_channel_01.deposit(100) assert netting_channel_01.can_transfer() is False assert netting_channel_02.can_transfer() is False assert netting_channel_01.detail()['our_balance'] == 0 assert netting_channel_02.detail()['our_balance'] == 0 # single-funded channel app0.raiden.chain.token(token_address).approve(netting_address_01, 100) netting_channel_01.deposit(100) assert netting_channel_01.can_transfer() is True assert netting_channel_02.can_transfer() is False assert netting_channel_01.detail()['our_balance'] == 100 assert netting_channel_02.detail()['our_balance'] == 0 # double-funded channel app0.raiden.chain.token(token_address).approve(netting_address_02, 70) netting_channel_02.deposit(70) assert netting_channel_01.can_transfer() is True assert netting_channel_02.can_transfer() is True assert netting_channel_02.detail()['our_balance'] == 70 assert netting_channel_02.detail()['partner_balance'] == 0 app2.raiden.chain.token(token_address).approve(netting_address_02, 130) app2.raiden.chain.netting_channel(netting_address_02).deposit(130) assert netting_channel_01.can_transfer() is True assert netting_channel_02.can_transfer() is True assert netting_channel_02.detail()['our_balance'] == 70 assert netting_channel_02.detail()['partner_balance'] == 130 # open channel with same peer again after settling netting_channel_01.close( nonce=0, transferred_amount=0, locksroot='', extra_hash='', signature='', ) wait_until_block(app0.raiden.chain, app0.raiden.chain.block_number() + settle_timeout + 1) netting_channel_01.settle() with pytest.raises(AddressWithoutCode): netting_channel_01.closed() with pytest.raises(AddressWithoutCode): netting_channel_01.opened() # open channel with same peer again netting_address_01_reopened = manager0.new_netting_channel( peer1_address, settle_timeout, ) netting_channel_01_reopened = blockchain_service0.netting_channel(netting_address_01_reopened) assert netting_channel_01_reopened.opened() != 0 assert netting_address_01_reopened in manager0.channels_by_participant(peer0_address) assert netting_address_01 not in manager0.channels_by_participant(peer0_address) app0.raiden.chain.token(token_address).approve(netting_address_01_reopened, 100) netting_channel_01_reopened.deposit(100) assert netting_channel_01_reopened.opened() != 0
def test_participant_selection(raiden_network, token_addresses): # pylint: disable=too-many-locals token_address = token_addresses[0] # connect the first node (will register the token if necessary) RaidenAPI(raiden_network[0].raiden).token_network_connect( token_address, 100) # connect the other nodes connect_greenlets = [ gevent.spawn( RaidenAPI(app.raiden).token_network_connect, token_address, 100) for app in raiden_network[1:] ] gevent.wait(connect_greenlets) # wait some blocks to let the network connect wait_blocks = 15 for _ in range(wait_blocks): for app in raiden_network: wait_until_block(app.raiden.chain, app.raiden.chain.block_number() + 1) connection_managers = [ app.raiden.connection_manager_for_token(token_address) for app in raiden_network ] def open_channels_count(connection_managers_): return [ connection_manager.open_channels for connection_manager in connection_managers_ ] assert all(open_channels_count(connection_managers)) def not_saturated(connection_managers_): return [ 1 for connection_manager_ in connection_managers_ if len(connection_manager_.open_channels) < connection_manager_.initial_channel_target ] chain = raiden_network[-1].raiden.chain max_wait = 12 while not_saturated(connection_managers) and max_wait > 0: wait_until_block(chain, chain.block_number() + 1) max_wait -= 1 assert not not_saturated(connection_managers) # Ensure unpartitioned network addresses = [app.raiden.address for app in raiden_network] for connection_manager in connection_managers: assert all( connection_manager.channelgraph.has_path( connection_manager.raiden.address, address) for address in addresses) # average channel count acc = (sum( len(connection_manager.open_channels) for connection_manager in connection_managers) / len(connection_managers)) try: # FIXME: depending on the number of channels, this will fail, due to weak # selection algorithm # https://github.com/raiden-network/raiden/issues/576 assert not any( len(connection_manager.open_channels) > 2 * acc for connection_manager in connection_managers) except AssertionError: pass # create a transfer to the leaving node, so we have a channel to settle sender = raiden_network[-1].raiden receiver = raiden_network[0].raiden # assert there is a direct channel receiver -> sender (vv) receiver_channel = RaidenAPI(receiver).get_channel_list( token_address=token_address, partner_address=sender.address) assert len(receiver_channel) == 1 receiver_channel = receiver_channel[0] assert receiver_channel.external_state.opened_block != 0 assert not receiver_channel.received_transfers # assert there is a direct channel sender -> receiver sender_channel = RaidenAPI(sender).get_channel_list( token_address=token_address, partner_address=receiver.address) assert len(sender_channel) == 1 sender_channel = sender_channel[0] assert sender_channel.can_transfer assert sender_channel.external_state.opened_block != 0 RaidenAPI(sender).transfer_and_wait(token_address, 1, receiver.address) # now receiver has a transfer assert len(receiver_channel.received_transfers) # test `leave()` method connection_manager = connection_managers[0] before = len(connection_manager.receiving_channels) timeout = (connection_manager.min_settle_blocks * connection_manager.raiden.chain.estimate_blocktime() * 5) assert timeout > 0 with gevent.timeout.Timeout(timeout): try: RaidenAPI( raiden_network[0].raiden).token_network_leave(token_address) except gevent.timeout.Timeout: log.error('timeout while waiting for leave') before_block = connection_manager.raiden.chain.block_number() wait_blocks = connection_manager.min_settle_blocks + 10 wait_until_block(connection_manager.raiden.chain, before_block + wait_blocks) assert connection_manager.raiden.chain.block_number >= before_block + wait_blocks wait_until_block(receiver.chain, before_block + wait_blocks) while receiver_channel.state != CHANNEL_STATE_SETTLED: gevent.sleep(receiver.alarm.wait_time) after = len(connection_manager.receiving_channels) assert before > after assert after == 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
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
def test_settlement(raiden_network, settle_timeout, reveal_timeout): alice_app, bob_app = raiden_network # pylint: disable=unbalanced-tuple-unpacking setup_messages_cb() alice_graph = list(alice_app.raiden.token_to_channelgraph.values())[0] bob_graph = list(bob_app.raiden.token_to_channelgraph.values())[0] assert alice_graph.token_address == bob_graph.token_address alice_bob_channel = alice_graph.partneraddress_to_channel[bob_app.raiden.address] bob_alice_channel = bob_graph.partneraddress_to_channel[alice_app.raiden.address] alice_deposit = alice_bob_channel.balance bob_deposit = bob_alice_channel.balance token = alice_app.raiden.chain.token(alice_bob_channel.token_address) alice_balance = token.balance_of(alice_app.raiden.address) bob_balance = token.balance_of(bob_app.raiden.address) alice_chain = alice_app.raiden.chain alice_to_bob_amount = 10 expiration = alice_app.raiden.chain.block_number() + reveal_timeout + 1 secret = b'secretsecretsecretsecretsecretse' hashlock = sha3(secret) assert bob_app.raiden.address in alice_graph.partneraddress_to_channel nettingaddress0 = alice_bob_channel.external_state.netting_channel.address nettingaddress1 = bob_alice_channel.external_state.netting_channel.address assert nettingaddress0 == nettingaddress1 identifier = 1 fee = 0 transfermessage = alice_bob_channel.create_mediatedtransfer( alice_app.raiden.address, bob_app.raiden.address, fee, alice_to_bob_amount, identifier, expiration, hashlock, ) alice_app.raiden.sign(transfermessage) alice_bob_channel.register_transfer( alice_app.raiden.get_block_number(), transfermessage, ) bob_alice_channel.register_transfer( bob_app.raiden.get_block_number(), transfermessage, ) assert_synched_channels( alice_bob_channel, alice_deposit, [], bob_alice_channel, bob_deposit, [transfermessage.lock], ) # At this point we are assuming the following: # # A -> B MediatedTransfer # B -> A SecretRequest # A -> B RevealSecret # - protocol didn't continue # # B knowns the secret but doesn't have an updated balance proof, B needs to # call settle. # get proof, that locked transfermessage was in merkle tree, with locked.root lock = bob_alice_channel.partner_state.get_lock_by_hashlock(hashlock) assert sha3(secret) == hashlock unlock_proof = bob_alice_channel.partner_state.compute_proof_for_lock(secret, lock) root = merkleroot(bob_alice_channel.partner_state.merkletree) assert validate_proof( unlock_proof.merkle_proof, root, sha3(transfermessage.lock.as_bytes), ) assert unlock_proof.lock_encoded == transfermessage.lock.as_bytes assert unlock_proof.secret == secret # a ChannelClose event will be generated, this will be polled by both apps # and each must start a task for calling settle balance_proof = transfermessage.to_balanceproof() bob_alice_channel.external_state.close(balance_proof) wait_until_block(alice_chain, alice_chain.block_number() + 1) assert alice_bob_channel.external_state.close_event.wait(timeout=15) assert bob_alice_channel.external_state.close_event.wait(timeout=15) assert alice_bob_channel.external_state.closed_block != 0 assert bob_alice_channel.external_state.closed_block != 0 assert alice_bob_channel.external_state.settled_block == 0 assert bob_alice_channel.external_state.settled_block == 0 # unlock will not be called by Channel.channel_closed because we did not # register the secret assert lock.expiration > alice_app.raiden.chain.block_number() assert lock.hashlock == sha3(secret) bob_alice_channel.external_state.netting_channel.withdraw([unlock_proof]) settle_expiration = alice_chain.block_number() + settle_timeout + 2 wait_until_block(alice_chain, settle_expiration) assert alice_bob_channel.external_state.settle_event.wait(timeout=15) assert bob_alice_channel.external_state.settle_event.wait(timeout=15) # settle must be called by the apps triggered by the ChannelClose event, # and the channels must update it's state based on the ChannelSettled event assert alice_bob_channel.external_state.settled_block != 0 assert bob_alice_channel.external_state.settled_block != 0 address0 = alice_app.raiden.address address1 = bob_app.raiden.address alice_netted_balance = alice_balance + alice_deposit - alice_to_bob_amount bob_netted_balance = bob_balance + bob_deposit + alice_to_bob_amount assert token.balance_of(address0) == alice_netted_balance assert token.balance_of(address1) == bob_netted_balance # Now let's query the WAL to see if the state changes were logged as expected state_changes = [ change[1] for change in get_all_state_changes(alice_app.raiden.transaction_log) if not isinstance(change[1], Block) ] assert must_contain_entry(state_changes, ContractReceiveClosed, { 'channel_address': nettingaddress0, 'closing_address': bob_app.raiden.address, 'block_number': alice_bob_channel.external_state.closed_block, }) assert must_contain_entry(state_changes, ReceiveSecretReveal, { 'secret': secret, 'sender': bob_app.raiden.address, }) assert must_contain_entry(state_changes, ContractReceiveWithdraw, { 'channel_address': nettingaddress0, 'secret': secret, 'receiver': bob_app.raiden.address, }) assert must_contain_entry(state_changes, ContractReceiveSettled, { 'channel_address': nettingaddress0, 'block_number': bob_alice_channel.external_state.settled_block, })
def test_settlement(raiden_network, settle_timeout, reveal_timeout): alice_app, bob_app = raiden_network # pylint: disable=unbalanced-tuple-unpacking setup_messages_cb() alice_graph = alice_app.raiden.channelgraphs.values()[0] bob_graph = bob_app.raiden.channelgraphs.values()[0] assert alice_graph.token_address == bob_graph.token_address alice_bob_channel = alice_graph.partneraddress_channel[ bob_app.raiden.address] bob_alice_channel = bob_graph.partneraddress_channel[ alice_app.raiden.address] alice_deposit = alice_bob_channel.balance bob_deposit = bob_alice_channel.balance token = alice_app.raiden.chain.token(alice_bob_channel.token_address) alice_balance = token.balance_of(alice_app.raiden.address) bob_balance = token.balance_of(bob_app.raiden.address) alice_chain = alice_app.raiden.chain alice_to_bob_amount = 10 expiration = alice_app.raiden.chain.block_number() + reveal_timeout + 1 secret = 'secretsecretsecretsecretsecretse' hashlock = sha3(secret) assert bob_app.raiden.address in alice_graph.partneraddress_channel nettingaddress0 = alice_bob_channel.external_state.netting_channel.address nettingaddress1 = bob_alice_channel.external_state.netting_channel.address assert nettingaddress0 == nettingaddress1 identifier = 1 fee = 0 transfermessage = alice_bob_channel.create_mediatedtransfer( alice_app.raiden.get_block_number(), alice_app.raiden.address, bob_app.raiden.address, fee, alice_to_bob_amount, identifier, expiration, hashlock, ) alice_app.raiden.sign(transfermessage) alice_bob_channel.register_transfer( alice_app.raiden.get_block_number(), transfermessage, ) bob_alice_channel.register_transfer( bob_app.raiden.get_block_number(), transfermessage, ) assert_synched_channels( alice_bob_channel, alice_deposit, [], bob_alice_channel, bob_deposit, [transfermessage.lock], ) # At this point we are assuming the following: # # A -> B MediatedTransfer # B -> A SecretRequest # A -> B RevealSecret # - protocol didn't continue # # B knowns the secret but doesn't have an updated balance proof, B needs to # call settle. # get proof, that locked transfermessage was in merkle tree, with locked.root lock = bob_alice_channel.our_state.balance_proof.get_lock_by_hashlock( hashlock) assert sha3(secret) == hashlock unlock_proof = bob_alice_channel.our_state.balance_proof.compute_proof_for_lock( secret, lock) root = bob_alice_channel.our_state.balance_proof.merkleroot_for_unclaimed() assert check_proof( unlock_proof.merkle_proof, root, sha3(transfermessage.lock.as_bytes), ) assert unlock_proof.lock_encoded == transfermessage.lock.as_bytes assert unlock_proof.secret == secret # a ChannelClose event will be generated, this will be polled by both apps # and each must start a task for calling settle bob_alice_channel.external_state.netting_channel.close(transfermessage) wait_until_block(alice_chain, alice_chain.block_number() + 1) assert alice_bob_channel.external_state.close_event.wait(timeout=15) assert bob_alice_channel.external_state.close_event.wait(timeout=15) assert alice_bob_channel.external_state.closed_block != 0 assert bob_alice_channel.external_state.closed_block != 0 assert alice_bob_channel.external_state.settled_block == 0 assert bob_alice_channel.external_state.settled_block == 0 # unlock will not be called by Channel.channel_closed because we did not # register the secret assert lock.expiration > alice_app.raiden.chain.block_number() assert lock.hashlock == sha3(secret) bob_alice_channel.external_state.netting_channel.withdraw([unlock_proof]) settle_expiration = alice_chain.block_number() + settle_timeout + 2 wait_until_block(alice_chain, settle_expiration) assert alice_bob_channel.external_state.settle_event.wait(timeout=15) assert bob_alice_channel.external_state.settle_event.wait(timeout=15) # settle must be called by the apps triggered by the ChannelClose event, # and the channels must update it's state based on the ChannelSettled event assert alice_bob_channel.external_state.settled_block != 0 assert bob_alice_channel.external_state.settled_block != 0 address0 = alice_app.raiden.address address1 = bob_app.raiden.address alice_netted_balance = alice_balance + alice_deposit - alice_to_bob_amount bob_netted_balance = bob_balance + bob_deposit + alice_to_bob_amount assert token.balance_of(address0) == alice_netted_balance assert token.balance_of(address1) == bob_netted_balance # Now let's query the WAL to see if the state changes were logged as expected state_changes = [ change[1] for change in get_all_state_changes(alice_app.raiden.transaction_log) if not isinstance(change[1], Block) ] state_change1 = state_changes[0] state_change2 = state_changes[1] state_change3 = state_changes[2] state_change4 = state_changes[3] assert isinstance(state_change1, ContractReceiveClosed) assert state_change1.channel_address == nettingaddress0 assert state_change1.closing_address == bob_app.raiden.address assert state_change1.block_number == alice_bob_channel.external_state.closed_block # Can't be sure of the order in which we encounter the SecretReveal and the withdraw assert_secretreveal_or_withdraw(state_change2, secret, nettingaddress0, bob_app.raiden.address) assert_secretreveal_or_withdraw(state_change3, secret, nettingaddress0, bob_app.raiden.address) assert isinstance(state_change4, ContractReceiveSettled) assert state_change4.channel_address == nettingaddress0 assert state_change4.block_number == bob_alice_channel.external_state.settled_block
def test_automatic_dispute(raiden_network, deposit, settle_timeout): app0, app1 = raiden_network channel0 = list(list(app0.raiden.token_to_channelgraph.values())[0].partneraddress_to_channel.values())[0] # noqa: E501 channel1 = list(list(app1.raiden.token_to_channelgraph.values())[0].partneraddress_to_channel.values())[0] # noqa: E501 privatekey0 = app0.raiden.private_key privatekey1 = app1.raiden.private_key address0 = privatekey_to_address(privatekey0.secret) address1 = privatekey_to_address(privatekey1.secret) token = app0.raiden.chain.token(channel0.token_address) initial_balance0 = token.balance_of(address0) initial_balance1 = token.balance_of(address1) # Alice sends Bob 10 tokens amount_alice1 = 10 identifier_alice1 = 1 alice_first_transfer = channel0.create_directtransfer( amount_alice1, identifier_alice1, ) alice_first_transfer.sign(privatekey0, address0) channel0.register_transfer( app0.raiden.get_block_number(), alice_first_transfer, ) channel1.register_transfer( app1.raiden.get_block_number(), alice_first_transfer, ) # Bob sends Alice 50 tokens amount_bob1 = 50 identifier_bob1 = 1 bob_first_transfer = channel1.create_directtransfer( amount_bob1, identifier_bob1, ) bob_first_transfer.sign(privatekey1, address1) channel0.register_transfer( app0.raiden.get_block_number(), bob_first_transfer, ) channel1.register_transfer( app1.raiden.get_block_number(), bob_first_transfer, ) # Finally Alice sends Bob 60 tokens identifier_alice2 = 2 amount_alice2 = 60 alice_second_transfer = channel0.create_directtransfer( amount_alice2, identifier_alice2, ) alice_second_transfer.sign(privatekey0, address0) channel0.register_transfer( app0.raiden.get_block_number(), alice_second_transfer, ) channel1.register_transfer( app1.raiden.get_block_number(), alice_second_transfer, ) # Alice can only provide one of Bob's transfer, so she is incentivized to # use the one with the largest transferred_amount. channel0.external_state.close(channel0.partner_state.balance_proof) chain0 = app0.raiden.chain wait_until_block(chain0, chain0.block_number() + 1) assert channel0.external_state.close_event.wait(timeout=25) assert channel1.external_state.close_event.wait(timeout=25) assert channel0.external_state.closed_block != 0 assert channel1.external_state.closed_block != 0 # Bob needs to provide a transfer otherwise it's netted balance will be # wrong, so he is incetivized to use Alice's transfer with the largest # transferred_amount. # # This is done automatically # channel1.external_state.update_transfer( # alice_second_transfer, # ) # wait until the settle timeout has passed settle_expiration = chain0.block_number() + settle_timeout wait_until_block(chain0, settle_expiration) # the settle event must be set assert channel0.external_state.settle_event.wait(timeout=60) assert channel1.external_state.settle_event.wait(timeout=60) # check that the channel is properly settled and that Bob's client # automatically called updateTransfer() to reflect the actual transactions assert channel0.external_state.settled_block != 0 assert channel1.external_state.settled_block != 0 assert token.balance_of(channel0.external_state.netting_channel.address) == 0 total_alice = amount_alice1 + amount_alice2 total_bob = amount_bob1 assert token.balance_of(address0) == initial_balance0 + deposit - total_alice + total_bob assert token.balance_of(address1) == initial_balance1 + deposit + total_alice - total_bob
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_settlement(raiden_network, settle_timeout): app0, app1 = raiden_network # pylint: disable=unbalanced-tuple-unpacking setup_messages_cb() asset_manager0 = app0.raiden.managers_by_asset_address.values()[0] asset_manager1 = app1.raiden.managers_by_asset_address.values()[0] chain0 = app0.raiden.chain channel0 = asset_manager0.partneraddress_channel[app1.raiden.address] channel1 = asset_manager1.partneraddress_channel[app0.raiden.address] balance0 = channel0.balance balance1 = channel1.balance amount = 10 expiration = app0.raiden.chain.block_number() + 5 secret = 'secret' hashlock = sha3(secret) assert app1.raiden.address in asset_manager0.partneraddress_channel assert asset_manager0.asset_address == asset_manager1.asset_address assert channel0.external_state.netting_channel.address == channel1.external_state.netting_channel.address transfermessage = channel0.create_lockedtransfer(amount, expiration, hashlock) app0.raiden.sign(transfermessage) channel0.register_transfer(transfermessage) channel1.register_transfer(transfermessage) assert_synched_channels( channel0, balance0, [], channel1, balance1, [transfermessage.lock], ) # Bob learns the secret, but Alice did not send a signed updated balance to # reflect this Bob wants to settle # get proof, that locked transfermessage was in merkle tree, with locked.root lock = channel1.our_state.balance_proof.get_lock_by_hashlock(hashlock) unlock_proof = channel1.our_state.balance_proof.compute_proof_for_lock( secret, lock) root = channel1.our_state.balance_proof.merkleroot_for_unclaimed() assert check_proof( unlock_proof.merkle_proof, root, sha3(transfermessage.lock.as_bytes), ) assert unlock_proof.lock_encoded == transfermessage.lock.as_bytes assert unlock_proof.secret == secret channel0.external_state.netting_channel.close( app0.raiden.address, transfermessage, None, ) channel0.external_state.netting_channel.unlock( app0.raiden.address, [unlock_proof], ) settle_expiration = chain0.block_number() + settle_timeout wait_until_block(chain0, settle_expiration) channel0.external_state.netting_channel.settle()
def test_settlement(raiden_network, settle_timeout, reveal_timeout): app0, app1 = raiden_network # pylint: disable=unbalanced-tuple-unpacking setup_messages_cb() asset_manager0 = app0.raiden.managers_by_asset_address.values()[0] asset_manager1 = app1.raiden.managers_by_asset_address.values()[0] chain0 = app0.raiden.chain channel0 = asset_manager0.partneraddress_channel[app1.raiden.address] channel1 = asset_manager1.partneraddress_channel[app0.raiden.address] balance0 = channel0.balance balance1 = channel1.balance amount = 10 expiration = app0.raiden.chain.block_number() + reveal_timeout + 1 secret = 'secret' hashlock = sha3(secret) assert app1.raiden.address in asset_manager0.partneraddress_channel assert asset_manager0.asset_address == asset_manager1.asset_address nettingaddress0 = channel0.external_state.netting_channel.address nettingaddress1 = channel1.external_state.netting_channel.address assert nettingaddress0 == nettingaddress1 identifier = 1 fee = 0 transfermessage = channel0.create_mediatedtransfer( app0.raiden.address, app1.raiden.address, fee, amount, identifier, expiration, hashlock, ) app0.raiden.sign(transfermessage) channel0.register_transfer(transfermessage) channel1.register_transfer(transfermessage) assert_synched_channels( channel0, balance0, [], channel1, balance1, [transfermessage.lock], ) # At this point we are assuming the following: # # A -> B MediatedTransfer # B -> A SecretRequest # A -> B RevealSecret # - protocol didn't continue # # B knowns the secret but doesn't have an updated balance proof, B needs to # call settle. # get proof, that locked transfermessage was in merkle tree, with locked.root lock = channel1.our_state.balance_proof.get_lock_by_hashlock(hashlock) unlock_proof = channel1.our_state.balance_proof.compute_proof_for_lock(secret, lock) root = channel1.our_state.balance_proof.merkleroot_for_unclaimed() assert check_proof( unlock_proof.merkle_proof, root, sha3(transfermessage.lock.as_bytes), ) assert unlock_proof.lock_encoded == transfermessage.lock.as_bytes assert unlock_proof.secret == secret # a ChannelClose event will be generated, this will be polled by both apps # and each must start a task for calling settle channel0.external_state.netting_channel.close( app0.raiden.address, transfermessage, None, ) # unlock will not be called by Channel.channel_closed because we did not # register the secret channel0.external_state.netting_channel.unlock( app0.raiden.address, [unlock_proof], ) settle_expiration = chain0.block_number() + settle_timeout wait_until_block(chain0, settle_expiration) # settle must be called by the apps triggered by the ChannelClose event, # and the channels must update it's state based on the ChannelSettled event assert channel0.external_state.settled_block != 0 assert channel1.external_state.settled_block != 0
def test_query_events(raiden_chain, deposit, settle_timeout, events_poll_timeout): app0, app1 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking token_address = app0.raiden.default_registry.token_addresses()[0] assert len(app0.raiden.token_to_channelgraph[token_address].address_to_channel) == 0 assert len(app1.raiden.token_to_channelgraph[token_address].address_to_channel) == 0 token0 = app0.raiden.chain.token(token_address) manager0 = app0.raiden.default_registry.manager_by_token(token_address) events = get_all_registry_events( app0.raiden.chain, app0.raiden.default_registry.address, events=ALL_EVENTS, from_block=0, to_block='latest', ) assert len(events) == 1 assert event_dicts_are_equal(events[0], { '_event_type': b'TokenAdded', 'channel_manager_address': address_encoder(manager0.address), 'token_address': address_encoder(token_address), 'block_number': 'ignore', }) events = get_all_registry_events( app0.raiden.chain, app0.raiden.default_registry.address, events=ALL_EVENTS, from_block=999999998, to_block=999999999, ) assert not events netcontract_address = manager0.new_netting_channel( app1.raiden.address, settle_timeout, ) events = get_all_channel_manager_events( app0.raiden.chain, manager0.address, events=ALL_EVENTS, from_block=0, to_block='latest', ) assert len(events) == 1 assert event_dicts_are_equal(events[0], { '_event_type': b'ChannelNew', 'settle_timeout': settle_timeout, 'netting_channel': address_encoder(netcontract_address), 'participant1': address_encoder(app0.raiden.address), 'participant2': address_encoder(app1.raiden.address), 'block_number': 'ignore', }) events = get_all_channel_manager_events( app0.raiden.chain, manager0.address, events=ALL_EVENTS, from_block=999999998, to_block=999999999, ) assert not events netting_channel0 = app0.raiden.chain.netting_channel(netcontract_address) gevent.sleep(events_poll_timeout * 2) # channel is created but not opened and without funds assert len(app0.raiden.token_to_channelgraph[token_address].address_to_channel) == 1 assert len(app1.raiden.token_to_channelgraph[token_address].address_to_channel) == 1 channel0 = list(app0.raiden.token_to_channelgraph[token_address].address_to_channel.values())[0] # noqa: E501 channel1 = list(app1.raiden.token_to_channelgraph[token_address].address_to_channel.values())[0] # noqa: E501 assert_synched_channels( channel0, 0, [], channel1, 0, [], ) token0.approve(netcontract_address, deposit) netting_channel0.deposit(deposit) all_netting_channel_events = get_all_netting_channel_events( app0.raiden.chain, netting_channel_address=netcontract_address, from_block=0, to_block='latest', ) events = get_all_netting_channel_events( app0.raiden.chain, netcontract_address, events=[CONTRACT_MANAGER.get_event_id(EVENT_CHANNEL_NEW_BALANCE)], ) assert len(all_netting_channel_events) == 1 assert len(events) == 1 new_balance_event = { '_event_type': b'ChannelNewBalance', 'token_address': address_encoder(token_address), 'participant': address_encoder(app0.raiden.address), 'balance': deposit, 'block_number': 'ignore', } assert event_dicts_are_equal(all_netting_channel_events[-1], new_balance_event) assert event_dicts_are_equal(events[0], new_balance_event) channel0.external_state.close(None) all_netting_channel_events = get_all_netting_channel_events( app0.raiden.chain, netting_channel_address=netcontract_address, from_block=0, to_block='latest', ) events = get_all_netting_channel_events( app0.raiden.chain, netcontract_address, events=[CONTRACT_MANAGER.get_event_id(EVENT_CHANNEL_CLOSED)], ) assert len(all_netting_channel_events) == 2 assert len(events) == 1 closed_event = { '_event_type': b'ChannelClosed', 'closing_address': address_encoder(app0.raiden.address), 'block_number': 'ignore', } assert event_dicts_are_equal(all_netting_channel_events[-1], closed_event) assert event_dicts_are_equal(events[0], closed_event) settle_expiration = app0.raiden.chain.block_number() + settle_timeout + 1 wait_until_block(app0.raiden.chain, settle_expiration) channel1.external_state.settle() all_netting_channel_events = get_all_netting_channel_events( app0.raiden.chain, netting_channel_address=netcontract_address, from_block=0, to_block='latest', ) events = get_all_netting_channel_events( app0.raiden.chain, netcontract_address, events=[CONTRACT_MANAGER.get_event_id(EVENT_CHANNEL_SETTLED)], ) assert len(all_netting_channel_events) == 3 assert len(events) == 1 settled_event = { '_event_type': b'ChannelSettled', 'block_number': 'ignore', } assert event_dicts_are_equal(all_netting_channel_events[-1], settled_event) assert event_dicts_are_equal(events[0], settled_event)