Skip to content

Commit

Permalink
Support testnet and regtest in BuildCheckpoints tool.
Browse files Browse the repository at this point in the history
  • Loading branch information
devrandom authored and schildbach committed Aug 7, 2015
1 parent 5f3d3a7 commit 044c98e
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 24 deletions.
61 changes: 45 additions & 16 deletions tools/src/main/java/org/bitcoinj/tools/BuildCheckpoints.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@

import org.bitcoinj.core.*;
import org.bitcoinj.params.MainNetParams;
import org.bitcoinj.params.RegTestParams;
import org.bitcoinj.params.TestNet3Params;
import org.bitcoinj.store.BlockStore;
import org.bitcoinj.store.MemoryBlockStore;
import org.bitcoinj.utils.BriefLogFormatter;
import org.bitcoinj.utils.Threading;
import com.google.common.base.Charsets;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import joptsimple.OptionSpec;

import java.io.DataOutputStream;
import java.io.File;
Expand All @@ -46,35 +51,56 @@
* to a file which is then signed with your key.
*/
public class BuildCheckpoints {

private static final NetworkParameters PARAMS = MainNetParams.get();
private static final File PLAIN_CHECKPOINTS_FILE = new File("checkpoints");
private static final File TEXTUAL_CHECKPOINTS_FILE = new File("checkpoints.txt");
private static NetworkParameters params;

public static void main(String[] args) throws Exception {
OptionParser parser = new OptionParser();
OptionSpec<NetworkEnum> netFlag = parser.accepts("net").withRequiredArg().ofType(NetworkEnum.class).defaultsTo(NetworkEnum.MAIN);
OptionSpec<Integer> daysFlag = parser.accepts("days").withRequiredArg().ofType(Integer.class).defaultsTo(30);
OptionSet options = parser.parse(args);

String suffix;
switch (netFlag.value(options)) {
case MAIN:
case PROD:
params = MainNetParams.get();
suffix = "";
break;
case TEST:
params = TestNet3Params.get();
suffix = "-testnet";
break;
case REGTEST:
params = RegTestParams.get();
suffix = "-regtest";
break;
default:
throw new RuntimeException("Unreachable.");
}
BriefLogFormatter.initWithSilentBitcoinJ();

// Sorted map of block height to StoredBlock object.
final TreeMap<Integer, StoredBlock> checkpoints = new TreeMap<Integer, StoredBlock>();

// Configure bitcoinj to fetch only headers, not save them to disk, connect to a local fully synced/validated
// node and to save block headers that are on interval boundaries, as long as they are <1 month old.
final BlockStore store = new MemoryBlockStore(PARAMS);
final BlockChain chain = new BlockChain(PARAMS, store);
final PeerGroup peerGroup = new PeerGroup(PARAMS, chain);
final BlockStore store = new MemoryBlockStore(params);
final BlockChain chain = new BlockChain(params, store);
final PeerGroup peerGroup = new PeerGroup(params, chain);
final InetAddress peerAddress = InetAddress.getLocalHost();
System.out.println("Connecting to " + peerAddress + "...");
peerGroup.addAddress(peerAddress);
long now = new Date().getTime() / 1000;
peerGroup.setFastCatchupTimeSecs(now);

final long oneMonthAgo = now - (86400 * 30);
final long timeAgo = now - (86400 * options.valueOf(daysFlag));
System.out.println("Checkpointing up to " + Utils.dateTimeFormat(timeAgo * 1000));

chain.addListener(new AbstractBlockChainListener() {
@Override
public void notifyNewBestBlock(StoredBlock block) throws VerificationException {
int height = block.getHeight();
if (height % PARAMS.getInterval() == 0 && block.getHeader().getTimeSeconds() <= oneMonthAgo) {
if (height % params.getInterval() == 0 && block.getHeader().getTimeSeconds() <= timeAgo) {
System.out.println(String.format("Checkpointing block %s at height %d",
block.getHeader().getHash(), block.getHeight()));
checkpoints.put(height, block);
Expand All @@ -87,16 +113,19 @@ public void notifyNewBestBlock(StoredBlock block) throws VerificationException {

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, PLAIN_CHECKPOINTS_FILE);
writeTextualCheckpoints(checkpoints, TEXTUAL_CHECKPOINTS_FILE);
writeBinaryCheckpoints(checkpoints, plainFile);
writeTextualCheckpoints(checkpoints, textFile);

peerGroup.stop();
store.close();

// Sanity check the created files.
sanityCheck(PLAIN_CHECKPOINTS_FILE, checkpoints.size());
sanityCheck(TEXTUAL_CHECKPOINTS_FILE, checkpoints.size());
sanityCheck(plainFile, checkpoints.size());
sanityCheck(textFile, checkpoints.size());
}

private static void writeBinaryCheckpoints(TreeMap<Integer, StoredBlock> checkpoints, File file) throws Exception {
Expand Down Expand Up @@ -139,15 +168,15 @@ private static void writeTextualCheckpoints(TreeMap<Integer, StoredBlock> checkp
}

private static void sanityCheck(File file, int expectedSize) throws IOException {
CheckpointManager manager = new CheckpointManager(PARAMS, new FileInputStream(file));
CheckpointManager manager = new CheckpointManager(params, new FileInputStream(file));
checkState(manager.numCheckpoints() == expectedSize);

if (PARAMS.getId().equals(NetworkParameters.ID_MAINNET)) {
if (params.getId().equals(NetworkParameters.ID_MAINNET)) {
StoredBlock test = manager.getCheckpointBefore(1390500000); // Thu Jan 23 19:00:00 CET 2014
checkState(test.getHeight() == 280224);
checkState(test.getHeader().getHashAsString()
.equals("00000000000000000b5d59a15f831e1c45cb688a4db6b0a60054d49a9997fa34"));
} else if (PARAMS.getId().equals(NetworkParameters.ID_TESTNET)) {
} else if (params.getId().equals(NetworkParameters.ID_TESTNET)) {
StoredBlock test = manager.getCheckpointBefore(1390500000); // Thu Jan 23 19:00:00 CET 2014
checkState(test.getHeight() == 167328);
checkState(test.getHeader().getHashAsString()
Expand Down
24 changes: 24 additions & 0 deletions tools/src/main/java/org/bitcoinj/tools/NetworkEnum.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.bitcoinj.tools;

/*
* Copyright 2014 Mike Hearn
*
* 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.
*/

public enum NetworkEnum {
MAIN,
PROD, // alias for MAIN
TEST,
REGTEST
}
9 changes: 1 addition & 8 deletions tools/src/main/java/org/bitcoinj/tools/WalletTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,13 +182,6 @@ public enum WaitForEnum {
BLOCK,
BALANCE
}

public enum NetworkEnum {
MAIN,
PROD, // alias for MAIN
TEST,
REGTEST
}

public enum ValidationMode {
FULL,
Expand All @@ -203,7 +196,7 @@ public static void main(String[] args) throws Exception {
OptionSpec<String> walletFileName = parser.accepts("wallet").withRequiredArg().defaultsTo("wallet");
seedFlag = parser.accepts("seed").withRequiredArg();
watchFlag = parser.accepts("watchkey").withRequiredArg();
OptionSpec<NetworkEnum> netFlag = parser.accepts("net").withOptionalArg().ofType(NetworkEnum.class).defaultsTo(NetworkEnum.MAIN);
OptionSpec<NetworkEnum> netFlag = parser.accepts("net").withRequiredArg().ofType(NetworkEnum.class).defaultsTo(NetworkEnum.MAIN);
dateFlag = parser.accepts("date").withRequiredArg().ofType(Date.class)
.withValuesConvertedBy(DateConverter.datePattern("yyyy/MM/dd"));
OptionSpec<WaitForEnum> waitForFlag = parser.accepts("waitfor").withRequiredArg().ofType(WaitForEnum.class);
Expand Down

0 comments on commit 044c98e

Please sign in to comment.