Java Code Examples for org.bitcoinj.core.Sha256Hash#of()

The following examples show how to use org.bitcoinj.core.Sha256Hash#of() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: WalletTest.java    From bcm-android with GNU General Public License v3.0 6 votes vote down vote up
@Test
public void autosaveImmediate() throws Exception {
    // Test that the wallet will save itself automatically when it changes.
    File f = File.createTempFile("bitcoinj-unit-test", null);
    Sha256Hash hash1 = Sha256Hash.of(f);
    // Start with zero delay and ensure the wallet file changes after adding a key.
    wallet.autosaveToFile(f, 0, TimeUnit.SECONDS, null);
    ECKey key = wallet.freshReceiveKey();
    Sha256Hash hash2 = Sha256Hash.of(f);
    assertFalse("Wallet not saved after generating fresh key", hash1.equals(hash2));  // File has changed.

    Transaction t1 = createFakeTx(UNITTEST, valueOf(5, 0), key);
    if (wallet.isPendingTransactionRelevant(t1))
        wallet.receivePending(t1, null);
    Sha256Hash hash3 = Sha256Hash.of(f);
    assertFalse("Wallet not saved after receivePending", hash2.equals(hash3));  // File has changed again.
}
 
Example 2
Source File: WalletTest.java    From green_android with GNU General Public License v3.0 6 votes vote down vote up
@Test
public void autosaveImmediate() throws Exception {
    // Test that the wallet will save itself automatically when it changes.
    File f = File.createTempFile("bitcoinj-unit-test", null);
    Sha256Hash hash1 = Sha256Hash.of(f);
    // Start with zero delay and ensure the wallet file changes after adding a key.
    wallet.autosaveToFile(f, 0, TimeUnit.SECONDS, null);
    ECKey key = wallet.freshReceiveKey();
    Sha256Hash hash2 = Sha256Hash.of(f);
    assertFalse("Wallet not saved after generating fresh key", hash1.equals(hash2));  // File has changed.

    Transaction t1 = createFakeTx(PARAMS, valueOf(5, 0), key);
    if (wallet.isPendingTransactionRelevant(t1))
        wallet.receivePending(t1, null);
    Sha256Hash hash3 = Sha256Hash.of(f);
    assertFalse("Wallet not saved after receivePending", hash2.equals(hash3));  // File has changed again.
}
 
Example 3
Source File: WalletTest.java    From GreenBits with GNU General Public License v3.0 6 votes vote down vote up
@Test
public void autosaveImmediate() throws Exception {
    // Test that the wallet will save itself automatically when it changes.
    File f = File.createTempFile("bitcoinj-unit-test", null);
    Sha256Hash hash1 = Sha256Hash.of(f);
    // Start with zero delay and ensure the wallet file changes after adding a key.
    wallet.autosaveToFile(f, 0, TimeUnit.SECONDS, null);
    ECKey key = wallet.freshReceiveKey();
    Sha256Hash hash2 = Sha256Hash.of(f);
    assertFalse("Wallet not saved after generating fresh key", hash1.equals(hash2));  // File has changed.

    Transaction t1 = createFakeTx(PARAMS, valueOf(5, 0), key);
    if (wallet.isPendingTransactionRelevant(t1))
        wallet.receivePending(t1, null);
    Sha256Hash hash3 = Sha256Hash.of(f);
    assertFalse("Wallet not saved after receivePending", hash2.equals(hash3));  // File has changed again.
}
 
Example 4
Source File: Secp256k1Context.java    From sawtooth-sdk-java with Apache License 2.0 5 votes vote down vote up
/**
 * Generate a bitcoin-style compact signature.
 *
 * @param privateKey ECKey private key
 * @param data the raw message bytes
 * @return the raw signature bytes
 */
