class Store implements UpdatableStore {

  public static SafeFuture<UpdatableStore> create(
      final AsyncRunner asyncRunner,
      final MetricsSystem metricsSystem,
      final BlockProvider blockProvider,
      final StateAndBlockProvider stateAndBlockProvider,
      final UInt64 time,
      final UInt64 genesisTime,
      final Checkpoint justifiedCheckpoint,
      final Checkpoint finalizedCheckpoint,
      final Checkpoint bestJustifiedCheckpoint,
      final Map<Bytes32, Bytes32> childToParentRoot,
      final Map<Bytes32, UInt64> rootToSlotMap,
      final SignedBlockAndState finalizedBlockAndState,
      final Map<UInt64, VoteTracker> votes,
      final StoreConfig config) {

    // Create limited collections for non-final data
    final Map<Bytes32, SignedBeaconBlock> blocks = LimitedMap.create(config.getBlockCacheSize());
    final CachingTaskQueue<Checkpoint, BeaconState> checkpointStateTaskQueue =
        CachingTaskQueue.create(
            asyncRunner,
            metricsSystem,
            "memory_checkpoint_states",
            config.getCheckpointStateCacheSize());
    final CachingTaskQueue<Bytes32, SignedBlockAndState> stateTaskQueue =
        CachingTaskQueue.create(
            asyncRunner, metricsSystem, "memory_states", config.getStateCacheSize());

    // Build block tree structure
    HashTree.Builder treeBuilder = HashTree.builder().rootHash(finalizedBlockAndState.getRoot());
    childToParentRoot.forEach(treeBuilder::childAndParentRoots);
    final BlockTree blockTree = BlockTree.create(treeBuilder.build(), rootToSlotMap);
    if (blockTree.size() < childToParentRoot.size()) {
      // This should be an error, but keeping this as a warning now for backwards-compatibility
      // reasons.  Some existing databases may have unpruned fork blocks, and could become
      // unusable
      // if we throw here.  In the future, we should convert this to an error.
      LOG.warn("Ignoring {} non-canonical blocks", childToParentRoot.size() - blockTree.size());
    }

    return SafeFuture.completedFuture(
        new Store(
            metricsSystem,
            config.getHotStatePersistenceFrequencyInEpochs(),
            blockProvider,
            stateAndBlockProvider,
            stateTaskQueue,
            time,
            genesisTime,
            justifiedCheckpoint,
            finalizedCheckpoint,
            bestJustifiedCheckpoint,
            blockTree,
            finalizedBlockAndState,
            votes,
            blocks,
            checkpointStateTaskQueue));
  }

  private  Store(
      final MetricsSystem metricsSystem,
      int hotStatePersistenceFrequencyInEpochs,
      final BlockProvider blockProvider,
      final StateAndBlockProvider stateAndBlockProvider,
      final CachingTaskQueue<Bytes32, SignedBlockAndState> states,
      final UInt64 time,
      final UInt64 genesis_time,
      final Checkpoint justified_checkpoint,
      final Checkpoint finalized_checkpoint,
      final Checkpoint best_justified_checkpoint,
      final BlockTree blockTree,
      final SignedBlockAndState finalizedBlockAndState,
      final Map<UInt64, VoteTracker> votes,
      final Map<Bytes32, SignedBeaconBlock> blocks,
      final CachingTaskQueue<Checkpoint, BeaconState> checkpointStates);

}