<p>I'm not an expert in this field by any means (and my error message was different), but I spent last week trying to make Bitcoinj sign a transaction and send in raw form (i.e. without using transport protocol which Bitcoinj provides) and here's what I've learned (the hard way): You can't sign transactions like that. If you call <code>tx.addSignedInput</code> in a loop, <a href="https://github.com/bitcoinj/bitcoinj/issues/1302#issuecomment-259462443" rel="nofollow noreferrer">you'll corrupt transaction's signature and it's gonna to be invalid</a>. The solution (after brainstorming with my team and trying a few recipes here (<a href="https://bitcoin.stackexchange.com/a/48709/90286">this one</a> didn't work), at Bitcoin Stack Exchange) was <a href="https://bitcoin.stackexchange.com/a/63294/90286">add all Inputs to the transaction and then sign them manually</a>.</p>



<pre><code>Transaction tx = new Transaction(networkParams);
tx.addOutput(Coin.valueOf(amount), targetAddress);
addInputsToTransaction(sourceAddress, tx, unspents, amount);
signInputsOfTransaction(sourceAddress, tx, key);

tx.verify();
tx.getConfidence().setSource(TransactionConfidence.Source.SELF);
tx.setPurpose(Transaction.Purpose.USER_PAYMENT);
String valueToSend = byteArrayToHexString(tx.bitcoinSerialize());
</code></pre>

<p>and the methods:</p>



