mirror of
https://github.com/lightninglabs/loop
synced 2024-11-08 01:10:29 +00:00
6a0a9556a0
This commit adds the required code to persist loop in swaps. It also introduces the file loop.go to which shared code is moved. Sharing of contract serialization/deserialization code has been reverted. The prepay fields do not apply to loop in, but were part of the shared contract struct. Without also adding a migration, it wouldn't be possible to keep the shared code. In general it is probably more flexible to keep the contract serialization code separated between in and out swaps.
283 lines
6.8 KiB
Go
283 lines
6.8 KiB
Go
package loopdb
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"io/ioutil"
|
|
"os"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/btcsuite/btcd/chaincfg"
|
|
"github.com/lightninglabs/loop/test"
|
|
"github.com/lightningnetwork/lnd/lntypes"
|
|
)
|
|
|
|
var (
|
|
senderKey = [33]byte{
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
|
|
}
|
|
|
|
receiverKey = [33]byte{
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3,
|
|
}
|
|
|
|
testPreimage = lntypes.Preimage([32]byte{
|
|
1, 1, 1, 1, 2, 2, 2, 2,
|
|
3, 3, 3, 3, 4, 4, 4, 4,
|
|
1, 1, 1, 1, 2, 2, 2, 2,
|
|
3, 3, 3, 3, 4, 4, 4, 4,
|
|
})
|
|
|
|
testTime = time.Date(2018, time.January, 9, 14, 00, 00, 0, time.UTC)
|
|
)
|
|
|
|
// TestLoopOutStore tests all the basic functionality of the current bbolt
|
|
// swap store.
|
|
func TestLoopOutStore(t *testing.T) {
|
|
tempDirName, err := ioutil.TempDir("", "clientstore")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(tempDirName)
|
|
|
|
store, err := NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// First, verify that an empty database has no active swaps.
|
|
swaps, err := store.FetchLoopOutSwaps()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(swaps) != 0 {
|
|
t.Fatal("expected empty store")
|
|
}
|
|
|
|
destAddr := test.GetDestAddr(t, 0)
|
|
hash := sha256.Sum256(testPreimage[:])
|
|
initiationTime := time.Date(2018, 11, 1, 0, 0, 0, 0, time.UTC)
|
|
|
|
// Next, we'll make a new pending swap that we'll insert into the
|
|
// database shortly.
|
|
pendingSwap := LoopOutContract{
|
|
SwapContract: SwapContract{
|
|
AmountRequested: 100,
|
|
Preimage: testPreimage,
|
|
CltvExpiry: 144,
|
|
SenderKey: senderKey,
|
|
|
|
ReceiverKey: receiverKey,
|
|
MaxMinerFee: 10,
|
|
MaxSwapFee: 20,
|
|
|
|
InitiationHeight: 99,
|
|
|
|
// Convert to/from unix to remove timezone, so that it
|
|
// doesn't interfere with DeepEqual.
|
|
InitiationTime: time.Unix(0, initiationTime.UnixNano()),
|
|
},
|
|
MaxPrepayRoutingFee: 40,
|
|
PrepayInvoice: "prepayinvoice",
|
|
DestAddr: destAddr,
|
|
SwapInvoice: "swapinvoice",
|
|
MaxSwapRoutingFee: 30,
|
|
SweepConfTarget: 2,
|
|
}
|
|
|
|
// checkSwap is a test helper function that'll assert the state of a
|
|
// swap.
|
|
checkSwap := func(expectedState SwapState) {
|
|
t.Helper()
|
|
|
|
swaps, err := store.FetchLoopOutSwaps()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(swaps) != 1 {
|
|
t.Fatal("expected pending swap in store")
|
|
}
|
|
|
|
swap := swaps[0].Contract
|
|
if !reflect.DeepEqual(swap, &pendingSwap) {
|
|
t.Fatal("invalid pending swap data")
|
|
}
|
|
|
|
if swaps[0].State() != expectedState {
|
|
t.Fatalf("expected state %v, but got %v",
|
|
expectedState, swaps[0].State(),
|
|
)
|
|
}
|
|
}
|
|
|
|
// If we create a new swap, then it should show up as being initialized
|
|
// right after.
|
|
if err := store.CreateLoopOut(hash, &pendingSwap); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
checkSwap(StateInitiated)
|
|
|
|
// Trying to make the same swap again should result in an error.
|
|
if err := store.CreateLoopOut(hash, &pendingSwap); err == nil {
|
|
t.Fatal("expected error on storing duplicate")
|
|
}
|
|
checkSwap(StateInitiated)
|
|
|
|
// Next, we'll update to the next state of the pre-image being
|
|
// revealed. The state should be reflected here again.
|
|
err = store.UpdateLoopOut(
|
|
hash, testTime, StatePreimageRevealed,
|
|
)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
checkSwap(StatePreimageRevealed)
|
|
|
|
// Next, we'll update to the final state to ensure that the state is
|
|
// properly updated.
|
|
err = store.UpdateLoopOut(
|
|
hash, testTime, StateFailInsufficientValue,
|
|
)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
checkSwap(StateFailInsufficientValue)
|
|
|
|
if err := store.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// If we re-open the same store, then the state of the current swap
|
|
// should be the same.
|
|
store, err = NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
checkSwap(StateFailInsufficientValue)
|
|
}
|
|
|
|
// TestLoopInStore tests all the basic functionality of the current bbolt
|
|
// swap store.
|
|
func TestLoopInStore(t *testing.T) {
|
|
tempDirName, err := ioutil.TempDir("", "clientstore")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(tempDirName)
|
|
|
|
store, err := NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// First, verify that an empty database has no active swaps.
|
|
swaps, err := store.FetchLoopInSwaps()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(swaps) != 0 {
|
|
t.Fatal("expected empty store")
|
|
}
|
|
|
|
hash := sha256.Sum256(testPreimage[:])
|
|
initiationTime := time.Date(2018, 11, 1, 0, 0, 0, 0, time.UTC)
|
|
|
|
// Next, we'll make a new pending swap that we'll insert into the
|
|
// database shortly.
|
|
loopInChannel := uint64(123)
|
|
|
|
pendingSwap := LoopInContract{
|
|
SwapContract: SwapContract{
|
|
AmountRequested: 100,
|
|
Preimage: testPreimage,
|
|
CltvExpiry: 144,
|
|
SenderKey: senderKey,
|
|
ReceiverKey: receiverKey,
|
|
MaxMinerFee: 10,
|
|
MaxSwapFee: 20,
|
|
InitiationHeight: 99,
|
|
|
|
// Convert to/from unix to remove timezone, so that it
|
|
// doesn't interfere with DeepEqual.
|
|
InitiationTime: time.Unix(0, initiationTime.UnixNano()),
|
|
},
|
|
HtlcConfTarget: 2,
|
|
LoopInChannel: &loopInChannel,
|
|
}
|
|
|
|
// checkSwap is a test helper function that'll assert the state of a
|
|
// swap.
|
|
checkSwap := func(expectedState SwapState) {
|
|
t.Helper()
|
|
|
|
swaps, err := store.FetchLoopInSwaps()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(swaps) != 1 {
|
|
t.Fatal("expected pending swap in store")
|
|
}
|
|
|
|
swap := swaps[0].Contract
|
|
if !reflect.DeepEqual(swap, &pendingSwap) {
|
|
t.Fatal("invalid pending swap data")
|
|
}
|
|
|
|
if swaps[0].State() != expectedState {
|
|
t.Fatalf("expected state %v, but got %v",
|
|
expectedState, swaps[0].State(),
|
|
)
|
|
}
|
|
}
|
|
|
|
// If we create a new swap, then it should show up as being initialized
|
|
// right after.
|
|
if err := store.CreateLoopIn(hash, &pendingSwap); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
checkSwap(StateInitiated)
|
|
|
|
// Trying to make the same swap again should result in an error.
|
|
if err := store.CreateLoopIn(hash, &pendingSwap); err == nil {
|
|
t.Fatal("expected error on storing duplicate")
|
|
}
|
|
checkSwap(StateInitiated)
|
|
|
|
// Next, we'll update to the next state of the pre-image being
|
|
// revealed. The state should be reflected here again.
|
|
err = store.UpdateLoopIn(
|
|
hash, testTime, StatePreimageRevealed,
|
|
)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
checkSwap(StatePreimageRevealed)
|
|
|
|
// Next, we'll update to the final state to ensure that the state is
|
|
// properly updated.
|
|
err = store.UpdateLoopIn(
|
|
hash, testTime, StateFailInsufficientValue,
|
|
)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
checkSwap(StateFailInsufficientValue)
|
|
|
|
if err := store.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// If we re-open the same store, then the state of the current swap
|
|
// should be the same.
|
|
store, err = NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
checkSwap(StateFailInsufficientValue)
|
|
}
|