/**
  * When the servers signature for the refund transaction is received, call this to verify it and
  * sign the complete refund ourselves.
  *
  * <p>If this does not throw an exception, we are secure against the loss of funds and can safely
  * provide the server with the multi-sig contract to lock in the agreement. In this case, both the
  * multisig contract and the refund transaction are automatically committed to wallet so that it
  * can handle broadcasting the refund transaction at the appropriate time if necessary.
  */
 public synchronized void provideRefundSignature(byte[] theirSignature)
     throws VerificationException {
   checkNotNull(theirSignature);
   checkState(state == State.WAITING_FOR_SIGNED_REFUND);
   TransactionSignature theirSig = TransactionSignature.decodeFromBitcoin(theirSignature, true);
   if (theirSig.sigHashMode() != Transaction.SigHash.NONE || !theirSig.anyoneCanPay())
     throw new VerificationException("Refund signature was not SIGHASH_NONE|SIGHASH_ANYONECANPAY");
   // Sign the refund transaction ourselves.
   final TransactionOutput multisigContractOutput = multisigContract.getOutput(0);
   try {
     multisigScript = multisigContractOutput.getScriptPubKey();
   } catch (ScriptException e) {
     throw new RuntimeException(e); // Cannot happen: we built this ourselves.
   }
   TransactionSignature ourSignature =
       refundTx.calculateSignature(0, myKey, multisigScript, Transaction.SigHash.ALL, false);
   // Insert the signatures.
   Script scriptSig = ScriptBuilder.createMultiSigInputScript(ourSignature, theirSig);
   log.info("Refund scriptSig: {}", scriptSig);
   log.info("Multi-sig contract scriptPubKey: {}", multisigScript);
   TransactionInput refundInput = refundTx.getInput(0);
   refundInput.setScriptSig(scriptSig);
   refundInput.verify(multisigContractOutput);
   state = State.SAVE_STATE_IN_WALLET;
 }
 /** Returns true if the tx is a valid settlement transaction. */
 public synchronized boolean isSettlementTransaction(Transaction tx) {
   try {
     tx.verify();
     tx.getInput(0).verify(multisigContract.getOutput(0));
     return true;
   } catch (VerificationException e) {
     return false;
   }
 }
Ejemplo n.º 3
0
  private WalletTransaction connectTransactionOutputs(
      org.bitcoinj.wallet.Protos.Transaction txProto) {
    Transaction tx = txMap.get(txProto.getHash());
    WalletTransaction.Pool pool = WalletTransaction.Pool.valueOf(txProto.getPool().getNumber());
    if (pool == WalletTransaction.Pool.INACTIVE
        || pool == WalletTransaction.Pool.PENDING_INACTIVE) {
      // 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.
      pool = WalletTransaction.Pool.PENDING;
    }
    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 IllegalArgumentException(
              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);
  }