channeldb: make database logic MPP compatible

This commit redefines how the control tower handles shard and payment
level settles and failures. We now consider the payment in flight as
long it has active shards, or it has no active shards but has not
reached a terminal condition (settle of one of the shards, or a payment
level failure has been encountered).

We also make it possible to settle/fail shards regardless of the payment
level status (since we must allow late shards recording their status
even though we have already settled/failed the payment).

Finally, we make it possible to Fail the payment when it is already
failed. This is to allow multiple concurrent shards that reach terminal
errors to mark the payment failed, without havinng to synchronize.
This commit is contained in:
Johan T. Halseth
2020-04-01 00:13:25 +02:00
parent f6c97daf0c
commit 70202be580
4 changed files with 138 additions and 83 deletions

View File

@@ -290,16 +290,7 @@ func (m *mockControlTower) SettleAttempt(phash lntypes.Hash,
m.success <- successArgs{settleInfo.Preimage}
}
// Only allow setting attempts for payments not yet succeeded or
// failed.
if _, ok := m.successful[phash]; ok {
return channeldb.ErrPaymentAlreadySucceeded
}
if _, ok := m.failed[phash]; ok {
return channeldb.ErrPaymentAlreadyFailed
}
// Only allow setting attempts if the payment is known.
p, ok := m.payments[phash]
if !ok {
return channeldb.ErrPaymentNotInitiated
@@ -311,6 +302,13 @@ func (m *mockControlTower) SettleAttempt(phash lntypes.Hash,
continue
}
if a.Settle != nil {
return channeldb.ErrAttemptAlreadySettled
}
if a.Failure != nil {
return channeldb.ErrAttemptAlreadyFailed
}
p.attempts[i].Settle = settleInfo
// Mark the payment successful on first settled attempt.
@@ -327,16 +325,7 @@ func (m *mockControlTower) FailAttempt(phash lntypes.Hash, pid uint64,
m.Lock()
defer m.Unlock()
// Only allow failing attempts for payments not yet succeeded or
// failed.
if _, ok := m.successful[phash]; ok {
return channeldb.ErrPaymentAlreadySucceeded
}
if _, ok := m.failed[phash]; ok {
return channeldb.ErrPaymentAlreadyFailed
}
// Only allow failing attempts if the payment is known.
p, ok := m.payments[phash]
if !ok {
return channeldb.ErrPaymentNotInitiated
@@ -348,6 +337,13 @@ func (m *mockControlTower) FailAttempt(phash lntypes.Hash, pid uint64,
continue
}
if a.Settle != nil {
return channeldb.ErrAttemptAlreadySettled
}
if a.Failure != nil {
return channeldb.ErrAttemptAlreadyFailed
}
p.attempts[i].Failure = failInfo
return nil
}
@@ -365,15 +361,7 @@ func (m *mockControlTower) Fail(phash lntypes.Hash,
m.fail <- failArgs{reason}
}
// Cannot fail already successful or failed payments.
if _, ok := m.successful[phash]; ok {
return channeldb.ErrPaymentAlreadySucceeded
}
if _, ok := m.failed[phash]; ok {
return channeldb.ErrPaymentAlreadyFailed
}
// Payment must be known.
if _, ok := m.payments[phash]; !ok {
return channeldb.ErrPaymentNotInitiated
}