Search in sources :

Example 1 with TransactionInput

use of org.bitcoinj.core.TransactionInput in project bitcoin-wallet by bitcoin-wallet.

the class SweepWalletFragment method requestWalletBalance.

private void requestWalletBalance() {
    ProgressDialogFragment.showProgress(fragmentManager, getString(R.string.sweep_wallet_fragment_request_wallet_balance_progress));
    final RequestWalletBalanceTask.ResultCallback callback = new RequestWalletBalanceTask.ResultCallback() {

        @Override
        public void onResult(final Set<UTXO> utxos) {
            ProgressDialogFragment.dismissProgress(fragmentManager);
            // Filter UTXOs we've already spent and sort the rest.
            final Set<Transaction> walletTxns = application.getWallet().getTransactions(false);
            final Set<UTXO> sortedUtxos = new TreeSet<>(UTXO_COMPARATOR);
            for (final UTXO utxo : utxos) if (!utxoSpentBy(walletTxns, utxo))
                sortedUtxos.add(utxo);
            // Fake transaction funding the wallet to sweep.
            final Map<Sha256Hash, Transaction> fakeTxns = new HashMap<>();
            for (final UTXO utxo : sortedUtxos) {
                Transaction fakeTx = fakeTxns.get(utxo.getHash());
                if (fakeTx == null) {
                    fakeTx = new FakeTransaction(Constants.NETWORK_PARAMETERS, utxo.getHash());
                    fakeTx.getConfidence().setConfidenceType(ConfidenceType.BUILDING);
                    fakeTxns.put(fakeTx.getHash(), fakeTx);
                }
                final TransactionOutput fakeOutput = new TransactionOutput(Constants.NETWORK_PARAMETERS, fakeTx, utxo.getValue(), utxo.getScript().getProgram());
                // Fill with output dummies as needed.
                while (fakeTx.getOutputs().size() < utxo.getIndex()) fakeTx.addOutput(new TransactionOutput(Constants.NETWORK_PARAMETERS, fakeTx, Coin.NEGATIVE_SATOSHI, new byte[] {}));
                // Add the actual output we will spend later.
                fakeTx.addOutput(fakeOutput);
            }
            walletToSweep.clearTransactions(0);
            for (final Transaction tx : fakeTxns.values()) walletToSweep.addWalletTransaction(new WalletTransaction(WalletTransaction.Pool.UNSPENT, tx));
            log.info("built wallet to sweep:\n{}", walletToSweep.toString(false, true, false, null));
            updateView();
        }

        private boolean utxoSpentBy(final Set<Transaction> transactions, final UTXO utxo) {
            for (final Transaction tx : transactions) {
                for (final TransactionInput input : tx.getInputs()) {
                    final TransactionOutPoint outpoint = input.getOutpoint();
                    if (outpoint.getHash().equals(utxo.getHash()) && outpoint.getIndex() == utxo.getIndex())
                        return true;
                }
            }
            return false;
        }

        @Override
        public void onFail(final int messageResId, final Object... messageArgs) {
            ProgressDialogFragment.dismissProgress(fragmentManager);
            final DialogBuilder dialog = DialogBuilder.warn(activity, R.string.sweep_wallet_fragment_request_wallet_balance_failed_title);
            dialog.setMessage(getString(messageResId, messageArgs));
            dialog.setPositiveButton(R.string.button_retry, new DialogInterface.OnClickListener() {

                @Override
                public void onClick(final DialogInterface dialog, final int which) {
                    requestWalletBalance();
                }
            });
            dialog.setNegativeButton(R.string.button_dismiss, null);
            dialog.show();
        }
    };
    final Address address = walletToSweep.getImportedKeys().iterator().next().toAddress(Constants.NETWORK_PARAMETERS);
    new RequestWalletBalanceTask(backgroundHandler, callback).requestWalletBalance(activity.getAssets(), address);
}
Also used : Set(java.util.Set) TreeSet(java.util.TreeSet) TransactionOutput(org.bitcoinj.core.TransactionOutput) Address(org.bitcoinj.core.Address) HashMap(java.util.HashMap) DialogInterface(android.content.DialogInterface) Sha256Hash(org.bitcoinj.core.Sha256Hash) TransactionInput(org.bitcoinj.core.TransactionInput) TransactionOutPoint(org.bitcoinj.core.TransactionOutPoint) UTXO(org.bitcoinj.core.UTXO) Transaction(org.bitcoinj.core.Transaction) WalletTransaction(org.bitcoinj.wallet.WalletTransaction) TreeSet(java.util.TreeSet) WalletTransaction(org.bitcoinj.wallet.WalletTransaction) DialogBuilder(de.schildbach.wallet.ui.DialogBuilder) TransactionOutPoint(org.bitcoinj.core.TransactionOutPoint)

