tezos-checker / checker

An in-development "robocoin" system for the Tezos blockchain
24 stars 16 forks source link

internalError_KitSubNegative error raised #209

Closed gkaracha closed 3 years ago

gkaracha commented 3 years ago

While developing #207 I came across a scenario which raises an internal error (internalError_KitSubNegative). I tried to simplify the example a bit though it probably can be simplified further. The scenario goes as follows:

  1. Initial state (timestamp:0, level:0):

    last_index = 1_000_000n
    circulating = 0mukit
    outstanding = 0mukit
  2. After (~seconds_passed:0 ~blocks_passed:0), create a burrow with 10_000_000mutez (1tez deposit + 9tez collateral).

    circulating = 0mukit
    outstanding = 0mukit
  3. After (~seconds_passed:1181 ~blocks_passed:18), mint as much kit as possible (4_285_714mukit).

    circulating = 4_285_714mukit
    outstanding = 4_285_714mukit
    alice_addr : 4_285_714mukit
  4. After (~seconds_passed:0 ~blocks_passed:0), set the last observed index to 1_357_906n

  5. After (~seconds_passed:(60 * 191) ~blocks_passed:191), touch checker (last index still at 1_357_906n).

    circulating = 205_969_055mukit  -- 4_285_714mukit minted + 201_683_333 touch reward + 8mukit cfmm accrual
    outstanding = 4_285_807mukit    -- 4_285_714mukit minted scaled up (burrowing fees and/or imbalance)
    alice_addr : 205_969_047mukit  -- 4_285_714mukit minted + 201_683_333 touch reward
    checker    : 8mukit            -- accrual of burrow fees to cfmm.kit
  6. After (~seconds_passed:342 ~blocks_passed:5), mark the burrow for liquidation.

    circulating = 205_969_055mukit  -- (as it was) 4_285_714mukit minted + 201_683_333 touch reward + 8mukit cfmm accrual
    outstanding = 4_285_807mukit    -- (as it was) 4_285_714mukit minted scaled up (burrowing fees and/or imbalance)
    alice_addr : 205_969_047mukit  -- (as it was) 4_285_714mukit minted + 201_683_333 touch reward
    checker    : 8mukit            -- (as it was) accrual of burrow fees to cfmm.kit
  7. After (~seconds_passed:63 ~blocks_passed:1), touch checker to start an auction (last index still at 1_357_906n).

    circulating = 206_644_055mukit -- (+675_000mukit touch reward)
    outstanding = 4_285_809mukit   -- (+2mukit (burrowing fees and/or imbalance))
    alice_addr : 206_644_047mukit -- (+675_000mukit touch reward)
    checker    : 8mukit           -- (as it was) accrual of burrow fees to cfmm.kit
  8. After (~seconds_passed:394 ~blocks_passed:6), place a bid of 4_285_824mukit.

    circulating = 206_644_055mukit -- (as it was)
    outstanding = 4_285_809mukit   -- (as it was)
    alice_addr : 202_358_223mukit -- (-4_285_824mukit auction bid)
    checker    : 4_285_832mukit   -- (8mukit in cfmm.kit + 4_285_824mukit auction bid)
  9. If we touch checker now, what happens is that the received kit (the bid, equal to 4_285_824mukit) is subtracted (burned) from the outstanding kit (currently at 4_285_820mukit, 4mukit less than the bid) and we get a failure.

Each individual step above makes sense to me, so I am not entirely sure how to classify this error. Some thoughts:

Any thoughts?

gkaracha commented 3 years ago

More thoughts on this:

I believe it's a more general issue, arising when parameters.circulating_kit exceeds parameters.outstanding_kit. We might thus be able to treat similar cases similarly.

I thought initially that perhaps burning from the total parameters.outstanding_kit the burrow.outstanding_kit when touching a slice would be sufficient to protect us from the error above, but I don't think so after all. As stated in #156, parameters.oustanding_kit can potentially drift from the real value (i.e., sum burrow_i.outstanding_kit), and we have not evaluated yet how far can that be. My expectation (given the calculations) is that

parameters.oustanding_kit >= sum burrow_i.outstanding_kit

but that remains to be seen. Hopefully #204 will help with this.

So, I think the safest option when returning a slice (or, in general, when removing kit from parameters.outstanding_kit) is to burn up to parameters.outstanding_kit, and deal with the remaining kit differently. The best way to deal with it that I can think of is to burn the excess as well (i.e., subtract it from parameters.circulating_kit). So, in short, when touching a slice:

kit_to_remove_from_outstanding = min parameters.outstanding_kit kit_from_auction
kit_to_remove_from_circulating = kit_from_auction

parameters.outstanding_kit = parameters.outstanding_kit - kit_to_remove_from_outstanding
parameters.circulating_kit = parameters.circulating_kit - kit_to_remove_from_circulating

I am not sure what this means for the system though (e.g., if it introduces the wrong incentives, or positive feedback loops).

@murbard I could use your input on this one :slightly_smiling_face:

Edit: Actually, I think that we should eliminate the concept of excess_kit as well, for the reasons I mentioned on #136. I think it's much cleaner if we just credit the burrow owner the excess kit directly.