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);
Fout:
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)
Answer
Ik “ben op geen enkele manier een expert op dit gebied (en mijn foutmelding was anders), maar ik heb vorige week geprobeerd om Bitcoinj ondertekent een transactie en verzendt deze in ruwe vorm (dwz zonder gebruik te maken van het transportprotocol dat Bitcoinj biedt) en dit is wat ik heb geleerd (op de moeilijke manier): Je kunt dergelijke transacties niet ondertekenen. Als je tx.addSignedInput
in een lus aanroept, , zal je de handtekening van de transactie beschadigen en wordt deze ongeldig . De oplossing (na brainstormen met mijn team en het uitproberen van een paar recepten hier ( deze werkte niet), bij Bitcoin Stack Exchange) was voeg alle invoer toe aan de transactie en onderteken ze vervolgens handmatig .
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());
en de methoden:
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)); } } }
Ik hoop dat het je zal helpen.
Reacties
- Verander waar naar vals, het werkt voor mij. Sha256Hash hash = tx.hashForSignature (i, scriptPubKey, Transaction.SigHash.ALL, false); ECKey.ECDSASignature ecdsaSignature = key.sign (hash); TransactionSignature txSignature = nieuwe TransactionSignature (ecdsaSignature, Transaction.SigHash.ALL, false);