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());
}
}
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());
}
}
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;
}
Aggregations