private static byte[] generateCompactSig(final ECKey privateKey, final byte[] data) {
  Sha256Hash hash = Sha256Hash.of(data);
  ECKey.ECDSASignature sig = privateKey.sign(hash);

  byte[] csig = new byte[NUM_SIGNATURE_BYTES];

  System.arraycopy(Utils.bigIntegerToBytes(sig.r, HALF_NUM_SIGNATURE_BYTES), 0,
                                           csig, 0, HALF_NUM_SIGNATURE_BYTES);
  System.arraycopy(Utils.bigIntegerToBytes(sig.s, HALF_NUM_SIGNATURE_BYTES), 0,
                                           csig, HALF_NUM_SIGNATURE_BYTES, HALF_NUM_SIGNATURE_BYTES);

  return csig;
}
 
Example 5
Source File: PaymentChannelClientConnection.java    From bcm-android with GNU General Public License v3.0 4 votes vote down vote up
/**
 * Attempts to open a new connection to and open a payment channel with the given host and port, blocking until the
 * connection is open.  The server is requested to keep the channel open for {@code timeoutSeconds}
 * seconds. If the server proposes a longer time the channel will be closed.
 *
 * @param server                  The host/port pair where the server is listening.
 * @param timeoutSeconds          The connection timeout and read timeout during initialization. This should be large enough
 *                                to accommodate ECDSA signature operations and network latency.
 * @param wallet                  The wallet which will be paid from, and where completed transactions will be committed.
 *                                Can be encrypted if user key is supplied when needed. Must already have a
 *                                {@link StoredPaymentChannelClientStates} object in its extensions set.
 * @param myKey                   A freshly generated keypair used for the multisig contract and refund output.
 * @param maxValue                The maximum value this channel is allowed to request
 * @param serverId                A unique ID which is used to attempt reopening of an existing channel.
 *                                This must be unique to the server, and, if your application is exposing payment channels to some
 *                                API, this should also probably encompass some caller UID to avoid applications opening channels
 *                                which were created by others.
 * @param userKeySetup            Key derived from a user password, used to decrypt myKey, if it is encrypted, during setup.
 * @param clientChannelProperties Modifier to change the channel's configuration.
 * @throws IOException              if there's an issue using the network.
 * @throws ValueOutOfRangeException if the balance of wallet is lower than maxValue.
 */
public PaymentChannelClientConnection(InetSocketAddress server, int timeoutSeconds, Wallet wallet, ECKey myKey,
                                      Coin maxValue, String serverId,
                                      @Nullable KeyParameter userKeySetup, final ClientChannelProperties clientChannelProperties)
        throws IOException, ValueOutOfRangeException {
    // Glue the object which vends/ingests protobuf messages in order to manage state to the network object which
    // reads/writes them to the wire in length prefixed form.
    channelClient = new PaymentChannelClient(wallet, myKey, maxValue, Sha256Hash.of(serverId.getBytes()),
            userKeySetup, clientChannelProperties, new PaymentChannelClient.ClientConnection() {
        @Override
        public void sendToServer(Protos.TwoWayChannelMessage msg) {
            wireParser.write(msg);
        }

        @Override
        public void destroyConnection(PaymentChannelCloseException.CloseReason reason) {
            channelOpenFuture.setException(new PaymentChannelCloseException("Payment channel client requested that the connection be closed: " + reason, reason));
            wireParser.closeConnection();
        }

        @Override
        public boolean acceptExpireTime(long expireTime) {
            return expireTime <= (clientChannelProperties.timeWindow() + Utils.currentTimeSeconds() + 60);  // One extra minute to compensate for time skew and latency
        }

        @Override
        public void channelOpen(boolean wasInitiated) {
            wireParser.setSocketTimeout(0);
            // Inform the API user that we're done and ready to roll.
            channelOpenFuture.set(PaymentChannelClientConnection.this);
        }
    });

    // And glue back in the opposite direction - network to the channelClient.
    wireParser = new ProtobufConnection<Protos.TwoWayChannelMessage>(new ProtobufConnection.Listener<Protos.TwoWayChannelMessage>() {
        @Override
        public void messageReceived(ProtobufConnection<Protos.TwoWayChannelMessage> handler, Protos.TwoWayChannelMessage msg) {
            try {
                channelClient.receiveMessage(msg);
            } catch (InsufficientMoneyException e) {
                // We should only get this exception during INITIATE, so channelOpen wasn't called yet.
                channelOpenFuture.setException(e);
            }
        }

        @Override
        public void connectionOpen(ProtobufConnection<Protos.TwoWayChannelMessage> handler) {
            channelClient.connectionOpen();
        }

        @Override
        public void connectionClosed(ProtobufConnection<Protos.TwoWayChannelMessage> handler) {
            channelClient.connectionClosed();
            channelOpenFuture.setException(new PaymentChannelCloseException("The TCP socket died",
                    PaymentChannelCloseException.CloseReason.CONNECTION_CLOSED));
        }
    }, Protos.TwoWayChannelMessage.getDefaultInstance(), Short.MAX_VALUE, timeoutSeconds * 1000);

    // Initiate the outbound network connection. We don't need to keep this around. The wireParser object will handle
    // things from here on out.
    new NioClient(server, wireParser, timeoutSeconds * 1000);
}
 
