mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2024-11-19 09:50:32 +01:00
Add HeadersMessage and parsing support for it. Patch from Roman Mandeleil.
This commit is contained in:
parent
525d5e8d55
commit
457ef5f318
1
AUTHORS
1
AUTHORS
@ -10,3 +10,4 @@ Jan Møller <jan.moller@gmail.com>
|
||||
Wolfgang Nagele <wolfgang.nagele@gmail.com>
|
||||
Jonny Heggheim <hegjon@gmail.com>
|
||||
Steve Coughlan <shadders.del@gmail.com>
|
||||
Roman Mandeleil <roman.mandeleil@gmail.com>
|
||||
|
@ -68,6 +68,8 @@ public class BitcoinSerializer {
|
||||
names.put(VersionAck.class, "verack");
|
||||
names.put(GetBlocksMessage.class, "getblocks");
|
||||
names.put(GetAddrMessage.class, "getaddr");
|
||||
names.put(HeadersMessage.class, "headers");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -330,6 +332,8 @@ public class BitcoinSerializer {
|
||||
return new Ping();
|
||||
} else if (command.equals("verack")) {
|
||||
return new VersionAck(params, payloadBytes);
|
||||
} else if (command.equals("headers")) {
|
||||
return new HeadersMessage(params, payloadBytes);
|
||||
} else {
|
||||
throw new ProtocolException("No support for deserializing message with name " + command);
|
||||
}
|
||||
|
82
src/com/google/bitcoin/core/HeadersMessage.java
Normal file
82
src/com/google/bitcoin/core/HeadersMessage.java
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.bitcoin.core;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A protocol message that contains a repeated series of block headers, sent in response to the "getheaders" command.
|
||||
* This is useful when you want to traverse the chain but know you don't care about the block contents, for example,
|
||||
* because you have a freshly created wallet with no keys.
|
||||
*/
|
||||
public class HeadersMessage extends Message {
|
||||
private static final Logger log = LoggerFactory.getLogger(HeadersMessage.class);
|
||||
|
||||
// The main client will never send us more than this number of headers.
|
||||
final static int MAX_HEADERS = 2000;
|
||||
|
||||
private List<Block> blockHeaders;
|
||||
|
||||
public HeadersMessage(NetworkParameters params, byte[] payload) throws ProtocolException {
|
||||
super(params, payload, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseLite() throws ProtocolException {
|
||||
if (length == UNKNOWN_LENGTH) {
|
||||
long numHeaders = readVarInt();
|
||||
|
||||
// Each header has 80 bytes and one more byte for transactions number which is 00.
|
||||
length = 81 * (int)numHeaders;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void parse() throws ProtocolException {
|
||||
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>();
|
||||
|
||||
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(81);
|
||||
if (blockHeader[80] != 00)
|
||||
throw new ProtocolException("Block header does not end with a null byte");
|
||||
Block newBlockHeader = new Block(this.params, blockHeader);
|
||||
blockHeaders.add(newBlockHeader);
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
for (int i = 0; i < numHeaders; ++i) {
|
||||
log.debug(this.blockHeaders.get(i).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<Block> getBlockHeaders() {
|
||||
return blockHeaders;
|
||||
}
|
||||
}
|
@ -200,4 +200,83 @@ public class BitcoinSerializerTest {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get 1 header of the block number 1 (the first one is 0) in the chain
|
||||
*/
|
||||
@Test
|
||||
public void testHeaders1() throws Exception {
|
||||
|
||||
BitcoinSerializer bs = new BitcoinSerializer(NetworkParameters.prodNet(), true,
|
||||
null);
|
||||
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(Hex.decode("f9beb4d9686561" +
|
||||
"646572730000000000520000005d4fab8101010000006fe28c0ab6f1b372c1a6a246ae6" +
|
||||
"3f74f931e8365e15a089c68d6190000000000982051fd1e4ba744bbbe680e1fee14677b" +
|
||||
"a1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e3629900"));
|
||||
|
||||
HeadersMessage hm = (HeadersMessage) bs.deserialize(bais);
|
||||
|
||||
// The first block after the genesis
|
||||
// http://blockexplorer.com/b/1
|
||||
Block block = hm.getBlockHeaders().get(0);
|
||||
String hash = block.getHashAsString();
|
||||
assertEquals(hash, "00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048");
|
||||
|
||||
assertEquals(block.transactions.size(), 0);
|
||||
|
||||
assertEquals(Utils.bytesToHexString(block.getMerkleRoot().getBytes()),
|
||||
"0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Get 6 headers of blocks 1-6 in the chain
|
||||
*/
|
||||
public void testHeaders2() throws Exception {
|
||||
BitcoinSerializer bs = new BitcoinSerializer(NetworkParameters.prodNet(), true,
|
||||
null);
|
||||
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(Hex.decode("f9beb4d96865616465" +
|
||||
"72730000000000e701000085acd4ea06010000006fe28c0ab6f1b372c1a6a246ae63f74f931e" +
|
||||
"8365e15a089c68d6190000000000982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1c" +
|
||||
"db606e857233e0e61bc6649ffff001d01e3629900010000004860eb18bf1b1620e37e9490fc8a" +
|
||||
"427514416fd75159ab86688e9a8300000000d5fdcc541e25de1c7a5addedf24858b8bb665c9f36" +
|
||||
"ef744ee42c316022c90f9bb0bc6649ffff001d08d2bd610001000000bddd99ccfda39da1b108ce1" +
|
||||
"a5d70038d0a967bacb68b6b63065f626a0000000044f672226090d85db9a9f2fbfe5f0f9609b387" +
|
||||
"af7be5b7fbb7a1767c831c9e995dbe6649ffff001d05e0ed6d00010000004944469562ae1c2c74" +
|
||||
"d9a535e00b6f3e40ffbad4f2fda3895501b582000000007a06ea98cd40ba2e3288262b28638cec" +
|
||||
"5337c1456aaf5eedc8e9e5a20f062bdf8cc16649ffff001d2bfee0a9000100000085144a84488e" +
|
||||
"a88d221c8bd6c059da090e88f8a2c99690ee55dbba4e00000000e11c48fecdd9e72510ca84f023" +
|
||||
"370c9a38bf91ac5cae88019bee94d24528526344c36649ffff001d1d03e4770001000000fc33f5" +
|
||||
"96f822a0a1951ffdbf2a897b095636ad871707bf5d3162729b00000000379dfb96a5ea8c81700ea4" +
|
||||
"ac6b97ae9a9312b2d4301a29580e924ee6761a2520adc46649ffff001d189c4c9700"));
|
||||
|
||||
HeadersMessage hm = (HeadersMessage) bs.deserialize(bais);
|
||||
|
||||
int nBlocks = hm.getBlockHeaders().size();
|
||||
assertEquals(nBlocks, 6);
|
||||
|
||||
// index 0 block is the number 1 block in the block chain
|
||||
// http://blockexplorer.com/b/1
|
||||
Block zeroBlock = hm.getBlockHeaders().get(0);
|
||||
String zeroBlockHash = zeroBlock.getHashAsString();
|
||||
|
||||
assertEquals("00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048",
|
||||
zeroBlockHash);
|
||||
assertEquals(zeroBlock.getNonce(), 2573394689L);
|
||||
|
||||
|
||||
Block thirdBlock = hm.getBlockHeaders().get(3);
|
||||
String thirdBlockHash = thirdBlock.getHashAsString();
|
||||
|
||||
// index 3 block is the number 4 block in the block chain
|
||||
// http://blockexplorer.com/b/4
|
||||
assertEquals("000000004ebadb55ee9096c9a2f8880e09da59c0d68b1c228da88e48844a1485",
|
||||
thirdBlockHash);
|
||||
assertEquals(thirdBlock.getNonce(), 2850094635L);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user