Hur signerar jag och skickar en rå transaktion med BitcoinJ?

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); 

Fel:

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) 

Svar

Jag är inte expert på det här området på något sätt (och mitt felmeddelande var annorlunda), men jag spenderade förra veckan på att göra Bitcoinj undertecknar en transaktion och skickar i rå form (dvs utan att använda transportprotokoll som Bitcoinj tillhandahåller) och här är vad jag har lärt mig (på det hårda sättet): Du kan inte skriva på sådana transaktioner. Om du ringer till tx.addSignedInput i en slinga, kommer du att ”skada transaktionens signatur och den kommer att vara ogiltig . Lösningen (efter brainstorming med mitt team och försökt några recept här ( den här fungerade inte), på Bitcoin Stack Exchange) var lägg till alla ingångar till transaktionen och underteckna dem sedan manuellt .

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()); 

och metoderna:

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)); } } } 

Jag hoppas att det hjälper dig.

Kommentarer

  • Ändra sant till falskt, det fungerar för mig. Sha256Hash hash = tx.hashForSignature (i, scriptPubKey, Transaction.SigHash.ALL, false); ECKey.ECDSASignature ecdsaSignature = key.sign (hash); TransactionSignature txSignature = ny TransactionSignature (ecdsaSignature, Transaction.SigHash.ALL, false);

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *