Merge pull request #1448 from Roasbeef/check-invoice-min-final

channeldb+htlcswitch: use the final min cltv delta in the invoice when link at exit hop
This commit is contained in:
Olaoluwa Osuntokun 2018-06-28 18:39:33 -07:00 committed by GitHub
commit 3a47c41c6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 28 additions and 7 deletions

View File

@ -3,6 +3,7 @@ package channeldb
import ( import (
"crypto/rand" "crypto/rand"
"crypto/sha256" "crypto/sha256"
prand "math/rand"
"reflect" "reflect"
"testing" "testing"
"time" "time"
@ -24,6 +25,7 @@ func randInvoice(value lnwire.MilliSatoshi) (*Invoice, error) {
Terms: ContractTerm{ Terms: ContractTerm{
PaymentPreimage: pre, PaymentPreimage: pre,
Value: value, Value: value,
FinalCltvDelta: uint16(prand.Int31()),
}, },
} }
i.Memo = []byte("memo") i.Memo = []byte("memo")
@ -66,6 +68,7 @@ func TestInvoiceWorkflow(t *testing.T) {
fakeInvoice.PaymentRequest = []byte("") fakeInvoice.PaymentRequest = []byte("")
copy(fakeInvoice.Terms.PaymentPreimage[:], rev[:]) copy(fakeInvoice.Terms.PaymentPreimage[:], rev[:])
fakeInvoice.Terms.Value = lnwire.NewMSatFromSatoshis(10000) fakeInvoice.Terms.Value = lnwire.NewMSatFromSatoshis(10000)
fakeInvoice.Terms.FinalCltvDelta = uint16(prand.Int31())
// Add the invoice to the database, this should succeed as there aren't // Add the invoice to the database, this should succeed as there aren't
// any existing invoices within the database with the same payment // any existing invoices within the database with the same payment

View File

@ -68,6 +68,13 @@ type ContractTerm struct {
// Settled indicates if this particular contract term has been fully // Settled indicates if this particular contract term has been fully
// settled by the payer. // settled by the payer.
Settled bool Settled bool
// FinalCltvDelta is the lower bound of a delta from the current height
// that the HTLC that wishes to settle this invoice MUST carry. This
// allows the receiver to specify the time window that should be
// available for them to sweep the HTLC on-chain if that becomes
// necessary.
FinalCltvDelta uint16
} }
// Invoice is a payment invoice generated by a payee in order to request // Invoice is a payment invoice generated by a payee in order to request
@ -79,8 +86,7 @@ type ContractTerm struct {
// invoices are never deleted from the database, instead a bit is toggled // invoices are never deleted from the database, instead a bit is toggled
// denoting the invoice has been fully settled. Within the database, all // denoting the invoice has been fully settled. Within the database, all
// invoices must have a unique payment hash which is generated by taking the // invoices must have a unique payment hash which is generated by taking the
// sha256 of the payment // sha256 of the payment preimage.
// preimage.
type Invoice struct { type Invoice struct {
// Memo is an optional memo to be stored along side an invoice. The // Memo is an optional memo to be stored along side an invoice. The
// memo may contain further details pertaining to the invoice itself, // memo may contain further details pertaining to the invoice itself,
@ -361,7 +367,7 @@ func serializeInvoice(w io.Writer, i *Invoice) error {
return err return err
} }
return nil return binary.Write(w, byteOrder, i.Terms.FinalCltvDelta)
} }
func fetchInvoice(invoiceNum []byte, invoices *bolt.Bucket) (*Invoice, error) { func fetchInvoice(invoiceNum []byte, invoices *bolt.Bucket) (*Invoice, error) {
@ -423,6 +429,18 @@ func deserializeInvoice(r io.Reader) (*Invoice, error) {
return nil, err return nil, err
} }
// Before we return with the current invoice, we'll check to see if
// there's still enough space in the buffer to read out the final ctlv
// delta. We'll get an EOF error if there isn't any thing else
// lingering in the buffer.
err = binary.Read(r, byteOrder, &invoice.Terms.FinalCltvDelta)
if err != nil && err != io.EOF {
// If we got a non-eof error, then we know there's an actually
// issue. Otherwise, it may have been the case that this
// summary didn't have the set of optional fields.
return nil, err
}
return invoice, nil return invoice, nil
} }

View File

@ -2258,9 +2258,8 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
// We'll also ensure that our time-lock value has been // We'll also ensure that our time-lock value has been
// computed correctly. // computed correctly.
// minCltvDelta := uint32(invoice.Terms.FinalCltvDelta)
// TODO(roasbeef): also accept global default? expectedHeight := heightNow + minCltvDelta
expectedHeight := heightNow + l.cfg.FwrdingPolicy.TimeLockDelta
switch { switch {
case !l.cfg.DebugHTLC && fwdInfo.OutgoingCTLV < expectedHeight: case !l.cfg.DebugHTLC && fwdInfo.OutgoingCTLV < expectedHeight:

View File

@ -2659,7 +2659,8 @@ func (r *rpcServer) AddInvoice(ctx context.Context,
Receipt: invoice.Receipt, Receipt: invoice.Receipt,
PaymentRequest: []byte(payReqString), PaymentRequest: []byte(payReqString),
Terms: channeldb.ContractTerm{ Terms: channeldb.ContractTerm{
Value: amtMSat, Value: amtMSat,
FinalCltvDelta: uint16(payReq.MinFinalCLTVExpiry()),
}, },
} }
copy(i.Terms.PaymentPreimage[:], paymentPreimage[:]) copy(i.Terms.PaymentPreimage[:], paymentPreimage[:])