Example 2 with TransactionInput

use of org.bitcoinj.core.TransactionInput in project bisq-core by bisq-network.

the class WalletService method getOutputsWithConnectedOutputs.

protected List<TransactionOutput> getOutputsWithConnectedOutputs(Transaction tx) {
    List<TransactionOutput> transactionOutputs = tx.getOutputs();
    List<TransactionOutput> connectedOutputs = new ArrayList<>();
    // add all connected outputs from any inputs as well
    List<TransactionInput> transactionInputs = tx.getInputs();
    for (TransactionInput transactionInput : transactionInputs) {
        TransactionOutput transactionOutput = transactionInput.getConnectedOutput();
        if (transactionOutput != null) {
            connectedOutputs.add(transactionOutput);
        }
    }
    List<TransactionOutput> mergedOutputs = new ArrayList<>();
    mergedOutputs.addAll(transactionOutputs);
    mergedOutputs.addAll(connectedOutputs);
    return mergedOutputs;
}
Also used : TransactionOutput(org.bitcoinj.core.TransactionOutput) ArrayList(java.util.ArrayList) TransactionInput(org.bitcoinj.core.TransactionInput)

Example 3 with TransactionInput

use of org.bitcoinj.core.TransactionInput in project bisq-core by bisq-network.

the class BsqWalletService method getPreparedVoteRevealTx.

// /////////////////////////////////////////////////////////////////////////////////////////
// MyVote reveal tx
// /////////////////////////////////////////////////////////////////////////////////////////
public Transaction getPreparedVoteRevealTx(TxOutput stakeTxOutput) {
    Transaction tx = new Transaction(params);
    final Coin stake = Coin.valueOf(stakeTxOutput.getValue());
    Transaction connectedOutputParentTransaction = getTransaction(stakeTxOutput.getTxId());
    TransactionOutPoint transactionOutPoint = new TransactionOutPoint(params, stakeTxOutput.getIndex(), connectedOutputParentTransaction);
    tx.addInput(new TransactionInput(params, tx, new byte[] {}, transactionOutPoint, stake));
    tx.addOutput(new TransactionOutput(params, tx, stake, getUnusedAddress()));
    printTx("getPreparedVoteRevealTx", tx);
    return tx;
}
Also used : Coin(org.bitcoinj.core.Coin) TransactionOutput(org.bitcoinj.core.TransactionOutput) Transaction(org.bitcoinj.core.Transaction) TransactionOutPoint(org.bitcoinj.core.TransactionOutPoint) TransactionInput(org.bitcoinj.core.TransactionInput)

Example 4 with TransactionInput

use of org.bitcoinj.core.TransactionInput in project bisq-core by bisq-network.

the class BtcWalletService method completePreparedBlindVoteTx.

