예제 #1
0
  // Check that it starts downloading the block chain correctly on request.
  @Test
  public void startBlockChainDownload() throws Exception {
    Block b1 = createFakeBlock(blockStore).block;
    blockChain.add(b1);
    Block b2 = makeSolvedTestBlock(b1);
    blockChain.add(b2);

    connect();
    fail.set(true);
    peer.addEventListener(
        new AbstractPeerEventListener() {
          @Override
          public void onChainDownloadStarted(Peer p, int blocksLeft) {
            if (p == peer && blocksLeft == 108) fail.set(false);
          }
        },
        Threading.SAME_THREAD);
    peer.startBlockChainDownload();

    List<Sha256Hash> expectedLocator = new ArrayList<Sha256Hash>();
    expectedLocator.add(b2.getHash());
    expectedLocator.add(b1.getHash());
    expectedLocator.add(unitTestParams.getGenesisBlock().getHash());

    GetBlocksMessage message = (GetBlocksMessage) outbound(writeTarget);
    assertEquals(message.getLocator(), expectedLocator);
    assertEquals(Sha256Hash.ZERO_HASH, message.getStopHash());
  }
예제 #2
0
  // Check that inventory message containing blocks we want is processed correctly.
  @Test
  public void newBlock() throws Exception {
    Block b1 = createFakeBlock(blockStore).block;
    blockChain.add(b1);
    final Block b2 = makeSolvedTestBlock(b1);
    // Receive notification of a new block.
    final InventoryMessage inv = new InventoryMessage(unitTestParams);
    InventoryItem item = new InventoryItem(InventoryItem.Type.Block, b2.getHash());
    inv.addItem(item);

    final AtomicInteger newBlockMessagesReceived = new AtomicInteger(0);

    connect();
    // Round-trip a ping so that we never see the response verack if we attach too quick
    pingAndWait(writeTarget);
    peer.addEventListener(
        new AbstractPeerEventListener() {
          @Override
          public synchronized Message onPreMessageReceived(Peer p, Message m) {
            if (p != peer) fail.set(true);
            if (m instanceof Pong) return m;
            int newValue = newBlockMessagesReceived.incrementAndGet();
            if (newValue == 1 && !inv.equals(m)) fail.set(true);
            else if (newValue == 2 && !b2.equals(m)) fail.set(true);
            else if (newValue > 3) fail.set(true);
            return m;
          }

          @Override
          public synchronized void onBlocksDownloaded(Peer p, Block block, int blocksLeft) {
            int newValue = newBlockMessagesReceived.incrementAndGet();
            if (newValue != 3
                || p != peer
                || !block.equals(b2)
                || blocksLeft != OTHER_PEER_CHAIN_HEIGHT - 2) fail.set(true);
          }
        },
        Threading.SAME_THREAD);
    long height = peer.getBestHeight();

    inbound(writeTarget, inv);
    pingAndWait(writeTarget);
    assertEquals(height + 1, peer.getBestHeight());
    // Response to the getdata message.
    inbound(writeTarget, b2);

    pingAndWait(writeTarget);
    Threading.waitForUserCode();
    pingAndWait(writeTarget);
    assertEquals(3, newBlockMessagesReceived.get());

    GetDataMessage getdata = (GetDataMessage) outbound(writeTarget);
    List<InventoryItem> items = getdata.getItems();
    assertEquals(1, items.size());
    assertEquals(b2.getHash(), items.get(0).hash);
    assertEquals(InventoryItem.Type.Block, items.get(0).type);
  }
예제 #3
0
  @Test
  public void getBlock() throws Exception {
    connect();

    Block b1 = createFakeBlock(blockStore).block;
    blockChain.add(b1);
    Block b2 = makeSolvedTestBlock(b1);
    Block b3 = makeSolvedTestBlock(b2);

    // Request the block.
    Future<Block> resultFuture = peer.getBlock(b3.getHash());
    assertFalse(resultFuture.isDone());
    // Peer asks for it.
    GetDataMessage message = (GetDataMessage) outbound(writeTarget);
    assertEquals(message.getItems().get(0).hash, b3.getHash());
    assertFalse(resultFuture.isDone());
    // Peer receives it.
    inbound(writeTarget, b3);
    Block b = resultFuture.get();
    assertEquals(b, b3);
  }
