/ htlcswitch / resolution_store_test.go
resolution_store_test.go
  1  package htlcswitch
  2  
  3  import (
  4  	"path/filepath"
  5  	"testing"
  6  
  7  	"github.com/lightningnetwork/lnd/contractcourt"
  8  	"github.com/lightningnetwork/lnd/kvdb"
  9  	"github.com/lightningnetwork/lnd/lnwire"
 10  	"github.com/stretchr/testify/require"
 11  )
 12  
 13  // TestInsertAndDelete tests that an inserted resolution message can be
 14  // deleted.
 15  func TestInsertAndDelete(t *testing.T) {
 16  	t.Parallel()
 17  
 18  	scid := lnwire.NewShortChanIDFromInt(1)
 19  
 20  	failResMsg := &contractcourt.ResolutionMsg{
 21  		SourceChan: scid,
 22  		HtlcIndex:  2,
 23  		Failure:    &lnwire.FailTemporaryChannelFailure{},
 24  	}
 25  
 26  	settleBytes := [32]byte{
 27  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 28  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 29  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 30  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
 31  	}
 32  
 33  	settleResMsg := &contractcourt.ResolutionMsg{
 34  		SourceChan: scid,
 35  		HtlcIndex:  3,
 36  		PreImage:   &settleBytes,
 37  	}
 38  
 39  	// Create the backend database and use it to create the resolution
 40  	// store.
 41  	dbPath := filepath.Join(t.TempDir(), "testdb")
 42  	db, err := kvdb.Create(
 43  		kvdb.BoltBackendName, dbPath, true, kvdb.DefaultDBTimeout,
 44  		false,
 45  	)
 46  	require.NoError(t, err)
 47  	t.Cleanup(func() {
 48  		db.Close()
 49  	})
 50  
 51  	resStore := newResolutionStore(db)
 52  
 53  	// We'll add the failure resolution message first, then check that it
 54  	// exists in the store.
 55  	err = resStore.addResolutionMsg(failResMsg)
 56  	require.NoError(t, err)
 57  
 58  	// Assert that checkResolutionMsg returns nil, signalling that the
 59  	// resolution message was properly stored.
 60  	outKey := &CircuitKey{
 61  		ChanID: failResMsg.SourceChan,
 62  		HtlcID: failResMsg.HtlcIndex,
 63  	}
 64  	err = resStore.checkResolutionMsg(outKey)
 65  	require.NoError(t, err)
 66  
 67  	resMsgs, err := resStore.fetchAllResolutionMsg()
 68  	require.NoError(t, err)
 69  	require.Equal(t, 1, len(resMsgs))
 70  
 71  	// It should match failResMsg above.
 72  	require.Equal(t, failResMsg.SourceChan, resMsgs[0].SourceChan)
 73  	require.Equal(t, failResMsg.HtlcIndex, resMsgs[0].HtlcIndex)
 74  	require.NotNil(t, resMsgs[0].Failure)
 75  	require.Nil(t, resMsgs[0].PreImage)
 76  
 77  	// We'll add the settleResMsg now.
 78  	err = resStore.addResolutionMsg(settleResMsg)
 79  	require.NoError(t, err)
 80  
 81  	// Check that checkResolutionMsg returns nil for the settle CircuitKey.
 82  	outKey.ChanID = settleResMsg.SourceChan
 83  	outKey.HtlcID = settleResMsg.HtlcIndex
 84  	err = resStore.checkResolutionMsg(outKey)
 85  	require.NoError(t, err)
 86  
 87  	// We should have two resolution messages in the store, one failure and
 88  	// one success.
 89  	resMsgs, err = resStore.fetchAllResolutionMsg()
 90  	require.NoError(t, err)
 91  	require.Equal(t, 2, len(resMsgs))
 92  
 93  	// The first resolution message should be the failure.
 94  	require.Equal(t, failResMsg.SourceChan, resMsgs[0].SourceChan)
 95  	require.Equal(t, failResMsg.HtlcIndex, resMsgs[0].HtlcIndex)
 96  	require.NotNil(t, resMsgs[0].Failure)
 97  	require.Nil(t, resMsgs[0].PreImage)
 98  
 99  	// The second resolution message should be the success.
100  	require.Equal(t, settleResMsg.SourceChan, resMsgs[1].SourceChan)
101  	require.Equal(t, settleResMsg.HtlcIndex, resMsgs[1].HtlcIndex)
102  	require.Nil(t, resMsgs[1].Failure)
103  	require.Equal(t, settleBytes, *resMsgs[1].PreImage)
104  
105  	// We'll now delete the failure resolution message and assert that only
106  	// the success is left.
107  	failKey := &CircuitKey{
108  		ChanID: scid,
109  		HtlcID: failResMsg.HtlcIndex,
110  	}
111  
112  	err = resStore.deleteResolutionMsg(failKey)
113  	require.NoError(t, err)
114  
115  	// Assert that checkResolutionMsg returns errResMsgNotFound.
116  	err = resStore.checkResolutionMsg(failKey)
117  	require.ErrorIs(t, err, errResMsgNotFound)
118  
119  	resMsgs, err = resStore.fetchAllResolutionMsg()
120  	require.NoError(t, err)
121  	require.Equal(t, 1, len(resMsgs))
122  
123  	// Assert that the success is left.
124  	require.Equal(t, settleResMsg.SourceChan, resMsgs[0].SourceChan)
125  	require.Equal(t, settleResMsg.HtlcIndex, resMsgs[0].HtlcIndex)
126  	require.Nil(t, resMsgs[0].Failure)
127  	require.Equal(t, settleBytes, *resMsgs[0].PreImage)
128  
129  	// Now we'll delete the settle resolution message and assert that the
130  	// store is empty.
131  	settleKey := &CircuitKey{
132  		ChanID: scid,
133  		HtlcID: settleResMsg.HtlcIndex,
134  	}
135  
136  	err = resStore.deleteResolutionMsg(settleKey)
137  	require.NoError(t, err)
138  
139  	// Assert that checkResolutionMsg returns errResMsgNotFound for the
140  	// settle key.
141  	err = resStore.checkResolutionMsg(settleKey)
142  	require.ErrorIs(t, err, errResMsgNotFound)
143  
144  	resMsgs, err = resStore.fetchAllResolutionMsg()
145  	require.NoError(t, err)
146  	require.Equal(t, 0, len(resMsgs))
147  }