@@ -502,6 +502,92 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::
502
502
vErrorsRet.push_back (entry);
503
503
}
504
504
505
+ UniValue combinerawtransaction (const JSONRPCRequest& request)
506
+ {
507
+ if (request.fHelp || request.params .size () != 1 )
508
+ throw std::runtime_error (
509
+ " combinerawtransaction [\" hexstring\" ,...]\n "
510
+ " \n Combine multiple partially signed transactions into one transaction.\n "
511
+ " The combined transaction may be another partially signed transaction or a \n "
512
+ " fully signed transaction."
513
+
514
+ " \n Arguments:\n "
515
+ " 1. \" txs\" (string) A json array of hex strings of partially signed transactions\n "
516
+ " [\n "
517
+ " \" hexstring\" (string) A transaction hash\n "
518
+ " ,...\n "
519
+ " ]\n "
520
+
521
+ " \n Result:\n "
522
+ " \" hex\" : \" value\" , (string) The hex-encoded raw transaction with signature(s)\n "
523
+
524
+ " \n Examples:\n "
525
+ + HelpExampleCli (" combinerawtransaction" , " [\" myhex1\" , \" myhex2\" , \" myhex3\" ]" )
526
+ );
527
+
528
+
529
+ UniValue txs = request.params [0 ].get_array ();
530
+ std::vector<CMutableTransaction> txVariants (txs.size ());
531
+
532
+ for (unsigned int idx = 0 ; idx < txs.size (); idx++) {
533
+ if (!DecodeHexTx (txVariants[idx], txs[idx].get_str ())) {
534
+ throw JSONRPCError (RPC_DESERIALIZATION_ERROR, strprintf (" TX decode failed for tx %d" , idx));
535
+ }
536
+ }
537
+
538
+ if (txVariants.empty ()) {
539
+ throw JSONRPCError (RPC_DESERIALIZATION_ERROR, " Missing transactions" );
540
+ }
541
+
542
+ // mergedTx will end up with all the signatures; it
543
+ // starts as a clone of the rawtx:
544
+ CMutableTransaction mergedTx (txVariants[0 ]);
545
+
546
+ // Fetch previous transactions (inputs):
547
+ CCoinsView viewDummy;
548
+ CCoinsViewCache view (&viewDummy);
549
+ {
550
+ LOCK (cs_main);
551
+ LOCK (mempool.cs );
552
+ CCoinsViewCache &viewChain = *pcoinsTip;
553
+ CCoinsViewMemPool viewMempool (&viewChain, mempool);
554
+ view.SetBackend (viewMempool); // temporarily switch cache backend to db+mempool view
555
+
556
+ for (const CTxIn& txin : mergedTx.vin ) {
557
+ view.AccessCoin (txin.prevout ); // Load entries from viewChain into view; can fail.
558
+ }
559
+
560
+ view.SetBackend (viewDummy); // switch back to avoid locking mempool for too long
561
+ }
562
+
563
+ // Use CTransaction for the constant parts of the
564
+ // transaction to avoid rehashing.
565
+ const CTransaction txConst (mergedTx);
566
+ // Sign what we can:
567
+ for (unsigned int i = 0 ; i < mergedTx.vin .size (); i++) {
568
+ CTxIn& txin = mergedTx.vin [i];
569
+ const Coin& coin = view.AccessCoin (txin.prevout );
570
+ if (coin.IsSpent ()) {
571
+ throw JSONRPCError (RPC_VERIFY_ERROR, " Input not found or already spent" );
572
+ }
573
+ const CScript& prevPubKey = coin.out .scriptPubKey ;
574
+ const CAmount& amount = coin.out .nValue ;
575
+
576
+ SignatureData sigdata;
577
+
578
+ // ... and merge in other signatures:
579
+ for (const CMutableTransaction& txv : txVariants) {
580
+ if (txv.vin .size () > i) {
581
+ sigdata = CombineSignatures (prevPubKey, TransactionSignatureChecker (&txConst, i, amount), sigdata, DataFromTransaction (txv, i));
582
+ }
583
+ }
584
+
585
+ UpdateTransaction (mergedTx, i, sigdata);
586
+ }
587
+
588
+ return EncodeHexTx (mergedTx);
589
+ }
590
+
505
591
UniValue signrawtransaction (const JSONRPCRequest& request)
506
592
{
507
593
CWallet * const pwallet = GetWalletForJSONRPCRequest (request);
@@ -570,30 +656,14 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
570
656
#endif
571
657
RPCTypeCheck (request.params , {UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true );
572
658
573
- std::vector<unsigned char > txData (ParseHexV (request.params [0 ], " argument 1" ));
574
- CDataStream ssData (txData, SER_NETWORK, PROTOCOL_VERSION);
575
- std::vector<CMutableTransaction> txVariants;
576
- while (!ssData.empty ()) {
577
- try {
578
- CMutableTransaction tx;
579
- ssData >> tx;
580
- txVariants.push_back (tx);
581
- } catch (const std::exception&) {
582
- throw JSONRPCError (RPC_DESERIALIZATION_ERROR, " TX decode failed" );
583
- }
584
- }
585
-
586
- if (txVariants.empty ())
587
- throw JSONRPCError (RPC_DESERIALIZATION_ERROR, " Missing transaction" );
588
-
589
- // mergedTx will end up with all the signatures; it
590
- // starts as a clone of the rawtx:
591
- CMutableTransaction mergedTx (txVariants[0 ]);
659
+ CMutableTransaction mtx;
660
+ if (!DecodeHexTx (mtx, request.params [0 ].get_str ()))
661
+ throw JSONRPCError (RPC_DESERIALIZATION_ERROR, " TX decode failed" );
592
662
593
663
// Fetch previous transactions (inputs):
594
664
std::map<COutPoint, std::pair<CScript, CAmount>> mapPrevOut; // todo: check why do we have this for regtest..
595
665
if (Params ().IsRegTestNet ()) {
596
- for (const CTxIn &txbase : mergedTx .vin )
666
+ for (const CTxIn &txbase : mtx .vin )
597
667
{
598
668
CTransactionRef tempTx;
599
669
uint256 hashBlock;
@@ -611,7 +681,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
611
681
CCoinsViewMemPool viewMempool (&viewChain, mempool);
612
682
view.SetBackend (viewMempool); // temporarily switch cache backend to db+mempool view
613
683
614
- for (const CTxIn& txin : mergedTx .vin ) {
684
+ for (const CTxIn& txin : mtx .vin ) {
615
685
view.AccessCoin (txin.prevout ); // Load entries from viewChain into view; can fail.
616
686
}
617
687
@@ -732,10 +802,10 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
732
802
733
803
// Use CTransaction for the constant parts of the
734
804
// transaction to avoid rehashing.
735
- const CTransaction txConst (mergedTx );
805
+ const CTransaction txConst (mtx );
736
806
// Sign what we can:
737
- for (unsigned int i = 0 ; i < mergedTx .vin .size (); i++) {
738
- CTxIn& txin = mergedTx .vin [i];
807
+ for (unsigned int i = 0 ; i < mtx .vin .size (); i++) {
808
+ CTxIn& txin = mtx .vin [i];
739
809
const Coin& coin = view.AccessCoin (txin.prevout );
740
810
if (Params ().IsRegTestNet ()) {
741
811
if (mapPrevOut.count (txin.prevout ) == 0 && coin.IsSpent ())
@@ -763,18 +833,13 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
763
833
}
764
834
765
835
SignatureData sigdata;
766
- SigVersion sigversion = mergedTx .GetRequiredSigVersion ();
836
+ SigVersion sigversion = mtx .GetRequiredSigVersion ();
767
837
// Only sign SIGHASH_SINGLE if there's a corresponding output:
768
- if (!fHashSingle || (i < mergedTx .vout .size ()))
769
- ProduceSignature (MutableTransactionSignatureCreator (&keystore, &mergedTx , i, amount, nHashType),
770
- prevPubKey , sigdata, sigversion, fColdStake );
838
+ if (!fHashSingle || (i < mtx .vout .size ()))
839
+ ProduceSignature (MutableTransactionSignatureCreator (&keystore, &mtx , i, amount, nHashType), prevPubKey, sigdata, sigversion, fColdStake );
840
+ sigdata = CombineSignatures (prevPubKey, TransactionSignatureChecker (&txConst, i, amount) , sigdata, DataFromTransaction (mtx, i) );
771
841
772
- // ... and merge in other signatures:
773
- for (const CMutableTransaction& txv : txVariants) {
774
- sigdata = CombineSignatures (prevPubKey, TransactionSignatureChecker (&txConst, i, amount), sigdata, DataFromTransaction (txv, i));
775
- }
776
-
777
- UpdateTransaction (mergedTx, i, sigdata);
842
+ UpdateTransaction (mtx, i, sigdata);
778
843
779
844
ScriptError serror = SCRIPT_ERR_OK;
780
845
if (!VerifyScript (txin.scriptSig , prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS,
@@ -785,7 +850,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
785
850
bool fComplete = vErrors.empty ();
786
851
787
852
UniValue result (UniValue::VOBJ);
788
- result.pushKV (" hex" , EncodeHexTx (mergedTx ));
853
+ result.pushKV (" hex" , EncodeHexTx (mtx ));
789
854
result.pushKV (" complete" , fComplete );
790
855
if (!vErrors.empty ()) {
791
856
result.pushKV (" errors" , vErrors);
@@ -895,6 +960,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
895
960
static const CRPCCommand commands[] =
896
961
{ // category name actor (function) okSafe argNames
897
962
// --------------------- ------------------------ ----------------------- ------ --------
963
+ { " rawtransactions" , " combinerawtransaction" , &combinerawtransaction, true , {" txs" } },
898
964
{ " rawtransactions" , " createrawtransaction" , &createrawtransaction, true , {" inputs" ," outputs" ," locktime" } },
899
965
{ " rawtransactions" , " decoderawtransaction" , &decoderawtransaction, true , {" hexstring" } },
900
966
{ " rawtransactions" , " decodescript" , &decodescript, true , {" hexstring" } },
0 commit comments