Example 6
Source File: WalletTest.java    From bcm-android with GNU General Public License v3.0 4 votes vote down vote up
@Test
public void autosaveDelayed() throws Exception {
    // Test that the wallet will save itself automatically when it changes, but not immediately and near-by
    // updates are coalesced together. This test is a bit racy, it assumes we can complete the unit test within
    // an auto-save cycle of 1 second.
    final File[] results = new File[2];
    final CountDownLatch latch = new CountDownLatch(3);
    File f = File.createTempFile("bitcoinj-unit-test", null);
    Sha256Hash hash1 = Sha256Hash.of(f);
    wallet.autosaveToFile(f, 1, TimeUnit.SECONDS,
            new WalletFiles.Listener() {
                @Override
                public void onBeforeAutoSave(File tempFile) {
                    results[0] = tempFile;
                }

                @Override
                public void onAfterAutoSave(File newlySavedFile) {
                    results[1] = newlySavedFile;
                    latch.countDown();
                }
            }
    );
    ECKey key = wallet.freshReceiveKey();
    Sha256Hash hash2 = Sha256Hash.of(f);
    assertFalse(hash1.equals(hash2));  // File has changed immediately despite the delay, as keys are important.
    assertNotNull(results[0]);
    assertEquals(f, results[1]);
    results[0] = results[1] = null;

    sendMoneyToWallet(BlockChain.NewBlockType.BEST_CHAIN);
    Sha256Hash hash3 = Sha256Hash.of(f);
    assertEquals(hash2, hash3);  // File has NOT changed yet. Just new blocks with no txns - delayed.
    assertNull(results[0]);
    assertNull(results[1]);

    sendMoneyToWallet(BlockChain.NewBlockType.BEST_CHAIN, valueOf(5, 0), key);
    Sha256Hash hash4 = Sha256Hash.of(f);
    assertFalse(hash3.equals(hash4));  // File HAS changed.
    results[0] = results[1] = null;

    // A block that contains some random tx we don't care about.
    sendMoneyToWallet(BlockChain.NewBlockType.BEST_CHAIN, Coin.COIN, OTHER_ADDRESS);
    assertEquals(hash4, Sha256Hash.of(f));  // File has NOT changed.
    assertNull(results[0]);
    assertNull(results[1]);

    // Wait for an auto-save to occur.
    latch.await();
    Sha256Hash hash5 = Sha256Hash.of(f);
    assertFalse(hash4.equals(hash5));  // File has now changed.
    assertNotNull(results[0]);
    assertEquals(f, results[1]);

    // Now we shutdown auto-saving and expect wallet changes to remain unsaved, even "important" changes.
    wallet.shutdownAutosaveAndWait();
    results[0] = results[1] = null;
    ECKey key2 = new ECKey();
    wallet.importKey(key2);
    assertEquals(hash5, Sha256Hash.of(f)); // File has NOT changed.
    sendMoneyToWallet(BlockChain.NewBlockType.BEST_CHAIN, valueOf(5, 0), key2);
    Thread.sleep(2000); // Wait longer than autosave delay. TODO Fix the racyness.
    assertEquals(hash5, Sha256Hash.of(f)); // File has still NOT changed.
    assertNull(results[0]);
    assertNull(results[1]);
}
 
