578af99618
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.
219 lines
5.0 KiB
Go
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)
|
|
})
|
|
}
|
|
}
|