package com.yoghurt.crypto.transactions.client.util.block;
import java.util.Date;
import com.yoghurt.crypto.transactions.client.util.transaction.ComputeUtil;
import com.yoghurt.crypto.transactions.shared.domain.Block;
import com.yoghurt.crypto.transactions.shared.util.ArrayUtil;
import com.yoghurt.crypto.transactions.shared.util.NumberParseUtil;
public final class BlockParseUtil extends BlockUtil {
private static final int MS_TO_S = 1000;
public static Block parseBlockBytes(final byte[] bytes) {
return parseBlockBytes(bytes, new Block());
}
public static Block parseBlockBytes(final byte[] bytes, final Block b) {
return parseBlockBytes(bytes, b, 0);
}
private static Block parseBlockBytes(final byte[] bytes, final Block block, final int initialPointer) {
int pointer = initialPointer;
// Parse the version bytes
pointer = parseVersion(block, pointer, bytes);
// Parse the previous block hash
pointer = parsePreviousBlockHash(block, pointer, bytes);
// Parse the merkle root
pointer = parseMerkleRoot(block, pointer, bytes);
// Parse the timestamp field
pointer = parseTimestamp(block, pointer, bytes);
// Parse the bits field
pointer = parseBits(block, pointer, bytes);
// Parse the nonce
pointer = parseNonce(block, pointer, bytes);
// Compute the block hash
computeBlockHash(block, initialPointer, pointer, bytes);
return block;
}
private static void computeBlockHash(final Block block, final int initialPointer, final int pointer, final byte[] bytes) {
final byte[] blockBytes = ArrayUtil.arrayCopy(bytes, initialPointer, pointer);
// Create SHA256 digest and feed it the tx bytes
final byte[] blockHash = ComputeUtil.computeDoubleSHA256(blockBytes);
// Convert to LE
ArrayUtil.reverse(blockHash);
// Set the transaction tx
block.setBlockHash(blockHash);
}
private static int parseVersion(final Block block, final int initialPointer, final byte[] bytes) {
int pointer = initialPointer;
block.setVersion(NumberParseUtil.parseUint32(ArrayUtil.arrayCopy(bytes, pointer, pointer = pointer + BLOCK_VERSION_FIELD_SIZE)));
return pointer;
}
private static int parsePreviousBlockHash(final Block block, final int initialPointer, final byte[] bytes) {
int pointer = initialPointer;
final byte[] prevBlockBytes = ArrayUtil.arrayCopy(bytes, pointer, pointer = pointer + BLOCK_PREVIOUS_BLOCK_HASH_SIZE);
ArrayUtil.reverse(prevBlockBytes);
block.setPreviousBlockHash(prevBlockBytes);
return pointer;
}
private static int parseMerkleRoot(final Block block, final int initialPointer, final byte[] bytes) {
int pointer = initialPointer;
final byte[] merkleRootBytes = ArrayUtil.arrayCopy(bytes, pointer, pointer = pointer + BLOCK_MERKLE_ROOT_SIZE);
ArrayUtil.reverse(merkleRootBytes);
block.setMerkleRoot(merkleRootBytes);
return pointer;
}
private static int parseBits(final Block block, final int initialPointer, final byte[] bytes) {
int pointer = initialPointer;
final byte[] bitsBytes = ArrayUtil.arrayCopy(bytes, pointer, pointer = pointer + BLOCK_BITS_FIELD_SIZE);
ArrayUtil.reverse(bitsBytes);
block.setBits(bitsBytes);
return pointer;
}
private static int parseTimestamp(final Block block, final int initialPointer, final byte[] bytes) {
int pointer = initialPointer;
block.setTimestamp(new Date(NumberParseUtil.parseUint32(ArrayUtil.arrayCopy(bytes, pointer, pointer = pointer + BLOCK_TIMESTAMP_FIELD_SIZE)) * MS_TO_S));
return pointer;
}
private static int parseNonce(final Block block, final int initialPointer, final byte[] bytes) {
int pointer = initialPointer;
block.setNonce(NumberParseUtil.parseUint32(ArrayUtil.arrayCopy(bytes, pointer, pointer = pointer + BLOCK_NONCE_FIELD_SIZE)));
return pointer;
}
}