channeldb/payments+control_tower: split OutgoingPayments

This commit changes the format used to store payments within the
DB. Previously this was serialized as one continuous struct
OutgoingPayment, which also contained an Invoice struct we where only
using a few fields of. We now split it up into two simpler sub-structs
CreationInfo, AttemptInfo and PaymentPreimage.

We also want to associate the payments more closely with payment
statuses, so we move to this hierarchy:

There's one top-level bucket "sentPaymentsBucket" which contains a set
of sub-buckets indexed by a payment's payment hash. Each such sub-bucket
contains several fields:
paymentStatusKey -> the payment's status
paymentCreationInfoKey -> the payment's CreationInfo.
paymentAttemptInfoKey -> the payment's AttemptInfo.
paymentSettleInfoKey -> the payment's preimage (or zeroes for
non-settled payments)

The CreationInfo is information that is static during the whole payment
lifcycle. The attempt info is set each time a new payment attempt
(route+paymentID) is sent on the network. The preimage is information
only known when a payment succeeds.  It therefore makes sense to split
them.

We keep legacy serialization code for migration puproses.
This commit is contained in:
Johan T. Halseth
2019-05-23 20:05:27 +02:00
parent f022810f8b
commit 178996f0d3
2 changed files with 238 additions and 9 deletions

View File

@@ -10,6 +10,7 @@ import (
"github.com/btcsuite/btcd/btcec"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing/route"
)
@@ -64,6 +65,27 @@ func makeFakePayment() *OutgoingPayment {
return fakePayment
}
func makeFakeInfo() (*PaymentCreationInfo, *PaymentAttemptInfo) {
var preimg lntypes.Preimage
copy(preimg[:], rev[:])
c := &PaymentCreationInfo{
PaymentHash: preimg.Hash(),
Value: 1000,
// Use single second precision to avoid false positive test
// failures due to the monotonic time component.
CreationDate: time.Unix(time.Now().Unix(), 0),
PaymentRequest: []byte(""),
}
a := &PaymentAttemptInfo{
PaymentID: 44,
SessionKey: priv,
Route: testRoute,
}
return c, a
}
func makeFakePaymentHash() [32]byte {
var paymentHash [32]byte
rBytes, _ := randomBytes(0, 32)
@@ -133,28 +155,45 @@ func makeRandomFakePayment() (*OutgoingPayment, error) {
return fakePayment, nil
}
func TestOutgoingPaymentSerialization(t *testing.T) {
func TestSentPaymentSerialization(t *testing.T) {
t.Parallel()
fakePayment := makeFakePayment()
c, s := makeFakeInfo()
var b bytes.Buffer
if err := serializeOutgoingPayment(&b, fakePayment); err != nil {
t.Fatalf("unable to serialize outgoing payment: %v", err)
if err := serializePaymentCreationInfo(&b, c); err != nil {
t.Fatalf("unable to serialize creation info: %v", err)
}
newPayment, err := deserializeOutgoingPayment(&b)
newCreationInfo, err := deserializePaymentCreationInfo(&b)
if err != nil {
t.Fatalf("unable to deserialize outgoing payment: %v", err)
t.Fatalf("unable to deserialize creation info: %v", err)
}
if !reflect.DeepEqual(fakePayment, newPayment) {
if !reflect.DeepEqual(c, newCreationInfo) {
t.Fatalf("Payments do not match after "+
"serialization/deserialization %v vs %v",
spew.Sdump(fakePayment),
spew.Sdump(newPayment),
spew.Sdump(c), spew.Sdump(newCreationInfo),
)
}
b.Reset()
if err := serializePaymentAttemptInfo(&b, s); err != nil {
t.Fatalf("unable to serialize info: %v", err)
}
newAttemptInfo, err := deserializePaymentAttemptInfo(&b)
if err != nil {
t.Fatalf("unable to deserialize info: %v", err)
}
if !reflect.DeepEqual(s, newAttemptInfo) {
t.Fatalf("Payments do not match after "+
"serialization/deserialization %v vs %v",
spew.Sdump(s), spew.Sdump(newAttemptInfo),
)
}
}
func TestOutgoingPaymentWorkflow(t *testing.T) {