// /////////////////////////////////////////////////////////////////////////////////////////
// Blind vote tx
// /////////////////////////////////////////////////////////////////////////////////////////
public Transaction completePreparedBlindVoteTx(Transaction feeTx, byte[] opReturnData) throws TransactionVerificationException, WalletException, InsufficientMoneyException {
    // (BsqFee)tx has following structure:
    // inputs [1-n] BSQ inputs (fee + stake)
    // outputs [1] BSQ stake
    // outputs [0-1] BSQ change output (>= 2730 Satoshi)
    // preparedVoteTx has following structure:
    // inputs [1-n] BSQ inputs for vote fee
    // inputs [1-n] BTC inputs for miner fee
    // outputs [1] BSQ stake
    // outputs [0-1] BSQ change output (>= 2730 Satoshi)
    // outputs [0-1] BTC change output from miner fee inputs (>= 2730 Satoshi)
    // outputs [0-1] OP_RETURN with opReturnData and amount 0
    // mining fee: BTC mining fee + burned BSQ fee
    Transaction preparedTx = new Transaction(params);
    // Copy inputs from BSQ fee tx
    feeTx.getInputs().forEach(preparedTx::addInput);
    int indexOfBtcFirstInput = feeTx.getInputs().size();
    // BSQ change outputs from BSQ fee inputs.
    feeTx.getOutputs().forEach(preparedTx::addOutput);
    // safety check counter to avoid endless loops
    int counter = 0;
    // estimated size of input sig
    final int sigSizePerInput = 106;
    // typical size for a tx with 3 inputs
    int txSizeWithUnsignedInputs = 300;
    final Coin txFeePerByte = feeService.getTxFeePerByte();
    Address changeAddress = getOrCreateAddressEntry(AddressEntry.Context.AVAILABLE).getAddress();
    checkNotNull(changeAddress, "changeAddress must not be null");
    final BtcCoinSelector coinSelector = new BtcCoinSelector(walletsSetup.getAddressesByContext(AddressEntry.Context.AVAILABLE));
    final List<TransactionInput> preparedBsqTxInputs = preparedTx.getInputs();
    final List<TransactionOutput> preparedBsqTxOutputs = preparedTx.getOutputs();
    int numInputs = preparedBsqTxInputs.size();
    Transaction resultTx = null;
    boolean isFeeOutsideTolerance;
    do {
        counter++;
        if (counter >= 10) {
            checkNotNull(resultTx, "resultTx must not be null");
            log.error("Could not calculate the fee. Tx=" + resultTx);
            break;
        }
        Transaction tx = new Transaction(params);
        preparedBsqTxInputs.forEach(tx::addInput);
        preparedBsqTxOutputs.forEach(tx::addOutput);
        SendRequest sendRequest = SendRequest.forTx(tx);
        sendRequest.shuffleOutputs = false;
        sendRequest.aesKey = aesKey;
        // signInputs needs to be false as it would try to sign all inputs (BSQ inputs are not in this wallet)
        sendRequest.signInputs = false;
        sendRequest.fee = txFeePerByte.multiply(txSizeWithUnsignedInputs + sigSizePerInput * numInputs);
        sendRequest.feePerKb = Coin.ZERO;
        sendRequest.ensureMinRequiredFee = false;
        sendRequest.coinSelector = coinSelector;
        sendRequest.changeAddress = changeAddress;
        wallet.completeTx(sendRequest);
        resultTx = sendRequest.tx;
        // add OP_RETURN output
        resultTx.addOutput(new TransactionOutput(params, resultTx, Coin.ZERO, ScriptBuilder.createOpReturnScript(opReturnData).getProgram()));
        numInputs = resultTx.getInputs().size();
        txSizeWithUnsignedInputs = resultTx.bitcoinSerialize().length;
        final long estimatedFeeAsLong = txFeePerByte.multiply(txSizeWithUnsignedInputs + sigSizePerInput * numInputs).value;
        // calculated fee must be inside of a tolerance range with tx fee
        isFeeOutsideTolerance = Math.abs(resultTx.getFee().value - estimatedFeeAsLong) > 1000;
    } while (isFeeOutsideTolerance);
    // Sign all BTC inputs
    for (int i = indexOfBtcFirstInput; i < resultTx.getInputs().size(); i++) {
        TransactionInput txIn = resultTx.getInputs().get(i);
        checkArgument(txIn.getConnectedOutput() != null && txIn.getConnectedOutput().isMine(wallet), "txIn.getConnectedOutput() is not in our wallet. That must not happen.");
        signTransactionInput(wallet, aesKey, resultTx, txIn, i);
        checkScriptSig(resultTx, txIn, i);
    }
    checkWalletConsistency(wallet);
    verifyTransaction(resultTx);
    printTx("BTC wallet: Signed tx", resultTx);
    return resultTx;
}
Also used : TransactionOutput(org.bitcoinj.core.TransactionOutput) SendRequest(org.bitcoinj.wallet.SendRequest) Address(org.bitcoinj.core.Address) TransactionOutPoint(org.bitcoinj.core.TransactionOutPoint) TransactionInput(org.bitcoinj.core.TransactionInput) Coin(org.bitcoinj.core.Coin) Transaction(org.bitcoinj.core.Transaction)