Example 7
Source File: PaymentChannelClientConnection.java    From green_android with GNU General Public License v3.0 4 votes vote down vote up
/**
 * Attempts to open a new connection to and open a payment channel with the given host and port, blocking until the
 * connection is open.  The server is requested to keep the channel open for {@param timeWindow}
 * seconds. If the server proposes a longer time the channel will be closed.
 *
 * @param server The host/port pair where the server is listening.
 * @param timeoutSeconds The connection timeout and read timeout during initialization. This should be large enough
 *                       to accommodate ECDSA signature operations and network latency.
 * @param wallet The wallet which will be paid from, and where completed transactions will be committed.
 *               Can be encrypted if user key is supplied when needed. Must already have a
 *               {@link StoredPaymentChannelClientStates} object in its extensions set.
 * @param myKey A freshly generated keypair used for the multisig contract and refund output.
 * @param maxValue The maximum value this channel is allowed to request
 * @param serverId A unique ID which is used to attempt reopening of an existing channel.
 *                 This must be unique to the server, and, if your application is exposing payment channels to some
 *                 API, this should also probably encompass some caller UID to avoid applications opening channels
 *                 which were created by others.
 * @param userKeySetup Key derived from a user password, used to decrypt myKey, if it is encrypted, during setup.
 * @param clientChannelProperties Modifier to change the channel's configuration.
 *
 * @throws IOException if there's an issue using the network.
 * @throws ValueOutOfRangeException if the balance of wallet is lower than maxValue.
 */
public PaymentChannelClientConnection(InetSocketAddress server, int timeoutSeconds, Wallet wallet, ECKey myKey,
                                      Coin maxValue, String serverId,
                                      @Nullable KeyParameter userKeySetup, final ClientChannelProperties clientChannelProperties)
        throws IOException, ValueOutOfRangeException {
    // Glue the object which vends/ingests protobuf messages in order to manage state to the network object which
    // reads/writes them to the wire in length prefixed form.
    channelClient = new PaymentChannelClient(wallet, myKey, maxValue, Sha256Hash.of(serverId.getBytes()),
            userKeySetup, clientChannelProperties, new PaymentChannelClient.ClientConnection() {
        @Override
        public void sendToServer(Protos.TwoWayChannelMessage msg) {
            wireParser.write(msg);
        }

        @Override
        public void destroyConnection(PaymentChannelCloseException.CloseReason reason) {
            channelOpenFuture.setException(new PaymentChannelCloseException("Payment channel client requested that the connection be closed: " + reason, reason));
            wireParser.closeConnection();
        }

        @Override
        public boolean acceptExpireTime(long expireTime) {
            return expireTime <= (clientChannelProperties.timeWindow() + Utils.currentTimeSeconds() + 60);  // One extra minute to compensate for time skew and latency
        }

        @Override
        public void channelOpen(boolean wasInitiated) {
            wireParser.setSocketTimeout(0);
            // Inform the API user that we're done and ready to roll.
            channelOpenFuture.set(PaymentChannelClientConnection.this);
        }
    });

    // And glue back in the opposite direction - network to the channelClient.
    wireParser = new ProtobufConnection<Protos.TwoWayChannelMessage>(new ProtobufConnection.Listener<Protos.TwoWayChannelMessage>() {
        @Override
        public void messageReceived(ProtobufConnection<Protos.TwoWayChannelMessage> handler, Protos.TwoWayChannelMessage msg) {
            try {
                channelClient.receiveMessage(msg);
            } catch (InsufficientMoneyException e) {
                // We should only get this exception during INITIATE, so channelOpen wasn't called yet.
                channelOpenFuture.setException(e);
            }
        }

        @Override
        public void connectionOpen(ProtobufConnection<Protos.TwoWayChannelMessage> handler) {
            channelClient.connectionOpen();
        }

        @Override
        public void connectionClosed(ProtobufConnection<Protos.TwoWayChannelMessage> handler) {
            channelClient.connectionClosed();
            channelOpenFuture.setException(new PaymentChannelCloseException("The TCP socket died",
                    PaymentChannelCloseException.CloseReason.CONNECTION_CLOSED));
        }
    }, Protos.TwoWayChannelMessage.getDefaultInstance(), Short.MAX_VALUE, timeoutSeconds*1000);

    // Initiate the outbound network connection. We don't need to keep this around. The wireParser object will handle
    // things from here on out.
    new NioClient(server, wireParser, timeoutSeconds * 1000);
}
 
