def get_capacity_update_message( # pylint: disable=too-many-arguments updating_participant: Address, other_participant: Address, chain_id=ChainID(61), channel_identifier=DEFAULT_CHANNEL_ID, token_network_address: TokenNetworkAddress = DEFAULT_TOKEN_NETWORK_ADDRESS, updating_nonce=Nonce(1), other_nonce=Nonce(0), updating_capacity=TA(90), other_capacity=TA(110), reveal_timeout: BlockTimeout = BlockTimeout(2), privkey_signer: bytes = PRIVATE_KEY_1, ) -> PFSCapacityUpdate: updatepfs_message = PFSCapacityUpdate( canonical_identifier=CanonicalIdentifier( chain_identifier=chain_id, channel_identifier=channel_identifier, token_network_address=token_network_address, ), updating_participant=updating_participant, other_participant=other_participant, updating_nonce=updating_nonce, other_nonce=other_nonce, updating_capacity=updating_capacity, other_capacity=other_capacity, reveal_timeout=reveal_timeout, signature=EMPTY_SIGNATURE, ) updatepfs_message.sign(LocalSigner(privkey_signer)) return updatepfs_message
def test_pfs_rejects_capacity_update_with_impossible_other_capacity( pathfinding_service_web3_mock: PathfindingService, ): setup_channel(pathfinding_service_web3_mock) message = get_capacity_update_message( updating_participant=PRIVATE_KEY_1_ADDRESS, other_participant=PRIVATE_KEY_2_ADDRESS, other_capacity=TA(UINT256_MAX), privkey_signer=PRIVATE_KEY_1, ) message.other_capacity = TA(UINT256_MAX + 1) with pytest.raises(InvalidCapacityUpdate) as exinfo: pathfinding_service_web3_mock.on_capacity_update(message) assert "with impossible other_capacity" in str(exinfo.value)
def __init__(self, channels: List[dict], default_capacity: TA = TA(1000)): super().__init__( token_network_address=TokenNetworkAddress(a(255)), settle_timeout=DEFAULT_TOKEN_NETWORK_SETTLE_TIMEOUT, ) # open channels channel_ids = itertools.count(100) for chan in channels: self.handle_channel_opened_event( channel_identifier=ChannelID(next(channel_ids)), participant1=a(chan["participant1"]), participant2=a(chan["participant2"]), ) cv1: ChannelView = self.G[a(chan["participant1"])][a( chan["participant2"])]["view"] cv1.capacity = chan.get("capacity1", default_capacity) cv2: ChannelView = self.G[a(chan["participant2"])][a( chan["participant1"])]["view"] cv2.capacity = chan.get("capacity2", default_capacity) # create reachability mapping for testing self.reachability_state = SimpleReachabilityContainer( {node: AddressReachability.REACHABLE for node in self.G.nodes})
def test_regression_issue_554(): """Regression test for https://github.com/raiden-network/raiden-services/issues/554""" tn = TokenNetworkForTests(channels=[ dict(participant1=1, participant2=2, capacity1=100, capacity2=0), dict(participant1=2, participant2=3, capacity1=100, capacity2=0), ]) tn.set_fee(2, 1, imbalance_penalty=[(TA(0), FA(20)), (TA(100), FA(0))]) assert tn.estimate_fee(1, 3) is not None capacity = TA(100_000) tn2 = TokenNetworkForTests(channels=[ dict(participant1=1, participant2=2, capacity1=capacity, capacity2=0), dict(participant1=2, participant2=3, capacity1=capacity, capacity2=0), ]) tn2.set_fee(2, 1, imbalance_penalty=[(TA(0), FA(1000)), (capacity // 2, 0), (capacity, FA(1000))]) assert tn2.estimate_fee(1, 3, value=PA(10_000)) is not None
def test_pfs_min_calculation_with_capacity_updates( pathfinding_service_web3_mock: PathfindingService, ): token_network = setup_channel(pathfinding_service_web3_mock) view_to_partner, view_from_partner = token_network.get_channel_views_for_partner( updating_participant=PRIVATE_KEY_1_ADDRESS, other_participant=PRIVATE_KEY_2_ADDRESS) message1 = get_capacity_update_message( updating_participant=PRIVATE_KEY_1_ADDRESS, other_participant=PRIVATE_KEY_2_ADDRESS, privkey_signer=PRIVATE_KEY_1, updating_capacity=TA(90), other_capacity=TA(110), ) pathfinding_service_web3_mock.on_capacity_update(message1) # Now the channel capacities are set to 0, since only P1 sent an update assert view_to_partner.capacity == 0 assert view_from_partner.capacity == 0 # We need two Capacity Updates, one from each side to set the capacities due to min calculation message2 = get_capacity_update_message( updating_participant=PRIVATE_KEY_2_ADDRESS, other_participant=PRIVATE_KEY_1_ADDRESS, privkey_signer=PRIVATE_KEY_2, updating_capacity=TA(110), other_capacity=TA(90), ) pathfinding_service_web3_mock.on_capacity_update(message2) # Now after both participants have sent Capacity Updates, we have the correct capacities assert view_to_partner.capacity == 90 assert view_from_partner.capacity == 110 # Now P1 sends the same update again, the capacities should not change (no need for nonces) pathfinding_service_web3_mock.on_capacity_update(message1) assert view_to_partner.capacity == 90 assert view_from_partner.capacity == 110 # Now P1 tries to cheat and lies about his own capacity (10000) to mediate more message3 = get_capacity_update_message( updating_participant=PRIVATE_KEY_1_ADDRESS, other_participant=PRIVATE_KEY_2_ADDRESS, privkey_signer=PRIVATE_KEY_1, updating_capacity=TA(10000), other_capacity=TA(110), ) pathfinding_service_web3_mock.on_capacity_update(message3) # The capacities should be calculated out of the minimum of the two capacity updates, # so stay the same assert view_to_partner.capacity == 90 assert view_from_partner.capacity == 110 # Now P1 tries to cheat and lies about his partner's capacity (0) to block him message4 = get_capacity_update_message( updating_participant=PRIVATE_KEY_1_ADDRESS, other_participant=PRIVATE_KEY_2_ADDRESS, privkey_signer=PRIVATE_KEY_1, updating_capacity=TA(90), other_capacity=TA(0), ) pathfinding_service_web3_mock.on_capacity_update(message4) # The capacities should be calculated out of the minimum of the two capacity updates, # he can block his partner assert view_to_partner.capacity == 90 assert view_from_partner.capacity == 0 # Now P1 tries to cheat and lies about his partner's capacity (10000) for no obvious reason message4 = get_capacity_update_message( updating_participant=PRIVATE_KEY_1_ADDRESS, other_participant=PRIVATE_KEY_2_ADDRESS, privkey_signer=PRIVATE_KEY_1, updating_capacity=TA(90), other_capacity=TA(10000), ) pathfinding_service_web3_mock.on_capacity_update(message4) # The capacities should be calculated out of the minimum of the two capacity updates assert view_to_partner.capacity == 90 assert view_from_partner.capacity == 110
def test_fees_in_unbalanced_routing(): # pylint: disable=too-many-statements """Tests fee estimation in a network where only one participant has funds in a channel.""" tn = TokenNetworkForTests(channels=[ dict(participant1=1, participant2=2, capacity1=1000, capacity2=0), dict(participant1=2, participant2=3, capacity1=1000, capacity2=0), ]) # Make sure that routing works and the default fees are zero assert tn.estimate_fee(1, 3) == 0 # Fees for the initiator are ignored tn.set_fee(1, 2, flat=FA(1)) assert tn.estimate_fee(1, 3) == 0 # Node 2 demands fees for incoming transfers tn.set_fee(2, 1, flat=FA(1)) assert tn.estimate_fee(1, 3) == 1 # Node 2 demands fees for outgoing transfers tn.set_fee(2, 3, flat=FA(1)) assert tn.estimate_fee(1, 3) == 2 # No capacity in the opposite direction assert tn.estimate_fee(3, 1) is None # Reset fees to zero tn.set_fee(1, 2) tn.set_fee(2, 1) tn.set_fee(2, 3) # Let's try imbalance fees! # When approximation iterations matter, those are given as sums of the steps. # Incoming channel # Without fee capping tn.set_fee(2, 3, cap_fees=False) tn.set_fee(2, 1, imbalance_penalty=[(TA(0), FA(0)), (TA(1000), FA(100))], cap_fees=False) assert tn.estimate_fee(1, 3) == 10 + 1 assert tn.estimate_fee(3, 1) is None # no balance in channel # With fee capping tn.set_fee(2, 3, cap_fees=True) tn.set_fee(2, 1, imbalance_penalty=[(TA(0), FA(0)), (TA(1000), FA(100))], cap_fees=True) assert tn.estimate_fee(1, 3) == 10 + 1 assert tn.estimate_fee(3, 1) is None # no balance in channel # The opposite fee schedule should give opposite results, without fee capping tn.set_fee(2, 3, cap_fees=False) tn.set_fee(2, 1, imbalance_penalty=[(TA(0), FA(100)), (TA(1000), FA(0))], cap_fees=False) assert tn.estimate_fee(1, 3) == -10 + 1 assert tn.estimate_fee(3, 1) is None # no balance in channel # Or zero with fee capping tn.set_fee(2, 3, cap_fees=True) tn.set_fee(2, 1, imbalance_penalty=[(TA(0), FA(100)), (TA(1000), FA(0))], cap_fees=True) assert tn.estimate_fee(1, 3) == 0 assert tn.estimate_fee(3, 1) is None # no balance in channel # Outgoing channel # Without fee capping tn.set_fee(2, 1, cap_fees=False) tn.set_fee(2, 3, imbalance_penalty=[(TA(0), FA(0)), (TA(1000), FA(100))], cap_fees=False) assert tn.estimate_fee(1, 3) == -10 assert tn.estimate_fee(3, 1) is None # no balance in channel # With fee capping tn.set_fee(2, 1, cap_fees=True) tn.set_fee(2, 3, imbalance_penalty=[(TA(0), FA(0)), (TA(1000), FA(100))], cap_fees=True) assert tn.estimate_fee(1, 3) == 0 assert tn.estimate_fee(3, 1) is None # no balance in channel # The opposite fee schedule should give opposite results tn.set_fee(2, 3, imbalance_penalty=[(TA(0), FA(100)), (TA(1000), FA(0))]) assert tn.estimate_fee(1, 3) == 10 assert tn.estimate_fee(3, 1) is None # no balance in channel # Combined fees cancel out # Works without fee capping tn.set_fee(2, 1, imbalance_penalty=[(TA(0), FA(0)), (TA(1000), FA(20))], cap_fees=False) tn.set_fee(2, 3, imbalance_penalty=[(TA(0), FA(0)), (TA(1000), FA(20))], cap_fees=False) assert tn.estimate_fee(1, 3) == 0 assert tn.estimate_fee(3, 1) is None # no balance in channel # With fee capping fees cancel out as well tn.set_fee(2, 1, imbalance_penalty=[(TA(0), FA(0)), (TA(1000), FA(20))], cap_fees=True) tn.set_fee(2, 3, imbalance_penalty=[(TA(0), FA(0)), (TA(1000), FA(20))], cap_fees=True) assert tn.estimate_fee(1, 3) == 0 assert tn.estimate_fee(3, 1) is None # no balance in channel # Works without fee capping tn.set_fee(2, 1, imbalance_penalty=[(TA(0), FA(20)), (TA(1000), FA(0))], cap_fees=False) tn.set_fee(2, 3, imbalance_penalty=[(TA(0), FA(20)), (TA(1000), FA(0))], cap_fees=False) assert tn.estimate_fee(1, 3) == 0 assert tn.estimate_fee(3, 1) is None # no balance in channel # With fee capping fees cancel out as well tn.set_fee(2, 1, imbalance_penalty=[(TA(0), FA(20)), (TA(1000), FA(0))], cap_fees=True) tn.set_fee(2, 3, imbalance_penalty=[(TA(0), FA(20)), (TA(1000), FA(0))], cap_fees=True) assert tn.estimate_fee(1, 3) == 0 assert tn.estimate_fee(3, 1) is None # no balance in channel # When the range covered by the imbalance_penalty does include the # necessary balance values, the route should be considered invalid. tn.set_fee(2, 3, imbalance_penalty=[(TA(0), FA(0)), (TA(80), FA(200))]) assert tn.estimate_fee(1, 3) is None
def test_fees_in_balanced_routing(): # pylint: disable=too-many-statements """Tests fee estimation in a network where both participants have funds in a channel.""" tn = TokenNetworkForTests(channels=[ dict(participant1=1, participant2=2), dict(participant1=2, participant2=3) ]) # Make sure that routing works and the default fees are zero assert tn.estimate_fee(1, 3) == 0 # Fees for the initiator are ignored tn.set_fee(1, 2, flat=FA(1)) assert tn.estimate_fee(1, 3) == 0 # Node 2 demands fees for incoming transfers tn.set_fee(2, 1, flat=FA(1)) assert tn.estimate_fee(1, 3) == 1 # Node 2 demands fees for outgoing transfers tn.set_fee(2, 3, flat=FA(1)) assert tn.estimate_fee(1, 3) == 2 # Same fee in the opposite direction assert tn.estimate_fee(3, 1) == 2 # Reset fees to zero tn.set_fee(1, 2) tn.set_fee(2, 1) tn.set_fee(2, 3) # Let's try imbalance fees # When the fees influence the amount strong that fee(amount) != fee(amount + fee) # the difference is given as an additional summand. # Incoming channel # Without fee capping tn.set_fee(2, 3, cap_fees=False) tn.set_fee(2, 1, imbalance_penalty=[(TA(0), FA(0)), (TA(2000), FA(200))], cap_fees=False) assert tn.estimate_fee(1, 3) == 10 + 1 assert tn.estimate_fee(3, 1) == -10 # With fee capping tn.set_fee(2, 3, cap_fees=True) tn.set_fee(2, 1, imbalance_penalty=[(TA(0), FA(0)), (TA(2000), FA(200))], cap_fees=True) assert tn.estimate_fee(1, 3) == 10 + 1 assert tn.estimate_fee(3, 1) == 0 # The opposite fee schedule should give opposite results # Without fee capping tn.set_fee(2, 3, cap_fees=False) tn.set_fee(2, 1, imbalance_penalty=[(TA(0), FA(200)), (TA(2000), FA(0))], cap_fees=False) assert tn.estimate_fee(1, 3) == -10 + 1 assert tn.estimate_fee(3, 1) == 10 # With fee capping tn.set_fee(2, 3, cap_fees=True) tn.set_fee(2, 1, imbalance_penalty=[(TA(0), FA(200)), (TA(2000), FA(0))], cap_fees=True) assert tn.estimate_fee(1, 3) == 0 assert tn.estimate_fee(3, 1) == 10 # Outgoing channel # Without fee capping tn.set_fee(2, 1, cap_fees=False) tn.set_fee(2, 3, imbalance_penalty=[(TA(0), FA(0)), (TA(2000), FA(200))], cap_fees=False) assert tn.estimate_fee(1, 3) == -10 assert tn.estimate_fee(3, 1) == 10 + 1 # With fee capping tn.set_fee(2, 1, cap_fees=True) tn.set_fee(2, 3, imbalance_penalty=[(TA(0), FA(0)), (TA(2000), FA(200))], cap_fees=True) assert tn.estimate_fee(1, 3) == 0 assert tn.estimate_fee(3, 1) == 10 + 1 # The opposite fee schedule should give opposite results # Without fee capping tn.set_fee(2, 1, cap_fees=False) tn.set_fee(2, 3, imbalance_penalty=[(TA(0), FA(200)), (TA(2000), FA(0))], cap_fees=False) assert tn.estimate_fee(1, 3) == 10 assert tn.estimate_fee(3, 1) == -10 + 1 # With fee capping tn.set_fee(2, 1, cap_fees=True) tn.set_fee(2, 3, imbalance_penalty=[(TA(0), FA(200)), (TA(2000), FA(0))], cap_fees=True) assert tn.estimate_fee(1, 3) == 10 assert tn.estimate_fee(3, 1) == 0 # Combined fees cancel out # Works without fee capping tn.set_fee(2, 1, imbalance_penalty=[(TA(0), FA(0)), (TA(2000), FA(20))], cap_fees=False) tn.set_fee(2, 3, imbalance_penalty=[(TA(0), FA(0)), (TA(2000), FA(20))], cap_fees=False) assert tn.estimate_fee(1, 3) == 0 assert tn.estimate_fee(3, 1) == 0 # And with fee capping, as the amounts even out tn.set_fee(2, 1, imbalance_penalty=[(TA(0), FA(0)), (TA(2000), FA(20))], cap_fees=True) tn.set_fee(2, 3, imbalance_penalty=[(TA(0), FA(0)), (TA(2000), FA(20))], cap_fees=True) assert tn.estimate_fee(1, 3) == 0 assert tn.estimate_fee(3, 1) == 0 # Works without fee capping tn.set_fee(2, 1, imbalance_penalty=[(TA(0), FA(20)), (TA(2000), FA(0))], cap_fees=False) tn.set_fee(2, 3, imbalance_penalty=[(TA(0), FA(20)), (TA(2000), FA(0))], cap_fees=False) assert tn.estimate_fee(1, 3) == 0 assert tn.estimate_fee(3, 1) == 0 # And with fee capping, as the amounts even out tn.set_fee(2, 1, imbalance_penalty=[(TA(0), FA(20)), (TA(2000), FA(0))], cap_fees=True) tn.set_fee(2, 3, imbalance_penalty=[(TA(0), FA(20)), (TA(2000), FA(0))], cap_fees=True) assert tn.estimate_fee(1, 3) == 0 assert tn.estimate_fee(3, 1) == 0 # When the range covered by the imbalance_penalty does include the # necessary balance values, the route should be considered invalid. tn.set_fee(2, 3, imbalance_penalty=[(TA(0), FA(0)), (TA(800), FA(200))]) assert tn.estimate_fee(1, 3) is None