Search in sources :

Example 11 with AionRepositoryImpl

use of org.aion.zero.impl.db.AionRepositoryImpl in project aion by aionnetwork.

the class AionBlockchainImpl method recoverWorldState.

@Override
public synchronized boolean recoverWorldState(IRepository repository, long blockNumber) {
    AionRepositoryImpl repo = (AionRepositoryImpl) repository;
    Map<Long, AionBlock> dirtyBlocks = new HashMap<>();
    AionBlock other;
    // find all the blocks missing a world state
    long index = blockNumber;
    do {
        other = repo.getBlockStore().getChainBlockByNumber(index);
        // cannot recover if no valid states exist (must build from genesis)
        if (other == null) {
            return false;
        } else {
            dirtyBlocks.put(other.getNumber(), other);
            index--;
        }
    } while (!repo.isValidRoot(other.getStateRoot()));
    // sync to the last correct state
    repo.syncToRoot(other.getStateRoot());
    // remove the last added block because it has a correct world state
    index = other.getNumber();
    dirtyBlocks.remove(index);
    LOG.info("Corrupt world state at block #" + blockNumber + ". Rebuilding from block #" + index + ".");
    index++;
    // rebuild world state for dirty blocks
    while (!dirtyBlocks.isEmpty()) {
        LOG.info("Rebuilding block #" + index + ".");
        other = dirtyBlocks.remove(index);
        this.add(other, true);
        index++;
    }
    // update the repository
    repo.flush();
    // return a flag indicating if the recovery worked
    if (repo.isValidRoot(repo.getBlockStore().getChainBlockByNumber(blockNumber).getStateRoot())) {
        return true;
    } else {
        // reverting back one block
        LOG.info("Rebuild FAILED. Reverting to previous block.");
        RecoveryUtils.Status status = RecoveryUtils.revertTo(this, blockNumber - 1);
        return (status == RecoveryUtils.Status.SUCCESS) && repo.isValidRoot(repo.getBlockStore().getChainBlockByNumber(blockNumber - 1).getStateRoot());
    }
}
Also used : RecoveryUtils(org.aion.zero.impl.db.RecoveryUtils) AionRepositoryImpl(org.aion.zero.impl.db.AionRepositoryImpl) AionBlock(org.aion.zero.impl.types.AionBlock)

Example 12 with AionRepositoryImpl

use of org.aion.zero.impl.db.AionRepositoryImpl in project aion by aionnetwork.

the class AionBlockchainImpl method storeBlock.

@Override
public synchronized void storeBlock(AionBlock block, List<AionTxReceipt> receipts) {
    if (fork) {
        getBlockStore().saveBlock(block, totalDifficulty, false);
    } else {
        getBlockStore().saveBlock(block, totalDifficulty, true);
    }
    for (int i = 0; i < receipts.size(); i++) {
        transactionStore.put(new AionTxInfo(receipts.get(i), block.getHash(), i));
    }
    ((AionRepositoryImpl) repository).commitBlock(block.getHeader());
    if (LOG.isDebugEnabled())
        LOG.debug("Block saved: number: {}, hash: {}, TD: {}", block.getNumber(), block.getShortHash(), totalDifficulty);
    setBestBlock(block);
    if (LOG.isDebugEnabled()) {
        LOG.debug("block added to the blockChain: index: [{}]", block.getNumber());
    }
}
Also used : AionTxInfo(org.aion.zero.impl.types.AionTxInfo) AionRepositoryImpl(org.aion.zero.impl.db.AionRepositoryImpl)

Example 13 with AionRepositoryImpl

use of org.aion.zero.impl.db.AionRepositoryImpl in project aion by aionnetwork.

the class AionBlockchainImpl method add.

