Example usage for com.google.common.collect Iterables getLast

List of usage examples for com.google.common.collect Iterables getLast

Introduction

In this page you can find the example usage for com.google.common.collect Iterables getLast.

Prototype

public static <T> T getLast(Iterable<T> iterable) 

Source Link

Document

Returns the last element of iterable .

Usage

From source file:edu.mit.streamjit.test.apps.channelvocoder7.ChannelVocoder7.java

public static void main(String[] args) throws InterruptedException {
    StreamCompiler sc = new Compiler2StreamCompiler().maxNumCores(8).multiplier(32);
    Benchmarker.runBenchmark(Iterables.getLast(new ChannelVocoder7()), sc).get(0).print(System.out);
}

From source file:com.basho.riak.spark.examples.SimpleJavaRiakTSExample.java

public static void main(String[] args) {
    SparkConf sparkConf = new SparkConf().setAppName("Simple Java Riak Demo");

    setSparkOpt(sparkConf, "spark.master", "local");
    setSparkOpt(sparkConf, "spark.riak.connection.host", "127.0.0.1:8087");

    long from = beginingOfQuantumMillis(Iterables.getFirst(DEMO_DATA, null).getTime());
    long to = endOfQuantumMillis(Iterables.getLast(DEMO_DATA).getTime());

    final JavaSparkContext jsc = new JavaSparkContext(sparkConf);

    loadDemoData(jsc);//w ww .  j  a va  2  s . c o m

    RiakTSJavaRDD<Row> rdd = javaFunctions(jsc).riakTSBucket(TABLE_NAME, Row.class)
            .sql(String.format(
                    "SELECT * FROM %s WHERE time >= %d AND time <= %d  AND  weather = 'sunny' AND family = 'f'",
                    TABLE_NAME, from, to));

    rdd.foreach(x -> System.out.println(Joiner.on(",").join(x.getCellsCopy())));
}

From source file:com.amazonaws.services.kinesis.producer.sample.MetricsAwareSampleProducer.java

public static void main(String[] args) throws InterruptedException, ExecutionException {
    final long totalRecordsToPut = 50000;
    final int dataSize = 64;
    final long outstandingLimit = 5000;

    final AtomicLong sequenceNumber = new AtomicLong(0);
    final AtomicLong completed = new AtomicLong(0);
    final String timetstamp = Long.toString(System.currentTimeMillis());

    KinesisProducerConfiguration config = new KinesisProducerConfiguration().setRecordMaxBufferedTime(3000)
            .setMaxConnections(1).setRequestTimeout(60000).setRegion(SampleProducer.REGION);

    final KinesisProducer kinesisProducer = new KinesisProducer(config);

    // Result handler
    final FutureCallback<UserRecordResult> callback = new FutureCallback<UserRecordResult>() {
        @Override// ww  w.  j a v a 2  s .c  om
        public void onFailure(Throwable t) {
            if (t instanceof UserRecordFailedException) {
                Attempt last = Iterables.getLast(((UserRecordFailedException) t).getResult().getAttempts());
                log.error(String.format("Record failed to put - %s : %s", last.getErrorCode(),
                        last.getErrorMessage()));
            }
            log.error("Exception during put", t);
            System.exit(1);
        }

        @Override
        public void onSuccess(UserRecordResult result) {
            completed.getAndIncrement();
        }
    };

    // Progress updates
    Thread progress = new Thread(new Runnable() {
        @Override
        public void run() {
            while (true) {
                long put = sequenceNumber.get();
                double putPercent = 100.0 * put / totalRecordsToPut;
                long done = completed.get();
                double donePercent = 100.0 * done / totalRecordsToPut;
                log.info(String.format("Put %d of %d so far (%.2f %%), %d have completed (%.2f %%)", put,
                        totalRecordsToPut, putPercent, done, donePercent));

                if (done == totalRecordsToPut) {
                    break;
                }

                // Numerous metrics are available from the KPL locally, as
                // well as uploaded to CloudWatch. See the metrics
                // documentation for details.
                //
                // KinesisProducer provides methods to retrieve metrics for
                // the current instance, with a customizable time window.
                // This allows us to get sliding window statistics in real
                // time for the current host.
                //
                // Here we're going to look at the number of user records
                // put over a 5 seconds sliding window.
                try {
                    for (Metric m : kinesisProducer.getMetrics("UserRecordsPut", 5)) {
                        // Metrics are emitted at different granularities, here
                        // we only look at the stream level metric, which has a
                        // single dimension of stream name.
                        if (m.getDimensions().size() == 1 && m.getSampleCount() > 0) {
                            log.info(String.format(
                                    "(Sliding 5 seconds) Avg put rate: %.2f per sec, success rate: %.2f, failure rate: %.2f, total attemped: %d",
                                    m.getSum() / 5, m.getSum() / m.getSampleCount() * 100,
                                    (m.getSampleCount() - m.getSum()) / m.getSampleCount() * 100,
                                    (long) m.getSampleCount()));
                        }
                    }
                } catch (Exception e) {
                    log.error("Unexpected error getting metrics", e);
                    System.exit(1);
                }

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
            }
        }
    });
    progress.start();

    // Put records
    while (true) {
        // We're going to put as fast as we can until we've reached the max
        // number of records outstanding.
        if (sequenceNumber.get() < totalRecordsToPut) {
            if (kinesisProducer.getOutstandingRecordsCount() < outstandingLimit) {
                ByteBuffer data = Utils.generateData(sequenceNumber.incrementAndGet(), dataSize);
                ListenableFuture<UserRecordResult> f = kinesisProducer.addUserRecord(SampleProducer.STREAM_NAME,
                        timetstamp, data);
                Futures.addCallback(f, callback);
            } else {
                Thread.sleep(1);
            }
        } else {
            break;
        }
    }

    // Wait for remaining records to finish
    while (kinesisProducer.getOutstandingRecordsCount() > 0) {
        kinesisProducer.flush();
        Thread.sleep(100);
    }

    progress.join();

    for (Metric m : kinesisProducer.getMetrics("UserRecordsPerKinesisRecord")) {
        if (m.getDimensions().containsKey("ShardId")) {
            log.info(String.format(
                    "%.2f user records were aggregated into each Kinesis record on average for shard %s, for a total of %d Kinesis records.",
                    m.getMean(), m.getDimensions().get("ShardId"), (long) m.getSampleCount()));
        }
    }

    kinesisProducer.destroy();
    log.info("Finished.");
}

From source file:edu.mit.streamjit.test.apps.bitonicsort.BitonicSort.java

public static void main(String[] args) throws InterruptedException {
    StreamCompiler sc = new Compiler2StreamCompiler().maxNumCores(8).multiplier(64);
    Benchmarker.runBenchmark(Iterables.getLast(new BitonicSort()), sc).get(0).print(System.out);
}

From source file:com.amazonaws.kinesis.producer.SampleKPLProducer.java

public static void main(String[] args) throws Exception {
    if (args.length != 2) {
        System.err.println("Usage SampleKPLProducer <stream name> <region>");
        System.exit(1);//from   w  w w.j ava 2  s  .com
    }

    String streamName = args[0];
    String regionName = args[1];

    final KinesisProducer producer = getKinesisProducer(regionName);

    final AtomicLong sequenceNumber = new AtomicLong(0);
    final AtomicLong completed = new AtomicLong(0);

    final FutureCallback<UserRecordResult> callback = new FutureCallback<UserRecordResult>() {
        @Override
        public void onFailure(Throwable t) {
            if (t instanceof UserRecordFailedException) {
                Attempt last = Iterables.getLast(((UserRecordFailedException) t).getResult().getAttempts());
                System.err.println(String.format("Record failed to put - %s : %s", last.getErrorCode(),
                        last.getErrorMessage()));
            }
            System.err.println("Exception during put: " + t.getMessage());
            t.printStackTrace();
            System.exit(1);
        }

        @Override
        public void onSuccess(UserRecordResult result) {
            completed.getAndIncrement();
        }
    };

    final Runnable putOneRecord = new Runnable() {
        @Override
        public void run() {
            byte[] data = ProducerUtils.randomData(sequenceNumber.get(), ProducerConfig.RECORD_SIZE_BYTES);
            ListenableFuture<UserRecordResult> f = producer.addUserRecord(streamName,
                    ProducerUtils.randomPartitionKey(), ProducerUtils.randomExplicitHashKey(),
                    ByteBuffer.wrap(data));
            Futures.addCallback(f, callback);
        }
    };

    EXECUTOR.scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            long put = sequenceNumber.get();
            long total = RECORDS_PER_SECOND * SECONDS_TO_RUN;
            double putPercent = 100.0 * put / total;
            long done = completed.get();
            double donePercent = 100.0 * done / total;
            System.out.println(String.format("Put %d of %d so far (%.2f %%), %d have completed (%.2f %%)", put,
                    total, putPercent, done, donePercent));
        }
    }, 1, 1, TimeUnit.SECONDS);

    System.out.println(String.format("Starting puts... will run for %d seconds at %d records per second",
            SECONDS_TO_RUN, RECORDS_PER_SECOND));

    executeAtTargetRate(EXECUTOR, putOneRecord, sequenceNumber, SECONDS_TO_RUN, RECORDS_PER_SECOND);

    EXECUTOR.awaitTermination(SECONDS_TO_RUN + 1, TimeUnit.SECONDS);

    System.out.println("Waiting for remaining puts to finish...");
    producer.flushSync();
    System.out.println("All records complete.");

    producer.destroy();
    System.out.println("Finished.");
}

From source file:org.bitcoinj.core.BitcoindComparisonTool.java

