mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-08-31 17:51:33 +02:00
zpay32: add payment metadata field
This commit is contained in:
@@ -229,6 +229,15 @@ func parseTaggedFields(invoice *Invoice, fields []byte, net *chaincfg.Params) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
invoice.Description, err = parseDescription(base32Data)
|
invoice.Description, err = parseDescription(base32Data)
|
||||||
|
case fieldTypeM:
|
||||||
|
if invoice.Metadata != nil {
|
||||||
|
// We skip the field if we have already seen a
|
||||||
|
// supported one.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
invoice.Metadata, err = parseMetadata(base32Data)
|
||||||
|
|
||||||
case fieldTypeN:
|
case fieldTypeN:
|
||||||
if invoice.Destination != nil {
|
if invoice.Destination != nil {
|
||||||
// We skip the field if we have already seen a
|
// We skip the field if we have already seen a
|
||||||
@@ -345,6 +354,12 @@ func parseDescription(data []byte) (*string, error) {
|
|||||||
return &description, nil
|
return &description, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseMetadata converts the data (encoded in base32) into a byte slice to use
|
||||||
|
// as the metadata.
|
||||||
|
func parseMetadata(data []byte) ([]byte, error) {
|
||||||
|
return bech32.ConvertBits(data, 5, 8, false)
|
||||||
|
}
|
||||||
|
|
||||||
// parseDestination converts the data (encoded in base32) into a 33-byte public
|
// parseDestination converts the data (encoded in base32) into a 33-byte public
|
||||||
// key of the payee node.
|
// key of the payee node.
|
||||||
func parseDestination(data []byte) (*btcec.PublicKey, error) {
|
func parseDestination(data []byte) (*btcec.PublicKey, error) {
|
||||||
|
@@ -164,6 +164,17 @@ func writeTaggedFields(bufferBase32 *bytes.Buffer, invoice *Invoice) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if invoice.Metadata != nil {
|
||||||
|
base32, err := bech32.ConvertBits(invoice.Metadata, 8, 5, true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = writeTaggedField(bufferBase32, fieldTypeM, base32)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if invoice.minFinalCLTVExpiry != nil {
|
if invoice.minFinalCLTVExpiry != nil {
|
||||||
finalDelta := uint64ToBase32(*invoice.minFinalCLTVExpiry)
|
finalDelta := uint64ToBase32(*invoice.minFinalCLTVExpiry)
|
||||||
err := writeTaggedField(bufferBase32, fieldTypeC, finalDelta)
|
err := writeTaggedField(bufferBase32, fieldTypeC, finalDelta)
|
||||||
|
@@ -46,6 +46,9 @@ const (
|
|||||||
// fieldTypeD contains a short description of the payment.
|
// fieldTypeD contains a short description of the payment.
|
||||||
fieldTypeD = 13
|
fieldTypeD = 13
|
||||||
|
|
||||||
|
// fieldTypeM contains the payment metadata.
|
||||||
|
fieldTypeM = 27
|
||||||
|
|
||||||
// fieldTypeN contains the pubkey of the target node.
|
// fieldTypeN contains the pubkey of the target node.
|
||||||
fieldTypeN = 19
|
fieldTypeN = 19
|
||||||
|
|
||||||
@@ -183,6 +186,10 @@ type Invoice struct {
|
|||||||
// Features represents an optional field used to signal optional or
|
// Features represents an optional field used to signal optional or
|
||||||
// required support for features by the receiver.
|
// required support for features by the receiver.
|
||||||
Features *lnwire.FeatureVector
|
Features *lnwire.FeatureVector
|
||||||
|
|
||||||
|
// Metadata is additional data that is sent along with the payment to
|
||||||
|
// the payee.
|
||||||
|
Metadata []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// Amount is a functional option that allows callers of NewInvoice to set the
|
// Amount is a functional option that allows callers of NewInvoice to set the
|
||||||
@@ -273,6 +280,14 @@ func PaymentAddr(addr [32]byte) func(*Invoice) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Metadata is a functional option that allows callers of NewInvoice to set
|
||||||
|
// the desired payment Metadata tht is advertised on the invoice.
|
||||||
|
func Metadata(metadata []byte) func(*Invoice) {
|
||||||
|
return func(i *Invoice) {
|
||||||
|
i.Metadata = metadata
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewInvoice creates a new Invoice object. The last parameter is a set of
|
// NewInvoice creates a new Invoice object. The last parameter is a set of
|
||||||
// variadic arguments for setting optional fields of the invoice.
|
// variadic arguments for setting optional fields of the invoice.
|
||||||
//
|
//
|
||||||
|
@@ -27,6 +27,7 @@ var (
|
|||||||
testMillisat2500uBTC = lnwire.MilliSatoshi(250000000)
|
testMillisat2500uBTC = lnwire.MilliSatoshi(250000000)
|
||||||
testMillisat25mBTC = lnwire.MilliSatoshi(2500000000)
|
testMillisat25mBTC = lnwire.MilliSatoshi(2500000000)
|
||||||
testMillisat20mBTC = lnwire.MilliSatoshi(2000000000)
|
testMillisat20mBTC = lnwire.MilliSatoshi(2000000000)
|
||||||
|
testMillisat10mBTC = lnwire.MilliSatoshi(1000000000)
|
||||||
|
|
||||||
testPaymentHash = [32]byte{
|
testPaymentHash = [32]byte{
|
||||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||||
@@ -54,6 +55,7 @@ var (
|
|||||||
testCoffeeBeans = "coffee beans"
|
testCoffeeBeans = "coffee beans"
|
||||||
testCupOfNonsense = "ナンセンス 1杯"
|
testCupOfNonsense = "ナンセンス 1杯"
|
||||||
testPleaseConsider = "Please consider supporting this project"
|
testPleaseConsider = "Please consider supporting this project"
|
||||||
|
testPaymentMetadata = "payment metadata inside"
|
||||||
|
|
||||||
testPrivKeyBytes, _ = hex.DecodeString("e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734")
|
testPrivKeyBytes, _ = hex.DecodeString("e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734")
|
||||||
testPrivKey, testPubKey = btcec.PrivKeyFromBytes(testPrivKeyBytes)
|
testPrivKey, testPubKey = btcec.PrivKeyFromBytes(testPrivKeyBytes)
|
||||||
@@ -692,6 +694,33 @@ func TestDecodeEncode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// Please send 0.01 BTC with payment metadata 0x01fafaf0.
|
||||||
|
encodedInvoice: "lnbc10m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp9wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2mq8q8a04uqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q2gqqqqqqsgq7hf8he7ecf7n4ffphs6awl9t6676rrclv9ckg3d3ncn7fct63p6s365duk5wrk202cfy3aj5xnnp5gs3vrdvruverwwq7yzhkf5a3xqpd05wjc",
|
||||||
|
valid: true,
|
||||||
|
decodedInvoice: func() *Invoice {
|
||||||
|
return &Invoice{
|
||||||
|
Net: &chaincfg.MainNetParams,
|
||||||
|
MilliSat: &testMillisat10mBTC,
|
||||||
|
Timestamp: time.Unix(1496314658, 0),
|
||||||
|
PaymentHash: &testPaymentHash,
|
||||||
|
Description: &testPaymentMetadata,
|
||||||
|
Destination: testPubKey,
|
||||||
|
PaymentAddr: &specPaymentAddr,
|
||||||
|
Features: lnwire.NewFeatureVector(
|
||||||
|
lnwire.NewRawFeatureVector(8, 14, 48),
|
||||||
|
lnwire.Features,
|
||||||
|
),
|
||||||
|
Metadata: []byte{0x01, 0xfa, 0xfa, 0xf0},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeEncoding: func(i *Invoice) {
|
||||||
|
// Since this destination pubkey was recovered
|
||||||
|
// from the signature, we must set it nil before
|
||||||
|
// encoding to get back the same invoice string.
|
||||||
|
i.Destination = nil
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
|
Reference in New Issue
Block a user