lnd/channeldb/reports_test.go
carla 578af99618
channeldb: save resolver outcomes in close summaries top level bucket
Add a new top level bucket which holds closed channels nested by chain
hash which contains additional information about channel closes. We add
resolver resolutions under their own key so that we can extend the
bucket with additional information if required.
2020-07-07 19:49:36 +02:00

219 lines
5.0 KiB
Go

package channeldb
import (
"bytes"
"testing"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/channeldb/kvdb"
"github.com/stretchr/testify/require"
)
var (
testChainHash = [chainhash.HashSize]byte{
0x51, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
0x48, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
0x2d, 0xe7, 0x93, 0xe4,
}
testChanPoint1 = wire.OutPoint{
Hash: chainhash.Hash{
0x51, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
0x48, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
0x2d, 0xe7, 0x93, 0xe4,
},
Index: 1,
}
)
// TestPersistReport tests the writing and retrieval of a report on disk with
// and without a spend txid.
func TestPersistReport(t *testing.T) {
tests := []struct {
name string
spendTxID *chainhash.Hash
}{
{
name: "Non-nil spend txid",
spendTxID: &testChanPoint1.Hash,
},
{
name: "Nil spend txid",
spendTxID: nil,
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
db, cleanup, err := makeTestDB()
require.NoError(t, err)
defer cleanup()
channelOutpoint := testChanPoint1
testOutpoint := testChanPoint1
testOutpoint.Index++
report := &ResolverReport{
OutPoint: testOutpoint,
Amount: 2,
ResolverType: 1,
ResolverOutcome: 2,
SpendTxID: test.spendTxID,
}
// Write report to disk, and ensure it is identical when
// it is read.
err = db.PutResolverReport(
nil, testChainHash, &channelOutpoint, report,
)
require.NoError(t, err)
reports, err := db.FetchChannelReports(
testChainHash, &channelOutpoint,
)
require.NoError(t, err)
require.Equal(t, report, reports[0])
})
}
}
// TestFetchChannelReadBucket tests retrieval of the reports bucket for a
// channel, testing that the appropriate error is returned based on the state
// of the existing bucket.
func TestFetchChannelReadBucket(t *testing.T) {
db, cleanup, err := makeTestDB()
require.NoError(t, err)
defer cleanup()
channelOutpoint := testChanPoint1
testOutpoint := testChanPoint1
testOutpoint.Index++
// If we attempt to get reports when we do not have any present, we
// expect to fail because our chain hash bucket is not present.
_, err = db.FetchChannelReports(
testChainHash, &channelOutpoint,
)
require.Equal(t, ErrNoChainHashBucket, err)
// Finally we write a report to disk and check that we can fetch it.
report := &ResolverReport{
OutPoint: testOutpoint,
Amount: 2,
ResolverOutcome: 1,
ResolverType: 2,
SpendTxID: nil,
}
err = db.PutResolverReport(
nil, testChainHash, &channelOutpoint, report,
)
require.NoError(t, err)
// Now that the channel bucket exists, we expect the channel to be
// successfully fetched, with no reports.
reports, err := db.FetchChannelReports(testChainHash, &testChanPoint1)
require.NoError(t, err)
require.Equal(t, report, reports[0])
}
// TestFetchChannelWriteBucket tests the creation of missing buckets when
// retrieving the reports bucket.
func TestFetchChannelWriteBucket(t *testing.T) {
createReportsBucket := func(tx kvdb.RwTx) (kvdb.RwBucket, error) {
return tx.CreateTopLevelBucket(closedChannelBucket)
}
createChainHashBucket := func(reports kvdb.RwBucket) (kvdb.RwBucket,
error) {
return reports.CreateBucketIfNotExists(testChainHash[:])
}
createChannelBucket := func(chainHash kvdb.RwBucket) (kvdb.RwBucket,
error) {
var chanPointBuf bytes.Buffer
err := writeOutpoint(&chanPointBuf, &testChanPoint1)
require.NoError(t, err)
return chainHash.CreateBucketIfNotExists(chanPointBuf.Bytes())
}
tests := []struct {
name string
setup func(tx kvdb.RwTx) error
}{
{
name: "no existing buckets",
setup: func(tx kvdb.RwTx) error {
return nil
},
},
{
name: "reports bucket exists",
setup: func(tx kvdb.RwTx) error {
_, err := createReportsBucket(tx)
return err
},
},
{
name: "chainhash bucket exists",
setup: func(tx kvdb.RwTx) error {
reports, err := createReportsBucket(tx)
if err != nil {
return err
}
_, err = createChainHashBucket(reports)
return err
},
},
{
name: "channel bucket exists",
setup: func(tx kvdb.RwTx) error {
reports, err := createReportsBucket(tx)
if err != nil {
return err
}
chainHash, err := createChainHashBucket(reports)
if err != nil {
return err
}
_, err = createChannelBucket(chainHash)
return err
},
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
db, cleanup, err := makeTestDB()
require.NoError(t, err)
defer cleanup()
// Update our db to the starting state we expect.
err = kvdb.Update(db, test.setup)
require.NoError(t, err)
// Try to get our report bucket.
err = kvdb.Update(db, func(tx kvdb.RwTx) error {
_, err := fetchReportWriteBucket(
tx, testChainHash, &testChanPoint1,
)
return err
})
require.NoError(t, err)
})
}
}