Skip to content

Commit

Permalink
Add support for block headers of variable length, when parsing header…
Browse files Browse the repository at this point in the history
…s messages.
  • Loading branch information
Ross Nicoll committed Oct 18, 2015
1 parent e136642 commit 1c74aac
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 20 deletions.
4 changes: 2 additions & 2 deletions core/src/main/java/org/bitcoinj/core/BitcoinSerializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,8 @@ public Message makeAlertMessage(byte[] payloadBytes) throws ProtocolException {
* serialization format support.
*/
@Override
public Block makeBlock(final byte[] payloadBytes, final int length) throws ProtocolException {
return new Block(params, payloadBytes, this, length);
public Block makeBlock(final byte[] payloadBytes, final int offset, final int length) throws ProtocolException {
return new Block(params, payloadBytes, offset, this, length);
}

/**
Expand Down
15 changes: 15 additions & 0 deletions core/src/main/java/org/bitcoinj/core/Block.java
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,21 @@ public Block(NetworkParameters params, byte[] payloadBytes, MessageSerializer se
super(params, payloadBytes, 0, serializer, length);
}

/**
* Construct a block object from the Bitcoin wire format.
* @param params NetworkParameters object.
* @param payloadBytes the payload to extract the block from.
* @param offset The location of the first payload byte within the array.
* @param serializer the serializer to use for this message.
* @param length The length of message if known. Usually this is provided when deserializing of the wire
* as the length will be provided as part of the header. If unknown then set to Message.UNKNOWN_LENGTH
* @throws ProtocolException
*/
public Block(NetworkParameters params, byte[] payloadBytes, int offset, MessageSerializer serializer, int length)
throws ProtocolException {
super(params, payloadBytes, offset, serializer, length);
}

/**
* Construct a block object from the Bitcoin wire format. Used in the case of a block
* contained within another message (i.e. for AuxPoW header).
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/bitcoinj/core/DummySerializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public Message makeAlertMessage(byte[] payloadBytes) throws UnsupportedOperation
}

@Override
public Block makeBlock(byte[] payloadBytes, int length) throws UnsupportedOperationException {
public Block makeBlock(byte[] payloadBytes, int offset, int length) throws UnsupportedOperationException {
throw new UnsupportedOperationException(DEFAULT_EXCEPTION_MESSAGE);
}

Expand Down
24 changes: 9 additions & 15 deletions core/src/main/java/org/bitcoinj/core/HeadersMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,33 +64,27 @@ public void bitcoinSerializeToStream(OutputStream stream) throws IOException {

@Override
protected void parse() throws ProtocolException {
if (length == UNKNOWN_LENGTH) {
int saveCursor = cursor;
long numHeaders = readVarInt();
cursor = saveCursor;

// Each header has 80 bytes and one more byte for transactions number which is 00.
length = (Block.HEADER_SIZE + 1) * (int)numHeaders;
}

long numHeaders = readVarInt();
if (numHeaders > MAX_HEADERS)
throw new ProtocolException("Too many headers: got " + numHeaders + " which is larger than " +
MAX_HEADERS);

blockHeaders = new ArrayList<Block>();
final BitcoinSerializer serializer = this.params.getSerializer(true);

for (int i = 0; i < numHeaders; ++i) {
// Read 80 bytes of the header and one more byte for the transaction list, which is always a 00 because the
// transaction list is empty.
byte[] blockHeader = readBytes(Block.HEADER_SIZE + 1);
if (blockHeader[Block.HEADER_SIZE] != 0)
final Block newBlockHeader = serializer.makeBlock(payload, cursor, UNKNOWN_LENGTH);
if (newBlockHeader.hasTransactions()) {
throw new ProtocolException("Block header does not end with a null byte");
Block newBlockHeader = this.params.getSerializer(true)
.makeBlock(blockHeader, Block.HEADER_SIZE + 1);
}
cursor += newBlockHeader.optimalEncodingMessageSize;
blockHeaders.add(newBlockHeader);
}

if (length == UNKNOWN_LENGTH) {
length = cursor - offset;
}

if (log.isDebugEnabled()) {
for (int i = 0; i < numHeaders; ++i) {
log.debug(this.blockHeaders.get(i).toString());
Expand Down
12 changes: 10 additions & 2 deletions core/src/main/java/org/bitcoinj/core/MessageSerializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,23 @@ public abstract class MessageSerializer {
* length as block length.
*/
public final Block makeBlock(byte[] payloadBytes) throws ProtocolException {
return makeBlock(payloadBytes, payloadBytes.length);
return makeBlock(payloadBytes, 0, payloadBytes.length);
}

/**
* Make a block from the payload, using an offset of zero and the provided
* length as block length.
*/
public final Block makeBlock(byte[] payloadBytes, int length) throws ProtocolException {
return makeBlock(payloadBytes, 0, length);
}

/**
* Make a block from the payload, using an offset of zero and the provided
* length as block length. Extension point for alternative
* serialization format support.
*/
public abstract Block makeBlock(byte[] payloadBytes, int length) throws ProtocolException;
public abstract Block makeBlock(final byte[] payloadBytes, final int offset, final int length) throws ProtocolException, UnsupportedOperationException;

/**
* Make an filter message from the payload. Extension point for alternative
Expand Down

0 comments on commit 1c74aac

Please sign in to comment.