diff --git a/channeldb/invoice_test.go b/channeldb/invoice_test.go index a24c2f674..537480e97 100644 --- a/channeldb/invoice_test.go +++ b/channeldb/invoice_test.go @@ -20,7 +20,10 @@ var ( ) func randInvoice(value lnwire.MilliSatoshi) (*Invoice, error) { - var pre, payAddr [32]byte + var ( + pre lntypes.Preimage + payAddr [32]byte + ) if _, err := rand.Read(pre[:]); err != nil { return nil, err } @@ -32,7 +35,7 @@ func randInvoice(value lnwire.MilliSatoshi) (*Invoice, error) { CreationDate: testNow, Terms: ContractTerm{ Expiry: 4000, - PaymentPreimage: pre, + PaymentPreimage: &pre, PaymentAddr: payAddr, Value: value, Features: emptyFeatures, @@ -360,13 +363,18 @@ func TestInvoiceCancelSingleHtlc(t *testing.T) { t.Fatalf("unable to make test db: %v", err) } + preimage := lntypes.Preimage{1} + paymentHash := preimage.Hash() + testInvoice := &Invoice{ Htlcs: map[CircuitKey]*InvoiceHTLC{}, + Terms: ContractTerm{ + Value: lnwire.NewMSatFromSatoshis(10000), + Features: emptyFeatures, + PaymentPreimage: &preimage, + }, } - testInvoice.Terms.Value = lnwire.NewMSatFromSatoshis(10000) - testInvoice.Terms.Features = emptyFeatures - var paymentHash lntypes.Hash if _, err := db.AddInvoice(testInvoice, paymentHash); err != nil { t.Fatalf("unable to find invoice: %v", err) } @@ -1059,15 +1067,20 @@ func TestCustomRecords(t *testing.T) { t.Fatalf("unable to make test db: %v", err) } + preimage := lntypes.Preimage{1} + paymentHash := preimage.Hash() + testInvoice := &Invoice{ Htlcs: map[CircuitKey]*InvoiceHTLC{}, + Terms: ContractTerm{ + Value: lnwire.NewMSatFromSatoshis(10000), + Features: emptyFeatures, + PaymentPreimage: &preimage, + }, } - testInvoice.Terms.Value = lnwire.NewMSatFromSatoshis(10000) - testInvoice.Terms.Features = emptyFeatures - var paymentHash lntypes.Hash if _, err := db.AddInvoice(testInvoice, paymentHash); err != nil { - t.Fatalf("unable to find invoice: %v", err) + t.Fatalf("unable to add invoice: %v", err) } // Accept an htlc with custom records on this invoice. diff --git a/channeldb/invoices.go b/channeldb/invoices.go index 4b9c10022..a7ed43245 100644 --- a/channeldb/invoices.go +++ b/channeldb/invoices.go @@ -17,9 +17,9 @@ import ( ) var ( - // UnknownPreimage is an all-zeroes preimage that indicates that the + // unknownPreimage is an all-zeroes preimage that indicates that the // preimage for this invoice is not yet known. - UnknownPreimage lntypes.Preimage + unknownPreimage lntypes.Preimage // invoiceBucket is the name of the bucket within the database that // stores all data related to invoices no matter their final state. @@ -150,6 +150,7 @@ const ( featuresType tlv.Type = 11 invStateType tlv.Type = 12 amtPaidType tlv.Type = 13 + hodlInvoiceType tlv.Type = 14 ) // InvoiceRef is a composite identifier for invoices. Invoices can be referenced @@ -261,8 +262,8 @@ type ContractTerm struct { // PaymentPreimage is the preimage which is to be revealed in the // occasion that an HTLC paying to the hash of this preimage is - // extended. - PaymentPreimage lntypes.Preimage + // extended. Set to nil if the preimage isn't known yet. + PaymentPreimage *lntypes.Preimage // Value is the expected amount of milli-satoshis to be paid to an HTLC // which can be satisfied by the above preimage. @@ -346,6 +347,10 @@ type Invoice struct { // Htlcs records all htlcs that paid to this invoice. Some of these // htlcs may have been marked as canceled. Htlcs map[CircuitKey]*InvoiceHTLC + + // HodlInvoice indicates whether the invoice should be held in the + // Accepted state or be settled right away. + HodlInvoice bool } // HtlcState defines the states an htlc paying to an invoice can be in. @@ -439,14 +444,19 @@ type InvoiceStateUpdateDesc struct { NewState ContractState // Preimage must be set to the preimage when NewState is settled. - Preimage lntypes.Preimage + Preimage *lntypes.Preimage } // InvoiceUpdateCallback is a callback used in the db transaction to update the // invoice. type InvoiceUpdateCallback = func(invoice *Invoice) (*InvoiceUpdateDesc, error) -func validateInvoice(i *Invoice) error { +func validateInvoice(i *Invoice, paymentHash lntypes.Hash) error { + // Avoid conflicts with all-zeroes magic value in the database. + if paymentHash == unknownPreimage.Hash() { + return fmt.Errorf("cannot use hash of all-zeroes preimage") + } + if len(i.Memo) > MaxMemoSize { return fmt.Errorf("max length a memo is %v, and invoice "+ "of length %v was provided", MaxMemoSize, len(i.Memo)) @@ -459,6 +469,10 @@ func validateInvoice(i *Invoice) error { if i.Terms.Features == nil { return errors.New("invoice must have a feature vector") } + + if i.Terms.PaymentPreimage == nil && !i.HodlInvoice { + return errors.New("non-hodl invoices must have a preimage") + } return nil } @@ -475,7 +489,7 @@ func (i *Invoice) IsPending() bool { func (d *DB) AddInvoice(newInvoice *Invoice, paymentHash lntypes.Hash) ( uint64, error) { - if err := validateInvoice(newInvoice); err != nil { + if err := validateInvoice(newInvoice, paymentHash); err != nil { return 0, err } @@ -1131,7 +1145,13 @@ func serializeInvoice(w io.Writer, i *Invoice) error { } featureBytes := fb.Bytes() - preimage := [32]byte(i.Terms.PaymentPreimage) + preimage := [32]byte(unknownPreimage) + if i.Terms.PaymentPreimage != nil { + preimage = *i.Terms.PaymentPreimage + if preimage == unknownPreimage { + return errors.New("cannot use all-zeroes preimage") + } + } value := uint64(i.Terms.Value) cltvDelta := uint32(i.Terms.FinalCltvDelta) expiry := uint64(i.Terms.Expiry) @@ -1139,6 +1159,11 @@ func serializeInvoice(w io.Writer, i *Invoice) error { amtPaid := uint64(i.AmtPaid) state := uint8(i.State) + var hodlInvoice uint8 + if i.HodlInvoice { + hodlInvoice = 1 + } + tlvStream, err := tlv.NewStream( // Memo and payreq. tlv.MakePrimitiveRecord(memoType, &i.Memo), @@ -1161,6 +1186,8 @@ func serializeInvoice(w io.Writer, i *Invoice) error { // Invoice state. tlv.MakePrimitiveRecord(invStateType, &state), tlv.MakePrimitiveRecord(amtPaidType, &amtPaid), + + tlv.MakePrimitiveRecord(hodlInvoiceType, &hodlInvoice), ) if err != nil { return err @@ -1256,12 +1283,13 @@ func fetchInvoice(invoiceNum []byte, invoices kvdb.RBucket) (Invoice, error) { func deserializeInvoice(r io.Reader) (Invoice, error) { var ( - preimage [32]byte - value uint64 - cltvDelta uint32 - expiry uint64 - amtPaid uint64 - state uint8 + preimageBytes [32]byte + value uint64 + cltvDelta uint32 + expiry uint64 + amtPaid uint64 + state uint8 + hodlInvoice uint8 creationDateBytes []byte settleDateBytes []byte @@ -1281,7 +1309,7 @@ func deserializeInvoice(r io.Reader) (Invoice, error) { tlv.MakePrimitiveRecord(settleIndexType, &i.SettleIndex), // Terms. - tlv.MakePrimitiveRecord(preimageType, &preimage), + tlv.MakePrimitiveRecord(preimageType, &preimageBytes), tlv.MakePrimitiveRecord(valueType, &value), tlv.MakePrimitiveRecord(cltvDeltaType, &cltvDelta), tlv.MakePrimitiveRecord(expiryType, &expiry), @@ -1291,6 +1319,8 @@ func deserializeInvoice(r io.Reader) (Invoice, error) { // Invoice state. tlv.MakePrimitiveRecord(invStateType, &state), tlv.MakePrimitiveRecord(amtPaidType, &amtPaid), + + tlv.MakePrimitiveRecord(hodlInvoiceType, &hodlInvoice), ) if err != nil { return i, err @@ -1307,13 +1337,21 @@ func deserializeInvoice(r io.Reader) (Invoice, error) { return i, err } - i.Terms.PaymentPreimage = lntypes.Preimage(preimage) + preimage := lntypes.Preimage(preimageBytes) + if preimage != unknownPreimage { + i.Terms.PaymentPreimage = &preimage + } + i.Terms.Value = lnwire.MilliSatoshi(value) i.Terms.FinalCltvDelta = int32(cltvDelta) i.Terms.Expiry = time.Duration(expiry) i.AmtPaid = lnwire.MilliSatoshi(amtPaid) i.State = ContractState(state) + if hodlInvoice != 0 { + i.HodlInvoice = true + } + err = i.CreationDate.UnmarshalBinary(creationDateBytes) if err != nil { return i, err @@ -1443,10 +1481,16 @@ func copyInvoice(src *Invoice) *Invoice { Htlcs: make( map[CircuitKey]*InvoiceHTLC, len(src.Htlcs), ), + HodlInvoice: src.HodlInvoice, } dest.Terms.Features = src.Terms.Features.Clone() + if src.Terms.PaymentPreimage != nil { + preimage := *src.Terms.PaymentPreimage + dest.Terms.PaymentPreimage = &preimage + } + for k, v := range src.Htlcs { dest.Htlcs[k] = copyInvoiceHTLC(v) } @@ -1619,10 +1663,16 @@ func updateInvoiceState(invoice *Invoice, hash lntypes.Hash, case ContractOpen: if update.NewState == ContractSettled { // Validate preimage. - if update.Preimage.Hash() != hash { - return ErrInvoicePreimageMismatch + switch { + case update.Preimage != nil: + if update.Preimage.Hash() != hash { + return ErrInvoicePreimageMismatch + } + invoice.Terms.PaymentPreimage = update.Preimage + + case invoice.Terms.PaymentPreimage == nil: + return errors.New("unknown preimage") } - invoice.Terms.PaymentPreimage = update.Preimage } // Once settled, we are in a terminal state. diff --git a/contractcourt/channel_arbitrator.go b/contractcourt/channel_arbitrator.go index f6f7fedad..8ad7585a1 100644 --- a/contractcourt/channel_arbitrator.go +++ b/contractcourt/channel_arbitrator.go @@ -1457,8 +1457,7 @@ func (c *ChannelArbitrator) isPreimageAvailable(hash lntypes.Hash) (bool, return false, err } - preimageAvailable = invoice.Terms.PaymentPreimage != - channeldb.UnknownPreimage + preimageAvailable = invoice.Terms.PaymentPreimage != nil return preimageAvailable, nil } diff --git a/htlcswitch/link_test.go b/htlcswitch/link_test.go index 739dc0594..5bf076e9f 100644 --- a/htlcswitch/link_test.go +++ b/htlcswitch/link_test.go @@ -437,7 +437,9 @@ func TestChannelLinkCancelFullCommitment(t *testing.T) { var wg sync.WaitGroup for i := 0; i < count; i++ { - preimages[i] = lntypes.Preimage{byte(i >> 8), byte(i)} + // Deterministically generate preimages. Avoid the all-zeroes + // preimage because that will be rejected by the database. + preimages[i] = lntypes.Preimage{byte(i >> 8), byte(i), 1} wg.Add(1) go func(i int) { @@ -2015,13 +2017,13 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) { // If we now send in a valid HTLC settle for the prior HTLC we added, // then the bandwidth should remain unchanged as the remote party will // gain additional channel balance. - err = bobChannel.SettleHTLC(invoice.Terms.PaymentPreimage, bobIndex, nil, nil, nil) + err = bobChannel.SettleHTLC(*invoice.Terms.PaymentPreimage, bobIndex, nil, nil, nil) if err != nil { t.Fatalf("unable to settle htlc: %v", err) } htlcSettle := &lnwire.UpdateFulfillHTLC{ ID: 0, - PaymentPreimage: invoice.Terms.PaymentPreimage, + PaymentPreimage: *invoice.Terms.PaymentPreimage, } aliceLink.HandleChannelUpdate(htlcSettle) time.Sleep(time.Millisecond * 500) @@ -2193,7 +2195,7 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) { outgoingHTLCID: addPkt.outgoingHTLCID, htlc: &lnwire.UpdateFulfillHTLC{ ID: 0, - PaymentPreimage: invoice.Terms.PaymentPreimage, + PaymentPreimage: *invoice.Terms.PaymentPreimage, }, obfuscator: NewMockObfuscator(), } @@ -3153,13 +3155,13 @@ func TestChannelLinkBandwidthChanReserve(t *testing.T) { // If we now send in a valid HTLC settle for the prior HTLC we added, // then the bandwidth should remain unchanged as the remote party will // gain additional channel balance. - err = bobChannel.SettleHTLC(invoice.Terms.PaymentPreimage, bobIndex, nil, nil, nil) + err = bobChannel.SettleHTLC(*invoice.Terms.PaymentPreimage, bobIndex, nil, nil, nil) if err != nil { t.Fatalf("unable to settle htlc: %v", err) } htlcSettle := &lnwire.UpdateFulfillHTLC{ ID: bobIndex, - PaymentPreimage: invoice.Terms.PaymentPreimage, + PaymentPreimage: *invoice.Terms.PaymentPreimage, } aliceLink.HandleChannelUpdate(htlcSettle) time.Sleep(time.Millisecond * 500) @@ -4730,7 +4732,7 @@ func testChannelLinkBatchPreimageWrite(t *testing.T, disconnect bool) { for i, invoice := range invoices { ctx.sendSettleBobToAlice( uint64(i), - invoice.Terms.PaymentPreimage, + *invoice.Terms.PaymentPreimage, ) } @@ -5772,7 +5774,8 @@ func TestChannelLinkHoldInvoiceRestart(t *testing.T) { // Convert into a hodl invoice and save the preimage for later. preimage := invoice.Terms.PaymentPreimage - invoice.Terms.PaymentPreimage = channeldb.UnknownPreimage + invoice.Terms.PaymentPreimage = nil + invoice.HodlInvoice = true // We must add the invoice to the registry, such that Alice // expects this payment. @@ -5814,7 +5817,10 @@ func TestChannelLinkHoldInvoiceRestart(t *testing.T) { <-registry.settleChan // Settle the invoice with the preimage. - registry.SettleHodlInvoice(preimage) + err = registry.SettleHodlInvoice(*preimage) + if err != nil { + t.Fatalf("settle hodl invoice: %v", err) + } // Expect alice to send a settle and commitsig message to bob. ctx.receiveSettleAliceToBob() @@ -5957,10 +5963,12 @@ func TestChannelLinkRevocationWindowHodl(t *testing.T) { // Convert into hodl invoices and save the preimages for later. preimage1 := invoice1.Terms.PaymentPreimage - invoice1.Terms.PaymentPreimage = channeldb.UnknownPreimage + invoice1.Terms.PaymentPreimage = nil + invoice1.HodlInvoice = true preimage2 := invoice2.Terms.PaymentPreimage - invoice2.Terms.PaymentPreimage = channeldb.UnknownPreimage + invoice2.Terms.PaymentPreimage = nil + invoice2.HodlInvoice = true // We must add the invoices to the registry, such that Alice // expects the payments. @@ -6009,7 +6017,10 @@ func TestChannelLinkRevocationWindowHodl(t *testing.T) { } // Settle invoice 1 with the preimage. - registry.SettleHodlInvoice(preimage1) + err = registry.SettleHodlInvoice(*preimage1) + if err != nil { + t.Fatalf("settle hodl invoice: %v", err) + } // Expect alice to send a settle and commitsig message to bob. Bob does // not yet send the revocation. @@ -6017,7 +6028,10 @@ func TestChannelLinkRevocationWindowHodl(t *testing.T) { ctx.receiveCommitSigAliceToBob(1) // Settle invoice 2 with the preimage. - registry.SettleHodlInvoice(preimage2) + err = registry.SettleHodlInvoice(*preimage2) + if err != nil { + t.Fatalf("settle hodl invoice: %v", err) + } // Expect alice to send a settle for htlc 2. ctx.receiveSettleAliceToBob() diff --git a/htlcswitch/test_utils.go b/htlcswitch/test_utils.go index 429963d2c..ae64cf1bd 100644 --- a/htlcswitch/test_utils.go +++ b/htlcswitch/test_utils.go @@ -547,8 +547,8 @@ func getChanID(msg lnwire.Message) (lnwire.ChannelID, error) { // invoice which should be added by destination peer. func generatePaymentWithPreimage(invoiceAmt, htlcAmt lnwire.MilliSatoshi, timelock uint32, blob [lnwire.OnionPacketSize]byte, - preimage, rhash, payAddr [32]byte) (*channeldb.Invoice, *lnwire.UpdateAddHTLC, - uint64, error) { + preimage *lntypes.Preimage, rhash, payAddr [32]byte) ( + *channeldb.Invoice, *lnwire.UpdateAddHTLC, uint64, error) { // Create the db invoice. Normally the payment requests needs to be set, // because it is decoded in InvoiceRegistry to obtain the cltv expiry. @@ -556,6 +556,7 @@ func generatePaymentWithPreimage(invoiceAmt, htlcAmt lnwire.MilliSatoshi, // step and always returning the value of testInvoiceCltvExpiry, we // don't need to bother here with creating and signing a payment // request. + invoice := &channeldb.Invoice{ CreationDate: time.Now(), Terms: channeldb.ContractTerm{ @@ -567,6 +568,7 @@ func generatePaymentWithPreimage(invoiceAmt, htlcAmt lnwire.MilliSatoshi, nil, lnwire.Features, ), }, + HodlInvoice: preimage == nil, } htlc := &lnwire.UpdateAddHTLC{ @@ -591,7 +593,7 @@ func generatePayment(invoiceAmt, htlcAmt lnwire.MilliSatoshi, timelock uint32, blob [lnwire.OnionPacketSize]byte) (*channeldb.Invoice, *lnwire.UpdateAddHTLC, uint64, error) { - var preimage [sha256.Size]byte + var preimage lntypes.Preimage r, err := generateRandomBytes(sha256.Size) if err != nil { return nil, nil, 0, err @@ -608,7 +610,7 @@ func generatePayment(invoiceAmt, htlcAmt lnwire.MilliSatoshi, timelock uint32, copy(payAddr[:], r) return generatePaymentWithPreimage( - invoiceAmt, htlcAmt, timelock, blob, preimage, rhash, payAddr, + invoiceAmt, htlcAmt, timelock, blob, &preimage, rhash, payAddr, ) } @@ -1345,7 +1347,7 @@ func (n *twoHopNetwork) makeHoldPayment(sendingPeer, receivingPeer lnpeer.Peer, // Generate payment: invoice and htlc. invoice, htlc, pid, err := generatePaymentWithPreimage( invoiceAmt, htlcAmt, timelock, blob, - channeldb.UnknownPreimage, rhash, payAddr, + nil, rhash, payAddr, ) if err != nil { paymentErr <- err diff --git a/invoices/invoiceregistry.go b/invoices/invoiceregistry.go index 2bea21ed8..633284668 100644 --- a/invoices/invoiceregistry.go +++ b/invoices/invoiceregistry.go @@ -652,12 +652,6 @@ func (i *InvoiceRegistry) processKeySend(ctx invoiceUpdateCtx) error { return errors.New("invalid keysend preimage") } - // Don't accept zero preimages as those have a special meaning in our - // database for hodl invoices. - if preimage == channeldb.UnknownPreimage { - return errors.New("invalid keysend preimage") - } - // Only allow keysend for non-mpp payments. if ctx.mpp != nil { return errors.New("no mpp keysend supported") @@ -688,7 +682,7 @@ func (i *InvoiceRegistry) processKeySend(ctx invoiceUpdateCtx) error { Terms: channeldb.ContractTerm{ FinalCltvDelta: finalCltvDelta, Value: amt, - PaymentPreimage: preimage, + PaymentPreimage: &preimage, Features: features, }, } @@ -948,7 +942,7 @@ func (i *InvoiceRegistry) SettleHodlInvoice(preimage lntypes.Preimage) error { return &channeldb.InvoiceUpdateDesc{ State: &channeldb.InvoiceStateUpdateDesc{ NewState: channeldb.ContractSettled, - Preimage: preimage, + Preimage: &preimage, }, }, nil } diff --git a/invoices/test_utils_test.go b/invoices/test_utils_test.go index 8d98b132b..d7846aec2 100644 --- a/invoices/test_utils_test.go +++ b/invoices/test_utils_test.go @@ -92,7 +92,7 @@ var ( testInvoiceAmt = lnwire.MilliSatoshi(100000) testInvoice = &channeldb.Invoice{ Terms: channeldb.ContractTerm{ - PaymentPreimage: testInvoicePreimage, + PaymentPreimage: &testInvoicePreimage, Value: testInvoiceAmt, Expiry: time.Hour, Features: testFeatures, @@ -102,12 +102,12 @@ var ( testHodlInvoice = &channeldb.Invoice{ Terms: channeldb.ContractTerm{ - PaymentPreimage: channeldb.UnknownPreimage, - Value: testInvoiceAmt, - Expiry: time.Hour, - Features: testFeatures, + Value: testInvoiceAmt, + Expiry: time.Hour, + Features: testFeatures, }, CreationDate: testInvoiceCreationDate, + HodlInvoice: true, } ) @@ -225,7 +225,7 @@ func newTestInvoice(t *testing.T, preimage lntypes.Preimage, return &channeldb.Invoice{ Terms: channeldb.ContractTerm{ - PaymentPreimage: preimage, + PaymentPreimage: &preimage, PaymentAddr: payAddr, Value: testInvoiceAmount, Expiry: expiry, diff --git a/invoices/update.go b/invoices/update.go index 625223782..ff420b855 100644 --- a/invoices/update.go +++ b/invoices/update.go @@ -81,7 +81,7 @@ func updateInvoice(ctx *invoiceUpdateCtx, inv *channeldb.Invoice) ( case channeldb.HtlcStateSettled: return nil, ctx.settleRes( - inv.Terms.PaymentPreimage, + *inv.Terms.PaymentPreimage, ResultReplayToSettled, ), nil @@ -187,8 +187,7 @@ func updateMpp(ctx *invoiceUpdateCtx, // Check to see if we can settle or this is an hold invoice and // we need to wait for the preimage. - holdInvoice := inv.Terms.PaymentPreimage == channeldb.UnknownPreimage - if holdInvoice { + if inv.HodlInvoice { update.State = &channeldb.InvoiceStateUpdateDesc{ NewState: channeldb.ContractAccepted, } @@ -201,7 +200,7 @@ func updateMpp(ctx *invoiceUpdateCtx, } return &update, ctx.settleRes( - inv.Terms.PaymentPreimage, ResultSettled, + *inv.Terms.PaymentPreimage, ResultSettled, ), nil } @@ -269,14 +268,13 @@ func updateLegacy(ctx *invoiceUpdateCtx, case channeldb.ContractSettled: return &update, ctx.settleRes( - inv.Terms.PaymentPreimage, ResultDuplicateToSettled, + *inv.Terms.PaymentPreimage, ResultDuplicateToSettled, ), nil } // Check to see if we can settle or this is an hold invoice and we need // to wait for the preimage. - holdInvoice := inv.Terms.PaymentPreimage == channeldb.UnknownPreimage - if holdInvoice { + if inv.HodlInvoice { update.State = &channeldb.InvoiceStateUpdateDesc{ NewState: channeldb.ContractAccepted, } @@ -290,6 +288,6 @@ func updateLegacy(ctx *invoiceUpdateCtx, } return &update, ctx.settleRes( - inv.Terms.PaymentPreimage, ResultSettled, + *inv.Terms.PaymentPreimage, ResultSettled, ), nil } diff --git a/lnrpc/invoicesrpc/addinvoice.go b/lnrpc/invoicesrpc/addinvoice.go index 171e85b7b..c1cde48a3 100644 --- a/lnrpc/invoicesrpc/addinvoice.go +++ b/lnrpc/invoicesrpc/addinvoice.go @@ -88,6 +88,10 @@ type AddInvoiceData struct { // Whether this invoice should include routing hints for private // channels. Private bool + + // HodlInvoice signals that this invoice shouldn't be settled + // immediately upon receiving the payment. + HodlInvoice bool } // AddInvoice attempts to add a new invoice to the invoice database. Any @@ -97,7 +101,7 @@ func AddInvoice(ctx context.Context, cfg *AddInvoiceConfig, invoice *AddInvoiceData) (*lntypes.Hash, *channeldb.Invoice, error) { var ( - paymentPreimage lntypes.Preimage + paymentPreimage *lntypes.Preimage paymentHash lntypes.Hash ) @@ -108,26 +112,9 @@ func AddInvoice(ctx context.Context, cfg *AddInvoiceConfig, return nil, nil, errors.New("preimage and hash both set") - // Prevent the unknown preimage magic value from being used for a - // regular invoice. This would cause the invoice the be handled as if it - // was a hold invoice. - case invoice.Preimage != nil && - *invoice.Preimage == channeldb.UnknownPreimage: - - return nil, nil, - fmt.Errorf("cannot use all zeroes as a preimage") - - // Prevent the hash of the unknown preimage magic value to be used for a - // hold invoice. This would make it impossible to settle the invoice, - // because it would still be interpreted as not having a preimage. - case invoice.Hash != nil && - *invoice.Hash == channeldb.UnknownPreimage.Hash(): - - return nil, nil, - fmt.Errorf("cannot use hash of all zeroes preimage") - // If no hash or preimage is given, generate a random preimage. case invoice.Preimage == nil && invoice.Hash == nil: + paymentPreimage = &lntypes.Preimage{} if _, err := rand.Read(paymentPreimage[:]); err != nil { return nil, nil, err } @@ -136,12 +123,12 @@ func AddInvoice(ctx context.Context, cfg *AddInvoiceConfig, // If just a hash is given, we create a hold invoice by setting the // preimage to unknown. case invoice.Preimage == nil && invoice.Hash != nil: - paymentPreimage = channeldb.UnknownPreimage paymentHash = *invoice.Hash // A specific preimage was supplied. Use that for the invoice. case invoice.Preimage != nil && invoice.Hash == nil: - paymentPreimage = *invoice.Preimage + preimage := *invoice.Preimage + paymentPreimage = &preimage paymentHash = invoice.Preimage.Hash() } @@ -410,6 +397,7 @@ func AddInvoice(ctx context.Context, cfg *AddInvoiceConfig, PaymentAddr: paymentAddr, Features: invoiceFeatures, }, + HodlInvoice: invoice.HodlInvoice, } log.Tracef("[addinvoice] adding new invoice %v", diff --git a/lnrpc/invoicesrpc/invoices_server.go b/lnrpc/invoicesrpc/invoices_server.go index e915bc1a0..3d840a5ba 100644 --- a/lnrpc/invoicesrpc/invoices_server.go +++ b/lnrpc/invoicesrpc/invoices_server.go @@ -274,6 +274,8 @@ func (s *Server) AddHoldInvoice(ctx context.Context, FallbackAddr: invoice.FallbackAddr, CltvExpiry: invoice.CltvExpiry, Private: invoice.Private, + HodlInvoice: true, + Preimage: nil, } _, dbInvoice, err := AddInvoice(ctx, addInvoiceCfg, addInvoiceData) diff --git a/lnrpc/invoicesrpc/utils.go b/lnrpc/invoicesrpc/utils.go index 1d3bab33c..9ae1818e9 100644 --- a/lnrpc/invoicesrpc/utils.go +++ b/lnrpc/invoicesrpc/utils.go @@ -22,7 +22,7 @@ func decodePayReq(invoice *channeldb.Invoice, paymentRequest := string(invoice.PaymentRequest) if paymentRequest == "" { preimage := invoice.Terms.PaymentPreimage - if preimage == channeldb.UnknownPreimage { + if preimage == nil { return nil, errors.New("cannot reconstruct pay req") } hash := [32]byte(preimage.Hash()) @@ -149,7 +149,7 @@ func CreateRPCInvoice(invoice *channeldb.Invoice, IsKeysend: len(invoice.PaymentRequest) == 0, } - if preimage != channeldb.UnknownPreimage { + if preimage != nil { rpcInvoice.RPreimage = preimage[:] }