Example 8
Source File: WalletTest.java    From green_android with GNU General Public License v3.0 4 votes vote down vote up
@Test
public void autosaveDelayed() throws Exception {
    // Test that the wallet will save itself automatically when it changes, but not immediately and near-by
    // updates are coalesced together. This test is a bit racy, it assumes we can complete the unit test within
    // an auto-save cycle of 1 second.
    final File[] results = new File[2];
    final CountDownLatch latch = new CountDownLatch(3);
    File f = File.createTempFile("bitcoinj-unit-test", null);
    Sha256Hash hash1 = Sha256Hash.of(f);
    wallet.autosaveToFile(f, 1, TimeUnit.SECONDS,
            new WalletFiles.Listener() {
                @Override
                public void onBeforeAutoSave(File tempFile) {
                    results[0] = tempFile;
                }

                @Override
                public void onAfterAutoSave(File newlySavedFile) {
                    results[1] = newlySavedFile;
                    latch.countDown();
                }
            }
    );
    ECKey key = wallet.freshReceiveKey();
    Sha256Hash hash2 = Sha256Hash.of(f);
    assertFalse(hash1.equals(hash2));  // File has changed immediately despite the delay, as keys are important.
    assertNotNull(results[0]);
    assertEquals(f, results[1]);
    results[0] = results[1] = null;

    sendMoneyToWallet(BlockChain.NewBlockType.BEST_CHAIN);
    Sha256Hash hash3 = Sha256Hash.of(f);
    assertEquals(hash2, hash3);  // File has NOT changed yet. Just new blocks with no txns - delayed.
    assertNull(results[0]);
    assertNull(results[1]);

    sendMoneyToWallet(BlockChain.NewBlockType.BEST_CHAIN, valueOf(5, 0), key);
    Sha256Hash hash4 = Sha256Hash.of(f);
    assertFalse(hash3.equals(hash4));  // File HAS changed.
    results[0] = results[1] = null;

    // A block that contains some random tx we don't care about.
    sendMoneyToWallet(BlockChain.NewBlockType.BEST_CHAIN, Coin.COIN, OTHER_ADDRESS);
    assertEquals(hash4, Sha256Hash.of(f));  // File has NOT changed.
    assertNull(results[0]);
    assertNull(results[1]);

    // Wait for an auto-save to occur.
    latch.await();
    Sha256Hash hash5 = Sha256Hash.of(f);
    assertFalse(hash4.equals(hash5));  // File has now changed.
    assertNotNull(results[0]);
    assertEquals(f, results[1]);

    // Now we shutdown auto-saving and expect wallet changes to remain unsaved, even "important" changes.
    wallet.shutdownAutosaveAndWait();
    results[0] = results[1] = null;
    ECKey key2 = new ECKey();
    wallet.importKey(key2);
    assertEquals(hash5, Sha256Hash.of(f)); // File has NOT changed.
    sendMoneyToWallet(BlockChain.NewBlockType.BEST_CHAIN, valueOf(5, 0), key2);
    Thread.sleep(2000); // Wait longer than autosave delay. TODO Fix the racyness.
    assertEquals(hash5, Sha256Hash.of(f)); // File has still NOT changed.
    assertNull(results[0]);
    assertNull(results[1]);
}
 