public synchronized AionBlockSummary add(AionBlock block, boolean rebuild) {
    if (block == null) {
        LOG.error("Attempting to add NULL block.");
        return null;
    }
    if (exitOn < block.getNumber()) {
        LOG.error("Exiting after block.number: ", bestBlock.getNumber());
        flush();
        System.exit(-1);
    }
    if (!isValid(block)) {
        LOG.error("Attempting to add INVALID block.");
        return null;
    }
    track = repository.startTracking();
    byte[] origRoot = repository.getRoot();
    // (if not reconstructing old blocks) keep chain continuity
    if (!rebuild && !Arrays.equals(bestBlock.getHash(), block.getParentHash())) {
        LOG.error("Attempting to add NON-SEQUENTIAL block.");
        return null;
    }
    AionBlockSummary summary = processBlock(block);
    List<AionTxReceipt> receipts = summary.getReceipts();
    // Sanity checks
    byte[] receiptHash = block.getReceiptsRoot();
    byte[] receiptListHash = calcReceiptsTrie(receipts);
    if (!Arrays.equals(receiptHash, receiptListHash)) {
        if (LOG.isWarnEnabled()) {
            LOG.warn("Block's given Receipt Hash doesn't match: {} != {}", receiptHash, receiptListHash);
            LOG.warn("Calculated receipts: " + receipts);
        }
        return null;
    }
    byte[] logBloomHash = block.getLogBloom();
    byte[] logBloomListHash = calcLogBloom(receipts);
    if (!Arrays.equals(logBloomHash, logBloomListHash)) {
        if (LOG.isWarnEnabled())
            LOG.warn("Block's given logBloom Hash doesn't match: {} != {}", ByteUtil.toHexString(logBloomHash), ByteUtil.toHexString(logBloomListHash));
        track.rollback();
        return null;
    }
    if (!rebuild) {
        byte[] blockStateRootHash = block.getStateRoot();
        byte[] worldStateRootHash = repository.getRoot();
        if (!Arrays.equals(blockStateRootHash, worldStateRootHash)) {
            LOG.warn("BLOCK: State conflict or received invalid block. block: {} worldstate {} mismatch", block.getNumber(), worldStateRootHash);
            LOG.warn("Conflict block dump: {}", Hex.toHexString(block.getEncoded()));
            track.rollback();
            // block is bad so 'rollback' the state root to the original
            // state
            ((AionRepositoryImpl) repository).setRoot(origRoot);
            if (this.config.getExitOnBlockConflict()) {
                chainStats.lostConsensus();
                System.out.println("CONFLICT: BLOCK #" + block.getNumber() + ", dump: " + Hex.toHexString(block.getEncoded()));
                System.exit(1);
            } else {
                return null;
            }
        }
    }
    // update corresponding account with the new balance
    track.flush();
    if (rebuild) {
        for (int i = 0; i < receipts.size(); i++) {
            transactionStore.put(new AionTxInfo(receipts.get(i), block.getHash(), i));
        }
        ((AionRepositoryImpl) repository).commitBlock(block.getHeader());
        if (LOG.isDebugEnabled())
            LOG.debug("Block rebuilt: number: {}, hash: {}, TD: {}", block.getNumber(), block.getShortHash(), totalDifficulty);
    }
    return summary;
}
Also used : AionBlockSummary(org.aion.zero.impl.types.AionBlockSummary) AionTxInfo(org.aion.zero.impl.types.AionTxInfo) AionRepositoryImpl(org.aion.zero.impl.db.AionRepositoryImpl)

Aggregations

AionRepositoryImpl (org.aion.zero.impl.db.AionRepositoryImpl)13 Address (org.aion.base.type.Address)10 Test (org.junit.Test)10 IRepositoryCache (org.aion.base.db.IRepositoryCache)7 DataWord (org.aion.mcf.vm.types.DataWord)5 IByteArrayKeyValueDatabase (org.aion.base.db.IByteArrayKeyValueDatabase)3 AionContractDetailsImpl (org.aion.zero.db.AionContractDetailsImpl)3 HashMap (java.util.HashMap)2 AionTxInfo (org.aion.zero.impl.types.AionTxInfo)2 BigInteger (java.math.BigInteger)1 IContractDetails (org.aion.base.db.IContractDetails)1 AccountState (org.aion.mcf.core.AccountState)1 IBlockStoreBase (org.aion.mcf.db.IBlockStoreBase)1 RecoveryUtils (org.aion.zero.impl.db.RecoveryUtils)1 AionBlock (org.aion.zero.impl.types.AionBlock)1 AionBlockSummary (org.aion.zero.impl.types.AionBlockSummary)1