def test_events_for_onchain_secretreveal_with_unfit_channels(): settle = factories.TransactionExecutionStatusProperties() settled = factories.create( factories.NettingChannelStateProperties(settle_transaction=settle)) secret = factories.UNIT_SECRET block_hash = factories.make_block_hash() events = events_for_onchain_secretreveal(settled, secret, 10, block_hash) assert not events, "Secret reveal event should not be generated for settled channel" settle = factories.replace(settle, result=TransactionExecutionStatus.FAILURE) unusable = factories.create( factories.NettingChannelStateProperties(settle_transaction=settle)) events = events_for_onchain_secretreveal(unusable, secret, 10, block_hash) assert not events, "Secret reveal event should not be generated for unusable channel."
def test_mediator_skips_used_routes(): prng = random.Random() block_number = 3 defaults = factories.NettingChannelStateProperties( our_state=factories.NettingChannelEndStateProperties.OUR_STATE, partner_state=factories.NettingChannelEndStateProperties( balance=UNIT_TRANSFER_AMOUNT), open_transaction=factories.TransactionExecutionStatusProperties( started_block_number=1, finished_block_number=2, result="success"), ) properties = [ factories.NettingChannelStateProperties( partner_state=factories.NettingChannelEndStateProperties( privatekey=factories.HOP1_KEY, address=factories.HOP1)), factories.NettingChannelStateProperties( partner_state=factories.NettingChannelEndStateProperties( privatekey=factories.HOP2_KEY, address=factories.HOP2)), factories.NettingChannelStateProperties( partner_state=factories.NettingChannelEndStateProperties( privatekey=factories.HOP3_KEY, address=factories.HOP3)), ] channels = factories.make_channel_set(properties=properties, number_of_channels=3, defaults=defaults) bob = channels.channels[1].partner_state.address charlie = channels.channels[2].partner_state.address dave = factories.make_address() eric = factories.make_address() locked_transfer = factories.create( factories.LockedTransferSignedStateProperties( expiration=10, routes=[ [ factories.UNIT_OUR_ADDRESS, bob, dave, factories.UNIT_TRANSFER_TARGET ], [ factories.UNIT_OUR_ADDRESS, bob, eric, factories.UNIT_TRANSFER_TARGET ], [ factories.UNIT_OUR_ADDRESS, charlie, eric, factories.UNIT_TRANSFER_TARGET ], ], canonical_identifier=channels.channels[0].canonical_identifier, pkey=factories.HOP1_KEY, sender=factories.HOP1, )) init_action = factories.mediator_make_init_action(channels=channels, transfer=locked_transfer) nodeaddresses_to_networkstates = { channel.partner_state.address: NetworkState.REACHABLE for channel in channels.channels } transition_result = mediator.handle_init( state_change=init_action, channelidentifiers_to_channels=channels.channel_map, nodeaddresses_to_networkstates=nodeaddresses_to_networkstates, pseudo_random_generator=prng, block_number=block_number, ) mediator_state = transition_result.new_state events = transition_result.events assert mediator_state is not None assert events assert len(mediator_state.routes) == 3 assert mediator_state.routes[0].route[1] == bob assert mediator_state.routes[1].route[1] == bob assert mediator_state.routes[2].route[1] == charlie # now we receive a refund from whoever we forwarded to (should be HOP2) assert isinstance(events[-1], SendLockedTransfer) assert events[-1].recipient == factories.HOP2 last_pair = mediator_state.transfers_pair[-1] canonical_identifier = last_pair.payee_transfer.balance_proof.canonical_identifier lock_expiration = last_pair.payee_transfer.lock.expiration payment_identifier = last_pair.payee_transfer.payment_identifier received_transfer = factories.create( factories.LockedTransferSignedStateProperties( expiration=lock_expiration, payment_identifier=payment_identifier, canonical_identifier=canonical_identifier, sender=factories.HOP2, pkey=factories.HOP2_KEY, message_identifier=factories.make_message_identifier(), )) refund_state_change = ReceiveTransferRefund( transfer=received_transfer, balance_proof=received_transfer.balance_proof, sender=received_transfer.balance_proof.sender, # pylint: disable=no-member ) transition_result = mediator.handle_refundtransfer( mediator_state=mediator_state, mediator_state_change=refund_state_change, channelidentifiers_to_channels=channels.channel_map, nodeaddresses_to_networkstates=nodeaddresses_to_networkstates, pseudo_random_generator=prng, block_number=block_number, ) mediator_state = transition_result.new_state events = transition_result.events assert mediator_state is not None assert events assert mediator_state.transfers_pair[-1].payee_address == charlie # now we should have a forward transfer to HOP3 assert isinstance(events[-1], SendLockedTransfer) assert events[-1].recipient == factories.HOP3 # now we will receive a refund from HOP3 last_pair = mediator_state.transfers_pair[-1] canonical_identifier = last_pair.payee_transfer.balance_proof.canonical_identifier lock_expiration = last_pair.payee_transfer.lock.expiration payment_identifier = last_pair.payee_transfer.payment_identifier received_transfer = factories.create( factories.LockedTransferSignedStateProperties( expiration=lock_expiration, payment_identifier=payment_identifier, canonical_identifier=canonical_identifier, sender=factories.HOP3, pkey=factories.HOP3_KEY, message_identifier=factories.make_message_identifier(), )) refund_state_change = ReceiveTransferRefund( transfer=received_transfer, balance_proof=received_transfer.balance_proof, sender=received_transfer.balance_proof.sender, # pylint: disable=no-member ) transition_result = mediator.handle_refundtransfer( mediator_state=mediator_state, mediator_state_change=refund_state_change, channelidentifiers_to_channels=channels.channel_map, nodeaddresses_to_networkstates=nodeaddresses_to_networkstates, pseudo_random_generator=prng, block_number=block_number, ) mediator_state = transition_result.new_state events = transition_result.events assert mediator_state is not None assert events # no other routes available, so refund HOP1 assert isinstance(events[-1], SendRefundTransfer) assert events[-1].recipient == factories.HOP1
def test_initiator_skips_used_routes(): defaults = factories.NettingChannelStateProperties( our_state=factories.NettingChannelEndStateProperties.OUR_STATE, partner_state=factories.NettingChannelEndStateProperties(balance=10), open_transaction=factories.TransactionExecutionStatusProperties( started_block_number=1, finished_block_number=2, result="success"), ) properties = [ factories.NettingChannelStateProperties( partner_state=factories.NettingChannelEndStateProperties( privatekey=factories.HOP1_KEY, address=factories.HOP1)) ] test_chain_state = factories.make_chain_state(number_of_channels=1, properties=properties, defaults=defaults) channels = test_chain_state.channel_set bob = channels.channels[0].partner_state.address routes = [[ factories.UNIT_OUR_ADDRESS, bob, factories.UNIT_TRANSFER_TARGET ]] transfer = factories.create( factories.TransferDescriptionProperties( initiator=factories.UNIT_OUR_ADDRESS, target=factories.UNIT_TRANSFER_TARGET)) init_action = factories.initiator_make_init_action( channels=channels, routes=routes, transfer=transfer, estimated_fee=FeeAmount(0)) transition_result = handle_action_init_initiator( chain_state=test_chain_state.chain_state, state_change=init_action) chain_state = transition_result.new_state assert transfer.secrethash in chain_state.payment_mapping.secrethashes_to_task initiator_task = chain_state.payment_mapping.secrethashes_to_task[ transfer.secrethash] initiator_state = initiator_task.manager_state assert len(initiator_state.routes) == 1, "Should have one route" assert len( initiator_state.routes[0].route) == 3, "Route should not be pruned" assert initiator_state.routes[0].route == routes[ 0], "Should have test route" events = transition_result.events assert isinstance(events[-1], SendLockedTransfer) locked_transfer = initiator_state.initiator_transfers[ transfer.secrethash].transfer received_transfer = factories.create( factories.LockedTransferSignedStateProperties( expiration=locked_transfer.lock.expiration, payment_identifier=locked_transfer.payment_identifier, canonical_identifier=locked_transfer.balance_proof. canonical_identifier, initiator=factories.UNIT_OUR_ADDRESS, sender=bob, pkey=factories.HOP1_KEY, message_identifier=factories.make_message_identifier(), routes=[], secret=transfer.secret, )) role = views.get_transfer_role(chain_state=chain_state, secrethash=locked_transfer.lock.secrethash) assert role == "initiator", "Should keep initiator role" failed_route_state_change = ReceiveTransferCancelRoute( transfer=received_transfer, balance_proof=received_transfer.balance_proof, sender=received_transfer.balance_proof.sender, # pylint: disable=no-member ) state_transition(chain_state=chain_state, state_change=failed_route_state_change) reroute_state_change = ActionTransferReroute( transfer=received_transfer, balance_proof=received_transfer.balance_proof, sender=received_transfer.balance_proof.sender, # pylint: disable=no-member secret=factories.make_secret(), ) iteration = state_transition(chain_state=chain_state, state_change=reroute_state_change) assert search_for_item(iteration.events, SendLockedTransfer, {}) is None