From d32eb2b43317947555797c2a23668a08813b5dac Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 5 Sep 2019 13:33:53 +0200 Subject: [PATCH 01/17] Add a fee for internal routing that is a percentage to the amount Part of #4751 --- raiden/routing.py | 8 ++++++-- raiden/settings.py | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/raiden/routing.py b/raiden/routing.py index 3d2811177b..f20418b0ab 100644 --- a/raiden/routing.py +++ b/raiden/routing.py @@ -9,6 +9,7 @@ from raiden.exceptions import ServiceRequestFailed from raiden.messages.metadata import RouteMetadata from raiden.network.pathfinding import PFSConfig, query_paths +from raiden.settings import INTERNAL_ROUTING_DEFAULT_FEE_PERC from raiden.transfer import channel, views from raiden.transfer.state import ChainState, ChannelState, RouteState from raiden.utils.typing import ( @@ -209,12 +210,15 @@ def get_best_routes_internal( # The complete route includes the initiator, add it to the beginning complete_route = [Address(from_address)] + neighbour.route + # https://github.com/raiden-network/raiden/issues/4751 + # Internal routing doesn't know about fee so it should set a percentage per hop + estimated_fee = FeeAmount(int(INTERNAL_ROUTING_DEFAULT_FEE_PERC * amount)) + available_routes.append( RouteState( route=complete_route, forward_channel_id=neighbour.channelid, - # Internal routing doesn't know about fees, so set them to 0 - estimated_fee=FeeAmount(0), + estimated_fee=estimated_fee, ) ) diff --git a/raiden/settings.py b/raiden/settings.py index bf8bd30d17..a1d83a428d 100644 --- a/raiden/settings.py +++ b/raiden/settings.py @@ -56,6 +56,7 @@ DEFAULT_MEDIATION_PROPORTIONAL_FEE = ProportionalFeeAmount(0) DEFAULT_MEDIATION_PROPORTIONAL_IMBALANCE_FEE = ProportionalFeeAmount(0) DEFAULT_MEDIATION_FEE_MARGIN: float = 0.05 +INTERNAL_ROUTING_DEFAULT_FEE_PERC: float = 0.02 ORACLE_BLOCKNUMBER_DRIFT_TOLERANCE = 3 ETHERSCAN_API = "https://{network}.etherscan.io/api?module=proxy&action={action}" From 2430e3c5b159ca58d0765b439ea6a232d8e456d4 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 5 Sep 2019 14:26:20 +0200 Subject: [PATCH 02/17] Add a check for the maximum amount limit of transfer + fees Part of #4751 --- raiden/settings.py | 1 + raiden/transfer/mediated_transfer/initiator.py | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/raiden/settings.py b/raiden/settings.py index a1d83a428d..5bfd29aacc 100644 --- a/raiden/settings.py +++ b/raiden/settings.py @@ -57,6 +57,7 @@ DEFAULT_MEDIATION_PROPORTIONAL_IMBALANCE_FEE = ProportionalFeeAmount(0) DEFAULT_MEDIATION_FEE_MARGIN: float = 0.05 INTERNAL_ROUTING_DEFAULT_FEE_PERC: float = 0.02 +MAX_MEDIATION_FEE_PERC: float = 0.1 ORACLE_BLOCKNUMBER_DRIFT_TOLERANCE = 3 ETHERSCAN_API = "https://{network}.etherscan.io/api?module=proxy&action={action}" diff --git a/raiden/transfer/mediated_transfer/initiator.py b/raiden/transfer/mediated_transfer/initiator.py index 666bf8a29e..7a197815fc 100644 --- a/raiden/transfer/mediated_transfer/initiator.py +++ b/raiden/transfer/mediated_transfer/initiator.py @@ -1,7 +1,11 @@ import random from raiden.constants import ABSENT_SECRET -from raiden.settings import DEFAULT_MEDIATION_FEE_MARGIN, DEFAULT_WAIT_BEFORE_LOCK_REMOVAL +from raiden.settings import ( + DEFAULT_MEDIATION_FEE_MARGIN, + DEFAULT_WAIT_BEFORE_LOCK_REMOVAL, + MAX_MEDIATION_FEE_PERC, +) from raiden.transfer import channel, routes from raiden.transfer.architecture import Event, TransitionResult from raiden.transfer.events import EventPaymentSentFailed, EventPaymentSentSuccess @@ -220,6 +224,14 @@ def try_new_route( payment_amount=transfer_description.amount, estimated_fee=reachable_route_state.estimated_fee, ) + # https://github.com/raiden-network/raiden/issues/4751 + # If the transfer amount + fees exceeds a percentage of the + # initial amount then don't use this route + max_amount_limit = transfer_description.amount + int( + transfer_description.amount * MAX_MEDIATION_FEE_PERC + ) + if amount_with_fee > max_amount_limit: + continue is_channel_usable = channel.is_channel_usable_for_new_transfer( channel_state=candidate_channel_state, transfer_amount=amount_with_fee From fc2a01a231959f8eaf2b76fde5fb834a124f7f53 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 5 Sep 2019 15:33:24 +0200 Subject: [PATCH 03/17] Use UNIT_TRANSFER_AMOUNT in tests instead of magic constants --- .../transfer/mediated_transfer/test_initiatorstate.py | 1 + .../transfer/mediated_transfer/test_mediatorstate.py | 10 ++++++---- .../mediated_transfer/test_mediatorstate_regression.py | 5 +++-- raiden/tests/unit/transfer/test_source_routing.py | 3 ++- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/raiden/tests/unit/transfer/mediated_transfer/test_initiatorstate.py b/raiden/tests/unit/transfer/mediated_transfer/test_initiatorstate.py index bdfc88650a..fa4de850e1 100644 --- a/raiden/tests/unit/transfer/mediated_transfer/test_initiatorstate.py +++ b/raiden/tests/unit/transfer/mediated_transfer/test_initiatorstate.py @@ -150,6 +150,7 @@ def setup_initiator_tests( ) initiator_state = get_transfer_at_index(current_state, 0) + assert initiator_state, "There should be an ininitial initiator state" lock = channel.get_lock(channels[0].our_state, initiator_state.transfer_description.secrethash) assert lock available_routes = channels.get_routes(estimated_fee=allocated_fee) diff --git a/raiden/tests/unit/transfer/mediated_transfer/test_mediatorstate.py b/raiden/tests/unit/transfer/mediated_transfer/test_mediatorstate.py index 8a70bf82ea..dc61695c2b 100644 --- a/raiden/tests/unit/transfer/mediated_transfer/test_mediatorstate.py +++ b/raiden/tests/unit/transfer/mediated_transfer/test_mediatorstate.py @@ -439,7 +439,7 @@ def test_events_for_balanceproof(): """ pseudo_random_generator = random.Random() - setup = factories.make_transfers_pair(2, amount=10, block_number=1) + setup = factories.make_transfers_pair(2, amount=UNIT_TRANSFER_AMOUNT, block_number=1) last_pair = setup.transfers_pair[-1] last_pair.payee_state = "payee_secret_revealed" @@ -1553,14 +1553,14 @@ def test_mediator_lock_expired_with_receive_lock_expired(): "recipient": UNIT_TRANSFER_TARGET, "transfer": { "lock": { - "amount": 10, + "amount": UNIT_TRANSFER_AMOUNT, "expiration": expiration, "secrethash": transfer.lock.secrethash, }, "balance_proof": { "nonce": 1, "transferred_amount": 0, - "locked_amount": 10, + "locked_amount": UNIT_TRANSFER_AMOUNT, # pylint: disable=no-member "locksroot": transfer.balance_proof.locksroot, }, @@ -2091,7 +2091,9 @@ def test_receive_unlock(): assert search_for_item(iteration.events, EventInvalidReceivedUnlock, {}), msg sender_state = channels[0].partner_state - lock = HashTimeLockState(amount=10, expiration=10, secrethash=UNIT_SECRETHASH) + lock = HashTimeLockState( + amount=UNIT_TRANSFER_AMOUNT, expiration=10, secrethash=UNIT_SECRETHASH + ) sender_state.secrethashes_to_lockedlocks[factories.UNIT_SECRETHASH] = lock sender_state.pending_locks = factories.make_pending_locks([lock]) sender_state.balance_proof = factories.create( diff --git a/raiden/tests/unit/transfer/mediated_transfer/test_mediatorstate_regression.py b/raiden/tests/unit/transfer/mediated_transfer/test_mediatorstate_regression.py index 8366a9c77d..53e28f4074 100644 --- a/raiden/tests/unit/transfer/mediated_transfer/test_mediatorstate_regression.py +++ b/raiden/tests/unit/transfer/mediated_transfer/test_mediatorstate_regression.py @@ -13,6 +13,7 @@ UNIT_SECRET, UNIT_SECRETHASH, UNIT_TOKEN_ADDRESS, + UNIT_TRANSFER_AMOUNT, UNIT_TRANSFER_IDENTIFIER, UNIT_TRANSFER_INITIATOR, UNIT_TRANSFER_TARGET, @@ -192,7 +193,7 @@ def test_regression_send_refund(): "token": UNIT_TOKEN_ADDRESS, "balance_proof": { "transferred_amount": 0, - "locked_amount": 10, + "locked_amount": UNIT_TRANSFER_AMOUNT, "locksroot": keccak(lock.encoded), "token_network_address": token_network_address, "channel_identifier": first_payer_transfer.balance_proof.channel_identifier, @@ -296,7 +297,7 @@ def test_regression_mediator_task_no_routes(): NettingChannelStateProperties( our_state=NettingChannelEndStateProperties(balance=0), partner_state=NettingChannelEndStateProperties( - balance=10, address=HOP2, privatekey=HOP2_KEY + balance=UNIT_TRANSFER_AMOUNT, address=HOP2, privatekey=HOP2_KEY ), ) ] diff --git a/raiden/tests/unit/transfer/test_source_routing.py b/raiden/tests/unit/transfer/test_source_routing.py index 671a3a1bbf..dfdbce79f7 100644 --- a/raiden/tests/unit/transfer/test_source_routing.py +++ b/raiden/tests/unit/transfer/test_source_routing.py @@ -6,6 +6,7 @@ from raiden.storage.serialization import DictSerializer from raiden.tests.utils import factories from raiden.tests.utils.events import search_for_item +from raiden.tests.utils.factories import UNIT_TRANSFER_AMOUNT from raiden.transfer import views from raiden.transfer.architecture import TransitionResult from raiden.transfer.events import EventPaymentSentFailed @@ -323,7 +324,7 @@ def test_mediator_skips_used_routes(): block_number = 3 defaults = factories.NettingChannelStateProperties( our_state=factories.NettingChannelEndStateProperties.OUR_STATE, - partner_state=factories.NettingChannelEndStateProperties(balance=10), + partner_state=factories.NettingChannelEndStateProperties(balance=UNIT_TRANSFER_AMOUNT), open_transaction=factories.TransactionExecutionStatusProperties( started_block_number=1, finished_block_number=2, result="success" ), From 446018fc55a0a6c17d36a2942debc0e7d37cae59 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 5 Sep 2019 15:37:32 +0200 Subject: [PATCH 04/17] Set amount/fees in unit tests that agree with our defaults --- raiden/settings.py | 2 +- raiden/tests/utils/factories.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/raiden/settings.py b/raiden/settings.py index 5bfd29aacc..3c4f900496 100644 --- a/raiden/settings.py +++ b/raiden/settings.py @@ -57,7 +57,7 @@ DEFAULT_MEDIATION_PROPORTIONAL_IMBALANCE_FEE = ProportionalFeeAmount(0) DEFAULT_MEDIATION_FEE_MARGIN: float = 0.05 INTERNAL_ROUTING_DEFAULT_FEE_PERC: float = 0.02 -MAX_MEDIATION_FEE_PERC: float = 0.1 +MAX_MEDIATION_FEE_PERC: float = 0.2 ORACLE_BLOCKNUMBER_DRIFT_TOLERANCE = 3 ETHERSCAN_API = "https://{network}.etherscan.io/api?module=proxy&action={action}" diff --git a/raiden/tests/utils/factories.py b/raiden/tests/utils/factories.py index f9bd0d4371..cdf950f151 100644 --- a/raiden/tests/utils/factories.py +++ b/raiden/tests/utils/factories.py @@ -307,8 +307,8 @@ def make_hop_to_channel(channel_state: NettingChannelState = EMPTY) -> HopState: # Prefixing with UNIT_ to differ from the default globals. UNIT_SETTLE_TIMEOUT = 50 UNIT_REVEAL_TIMEOUT = 5 -UNIT_TRANSFER_AMOUNT = 10 -UNIT_TRANSFER_FEE = 5 +UNIT_TRANSFER_AMOUNT = 50 +UNIT_TRANSFER_FEE = 2 UNIT_SECRET = Secret(b"secretsecretsecretsecretsecretse") UNIT_SECRETHASH = sha256_secrethash(UNIT_SECRET) UNIT_TOKEN_ADDRESS = b"tokentokentokentoken" From 67d1022a76db010537f81032b420e20dbdd0bd81 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 5 Sep 2019 16:14:10 +0200 Subject: [PATCH 05/17] Add a test for the maximum mediation fee limit --- .../mediated_transfer/test_initiatorstate.py | 38 ++++++++++++++++++- .../transfer/mediated_transfer/initiator.py | 5 +++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/raiden/tests/unit/transfer/mediated_transfer/test_initiatorstate.py b/raiden/tests/unit/transfer/mediated_transfer/test_initiatorstate.py index fa4de850e1..d66458d6c4 100644 --- a/raiden/tests/unit/transfer/mediated_transfer/test_initiatorstate.py +++ b/raiden/tests/unit/transfer/mediated_transfer/test_initiatorstate.py @@ -9,7 +9,7 @@ from raiden.constants import EMPTY_HASH, MAXIMUM_PENDING_TRANSFERS from raiden.raiden_service import initiator_init -from raiden.settings import DEFAULT_MEDIATION_FEE_MARGIN +from raiden.settings import DEFAULT_MEDIATION_FEE_MARGIN, MAX_MEDIATION_FEE_PERC from raiden.tests.utils import factories from raiden.tests.utils.events import search_for_item from raiden.tests.utils.factories import ( @@ -244,6 +244,42 @@ def test_init_with_usable_routes(): assert send_mediated_transfer.recipient == channels[0].partner_state.address +def test_init_with_fees_more_than_max_limit(): + transfer_amount = TokenAmount(100) + flat_fee = FeeAmount(int(transfer_amount + MAX_MEDIATION_FEE_PERC * transfer_amount)) + expected_fee_margin = int(flat_fee * DEFAULT_MEDIATION_FEE_MARGIN) # == 1 + properties = factories.NettingChannelStateProperties( + our_state=factories.NettingChannelEndStateProperties( + balance=TokenAmount(transfer_amount + flat_fee + expected_fee_margin) + ) + ) + channels = factories.make_channel_set([properties]) + pseudo_random_generator = random.Random() + + transfer_description = create( + TransferDescriptionProperties(secret=UNIT_SECRET, amount=transfer_amount) + ) + routes = channels.get_routes(estimated_fee=flat_fee) + init_state_change = ActionInitInitiator(transfer=transfer_description, routes=routes) + + block_number = BlockNumber(1) + transition = initiator_manager.state_transition( + payment_state=None, + state_change=init_state_change, + channelidentifiers_to_channels=channels.channel_map, + nodeaddresses_to_networkstates=channels.nodeaddresses_to_networkstates, + pseudo_random_generator=pseudo_random_generator, + block_number=block_number, + ) + assert transition.new_state is None + assert isinstance(transition.events[0], EventPaymentSentFailed) + reason_msg = ( + "none of the available routes could be used and at least one of them " + "exceeded the maximum fee limit" + ) + assert transition.events[0].reason == reason_msg + + def test_init_without_routes(): block_number = BlockNumber(1) routes = [] diff --git a/raiden/transfer/mediated_transfer/initiator.py b/raiden/transfer/mediated_transfer/initiator.py index 7a197815fc..bf50b1bd96 100644 --- a/raiden/transfer/mediated_transfer/initiator.py +++ b/raiden/transfer/mediated_transfer/initiator.py @@ -203,6 +203,7 @@ def try_new_route( initiator_state = None events: List[Event] = list() + route_fee_exceeds_max = False channel_state = None route_state = None @@ -231,6 +232,7 @@ def try_new_route( transfer_description.amount * MAX_MEDIATION_FEE_PERC ) if amount_with_fee > max_amount_limit: + route_fee_exceeds_max = True continue is_channel_usable = channel.is_channel_usable_for_new_transfer( @@ -247,6 +249,9 @@ def try_new_route( else: reason = "none of the available routes could be used" + if route_fee_exceeds_max: + reason += " and at least one of them exceeded the maximum fee limit" + transfer_failed = EventPaymentSentFailed( token_network_registry_address=transfer_description.token_network_registry_address, token_network_address=transfer_description.token_network_address, From c9c6bb0beae5467c43e07749d150696553f6412d Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 6 Sep 2019 11:20:56 +0200 Subject: [PATCH 06/17] Adjust test_mediated_transfer for the fee changes --- .../transfer/test_mediatedtransfer.py | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/raiden/tests/integration/transfer/test_mediatedtransfer.py b/raiden/tests/integration/transfer/test_mediatedtransfer.py index bcc5bb5819..7eab505c5d 100644 --- a/raiden/tests/integration/transfer/test_mediatedtransfer.py +++ b/raiden/tests/integration/transfer/test_mediatedtransfer.py @@ -1,4 +1,5 @@ from hashlib import sha256 +from math import ceil from typing import List from unittest.mock import patch @@ -10,7 +11,11 @@ from raiden.messages.transfers import LockedTransfer, RevealSecret, SecretRequest from raiden.network.pathfinding import PFSConfig, PFSInfo from raiden.routing import get_best_routes_internal -from raiden.settings import DEFAULT_MEDIATION_FEE_MARGIN, DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS +from raiden.settings import ( + DEFAULT_MEDIATION_FEE_MARGIN, + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS, + INTERNAL_ROUTING_DEFAULT_FEE_PERC, +) from raiden.storage.sqlite import RANGE_ALL_STATE_CHANGES from raiden.tests.utils import factories from raiden.tests.utils.detect_failure import raise_on_failure @@ -195,10 +200,20 @@ def run_test_mediated_transfer_with_entire_deposit( chain_state, token_network_registry_address, token_address ) + # calculate the amount to send so that including fees it covers the entire deposit + amount = ceil( + deposit + / ( + 1 + + INTERNAL_ROUTING_DEFAULT_FEE_PERC + + INTERNAL_ROUTING_DEFAULT_FEE_PERC * DEFAULT_MEDIATION_FEE_MARGIN + ) + ) + secrethash = transfer_and_assert_path( path=raiden_network, token_address=token_address, - amount=deposit, + amount=amount, identifier=1, timeout=network_wait * number_of_nodes, ) @@ -207,7 +222,7 @@ def run_test_mediated_transfer_with_entire_deposit( transfer_and_assert_path( path=reverse_path, token_address=token_address, - amount=deposit * 2, + amount=amount * 2, identifier=2, timeout=network_wait * number_of_nodes, ) @@ -442,7 +457,7 @@ def run_test_mediated_transfer_with_node_consuming_more_than_allocated_fee( chain_state, token_network_registry_address, token_address ) fee = FeeAmount(5) - amount = PaymentAmount(10) + amount = PaymentAmount(100) app1_app2_channel_state = views.get_channelstate_by_token_network_and_partner( chain_state=views.state_from_raiden(app1.raiden), From 43f4bbf9b8b547da8469632f1b8950fab5e5053a Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 6 Sep 2019 13:32:32 +0200 Subject: [PATCH 07/17] Adjust test_restapi for the fee changes --- raiden/tests/integration/api/test_restapi.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/raiden/tests/integration/api/test_restapi.py b/raiden/tests/integration/api/test_restapi.py index b96db05d61..c3e8c7e70f 100644 --- a/raiden/tests/integration/api/test_restapi.py +++ b/raiden/tests/integration/api/test_restapi.py @@ -840,7 +840,7 @@ def test_api_payments_target_error(api_server_test_instance, raiden_network, tok @pytest.mark.parametrize("number_of_nodes", [2]) def test_api_payments(api_server_test_instance, raiden_network, token_addresses): _, app1 = raiden_network - amount = 200 + amount = 100 identifier = 42 token_address = token_addresses[0] target_address = app1.raiden.address @@ -985,7 +985,7 @@ def test_api_payments_with_secret_no_hash( api_server_test_instance, raiden_network, token_addresses ): _, app1 = raiden_network - amount = 200 + amount = 100 identifier = 42 token_address = token_addresses[0] target_address = app1.raiden.address @@ -1058,7 +1058,7 @@ def test_api_payments_with_secret_and_hash( api_server_test_instance, raiden_network, token_addresses ): _, app1 = raiden_network - amount = 200 + amount = 100 identifier = 42 token_address = token_addresses[0] target_address = app1.raiden.address @@ -1556,7 +1556,7 @@ def test_api_deposit_limit(api_server_test_instance, token_addresses, reveal_tim @pytest.mark.parametrize("number_of_nodes", [3]) def test_payment_events_endpoints(api_server_test_instance, raiden_network, token_addresses): app0, app1, app2 = raiden_network - amount1 = 200 + amount1 = 10 identifier1 = 42 secret1, secrethash1 = factories.make_secret_with_hash() token_address = token_addresses[0] @@ -1582,7 +1582,7 @@ def test_payment_events_endpoints(api_server_test_instance, raiden_network, toke # app0 is sending some tokens to target 2 identifier2 = 43 - amount2 = 123 + amount2 = 10 secret2, secrethash2 = factories.make_secret_with_hash() request = grequests.post( api_url_for( @@ -1884,7 +1884,7 @@ def test_payment_events_endpoints(api_server_test_instance, raiden_network, toke @pytest.mark.parametrize("number_of_nodes", [2]) def test_channel_events_raiden(api_server_test_instance, raiden_network, token_addresses): _, app1 = raiden_network - amount = 200 + amount = 100 identifier = 42 token_address = token_addresses[0] target_address = app1.raiden.address From 07b392ea55d93551be5451be2ca32adec4a7296c Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 6 Sep 2019 15:56:17 +0200 Subject: [PATCH 08/17] Adjust test_refund_transfer for fee changes --- raiden/routing.py | 2 +- .../transfer/test_mediatedtransfer.py | 18 +----- .../transfer/test_refundtransfer.py | 62 ++++++++++++------- raiden/tests/utils/transfer.py | 21 +++++++ 4 files changed, 66 insertions(+), 37 deletions(-) diff --git a/raiden/routing.py b/raiden/routing.py index f20418b0ab..d2b036fd4e 100644 --- a/raiden/routing.py +++ b/raiden/routing.py @@ -212,7 +212,7 @@ def get_best_routes_internal( # https://github.com/raiden-network/raiden/issues/4751 # Internal routing doesn't know about fee so it should set a percentage per hop - estimated_fee = FeeAmount(int(INTERNAL_ROUTING_DEFAULT_FEE_PERC * amount)) + estimated_fee = FeeAmount(round(INTERNAL_ROUTING_DEFAULT_FEE_PERC * amount)) available_routes.append( RouteState( diff --git a/raiden/tests/integration/transfer/test_mediatedtransfer.py b/raiden/tests/integration/transfer/test_mediatedtransfer.py index 7eab505c5d..2ebc03af2a 100644 --- a/raiden/tests/integration/transfer/test_mediatedtransfer.py +++ b/raiden/tests/integration/transfer/test_mediatedtransfer.py @@ -1,5 +1,4 @@ from hashlib import sha256 -from math import ceil from typing import List from unittest.mock import patch @@ -11,11 +10,7 @@ from raiden.messages.transfers import LockedTransfer, RevealSecret, SecretRequest from raiden.network.pathfinding import PFSConfig, PFSInfo from raiden.routing import get_best_routes_internal -from raiden.settings import ( - DEFAULT_MEDIATION_FEE_MARGIN, - DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS, - INTERNAL_ROUTING_DEFAULT_FEE_PERC, -) +from raiden.settings import DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS from raiden.storage.sqlite import RANGE_ALL_STATE_CHANGES from raiden.tests.utils import factories from raiden.tests.utils.detect_failure import raise_on_failure @@ -26,6 +21,7 @@ assert_succeeding_transfer_invariants, assert_synced_channel_state, block_timeout_for_transfer_by_secrethash, + calculate_amount_to_drain_channel, transfer, transfer_and_assert_path, wait_assert, @@ -200,15 +196,7 @@ def run_test_mediated_transfer_with_entire_deposit( chain_state, token_network_registry_address, token_address ) - # calculate the amount to send so that including fees it covers the entire deposit - amount = ceil( - deposit - / ( - 1 - + INTERNAL_ROUTING_DEFAULT_FEE_PERC - + INTERNAL_ROUTING_DEFAULT_FEE_PERC * DEFAULT_MEDIATION_FEE_MARGIN - ) - ) + amount = calculate_amount_to_drain_channel(deposit) secrethash = transfer_and_assert_path( path=raiden_network, diff --git a/raiden/tests/integration/transfer/test_refundtransfer.py b/raiden/tests/integration/transfer/test_refundtransfer.py index 7e22388615..6ad7866b63 100644 --- a/raiden/tests/integration/transfer/test_refundtransfer.py +++ b/raiden/tests/integration/transfer/test_refundtransfer.py @@ -17,6 +17,8 @@ ) from raiden.tests.utils.transfer import ( assert_synced_channel_state, + calculate_amount_to_drain_channel, + calculate_fee_for_amount, get_channelstate, transfer, wait_assert, @@ -60,7 +62,7 @@ def run_test_refund_messages(raiden_chain, token_addresses, deposit, network_wai ) # Exhaust the channel App1 <-> App2 (to force the refund transfer) - exhaust_amount = deposit + exhaust_amount = calculate_amount_to_drain_channel(deposit) transfer( initiator_app=app1, target_app=app2, @@ -70,6 +72,8 @@ def run_test_refund_messages(raiden_chain, token_addresses, deposit, network_wai ) refund_amount = deposit // 2 + refund_fees = calculate_fee_for_amount(refund_amount) + refund_amount_with_fees = refund_amount + refund_fees identifier = 1 payment_status = app0.raiden.mediated_transfer_async( token_network_address, refund_amount, app2.raiden.address, identifier @@ -81,7 +85,9 @@ def run_test_refund_messages(raiden_chain, token_addresses, deposit, network_wai # Since the refund is not unlocked both channels have the corresponding # amount locked (issue #1091) send_lockedtransfer = raiden_events_search_for_item( - app0.raiden, SendLockedTransfer, {"transfer": {"lock": {"amount": refund_amount}}} + app0.raiden, + SendLockedTransfer, + {"transfer": {"lock": {"amount": refund_amount_with_fees}}}, ) assert send_lockedtransfer @@ -100,7 +106,7 @@ def run_test_refund_messages(raiden_chain, token_addresses, deposit, network_wai [send_refundtransfer.transfer.lock], ) - # This channel was exhausted to force the refund transfer + # This channel was exhausted to force the refund transfer except for the fees with gevent.Timeout(network_wait): wait_assert( assert_synced_channel_state, token_network_address, app1, 0, [], app2, deposit * 2, [] @@ -160,6 +166,7 @@ def run_test_refund_transfer( # drain the channel app1 -> app2 identifier_drain = 2 amount_drain = deposit * 8 // 10 + amount_drain_with_fees = amount_drain + calculate_fee_for_amount(amount_drain) transfer( initiator_app=app1, target_app=app2, @@ -185,10 +192,10 @@ def run_test_refund_transfer( assert_synced_channel_state, token_network_address, app1, - deposit - amount_path - amount_drain, + deposit - amount_path - amount_drain_with_fees, [], app2, - deposit + amount_path + amount_drain, + deposit + amount_path + amount_drain_with_fees, [], ) @@ -196,6 +203,7 @@ def run_test_refund_transfer( # app2 doesn't have capacity, so a refund will be sent on app1 -> app0 identifier_refund = 3 amount_refund = 50 + amount_refund_with_fees = amount_refund + calculate_fee_for_amount(amount_refund) payment_status = app0.raiden.mediated_transfer_async( token_network_address, amount_refund, app2.raiden.address, identifier_refund ) @@ -205,7 +213,9 @@ def run_test_refund_transfer( # A lock structure with the correct amount send_locked = raiden_events_search_for_item( - app0.raiden, SendLockedTransfer, {"transfer": {"lock": {"amount": amount_refund}}} + app0.raiden, + SendLockedTransfer, + {"transfer": {"lock": {"amount": amount_refund_with_fees}}}, ) assert send_locked secrethash = send_locked.transfer.lock.secrethash @@ -237,10 +247,10 @@ def run_test_refund_transfer( assert_synced_channel_state, token_network_address, app1, - deposit - amount_path - amount_drain, + deposit - amount_path - amount_drain_with_fees, [], app2, - deposit + amount_path + amount_drain, + deposit + amount_path + amount_drain_with_fees, [], ) @@ -370,6 +380,7 @@ def run_test_different_view_of_last_bp_during_unlock( # drain the channel app1 -> app2 identifier_drain = 2 amount_drain = deposit * 8 // 10 + fee_app1_app2 = calculate_fee_for_amount(amount_drain) transfer( initiator_app=app1, target_app=app2, @@ -395,10 +406,10 @@ def run_test_different_view_of_last_bp_during_unlock( assert_synced_channel_state, token_network_address, app1, - deposit - amount_path - amount_drain, + deposit - amount_path - amount_drain - fee_app1_app2, [], app2, - deposit + amount_path + amount_drain, + deposit + amount_path + amount_drain + fee_app1_app2, [], ) @@ -406,6 +417,7 @@ def run_test_different_view_of_last_bp_during_unlock( # app2 doesn't have capacity, so a refund will be sent on app1 -> app0 identifier_refund = 3 amount_refund = 50 + amount_refund_with_fees = amount_refund + calculate_fee_for_amount(50) payment_status = app0.raiden.mediated_transfer_async( token_network_address, amount_refund, app2.raiden.address, identifier_refund ) @@ -415,7 +427,9 @@ def run_test_different_view_of_last_bp_during_unlock( # A lock structure with the correct amount send_locked = raiden_events_search_for_item( - app0.raiden, SendLockedTransfer, {"transfer": {"lock": {"amount": amount_refund}}} + app0.raiden, + SendLockedTransfer, + {"transfer": {"lock": {"amount": amount_refund_with_fees}}}, ) assert send_locked secrethash = send_locked.transfer.lock.secrethash @@ -447,10 +461,10 @@ def run_test_different_view_of_last_bp_during_unlock( assert_synced_channel_state, token_network_address, app1, - deposit - amount_path - amount_drain, + deposit - amount_path - amount_drain - fee_app1_app2, [], app2, - deposit + amount_path + amount_drain, + deposit + amount_path + amount_drain + fee_app1_app2, [], ) @@ -518,7 +532,7 @@ def patched_on_raiden_event(raiden, chain_state, event): {"receiver": app0.raiden.address}, retry_timeout, ) - assert unlock_app0.returned_tokens == 50 + assert unlock_app0.returned_tokens == amount_refund_with_fees with gevent.Timeout(timeout): unlock_app1 = wait_for_state_change( app1.raiden, @@ -526,7 +540,7 @@ def patched_on_raiden_event(raiden, chain_state, event): {"receiver": app1.raiden.address}, retry_timeout, ) - assert unlock_app1.returned_tokens == 50 + assert unlock_app1.returned_tokens == amount_refund_with_fees final_balance0 = token_proxy.balance_of(app0.raiden.address) final_balance1 = token_proxy.balance_of(app1.raiden.address) @@ -582,6 +596,7 @@ def run_test_refund_transfer_after_2nd_hop( # drain the channel app2 -> app3 identifier_drain = 2 amount_drain = deposit * 8 // 10 + amount_drain_with_fees = amount_drain + calculate_fee_for_amount(amount_drain) transfer( initiator_app=app2, target_app=app3, @@ -618,10 +633,10 @@ def run_test_refund_transfer_after_2nd_hop( assert_synced_channel_state, token_network_address, app2, - deposit - amount_path - amount_drain, + deposit - amount_path - amount_drain_with_fees, [], app3, - deposit + amount_path + amount_drain, + deposit + amount_path + amount_drain_with_fees, [], ) @@ -630,6 +645,7 @@ def run_test_refund_transfer_after_2nd_hop( # app2 -> app1 -> app0 identifier_refund = 3 amount_refund = 50 + amount_refund_with_fees = amount_refund + calculate_fee_for_amount(amount_refund) payment_status = app0.raiden.mediated_transfer_async( token_network_address, amount_refund, app3.raiden.address, identifier_refund ) @@ -639,7 +655,9 @@ def run_test_refund_transfer_after_2nd_hop( # Lock structures with the correct amount send_locked1 = raiden_events_search_for_item( - app0.raiden, SendLockedTransfer, {"transfer": {"lock": {"amount": amount_refund}}} + app0.raiden, + SendLockedTransfer, + {"transfer": {"lock": {"amount": amount_refund_with_fees}}}, ) assert send_locked1 @@ -652,7 +670,9 @@ def run_test_refund_transfer_after_2nd_hop( assert lock1.secrethash == refund_lock1.secrethash send_locked2 = raiden_events_search_for_item( - app1.raiden, SendLockedTransfer, {"transfer": {"lock": {"amount": amount_refund}}} + app1.raiden, + SendLockedTransfer, + {"transfer": {"lock": {"amount": amount_refund_with_fees}}}, ) assert send_locked2 @@ -693,9 +713,9 @@ def run_test_refund_transfer_after_2nd_hop( assert_synced_channel_state, token_network_address, app2, - deposit - amount_path - amount_drain, + deposit - amount_path - amount_drain_with_fees, [], app3, - deposit + amount_path + amount_drain, + deposit + amount_path + amount_drain_with_fees, [], ) diff --git a/raiden/tests/utils/transfer.py b/raiden/tests/utils/transfer.py index 58bf534367..65c24711b1 100644 --- a/raiden/tests/utils/transfer.py +++ b/raiden/tests/utils/transfer.py @@ -15,6 +15,11 @@ from raiden.messages.transfers import Lock, LockedTransfer, LockExpired, Unlock from raiden.raiden_service import RaidenService from raiden.settings import DEFAULT_RETRY_TIMEOUT +from raiden.settings import ( + DEFAULT_MEDIATION_FEE_MARGIN, + DEFAULT_RETRY_TIMEOUT, + INTERNAL_ROUTING_DEFAULT_FEE_PERC, +) from raiden.storage.restore import ( get_event_with_balance_proof_by_balance_hash, get_state_change_with_balance_proof_by_locksroot, @@ -1067,4 +1072,20 @@ def block_timeout_for_transfer_by_secrethash( exception_to_throw=ValueError(error_message or default_error_message), block_number=BlockNumber(expiration), retry_timeout=DEFAULT_RETRY_TIMEOUT, + +def calculate_amount_to_drain_channel(deposit: int) -> int: + # calculate the amount to send so that including fees it covers the entire deposit + denominator = ( + 1 + + INTERNAL_ROUTING_DEFAULT_FEE_PERC + + INTERNAL_ROUTING_DEFAULT_FEE_PERC * DEFAULT_MEDIATION_FEE_MARGIN + ) + amount = round(deposit / denominator) + return amount + + +def calculate_fee_for_amount(amount: int) -> int: + return round( + amount * INTERNAL_ROUTING_DEFAULT_FEE_PERC + + amount * INTERNAL_ROUTING_DEFAULT_FEE_PERC * DEFAULT_MEDIATION_FEE_MARGIN ) From bd5899faadcf8cb5941353a18667655178323878 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 6 Sep 2019 16:38:46 +0200 Subject: [PATCH 09/17] Adjust test_regression.py for the fee changes --- raiden/tests/integration/test_regression.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/raiden/tests/integration/test_regression.py b/raiden/tests/integration/test_regression.py index 0523e7c3ef..45d39dea4a 100644 --- a/raiden/tests/integration/test_regression.py +++ b/raiden/tests/integration/test_regression.py @@ -18,7 +18,12 @@ ) from raiden.tests.utils.factories import UNIT_CHAIN_ID from raiden.tests.utils.network import payment_channel_open_and_deposit -from raiden.tests.utils.transfer import get_channelstate, transfer, watch_for_unlock_failures +from raiden.tests.utils.transfer import ( + calculate_amount_to_drain_channel, + get_channelstate, + transfer, + watch_for_unlock_failures, +) from raiden.transfer import views from raiden.transfer.mediated_transfer.events import EventRouteFailed, SendSecretReveal from raiden.transfer.mediated_transfer.state_change import ReceiveTransferCancelRoute @@ -285,12 +290,13 @@ def run_regression_payment_complete_after_refund_to_the_initiator( app_channels = [(app0, app1), (app1, app2), (app0, app3), (app3, app4), (app4, app2)] open_and_wait_for_channels(app_channels, registry_address, token, deposit, settle_timeout) + exhaust_amount = calculate_amount_to_drain_channel(deposit) # Use all deposit from app1->app2 to force a refund transfer( initiator_app=app1, target_app=app2, token_address=token, - amount=deposit, + amount=exhaust_amount, identifier=PaymentID(1), ) @@ -299,7 +305,7 @@ def run_regression_payment_complete_after_refund_to_the_initiator( initiator_app=app0, target_app=app2, token_address=token, - amount=deposit, + amount=exhaust_amount, identifier=PaymentID(2), timeout=20, ) From eec83d379a7f77f6b40a4c8cd096fe218a8fd254 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 6 Sep 2019 18:12:22 +0200 Subject: [PATCH 10/17] Adjust test_pending_transfers_endpoint for fees --- raiden/tests/integration/api/test_restapi.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/raiden/tests/integration/api/test_restapi.py b/raiden/tests/integration/api/test_restapi.py index c3e8c7e70f..7532c139dc 100644 --- a/raiden/tests/integration/api/test_restapi.py +++ b/raiden/tests/integration/api/test_restapi.py @@ -30,6 +30,7 @@ from raiden.tests.utils.network import CHAIN from raiden.tests.utils.protocol import WaitForMessage from raiden.tests.utils.smartcontracts import deploy_contract_web3 +from raiden.tests.utils.transfer import calculate_fee_for_amount from raiden.transfer import views from raiden.transfer.state import ChannelState from raiden.waiting import ( @@ -1906,7 +1907,8 @@ def test_channel_events_raiden(api_server_test_instance, raiden_network, token_a @pytest.mark.parametrize("channels_per_node", [CHAIN]) def test_pending_transfers_endpoint(raiden_network, token_addresses): initiator, mediator, target = raiden_network - amount = 200 + amount = 150 + amount_with_fee = amount + calculate_fee_for_amount(amount) identifier = 42 token_address = token_addresses[0] @@ -1944,7 +1946,7 @@ def test_pending_transfers_endpoint(raiden_network, token_addresses): ) transfer_arrived = target_wait.wait_for_message(LockedTransfer, {"payment_identifier": 42}) - transfer_arrived.wait() + transfer_arrived.wait(timeout=30.0) for server in (initiator_server, mediator_server, target_server): request = grequests.get(api_url_for(server, "pending_transfers_resource")) @@ -1953,7 +1955,7 @@ def test_pending_transfers_endpoint(raiden_network, token_addresses): content = json.loads(response.content) assert len(content) == 1 assert content[0]["payment_identifier"] == str(identifier) - assert content[0]["locked_amount"] == str(amount) + assert content[0]["locked_amount"] == str(amount_with_fee) assert content[0]["token_address"] == to_checksum_address(token_address) assert content[0]["token_network_address"] == to_checksum_address(token_network_address) From cd837e9227dcdf0934b20412e866c8d3ac0ed826 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 6 Sep 2019 18:34:19 +0200 Subject: [PATCH 11/17] Adjust test_settlement after fee changes --- .../integration/long_running/test_settlement.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/raiden/tests/integration/long_running/test_settlement.py b/raiden/tests/integration/long_running/test_settlement.py index fa0ce8c1d1..3dad66cbcb 100644 --- a/raiden/tests/integration/long_running/test_settlement.py +++ b/raiden/tests/integration/long_running/test_settlement.py @@ -20,7 +20,12 @@ from raiden.tests.utils.events import raiden_state_changes_search_for_item, search_for_item from raiden.tests.utils.network import CHAIN from raiden.tests.utils.protocol import WaitForMessage -from raiden.tests.utils.transfer import assert_synced_channel_state, get_channelstate, transfer +from raiden.tests.utils.transfer import ( + assert_synced_channel_state, + calculate_fee_for_amount, + get_channelstate, + transfer, +) from raiden.transfer import channel, views from raiden.transfer.events import SendWithdrawConfirmation from raiden.transfer.identifiers import CanonicalIdentifier @@ -655,6 +660,7 @@ def run_test_settled_lock(token_addresses, raiden_network, deposit): registry_address = app0.raiden.default_registry.address token_address = token_addresses[0] amount = PaymentAmount(30) + amount_with_fee = amount + calculate_fee_for_amount(amount) token_network_address = views.get_token_network_address_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address ) @@ -727,8 +733,8 @@ def run_test_settled_lock(token_addresses, raiden_network, deposit): given_block_identifier=current_block, ) - expected_balance0 = initial_balance0 + deposit0 - amount * 2 - expected_balance1 = initial_balance1 + deposit1 + amount * 2 + expected_balance0 = initial_balance0 + deposit0 - amount_with_fee * 2 + expected_balance1 = initial_balance1 + deposit1 + amount_with_fee * 2 assert token_proxy.balance_of(address0) == expected_balance0 assert token_proxy.balance_of(address1) == expected_balance1 From 8a7cec94e2b9c43d86f5b2c25b01ffbe1016d30b Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Sat, 7 Sep 2019 00:42:22 +0200 Subject: [PATCH 12/17] Disable max mediation fee checks for test_mediated_transfer_with_fee --- .../tests/integration/transfer/test_mediatedtransfer.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/raiden/tests/integration/transfer/test_mediatedtransfer.py b/raiden/tests/integration/transfer/test_mediatedtransfer.py index 2ebc03af2a..4ca56e4b23 100644 --- a/raiden/tests/integration/transfer/test_mediatedtransfer.py +++ b/raiden/tests/integration/transfer/test_mediatedtransfer.py @@ -649,7 +649,13 @@ def assert_balances(expected_transferred_amounts=List[int]): for i, fee_schedule in enumerate(case.get("incoming_fee_schedules", [])): if fee_schedule: set_fee_schedule(apps[i + 1], apps[i], fee_schedule) - with patch("raiden.routing.get_best_routes_internal", get_best_routes_with_fees): + + route_patch = patch("raiden.routing.get_best_routes_internal", get_best_routes_with_fees) + disable_max_mediation_fee_patch = patch( + "raiden.transfer.mediated_transfer.initiator.MAX_MEDIATION_FEE_PERC", new=1 + ) + + with route_patch, disable_max_mediation_fee_patch: transfer_and_assert_path( path=raiden_network, token_address=token_address, amount=amount, identifier=2 ) From 1d0a27995fdc8171c632f20b8afe23e9a51c3602 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Sat, 7 Sep 2019 01:10:25 +0200 Subject: [PATCH 13/17] /s/ininitial/initial --- .../unit/transfer/mediated_transfer/test_initiatorstate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/raiden/tests/unit/transfer/mediated_transfer/test_initiatorstate.py b/raiden/tests/unit/transfer/mediated_transfer/test_initiatorstate.py index d66458d6c4..4029f04b00 100644 --- a/raiden/tests/unit/transfer/mediated_transfer/test_initiatorstate.py +++ b/raiden/tests/unit/transfer/mediated_transfer/test_initiatorstate.py @@ -150,7 +150,7 @@ def setup_initiator_tests( ) initiator_state = get_transfer_at_index(current_state, 0) - assert initiator_state, "There should be an ininitial initiator state" + assert initiator_state, "There should be an initial initiator state" lock = channel.get_lock(channels[0].our_state, initiator_state.transfer_description.secrethash) assert lock available_routes = channels.get_routes(estimated_fee=allocated_fee) From 1c299c21bb8e09f61f6a615e2425b5812178374e Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 9 Sep 2019 15:28:19 +0200 Subject: [PATCH 14/17] Fixes after rebase --- raiden/tests/utils/transfer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/raiden/tests/utils/transfer.py b/raiden/tests/utils/transfer.py index 65c24711b1..131192096d 100644 --- a/raiden/tests/utils/transfer.py +++ b/raiden/tests/utils/transfer.py @@ -14,7 +14,6 @@ from raiden.messages.metadata import Metadata, RouteMetadata from raiden.messages.transfers import Lock, LockedTransfer, LockExpired, Unlock from raiden.raiden_service import RaidenService -from raiden.settings import DEFAULT_RETRY_TIMEOUT from raiden.settings import ( DEFAULT_MEDIATION_FEE_MARGIN, DEFAULT_RETRY_TIMEOUT, @@ -1072,6 +1071,8 @@ def block_timeout_for_transfer_by_secrethash( exception_to_throw=ValueError(error_message or default_error_message), block_number=BlockNumber(expiration), retry_timeout=DEFAULT_RETRY_TIMEOUT, + ) + def calculate_amount_to_drain_channel(deposit: int) -> int: # calculate the amount to send so that including fees it covers the entire deposit From aff2ab772dc072990b116cfe7cfa80d35fdd6ac3 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 9 Sep 2019 16:39:42 +0200 Subject: [PATCH 15/17] PR review fixes for readability --- .../integration/transfer/test_mediatedtransfer.py | 2 +- .../transfer/mediated_transfer/test_initiatorstate.py | 2 +- raiden/tests/utils/transfer.py | 11 ++--------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/raiden/tests/integration/transfer/test_mediatedtransfer.py b/raiden/tests/integration/transfer/test_mediatedtransfer.py index 4ca56e4b23..3ad4a05ced 100644 --- a/raiden/tests/integration/transfer/test_mediatedtransfer.py +++ b/raiden/tests/integration/transfer/test_mediatedtransfer.py @@ -10,7 +10,7 @@ from raiden.messages.transfers import LockedTransfer, RevealSecret, SecretRequest from raiden.network.pathfinding import PFSConfig, PFSInfo from raiden.routing import get_best_routes_internal -from raiden.settings import DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS +from raiden.settings import DEFAULT_MEDIATION_FEE_MARGIN, DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS from raiden.storage.sqlite import RANGE_ALL_STATE_CHANGES from raiden.tests.utils import factories from raiden.tests.utils.detect_failure import raise_on_failure diff --git a/raiden/tests/unit/transfer/mediated_transfer/test_initiatorstate.py b/raiden/tests/unit/transfer/mediated_transfer/test_initiatorstate.py index 4029f04b00..b612640667 100644 --- a/raiden/tests/unit/transfer/mediated_transfer/test_initiatorstate.py +++ b/raiden/tests/unit/transfer/mediated_transfer/test_initiatorstate.py @@ -247,7 +247,7 @@ def test_init_with_usable_routes(): def test_init_with_fees_more_than_max_limit(): transfer_amount = TokenAmount(100) flat_fee = FeeAmount(int(transfer_amount + MAX_MEDIATION_FEE_PERC * transfer_amount)) - expected_fee_margin = int(flat_fee * DEFAULT_MEDIATION_FEE_MARGIN) # == 1 + expected_fee_margin = int(flat_fee * DEFAULT_MEDIATION_FEE_MARGIN) properties = factories.NettingChannelStateProperties( our_state=factories.NettingChannelEndStateProperties( balance=TokenAmount(transfer_amount + flat_fee + expected_fee_margin) diff --git a/raiden/tests/utils/transfer.py b/raiden/tests/utils/transfer.py index 131192096d..f183f3aad7 100644 --- a/raiden/tests/utils/transfer.py +++ b/raiden/tests/utils/transfer.py @@ -1076,17 +1076,10 @@ def block_timeout_for_transfer_by_secrethash( def calculate_amount_to_drain_channel(deposit: int) -> int: # calculate the amount to send so that including fees it covers the entire deposit - denominator = ( - 1 - + INTERNAL_ROUTING_DEFAULT_FEE_PERC - + INTERNAL_ROUTING_DEFAULT_FEE_PERC * DEFAULT_MEDIATION_FEE_MARGIN - ) + denominator = 1 + INTERNAL_ROUTING_DEFAULT_FEE_PERC * (1 + DEFAULT_MEDIATION_FEE_MARGIN) amount = round(deposit / denominator) return amount def calculate_fee_for_amount(amount: int) -> int: - return round( - amount * INTERNAL_ROUTING_DEFAULT_FEE_PERC - + amount * INTERNAL_ROUTING_DEFAULT_FEE_PERC * DEFAULT_MEDIATION_FEE_MARGIN - ) + return round((amount * INTERNAL_ROUTING_DEFAULT_FEE_PERC) * (1 + DEFAULT_MEDIATION_FEE_MARGIN)) From 5ddf099843a9fc6505d7ea0d43f68f6a2dc79dda Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 9 Sep 2019 23:45:50 +0200 Subject: [PATCH 16/17] Add exception with msg at timeout of wait for transfer in tests --- raiden/tests/utils/transfer.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/raiden/tests/utils/transfer.py b/raiden/tests/utils/transfer.py index f183f3aad7..f579907cdb 100644 --- a/raiden/tests/utils/transfer.py +++ b/raiden/tests/utils/transfer.py @@ -409,13 +409,15 @@ def transfer_and_assert_path( secret=secret, ) + msg = ( + f"transfer from {to_checksum_address(first_app.raiden.address)} " + f"to {to_checksum_address(last_app.raiden.address)} for amount " + f"{amount} failed" + ) + exception = RuntimeError(msg + " due to Timeout") with watch_for_unlock_failures(*path): - with Timeout(seconds=timeout): + with Timeout(seconds=timeout, exception=exception): gevent.wait(results) - msg = ( - f"transfer from {to_checksum_address(first_app.raiden.address)} " - f"to {to_checksum_address(last_app.raiden.address)} failed." - ) assert payment_status.payment_done.get(), msg return secrethash From 33df00bb2b2783632d9392da579f2562d0f3432f Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 10 Sep 2019 00:07:47 +0200 Subject: [PATCH 17/17] Add proper checks for amount/fee ratio in the mediation fee test --- .../integration/transfer/test_mediatedtransfer.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/raiden/tests/integration/transfer/test_mediatedtransfer.py b/raiden/tests/integration/transfer/test_mediatedtransfer.py index 3ad4a05ced..19c7f1a87e 100644 --- a/raiden/tests/integration/transfer/test_mediatedtransfer.py +++ b/raiden/tests/integration/transfer/test_mediatedtransfer.py @@ -573,7 +573,13 @@ def assert_balances(expected_transferred_amounts=List[int]): fee_without_margin = FeeAmount(20) fee = round(fee_without_margin * (1 + DEFAULT_MEDIATION_FEE_MARGIN)) - amount = PaymentAmount(10) + amount = PaymentAmount(35) + msg = ( + "The chosen values will result in less than the amount reaching " + "the target after the 3rd hop" + ) + amount_at_end = amount + fee - (amount + fee) // 5 - (amount + fee - (amount + fee) // 5) // 5 + assert amount_at_end >= amount, msg cases = [ # The fee is added by the initiator, but no mediator deducts fees. As a # result, the target receives the fee. @@ -652,7 +658,7 @@ def assert_balances(expected_transferred_amounts=List[int]): route_patch = patch("raiden.routing.get_best_routes_internal", get_best_routes_with_fees) disable_max_mediation_fee_patch = patch( - "raiden.transfer.mediated_transfer.initiator.MAX_MEDIATION_FEE_PERC", new=1 + "raiden.transfer.mediated_transfer.initiator.MAX_MEDIATION_FEE_PERC", new=10000 ) with route_patch, disable_max_mediation_fee_patch: