raiden-network / raiden

Raiden Network

Home Page:https://developer.raiden.network

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

MFEE4 hardcoded balances are imprecise

andrevmatos opened this issue · comments

Problem Definition

While implementing raiden-network/light-client#2785 and testing with values generated from a recent develop python client, I could not match the exact values returned for the piecewise imbalance penalty function generated from the client in JS. After some debugging, it became clear the culprit was calculate_imbalance_fees. It relies heavily in python's big binary number calculation, which can't be easily reproduced in other platforms. More specifically, the o ** b operation is the more problematic, since often o is the 1e+18 magnitude, and b may be fractional (e.g 2.5), giving a result in the order of 1e+45, which gave me a parameter a of 4.0000000000000003e-29, clearly indicating a binary rounding error.
Besides this, in several places, plain round calls are made which hide the fact that python rounds using the ROUND_HALF_EVEN heuristic (half decimals are rounded in even's direction).

It's not good that the reference implementation depends on such platform-specific details, so my suggestion is that these calculations are done using Decimal or other arbitrary generic number format. Hopefully, this should be enough to fix these precision issues. Also, moving to only integer arithmetic operations on producing these numbers would completely remove the source of differences between platforms (big floating point numbers handling).

As a quick workaround before that, we'd appreciate that the values asserted in MFEE4 scenario are relaxed a bit. In our tests, allow_balance_error: 10 is double what we need, should give a good margin, which is still 5e-16 times smaller than the transfer amount itself, so pretty negligible considering the default added fee margins.

For reference, below is the diff of the python's imbalance penalty curve (what's sent in PFSFeeUpdate message) for MFEE4's 2e+18 total capacity, where - are python's y values, and + is LC's decimal.js output with 40 significant digits precision and explicit ROUND_HALF_EVEN behavior (as PC's):

    @@ -6,27 +6,27 @@
            "0",
            "40000000000000000",
          ],
          Array [
            "100000000000000000",
    -       "30737338856836652",
    +       "30737338856836647",
          ],
          Array [
            "200000000000000000",
    -       "22897336089597848",
    +       "22897336089597846",
          ],
          Array [
            "300000000000000000",
    -       "16398536520067884",
    +       "16398536520067881",
          ],
          Array [
            "400000000000000000",
    -       "11154192037077362",
    +       "11154192037077361",
          ],
          Array [
            "500000000000000000",
    -       "7071067811865476",
    +       "7071067811865475",
          ],
          Array [
            "600000000000000000",
            "4047715405015526",
          ],
    @@ -62,27 +62,27 @@
            "1400000000000000000",
            "4047715405015526",
          ],
          Array [
            "1500000000000000000",
    -       "7071067811865476",
    +       "7071067811865475",
          ],
          Array [
            "1600000000000000000",
    -       "11154192037077362",
    +       "11154192037077361",
          ],
          Array [
            "1700000000000000000",
    -       "16398536520067884",
    +       "16398536520067881",
          ],
          Array [
            "1800000000000000000",
    -       "22897336089597848",
    +       "22897336089597846",
          ],
          Array [
            "1900000000000000000",
    -       "30737338856836652",
    +       "30737338856836647",
          ],
          Array [
            "2000000000000000000",
            "40000000000000000",
          ],