Skip to content
Permalink
Browse files

Fix SPVBlockStore for Qtum.

  • Loading branch information
oyyq99999 committed Jan 21, 2020
1 parent 250b6c8 commit 0b5ae10d3abbd89a99ddbdbde10077f66e6b237a
@@ -212,11 +212,17 @@ public Block(NetworkParameters params, long version, Sha256Hash prevBlockHash, S
this.version = version;
this.prevBlockHash = prevBlockHash;
this.merkleRoot = merkleRoot;
this.hashStateRoot = Sha256Hash.ZERO_HASH;
this.stakePrevTxid = Sha256Hash.ZERO_HASH;
this.hashUtxoRoot = KeccakHash.ZERO_HASH;
this.signature = new byte[0];
this.time = time;
this.difficultyTarget = difficultyTarget;
this.nonce = nonce;
this.transactions = new LinkedList<>();
this.transactions.addAll(transactions);

updateHeaderSize();
}


@@ -41,7 +41,7 @@
// bytes to represent this field, so 12 bytes should be plenty for now.
private static final int CHAIN_WORK_BYTES = 12;
private static final byte[] EMPTY_BYTES = new byte[CHAIN_WORK_BYTES];
public static final int COMPACT_SERIALIZED_SIZE = Block.HEADER_SIZE_WITHOUT_SIGNATURE + CHAIN_WORK_BYTES + 4; // for height
public static final int COMPACT_SERIALIZED_SIZE = 480; // make it fixed

private final Block header;
private final BigInteger chainWork;
@@ -122,8 +122,12 @@ public StoredBlock getPrev(BlockStore store) throws BlockStoreException {
return store.get(getHeader().getPrevBlockHash());
}

/** Serializes the stored block to a custom packed format. Used by {@link CheckpointManager}. */
public void serializeCompact(ByteBuffer buffer) {
serializeCompact(buffer, false);
}

/** Serializes the stored block to a custom packed format. Used by {@link CheckpointManager}. */
public void serializeCompact(ByteBuffer buffer, boolean padToFixedLength) {
byte[] chainWorkBytes = getChainWork().toByteArray();
checkState(chainWorkBytes.length <= CHAIN_WORK_BYTES, "Ran out of space to store chain work!");
if (chainWorkBytes.length < CHAIN_WORK_BYTES) {
@@ -134,8 +138,17 @@ public void serializeCompact(ByteBuffer buffer) {
buffer.putInt(getHeight());
// Using unsafeBitcoinSerialize here can give us direct access to the same bytes we read off the wire,
// avoiding serialization round-trips.
byte[] bytes = getHeader().unsafeBitcoinSerialize();
buffer.put(bytes, 0, Block.HEADER_SIZE_WITHOUT_SIGNATURE); // Trim the trailing 00 byte (zero transactions).
Block header = getHeader();
byte[] bytes = header.unsafeBitcoinSerialize();
int headerSize = header.getHeaderSize();
buffer.putInt(headerSize);
buffer.put(bytes, 0, headerSize); // Trim the trailing 00 byte (zero transactions).
if (padToFixedLength) {
int paddingLength = COMPACT_SERIALIZED_SIZE - CHAIN_WORK_BYTES - 8 - headerSize;
for (int i = 0; i < paddingLength; i++) {
buffer.put((byte) 0);
}
}
}

/** De-serializes the stored block from a custom packed format. Used by {@link CheckpointManager}. */
@@ -144,8 +157,9 @@ public static StoredBlock deserializeCompact(NetworkParameters params, ByteBuffe
buffer.get(chainWorkBytes);
BigInteger chainWork = new BigInteger(1, chainWorkBytes);
int height = buffer.getInt(); // +4 bytes
byte[] header = new byte[Block.HEADER_SIZE_WITHOUT_SIGNATURE + 1]; // Extra byte for the 00 transactions length.
buffer.get(header, 0, Block.HEADER_SIZE_WITHOUT_SIGNATURE);
int headerSize = buffer.getInt(); // +4 bytes
byte[] header = new byte[headerSize + 1]; // Extra byte for the 00 transactions length.
buffer.get(header, 0, headerSize);
return new StoredBlock(params.getDefaultSerializer().makeBlock(header), chainWork, height);
}

@@ -104,9 +104,9 @@ public int compare(final Transaction tx1, final Transaction tx2) {
public static final int MAX_STANDARD_TX_SIZE = 100000;

/**
* If feePerKb is lower than this, Bitcoin Core will treat it as if there were no fee.
* If feePerKb is lower than this, Qtum Core will treat it as if there were no fee.
*/
public static final Coin REFERENCE_DEFAULT_MIN_TX_FEE = Coin.valueOf(1000); // 0.01 mBTC
public static final Coin REFERENCE_DEFAULT_MIN_TX_FEE = Coin.valueOf(400000); // 0.004 QTUM

/**
* If using this feePerKb, transactions will get confirmed within the next couple of blocks.
@@ -195,7 +195,7 @@ public void put(StoredBlock block) throws BlockStoreException {
Sha256Hash hash = block.getHeader().getHash();
notFoundCache.remove(hash);
buffer.put(hash.getBytes());
block.serializeCompact(buffer);
block.serializeCompact(buffer, true);
setRingCursor(buffer, buffer.position());
blockCache.put(hash, block);
} finally { lock.unlock(); }
@@ -204,6 +204,10 @@ public void put(StoredBlock block) throws BlockStoreException {
@Override
@Nullable
public StoredBlock get(Sha256Hash hash) throws BlockStoreException {
// would fail at genesis block without this
if (hash.equals(Sha256Hash.ZERO_HASH)) {
return null;
}
final MappedByteBuffer buffer = this.buffer;
if (buffer == null) throw new BlockStoreException("Store closed");

@@ -300,20 +304,24 @@ public NetworkParameters getParams() {
return params;
}

protected static final int RECORD_SIZE = 32 /* hash */ + StoredBlock.COMPACT_SERIALIZED_SIZE;

// File format:
// 4 header bytes = "SPVB"
// 4 cursor bytes, which indicate the offset from the first kb where the next block header should be written.
// 32 bytes for the hash of the chain head
//
// For each header (128 bytes)
// For each header (512 bytes)
// 32 bytes hash of the header
// 12 bytes of chain work
// 4 bytes of height
// 80 bytes of block header data
// 4 bytes of header size
// ? bytes of block header data
// ? bytes of padding

protected static final int FILE_PROLOGUE_BYTES = 1024;

/* the size of a block header is dynamic, just leave more room to make it fixed */
protected static final int RECORD_SIZE = 32 + StoredBlock.COMPACT_SERIALIZED_SIZE;

/** Returns the offset from the file start where the latest block should be written (end of prev block). */
private int getRingCursor(ByteBuffer buffer) {
int c = buffer.getInt(4);

0 comments on commit 0b5ae10

Please sign in to comment.
You can’t perform that action at this time.