예제 #4
0
  // Check that an inv to a peer that is not set to download missing blocks does nothing.
  @Test
  public void invNoDownload() throws Exception {
    // Don't download missing blocks.
    peer.setDownloadData(false);

    connect();

    // Make a missing block that we receive.
    Block b1 = createFakeBlock(blockStore).block;
    blockChain.add(b1);
    Block b2 = makeSolvedTestBlock(b1);

    // Receive an inv.
    InventoryMessage inv = new InventoryMessage(unitTestParams);
    InventoryItem item = new InventoryItem(InventoryItem.Type.Block, b2.getHash());
    inv.addItem(item);
    inbound(writeTarget, inv);

    // Peer does nothing with it.
    assertNull(outbound(writeTarget));
  }
예제 #5
0
  @Test
  public void getLargeBlock() throws Exception {
    connect();

    Block b1 = createFakeBlock(blockStore).block;
    blockChain.add(b1);
    Block b2 = makeSolvedTestBlock(b1);
    Transaction t = new Transaction(unitTestParams);
    t.addInput(b1.getTransactions().get(0).getOutput(0));
    t.addOutput(
        new TransactionOutput(
            unitTestParams, t, BigInteger.ZERO, new byte[Block.MAX_BLOCK_SIZE - 1000]));
    b2.addTransaction(t);

    // Request the block.
    Future<Block> resultFuture = peer.getBlock(b2.getHash());
    assertFalse(resultFuture.isDone());
    // Peer asks for it.
    GetDataMessage message = (GetDataMessage) outbound(writeTarget);
    assertEquals(message.getItems().get(0).hash, b2.getHash());
    assertFalse(resultFuture.isDone());
    // Peer receives it.
    inbound(writeTarget, b2);
    Block b = resultFuture.get();
    assertEquals(b, b2);
  }
예제 #6
0
  // Check that an inventory tickle is processed correctly when downloading missing blocks is
  // active.
  @Test
  public void invTickle() throws Exception {
    connect();

    Block b1 = createFakeBlock(blockStore).block;
    blockChain.add(b1);
    // Make a missing block.
    Block b2 = makeSolvedTestBlock(b1);
    Block b3 = makeSolvedTestBlock(b2);
    inbound(writeTarget, b3);
    InventoryMessage inv = new InventoryMessage(unitTestParams);
    InventoryItem item = new InventoryItem(InventoryItem.Type.Block, b3.getHash());
    inv.addItem(item);
    inbound(writeTarget, inv);

    GetBlocksMessage getblocks = (GetBlocksMessage) outbound(writeTarget);
    List<Sha256Hash> expectedLocator = new ArrayList<Sha256Hash>();
    expectedLocator.add(b1.getHash());
    expectedLocator.add(unitTestParams.getGenesisBlock().getHash());

    assertEquals(getblocks.getLocator(), expectedLocator);
    assertEquals(getblocks.getStopHash(), b3.getHash());
    assertNull(outbound(writeTarget));
  }
예제 #7
0
  @Test
  public void fastCatchup() throws Exception {
    connect();

    // Check that blocks before the fast catchup point are retrieved using getheaders, and after
    // using getblocks.
    // This test is INCOMPLETE because it does not check we handle >2000 blocks correctly.
    Block b1 = createFakeBlock(blockStore).block;
    blockChain.add(b1);
    Utils.rollMockClock(60 * 10); // 10 minutes later.
    Block b2 = makeSolvedTestBlock(b1);
    Utils.rollMockClock(60 * 10); // 10 minutes later.
    Block b3 = makeSolvedTestBlock(b2);
    Utils.rollMockClock(60 * 10);
    Block b4 = makeSolvedTestBlock(b3);

    // Request headers until the last 2 blocks.
    peer.setDownloadParameters((Utils.now().getTime() / 1000) - (600 * 2) + 1, false);
    peer.startBlockChainDownload();
    GetHeadersMessage getheaders = (GetHeadersMessage) outbound(writeTarget);
    List<Sha256Hash> expectedLocator = new ArrayList<Sha256Hash>();
    expectedLocator.add(b1.getHash());
    expectedLocator.add(unitTestParams.getGenesisBlock().getHash());
    assertEquals(getheaders.getLocator(), expectedLocator);
    assertEquals(getheaders.getStopHash(), Sha256Hash.ZERO_HASH);
    // Now send all the headers.
    HeadersMessage headers =
        new HeadersMessage(
            unitTestParams, b2.cloneAsHeader(), b3.cloneAsHeader(), b4.cloneAsHeader());
    // We expect to be asked for b3 and b4 again, but this time, with a body.
    expectedLocator.clear();
    expectedLocator.add(b2.getHash());
    expectedLocator.add(b1.getHash());
    expectedLocator.add(unitTestParams.getGenesisBlock().getHash());
    inbound(writeTarget, headers);
    GetBlocksMessage getblocks = (GetBlocksMessage) outbound(writeTarget);
    assertEquals(expectedLocator, getblocks.getLocator());
    assertEquals(Sha256Hash.ZERO_HASH, getblocks.getStopHash());
    // We're supposed to get an inv here.
    InventoryMessage inv = new InventoryMessage(unitTestParams);
    inv.addItem(new InventoryItem(InventoryItem.Type.Block, b3.getHash()));
    inbound(writeTarget, inv);
    GetDataMessage getdata = (GetDataMessage) outbound(writeTarget);
    assertEquals(b3.getHash(), getdata.getItems().get(0).hash);
    // All done.
    inbound(writeTarget, b3);
    pingAndWait(writeTarget);
    closePeer(peer);
  }
