invoices: return accept height in hodl event
This is a preparation for passing back the accept height in the incorrect payment details failure message to the sender.
This commit is contained in:
parent
4e140213f9
commit
d3e206ef95
@ -272,7 +272,7 @@ type InvoiceHTLC struct {
|
|||||||
|
|
||||||
// State indicates the state the invoice htlc is currently in. A
|
// State indicates the state the invoice htlc is currently in. A
|
||||||
// cancelled htlc isn't just removed from the invoice htlcs map, because
|
// cancelled htlc isn't just removed from the invoice htlcs map, because
|
||||||
// we need AcceptedHeight to properly cancel the htlc back.
|
// we need AcceptHeight to properly cancel the htlc back.
|
||||||
State HtlcState
|
State HtlcState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +39,9 @@ type HodlEvent struct {
|
|||||||
// CircuitKey is the key of the htlc for which we have a resolution
|
// CircuitKey is the key of the htlc for which we have a resolution
|
||||||
// decision.
|
// decision.
|
||||||
CircuitKey channeldb.CircuitKey
|
CircuitKey channeldb.CircuitKey
|
||||||
|
|
||||||
|
// AcceptHeight is the original height at which the htlc was accepted.
|
||||||
|
AcceptHeight int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// InvoiceRegistry is a central registry of all the outstanding invoices
|
// InvoiceRegistry is a central registry of all the outstanding invoices
|
||||||
@ -552,20 +555,29 @@ func (i *InvoiceRegistry) NotifyExitHopHtlc(rHash lntypes.Hash,
|
|||||||
// If it isn't recorded, cancel htlc.
|
// If it isn't recorded, cancel htlc.
|
||||||
if !ok {
|
if !ok {
|
||||||
return &HodlEvent{
|
return &HodlEvent{
|
||||||
CircuitKey: circuitKey,
|
CircuitKey: circuitKey,
|
||||||
|
AcceptHeight: currentHeight,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine accepted height of this htlc. If the htlc reached the
|
||||||
|
// invoice database (possibly in a previous call to the invoice
|
||||||
|
// registry), we'll take the original accepted height as it was recorded
|
||||||
|
// in the database.
|
||||||
|
acceptHeight := int32(invoiceHtlc.AcceptHeight)
|
||||||
|
|
||||||
switch invoiceHtlc.State {
|
switch invoiceHtlc.State {
|
||||||
case channeldb.HtlcStateCancelled:
|
case channeldb.HtlcStateCancelled:
|
||||||
return &HodlEvent{
|
return &HodlEvent{
|
||||||
CircuitKey: circuitKey,
|
CircuitKey: circuitKey,
|
||||||
|
AcceptHeight: acceptHeight,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
case channeldb.HtlcStateSettled:
|
case channeldb.HtlcStateSettled:
|
||||||
return &HodlEvent{
|
return &HodlEvent{
|
||||||
CircuitKey: circuitKey,
|
CircuitKey: circuitKey,
|
||||||
Preimage: &invoice.Terms.PaymentPreimage,
|
Preimage: &invoice.Terms.PaymentPreimage,
|
||||||
|
AcceptHeight: acceptHeight,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
case channeldb.HtlcStateAccepted:
|
case channeldb.HtlcStateAccepted:
|
||||||
@ -622,8 +634,9 @@ func (i *InvoiceRegistry) SettleHodlInvoice(preimage lntypes.Preimage) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
i.notifyHodlSubscribers(HodlEvent{
|
i.notifyHodlSubscribers(HodlEvent{
|
||||||
CircuitKey: key,
|
CircuitKey: key,
|
||||||
Preimage: &preimage,
|
Preimage: &preimage,
|
||||||
|
AcceptHeight: int32(htlc.AcceptHeight),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
i.notifyClients(hash, invoice, invoice.Terms.State)
|
i.notifyClients(hash, invoice, invoice.Terms.State)
|
||||||
@ -703,7 +716,8 @@ func (i *InvoiceRegistry) CancelInvoice(payHash lntypes.Hash) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
i.notifyHodlSubscribers(HodlEvent{
|
i.notifyHodlSubscribers(HodlEvent{
|
||||||
CircuitKey: key,
|
CircuitKey: key,
|
||||||
|
AcceptHeight: int32(htlc.AcceptHeight),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
i.notifyClients(payHash, invoice, channeldb.ContractCanceled)
|
i.notifyClients(payHash, invoice, channeldb.ContractCanceled)
|
||||||
|
@ -23,6 +23,8 @@ var (
|
|||||||
|
|
||||||
testHtlcExpiry = uint32(5)
|
testHtlcExpiry = uint32(5)
|
||||||
|
|
||||||
|
testInvoiceCltvDelta = uint32(4)
|
||||||
|
|
||||||
testFinalCltvRejectDelta = int32(4)
|
testFinalCltvRejectDelta = int32(4)
|
||||||
|
|
||||||
testCurrentHeight = int32(1)
|
testCurrentHeight = int32(1)
|
||||||
@ -121,6 +123,23 @@ func TestSettleInvoice(t *testing.T) {
|
|||||||
|
|
||||||
hodlChan := make(chan interface{}, 1)
|
hodlChan := make(chan interface{}, 1)
|
||||||
|
|
||||||
|
// Try to settle invoice with an htlc that expires too soon.
|
||||||
|
event, err := registry.NotifyExitHopHtlc(
|
||||||
|
hash, testInvoice.Terms.Value,
|
||||||
|
uint32(testCurrentHeight)+testInvoiceCltvDelta-1,
|
||||||
|
testCurrentHeight, getCircuitKey(10), hodlChan, nil,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if event.Preimage != nil {
|
||||||
|
t.Fatal("expected cancel event")
|
||||||
|
}
|
||||||
|
if event.AcceptHeight != testCurrentHeight {
|
||||||
|
t.Fatalf("expected acceptHeight %v, but got %v",
|
||||||
|
testCurrentHeight, event.AcceptHeight)
|
||||||
|
}
|
||||||
|
|
||||||
// Settle invoice with a slightly higher amount.
|
// Settle invoice with a slightly higher amount.
|
||||||
amtPaid := lnwire.MilliSatoshi(100500)
|
amtPaid := lnwire.MilliSatoshi(100500)
|
||||||
_, err = registry.NotifyExitHopHtlc(
|
_, err = registry.NotifyExitHopHtlc(
|
||||||
@ -159,7 +178,7 @@ func TestSettleInvoice(t *testing.T) {
|
|||||||
|
|
||||||
// Try to settle again with the same htlc id. We need this idempotent
|
// Try to settle again with the same htlc id. We need this idempotent
|
||||||
// behaviour after a restart.
|
// behaviour after a restart.
|
||||||
event, err := registry.NotifyExitHopHtlc(
|
event, err = registry.NotifyExitHopHtlc(
|
||||||
hash, amtPaid, testHtlcExpiry, testCurrentHeight,
|
hash, amtPaid, testHtlcExpiry, testCurrentHeight,
|
||||||
getCircuitKey(0), hodlChan, nil,
|
getCircuitKey(0), hodlChan, nil,
|
||||||
)
|
)
|
||||||
@ -309,7 +328,7 @@ func TestCancelInvoice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Notify arrival of a new htlc paying to this invoice. This should
|
// Notify arrival of a new htlc paying to this invoice. This should
|
||||||
// succeed.
|
// result in a cancel event.
|
||||||
hodlChan := make(chan interface{})
|
hodlChan := make(chan interface{})
|
||||||
event, err := registry.NotifyExitHopHtlc(
|
event, err := registry.NotifyExitHopHtlc(
|
||||||
hash, amt, testHtlcExpiry, testCurrentHeight,
|
hash, amt, testHtlcExpiry, testCurrentHeight,
|
||||||
@ -322,10 +341,15 @@ func TestCancelInvoice(t *testing.T) {
|
|||||||
if event.Preimage != nil {
|
if event.Preimage != nil {
|
||||||
t.Fatal("expected cancel hodl event")
|
t.Fatal("expected cancel hodl event")
|
||||||
}
|
}
|
||||||
|
if event.AcceptHeight != testCurrentHeight {
|
||||||
|
t.Fatalf("expected acceptHeight %v, but got %v",
|
||||||
|
testCurrentHeight, event.AcceptHeight)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestHoldInvoice tests settling of a hold invoice and related notifications.
|
// TestSettleHoldInvoice tests settling of a hold invoice and related
|
||||||
func TestHoldInvoice(t *testing.T) {
|
// notifications.
|
||||||
|
func TestSettleHoldInvoice(t *testing.T) {
|
||||||
defer timeout(t)()
|
defer timeout(t)()
|
||||||
|
|
||||||
cdb, cleanup, err := newDB()
|
cdb, cleanup, err := newDB()
|
||||||
@ -462,6 +486,10 @@ func TestHoldInvoice(t *testing.T) {
|
|||||||
if *hodlEvent.Preimage != preimage {
|
if *hodlEvent.Preimage != preimage {
|
||||||
t.Fatal("unexpected preimage in hodl event")
|
t.Fatal("unexpected preimage in hodl event")
|
||||||
}
|
}
|
||||||
|
if hodlEvent.AcceptHeight != testCurrentHeight {
|
||||||
|
t.Fatalf("expected acceptHeight %v, but got %v",
|
||||||
|
testCurrentHeight, event.AcceptHeight)
|
||||||
|
}
|
||||||
|
|
||||||
// We expect a settled notification to be sent out for both all and
|
// We expect a settled notification to be sent out for both all and
|
||||||
// single invoice subscribers.
|
// single invoice subscribers.
|
||||||
@ -494,6 +522,85 @@ func TestHoldInvoice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestCancelHoldInvoice tests canceling of a hold invoice and related
|
||||||
|
// notifications.
|
||||||
|
func TestCancelHoldInvoice(t *testing.T) {
|
||||||
|
defer timeout(t)()
|
||||||
|
|
||||||
|
cdb, cleanup, err := newDB()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
// Instantiate and start the invoice registry.
|
||||||
|
registry := NewRegistry(cdb, testFinalCltvRejectDelta)
|
||||||
|
|
||||||
|
err = registry.Start()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer registry.Stop()
|
||||||
|
|
||||||
|
// Add the invoice.
|
||||||
|
invoice := &channeldb.Invoice{
|
||||||
|
Terms: channeldb.ContractTerm{
|
||||||
|
PaymentPreimage: channeldb.UnknownPreimage,
|
||||||
|
Value: lnwire.MilliSatoshi(100000),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = registry.AddInvoice(invoice, hash)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
amtPaid := lnwire.MilliSatoshi(100000)
|
||||||
|
hodlChan := make(chan interface{}, 1)
|
||||||
|
|
||||||
|
// NotifyExitHopHtlc without a preimage present in the invoice registry
|
||||||
|
// should be possible.
|
||||||
|
event, err := registry.NotifyExitHopHtlc(
|
||||||
|
hash, amtPaid, testHtlcExpiry, testCurrentHeight,
|
||||||
|
getCircuitKey(0), hodlChan, nil,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected settle to succeed but got %v", err)
|
||||||
|
}
|
||||||
|
if event != nil {
|
||||||
|
t.Fatalf("expected htlc to be held")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancel invoice.
|
||||||
|
err = registry.CancelInvoice(hash)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("cancel invoice failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
hodlEvent := (<-hodlChan).(HodlEvent)
|
||||||
|
if hodlEvent.Preimage != nil {
|
||||||
|
t.Fatal("expected cancel hodl event")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offering the same htlc again at a higher height should still result
|
||||||
|
// in a rejection. The accept height is expected to be the original
|
||||||
|
// accept height.
|
||||||
|
event, err = registry.NotifyExitHopHtlc(
|
||||||
|
hash, amtPaid, testHtlcExpiry, testCurrentHeight+1,
|
||||||
|
getCircuitKey(0), hodlChan, nil,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected settle to succeed but got %v", err)
|
||||||
|
}
|
||||||
|
if event.Preimage != nil {
|
||||||
|
t.Fatalf("expected htlc to be canceled")
|
||||||
|
}
|
||||||
|
if event.AcceptHeight != testCurrentHeight {
|
||||||
|
t.Fatalf("expected acceptHeight %v, but got %v",
|
||||||
|
testCurrentHeight, event.AcceptHeight)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func newDB() (*channeldb.DB, func(), error) {
|
func newDB() (*channeldb.DB, func(), error) {
|
||||||
// First, create a temporary directory to be used for the duration of
|
// First, create a temporary directory to be used for the duration of
|
||||||
// this test.
|
// this test.
|
||||||
|
Loading…
Reference in New Issue
Block a user