d89f51d1d0
Similarly as with kvdb.View this commits adds a reset closure to the kvdb.Update call in order to be able to reset external state if the underlying db backend needs to retry the transaction.
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, func() {})
|
|
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
|
|
}, func() {})
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
}
|