raiden-contracts
raiden-contracts copied to clipboard
Proposal for a new type of refund/cancellation
This is a rough sketch, it is by no means correct. I'm opening the issue so that we don't lose this proposal:
All values bellow are monotonic increasing.
## Settlement computation on-chain
Node's values set on the smart contract:
D = confirmed deposit
W = withdraw
Partner's balance proof values sent by the node:
L = locked
U = unlocked
E = expired
R = refund
Node's balance proof values sent by the partner:
R' = refund
U' = unlocked
Computed
N = net
P = pending
Constraints:
L,U,E,R,R',U',D,W >= 0
L >= U + E
Formulas:
N = D - W - U + U'
P = L - max(R', E) - U
The idea here is: For a channel A-B, the above definition would allow B to send a balance proof that changes the locked amount of A, with this balance proof A could prove to the smart contract that the tokens have been returned by B to A, so no backwards transfer would be required.
The biggest question that I have with the above is that if a locksroot is also required, or if just a returned amount is sufficient.
max
in max(R', E)
looks weird to me. You don't care about the value of R'
when you have lots of expired locks?
The biggest question that I have with the above is that if a locksroot is also required, or if just a returned amount is sufficient.
I think a locksroot is required. Say two transfers with two different secret hashes were refunded. And say only one of the secrets has been revealed. Now it matters a lot which lock was refunded and which lock is alive.
max in max(R', E) looks weird to me. You don't care about the value of R' when you have lots of expired locks?
I don't understand. How does max(R', E)
mean that expired locks are ignored? (I'm assuming that is what you meant by don't care).
The core idea here is that both participants will be changing the same value. To avoid synchronization among the parties the value is made monotonic and max
is used, otherwise we would require some sort of synchronization among the nodes to change this value. The next thing is to make sure the result of max(R', E)
is semantically correct and not exploitable.
max(0,100)
is equal to max(20,100)
. So when E
is 100
, you don't care whether R'
is 0
or 20
.
That's weird. When the channel is very young, E
is still zero, so every change in R'
matters. When the channel is very old after many expired locks of some value, E
would be big, and you don't care about small R'
s anymore.
I think E
can grow big while R'
can stay at zero.
max(0,100) is equal to max(20,100). So when E is 100, you don't care whether R' is 0 or 20.
Yes, that is intentional.
It has to possibilities, R' < E
or E < R'
. The value of R'
is controlled by the partner node, while the value of E
is controlled by the local node. For the case R' < E
the result would be E
, this means the local node does not have to wait for the partner to send a RemovedExpiredLock
message. E < R'
is the opposite, the partner does not have to wait for the local node to send a RefundTransfer
@hackaugusto
-
I send locked transfers but never reveal secrets. So
E == 100
or something. -
I send a payment through this channel but the routing fails, so I get a refund
R' == 20
. -
The max computation kills my refund.
@pirapira That would be an invalid message, it does not refund anything, the correct value for R'
is the previous E
in addition to the new refund amount, so it should be 120
.
Refunds include expired locks?
With this definition, yes. Pretty much a refund message would be the partner node saying it's okay for the local node to use the tokens from a given lock, because the partner is "anticipating" the expiration.
Edit: Perhaps refund is a bad name for this approach, but I didn't think much about alternative names and this is a proposal for a new approach to refunds after all.
I see definitions:
R' = refund
E = expired
but I see no equations between refund
and expired
.
Are they somehow related?
Is it intentional that
U' = unlock
Has unlock
instead of unlocked
?
Are they somehow related?
Yes, they are "the same value" from the settlement algorithm perspective. This happens because the max
is used in formula P = L - max(R', E) - U
.
So, R'
and E
supposed to be equal in a completely synchronous world?
Still max
is weird.
Let's say we have an event 1 that inceases R'
. And event 2 that increases E
. Both events increase the value by 10. In total the increase should be 20.
Event 1 happened on the peer's side so I see R' == 10
. Event 2 happened on my side so I see E == 10
. These two ten's come from different causes so the perfectly synchronous world I should see 20 already, but the max
calculation only gives me 10.
Yes, they are "the same value" from the settlement algorithm perspective. This happens because the max is used in formula P = L - max(R', E) - U.
Now you've put me in a loop. I asked why max
and you answered it's because the same value. It's the same value because the max is used?
I need to see what kind of event increases which variable.
Here are two examples:
A -> B; LockedTransfer; locked_amount = 10 B -> A; Refund; refund_amount = 10
With the above, there is nothing pending, so P = L - max(R', E) - U
would be P = 0 - max(10, 0) - 0
, and there is not transfer of value. Which means the partner did a refund without locking additional funds.
Let's add some interaction:
A -> B; LockedTransfer; locked_amount = 10 A -> B; LockedTransfer; locked_amount = 20 B -> A; Refund; refund_amount = 10 A -> B; Unlock; unlocked_amount = 10
In this case, there is nothing pending P = L - max(R', E) - U
would be P = 20 - max(10, 0) - 10
, and the partner get the 10 tokens, because it had a net positive of 10 token from the formula N = D - W - U' + U
, which would be N = D - 0 - 0 + 10
(Note: I had to fix the net formula)
This is a hard case for me:
- A->B; LockedTransfer
- A->B; LockedTransfer
- Time passes
- B->A; RefundTransfer for 1
- A->B; RemoveExpiredLock for 2
I don't really know how to fix that race.
A -> B; LockedTransfer; locked_amount = 10 A -> B; LockedTransfer; locked_amount = 20 B -> A; Refund; refund_amount = 10 A -> B; Unlock; unlocked_amount = 10
So the two parties disagree on the first lock, whether it's refunded or unlocked?
When you send RemoveExpiredLock, do you write a bigger E
?
When you receive Refund, do you expect a bigger R'
?
1. A->B; LockedTransfer
2. A->B; LockedTransfer
3. Time passes
4. B->A; RefundTransfer for 1
5. A->B; RemoveExpiredLock for 2
What's hard about this? I see no conflicting information.
So the two parties disagree on the first lock, whether it's refunded or unlocked?
No, the values are monotonic, so a locked_amount
of 20
means a second lock of 10
. I didn't specify which lock was unlocked an which was refunded in the example for simplicity's sake.
When you send RemoveExpiredLock, do you write a bigger E? When you receive Refund, do you expect a bigger R'?
Yes
Then why do E
and R'
grow together?
Then why do E and R' grow together?
They are changed by different computers separated by a network in between.
Edit: By "together", do you mean atomically?
I heard E
and R'
are "the same value" (in the synchronous world).
What's hard about this? I see no conflicting information.
One of the messages will be invalid, and then we have to reprocess the queue of messages. The whole point of using monotonically increasing values is to avoid synchronization, we need a policy on how to move forward even if that happens without having to synchronize.
Is there a rule like, "When you receive Refund, you have to send RemoveExpiredLock"?