Search in sources :

Example 76 with ByteArrayWrapper

use of org.aion.util.types.ByteArrayWrapper in project aion by aionnetwork.

the class AionBlockchainImpl method load.

/**
 * Loads the block chain attempting recovery if necessary and returns the starting block.
 *
 * @param genesis the expected genesis block
 * @param genLOG logger for output messages
 */
public void load(AionGenesis genesis, Logger genLOG) {
    // function repurposed for integrity checks since previously not implemented
    try {
        repository.getBlockStore().load();
    } catch (RuntimeException re) {
        genLOG.error("Fatal: can't load blockstore; exiting.", re);
        System.exit(org.aion.zero.impl.SystemExitCodes.INITIALIZATION_ERROR);
    }
    // Note: if block DB corruption, the bestBlock may not match with the indexDB.
    Block bestBlock = repository.getBestBlock();
    // AKI-716
    if (bestBlock != null && forkUtility.isSignatureSwapForkActive(bestBlock.getNumber())) {
        HashUtil.setAfterSignatureSwap();
    }
    boolean recovered = true;
    boolean bestBlockShifted = true;
    int countRecoveryAttempts = 0;
    // recover only for non-null blocks
    while (bestBlockShifted && countRecoveryAttempts < 5 && bestBlock != null && !repository.isValidRoot(bestBlock.getStateRoot())) {
        genLOG.info("Recovery initiated due to corrupt world state at block " + bestBlock.getNumber() + ".");
        long bestBlockNumber = bestBlock.getNumber();
        byte[] bestBlockRoot = bestBlock.getStateRoot();
        // ensure that the genesis state exists before attempting recovery
        if (!repository.isValidRoot(genesis.getStateRoot())) {
            genLOG.info("Corrupt world state for genesis block hash: " + genesis.getShortHash() + ", number: " + genesis.getNumber() + ".");
            repository.buildGenesis(genesis);
            if (repository.isValidRoot(genesis.getStateRoot())) {
                genLOG.info("Rebuilding genesis block SUCCEEDED.");
            } else {
                genLOG.info("Rebuilding genesis block FAILED.");
            }
        }
        recovered = recoverWorldState(repository, bestBlock);
        if (recovered && !repository.isIndexed(bestBlock.getHash(), bestBlock.getNumber())) {
            // correct the index for this block
            recovered = recoverIndexEntry(repository, bestBlock);
        }
        long blockNumber = bestBlock.getNumber();
        if (!repository.isValidRoot(bestBlock.getStateRoot())) {
            // reverting back one block
            genLOG.info("Rebuild state FAILED. Reverting to previous block.");
            --blockNumber;
            boolean isSuccessful = getRepository().revertTo(blockNumber, genLOG);
            recovered = isSuccessful && repository.isValidRoot(getBlockByNumber(blockNumber).getStateRoot());
        }
        if (recovered) {
            // reverting block & index DB
            repository.getBlockStore().rollback(blockNumber);
            // new best block after recovery
            bestBlock = repository.getBestBlock();
            if (bestBlock != null) {
                bestBlock.setTotalDifficulty(getTotalDifficultyForHash(bestBlock.getHash()));
                // TODO : [unity] The publicbestblock is a weird settings, should consider to remove it.
                resetPubBestBlock(bestBlock);
            } else {
                genLOG.error("Recovery failed! please re-import your database by ./aion.sh -n <network> --redo-import, it will take a while.");
                throw new IllegalStateException("Recovery failed due to database corruption.");
            }
            // checking is the best block has changed since attempting recovery
            bestBlockShifted = // block number changed
            !(bestBlockNumber == bestBlock.getNumber()) || // root hash changed
            !(Arrays.equals(bestBlockRoot, bestBlock.getStateRoot()));
            if (bestBlockShifted) {
                genLOG.info("Rebuilding world state SUCCEEDED by REVERTING to a previous block.");
            } else {
                genLOG.info("Rebuilding world state SUCCEEDED.");
            }
        } else {
            genLOG.error("Rebuilding world state FAILED. " + "Stop the kernel (Ctrl+C) and use the command line revert option to move back to a valid block. " + "Check the Aion wiki for recommendations on choosing the block number.");
        }
        countRecoveryAttempts++;
    }
    // rebuild from genesis if (1) no best block (2) recovery failed
    if (bestBlock == null || !recovered) {
        if (bestBlock == null) {
            genLOG.info("DB is empty - adding Genesis");
        } else {
            genLOG.info("DB could not be recovered - adding Genesis");
        }
        repository.buildGenesis(genesis);
        setBestBlock(genesis);
        setTotalDifficulty(genesis.getDifficultyBI());
        if (genesis.getTotalDifficulty().equals(BigInteger.ZERO)) {
            // setting the object runtime value
            genesis.setTotalDifficulty(genesis.getDifficultyBI());
        }
    } else {
        setBestBlock(bestBlock);
        if (bestBlock instanceof StakingBlock) {
            loadBestMiningBlock();
        } else if (bestBlock instanceof MiningBlock) {
            loadBestStakingBlock();
        } else {
            throw new IllegalStateException();
        }
        BigInteger totalDifficulty = repository.getBlockStore().getBestBlockWithInfo().getTotalDifficulty();
        setTotalDifficulty(totalDifficulty);
        if (bestBlock.getTotalDifficulty().equals(BigInteger.ZERO)) {
            // setting the object runtime value
            bestBlock.setTotalDifficulty(totalDifficulty);
        }
        genLOG.info("loaded block <num={}, root={}, td={}>", getBestBlock().getNumber(), LogUtil.toHexF8(getBestBlock().getStateRoot()), getTotalDifficulty());
    }
    ByteArrayWrapper genesisHash = genesis.getHashWrapper();
    ByteArrayWrapper databaseGenHash = getBlockByNumber(0) == null ? null : getBlockByNumber(0).getHashWrapper();
    // this indicates that DB and genesis are inconsistent
    if (genesisHash == null || databaseGenHash == null || !genesisHash.equals(databaseGenHash)) {
        if (genesisHash == null) {
            genLOG.error("failed to load genesis from config");
        }
        if (databaseGenHash == null) {
            genLOG.error("failed to load block 0 from database");
        }
        genLOG.error("genesis json rootHash {} is inconsistent with database rootHash {}\n" + "your configuration and genesis are incompatible, please do the following:\n" + "\t1) Remove your database folder\n" + "\t2) Verify that your genesis is correct by re-downloading the binary or checking online\n" + "\t3) Reboot with correct genesis and empty database\n", genesisHash == null ? "null" : genesisHash, databaseGenHash == null ? "null" : databaseGenHash);
        System.exit(org.aion.zero.impl.SystemExitCodes.INITIALIZATION_ERROR);
    }
    if (!Arrays.equals(getBestBlock().getStateRoot(), ConstantUtil.EMPTY_TRIE_HASH)) {
        repository.syncToRoot(getBestBlock().getStateRoot());
    }
    long bestNumber = getBestBlock().getNumber();
    if (forkUtility.isNonceForkActive(bestNumber + 1)) {
        // Reset the PoS difficulty as part of the fork logic.
        if (bestNumber == forkUtility.getNonceForkBlockHeight()) {
            // If this is the trigger for the fork calculate the new difficulty.
            Block block = getBestBlock();
            BigInteger newDiff = calculateFirstPoSDifficultyAtBlock(block);
            forkUtility.setNonceForkResetDiff(newDiff);
        } else {
            // Otherwise, assume that it was already calculated and validated during import.
            // The difficulty cannot be calculated here due to possible pruning of the world state.
            Block firstStaked = getBlockByNumber(forkUtility.getNonceForkBlockHeight() + 1);
            forkUtility.setNonceForkResetDiff(firstStaked.getDifficultyBI());
        }
    }
}
Also used : ByteArrayWrapper(org.aion.util.types.ByteArrayWrapper) Block(org.aion.zero.impl.types.Block) BlockDetailsValidator.isValidBlock(org.aion.zero.impl.valid.BlockDetailsValidator.isValidBlock) GenesisStakingBlock(org.aion.zero.impl.types.GenesisStakingBlock) RetValidPreBlock(org.aion.zero.impl.types.RetValidPreBlock) MiningBlock(org.aion.zero.impl.types.MiningBlock) EventBlock(org.aion.evtmgr.impl.evt.EventBlock) StakingBlock(org.aion.zero.impl.types.StakingBlock) BigInteger(java.math.BigInteger) MiningBlock(org.aion.zero.impl.types.MiningBlock) GenesisStakingBlock(org.aion.zero.impl.types.GenesisStakingBlock) StakingBlock(org.aion.zero.impl.types.StakingBlock)