Example 9
Source File: PaymentChannelClientConnection.java    From GreenBits with GNU General Public License v3.0 4 votes vote down vote up
/**
 * Attempts to open a new connection to and open a payment channel with the given host and port, blocking until the
 * connection is open.  The server is requested to keep the channel open for {@param timeWindow}
 * seconds. If the server proposes a longer time the channel will be closed.
 *
 * @param server The host/port pair where the server is listening.
 * @param timeoutSeconds The connection timeout and read timeout during initialization. This should be large enough
 *                       to accommodate ECDSA signature operations and network latency.
 * @param wallet The wallet which will be paid from, and where completed transactions will be committed.
 *               Can be encrypted if user key is supplied when needed. Must already have a
 *               {@link StoredPaymentChannelClientStates} object in its extensions set.
 * @param myKey A freshly generated keypair used for the multisig contract and refund output.
 * @param maxValue The maximum value this channel is allowed to request
 * @param serverId A unique ID which is used to attempt reopening of an existing channel.
 *                 This must be unique to the server, and, if your application is exposing payment channels to some
 *                 API, this should also probably encompass some caller UID to avoid applications opening channels
 *                 which were created by others.
 * @param userKeySetup Key derived from a user password, used to decrypt myKey, if it is encrypted, during setup.
 * @param clientChannelProperties Modifier to change the channel's configuration.
 *
 * @throws IOException if there's an issue using the network.
 * @throws ValueOutOfRangeException if the balance of wallet is lower than maxValue.
 */
public PaymentChannelClientConnection(InetSocketAddress server, int timeoutSeconds, Wallet wallet, ECKey myKey,
                                      Coin maxValue, String serverId,
                                      @Nullable KeyParameter userKeySetup, final ClientChannelProperties clientChannelProperties)
        throws IOException, ValueOutOfRangeException {
    // Glue the object which vends/ingests protobuf messages in order to manage state to the network object which
    // reads/writes them to the wire in length prefixed form.
    channelClient = new PaymentChannelClient(wallet, myKey, maxValue, Sha256Hash.of(serverId.getBytes()),
            userKeySetup, clientChannelProperties, new PaymentChannelClient.ClientConnection() {
        @Override
        public void sendToServer(Protos.TwoWayChannelMessage msg) {
            wireParser.write(msg);
        }

        @Override
        public void destroyConnection(PaymentChannelCloseException.CloseReason reason) {
            channelOpenFuture.setException(new PaymentChannelCloseException("Payment channel client requested that the connection be closed: " + reason, reason));
            wireParser.closeConnection();
        }

        @Override
        public boolean acceptExpireTime(long expireTime) {
            return expireTime <= (clientChannelProperties.timeWindow() + Utils.currentTimeSeconds() + 60);  // One extra minute to compensate for time skew and latency
        }

        @Override
        public void channelOpen(boolean wasInitiated) {
            wireParser.setSocketTimeout(0);
            // Inform the API user that we're done and ready to roll.
            channelOpenFuture.set(PaymentChannelClientConnection.this);
        }
    });

    // And glue back in the opposite direction - network to the channelClient.
    wireParser = new ProtobufConnection<Protos.TwoWayChannelMessage>(new ProtobufConnection.Listener<Protos.TwoWayChannelMessage>() {
        @Override
        public void messageReceived(ProtobufConnection<Protos.TwoWayChannelMessage> handler, Protos.TwoWayChannelMessage msg) {
            try {
                channelClient.receiveMessage(msg);
            } catch (InsufficientMoneyException e) {
                // We should only get this exception during INITIATE, so channelOpen wasn't called yet.
                channelOpenFuture.setException(e);
            }
        }

        @Override
        public void connectionOpen(ProtobufConnection<Protos.TwoWayChannelMessage> handler) {
            channelClient.connectionOpen();
        }

        @Override
        public void connectionClosed(ProtobufConnection<Protos.TwoWayChannelMessage> handler) {
            channelClient.connectionClosed();
            channelOpenFuture.setException(new PaymentChannelCloseException("The TCP socket died",
                    PaymentChannelCloseException.CloseReason.CONNECTION_CLOSED));
        }
    }, Protos.TwoWayChannelMessage.getDefaultInstance(), Short.MAX_VALUE, timeoutSeconds*1000);

    // Initiate the outbound network connection. We don't need to keep this around. The wireParser object will handle
    // things from here on out.
    new NioClient(server, wireParser, timeoutSeconds * 1000);
}
 