public static void main(String[] args) throws Exception {
    BriefLogFormatter.init();//from www  .j av  a2  s.c o  m
    System.out.println("USAGE: bitcoinjBlockStoreLocation runExpensiveTests(1/0) [port=18444]");
    boolean runExpensiveTests = args.length > 1 && Integer.parseInt(args[1]) == 1;

    params = RegTestParams.get();
    Context ctx = new Context(params);

    File blockFile = File.createTempFile("testBlocks", ".dat");
    blockFile.deleteOnExit();

    FullBlockTestGenerator generator = new FullBlockTestGenerator(params);
    final RuleList blockList = generator.getBlocksToTest(false, runExpensiveTests, blockFile);
    final Map<Sha256Hash, Block> preloadedBlocks = new HashMap<>();
    final Iterator<Block> blocks = new BlockFileLoader(params, Arrays.asList(blockFile));

    try {
        H2FullPrunedBlockStore store = new H2FullPrunedBlockStore(params,
                args.length > 0 ? args[0] : "BitcoindComparisonTool", blockList.maximumReorgBlockCount);
        store.resetStore();
        //store = new MemoryFullPrunedBlockStore(params, blockList.maximumReorgBlockCount);
        chain = new FullPrunedBlockChain(params, store);
    } catch (BlockStoreException e) {
        e.printStackTrace();
        System.exit(1);
    }

    VersionMessage ver = new VersionMessage(params, 42);
    ver.appendToSubVer("BlockAcceptanceComparisonTool", "1.1", null);
    ver.localServices = VersionMessage.NODE_NETWORK;
    final Peer bitcoind = new Peer(params, ver, new BlockChain(params, new MemoryBlockStore(params)),
            new PeerAddress(params, InetAddress.getLocalHost()));
    Preconditions.checkState(bitcoind.getVersionMessage().hasBlockChain());

    final BlockWrapper currentBlock = new BlockWrapper();

    final Set<Sha256Hash> blocksRequested = Collections.synchronizedSet(new HashSet<Sha256Hash>());
    final Set<Sha256Hash> blocksPendingSend = Collections.synchronizedSet(new HashSet<Sha256Hash>());
    final AtomicInteger unexpectedInvs = new AtomicInteger(0);
    final SettableFuture<Void> connectedFuture = SettableFuture.create();
    bitcoind.addConnectedEventListener(Threading.SAME_THREAD, new PeerConnectedEventListener() {
        @Override
        public void onPeerConnected(Peer peer, int peerCount) {
            if (!peer.getPeerVersionMessage().subVer.contains("Satoshi")) {
                System.out.println();
                System.out.println(
                        "************************************************************************************************************************\n"
                                + "WARNING: You appear to be using this to test an alternative implementation with full validation rules. You should go\n"
                                + "think hard about what you're doing. Seriously, no one has gotten even close to correctly reimplementing Bitcoin\n"
                                + "consensus rules, despite serious investment in trying. It is a huge task and the slightest difference is a huge bug.\n"
                                + "Instead, go work on making Bitcoin Core consensus rules a shared library and use that. Seriously, you wont get it right,\n"
                                + "and starting with this tester as a way to try to do so will simply end in pain and lost coins.\n"
                                + "************************************************************************************************************************");
                System.out.println();
            }
            log.info("bitcoind connected");
            // Make sure bitcoind has no blocks
            bitcoind.setDownloadParameters(0, false);
            bitcoind.startBlockChainDownload();
            connectedFuture.set(null);
        }
    });

    bitcoind.addDisconnectedEventListener(Threading.SAME_THREAD, new PeerDisconnectedEventListener() {
        @Override
        public void onPeerDisconnected(Peer peer, int peerCount) {
            log.error("bitcoind node disconnected!");
            System.exit(1);
        }
    });

    bitcoind.addPreMessageReceivedEventListener(Threading.SAME_THREAD, new PreMessageReceivedEventListener() {
        @Override
        public Message onPreMessageReceived(Peer peer, Message m) {
            if (m instanceof HeadersMessage) {
                if (!((HeadersMessage) m).getBlockHeaders().isEmpty()) {
                    Block b = Iterables.getLast(((HeadersMessage) m).getBlockHeaders());
                    log.info("Got header from bitcoind " + b.getHashAsString());
                    bitcoindChainHead = b.getHash();
                } else
                    log.info("Got empty header message from bitcoind");
                return null;
            } else if (m instanceof Block) {
                log.error("bitcoind sent us a block it already had, make sure bitcoind has no blocks!");
                System.exit(1);
            } else if (m instanceof GetDataMessage) {
                for (InventoryItem item : ((GetDataMessage) m).items)
                    if (item.type == InventoryItem.Type.Block) {
                        log.info("Requested " + item.hash);
                        if (currentBlock.block.getHash().equals(item.hash))
                            bitcoind.sendMessage(currentBlock.block);
                        else {
                            Block nextBlock = preloadedBlocks.get(item.hash);
                            if (nextBlock != null)
                                bitcoind.sendMessage(nextBlock);
                            else {
                                blocksPendingSend.add(item.hash);
                                log.info("...which we will not provide yet");
                            }
                        }
                        blocksRequested.add(item.hash);
                    }
                return null;
            } else if (m instanceof GetHeadersMessage) {
                try {
                    if (currentBlock.block == null) {
                        log.info("Got a request for a header before we had even begun processing blocks!");
                        return null;
                    }
                    LinkedList<Block> headers = new LinkedList<>();
                    Block it = blockList.hashHeaderMap.get(currentBlock.block.getHash());
                    while (it != null) {
                        headers.addFirst(it);
                        it = blockList.hashHeaderMap.get(it.getPrevBlockHash());
                    }
                    LinkedList<Block> sendHeaders = new LinkedList<>();
                    boolean found = false;
                    for (Sha256Hash hash : ((GetHeadersMessage) m).getLocator()) {
                        for (Block b : headers) {
                            if (found) {
                                sendHeaders.addLast(b);
                                log.info("Sending header (" + b.getPrevBlockHash() + ") -> " + b.getHash());
                                if (b.getHash().equals(((GetHeadersMessage) m).getStopHash()))
                                    break;
                            } else if (b.getHash().equals(hash)) {
                                log.info("Found header " + b.getHashAsString());
                                found = true;
                            }
                        }
                        if (found)
                            break;
                    }
                    if (!found)
                        sendHeaders = headers;
                    bitcoind.sendMessage(new HeadersMessage(params, sendHeaders));
                    InventoryMessage i = new InventoryMessage(params);
                    for (Block b : sendHeaders)
                        i.addBlock(b);
                    bitcoind.sendMessage(i);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                return null;
            } else if (m instanceof InventoryMessage) {
                if (mostRecentInv != null) {
                    log.error("Got an inv when we weren't expecting one");
                    unexpectedInvs.incrementAndGet();
                }
                mostRecentInv = (InventoryMessage) m;
            }
            return m;
        }
    });

    bitcoindChainHead = params.getGenesisBlock().getHash();

    // bitcoind MUST be on localhost or we will get banned as a DoSer
    new NioClient(new InetSocketAddress(InetAddress.getByName("127.0.0.1"),
            args.length > 2 ? Integer.parseInt(args[2]) : params.getPort()), bitcoind, 1000);

    connectedFuture.get();

    ArrayList<Sha256Hash> locator = new ArrayList<>(1);
    locator.add(params.getGenesisBlock().getHash());
    Sha256Hash hashTo = Sha256Hash.wrap("0000000000000000000000000000000000000000000000000000000000000000");

    int rulesSinceFirstFail = 0;
    for (Rule rule : blockList.list) {
        if (rule instanceof FullBlockTestGenerator.BlockAndValidity) {
            FullBlockTestGenerator.BlockAndValidity block = (FullBlockTestGenerator.BlockAndValidity) rule;
            boolean threw = false;
            Block nextBlock = preloadedBlocks.get(((FullBlockTestGenerator.BlockAndValidity) rule).blockHash);
            // Often load at least one block because sometimes we have duplicates with the same hash (b56/57)
            for (int i = 0; i < 1 || nextBlock == null || !nextBlock.getHash().equals(block.blockHash); i++) {
                try {
                    Block b = blocks.next();
                    Block oldBlockWithSameHash = preloadedBlocks.put(b.getHash(), b);
                    if (oldBlockWithSameHash != null
                            && oldBlockWithSameHash.getTransactions().size() != b.getTransactions().size())
                        blocksRequested.remove(b.getHash());
                    nextBlock = preloadedBlocks.get(block.blockHash);
                } catch (NoSuchElementException e) {
                    if (nextBlock == null || !nextBlock.getHash().equals(block.blockHash))
                        throw e;
                }
            }
            currentBlock.block = nextBlock;
            log.info("Testing block {} {}", block.ruleName, currentBlock.block.getHash());
            try {
                if (chain.add(nextBlock) != block.connects) {
                    log.error("ERROR: Block didn't match connects flag on block \"" + block.ruleName + "\"");
                    rulesSinceFirstFail++;
                }
            } catch (VerificationException e) {
                threw = true;
                if (!block.throwsException) {
                    log.error("ERROR: Block didn't match throws flag on block \"" + block.ruleName + "\"");
                    e.printStackTrace();
                    rulesSinceFirstFail++;
                } else if (block.connects) {
                    log.error("ERROR: Block didn't match connects flag on block \"" + block.ruleName + "\"");
                    e.printStackTrace();
                    rulesSinceFirstFail++;
                }
            }
            if (!threw && block.throwsException) {
                log.error("ERROR: Block didn't match throws flag on block \"" + block.ruleName + "\"");
                rulesSinceFirstFail++;
            } else if (!chain.getChainHead().getHeader().getHash().equals(block.hashChainTipAfterBlock)) {
                log.error("ERROR: New block head didn't match the correct value after block \"" + block.ruleName
                        + "\"");
                rulesSinceFirstFail++;
            } else if (chain.getChainHead().getHeight() != block.heightAfterBlock) {
                log.error(
                        "ERROR: New block head didn't match the correct height after block " + block.ruleName);
                rulesSinceFirstFail++;
            }

            // Shouldnt double-request
            boolean shouldntRequest = blocksRequested.contains(nextBlock.getHash());
            if (shouldntRequest)
                blocksRequested.remove(nextBlock.getHash());
            InventoryMessage message = new InventoryMessage(params);
            message.addBlock(nextBlock);
            bitcoind.sendMessage(message);
            log.info("Sent inv with block " + nextBlock.getHashAsString());
            if (blocksPendingSend.contains(nextBlock.getHash())) {
                bitcoind.sendMessage(nextBlock);
                log.info("Sent full block " + nextBlock.getHashAsString());
            }
            // bitcoind doesn't request blocks inline so we can't rely on a ping for synchronization
            for (int i = 0; !shouldntRequest && !blocksRequested.contains(nextBlock.getHash()); i++) {
                int SLEEP_TIME = 1;
                if (i % 1000 / SLEEP_TIME == 1000 / SLEEP_TIME - 1)
                    log.error("bitcoind still hasn't requested block " + block.ruleName + " with hash "
                            + nextBlock.getHash());
                Thread.sleep(SLEEP_TIME);
                if (i > 60000 / SLEEP_TIME) {
                    log.error("bitcoind failed to request block " + block.ruleName);
                    System.exit(1);
                }
            }
            if (shouldntRequest) {
                Thread.sleep(100);
                if (blocksRequested.contains(nextBlock.getHash())) {
                    log.error("ERROR: bitcoind re-requested block " + block.ruleName + " with hash "
                            + nextBlock.getHash());
                    rulesSinceFirstFail++;
                }
            }
            // If the block throws, we may want to get bitcoind to request the same block again
            if (block.throwsException)
                blocksRequested.remove(nextBlock.getHash());
            //bitcoind.sendMessage(nextBlock);
            locator.clear();
            locator.add(bitcoindChainHead);
            bitcoind.sendMessage(new GetHeadersMessage(params, locator, hashTo));
            bitcoind.ping().get();
            if (!chain.getChainHead().getHeader().getHash().equals(bitcoindChainHead)) {
                rulesSinceFirstFail++;
                log.error(
                        "ERROR: bitcoind and bitcoinj acceptance differs on block \"" + block.ruleName + "\"");
            }
            if (block.sendOnce)
                preloadedBlocks.remove(nextBlock.getHash());
            log.info("Block \"" + block.ruleName + "\" completed processing");
        } else if (rule instanceof MemoryPoolState) {
            MemoryPoolMessage message = new MemoryPoolMessage();
            bitcoind.sendMessage(message);
            bitcoind.ping().get();
            if (mostRecentInv == null && !((MemoryPoolState) rule).mempool.isEmpty()) {
                log.error("ERROR: bitcoind had an empty mempool, but we expected some transactions on rule "
                        + rule.ruleName);
                rulesSinceFirstFail++;
            } else if (mostRecentInv != null && ((MemoryPoolState) rule).mempool.isEmpty()) {
                log.error("ERROR: bitcoind had a non-empty mempool, but we expected an empty one on rule "
                        + rule.ruleName);
                rulesSinceFirstFail++;
            } else if (mostRecentInv != null) {
                Set<InventoryItem> originalRuleSet = new HashSet<>(((MemoryPoolState) rule).mempool);
                boolean matches = mostRecentInv.items.size() == ((MemoryPoolState) rule).mempool.size();
                for (InventoryItem item : mostRecentInv.items)
                    if (!((MemoryPoolState) rule).mempool.remove(item))
                        matches = false;
                if (matches)
                    continue;
                log.error("bitcoind's mempool didn't match what we were expecting on rule " + rule.ruleName);
                log.info("  bitcoind's mempool was: ");
                for (InventoryItem item : mostRecentInv.items)
                    log.info("    " + item.hash);
                log.info("  The expected mempool was: ");
                for (InventoryItem item : originalRuleSet)
                    log.info("    " + item.hash);
                rulesSinceFirstFail++;
            }
            mostRecentInv = null;
        } else if (rule instanceof UTXORule) {
            if (bitcoind.getPeerVersionMessage().isGetUTXOsSupported()) {
                UTXORule r = (UTXORule) rule;
                UTXOsMessage result = bitcoind.getUTXOs(r.query).get();
                if (!result.equals(r.result)) {
                    log.error("utxo result was not what we expected.");
                    log.error("Wanted  {}", r.result);
                    log.error("but got {}", result);
                    rulesSinceFirstFail++;
                } else {
                    log.info("Successful utxo query {}: {}", r.ruleName, result);
                }
            }
        } else {
            throw new RuntimeException("Unknown rule");
        }
        if (rulesSinceFirstFail > 0)
            rulesSinceFirstFail++;
        if (rulesSinceFirstFail > 6)
            System.exit(1);
    }

    if (unexpectedInvs.get() > 0)
        log.error("ERROR: Got " + unexpectedInvs.get() + " unexpected invs from bitcoind");
    log.info("Done testing.");
    System.exit(rulesSinceFirstFail > 0 || unexpectedInvs.get() > 0 ? 1 : 0);
}

From source file:org.guldenj.core.BitcoindComparisonTool.java

public static void main(String[] args) throws Exception {
    BriefLogFormatter.init();/*from ww  w . j  a va 2 s .  c o  m*/
    System.out.println("USAGE: guldenjBlockStoreLocation runExpensiveTests(1/0) [port=18444]");
    boolean runExpensiveTests = args.length > 1 && Integer.parseInt(args[1]) == 1;

    params = RegTestParams.get();
    Context ctx = new Context(params);

    File blockFile = File.createTempFile("testBlocks", ".dat");
    blockFile.deleteOnExit();

    FullBlockTestGenerator generator = new FullBlockTestGenerator(params);
    final RuleList blockList = generator.getBlocksToTest(false, runExpensiveTests, blockFile);
    final Map<Sha256Hash, Block> preloadedBlocks = new HashMap<Sha256Hash, Block>();
    final Iterator<Block> blocks = new BlockFileLoader(params, Arrays.asList(blockFile));

    try {
        H2FullPrunedBlockStore store = new H2FullPrunedBlockStore(params,
                args.length > 0 ? args[0] : "BitcoindComparisonTool", blockList.maximumReorgBlockCount);
        store.resetStore();
        //store = new MemoryFullPrunedBlockStore(params, blockList.maximumReorgBlockCount);
        chain = new FullPrunedBlockChain(params, store);
    } catch (BlockStoreException e) {
        e.printStackTrace();
        System.exit(1);
    }

    VersionMessage ver = new VersionMessage(params, 42);
    ver.appendToSubVer("BlockAcceptanceComparisonTool", "1.1", null);
    ver.localServices = VersionMessage.NODE_NETWORK;
    final Peer bitcoind = new Peer(params, ver, new BlockChain(params, new MemoryBlockStore(params)),
            new PeerAddress(params, InetAddress.getLocalHost()));
    Preconditions.checkState(bitcoind.getVersionMessage().hasBlockChain());

    final BlockWrapper currentBlock = new BlockWrapper();

    final Set<Sha256Hash> blocksRequested = Collections.synchronizedSet(new HashSet<Sha256Hash>());
    final Set<Sha256Hash> blocksPendingSend = Collections.synchronizedSet(new HashSet<Sha256Hash>());
    final AtomicInteger unexpectedInvs = new AtomicInteger(0);
    final SettableFuture<Void> connectedFuture = SettableFuture.create();
    bitcoind.addConnectedEventListener(Threading.SAME_THREAD, new PeerConnectedEventListener() {
        @Override
        public void onPeerConnected(Peer peer, int peerCount) {
            if (!peer.getPeerVersionMessage().subVer.contains("Satoshi")) {
                System.out.println();
                System.out.println(
                        "************************************************************************************************************************\n"
                                + "WARNING: You appear to be using this to test an alternative implementation with full validation rules. You should go\n"
                                + "think hard about what you're doing. Seriously, no one has gotten even close to correctly reimplementing Bitcoin\n"
                                + "consensus rules, despite serious investment in trying. It is a huge task and the slightest difference is a huge bug.\n"
                                + "Instead, go work on making Bitcoin Core consensus rules a shared library and use that. Seriously, you wont get it right,\n"
                                + "and starting with this tester as a way to try to do so will simply end in pain and lost coins.\n"
                                + "************************************************************************************************************************");
                System.out.println();
            }
            log.info("bitcoind connected");
            // Make sure bitcoind has no blocks
            bitcoind.setDownloadParameters(0, false);
            bitcoind.startBlockChainDownload();
            connectedFuture.set(null);
        }
    });

    bitcoind.addDisconnectedEventListener(Threading.SAME_THREAD, new PeerDisconnectedEventListener() {
        @Override
        public void onPeerDisconnected(Peer peer, int peerCount) {
            log.error("bitcoind node disconnected!");
            System.exit(1);
        }
    });

    bitcoind.addPreMessageReceivedEventListener(Threading.SAME_THREAD, new PreMessageReceivedEventListener() {
        @Override
        public Message onPreMessageReceived(Peer peer, Message m) {
            if (m instanceof HeadersMessage) {
                if (!((HeadersMessage) m).getBlockHeaders().isEmpty()) {
                    Block b = Iterables.getLast(((HeadersMessage) m).getBlockHeaders());
                    log.info("Got header from bitcoind " + b.getHashAsString());
                    bitcoindChainHead = b.getHash();
                } else
                    log.info("Got empty header message from bitcoind");
                return null;
            } else if (m instanceof Block) {
                log.error("bitcoind sent us a block it already had, make sure bitcoind has no blocks!");
                System.exit(1);
            } else if (m instanceof GetDataMessage) {
                for (InventoryItem item : ((GetDataMessage) m).items)
                    if (item.type == InventoryItem.Type.Block) {
                        log.info("Requested " + item.hash);
                        if (currentBlock.block.getHash().equals(item.hash))
                            bitcoind.sendMessage(currentBlock.block);
                        else {
                            Block nextBlock = preloadedBlocks.get(item.hash);
                            if (nextBlock != null)
                                bitcoind.sendMessage(nextBlock);
                            else {
                                blocksPendingSend.add(item.hash);
                                log.info("...which we will not provide yet");
                            }
                        }
                        blocksRequested.add(item.hash);
                    }
                return null;
            } else if (m instanceof GetHeadersMessage) {
                try {
                    if (currentBlock.block == null) {
                        log.info("Got a request for a header before we had even begun processing blocks!");
                        return null;
                    }
                    LinkedList<Block> headers = new LinkedList<Block>();
                    Block it = blockList.hashHeaderMap.get(currentBlock.block.getHash());
                    while (it != null) {
                        headers.addFirst(it);
                        it = blockList.hashHeaderMap.get(it.getPrevBlockHash());
                    }
                    LinkedList<Block> sendHeaders = new LinkedList<Block>();
                    boolean found = false;
                    for (Sha256Hash hash : ((GetHeadersMessage) m).getLocator()) {
                        for (Block b : headers) {
                            if (found) {
                                sendHeaders.addLast(b);
                                log.info("Sending header (" + b.getPrevBlockHash() + ") -> " + b.getHash());
                                if (b.getHash().equals(((GetHeadersMessage) m).getStopHash()))
                                    break;
                            } else if (b.getHash().equals(hash)) {
                                log.info("Found header " + b.getHashAsString());
                                found = true;
                            }
                        }
                        if (found)
                            break;
                    }
                    if (!found)
                        sendHeaders = headers;
                    bitcoind.sendMessage(new HeadersMessage(params, sendHeaders));
                    InventoryMessage i = new InventoryMessage(params);
                    for (Block b : sendHeaders)
                        i.addBlock(b);
                    bitcoind.sendMessage(i);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                return null;
            } else if (m instanceof InventoryMessage) {
                if (mostRecentInv != null) {
                    log.error("Got an inv when we weren't expecting one");
                    unexpectedInvs.incrementAndGet();
                }
                mostRecentInv = (InventoryMessage) m;
            }
            return m;
        }
    });

    bitcoindChainHead = params.getGenesisBlock().getHash();

    // bitcoind MUST be on localhost or we will get banned as a DoSer
    new NioClient(new InetSocketAddress(InetAddress.getByName("127.0.0.1"),
            args.length > 2 ? Integer.parseInt(args[2]) : params.getPort()), bitcoind, 1000);

    connectedFuture.get();

    ArrayList<Sha256Hash> locator = new ArrayList<Sha256Hash>(1);
    locator.add(params.getGenesisBlock().getHash());
    Sha256Hash hashTo = Sha256Hash.wrap("0000000000000000000000000000000000000000000000000000000000000000");

    int rulesSinceFirstFail = 0;
    for (Rule rule : blockList.list) {
        if (rule instanceof FullBlockTestGenerator.BlockAndValidity) {
            FullBlockTestGenerator.BlockAndValidity block = (FullBlockTestGenerator.BlockAndValidity) rule;
            boolean threw = false;
            Block nextBlock = preloadedBlocks.get(((FullBlockTestGenerator.BlockAndValidity) rule).blockHash);
            // Often load at least one block because sometimes we have duplicates with the same hash (b56/57)
            for (int i = 0; i < 1 || nextBlock == null || !nextBlock.getHash().equals(block.blockHash); i++) {
                try {
                    Block b = blocks.next();
                    Block oldBlockWithSameHash = preloadedBlocks.put(b.getHash(), b);
                    if (oldBlockWithSameHash != null
                            && oldBlockWithSameHash.getTransactions().size() != b.getTransactions().size())
                        blocksRequested.remove(b.getHash());
                    nextBlock = preloadedBlocks.get(block.blockHash);
                } catch (NoSuchElementException e) {
                    if (nextBlock == null || !nextBlock.getHash().equals(block.blockHash))
                        throw e;
                }
            }
            currentBlock.block = nextBlock;
            log.info("Testing block {} {}", block.ruleName, currentBlock.block.getHash());
            try {
                if (chain.add(nextBlock) != block.connects) {
                    log.error("ERROR: Block didn't match connects flag on block \"" + block.ruleName + "\"");
                    rulesSinceFirstFail++;
                }
            } catch (VerificationException e) {
                threw = true;
                if (!block.throwsException) {
                    log.error("ERROR: Block didn't match throws flag on block \"" + block.ruleName + "\"");
                    e.printStackTrace();
                    rulesSinceFirstFail++;
                } else if (block.connects) {
                    log.error("ERROR: Block didn't match connects flag on block \"" + block.ruleName + "\"");
                    e.printStackTrace();
                    rulesSinceFirstFail++;
                }
            }
            if (!threw && block.throwsException) {
                log.error("ERROR: Block didn't match throws flag on block \"" + block.ruleName + "\"");
                rulesSinceFirstFail++;
            } else if (!chain.getChainHead().getHeader().getHash().equals(block.hashChainTipAfterBlock)) {
                log.error("ERROR: New block head didn't match the correct value after block \"" + block.ruleName
                        + "\"");
                rulesSinceFirstFail++;
            } else if (chain.getChainHead().getHeight() != block.heightAfterBlock) {
                log.error(
                        "ERROR: New block head didn't match the correct height after block " + block.ruleName);
                rulesSinceFirstFail++;
            }

            // Shouldnt double-request
            boolean shouldntRequest = blocksRequested.contains(nextBlock.getHash());
            if (shouldntRequest)
                blocksRequested.remove(nextBlock.getHash());
            InventoryMessage message = new InventoryMessage(params);
            message.addBlock(nextBlock);
            bitcoind.sendMessage(message);
            log.info("Sent inv with block " + nextBlock.getHashAsString());
            if (blocksPendingSend.contains(nextBlock.getHash())) {
                bitcoind.sendMessage(nextBlock);
                log.info("Sent full block " + nextBlock.getHashAsString());
            }
            // bitcoind doesn't request blocks inline so we can't rely on a ping for synchronization
            for (int i = 0; !shouldntRequest && !blocksRequested.contains(nextBlock.getHash()); i++) {
                int SLEEP_TIME = 1;
                if (i % 1000 / SLEEP_TIME == 1000 / SLEEP_TIME - 1)
                    log.error("bitcoind still hasn't requested block " + block.ruleName + " with hash "
                            + nextBlock.getHash());
                Thread.sleep(SLEEP_TIME);
                if (i > 60000 / SLEEP_TIME) {
                    log.error("bitcoind failed to request block " + block.ruleName);
                    System.exit(1);
                }
            }
            if (shouldntRequest) {
                Thread.sleep(100);
                if (blocksRequested.contains(nextBlock.getHash())) {
                    log.error("ERROR: bitcoind re-requested block " + block.ruleName + " with hash "
                            + nextBlock.getHash());
                    rulesSinceFirstFail++;
                }
            }
            // If the block throws, we may want to get bitcoind to request the same block again
            if (block.throwsException)
                blocksRequested.remove(nextBlock.getHash());
            //bitcoind.sendMessage(nextBlock);
            locator.clear();
            locator.add(bitcoindChainHead);
            bitcoind.sendMessage(new GetHeadersMessage(params, locator, hashTo));
            bitcoind.ping().get();
            if (!chain.getChainHead().getHeader().getHash().equals(bitcoindChainHead)) {
                rulesSinceFirstFail++;
                log.error("ERROR: bitcoind and guldenj acceptance differs on block \"" + block.ruleName + "\"");
            }
            if (block.sendOnce)
                preloadedBlocks.remove(nextBlock.getHash());
            log.info("Block \"" + block.ruleName + "\" completed processing");
        } else if (rule instanceof MemoryPoolState) {
            MemoryPoolMessage message = new MemoryPoolMessage();
            bitcoind.sendMessage(message);
            bitcoind.ping().get();
            if (mostRecentInv == null && !((MemoryPoolState) rule).mempool.isEmpty()) {
                log.error("ERROR: bitcoind had an empty mempool, but we expected some transactions on rule "
                        + rule.ruleName);
                rulesSinceFirstFail++;
            } else if (mostRecentInv != null && ((MemoryPoolState) rule).mempool.isEmpty()) {
                log.error("ERROR: bitcoind had a non-empty mempool, but we expected an empty one on rule "
                        + rule.ruleName);
                rulesSinceFirstFail++;
            } else if (mostRecentInv != null) {
                Set<InventoryItem> originalRuleSet = new HashSet<InventoryItem>(
                        ((MemoryPoolState) rule).mempool);
                boolean matches = mostRecentInv.items.size() == ((MemoryPoolState) rule).mempool.size();
                for (InventoryItem item : mostRecentInv.items)
                    if (!((MemoryPoolState) rule).mempool.remove(item))
                        matches = false;
                if (matches)
                    continue;
                log.error("bitcoind's mempool didn't match what we were expecting on rule " + rule.ruleName);
                log.info("  bitcoind's mempool was: ");
                for (InventoryItem item : mostRecentInv.items)
                    log.info("    " + item.hash);
                log.info("  The expected mempool was: ");
                for (InventoryItem item : originalRuleSet)
                    log.info("    " + item.hash);
                rulesSinceFirstFail++;
            }
            mostRecentInv = null;
        } else if (rule instanceof UTXORule) {
            if (bitcoind.getPeerVersionMessage().isGetUTXOsSupported()) {
                UTXORule r = (UTXORule) rule;
                UTXOsMessage result = bitcoind.getUTXOs(r.query).get();
                if (!result.equals(r.result)) {
                    log.error("utxo result was not what we expected.");
                    log.error("Wanted  {}", r.result);
                    log.error("but got {}", result);
                    rulesSinceFirstFail++;
                } else {
                    log.info("Successful utxo query {}: {}", r.ruleName, result);
                }
            }
        } else {
            throw new RuntimeException("Unknown rule");
        }
        if (rulesSinceFirstFail > 0)
            rulesSinceFirstFail++;
        if (rulesSinceFirstFail > 6)
            System.exit(1);
    }

    if (unexpectedInvs.get() > 0)
        log.error("ERROR: Got " + unexpectedInvs.get() + " unexpected invs from bitcoind");
    log.info("Done testing.");
    System.exit(rulesSinceFirstFail > 0 || unexpectedInvs.get() > 0 ? 1 : 0);
}

From source file:org.litecoinj.core.BitcoindComparisonTool.java

public static void main(String[] args) throws Exception {
    BriefLogFormatter.init();/*ww w. j av  a 2s.c o m*/
    System.out.println("USAGE: bitcoinjBlockStoreLocation runExpensiveTests(1/0) [port=18444]");
    boolean runExpensiveTests = args.length > 1 && Integer.parseInt(args[1]) == 1;

    params = RegTestParams.get();
    Context ctx = new Context(params);

    File blockFile = File.createTempFile("testBlocks", ".dat");
    blockFile.deleteOnExit();

    FullBlockTestGenerator generator = new FullBlockTestGenerator(params);
    final RuleList blockList = generator.getBlocksToTest(false, runExpensiveTests, blockFile);
    final Map<Sha256Hash, Block> preloadedBlocks = new HashMap<>();
    final Iterator<Block> blocks = new BlockFileLoader(params, Arrays.asList(blockFile));

    try {
        H2FullPrunedBlockStore store = new H2FullPrunedBlockStore(params,
                args.length > 0 ? args[0] : "BitcoindComparisonTool", blockList.maximumReorgBlockCount);
        store.resetStore();
        //store = new MemoryFullPrunedBlockStore(params, blockList.maximumReorgBlockCount);
        chain = new FullPrunedBlockChain(params, store);
    } catch (BlockStoreException e) {
        e.printStackTrace();
        System.exit(1);
    }

    VersionMessage ver = new VersionMessage(params, 42);
    ver.appendToSubVer("BlockAcceptanceComparisonTool", "1.1", null);
    ver.localServices = VersionMessage.NODE_NETWORK;
    final Peer bitcoind = new Peer(params, ver, new BlockChain(params, new MemoryBlockStore(params)),
            new PeerAddress(params, InetAddress.getLocalHost()));
    Preconditions.checkState(bitcoind.getVersionMessage().hasBlockChain());

    final BlockWrapper currentBlock = new BlockWrapper();

    final Set<Sha256Hash> blocksRequested = Collections.synchronizedSet(new HashSet<Sha256Hash>());
    final Set<Sha256Hash> blocksPendingSend = Collections.synchronizedSet(new HashSet<Sha256Hash>());
    final AtomicInteger unexpectedInvs = new AtomicInteger(0);
    final SettableFuture<Void> connectedFuture = SettableFuture.create();
    bitcoind.addConnectedEventListener(Threading.SAME_THREAD, new PeerConnectedEventListener() {
        @Override
        public void onPeerConnected(Peer peer, int peerCount) {
            if (!peer.getPeerVersionMessage().subVer.contains("Satoshi")) {
                System.out.println();
                System.out.println(
                        "************************************************************************************************************************\n"
                                + "WARNING: You appear to be using this to test an alternative implementation with full validation rules. You should go\n"
                                + "think hard about what you're doing. Seriously, no one has gotten even close to correctly reimplementing Bitcoin\n"
                                + "consensus rules, despite serious investment in trying. It is a huge task and the slightest difference is a huge bug.\n"
                                + "Instead, go work on making Bitcoin Core consensus rules a shared library and use that. Seriously, you wont get it right,\n"
                                + "and starting with this tester as a way to try to do so will simply end in pain and lost coins.\n"
                                + "************************************************************************************************************************");
                System.out.println();
            }
            log.info("bitcoind connected");
            // Make sure bitcoind has no blocks
            bitcoind.setDownloadParameters(0, false);
            bitcoind.startBlockChainDownload();
            connectedFuture.set(null);
        }
    });

    bitcoind.addDisconnectedEventListener(Threading.SAME_THREAD, new PeerDisconnectedEventListener() {
        @Override
        public void onPeerDisconnected(Peer peer, int peerCount) {
            log.error("bitcoind node disconnected!");
            System.exit(1);
        }
    });

    bitcoind.addPreMessageReceivedEventListener(Threading.SAME_THREAD, new PreMessageReceivedEventListener() {
        @Override
        public Message onPreMessageReceived(Peer peer, Message m) {
            if (m instanceof HeadersMessage) {
                if (!((HeadersMessage) m).getBlockHeaders().isEmpty()) {
                    Block b = Iterables.getLast(((HeadersMessage) m).getBlockHeaders());
                    log.info("Got header from bitcoind " + b.getHashAsString());
                    bitcoindChainHead = b.getHash();
                } else
                    log.info("Got empty header message from bitcoind");
                return null;
            } else if (m instanceof Block) {
                log.error("bitcoind sent us a block it already had, make sure bitcoind has no blocks!");
                System.exit(1);
            } else if (m instanceof GetDataMessage) {
                for (InventoryItem item : ((GetDataMessage) m).items)
                    if (item.type == InventoryItem.Type.Block) {
                        log.info("Requested " + item.hash);
                        if (currentBlock.block.getHash().equals(item.hash))
                            bitcoind.sendMessage(currentBlock.block);
                        else {
                            Block nextBlock = preloadedBlocks.get(item.hash);
                            if (nextBlock != null)
                                bitcoind.sendMessage(nextBlock);
                            else {
                                blocksPendingSend.add(item.hash);
                                log.info("...which we will not provide yet");
                            }
                        }
                        blocksRequested.add(item.hash);
                    }
                return null;
            } else if (m instanceof GetHeadersMessage) {
                try {
                    if (currentBlock.block == null) {
                        log.info("Got a request for a header before we had even begun processing blocks!");
                        return null;
                    }
                    LinkedList<Block> headers = new LinkedList<>();
                    Block it = blockList.hashHeaderMap.get(currentBlock.block.getHash());
                    while (it != null) {
                        headers.addFirst(it);
                        it = blockList.hashHeaderMap.get(it.getPrevBlockHash());
                    }
                    LinkedList<Block> sendHeaders = new LinkedList<>();
                    boolean found = false;
                    for (Sha256Hash hash : ((GetHeadersMessage) m).getLocator()) {
                        for (Block b : headers) {
                            if (found) {
                                sendHeaders.addLast(b);
                                log.info("Sending header (" + b.getPrevBlockHash() + ") -> " + b.getHash());
                                if (b.getHash().equals(((GetHeadersMessage) m).getStopHash()))
                                    break;
                            } else if (b.getHash().equals(hash)) {
                                log.info("Found header " + b.getHashAsString());
                                found = true;
                            }
                        }
                        if (found)
                            break;
                    }
                    if (!found)
                        sendHeaders = headers;
                    bitcoind.sendMessage(new HeadersMessage(params, sendHeaders));
                    InventoryMessage i = new InventoryMessage(params);
                    for (Block b : sendHeaders)
                        i.addBlock(b);
                    bitcoind.sendMessage(i);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                return null;
            } else if (m instanceof InventoryMessage) {
                if (mostRecentInv != null) {
                    log.error("Got an inv when we weren't expecting one");
                    unexpectedInvs.incrementAndGet();
                }
                mostRecentInv = (InventoryMessage) m;
            }
            return m;
        }
    });

    bitcoindChainHead = params.getGenesisBlock().getHash();

    // bitcoind MUST be on localhost or we will get banned as a DoSer
    new NioClient(new InetSocketAddress(InetAddress.getByName("127.0.0.1"),
            args.length > 2 ? Integer.parseInt(args[2]) : params.getPort()), bitcoind, 1000);

    connectedFuture.get();

    ArrayList<Sha256Hash> locator = new ArrayList<>(1);
    locator.add(params.getGenesisBlock().getHash());
    Sha256Hash hashTo = Sha256Hash.wrap("0000000000000000000000000000000000000000000000000000000000000000");

    int rulesSinceFirstFail = 0;
    for (Rule rule : blockList.list) {
        if (rule instanceof FullBlockTestGenerator.BlockAndValidity) {
            FullBlockTestGenerator.BlockAndValidity block = (FullBlockTestGenerator.BlockAndValidity) rule;
            boolean threw = false;
            Block nextBlock = preloadedBlocks.get(((FullBlockTestGenerator.BlockAndValidity) rule).blockHash);
            // Often load at least one block because sometimes we have duplicates with the same hash (b56/57)
            for (int i = 0; i < 1 || nextBlock == null || !nextBlock.getHash().equals(block.blockHash); i++) {
                try {
                    Block b = blocks.next();
                    Block oldBlockWithSameHash = preloadedBlocks.put(b.getHash(), b);
                    if (oldBlockWithSameHash != null
                            && oldBlockWithSameHash.getTransactions().size() != b.getTransactions().size())
                        blocksRequested.remove(b.getHash());
                    nextBlock = preloadedBlocks.get(block.blockHash);
                } catch (NoSuchElementException e) {
                    if (nextBlock == null || !nextBlock.getHash().equals(block.blockHash))
                        throw e;
                }
            }
            currentBlock.block = nextBlock;
            log.info("Testing block {} {}", block.ruleName, currentBlock.block.getHash());
            try {
                if (chain.add(nextBlock) != block.connects) {
                    log.error("ERROR: Block didn't match connects flag on block \"" + block.ruleName + "\"");
                    rulesSinceFirstFail++;
                }
            } catch (VerificationException e) {
                threw = true;
                if (!block.throwsException) {
                    log.error("ERROR: Block didn't match throws flag on block \"" + block.ruleName + "\"");
                    e.printStackTrace();
                    rulesSinceFirstFail++;
                } else if (block.connects) {
                    log.error("ERROR: Block didn't match connects flag on block \"" + block.ruleName + "\"");
                    e.printStackTrace();
                    rulesSinceFirstFail++;
                }
            }
            if (!threw && block.throwsException) {
                log.error("ERROR: Block didn't match throws flag on block \"" + block.ruleName + "\"");
                rulesSinceFirstFail++;
            } else if (!chain.getChainHead().getHeader().getHash().equals(block.hashChainTipAfterBlock)) {
                log.error("ERROR: New block head didn't match the correct value after block \"" + block.ruleName
                        + "\"");
                rulesSinceFirstFail++;
            } else if (chain.getChainHead().getHeight() != block.heightAfterBlock) {
                log.error(
                        "ERROR: New block head didn't match the correct height after block " + block.ruleName);
                rulesSinceFirstFail++;
            }

            // Shouldnt double-request
            boolean shouldntRequest = blocksRequested.contains(nextBlock.getHash());
            if (shouldntRequest)
                blocksRequested.remove(nextBlock.getHash());
            InventoryMessage message = new InventoryMessage(params);
            message.addBlock(nextBlock);
            bitcoind.sendMessage(message);
            log.info("Sent inv with block " + nextBlock.getHashAsString());
            if (blocksPendingSend.contains(nextBlock.getHash())) {
                bitcoind.sendMessage(nextBlock);
                log.info("Sent full block " + nextBlock.getHashAsString());
            }
            // bitcoind doesn't request blocks inline so we can't rely on a ping for synchronization
            for (int i = 0; !shouldntRequest && !blocksRequested.contains(nextBlock.getHash()); i++) {
                int SLEEP_TIME = 1;
                if (i % 1000 / SLEEP_TIME == 1000 / SLEEP_TIME - 1)
                    log.error("bitcoind still hasn't requested block " + block.ruleName + " with hash "
                            + nextBlock.getHash());
                Thread.sleep(SLEEP_TIME);
                if (i > 60000 / SLEEP_TIME) {
                    log.error("bitcoind failed to request block " + block.ruleName);
                    System.exit(1);
                }
            }
            if (shouldntRequest) {
                Thread.sleep(100);
                if (blocksRequested.contains(nextBlock.getHash())) {
                    log.error("ERROR: bitcoind re-requested block " + block.ruleName + " with hash "
                            + nextBlock.getHash());
                    rulesSinceFirstFail++;
                }
            }
            // If the block throws, we may want to get bitcoind to request the same block again
            if (block.throwsException)
                blocksRequested.remove(nextBlock.getHash());
            //bitcoind.sendMessage(nextBlock);
            locator.clear();
            locator.add(bitcoindChainHead);
            bitcoind.sendMessage(new GetHeadersMessage(params, locator, hashTo));
            bitcoind.ping().get();
            if (!chain.getChainHead().getHeader().getHash().equals(bitcoindChainHead)) {
                rulesSinceFirstFail++;
                log.error(
                        "ERROR: bitcoind and litecoinj acceptance differs on block \"" + block.ruleName + "\"");
            }
            if (block.sendOnce)
                preloadedBlocks.remove(nextBlock.getHash());
            log.info("Block \"" + block.ruleName + "\" completed processing");
        } else if (rule instanceof MemoryPoolState) {
            MemoryPoolMessage message = new MemoryPoolMessage();
            bitcoind.sendMessage(message);
            bitcoind.ping().get();
            if (mostRecentInv == null && !((MemoryPoolState) rule).mempool.isEmpty()) {
                log.error("ERROR: bitcoind had an empty mempool, but we expected some transactions on rule "
                        + rule.ruleName);
                rulesSinceFirstFail++;
            } else if (mostRecentInv != null && ((MemoryPoolState) rule).mempool.isEmpty()) {
                log.error("ERROR: bitcoind had a non-empty mempool, but we expected an empty one on rule "
                        + rule.ruleName);
                rulesSinceFirstFail++;
            } else if (mostRecentInv != null) {
                Set<InventoryItem> originalRuleSet = new HashSet<>(((MemoryPoolState) rule).mempool);
                boolean matches = mostRecentInv.items.size() == ((MemoryPoolState) rule).mempool.size();
                for (InventoryItem item : mostRecentInv.items)
                    if (!((MemoryPoolState) rule).mempool.remove(item))
                        matches = false;
                if (matches)
                    continue;
                log.error("bitcoind's mempool didn't match what we were expecting on rule " + rule.ruleName);
                log.info("  bitcoind's mempool was: ");
                for (InventoryItem item : mostRecentInv.items)
                    log.info("    " + item.hash);
                log.info("  The expected mempool was: ");
                for (InventoryItem item : originalRuleSet)
                    log.info("    " + item.hash);
                rulesSinceFirstFail++;
            }
            mostRecentInv = null;
        } else if (rule instanceof UTXORule) {
            if (bitcoind.getPeerVersionMessage().isGetUTXOsSupported()) {
                UTXORule r = (UTXORule) rule;
                UTXOsMessage result = bitcoind.getUTXOs(r.query).get();
                if (!result.equals(r.result)) {
                    log.error("utxo result was not what we expected.");
                    log.error("Wanted  {}", r.result);
                    log.error("but got {}", result);
                    rulesSinceFirstFail++;
                } else {
                    log.info("Successful utxo query {}: {}", r.ruleName, result);
                }
            }
        } else {
            throw new RuntimeException("Unknown rule");
        }
        if (rulesSinceFirstFail > 0)
            rulesSinceFirstFail++;
        if (rulesSinceFirstFail > 6)
            System.exit(1);
    }

    if (unexpectedInvs.get() > 0)
        log.error("ERROR: Got " + unexpectedInvs.get() + " unexpected invs from bitcoind");
    log.info("Done testing.");
    System.exit(rulesSinceFirstFail > 0 || unexpectedInvs.get() > 0 ? 1 : 0);
}

From source file:org.bitcoinj_extra.core.BitcoindComparisonTool.java

public static void main(String[] args) throws Exception {
    BriefLogFormatter.init();//from w w w .  j  a  va  2  s  . c o  m
    System.out.println("USAGE: bitcoinjBlockStoreLocation runExpensiveTests(1/0) [port=18444]");
    boolean runExpensiveTests = args.length > 1 && Integer.parseInt(args[1]) == 1;

    params = RegTestParams.get();
    Context ctx = new Context(params);

    File blockFile = File.createTempFile("testBlocks", ".dat");
    blockFile.deleteOnExit();

    FullBlockTestGenerator generator = new FullBlockTestGenerator(params);
    final RuleList blockList = generator.getBlocksToTest(false, runExpensiveTests, blockFile);
    final Map<Sha256Hash, Block> preloadedBlocks = new HashMap<Sha256Hash, Block>();
    final Iterator<Block> blocks = new BlockFileLoader(params, Arrays.asList(blockFile));

    try {
        H2FullPrunedBlockStore store = new H2FullPrunedBlockStore(params,
                args.length > 0 ? args[0] : "BitcoindComparisonTool", blockList.maximumReorgBlockCount);
        store.resetStore();
        //store = new MemoryFullPrunedBlockStore(params, blockList.maximumReorgBlockCount);
        chain = new FullPrunedBlockChain(params, store);
    } catch (BlockStoreException e) {
        e.printStackTrace();
        System.exit(1);
    }

    VersionMessage ver = new VersionMessage(params, 42);
    ver.appendToSubVer("BlockAcceptanceComparisonTool", "1.1", null);
    ver.localServices = VersionMessage.NODE_NETWORK;
    final Peer bitcoind = new Peer(params, ver, new BlockChain(params, new MemoryBlockStore(params)),
            new PeerAddress(params, InetAddress.getLocalHost()));
    Preconditions.checkState(bitcoind.getVersionMessage().hasBlockChain());

    final BlockWrapper currentBlock = new BlockWrapper();

    final Set<Sha256Hash> blocksRequested = Collections.synchronizedSet(new HashSet<Sha256Hash>());
    final Set<Sha256Hash> blocksPendingSend = Collections.synchronizedSet(new HashSet<Sha256Hash>());
    final AtomicInteger unexpectedInvs = new AtomicInteger(0);
    final SettableFuture<Void> connectedFuture = SettableFuture.create();
    bitcoind.addConnectedEventListener(Threading.SAME_THREAD, new PeerConnectedEventListener() {
        @Override
        public void onPeerConnected(Peer peer, int peerCount) {
            if (!peer.getPeerVersionMessage().subVer.contains("Satoshi")) {
                System.out.println();
                System.out.println(
                        "************************************************************************************************************************\n"
                                + "WARNING: You appear to be using this to test an alternative implementation with full validation rules. You should go\n"
                                + "think hard about what you're doing. Seriously, no one has gotten even close to correctly reimplementing Bitcoin\n"
                                + "consensus rules, despite serious investment in trying. It is a huge task and the slightest difference is a huge bug.\n"
                                + "Instead, go work on making Bitcoin Core consensus rules a shared library and use that. Seriously, you wont get it right,\n"
                                + "and starting with this tester as a way to try to do so will simply end in pain and lost coins.\n"
                                + "************************************************************************************************************************");
                System.out.println();
            }
            log.info("bitcoind connected");
            // Make sure bitcoind has no blocks
            bitcoind.setDownloadParameters(0, false);
            bitcoind.startBlockChainDownload();
            connectedFuture.set(null);
        }
    });

    bitcoind.addDisconnectedEventListener(Threading.SAME_THREAD, new PeerDisconnectedEventListener() {
        @Override
        public void onPeerDisconnected(Peer peer, int peerCount) {
            log.error("bitcoind node disconnected!");
            System.exit(1);
        }
    });

    bitcoind.addPreMessageReceivedEventListener(Threading.SAME_THREAD, new PreMessageReceivedEventListener() {
        @Override
        public Message onPreMessageReceived(Peer peer, Message m) {
            if (m instanceof HeadersMessage) {
                if (!((HeadersMessage) m).getBlockHeaders().isEmpty()) {
                    Block b = Iterables.getLast(((HeadersMessage) m).getBlockHeaders());
                    log.info("Got header from bitcoind " + b.getHashAsString());
                    bitcoindChainHead = b.getHash();
                } else
                    log.info("Got empty header message from bitcoind");
                return null;
            } else if (m instanceof Block) {
                log.error("bitcoind sent us a block it already had, make sure bitcoind has no blocks!");
                System.exit(1);
            } else if (m instanceof GetDataMessage) {
                for (InventoryItem item : ((GetDataMessage) m).items)
                    if (item.type == InventoryItem.Type.Block) {
                        log.info("Requested " + item.hash);
                        if (currentBlock.block.getHash().equals(item.hash))
                            bitcoind.sendMessage(currentBlock.block);
                        else {
                            Block nextBlock = preloadedBlocks.get(item.hash);
                            if (nextBlock != null)
                                bitcoind.sendMessage(nextBlock);
                            else {
                                blocksPendingSend.add(item.hash);
                                log.info("...which we will not provide yet");
                            }
                        }
                        blocksRequested.add(item.hash);
                    }
                return null;
            } else if (m instanceof GetHeadersMessage) {
                try {
                    if (currentBlock.block == null) {
                        log.info("Got a request for a header before we had even begun processing blocks!");
                        return null;
                    }
                    LinkedList<Block> headers = new LinkedList<Block>();
                    Block it = blockList.hashHeaderMap.get(currentBlock.block.getHash());
                    while (it != null) {
                        headers.addFirst(it);
                        it = blockList.hashHeaderMap.get(it.getPrevBlockHash());
                    }
                    LinkedList<Block> sendHeaders = new LinkedList<Block>();
                    boolean found = false;
                    for (Sha256Hash hash : ((GetHeadersMessage) m).getLocator()) {
                        for (Block b : headers) {
                            if (found) {
                                sendHeaders.addLast(b);
                                log.info("Sending header (" + b.getPrevBlockHash() + ") -> " + b.getHash());
                                if (b.getHash().equals(((GetHeadersMessage) m).getStopHash()))
                                    break;
                            } else if (b.getHash().equals(hash)) {
                                log.info("Found header " + b.getHashAsString());
                                found = true;
                            }
                        }
                        if (found)
                            break;
                    }
                    if (!found)
                        sendHeaders = headers;
                    bitcoind.sendMessage(new HeadersMessage(params, sendHeaders));
                    InventoryMessage i = new InventoryMessage(params);
                    for (Block b : sendHeaders)
                        i.addBlock(b);
                    bitcoind.sendMessage(i);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                return null;
            } else if (m instanceof InventoryMessage) {
                if (mostRecentInv != null) {
                    log.error("Got an inv when we weren't expecting one");
                    unexpectedInvs.incrementAndGet();
                }
                mostRecentInv = (InventoryMessage) m;
            }
            return m;
        }
    });

    bitcoindChainHead = params.getGenesisBlock().getHash();

    // bitcoind MUST be on localhost or we will get banned as a DoSer
    new NioClient(new InetSocketAddress(InetAddress.getByName("127.0.0.1"),
            args.length > 2 ? Integer.parseInt(args[2]) : params.getPort()), bitcoind, 1000);

    connectedFuture.get();

    ArrayList<Sha256Hash> locator = new ArrayList<Sha256Hash>(1);
    locator.add(params.getGenesisBlock().getHash());
    Sha256Hash hashTo = Sha256Hash.wrap("0000000000000000000000000000000000000000000000000000000000000000");

    int rulesSinceFirstFail = 0;
    for (Rule rule : blockList.list) {
        if (rule instanceof FullBlockTestGenerator.BlockAndValidity) {
            FullBlockTestGenerator.BlockAndValidity block = (FullBlockTestGenerator.BlockAndValidity) rule;
            boolean threw = false;
            Block nextBlock = preloadedBlocks.get(((FullBlockTestGenerator.BlockAndValidity) rule).blockHash);
            // Often load at least one block because sometimes we have duplicates with the same hash (b56/57)
            for (int i = 0; i < 1 || nextBlock == null || !nextBlock.getHash().equals(block.blockHash); i++) {
                try {
                    Block b = blocks.next();
                    Block oldBlockWithSameHash = preloadedBlocks.put(b.getHash(), b);
                    if (oldBlockWithSameHash != null
                            && oldBlockWithSameHash.getTransactions().size() != b.getTransactions().size())
                        blocksRequested.remove(b.getHash());
                    nextBlock = preloadedBlocks.get(block.blockHash);
                } catch (NoSuchElementException e) {
                    if (nextBlock == null || !nextBlock.getHash().equals(block.blockHash))
                        throw e;
                }
            }
            currentBlock.block = nextBlock;
            log.info("Testing block {} {}", block.ruleName, currentBlock.block.getHash());
            try {
                if (chain.add(nextBlock) != block.connects) {
                    log.error("ERROR: Block didn't match connects flag on block \"" + block.ruleName + "\"");
                    rulesSinceFirstFail++;
                }
            } catch (VerificationException e) {
                threw = true;
                if (!block.throwsException) {
                    log.error("ERROR: Block didn't match throws flag on block \"" + block.ruleName + "\"");
                    e.printStackTrace();
                    rulesSinceFirstFail++;
                } else if (block.connects) {
                    log.error("ERROR: Block didn't match connects flag on block \"" + block.ruleName + "\"");
                    e.printStackTrace();
                    rulesSinceFirstFail++;
                }
            }
            if (!threw && block.throwsException) {
                log.error("ERROR: Block didn't match throws flag on block \"" + block.ruleName + "\"");
                rulesSinceFirstFail++;
            } else if (!chain.getChainHead().getHeader().getHash().equals(block.hashChainTipAfterBlock)) {
                log.error("ERROR: New block head didn't match the correct value after block \"" + block.ruleName
                        + "\"");
                rulesSinceFirstFail++;
            } else if (chain.getChainHead().getHeight() != block.heightAfterBlock) {
                log.error(
                        "ERROR: New block head didn't match the correct height after block " + block.ruleName);
                rulesSinceFirstFail++;
            }

            // Shouldnt double-request
            boolean shouldntRequest = blocksRequested.contains(nextBlock.getHash());
            if (shouldntRequest)
                blocksRequested.remove(nextBlock.getHash());
            InventoryMessage message = new InventoryMessage(params);
            message.addBlock(nextBlock);
            bitcoind.sendMessage(message);
            log.info("Sent inv with block " + nextBlock.getHashAsString());
            if (blocksPendingSend.contains(nextBlock.getHash())) {
                bitcoind.sendMessage(nextBlock);
                log.info("Sent full block " + nextBlock.getHashAsString());
            }
            // bitcoind doesn't request blocks inline so we can't rely on a ping for synchronization
            for (int i = 0; !shouldntRequest && !blocksRequested.contains(nextBlock.getHash()); i++) {
                int SLEEP_TIME = 1;
                if (i % 1000 / SLEEP_TIME == 1000 / SLEEP_TIME - 1)
                    log.error("bitcoind still hasn't requested block " + block.ruleName + " with hash "
                            + nextBlock.getHash());
                Thread.sleep(SLEEP_TIME);
                if (i > 60000 / SLEEP_TIME) {
                    log.error("bitcoind failed to request block " + block.ruleName);
                    System.exit(1);
                }
            }
            if (shouldntRequest) {
                Thread.sleep(100);
                if (blocksRequested.contains(nextBlock.getHash())) {
                    log.error("ERROR: bitcoind re-requested block " + block.ruleName + " with hash "
                            + nextBlock.getHash());
                    rulesSinceFirstFail++;
                }
            }
            // If the block throws, we may want to get bitcoind to request the same block again
            if (block.throwsException)
                blocksRequested.remove(nextBlock.getHash());
            //bitcoind.sendMessage(nextBlock);
            locator.clear();
            locator.add(bitcoindChainHead);
            bitcoind.sendMessage(new GetHeadersMessage(params, locator, hashTo));
            bitcoind.ping().get();
            if (!chain.getChainHead().getHeader().getHash().equals(bitcoindChainHead)) {
                rulesSinceFirstFail++;
                log.error("ERROR: bitcoind and bitcoinj_extra acceptance differs on block \"" + block.ruleName
                        + "\"");
            }
            if (block.sendOnce)
                preloadedBlocks.remove(nextBlock.getHash());
            log.info("Block \"" + block.ruleName + "\" completed processing");
        } else if (rule instanceof MemoryPoolState) {
            MemoryPoolMessage message = new MemoryPoolMessage();
            bitcoind.sendMessage(message);
            bitcoind.ping().get();
            if (mostRecentInv == null && !((MemoryPoolState) rule).mempool.isEmpty()) {
                log.error("ERROR: bitcoind had an empty mempool, but we expected some transactions on rule "
                        + rule.ruleName);
                rulesSinceFirstFail++;
            } else if (mostRecentInv != null && ((MemoryPoolState) rule).mempool.isEmpty()) {
                log.error("ERROR: bitcoind had a non-empty mempool, but we expected an empty one on rule "
                        + rule.ruleName);
                rulesSinceFirstFail++;
            } else if (mostRecentInv != null) {
                Set<InventoryItem> originalRuleSet = new HashSet<InventoryItem>(
                        ((MemoryPoolState) rule).mempool);
                boolean matches = mostRecentInv.items.size() == ((MemoryPoolState) rule).mempool.size();
                for (InventoryItem item : mostRecentInv.items)
                    if (!((MemoryPoolState) rule).mempool.remove(item))
                        matches = false;
                if (matches)
                    continue;
                log.error("bitcoind's mempool didn't match what we were expecting on rule " + rule.ruleName);
                log.info("  bitcoind's mempool was: ");
                for (InventoryItem item : mostRecentInv.items)
                    log.info("    " + item.hash);
                log.info("  The expected mempool was: ");
                for (InventoryItem item : originalRuleSet)
                    log.info("    " + item.hash);
                rulesSinceFirstFail++;
            }
            mostRecentInv = null;
        } else if (rule instanceof UTXORule) {
            if (bitcoind.getPeerVersionMessage().isGetUTXOsSupported()) {
                UTXORule r = (UTXORule) rule;
                UTXOsMessage result = bitcoind.getUTXOs(r.query).get();
                if (!result.equals(r.result)) {
                    log.error("utxo result was not what we expected.");
                    log.error("Wanted  {}", r.result);
                    log.error("but got {}", result);
                    rulesSinceFirstFail++;
                } else {
                    log.info("Successful utxo query {}: {}", r.ruleName, result);
                }
            }
        } else {
            throw new RuntimeException("Unknown rule");
        }
        if (rulesSinceFirstFail > 0)
            rulesSinceFirstFail++;
        if (rulesSinceFirstFail > 6)
            System.exit(1);
    }

    if (unexpectedInvs.get() > 0)
        log.error("ERROR: Got " + unexpectedInvs.get() + " unexpected invs from bitcoind");
    log.info("Done testing.");
    System.exit(rulesSinceFirstFail > 0 || unexpectedInvs.get() > 0 ? 1 : 0);
}

From source file:org.neoscoinj.core.NeoscoindComparisonTool.java

public static void main(String[] args) throws Exception {
    BriefLogFormatter.init();// w ww.ja v a  2 s.c om
    System.out.println("USAGE: neoscoinjBlockStoreLocation runExpensiveTests(1/0) [port=18444]");
    boolean runExpensiveTests = args.length > 1 && Integer.parseInt(args[1]) == 1;

    params = RegTestParams.get();

    File blockFile = File.createTempFile("testBlocks", ".dat");
    blockFile.deleteOnExit();

    FullBlockTestGenerator generator = new FullBlockTestGenerator(params);
    final RuleList blockList = generator.getBlocksToTest(false, runExpensiveTests, blockFile);
    final Map<Sha256Hash, Block> preloadedBlocks = new HashMap<Sha256Hash, Block>();
    final Iterator<Block> blocks = new BlockFileLoader(params, Arrays.asList(blockFile));

    try {
        store = new H2FullPrunedBlockStore(params, args.length > 0 ? args[0] : "NeoscoindComparisonTool",
                blockList.maximumReorgBlockCount);
        ((H2FullPrunedBlockStore) store).resetStore();
        //store = new MemoryFullPrunedBlockStore(params, blockList.maximumReorgBlockCount);
        chain = new FullPrunedBlockChain(params, store);
    } catch (BlockStoreException e) {
        e.printStackTrace();
        System.exit(1);
    }

    VersionMessage ver = new VersionMessage(params, 42);
    ver.appendToSubVer("BlockAcceptanceComparisonTool", "1.1", null);
    ver.localServices = VersionMessage.NODE_NETWORK;
    final Peer neoscoind = new Peer(params, ver, new BlockChain(params, new MemoryBlockStore(params)),
            new PeerAddress(InetAddress.getLocalHost()));
    Preconditions.checkState(neoscoind.getVersionMessage().hasBlockChain());

    final BlockWrapper currentBlock = new BlockWrapper();

    final Set<Sha256Hash> blocksRequested = Collections.synchronizedSet(new HashSet<Sha256Hash>());
    final Set<Sha256Hash> blocksPendingSend = Collections.synchronizedSet(new HashSet<Sha256Hash>());
    final AtomicInteger unexpectedInvs = new AtomicInteger(0);
    final SettableFuture<Void> connectedFuture = SettableFuture.create();
    neoscoind.addEventListener(new AbstractPeerEventListener() {
        @Override
        public void onPeerConnected(Peer peer, int peerCount) {
            if (!peer.getPeerVersionMessage().subVer.contains("Satoshi")) {
                System.out.println();
                System.out.println(
                        "************************************************************************************************************************\n"
                                + "WARNING: You appear to be using this to test an alternative implementation with full validation rules. You should go\n"
                                + "think hard about what you're doing. Seriously, no one has gotten even close to correctly reimplementing Neoscoin\n"
                                + "consensus rules, despite serious investment in trying. It is a huge task and the slightest difference is a huge bug.\n"
                                + "Instead, go work on making Neoscoin Core consensus rules a shared library and use that. Seriously, you wont get it right,\n"
                                + "and starting with this tester as a way to try to do so will simply end in pain and lost coins.\n"
                                + "************************************************************************************************************************");
                System.out.println();
                System.out.println("Giving you 30 seconds to think about the above warning...");
                Uninterruptibles.sleepUninterruptibly(30, TimeUnit.SECONDS);
            }
            log.info("neoscoind connected");
            // Make sure neoscoind has no blocks
            neoscoind.setDownloadParameters(0, false);
            neoscoind.startBlockChainDownload();
            connectedFuture.set(null);
        }

        @Override
        public void onPeerDisconnected(Peer peer, int peerCount) {
            log.error("neoscoind node disconnected!");
            System.exit(1);
        }

        @Override
        public Message onPreMessageReceived(Peer peer, Message m) {
            if (m instanceof HeadersMessage) {
                if (!((HeadersMessage) m).getBlockHeaders().isEmpty()) {
                    Block b = Iterables.getLast(((HeadersMessage) m).getBlockHeaders());
                    log.info("Got header from neoscoind " + b.getHashAsString());
                    neoscoindChainHead = b.getHash();
                } else
                    log.info("Got empty header message from neoscoind");
                return null;
            } else if (m instanceof Block) {
                log.error("neoscoind sent us a block it already had, make sure neoscoind has no blocks!");
                System.exit(1);
            } else if (m instanceof GetDataMessage) {
                for (InventoryItem item : ((GetDataMessage) m).items)
                    if (item.type == InventoryItem.Type.Block) {
                        log.info("Requested " + item.hash);
                        if (currentBlock.block.getHash().equals(item.hash))
                            neoscoind.sendMessage(currentBlock.block);
                        else {
                            Block nextBlock = preloadedBlocks.get(item.hash);
                            if (nextBlock != null)
                                neoscoind.sendMessage(nextBlock);
                            else {
                                blocksPendingSend.add(item.hash);
                                log.info("...which we will not provide yet");
                            }
                        }
                        blocksRequested.add(item.hash);
                    }
                return null;
            } else if (m instanceof GetHeadersMessage) {
                try {
                    if (currentBlock.block == null) {
                        log.info("Got a request for a header before we had even begun processing blocks!");
                        return null;
                    }
                    LinkedList<Block> headers = new LinkedList<Block>();
                    Block it = blockList.hashHeaderMap.get(currentBlock.block.getHash());
                    while (it != null) {
                        headers.addFirst(it);
                        it = blockList.hashHeaderMap.get(it.getPrevBlockHash());
                    }
                    LinkedList<Block> sendHeaders = new LinkedList<Block>();
                    boolean found = false;
                    for (Sha256Hash hash : ((GetHeadersMessage) m).getLocator()) {
                        for (Block b : headers) {
                            if (found) {
                                sendHeaders.addLast(b);
                                log.info("Sending header (" + b.getPrevBlockHash() + ") -> " + b.getHash());
                                if (b.getHash().equals(((GetHeadersMessage) m).getStopHash()))
                                    break;
                            } else if (b.getHash().equals(hash)) {
                                log.info("Found header " + b.getHashAsString());
                                found = true;
                            }
                        }
                        if (found)
                            break;
                    }
                    if (!found)
                        sendHeaders = headers;
                    neoscoind.sendMessage(new HeadersMessage(params, sendHeaders));
                    InventoryMessage i = new InventoryMessage(params);
                    for (Block b : sendHeaders)
                        i.addBlock(b);
                    neoscoind.sendMessage(i);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                return null;
            } else if (m instanceof InventoryMessage) {
                if (mostRecentInv != null) {
                    log.error("Got an inv when we weren't expecting one");
                    unexpectedInvs.incrementAndGet();
                }
                mostRecentInv = (InventoryMessage) m;
            }
            return m;
        }
    }, Threading.SAME_THREAD);

    neoscoindChainHead = params.getGenesisBlock().getHash();

    // neoscoind MUST be on localhost or we will get banned as a DoSer
    new NioClient(new InetSocketAddress(InetAddress.getByName("127.0.0.1"),
            args.length > 2 ? Integer.parseInt(args[2]) : params.getPort()), neoscoind, 1000);

    connectedFuture.get();

    ArrayList<Sha256Hash> locator = new ArrayList<Sha256Hash>(1);
    locator.add(params.getGenesisBlock().getHash());
    Sha256Hash hashTo = new Sha256Hash("0000000000000000000000000000000000000000000000000000000000000000");

    int rulesSinceFirstFail = 0;
    for (Rule rule : blockList.list) {
        if (rule instanceof FullBlockTestGenerator.BlockAndValidity) {
            FullBlockTestGenerator.BlockAndValidity block = (FullBlockTestGenerator.BlockAndValidity) rule;
            boolean threw = false;
            Block nextBlock = preloadedBlocks.get(((FullBlockTestGenerator.BlockAndValidity) rule).blockHash);
            // Often load at least one block because sometimes we have duplicates with the same hash (b56/57)
            for (int i = 0; i < 1 || nextBlock == null || !nextBlock.getHash().equals(block.blockHash); i++) {
                try {
                    Block b = blocks.next();
                    Block oldBlockWithSameHash = preloadedBlocks.put(b.getHash(), b);
                    if (oldBlockWithSameHash != null
                            && oldBlockWithSameHash.getTransactions().size() != b.getTransactions().size())
                        blocksRequested.remove(b.getHash());
                    nextBlock = preloadedBlocks.get(block.blockHash);
                } catch (NoSuchElementException e) {
                    if (nextBlock == null || !nextBlock.getHash().equals(block.blockHash))
                        throw e;
                }
            }
            currentBlock.block = nextBlock;
            log.info("Testing block {} {}", block.ruleName, currentBlock.block.getHash());
            try {
                if (chain.add(nextBlock) != block.connects) {
                    log.error("ERROR: Block didn't match connects flag on block \"" + block.ruleName + "\"");
                    rulesSinceFirstFail++;
                }
            } catch (VerificationException e) {
                threw = true;
                if (!block.throwsException) {
                    log.error("ERROR: Block didn't match throws flag on block \"" + block.ruleName + "\"");
                    e.printStackTrace();
                    rulesSinceFirstFail++;
                } else if (block.connects) {
                    log.error("ERROR: Block didn't match connects flag on block \"" + block.ruleName + "\"");
                    e.printStackTrace();
                    rulesSinceFirstFail++;
                }
            }
            if (!threw && block.throwsException) {
                log.error("ERROR: Block didn't match throws flag on block \"" + block.ruleName + "\"");
                rulesSinceFirstFail++;
            } else if (!chain.getChainHead().getHeader().getHash().equals(block.hashChainTipAfterBlock)) {
                log.error("ERROR: New block head didn't match the correct value after block \"" + block.ruleName
                        + "\"");
                rulesSinceFirstFail++;
            } else if (chain.getChainHead().getHeight() != block.heightAfterBlock) {
                log.error(
                        "ERROR: New block head didn't match the correct height after block " + block.ruleName);
                rulesSinceFirstFail++;
            }

            // Shouldnt double-request
            boolean shouldntRequest = blocksRequested.contains(nextBlock.getHash());
            if (shouldntRequest)
                blocksRequested.remove(nextBlock.getHash());
            InventoryMessage message = new InventoryMessage(params);
            message.addBlock(nextBlock);
            neoscoind.sendMessage(message);
            log.info("Sent inv with block " + nextBlock.getHashAsString());
            if (blocksPendingSend.contains(nextBlock.getHash())) {
                neoscoind.sendMessage(nextBlock);
                log.info("Sent full block " + nextBlock.getHashAsString());
            }
            // neoscoind doesn't request blocks inline so we can't rely on a ping for synchronization
            for (int i = 0; !shouldntRequest && !blocksRequested.contains(nextBlock.getHash()); i++) {
                int SLEEP_TIME = 1;
                if (i % 1000 / SLEEP_TIME == 1000 / SLEEP_TIME - 1)
                    log.error("neoscoind still hasn't requested block " + block.ruleName + " with hash "
                            + nextBlock.getHash());
                Thread.sleep(SLEEP_TIME);
                if (i > 60000 / SLEEP_TIME) {
                    log.error("neoscoind failed to request block " + block.ruleName);
                    System.exit(1);
                }
            }
            if (shouldntRequest) {
                Thread.sleep(100);
                if (blocksRequested.contains(nextBlock.getHash())) {
                    log.error("ERROR: neoscoind re-requested block " + block.ruleName + " with hash "
                            + nextBlock.getHash());
                    rulesSinceFirstFail++;
                }
            }
            // If the block throws, we may want to get neoscoind to request the same block again
            if (block.throwsException)
                blocksRequested.remove(nextBlock.getHash());
            //neoscoind.sendMessage(nextBlock);
            locator.clear();
            locator.add(neoscoindChainHead);
            neoscoind.sendMessage(new GetHeadersMessage(params, locator, hashTo));
            neoscoind.ping().get();
            if (!chain.getChainHead().getHeader().getHash().equals(neoscoindChainHead)) {
                rulesSinceFirstFail++;
                log.error("ERROR: neoscoind and neoscoinj acceptance differs on block \"" + block.ruleName
                        + "\"");
            }
            if (block.sendOnce)
                preloadedBlocks.remove(nextBlock.getHash());
            log.info("Block \"" + block.ruleName + "\" completed processing");
        } else if (rule instanceof MemoryPoolState) {
            MemoryPoolMessage message = new MemoryPoolMessage();
            neoscoind.sendMessage(message);
            neoscoind.ping().get();
            if (mostRecentInv == null && !((MemoryPoolState) rule).mempool.isEmpty()) {
                log.error("ERROR: neoscoind had an empty mempool, but we expected some transactions on rule "
                        + rule.ruleName);
                rulesSinceFirstFail++;
            } else if (mostRecentInv != null && ((MemoryPoolState) rule).mempool.isEmpty()) {
                log.error("ERROR: neoscoind had a non-empty mempool, but we expected an empty one on rule "
                        + rule.ruleName);
                rulesSinceFirstFail++;
            } else if (mostRecentInv != null) {
                Set<InventoryItem> originalRuleSet = new HashSet<InventoryItem>(
                        ((MemoryPoolState) rule).mempool);
                boolean matches = mostRecentInv.items.size() == ((MemoryPoolState) rule).mempool.size();
                for (InventoryItem item : mostRecentInv.items)
                    if (!((MemoryPoolState) rule).mempool.remove(item))
                        matches = false;
                if (matches)
                    continue;
                log.error("neoscoind's mempool didn't match what we were expecting on rule " + rule.ruleName);
                log.info("  neoscoind's mempool was: ");
                for (InventoryItem item : mostRecentInv.items)
                    log.info("    " + item.hash);
                log.info("  The expected mempool was: ");
                for (InventoryItem item : originalRuleSet)
                    log.info("    " + item.hash);
                rulesSinceFirstFail++;
            }
            mostRecentInv = null;
        } else if (rule instanceof UTXORule) {
            if (neoscoind.getPeerVersionMessage().isGetUTXOsSupported()) {
                UTXORule r = (UTXORule) rule;
                UTXOsMessage result = neoscoind.getUTXOs(r.query).get();
                if (!result.equals(r.result)) {
                    log.error("utxo result was not what we expected.");
                    log.error("Wanted  {}", r.result);
                    log.error("but got {}", result);
                    rulesSinceFirstFail++;
                } else {
                    log.info("Successful utxo query {}: {}", r.ruleName, result);
                }
            }
        } else {
            throw new RuntimeException("Unknown rule");
        }
        if (rulesSinceFirstFail > 0)
            rulesSinceFirstFail++;
        if (rulesSinceFirstFail > 6)
            System.exit(1);
    }

    if (unexpectedInvs.get() > 0)
        log.error("ERROR: Got " + unexpectedInvs.get() + " unexpected invs from neoscoind");
    log.info("Done testing.");
    System.exit(rulesSinceFirstFail > 0 || unexpectedInvs.get() > 0 ? 1 : 0);
}