zpay32: add new 'c' field to payreqs for specifying final cltv delta

This commit is contained in:
Olaoluwa Osuntokun
2017-10-18 22:14:54 -07:00
parent de7e339281
commit c54e6fc803
2 changed files with 84 additions and 5 deletions

View File

@@ -8,6 +8,7 @@ import (
"time"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/chaincfg"
"github.com/roasbeef/btcd/chaincfg/chainhash"
@@ -60,12 +61,14 @@ const (
// fieldTypeR contains extra routing information.
fieldTypeR = 3
// fieldTypeC contains an optional requested final CLTV delta.
fieldTypeC = 24
)
// MessageSigner is passed to the Encode method to provide a signature
// corresponding to the node's pubkey.
type MessageSigner struct {
// SignCompact signs the passed hash with the node's privkey. The
// returned signature should be 65 bytes, where the last 64 are the
// compact signature, and the first one is a header byte. This is the
@@ -100,6 +103,18 @@ type Invoice struct {
// and the pubkey will be extracted from the signature during decoding.
Destination *btcec.PublicKey
// minFinalCLTVExpiry is the value that the creator of the invoice
// expects to be used for the
//
// NOTE: This value is optional, and should be set to nil if the
// invoice creator doesn't have a strong requirement on the CLTV expiry
// of the final HTLC extended to it.
//
// This field is un-exported and can only be read by the
// MinFinalCLTVExpiry() method. By forcing callers to read via this
// method, we can easily enforce the default if not specified.
minFinalCLTVExpiry *uint64
// Description is a short description of the purpose of this invoice.
// Optional. Non-nil iff DescriptionHash is nil.
Description *string
@@ -162,16 +177,27 @@ func Destination(destination *btcec.PublicKey) func(*Invoice) {
// Description is a functional option that allows callers of NewInvoice to set
// the payment description of the created Invoice.
// Note: Must be used if and only if DescriptionHash is not used.
//
// NOTE: Must be used if and only if DescriptionHash is not used.
func Description(description string) func(*Invoice) {
return func(i *Invoice) {
i.Description = &description
}
}
// CLTVExpiry is an optional value which allows the receiver of the payment to
// specify the delta between the current height and the HTLC extended to the
// receiver.
func CLTVExpiry(delta uint64) func(*Invoice) {
return func(i *Invoice) {
i.minFinalCLTVExpiry = &delta
}
}
// DescriptionHash is a functional option that allows callers of NewInvoice to
// set the payment description hash of the created Invoice.
// Note: Must be used if and only if Description is not used.
//
// NOTE: Must be used if and only if Description is not used.
func DescriptionHash(descriptionHash [32]byte) func(*Invoice) {
return func(i *Invoice) {
i.DescriptionHash = &descriptionHash
@@ -207,7 +233,8 @@ func RoutingInfo(routingInfo []ExtraRoutingInfo) func(*Invoice) {
// NewInvoice creates a new Invoice object. The last parameter is a set of
// variadic argumements for setting optional fields of the invoice.
// Note: Either Description or DescriptionHash must be provided for the Invoice
//
// NOTE: Either Description or DescriptionHash must be provided for the Invoice
// to be considered valid.
func NewInvoice(net *chaincfg.Params, paymentHash [32]byte,
timestamp time.Time, options ...func(*Invoice)) (*Invoice, error) {
@@ -459,6 +486,19 @@ func (invoice *Invoice) Expiry() time.Duration {
return 3600 * time.Second
}
// MinFinalCLTVExpiry returns the minimum final CLTV expiry delta as specified
// by the creator of the invoice. This value specifies the delta between the
// current height and the expiry height of the HTLC extended in the last hop.
func (invoice *Invoice) MinFinalCLTVExpiry() uint64 {
if invoice.minFinalCLTVExpiry != nil {
fmt.Println("USING SET CLTV")
return *invoice.minFinalCLTVExpiry
}
fmt.Println("USING DEFAULT CLTV")
return routing.DefaultFinalCLTVDelta
}
// validateInvoice does a sanity check of the provided Invoice, making sure it
// has all the necessary fields set for it to be considered valid by BOLT-0011.
func validateInvoice(invoice *Invoice) error {
@@ -651,6 +691,18 @@ func parseTaggedFields(invoice *Invoice, fields []byte, net *chaincfg.Params) er
}
dur := time.Duration(exp) * time.Second
invoice.expiry = &dur
case fieldTypeC:
if invoice.minFinalCLTVExpiry != nil {
// We skip the field if we have already seen a
// supported one.
continue
}
expiry, err := base32ToUint64(base32Data)
if err != nil {
return err
}
invoice.minFinalCLTVExpiry = &expiry
case fieldTypeF:
if invoice.FallbackAddr != nil {
// We skip the field if we have already seen a
@@ -675,7 +727,7 @@ func parseTaggedFields(invoice *Invoice, fields []byte, net *chaincfg.Params) er
addr, err = btcutil.NewAddressWitnessScriptHash(
witness, net)
default:
return fmt.Errorf("unknow witness "+
return fmt.Errorf("unknown witness "+
"program length: %d", len(witness))
}
if err != nil {
@@ -798,6 +850,14 @@ func writeTaggedFields(bufferBase32 *bytes.Buffer, invoice *Invoice) error {
}
}
if invoice.minFinalCLTVExpiry != nil {
finalDelta := uint64ToBase32(uint64(*invoice.minFinalCLTVExpiry))
err := writeTaggedField(bufferBase32, fieldTypeC, finalDelta)
if err != nil {
return err
}
}
if invoice.expiry != nil {
seconds := invoice.expiry.Seconds()
expiry := uint64ToBase32(uint64(seconds))