Example 5 with TransactionInput

use of org.bitcoinj.core.TransactionInput in project bisq-core by bisq-network.

the class TradeWalletService method emergencySignAndPublishPayoutTx.

// Emergency payout tool. Used only in cased when the payput from the arbitrator does not work because some data
// in the trade/dispute are messed up.
// We keep here arbitratorPayoutAmount just in case (requires cooperation from peer anyway)
public Transaction emergencySignAndPublishPayoutTx(String depositTxHex, Coin buyerPayoutAmount, Coin sellerPayoutAmount, Coin arbitratorPayoutAmount, Coin txFee, String buyerAddressString, String sellerAddressString, String arbitratorAddressString, @Nullable String buyerPrivateKeyAsHex, @Nullable String sellerPrivateKeyAsHex, String arbitratorPrivateKeyAsHex, String buyerPubKeyAsHex, String sellerPubKeyAsHex, String arbitratorPubKeyAsHex, String P2SHMultiSigOutputScript, FutureCallback<Transaction> callback) throws AddressFormatException, TransactionVerificationException, WalletException {
    log.info("signAndPublishPayoutTx called");
    log.info("depositTxHex " + depositTxHex);
    log.info("buyerPayoutAmount " + buyerPayoutAmount.toFriendlyString());
    log.info("sellerPayoutAmount " + sellerPayoutAmount.toFriendlyString());
    log.info("arbitratorPayoutAmount " + arbitratorPayoutAmount.toFriendlyString());
    log.info("buyerAddressString " + buyerAddressString);
    log.info("sellerAddressString " + sellerAddressString);
    log.info("arbitratorAddressString " + arbitratorAddressString);
    log.info("buyerPrivateKeyAsHex (not displayed for security reasons)");
    log.info("sellerPrivateKeyAsHex (not displayed for security reasons)");
    log.info("arbitratorPrivateKeyAsHex (not displayed for security reasons)");
    log.info("buyerPubKeyAsHex " + buyerPubKeyAsHex);
    log.info("sellerPubKeyAsHex " + sellerPubKeyAsHex);
    log.info("arbitratorPubKeyAsHex " + arbitratorPubKeyAsHex);
    log.info("P2SHMultiSigOutputScript " + P2SHMultiSigOutputScript);
    checkNotNull((buyerPrivateKeyAsHex != null || sellerPrivateKeyAsHex != null), "either buyerPrivateKeyAsHex or sellerPrivateKeyAsHex must not be null");
    byte[] buyerPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(buyerPubKeyAsHex)).getPubKey();
    byte[] sellerPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(sellerPubKeyAsHex)).getPubKey();
    final byte[] arbitratorPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(arbitratorPubKeyAsHex)).getPubKey();
    Script p2SHMultiSigOutputScript = getP2SHMultiSigOutputScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
    Coin msOutput = buyerPayoutAmount.add(sellerPayoutAmount).add(arbitratorPayoutAmount).add(txFee);
    TransactionOutput p2SHMultiSigOutput = new TransactionOutput(params, null, msOutput, p2SHMultiSigOutputScript.getProgram());
    Transaction depositTx = new Transaction(params);
    depositTx.addOutput(p2SHMultiSigOutput);
    Transaction payoutTx = new Transaction(params);
    Sha256Hash spendTxHash = Sha256Hash.wrap(depositTxHex);
    payoutTx.addInput(new TransactionInput(params, depositTx, p2SHMultiSigOutputScript.getProgram(), new TransactionOutPoint(params, 0, spendTxHash), msOutput));
    if (buyerPayoutAmount.isGreaterThan(Coin.ZERO))
        payoutTx.addOutput(buyerPayoutAmount, Address.fromBase58(params, buyerAddressString));
    if (sellerPayoutAmount.isGreaterThan(Coin.ZERO))
        payoutTx.addOutput(sellerPayoutAmount, Address.fromBase58(params, sellerAddressString));
    if (arbitratorPayoutAmount.isGreaterThan(Coin.ZERO))
        payoutTx.addOutput(arbitratorPayoutAmount, Address.fromBase58(params, arbitratorAddressString));
    // take care of sorting!
    Script redeemScript = getMultiSigRedeemScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
    Sha256Hash sigHash = payoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
    ECKey.ECDSASignature tradersSignature;
    if (buyerPrivateKeyAsHex != null && !buyerPrivateKeyAsHex.isEmpty()) {
        final ECKey buyerPrivateKey = ECKey.fromPrivate(Utils.HEX.decode(buyerPrivateKeyAsHex));
        checkNotNull(buyerPrivateKey, "buyerPrivateKey must not be null");
        tradersSignature = buyerPrivateKey.sign(sigHash, aesKey).toCanonicalised();
    } else {
        checkNotNull(sellerPrivateKeyAsHex, "sellerPrivateKeyAsHex must not be null");
        final ECKey sellerPrivateKey = ECKey.fromPrivate(Utils.HEX.decode(sellerPrivateKeyAsHex));
        checkNotNull(sellerPrivateKey, "sellerPrivateKey must not be null");
        tradersSignature = sellerPrivateKey.sign(sigHash, aesKey).toCanonicalised();
    }
    final ECKey key = ECKey.fromPrivate(Utils.HEX.decode(arbitratorPrivateKeyAsHex));
    checkNotNull(key, "key must not be null");
    ECKey.ECDSASignature arbitratorSignature = key.sign(sigHash, aesKey).toCanonicalised();
    TransactionSignature tradersTxSig = new TransactionSignature(tradersSignature, Transaction.SigHash.ALL, false);
    TransactionSignature arbitratorTxSig = new TransactionSignature(arbitratorSignature, Transaction.SigHash.ALL, false);
    // Take care of order of signatures. See comment below at getMultiSigRedeemScript (sort order needed here: arbitrator, seller, buyer)
    Script inputScript = ScriptBuilder.createP2SHMultiSigInputScript(ImmutableList.of(arbitratorTxSig, tradersTxSig), redeemScript);
    TransactionInput input = payoutTx.getInput(0);
    input.setScriptSig(inputScript);
    WalletService.printTx("payoutTx", payoutTx);
    WalletService.verifyTransaction(payoutTx);
    WalletService.checkWalletConsistency(wallet);
    broadcastTx(payoutTx, callback, 20);
    return payoutTx;
}
Also used : Script(org.bitcoinj.script.Script) Coin(org.bitcoinj.core.Coin) TransactionOutput(org.bitcoinj.core.TransactionOutput) Transaction(org.bitcoinj.core.Transaction) Sha256Hash(org.bitcoinj.core.Sha256Hash) ECKey(org.bitcoinj.core.ECKey) TransactionSignature(org.bitcoinj.crypto.TransactionSignature) RawTransactionInput(bisq.core.btc.data.RawTransactionInput) TransactionInput(org.bitcoinj.core.TransactionInput) TransactionOutPoint(org.bitcoinj.core.TransactionOutPoint)

