Skip to content

Commit 39241f9

Browse files
committed
contractcourt: track best block height in chain arbitrator
This commit adds tracking of our best block height to the chain arbitrator, relying on our existing block dispatch goroutine to update this value. This change decreases the number of times we need to call GetBestBlock from once per channel, to a single call on startup. This call is pretty slow in bitcoind (up to 5 minutes sometimes, screm), and can slow down channel opening, so we move towards less reliance on it.
1 parent db5af6f commit 39241f9

File tree

3 files changed

+73
-26
lines changed

3 files changed

+73
-26
lines changed

contractcourt/chain_arbitrator.go

+53-2
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,14 @@ type ChainArbitrator struct {
204204
// active channels that it must still watch over.
205205
chanSource *channeldb.DB
206206

207+
// bestBlockHeight is the best block height that we currently have
208+
// knowledge of.
209+
bestBlock int32
210+
211+
// bestBlockLock is a lock used for getting and setting the value of
212+
// bestBlockHeight.
213+
bestBlockLock sync.Mutex
214+
207215
quit chan struct{}
208216

209217
wg sync.WaitGroup
@@ -643,6 +651,13 @@ func (c *ChainArbitrator) Start() error {
643651
return err
644652
}
645653

654+
// Lookup our best height once so that we can start each arbitrator
655+
// off with a height hint.
656+
bestHeight, err := c.getBestBlock()
657+
if err != nil {
658+
return err
659+
}
660+
646661
// Launch all the goroutines for each arbitrator so they can carry out
647662
// their duties.
648663
for _, arbitrator := range c.activeChannels {
@@ -653,7 +668,7 @@ func (c *ChainArbitrator) Start() error {
653668
arbitrator.cfg.ChanPoint)
654669
}
655670

656-
if err := arbitrator.Start(startState); err != nil {
671+
if err := arbitrator.Start(startState, bestHeight); err != nil {
657672
stopAndLog()
658673
return err
659674
}
@@ -678,6 +693,34 @@ func (c *ChainArbitrator) Start() error {
678693
return nil
679694
}
680695

696+
// getBestBlock gets the best block height that the arbitrator has knowledge of
697+
// querying our chain backend directly if this value is not yet set.
698+
func (c *ChainArbitrator) getBestBlock() (int32, error) {
699+
c.bestBlockLock.Lock()
700+
height := c.bestBlock
701+
c.bestBlockLock.Unlock()
702+
703+
if height != 0 {
704+
return height, nil
705+
}
706+
707+
_, height, err := c.cfg.ChainIO.GetBestBlock()
708+
if err != nil {
709+
return 0, err
710+
}
711+
712+
c.setBestBlock(height)
713+
return height, nil
714+
}
715+
716+
// setBestBlock updates the arbitrator's best block height.
717+
func (c *ChainArbitrator) setBestBlock(height int32) {
718+
c.bestBlockLock.Lock()
719+
defer c.bestBlockLock.Unlock()
720+
721+
c.bestBlock = height
722+
}
723+
681724
// blockRecipient contains the information we need to dispatch a block to a
682725
// channel arbitrator.
683726
type blockRecipient struct {
@@ -739,6 +782,9 @@ func (c *ChainArbitrator) dispatchBlocks(
739782
return
740783
}
741784

785+
// Update our best block height.
786+
c.setBestBlock(block.Height)
787+
742788
// Get the set of currently active channels block
743789
// subscription channels and dispatch the block to
744790
// each.
@@ -1103,7 +1149,12 @@ func (c *ChainArbitrator) WatchNewChannel(newChan *channeldb.OpenChannel) error
11031149
// arbitrators, then launch it.
11041150
c.activeChannels[chanPoint] = channelArb
11051151

1106-
if err := channelArb.Start(nil); err != nil {
1152+
height, err := c.getBestBlock()
1153+
if err != nil {
1154+
return err
1155+
}
1156+
1157+
if err := channelArb.Start(nil, height); err != nil {
11071158
return err
11081159
}
11091160

contractcourt/channel_arbitrator.go

+3-7
Original file line numberDiff line numberDiff line change
@@ -416,8 +416,9 @@ func (c *ChannelArbitrator) getStartState(tx kvdb.RTx) (*chanArbStartState,
416416

417417
// Start starts all the goroutines that the ChannelArbitrator needs to operate.
418418
// If takes a start state, which will be looked up on disk if it is not
419-
// provided.
420-
func (c *ChannelArbitrator) Start(state *chanArbStartState) error {
419+
// provided, and the height of our current best block.
420+
func (c *ChannelArbitrator) Start(state *chanArbStartState,
421+
bestHeight int32) error {
421422
if !atomic.CompareAndSwapInt32(&c.started, 0, 1) {
422423
return nil
423424
}
@@ -441,11 +442,6 @@ func (c *ChannelArbitrator) Start(state *chanArbStartState) error {
441442
// Set our state from our starting state.
442443
c.state = state.currentState
443444

444-
_, bestHeight, err := c.cfg.ChainIO.GetBestBlock()
445-
if err != nil {
446-
return err
447-
}
448-
449445
// If the channel has been marked pending close in the database, and we
450446
// haven't transitioned the state machine to StateContractClosed (or a
451447
// succeeding state), then a state transition most likely failed. We'll

contractcourt/channel_arbitrator_test.go

+17-17
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ func (c *chanArbTestCtx) Restart(restartClosure func(*chanArbTestCtx)) (*chanArb
275275
restartClosure(newCtx)
276276
}
277277

278-
if err := newCtx.chanArb.Start(nil); err != nil {
278+
if err := newCtx.chanArb.Start(nil, 0); err != nil {
279279
return nil, err
280280
}
281281

@@ -447,7 +447,7 @@ func TestChannelArbitratorCooperativeClose(t *testing.T) {
447447
t.Fatalf("unable to create ChannelArbitrator: %v", err)
448448
}
449449

450-
if err := chanArbCtx.chanArb.Start(nil); err != nil {
450+
if err := chanArbCtx.chanArb.Start(nil, 0); err != nil {
451451
t.Fatalf("unable to start ChannelArbitrator: %v", err)
452452
}
453453
defer func() {
@@ -509,7 +509,7 @@ func TestChannelArbitratorRemoteForceClose(t *testing.T) {
509509
}
510510
chanArb := chanArbCtx.chanArb
511511

512-
if err := chanArb.Start(nil); err != nil {
512+
if err := chanArb.Start(nil, 0); err != nil {
513513
t.Fatalf("unable to start ChannelArbitrator: %v", err)
514514
}
515515
defer chanArb.Stop()
@@ -564,7 +564,7 @@ func TestChannelArbitratorLocalForceClose(t *testing.T) {
564564
}
565565
chanArb := chanArbCtx.chanArb
566566

567-
if err := chanArb.Start(nil); err != nil {
567+
if err := chanArb.Start(nil, 0); err != nil {
568568
t.Fatalf("unable to start ChannelArbitrator: %v", err)
569569
}
570570
defer chanArb.Stop()
@@ -670,7 +670,7 @@ func TestChannelArbitratorBreachClose(t *testing.T) {
670670
}
671671
chanArb := chanArbCtx.chanArb
672672

673-
if err := chanArb.Start(nil); err != nil {
673+
if err := chanArb.Start(nil, 0); err != nil {
674674
t.Fatalf("unable to start ChannelArbitrator: %v", err)
675675
}
676676
defer func() {
@@ -715,7 +715,7 @@ func TestChannelArbitratorLocalForceClosePendingHtlc(t *testing.T) {
715715
chanArb.cfg.PreimageDB = newMockWitnessBeacon()
716716
chanArb.cfg.Registry = &mockRegistry{}
717717

718-
if err := chanArb.Start(nil); err != nil {
718+
if err := chanArb.Start(nil, 0); err != nil {
719719
t.Fatalf("unable to start ChannelArbitrator: %v", err)
720720
}
721721
defer chanArb.Stop()
@@ -987,7 +987,7 @@ func TestChannelArbitratorLocalForceCloseRemoteConfirmed(t *testing.T) {
987987
}
988988
chanArb := chanArbCtx.chanArb
989989

990-
if err := chanArb.Start(nil); err != nil {
990+
if err := chanArb.Start(nil, 0); err != nil {
991991
t.Fatalf("unable to start ChannelArbitrator: %v", err)
992992
}
993993
defer chanArb.Stop()
@@ -1096,7 +1096,7 @@ func TestChannelArbitratorLocalForceDoubleSpend(t *testing.T) {
10961096
}
10971097
chanArb := chanArbCtx.chanArb
10981098

1099-
if err := chanArb.Start(nil); err != nil {
1099+
if err := chanArb.Start(nil, 0); err != nil {
11001100
t.Fatalf("unable to start ChannelArbitrator: %v", err)
11011101
}
11021102
defer chanArb.Stop()
@@ -1204,7 +1204,7 @@ func TestChannelArbitratorPersistence(t *testing.T) {
12041204
}
12051205

12061206
chanArb := chanArbCtx.chanArb
1207-
if err := chanArb.Start(nil); err != nil {
1207+
if err := chanArb.Start(nil, 0); err != nil {
12081208
t.Fatalf("unable to start ChannelArbitrator: %v", err)
12091209
}
12101210

@@ -1328,7 +1328,7 @@ func TestChannelArbitratorForceCloseBreachedChannel(t *testing.T) {
13281328
}
13291329

13301330
chanArb := chanArbCtx.chanArb
1331-
if err := chanArb.Start(nil); err != nil {
1331+
if err := chanArb.Start(nil, 0); err != nil {
13321332
t.Fatalf("unable to start ChannelArbitrator: %v", err)
13331333
}
13341334

@@ -1490,7 +1490,7 @@ func TestChannelArbitratorCommitFailure(t *testing.T) {
14901490
}
14911491

14921492
chanArb := chanArbCtx.chanArb
1493-
if err := chanArb.Start(nil); err != nil {
1493+
if err := chanArb.Start(nil, 0); err != nil {
14941494
t.Fatalf("unable to start ChannelArbitrator: %v", err)
14951495
}
14961496

@@ -1575,7 +1575,7 @@ func TestChannelArbitratorEmptyResolutions(t *testing.T) {
15751575
chanArb.cfg.ClosingHeight = 100
15761576
chanArb.cfg.CloseType = channeldb.RemoteForceClose
15771577

1578-
if err := chanArb.Start(nil); err != nil {
1578+
if err := chanArb.Start(nil, 0); err != nil {
15791579
t.Fatalf("unable to start ChannelArbitrator: %v", err)
15801580
}
15811581

@@ -1607,7 +1607,7 @@ func TestChannelArbitratorAlreadyForceClosed(t *testing.T) {
16071607
t.Fatalf("unable to create ChannelArbitrator: %v", err)
16081608
}
16091609
chanArb := chanArbCtx.chanArb
1610-
if err := chanArb.Start(nil); err != nil {
1610+
if err := chanArb.Start(nil, 0); err != nil {
16111611
t.Fatalf("unable to start ChannelArbitrator: %v", err)
16121612
}
16131613
defer chanArb.Stop()
@@ -1705,7 +1705,7 @@ func TestChannelArbitratorDanglingCommitForceClose(t *testing.T) {
17051705
t.Fatalf("unable to create ChannelArbitrator: %v", err)
17061706
}
17071707
chanArb := chanArbCtx.chanArb
1708-
if err := chanArb.Start(nil); err != nil {
1708+
if err := chanArb.Start(nil, 0); err != nil {
17091709
t.Fatalf("unable to start ChannelArbitrator: %v", err)
17101710
}
17111711
defer chanArb.Stop()
@@ -1896,7 +1896,7 @@ func TestChannelArbitratorPendingExpiredHTLC(t *testing.T) {
18961896
return false
18971897
}
18981898

1899-
if err := chanArb.Start(nil); err != nil {
1899+
if err := chanArb.Start(nil, 0); err != nil {
19001900
t.Fatalf("unable to start ChannelArbitrator: %v", err)
19011901
}
19021902
defer func() {
@@ -2053,7 +2053,7 @@ func TestRemoteCloseInitiator(t *testing.T) {
20532053
}
20542054
chanArb := chanArbCtx.chanArb
20552055

2056-
if err := chanArb.Start(nil); err != nil {
2056+
if err := chanArb.Start(nil, 0); err != nil {
20572057
t.Fatalf("unable to start "+
20582058
"ChannelArbitrator: %v", err)
20592059
}
@@ -2123,7 +2123,7 @@ func TestChannelArbitratorAnchors(t *testing.T) {
21232123
{}, {},
21242124
}
21252125

2126-
if err := chanArb.Start(nil); err != nil {
2126+
if err := chanArb.Start(nil, 0); err != nil {
21272127
t.Fatalf("unable to start ChannelArbitrator: %v", err)
21282128
}
21292129
defer func() {

0 commit comments

Comments
 (0)