MerosCrypto / Meros

An instant and feeless cryptocurrency for the future, secured by the Merit Caching Consensus Mechanism.
https://meroscrypto.io
Other
82 stars 19 forks source link

Unlocked Merit can become negative. #264

Closed kayabaNerve closed 3 years ago

kayabaNerve commented 3 years ago

Discovered during the recent testnet thanks to @Vyryn.

Unlocked is produced by state.counted - state.pending. Both can turn negative of their own accord thanks to the Dead Merit code, notably an oversight which updated these variables based on the status of who just gained Merit, not whoever just lost Merit.

This bug did end the testnet. While nodes were stable, and we never hit a negative Merit threshold thanks to a max statement, this did change Mints and therefore invalidate most of the chain. The net ran for 4.5 days out of its planned 7 days,

kayabaNerve commented 3 years ago

I generally don't comment with this sort of stuff, yet I feel it may be helpful.

I added this to the bottom of State.processBlock in order to find the first block at which these values diverged from the expectation.

  var
    tCopy: int = state.total
    cCopy: int = state.counted
    pCopy: int = state.pending
  try:
    for h in 0 ..< state.merit.len:
      tCopy -= state.merit[h]
      if state.statuses[h] == MeritStatus.Unlocked:
        cCopy -= state.merit[h]
      if state.statuses[h] == MeritStatus.Pending:
        cCopy -= state.merit[h]
        pCopy -= state.merit[h]
  except Exception as e:
    panic("Exception when checking Merit status of a holder: " & e.msg)
  if tCopy != 0:
    panic("Total is wrong.")
  if cCopy != 0:
    panic("Counted is wrong.")
  if pCopy != 0:
    panic("Pending is wrong.")