2016-09-17 03:23:37 +03:00
|
|
|
package channeldb
|
|
|
|
|
|
|
|
import (
|
2016-09-19 21:51:37 +03:00
|
|
|
"crypto/rand"
|
2017-03-16 04:56:25 +03:00
|
|
|
"crypto/sha256"
|
2016-09-17 03:23:37 +03:00
|
|
|
"reflect"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/davecgh/go-spew/spew"
|
2017-08-22 08:51:19 +03:00
|
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
2016-09-17 03:23:37 +03:00
|
|
|
)
|
|
|
|
|
2017-08-22 08:51:19 +03:00
|
|
|
func randInvoice(value lnwire.MilliSatoshi) (*Invoice, error) {
|
2016-09-19 21:51:37 +03:00
|
|
|
var pre [32]byte
|
|
|
|
if _, err := rand.Read(pre[:]); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
i := &Invoice{
|
2017-08-29 06:04:06 +03:00
|
|
|
// Use single second precision to avoid false positive test
|
|
|
|
// failures due to the monotonic time component.
|
|
|
|
CreationDate: time.Unix(time.Now().Unix(), 0),
|
2016-09-19 21:51:37 +03:00
|
|
|
Terms: ContractTerm{
|
|
|
|
PaymentPreimage: pre,
|
|
|
|
Value: value,
|
|
|
|
},
|
|
|
|
}
|
2016-09-24 01:15:22 +03:00
|
|
|
i.Memo = []byte("memo")
|
|
|
|
i.Receipt = []byte("recipt")
|
2016-09-19 21:51:37 +03:00
|
|
|
|
2017-09-05 18:59:52 +03:00
|
|
|
// Create a random byte slice of MaxPaymentRequestSize bytes to be used
|
|
|
|
// as a dummy paymentrequest, and determine if it should be set based
|
|
|
|
// on one of the random bytes.
|
|
|
|
var r [MaxPaymentRequestSize]byte
|
|
|
|
if _, err := rand.Read(r[:]); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if r[0]&1 == 0 {
|
|
|
|
i.PaymentRequest = r[:]
|
|
|
|
} else {
|
|
|
|
i.PaymentRequest = []byte("")
|
|
|
|
}
|
|
|
|
|
2016-09-19 21:51:37 +03:00
|
|
|
return i, nil
|
|
|
|
}
|
|
|
|
|
2016-09-17 03:23:37 +03:00
|
|
|
func TestInvoiceWorkflow(t *testing.T) {
|
2017-06-17 01:59:20 +03:00
|
|
|
t.Parallel()
|
|
|
|
|
2016-09-17 03:23:37 +03:00
|
|
|
db, cleanUp, err := makeTestDB()
|
2016-12-22 23:04:41 +03:00
|
|
|
defer cleanUp()
|
2016-09-17 03:23:37 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to make test db: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a fake invoice which we'll use several times in the tests
|
|
|
|
// below.
|
|
|
|
fakeInvoice := &Invoice{
|
2017-08-29 06:04:06 +03:00
|
|
|
// Use single second precision to avoid false positive test
|
|
|
|
// failures due to the monotonic time component.
|
|
|
|
CreationDate: time.Unix(time.Now().Unix(), 0),
|
2016-09-17 03:23:37 +03:00
|
|
|
}
|
2016-09-24 01:15:22 +03:00
|
|
|
fakeInvoice.Memo = []byte("memo")
|
|
|
|
fakeInvoice.Receipt = []byte("recipt")
|
2017-09-05 18:59:52 +03:00
|
|
|
fakeInvoice.PaymentRequest = []byte("")
|
2016-09-17 03:23:37 +03:00
|
|
|
copy(fakeInvoice.Terms.PaymentPreimage[:], rev[:])
|
2017-08-22 08:51:19 +03:00
|
|
|
fakeInvoice.Terms.Value = lnwire.NewMSatFromSatoshis(10000)
|
2016-09-17 03:23:37 +03:00
|
|
|
|
|
|
|
// Add the invoice to the database, this should suceed as there aren't
|
|
|
|
// any existing invoices within the database with the same payment
|
|
|
|
// hash.
|
|
|
|
if err := db.AddInvoice(fakeInvoice); err != nil {
|
|
|
|
t.Fatalf("unable to find invoice: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attempt to retrieve the invoice which was just added to the
|
|
|
|
// database. It should be found, and the invoice returned should be
|
|
|
|
// identical to the one created above.
|
2017-03-16 04:56:25 +03:00
|
|
|
paymentHash := sha256.Sum256(fakeInvoice.Terms.PaymentPreimage[:])
|
2016-09-17 03:23:37 +03:00
|
|
|
dbInvoice, err := db.LookupInvoice(paymentHash)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to find invoice: %v", err)
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(fakeInvoice, dbInvoice) {
|
|
|
|
t.Fatalf("invoice fetched from db doesn't match original %v vs %v",
|
|
|
|
spew.Sdump(fakeInvoice), spew.Sdump(dbInvoice))
|
|
|
|
}
|
|
|
|
|
2017-12-05 09:07:21 +03:00
|
|
|
// Settle the invoice, the version retrieved from the database should
|
|
|
|
// now have the settled bit toggle to true and a non-default
|
|
|
|
// SettledDate
|
2016-09-17 03:23:37 +03:00
|
|
|
if err := db.SettleInvoice(paymentHash); err != nil {
|
|
|
|
t.Fatalf("unable to settle invoice: %v", err)
|
|
|
|
}
|
|
|
|
dbInvoice2, err := db.LookupInvoice(paymentHash)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to fetch invoice: %v", err)
|
|
|
|
}
|
|
|
|
if !dbInvoice2.Terms.Settled {
|
|
|
|
t.Fatalf("invoice should now be settled but isn't")
|
|
|
|
}
|
|
|
|
|
2017-12-05 09:07:21 +03:00
|
|
|
if dbInvoice2.SettleDate.IsZero() {
|
|
|
|
t.Fatalf("invoice should have non-zero SettledDate but isn't")
|
|
|
|
}
|
|
|
|
|
2016-09-17 03:23:37 +03:00
|
|
|
// Attempt to insert generated above again, this should fail as
|
|
|
|
// duplicates are rejected by the processing logic.
|
|
|
|
if err := db.AddInvoice(fakeInvoice); err != ErrDuplicateInvoice {
|
|
|
|
t.Fatalf("invoice insertion should fail due to duplication, "+
|
|
|
|
"instead %v", err)
|
|
|
|
}
|
|
|
|
|
2017-09-25 21:25:58 +03:00
|
|
|
// Attempt to look up a non-existent invoice, this should also fail but
|
2016-09-17 03:23:37 +03:00
|
|
|
// with a "not found" error.
|
|
|
|
var fakeHash [32]byte
|
|
|
|
if _, err := db.LookupInvoice(fakeHash); err != ErrInvoiceNotFound {
|
|
|
|
t.Fatalf("lookup should have failed, instead %v", err)
|
|
|
|
}
|
2016-09-19 21:51:37 +03:00
|
|
|
|
|
|
|
// Add 100 random invoices.
|
|
|
|
const numInvoices = 10
|
2017-08-22 08:51:19 +03:00
|
|
|
amt := lnwire.NewMSatFromSatoshis(1000)
|
2016-09-19 21:51:37 +03:00
|
|
|
invoices := make([]*Invoice, numInvoices+1)
|
|
|
|
invoices[0] = dbInvoice2
|
|
|
|
for i := 1; i < len(invoices)-1; i++ {
|
|
|
|
invoice, err := randInvoice(amt)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to create invoice: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := db.AddInvoice(invoice); err != nil {
|
|
|
|
t.Fatalf("unable to add invoice %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
invoices[i] = invoice
|
|
|
|
}
|
|
|
|
|
|
|
|
// Perform a scan to collect all the active invoices.
|
|
|
|
dbInvoices, err := db.FetchAllInvoices(false)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to fetch all invoices: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// The retrieve list of invoices should be identical as since we're
|
|
|
|
// using big endian, the invoices should be retrieved in asecending
|
|
|
|
// order (and the primary key should be incremented with each
|
|
|
|
// insertion).
|
|
|
|
for i := 0; i < len(invoices)-1; i++ {
|
|
|
|
if !reflect.DeepEqual(invoices[i], dbInvoices[i]) {
|
|
|
|
t.Fatalf("retrived invoices don't match %v vs %v",
|
|
|
|
spew.Sdump(invoices[i]),
|
|
|
|
spew.Sdump(dbInvoices[i]))
|
|
|
|
}
|
|
|
|
}
|
2016-09-17 03:23:37 +03:00
|
|
|
}
|