All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hedera.node.app.statedumpers.StateDumper Maven / Gradle / Ivy

There is a newer version: 0.57.3
Show newest version
/*
 * Copyright (C) 2024 Hedera Hashgraph, LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.hedera.node.app.statedumpers;

import static com.hedera.node.app.ids.schemas.V0490EntityIdSchema.ENTITY_ID_STATE_KEY;
import static com.hedera.node.app.records.schemas.V0490BlockRecordSchema.BLOCK_INFO_STATE_KEY;
import static com.hedera.node.app.records.schemas.V0490BlockRecordSchema.RUNNING_HASHES_STATE_KEY;
import static com.hedera.node.app.service.schedule.impl.schemas.V0490ScheduleSchema.SCHEDULES_BY_EQUALITY_KEY;
import static com.hedera.node.app.service.schedule.impl.schemas.V0490ScheduleSchema.SCHEDULES_BY_EXPIRY_SEC_KEY;
import static com.hedera.node.app.service.schedule.impl.schemas.V0490ScheduleSchema.SCHEDULES_BY_ID_KEY;
import static com.hedera.node.app.service.token.impl.schemas.V0490TokenSchema.ACCOUNTS_KEY;
import static com.hedera.node.app.service.token.impl.schemas.V0490TokenSchema.NFTS_KEY;
import static com.hedera.node.app.service.token.impl.schemas.V0490TokenSchema.STAKING_INFO_KEY;
import static com.hedera.node.app.service.token.impl.schemas.V0490TokenSchema.STAKING_NETWORK_REWARDS_KEY;
import static com.hedera.node.app.service.token.impl.schemas.V0490TokenSchema.TOKENS_KEY;
import static com.hedera.node.app.service.token.impl.schemas.V0490TokenSchema.TOKEN_RELS_KEY;
import static com.hedera.node.app.state.recordcache.schemas.V0490RecordCacheSchema.TXN_RECORD_QUEUE;
import static com.hedera.node.app.statedumpers.accounts.AccountDumpUtils.dumpModAccounts;
import static com.hedera.node.app.statedumpers.associations.TokenAssociationsDumpUtils.dumpModTokenRelations;
import static com.hedera.node.app.statedumpers.contracts.ContractBytecodesDumpUtils.dumpModContractBytecodes;
import static com.hedera.node.app.statedumpers.files.FilesDumpUtils.dumpModFiles;
import static com.hedera.node.app.statedumpers.nfts.UniqueTokenDumpUtils.dumpModUniqueTokens;
import static com.hedera.node.app.statedumpers.scheduledtransactions.ScheduledTransactionsDumpUtils.dumpModScheduledTransactions;
import static com.hedera.node.app.statedumpers.singleton.BlockInfoDumpUtils.dumpModBlockInfo;
import static com.hedera.node.app.statedumpers.singleton.CongestionDumpUtils.dumpModCongestion;
import static com.hedera.node.app.statedumpers.singleton.PayerRecordsDumpUtils.dumpModTxnRecordQueue;
import static com.hedera.node.app.statedumpers.singleton.StakingInfoDumpUtils.dumpModStakingInfo;
import static com.hedera.node.app.statedumpers.singleton.StakingRewardsDumpUtils.dumpModStakingRewards;
import static com.hedera.node.app.statedumpers.tokentypes.TokenTypesDumpUtils.dumpModTokenType;
import static com.hedera.node.app.statedumpers.topics.TopicDumpUtils.dumpModTopics;
import static com.hedera.node.app.throttle.schemas.V0490CongestionThrottleSchema.CONGESTION_LEVEL_STARTS_STATE_KEY;
import static com.hedera.node.app.throttle.schemas.V0490CongestionThrottleSchema.THROTTLE_USAGE_SNAPSHOTS_STATE_KEY;
import static java.util.Objects.requireNonNull;

import com.hedera.hapi.node.base.AccountID;
import com.hedera.hapi.node.base.ContractID;
import com.hedera.hapi.node.base.FileID;
import com.hedera.hapi.node.base.NftID;
import com.hedera.hapi.node.base.ScheduleID;
import com.hedera.hapi.node.base.TokenID;
import com.hedera.hapi.node.base.TopicID;
import com.hedera.hapi.node.state.blockrecords.BlockInfo;
import com.hedera.hapi.node.state.blockrecords.RunningHashes;
import com.hedera.hapi.node.state.common.EntityIDPair;
import com.hedera.hapi.node.state.common.EntityNumber;
import com.hedera.hapi.node.state.congestion.CongestionLevelStarts;
import com.hedera.hapi.node.state.consensus.Topic;
import com.hedera.hapi.node.state.contract.Bytecode;
import com.hedera.hapi.node.state.primitives.ProtoBytes;
import com.hedera.hapi.node.state.primitives.ProtoLong;
import com.hedera.hapi.node.state.recordcache.TransactionRecordEntry;
import com.hedera.hapi.node.state.schedule.Schedule;
import com.hedera.hapi.node.state.schedule.ScheduleList;
import com.hedera.hapi.node.state.throttles.ThrottleUsageSnapshots;
import com.hedera.hapi.node.state.token.Account;
import com.hedera.hapi.node.state.token.NetworkStakingRewards;
import com.hedera.hapi.node.state.token.Nft;
import com.hedera.hapi.node.state.token.StakingNodeInfo;
import com.hedera.hapi.node.state.token.Token;
import com.hedera.hapi.node.state.token.TokenRelation;
import com.hedera.node.app.ids.EntityIdService;
import com.hedera.node.app.records.BlockRecordService;
import com.hedera.node.app.service.consensus.ConsensusService;
import com.hedera.node.app.service.consensus.impl.ConsensusServiceImpl;
import com.hedera.node.app.service.contract.ContractService;
import com.hedera.node.app.service.contract.impl.schemas.V0490ContractSchema;
import com.hedera.node.app.service.file.FileService;
import com.hedera.node.app.service.file.impl.schemas.V0490FileSchema;
import com.hedera.node.app.service.schedule.ScheduleService;
import com.hedera.node.app.service.token.TokenService;
import com.hedera.node.app.state.recordcache.RecordCacheService;
import com.hedera.node.app.throttle.CongestionThrottleService;
import com.swirlds.platform.state.MerkleStateRoot;
import com.swirlds.state.State;
import com.swirlds.state.merkle.StateMetadata;
import com.swirlds.state.merkle.disk.OnDiskKey;
import com.swirlds.state.merkle.disk.OnDiskValue;
import com.swirlds.state.merkle.queue.QueueNode;
import com.swirlds.state.merkle.singleton.SingletonNode;
import com.swirlds.virtualmap.VirtualMap;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.io.File;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.Optional;
import java.util.Set;

/**
 * A utility class for dumping the state of the {@link MerkleStateRoot} to a directory.
 */
