|
|
@ -4,7 +4,7 @@ import com.alexitc.playsonify.core.FutureApplicationResult |
|
|
|
import com.alexitc.playsonify.core.FutureOr.Implicits.{FutureOps, OptionOps} |
|
|
|
import com.xsn.explorer.data.async.{BlockFutureDataHandler, LedgerFutureDataHandler} |
|
|
|
import com.xsn.explorer.errors.BlockNotFoundError |
|
|
|
import com.xsn.explorer.models.persisted.{Block, Transaction} |
|
|
|
import com.xsn.explorer.models.persisted.Block |
|
|
|
import com.xsn.explorer.models.transformers._ |
|
|
|
import com.xsn.explorer.models.values.{Blockhash, Height} |
|
|
|
import com.xsn.explorer.util.Extensions.FutureOrExt |
|
|
@ -34,15 +34,14 @@ class LedgerSynchronizerService @Inject() ( |
|
|
|
*/ |
|
|
|
def synchronize(blockhash: Blockhash): FutureApplicationResult[Unit] = { |
|
|
|
val result = for { |
|
|
|
x <- getRPCBlock(blockhash).toFutureOr |
|
|
|
(block, transactions) = x |
|
|
|
_ <- synchronize(block, transactions).toFutureOr |
|
|
|
block <- getRPCBlock(blockhash).toFutureOr |
|
|
|
_ <- synchronize(block).toFutureOr |
|
|
|
} yield () |
|
|
|
|
|
|
|
result.toFuture |
|
|
|
} |
|
|
|
|
|
|
|
private def synchronize(block: Block, transactions: List[Transaction.HasIO]): FutureApplicationResult[Unit] = { |
|
|
|
private def synchronize(block: Block.HasTransactions): FutureApplicationResult[Unit] = { |
|
|
|
logger.info(s"Synchronize block ${block.height}, hash = ${block.hash}") |
|
|
|
|
|
|
|
val result = for { |
|
|
@ -53,8 +52,8 @@ class LedgerSynchronizerService @Inject() ( |
|
|
|
.recoverFrom(BlockNotFoundError)(None) |
|
|
|
|
|
|
|
_ <- latestBlockMaybe |
|
|
|
.map { latestBlock => onLatestBlock(latestBlock, block, transactions) } |
|
|
|
.getOrElse { onEmptyLedger(block, transactions) } |
|
|
|
.map { latestBlock => onLatestBlock(latestBlock, block) } |
|
|
|
.getOrElse { onEmptyLedger(block) } |
|
|
|
.toFutureOr |
|
|
|
} yield () |
|
|
|
|
|
|
@ -66,15 +65,15 @@ class LedgerSynchronizerService @Inject() ( |
|
|
|
* 1.1. the given block is the genensis block, it is added. |
|
|
|
* 1.2. the given block is not the genesis block, sync everything until the given block. |
|
|
|
*/ |
|
|
|
private def onEmptyLedger(block: Block, transactions: List[Transaction.HasIO]): FutureApplicationResult[Unit] = { |
|
|
|
private def onEmptyLedger(block: Block.HasTransactions): FutureApplicationResult[Unit] = { |
|
|
|
if (block.height.int == 0) { |
|
|
|
logger.info(s"Synchronize genesis block on empty ledger, hash = ${block.hash}") |
|
|
|
ledgerDataHandler.push(block, transactions) |
|
|
|
ledgerDataHandler.push(block) |
|
|
|
} else { |
|
|
|
logger.info(s"Synchronize block ${block.height} on empty ledger, hash = ${block.hash}") |
|
|
|
val result = for { |
|
|
|
_ <- sync(0 until block.height.int).toFutureOr |
|
|
|
_ <- synchronize(block, transactions).toFutureOr |
|
|
|
_ <- synchronize(block).toFutureOr |
|
|
|
} yield () |
|
|
|
|
|
|
|
result.toFuture |
|
|
@ -89,20 +88,19 @@ class LedgerSynchronizerService @Inject() ( |
|
|
|
* 2.4. if H <= N, if the hash already exists, it is ignored. |
|
|
|
* 2.5. if H <= N, if the hash doesn't exists, remove blocks from N to H (included), then, add the new H. |
|
|
|
*/ |
|
|
|
private def onLatestBlock(ledgerBlock: Block, newBlock: Block, newTransactions: List[Transaction.HasIO]): FutureApplicationResult[Unit] = { |
|
|
|
private def onLatestBlock(ledgerBlock: Block, newBlock: Block.HasTransactions): FutureApplicationResult[Unit] = { |
|
|
|
if (ledgerBlock.height.int + 1 == newBlock.height.int && |
|
|
|
newBlock.previousBlockhash.contains(ledgerBlock.hash)) { |
|
|
|
|
|
|
|
logger.info(s"Appending block ${newBlock.height}, hash = ${newBlock.hash}") |
|
|
|
ledgerDataHandler.push(newBlock, newTransactions) |
|
|
|
ledgerDataHandler.push(newBlock) |
|
|
|
} else if (ledgerBlock.height.int + 1 == newBlock.height.int) { |
|
|
|
logger.info(s"Reorganization to push block ${newBlock.height}, hash = ${newBlock.hash}") |
|
|
|
val result = for { |
|
|
|
blockhash <- newBlock.previousBlockhash.toFutureOr(BlockNotFoundError) |
|
|
|
x <- getRPCBlock(blockhash).toFutureOr |
|
|
|
(previousBlock, previousTransactions) = x |
|
|
|
_ <- synchronize(previousBlock, previousTransactions).toFutureOr |
|
|
|
_ <- synchronize(newBlock, newTransactions).toFutureOr |
|
|
|
previousBlock <- getRPCBlock(blockhash).toFutureOr |
|
|
|
_ <- synchronize(previousBlock).toFutureOr |
|
|
|
_ <- synchronize(newBlock).toFutureOr |
|
|
|
} yield () |
|
|
|
|
|
|
|
result.toFuture |
|
|
@ -110,7 +108,7 @@ class LedgerSynchronizerService @Inject() ( |
|
|
|
logger.info(s"Filling holes to push block ${newBlock.height}, hash = ${newBlock.hash}") |
|
|
|
val result = for { |
|
|
|
_ <- sync(ledgerBlock.height.int + 1 until newBlock.height.int).toFutureOr |
|
|
|
_ <- synchronize(newBlock, newTransactions).toFutureOr |
|
|
|
_ <- synchronize(newBlock).toFutureOr |
|
|
|
} yield () |
|
|
|
|
|
|
|
result.toFuture |
|
|
@ -128,7 +126,7 @@ class LedgerSynchronizerService @Inject() ( |
|
|
|
.getOrElse { |
|
|
|
val x = for { |
|
|
|
_ <- trimTo(newBlock.height).toFutureOr |
|
|
|
_ <- synchronize(newBlock, newTransactions).toFutureOr |
|
|
|
_ <- synchronize(newBlock).toFutureOr |
|
|
|
} yield () |
|
|
|
x.toFuture |
|
|
|
} |
|
|
@ -150,21 +148,20 @@ class LedgerSynchronizerService @Inject() ( |
|
|
|
val result = for { |
|
|
|
_ <- previous.toFutureOr |
|
|
|
blockhash <- xsnService.getBlockhash(Height(height)).toFutureOr |
|
|
|
x <- getRPCBlock(blockhash).toFutureOr |
|
|
|
(block, transactions) = x |
|
|
|
_ <- synchronize(block, transactions).toFutureOr |
|
|
|
block <- getRPCBlock(blockhash).toFutureOr |
|
|
|
_ <- synchronize(block).toFutureOr |
|
|
|
} yield () |
|
|
|
|
|
|
|
result.toFuture |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private def getRPCBlock(blockhash: Blockhash): FutureApplicationResult[(Block, List[Transaction.HasIO])] = { |
|
|
|
private def getRPCBlock(blockhash: Blockhash): FutureApplicationResult[Block.HasTransactions] = { |
|
|
|
val result = for { |
|
|
|
rpcBlock <- xsnService.getBlock(blockhash).toFutureOr |
|
|
|
extractionMethod <- blockService.extractionMethod(rpcBlock).toFutureOr |
|
|
|
transactions <- transactionRPCService.getTransactions(rpcBlock.transactions).toFutureOr |
|
|
|
} yield (toPersistedBlock(rpcBlock, extractionMethod), transactions) |
|
|
|
} yield toPersistedBlock(rpcBlock, extractionMethod).withTransactions(transactions) |
|
|
|
|
|
|
|
result.toFuture |
|
|
|
} |
|
|
|