package sweep import ( "bytes" "testing" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/kvdb" "github.com/stretchr/testify/require" ) // TestStore asserts that the store persists the presented data to disk and is // able to retrieve it again. func TestStore(t *testing.T) { // Create new store. cdb, err := channeldb.MakeTestDB(t) require.NoError(t, err) var chain chainhash.Hash store, err := NewSweeperStore(cdb, &chain) require.NoError(t, err) // Notify publication of tx1 tx1 := wire.MsgTx{} tx1.AddTxIn(&wire.TxIn{ PreviousOutPoint: wire.OutPoint{ Index: 1, }, }) tr1 := &TxRecord{ Txid: tx1.TxHash(), } err = store.StoreTx(tr1) require.NoError(t, err) // Notify publication of tx2 tx2 := wire.MsgTx{} tx2.AddTxIn(&wire.TxIn{ PreviousOutPoint: wire.OutPoint{ Index: 2, }, }) tr2 := &TxRecord{ Txid: tx2.TxHash(), } err = store.StoreTx(tr2) require.NoError(t, err) // Recreate the sweeper store store, err = NewSweeperStore(cdb, &chain) require.NoError(t, err) // Assert that both txes are recognized as our own. ours, err := store.IsOurTx(tx1.TxHash()) require.NoError(t, err) require.True(t, ours, "expected tx to be ours") ours, err = store.IsOurTx(tx2.TxHash()) require.NoError(t, err) require.True(t, ours, "expected tx to be ours") // An different hash should be reported as not being ours. var unknownHash chainhash.Hash ours, err = store.IsOurTx(unknownHash) require.NoError(t, err) require.False(t, ours, "expected tx to not be ours") txns, err := store.ListSweeps() require.NoError(t, err, "unexpected error") // Create a map containing the sweeps we expect to be returned by list // sweeps. expected := map[chainhash.Hash]bool{ tx1.TxHash(): true, tx2.TxHash(): true, } require.Len(t, txns, len(expected)) for _, tx := range txns { _, ok := expected[tx] require.Truef(t, ok, "unexpected txid returned: %v", tx) } } // TestTxRecord asserts that the serializeTxRecord and deserializeTxRecord // behave as expected. func TestTxRecord(t *testing.T) { t.Parallel() // Create a testing record. // // NOTE: Txid is omitted because it is not serialized. tr := &TxRecord{ FeeRate: 1000, Fee: 10000, Published: true, } var b bytes.Buffer // Assert we can serialize the record. err := serializeTxRecord(&b, tr) require.NoError(t, err) // Assert we can deserialize the record. result, err := deserializeTxRecord(&b) require.NoError(t, err) // Assert the deserialized record is equal to the original. require.Equal(t, tr, result) } // TestGetTx asserts that the GetTx method behaves as expected. func TestGetTx(t *testing.T) { t.Parallel() cdb, err := channeldb.MakeTestDB(t) require.NoError(t, err) // Create a testing store. chain := chainhash.Hash{} store, err := NewSweeperStore(cdb, &chain) require.NoError(t, err) // Create a testing record. txid := chainhash.Hash{1, 2, 3} tr := &TxRecord{ Txid: txid, FeeRate: 1000, Fee: 10000, Published: true, } // Assert we can store this tx record. err = store.StoreTx(tr) require.NoError(t, err) // Assert we can query the tx record. result, err := store.GetTx(txid) require.NoError(t, err) require.Equal(t, tr, result) // Assert we get an error when querying a non-existing tx. _, err = store.GetTx(chainhash.Hash{4, 5, 6}) require.ErrorIs(t, ErrTxNotFound, err) } // TestGetTxCompatible asserts that when there's old tx record data in the // database it can be successfully queried. func TestGetTxCompatible(t *testing.T) { t.Parallel() cdb, err := channeldb.MakeTestDB(t) require.NoError(t, err) // Create a testing store. chain := chainhash.Hash{} store, err := NewSweeperStore(cdb, &chain) require.NoError(t, err) // Create a testing txid. txid := chainhash.Hash{0, 1, 2, 3} // Create a record using the old format "hash -> empty byte slice". err = kvdb.Update(cdb, func(tx kvdb.RwTx) error { txHashesBucket := tx.ReadWriteBucket(txHashesBucketKey) return txHashesBucket.Put(txid[:], []byte{}) }, func() {}) require.NoError(t, err) // Assert we can query the tx record. result, err := store.GetTx(txid) require.NoError(t, err) require.Equal(t, txid, result.Txid) // Assert the Published field is true. require.True(t, result.Published) } // TestDeleteTx asserts that the DeleteTx method behaves as expected. func TestDeleteTx(t *testing.T) { t.Parallel() cdb, err := channeldb.MakeTestDB(t) require.NoError(t, err) // Create a testing store. chain := chainhash.Hash{} store, err := NewSweeperStore(cdb, &chain) require.NoError(t, err) // Create a testing record. txid := chainhash.Hash{1, 2, 3} tr := &TxRecord{ Txid: txid, FeeRate: 1000, Fee: 10000, Published: true, } // Assert we can store this tx record. err = store.StoreTx(tr) require.NoError(t, err) // Assert we can delete the tx record. err = store.DeleteTx(txid) require.NoError(t, err) // Query it again should give us an error. _, err = store.GetTx(txid) require.ErrorIs(t, ErrTxNotFound, err) // Assert deleting a non-existing tx doesn't return an error. err = store.DeleteTx(chainhash.Hash{4, 5, 6}) require.NoError(t, err) }