private WalletTransaction connectTransactionOutputs(
      org.bitcoinj.wallet.Protos.Transaction txProto) throws UnreadableWalletException {
    Transaction tx = txMap.get(txProto.getHash());
    final WalletTransaction.Pool pool;
    switch (txProto.getPool()) {
      case DEAD:
        pool = WalletTransaction.Pool.DEAD;
        break;
      case PENDING:
        pool = WalletTransaction.Pool.PENDING;
        break;
      case SPENT:
        pool = WalletTransaction.Pool.SPENT;
        break;
      case UNSPENT:
        pool = WalletTransaction.Pool.UNSPENT;
        break;
        // Upgrade old wallets: inactive pool has been merged with the pending pool.
        // Remove this some time after 0.9 is old and everyone has upgraded.
        // There should not be any spent outputs in this tx as old wallets would not allow them to
        // be spent
        // in this state.
      case INACTIVE:
      case PENDING_INACTIVE:
        pool = WalletTransaction.Pool.PENDING;
        break;
      default:
        throw new UnreadableWalletException("Unknown transaction pool: " + txProto.getPool());
    }
    for (int i = 0; i < tx.getOutputs().size(); i++) {
      TransactionOutput output = tx.getOutputs().get(i);
      final Protos.TransactionOutput transactionOutput = txProto.getTransactionOutput(i);
      if (transactionOutput.hasSpentByTransactionHash()) {
        final ByteString spentByTransactionHash = transactionOutput.getSpentByTransactionHash();
        Transaction spendingTx = txMap.get(spentByTransactionHash);
        if (spendingTx == null) {
          throw new UnreadableWalletException(
              String.format(
                  "Could not connect %s to %s",
                  tx.getHashAsString(), byteStringToHash(spentByTransactionHash)));
        }
        final int spendingIndex = transactionOutput.getSpentByTransactionIndex();
        TransactionInput input = checkNotNull(spendingTx.getInput(spendingIndex));
        input.connect(output);
      }
    }

    if (txProto.hasConfidence()) {
      Protos.TransactionConfidence confidenceProto = txProto.getConfidence();
      TransactionConfidence confidence = tx.getConfidence();
      readConfidence(tx, confidenceProto, confidence);
    }

    return new WalletTransaction(pool, tx);
  }
예제 #2
0
  public static List<TransactionOutput> getMyOutputs(Transaction tx, DeterministicKey key) {
    List<TransactionOutput> mines = new ArrayList<>();
    for (TransactionOutput curr : tx.getOutputs()) {
      boolean isMine = false;

      String to = null;
      Address add = curr.getAddressFromP2PKHScript(BitcoinNetwork.getInstance().get().getParams());
      if (add != null) to = add.toString();
      else {
        add = curr.getAddressFromP2SH(BitcoinNetwork.getInstance().get().getParams());
        if (add != null) to = add.toString();
      }
      if (to != null) { // VERIFICATION BY ADDRESS
        isMine = to.equals(keyToStringAddress(key));
      } else { // VERIFICATION BY PUBKEY
        final byte[] pubKeyCurr = curr.getScriptPubKey().getPubKey();
        isMine = Arrays.equals(key.getPubKey(), pubKeyCurr);
      }

      if (isMine) {
        mines.add(curr);
        break;
      }
    }
    return mines;
  }
 @CheckForNull
 private static List<Address> getToAddresses(
     @Nonnull final Transaction tx, @Nonnull final AbstractWallet pocket, boolean toMe) {
   List<Address> addresses = new ArrayList<Address>();
   for (final TransactionOutput output : tx.getOutputs()) {
     try {
       if (output.isMine(pocket) == toMe) {
         addresses.add(output.getScriptPubKey().getToAddress(pocket.getCoinType()));
       }
     } catch (final ScriptException x) {
       /* ignore this output */
     }
   }
   return addresses;
 }
  public static boolean isInternal(@Nonnull final Transaction tx) {
    if (tx.isCoinBase()) return false;

    final List<TransactionOutput> outputs = tx.getOutputs();
    if (outputs.size() != 1) return false;

    try {
      final TransactionOutput output = outputs.get(0);
      final Script scriptPubKey = output.getScriptPubKey();
      if (!scriptPubKey.isSentToRawPubKey()) return false;

      return true;
    } catch (final ScriptException x) {
      return false;
    }
  }
  /**
   * Called when the client provides the refund transaction. The refund transaction must have one
   * input from the multisig contract (that we don't have yet) and one output that the client
   * creates to themselves. This object will later be modified when we start getting paid.
   *
   * @param refundTx The refund transaction, this object will be mutated when payment is
   *     incremented.
   * @param clientMultiSigPubKey The client's pubkey which is required for the multisig output
   * @return Our signature that makes the refund transaction valid
   * @throws VerificationException If the transaction isnt valid or did not meet the requirements of
   *     a refund transaction.
   */
  public synchronized byte[] provideRefundTransaction(
      Transaction refundTx, byte[] clientMultiSigPubKey) throws VerificationException {
    checkNotNull(refundTx);
    checkNotNull(clientMultiSigPubKey);
    checkState(state == State.WAITING_FOR_REFUND_TRANSACTION);
    log.info("Provided with refund transaction: {}", refundTx);
    // Do a few very basic syntax sanity checks.
    refundTx.verify();
    // Verify that the refund transaction has a single input (that we can fill to sign the multisig
    // output).
    if (refundTx.getInputs().size() != 1)
      throw new VerificationException("Refund transaction does not have exactly one input");
    // Verify that the refund transaction has a time lock on it and a sequence number of zero.
    if (refundTx.getInput(0).getSequenceNumber() != 0)
      throw new VerificationException("Refund transaction's input's sequence number is non-0");
    if (refundTx.getLockTime() < minExpireTime)
      throw new VerificationException("Refund transaction has a lock time too soon");
    // Verify the transaction has one output (we don't care about its contents, its up to the
    // client)
    // Note that because we sign with SIGHASH_NONE|SIGHASH_ANYOENCANPAY the client can later add
    // more outputs and
    // inputs, but we will need only one output later to create the paying transactions
    if (refundTx.getOutputs().size() != 1)
      throw new VerificationException("Refund transaction does not have exactly one output");

    refundTransactionUnlockTimeSecs = refundTx.getLockTime();

    // Sign the refund tx with the scriptPubKey and return the signature. We don't have the spending
    // transaction
    // so do the steps individually.
    clientKey = ECKey.fromPublicOnly(clientMultiSigPubKey);
    Script multisigPubKey =
        ScriptBuilder.createMultiSigOutputScript(2, ImmutableList.of(clientKey, serverKey));
    // We are really only signing the fact that the transaction has a proper lock time and don't
    // care about anything
    // else, so we sign SIGHASH_NONE and SIGHASH_ANYONECANPAY.
    TransactionSignature sig =
        refundTx.calculateSignature(0, serverKey, multisigPubKey, Transaction.SigHash.NONE, true);
    log.info("Signed refund transaction.");
    this.clientOutput = refundTx.getOutput(0);
    state = State.WAITING_FOR_MULTISIG_CONTRACT;
    return sig.encodeToBitcoin();
  }
  /**
   * This is required for signatures which use a sigHashType which cannot be represented using
   * SigHash and anyoneCanPay See transaction
   * c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73, which has sigHashType 0
   */
  public static synchronized byte[] serializeForSignature(
      Transaction spendingTx, int inputIndex, byte[] connectedScript, byte sigHashType) {
    NetworkParameters params = TestNet3Params.get();
    // The SIGHASH flags are used in the design of contracts, please see this page for a further
    // understanding of
    // the purposes of the code in this method:
    //
    //   https://en.bitcoin.it/wiki/Contracts

    try {

      Transaction tx = new Transaction(params, spendingTx.bitcoinSerialize());
      // Store all the input scripts and clear them in preparation for signing. If we're signing a
      // fresh
      // transaction that step isn't very helpful, but it doesn't add much cost relative to the
      // actual
      // EC math so we'll do it anyway.
      //
      // Also store the input sequence numbers in case we are clearing them with SigHash.NONE/SINGLE

      byte[][] inputScripts = new byte[tx.getInputs().size()][];
      long[] inputSequenceNumbers = new long[tx.getInputs().size()];
      for (int i = 0; i < tx.getInputs().size(); i++) {
        inputScripts[i] = tx.getInputs().get(i).getScriptBytes();
        inputSequenceNumbers[i] = tx.getInputs().get(i).getSequenceNumber();
        tx.getInput(i).setScriptSig(new Script(new byte[0]));
      }

      // This step has no purpose beyond being synchronized with the reference clients bugs.
      // OP_CODESEPARATOR
      // is a legacy holdover from a previous, broken design of executing scripts that shipped in
      // Bitcoin 0.1.
      // It was seriously flawed and would have let anyone take anyone elses money. Later versions
      // switched to
      // the design we use today where scripts are executed independently but share a stack. This
      // left the
      // OP_CODESEPARATOR instruction having no purpose as it was only meant to be used internally,
      // not actually
      // ever put into scripts. Deleting OP_CODESEPARATOR is a step that should never be required
      // but if we don't
      // do it, we could split off the main chain.

      connectedScript =
          Script.removeAllInstancesOfOp(connectedScript, ScriptOpCodes.OP_CODESEPARATOR);
      // Set the input to the script of its output. Satoshi does this but the step has no obvious
      // purpose as
      // the signature covers the hash of the prevout transaction which obviously includes the
      // output script
      // already. Perhaps it felt safer to him in some way, or is another leftover from how the code
      // was written.
      TransactionInput input = tx.getInputs().get(inputIndex);
      input.setScriptSig(new Script(connectedScript));
      List<TransactionOutput> outputs = tx.getOutputs();

      if ((sigHashType & 0x1f) == (Transaction.SigHash.NONE.ordinal() + 1)) {
        // SIGHASH_NONE means no outputs are signed at all - the signature is effectively for a
        // "blank cheque".
        // this.outputs = new ArrayList<TransactionOutput>(0);
        tx.clearOutputs();
        // The signature isn't broken by new versions of the transaction issued by other parties.
        for (int i = 0; i < tx.getInputs().size(); i++)
          if (i != inputIndex) tx.getInputs().get(i).setSequenceNumber(0);
      } else if ((sigHashType & 0x1f) == (Transaction.SigHash.SINGLE.ordinal() + 1)) {
        // SIGHASH_SINGLE means only sign the output at the same index as the input (ie, my output).
        if (inputIndex >= tx.getOutputs().size()) {
          // The input index is beyond the number of outputs, it's a buggy signature made by a
          // broken
          // Bitcoin implementation. The reference client also contains a bug in handling this case:
          // any transaction output that is signed in this case will result in both the signed
          // output
          // and any future outputs to this public key being steal-able by anyone who has
          // the resulting signature and the public key (both of which are part of the signed tx
          // input).
          // Put the transaction back to how we found it.
          //
          // TODO: Only allow this to happen if we are checking a signature, not signing a
          // transactions
          for (int i = 0; i < tx.getInputs().size(); i++) {
            // tx.getInputs().get(i).setScriptSig(inputScripts[i]);
            /*                        tx.getInputs().get(i).setScriptSig(ScriptBuilder.createMultiSigInputScriptBytes(
            Arrays.asList(inputScripts[i])));*/
            tx.getInput(i).setScriptSig(new Script(inputScripts[i]));
            tx.getInputs().get(i).setSequenceNumber(inputSequenceNumbers[i]);
          }
          // this.outputs = outputs;

          // Satoshis bug is that SignatureHash was supposed to return a hash and on this codepath
          // it
          // actually returns the constant "1" to indicate an error, which is never checked for.
          // Oops.
          return Utils.HEX.decode(
              "0100000000000000000000000000000000000000000000000000000000000000");
        }

        // In SIGHASH_SINGLE the outputs after the matching input index are deleted, and the outputs
        // before
        // that position are "nulled out". Unintuitively, the value in a "null" transaction is set
        // to -1.
        /*                this.outputs = new ArrayList<TransactionOutput>(this.outputs.subList(0, inputIndex + 1));
        for (int i = 0; i < inputIndex; i++)
            this.outputs.set(i, new TransactionOutput(params, this, Coin.NEGATIVE_SATOSHI, new byte[] {}));
        // The signature isn't broken by new versions of the transaction issued by other parties.
        for (int i = 0; i < inputs.size(); i++)
            if (i != inputIndex)
                inputs.get(i).setSequenceNumber(0);*/
        // In SIGHASH_SINGLE the outputs after the matching input index are deleted, and the outputs
        // before
        // that position are "nulled out". Unintuitively, the value in a "null" transaction is set
        // to -1.
        // tx.outputs = new ArrayList<TransactionOutput>(tx.getOutputs().subList(0, inputIndex +
        // 1));
        tx.clearOutputs();
        for (int i = 0; i <= inputIndex; i++)
          if (i == inputIndex) {
            // need to make sure the output at inputIndex stays the same
            tx.addOutput(spendingTx.getOutput(inputIndex));
          } else {
            // this.outputs.set(i, new TransactionOutput(params, this, Coin.NEGATIVE_SATOSHI, new
            // byte[] {}));
            tx.addOutput(new TransactionOutput(params, tx, Coin.NEGATIVE_SATOSHI, new byte[] {}));
          }

        // The signature isn't broken by new versions of the transaction issued by other parties.
        for (int i = 0; i < tx.getInputs().size(); i++)
          if (i != inputIndex) tx.getInputs().get(i).setSequenceNumber(0);
      }

      List<TransactionInput> inputs = tx.getInputs();
      if ((sigHashType & (byte) 0x80) == 0x80) {
        // SIGHASH_ANYONECANPAY means the signature in the input is not broken by
        // changes/additions/removals
        // of other inputs. For example, this is useful for building assurance contracts.
        tx.clearInputs();
        tx.getInputs().add(input);
      }

      ByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(256);
      tx.bitcoinSerialize(bos);
      // We also have to write a hash type (sigHashType is actually an unsigned char)
      uint32ToByteStreamLE(0x000000ff & sigHashType, bos);
      // Note that this is NOT reversed to ensure it will be signed correctly. If it were to be
      // printed out
      // however then we would expect that it is IS reversed.
      byte[] txSignatureBytes = bos.toByteArray();
      bos.close();

      // Put the transaction back to how we found it.
      // tx.inputs = inputs;
      tx.clearInputs();
      for (int i = 0; i < inputs.size(); i++) {
        tx.addInput(inputs.get(i));
      }
      for (int i = 0; i < inputs.size(); i++) {
        inputs.get(i).setScriptSig(new Script(inputScripts[i]));
        inputs.get(i).setSequenceNumber(inputSequenceNumbers[i]);
      }
      // this.outputs = outputs;
      tx.clearOutputs();
      for (int i = 0; i < outputs.size(); i++) {
        tx.addOutput(outputs.get(i));
      }
      return txSignatureBytes;
    } catch (IOException e) {
      throw new RuntimeException(e); // Cannot happen.
    }
  }
  private static Protos.Transaction makeTxProto(WalletTransaction wtx) {
    Transaction tx = wtx.getTransaction();
    Protos.Transaction.Builder txBuilder = Protos.Transaction.newBuilder();

    txBuilder
        .setPool(getProtoPool(wtx))
        .setHash(hashToByteString(tx.getHash()))
        .setVersion((int) tx.getVersion());

    if (tx.getUpdateTime() != null) {
      txBuilder.setUpdatedAt(tx.getUpdateTime().getTime());
    }

    if (tx.getLockTime() > 0) {
      txBuilder.setLockTime((int) tx.getLockTime());
    }

    // Handle inputs.
    for (TransactionInput input : tx.getInputs()) {
      Protos.TransactionInput.Builder inputBuilder =
          Protos.TransactionInput.newBuilder()
              .setScriptBytes(ByteString.copyFrom(input.getScriptBytes()))
              .setTransactionOutPointHash(hashToByteString(input.getOutpoint().getHash()))
              .setTransactionOutPointIndex((int) input.getOutpoint().getIndex());
      if (input.hasSequence()) inputBuilder.setSequence((int) input.getSequenceNumber());
      if (input.getValue() != null) inputBuilder.setValue(input.getValue().value);
      txBuilder.addTransactionInput(inputBuilder);
    }

    // Handle outputs.
    for (TransactionOutput output : tx.getOutputs()) {
      Protos.TransactionOutput.Builder outputBuilder =
          Protos.TransactionOutput.newBuilder()
              .setScriptBytes(ByteString.copyFrom(output.getScriptBytes()))
              .setValue(output.getValue().value);
      final TransactionInput spentBy = output.getSpentBy();
      if (spentBy != null) {
        Sha256Hash spendingHash = spentBy.getParentTransaction().getHash();
        int spentByTransactionIndex = spentBy.getParentTransaction().getInputs().indexOf(spentBy);
        outputBuilder
            .setSpentByTransactionHash(hashToByteString(spendingHash))
            .setSpentByTransactionIndex(spentByTransactionIndex);
      }
      txBuilder.addTransactionOutput(outputBuilder);
    }

    // Handle which blocks tx was seen in.
    final Map<Sha256Hash, Integer> appearsInHashes = tx.getAppearsInHashes();
    if (appearsInHashes != null) {
      for (Map.Entry<Sha256Hash, Integer> entry : appearsInHashes.entrySet()) {
        txBuilder.addBlockHash(hashToByteString(entry.getKey()));
        txBuilder.addBlockRelativityOffsets(entry.getValue());
      }
    }

    if (tx.hasConfidence()) {
      TransactionConfidence confidence = tx.getConfidence();
      Protos.TransactionConfidence.Builder confidenceBuilder =
          Protos.TransactionConfidence.newBuilder();
      writeConfidence(txBuilder, confidence, confidenceBuilder);
    }

    Protos.Transaction.Purpose purpose;
    switch (tx.getPurpose()) {
      case UNKNOWN:
        purpose = Protos.Transaction.Purpose.UNKNOWN;
        break;
      case USER_PAYMENT:
        purpose = Protos.Transaction.Purpose.USER_PAYMENT;
        break;
      case KEY_ROTATION:
        purpose = Protos.Transaction.Purpose.KEY_ROTATION;
        break;
      case ASSURANCE_CONTRACT_CLAIM:
        purpose = Protos.Transaction.Purpose.ASSURANCE_CONTRACT_CLAIM;
        break;
      case ASSURANCE_CONTRACT_PLEDGE:
        purpose = Protos.Transaction.Purpose.ASSURANCE_CONTRACT_PLEDGE;
        break;
      case ASSURANCE_CONTRACT_STUB:
        purpose = Protos.Transaction.Purpose.ASSURANCE_CONTRACT_STUB;
        break;
      default:
        throw new RuntimeException("New tx purpose serialization not implemented.");
    }
    txBuilder.setPurpose(purpose);

    ExchangeRate exchangeRate = tx.getExchangeRate();
    if (exchangeRate != null) {
      Protos.ExchangeRate.Builder exchangeRateBuilder =
          Protos.ExchangeRate.newBuilder()
              .setCoinValue(exchangeRate.coin.value)
              .setFiatValue(exchangeRate.fiat.value)
              .setFiatCurrencyCode(exchangeRate.fiat.currencyCode);
      txBuilder.setExchangeRate(exchangeRateBuilder);
    }

    if (tx.getMemo() != null) txBuilder.setMemo(tx.getMemo());

    return txBuilder.build();
  }