From db329beca53464bfe267f765a48f485f097f2ba3 Mon Sep 17 00:00:00 2001
From: Andreas Schildbach
The file format consists of the string "CHECKPOINTS 1", followed by a uint32 containing the number of signatures - * to read. The value may not be larger than 256 (so it could have been a byte but isn't for historical reasons). + *
Checkpoints are read from a text file, one value per line. + * It consists of the magic string "TXT CHECKPOINTS 1", followed by the number of signatures + * to read. The value may not be larger than 256. * If the number of signatures is larger than zero, each 65 byte ECDSA secp256k1 signature then follows. The signatures * sign the hash of all bytes that follow the last signature.
* - *After the signatures come an int32 containing the number of checkpoints in the file. Then each checkpoint follows - * one after the other. A checkpoint is 12 bytes for the total work done field, 4 bytes for the height, 80 bytes - * for the block header and then 1 zero byte at the end (i.e. number of transactions in the block: always zero).
+ *After the signatures come the number of checkpoints in the file. Then each checkpoint follows one per line in + * compact format (as written by {@link StoredBlock#serializeCompact(ByteBuffer)}) as a base64-encoded blob.
*/ public class CheckpointManager { private static final Logger log = LoggerFactory.getLogger(CheckpointManager.class); - private static final String BINARY_MAGIC = "CHECKPOINTS 1"; private static final String TEXTUAL_MAGIC = "TXT CHECKPOINTS 1"; private static final int MAX_SIGNATURES = 256; @@ -105,9 +104,7 @@ public CheckpointManager(NetworkParameters params, @Nullable InputStream inputSt inputStream.mark(1); int first = inputStream.read(); inputStream.reset(); - if (first == BINARY_MAGIC.charAt(0)) - dataHash = readBinary(inputStream); - else if (first == TEXTUAL_MAGIC.charAt(0)) + if (first == TEXTUAL_MAGIC.charAt(0)) dataHash = readTextual(inputStream); else throw new IOException("Unsupported format."); @@ -118,49 +115,6 @@ public static InputStream openStream(NetworkParameters params) { return CheckpointManager.class.getResourceAsStream("/" + params.getId() + ".checkpoints.txt"); } - private Sha256Hash readBinary(InputStream inputStream) throws IOException { - DataInputStream dis = null; - try { - MessageDigest digest = Sha256Hash.newDigest(); - DigestInputStream digestInputStream = new DigestInputStream(inputStream, digest); - dis = new DataInputStream(digestInputStream); - digestInputStream.on(false); - byte[] header = new byte[BINARY_MAGIC.length()]; - dis.readFully(header); - if (!Arrays.equals(header, BINARY_MAGIC.getBytes(StandardCharsets.US_ASCII))) - throw new IOException("Header bytes did not match expected version"); - int numSignatures = dis.readInt(); - checkState(numSignatures >= 0 && numSignatures < MAX_SIGNATURES, () -> - "numSignatures out of range: " + numSignatures); - for (int i = 0; i < numSignatures; i++) { - byte[] sig = new byte[65]; - dis.readFully(sig); - // TODO: Do something with the signature here. - } - digestInputStream.on(true); - int numCheckpoints = dis.readInt(); - checkState(numCheckpoints > 0); - final int size = StoredBlock.COMPACT_SERIALIZED_SIZE; - ByteBuffer buffer = ByteBuffer.allocate(size); - for (int i = 0; i < numCheckpoints; i++) { - if (dis.read(buffer.array(), 0, size) < size) - throw new IOException("Incomplete read whilst loading checkpoints."); - StoredBlock block = StoredBlock.deserializeCompact(buffer); - ((Buffer) buffer).position(0); - checkpoints.put(block.getHeader().time(), block); - } - Sha256Hash dataHash = Sha256Hash.wrap(digest.digest()); - log.info("Read {} checkpoints up to time {}, hash is {}", checkpoints.size(), - TimeUtils.dateTimeFormat(checkpoints.lastEntry().getKey()), dataHash); - return dataHash; - } catch (ProtocolException e) { - throw new IOException(e); - } finally { - if (dis != null) dis.close(); - inputStream.close(); - } - } - private Sha256Hash readTextual(InputStream inputStream) throws IOException { Hasher hasher = Hashing.sha256().newHasher(); try (BufferedReader reader = diff --git a/tools/src/main/java/org/bitcoinj/tools/BuildCheckpoints.java b/tools/src/main/java/org/bitcoinj/tools/BuildCheckpoints.java index 709308040a2..963e5cdc107 100644 --- a/tools/src/main/java/org/bitcoinj/tools/BuildCheckpoints.java +++ b/tools/src/main/java/org/bitcoinj/tools/BuildCheckpoints.java @@ -158,45 +158,20 @@ public Integer call() throws Exception { checkState(checkpoints.size() > 0); - final File plainFile = new File("checkpoints" + suffix); final File textFile = new File("checkpoints" + suffix + ".txt"); // Write checkpoint data out. - writeBinaryCheckpoints(checkpoints, plainFile); writeTextualCheckpoints(checkpoints, textFile); peerGroup.stop(); store.close(); // Sanity check the created files. - sanityCheck(plainFile, checkpoints.size()); sanityCheck(textFile, checkpoints.size()); return 0; } - private static void writeBinaryCheckpoints(TreeMap