diff --git a/conseil-common/src/main/scala/tech/cryptonomic/conseil/common/tezos/TezosOptics.scala b/conseil-common/src/main/scala/tech/cryptonomic/conseil/common/tezos/TezosOptics.scala index f8d4d2cda..460bad6c4 100644 --- a/conseil-common/src/main/scala/tech/cryptonomic/conseil/common/tezos/TezosOptics.scala +++ b/conseil-common/src/main/scala/tech/cryptonomic/conseil/common/tezos/TezosOptics.scala @@ -409,12 +409,121 @@ object TezosOptics { * @return a Map holding for each group both external and internal operations' results */ def extractOperationsAlongWithInternalResults( - block: Block + block: Block, + knownAddresses: Option[List[Tables.KnownAddressesRow]] ): Map[OperationsGroup, (List[Operation], List[InternalOperationResults.InternalOperationResult])] = block.operationGroups.map { group => val updatedGroup = addIndexesToOperationGroup(group) - val internal = updatedGroup.contents.flatMap { op => + val filteredOperations = updatedGroup.contents.filter { op => + knownAddresses match { + case Some(ka) => + val addresses = ka.map(_.address) + op match { + case Endorsement(level, metadata, blockOrder) => false + case EndorsementWithSlot(endorsement, metadata, blockOrder) => false + case Preendorsement(level, metadata, blockOrder) => false + case SeedNonceRevelation(level, nonce, metadata, blockOrder) => false + case ActivateAccount(pkh, secret, metadata, blockOrder) => addresses.contains(pkh.value) + case Reveal(counter, fee, gas_limit, storage_limit, public_key, source, metadata, blockOrder) => + addresses.contains(public_key.value) || addresses.contains(source.value) + case Transaction( + counter, + amount, + fee, + gas_limit, + storage_limit, + source, + destination, + parameters, + parameters_micheline, + metadata, + blockOrder + ) => + addresses.contains(source.value) || addresses.contains(destination.id) + case Origination( + counter, + fee, + source, + balance, + gas_limit, + storage_limit, + manager_pubkey, + delegatable, + delegate, + spendable, + script, + metadata, + blockOrder + ) => + addresses.contains(source.value) || addresses.contains( + delegate.getOrElse(PublicKeyHash("")).value + ) || addresses.contains(manager_pubkey.getOrElse(PublicKeyHash("")).value) + case Delegation(counter, source, fee, gas_limit, storage_limit, delegate, metadata, blockOrder) => + addresses.contains(source.value) || addresses.contains(delegate.getOrElse(PublicKeyHash("")).value) + case DoubleEndorsementEvidence(blockOrder) => false + case DoublePreendorsementEvidence(blockOrder) => false + case DoubleBakingEvidence(blockOrder) => false + case Proposals(source, period, proposals, blockOrder) => + addresses.contains(source.getOrElse(ContractId("")).id) + case Ballot(ballot, proposal, source, period, blockOrder) => + addresses.contains(source.getOrElse(ContractId("")).id) + case RegisterGlobalConstant( + source, + fee, + counter, + gas_limit, + storage_limit, + value, + blockOrder, + metadata + ) => + addresses.contains(source.getOrElse(ContractId("")).id) + case SetDepositsLimit(source, fee, counter, gas_limit, storage_limit, limit, blockOrder, metadata) => + addresses.contains(source.getOrElse(ContractId("")).id) + case TxRollupCommit(counter, fee, source, gas_limit, storage_limit, rollup, metadata, blockOrder) => + addresses.contains(source.value) + case TxRollupFinalizeCommitment( + counter, + fee, + source, + gas_limit, + storage_limit, + rollup, + metadata, + blockOrder + ) => + addresses.contains(source.value) + case TxRollupOrigination(counter, fee, source, gas_limit, storage_limit, metadata, blockOrder) => + addresses.contains(source.value) + case TxRollupSubmitBatch( + counter, + fee, + source, + gas_limit, + storage_limit, + rollup, + metadata, + blockOrder + ) => + addresses.contains(source.value) + case TxRollupDispatchTickets( + counter, + fee, + source, + gas_limit, + storage_limit, + tx_rollup, + metadata, + blockOrder + ) => + addresses.contains(source.value) + case DefaultOperation(kind, blockOrder) => true + } + case None => true + } + } + val internal = filteredOperations.flatMap { op => op match { case r: Reveal => r.metadata.internal_operation_results.toList.flatten case t: Transaction => t.metadata.internal_operation_results.toList.flatten @@ -423,7 +532,7 @@ object TezosOptics { case _ => List.empty } } - updatedGroup -> (updatedGroup.contents, internal) + updatedGroup -> (filteredOperations, internal) }.toMap /** Extracts all operations, primary and internal, and pre-order traverse diff --git a/conseil-lorre/src/main/resources/application.conf b/conseil-lorre/src/main/resources/application.conf index 3bd45e8be..90a825bea 100644 --- a/conseil-lorre/src/main/resources/application.conf +++ b/conseil-lorre/src/main/resources/application.conf @@ -49,6 +49,8 @@ lorre { rights-processing-is-on: ${?CONSEIL_LORRE_RIGHTS_PROCESSING_ENABLED} baker-features-are-on: false baker-features-are-on: ${?CONSEIL_LORRE_BAKER_FEATURES_ENABLED} + lightweight-indexing: false + lightweight-indexing: ${?CONSEIL_LORRE_LIGHTWEIGHT_INDEXING_ENABLED} } # TODO Should we wrap configuration from below into 'Tezos' secion? The same in the *Configuration class? diff --git a/conseil-lorre/src/main/resources/registered_tokens/hangzhounet.csv b/conseil-lorre/src/main/resources/tezos/registered_tokens/hangzhounet.csv similarity index 100% rename from conseil-lorre/src/main/resources/registered_tokens/hangzhounet.csv rename to conseil-lorre/src/main/resources/tezos/registered_tokens/hangzhounet.csv diff --git a/conseil-lorre/src/main/resources/registered_tokens/hangzhounet.json b/conseil-lorre/src/main/resources/tezos/registered_tokens/hangzhounet.json similarity index 100% rename from conseil-lorre/src/main/resources/registered_tokens/hangzhounet.json rename to conseil-lorre/src/main/resources/tezos/registered_tokens/hangzhounet.json diff --git a/conseil-lorre/src/main/resources/registered_tokens/ithacanet.json b/conseil-lorre/src/main/resources/tezos/registered_tokens/ithacanet.json similarity index 100% rename from conseil-lorre/src/main/resources/registered_tokens/ithacanet.json rename to conseil-lorre/src/main/resources/tezos/registered_tokens/ithacanet.json diff --git a/conseil-lorre/src/main/resources/registered_tokens/jakartanet.json b/conseil-lorre/src/main/resources/tezos/registered_tokens/jakartanet.json similarity index 100% rename from conseil-lorre/src/main/resources/registered_tokens/jakartanet.json rename to conseil-lorre/src/main/resources/tezos/registered_tokens/jakartanet.json diff --git a/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/config/LorreConfiguration.scala b/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/config/LorreConfiguration.scala index e99b8909d..de4ec4afa 100644 --- a/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/config/LorreConfiguration.scala +++ b/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/config/LorreConfiguration.scala @@ -110,7 +110,8 @@ final case class Features( metadataFetchingIsOn: Boolean, registeredTokensIsOn: Boolean, rightsProcessingIsOn: Boolean, - bakerFeaturesAreOn: Boolean + bakerFeaturesAreOn: Boolean, + lightweightIndexing: Boolean ) final case class TokenContracts( diff --git a/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/tezos/TezosDatabaseConversions.scala b/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/tezos/TezosDatabaseConversions.scala index 32dbe667e..d6c1f1cc8 100644 --- a/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/tezos/TezosDatabaseConversions.scala +++ b/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/tezos/TezosDatabaseConversions.scala @@ -829,34 +829,37 @@ private[tezos] object TezosDatabaseConversions { * To correctly create the relation on the db, we must first store the operations, get * each generated id, and pass it to the associated balance-updates */ - implicit val blockToOperationTablesData = new Conversion[List, Block, OperationTablesData] { - import OperationBalances._ - import SymbolSourceLabels.Show._ - import tech.cryptonomic.conseil.common.util.Conversion.Syntax._ - - override def convert(from: Block) = - TezosOptics.Blocks - .extractOperationsAlongWithInternalResults(from) - .flatMap { case (group, (operations, internalResults)) => - val mainOperationData = operations.map(op => - (from, group.hash, op).convertTo[Tables.OperationsRow] -> - BlockTagged - .fromBlockData(from.data, op) + implicit val blockToOperationTablesData = + new Conversion[List, (Block, Option[List[Tables.KnownAddressesRow]]), OperationTablesData] { + import OperationBalances._ + import SymbolSourceLabels.Show._ + import tech.cryptonomic.conseil.common.util.Conversion.Syntax._ + + override def convert(from: (Block, Option[List[Tables.KnownAddressesRow]])) = { + val (block, knownAddresses) = from + TezosOptics.Blocks + .extractOperationsAlongWithInternalResults(block, knownAddresses) + .flatMap { case (group, (operations, internalResults)) => + val mainOperationData = operations.map(op => + (block, group.hash, op).convertTo[Tables.OperationsRow] -> + BlockTagged + .fromBlockData(block.data, op) + .convertToA[List, Tables.BalanceUpdatesRow] + ) + val internalOperationData = internalResults.map { case oop => + val op = oop.convertTo[Operation] + (block, group.hash, op) + .convertTo[Tables.OperationsRow] + .copy(internal = true, nonce = Some(oop.nonce.toString)) -> BlockTagged + .fromBlockData(block.data, op) .convertToA[List, Tables.BalanceUpdatesRow] - ) - val internalOperationData = internalResults.map { case oop => - val op = oop.convertTo[Operation] - (from, group.hash, op) - .convertTo[Tables.OperationsRow] - .copy(internal = true, nonce = Some(oop.nonce.toString)) -> BlockTagged - .fromBlockData(from.data, op) - .convertToA[List, Tables.BalanceUpdatesRow] + } + mainOperationData ++ internalOperationData } - mainOperationData ++ internalOperationData - } - .toList + .toList + } - } + } implicit val blockAccountsAssociationToCheckpointRow = new Conversion[ diff --git a/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/tezos/TezosDatabaseOperations.scala b/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/tezos/TezosDatabaseOperations.scala index 706f3e6b6..cdbb5159d 100644 --- a/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/tezos/TezosDatabaseOperations.scala +++ b/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/tezos/TezosDatabaseOperations.scala @@ -13,7 +13,6 @@ import tech.cryptonomic.conseil.common.generic.chain.DataTypes.{Query => _} import tech.cryptonomic.conseil.common.sql.CustomProfileExtension import tech.cryptonomic.conseil.common.tezos.{Fork, Tables} import tech.cryptonomic.conseil.common.tezos.Tables.{ - AccountsRow, GovernanceRow, OperationsRow, OriginatedAccountMapsRow, @@ -37,6 +36,8 @@ import java.util.UUID import slick.dbio.DBIOAction import tech.cryptonomic.conseil.indexer.tezos.RegisteredTokensFetcher.RegisteredToken +import scala.io.Source + /** * Functions for writing Tezos data to a database. */ @@ -101,7 +102,8 @@ object TezosDatabaseOperations extends ConseilLogSupport { */ def writeBlocks( blocks: List[Block], - tokenContracts: TokenContracts + tokenContracts: TokenContracts, + knownAddresses: Option[List[Tables.KnownAddressesRow]] )(implicit ec: ExecutionContext, tnsContracts: TNSContract): DBIO[Unit] = { // Kleisli is a Function with effects, Kleisli[F, A, B] ~= A => F[B] import TezosDatabaseConversions.OperationTablesData @@ -118,6 +120,11 @@ object TezosDatabaseOperations extends ConseilLogSupport { val saveBlocksAction = Tables.Blocks ++= blocks.map(_.convertTo[BlocksRow]) val saveBlocksBalanceUpdatesAction = Tables.BalanceUpdates ++= blocks.flatMap { block => block.data.convertToA[List, BalanceUpdatesRow] + }.filter { updatesRow => + knownAddresses match { + case Some(value) => value.map(_.address).contains(updatesRow.accountId) + case None => true + } } val saveGroupsAction = Tables.OperationGroups ++= blocks.flatMap(_.convertToA[List, OperationGroupsRow]) @@ -147,7 +154,9 @@ object TezosDatabaseOperations extends ConseilLogSupport { saveBlocksAction, saveBlocksBalanceUpdatesAction, saveGroupsAction, - saveOperationsAndBalances.traverse(blocks.flatMap(_.convertToA[List, OperationTablesData])), + saveOperationsAndBalances.traverse( + blocks.flatMap(block => (block -> knownAddresses).convertToA[List, OperationTablesData]) + ), saveBigMaps(blocks)(ec, tokenContracts, tnsContracts) ) @@ -396,7 +405,8 @@ object TezosDatabaseOperations extends ConseilLogSupport { */ def writeBlocksAndCheckpointAccounts( blocks: List[Block], - accountUpdates: List[BlockTagged[List[AccountId]]] + accountUpdates: List[BlockTagged[List[AccountId]]], + knownAddresses: Option[List[Tables.KnownAddressesRow]] )(implicit ec: ExecutionContext, tnsContracts: TNSContract): DBIO[Option[Int]] = { logger.info("Writing blocks and account checkpoints to the DB...") //sequence both operations in a single transaction @@ -407,7 +417,9 @@ object TezosDatabaseOperations extends ConseilLogSupport { ContractId(address) -> interfaces }.toList ) - (writeBlocks(blocks, tokens) andThen writeAccountsCheckpoint(accountUpdates.map(_.asTuple))).transactionally + (writeBlocks(blocks, tokens, knownAddresses) andThen writeAccountsCheckpoint( + accountUpdates.map(_.asTuple) + )).transactionally } } @@ -834,7 +846,6 @@ object TezosDatabaseOperations extends ConseilLogSupport { import io.circe.parser.decode import RegisteredTokensFetcher.decoder import java.io.{BufferedReader, InputStreamReader} - import scala.io.Source val file = getClass.getResource(s"/tezos/registered_tokens/$network.json") val content = Source.fromFile(file.toURI).getLines.mkString diff --git a/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/tezos/TezosIndexer.scala b/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/tezos/TezosIndexer.scala index e0931a26e..7e0936a35 100644 --- a/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/tezos/TezosIndexer.scala +++ b/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/tezos/TezosIndexer.scala @@ -64,6 +64,7 @@ class TezosIndexer private ( forkHandler: ForkHandler[Future, TezosBlockHash], backtrackingForkProcessor: BacktracingForkProcessor, feeOperations: TezosFeeOperations, + knownAddresses: List[Tables.KnownAddressesRow], terminationSequence: () => Future[ShutdownComplete] )(implicit system: ActorSystem, @@ -350,6 +351,15 @@ object TezosIndexer extends ConseilLogSupport { lorreConf.headOffset ) + /* the shutdown sequence to free resources */ + val gracefulTermination = () => + for { + _ <- Future.successful(db.close()) + _ = materializer.shutdown() + _: Terminated <- system.terminate() + _: ShutdownComplete <- nodeOperator.node.shutdown() + } yield ShutdownComplete + /* provides operations to handle rights to bake and endorse blocks */ val rightsProcessor = new BakingAndEndorsingRightsProcessor( nodeOperator, @@ -392,6 +402,54 @@ object TezosIndexer extends ConseilLogSupport { //build operations on tns based on the implicit contracts defined before val tnsOperations = new TezosNamesOperations(tns, nodeOperator) + /* Reads csv resources to initialize db tables and smart contracts objects */ + def parseCSVConfigurations() = { + /* This will derive automatically all needed implicit arguments to convert csv rows into a proper table row + * Using generic representations for case classes, provided by the `shapeless` library, it will create the + * appropriate `kantan.csv.Decoder` for + * - headers, as extracted by the case class definition which, should match name and order of the csv header row + * - table row types, which can be converted to shapeless HLists, which so happens to be of any case class. + * + * What shapeless does, is provide an automatic conversion, from a case class to a typed generic list of values, + * where each element has a type corresponding to a field in the case class, and a "label" that is + * a sort of string extracted at compile-time via macros, to figure out the field names. + * Such special list, is a `shapeless.HList`, or heterogeneous list, sort of a dynamic tuple, + * to be built by adding/removing individual elements in the list, recursively. + * This allows generic libraries like kantan to define codecs for generic HLists and, + * using shapeless, to adapt any case class to his specific HList, at compile-time. + * + * For additional information, refer to the project wiki, and + * - http://nrinaudo.github.io/kantan.csv/ + * - http://www.shapeless.io/ + */ + import kantan.csv.generic._ + //we add any missing implicit decoder for column types, not provided by default from the library + import tech.cryptonomic.conseil.common.util.ConfigUtil.Csv._ + import cats.implicits._ + + /* Inits tables with values from CSV files */ + ( + DefaultDatabaseOperations.initTableFromCsv(db, Tables.KnownAddresses, "tezos", selectedNetwork), + DefaultDatabaseOperations.initTableFromCsv(db, Tables.BakerRegistry, "tezos", selectedNetwork), + TezosDb.initRegisteredTokensTableFromJson(db, selectedNetwork) + ).mapN { case (ka, _, _) => + ka._1 + } + /* Here we want to initialize the registered tokens and additionally get the token data back + * since it's needed to process calls to the same token smart contracts as the chain evolves + */ + } + + val knownAddresses = Try(Await.result(parseCSVConfigurations(), 5.seconds)) match { + case Success(ka) => + logger.info("DB initialization successful") + ka + case Failure(exception) => + logger.error("DB initialization failed", exception) + gracefulTermination().map(_ => ()) + List.empty + } + /* this is the principal data processor, handling paginated blocks, and the correlated data within */ val blocksProcessor = new BlocksProcessor( nodeOperator, @@ -399,7 +457,8 @@ object TezosIndexer extends ConseilLogSupport { tnsOperations, accountsProcessor, bakersProcessor, - lorreConf.enabledFeatures + lorreConf.enabledFeatures, + if (lorreConf.enabledFeatures.lightweightIndexing) Some(knownAddresses) else None ) val metadataProcessor = new MetadataProcessor( @@ -438,66 +497,9 @@ object TezosIndexer extends ConseilLogSupport { val feeOperations = new TezosFeeOperations(db) - /* the shutdown sequence to free resources */ - val gracefulTermination = () => - for { - _ <- Future.successful(db.close()) - _ = materializer.shutdown() - _: Terminated <- system.terminate() - _: ShutdownComplete <- nodeOperator.node.shutdown() - } yield ShutdownComplete - /* Used for fetching and handling registered tokens */ val registeredTokensFetcher = new RegisteredTokensFetcher(db, lorreConf.tokenContracts, gracefulTermination) - /* Reads csv resources to initialize db tables and smart contracts objects */ - def parseCSVConfigurations() = { - /* This will derive automatically all needed implicit arguments to convert csv rows into a proper table row - * Using generic representations for case classes, provided by the `shapeless` library, it will create the - * appropriate `kantan.csv.Decoder` for - * - headers, as extracted by the case class definition which, should match name and order of the csv header row - * - table row types, which can be converted to shapeless HLists, which so happens to be of any case class. - * - * What shapeless does, is provide an automatic conversion, from a case class to a typed generic list of values, - * where each element has a type corresponding to a field in the case class, and a "label" that is - * a sort of string extracted at compile-time via macros, to figure out the field names. - * Such special list, is a `shapeless.HList`, or heterogeneous list, sort of a dynamic tuple, - * to be built by adding/removing individual elements in the list, recursively. - * This allows generic libraries like kantan to define codecs for generic HLists and, - * using shapeless, to adapt any case class to his specific HList, at compile-time. - * - * For additional information, refer to the project wiki, and - * - http://nrinaudo.github.io/kantan.csv/ - * - http://www.shapeless.io/ - */ - import kantan.csv.generic._ - //we add any missing implicit decoder for column types, not provided by default from the library - import tech.cryptonomic.conseil.common.util.ConfigUtil.Csv._ - import cats.implicits._ - - /* Inits tables with values from CSV files */ - ( - DefaultDatabaseOperations.initTableFromCsv(db, Tables.KnownAddresses, "tezos", selectedNetwork), - DefaultDatabaseOperations.initTableFromCsv(db, Tables.BakerRegistry, "tezos", selectedNetwork), - TezosDb.initRegisteredTokensTableFromJson(db, selectedNetwork) - ).mapN { case (_, _, _) => - () - } - /* Here we want to initialize the registered tokens and additionally get the token data back - * since it's needed to process calls to the same token smart contracts as the chain evolves - */ - - } - - Try(Await.result(parseCSVConfigurations(), 5.seconds)) match { - case Success(_) => - () - logger.info("DB initialization successful") - case Failure(exception) => - logger.error("DB initialization failed", exception) - gracefulTermination().map(_ => ()) - } - new TezosIndexer( ignoreProcessFailures, lorreConf, @@ -513,6 +515,7 @@ object TezosIndexer extends ConseilLogSupport { forkHandler, backtracingForkProcessor, feeOperations, + knownAddresses, gracefulTermination ) } diff --git a/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/tezos/processing/BlocksProcessor.scala b/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/tezos/processing/BlocksProcessor.scala index d9c16faf2..9f717e400 100644 --- a/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/tezos/processing/BlocksProcessor.scala +++ b/conseil-lorre/src/main/scala/tech/cryptonomic/conseil/indexer/tezos/processing/BlocksProcessor.scala @@ -12,7 +12,7 @@ import tech.cryptonomic.conseil.indexer.tezos.{ TezosDatabaseOperations => TezosDb } import tech.cryptonomic.conseil.common.io.Logging.ConseilLogSupport -import tech.cryptonomic.conseil.common.tezos.TezosTypes +import tech.cryptonomic.conseil.common.tezos.{Tables, TezosTypes} import tech.cryptonomic.conseil.common.tezos.TezosTypes.{Block, InternalOperationResults, Voting} import tech.cryptonomic.conseil.common.tezos.TezosTypes.Syntax._ import tech.cryptonomic.conseil.indexer.config.Features @@ -38,7 +38,8 @@ class BlocksProcessor( tnsOperations: TezosNamesOperations, accountsProcessor: AccountsProcessor, bakersProcessor: BakersProcessor, - featureFlags: Features + featureFlags: Features, + knownAddresses: Option[List[Tables.KnownAddressesRow]] )(implicit tns: TNSContract) extends ConseilLogSupport { @@ -56,13 +57,25 @@ class BlocksProcessor( //ignore the account ids for storage, and prepare the checkpoint account data //we do this on a single sweep over the list, pairing the results and then unzipping the outcome - val (blocks, accountUpdates) = - results.map { case (block, accountIds) => - block -> accountIds.taggedWithBlockData(block.data) - }.unzip + val (blocks, accountUpdates) = { + knownAddresses match { + case Some(value) => + results.map { case (block, accountIds) => + val ids = accountIds.toSet.intersect(value.map(x => TezosTypes.PublicKeyHash(x.address)).toSet).toList + block -> ids.taggedWithBlockData(block.data) + }.unzip + case None => + results.map { case (block, accountIds) => + block -> accountIds.taggedWithBlockData(block.data) + }.unzip + } + + } for { - _ <- db.run(TezosDb.writeBlocksAndCheckpointAccounts(blocks, accountUpdates)) andThen logBlockOutcome + _ <- db.run( + TezosDb.writeBlocksAndCheckpointAccounts(blocks, accountUpdates, knownAddresses) + ) andThen logBlockOutcome _ <- tnsOperations.processNamesRegistrations(blocks).flatMap(db.run) bakersCheckpoints <- accountsProcessor.processAccountsForBlocks( accountUpdates