invoice: add unit tests for each parsed tagged field

This commit introduces unit tests for each parsed tagged field to cover
all possible input scenarios.
This commit is contained in:
Wilmer Paulino 2018-01-09 01:14:31 -05:00
parent 07ac278771
commit 8807fb804b
No known key found for this signature in database
GPG Key ID: 6DF57B9F9514972F
2 changed files with 675 additions and 176 deletions

View File

@ -1,9 +1,16 @@
package zpay32
import (
"encoding/binary"
"reflect"
"testing"
"time"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/chaincfg"
"github.com/roasbeef/btcutil"
"github.com/roasbeef/btcutil/bech32"
)
// TestDecodeAmount ensures that the amount string in the hrp of the Invoice
@ -118,11 +125,11 @@ func TestDecodeAmount(t *testing.T) {
for i, test := range tests {
sat, err := decodeAmount(test.amount)
if (err == nil) != test.valid {
t.Errorf("Amount decoding test %d failed: %v", i, err)
t.Errorf("amount decoding test %d failed: %v", i, err)
return
}
if test.valid && sat != test.result {
t.Fatalf("%d) failed decoding amount, expected %v, "+
t.Fatalf("test %d failed decoding amount, expected %v, "+
"got %v", i, test.result, sat)
}
}
@ -193,11 +200,11 @@ func TestEncodeAmount(t *testing.T) {
for i, test := range tests {
shortened, err := encodeAmount(test.msat)
if (err == nil) != test.valid {
t.Errorf("Amount encoding test %d failed: %v", i, err)
t.Errorf("amount encoding test %d failed: %v", i, err)
return
}
if test.valid && shortened != test.result {
t.Fatalf("%d) failed encoding amount, expected %v, "+
t.Fatalf("test %d failed encoding amount, expected %v, "+
"got %v", i, test.result, shortened)
}
}
@ -230,13 +237,505 @@ func TestParseTimestamp(t *testing.T) {
for i, test := range tests {
time, err := parseTimestamp(test.data)
if (err == nil) != test.valid {
t.Errorf("Data decoding test %d failed: %v", i, err)
t.Errorf("timestamp decoding test %d failed: %v", i, err)
return
}
if test.valid && time != test.result {
t.Errorf("Timestamp decoding test %d failed: expected "+
"timestamp %d, got %d", i, test.result, time)
t.Fatalf("test %d failed decoding timestamp: "+
"expected %d, got %d",
i, test.result, time)
return
}
}
}
// TestParseFieldDataLength checks that the 16 bit length is properly parsed.
func TestParseFieldDataLength(t *testing.T) {
t.Parallel()
tests := []struct {
data []byte
valid bool
result uint16
}{
{
data: []byte{},
valid: false, // empty data
},
{
data: []byte{0x0},
valid: false, // data too short
},
{
data: []byte{0x0, 0x0, 0x0},
valid: false, // data too long
},
{
data: []byte{0x0, 0x0},
valid: true,
result: 0,
},
{
data: []byte{0x1f, 0x1f},
valid: true,
result: 1023,
},
{
// The first byte is <= 3 bits long.
data: []byte{0x1, 0x2},
valid: true,
result: 34,
},
{
// The first byte is > 3 bits long.
data: []byte{0xa, 0x0},
valid: true,
result: 320,
},
}
for i, test := range tests {
length, err := parseFieldDataLength(test.data)
if (err == nil) != test.valid {
t.Errorf("field data length decoding test %d failed: %v", i, err)
return
}
if test.valid && length != test.result {
t.Fatalf("test %d failed decoding field data length: "+
"expected %d, got %d",
i, test.result, length)
return
}
}
}
// TestParsePaymentHash checks that the payment hash is properly parsed.
// If the data does not have a length of 52 bytes, we skip over parsing the
// field and do not return an error.
func TestParsePaymentHash(t *testing.T) {
t.Parallel()
testPaymentHashData, _ := bech32.ConvertBits(testPaymentHash[:], 8, 5, true)
tests := []struct {
data []byte
valid bool
result *[32]byte
}{
{
data: []byte{},
valid: true,
result: nil, // skip unknown length, not 52 bytes
},
{
data: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
valid: true,
result: nil, // skip unknown length, not 52 bytes
},
{
data: testPaymentHashData,
valid: true,
result: &testPaymentHash,
},
{
data: append(testPaymentHashData, 0x0),
valid: true,
result: nil, // skip unknown length, not 52 bytes
},
}
for i, test := range tests {
paymentHash, err := parsePaymentHash(test.data)
if (err == nil) != test.valid {
t.Errorf("payment hash decoding test %d failed: %v", i, err)
return
}
if test.valid && !compareHashes(paymentHash, test.result) {
t.Fatalf("test %d failed decoding payment hash: "+
"expected %x, got %x",
i, *test.result, *paymentHash)
return
}
}
}
// TestParseDescription checks that the description is properly parsed.
func TestParseDescription(t *testing.T) {
t.Parallel()
testCupOfCoffeeData, _ := bech32.ConvertBits([]byte(testCupOfCoffee), 8, 5, true)
testPleaseConsiderData, _ := bech32.ConvertBits([]byte(testPleaseConsider), 8, 5, true)
tests := []struct {
data []byte
valid bool
result *string
}{
{
data: []byte{},
valid: true,
result: &testEmptyString,
},
{
data: testCupOfCoffeeData,
valid: true,
result: &testCupOfCoffee,
},
{
data: testPleaseConsiderData,
valid: true,
result: &testPleaseConsider,
},
}
for i, test := range tests {
description, err := parseDescription(test.data)
if (err == nil) != test.valid {
t.Errorf("description decoding test %d failed: %v", i, err)
return
}
if test.valid && !reflect.DeepEqual(description, test.result) {
t.Fatalf("test %d failed decoding description: "+
"expected \"%s\", got \"%s\"",
i, *test.result, *description)
return
}
}
}
// TestParseDestination checks that the destination is properly parsed.
// If the data does not have a length of 53 bytes, we skip over parsing the
// field and do not return an error.
func TestParseDestination(t *testing.T) {
t.Parallel()
testPubKeyData, _ := bech32.ConvertBits(testPubKey.SerializeCompressed(), 8, 5, true)
tests := []struct {
data []byte
valid bool
result *btcec.PublicKey
}{
{
data: []byte{},
valid: true,
result: nil, // skip unknown length, not 53 bytes
},
{
data: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
valid: true,
result: nil, // skip unknown length, not 53 bytes
},
{
data: testPubKeyData,
valid: true,
result: testPubKey,
},
{
data: append(testPubKeyData, 0x0),
valid: true,
result: nil, // skip unknown length, not 53 bytes
},
}
for i, test := range tests {
destination, err := parseDestination(test.data)
if (err == nil) != test.valid {
t.Errorf("destination decoding test %d failed: %v", i, err)
return
}
if test.valid && !comparePubkeys(destination, test.result) {
t.Fatalf("test %d failed decoding destination: "+
"expected %x, got %x",
i, *test.result, *destination)
return
}
}
}
// TestParseDescriptionHash checks that the description hash is properly parsed.
// If the data does not have a length of 52 bytes, we skip over parsing the
// field and do not return an error.
func TestParseDescriptionHash(t *testing.T) {
t.Parallel()
testDescriptionHashData, _ := bech32.ConvertBits(testDescriptionHash[:], 8, 5, true)
tests := []struct {
data []byte
valid bool
result *[32]byte
}{
{
data: []byte{},
valid: true,
result: nil, // skip unknown length, not 52 bytes
},
{
data: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
valid: true,
result: nil, // skip unknown length, not 52 bytes
},
{
data: testDescriptionHashData,
valid: true,
result: &testDescriptionHash,
},
{
data: append(testDescriptionHashData, 0x0),
valid: true,
result: nil, // skip unknown length, not 52 bytes
},
}
for i, test := range tests {
descriptionHash, err := parseDescriptionHash(test.data)
if (err == nil) != test.valid {
t.Errorf("description hash decoding test %d failed: %v", i, err)
return
}
if test.valid && !compareHashes(descriptionHash, test.result) {
t.Fatalf("test %d failed decoding description hash: "+
"expected %x, got %x",
i, *test.result, *descriptionHash)
return
}
}
}
// TestParseExpiry checks that the expiry is properly parsed.
func TestParseExpiry(t *testing.T) {
t.Parallel()
tests := []struct {
data []byte
valid bool
result *time.Duration
}{
{
data: []byte{},
valid: true,
result: &testExpiry0,
},
{
data: []byte{0x1, 0x1c},
valid: true,
result: &testExpiry60,
},
{
data: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc},
valid: false, // data too long
},
}
for i, test := range tests {
expiry, err := parseExpiry(test.data)
if (err == nil) != test.valid {
t.Errorf("expiry decoding test %d failed: %v", i, err)
return
}
if test.valid && !reflect.DeepEqual(expiry, test.result) {
t.Fatalf("test %d failed decoding expiry: "+
"expected expiry %v, got %v",
i, *test.result, *expiry)
return
}
}
}
// TestParseMinFinalCLTVExpiry checks that the minFinalCLTVExpiry is properly parsed.
func TestParseMinFinalCLTVExpiry(t *testing.T) {
t.Parallel()
tests := []struct {
data []byte
valid bool
result uint64
}{
{
data: []byte{},
valid: true,
result: 0,
},
{
data: []byte{0x1, 0x1c},
valid: true,
result: 60,
},
{
data: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc},
valid: true,
result: 38390726480144748,
},
{
data: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc},
valid: false, // data too long
},
}
for i, test := range tests {
expiry, err := parseMinFinalCLTVExpiry(test.data)
if (err == nil) != test.valid {
t.Errorf("minFinalCLTVExpiry decoding test %d failed: %v", i, err)
return
}
if test.valid && *expiry != test.result {
t.Fatalf("test %d failed decoding minFinalCLTVExpiry: "+
"expected %d, got %d",
i, test.result, *expiry)
return
}
}
}
// TestParseFallbackAddr checks that the fallback address is properly parsed.
func TestParseFallbackAddr(t *testing.T) {
t.Parallel()
testAddrTestnetData, _ := bech32.ConvertBits(testAddrTestnet.ScriptAddress(), 8, 5, true)
testAddrTestnetDataWithVersion := append([]byte{17}, testAddrTestnetData...)
testRustyAddrData, _ := bech32.ConvertBits(testRustyAddr.ScriptAddress(), 8, 5, true)
testRustyAddrDataWithVersion := append([]byte{17}, testRustyAddrData...)
testAddrMainnetP2SHData, _ := bech32.ConvertBits(testAddrMainnetP2SH.ScriptAddress(), 8, 5, true)
testAddrMainnetP2SHDataWithVersion := append([]byte{18}, testAddrMainnetP2SHData...)
testAddrMainnetP2WPKHData, _ := bech32.ConvertBits(testAddrMainnetP2WPKH.ScriptAddress(), 8, 5, true)
testAddrMainnetP2WPKHDataWithVersion := append([]byte{0}, testAddrMainnetP2WPKHData...)
testAddrMainnetP2WSHData, _ := bech32.ConvertBits(testAddrMainnetP2WSH.ScriptAddress(), 8, 5, true)
testAddrMainnetP2WSHDataWithVersion := append([]byte{0}, testAddrMainnetP2WSHData...)
tests := []struct {
data []byte
net *chaincfg.Params
valid bool
result btcutil.Address
}{
{
data: []byte{},
valid: false, // empty data
},
{
data: []byte{0x0},
valid: false, // data too short, version without address
},
{
data: testAddrTestnetDataWithVersion,
net: &chaincfg.TestNet3Params,
valid: true,
result: testAddrTestnet,
},
{
data: testRustyAddrDataWithVersion,
net: &chaincfg.MainNetParams,
valid: true,
result: testRustyAddr,
},
{
data: testAddrMainnetP2SHDataWithVersion,
net: &chaincfg.MainNetParams,
valid: true,
result: testAddrMainnetP2SH,
},
{
data: testAddrMainnetP2WPKHDataWithVersion,
net: &chaincfg.MainNetParams,
valid: true,
result: testAddrMainnetP2WPKH,
},
{
data: testAddrMainnetP2WSHDataWithVersion,
net: &chaincfg.MainNetParams,
valid: true,
result: testAddrMainnetP2WSH,
},
}
for i, test := range tests {
fallbackAddr, err := parseFallbackAddr(test.data, test.net)
if (err == nil) != test.valid {
t.Errorf("fallback addr decoding test %d failed: %v", i, err)
return
}
if test.valid && !reflect.DeepEqual(test.result, fallbackAddr) {
t.Fatalf("test %d failed decoding fallback addr: "+
"expected %v, got %v",
i, test.result, fallbackAddr)
return
}
}
}
// TestParseRoutingInfo checks that the routing info is properly parsed.
func TestParseRoutingInfo(t *testing.T) {
t.Parallel()
var testSingleHopData []byte
for _, r := range testSingleHop {
base256 := make([]byte, 51)
copy(base256[:33], r.PubKey.SerializeCompressed())
binary.BigEndian.PutUint64(base256[33:41], r.ShortChanID)
binary.BigEndian.PutUint32(base256[41:45], r.FeeBaseMsat)
binary.BigEndian.PutUint32(base256[45:49], r.FeeProportionalMillionths)
binary.BigEndian.PutUint16(base256[49:51], r.CltvExpDelta)
testSingleHopData = append(testSingleHopData, base256...)
}
testSingleHopData, _ = bech32.ConvertBits(testSingleHopData, 8, 5, true)
var testDoubleHopData []byte
for _, r := range testDoubleHop {
base256 := make([]byte, 51)
copy(base256[:33], r.PubKey.SerializeCompressed())
binary.BigEndian.PutUint64(base256[33:41], r.ShortChanID)
binary.BigEndian.PutUint32(base256[41:45], r.FeeBaseMsat)
binary.BigEndian.PutUint32(base256[45:49], r.FeeProportionalMillionths)
binary.BigEndian.PutUint16(base256[49:51], r.CltvExpDelta)
testDoubleHopData = append(testDoubleHopData, base256...)
}
testDoubleHopData, _ = bech32.ConvertBits(testDoubleHopData, 8, 5, true)
tests := []struct {
data []byte
valid bool
result []ExtraRoutingInfo
}{
{
data: []byte{0x0, 0x0, 0x0, 0x0},
valid: false, // data too short, not multiple of 51 bytes
},
{
data: []byte{},
valid: true,
result: []ExtraRoutingInfo{},
},
{
data: testSingleHopData,
valid: true,
result: testSingleHop,
},
{
data: append(testSingleHopData, 0x0),
valid: false, // data too long, not multiple of 51 bytes
},
{
data: testDoubleHopData,
valid: true,
result: testDoubleHop,
},
}
for i, test := range tests {
routingInfo, err := parseRoutingInfo(test.data)
if (err == nil) != test.valid {
t.Errorf("routing info decoding test %d failed: %v", i, err)
return
}
if test.valid {
if err := compareRoutingInfos(test.result, routingInfo); err != nil {
t.Fatalf("test %d failed decoding routing info: %v", i, err)
}
}
}
}

View File

@ -1,4 +1,7 @@
package zpay32_test
package zpay32
// We use package `zpay32` rather than `zpay32_test` in order to share test data
// with the internal tests.
import (
"bytes"
@ -9,7 +12,6 @@ import (
"time"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/zpay32"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/chaincfg"
"github.com/roasbeef/btcd/chaincfg/chainhash"
@ -17,35 +19,62 @@ import (
)
var (
testMillisat24BTC = lnwire.MilliSatoshi(2400000000000)
testMillisat2500uBTC = lnwire.MilliSatoshi(250000000)
testMillisat20mBTC = lnwire.MilliSatoshi(2000000000)
testPaymentHashSlice, _ = hex.DecodeString("0001020304050607080900010203040506070809000102030405060708090102")
testEmptyString = ""
testCupOfCoffee = "1 cup coffee"
testPleaseConsider = "Please consider supporting this project"
testPrivKeyBytes, _ = hex.DecodeString("e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734")
testPrivKey, testPubKey = btcec.PrivKeyFromBytes(btcec.S256(), testPrivKeyBytes)
testDescriptionHashSlice = chainhash.HashB([]byte("One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon"))
testExpiry0 = time.Duration(0) * time.Second
testExpiry60 = time.Duration(60) * time.Second
testAddrTestnet, _ = btcutil.DecodeAddress("mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP", &chaincfg.TestNet3Params)
testRustyAddr, _ = btcutil.DecodeAddress("1RustyRX2oai4EYYDpQGWvEL62BBGqN9T", &chaincfg.MainNetParams)
testAddrMainnetP2SH, _ = btcutil.DecodeAddress("3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX", &chaincfg.MainNetParams)
testAddrMainnetP2WPKH, _ = btcutil.DecodeAddress("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", &chaincfg.MainNetParams)
testAddrMainnetP2WSH, _ = btcutil.DecodeAddress("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3", &chaincfg.MainNetParams)
testRoutingInfoPubkeyBytes, _ = hex.DecodeString("029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255")
testRoutingInfoPubkey, _ = btcec.ParsePubKey(testRoutingInfoPubkeyBytes, btcec.S256())
testRoutingInfoPubkeyBytes2, _ = hex.DecodeString("039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255")
testRoutingInfoPubkey2, _ = btcec.ParsePubKey(testRoutingInfoPubkeyBytes2, btcec.S256())
testMillisat24BTC = lnwire.MilliSatoshi(2400000000000)
testMillisat2500uBTC = lnwire.MilliSatoshi(250000000)
testMillisat20mBTC = lnwire.MilliSatoshi(2000000000)
testSingleHop = []ExtraRoutingInfo{
{
PubKey: testRoutingInfoPubkey,
ShortChanID: 0x0102030405060708,
FeeBaseMsat: 0,
FeeProportionalMillionths: 20,
CltvExpDelta: 3,
},
}
testDoubleHop = []ExtraRoutingInfo{
{
PubKey: testRoutingInfoPubkey,
ShortChanID: 0x0102030405060708,
FeeBaseMsat: 1,
FeeProportionalMillionths: 20,
CltvExpDelta: 3,
},
{
PubKey: testRoutingInfoPubkey2,
ShortChanID: 0x030405060708090a,
FeeBaseMsat: 2,
FeeProportionalMillionths: 30,
CltvExpDelta: 4,
},
}
testExpiry60 = 60 * time.Second
testEmptyString = ""
testCupOfCoffee = "1 cup coffee"
testPleaseConsider = "Please consider supporting this project"
testRustyAddr, _ = btcutil.DecodeAddress("1RustyRX2oai4EYYDpQGWvEL62BBGqN9T", &chaincfg.MainNetParams)
testAddrTestnet, _ = btcutil.DecodeAddress("mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP", &chaincfg.TestNet3Params)
testAddrMainnetP2SH, _ = btcutil.DecodeAddress("3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX", &chaincfg.MainNetParams)
testAddrMainnetP2WPKH, _ = btcutil.DecodeAddress("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", &chaincfg.MainNetParams)
testAddrMainnetP2WSH, _ = btcutil.DecodeAddress("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3", &chaincfg.MainNetParams)
testPaymentHashSlice, _ = hex.DecodeString("0001020304050607080900010203040506070809000102030405060708090102")
testDescriptionHashSlice = chainhash.HashB([]byte("One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon"))
// Must be initialized in init().
testPaymentHash [32]byte
testDescriptionHash [32]byte
testMessageSigner = zpay32.MessageSigner{
testMessageSigner = MessageSigner{
SignCompact: func(hash []byte) ([]byte, error) {
sig, err := btcec.SignCompact(btcec.S256(),
testPrivKey, hash, true)
@ -56,6 +85,10 @@ var (
return sig, nil
},
}
// Must be initialized in init().
testPaymentHash [32]byte
testDescriptionHash [32]byte
)
func init() {
@ -72,9 +105,9 @@ func TestDecodeEncode(t *testing.T) {
tests := []struct {
encodedInvoice string
valid bool
decodedInvoice func() *zpay32.Invoice
decodedInvoice func() *Invoice
skipEncoding bool
beforeEncoding func(*zpay32.Invoice)
beforeEncoding func(*Invoice)
}{
{
encodedInvoice: "asdsaddnasdnas", // no hrp
@ -112,8 +145,8 @@ func TestDecodeEncode(t *testing.T) {
// no payment hash set
encodedInvoice: "lnbc20m1pvjluezhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsjv38luh6p6s2xrv3mzvlmzaya43376h0twal5ax0k6p47498hp3hnaymzhsn424rxqjs0q7apn26yrhaxltq3vzwpqj9nc2r3kzwccsplnq470",
valid: false,
decodedInvoice: func() *zpay32.Invoice {
return &zpay32.Invoice{
decodedInvoice: func() *Invoice {
return &Invoice{
Net: &chaincfg.MainNetParams,
MilliSat: &testMillisat20mBTC,
Timestamp: time.Unix(1496314658, 0),
@ -126,8 +159,8 @@ func TestDecodeEncode(t *testing.T) {
// Both Description and DescriptionHash set.
encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs03vghs8y0kuj4ulrzls8ln7fnm9dk7sjsnqmghql6hd6jut36clkqpyuq0s5m6fhureyz0szx2qjc8hkgf4xc2hpw8jpu26jfeyvf4cpga36gt",
valid: false,
decodedInvoice: func() *zpay32.Invoice {
return &zpay32.Invoice{
decodedInvoice: func() *Invoice {
return &Invoice{
Net: &chaincfg.MainNetParams,
MilliSat: &testMillisat20mBTC,
Timestamp: time.Unix(1496314658, 0),
@ -142,8 +175,8 @@ func TestDecodeEncode(t *testing.T) {
// Neither Description nor DescriptionHash set.
encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqn2rne0kagfl4e0xag0w6hqeg2dwgc54hrm9m0auw52dhwhwcu559qav309h598pyzn69wh2nqauneyyesnpmaax0g6acr8lh9559jmcquyq5a9",
valid: false,
decodedInvoice: func() *zpay32.Invoice {
return &zpay32.Invoice{
decodedInvoice: func() *Invoice {
return &Invoice{
Net: &chaincfg.MainNetParams,
MilliSat: &testMillisat20mBTC,
Timestamp: time.Unix(1496314658, 0),
@ -156,8 +189,8 @@ func TestDecodeEncode(t *testing.T) {
// Has a few unknown fields, should just be ignored.
encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaqtq2v93xxer9vczq8v93xxeqv72xr42ca60022jqu6fu73n453tmnr0ukc0pl0t23w7eavtensjz0j2wcu7nkxhfdgp9y37welajh5kw34mq7m4xuay0a72cwec8qwgqt5vqht",
valid: true,
decodedInvoice: func() *zpay32.Invoice {
return &zpay32.Invoice{
decodedInvoice: func() *Invoice {
return &Invoice{
Net: &chaincfg.MainNetParams,
MilliSat: &testMillisat20mBTC,
Timestamp: time.Unix(1496314658, 0),
@ -172,8 +205,8 @@ func TestDecodeEncode(t *testing.T) {
// Ignore unknown witness version in fallback address.
encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpppw508d6qejxtdg4y5r3zarvary0c5xw7k8txqv6x0a75xuzp0zsdzk5hq6tmfgweltvs6jk5nhtyd9uqksvr48zga9mw08667w8264gkspluu66jhtcmct36nx363km6cquhhv2cpc6q43r",
valid: true,
decodedInvoice: func() *zpay32.Invoice {
return &zpay32.Invoice{
decodedInvoice: func() *Invoice {
return &Invoice{
Net: &chaincfg.MainNetParams,
MilliSat: &testMillisat20mBTC,
Timestamp: time.Unix(1496314658, 0),
@ -188,8 +221,8 @@ func TestDecodeEncode(t *testing.T) {
// Ignore fields with unknown lengths.
encodedInvoice: "lnbc241pveeq09pp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqpp3qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqshp38yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahnp4q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66np3q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfy8huflvs2zwkymx47cszugvzn5v64ahemzzlmm62rpn9l9rm05h35aceq00tkt296289wepws9jh4499wq2l0vk6xcxffd90dpuqchqqztyayq",
valid: true,
decodedInvoice: func() *zpay32.Invoice {
return &zpay32.Invoice{
decodedInvoice: func() *Invoice {
return &Invoice{
Net: &chaincfg.MainNetParams,
MilliSat: &testMillisat24BTC,
Timestamp: time.Unix(1503429093, 0),
@ -204,8 +237,8 @@ func TestDecodeEncode(t *testing.T) {
// Please make a donation of any amount using rhash 0001020304050607080900010203040506070809000102030405060708090102 to me @03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad
encodedInvoice: "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w",
valid: true,
decodedInvoice: func() *zpay32.Invoice {
return &zpay32.Invoice{
decodedInvoice: func() *Invoice {
return &Invoice{
Net: &chaincfg.MainNetParams,
Timestamp: time.Unix(1496314658, 0),
PaymentHash: &testPaymentHash,
@ -213,7 +246,7 @@ func TestDecodeEncode(t *testing.T) {
Destination: testPubKey,
}
},
beforeEncoding: func(i *zpay32.Invoice) {
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.
@ -224,8 +257,8 @@ func TestDecodeEncode(t *testing.T) {
// Same as above, pubkey set in 'n' field.
encodedInvoice: "lnbc241pveeq09pp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdqqnp4q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66jd3m5klcwhq68vdsmx2rjgxeay5v0tkt2v5sjaky4eqahe4fx3k9sqavvce3capfuwv8rvjng57jrtfajn5dkpqv8yelsewtljwmmycq62k443",
valid: true,
decodedInvoice: func() *zpay32.Invoice {
return &zpay32.Invoice{
decodedInvoice: func() *Invoice {
return &Invoice{
Net: &chaincfg.MainNetParams,
MilliSat: &testMillisat24BTC,
Timestamp: time.Unix(1503429093, 0),
@ -239,18 +272,18 @@ func TestDecodeEncode(t *testing.T) {
// Please send $3 for a cup of coffee to the same peer, within 1 minute
encodedInvoice: "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaztrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspfj9srp",
valid: true,
decodedInvoice: func() *zpay32.Invoice {
i, _ := zpay32.NewInvoice(
decodedInvoice: func() *Invoice {
i, _ := NewInvoice(
&chaincfg.MainNetParams,
testPaymentHash,
time.Unix(1496314658, 0),
zpay32.Amount(testMillisat2500uBTC),
zpay32.Description(testCupOfCoffee),
zpay32.Destination(testPubKey),
zpay32.Expiry(testExpiry60))
Amount(testMillisat2500uBTC),
Description(testCupOfCoffee),
Destination(testPubKey),
Expiry(testExpiry60))
return i
},
beforeEncoding: func(i *zpay32.Invoice) {
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.
@ -261,8 +294,8 @@ func TestDecodeEncode(t *testing.T) {
// Now send $24 for an entire list of things (hashed)
encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqscc6gd6ql3jrc5yzme8v4ntcewwz5cnw92tz0pc8qcuufvq7khhr8wpald05e92xw006sq94mg8v2ndf4sefvf9sygkshp5zfem29trqq2yxxz7",
valid: true,
decodedInvoice: func() *zpay32.Invoice {
return &zpay32.Invoice{
decodedInvoice: func() *Invoice {
return &Invoice{
Net: &chaincfg.MainNetParams,
MilliSat: &testMillisat20mBTC,
Timestamp: time.Unix(1496314658, 0),
@ -271,7 +304,7 @@ func TestDecodeEncode(t *testing.T) {
Destination: testPubKey,
}
},
beforeEncoding: func(i *zpay32.Invoice) {
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.
@ -282,8 +315,8 @@ func TestDecodeEncode(t *testing.T) {
// The same, on testnet, with a fallback address mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP
encodedInvoice: "lntb20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3x9et2e20v6pu37c5d9vax37wxq72un98k6vcx9fz94w0qf237cm2rqv9pmn5lnexfvf5579slr4zq3u8kmczecytdx0xg9rwzngp7e6guwqpqlhssu04sucpnz4axcv2dstmknqq6jsk2l",
valid: true,
decodedInvoice: func() *zpay32.Invoice {
return &zpay32.Invoice{
decodedInvoice: func() *Invoice {
return &Invoice{
Net: &chaincfg.TestNet3Params,
MilliSat: &testMillisat20mBTC,
Timestamp: time.Unix(1496314658, 0),
@ -293,7 +326,7 @@ func TestDecodeEncode(t *testing.T) {
FallbackAddr: testAddrTestnet,
}
},
beforeEncoding: func(i *zpay32.Invoice) {
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.
@ -304,8 +337,8 @@ 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: func() *zpay32.Invoice {
return &zpay32.Invoice{
decodedInvoice: func() *Invoice {
return &Invoice{
Net: &chaincfg.MainNetParams,
MilliSat: &testMillisat20mBTC,
Timestamp: time.Unix(1496314658, 0),
@ -313,18 +346,10 @@ func TestDecodeEncode(t *testing.T) {
DescriptionHash: &testDescriptionHash,
Destination: testPubKey,
FallbackAddr: testRustyAddr,
RoutingInfo: []zpay32.ExtraRoutingInfo{
{
PubKey: testRoutingInfoPubkey,
ShortChanID: 0x0102030405060708,
FeeBaseMsat: 0,
FeeProportionalMillionths: 20,
CltvExpDelta: 3,
},
},
RoutingInfo: testSingleHop,
}
},
beforeEncoding: func(i *zpay32.Invoice) {
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.
@ -335,8 +360,8 @@ func TestDecodeEncode(t *testing.T) {
// On mainnet, with fallback address 1RustyRX2oai4EYYDpQGWvEL62BBGqN9T with extra routing info to go via nodes 029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255 then 039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255
encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzqj9n4evl6mr5aj9f58zp6fyjzup6ywn3x6sk8akg5v4tgn2q8g4fhx05wf6juaxu9760yp46454gpg5mtzgerlzezqcqvjnhjh8z3g2qqdhhwkj",
valid: true,
decodedInvoice: func() *zpay32.Invoice {
return &zpay32.Invoice{
decodedInvoice: func() *Invoice {
return &Invoice{
Net: &chaincfg.MainNetParams,
MilliSat: &testMillisat20mBTC,
Timestamp: time.Unix(1496314658, 0),
@ -344,25 +369,10 @@ func TestDecodeEncode(t *testing.T) {
DescriptionHash: &testDescriptionHash,
Destination: testPubKey,
FallbackAddr: testRustyAddr,
RoutingInfo: []zpay32.ExtraRoutingInfo{
{
PubKey: testRoutingInfoPubkey,
ShortChanID: 0x0102030405060708,
FeeBaseMsat: 1,
FeeProportionalMillionths: 20,
CltvExpDelta: 3,
},
{
PubKey: testRoutingInfoPubkey2,
ShortChanID: 0x030405060708090a,
FeeBaseMsat: 2,
FeeProportionalMillionths: 30,
CltvExpDelta: 4,
},
},
RoutingInfo: testDoubleHop,
}
},
beforeEncoding: func(i *zpay32.Invoice) {
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.
@ -373,8 +383,8 @@ func TestDecodeEncode(t *testing.T) {
// On mainnet, with fallback (p2sh) address 3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX
encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfppj3a24vwu6r8ejrss3axul8rxldph2q7z9kk822r8plup77n9yq5ep2dfpcydrjwzxs0la84v3tfw43t3vqhek7f05m6uf8lmfkjn7zv7enn76sq65d8u9lxav2pl6x3xnc2ww3lqpagnh0u",
valid: true,
decodedInvoice: func() *zpay32.Invoice {
return &zpay32.Invoice{
decodedInvoice: func() *Invoice {
return &Invoice{
Net: &chaincfg.MainNetParams,
MilliSat: &testMillisat20mBTC,
Timestamp: time.Unix(1496314658, 0),
@ -384,7 +394,7 @@ func TestDecodeEncode(t *testing.T) {
FallbackAddr: testAddrMainnetP2SH,
}
},
beforeEncoding: func(i *zpay32.Invoice) {
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.
@ -395,8 +405,8 @@ func TestDecodeEncode(t *testing.T) {
// On mainnet, with fallback (p2wpkh) address bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4
encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfppqw508d6qejxtdg4y5r3zarvary0c5xw7kknt6zz5vxa8yh8jrnlkl63dah48yh6eupakk87fjdcnwqfcyt7snnpuz7vp83txauq4c60sys3xyucesxjf46yqnpplj0saq36a554cp9wt865",
valid: true,
decodedInvoice: func() *zpay32.Invoice {
return &zpay32.Invoice{
decodedInvoice: func() *Invoice {
return &Invoice{
Net: &chaincfg.MainNetParams,
MilliSat: &testMillisat20mBTC,
Timestamp: time.Unix(1496314658, 0),
@ -406,7 +416,7 @@ func TestDecodeEncode(t *testing.T) {
FallbackAddr: testAddrMainnetP2WPKH,
}
},
beforeEncoding: func(i *zpay32.Invoice) {
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.
@ -417,8 +427,8 @@ func TestDecodeEncode(t *testing.T) {
// On mainnet, with fallback (p2wsh) address bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3
encodedInvoice: "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfp4qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qvnjha2auylmwrltv2pkp2t22uy8ura2xsdwhq5nm7s574xva47djmnj2xeycsu7u5v8929mvuux43j0cqhhf32wfyn2th0sv4t9x55sppz5we8",
valid: true,
decodedInvoice: func() *zpay32.Invoice {
return &zpay32.Invoice{
decodedInvoice: func() *Invoice {
return &Invoice{
Net: &chaincfg.MainNetParams,
MilliSat: &testMillisat20mBTC,
Timestamp: time.Unix(1496314658, 0),
@ -428,7 +438,7 @@ func TestDecodeEncode(t *testing.T) {
FallbackAddr: testAddrMainnetP2WSH,
}
},
beforeEncoding: func(i *zpay32.Invoice) {
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.
@ -440,15 +450,15 @@ func TestDecodeEncode(t *testing.T) {
// expiry value.
encodedInvoice: "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jscqzysnp4q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66ysxkvnxhcvhz48sn72lp77h4fxcur27z0he48u5qvk3sxse9mr9jhkltt962s8arjnzk8rk59yj5nw4p495747gksj30gza0crhzwjcpgxzy00",
valid: true,
decodedInvoice: func() *zpay32.Invoice {
i, _ := zpay32.NewInvoice(
decodedInvoice: func() *Invoice {
i, _ := NewInvoice(
&chaincfg.MainNetParams,
testPaymentHash,
time.Unix(1496314658, 0),
zpay32.Amount(testMillisat2500uBTC),
zpay32.Description(testCupOfCoffee),
zpay32.Destination(testPubKey),
zpay32.CLTVExpiry(144),
Amount(testMillisat2500uBTC),
Description(testCupOfCoffee),
Destination(testPubKey),
CLTVExpiry(144),
)
return i
@ -457,7 +467,7 @@ func TestDecodeEncode(t *testing.T) {
}
for i, test := range tests {
invoice, err := zpay32.Decode(test.encodedInvoice)
invoice, err := Decode(test.encodedInvoice)
if (err == nil) != test.valid {
t.Errorf("Decoding test %d failed: %v", i, err)
return
@ -474,7 +484,7 @@ func TestDecodeEncode(t *testing.T) {
continue
}
var decodedInvoice *zpay32.Invoice
var decodedInvoice *Invoice
if test.decodedInvoice != nil {
decodedInvoice = test.decodedInvoice()
}
@ -507,58 +517,41 @@ func TestNewInvoice(t *testing.T) {
t.Parallel()
tests := []struct {
newInvoice func() (*zpay32.Invoice, error)
newInvoice func() (*Invoice, error)
encodedInvoice string
valid bool
}{
{
// Both Description and DescriptionHash set.
newInvoice: func() (*zpay32.Invoice, error) {
return zpay32.NewInvoice(&chaincfg.MainNetParams,
newInvoice: func() (*Invoice, error) {
return NewInvoice(&chaincfg.MainNetParams,
testPaymentHash, time.Unix(1496314658, 0),
zpay32.DescriptionHash(testDescriptionHash),
zpay32.Description(testPleaseConsider))
DescriptionHash(testDescriptionHash),
Description(testPleaseConsider))
},
valid: false, // Both Description and DescriptionHash set.
},
{
// 'n' field set.
newInvoice: func() (*zpay32.Invoice, error) {
return zpay32.NewInvoice(&chaincfg.MainNetParams,
newInvoice: func() (*Invoice, error) {
return NewInvoice(&chaincfg.MainNetParams,
testPaymentHash, time.Unix(1503429093, 0),
zpay32.Amount(testMillisat24BTC),
zpay32.Description(testEmptyString),
zpay32.Destination(testPubKey))
Amount(testMillisat24BTC),
Description(testEmptyString),
Destination(testPubKey))
},
valid: true,
encodedInvoice: "lnbc241pveeq09pp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdqqnp4q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66jd3m5klcwhq68vdsmx2rjgxeay5v0tkt2v5sjaky4eqahe4fx3k9sqavvce3capfuwv8rvjng57jrtfajn5dkpqv8yelsewtljwmmycq62k443",
},
{
// On mainnet, with fallback address 1RustyRX2oai4EYYDpQGWvEL62BBGqN9T with extra routing info to go via nodes 029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255 then 039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255
newInvoice: func() (*zpay32.Invoice, error) {
return zpay32.NewInvoice(&chaincfg.MainNetParams,
newInvoice: func() (*Invoice, error) {
return NewInvoice(&chaincfg.MainNetParams,
testPaymentHash, time.Unix(1496314658, 0),
zpay32.Amount(testMillisat20mBTC),
zpay32.DescriptionHash(testDescriptionHash),
zpay32.FallbackAddr(testRustyAddr),
zpay32.RoutingInfo(
[]zpay32.ExtraRoutingInfo{
{
PubKey: testRoutingInfoPubkey,
ShortChanID: 0x0102030405060708,
FeeBaseMsat: 1,
FeeProportionalMillionths: 20,
CltvExpDelta: 3,
},
{
PubKey: testRoutingInfoPubkey2,
ShortChanID: 0x030405060708090a,
FeeBaseMsat: 2,
FeeProportionalMillionths: 30,
CltvExpDelta: 4,
},
},
),
Amount(testMillisat20mBTC),
DescriptionHash(testDescriptionHash),
FallbackAddr(testRustyAddr),
RoutingInfo(testDoubleHop),
)
},
valid: true,
@ -586,7 +579,7 @@ func TestNewInvoice(t *testing.T) {
}
}
func compareInvoices(expected, actual *zpay32.Invoice) error {
func compareInvoices(expected, actual *Invoice) error {
if !reflect.DeepEqual(expected.Net, actual.Net) {
return fmt.Errorf("expected net %v, got %v",
expected.Net, actual.Net)
@ -596,8 +589,9 @@ func compareInvoices(expected, actual *zpay32.Invoice) error {
return fmt.Errorf("expected milli sat %d, got %d",
*expected.MilliSat, *actual.MilliSat)
}
if expected.Timestamp != actual.Timestamp {
return fmt.Errorf("expected Timestamp %d, got %d",
return fmt.Errorf("expected timestamp %v, got %v",
expected.Timestamp, actual.Timestamp)
}
@ -631,40 +625,10 @@ func compareInvoices(expected, actual *zpay32.Invoice) error {
expected.FallbackAddr, actual.FallbackAddr)
}
if len(expected.RoutingInfo) != len(actual.RoutingInfo) {
return fmt.Errorf("expected len routingInfo %d, got %d",
len(expected.RoutingInfo), len(actual.RoutingInfo))
if err := compareRoutingInfos(expected.RoutingInfo, actual.RoutingInfo); err != nil {
return err
}
for i := 0; i < len(expected.RoutingInfo); i++ {
a := expected.RoutingInfo[i]
b := actual.RoutingInfo[i]
if !comparePubkeys(a.PubKey, b.PubKey) {
return fmt.Errorf("expected routingInfo pubkey %x, "+
"got %x", a.PubKey, b.PubKey)
}
if a.ShortChanID != b.ShortChanID {
return fmt.Errorf("expected routingInfo shortChanID "+
"%d, got %d", a.ShortChanID, b.ShortChanID)
}
if a.FeeBaseMsat != b.FeeBaseMsat {
return fmt.Errorf("expected routingInfo feeBaseMsat %d, got %d",
a.FeeBaseMsat, b.FeeBaseMsat)
}
if a.FeeProportionalMillionths != b.FeeProportionalMillionths {
return fmt.Errorf("expected routingInfo feeProportionalMillionths %d, got %d",
a.FeeProportionalMillionths, b.FeeProportionalMillionths)
}
if a.CltvExpDelta != b.CltvExpDelta {
return fmt.Errorf("expected routingInfo cltvExpDelta "+
"%d, got %d", a.CltvExpDelta, b.CltvExpDelta)
}
}
return nil
}
@ -693,3 +657,39 @@ func compareHashes(a, b *[32]byte) bool {
}
return bytes.Equal(a[:], b[:])
}
func compareRoutingInfos(a, b []ExtraRoutingInfo) error {
if len(a) != len(b) {
return fmt.Errorf("expected len routingInfo %d, got %d",
len(a), len(b))
}
for i := 0; i < len(a); i++ {
if !comparePubkeys(a[i].PubKey, b[i].PubKey) {
return fmt.Errorf("expected routingInfo pubkey %x, "+
"got %x", a[i].PubKey, b[i].PubKey)
}
if a[i].ShortChanID != b[i].ShortChanID {
return fmt.Errorf("expected routingInfo shortChanID "+
"%d, got %d", a[i].ShortChanID, b[i].ShortChanID)
}
if a[i].FeeBaseMsat != b[i].FeeBaseMsat {
return fmt.Errorf("expected routingInfo feeBaseMsat %d, got %d",
a[i].FeeBaseMsat, b[i].FeeBaseMsat)
}
if a[i].FeeProportionalMillionths != b[i].FeeProportionalMillionths {
return fmt.Errorf("expected routingInfo feeProportionalMillionths %d, got %d",
a[i].FeeProportionalMillionths, b[i].FeeProportionalMillionths)
}
if a[i].CltvExpDelta != b[i].CltvExpDelta {
return fmt.Errorf("expected routingInfo cltvExpDelta "+
"%d, got %d", a[i].CltvExpDelta, b[i].CltvExpDelta)
}
}
return nil
}