11import { inject , injectable } from "tsyringe" ;
22import { log } from "@proto-kit/common" ;
3- import gcd from "compute-gcd" ;
43
54import { closeable , Closeable } from "../../../sequencer/builder/Closeable" ;
65import { BatchProducerModule } from "../BatchProducerModule" ;
@@ -14,37 +13,23 @@ import {
1413} from "../../../settlement/BridgingModule" ;
1514import { ensureNotBusy } from "../../../helpers/BusyGuard" ;
1615
17- import { BlockEvents , BlockTriggerBase } from "./BlockTrigger" ;
16+ import { BlockTriggerBase } from "./BlockTrigger" ;
1817
1918export interface TimedBlockTriggerConfig {
20- /**
21- * Interval for the tick event to be fired.
22- * The time x of any block trigger time is always guaranteed to be
23- * tick % x == 0.
24- * Value has to be a divisor of gcd(blockInterval, settlementInterval).
25- * If it doesn't satisfy this requirement, this config will not be respected
26- */
27- tick ?: number ;
2819 settlementInterval ?: number ;
2920 blockInterval : number ;
3021 produceEmptyBlocks ?: boolean ;
3122
3223 settlementTokenConfig : SettlementTokenConfig ;
3324}
3425
35- export interface TimedBlockTriggerEvent extends BlockEvents {
36- tick : [ number ] ;
37- }
38-
3926@injectable ( )
4027@closeable ( )
4128export class TimedBlockTrigger
42- extends BlockTriggerBase < TimedBlockTriggerConfig , TimedBlockTriggerEvent >
29+ extends BlockTriggerBase < TimedBlockTriggerConfig >
4330 implements Closeable
4431{
45- // There is no real type for interval ids somehow, so any it is
46-
47- private interval ?: any ;
32+ private intervals : NodeJS . Timeout [ ] = [ ] ;
4833
4934 public constructor (
5035 @inject ( "BatchProducerModule" , { isOptional : true } )
@@ -69,26 +54,6 @@ export class TimedBlockTrigger
6954 ) ;
7055 }
7156
72- private getTimerInterval ( ) : number {
73- const { settlementInterval, blockInterval, tick } = this . config ;
74-
75- let timerInterval =
76- settlementInterval !== undefined
77- ? gcd ( settlementInterval , blockInterval )
78- : blockInterval ;
79-
80- const definedTick = tick ?? 1000 ;
81- if ( definedTick <= timerInterval ) {
82- // Check if tick is a divisor of the calculated interval
83- const div = timerInterval / definedTick ;
84- if ( Math . floor ( div ) === div ) {
85- timerInterval = definedTick ;
86- }
87- }
88-
89- return timerInterval ;
90- }
91-
9257 public async start ( ) : Promise < void > {
9358 log . info ( "Starting timed block trigger" ) ;
9459 const { settlementInterval, blockInterval } = this . config ;
@@ -102,43 +67,39 @@ export class TimedBlockTrigger
10267 ) ;
10368 }
10469
105- const timerInterval = this . getTimerInterval ( ) ;
106-
107- let totalTime = 0 ;
108- this . interval = setInterval ( async ( ) => {
109- totalTime += timerInterval ;
110-
111- this . events . emit ( "tick" , totalTime ) ;
112-
70+ const blockIntervalId = setInterval ( async ( ) => {
11371 try {
11472 // Trigger unproven blocks
115- if ( totalTime % blockInterval === 0 ) {
116- await this . produceUnprovenBlock ( ) ;
117- }
118-
119- // Trigger proven (settlement) blocks
120- // Only produce settlements if a time has been set
121- // otherwise treat as unproven-only
122- if (
123- settlementInterval !== undefined &&
124- totalTime % settlementInterval === 0
125- ) {
126- await this . tryProduceSettlement ( ) ;
127- }
73+ await this . produceUnprovenBlock ( ) ;
12874 } catch ( error ) {
12975 log . error ( error ) ;
13076 }
131- } , timerInterval ) ;
77+ } , blockInterval ) ;
78+ this . intervals . push ( blockIntervalId ) ;
79+
80+ if ( settlementInterval !== undefined ) {
81+ const settlementIntervalId = setInterval ( async ( ) => {
82+ try {
83+ // Trigger settlement
84+ await this . tryProduceSettlement ( ) ;
85+ } catch ( error ) {
86+ log . error ( error ) ;
87+ }
88+ } , settlementInterval ) ;
89+ this . intervals . push ( settlementIntervalId ) ;
90+ }
13291
13392 await super . start ( ) ;
13493 }
13594
95+ // This is technically not necessary since produceBlock checks business down the line
96+ // but we save a bunch of DB checks before
97+ @ensureNotBusy ( )
13698 private async produceUnprovenBlock ( ) {
137- // TODO Optimize towards mempool.length()
138- const mempoolTxs = await this . mempool . getTxs ( 0 ) ;
99+ const mempoolLength = await this . mempool . length ( ) ;
139100 // Produce a block if either produceEmptyBlocks is true or we have more
140- // than 1 tx in mempool
141- if ( mempoolTxs . length > 0 || ( this . config . produceEmptyBlocks ?? true ) ) {
101+ // than 1 tx in mempool or messages
102+ if ( mempoolLength > 0 || ( this . config . produceEmptyBlocks ?? true ) ) {
142103 await this . produceBlock ( ) ;
143104 }
144105 }
@@ -152,7 +113,8 @@ export class TimedBlockTrigger
152113 }
153114
154115 public async close ( ) : Promise < void > {
155- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
156- clearInterval ( this . interval ) ;
116+ this . intervals . forEach ( ( interval ) => {
117+ clearInterval ( interval ) ;
118+ } ) ;
157119 }
158120}
0 commit comments