Search in sources :

Example 1 with KeyBag

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

the class WalletService method signTransactionInput.

// /////////////////////////////////////////////////////////////////////////////////////////
// Sign tx
// /////////////////////////////////////////////////////////////////////////////////////////
public static void signTransactionInput(Wallet wallet, KeyParameter aesKey, Transaction tx, TransactionInput txIn, int index) {
    KeyBag maybeDecryptingKeyBag = new DecryptingKeyBag(wallet, aesKey);
    if (txIn.getConnectedOutput() != null) {
        try {
            // We assume if its already signed, its hopefully got a SIGHASH type that will not invalidate when
            // we sign missing pieces (to check this would require either assuming any signatures are signing
            // standard output types or a way to get processed signatures out of script execution)
            txIn.getScriptSig().correctlySpends(tx, index, txIn.getConnectedOutput().getScriptPubKey(), Script.ALL_VERIFY_FLAGS);
            log.warn("Input {} already correctly spends output, assuming SIGHASH type used will be safe and skipping signing.", index);
            return;
        } catch (ScriptException e) {
        // Expected.
        }
        Script scriptPubKey = txIn.getConnectedOutput().getScriptPubKey();
        RedeemData redeemData = txIn.getConnectedRedeemData(maybeDecryptingKeyBag);
        checkNotNull(redeemData, "Transaction exists in wallet that we cannot redeem: %s", txIn.getOutpoint().getHash());
        txIn.setScriptSig(scriptPubKey.createEmptyInputScript(redeemData.keys.get(0), redeemData.redeemScript));
        TransactionSigner.ProposedTransaction propTx = new TransactionSigner.ProposedTransaction(tx);
        Transaction partialTx = propTx.partialTx;
        txIn = partialTx.getInput(index);
        if (txIn.getConnectedOutput() != null) {
            // If we dont have a sig we don't do the check to avoid error reports of failed sig checks
            final List<ScriptChunk> chunks = txIn.getConnectedOutput().getScriptPubKey().getChunks();
            if (!chunks.isEmpty() && chunks.get(0).data != null && chunks.get(0).data.length > 0) {
                try {
                    // We assume if its already signed, its hopefully got a SIGHASH type that will not invalidate when
                    // we sign missing pieces (to check this would require either assuming any signatures are signing
                    // standard output types or a way to get processed signatures out of script execution)
                    txIn.getScriptSig().correctlySpends(tx, index, txIn.getConnectedOutput().getScriptPubKey(), Script.ALL_VERIFY_FLAGS);
                    log.warn("Input {} already correctly spends output, assuming SIGHASH type used will be safe and skipping signing.", index);
                    return;
                } catch (ScriptException e) {
                // Expected.
                }
            }
            redeemData = txIn.getConnectedRedeemData(maybeDecryptingKeyBag);
            scriptPubKey = txIn.getConnectedOutput().getScriptPubKey();
            checkNotNull(redeemData, "redeemData must not be null");
            ECKey pubKey = redeemData.keys.get(0);
            if (pubKey instanceof DeterministicKey)
                propTx.keyPaths.put(scriptPubKey, (((DeterministicKey) pubKey).getPath()));
            ECKey key;
            if ((key = redeemData.getFullKey()) == null) {
                log.warn("No local key found for input {}", index);
                return;
            }
            Script inputScript = txIn.getScriptSig();
            byte[] script = redeemData.redeemScript.getProgram();
            try {
                TransactionSignature signature = partialTx.calculateSignature(index, key, script, Transaction.SigHash.ALL, false);
                inputScript = scriptPubKey.getScriptSigWithSignature(inputScript, signature.encodeToBitcoin(), 0);
                txIn.setScriptSig(inputScript);
            } catch (ECKey.KeyIsEncryptedException e1) {
                throw e1;
            } catch (ECKey.MissingPrivateKeyException e1) {
                log.warn("No private key in keypair for input {}", index);
            }
        } else {
            log.warn("Missing connected output, assuming input {} is already signed.", index);
        }
    } else {
        log.error("Missing connected output, assuming already signed.");
    }
}
Also used : Script(org.bitcoinj.script.Script) TransactionSigner(org.bitcoinj.signers.TransactionSigner) ECKey(org.bitcoinj.core.ECKey) TransactionSignature(org.bitcoinj.crypto.TransactionSignature) KeyBag(org.bitcoinj.wallet.KeyBag) DecryptingKeyBag(org.bitcoinj.wallet.DecryptingKeyBag) RedeemData(org.bitcoinj.wallet.RedeemData) ScriptChunk(org.bitcoinj.script.ScriptChunk) DecryptingKeyBag(org.bitcoinj.wallet.DecryptingKeyBag) ScriptException(org.bitcoinj.core.ScriptException) Transaction(org.bitcoinj.core.Transaction) DeterministicKey(org.bitcoinj.crypto.DeterministicKey)

Aggregations

ECKey (org.bitcoinj.core.ECKey)1 ScriptException (org.bitcoinj.core.ScriptException)1 Transaction (org.bitcoinj.core.Transaction)1 DeterministicKey (org.bitcoinj.crypto.DeterministicKey)1 TransactionSignature (org.bitcoinj.crypto.TransactionSignature)1 Script (org.bitcoinj.script.Script)1 ScriptChunk (org.bitcoinj.script.ScriptChunk)1 TransactionSigner (org.bitcoinj.signers.TransactionSigner)1 DecryptingKeyBag (org.bitcoinj.wallet.DecryptingKeyBag)1 KeyBag (org.bitcoinj.wallet.KeyBag)1 RedeemData (org.bitcoinj.wallet.RedeemData)1