@@ -554,6 +554,93 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::
554
554
vErrorsRet.push_back (entry);
555
555
}
556
556
557
+ UniValue combinerawtransaction (const JSONRPCRequest& request)
558
+ {
559
+
560
+ if (request.fHelp || request.params .size () != 1 )
561
+ throw std::runtime_error (
562
+ " combinerawtransaction [\" hexstring\" ,...]\n "
563
+ " \n Combine multiple partially signed transactions into one transaction.\n "
564
+ " The combined transaction may be another partially signed transaction or a \n "
565
+ " fully signed transaction."
566
+
567
+ " \n Arguments:\n "
568
+ " 1. \" txs\" (string) A json array of hex strings of partially signed transactions\n "
569
+ " [\n "
570
+ " \" hexstring\" (string) A transaction hash\n "
571
+ " ,...\n "
572
+ " ]\n "
573
+
574
+ " \n Result:\n "
575
+ " \" hex\" : \" value\" , (string) The hex-encoded raw transaction with signature(s)\n "
576
+
577
+ " \n Examples:\n "
578
+ + HelpExampleCli (" combinerawtransaction" , " [\" myhex1\" , \" myhex2\" , \" myhex3\" ]" )
579
+ );
580
+
581
+
582
+ UniValue txs = request.params [0 ].get_array ();
583
+ std::vector<CMutableTransaction> txVariants (txs.size ());
584
+
585
+ for (unsigned int idx = 0 ; idx < txs.size (); idx++) {
586
+ if (!DecodeHexTx (txVariants[idx], txs[idx].get_str (), true )) {
587
+ throw JSONRPCError (RPC_DESERIALIZATION_ERROR, strprintf (" TX decode failed for tx %d" , idx));
588
+ }
589
+ }
590
+
591
+ if (txVariants.empty ()) {
592
+ throw JSONRPCError (RPC_DESERIALIZATION_ERROR, " Missing transactions" );
593
+ }
594
+
595
+ // mergedTx will end up with all the signatures; it
596
+ // starts as a clone of the rawtx:
597
+ CMutableTransaction mergedTx (txVariants[0 ]);
598
+
599
+ // Fetch previous transactions (inputs):
600
+ CCoinsView viewDummy;
601
+ CCoinsViewCache view (&viewDummy);
602
+ {
603
+ LOCK (cs_main);
604
+ LOCK (mempool.cs );
605
+ CCoinsViewCache &viewChain = *pcoinsTip;
606
+ CCoinsViewMemPool viewMempool (&viewChain, mempool);
607
+ view.SetBackend (viewMempool); // temporarily switch cache backend to db+mempool view
608
+
609
+ for (const CTxIn& txin : mergedTx.vin ) {
610
+ view.AccessCoin (txin.prevout ); // Load entries from viewChain into view; can fail.
611
+ }
612
+
613
+ view.SetBackend (viewDummy); // switch back to avoid locking mempool for too long
614
+ }
615
+
616
+ // Use CTransaction for the constant parts of the
617
+ // transaction to avoid rehashing.
618
+ const CTransaction txConst (mergedTx);
619
+ // Sign what we can:
620
+ for (unsigned int i = 0 ; i < mergedTx.vin .size (); i++) {
621
+ CTxIn& txin = mergedTx.vin [i];
622
+ const Coin& coin = view.AccessCoin (txin.prevout );
623
+ if (coin.IsSpent ()) {
624
+ throw JSONRPCError (RPC_VERIFY_ERROR, " Input not found or already spent" );
625
+ }
626
+ const CScript& prevPubKey = coin.out .scriptPubKey ;
627
+ const CAmount& amount = coin.out .nValue ;
628
+
629
+ SignatureData sigdata;
630
+
631
+ // ... and merge in other signatures:
632
+ for (const CMutableTransaction& txv : txVariants) {
633
+ if (txv.vin .size () > i) {
634
+ sigdata = CombineSignatures (prevPubKey, TransactionSignatureChecker (&txConst, i, amount), sigdata, DataFromTransaction (txv, i));
635
+ }
636
+ }
637
+
638
+ UpdateTransaction (mergedTx, i, sigdata);
639
+ }
640
+
641
+ return EncodeHexTx (mergedTx);
642
+ }
643
+
557
644
UniValue signrawtransaction (const JSONRPCRequest& request)
558
645
{
559
646
#ifdef ENABLE_WALLET
@@ -626,26 +713,9 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
626
713
#endif
627
714
RPCTypeCheck (request.params , {UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true );
628
715
629
- std::vector<unsigned char > txData (ParseHexV (request.params [0 ], " argument 1" ));
630
- CDataStream ssData (txData, SER_NETWORK, PROTOCOL_VERSION);
631
- std::vector<CMutableTransaction> txVariants;
632
- while (!ssData.empty ()) {
633
- try {
634
- CMutableTransaction tx;
635
- ssData >> tx;
636
- txVariants.push_back (tx);
637
- }
638
- catch (const std::exception&) {
639
- throw JSONRPCError (RPC_DESERIALIZATION_ERROR, " TX decode failed" );
640
- }
641
- }
642
-
643
- if (txVariants.empty ())
644
- throw JSONRPCError (RPC_DESERIALIZATION_ERROR, " Missing transaction" );
645
-
646
- // mergedTx will end up with all the signatures; it
647
- // starts as a clone of the rawtx:
648
- CMutableTransaction mergedTx (txVariants[0 ]);
716
+ CMutableTransaction mtx;
717
+ if (!DecodeHexTx (mtx, request.params [0 ].get_str (), true ))
718
+ throw JSONRPCError (RPC_DESERIALIZATION_ERROR, " TX decode failed" );
649
719
650
720
// Fetch previous transactions (inputs):
651
721
CCoinsView viewDummy;
@@ -656,7 +726,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
656
726
CCoinsViewMemPool viewMempool (&viewChain, mempool);
657
727
view.SetBackend (viewMempool); // temporarily switch cache backend to db+mempool view
658
728
659
- for (const CTxIn& txin : mergedTx .vin ) {
729
+ for (const CTxIn& txin : mtx .vin ) {
660
730
view.AccessCoin (txin.prevout ); // Load entries from viewChain into view; can fail.
661
731
}
662
732
@@ -781,10 +851,10 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
781
851
782
852
// Use CTransaction for the constant parts of the
783
853
// transaction to avoid rehashing.
784
- const CTransaction txConst (mergedTx );
854
+ const CTransaction txConst (mtx );
785
855
// Sign what we can:
786
- for (unsigned int i = 0 ; i < mergedTx .vin .size (); i++) {
787
- CTxIn& txin = mergedTx .vin [i];
856
+ for (unsigned int i = 0 ; i < mtx .vin .size (); i++) {
857
+ CTxIn& txin = mtx .vin [i];
788
858
const Coin& coin = view.AccessCoin (txin.prevout );
789
859
if (coin.IsSpent ()) {
790
860
TxInErrorToJSON (txin, vErrors, " Input not found or already spent" );
@@ -795,17 +865,11 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
795
865
796
866
SignatureData sigdata;
797
867
// Only sign SIGHASH_SINGLE if there's a corresponding output:
798
- if (!fHashSingle || (i < mergedTx.vout .size ()))
799
- ProduceSignature (MutableTransactionSignatureCreator (&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata);
868
+ if (!fHashSingle || (i < mtx.vout .size ()))
869
+ ProduceSignature (MutableTransactionSignatureCreator (&keystore, &mtx, i, amount, nHashType), prevPubKey, sigdata);
870
+ sigdata = CombineSignatures (prevPubKey, TransactionSignatureChecker (&txConst, i, amount), sigdata, DataFromTransaction (mtx, i));
800
871
801
- // ... and merge in other signatures:
802
- for (const CMutableTransaction& txv : txVariants) {
803
- if (txv.vin .size () > i) {
804
- sigdata = CombineSignatures (prevPubKey, TransactionSignatureChecker (&txConst, i, amount), sigdata, DataFromTransaction (txv, i));
805
- }
806
- }
807
-
808
- UpdateTransaction (mergedTx, i, sigdata);
872
+ UpdateTransaction (mtx, i, sigdata);
809
873
810
874
ScriptError serror = SCRIPT_ERR_OK;
811
875
if (!VerifyScript (txin.scriptSig , prevPubKey, &txin.scriptWitness , STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker (&txConst, i, amount), &serror)) {
@@ -815,7 +879,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
815
879
bool fComplete = vErrors.empty ();
816
880
817
881
UniValue result (UniValue::VOBJ);
818
- result.push_back (Pair (" hex" , EncodeHexTx (mergedTx )));
882
+ result.push_back (Pair (" hex" , EncodeHexTx (mtx )));
819
883
result.push_back (Pair (" complete" , fComplete ));
820
884
if (!vErrors.empty ()) {
821
885
result.push_back (Pair (" errors" , vErrors));
@@ -905,6 +969,7 @@ static const CRPCCommand commands[] =
905
969
{ " rawtransactions" , " decoderawtransaction" , &decoderawtransaction, true , {" hexstring" } },
906
970
{ " rawtransactions" , " decodescript" , &decodescript, true , {" hexstring" } },
907
971
{ " rawtransactions" , " sendrawtransaction" , &sendrawtransaction, false , {" hexstring" ," allowhighfees" } },
972
+ { " rawtransactions" , " combinerawtransaction" , &combinerawtransaction, true , {" txs" } },
908
973
{ " rawtransactions" , " signrawtransaction" , &signrawtransaction, false , {" hexstring" ," prevtxs" ," privkeys" ," sighashtype" } }, /* uses wallet if enabled */
909
974
910
975
{ " blockchain" , " gettxoutproof" , &gettxoutproof, true , {" txids" , " blockhash" } },
0 commit comments