def test_event_transfer_received_success(token_addresses, raiden_chain): app0, app1, app2, receiver_app = raiden_chain token_address = token_addresses[0] expected = dict() for num, app in enumerate([app0, app1, app2]): amount = 1 + num transfer_event = RaidenAPI(app.raiden).transfer_async( app.raiden.default_registry.address, token_address, amount, receiver_app.raiden.address, ) transfer_event.wait(timeout=20) expected[app.raiden.address] = amount # sleep is for the receiver's node to have time to process all events gevent.sleep(1) events = receiver_app.raiden.wal.storage.get_events_by_block(0, 'latest') events = [e[1] for e in events] assert must_contain_entry(events, EventTransferReceivedSuccess, { 'amount': 1, 'initiator': app0.raiden.address }) assert must_contain_entry(events, EventTransferReceivedSuccess, { 'amount': 2, 'initiator': app1.raiden.address }) assert must_contain_entry(events, EventTransferReceivedSuccess, { 'amount': 3, 'initiator': app2.raiden.address })
def test_initiator_log_directransfer_success(raiden_chain, token_addresses, deposit): app0, app1 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking token_address = token_addresses[0] amount = int(deposit / 2.) identifier = 7 token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) direct_transfer( app0, app1, token_network_identifier, amount, identifier, ) app0_all_events = app0.raiden.wal.storage.get_events() assert must_contain_entry( app0_all_events, EventPaymentSentSuccess, { 'identifier': identifier, 'amount': amount, 'target': app1.raiden.address, }) app1_all_events = app1.raiden.wal.storage.get_events() assert must_contain_entry( app1_all_events, EventPaymentReceivedSuccess, { 'identifier': identifier, 'amount': amount, 'initiator': app0.raiden.address, })
def pending_mediated_transfer(app_chain, token, amount, identifier): """ Nice to read shortcut to make a LockedTransfer where the secret is _not_ revealed. While the secret is not revealed all apps will be synchronized, meaning they are all going to receive the LockedTransfer message. Returns: The secret used to generate the LockedTransfer """ # pylint: disable=too-many-locals if len(app_chain) < 2: raise ValueError( 'Cannot make a LockedTransfer with less than two apps') target = app_chain[-1].raiden.address # Generate a secret initiator_channel = get_channelstate(app_chain[0], app_chain[1], token) address = initiator_channel.identifier nonce_int = channel.get_next_nonce(initiator_channel.our_state) nonce_bytes = nonce_int.to_bytes(2, 'big') secret = sha3(address + nonce_bytes) initiator_app = app_chain[0] init_initiator_statechange = initiator_init( initiator_app.raiden, identifier, amount, secret, initiator_app.raiden.default_registry.address, token, target, ) events = initiator_app.raiden.wal.log_and_dispatch( init_initiator_statechange, initiator_app.raiden.get_block_number(), ) send_transfermessage = must_contain_entry(events, SendLockedTransfer, {}) transfermessage = LockedTransfer.from_event(send_transfermessage) initiator_app.raiden.sign(transfermessage) for mediator_app in app_chain[1:-1]: mediator_init_statechange = mediator_init(mediator_app.raiden, transfermessage) events = mediator_app.raiden.wal.log_and_dispatch( mediator_init_statechange, mediator_app.raiden.get_block_number(), ) send_transfermessage = must_contain_entry(events, SendLockedTransfer, {}) transfermessage = LockedTransfer.from_event(send_transfermessage) mediator_app.raiden.sign(transfermessage) target_app = app_chain[-1] mediator_init_statechange = target_init(target_app.raiden, transfermessage) events = target_app.raiden.wal.log_and_dispatch( mediator_init_statechange, target_app.raiden.get_block_number(), ) return secret
def test_target_events(): target_events = app2.raiden.wal.storage.get_events() return ( must_contain_entry(target_events, SendSecretRequest, {}) and must_contain_entry(target_events, SendSecretReveal, {}) and must_contain_entry(target_events, EventUnlockClaimSuccess, {}) )
def test_raiden_service_callback_new_block(raiden_network): """ Regression test for: https://github.com/raiden-network/raiden/issues/2894 """ app0 = raiden_network[0] app0.raiden.alarm.stop() target_block_num = app0.raiden.chain.block_number( ) + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1 wait_until_block( app0.raiden.chain, target_block_num, ) latest_block = app0.raiden.chain.get_block(block_identifier='latest') app0.raiden._callback_new_block(latest_block=latest_block) target_block_num = latest_block['number'] app0_state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) assert must_contain_entry(app0_state_changes, Block, { 'block_number': target_block_num - DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS, }) assert not must_contain_entry(app0_state_changes, Block, { 'block_number': target_block_num, })
def pending_mediated_transfer(app_chain, token_network_identifier, amount, identifier): """ Nice to read shortcut to make a LockedTransfer where the secret is _not_ revealed. While the secret is not revealed all apps will be synchronized, meaning they are all going to receive the LockedTransfer message. Returns: The secret used to generate the LockedTransfer """ # pylint: disable=too-many-locals if len(app_chain) < 2: raise ValueError('Cannot make a LockedTransfer with less than two apps') target = app_chain[-1].raiden.address # Generate a secret initiator_channel = views.get_channelstate_by_token_network_and_partner( views.state_from_app(app_chain[0]), token_network_identifier, app_chain[1].raiden.address, ) address = initiator_channel.identifier nonce_int = channel.get_next_nonce(initiator_channel.our_state) nonce_bytes = nonce_int.to_bytes(2, 'big') secret = sha3(address + nonce_bytes) initiator_app = app_chain[0] init_initiator_statechange = initiator_init( initiator_app.raiden, identifier, amount, secret, token_network_identifier, target, ) events = initiator_app.raiden.wal.log_and_dispatch( init_initiator_statechange, initiator_app.raiden.get_block_number(), ) send_transfermessage = must_contain_entry(events, SendLockedTransfer, {}) transfermessage = LockedTransfer.from_event(send_transfermessage) initiator_app.raiden.sign(transfermessage) for mediator_app in app_chain[1:-1]: mediator_init_statechange = mediator_init(mediator_app.raiden, transfermessage) events = mediator_app.raiden.wal.log_and_dispatch( mediator_init_statechange, mediator_app.raiden.get_block_number(), ) send_transfermessage = must_contain_entry(events, SendLockedTransfer, {}) transfermessage = LockedTransfer.from_event(send_transfermessage) mediator_app.raiden.sign(transfermessage) target_app = app_chain[-1] mediator_init_statechange = target_init(transfermessage) events = target_app.raiden.wal.log_and_dispatch( mediator_init_statechange, target_app.raiden.get_block_number(), ) return secret
def test_raiden_service_callback_new_block(raiden_network): """ Regression test for: https://github.com/raiden-network/raiden/issues/2894 """ app0 = raiden_network[0] app0.raiden.alarm.stop() target_block_num = app0.raiden.chain.block_number() + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1 wait_until_block( app0.raiden.chain, target_block_num, ) latest_block = app0.raiden.chain.get_block(block_identifier='latest') app0.raiden._callback_new_block(latest_block=latest_block) target_block_num = latest_block['number'] app0_state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) assert must_contain_entry(app0_state_changes, Block, { 'block_number': target_block_num - DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS, }) assert not must_contain_entry(app0_state_changes, Block, { 'block_number': target_block_num, })
def test_locked_transfer_secret_registered_onchain( raiden_network, token_addresses, secret_registry_address, ): app0 = raiden_network[0] token_address = token_addresses[0] chain_state = views.state_from_app(app0) payment_network_id = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state, payment_network_id, token_address, ) amount = 1 target = UNIT_TRANSFER_INITIATOR identifier = 1 transfer_secret = sha3(target + b'1') secret_registry_proxy = app0.raiden.chain.secret_registry( secret_registry_address, ) secret_registry_proxy.register_secret(transfer_secret) # Test that sending a transfer with a secret already registered on-chain fails with pytest.raises(RaidenUnrecoverableError): app0.raiden.start_mediated_transfer_with_secret( token_network_identifier, amount, target, identifier, transfer_secret, ) expiration = 9999 transfer = make_signed_transfer( amount, UNIT_TRANSFER_INITIATOR, app0.raiden.address, expiration, transfer_secret, ) message_handler = MessageHandler() message_handler.handle_message_lockedtransfer( app0.raiden, transfer, ) state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier(0, 'latest') transfer_statechange_dispatched = ( must_contain_entry(state_changes, ActionInitMediator, {}) or must_contain_entry(state_changes, ActionInitTarget, {}) ) assert not transfer_statechange_dispatched
def test_settle_is_automatically_called(raiden_network, token_addresses, deposit): """Settle is automatically called by one of the nodes.""" app0, app1 = raiden_network 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, ) channel_identifier = get_channelstate(app0, app1, token_network_identifier).identifier # A ChannelClose event will be generated, this will be polled by both apps # and each must start a task for calling settle RaidenAPI(app1.raiden).channel_close( registry_address, token_address, app0.raiden.address, ) waiting.wait_for_settle( app0.raiden, registry_address, token_address, [channel_identifier], app0.raiden.alarm.sleep_time, ) assert_synched_channel_state( token_network_identifier, app0, deposit, [], app1, deposit, [], ) state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) channel_state = get_channelstate(app0, app1, token_network_identifier) assert channel_state.close_transaction.finished_block_number assert channel_state.settle_transaction.finished_block_number assert must_contain_entry(state_changes, ContractReceiveChannelClosed, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, 'closing_address': app1.raiden.address, 'closed_block_number': channel_state.close_transaction.finished_block_number, }) assert must_contain_entry(state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, 'settle_block_number': channel_state.settle_transaction.finished_block_number, })
def test_settle_is_automatically_called(raiden_network, token_addresses, deposit): """Settle is automatically called by one of the nodes.""" app0, app1 = raiden_network 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, ) channel_identifier = get_channelstate(app0, app1, token_network_identifier).identifier # A ChannelClose event will be generated, this will be polled by both apps # and each must start a task for calling settle RaidenAPI(app1.raiden).channel_close( registry_address, token_address, app0.raiden.address, ) waiting.wait_for_settle( app0.raiden, registry_address, token_address, [channel_identifier], app0.raiden.alarm.wait_time, ) assert_synched_channel_state( token_network_identifier, app0, deposit, [], app1, deposit, [], ) state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) channel_state = get_channelstate(app0, app1, token_network_identifier) assert channel_state.close_transaction.finished_block_number assert channel_state.settle_transaction.finished_block_number assert must_contain_entry(state_changes, ContractReceiveChannelClosed, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, 'closing_address': app1.raiden.address, 'closed_block_number': channel_state.close_transaction.finished_block_number, }) assert must_contain_entry(state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel_identifier, 'settle_block_number': channel_state.settle_transaction.finished_block_number, })
def test_channelstate_unlock(): """The node must call unlock after the channel is settled""" our_model1, _ = create_model(70) partner_model1, privkey2 = create_model(100) channel_state = create_channel_from_models(our_model1, partner_model1) lock_amount = 10 lock_expiration = 100 lock_secret = sha3(b'test_channelstate_lockedtransfer_overspent') lock_secrethash = sha3(lock_secret) lock = HashTimeLockState( lock_amount, lock_expiration, lock_secrethash, ) nonce = 1 transferred_amount = 0 receive_lockedtransfer = make_receive_transfer_mediated( channel_state, privkey2, nonce, transferred_amount, lock, ) is_valid, _, msg = channel.handle_receive_lockedtransfer( channel_state, receive_lockedtransfer, ) assert is_valid, msg channel.register_secret(channel_state, lock_secret, lock_secrethash) closed_block_number = lock_expiration - channel_state.reveal_timeout - 1 close_state_change = ContractReceiveChannelClosed( channel_state.token_network_identifier, channel_state.identifier, partner_model1.participant_address, closed_block_number, ) iteration = channel.handle_channel_closed(channel_state, close_state_change) assert not must_contain_entry(iteration.events, ContractSendChannelBatchUnlock, {}) settle_block_number = lock_expiration + channel_state.reveal_timeout + 1 settle_state_change = ContractReceiveChannelSettled( channel_state.token_network_identifier, channel_state.identifier, settle_block_number, ) iteration = channel.handle_channel_settled( channel_state, settle_state_change, settle_block_number, ) assert must_contain_entry(iteration.events, ContractSendChannelBatchUnlock, {})
def test_mediator_events(): mediator_blockevents = app1.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) mediator_events = [blocknumber_event[1] for blocknumber_event in mediator_blockevents] return ( must_contain_entry(mediator_events, EventUnlockSuccess, {}) and must_contain_entry(mediator_events, EventUnlockClaimSuccess, {}) )
def test_initiator_events(): initiator_blockevents = app0.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) initiator_events = [blocknumber_event[1] for blocknumber_event in initiator_blockevents] return ( must_contain_entry(initiator_events, SendRevealSecret, {}) and must_contain_entry(initiator_events, EventUnlockSuccess, {}) )
def test_initiator_events(): initiator_blockevents = app0.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) initiator_events = [ blocknumber_event[1] for blocknumber_event in initiator_blockevents ] return (must_contain_entry(initiator_events, SendRevealSecret, {}) and must_contain_entry(initiator_events, EventUnlockSuccess, {}))
def test_regression_mediator_send_lock_expired_with_new_block(): """ The mediator must send the lock expired, but it must **not** clear itself if it has not **received** the corresponding message. """ pseudo_random_generator = random.Random() channels = factories.mediator_make_channel_pair() payer_transfer = factories.make_default_signed_transfer_for( channels[0], initiator=HOP1, expiration=30, ) init_iteration = mediator.state_transition( mediator_state=None, state_change=factories.mediator_make_init_action( channels, payer_transfer), channelidentifiers_to_channels=channels.channel_map, pseudo_random_generator=pseudo_random_generator, block_number=5, ) assert init_iteration.new_state is not None send_transfer = must_contain_entry(init_iteration.events, SendLockedTransfer, {}) assert send_transfer transfer = send_transfer.transfer block_expiration_number = transfer.lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2 block = Block( block_number=block_expiration_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = mediator.state_transition( mediator_state=init_iteration.new_state, state_change=block, channelidentifiers_to_channels=channels.channel_map, pseudo_random_generator=pseudo_random_generator, block_number=block_expiration_number, ) msg = ("The payer's lock has also expired, " "but it must not be removed locally (without an Expired lock)") assert transfer.lock.secrethash in channels[ 0].partner_state.secrethashes_to_lockedlocks, msg msg = 'The payer has not yet sent an expired lock, the task can not be cleared yet' assert iteration.new_state is not None, msg assert must_contain_entry(iteration.events, SendLockExpired, { 'secrethash': transfer.lock.secrethash, }) assert transfer.lock.secrethash not in channels[ 1].our_state.secrethashes_to_lockedlocks
def test_mediator_events(): mediator_blockevents = app1.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) mediator_events = [ blocknumber_event[1] for blocknumber_event in mediator_blockevents ] return (must_contain_entry(mediator_events, EventUnlockSuccess, {}) and must_contain_entry(mediator_events, EventUnlockClaimSuccess, {}))
def test_target_events(): target_blockevents = app2.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) target_events = [ blocknumber_event[1] for blocknumber_event in target_blockevents ] return (must_contain_entry(target_events, SendSecretRequest, {}) and must_contain_entry(target_events, SendRevealSecret, {}) and must_contain_entry(target_events, EventUnlockClaimSuccess, {}))
def test_target_events(): target_blockevents = app2.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) target_events = [blocknumber_event[1] for blocknumber_event in target_blockevents] return ( must_contain_entry(target_events, SendSecretRequest, {}) and must_contain_entry(target_events, SendRevealSecret, {}) and must_contain_entry(target_events, EventUnlockClaimSuccess, {}) )
def test_handle_offchain_secretreveal_after_lock_expired(): """Test that getting the secret revealed after lock expiration for the target does not end up continuously emitting EventUnlockClaimFailed Target part for https://github.com/raiden-network/raiden/issues/3086 """ setup = make_target_state() lock_expiration = setup.new_state.transfer.lock.expiration lock_expiration_block_number = lock_expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2 lock_expiration_block = Block( block_number=lock_expiration_block_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = target.state_transition( target_state=setup.new_state, state_change=lock_expiration_block, channel_state=setup.channel, pseudo_random_generator=setup.pseudo_random_generator, block_number=lock_expiration_block_number, ) state = iteration.new_state msg = 'At the expiration block we should get an EventUnlockClaimFailed' assert must_contain_entry(iteration.events, EventUnlockClaimFailed, {}), msg iteration = target.state_transition( target_state=state, state_change=ReceiveSecretReveal(UNIT_SECRET, setup.initiator), channel_state=setup.channel, pseudo_random_generator=setup.pseudo_random_generator, block_number=lock_expiration_block_number + 1, ) state = iteration.new_state next_block = Block( block_number=lock_expiration_block_number + 1, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = target.state_transition( target_state=state, state_change=next_block, channel_state=setup.channel, pseudo_random_generator=setup.pseudo_random_generator, block_number=lock_expiration_block_number + 1, ) msg = 'At the next block we should not get the same event' assert not must_contain_entry(iteration.events, EventUnlockClaimFailed, {}), msg
def test_handle_offchain_secretreveal_after_lock_expired(): """Test that getting the secret revealed after lock expiration for the target does not end up continuously emitting EventUnlockClaimFailed Target part for https://github.com/raiden-network/raiden/issues/3086 """ setup = make_target_state() lock_expiration_block_number = channel.get_sender_expiration_threshold( setup.new_state.transfer.lock, ) lock_expiration_block = Block( block_number=lock_expiration_block_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = target.state_transition( target_state=setup.new_state, state_change=lock_expiration_block, channel_state=setup.channel, pseudo_random_generator=setup.pseudo_random_generator, block_number=lock_expiration_block_number, ) state = iteration.new_state msg = 'At the expiration block we should get an EventUnlockClaimFailed' assert must_contain_entry(iteration.events, EventUnlockClaimFailed, {}), msg iteration = target.state_transition( target_state=state, state_change=ReceiveSecretReveal(UNIT_SECRET, setup.initiator), channel_state=setup.channel, pseudo_random_generator=setup.pseudo_random_generator, block_number=lock_expiration_block_number + 1, ) state = iteration.new_state next_block = Block( block_number=lock_expiration_block_number + 1, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = target.state_transition( target_state=state, state_change=next_block, channel_state=setup.channel, pseudo_random_generator=setup.pseudo_random_generator, block_number=lock_expiration_block_number + 1, ) msg = 'At the next block we should not get the same event' assert not must_contain_entry(iteration.events, EventUnlockClaimFailed, {}), msg
def test_regression_mediator_send_lock_expired_with_new_block(): """ The mediator must send the lock expired, but it must **not** clear itself if it has not **received** the corresponding message. """ pseudo_random_generator = random.Random() channels = factories.mediator_make_channel_pair() payer_transfer = factories.make_signed_transfer_for(channels[0], LONG_EXPIRATION) init_iteration = mediator.state_transition( mediator_state=None, state_change=factories.mediator_make_init_action(channels, payer_transfer), channelidentifiers_to_channels=channels.channel_map, pseudo_random_generator=pseudo_random_generator, block_number=5, ) assert init_iteration.new_state is not None send_transfer = must_contain_entry(init_iteration.events, SendLockedTransfer, {}) assert send_transfer transfer = send_transfer.transfer block_expiration_number = channel.get_sender_expiration_threshold(transfer.lock) block = Block( block_number=block_expiration_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = mediator.state_transition( mediator_state=init_iteration.new_state, state_change=block, channelidentifiers_to_channels=channels.channel_map, pseudo_random_generator=pseudo_random_generator, block_number=block_expiration_number, ) msg = ( "The payer's lock has also expired, " "but it must not be removed locally (without an Expired lock)" ) assert transfer.lock.secrethash in channels[0].partner_state.secrethashes_to_lockedlocks, msg msg = 'The payer has not yet sent an expired lock, the task can not be cleared yet' assert iteration.new_state is not None, msg assert must_contain_entry(iteration.events, SendLockExpired, { 'secrethash': transfer.lock.secrethash, }) assert transfer.lock.secrethash not in channels[1].our_state.secrethashes_to_lockedlocks
def test_log_directransfer(raiden_chain, token_addresses, deposit): """The action that starts a direct transfer must be logged in the WAL.""" app0, app1 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking token_address = token_addresses[0] amount = int(deposit / 2.) identifier = 13 direct_transfer( app0, app1, token_address, amount, identifier, ) app0_state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) # ActionTransferDirect assert must_contain_entry( app0_state_changes, ActionForTokenNetwork, { 'token_network_identifier': token_address, 'sub_state_change': { 'identifier': identifier, 'amount': amount, 'receiver_address': app1.raiden.address, } }) # ReceiveTransferDirect app1_state_changes = app1.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) assert must_contain_entry( app1_state_changes, ActionForTokenNetwork, { 'token_network_identifier': token_address, 'sub_state_change': { 'transfer_identifier': identifier, 'balance_proof': { 'transferred_amount': amount, 'sender': app0.raiden.address, } } })
def test_initiator_handle_contract_receive_secret_reveal(): """ Initiator must unlock off-chain if the secret is revealed on-chain and the channel is open. """ setup = setup_initiator_tests(amount=UNIT_TRANSFER_AMOUNT * 2, block_number=10) transfer = setup.current_state.initiator.transfer assert transfer.lock.secrethash in setup.channel.our_state.secrethashes_to_lockedlocks state_change = ContractReceiveSecretReveal( transaction_hash=factories.make_transaction_hash(), secret_registry_address=factories.make_address(), secrethash=transfer.lock.secrethash, secret=UNIT_SECRET, block_number=transfer.lock.expiration, ) message_identifier = message_identifier_from_prng(deepcopy(setup.prng)) iteration = initiator_manager.handle_onchain_secretreveal( payment_state=setup.current_state, state_change=state_change, channelidentifiers_to_channels=setup.channel_map, pseudo_random_generator=setup.prng, ) payment_identifier = setup.current_state.initiator.transfer_description.payment_identifier assert events.must_contain_entry(iteration.events, SendBalanceProof, { 'message_identifier': message_identifier, 'payment_identifier': payment_identifier, })
def test_initiator_handle_contract_receive_secret_reveal_expired(): """ Initiator must *not* unlock off-chain if the secret is revealed on-chain *after* the lock expiration. """ setup = setup_initiator_tests(amount=UNIT_TRANSFER_AMOUNT * 2, block_number=10) transfer = setup.current_state.initiator.transfer assert transfer.lock.secrethash in setup.channel.our_state.secrethashes_to_lockedlocks state_change = ContractReceiveSecretReveal( transaction_hash=factories.make_transaction_hash(), secret_registry_address=factories.make_address(), secrethash=transfer.lock.secrethash, secret=UNIT_SECRET, block_number=transfer.lock.expiration + 1, ) iteration = initiator_manager.handle_onchain_secretreveal( payment_state=setup.current_state, state_change=state_change, channelidentifiers_to_channels=setup.channel_map, pseudo_random_generator=setup.prng, ) assert events.must_contain_entry(iteration.events, SendBalanceProof, {}) is None
def test_initiator_handle_contract_receive_secret_reveal(): """ Initiator must unlock off-chain if the secret is revealed on-chain and the channel is open. """ setup = setup_initiator_tests(amount=UNIT_TRANSFER_AMOUNT * 2, block_number=10) transfer = setup.current_state.initiator.transfer assert transfer.lock.secrethash in setup.channel.our_state.secrethashes_to_lockedlocks state_change = ContractReceiveSecretReveal( transaction_hash=factories.make_transaction_hash(), secret_registry_address=factories.make_address(), secrethash=transfer.lock.secrethash, secret=UNIT_SECRET, block_number=transfer.lock.expiration, ) message_identifier = message_identifier_from_prng(deepcopy(setup.prng)) iteration = initiator_manager.handle_onchain_secretreveal( payment_state=setup.current_state, state_change=state_change, channelidentifiers_to_channels=setup.channel_map, pseudo_random_generator=setup.prng, ) payment_identifier = setup.current_state.initiator.transfer_description.payment_identifier assert events.must_contain_entry( iteration.events, SendBalanceProof, { 'message_identifier': message_identifier, 'payment_identifier': payment_identifier, })
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_target_lock_is_expired_if_secret_is_not_registered_onchain(): lock_amount = 7 block_number = 1 initiator = factories.HOP6 pseudo_random_generator = random.Random() our_balance = 100 our_address = factories.make_address() partner_balance = 130 from_channel = factories.make_channel( our_address=our_address, our_balance=our_balance, partner_address=UNIT_TRANSFER_SENDER, partner_balance=partner_balance, ) from_route = factories.route_from_channel(from_channel) expiration = block_number + from_channel.settle_timeout - from_channel.reveal_timeout from_transfer = factories.make_signed_transfer_for( from_channel, lock_amount, initiator, our_address, expiration, UNIT_SECRET, ) init = ActionInitTarget( from_route, from_transfer, ) init_transition = target.state_transition( None, init, from_channel, pseudo_random_generator, block_number, ) assert init_transition.new_state is not None secret_reveal_iteration = target.state_transition( target_state=init_transition.new_state, state_change=ReceiveSecretReveal(UNIT_SECRET, from_channel.partner_state.address), channel_state=from_channel, pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) expired_block_number = from_transfer.lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS iteration = target.state_transition( target_state=secret_reveal_iteration.new_state, state_change=Block(expired_block_number, None, None), channel_state=from_channel, pseudo_random_generator=pseudo_random_generator, block_number=expired_block_number, ) assert must_contain_entry(iteration.events, EventUnlockClaimFailed, {})
def test_handle_inittarget_bad_expiration(): """ Init transfer must do nothing if the expiration is bad. """ block_number = 1 amount = 3 initiator = factories.HOP1 target_address = UNIT_TRANSFER_TARGET payment_network_identifier = factories.make_address() from_channel = factories.make_channel( our_address=target_address, partner_address=UNIT_TRANSFER_SENDER, partner_balance=amount, ) from_route = factories.route_from_channel(from_channel) expiration = from_channel.reveal_timeout + block_number + 1 from_transfer = factories.make_signed_transfer_for( from_channel, amount, initiator, target_address, expiration, UNIT_SECRET, ) channel.handle_receive_lockedtransfer( from_channel, from_transfer, ) state_change = ActionInitTarget(payment_network_identifier, from_route, from_transfer) iteration = target.handle_inittarget(state_change, from_channel, block_number) assert must_contain_entry(iteration.events, EventWithdrawFailed, {})
def test_receive_directdtransfer_before_deposit(): """Regression test that ensures that we accept incoming direct transfers, even if we don't have any balance on the channel. """ our_model1, _ = create_model(0) # our deposit is 0 partner_model1, privkey2 = create_model(100) channel_state = create_channel_from_models(our_model1, partner_model1) payment_network_identifier = factories.make_address() nonce = 1 transferred_amount = 30 receive_directtransfer = make_receive_transfer_direct( payment_network_identifier, channel_state, privkey2, nonce, transferred_amount, ) # this node partner has enough balance, the transfer must be accepted iteration = channel.handle_receive_directtransfer( channel_state, receive_directtransfer, ) assert must_contain_entry(iteration.events, EventTransferReceivedSuccess, {})
def test_events_for_onchain_secretreveal(): """ Secret must be registered on-chain when the unsafe region is reached and the secret is known. """ block_number = 10 expiration = block_number + 30 channels = make_channel_set([channel_properties]) from_transfer = make_target_transfer(channels[0], expiration=expiration) channel.handle_receive_lockedtransfer(channels[0], from_transfer) channel.register_offchain_secret(channels[0], UNIT_SECRET, UNIT_SECRETHASH) safe_to_wait = expiration - channels[0].reveal_timeout - 1 unsafe_to_wait = expiration - channels[0].reveal_timeout state = TargetTransferState(channels.get_route(0), from_transfer) events = target.events_for_onchain_secretreveal(state, channels[0], safe_to_wait) assert not events events = target.events_for_onchain_secretreveal(state, channels[0], unsafe_to_wait) msg = 'when its not safe to wait, the contract send must be emitted' assert must_contain_entry(events, ContractSendSecretReveal, {'secret': UNIT_SECRET}), msg msg = 'second call must not emit ContractSendSecretReveal again' assert not target.events_for_onchain_secretreveal(state, channels[0], unsafe_to_wait), msg
def test_channelstate_directtransfer_overspent(): """Receiving a direct transfer with an amount large than distributable must be ignored. """ our_model1, _ = create_model(70) partner_model1, privkey2 = create_model(100) channel_state = create_channel_from_models(our_model1, partner_model1) distributable = channel.get_distributable(channel_state.partner_state, channel_state.our_state) nonce = 1 transferred_amount = distributable + 1 receive_lockedtransfer = make_receive_transfer_direct( channel_state, privkey2, nonce, transferred_amount, ) is_valid, _ = channel.is_valid_directtransfer( receive_lockedtransfer, channel_state, channel_state.partner_state, channel_state.our_state, ) assert not is_valid, 'message is invalid because it is spending more than the distributable' iteration = channel.handle_receive_directtransfer( channel_state, receive_lockedtransfer, ) assert must_contain_entry(iteration.events, EventTransferReceivedInvalidDirectTransfer, {}) assert_partner_state(channel_state.our_state, channel_state.partner_state, our_model1) assert_partner_state(channel_state.partner_state, channel_state.our_state, partner_model1)
def test_initiator_handle_contract_receive_secret_reveal(): """ Initiator must unlock off-chain if the secret is revealed on-chain and the channel is open. """ amount = UNIT_TRANSFER_AMOUNT * 2 channel1 = factories.make_channel( our_balance=amount, token_address=UNIT_TOKEN_ADDRESS, token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS, ) pseudo_random_generator = random.Random() channel_map = { channel1.identifier: channel1, } available_routes = [ factories.route_from_channel(channel1), ] block_number = 10 current_state = make_initiator_manager_state( routes=available_routes, transfer_description=factories.UNIT_TRANSFER_DESCRIPTION, channel_map=channel_map, pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) transfer = current_state.initiator.transfer assert transfer.lock.secrethash in channel1.our_state.secrethashes_to_lockedlocks state_change = ContractReceiveSecretReveal( transaction_hash=factories.make_transaction_hash(), secret_registry_address=factories.make_address(), secrethash=transfer.lock.secrethash, secret=UNIT_SECRET, block_number=transfer.lock.expiration, ) message_identifier = message_identifier_from_prng( deepcopy(pseudo_random_generator)) iteration = initiator_manager.handle_onchain_secretreveal( payment_state=current_state, state_change=state_change, channelidentifiers_to_channels=channel_map, pseudo_random_generator=pseudo_random_generator, ) assert events.must_contain_entry( iteration.events, SendBalanceProof, { 'message_identifier': message_identifier, 'payment_identifier': current_state.initiator.transfer_description.payment_identifier, })
def test_log_directransfer(raiden_chain, token_addresses, deposit): """The action that starts a direct transfer must be logged in the WAL.""" app0, app1 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking 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 = int(deposit / 2.) payment_identifier = 13 direct_transfer( app0, app1, token_network_identifier, amount, payment_identifier, ) app0_state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) assert must_contain_entry( app0_state_changes, ActionTransferDirect, { 'token_network_identifier': token_network_identifier, 'amount': amount, 'receiver_address': app1.raiden.address, }) app1_state_changes = app1.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) assert must_contain_entry( app1_state_changes, ReceiveTransferDirect, { 'token_network_identifier': token_network_identifier, 'payment_identifier': payment_identifier, 'balance_proof': { 'transferred_amount': amount, 'sender': app0.raiden.address, }, })
def test_handle_inittarget(): """ Init transfer must send a secret request if the expiration is valid. """ amount = 3 block_number = 1 initiator = factories.HOP1 target_address = UNIT_TRANSFER_TARGET pseudo_random_generator = random.Random() from_channel = factories.make_channel( our_address=target_address, partner_address=UNIT_TRANSFER_SENDER, partner_balance=amount, ) from_route = factories.route_from_channel(from_channel) expiration = from_channel.reveal_timeout + block_number + 1 from_transfer = factories.make_signed_transfer( amount, initiator, target_address, expiration, UNIT_SECRET, channel_identifier=from_channel.identifier, token_network_address=from_channel.token_network_identifier, ) state_change = ActionInitTarget( from_route, from_transfer, ) iteration = target.handle_inittarget( state_change, from_channel, pseudo_random_generator, block_number, ) assert must_contain_entry( iteration.events, SendSecretRequest, { 'payment_identifier': from_transfer.payment_identifier, 'amount': from_transfer.lock.amount, 'secrethash': from_transfer.lock.secrethash, 'recipient': initiator, }) assert must_contain_entry(iteration.events, SendProcessed, {})
def test_events(amount, address): return must_contain_entry( receiver_app.raiden.wal.storage.get_events(), EventPaymentReceivedSuccess, { 'amount': amount, 'initiator': address }, )
def test_log_directransfer(raiden_chain, token_addresses, deposit): """The action that starts a direct transfer must be logged in the WAL.""" app0, app1 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking 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 = int(deposit / 2.) payment_identifier = 13 direct_transfer( app0, app1, token_network_identifier, amount, payment_identifier, ) app0_state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) assert must_contain_entry(app0_state_changes, ActionTransferDirect, { 'token_network_identifier': token_network_identifier, 'amount': amount, 'receiver_address': app1.raiden.address, }) app1_state_changes = app1.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) assert must_contain_entry(app1_state_changes, ReceiveTransferDirect, { 'token_network_identifier': token_network_identifier, 'payment_identifier': payment_identifier, 'balance_proof': { 'transferred_amount': amount, 'sender': app0.raiden.address, }, })
def test_events(amount, address): events = receiver_app.raiden.wal.storage.get_events_by_block( 0, 'latest') events = [e[1] for e in events] return must_contain_entry( events, EventPaymentReceivedSuccess, { 'amount': amount, 'initiator': address }, )
def test_initiator_handle_contract_receive_after_channel_closed(): """ Initiator must accept on-chain secret reveal if the channel is closed. However, the off-chain unlock must not be done! This will happen because secrets are registered after a channel is closed, during the settlement window. """ block_number = 10 setup = setup_initiator_tests(amount=UNIT_TRANSFER_AMOUNT * 2, block_number=block_number) transfer = setup.current_state.initiator.transfer assert transfer.lock.secrethash in setup.channel.our_state.secrethashes_to_lockedlocks channel_closed = ContractReceiveChannelClosed( transaction_hash=factories.make_transaction_hash(), transaction_from=factories.make_address(), token_network_identifier=setup.channel.token_network_identifier, channel_identifier=setup.channel.identifier, block_number=block_number, ) channel_close_transition = channel.state_transition( channel_state=setup.channel, state_change=channel_closed, pseudo_random_generator=setup.prng, block_number=block_number, ) channel_state = channel_close_transition.new_state state_change = ContractReceiveSecretReveal( transaction_hash=factories.make_transaction_hash(), secret_registry_address=factories.make_address(), secrethash=transfer.lock.secrethash, secret=UNIT_SECRET, block_number=transfer.lock.expiration, ) channel_map = { channel_state.identifier: channel_state, } iteration = initiator_manager.handle_onchain_secretreveal( payment_state=setup.current_state, state_change=state_change, channelidentifiers_to_channels=channel_map, pseudo_random_generator=setup.prng, ) secrethash = setup.current_state.initiator.transfer_description.secrethash assert secrethash in channel_state.our_state.secrethashes_to_onchain_unlockedlocks msg = 'The channel is closed already, the balance proof must not be sent off-chain' assert not events.must_contain_entry(iteration.events, SendBalanceProof, {}), msg
def test_initiator_log_directransfer_success(raiden_chain, token_addresses, deposit): app0, app1 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking token_address = token_addresses[0] amount = int(deposit / 2.) identifier = 7 token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) direct_transfer( app0, app1, token_network_identifier, amount, identifier, ) app0_events = app0.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) app0_all_events = [event for _, event in app0_events] assert must_contain_entry(app0_all_events, EventTransferSentSuccess, { 'identifier': identifier, 'amount': amount, 'target': app1.raiden.address, }) app1_state_events = app1.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) app1_all_events = [event for _, event in app1_state_events] assert must_contain_entry(app1_all_events, EventTransferReceivedSuccess, { 'identifier': identifier, 'amount': amount, 'initiator': app0.raiden.address, })
def wait_for_batch_unlock(app, channel_id, token_network_id): unlock_event = None while not unlock_event: gevent.sleep(1) state_changes = app.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) unlock_event = must_contain_entry(state_changes, ContractReceiveChannelBatchUnlock, { 'channel_identifier': channel_id, 'token_network_identifier': token_network_id, })
def test_handle_inittarget(): """ Init transfer must send a secret request if the expiration is valid. """ block_number = 1 pseudo_random_generator = random.Random() channels = make_channel_set([channel_properties]) transfer_properties = LockedTransferSignedStateProperties( transfer=LockedTransferProperties( amount=channels[0].partner_state.contract_balance, expiration=channels[0].reveal_timeout + block_number + 1, balance_proof=BalanceProofProperties( channel_identifier=channels[0].identifier, token_network_identifier=channels[0].token_network_identifier, transferred_amount=0, locked_amount=channels[0].partner_state.contract_balance, ), ), ) from_transfer = create(transfer_properties) state_change = ActionInitTarget(channels.get_route(0), from_transfer) iteration = target.handle_inittarget( state_change, channels[0], pseudo_random_generator, block_number, ) assert must_contain_entry( iteration.events, SendSecretRequest, { 'payment_identifier': from_transfer.payment_identifier, 'amount': from_transfer.lock.amount, 'secrethash': from_transfer.lock.secrethash, 'recipient': UNIT_TRANSFER_INITIATOR, }) assert must_contain_entry(iteration.events, SendProcessed, {})
def test_handle_inittarget(): """ Init transfer must send a secret request if the expiration is valid. """ block_number = 1 pseudo_random_generator = random.Random() channels = make_channel_set([channel_properties]) transfer_properties = LockedTransferSignedStateProperties( transfer=LockedTransferProperties( amount=channels[0].partner_state.contract_balance, expiration=channels[0].reveal_timeout + block_number + 1, balance_proof=BalanceProofProperties( channel_identifier=channels[0].identifier, token_network_identifier=channels[0].token_network_identifier, transferred_amount=0, locked_amount=channels[0].partner_state.contract_balance, ), ), ) from_transfer = create(transfer_properties) state_change = ActionInitTarget(channels.get_route(0), from_transfer) iteration = target.handle_inittarget( state_change, channels[0], pseudo_random_generator, block_number, ) assert must_contain_entry(iteration.events, SendSecretRequest, { 'payment_identifier': from_transfer.payment_identifier, 'amount': from_transfer.lock.amount, 'secrethash': from_transfer.lock.secrethash, 'recipient': UNIT_TRANSFER_INITIATOR, }) assert must_contain_entry(iteration.events, SendProcessed, {})
def test_mediated_transfer_events(raiden_network, token_addresses, network_wait): network_wait *= 1.4 app0, app1, app2 = raiden_network token_address = token_addresses[0] node_state = views.state_from_app(app0) payment_network_id = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( node_state, payment_network_id, token_address, ) amount = 10 mediated_transfer( app0, app2, token_network_identifier, amount, timeout=network_wait, ) initiator_blockevents = app0.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) initiator_events = [ blocknumber_event[1] for blocknumber_event in initiator_blockevents ] assert must_contain_entry(initiator_events, SendRevealSecret, {}) assert must_contain_entry(initiator_events, EventUnlockSuccess, {}) mediator_blockevents = app1.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) mediator_events = [ blocknumber_event[1] for blocknumber_event in mediator_blockevents ] assert must_contain_entry(mediator_events, EventUnlockSuccess, {}) assert must_contain_entry(mediator_events, EventUnlockClaimSuccess, {}) target_blockevents = app2.raiden.wal.storage.get_events_by_identifier( from_identifier=0, to_identifier='latest', ) target_events = [ blocknumber_event[1] for blocknumber_event in target_blockevents ] assert must_contain_entry(target_events, SendSecretRequest, {}) assert must_contain_entry(target_events, SendRevealSecret, {}) assert must_contain_entry(target_events, EventUnlockClaimSuccess, {})
def wait_for_batch_unlock(app, token_network_id, participant, partner): unlock_event = None while not unlock_event: gevent.sleep(1) state_changes = app.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) unlock_event = must_contain_entry(state_changes, ContractReceiveChannelBatchUnlock, { 'token_network_identifier': token_network_id, 'participant': participant, 'partner': partner, })
def test_regression_revealsecret_after_secret(raiden_network, token_addresses, transport_protocol): """ A RevealSecret message received after a Secret message must be cleanly handled. """ app0, app1, app2 = raiden_network token = token_addresses[0] identifier = 1 payment_network_identifier = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), payment_network_identifier, token, ) transfer = app0.raiden.mediated_transfer_async( token_network_identifier, amount=1, target=app2.raiden.address, identifier=identifier, ) assert transfer.wait() event = must_contain_entry( app1.raiden.wal.storage.get_events(), SendSecretReveal, {}, ) assert event message_identifier = random.randint(0, UINT64_MAX) reveal_secret = RevealSecret( message_identifier, event.secret, ) app2.raiden.sign(reveal_secret) if transport_protocol is TransportProtocol.UDP: reveal_data = reveal_secret.encode() host_port = None app1.raiden.transport.receive(reveal_data, host_port) elif transport_protocol is TransportProtocol.MATRIX: app1.raiden.transport._receive_message(reveal_secret) # pylint: disable=protected-access else: raise TypeError('Unknown TransportProtocol')
def test_handle_inittarget_bad_expiration(): """ Init transfer must do nothing if the expiration is bad. """ block_number = 1 pseudo_random_generator = random.Random() channels = make_channel_set([channel_properties]) expiration = channels[0].reveal_timeout + block_number + 1 from_transfer = make_target_transfer(channels[0], expiration=expiration) channel.handle_receive_lockedtransfer(channels[0], from_transfer) state_change = ActionInitTarget(channels.get_route(0), from_transfer) iteration = target.handle_inittarget( state_change, channels[0], pseudo_random_generator, block_number, ) assert must_contain_entry(iteration.events, EventUnlockClaimFailed, {})
def test_handle_offchain_secretreveal(): setup = setup_initiator_tests() secret_reveal = ReceiveSecretReveal( secret=UNIT_SECRET, sender=setup.channel.partner_state.address, ) message_identifier = message_identifier_from_prng(deepcopy(setup.prng)) iteration = initiator.handle_offchain_secretreveal( initiator_state=setup.current_state.initiator, state_change=secret_reveal, channel_state=setup.channel, pseudo_random_generator=setup.prng, ) payment_identifier = setup.current_state.initiator.transfer_description.payment_identifier assert events.must_contain_entry(iteration.events, SendBalanceProof, { 'message_identifier': message_identifier, 'payment_identifier': payment_identifier, })
def test_handle_inittarget_bad_expiration(): """ Init transfer must do nothing if the expiration is bad. """ block_number = 1 amount = 3 initiator = factories.HOP1 target_address = UNIT_TRANSFER_TARGET pseudo_random_generator = random.Random() from_channel = factories.make_channel( our_address=target_address, partner_address=UNIT_TRANSFER_SENDER, partner_balance=amount, ) from_route = factories.route_from_channel(from_channel) expiration = from_channel.reveal_timeout + block_number + 1 from_transfer = factories.make_signed_transfer_for( from_channel, amount, initiator, target_address, expiration, UNIT_SECRET, ) channel.handle_receive_lockedtransfer( from_channel, from_transfer, ) state_change = ActionInitTarget(from_route, from_transfer) iteration = target.handle_inittarget( state_change, from_channel, pseudo_random_generator, block_number, ) assert must_contain_entry(iteration.events, EventUnlockClaimFailed, {})
def test_initiator_lock_expired_must_not_be_sent_if_channel_is_closed(): """ If the channel is closed there is no rason to send balance proofs off-chain, so a remove expired lock must not be sent when the channel is closed. """ block_number = 10 setup = setup_initiator_tests(amount=UNIT_TRANSFER_AMOUNT * 2, block_number=block_number) channel_closed = ContractReceiveChannelClosed( transaction_hash=factories.make_transaction_hash(), transaction_from=factories.make_address(), token_network_identifier=setup.channel.token_network_identifier, channel_identifier=setup.channel.identifier, block_number=block_number, ) channel_close_transition = channel.state_transition( channel_state=setup.channel, state_change=channel_closed, pseudo_random_generator=setup.prng, block_number=block_number, ) channel_state = channel_close_transition.new_state expiration_block_number = channel.get_sender_expiration_threshold(setup.lock) block = Block( block_number=expiration_block_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) channel_map = {channel_state.identifier: channel_state} iteration = initiator_manager.state_transition( setup.current_state, block, channel_map, setup.prng, expiration_block_number, ) assert events.must_contain_entry(iteration.events, SendLockExpired, {}) is None
def test_target_lock_is_expired_if_secret_is_not_registered_onchain(): lock_amount = 7 block_number = 1 pseudo_random_generator = random.Random() channels = make_channel_set([channel_properties2]) from_transfer = make_target_transfer(channels[0], amount=lock_amount, block_number=1) init = ActionInitTarget(channels.get_route(0), from_transfer) init_transition = target.state_transition( target_state=None, state_change=init, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) assert init_transition.new_state is not None secret_reveal_iteration = target.state_transition( target_state=init_transition.new_state, state_change=ReceiveSecretReveal(UNIT_SECRET, channels[0].partner_state.address), channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) expired_block_number = channel.get_receiver_expiration_threshold(from_transfer.lock) iteration = target.state_transition( target_state=secret_reveal_iteration.new_state, state_change=Block(expired_block_number, None, None), channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=expired_block_number, ) assert must_contain_entry(iteration.events, EventUnlockClaimFailed, {})
def has_initiator_events(): initiator_events = app0.raiden.wal.storage.get_events() return must_contain_entry(initiator_events, SendLockedTransfer, {})
def test_target_receive_lock_expired(): lock_amount = 7 block_number = 1 pseudo_random_generator = random.Random() channels = make_channel_set([channel_properties2]) expiration = block_number + channels[0].settle_timeout - channels[0].reveal_timeout from_transfer = make_target_transfer( channels[0], amount=lock_amount, block_number=block_number, ) init = ActionInitTarget(channels.get_route(0), from_transfer) init_transition = target.state_transition( target_state=None, state_change=init, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) assert init_transition.new_state is not None assert init_transition.new_state.route == channels.get_route(0) assert init_transition.new_state.transfer == from_transfer balance_proof = create(BalanceProofSignedStateProperties( balance_proof=BalanceProofProperties( nonce=2, transferred_amount=from_transfer.balance_proof.transferred_amount, locked_amount=0, token_network_identifier=from_transfer.balance_proof.token_network_identifier, channel_identifier=channels[0].identifier, ), message_hash=from_transfer.lock.secrethash, )) lock_expired_state_change = ReceiveLockExpired( balance_proof=balance_proof, secrethash=from_transfer.lock.secrethash, message_identifier=1, ) block_before_confirmed_expiration = expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS - 1 iteration = target.state_transition( target_state=init_transition.new_state, state_change=lock_expired_state_change, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_before_confirmed_expiration, ) assert not must_contain_entry(iteration.events, SendProcessed, {}) block_lock_expired = block_before_confirmed_expiration + 1 iteration = target.state_transition( target_state=init_transition.new_state, state_change=lock_expired_state_change, channel_state=channels[0], pseudo_random_generator=pseudo_random_generator, block_number=block_lock_expired, ) assert must_contain_entry(iteration.events, SendProcessed, {})
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_recovery_blockchain_events( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, skip_if_not_udp, ): """ Close one of the two raiden apps that have a channel between them, have the counterparty close the channel and then make sure the restarted app sees the change """ app0, app1 = raiden_network token_address = token_addresses[0] app0.raiden.stop() host_port = ( app0.raiden.config['transport']['udp']['host'], app0.raiden.config['transport']['udp']['port'], ) socket = server._udp_socket(host_port) new_transport = UDPTransport( app0.raiden.address, app0.discovery, socket, app0.raiden.transport.throttle_policy, app0.raiden.config['transport']['udp'], ) app1_api = RaidenAPI(app1.raiden) app1_api.channel_close( registry_address=app0.raiden.default_registry.address, token_address=token_address, partner_address=app0.raiden.address, ) app0.stop() import gevent gevent.sleep(1) raiden_event_handler = RaidenEventHandler() message_handler = MessageHandler() app0_restart = App( config=app0.config, chain=app0.raiden.chain, query_start_block=0, default_registry=app0.raiden.default_registry, default_secret_registry=app0.raiden.default_secret_registry, transport=new_transport, raiden_event_handler=raiden_event_handler, message_handler=message_handler, discovery=app0.raiden.discovery, ) del app0 # from here on the app0_restart should be used app0_restart.raiden.start() # wait for the nodes' healthcheck to update the network statuses waiting.wait_for_healthy( app0_restart.raiden, app1.raiden.address, network_wait, ) waiting.wait_for_healthy( app1.raiden, app0_restart.raiden.address, network_wait, ) restarted_state_changes = app0_restart.raiden.wal.storage.get_statechanges_by_identifier( 0, 'latest', ) assert must_contain_entry(restarted_state_changes, ContractReceiveChannelClosed, {})
def test_recovery_unhappy_case( raiden_network, number_of_nodes, deposit, token_addresses, network_wait, skip_if_not_udp, retry_timeout, ): app0, app1, app2 = raiden_network token_address = token_addresses[0] chain_state = views.state_from_app(app0) payment_network_id = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( chain_state, payment_network_id, token_address, ) # make a few transfers from app0 to app2 amount = 1 spent_amount = deposit - 2 for _ in range(spent_amount): mediated_transfer( app0, app2, token_network_identifier, amount, timeout=network_wait * number_of_nodes, ) app0.raiden.stop() host_port = ( app0.raiden.config['transport']['udp']['host'], app0.raiden.config['transport']['udp']['port'], ) socket = server._udp_socket(host_port) new_transport = UDPTransport( app0.raiden.address, app0.discovery, socket, app0.raiden.transport.throttle_policy, app0.raiden.config['transport']['udp'], ) app0.stop() RaidenAPI(app1.raiden).channel_close( app1.raiden.default_registry.address, token_address, app0.raiden.address, ) channel01 = views.get_channelstate_for( views.state_from_app(app1), app1.raiden.default_registry.address, token_address, app0.raiden.address, ) waiting.wait_for_settle( app1.raiden, app1.raiden.default_registry.address, token_address, [channel01.identifier], retry_timeout, ) raiden_event_handler = RaidenEventHandler() message_handler = MessageHandler() app0_restart = App( config=app0.config, chain=app0.raiden.chain, query_start_block=0, default_registry=app0.raiden.default_registry, default_secret_registry=app0.raiden.default_secret_registry, transport=new_transport, raiden_event_handler=raiden_event_handler, message_handler=message_handler, discovery=app0.raiden.discovery, ) del app0 # from here on the app0_restart should be used app0_restart.start() state_changes = app0_restart.raiden.wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) assert must_contain_entry(state_changes, ContractReceiveChannelSettled, { 'token_network_identifier': token_network_identifier, 'channel_identifier': channel01.identifier, })