<pre><code>private void addInputsToTransaction(Address sourceAddress, Transaction tx, @NonNull BalanceResponse.Unspents[] unspents, Long amount) {
    long gatheredAmount = 0L;
    long requiredAmount = amount + TX_FEE;
    for (BalanceResponse.Unspents unspent : unspents) {
        gatheredAmount += unspent.getAmount();
        TransactionOutPoint outPoint = new TransactionOutPoint(networkParams, unspent.getvOut(), Sha256Hash.wrap(unspent.getTxId()));
        TransactionInput transactionInput = new TransactionInput(networkParams, tx, hexStringToByteArray(unspent.getScriptPubKey()),
                outPoint, Coin.valueOf(unspent.getAmount());
        tx.addInput(transactionInput);

        if (gatheredAmount &gt;= requiredAmount) {
            break;
        }
    }
    if (gatheredAmount &gt; requiredAmount) {
        //return change to sender, in real life it should use different address
        tx.addOutput(Coin.valueOf((gatheredAmount - requiredAmount)), sourceAddress);
    }
}

private void signInputsOfTransaction(Address sourceAddress, @NonNull Transaction tx, ECKey key) {
    for (int i = 0; i &lt; tx.getInputs().size(); i++) {
        Script scriptPubKey = ScriptBuilder.createOutputScript(sourceAddress);
        Sha256Hash hash = tx.hashForSignature(i, scriptPubKey, Transaction.SigHash.ALL, true);
        ECKey.ECDSASignature ecdsaSignature = key.sign(hash);
        TransactionSignature txSignature = new TransactionSignature(ecdsaSignature, Transaction.SigHash.ALL, true);

        if (ScriptPattern.isP2PK(scriptPubKey)) {
            tx.getInput(i).setScriptSig(ScriptBuilder.createInputScript(txSignature));
        } else {
            if (!ScriptPattern.isP2PKH(scriptPubKey)) {
                throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Unable to sign this scrptPubKey: " + scriptPubKey);
            }
            tx.getInput(i).setScriptSig(ScriptBuilder.createInputScript(txSignature, key));
        }
    }
}
</code></pre>

<p>I hope, it will help you.</p>

CC BY-SA 4.0
2020-12-19T20:43:01.983Z
Change true to false, it works for me. Sha256Hash hash = tx.hashForSignature(i, scriptPubKey, Transaction.SigHash.ALL, false);
        ECKey.ECDSASignature ecdsaSignature = key.sign(hash);
        TransactionSignature txSignature = new TransactionSignature(ecdsaSignature, Transaction.SigHash.ALL, false);
tiennv
CC BY-SA 4.0
2018-12-12T00:07:53.997Z
2019-05-10T19:58:40.370Z
2019-05-10T19:58:40.370Z
Oleg Kuznetsov
<pre><code>Transaction transaction = new Transaction(params);
    // 遍历未花费列表，组装合适的item

    double sum = 0;
    String address = null;
    List&lt;Unspent&gt; unspents = new ArrayList&lt;&gt;();
    Map&lt;String, AddrDTO&gt; keysMap = new HashMap&lt;&gt;();
    for (Unspent utxo : unSpentBTCList) {
        /*
         * if(!script.isSentToRawPubKey() &amp;&amp; !script.isSentToAddress()) {
         * logger.info("格式不對:" + utxo.address()); continue; }
         */
        AddrDTO addrDto = this.getAddrDTO(utxo.address());
        if (addrDto == null) {
            logger.info("address 找不到:" + utxo.address());
            continue;
        }
        keysMap.put(utxo.address(), addrDto);
        unspents.add(utxo);
        sum += utxo.amount();
        address = utxo.address();
        if (sum &gt;= amount) {
            break;// 停止。
        }
    }
    if (sum &lt; amount) {
        logger.error("余额不足");
        throw new RuntimeException("余额不足！");
    }

    long value = btc2Satoshi(amount);
    transaction.addOutput(Coin.valueOf(value), Address.fromBase58(params, to));
    // transaction.

    // 消费列表总金额 - 已经转账的金额 - 手续费 就等于需要返回给自己的金额了
    long longFee = btc2Satoshi(fee);
    long balance = btc2Satoshi(sum) - value - longFee;
    // 输出-转给自己
    if (balance &gt; 0) {
        transaction.addOutput(Coin.valueOf(balance), Address.fromBase58(params, address));
    }
    int i = 0;
    for (Unspent utxo : unspents) {
        AddrDTO addrDto = keysMap.get(utxo.address());
        logger.info("xxxxxxxxxx:" + utxo.txid() + ":" + addrDto.getAddress());
        DumpedPrivateKey dumpedPrivateKey = DumpedPrivateKey.fromBase58(params, addrDto.getPrivateKey());
        Script s = new Script(Hex.decode(utxo.scriptPubKey()));
        TransactionOutPoint outPoint = new TransactionOutPoint(params, i++, Sha256Hash.wrap(utxo.txid()));
        ECKey ecKey = dumpedPrivateKey.getKey();
        transaction.addSignedInput(outPoint, s, ecKey, Transaction.SigHash.ALL, true);
        logger.info("xxxxxxxxxx:" + utxo.amount());
    }
    String hex = Hex.toHexString(transaction.bitcoinSerialize());
    logger.info("bitcoinj hex = " + hex);
</code></pre>

<p>Error:</p>

<pre><code>Exception in thread "main" org.bitcoinj.core.ScriptException: Don't know how to sign for this kind of scriptPubKey: HASH160 PUSHDATA(20)[1a0a82f0669c14c6739e4cf1a5a3f221f657e28f] EQUAL
    at org.bitcoinj.core.Transaction.addSignedInput(Transaction.java:823)
    at com.idasex.bitcoin.BitcoinClient.signBTCTransactionData(BitcoinClient.java:337)
    at com.idasex.bitcoin.BitcoinClient.sendRawTx(BitcoinClient.java:274)
    at com.idasex.bitcoin.BitcoinClient.main(BitcoinClient.java:409)
</code></pre>

<raw-transaction><bitcoinj><signrawtransaction>
How do I sign and send a raw transaction using BitcoinJ?
Jon Chiang
# How do I sign and send a raw transaction using BitcoinJ?

(Asked by: username_0 on 2018-11-26)

```
Transaction transaction = new Transaction(params);
    // 遍历未花费列表，组装合适的item

    double sum = 0;
    String address = null;
    List<Unspent> unspents = new ArrayList<>();
    Map<String, AddrDTO> keysMap = new HashMap<>();
    for (Unspent utxo : unSpentBTCList) {
        /*
         * if(!script.isSentToRawPubKey() && !script.isSentToAddress()) {
         * logger.info("格式不對:" + utxo.address()); continue; }
         */
        AddrDTO addrDto = this.getAddrDTO(utxo.address());
        if (addrDto == null) {
            logger.info("address 找不到:" + utxo.address());
            continue;
        }
        keysMap.put(utxo.address(), addrDto);
        unspents.add(utxo);
        sum += utxo.amount();
        address = utxo.address();
        if (sum >= amount) {
            break;// 停止。
        }
    }
    if (sum < amount) {
        logger.error("余额不足");
        throw new RuntimeException("余额不足！");
    }

    long value = btc2Satoshi(amount);
    transaction.addOutput(Coin.valueOf(value), Address.fromBase58(params, to));
    // transaction.

    // 消费列表总金额 - 已经转账的金额 - 手续费 就等于需要返回给自己的金额了
    long longFee = btc2Satoshi(fee);
    long balance = btc2Satoshi(sum) - value - longFee;
    // 输出-转给自己
    if (balance > 0) {
        transaction.addOutput(Coin.valueOf(balance), Address.fromBase58(params, address));
    }
    int i = 0;
    for (Unspent utxo : unspents) {
        AddrDTO addrDto = keysMap.get(utxo.address());
        logger.info("xxxxxxxxxx:" + utxo.txid() + ":" + addrDto.getAddress());
        DumpedPrivateKey dumpedPrivateKey = DumpedPrivateKey.fromBase58(params, addrDto.getPrivateKey());
        Script s = new Script(Hex.decode(utxo.scriptPubKey()));
        TransactionOutPoint outPoint = new TransactionOutPoint(params, i++, Sha256Hash.wrap(utxo.txid()));
        ECKey ecKey = dumpedPrivateKey.getKey();
        transaction.addSignedInput(outPoint, s, ecKey, Transaction.SigHash.ALL, true);
        logger.info("xxxxxxxxxx:" + utxo.amount());
    }
    String hex = Hex.toHexString(transaction.bitcoinSerialize());
    logger.info("bitcoinj hex = " + hex);

```

Error:

```
Exception in thread "main" org.bitcoinj.core.ScriptException: Don't know how to sign for this kind of scriptPubKey: HASH160 PUSHDATA(20)[1a0a82f0669c14c6739e4cf1a5a3f221f657e28f] EQUAL
    at org.bitcoinj.core.Transaction.addSignedInput(Transaction.java:823)
    at com.idasex.bitcoin.BitcoinClient.signBTCTransactionData(BitcoinClient.java:337)
    at com.idasex.bitcoin.BitcoinClient.sendRawTx(BitcoinClient.java:274)
    at com.idasex.bitcoin.BitcoinClient.main(BitcoinClient.java:409)

```

**Tags:** raw-transaction, bitcoinj, signrawtransaction


---

## 1 answers

### Answer by username_1 on 2018-12-12. Score: 5

I'm not an expert in this field by any means (and my error message was different), but I spent last week trying to make Bitcoinj sign a transaction and send in raw form (i.e. without using transport protocol which Bitcoinj provides) and here's what I've learned (the hard way): You can't sign transactions like that. If you call `tx.addSignedInput` in a loop, [you'll corrupt transaction's signature and it's gonna to be invalid](https://github.com/bitcoinj/bitcoinj/issues/1302#issuecomment-259462443). The solution (after brainstorming with my team and trying a few recipes here ([this one](https://bitcoin.stackexchange.com/a/48709/90286) didn't work), at Bitcoin Stack Exchange) was [add all Inputs to the transaction and then sign them manually](https://bitcoin.stackexchange.com/a/63294/90286).

```
Transaction tx = new Transaction(networkParams);
tx.addOutput(Coin.valueOf(amount), targetAddress);
addInputsToTransaction(sourceAddress, tx, unspents, amount);
signInputsOfTransaction(sourceAddress, tx, key);

tx.verify();
tx.getConfidence().setSource(TransactionConfidence.Source.SELF);
tx.setPurpose(Transaction.Purpose.USER_PAYMENT);
String valueToSend = byteArrayToHexString(tx.bitcoinSerialize());

```

and the methods:

```
private void addInputsToTransaction(Address sourceAddress, Transaction tx, @NonNull BalanceResponse.Unspents[] unspents, Long amount) {
    long gatheredAmount = 0L;
    long requiredAmount = amount + TX_FEE;
    for (BalanceResponse.Unspents unspent : unspents) {
        gatheredAmount += unspent.getAmount();
        TransactionOutPoint outPoint = new TransactionOutPoint(networkParams, unspent.getvOut(), Sha256Hash.wrap(unspent.getTxId()));
        TransactionInput transactionInput = new TransactionInput(networkParams, tx, hexStringToByteArray(unspent.getScriptPubKey()),
                outPoint, Coin.valueOf(unspent.getAmount());
        tx.addInput(transactionInput);

        if (gatheredAmount >= requiredAmount) {
            break;
        }
    }
    if (gatheredAmount > requiredAmount) {
        //return change to sender, in real life it should use different address
        tx.addOutput(Coin.valueOf((gatheredAmount - requiredAmount)), sourceAddress);
    }
}

private void signInputsOfTransaction(Address sourceAddress, @NonNull Transaction tx, ECKey key) {
    for (int i = 0; i < tx.getInputs().size(); i++) {
        Script scriptPubKey = ScriptBuilder.createOutputScript(sourceAddress);
        Sha256Hash hash = tx.hashForSignature(i, scriptPubKey, Transaction.SigHash.ALL, true);
        ECKey.ECDSASignature ecdsaSignature = key.sign(hash);
        TransactionSignature txSignature = new TransactionSignature(ecdsaSignature, Transaction.SigHash.ALL, true);

        if (ScriptPattern.isP2PK(scriptPubKey)) {
            tx.getInput(i).setScriptSig(ScriptBuilder.createInputScript(txSignature));
        } else {
            if (!ScriptPattern.isP2PKH(scriptPubKey)) {
                throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Unable to sign this scrptPubKey: " + scriptPubKey);
            }
            tx.getInput(i).setScriptSig(ScriptBuilder.createInputScript(txSignature, key));
        }
    }
}

```

I hope, it will help you.

> **Comments:**
> **username_2**: Change true to false, it works for me. Sha256Hash hash = tx.hashForSignature(i, scriptPubKey, Transaction.SigHash.ALL, false);         ECKey.ECDSASignature ecdsaSignature = key.sign(hash);         TransactionSignature txSignature = new TransactionSignature(ecdsaSignature, Transaction.SigHash.ALL, false);  

---

