zpay32: ensure feature vector is always populated
This commit is contained in:
parent
62dadff291
commit
840476996c
@ -257,7 +257,8 @@ func RouteHint(routeHint []HopHint) func(*Invoice) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Features is a functional option that allows callers of NewInvoice to set the
|
// Features is a functional option that allows callers of NewInvoice to set the
|
||||||
// desired feature bits that are advertised on the invoice.
|
// desired feature bits that are advertised on the invoice. If this option is
|
||||||
|
// not used, an empty feature vector will automatically be populated.
|
||||||
func Features(features *lnwire.FeatureVector) func(*Invoice) {
|
func Features(features *lnwire.FeatureVector) func(*Invoice) {
|
||||||
return func(i *Invoice) {
|
return func(i *Invoice) {
|
||||||
i.Features = features
|
i.Features = features
|
||||||
@ -290,6 +291,13 @@ func NewInvoice(net *chaincfg.Params, paymentHash [32]byte,
|
|||||||
option(invoice)
|
option(invoice)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If no features were set, we'll populate an empty feature vector.
|
||||||
|
if invoice.Features == nil {
|
||||||
|
invoice.Features = lnwire.NewFeatureVector(
|
||||||
|
nil, lnwire.Features,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if err := validateInvoice(invoice); err != nil {
|
if err := validateInvoice(invoice); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -398,6 +406,13 @@ func Decode(invoice string, net *chaincfg.Params) (*Invoice, error) {
|
|||||||
decodedInvoice.Destination = pubkey
|
decodedInvoice.Destination = pubkey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If no feature vector was decoded, populate an empty one.
|
||||||
|
if decodedInvoice.Features == nil {
|
||||||
|
decodedInvoice.Features = lnwire.NewFeatureVector(
|
||||||
|
nil, lnwire.Features,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Now that we have created the invoice, make sure it has the required
|
// Now that we have created the invoice, make sure it has the required
|
||||||
// fields set.
|
// fields set.
|
||||||
if err := validateInvoice(&decodedInvoice); err != nil {
|
if err := validateInvoice(&decodedInvoice); err != nil {
|
||||||
@ -586,6 +601,11 @@ func validateInvoice(invoice *Invoice) error {
|
|||||||
len(invoice.Destination.SerializeCompressed()))
|
len(invoice.Destination.SerializeCompressed()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure that all invoices have feature vectors.
|
||||||
|
if invoice.Features == nil {
|
||||||
|
return fmt.Errorf("missing feature vector")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1070,7 +1090,7 @@ func writeTaggedFields(bufferBase32 *bytes.Buffer, invoice *Invoice) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if invoice.Features != nil && invoice.Features.SerializeSize32() > 0 {
|
if invoice.Features.SerializeSize32() > 0 {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
err := invoice.Features.RawFeatureVector.EncodeBase32(&b)
|
err := invoice.Features.RawFeatureVector.EncodeBase32(&b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -105,6 +105,8 @@ var (
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emptyFeatures = lnwire.NewFeatureVector(nil, lnwire.Features)
|
||||||
|
|
||||||
// Must be initialized in init().
|
// Must be initialized in init().
|
||||||
testDescriptionHash [32]byte
|
testDescriptionHash [32]byte
|
||||||
|
|
||||||
@ -190,6 +192,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
Timestamp: time.Unix(1496314658, 0),
|
Timestamp: time.Unix(1496314658, 0),
|
||||||
DescriptionHash: &testDescriptionHash,
|
DescriptionHash: &testDescriptionHash,
|
||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
|
Features: emptyFeatures,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -206,6 +209,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
Description: &testPleaseConsider,
|
Description: &testPleaseConsider,
|
||||||
DescriptionHash: &testDescriptionHash,
|
DescriptionHash: &testDescriptionHash,
|
||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
|
Features: emptyFeatures,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -220,6 +224,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
Timestamp: time.Unix(1496314658, 0),
|
Timestamp: time.Unix(1496314658, 0),
|
||||||
PaymentHash: &testPaymentHash,
|
PaymentHash: &testPaymentHash,
|
||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
|
Features: emptyFeatures,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -235,6 +240,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
PaymentHash: &testPaymentHash,
|
PaymentHash: &testPaymentHash,
|
||||||
Description: &testPleaseConsider,
|
Description: &testPleaseConsider,
|
||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
|
Features: emptyFeatures,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
skipEncoding: true, // Skip encoding since we don't have the unknown fields to encode.
|
skipEncoding: true, // Skip encoding since we don't have the unknown fields to encode.
|
||||||
@ -251,6 +257,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
PaymentHash: &testPaymentHash,
|
PaymentHash: &testPaymentHash,
|
||||||
DescriptionHash: &testDescriptionHash,
|
DescriptionHash: &testDescriptionHash,
|
||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
|
Features: emptyFeatures,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
skipEncoding: true, // Skip encoding since we don't have the unknown fields to encode.
|
skipEncoding: true, // Skip encoding since we don't have the unknown fields to encode.
|
||||||
@ -267,6 +274,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
PaymentHash: &testPaymentHash,
|
PaymentHash: &testPaymentHash,
|
||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
DescriptionHash: &testDescriptionHash,
|
DescriptionHash: &testDescriptionHash,
|
||||||
|
Features: emptyFeatures,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
skipEncoding: true, // Skip encoding since we don't have the unknown fields to encode.
|
skipEncoding: true, // Skip encoding since we don't have the unknown fields to encode.
|
||||||
@ -282,6 +290,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
PaymentHash: &testPaymentHash,
|
PaymentHash: &testPaymentHash,
|
||||||
Description: &testCupOfCoffee,
|
Description: &testCupOfCoffee,
|
||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
|
Features: emptyFeatures,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeEncoding: func(i *Invoice) {
|
beforeEncoding: func(i *Invoice) {
|
||||||
@ -302,6 +311,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
PaymentHash: &testPaymentHash,
|
PaymentHash: &testPaymentHash,
|
||||||
Description: &testPleaseConsider,
|
Description: &testPleaseConsider,
|
||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
|
Features: emptyFeatures,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeEncoding: func(i *Invoice) {
|
beforeEncoding: func(i *Invoice) {
|
||||||
@ -323,6 +333,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
PaymentHash: &testPaymentHash,
|
PaymentHash: &testPaymentHash,
|
||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
Description: &testEmptyString,
|
Description: &testEmptyString,
|
||||||
|
Features: emptyFeatures,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -382,6 +393,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
PaymentHash: &testPaymentHash,
|
PaymentHash: &testPaymentHash,
|
||||||
DescriptionHash: &testDescriptionHash,
|
DescriptionHash: &testDescriptionHash,
|
||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
|
Features: emptyFeatures,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeEncoding: func(i *Invoice) {
|
beforeEncoding: func(i *Invoice) {
|
||||||
@ -404,6 +416,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
DescriptionHash: &testDescriptionHash,
|
DescriptionHash: &testDescriptionHash,
|
||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
FallbackAddr: testAddrTestnet,
|
FallbackAddr: testAddrTestnet,
|
||||||
|
Features: emptyFeatures,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeEncoding: func(i *Invoice) {
|
beforeEncoding: func(i *Invoice) {
|
||||||
@ -427,6 +440,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
FallbackAddr: testRustyAddr,
|
FallbackAddr: testRustyAddr,
|
||||||
RouteHints: [][]HopHint{testSingleHop},
|
RouteHints: [][]HopHint{testSingleHop},
|
||||||
|
Features: emptyFeatures,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeEncoding: func(i *Invoice) {
|
beforeEncoding: func(i *Invoice) {
|
||||||
@ -450,6 +464,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
FallbackAddr: testRustyAddr,
|
FallbackAddr: testRustyAddr,
|
||||||
RouteHints: [][]HopHint{testDoubleHop},
|
RouteHints: [][]HopHint{testDoubleHop},
|
||||||
|
Features: emptyFeatures,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeEncoding: func(i *Invoice) {
|
beforeEncoding: func(i *Invoice) {
|
||||||
@ -472,6 +487,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
DescriptionHash: &testDescriptionHash,
|
DescriptionHash: &testDescriptionHash,
|
||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
FallbackAddr: testAddrMainnetP2SH,
|
FallbackAddr: testAddrMainnetP2SH,
|
||||||
|
Features: emptyFeatures,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeEncoding: func(i *Invoice) {
|
beforeEncoding: func(i *Invoice) {
|
||||||
@ -547,6 +563,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
DescriptionHash: &testDescriptionHash,
|
DescriptionHash: &testDescriptionHash,
|
||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
FallbackAddr: testAddrMainnetP2WPKH,
|
FallbackAddr: testAddrMainnetP2WPKH,
|
||||||
|
Features: emptyFeatures,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeEncoding: func(i *Invoice) {
|
beforeEncoding: func(i *Invoice) {
|
||||||
@ -569,6 +586,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
DescriptionHash: &testDescriptionHash,
|
DescriptionHash: &testDescriptionHash,
|
||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
FallbackAddr: testAddrMainnetP2WSH,
|
FallbackAddr: testAddrMainnetP2WSH,
|
||||||
|
Features: emptyFeatures,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeEncoding: func(i *Invoice) {
|
beforeEncoding: func(i *Invoice) {
|
||||||
@ -628,6 +646,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
PaymentHash: &testPaymentHash,
|
PaymentHash: &testPaymentHash,
|
||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
Description: &testEmptyString,
|
Description: &testEmptyString,
|
||||||
|
Features: emptyFeatures,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
skipEncoding: true, // Skip encoding since we were given the wrong net
|
skipEncoding: true, // Skip encoding since we were given the wrong net
|
||||||
@ -645,6 +664,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
PaymentHash: &testPaymentHash,
|
PaymentHash: &testPaymentHash,
|
||||||
DescriptionHash: &testDescriptionHash,
|
DescriptionHash: &testDescriptionHash,
|
||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
|
Features: emptyFeatures,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -660,6 +680,7 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
PaymentHash: &testPaymentHash,
|
PaymentHash: &testPaymentHash,
|
||||||
DescriptionHash: &testDescriptionHash,
|
DescriptionHash: &testDescriptionHash,
|
||||||
Destination: testPubKey,
|
Destination: testPubKey,
|
||||||
|
Features: emptyFeatures,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -983,7 +1004,7 @@ func compareInvoices(expected, actual *Invoice) error {
|
|||||||
|
|
||||||
if !reflect.DeepEqual(expected.Features, actual.Features) {
|
if !reflect.DeepEqual(expected.Features, actual.Features) {
|
||||||
return fmt.Errorf("expected features %v, got %v",
|
return fmt.Errorf("expected features %v, got %v",
|
||||||
expected.Features.RawFeatureVector, actual.Features.RawFeatureVector)
|
expected.Features, actual.Features)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
Loading…
Reference in New Issue
Block a user