diff --git a/channeldb/invoice_test.go b/channeldb/invoice_test.go index e109d387..46687e25 100644 --- a/channeldb/invoice_test.go +++ b/channeldb/invoice_test.go @@ -25,12 +25,12 @@ func randInvoice(value lnwire.MilliSatoshi) (*Invoice, error) { // failures due to the monotonic time component. CreationDate: time.Unix(time.Now().Unix(), 0), Terms: ContractTerm{ + Expiry: 4000, PaymentPreimage: pre, Value: value, Features: emptyFeatures, }, - Htlcs: map[CircuitKey]*InvoiceHTLC{}, - Expiry: 4000, + Htlcs: map[CircuitKey]*InvoiceHTLC{}, } i.Memo = []byte("memo") @@ -114,7 +114,7 @@ func TestInvoiceWorkflow(t *testing.T) { if err != nil { t.Fatalf("unable to fetch invoice: %v", err) } - if dbInvoice2.Terms.State != ContractSettled { + if dbInvoice2.State != ContractSettled { t.Fatalf("invoice should now be settled but isn't") } if dbInvoice2.SettleDate.IsZero() { @@ -363,7 +363,7 @@ func TestDuplicateSettleInvoice(t *testing.T) { // We'll update what we expect the settle invoice to be so that our // comparison below has the correct assumption. invoice.SettleIndex = 1 - invoice.Terms.State = ContractSettled + invoice.State = ContractSettled invoice.AmtPaid = amt invoice.SettleDate = dbInvoice.SettleDate invoice.Htlcs = map[CircuitKey]*InvoiceHTLC{ @@ -679,7 +679,7 @@ func TestQueryInvoices(t *testing.T) { // settles the invoice with the given amount. func getUpdateInvoice(amt lnwire.MilliSatoshi) InvoiceUpdateCallback { return func(invoice *Invoice) (*InvoiceUpdateDesc, error) { - if invoice.Terms.State == ContractSettled { + if invoice.State == ContractSettled { return nil, ErrInvoiceAlreadySettled } diff --git a/channeldb/invoices.go b/channeldb/invoices.go index eaedd178..d06ef46a 100644 --- a/channeldb/invoices.go +++ b/channeldb/invoices.go @@ -166,6 +166,13 @@ func (c ContractState) String() string { // the necessary conditions required before the invoice can be considered fully // settled by the payee. type ContractTerm struct { + // FinalCltvDelta is the minimum required number of blocks before htlc + // expiry when the invoice is accepted. + FinalCltvDelta int32 + + // Expiry defines how long after creation this invoice should expire. + Expiry time.Duration + // PaymentPreimage is the preimage which is to be revealed in the // occasion that an HTLC paying to the hash of this preimage is // extended. @@ -175,9 +182,6 @@ type ContractTerm struct { // which can be satisfied by the above preimage. Value lnwire.MilliSatoshi - // State describes the state the invoice is in. - State ContractState - // PaymentAddr is a randomly generated value include in the MPP record // by the sender to prevent probing of the receiver. PaymentAddr [32]byte @@ -206,13 +210,6 @@ type Invoice struct { // for this invoice can be stored. PaymentRequest []byte - // FinalCltvDelta is the minimum required number of blocks before htlc - // expiry when the invoice is accepted. - FinalCltvDelta int32 - - // Expiry defines how long after creation this invoice should expire. - Expiry time.Duration - // CreationDate is the exact time the invoice was created. CreationDate time.Time @@ -245,6 +242,9 @@ type Invoice struct { // NOTE: This index starts at 1. SettleIndex uint64 + // State describes the state the invoice is in. + State ContractState + // AmtPaid is the final amount that we ultimately accepted for pay for // this invoice. We specify this value independently as it's possible // that the invoice originally didn't specify an amount, or the sender @@ -552,7 +552,7 @@ func (d *DB) FetchAllInvoices(pendingOnly bool) ([]Invoice, error) { } if pendingOnly && - invoice.Terms.State == ContractSettled { + invoice.State == ContractSettled { return nil } @@ -702,7 +702,7 @@ func (d *DB) QueryInvoices(q InvoiceQuery) (InvoiceSlice, error) { // Skip any settled invoices if the caller is only // interested in unsettled. if q.PendingOnly && - invoice.Terms.State == ContractSettled { + invoice.State == ContractSettled { continue } @@ -931,11 +931,11 @@ func serializeInvoice(w io.Writer, i *Invoice) error { preimage := [32]byte(i.Terms.PaymentPreimage) value := uint64(i.Terms.Value) - cltvDelta := uint32(i.FinalCltvDelta) - expiry := uint64(i.Expiry) + cltvDelta := uint32(i.Terms.FinalCltvDelta) + expiry := uint64(i.Terms.Expiry) amtPaid := uint64(i.AmtPaid) - state := uint8(i.Terms.State) + state := uint8(i.State) tlvStream, err := tlv.NewStream( // Memo and payreq. @@ -1094,10 +1094,10 @@ func deserializeInvoice(r io.Reader) (Invoice, error) { i.Terms.PaymentPreimage = lntypes.Preimage(preimage) i.Terms.Value = lnwire.MilliSatoshi(value) - i.FinalCltvDelta = int32(cltvDelta) - i.Expiry = time.Duration(expiry) + i.Terms.FinalCltvDelta = int32(cltvDelta) + i.Terms.Expiry = time.Duration(expiry) i.AmtPaid = lnwire.MilliSatoshi(amtPaid) - i.Terms.State = ContractState(state) + i.State = ContractState(state) err = i.CreationDate.UnmarshalBinary(creationDateBytes) if err != nil { @@ -1198,13 +1198,12 @@ func copyInvoice(src *Invoice) *Invoice { dest := Invoice{ Memo: copySlice(src.Memo), PaymentRequest: copySlice(src.PaymentRequest), - FinalCltvDelta: src.FinalCltvDelta, - Expiry: src.Expiry, CreationDate: src.CreationDate, SettleDate: src.SettleDate, Terms: src.Terms, AddIndex: src.AddIndex, SettleIndex: src.SettleIndex, + State: src.State, AmtPaid: src.AmtPaid, Htlcs: make( map[CircuitKey]*InvoiceHTLC, len(src.Htlcs), @@ -1230,7 +1229,7 @@ func (d *DB) updateInvoice(hash lntypes.Hash, invoices, settleIndex *bbolt.Bucke return nil, err } - preUpdateState := invoice.Terms.State + preUpdateState := invoice.State // Create deep copy to prevent any accidental modification in the // callback. @@ -1243,7 +1242,7 @@ func (d *DB) updateInvoice(hash lntypes.Hash, invoices, settleIndex *bbolt.Bucke } // Update invoice state. - invoice.Terms.State = update.State + invoice.State = update.State now := d.now() @@ -1291,8 +1290,8 @@ func (d *DB) updateInvoice(hash lntypes.Hash, invoices, settleIndex *bbolt.Bucke // If invoice moved to the settled state, update settle index and settle // time. - if preUpdateState != invoice.Terms.State && - invoice.Terms.State == ContractSettled { + if preUpdateState != invoice.State && + invoice.State == ContractSettled { if update.Preimage.Hash() != hash { return nil, fmt.Errorf("preimage does not match") @@ -1344,7 +1343,7 @@ func setSettleFields(settleIndex *bbolt.Bucket, invoiceNum []byte, return err } - invoice.Terms.State = ContractSettled + invoice.State = ContractSettled invoice.SettleDate = now invoice.SettleIndex = nextSettleSeqNo diff --git a/htlcswitch/link_test.go b/htlcswitch/link_test.go index 06613aa1..810b5831 100644 --- a/htlcswitch/link_test.go +++ b/htlcswitch/link_test.go @@ -245,7 +245,7 @@ func TestChannelLinkSingleHopPayment(t *testing.T) { if err != nil { t.Fatalf("unable to get invoice: %v", err) } - if invoice.Terms.State != channeldb.ContractSettled { + if invoice.State != channeldb.ContractSettled { t.Fatal("alice invoice wasn't settled") } @@ -505,7 +505,7 @@ func testChannelLinkMultiHopPayment(t *testing.T, if err != nil { t.Fatalf("unable to get invoice: %v", err) } - if invoice.Terms.State != channeldb.ContractSettled { + if invoice.State != channeldb.ContractSettled { t.Fatal("carol invoice haven't been settled") } @@ -919,7 +919,7 @@ func TestUpdateForwardingPolicy(t *testing.T) { if err != nil { t.Fatalf("unable to get invoice: %v", err) } - if invoice.Terms.State != channeldb.ContractSettled { + if invoice.State != channeldb.ContractSettled { t.Fatal("carol invoice haven't been settled") } @@ -1078,7 +1078,7 @@ func TestChannelLinkMultiHopInsufficientPayment(t *testing.T) { if err != nil { t.Fatalf("unable to get invoice: %v", err) } - if invoice.Terms.State == channeldb.ContractSettled { + if invoice.State == channeldb.ContractSettled { t.Fatal("carol invoice have been settled") } @@ -1269,7 +1269,7 @@ func TestChannelLinkMultiHopUnknownNextHop(t *testing.T) { if err != nil { t.Fatalf("unable to get invoice: %v", err) } - if invoice.Terms.State == channeldb.ContractSettled { + if invoice.State == channeldb.ContractSettled { t.Fatal("carol invoice have been settled") } @@ -1384,7 +1384,7 @@ func TestChannelLinkMultiHopDecodeError(t *testing.T) { if err != nil { t.Fatalf("unable to get invoice: %v", err) } - if invoice.Terms.State == channeldb.ContractSettled { + if invoice.State == channeldb.ContractSettled { t.Fatal("carol invoice have been settled") } @@ -3518,7 +3518,7 @@ func TestChannelRetransmission(t *testing.T) { err = errors.Errorf("unable to get invoice: %v", err) continue } - if invoice.Terms.State != channeldb.ContractSettled { + if invoice.State != channeldb.ContractSettled { err = errors.Errorf("alice invoice haven't been settled") continue } @@ -4055,7 +4055,7 @@ func TestChannelLinkAcceptOverpay(t *testing.T) { if err != nil { t.Fatalf("unable to get invoice: %v", err) } - if invoice.Terms.State != channeldb.ContractSettled { + if invoice.State != channeldb.ContractSettled { t.Fatal("carol invoice haven't been settled") } diff --git a/htlcswitch/test_utils.go b/htlcswitch/test_utils.go index 4f6d02eb..1308bf79 100644 --- a/htlcswitch/test_utils.go +++ b/htlcswitch/test_utils.go @@ -560,13 +560,13 @@ func generatePaymentWithPreimage(invoiceAmt, htlcAmt lnwire.MilliSatoshi, invoice := &channeldb.Invoice{ CreationDate: time.Now(), Terms: channeldb.ContractTerm{ + FinalCltvDelta: testInvoiceCltvExpiry, Value: invoiceAmt, PaymentPreimage: preimage, Features: lnwire.NewFeatureVector( nil, lnwire.Features, ), }, - FinalCltvDelta: testInvoiceCltvExpiry, } htlc := &lnwire.UpdateAddHTLC{ diff --git a/invoices/invoiceregistry.go b/invoices/invoiceregistry.go index 61f0feaf..51b57c09 100644 --- a/invoices/invoiceregistry.go +++ b/invoices/invoiceregistry.go @@ -179,7 +179,7 @@ func (i *InvoiceRegistry) invoiceEventNotifier() { // For backwards compatibility, do not notify // all invoice subscribers of cancel and accept // events. - state := e.invoice.Terms.State + state := e.invoice.State if state != channeldb.ContractCanceled && state != channeldb.ContractAccepted { @@ -231,7 +231,7 @@ func (i *InvoiceRegistry) dispatchToClients(event *invoiceEvent) { // ensure we don't duplicate any events. // TODO(joostjager): Refactor switches. - state := event.invoice.Terms.State + state := event.invoice.State switch { // If we've already sent this settle event to // the client, then we can skip this. @@ -277,14 +277,14 @@ func (i *InvoiceRegistry) dispatchToClients(event *invoiceEvent) { // the latest add/settle index it has. We'll use this to ensure // we don't send a notification twice, which can happen if a new // event is added while we're catching up a new client. - switch event.invoice.Terms.State { + switch event.invoice.State { case channeldb.ContractSettled: client.settleIndex = invoice.SettleIndex case channeldb.ContractOpen: client.addIndex = invoice.AddIndex default: log.Errorf("unexpected invoice state: %v", - event.invoice.Terms.State) + event.invoice.State) } } } @@ -467,7 +467,7 @@ func (i *InvoiceRegistry) NotifyExitHopHtlc(rHash lntypes.Hash, // If the invoice is already canceled, there is no further // checking to do. - if inv.Terms.State == channeldb.ContractCanceled { + if inv.State == channeldb.ContractCanceled { debugLog("invoice already canceled") return nil, errNoUpdate } @@ -486,7 +486,7 @@ func (i *InvoiceRegistry) NotifyExitHopHtlc(rHash lntypes.Hash, return nil, errNoUpdate } - if expiry < uint32(currentHeight+inv.FinalCltvDelta) { + if expiry < uint32(currentHeight+inv.Terms.FinalCltvDelta) { debugLog("expiry too soon") return nil, errNoUpdate } @@ -506,7 +506,7 @@ func (i *InvoiceRegistry) NotifyExitHopHtlc(rHash lntypes.Hash, // Don't update invoice state if we are accepting a duplicate // payment. We do accept or settle the HTLC. - switch inv.Terms.State { + switch inv.State { case channeldb.ContractAccepted: debugLog("accepting duplicate payment to accepted invoice") update.State = channeldb.ContractAccepted @@ -546,7 +546,7 @@ func (i *InvoiceRegistry) NotifyExitHopHtlc(rHash lntypes.Hash, } if updateSubscribers { - i.notifyClients(rHash, invoice, invoice.Terms.State) + i.notifyClients(rHash, invoice, invoice.State) } // Inspect latest htlc state on the invoice. @@ -597,7 +597,7 @@ func (i *InvoiceRegistry) SettleHodlInvoice(preimage lntypes.Preimage) error { updateInvoice := func(invoice *channeldb.Invoice) ( *channeldb.InvoiceUpdateDesc, error) { - switch invoice.Terms.State { + switch invoice.State { case channeldb.ContractOpen: return nil, channeldb.ErrInvoiceStillOpen case channeldb.ContractCanceled: @@ -639,7 +639,7 @@ func (i *InvoiceRegistry) SettleHodlInvoice(preimage lntypes.Preimage) error { AcceptHeight: int32(htlc.AcceptHeight), }) } - i.notifyClients(hash, invoice, invoice.Terms.State) + i.notifyClients(hash, invoice, invoice.State) return nil } @@ -655,7 +655,7 @@ func (i *InvoiceRegistry) CancelInvoice(payHash lntypes.Hash) error { updateInvoice := func(invoice *channeldb.Invoice) ( *channeldb.InvoiceUpdateDesc, error) { - switch invoice.Terms.State { + switch invoice.State { case channeldb.ContractSettled: return nil, channeldb.ErrInvoiceAlreadySettled case channeldb.ContractCanceled: @@ -868,7 +868,7 @@ func (i *InvoiceRegistry) SubscribeNotifications(addIndex, settleIndex uint64) * invoiceEvent := ntfn.(*invoiceEvent) var targetChan chan *channeldb.Invoice - state := invoiceEvent.invoice.Terms.State + state := invoiceEvent.invoice.State switch state { case channeldb.ContractOpen: targetChan = client.NewInvoices diff --git a/invoices/invoiceregistry_test.go b/invoices/invoiceregistry_test.go index 51270354..9e6fc62a 100644 --- a/invoices/invoiceregistry_test.go +++ b/invoices/invoiceregistry_test.go @@ -115,9 +115,9 @@ func TestSettleInvoice(t *testing.T) { // We expect the open state to be sent to the single invoice subscriber. select { case update := <-subscription.Updates: - if update.Terms.State != channeldb.ContractOpen { + if update.State != channeldb.ContractOpen { t.Fatalf("expected state ContractOpen, but got %v", - update.Terms.State) + update.State) } case <-time.After(testTimeout): t.Fatal("no update received") @@ -126,9 +126,9 @@ func TestSettleInvoice(t *testing.T) { // We expect a new invoice notification to be sent out. select { case newInvoice := <-allSubscriptions.NewInvoices: - if newInvoice.Terms.State != channeldb.ContractOpen { + if newInvoice.State != channeldb.ContractOpen { t.Fatalf("expected state ContractOpen, but got %v", - newInvoice.Terms.State) + newInvoice.State) } case <-time.After(testTimeout): t.Fatal("no update received") @@ -167,9 +167,9 @@ func TestSettleInvoice(t *testing.T) { // subscriber. select { case update := <-subscription.Updates: - if update.Terms.State != channeldb.ContractSettled { + if update.State != channeldb.ContractSettled { t.Fatalf("expected state ContractOpen, but got %v", - update.Terms.State) + update.State) } if update.AmtPaid != amtPaid { t.Fatal("invoice AmtPaid incorrect") @@ -181,9 +181,9 @@ func TestSettleInvoice(t *testing.T) { // We expect a settled notification to be sent out. select { case settledInvoice := <-allSubscriptions.SettledInvoices: - if settledInvoice.Terms.State != channeldb.ContractSettled { + if settledInvoice.State != channeldb.ContractSettled { t.Fatalf("expected state ContractOpen, but got %v", - settledInvoice.Terms.State) + settledInvoice.State) } case <-time.After(testTimeout): t.Fatal("no update received") @@ -288,10 +288,10 @@ func TestCancelInvoice(t *testing.T) { // We expect the open state to be sent to the single invoice subscriber. select { case update := <-subscription.Updates: - if update.Terms.State != channeldb.ContractOpen { + if update.State != channeldb.ContractOpen { t.Fatalf( "expected state ContractOpen, but got %v", - update.Terms.State, + update.State, ) } case <-time.After(testTimeout): @@ -301,10 +301,10 @@ func TestCancelInvoice(t *testing.T) { // We expect a new invoice notification to be sent out. select { case newInvoice := <-allSubscriptions.NewInvoices: - if newInvoice.Terms.State != channeldb.ContractOpen { + if newInvoice.State != channeldb.ContractOpen { t.Fatalf( "expected state ContractOpen, but got %v", - newInvoice.Terms.State, + newInvoice.State, ) } case <-time.After(testTimeout): @@ -321,10 +321,10 @@ func TestCancelInvoice(t *testing.T) { // subscriber. select { case update := <-subscription.Updates: - if update.Terms.State != channeldb.ContractCanceled { + if update.State != channeldb.ContractCanceled { t.Fatalf( "expected state ContractCanceled, but got %v", - update.Terms.State, + update.State, ) } case <-time.After(testTimeout): @@ -402,16 +402,16 @@ func TestSettleHoldInvoice(t *testing.T) { // We expect the open state to be sent to the single invoice subscriber. update := <-subscription.Updates - if update.Terms.State != channeldb.ContractOpen { + if update.State != channeldb.ContractOpen { t.Fatalf("expected state ContractOpen, but got %v", - update.Terms.State) + update.State) } // We expect a new invoice notification to be sent out. newInvoice := <-allSubscriptions.NewInvoices - if newInvoice.Terms.State != channeldb.ContractOpen { + if newInvoice.State != channeldb.ContractOpen { t.Fatalf("expected state ContractOpen, but got %v", - newInvoice.Terms.State) + newInvoice.State) } // Use slightly higher amount for accept/settle. @@ -474,9 +474,9 @@ func TestSettleHoldInvoice(t *testing.T) { // subscriber. For all invoice subscribers, we don't expect an update. // Those only get notified on settle. update = <-subscription.Updates - if update.Terms.State != channeldb.ContractAccepted { + if update.State != channeldb.ContractAccepted { t.Fatalf("expected state ContractAccepted, but got %v", - update.Terms.State) + update.State) } if update.AmtPaid != amtPaid { t.Fatal("invoice AmtPaid incorrect") @@ -500,9 +500,9 @@ func TestSettleHoldInvoice(t *testing.T) { // We expect a settled notification to be sent out for both all and // single invoice subscribers. settledInvoice := <-allSubscriptions.SettledInvoices - if settledInvoice.Terms.State != channeldb.ContractSettled { + if settledInvoice.State != channeldb.ContractSettled { t.Fatalf("expected state ContractSettled, but got %v", - settledInvoice.Terms.State) + settledInvoice.State) } if settledInvoice.AmtPaid != amtPaid { t.Fatalf("expected amount to be %v, but got %v", @@ -510,9 +510,9 @@ func TestSettleHoldInvoice(t *testing.T) { } update = <-subscription.Updates - if update.Terms.State != channeldb.ContractSettled { + if update.State != channeldb.ContractSettled { t.Fatalf("expected state ContractSettled, but got %v", - update.Terms.State) + update.State) } // Idempotency. diff --git a/lnrpc/invoicesrpc/addinvoice.go b/lnrpc/invoicesrpc/addinvoice.go index 70955e0f..e99e9417 100644 --- a/lnrpc/invoicesrpc/addinvoice.go +++ b/lnrpc/invoicesrpc/addinvoice.go @@ -392,9 +392,9 @@ func AddInvoice(ctx context.Context, cfg *AddInvoiceConfig, CreationDate: creationDate, Memo: []byte(invoice.Memo), PaymentRequest: []byte(payReqString), - FinalCltvDelta: int32(payReq.MinFinalCLTVExpiry()), - Expiry: payReq.Expiry(), Terms: channeldb.ContractTerm{ + FinalCltvDelta: int32(payReq.MinFinalCLTVExpiry()), + Expiry: payReq.Expiry(), Value: amtMSat, PaymentPreimage: paymentPreimage, Features: invoiceFeatures, diff --git a/lnrpc/invoicesrpc/utils.go b/lnrpc/invoicesrpc/utils.go index a12cc858..7e56d17e 100644 --- a/lnrpc/invoicesrpc/utils.go +++ b/lnrpc/invoicesrpc/utils.go @@ -43,10 +43,10 @@ func CreateRPCInvoice(invoice *channeldb.Invoice, satAmt := invoice.Terms.Value.ToSatoshis() satAmtPaid := invoice.AmtPaid.ToSatoshis() - isSettled := invoice.Terms.State == channeldb.ContractSettled + isSettled := invoice.State == channeldb.ContractSettled var state lnrpc.Invoice_InvoiceState - switch invoice.Terms.State { + switch invoice.State { case channeldb.ContractOpen: state = lnrpc.Invoice_OPEN case channeldb.ContractSettled: @@ -57,7 +57,7 @@ func CreateRPCInvoice(invoice *channeldb.Invoice, state = lnrpc.Invoice_ACCEPTED default: return nil, fmt.Errorf("unknown invoice state %v", - invoice.Terms.State) + invoice.State) } rpcHtlcs := make([]*lnrpc.InvoiceHTLC, 0, len(invoice.Htlcs)) @@ -102,8 +102,8 @@ func CreateRPCInvoice(invoice *channeldb.Invoice, Settled: isSettled, PaymentRequest: paymentRequest, DescriptionHash: descHash, - Expiry: int64(invoice.Expiry.Seconds()), - CltvExpiry: uint64(invoice.FinalCltvDelta), + Expiry: int64(invoice.Terms.Expiry.Seconds()), + CltvExpiry: uint64(invoice.Terms.FinalCltvDelta), FallbackAddr: fallbackAddr, RouteHints: routeHints, AddIndex: invoice.AddIndex,