@@ -19,7 +19,7 @@ package org.alephium.explorer.service
19
19
import java .util .concurrent .atomic .AtomicBoolean
20
20
21
21
import scala .collection .immutable .ArraySeq
22
- import scala .concurrent .{ExecutionContext , Future }
22
+ import scala .concurrent .{ExecutionContext , Future , Promise }
23
23
import scala .concurrent .duration .{Duration => ScalaDuration , FiniteDuration }
24
24
import scala .util .{Failure , Success }
25
25
@@ -31,6 +31,7 @@ import sttp.model.Uri
31
31
import org .alephium .explorer .{foldFutures , GroupSetting }
32
32
import org .alephium .explorer .api .model .Height
33
33
import org .alephium .explorer .cache .BlockCache
34
+ import org .alephium .explorer .config .ExplorerConfig .Consensus
34
35
import org .alephium .explorer .error .ExplorerError .BlocksInDifferentChains
35
36
import org .alephium .explorer .persistence .DBRunner ._
36
37
import org .alephium .explorer .persistence .dao .BlockDao
@@ -53,6 +54,8 @@ import org.alephium.util.{Duration, TimeStamp}
53
54
* 5. For each last block of each chains, mark it as part of the main chain and travel
54
55
* down the parents recursively until we found back a parent that is part of the main chain.
55
56
* 6. During step 5, if a parent is missing, we download it and continue the procces at 5.
57
+ * 7. Once the blocks are up-to-date with the node, we switch to websocket syncing
58
+ * 8. If the websocket close or is late, in case of network issue, we go back to step 1.
56
59
*
57
60
* TODO: Step 5 is costly, but it's an easy way to handle reorg. In step 3 we know we receive the current main chain
58
61
* for that timerange, so in step 4 we could directly insert them as `mainChain = true`, but we need to sync
@@ -66,13 +69,15 @@ case object BlockFlowSyncService extends StrictLogging {
66
69
private val defaultStep = Duration .ofMinutesUnsafe(30L )
67
70
private val defaultBackStep = Duration .ofSecondsUnsafe(10L )
68
71
private val initialBackStep = Duration .ofMinutesUnsafe(30L )
72
+ private val upToDateDelta = Duration .ofSecondsUnsafe(30L )
69
73
// scalastyle:on magic.number
70
74
71
75
def start (nodeUris : ArraySeq [Uri ], interval : FiniteDuration )(implicit
72
76
ec : ExecutionContext ,
73
77
dc : DatabaseConfig [PostgresProfile ],
74
78
blockFlowClient : BlockFlowClient ,
75
79
cache : BlockCache ,
80
+ consensus : Consensus ,
76
81
groupSetting : GroupSetting ,
77
82
scheduler : Scheduler
78
83
): Future [Unit ] =
@@ -87,14 +92,38 @@ case object BlockFlowSyncService extends StrictLogging {
87
92
ec : ExecutionContext ,
88
93
dc : DatabaseConfig [PostgresProfile ],
89
94
blockFlowClient : BlockFlowClient ,
95
+ consensus : Consensus ,
90
96
cache : BlockCache ,
91
97
groupSetting : GroupSetting
92
98
): Future [Unit ] = {
93
- if (initialBackStepDone.get()) {
94
- syncOnceWith(nodeUris, defaultStep, defaultBackStep)
95
- } else {
96
- syncOnceWith(nodeUris, defaultStep, initialBackStep).map { _ =>
97
- initialBackStepDone.set(true )
99
+ val syncResult =
100
+ if (initialBackStepDone.get()) {
101
+ syncOnceWith(nodeUris, defaultStep, defaultBackStep)
102
+ } else {
103
+ syncOnceWith(nodeUris, defaultStep, initialBackStep).map { result =>
104
+ initialBackStepDone.set(true )
105
+ result
106
+ }
107
+ }
108
+
109
+ syncResult.flatMap { isUpToDate =>
110
+ if (isUpToDate) {
111
+ logger.info(" Blocks are up to date, switching to web socket syncing" )
112
+ val stopPromise = Promise [Unit ]()
113
+ // TODO Use config values
114
+ // scalastyle:off magic.number
115
+ WebSocketSyncService .sync(
116
+ stopPromise,
117
+ host = " 127.0.0.1" ,
118
+ port = 22973 ,
119
+ flushInterval = Duration .ofMillisUnsafe(500 )
120
+ )
121
+ // scalastyle:on magic.number
122
+ stopPromise.future.map { _ =>
123
+ logger.info(" WebSocket syncing stopped, resuming http syncing" )
124
+ }
125
+ } else {
126
+ Future .successful(())
98
127
}
99
128
}
100
129
}
@@ -106,7 +135,7 @@ case object BlockFlowSyncService extends StrictLogging {
106
135
blockFlowClient : BlockFlowClient ,
107
136
cache : BlockCache ,
108
137
groupSetting : GroupSetting
109
- ): Future [Unit ] = {
138
+ ): Future [Boolean ] = {
110
139
getTimeStampRange(step, backStep)
111
140
.flatMap { ranges =>
112
141
Future .sequence {
@@ -116,12 +145,16 @@ case object BlockFlowSyncService extends StrictLogging {
116
145
s " Syncing from ${TimeUtil .toInstant(from)} to ${TimeUtil
117
146
.toInstant(to)} ( ${from.millis} - ${to.millis}) "
118
147
)
119
- syncTimeRange(from, to, uri)
148
+ syncTimeRange(from, to, uri).map { _ =>
149
+ (TimeStamp .now() -- to).map(_ < upToDateDelta).getOrElse(false )
150
+ }
120
151
}
121
152
}
122
153
}
123
154
}
124
- .map(_ => ())
155
+ .map { upToDates =>
156
+ upToDates.flatten.contains(true )
157
+ }
125
158
}
126
159
// scalastyle:on magic.number
127
160
@@ -360,7 +393,7 @@ case object BlockFlowSyncService extends StrictLogging {
360
393
}
361
394
}
362
395
363
- private def insertBlocks (blocksWithEvents : ArraySeq [BlockEntityWithEvents ])(implicit
396
+ def insertBlocks (blocksWithEvents : ArraySeq [BlockEntityWithEvents ])(implicit
364
397
ec : ExecutionContext ,
365
398
dc : DatabaseConfig [PostgresProfile ],
366
399
blockFlowClient : BlockFlowClient ,
0 commit comments