Skip to content

Commit

Permalink
extract method migrateV1toV2()
Browse files Browse the repository at this point in the history
  • Loading branch information
schildbach committed Jul 31, 2024
1 parent 626e5fb commit 7383f1d
Showing 1 changed file with 38 additions and 34 deletions.
72 changes: 38 additions & 34 deletions core/src/main/java/org/bitcoinj/store/SPVBlockStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ protected boolean removeEldestEntry(Map.Entry<Sha256Hash, Object> entry) {
// Used to stop other applications/processes from opening the store.
protected FileLock fileLock = null;
protected RandomAccessFile randomAccessFile = null;
private FileChannel channel;
private int fileLength;

/**
Expand Down Expand Up @@ -127,7 +128,7 @@ public SPVBlockStore(NetworkParameters params, File file, int capacity, boolean

// Set up the backing file, empty if it doesn't exist.
randomAccessFile = new RandomAccessFile(file, "rw");
FileChannel channel = randomAccessFile.getChannel();
channel = randomAccessFile.getChannel();

// Lock the file.
fileLock = channel.tryLock();
Expand Down Expand Up @@ -156,39 +157,8 @@ public SPVBlockStore(NetworkParameters params, File file, int capacity, boolean

// Maybe migrate V1 to V2 format.
if (Arrays.equals(HEADER_MAGIC_V1, currentHeader)) {
long currentLength = randomAccessFile.length();
long currentBlocksLength = currentLength - FILE_PROLOGUE_BYTES;
if (currentBlocksLength % RECORD_SIZE_V1 != 0)
throw new BlockStoreException(
"File size on disk indicates this is not a V1 block store: " + currentLength);
int currentCapacity = (int) (currentBlocksLength / RECORD_SIZE_V1);
log.info("Migrating SPV block chain file containing " + currentCapacity + " blocks from V1 to V2 " +
"format: " + file);

randomAccessFile.setLength(fileLength);
// Map it into memory again because of the length change.
buffer.force();
buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, fileLength);

// migrate magic header
((Buffer) buffer).rewind();
buffer.put(HEADER_MAGIC_V2);

// migrate headers
final byte[] zeroPadding = new byte[20]; // 32 (V2 work) - 12 (V1 work)
for (int i = currentCapacity - 1; i >= 0; i--) {
byte[] record = new byte[RECORD_SIZE_V1];
buffer.position(FILE_PROLOGUE_BYTES + i * RECORD_SIZE_V1);
buffer.get(record);
buffer.position(FILE_PROLOGUE_BYTES + i * RECORD_SIZE_V2);
buffer.put(record, 0, 32); // hash
buffer.put(zeroPadding);
buffer.put(record, 32, RECORD_SIZE_V1 - 32); // work, height, block header
}

// migrate cursor
int cursorRecord = (getRingCursor() - FILE_PROLOGUE_BYTES) / RECORD_SIZE_V1;
setRingCursor(FILE_PROLOGUE_BYTES + cursorRecord * RECORD_SIZE_V2);
log.info("Migrating SPV block chain file from V1 to V2 format: " + file);
migrateV1toV2();
}

// Maybe grow.
Expand Down Expand Up @@ -245,6 +215,40 @@ private void initNewStore(Block genesisBlock) throws Exception {
setChainHead(storedGenesis);
}

private void migrateV1toV2() throws BlockStoreException, IOException {
long currentLength = randomAccessFile.length();
long currentBlocksLength = currentLength - FILE_PROLOGUE_BYTES;
if (currentBlocksLength % RECORD_SIZE_V1 != 0)
throw new BlockStoreException(
"File size on disk indicates this is not a V1 block store: " + currentLength);
int currentCapacity = (int) (currentBlocksLength / RECORD_SIZE_V1);

randomAccessFile.setLength(fileLength);
// Map it into memory again because of the length change.
buffer.force();
buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, fileLength);

// migrate magic header
((Buffer) buffer).rewind();
buffer.put(HEADER_MAGIC_V2);

// migrate headers
final byte[] zeroPadding = new byte[20]; // 32 (V2 work) - 12 (V1 work)
for (int i = currentCapacity - 1; i >= 0; i--) {
byte[] record = new byte[RECORD_SIZE_V1];
buffer.position(FILE_PROLOGUE_BYTES + i * RECORD_SIZE_V1);
buffer.get(record);
buffer.position(FILE_PROLOGUE_BYTES + i * RECORD_SIZE_V2);
buffer.put(record, 0, 32); // hash
buffer.put(zeroPadding);
buffer.put(record, 32, RECORD_SIZE_V1 - 32); // work, height, block header
}

// migrate cursor
int cursorRecord = (getRingCursor() - FILE_PROLOGUE_BYTES) / RECORD_SIZE_V1;
setRingCursor(FILE_PROLOGUE_BYTES + cursorRecord * RECORD_SIZE_V2);
}

/** Returns the size in bytes of the file that is used to store the chain with the current parameters. */
public static int getFileSize(int capacity) {
return RECORD_SIZE_V2 * capacity + FILE_PROLOGUE_BYTES /* extra kilobyte for stuff */;
Expand Down

0 comments on commit 7383f1d

Please sign in to comment.