Example 77 with ByteArrayWrapper

use of org.aion.util.types.ByteArrayWrapper in project aion by aionnetwork.

the class AionBlockchainImpl method getTransactionInfo.

@Override
public /* NOTE: only returns receipts from the main chain */
AionTxInfo getTransactionInfo(byte[] hash) {
    // Try to get info if the hash is from an invokable transaction
    Map<ByteArrayWrapper, AionTxInfo> infos = getTransactionInfoByAlias(hash);
    // If we didn't find the alias for an invokable
    if (infos == null || infos.isEmpty()) {
        infos = transactionStore.getTxInfo(hash);
    }
    if (infos == null || infos.isEmpty()) {
        return null;
    }
    AionTxInfo txInfo = null;
    // pick up the receipt from the block on the main chain
    for (ByteArrayWrapper blockHash : infos.keySet()) {
        if (!isMainChain(blockHash.toBytes())) {
            continue;
        } else {
            txInfo = infos.get(blockHash);
            break;
        }
    }
    if (txInfo == null) {
        LOG.warn("Can't find block from main chain for transaction " + toHexString(hash));
        return null;
    }
    AionTransaction tx = this.getBlockByHash(txInfo.getBlockHash()).getTransactionsList().get(txInfo.getIndex());
    txInfo.setTransaction(tx);
    return txInfo;
}
Also used : ByteArrayWrapper(org.aion.util.types.ByteArrayWrapper) AionTxInfo(org.aion.zero.impl.types.AionTxInfo) AionTransaction(org.aion.base.AionTransaction)