public class StateDumper {
    private static final String SEMANTIC_UNIQUE_TOKENS = "uniqueTokens.txt";
    private static final String SEMANTIC_TOKEN_RELATIONS = "tokenRelations.txt";
    private static final String SEMANTIC_FILES = "files.txt";
    private static final String SEMANTIC_ACCOUNTS = "accounts.txt";
    private static final String SEMANTIC_CONTRACT_BYTECODES = "contractBytecodes.txt";
    private static final String SEMANTIC_TOPICS = "topics.txt";
    private static final String SEMANTIC_SCHEDULED_TRANSACTIONS = "scheduledTransactions.txt";
    private static final String SEMANTIC_TOKEN_TYPE = "tokenTypes.txt";

    private static final String SEMANTIC_BLOCK = "blockInfo.txt";
    private static final String SEMANTIC_STAKING_INFO = "stakingInfo.txt";
    private static final String SEMANTIC_STAKING_REWARDS = "stakingRewards.txt";
    private static final String SEMANTIC_TXN_RECORD_QUEUE = "transactionRecords.txt";
    private static final String SEMANTIC_CONGESTION = "congestion.txt";

    public static void dumpModChildrenFrom(
            @NonNull final State state,
            @NonNull final DumpCheckpoint checkpoint,
            @NonNull final Set childrenToDump) {
        if (!(state instanceof MerkleStateRoot merkleState)) {
            throw new IllegalArgumentException("Expected a " + MerkleStateRoot.class.getSimpleName());
        }
        final SingletonNode blockInfoNode = requireNonNull(
                merkleState.getChild(merkleState.findNodeIndex(BlockRecordService.NAME, BLOCK_INFO_STATE_KEY)));
        final var blockInfo = blockInfoNode.getValue();
        final var dumpLoc = getExtantDumpLoc(
                "mod",
                Optional.ofNullable(blockInfo.consTimeOfLastHandledTxn())
                        .map(then -> Instant.ofEpochSecond(then.seconds(), then.nanos()))
                        .orElse(null));

        if (childrenToDump.contains(MerkleStateChild.NFTS)) {
            final VirtualMap, OnDiskValue> uniqueTokens =
                    requireNonNull(merkleState.getChild(merkleState.findNodeIndex(TokenService.NAME, NFTS_KEY)));
            dumpModUniqueTokens(Paths.get(dumpLoc, SEMANTIC_UNIQUE_TOKENS), uniqueTokens, checkpoint);
        }

        if (childrenToDump.contains(MerkleStateChild.TOKEN_RELS)) {
            final VirtualMap, OnDiskValue> tokenRelations =
                    requireNonNull(merkleState.getChild(merkleState.findNodeIndex(TokenService.NAME, TOKEN_RELS_KEY)));
            dumpModTokenRelations(Paths.get(dumpLoc, SEMANTIC_TOKEN_RELATIONS), tokenRelations, checkpoint);
        }

        if (childrenToDump.contains(MerkleStateChild.FILES)) {
            final VirtualMap, OnDiskValue> files =
                    requireNonNull(merkleState.getChild(
                            merkleState.findNodeIndex(FileService.NAME, V0490FileSchema.BLOBS_KEY)));
            dumpModFiles(Paths.get(dumpLoc, SEMANTIC_FILES), files, checkpoint);
        }

        if (childrenToDump.contains(MerkleStateChild.ACCOUNTS)) {
            final VirtualMap, OnDiskValue> accounts =
                    requireNonNull(merkleState.getChild(merkleState.findNodeIndex(TokenService.NAME, ACCOUNTS_KEY)));
            dumpModAccounts(Paths.get(dumpLoc, SEMANTIC_ACCOUNTS), accounts, checkpoint);
        }

        if (childrenToDump.contains(MerkleStateChild.BYTECODE)) {
            final VirtualMap, OnDiskValue> accounts =
                    requireNonNull(merkleState.getChild(merkleState.findNodeIndex(TokenService.NAME, ACCOUNTS_KEY)));
            final VirtualMap, OnDiskValue> byteCodes =
                    requireNonNull(merkleState.getChild(
                            merkleState.findNodeIndex(ContractService.NAME, V0490ContractSchema.BYTECODE_KEY)));
            dumpModContractBytecodes(
                    Paths.get(dumpLoc, SEMANTIC_CONTRACT_BYTECODES),
                    byteCodes,
                    accounts,
                    (StateMetadata)
                            merkleState.getServices().get(TokenService.NAME).get(ACCOUNTS_KEY),
                    checkpoint);
        }

        if (childrenToDump.contains(MerkleStateChild.TOPICS)) {
            final VirtualMap, OnDiskValue> topics = requireNonNull(merkleState.getChild(
                    merkleState.findNodeIndex(ConsensusService.NAME, ConsensusServiceImpl.TOPICS_KEY)));
            dumpModTopics(Paths.get(dumpLoc, SEMANTIC_TOPICS), topics, checkpoint);
        }

        if (childrenToDump.contains(MerkleStateChild.SCHEDULED_TRANSACTIONS)) {
            final VirtualMap, OnDiskValue> scheduledTransactionsByKey = requireNonNull(
                    merkleState.getChild(merkleState.findNodeIndex(ScheduleService.NAME, SCHEDULES_BY_ID_KEY)));
            final VirtualMap, OnDiskValue> scheduledTransactionsByEquality =
                    requireNonNull(merkleState.getChild(
                            merkleState.findNodeIndex(ScheduleService.NAME, SCHEDULES_BY_EQUALITY_KEY)));
            final VirtualMap, OnDiskValue> scheduledTransactionsByExpiry =
                    requireNonNull(merkleState.getChild(
                            merkleState.findNodeIndex(ScheduleService.NAME, SCHEDULES_BY_EXPIRY_SEC_KEY)));
            dumpModScheduledTransactions(
                    Paths.get(dumpLoc, SEMANTIC_SCHEDULED_TRANSACTIONS),
                    scheduledTransactionsByKey,
                    scheduledTransactionsByEquality,
                    scheduledTransactionsByExpiry);
        }

        if (childrenToDump.contains(MerkleStateChild.TOKENS)) {
            final VirtualMap, OnDiskValue> tokenTypes =
                    requireNonNull(merkleState.getChild(merkleState.findNodeIndex(TokenService.NAME, TOKENS_KEY)));
            dumpModTokenType(Paths.get(dumpLoc, SEMANTIC_TOKEN_TYPE), tokenTypes, checkpoint);
        }

        if (childrenToDump.contains(MerkleStateChild.BLOCK_METADATA)) {
            final SingletonNode runningHashesSingleton = requireNonNull(
                    merkleState.getChild(merkleState.findNodeIndex(BlockRecordService.NAME, RUNNING_HASHES_STATE_KEY)));
            final SingletonNode blocksStateSingleton = requireNonNull(
                    merkleState.getChild(merkleState.findNodeIndex(BlockRecordService.NAME, BLOCK_INFO_STATE_KEY)));
            final SingletonNode entityIdSingleton = requireNonNull(
                    merkleState.getChild(merkleState.findNodeIndex(EntityIdService.NAME, ENTITY_ID_STATE_KEY)));
            dumpModBlockInfo(
                    Paths.get(dumpLoc, SEMANTIC_BLOCK),
                    runningHashesSingleton.getValue(),
                    blocksStateSingleton.getValue(),
                    entityIdSingleton.getValue(),
                    checkpoint);
        }

        if (childrenToDump.contains(MerkleStateChild.STAKING_INFOS)) {
            final VirtualMap, OnDiskValue> stakingInfoMap = requireNonNull(
                    merkleState.getChild(merkleState.findNodeIndex(TokenService.NAME, STAKING_INFO_KEY)));
            dumpModStakingInfo(Paths.get(dumpLoc, SEMANTIC_STAKING_INFO), stakingInfoMap);
        }

        if (childrenToDump.contains(MerkleStateChild.STAKING_NETWORK_METADATA)) {
            final SingletonNode stakingRewards = requireNonNull(
                    merkleState.getChild(merkleState.findNodeIndex(TokenService.NAME, STAKING_NETWORK_REWARDS_KEY)));
            dumpModStakingRewards(Paths.get(dumpLoc, SEMANTIC_STAKING_REWARDS), stakingRewards.getValue());
        }

        if (childrenToDump.contains(MerkleStateChild.TRANSACTION_RECORD_QUEUE)) {
            final QueueNode queue = requireNonNull(
                    merkleState.getChild(merkleState.findNodeIndex(RecordCacheService.NAME, TXN_RECORD_QUEUE)));
            dumpModTxnRecordQueue(Paths.get(dumpLoc, SEMANTIC_TXN_RECORD_QUEUE), queue);
        }

        if (childrenToDump.contains(MerkleStateChild.THROTTLE_METADATA)) {
            final SingletonNode congestionLevelStartsSingletonNode =
                    requireNonNull(merkleState.getChild(merkleState.findNodeIndex(
                            CongestionThrottleService.NAME, CONGESTION_LEVEL_STARTS_STATE_KEY)));
            final SingletonNode throttleUsageSnapshotsSingletonNode =
                    requireNonNull(merkleState.getChild(merkleState.findNodeIndex(
                            CongestionThrottleService.NAME, THROTTLE_USAGE_SNAPSHOTS_STATE_KEY)));
            dumpModCongestion(
                    Paths.get(dumpLoc, SEMANTIC_CONGESTION),
                    congestionLevelStartsSingletonNode.getValue(),
                    throttleUsageSnapshotsSingletonNode.getValue());
        }
    }

    private static String getExtantDumpLoc(
            @NonNull final String stateType, @Nullable final Instant lastHandledConsensusTime) {
        final var dumpLoc = dirFor(stateType, lastHandledConsensusTime);
        new File(dumpLoc).mkdirs();
        return dumpLoc;
    }

    private static String dirFor(@NonNull final String stateType, @Nullable final Instant lastHandledConsensusTime) {
        final var effectiveTime = lastHandledConsensusTime == null ? Instant.EPOCH : lastHandledConsensusTime;
        return String.format("%s-%s", stateType, effectiveTime.toString().replace(":", "_"));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy