@Test
  public void oneTx() throws Exception {
    // Check basic tx serialization.
    Coin v1 = COIN;
    Transaction t1 = createFakeTx(params, v1, myAddress);
    t1.getConfidence().markBroadcastBy(new PeerAddress(InetAddress.getByName("1.2.3.4")));
    t1.getConfidence().markBroadcastBy(new PeerAddress(InetAddress.getByName("5.6.7.8")));
    t1.getConfidence().setSource(TransactionConfidence.Source.NETWORK);
    myWallet.receivePending(t1, null);
    Wallet wallet1 = roundTrip(myWallet);
    assertEquals(1, wallet1.getTransactions(true).size());
    assertEquals(v1, wallet1.getBalance(Wallet.BalanceType.ESTIMATED));
    Transaction t1copy = wallet1.getTransaction(t1.getHash());
    assertArrayEquals(t1.bitcoinSerialize(), t1copy.bitcoinSerialize());
    assertEquals(2, t1copy.getConfidence().numBroadcastPeers());
    assertEquals(TransactionConfidence.Source.NETWORK, t1copy.getConfidence().getSource());

    Protos.Wallet walletProto = new WalletProtobufSerializer().walletToProto(myWallet);
    assertEquals(Protos.Key.Type.ORIGINAL, walletProto.getKey(0).getType());
    assertEquals(0, walletProto.getExtensionCount());
    assertEquals(1, walletProto.getTransactionCount());
    assertEquals(6, walletProto.getKeyCount());

    Protos.Transaction t1p = walletProto.getTransaction(0);
    assertEquals(0, t1p.getBlockHashCount());
    assertArrayEquals(t1.getHash().getBytes(), t1p.getHash().toByteArray());
    assertEquals(Protos.Transaction.Pool.PENDING, t1p.getPool());
    assertFalse(t1p.hasLockTime());
    assertFalse(t1p.getTransactionInput(0).hasSequence());
    assertArrayEquals(
        t1.getInputs().get(0).getOutpoint().getHash().getBytes(),
        t1p.getTransactionInput(0).getTransactionOutPointHash().toByteArray());
    assertEquals(0, t1p.getTransactionInput(0).getTransactionOutPointIndex());
    assertEquals(t1p.getTransactionOutput(0).getValue(), v1.value);
  }
 @Test
 public void raiseFeeTx() throws Exception {
   // Check basic tx serialization.
   Coin v1 = COIN;
   Transaction t1 = createFakeTx(params, v1, myAddress);
   t1.setPurpose(Purpose.RAISE_FEE);
   myWallet.receivePending(t1, null);
   Wallet wallet1 = roundTrip(myWallet);
   Transaction t1copy = wallet1.getTransaction(t1.getHash());
   assertEquals(Purpose.RAISE_FEE, t1copy.getPurpose());
 }
 @Test
 public void coinbaseTxns() throws Exception {
   // Covers issue 420 where the outpoint index of a coinbase tx input was being mis-serialized.
   Block b =
       params
           .getGenesisBlock()
           .createNextBlockWithCoinbase(
               Block.BLOCK_VERSION_GENESIS,
               myKey.getPubKey(),
               FIFTY_COINS,
               Block.BLOCK_HEIGHT_GENESIS);
   Transaction coinbase = b.getTransactions().get(0);
   assertTrue(coinbase.isCoinBase());
   BlockChain chain = new BlockChain(params, myWallet, new MemoryBlockStore(params));
   assertTrue(chain.add(b));
   // Wallet now has a coinbase tx in it.
   assertEquals(1, myWallet.getTransactions(true).size());
   assertTrue(myWallet.getTransaction(coinbase.getHash()).isCoinBase());
   Wallet wallet2 = roundTrip(myWallet);
   assertEquals(1, wallet2.getTransactions(true).size());
   assertTrue(wallet2.getTransaction(coinbase.getHash()).isCoinBase());
 }
  @Test
  public void doubleSpend() throws Exception {
    // Check that we can serialize double spends correctly, as this is a slightly tricky case.
    FakeTxBuilder.DoubleSpends doubleSpends =
        FakeTxBuilder.createFakeDoubleSpendTxns(params, myAddress);
    // t1 spends to our wallet.
    myWallet.receivePending(doubleSpends.t1, null);
    // t2 rolls back t1 and spends somewhere else.
    myWallet.receiveFromBlock(doubleSpends.t2, null, BlockChain.NewBlockType.BEST_CHAIN, 0);
    Wallet wallet1 = roundTrip(myWallet);
    assertEquals(1, wallet1.getTransactions(true).size());
    Transaction t1 = wallet1.getTransaction(doubleSpends.t1.getHash());
    assertEquals(ConfidenceType.DEAD, t1.getConfidence().getConfidenceType());
    assertEquals(Coin.ZERO, wallet1.getBalance());

    // TODO: Wallet should store overriding transactions even if they are not wallet-relevant.
    // assertEquals(doubleSpends.t2, t1.getConfidence().getOverridingTransaction());
  }
 @Override
 public void deserializeWalletExtension(Wallet containingWallet, byte[] data) throws Exception {
   lock.lock();
   try {
     checkState(this.containingWallet == null || this.containingWallet == containingWallet);
     this.containingWallet = containingWallet;
     NetworkParameters params = containingWallet.getParams();
     ClientState.StoredClientPaymentChannels states =
         ClientState.StoredClientPaymentChannels.parseFrom(data);
     for (ClientState.StoredClientPaymentChannel storedState : states.getChannelsList()) {
       Transaction refundTransaction =
           params
               .getDefaultSerializer()
               .makeTransaction(storedState.getRefundTransaction().toByteArray());
       refundTransaction.getConfidence().setSource(TransactionConfidence.Source.SELF);
       ECKey myKey =
           (storedState.getMyKey().isEmpty())
               ? containingWallet.findKeyFromPubKey(storedState.getMyPublicKey().toByteArray())
               : ECKey.fromPrivate(storedState.getMyKey().toByteArray());
       StoredClientChannel channel =
           new StoredClientChannel(
               Sha256Hash.wrap(storedState.getId().toByteArray()),
               params
                   .getDefaultSerializer()
                   .makeTransaction(storedState.getContractTransaction().toByteArray()),
               refundTransaction,
               myKey,
               Coin.valueOf(storedState.getValueToMe()),
               Coin.valueOf(storedState.getRefundFees()),
               false);
       if (storedState.hasCloseTransactionHash()) {
         Sha256Hash closeTxHash =
             Sha256Hash.wrap(storedState.getCloseTransactionHash().toByteArray());
         channel.close = containingWallet.getTransaction(closeTxHash);
       }
       putChannel(channel, false);
     }
   } finally {
     lock.unlock();
   }
 }
  /**
   * Called when the client provides us with a new signature and wishes to increment total payment
   * by size. Verifies the provided signature and only updates values if everything checks out. If
   * the new refundSize is not the lowest we have seen, it is simply ignored.
   *
   * @param refundSize How many satoshis of the original contract are refunded to the client (the
   *     rest are ours)
   * @param signatureBytes The new signature spending the multi-sig contract to a new payment
   *     transaction
   * @throws VerificationException If the signature does not verify or size is out of range (incl
   *     being rejected by the network as dust).
   * @return true if there is more value left on the channel, false if it is now fully used up.
   */
  public synchronized boolean incrementPayment(Coin refundSize, byte[] signatureBytes)
      throws VerificationException, ValueOutOfRangeException, InsufficientMoneyException {
    checkState(state == State.READY);
    checkNotNull(refundSize);
    checkNotNull(signatureBytes);
    TransactionSignature signature = TransactionSignature.decodeFromBitcoin(signatureBytes, true);
    // We allow snapping to zero for the payment amount because it's treated specially later, but
    // not less than
    // the dust level because that would prevent the transaction from being relayed/mined.
    final boolean fullyUsedUp = refundSize.equals(Coin.ZERO);
    if (refundSize.compareTo(clientOutput.getMinNonDustValue()) < 0 && !fullyUsedUp)
      throw new ValueOutOfRangeException(
          "Attempt to refund negative value or value too small to be accepted by the network");
    Coin newValueToMe = totalValue.subtract(refundSize);
    if (newValueToMe.signum() < 0)
      throw new ValueOutOfRangeException("Attempt to refund more than the contract allows.");
    if (newValueToMe.compareTo(bestValueToMe) < 0)
      throw new ValueOutOfRangeException("Attempt to roll back payment on the channel.");

    // Get the wallet's copy of the multisigContract (ie with confidence information), if this is
    // null, the wallet
    // was not connected to the peergroup when the contract was broadcast (which may cause issues
    // down the road, and
    // disables our double-spend check next)
    Transaction walletContract = wallet.getTransaction(multisigContract.getHash());
    checkNotNull(
        walletContract,
        "Wallet did not contain multisig contract {} after state was marked READY",
        multisigContract.getHash());

    // Note that we check for DEAD state here, but this test is essentially useless in production
    // because we will
    // miss most double-spends due to bloom filtering right now anyway. This will eventually fixed
    // by network-wide
    // double-spend notifications, so we just wait instead of attempting to add all dependant
    // outpoints to our bloom
    // filters (and probably missing lots of edge-cases).
    if (walletContract.getConfidence().getConfidenceType()
        == TransactionConfidence.ConfidenceType.DEAD) {
      close();
      throw new VerificationException("Multisig contract was double-spent");
    }

    Transaction.SigHash mode;
    // If the client doesn't want anything back, they shouldn't sign any outputs at all.
    if (fullyUsedUp) mode = Transaction.SigHash.NONE;
    else mode = Transaction.SigHash.SINGLE;

    if (signature.sigHashMode() != mode || !signature.anyoneCanPay())
      throw new VerificationException(
          "New payment signature was not signed with the right SIGHASH flags.");

    Wallet.SendRequest req = makeUnsignedChannelContract(newValueToMe);
    // Now check the signature is correct.
    // Note that the client must sign with SIGHASH_{SINGLE/NONE} | SIGHASH_ANYONECANPAY to allow us
    // to add additional
    // inputs (in case we need to add significant fee, or something...) and any outputs we want to
    // pay to.
    Sha256Hash sighash = req.tx.hashForSignature(0, multisigScript, mode, true);

    if (!clientKey.verify(sighash, signature))
      throw new VerificationException("Signature does not verify on tx\n" + req.tx);
    bestValueToMe = newValueToMe;
    bestValueSignature = signatureBytes;
    updateChannelInWallet();
    return !fullyUsedUp;
  }