channeldb: return updated payment on attempt update

Similar to what is done for SettleAttempt.

Co-authored-by: Johan T. Halseth <johanth@gmail.com>
This commit is contained in:
Joost Jager 2020-04-06 09:26:52 +02:00
parent 351d8e174c
commit 278915e598
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7
3 changed files with 50 additions and 36 deletions

View File

@ -186,38 +186,39 @@ func (p *PaymentControl) InitPayment(paymentHash lntypes.Hash,
// RegisterAttempt atomically records the provided HTLCAttemptInfo to the
// DB.
func (p *PaymentControl) RegisterAttempt(paymentHash lntypes.Hash,
attempt *HTLCAttemptInfo) error {
attempt *HTLCAttemptInfo) (*MPPayment, error) {
// Serialize the information before opening the db transaction.
var a bytes.Buffer
err := serializeHTLCAttemptInfo(&a, attempt)
if err != nil {
return err
return nil, err
}
htlcInfoBytes := a.Bytes()
htlcIDBytes := make([]byte, 8)
binary.BigEndian.PutUint64(htlcIDBytes, attempt.AttemptID)
return kvdb.Batch(p.db.Backend, func(tx kvdb.RwTx) error {
var payment *MPPayment
err = kvdb.Batch(p.db.Backend, func(tx kvdb.RwTx) error {
bucket, err := fetchPaymentBucketUpdate(tx, paymentHash)
if err != nil {
return err
}
payment, err := fetchPayment(bucket)
p, err := fetchPayment(bucket)
if err != nil {
return err
}
// Ensure the payment is in-flight.
if err := ensureInFlight(payment); err != nil {
if err := ensureInFlight(p); err != nil {
return err
}
// We cannot register a new attempt if the payment already has
// reached a terminal condition:
settle, fail := payment.TerminalInfo()
settle, fail := p.TerminalInfo()
if settle != nil || fail != nil {
return ErrPaymentTerminal
}
@ -225,7 +226,7 @@ func (p *PaymentControl) RegisterAttempt(paymentHash lntypes.Hash,
// Make sure any existing shards match the new one with regards
// to MPP options.
mpp := attempt.Route.FinalHop().MPP
for _, h := range payment.InFlightHTLCs() {
for _, h := range p.InFlightHTLCs() {
hMpp := h.Route.FinalHop().MPP
switch {
@ -258,13 +259,13 @@ func (p *PaymentControl) RegisterAttempt(paymentHash lntypes.Hash,
// If this is a non-MPP attempt, it must match the total amount
// exactly.
amt := attempt.Route.ReceiverAmt()
if mpp == nil && amt != payment.Info.Value {
if mpp == nil && amt != p.Info.Value {
return ErrValueMismatch
}
// Ensure we aren't sending more than the total payment amount.
sentAmt, _ := payment.SentAmt()
if sentAmt+amt > payment.Info.Value {
sentAmt, _ := p.SentAmt()
if sentAmt+amt > p.Info.Value {
return ErrValueExceedsAmt
}
@ -282,8 +283,20 @@ func (p *PaymentControl) RegisterAttempt(paymentHash lntypes.Hash,
return err
}
return htlcBucket.Put(htlcAttemptInfoKey, htlcInfoBytes)
err = htlcBucket.Put(htlcAttemptInfoKey, htlcInfoBytes)
if err != nil {
return err
}
// Retrieve attempt info for the notification.
payment, err = fetchPayment(bucket)
return err
})
if err != nil {
return nil, err
}
return payment, err
}
// SettleAttempt marks the given attempt settled with the preimage. If this is
@ -307,16 +320,15 @@ func (p *PaymentControl) SettleAttempt(hash lntypes.Hash,
// FailAttempt marks the given payment attempt failed.
func (p *PaymentControl) FailAttempt(hash lntypes.Hash,
attemptID uint64, failInfo *HTLCFailInfo) error {
attemptID uint64, failInfo *HTLCFailInfo) (*MPPayment, error) {
var b bytes.Buffer
if err := serializeHTLCFailInfo(&b, failInfo); err != nil {
return err
return nil, err
}
failBytes := b.Bytes()
_, err := p.updateHtlcKey(hash, attemptID, htlcFailInfoKey, failBytes)
return err
return p.updateHtlcKey(hash, attemptID, htlcFailInfoKey, failBytes)
}
// updateHtlcKey updates a database key for the specified htlc.

View File

@ -117,13 +117,13 @@ func TestPaymentControlSwitchFail(t *testing.T) {
// Record a new attempt. In this test scenario, the attempt fails.
// However, this is not communicated to control tower in the current
// implementation. It only registers the initiation of the attempt.
err = pControl.RegisterAttempt(info.PaymentHash, attempt)
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt)
if err != nil {
t.Fatalf("unable to register attempt: %v", err)
}
htlcReason := HTLCFailUnreadable
err = pControl.FailAttempt(
_, err = pControl.FailAttempt(
info.PaymentHash, attempt.AttemptID,
&HTLCFailInfo{
Reason: htlcReason,
@ -143,7 +143,7 @@ func TestPaymentControlSwitchFail(t *testing.T) {
// Record another attempt.
attempt.AttemptID = 1
err = pControl.RegisterAttempt(info.PaymentHash, attempt)
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt)
if err != nil {
t.Fatalf("unable to send htlc message: %v", err)
}
@ -236,7 +236,7 @@ func TestPaymentControlSwitchDoubleSend(t *testing.T) {
}
// Record an attempt.
err = pControl.RegisterAttempt(info.PaymentHash, attempt)
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt)
if err != nil {
t.Fatalf("unable to send htlc message: %v", err)
}
@ -375,7 +375,7 @@ func TestPaymentControlDeleteNonInFligt(t *testing.T) {
if err != nil {
t.Fatalf("unable to send htlc message: %v", err)
}
err = pControl.RegisterAttempt(info.PaymentHash, attempt)
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt)
if err != nil {
t.Fatalf("unable to send htlc message: %v", err)
}
@ -387,7 +387,7 @@ func TestPaymentControlDeleteNonInFligt(t *testing.T) {
if p.failed {
// Fail the payment attempt.
htlcFailure := HTLCFailUnreadable
err := pControl.FailAttempt(
_, err := pControl.FailAttempt(
info.PaymentHash, attempt.AttemptID,
&HTLCFailInfo{
Reason: htlcFailure,
@ -520,7 +520,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
a.AttemptID = i
attempts = append(attempts, &a)
err = pControl.RegisterAttempt(info.PaymentHash, &a)
_, err = pControl.RegisterAttempt(info.PaymentHash, &a)
if err != nil {
t.Fatalf("unable to send htlc message: %v", err)
}
@ -541,7 +541,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
// will be too large.
b := *attempt
b.AttemptID = 3
err = pControl.RegisterAttempt(info.PaymentHash, &b)
_, err = pControl.RegisterAttempt(info.PaymentHash, &b)
if err != ErrValueExceedsAmt {
t.Fatalf("expected ErrValueExceedsAmt, got: %v",
err)
@ -550,7 +550,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
// Fail the second attempt.
a := attempts[1]
htlcFail := HTLCFailUnreadable
err = pControl.FailAttempt(
_, err = pControl.FailAttempt(
info.PaymentHash, a.AttemptID,
&HTLCFailInfo{
Reason: htlcFail,
@ -596,7 +596,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
t, pControl, info.PaymentHash, info, nil, htlc,
)
} else {
err := pControl.FailAttempt(
_, err := pControl.FailAttempt(
info.PaymentHash, a.AttemptID,
&HTLCFailInfo{
Reason: htlcFail,
@ -634,7 +634,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
// that the payment has reached a terminal condition.
b = *attempt
b.AttemptID = 3
err = pControl.RegisterAttempt(info.PaymentHash, &b)
_, err = pControl.RegisterAttempt(info.PaymentHash, &b)
if err != ErrPaymentTerminal {
t.Fatalf("expected ErrPaymentTerminal, got: %v", err)
}
@ -666,7 +666,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
)
} else {
// Fail the attempt.
err := pControl.FailAttempt(
_, err := pControl.FailAttempt(
info.PaymentHash, a.AttemptID,
&HTLCFailInfo{
Reason: htlcFail,
@ -708,7 +708,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
assertPaymentStatus(t, pControl, info.PaymentHash, finalStatus)
// Finally assert we cannot register more attempts.
err = pControl.RegisterAttempt(info.PaymentHash, &b)
_, err = pControl.RegisterAttempt(info.PaymentHash, &b)
if err != expRegErr {
t.Fatalf("expected error %v, got: %v", expRegErr, err)
}
@ -756,7 +756,7 @@ func TestPaymentControlMPPRecordValidation(t *testing.T) {
info.Value, [32]byte{1},
)
err = pControl.RegisterAttempt(info.PaymentHash, attempt)
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt)
if err != nil {
t.Fatalf("unable to send htlc message: %v", err)
}
@ -765,7 +765,7 @@ func TestPaymentControlMPPRecordValidation(t *testing.T) {
b := *attempt
b.AttemptID = 1
b.Route.FinalHop().MPP = nil
err = pControl.RegisterAttempt(info.PaymentHash, &b)
_, err = pControl.RegisterAttempt(info.PaymentHash, &b)
if err != ErrMPPayment {
t.Fatalf("expected ErrMPPayment, got: %v", err)
}
@ -774,7 +774,7 @@ func TestPaymentControlMPPRecordValidation(t *testing.T) {
b.Route.FinalHop().MPP = record.NewMPP(
info.Value, [32]byte{2},
)
err = pControl.RegisterAttempt(info.PaymentHash, &b)
_, err = pControl.RegisterAttempt(info.PaymentHash, &b)
if err != ErrMPPPaymentAddrMismatch {
t.Fatalf("expected ErrMPPPaymentAddrMismatch, got: %v", err)
}
@ -783,7 +783,7 @@ func TestPaymentControlMPPRecordValidation(t *testing.T) {
b.Route.FinalHop().MPP = record.NewMPP(
info.Value/2, [32]byte{1},
)
err = pControl.RegisterAttempt(info.PaymentHash, &b)
_, err = pControl.RegisterAttempt(info.PaymentHash, &b)
if err != ErrMPPTotalAmountMismatch {
t.Fatalf("expected ErrMPPTotalAmountMismatch, got: %v", err)
}
@ -801,7 +801,7 @@ func TestPaymentControlMPPRecordValidation(t *testing.T) {
}
attempt.Route.FinalHop().MPP = nil
err = pControl.RegisterAttempt(info.PaymentHash, attempt)
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt)
if err != nil {
t.Fatalf("unable to send htlc message: %v", err)
}
@ -813,7 +813,7 @@ func TestPaymentControlMPPRecordValidation(t *testing.T) {
info.Value, [32]byte{1},
)
err = pControl.RegisterAttempt(info.PaymentHash, &b)
_, err = pControl.RegisterAttempt(info.PaymentHash, &b)
if err != ErrNonMPPayment {
t.Fatalf("expected ErrNonMPPayment, got: %v", err)
}

View File

@ -107,7 +107,8 @@ func (p *controlTower) InitPayment(paymentHash lntypes.Hash,
func (p *controlTower) RegisterAttempt(paymentHash lntypes.Hash,
attempt *channeldb.HTLCAttemptInfo) error {
return p.db.RegisterAttempt(paymentHash, attempt)
_, err := p.db.RegisterAttempt(paymentHash, attempt)
return err
}
// SettleAttempt marks the given attempt settled with the preimage. If
@ -133,7 +134,8 @@ func (p *controlTower) SettleAttempt(paymentHash lntypes.Hash,
func (p *controlTower) FailAttempt(paymentHash lntypes.Hash,
attemptID uint64, failInfo *channeldb.HTLCFailInfo) error {
return p.db.FailAttempt(paymentHash, attemptID, failInfo)
_, err := p.db.FailAttempt(paymentHash, attemptID, failInfo)
return err
}
// FetchPayment fetches the payment corresponding to the given payment hash.