2022-02-11 19:37:56 +01:00
|
|
|
package htlcswitch
|
|
|
|
|
|
|
|
import (
|
|
|
|
"path/filepath"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/lightningnetwork/lnd/contractcourt"
|
|
|
|
"github.com/lightningnetwork/lnd/kvdb"
|
|
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
// TestInsertAndDelete tests that an inserted resolution message can be
|
|
|
|
// deleted.
|
|
|
|
func TestInsertAndDelete(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
scid := lnwire.NewShortChanIDFromInt(1)
|
|
|
|
|
|
|
|
failResMsg := &contractcourt.ResolutionMsg{
|
|
|
|
SourceChan: scid,
|
|
|
|
HtlcIndex: 2,
|
|
|
|
Failure: &lnwire.FailTemporaryChannelFailure{},
|
|
|
|
}
|
|
|
|
|
|
|
|
settleBytes := [32]byte{
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
|
|
|
}
|
|
|
|
|
|
|
|
settleResMsg := &contractcourt.ResolutionMsg{
|
|
|
|
SourceChan: scid,
|
|
|
|
HtlcIndex: 3,
|
|
|
|
PreImage: &settleBytes,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the backend database and use it to create the resolution
|
|
|
|
// store.
|
2022-08-15 15:06:21 +02:00
|
|
|
dbPath := filepath.Join(t.TempDir(), "testdb")
|
2022-02-11 19:37:56 +01:00
|
|
|
db, err := kvdb.Create(
|
|
|
|
kvdb.BoltBackendName, dbPath, true, kvdb.DefaultDBTimeout,
|
|
|
|
)
|
|
|
|
require.NoError(t, err)
|
2022-08-15 15:06:21 +02:00
|
|
|
t.Cleanup(func() {
|
2022-02-11 19:37:56 +01:00
|
|
|
db.Close()
|
2022-08-15 15:06:21 +02:00
|
|
|
})
|
2022-02-11 19:37:56 +01:00
|
|
|
|
|
|
|
resStore := newResolutionStore(db)
|
|
|
|
|
|
|
|
// We'll add the failure resolution message first, then check that it
|
|
|
|
// exists in the store.
|
|
|
|
err = resStore.addResolutionMsg(failResMsg)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Assert that checkResolutionMsg returns nil, signalling that the
|
|
|
|
// resolution message was properly stored.
|
|
|
|
outKey := &CircuitKey{
|
|
|
|
ChanID: failResMsg.SourceChan,
|
|
|
|
HtlcID: failResMsg.HtlcIndex,
|
|
|
|
}
|
|
|
|
err = resStore.checkResolutionMsg(outKey)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
resMsgs, err := resStore.fetchAllResolutionMsg()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(resMsgs))
|
|
|
|
|
|
|
|
// It should match failResMsg above.
|
|
|
|
require.Equal(t, failResMsg.SourceChan, resMsgs[0].SourceChan)
|
|
|
|
require.Equal(t, failResMsg.HtlcIndex, resMsgs[0].HtlcIndex)
|
|
|
|
require.NotNil(t, resMsgs[0].Failure)
|
|
|
|
require.Nil(t, resMsgs[0].PreImage)
|
|
|
|
|
|
|
|
// We'll add the settleResMsg now.
|
|
|
|
err = resStore.addResolutionMsg(settleResMsg)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Check that checkResolutionMsg returns nil for the settle CircuitKey.
|
|
|
|
outKey.ChanID = settleResMsg.SourceChan
|
|
|
|
outKey.HtlcID = settleResMsg.HtlcIndex
|
|
|
|
err = resStore.checkResolutionMsg(outKey)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// We should have two resolution messages in the store, one failure and
|
|
|
|
// one success.
|
|
|
|
resMsgs, err = resStore.fetchAllResolutionMsg()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 2, len(resMsgs))
|
|
|
|
|
|
|
|
// The first resolution message should be the failure.
|
|
|
|
require.Equal(t, failResMsg.SourceChan, resMsgs[0].SourceChan)
|
|
|
|
require.Equal(t, failResMsg.HtlcIndex, resMsgs[0].HtlcIndex)
|
|
|
|
require.NotNil(t, resMsgs[0].Failure)
|
|
|
|
require.Nil(t, resMsgs[0].PreImage)
|
|
|
|
|
|
|
|
// The second resolution message should be the success.
|
|
|
|
require.Equal(t, settleResMsg.SourceChan, resMsgs[1].SourceChan)
|
|
|
|
require.Equal(t, settleResMsg.HtlcIndex, resMsgs[1].HtlcIndex)
|
|
|
|
require.Nil(t, resMsgs[1].Failure)
|
|
|
|
require.Equal(t, settleBytes, *resMsgs[1].PreImage)
|
|
|
|
|
|
|
|
// We'll now delete the failure resolution message and assert that only
|
|
|
|
// the success is left.
|
|
|
|
failKey := &CircuitKey{
|
|
|
|
ChanID: scid,
|
|
|
|
HtlcID: failResMsg.HtlcIndex,
|
|
|
|
}
|
|
|
|
|
|
|
|
err = resStore.deleteResolutionMsg(failKey)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Assert that checkResolutionMsg returns errResMsgNotFound.
|
|
|
|
err = resStore.checkResolutionMsg(failKey)
|
|
|
|
require.ErrorIs(t, err, errResMsgNotFound)
|
|
|
|
|
|
|
|
resMsgs, err = resStore.fetchAllResolutionMsg()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(resMsgs))
|
|
|
|
|
|
|
|
// Assert that the success is left.
|
|
|
|
require.Equal(t, settleResMsg.SourceChan, resMsgs[0].SourceChan)
|
|
|
|
require.Equal(t, settleResMsg.HtlcIndex, resMsgs[0].HtlcIndex)
|
|
|
|
require.Nil(t, resMsgs[0].Failure)
|
|
|
|
require.Equal(t, settleBytes, *resMsgs[0].PreImage)
|
|
|
|
|
|
|
|
// Now we'll delete the settle resolution message and assert that the
|
|
|
|
// store is empty.
|
|
|
|
settleKey := &CircuitKey{
|
|
|
|
ChanID: scid,
|
|
|
|
HtlcID: settleResMsg.HtlcIndex,
|
|
|
|
}
|
|
|
|
|
|
|
|
err = resStore.deleteResolutionMsg(settleKey)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Assert that checkResolutionMsg returns errResMsgNotFound for the
|
|
|
|
// settle key.
|
|
|
|
err = resStore.checkResolutionMsg(settleKey)
|
|
|
|
require.ErrorIs(t, err, errResMsgNotFound)
|
|
|
|
|
|
|
|
resMsgs, err = resStore.fetchAllResolutionMsg()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 0, len(resMsgs))
|
|
|
|
}
|