diff --git a/zpay32/invoice.go b/zpay32/invoice.go index 5dd6cb32d..9097197df 100644 --- a/zpay32/invoice.go +++ b/zpay32/invoice.go @@ -109,9 +109,13 @@ type Invoice struct { // Optional. Non-nil iff Description is nil. 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. - 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 // 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 of the created Invoice. If not set, a default expiry of 60 min will // be implied. -func Expiry(expiry time.Time) func(*Invoice) { +func Expiry(expiry time.Duration) func(*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 } +// 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 // has all the necessary fields set for it to be considered valid by BOLT-0011. func validateInvoice(invoice *Invoice) error { @@ -624,7 +639,7 @@ func parseTaggedFields(invoice *Invoice, fields []byte, net *chaincfg.Params) er copy(dHash[:], hash[:]) invoice.DescriptionHash = &dHash case fieldTypeX: - if invoice.Expiry != nil { + if invoice.expiry != nil { // We skip the field if we have already seen a // supported one. continue @@ -634,8 +649,8 @@ func parseTaggedFields(invoice *Invoice, fields []byte, net *chaincfg.Params) er if err != nil { return err } - unix := time.Unix(int64(exp), 0) - invoice.Expiry = &unix + dur := time.Duration(exp) * time.Second + invoice.expiry = &dur case fieldTypeF: if invoice.FallbackAddr != nil { // 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 { - unix := invoice.Expiry.Unix() - expiry := uint64ToBase32(uint64(unix)) + if invoice.expiry != nil { + seconds := invoice.expiry.Seconds() + expiry := uint64ToBase32(uint64(seconds)) err := writeTaggedField(bufferBase32, fieldTypeX, expiry) if err != nil { return err diff --git a/zpay32/invoice_test.go b/zpay32/invoice_test.go index 4da7e25c5..520927bf5 100644 --- a/zpay32/invoice_test.go +++ b/zpay32/invoice_test.go @@ -29,7 +29,7 @@ var ( testMillisat2500uBTC = lnwire.MilliSatoshi(250000000) testMillisat20mBTC = lnwire.MilliSatoshi(2000000000) - testExpiry60 = time.Unix(60, 0) + testExpiry60 = 60 * time.Second testEmptyString = "" testCupOfCoffee = "1 cup coffee" testPleaseConsider = "Please consider supporting this project" @@ -72,7 +72,7 @@ func TestDecodeEncode(t *testing.T) { tests := []struct { encodedInvoice string valid bool - decodedInvoice *zpay32.Invoice + decodedInvoice func() *zpay32.Invoice skipEncoding bool beforeEncoding func(*zpay32.Invoice) }{ @@ -112,51 +112,59 @@ func TestDecodeEncode(t *testing.T) { // no payment hash set encodedInvoice: "lnbc20m1pvjluezhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsjv38luh6p6s2xrv3mzvlmzaya43376h0twal5ax0k6p47498hp3hnaymzhsn424rxqjs0q7apn26yrhaxltq3vzwpqj9nc2r3kzwccsplnq470", valid: false, - decodedInvoice: &zpay32.Invoice{ - Net: &chaincfg.MainNetParams, - MilliSat: &testMillisat20mBTC, - Timestamp: time.Unix(1496314658, 0), - DescriptionHash: &testDescriptionHash, - Destination: testPubKey, + decodedInvoice: func() *zpay32.Invoice { + return &zpay32.Invoice{ + Net: &chaincfg.MainNetParams, + MilliSat: &testMillisat20mBTC, + Timestamp: time.Unix(1496314658, 0), + DescriptionHash: &testDescriptionHash, + Destination: testPubKey, + } }, }, { // Both Description and DescriptionHash set. encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs03vghs8y0kuj4ulrzls8ln7fnm9dk7sjsnqmghql6hd6jut36clkqpyuq0s5m6fhureyz0szx2qjc8hkgf4xc2hpw8jpu26jfeyvf4cpga36gt", valid: false, - decodedInvoice: &zpay32.Invoice{ - Net: &chaincfg.MainNetParams, - MilliSat: &testMillisat20mBTC, - Timestamp: time.Unix(1496314658, 0), - PaymentHash: &testPaymentHash, - Description: &testPleaseConsider, - DescriptionHash: &testDescriptionHash, - Destination: testPubKey, + decodedInvoice: func() *zpay32.Invoice { + return &zpay32.Invoice{ + Net: &chaincfg.MainNetParams, + MilliSat: &testMillisat20mBTC, + Timestamp: time.Unix(1496314658, 0), + PaymentHash: &testPaymentHash, + Description: &testPleaseConsider, + DescriptionHash: &testDescriptionHash, + Destination: testPubKey, + } }, }, { // Neither Description nor DescriptionHash set. encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqn2rne0kagfl4e0xag0w6hqeg2dwgc54hrm9m0auw52dhwhwcu559qav309h598pyzn69wh2nqauneyyesnpmaax0g6acr8lh9559jmcquyq5a9", valid: false, - decodedInvoice: &zpay32.Invoice{ - Net: &chaincfg.MainNetParams, - MilliSat: &testMillisat20mBTC, - Timestamp: time.Unix(1496314658, 0), - PaymentHash: &testPaymentHash, - Destination: testPubKey, + decodedInvoice: func() *zpay32.Invoice { + return &zpay32.Invoice{ + Net: &chaincfg.MainNetParams, + MilliSat: &testMillisat20mBTC, + Timestamp: time.Unix(1496314658, 0), + PaymentHash: &testPaymentHash, + Destination: testPubKey, + } }, }, { // Has a few unknown fields, should just be ignored. encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaqtq2v93xxer9vczq8v93xxeqv72xr42ca60022jqu6fu73n453tmnr0ukc0pl0t23w7eavtensjz0j2wcu7nkxhfdgp9y37welajh5kw34mq7m4xuay0a72cwec8qwgqt5vqht", valid: true, - decodedInvoice: &zpay32.Invoice{ - Net: &chaincfg.MainNetParams, - MilliSat: &testMillisat20mBTC, - Timestamp: time.Unix(1496314658, 0), - PaymentHash: &testPaymentHash, - Description: &testPleaseConsider, - Destination: testPubKey, + decodedInvoice: func() *zpay32.Invoice { + return &zpay32.Invoice{ + Net: &chaincfg.MainNetParams, + MilliSat: &testMillisat20mBTC, + Timestamp: time.Unix(1496314658, 0), + PaymentHash: &testPaymentHash, + Description: &testPleaseConsider, + Destination: testPubKey, + } }, 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. encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpppw508d6qejxtdg4y5r3zarvary0c5xw7k8txqv6x0a75xuzp0zsdzk5hq6tmfgweltvs6jk5nhtyd9uqksvr48zga9mw08667w8264gkspluu66jhtcmct36nx363km6cquhhv2cpc6q43r", valid: true, - decodedInvoice: &zpay32.Invoice{ - Net: &chaincfg.MainNetParams, - MilliSat: &testMillisat20mBTC, - Timestamp: time.Unix(1496314658, 0), - PaymentHash: &testPaymentHash, - DescriptionHash: &testDescriptionHash, - Destination: testPubKey, + decodedInvoice: func() *zpay32.Invoice { + return &zpay32.Invoice{ + Net: &chaincfg.MainNetParams, + MilliSat: &testMillisat20mBTC, + Timestamp: time.Unix(1496314658, 0), + PaymentHash: &testPaymentHash, + DescriptionHash: &testDescriptionHash, + Destination: testPubKey, + } }, 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. encodedInvoice: "lnbc241pveeq09pp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqpp3qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqshp38yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahnp4q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66np3q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfy8huflvs2zwkymx47cszugvzn5v64ahemzzlmm62rpn9l9rm05h35aceq00tkt296289wepws9jh4499wq2l0vk6xcxffd90dpuqchqqztyayq", valid: true, - decodedInvoice: &zpay32.Invoice{ - Net: &chaincfg.MainNetParams, - MilliSat: &testMillisat24BTC, - Timestamp: time.Unix(1503429093, 0), - PaymentHash: &testPaymentHash, - Destination: testPubKey, - DescriptionHash: &testDescriptionHash, + decodedInvoice: func() *zpay32.Invoice { + return &zpay32.Invoice{ + Net: &chaincfg.MainNetParams, + MilliSat: &testMillisat24BTC, + Timestamp: time.Unix(1503429093, 0), + PaymentHash: &testPaymentHash, + Destination: testPubKey, + DescriptionHash: &testDescriptionHash, + } }, 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 encodedInvoice: "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w", valid: true, - decodedInvoice: &zpay32.Invoice{ - Net: &chaincfg.MainNetParams, - Timestamp: time.Unix(1496314658, 0), - PaymentHash: &testPaymentHash, - Description: &testPleaseConsider, - Destination: testPubKey, + decodedInvoice: func() *zpay32.Invoice { + return &zpay32.Invoice{ + Net: &chaincfg.MainNetParams, + Timestamp: time.Unix(1496314658, 0), + PaymentHash: &testPaymentHash, + Description: &testPleaseConsider, + Destination: testPubKey, + } }, beforeEncoding: func(i *zpay32.Invoice) { // Since this destination pubkey was recovered @@ -210,27 +224,31 @@ func TestDecodeEncode(t *testing.T) { // Same as above, pubkey set in 'n' field. encodedInvoice: "lnbc241pveeq09pp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdqqnp4q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66jd3m5klcwhq68vdsmx2rjgxeay5v0tkt2v5sjaky4eqahe4fx3k9sqavvce3capfuwv8rvjng57jrtfajn5dkpqv8yelsewtljwmmycq62k443", valid: true, - decodedInvoice: &zpay32.Invoice{ - Net: &chaincfg.MainNetParams, - MilliSat: &testMillisat24BTC, - Timestamp: time.Unix(1503429093, 0), - PaymentHash: &testPaymentHash, - Destination: testPubKey, - Description: &testEmptyString, + decodedInvoice: func() *zpay32.Invoice { + return &zpay32.Invoice{ + Net: &chaincfg.MainNetParams, + MilliSat: &testMillisat24BTC, + Timestamp: time.Unix(1503429093, 0), + PaymentHash: &testPaymentHash, + Destination: testPubKey, + Description: &testEmptyString, + } }, }, { // Please send $3 for a cup of coffee to the same peer, within 1 minute encodedInvoice: "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaztrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspfj9srp", valid: true, - decodedInvoice: &zpay32.Invoice{ - Net: &chaincfg.MainNetParams, - MilliSat: &testMillisat2500uBTC, - Timestamp: time.Unix(1496314658, 0), - PaymentHash: &testPaymentHash, - Description: &testCupOfCoffee, - Destination: testPubKey, - Expiry: &testExpiry60, + decodedInvoice: func() *zpay32.Invoice { + i, _ := zpay32.NewInvoice( + &chaincfg.MainNetParams, + testPaymentHash, + time.Unix(1496314658, 0), + zpay32.Amount(testMillisat2500uBTC), + zpay32.Description(testCupOfCoffee), + zpay32.Destination(testPubKey), + zpay32.Expiry(testExpiry60)) + return i }, beforeEncoding: func(i *zpay32.Invoice) { // 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) encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqscc6gd6ql3jrc5yzme8v4ntcewwz5cnw92tz0pc8qcuufvq7khhr8wpald05e92xw006sq94mg8v2ndf4sefvf9sygkshp5zfem29trqq2yxxz7", valid: true, - decodedInvoice: &zpay32.Invoice{ - Net: &chaincfg.MainNetParams, - MilliSat: &testMillisat20mBTC, - Timestamp: time.Unix(1496314658, 0), - PaymentHash: &testPaymentHash, - DescriptionHash: &testDescriptionHash, - Destination: testPubKey, + decodedInvoice: func() *zpay32.Invoice { + return &zpay32.Invoice{ + Net: &chaincfg.MainNetParams, + MilliSat: &testMillisat20mBTC, + Timestamp: time.Unix(1496314658, 0), + PaymentHash: &testPaymentHash, + DescriptionHash: &testDescriptionHash, + Destination: testPubKey, + } }, beforeEncoding: func(i *zpay32.Invoice) { // Since this destination pubkey was recovered @@ -262,14 +282,16 @@ func TestDecodeEncode(t *testing.T) { // The same, on testnet, with a fallback address mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP encodedInvoice: "lntb20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3x9et2e20v6pu37c5d9vax37wxq72un98k6vcx9fz94w0qf237cm2rqv9pmn5lnexfvf5579slr4zq3u8kmczecytdx0xg9rwzngp7e6guwqpqlhssu04sucpnz4axcv2dstmknqq6jsk2l", valid: true, - decodedInvoice: &zpay32.Invoice{ - Net: &chaincfg.TestNet3Params, - MilliSat: &testMillisat20mBTC, - Timestamp: time.Unix(1496314658, 0), - PaymentHash: &testPaymentHash, - DescriptionHash: &testDescriptionHash, - Destination: testPubKey, - FallbackAddr: testAddrTestnet, + decodedInvoice: func() *zpay32.Invoice { + return &zpay32.Invoice{ + Net: &chaincfg.TestNet3Params, + MilliSat: &testMillisat20mBTC, + Timestamp: time.Unix(1496314658, 0), + PaymentHash: &testPaymentHash, + DescriptionHash: &testDescriptionHash, + Destination: testPubKey, + FallbackAddr: testAddrTestnet, + } }, beforeEncoding: func(i *zpay32.Invoice) { // 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 encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85frzjq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqqqqqqq9qqqvncsk57n4v9ehw86wq8fzvjejhv9z3w3q5zh6qkql005x9xl240ch23jk79ujzvr4hsmmafyxghpqe79psktnjl668ntaf4ne7ucs5csqh5mnnk", valid: true, - decodedInvoice: &zpay32.Invoice{ - Net: &chaincfg.MainNetParams, - MilliSat: &testMillisat20mBTC, - Timestamp: time.Unix(1496314658, 0), - PaymentHash: &testPaymentHash, - DescriptionHash: &testDescriptionHash, - Destination: testPubKey, - FallbackAddr: testRustyAddr, - RoutingInfo: []zpay32.ExtraRoutingInfo{ - { - PubKey: testRoutingInfoPubkey, - ShortChanID: 0x0102030405060708, - Fee: 20, - CltvExpDelta: 3, + decodedInvoice: func() *zpay32.Invoice { + return &zpay32.Invoice{ + Net: &chaincfg.MainNetParams, + MilliSat: &testMillisat20mBTC, + Timestamp: time.Unix(1496314658, 0), + PaymentHash: &testPaymentHash, + DescriptionHash: &testDescriptionHash, + Destination: testPubKey, + FallbackAddr: testRustyAddr, + RoutingInfo: []zpay32.ExtraRoutingInfo{ + { + PubKey: testRoutingInfoPubkey, + ShortChanID: 0x0102030405060708, + Fee: 20, + CltvExpDelta: 3, + }, }, - }, + } }, beforeEncoding: func(i *zpay32.Invoice) { // 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 encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqqqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqqqqqqq7qqzqfnlkwydm8rg30gjku7wmxmk06sevjp53fmvrcfegvwy7d5443jvyhxsel0hulkstws7vqv400q4j3wgpk4crg49682hr4scqvmad43cqd5m7tf", valid: true, - decodedInvoice: &zpay32.Invoice{ - Net: &chaincfg.MainNetParams, - MilliSat: &testMillisat20mBTC, - Timestamp: time.Unix(1496314658, 0), - PaymentHash: &testPaymentHash, - DescriptionHash: &testDescriptionHash, - Destination: testPubKey, - FallbackAddr: testRustyAddr, - RoutingInfo: []zpay32.ExtraRoutingInfo{ - { - PubKey: testRoutingInfoPubkey, - ShortChanID: 0x0102030405060708, - Fee: 20, - CltvExpDelta: 3, + decodedInvoice: func() *zpay32.Invoice { + return &zpay32.Invoice{ + Net: &chaincfg.MainNetParams, + MilliSat: &testMillisat20mBTC, + Timestamp: time.Unix(1496314658, 0), + PaymentHash: &testPaymentHash, + DescriptionHash: &testDescriptionHash, + Destination: testPubKey, + FallbackAddr: testRustyAddr, + RoutingInfo: []zpay32.ExtraRoutingInfo{ + { + PubKey: testRoutingInfoPubkey, + ShortChanID: 0x0102030405060708, + 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) { // Since this destination pubkey was recovered @@ -344,14 +370,16 @@ func TestDecodeEncode(t *testing.T) { // On mainnet, with fallback (p2sh) address 3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfppj3a24vwu6r8ejrss3axul8rxldph2q7z9kk822r8plup77n9yq5ep2dfpcydrjwzxs0la84v3tfw43t3vqhek7f05m6uf8lmfkjn7zv7enn76sq65d8u9lxav2pl6x3xnc2ww3lqpagnh0u", valid: true, - decodedInvoice: &zpay32.Invoice{ - Net: &chaincfg.MainNetParams, - MilliSat: &testMillisat20mBTC, - Timestamp: time.Unix(1496314658, 0), - PaymentHash: &testPaymentHash, - DescriptionHash: &testDescriptionHash, - Destination: testPubKey, - FallbackAddr: testAddrMainnetP2SH, + decodedInvoice: func() *zpay32.Invoice { + return &zpay32.Invoice{ + Net: &chaincfg.MainNetParams, + MilliSat: &testMillisat20mBTC, + Timestamp: time.Unix(1496314658, 0), + PaymentHash: &testPaymentHash, + DescriptionHash: &testDescriptionHash, + Destination: testPubKey, + FallbackAddr: testAddrMainnetP2SH, + } }, beforeEncoding: func(i *zpay32.Invoice) { // Since this destination pubkey was recovered @@ -364,14 +392,16 @@ func TestDecodeEncode(t *testing.T) { // On mainnet, with fallback (p2wpkh) address bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfppqw508d6qejxtdg4y5r3zarvary0c5xw7kknt6zz5vxa8yh8jrnlkl63dah48yh6eupakk87fjdcnwqfcyt7snnpuz7vp83txauq4c60sys3xyucesxjf46yqnpplj0saq36a554cp9wt865", valid: true, - decodedInvoice: &zpay32.Invoice{ - Net: &chaincfg.MainNetParams, - MilliSat: &testMillisat20mBTC, - Timestamp: time.Unix(1496314658, 0), - PaymentHash: &testPaymentHash, - DescriptionHash: &testDescriptionHash, - Destination: testPubKey, - FallbackAddr: testAddrMainnetP2WPKH, + decodedInvoice: func() *zpay32.Invoice { + return &zpay32.Invoice{ + Net: &chaincfg.MainNetParams, + MilliSat: &testMillisat20mBTC, + Timestamp: time.Unix(1496314658, 0), + PaymentHash: &testPaymentHash, + DescriptionHash: &testDescriptionHash, + Destination: testPubKey, + FallbackAddr: testAddrMainnetP2WPKH, + } }, beforeEncoding: func(i *zpay32.Invoice) { // Since this destination pubkey was recovered @@ -384,14 +414,16 @@ func TestDecodeEncode(t *testing.T) { // On mainnet, with fallback (p2wsh) address bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3 encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfp4qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qvnjha2auylmwrltv2pkp2t22uy8ura2xsdwhq5nm7s574xva47djmnj2xeycsu7u5v8929mvuux43j0cqhhf32wfyn2th0sv4t9x55sppz5we8", valid: true, - decodedInvoice: &zpay32.Invoice{ - Net: &chaincfg.MainNetParams, - MilliSat: &testMillisat20mBTC, - Timestamp: time.Unix(1496314658, 0), - PaymentHash: &testPaymentHash, - DescriptionHash: &testDescriptionHash, - Destination: testPubKey, - FallbackAddr: testAddrMainnetP2WSH, + decodedInvoice: func() *zpay32.Invoice { + return &zpay32.Invoice{ + Net: &chaincfg.MainNetParams, + MilliSat: &testMillisat20mBTC, + Timestamp: time.Unix(1496314658, 0), + PaymentHash: &testPaymentHash, + DescriptionHash: &testDescriptionHash, + Destination: testPubKey, + FallbackAddr: testAddrMainnetP2WSH, + } }, beforeEncoding: func(i *zpay32.Invoice) { // Since this destination pubkey was recovered @@ -410,7 +442,7 @@ func TestDecodeEncode(t *testing.T) { } 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) return } @@ -420,12 +452,17 @@ func TestDecodeEncode(t *testing.T) { continue } - if test.beforeEncoding != nil { - test.beforeEncoding(test.decodedInvoice) + var decodedInvoice *zpay32.Invoice + if test.decodedInvoice != nil { + decodedInvoice = test.decodedInvoice() } - if test.decodedInvoice != nil { - reencoded, err := test.decodedInvoice.Encode( + if test.beforeEncoding != nil { + test.beforeEncoding(decodedInvoice) + } + + if decodedInvoice != nil { + reencoded, err := decodedInvoice.Encode( testMessageSigner, ) if (err == nil) != test.valid { @@ -560,9 +597,9 @@ func compareInvoices(expected, actual *zpay32.Invoice) error { *expected.DescriptionHash, *actual.DescriptionHash) } - if !reflect.DeepEqual(expected.Expiry, actual.Expiry) { + if expected.Expiry() != actual.Expiry() { return fmt.Errorf("expected expiry %d, got %d", - expected.Expiry, actual.Expiry) + expected.Expiry(), actual.Expiry()) } if !reflect.DeepEqual(expected.FallbackAddr, actual.FallbackAddr) {