Merge pull request #4334 from joostjager/hold-keysend-part1
invoices: add explicit hodl invoice flag
This commit is contained in:
commit
9f32942a90
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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)
|
||||
|
@ -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[:]
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user