forked from Qortal/qortal
Added importFromArchive() feature
This allows archived blocks to be imported back into HSQLDB in order to make them SQL-compatible again.
This commit is contained in:
parent
fea7b62b9c
commit
9813dde3d9
@ -105,6 +105,21 @@ public class BlockArchiveReader {
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Triple<BlockData, List<TransactionData>, List<ATStateData>>> fetchBlocksFromRange(
|
||||
int startHeight, int endHeight) {
|
||||
|
||||
List<Triple<BlockData, List<TransactionData>, List<ATStateData>>> blockInfoList = new ArrayList<>();
|
||||
|
||||
for (int height = startHeight; height <= endHeight; height++) {
|
||||
Triple<BlockData, List<TransactionData>, List<ATStateData>> blockInfo = this.fetchBlockAtHeight(height);
|
||||
if (blockInfo == null) {
|
||||
return blockInfoList;
|
||||
}
|
||||
blockInfoList.add(blockInfo);
|
||||
}
|
||||
return blockInfoList;
|
||||
}
|
||||
|
||||
public Integer fetchHeightForSignature(byte[] signature, Repository repository) {
|
||||
// Lookup the height for the requested signature
|
||||
try {
|
||||
|
@ -36,6 +36,18 @@ public interface BlockArchiveRepository {
|
||||
*/
|
||||
public BlockData fromHeight(int height) throws DataException;
|
||||
|
||||
/**
|
||||
* Returns a list of BlockData objects from archive using
|
||||
* block height range.
|
||||
*
|
||||
* @param startHeight
|
||||
* @return a list of BlockData objects, or an empty list if
|
||||
* not found in blockchain. It is not guaranteed that all
|
||||
* requested blocks will be returned.
|
||||
* @throws DataException
|
||||
*/
|
||||
public List<BlockData> fromRange(int startHeight, int endHeight) throws DataException;
|
||||
|
||||
/**
|
||||
* Returns BlockData from archive using block reference.
|
||||
* Currently relies on a child block being the one block
|
||||
|
@ -3,6 +3,7 @@ package org.qortal.repository.hsqldb;
|
||||
import org.qortal.api.ApiError;
|
||||
import org.qortal.api.ApiExceptionFactory;
|
||||
import org.qortal.api.model.BlockSignerSummary;
|
||||
import org.qortal.block.Block;
|
||||
import org.qortal.data.block.BlockArchiveData;
|
||||
import org.qortal.data.block.BlockData;
|
||||
import org.qortal.data.block.BlockSummaryData;
|
||||
@ -53,6 +54,20 @@ public class HSQLDBBlockArchiveRepository implements BlockArchiveRepository {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BlockData> fromRange(int startHeight, int endHeight) throws DataException {
|
||||
List<BlockData> blocks = new ArrayList<>();
|
||||
|
||||
for (int height = startHeight; height < endHeight; height++) {
|
||||
BlockData blockData = this.fromHeight(height);
|
||||
if (blockData == null) {
|
||||
return blocks;
|
||||
}
|
||||
blocks.add(blockData);
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockData fromReference(byte[] reference) throws DataException {
|
||||
BlockData referenceBlock = this.repository.getBlockArchiveRepository().fromSignature(reference);
|
||||
|
78
src/main/java/org/qortal/utils/BlockArchiveUtils.java
Normal file
78
src/main/java/org/qortal/utils/BlockArchiveUtils.java
Normal file
@ -0,0 +1,78 @@
|
||||
package org.qortal.utils;
|
||||
|
||||
import org.qortal.data.at.ATStateData;
|
||||
import org.qortal.data.block.BlockData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.repository.BlockArchiveReader;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.repository.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BlockArchiveUtils {
|
||||
|
||||
/**
|
||||
* importFromArchive
|
||||
* <p>
|
||||
* Reads the requested block range from the archive
|
||||
* and imports the BlockData and AT state data hashes
|
||||
* This can be used to convert a block archive back
|
||||
* into the HSQLDB, in order to make it SQL-compatible
|
||||
* again.
|
||||
* <p>
|
||||
* Note: calls discardChanges() and saveChanges(), so
|
||||
* make sure that you commit any existing repository
|
||||
* changes before calling this method.
|
||||
*
|
||||
* @param startHeight The earliest block to import
|
||||
* @param endHeight The latest block to import
|
||||
* @param repository A clean repository session
|
||||
* @throws DataException
|
||||
*/
|
||||
public static void importFromArchive(int startHeight, int endHeight, Repository repository) throws DataException {
|
||||
repository.discardChanges();
|
||||
final int requestedRange = endHeight+1-startHeight;
|
||||
|
||||
List<Triple<BlockData, List<TransactionData>, List<ATStateData>>> blockInfoList =
|
||||
BlockArchiveReader.getInstance().fetchBlocksFromRange(startHeight, endHeight);
|
||||
|
||||
// Ensure that we have received all of the requested blocks
|
||||
if (blockInfoList == null || blockInfoList.isEmpty()) {
|
||||
throw new IllegalStateException("No blocks found when importing from archive");
|
||||
}
|
||||
if (blockInfoList.size() != requestedRange) {
|
||||
throw new IllegalStateException("Non matching block count when importing from archive");
|
||||
}
|
||||
Triple<BlockData, List<TransactionData>, List<ATStateData>> firstBlock = blockInfoList.get(0);
|
||||
if (firstBlock == null || firstBlock.getA().getHeight() != startHeight) {
|
||||
throw new IllegalStateException("Non matching first block when importing from archive");
|
||||
}
|
||||
if (blockInfoList.size() > 0) {
|
||||
Triple<BlockData, List<TransactionData>, List<ATStateData>> lastBlock =
|
||||
blockInfoList.get(blockInfoList.size() - 1);
|
||||
if (lastBlock == null || lastBlock.getA().getHeight() != endHeight) {
|
||||
throw new IllegalStateException("Non matching last block when importing from archive");
|
||||
}
|
||||
}
|
||||
|
||||
// Everything seems okay, so go ahead with the import
|
||||
for (Triple<BlockData, List<TransactionData>, List<ATStateData>> blockInfo : blockInfoList) {
|
||||
try {
|
||||
// Save block
|
||||
repository.getBlockRepository().save(blockInfo.getA());
|
||||
|
||||
// Save AT state data hashes
|
||||
for (ATStateData atStateData : blockInfo.getC()) {
|
||||
atStateData.setHeight(blockInfo.getA().getHeight());
|
||||
repository.getATRepository().save(atStateData);
|
||||
}
|
||||
|
||||
} catch (DataException e) {
|
||||
repository.discardChanges();
|
||||
throw new IllegalStateException("Unable to import blocks from archive");
|
||||
}
|
||||
}
|
||||
repository.saveChanges();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user