raiden-contracts
raiden-contracts copied to clipboard
Can't recover from state loss after close/update and before settle
If a pair of nodes call closeChannel
/updateNonClosingBalanceProof
, but then for any reason lose the state (namely, transferred_amount
, locked_amount
& locksroot
of each side which produced the balance_hash
of the close/update calls), the channel can never be settled, the funds stay forever locked in the contracts, and that pair of nodes can never have a new channel between them on the same TokeNetwork.
Of course we don't expect both nodes to lose state often, but nonetheless IMO this lockout scenario isn't desired in any situation, and maybe we can consider this a bug to be fixed.
@andrevmatos is your focus more on not being able to recover the funds or not being able to open a new channel within that pair?
- [ ] Discussion: Is the assumption still valid in the current raiden
- [ ] Is this a problem which we want to cover somehow?
- [ ] If yes, make a proposal how to solve this issue
I think both, but on our testnet testings, what was more annoying was not being able to open a new channel within that pair. The main point of this issue is that closing/updating with hashes, but requiring the actual values to settle, works as an unintended secrecy mechanism between closing and settling. Although settling is expected to be able to be performed by anyone, in practice, current method can only be called by someone who knows the amounts which composed both side's balanceHash.
In a discussion with andre he stated that this problem appears to be more relevant in the LC since it only stores the latest balance hashes. This issue is addressed in https://github.com/raiden-network/light-client/issues/1607
That LightClient issue isn't replacing this one. It was just a new issue we discovered about our LC implementation upon thinking more about it in the light of this one, but this is a different issue, which can affect not only the light-client.
It happens if both nodes lose state (e.g delete ~/.raiden
) after close/update, but before settling a channel. Of course, it isn't expected for this to happen and surely not advisable, but IMO this doesn't excuse the contracts from holding the funds forever with no way to settle this, and also preventing the peers from connecting again on this token network.
This issue happen because on close/update, the nodes set a balanceHash
, which is the hash of 3 fields: transferredAmount
, lockedAmount
and locksroot
, on each other's side of the channel, and this works as a kind of secret. After settleTimeout
, anyone can call settleChannel
, but need to know the 6 values which generated the hash stored for both sides. If the state is lost and the peers can't know the values which composed the hashes, the SC don't allow anyone in the world, not even the peers accounts, to settle the channel, the funds stays locked forever on it and the peers can never reopen a channel on this network with each other again.
We could still allow a cooperative settle in that case. That would nicely solve the issue without introducing much additional code to write and test and even allows the nodes to decide on the fair split in this case in a flexible way. I don't think we need to provide a way for totally uncooperative nodes to resolve this rare case. If the alternative is to not get any funds out, the nodes should be willing to cooperate somehow.
other options
- allow to open concurrent channels (n closed, not settled, channels can coexist with one open channel), see https://github.com/raiden-network/raiden-contracts/issues/916
- allow for a default settlement (back to initial deposits) after waiting, e.g.
10 * settlement_timeout
- allow for full balance proofs at closing time
- don't fix it: addresses are cheap
For this current sprint, we want to come to a decision on the way forward.
Looking through the TokenNetwork code, it seems like withdraws are possible for closed (but not settled) channels. So the tokens are not lost if both participants can agree on the balances. If both participants lost their dbs, I would expect them to revert to the on-chain balances and would thus be in agreement about the balances. This is similar to what I wrote about coop settle above, but more interesting, since we already have working withdraws.
This does not help with the "we can't get an open channel between those participants again"-problem, though.
Ok, after a call with @karlb , we understand that allowing for a default settle after no matter how long timeout isn't advisable, since the nodes are responsible for settling (there's no MS for settle) and a node which knows their partner will be offline for long can take advantage this to do a unilateral settle. Full BPs at closing time has the drawback of being less private, since the MSs would need to not only be provided with hashed/shadowed balanceHashes but actually with full values which would reveal too much about the transfer history. So the best way which don't put user's funds at risk (at least not anymore than they would already be on state loss) would be cooperative settle. Possibly we could have normal coopSettle (like one done without close, to speed up settling, as in commented code in current contracts) but taking care of allowing it also after close/update, but regardless of its values, so a coopSettle can be performed with zeroed/agreed values even on this unexpecter state, at any point in time (before or after close/update, before or after settleTimeout) as long as the both peers agree/sign on the values. Related #399 and #1383