Jak podpisać i wysłać surową transakcję za pomocą 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); 

Błąd:

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) 

Odpowiedź

W żadnym wypadku nie jestem ekspertem w tej dziedzinie (a mój komunikat o błędzie był inny), ale w zeszłym tygodniu próbowałem Bitcoinj podpisuje transakcję i wysyła ją w postaci surowej (tj. Bez użycia protokołu transportowego, który zapewnia Bitcoinj) i oto, czego się nauczyłem (na własnej skórze): Nie możesz podpisywać takich transakcji. Jeśli zadzwonisz do tx.addSignedInput w pętli, otrzymasz „uszkodzony podpis transakcji” i będzie on nieprawidłowy . Rozwiązanie (po przeprowadzeniu burzy mózgów z moim zespołem i wypróbowaniu kilku przepisów tutaj ( ten nie zadziałało) na Bitcoin Stack Exchange) było dodaj wszystkie dane wejściowe do transakcji, a następnie podpisz je ręcznie .

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

i metody:

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

Mam nadzieję, że to pomoże.

Komentarze

  • Zmień true na fałsz, to działa dla mnie. 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);

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *