SPVBlockStore: fix get() locates an invalid block if called with zero hash

This happens if the store is relatively fresh and has not yet fully wrapped
around at least once. Thus, entire entries of the ring buffer are still
zeroed, and in particular the hash field of store entries will be zero. In
consequence, get() is locating and returning an invalid block when asked to
look for the zero hash.

Valid blocks that hash to zero will require an astronomical amount of
mining. So we fix this bug by hardcoding the zero hash to never be found in
our store.

Includes a test for this edge case.
This commit is contained in:
Andreas Schildbach 2025-03-10 10:42:16 +01:00
parent 93519cc65a
commit 284fbcc20f
2 changed files with 15 additions and 0 deletions

View file

@ -279,6 +279,13 @@ public class SPVBlockStore implements BlockStore {
@Override @Override
@Nullable @Nullable
public StoredBlock get(Sha256Hash hash) throws BlockStoreException { public StoredBlock get(Sha256Hash hash) throws BlockStoreException {
if (hash.equals(Sha256Hash.ZERO_HASH)) {
// Valid blocks will never hash to zero, as it will need an astronomical amount of mining to create one.
// Nevertheless, we need to catch this case here because our ring buffer contains all zeros at the
// beginning so this method would indeed locate and return an invalid block.
return null;
}
final MappedByteBuffer buffer = this.buffer; final MappedByteBuffer buffer = this.buffer;
if (buffer == null) throw new BlockStoreException("Store closed"); if (buffer == null) throw new BlockStoreException("Store closed");

View file

@ -93,6 +93,14 @@ public class SPVBlockStoreTest {
store.close(); store.close();
} }
@Test
public void get_zeroHash() throws Exception {
SPVBlockStore store = new SPVBlockStore(TESTNET, blockStoreFile);
// Needs to fail locating a block even though our fresh ring buffer is full of zero hashes.
StoredBlock b = store.get(Sha256Hash.ZERO_HASH);
assertNull(b);
}
@Test(expected = BlockStoreException.class) @Test(expected = BlockStoreException.class)
public void twoStores_onSameFile() throws Exception { public void twoStores_onSameFile() throws Exception {
new SPVBlockStore(TESTNET, blockStoreFile); new SPVBlockStore(TESTNET, blockStoreFile);