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);
Fejl:
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
Jeg er på ingen måde ekspert på dette område (og min fejlmeddelelse var anderledes), men jeg brugte sidste uge på at lave Bitcoinj underskriver en transaktion og send i rå form (dvs. uden brug af transportprotokol, som Bitcoinj giver), og her er det, jeg har lært (på den hårde måde): Du kan ikke underskrive transaktioner sådan. Hvis du ringer til tx.addSignedInput
i en løkke, vil du “ødelægge transaktionens” underskrift, og den bliver ugyldig . Løsningen (efter brainstorming med mit team og prøvet et par opskrifter her ( denne virkede ikke) på Bitcoin Stack Exchange) var tilføj alle input til transaktionen, og underskriv dem derefter manuelt .
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());
og metoderne:
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)); } } }
Jeg håber, det hjælper dig.
Kommentarer
- Skift sand for falsk, det virker for 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);