ttest_mpp_split.py - electrum - Electrum Bitcoin wallet
HTML git clone https://git.parazyd.org/electrum
DIR Log
DIR Files
DIR Refs
DIR Submodules
---
ttest_mpp_split.py (4552B)
---
1 import random
2
3 import electrum.mpp_split as mpp_split # side effect for PART_PENALTY
4 from electrum.lnutil import NoPathFound
5
6 from . import ElectrumTestCase
7
8 PART_PENALTY = mpp_split.PART_PENALTY
9
10
11 class TestMppSplit(ElectrumTestCase):
12 def setUp(self):
13 super().setUp()
14 # to make tests reproducible:
15 random.seed(0)
16 self.channels_with_funds = {
17 0: 1_000_000_000,
18 1: 500_000_000,
19 2: 302_000_000,
20 3: 101_000_000,
21 }
22
23 def tearDown(self):
24 super().tearDown()
25 # undo side effect
26 mpp_split.PART_PENALTY = PART_PENALTY
27
28 def test_suggest_splits(self):
29 with self.subTest(msg="do a payment with the maximal amount spendable over a single channel"):
30 splits = mpp_split.suggest_splits(1_000_000_000, self.channels_with_funds, exclude_single_parts=True)
31 self.assertEqual({0: 660_000_000, 1: 340_000_000, 2: 0, 3: 0}, splits[0][0])
32
33 with self.subTest(msg="do a payment with a larger amount than what is supported by a single channel"):
34 splits = mpp_split.suggest_splits(1_100_000_000, self.channels_with_funds, exclude_single_parts=True)
35 self.assertEqual(2, mpp_split.number_nonzero_parts(splits[0][0]))
36
37 with self.subTest(msg="do a payment with the maximal amount spendable over all channels"):
38 splits = mpp_split.suggest_splits(sum(self.channels_with_funds.values()), self.channels_with_funds, exclude_single_parts=True)
39 self.assertEqual({0: 1_000_000_000, 1: 500_000_000, 2: 302_000_000, 3: 101_000_000}, splits[0][0])
40
41 with self.subTest(msg="do a payment with the amount supported by all channels"):
42 splits = mpp_split.suggest_splits(101_000_000, self.channels_with_funds, exclude_single_parts=False)
43 for s in splits[:4]:
44 self.assertEqual(1, mpp_split.number_nonzero_parts(s[0]))
45
46 def test_saturation(self):
47 """Split configurations which spend the full amount in a channel should be avoided."""
48 channels_with_funds = {0: 159_799_733_076, 1: 499_986_152_000}
49 splits = mpp_split.suggest_splits(600_000_000_000, channels_with_funds, exclude_single_parts=True)
50
51 uses_full_amount = False
52 for c, a in splits[0][0].items():
53 if a == channels_with_funds[c]:
54 uses_full_amount |= True
55
56 self.assertFalse(uses_full_amount)
57
58 def test_payment_below_min_part_size(self):
59 amount = mpp_split.MIN_PART_MSAT // 2
60 splits = mpp_split.suggest_splits(amount, self.channels_with_funds, exclude_single_parts=False)
61 # we only get four configurations that end up spending the full amount
62 # in a single channel
63 self.assertEqual(4, len(splits))
64
65 def test_suggest_part_penalty(self):
66 """Test is mainly for documentation purposes.
67 Decreasing the part penalty from 1.0 towards 0.0 leads to an increase
68 in the number of parts a payment is split. A configuration which has
69 about equally distributed amounts will result."""
70 with self.subTest(msg="split payments with intermediate part penalty"):
71 mpp_split.PART_PENALTY = 1.0
72 splits = mpp_split.suggest_splits(1_100_000_000, self.channels_with_funds)
73 self.assertEqual(2, mpp_split.number_nonzero_parts(splits[0][0]))
74
75 with self.subTest(msg="split payments with intermediate part penalty"):
76 mpp_split.PART_PENALTY = 0.3
77 splits = mpp_split.suggest_splits(1_100_000_000, self.channels_with_funds)
78 self.assertEqual(3, mpp_split.number_nonzero_parts(splits[0][0]))
79
80 with self.subTest(msg="split payments with no part penalty"):
81 mpp_split.PART_PENALTY = 0.0
82 splits = mpp_split.suggest_splits(1_100_000_000, self.channels_with_funds)
83 self.assertEqual(4, mpp_split.number_nonzero_parts(splits[0][0]))
84
85 def test_suggest_splits_single_channel(self):
86 channels_with_funds = {
87 0: 1_000_000_000,
88 }
89
90 with self.subTest(msg="do a payment with the maximal amount spendable on a single channel"):
91 splits = mpp_split.suggest_splits(1_000_000_000, channels_with_funds, exclude_single_parts=False)
92 self.assertEqual({0: 1_000_000_000}, splits[0][0])
93 with self.subTest(msg="test sending an amount greater than what we have available"):
94 self.assertRaises(NoPathFound, mpp_split.suggest_splits, *(1_100_000_000, channels_with_funds))