Browse Source
The same job can be done by the BackwardsSynchronizerTask, there is no need to keep both.scalafmt-draft v2018.06.10
2 changed files with 3 additions and 130 deletions
@ -1,124 +0,0 @@ |
|||
package com.xsn.explorer.tasks |
|||
|
|||
import javax.inject.{Inject, Singleton} |
|||
|
|||
import com.alexitc.playsonify.core.FutureApplicationResult |
|||
import com.alexitc.playsonify.core.FutureOr.Implicits.{FutureListOps, FutureOps, OrOps} |
|||
import com.xsn.explorer.data.DatabaseSeeder |
|||
import com.xsn.explorer.data.async.{BlockFutureDataHandler, DatabaseFutureSeeder} |
|||
import com.xsn.explorer.errors.BlockNotFoundError |
|||
import com.xsn.explorer.models.{Blockhash, Height} |
|||
import com.xsn.explorer.services.{TransactionService, XSNService} |
|||
import org.scalactic.{Bad, Good, One, Or} |
|||
import org.slf4j.LoggerFactory |
|||
|
|||
import scala.concurrent.ExecutionContext.Implicits.global |
|||
import scala.concurrent.Future |
|||
import scala.util.control.NonFatal |
|||
|
|||
/** |
|||
* The database might start to be filled from a block different to the genesis one. |
|||
* |
|||
* This task helps to sync it from the first saved block backwards to the genesis one. |
|||
*/ |
|||
@Singleton |
|||
class FirstBlockSynchronizerTask @Inject() ( |
|||
xsnService: XSNService, |
|||
transactionService: TransactionService, |
|||
blockDataHandler: BlockFutureDataHandler, |
|||
databaseSeeder: DatabaseFutureSeeder) { |
|||
|
|||
private val logger = LoggerFactory.getLogger(this.getClass) |
|||
private val lock = new Object |
|||
|
|||
/** |
|||
* TODO: Until https://github.com/X9Developers/XSN/issues/32 is fixed, ignore the genesis block. |
|||
*/ |
|||
private val FirstBlockHeight = Height(1) |
|||
|
|||
private var running = false |
|||
|
|||
def sync(): Unit = { |
|||
if (running) { |
|||
() |
|||
} else { |
|||
lock.synchronized { |
|||
if (running) { |
|||
() |
|||
} else { |
|||
running = true |
|||
|
|||
tryToSync().onComplete { _ => |
|||
running = false |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
private def tryToSync() = { |
|||
val futureOr = for { |
|||
firstBlock <- blockDataHandler.getFirstBlock().toFutureOr |
|||
previous <- Or.from(firstBlock.previousBlockhash, One(BlockNotFoundError)).toFutureOr |
|||
_ <- { |
|||
if (firstBlock.height == FirstBlockHeight) { |
|||
// no sync required |
|||
Future.successful(Good(())) |
|||
} else { |
|||
// sync |
|||
logger.info(s"Sync required until block ${firstBlock.height.int}") |
|||
val r = doSync(previous) |
|||
|
|||
r.foreach { |
|||
case Good(_) => |
|||
logger.info("Sync completed") |
|||
case _ => () |
|||
} |
|||
|
|||
r |
|||
} |
|||
}.toFutureOr |
|||
} yield () |
|||
|
|||
val result = futureOr.toFuture |
|||
|
|||
result.foreach { |
|||
case Bad(errors) => |
|||
logger.error(s"Failed to sync blocks, errors = $errors") |
|||
|
|||
case _ => () |
|||
} |
|||
|
|||
result.recover { |
|||
case NonFatal(ex) => |
|||
logger.error(s"Failed to sync blocks", ex) |
|||
} |
|||
|
|||
result |
|||
} |
|||
|
|||
private def doSync(blockhash: Blockhash): FutureApplicationResult[Unit] = { |
|||
val result = for { |
|||
block <- xsnService.getBlock(blockhash).toFutureOr |
|||
transactions <- block.transactions.map(transactionService.getTransaction).toFutureOr |
|||
|
|||
command = DatabaseSeeder.CreateBlockCommand(block, transactions) |
|||
_ <- databaseSeeder.newBlock(command).toFutureOr |
|||
_ = logger.debug(s"Block ${block.height.int} saved") |
|||
|
|||
_ <- block |
|||
.previousBlockhash |
|||
.filter(_ => block.height.int > FirstBlockHeight.int) |
|||
.map { previous => |
|||
doSync(previous) |
|||
} |
|||
.getOrElse { |
|||
logger.debug(s"No more blocks to sync") |
|||
Future.successful(Good(())) |
|||
} |
|||
.toFutureOr |
|||
} yield () |
|||
|
|||
result.toFuture |
|||
} |
|||
} |
Loading…
Reference in new issue