@@ -34,9 +34,10 @@ import scala.util.Random
34
34
/** Monitor secondary blockchain sources to detect when we're being eclipsed. */
35
35
object BlockchainWatchdog {
36
36
37
+ // @formatter:off
37
38
case class BlockHeaderAt (blockCount : Long , blockHeader : BlockHeader )
39
+ case object NoBlockReceivedTimer
38
40
39
- // @formatter:off
40
41
sealed trait BlockchainWatchdogEvent
41
42
/**
42
43
* We are missing too many blocks compared to one of our blockchain watchdogs.
@@ -50,21 +51,29 @@ object BlockchainWatchdog {
50
51
case class LatestHeaders (currentBlockCount : Long , blockHeaders : Set [BlockHeaderAt ], source : String ) extends Command
51
52
private [watchdogs] case class WrappedCurrentBlockCount (currentBlockCount : Long ) extends Command
52
53
private case class CheckLatestHeaders (currentBlockCount : Long ) extends Command
54
+ private case class NoBlockReceivedSince (lastBlockCount : Long ) extends Command
53
55
// @formatter:on
54
56
55
57
/**
56
58
* @param chainHash chain we're interested in.
57
59
* @param maxRandomDelay to avoid the herd effect whenever a block is created, we add a random delay before we query
58
60
* secondary blockchain sources. This parameter specifies the maximum delay we'll allow.
59
61
*/
60
- def apply (chainHash : ByteVector32 , maxRandomDelay : FiniteDuration ): Behavior [Command ] = {
62
+ def apply (chainHash : ByteVector32 , maxRandomDelay : FiniteDuration , blockTimeout : FiniteDuration = 15 minutes ): Behavior [Command ] = {
61
63
Behaviors .setup { context =>
62
64
context.system.eventStream ! EventStream .Subscribe (context.messageAdapter[CurrentBlockCount ](cbc => WrappedCurrentBlockCount (cbc.blockCount)))
63
65
Behaviors .withTimers { timers =>
66
+ // We start a timer to check blockchain watchdogs regularly even when we don't receive any block.
67
+ timers.startSingleTimer(NoBlockReceivedTimer , NoBlockReceivedSince (0 ), blockTimeout)
64
68
Behaviors .receiveMessage {
69
+ case NoBlockReceivedSince (lastBlockCount) =>
70
+ context.self ! CheckLatestHeaders (lastBlockCount)
71
+ timers.startSingleTimer(NoBlockReceivedTimer , NoBlockReceivedSince (lastBlockCount), blockTimeout)
72
+ Behaviors .same
65
73
case WrappedCurrentBlockCount (blockCount) =>
66
74
val delay = Random .nextInt(maxRandomDelay.toSeconds.toInt).seconds
67
75
timers.startSingleTimer(CheckLatestHeaders (blockCount), delay)
76
+ timers.startSingleTimer(NoBlockReceivedTimer , NoBlockReceivedSince (blockCount), blockTimeout)
68
77
Behaviors .same
69
78
case CheckLatestHeaders (blockCount) =>
70
79
val id = UUID .randomUUID()
0 commit comments