Example 78 with ByteArrayWrapper

use of org.aion.util.types.ByteArrayWrapper in project aion by aionnetwork.

the class AionImpl method getStorageValue.

@Override
public Optional<ByteArrayWrapper> getStorageValue(AionAddress address, ByteArrayWrapper key) {
    Objects.requireNonNull(address);
    Objects.requireNonNull(key);
    ByteArrayWrapper values = aionHub.getRepository().getStorageValue(address, key);
    return values == null ? Optional.empty() : Optional.of(values);
}
Also used : ByteArrayWrapper(org.aion.util.types.ByteArrayWrapper)

Example 79 with ByteArrayWrapper

use of org.aion.util.types.ByteArrayWrapper in project aion by aionnetwork.

the class ResponseTrieDataTest method correctParameters.

/**
 * Parameters for testing:
 *
 * <ul>
 *   <li>{@link #testDecode_correct(ByteArrayWrapper, byte[], Map, DatabaseType)}
 *   <li>{@link #testEncode_4Parameters_correct(ByteArrayWrapper, byte[], Map, DatabaseType)}
 *   <li>{@link #testEncodeDecode(ByteArrayWrapper, byte[], Map, DatabaseType)}
 * </ul>
 */
@SuppressWarnings("unused")
private Object correctParameters() {
    List<Object> parameters = new ArrayList<>();
    ByteArrayWrapper[] keyOptions = new ByteArrayWrapper[] { wrappedNodeKey, wrappedAltNodeKey, wrappedZeroNodeKey };
    byte[][] valueOptions = new byte[][] { leafValue, branchValue, extensionValue };
    Object[] refOptions = new Object[] { emptyReferences, singleReference, multipleReferences };
    DatabaseType[] dbOptions = new DatabaseType[] { STATE, STORAGE, DETAILS };
    // network and directory
    String[] net_values = new String[] { "mainnet", "invalid" };
    for (ByteArrayWrapper key : keyOptions) {
        for (byte[] value : valueOptions) {
            for (Object refs : refOptions) {
                for (DatabaseType db : dbOptions) {
                    parameters.add(new Object[] { key, value, refs, db });
                }
            }
        }
    }
    return parameters.toArray();
}
Also used : ByteArrayWrapper(org.aion.util.types.ByteArrayWrapper) DatabaseType(org.aion.zero.impl.sync.DatabaseType) ArrayList(java.util.ArrayList)

Example 80 with ByteArrayWrapper

use of org.aion.util.types.ByteArrayWrapper in project aion by aionnetwork.

the class ResponseTrieDataTest method correct3Parameters.

/**
 * Parameters for testing:
 *
 * <ul>
 *   <li>{@link #testEncode_3Parameters_correct(ByteArrayWrapper, byte[], DatabaseType)}
 *   <li>{@link #testEncodeDecode_3Parameters(ByteArrayWrapper, byte[], DatabaseType)}
 * </ul>
 */
@SuppressWarnings("unused")
private Object correct3Parameters() {
    List<Object> parameters = new ArrayList<>();
    ByteArrayWrapper[] keyOptions = new ByteArrayWrapper[] { wrappedNodeKey, wrappedAltNodeKey, wrappedZeroNodeKey };
    byte[][] valueOptions = new byte[][] { leafValue, branchValue, extensionValue };
    DatabaseType[] dbOptions = new DatabaseType[] { STATE, STORAGE, DETAILS };
    // network and directory
    String[] net_values = new String[] { "mainnet", "invalid" };
    for (ByteArrayWrapper key : keyOptions) {
        for (byte[] value : valueOptions) {
            for (DatabaseType db : dbOptions) {
                parameters.add(new Object[] { key, value, db });
            }
        }
    }
    return parameters.toArray();
}
Also used : ByteArrayWrapper(org.aion.util.types.ByteArrayWrapper) DatabaseType(org.aion.zero.impl.sync.DatabaseType) ArrayList(java.util.ArrayList)

Aggregations

ByteArrayWrapper (org.aion.util.types.ByteArrayWrapper)130 Test (org.junit.Test)51 HashMap (java.util.HashMap)39 ArrayList (java.util.ArrayList)33 AionAddress (org.aion.types.AionAddress)26 Block (org.aion.zero.impl.types.Block)24 Map (java.util.Map)20 BigInteger (java.math.BigInteger)14 MiningBlock (org.aion.zero.impl.types.MiningBlock)14 IOException (java.io.IOException)13 MockDB (org.aion.db.impl.mockdb.MockDB)13 DataWord (org.aion.util.types.DataWord)13 PooledTransaction (org.aion.base.PooledTransaction)11 List (java.util.List)10 AionTransaction (org.aion.base.AionTransaction)10 Properties (java.util.Properties)8 HashSet (java.util.HashSet)5 Optional (java.util.Optional)5 ECKey (org.aion.crypto.ECKey)5 RLPElement (org.aion.rlp.RLPElement)5