Example 10
Source File: WalletTest.java    From GreenBits with GNU General Public License v3.0 4 votes vote down vote up
@Test
public void autosaveDelayed() throws Exception {
    // Test that the wallet will save itself automatically when it changes, but not immediately and near-by
    // updates are coalesced together. This test is a bit racy, it assumes we can complete the unit test within
    // an auto-save cycle of 1 second.
    final File[] results = new File[2];
    final CountDownLatch latch = new CountDownLatch(3);
    File f = File.createTempFile("bitcoinj-unit-test", null);
    Sha256Hash hash1 = Sha256Hash.of(f);
    wallet.autosaveToFile(f, 1, TimeUnit.SECONDS,
            new WalletFiles.Listener() {
                @Override
                public void onBeforeAutoSave(File tempFile) {
                    results[0] = tempFile;
                }

                @Override
                public void onAfterAutoSave(File newlySavedFile) {
                    results[1] = newlySavedFile;
                    latch.countDown();
                }
            }
    );
    ECKey key = wallet.freshReceiveKey();
    Sha256Hash hash2 = Sha256Hash.of(f);
    assertFalse(hash1.equals(hash2));  // File has changed immediately despite the delay, as keys are important.
    assertNotNull(results[0]);
    assertEquals(f, results[1]);
    results[0] = results[1] = null;

    sendMoneyToWallet(BlockChain.NewBlockType.BEST_CHAIN);
    Sha256Hash hash3 = Sha256Hash.of(f);
    assertEquals(hash2, hash3);  // File has NOT changed yet. Just new blocks with no txns - delayed.
    assertNull(results[0]);
    assertNull(results[1]);

    sendMoneyToWallet(BlockChain.NewBlockType.BEST_CHAIN, valueOf(5, 0), key);
    Sha256Hash hash4 = Sha256Hash.of(f);
    assertFalse(hash3.equals(hash4));  // File HAS changed.
    results[0] = results[1] = null;

    // A block that contains some random tx we don't care about.
    sendMoneyToWallet(BlockChain.NewBlockType.BEST_CHAIN, Coin.COIN, OTHER_ADDRESS);
    assertEquals(hash4, Sha256Hash.of(f));  // File has NOT changed.
    assertNull(results[0]);
    assertNull(results[1]);

    // Wait for an auto-save to occur.
    latch.await();
    Sha256Hash hash5 = Sha256Hash.of(f);
    assertFalse(hash4.equals(hash5));  // File has now changed.
    assertNotNull(results[0]);
    assertEquals(f, results[1]);

    // Now we shutdown auto-saving and expect wallet changes to remain unsaved, even "important" changes.
    wallet.shutdownAutosaveAndWait();
    results[0] = results[1] = null;
    ECKey key2 = new ECKey();
    wallet.importKey(key2);
    assertEquals(hash5, Sha256Hash.of(f)); // File has NOT changed.
    sendMoneyToWallet(BlockChain.NewBlockType.BEST_CHAIN, valueOf(5, 0), key2);
    Thread.sleep(2000); // Wait longer than autosave delay. TODO Fix the racyness.
    assertEquals(hash5, Sha256Hash.of(f)); // File has still NOT changed.
    assertNull(results[0]);
    assertNull(results[1]);
}