예제 #8
0
  @Test
  public void chainDownloadEnd2End() throws Exception {
    // A full end-to-end test of the chain download process, with a new block being solved in the
    // middle.
    Block b1 = createFakeBlock(blockStore).block;
    blockChain.add(b1);
    Block b2 = makeSolvedTestBlock(b1);
    Block b3 = makeSolvedTestBlock(b2);
    Block b4 = makeSolvedTestBlock(b3);
    Block b5 = makeSolvedTestBlock(b4);

    connect();

    peer.startBlockChainDownload();
    GetBlocksMessage getblocks = (GetBlocksMessage) outbound(writeTarget);
    assertEquals(blockStore.getChainHead().getHeader().getHash(), getblocks.getLocator().get(0));
    assertEquals(Sha256Hash.ZERO_HASH, getblocks.getStopHash());
    // Remote peer sends us an inv with some blocks.
    InventoryMessage inv = new InventoryMessage(unitTestParams);
    inv.addBlock(b2);
    inv.addBlock(b3);
    // We do a getdata on them.
    inbound(writeTarget, inv);
    GetDataMessage getdata = (GetDataMessage) outbound(writeTarget);
    assertEquals(b2.getHash(), getdata.getItems().get(0).hash);
    assertEquals(b3.getHash(), getdata.getItems().get(1).hash);
    assertEquals(2, getdata.getItems().size());
    // Remote peer sends us the blocks. The act of doing a getdata for b3 results in getting an inv
    // with just the
    // best chain head in it.
    inbound(writeTarget, b2);
    inbound(writeTarget, b3);

    inv = new InventoryMessage(unitTestParams);
    inv.addBlock(b5);
    // We request the head block.
    inbound(writeTarget, inv);
    getdata = (GetDataMessage) outbound(writeTarget);
    assertEquals(b5.getHash(), getdata.getItems().get(0).hash);
    assertEquals(1, getdata.getItems().size());
    // Peer sends us the head block. The act of receiving the orphan block triggers a getblocks to
    // fill in the
    // rest of the chain.
    inbound(writeTarget, b5);
    getblocks = (GetBlocksMessage) outbound(writeTarget);
    assertEquals(b5.getHash(), getblocks.getStopHash());
    assertEquals(b3.getHash(), getblocks.getLocator().get(0));
    // At this point another block is solved and broadcast. The inv triggers a getdata but we do NOT
    // send another
    // getblocks afterwards, because that would result in us receiving the same set of blocks twice
    // which is a
    // timewaste. The getblocks message that would have been generated is set to be the same as the
    // previous
    // because we walk backwards down the orphan chain and then discover we already asked for those
    // blocks, so
    // nothing is done.
    Block b6 = makeSolvedTestBlock(b5);
    inv = new InventoryMessage(unitTestParams);
    inv.addBlock(b6);
    inbound(writeTarget, inv);
    getdata = (GetDataMessage) outbound(writeTarget);
    assertEquals(1, getdata.getItems().size());
    assertEquals(b6.getHash(), getdata.getItems().get(0).hash);
    inbound(writeTarget, b6);
    assertNull(outbound(writeTarget)); // Nothing is sent at this point.
    // We're still waiting for the response to the getblocks (b3,b5) sent above.
    inv = new InventoryMessage(unitTestParams);
    inv.addBlock(b4);
    inv.addBlock(b5);
    inbound(writeTarget, inv);
    getdata = (GetDataMessage) outbound(writeTarget);
    assertEquals(1, getdata.getItems().size());
    assertEquals(b4.getHash(), getdata.getItems().get(0).hash);
    // We already have b5 from before, so it's not requested again.
    inbound(writeTarget, b4);
    assertNull(outbound(writeTarget));
    // b5 and b6 are now connected by the block chain and we're done.
    assertNull(outbound(writeTarget));
    closePeer(peer);
  }