zpay32: make expiry time only accessable using Expiry()

This commit renames the invoice field Expiry to expiry, and changes
the type from time.Time to time.Duration. Getting the value of the
field will now have to be done using the getter Expiry(), which
will also return the default invoice expiry (3600s) if it is not set
explicitly by the the invoice.
This commit is contained in:
Johan T. Halseth 2017-09-27 12:09:11 +02:00
parent b645f02418
commit 070eb0ec3e
No known key found for this signature in database
GPG Key ID: 15BAADA29DA20D26
2 changed files with 208 additions and 156 deletions

@ -109,9 +109,13 @@ type Invoice struct {
// Optional. Non-nil iff Description is nil. // Optional. Non-nil iff Description is nil.
DescriptionHash *[32]byte DescriptionHash *[32]byte
// Expiry specifies the timespan this invoice will be valid. // expiry specifies the timespan this invoice will be valid.
// Optional. If not set, a default expiry of 60 min will be implied. // Optional. If not set, a default expiry of 60 min will be implied.
Expiry *time.Time //
// This field is unexported and can be read by the Expiry() method. This
// method makes sure the default expiry time is returned in case the
// field is not set.
expiry *time.Duration
// FallbackAddr is an on-chain address that can be used for payment in // FallbackAddr is an on-chain address that can be used for payment in
// case the Lightning payment fails. // case the Lightning payment fails.
@ -177,9 +181,9 @@ func DescriptionHash(descriptionHash [32]byte) func(*Invoice) {
// Expiry is a functional option that allows callers of NewInvoice to set the // Expiry is a functional option that allows callers of NewInvoice to set the
// expiry of the created Invoice. If not set, a default expiry of 60 min will // expiry of the created Invoice. If not set, a default expiry of 60 min will
// be implied. // be implied.
func Expiry(expiry time.Time) func(*Invoice) { func Expiry(expiry time.Duration) func(*Invoice) {
return func(i *Invoice) { return func(i *Invoice) {
i.Expiry = &expiry i.expiry = &expiry
} }
} }
@ -444,6 +448,17 @@ func (invoice *Invoice) Encode(signer MessageSigner) (string, error) {
return b32, nil return b32, nil
} }
// Expiry returns the expiry time for this invoice. If expiry time is not set
// explicitly, the default 3600 second expiry will be returned.
func (invoice *Invoice) Expiry() time.Duration {
if invoice.expiry != nil {
return *invoice.expiry
}
// If no expiry is set for this invoice, default is 3600 seconds.
return 3600 * time.Second
}
// validateInvoice does a sanity check of the provided Invoice, making sure it // 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. // has all the necessary fields set for it to be considered valid by BOLT-0011.
func validateInvoice(invoice *Invoice) error { func validateInvoice(invoice *Invoice) error {
@ -624,7 +639,7 @@ func parseTaggedFields(invoice *Invoice, fields []byte, net *chaincfg.Params) er
copy(dHash[:], hash[:]) copy(dHash[:], hash[:])
invoice.DescriptionHash = &dHash invoice.DescriptionHash = &dHash
case fieldTypeX: case fieldTypeX:
if invoice.Expiry != nil { if invoice.expiry != nil {
// We skip the field if we have already seen a // We skip the field if we have already seen a
// supported one. // supported one.
continue continue
@ -634,8 +649,8 @@ func parseTaggedFields(invoice *Invoice, fields []byte, net *chaincfg.Params) er
if err != nil { if err != nil {
return err return err
} }
unix := time.Unix(int64(exp), 0) dur := time.Duration(exp) * time.Second
invoice.Expiry = &unix invoice.expiry = &dur
case fieldTypeF: case fieldTypeF:
if invoice.FallbackAddr != nil { if invoice.FallbackAddr != nil {
// We skip the field if we have already seen a // We skip the field if we have already seen a
@ -783,9 +798,9 @@ func writeTaggedFields(bufferBase32 *bytes.Buffer, invoice *Invoice) error {
} }
} }
if invoice.Expiry != nil { if invoice.expiry != nil {
unix := invoice.Expiry.Unix() seconds := invoice.expiry.Seconds()
expiry := uint64ToBase32(uint64(unix)) expiry := uint64ToBase32(uint64(seconds))
err := writeTaggedField(bufferBase32, fieldTypeX, expiry) err := writeTaggedField(bufferBase32, fieldTypeX, expiry)
if err != nil { if err != nil {
return err return err

@ -29,7 +29,7 @@ var (
testMillisat2500uBTC = lnwire.MilliSatoshi(250000000) testMillisat2500uBTC = lnwire.MilliSatoshi(250000000)
testMillisat20mBTC = lnwire.MilliSatoshi(2000000000) testMillisat20mBTC = lnwire.MilliSatoshi(2000000000)
testExpiry60 = time.Unix(60, 0) testExpiry60 = 60 * time.Second
testEmptyString = "" testEmptyString = ""
testCupOfCoffee = "1 cup coffee" testCupOfCoffee = "1 cup coffee"
testPleaseConsider = "Please consider supporting this project" testPleaseConsider = "Please consider supporting this project"
@ -72,7 +72,7 @@ func TestDecodeEncode(t *testing.T) {
tests := []struct { tests := []struct {
encodedInvoice string encodedInvoice string
valid bool valid bool
decodedInvoice *zpay32.Invoice decodedInvoice func() *zpay32.Invoice
skipEncoding bool skipEncoding bool
beforeEncoding func(*zpay32.Invoice) beforeEncoding func(*zpay32.Invoice)
}{ }{
@ -112,51 +112,59 @@ func TestDecodeEncode(t *testing.T) {
// no payment hash set // no payment hash set
encodedInvoice: "lnbc20m1pvjluezhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsjv38luh6p6s2xrv3mzvlmzaya43376h0twal5ax0k6p47498hp3hnaymzhsn424rxqjs0q7apn26yrhaxltq3vzwpqj9nc2r3kzwccsplnq470", encodedInvoice: "lnbc20m1pvjluezhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsjv38luh6p6s2xrv3mzvlmzaya43376h0twal5ax0k6p47498hp3hnaymzhsn424rxqjs0q7apn26yrhaxltq3vzwpqj9nc2r3kzwccsplnq470",
valid: false, valid: false,
decodedInvoice: &zpay32.Invoice{ decodedInvoice: func() *zpay32.Invoice {
Net: &chaincfg.MainNetParams, return &zpay32.Invoice{
MilliSat: &testMillisat20mBTC, Net: &chaincfg.MainNetParams,
Timestamp: time.Unix(1496314658, 0), MilliSat: &testMillisat20mBTC,
DescriptionHash: &testDescriptionHash, Timestamp: time.Unix(1496314658, 0),
Destination: testPubKey, DescriptionHash: &testDescriptionHash,
Destination: testPubKey,
}
}, },
}, },
{ {
// Both Description and DescriptionHash set. // Both Description and DescriptionHash set.
encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs03vghs8y0kuj4ulrzls8ln7fnm9dk7sjsnqmghql6hd6jut36clkqpyuq0s5m6fhureyz0szx2qjc8hkgf4xc2hpw8jpu26jfeyvf4cpga36gt", encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs03vghs8y0kuj4ulrzls8ln7fnm9dk7sjsnqmghql6hd6jut36clkqpyuq0s5m6fhureyz0szx2qjc8hkgf4xc2hpw8jpu26jfeyvf4cpga36gt",
valid: false, valid: false,
decodedInvoice: &zpay32.Invoice{ decodedInvoice: func() *zpay32.Invoice {
Net: &chaincfg.MainNetParams, return &zpay32.Invoice{
MilliSat: &testMillisat20mBTC, Net: &chaincfg.MainNetParams,
Timestamp: time.Unix(1496314658, 0), MilliSat: &testMillisat20mBTC,
PaymentHash: &testPaymentHash, Timestamp: time.Unix(1496314658, 0),
Description: &testPleaseConsider, PaymentHash: &testPaymentHash,
DescriptionHash: &testDescriptionHash, Description: &testPleaseConsider,
Destination: testPubKey, DescriptionHash: &testDescriptionHash,
Destination: testPubKey,
}
}, },
}, },
{ {
// Neither Description nor DescriptionHash set. // Neither Description nor DescriptionHash set.
encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqn2rne0kagfl4e0xag0w6hqeg2dwgc54hrm9m0auw52dhwhwcu559qav309h598pyzn69wh2nqauneyyesnpmaax0g6acr8lh9559jmcquyq5a9", encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqn2rne0kagfl4e0xag0w6hqeg2dwgc54hrm9m0auw52dhwhwcu559qav309h598pyzn69wh2nqauneyyesnpmaax0g6acr8lh9559jmcquyq5a9",
valid: false, valid: false,
decodedInvoice: &zpay32.Invoice{ decodedInvoice: func() *zpay32.Invoice {
Net: &chaincfg.MainNetParams, return &zpay32.Invoice{
MilliSat: &testMillisat20mBTC, Net: &chaincfg.MainNetParams,
Timestamp: time.Unix(1496314658, 0), MilliSat: &testMillisat20mBTC,
PaymentHash: &testPaymentHash, Timestamp: time.Unix(1496314658, 0),
Destination: testPubKey, PaymentHash: &testPaymentHash,
Destination: testPubKey,
}
}, },
}, },
{ {
// Has a few unknown fields, should just be ignored. // Has a few unknown fields, should just be ignored.
encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaqtq2v93xxer9vczq8v93xxeqv72xr42ca60022jqu6fu73n453tmnr0ukc0pl0t23w7eavtensjz0j2wcu7nkxhfdgp9y37welajh5kw34mq7m4xuay0a72cwec8qwgqt5vqht", encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaqtq2v93xxer9vczq8v93xxeqv72xr42ca60022jqu6fu73n453tmnr0ukc0pl0t23w7eavtensjz0j2wcu7nkxhfdgp9y37welajh5kw34mq7m4xuay0a72cwec8qwgqt5vqht",
valid: true, valid: true,
decodedInvoice: &zpay32.Invoice{ decodedInvoice: func() *zpay32.Invoice {
Net: &chaincfg.MainNetParams, return &zpay32.Invoice{
MilliSat: &testMillisat20mBTC, Net: &chaincfg.MainNetParams,
Timestamp: time.Unix(1496314658, 0), MilliSat: &testMillisat20mBTC,
PaymentHash: &testPaymentHash, Timestamp: time.Unix(1496314658, 0),
Description: &testPleaseConsider, PaymentHash: &testPaymentHash,
Destination: testPubKey, Description: &testPleaseConsider,
Destination: testPubKey,
}
}, },
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.
}, },
@ -164,13 +172,15 @@ func TestDecodeEncode(t *testing.T) {
// Ignore unknown witness version in fallback address. // Ignore unknown witness version in fallback address.
encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpppw508d6qejxtdg4y5r3zarvary0c5xw7k8txqv6x0a75xuzp0zsdzk5hq6tmfgweltvs6jk5nhtyd9uqksvr48zga9mw08667w8264gkspluu66jhtcmct36nx363km6cquhhv2cpc6q43r", encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpppw508d6qejxtdg4y5r3zarvary0c5xw7k8txqv6x0a75xuzp0zsdzk5hq6tmfgweltvs6jk5nhtyd9uqksvr48zga9mw08667w8264gkspluu66jhtcmct36nx363km6cquhhv2cpc6q43r",
valid: true, valid: true,
decodedInvoice: &zpay32.Invoice{ decodedInvoice: func() *zpay32.Invoice {
Net: &chaincfg.MainNetParams, return &zpay32.Invoice{
MilliSat: &testMillisat20mBTC, Net: &chaincfg.MainNetParams,
Timestamp: time.Unix(1496314658, 0), MilliSat: &testMillisat20mBTC,
PaymentHash: &testPaymentHash, Timestamp: time.Unix(1496314658, 0),
DescriptionHash: &testDescriptionHash, PaymentHash: &testPaymentHash,
Destination: testPubKey, DescriptionHash: &testDescriptionHash,
Destination: testPubKey,
}
}, },
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.
}, },
@ -178,13 +188,15 @@ func TestDecodeEncode(t *testing.T) {
// Ignore fields with unknown lengths. // Ignore fields with unknown lengths.
encodedInvoice: "lnbc241pveeq09pp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqpp3qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqshp38yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahnp4q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66np3q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfy8huflvs2zwkymx47cszugvzn5v64ahemzzlmm62rpn9l9rm05h35aceq00tkt296289wepws9jh4499wq2l0vk6xcxffd90dpuqchqqztyayq", encodedInvoice: "lnbc241pveeq09pp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqpp3qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqshp38yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahnp4q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66np3q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfy8huflvs2zwkymx47cszugvzn5v64ahemzzlmm62rpn9l9rm05h35aceq00tkt296289wepws9jh4499wq2l0vk6xcxffd90dpuqchqqztyayq",
valid: true, valid: true,
decodedInvoice: &zpay32.Invoice{ decodedInvoice: func() *zpay32.Invoice {
Net: &chaincfg.MainNetParams, return &zpay32.Invoice{
MilliSat: &testMillisat24BTC, Net: &chaincfg.MainNetParams,
Timestamp: time.Unix(1503429093, 0), MilliSat: &testMillisat24BTC,
PaymentHash: &testPaymentHash, Timestamp: time.Unix(1503429093, 0),
Destination: testPubKey, PaymentHash: &testPaymentHash,
DescriptionHash: &testDescriptionHash, Destination: testPubKey,
DescriptionHash: &testDescriptionHash,
}
}, },
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.
}, },
@ -192,12 +204,14 @@ func TestDecodeEncode(t *testing.T) {
// Please make a donation of any amount using rhash 0001020304050607080900010203040506070809000102030405060708090102 to me @03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad // Please make a donation of any amount using rhash 0001020304050607080900010203040506070809000102030405060708090102 to me @03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad
encodedInvoice: "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w", encodedInvoice: "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w",
valid: true, valid: true,
decodedInvoice: &zpay32.Invoice{ decodedInvoice: func() *zpay32.Invoice {
Net: &chaincfg.MainNetParams, return &zpay32.Invoice{
Timestamp: time.Unix(1496314658, 0), Net: &chaincfg.MainNetParams,
PaymentHash: &testPaymentHash, Timestamp: time.Unix(1496314658, 0),
Description: &testPleaseConsider, PaymentHash: &testPaymentHash,
Destination: testPubKey, Description: &testPleaseConsider,
Destination: testPubKey,
}
}, },
beforeEncoding: func(i *zpay32.Invoice) { beforeEncoding: func(i *zpay32.Invoice) {
// Since this destination pubkey was recovered // Since this destination pubkey was recovered
@ -210,27 +224,31 @@ func TestDecodeEncode(t *testing.T) {
// Same as above, pubkey set in 'n' field. // Same as above, pubkey set in 'n' field.
encodedInvoice: "lnbc241pveeq09pp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdqqnp4q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66jd3m5klcwhq68vdsmx2rjgxeay5v0tkt2v5sjaky4eqahe4fx3k9sqavvce3capfuwv8rvjng57jrtfajn5dkpqv8yelsewtljwmmycq62k443", encodedInvoice: "lnbc241pveeq09pp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdqqnp4q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66jd3m5klcwhq68vdsmx2rjgxeay5v0tkt2v5sjaky4eqahe4fx3k9sqavvce3capfuwv8rvjng57jrtfajn5dkpqv8yelsewtljwmmycq62k443",
valid: true, valid: true,
decodedInvoice: &zpay32.Invoice{ decodedInvoice: func() *zpay32.Invoice {
Net: &chaincfg.MainNetParams, return &zpay32.Invoice{
MilliSat: &testMillisat24BTC, Net: &chaincfg.MainNetParams,
Timestamp: time.Unix(1503429093, 0), MilliSat: &testMillisat24BTC,
PaymentHash: &testPaymentHash, Timestamp: time.Unix(1503429093, 0),
Destination: testPubKey, PaymentHash: &testPaymentHash,
Description: &testEmptyString, Destination: testPubKey,
Description: &testEmptyString,
}
}, },
}, },
{ {
// Please send $3 for a cup of coffee to the same peer, within 1 minute // Please send $3 for a cup of coffee to the same peer, within 1 minute
encodedInvoice: "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaztrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspfj9srp", encodedInvoice: "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaztrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspfj9srp",
valid: true, valid: true,
decodedInvoice: &zpay32.Invoice{ decodedInvoice: func() *zpay32.Invoice {
Net: &chaincfg.MainNetParams, i, _ := zpay32.NewInvoice(
MilliSat: &testMillisat2500uBTC, &chaincfg.MainNetParams,
Timestamp: time.Unix(1496314658, 0), testPaymentHash,
PaymentHash: &testPaymentHash, time.Unix(1496314658, 0),
Description: &testCupOfCoffee, zpay32.Amount(testMillisat2500uBTC),
Destination: testPubKey, zpay32.Description(testCupOfCoffee),
Expiry: &testExpiry60, zpay32.Destination(testPubKey),
zpay32.Expiry(testExpiry60))
return i
}, },
beforeEncoding: func(i *zpay32.Invoice) { beforeEncoding: func(i *zpay32.Invoice) {
// Since this destination pubkey was recovered // Since this destination pubkey was recovered
@ -243,13 +261,15 @@ func TestDecodeEncode(t *testing.T) {
// Now send $24 for an entire list of things (hashed) // Now send $24 for an entire list of things (hashed)
encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqscc6gd6ql3jrc5yzme8v4ntcewwz5cnw92tz0pc8qcuufvq7khhr8wpald05e92xw006sq94mg8v2ndf4sefvf9sygkshp5zfem29trqq2yxxz7", encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqscc6gd6ql3jrc5yzme8v4ntcewwz5cnw92tz0pc8qcuufvq7khhr8wpald05e92xw006sq94mg8v2ndf4sefvf9sygkshp5zfem29trqq2yxxz7",
valid: true, valid: true,
decodedInvoice: &zpay32.Invoice{ decodedInvoice: func() *zpay32.Invoice {
Net: &chaincfg.MainNetParams, return &zpay32.Invoice{
MilliSat: &testMillisat20mBTC, Net: &chaincfg.MainNetParams,
Timestamp: time.Unix(1496314658, 0), MilliSat: &testMillisat20mBTC,
PaymentHash: &testPaymentHash, Timestamp: time.Unix(1496314658, 0),
DescriptionHash: &testDescriptionHash, PaymentHash: &testPaymentHash,
Destination: testPubKey, DescriptionHash: &testDescriptionHash,
Destination: testPubKey,
}
}, },
beforeEncoding: func(i *zpay32.Invoice) { beforeEncoding: func(i *zpay32.Invoice) {
// Since this destination pubkey was recovered // Since this destination pubkey was recovered
@ -262,14 +282,16 @@ func TestDecodeEncode(t *testing.T) {
// The same, on testnet, with a fallback address mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP // The same, on testnet, with a fallback address mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP
encodedInvoice: "lntb20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3x9et2e20v6pu37c5d9vax37wxq72un98k6vcx9fz94w0qf237cm2rqv9pmn5lnexfvf5579slr4zq3u8kmczecytdx0xg9rwzngp7e6guwqpqlhssu04sucpnz4axcv2dstmknqq6jsk2l", encodedInvoice: "lntb20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3x9et2e20v6pu37c5d9vax37wxq72un98k6vcx9fz94w0qf237cm2rqv9pmn5lnexfvf5579slr4zq3u8kmczecytdx0xg9rwzngp7e6guwqpqlhssu04sucpnz4axcv2dstmknqq6jsk2l",
valid: true, valid: true,
decodedInvoice: &zpay32.Invoice{ decodedInvoice: func() *zpay32.Invoice {
Net: &chaincfg.TestNet3Params, return &zpay32.Invoice{
MilliSat: &testMillisat20mBTC, Net: &chaincfg.TestNet3Params,
Timestamp: time.Unix(1496314658, 0), MilliSat: &testMillisat20mBTC,
PaymentHash: &testPaymentHash, Timestamp: time.Unix(1496314658, 0),
DescriptionHash: &testDescriptionHash, PaymentHash: &testPaymentHash,
Destination: testPubKey, DescriptionHash: &testDescriptionHash,
FallbackAddr: testAddrTestnet, Destination: testPubKey,
FallbackAddr: testAddrTestnet,
}
}, },
beforeEncoding: func(i *zpay32.Invoice) { beforeEncoding: func(i *zpay32.Invoice) {
// Since this destination pubkey was recovered // Since this destination pubkey was recovered
@ -282,22 +304,24 @@ func TestDecodeEncode(t *testing.T) {
// On mainnet, with fallback address 1RustyRX2oai4EYYDpQGWvEL62BBGqN9T with extra routing info to get to node 029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255 // On mainnet, with fallback address 1RustyRX2oai4EYYDpQGWvEL62BBGqN9T with extra routing info to get to node 029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255
encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85frzjq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqqqqqqq9qqqvncsk57n4v9ehw86wq8fzvjejhv9z3w3q5zh6qkql005x9xl240ch23jk79ujzvr4hsmmafyxghpqe79psktnjl668ntaf4ne7ucs5csqh5mnnk", encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85frzjq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqqqqqqq9qqqvncsk57n4v9ehw86wq8fzvjejhv9z3w3q5zh6qkql005x9xl240ch23jk79ujzvr4hsmmafyxghpqe79psktnjl668ntaf4ne7ucs5csqh5mnnk",
valid: true, valid: true,
decodedInvoice: &zpay32.Invoice{ decodedInvoice: func() *zpay32.Invoice {
Net: &chaincfg.MainNetParams, return &zpay32.Invoice{
MilliSat: &testMillisat20mBTC, Net: &chaincfg.MainNetParams,
Timestamp: time.Unix(1496314658, 0), MilliSat: &testMillisat20mBTC,
PaymentHash: &testPaymentHash, Timestamp: time.Unix(1496314658, 0),
DescriptionHash: &testDescriptionHash, PaymentHash: &testPaymentHash,
Destination: testPubKey, DescriptionHash: &testDescriptionHash,
FallbackAddr: testRustyAddr, Destination: testPubKey,
RoutingInfo: []zpay32.ExtraRoutingInfo{ FallbackAddr: testRustyAddr,
{ RoutingInfo: []zpay32.ExtraRoutingInfo{
PubKey: testRoutingInfoPubkey, {
ShortChanID: 0x0102030405060708, PubKey: testRoutingInfoPubkey,
Fee: 20, ShortChanID: 0x0102030405060708,
CltvExpDelta: 3, Fee: 20,
CltvExpDelta: 3,
},
}, },
}, }
}, },
beforeEncoding: func(i *zpay32.Invoice) { beforeEncoding: func(i *zpay32.Invoice) {
// Since this destination pubkey was recovered // Since this destination pubkey was recovered
@ -310,28 +334,30 @@ func TestDecodeEncode(t *testing.T) {
// On mainnet, with fallback address 1RustyRX2oai4EYYDpQGWvEL62BBGqN9T with extra routing info to go via nodes 029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255 then 039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255 // On mainnet, with fallback address 1RustyRX2oai4EYYDpQGWvEL62BBGqN9T with extra routing info to go via nodes 029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255 then 039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255
encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqqqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqqqqqqq7qqzqfnlkwydm8rg30gjku7wmxmk06sevjp53fmvrcfegvwy7d5443jvyhxsel0hulkstws7vqv400q4j3wgpk4crg49682hr4scqvmad43cqd5m7tf", encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqqqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqqqqqqq7qqzqfnlkwydm8rg30gjku7wmxmk06sevjp53fmvrcfegvwy7d5443jvyhxsel0hulkstws7vqv400q4j3wgpk4crg49682hr4scqvmad43cqd5m7tf",
valid: true, valid: true,
decodedInvoice: &zpay32.Invoice{ decodedInvoice: func() *zpay32.Invoice {
Net: &chaincfg.MainNetParams, return &zpay32.Invoice{
MilliSat: &testMillisat20mBTC, Net: &chaincfg.MainNetParams,
Timestamp: time.Unix(1496314658, 0), MilliSat: &testMillisat20mBTC,
PaymentHash: &testPaymentHash, Timestamp: time.Unix(1496314658, 0),
DescriptionHash: &testDescriptionHash, PaymentHash: &testPaymentHash,
Destination: testPubKey, DescriptionHash: &testDescriptionHash,
FallbackAddr: testRustyAddr, Destination: testPubKey,
RoutingInfo: []zpay32.ExtraRoutingInfo{ FallbackAddr: testRustyAddr,
{ RoutingInfo: []zpay32.ExtraRoutingInfo{
PubKey: testRoutingInfoPubkey, {
ShortChanID: 0x0102030405060708, PubKey: testRoutingInfoPubkey,
Fee: 20, ShortChanID: 0x0102030405060708,
CltvExpDelta: 3, Fee: 20,
CltvExpDelta: 3,
},
{
PubKey: testRoutingInfoPubkey2,
ShortChanID: 0x030405060708090a,
Fee: 30,
CltvExpDelta: 4,
},
}, },
{ }
PubKey: testRoutingInfoPubkey2,
ShortChanID: 0x030405060708090a,
Fee: 30,
CltvExpDelta: 4,
},
},
}, },
beforeEncoding: func(i *zpay32.Invoice) { beforeEncoding: func(i *zpay32.Invoice) {
// Since this destination pubkey was recovered // Since this destination pubkey was recovered
@ -344,14 +370,16 @@ func TestDecodeEncode(t *testing.T) {
// On mainnet, with fallback (p2sh) address 3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX // On mainnet, with fallback (p2sh) address 3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX
encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfppj3a24vwu6r8ejrss3axul8rxldph2q7z9kk822r8plup77n9yq5ep2dfpcydrjwzxs0la84v3tfw43t3vqhek7f05m6uf8lmfkjn7zv7enn76sq65d8u9lxav2pl6x3xnc2ww3lqpagnh0u", encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfppj3a24vwu6r8ejrss3axul8rxldph2q7z9kk822r8plup77n9yq5ep2dfpcydrjwzxs0la84v3tfw43t3vqhek7f05m6uf8lmfkjn7zv7enn76sq65d8u9lxav2pl6x3xnc2ww3lqpagnh0u",
valid: true, valid: true,
decodedInvoice: &zpay32.Invoice{ decodedInvoice: func() *zpay32.Invoice {
Net: &chaincfg.MainNetParams, return &zpay32.Invoice{
MilliSat: &testMillisat20mBTC, Net: &chaincfg.MainNetParams,
Timestamp: time.Unix(1496314658, 0), MilliSat: &testMillisat20mBTC,
PaymentHash: &testPaymentHash, Timestamp: time.Unix(1496314658, 0),
DescriptionHash: &testDescriptionHash, PaymentHash: &testPaymentHash,
Destination: testPubKey, DescriptionHash: &testDescriptionHash,
FallbackAddr: testAddrMainnetP2SH, Destination: testPubKey,
FallbackAddr: testAddrMainnetP2SH,
}
}, },
beforeEncoding: func(i *zpay32.Invoice) { beforeEncoding: func(i *zpay32.Invoice) {
// Since this destination pubkey was recovered // Since this destination pubkey was recovered
@ -364,14 +392,16 @@ func TestDecodeEncode(t *testing.T) {
// On mainnet, with fallback (p2wpkh) address bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 // On mainnet, with fallback (p2wpkh) address bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4
encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfppqw508d6qejxtdg4y5r3zarvary0c5xw7kknt6zz5vxa8yh8jrnlkl63dah48yh6eupakk87fjdcnwqfcyt7snnpuz7vp83txauq4c60sys3xyucesxjf46yqnpplj0saq36a554cp9wt865", encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfppqw508d6qejxtdg4y5r3zarvary0c5xw7kknt6zz5vxa8yh8jrnlkl63dah48yh6eupakk87fjdcnwqfcyt7snnpuz7vp83txauq4c60sys3xyucesxjf46yqnpplj0saq36a554cp9wt865",
valid: true, valid: true,
decodedInvoice: &zpay32.Invoice{ decodedInvoice: func() *zpay32.Invoice {
Net: &chaincfg.MainNetParams, return &zpay32.Invoice{
MilliSat: &testMillisat20mBTC, Net: &chaincfg.MainNetParams,
Timestamp: time.Unix(1496314658, 0), MilliSat: &testMillisat20mBTC,
PaymentHash: &testPaymentHash, Timestamp: time.Unix(1496314658, 0),
DescriptionHash: &testDescriptionHash, PaymentHash: &testPaymentHash,
Destination: testPubKey, DescriptionHash: &testDescriptionHash,
FallbackAddr: testAddrMainnetP2WPKH, Destination: testPubKey,
FallbackAddr: testAddrMainnetP2WPKH,
}
}, },
beforeEncoding: func(i *zpay32.Invoice) { beforeEncoding: func(i *zpay32.Invoice) {
// Since this destination pubkey was recovered // Since this destination pubkey was recovered
@ -384,14 +414,16 @@ func TestDecodeEncode(t *testing.T) {
// On mainnet, with fallback (p2wsh) address bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3 // On mainnet, with fallback (p2wsh) address bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3
encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfp4qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qvnjha2auylmwrltv2pkp2t22uy8ura2xsdwhq5nm7s574xva47djmnj2xeycsu7u5v8929mvuux43j0cqhhf32wfyn2th0sv4t9x55sppz5we8", encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfp4qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qvnjha2auylmwrltv2pkp2t22uy8ura2xsdwhq5nm7s574xva47djmnj2xeycsu7u5v8929mvuux43j0cqhhf32wfyn2th0sv4t9x55sppz5we8",
valid: true, valid: true,
decodedInvoice: &zpay32.Invoice{ decodedInvoice: func() *zpay32.Invoice {
Net: &chaincfg.MainNetParams, return &zpay32.Invoice{
MilliSat: &testMillisat20mBTC, Net: &chaincfg.MainNetParams,
Timestamp: time.Unix(1496314658, 0), MilliSat: &testMillisat20mBTC,
PaymentHash: &testPaymentHash, Timestamp: time.Unix(1496314658, 0),
DescriptionHash: &testDescriptionHash, PaymentHash: &testPaymentHash,
Destination: testPubKey, DescriptionHash: &testDescriptionHash,
FallbackAddr: testAddrMainnetP2WSH, Destination: testPubKey,
FallbackAddr: testAddrMainnetP2WSH,
}
}, },
beforeEncoding: func(i *zpay32.Invoice) { beforeEncoding: func(i *zpay32.Invoice) {
// Since this destination pubkey was recovered // Since this destination pubkey was recovered
@ -410,7 +442,7 @@ func TestDecodeEncode(t *testing.T) {
} }
if test.valid { if test.valid {
if err := compareInvoices(test.decodedInvoice, invoice); err != nil { if err := compareInvoices(test.decodedInvoice(), invoice); err != nil {
t.Errorf("Invoice decoding result %d not as expected: %v", i, err) t.Errorf("Invoice decoding result %d not as expected: %v", i, err)
return return
} }
@ -420,12 +452,17 @@ func TestDecodeEncode(t *testing.T) {
continue continue
} }
if test.beforeEncoding != nil { var decodedInvoice *zpay32.Invoice
test.beforeEncoding(test.decodedInvoice) if test.decodedInvoice != nil {
decodedInvoice = test.decodedInvoice()
} }
if test.decodedInvoice != nil { if test.beforeEncoding != nil {
reencoded, err := test.decodedInvoice.Encode( test.beforeEncoding(decodedInvoice)
}
if decodedInvoice != nil {
reencoded, err := decodedInvoice.Encode(
testMessageSigner, testMessageSigner,
) )
if (err == nil) != test.valid { if (err == nil) != test.valid {
@ -560,9 +597,9 @@ func compareInvoices(expected, actual *zpay32.Invoice) error {
*expected.DescriptionHash, *actual.DescriptionHash) *expected.DescriptionHash, *actual.DescriptionHash)
} }
if !reflect.DeepEqual(expected.Expiry, actual.Expiry) { if expected.Expiry() != actual.Expiry() {
return fmt.Errorf("expected expiry %d, got %d", return fmt.Errorf("expected expiry %d, got %d",
expected.Expiry, actual.Expiry) expected.Expiry(), actual.Expiry())
} }
if !reflect.DeepEqual(expected.FallbackAddr, actual.FallbackAddr) { if !reflect.DeepEqual(expected.FallbackAddr, actual.FallbackAddr) {