Aggregations

TransactionInput (org.bitcoinj.core.TransactionInput)36 Transaction (org.bitcoinj.core.Transaction)29 TransactionOutput (org.bitcoinj.core.TransactionOutput)20 TransactionOutPoint (org.bitcoinj.core.TransactionOutPoint)18 Script (org.bitcoinj.script.Script)16 ECKey (org.bitcoinj.core.ECKey)11 HashMap (java.util.HashMap)10 Address (org.bitcoinj.core.Address)9 Coin (org.bitcoinj.core.Coin)9 ArrayList (java.util.ArrayList)7 AddressFormatException (org.bitcoinj.core.AddressFormatException)7 RawTransactionInput (bisq.core.btc.data.RawTransactionInput)6 TransactionSignature (org.bitcoinj.crypto.TransactionSignature)6 ScriptException (org.bitcoinj.script.ScriptException)6 MyTransactionOutPoint (com.samourai.wallet.send.MyTransactionOutPoint)5 IOException (java.io.IOException)5 Sha256Hash (org.bitcoinj.core.Sha256Hash)5 MnemonicException (org.bitcoinj.crypto.MnemonicException)5 SendRequest (org.bitcoinj.wallet.SendRequest)5 BlockedUTXO (com.samourai.wallet.send.BlockedUTXO)4