lnd/chainntnfs/best_block_view_test.go
Keagan McClelland 405d4e5f73 chainntnfs: introduce system for chain state tracking and querying
This change adds a new subsystem that is responsible for providing
an up to date view of some global chainstate parameters.
2023-10-19 09:22:07 -07:00

113 lines
3.0 KiB
Go

package chainntnfs_test
import (
"math/rand"
"reflect"
"testing"
"testing/quick"
"time"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/lntest/mock"
"github.com/lightningnetwork/lnd/lntest/wait"
"github.com/stretchr/testify/require"
)
type blockEpoch chainntnfs.BlockEpoch
func (blockEpoch) Generate(r *rand.Rand, size int) reflect.Value {
var chainHash, prevBlockHash, merkleRootHash chainhash.Hash
r.Read(chainHash[:])
r.Read(prevBlockHash[:])
r.Read(merkleRootHash[:])
return reflect.ValueOf(blockEpoch(chainntnfs.BlockEpoch{
Hash: &chainHash,
Height: r.Int31n(1000000),
BlockHeader: &wire.BlockHeader{
Version: 2,
PrevBlock: prevBlockHash,
MerkleRoot: merkleRootHash,
Timestamp: time.Now(),
Bits: r.Uint32(),
Nonce: r.Uint32(),
},
}))
}
// TestBestBlockTracker ensures that the most recent event pushed on the
// underlying EpochChan is remembered by the BestBlockView functions as well
// as testing the idempotence of the BestBlockView interface.
func TestBestBlockTracker(t *testing.T) {
t.Parallel()
notifier := &mock.ChainNotifier{
SpendChan: nil,
EpochChan: make(chan *chainntnfs.BlockEpoch),
ConfChan: nil,
}
chainNotifierI := chainntnfs.ChainNotifier(notifier)
tracker := chainntnfs.NewBestBlockTracker(chainNotifierI)
require.Nil(t, tracker.Start(),
"BestBlockTacker could not be started")
// we have to limit test cases because the poll interval of
// wait.Predicate isn't tight enough to support the usual 100
cfg := quick.Config{MaxCount: 50}
correctness := func(epochRand blockEpoch) bool {
epoch := chainntnfs.BlockEpoch(epochRand)
notifier.EpochChan <- &epoch
// wait for new block to propagate
err := wait.Predicate(
func() bool {
_, err := tracker.BestHeight()
return err == nil
},
1*time.Second,
)
require.Nil(t, err,
"BestBlockTracker: block propagation timeout")
height, _ := tracker.BestHeight()
header, _ := tracker.BestBlockHeader()
return height == uint32(epoch.Height) &&
header == epoch.BlockHeader
}
idempotence := func(epochRand blockEpoch) bool {
epoch := chainntnfs.BlockEpoch(epochRand)
notifier.EpochChan <- &epoch
// wait for new block to propagate
err := wait.Predicate(
func() bool {
_, err := tracker.BestHeight()
return err == nil
},
1*time.Second,
)
require.Nil(t, err,
"ChainStateTracker: block propagation timeout")
height0, _ := tracker.BestHeight()
height1, _ := tracker.BestHeight()
header0, _ := tracker.BestBlockHeader()
header1, _ := tracker.BestBlockHeader()
return height0 == height1 && header0 == header1
}
err := quick.Check(correctness, &cfg)
require.Nil(t, err,
"ChainStateTracker does not give up to date info: %v", err)
require.Nil(t, quick.Check(idempotence, &cfg),
"ChainStateTracker is not idempotent")
require.Nil(t, tracker.Stop(), "ChainStateTracker could not be stopped")
}