@@ -75,10 +75,16 @@ static bool AppInitRawTx(int argc, char* argv[])
7575 strUsage += HelpMessageOpt (" locktime=N" , _ (" Set TX lock time to N" ));
7676 strUsage += HelpMessageOpt (" nversion=N" , _ (" Set TX version to N" ));
7777 strUsage += HelpMessageOpt (" outaddr=VALUE:ADDRESS" , _ (" Add address-based output to TX" ));
78+ strUsage += HelpMessageOpt (" outpubkey=VALUE:PUBKEY[:FLAGS]" , _ (" Add pay-to-pubkey output to TX" ) + " . " +
79+ _ (" Optionally add the \" W\" flag to produce a pay-to-witness-pubkey-hash output" ) + " . " +
80+ _ (" Optionally add the \" S\" flag to wrap the output in a pay-to-script-hash." ));
7881 strUsage += HelpMessageOpt (" outdata=[VALUE:]DATA" , _ (" Add data-based output to TX" ));
79- strUsage += HelpMessageOpt (" outscript=VALUE:SCRIPT(:\" SEGWIT\" )(:\" P2SH\" )" , _ (" Add raw script output to TX" ) + " . " +
80- _ (" Optionally add the \" SEGWIT\" flag to produce a segwit output" ) + " . " +
81- _ (" Optionally add the \" P2SH\" flag to wrap the script in a P2SH output." ));
82+ strUsage += HelpMessageOpt (" outscript=VALUE:SCRIPT[:FLAGS]" , _ (" Add raw script output to TX" ) + " . " +
83+ _ (" Optionally add the \" W\" flag to produce a pay-to-witness-script-hash output" ) + " . " +
84+ _ (" Optionally add the \" S\" flag to wrap the output in a pay-to-script-hash." ));
85+ strUsage += HelpMessageOpt (" outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]" , _ (" Add Pay To n-of-m Multi-sig output to TX. n = REQUIRED, m = PUBKEYS" ) + " . " +
86+ _ (" Optionally add the \" W\" flag to produce a pay-to-witness-script-hash output" ) + " . " +
87+ _ (" Optionally add the \" S\" flag to wrap the output in a pay-to-script-hash." ));
8288 strUsage += HelpMessageOpt (" sign=SIGHASH-FLAGS" , _ (" Add zero or more signatures to transaction" ) + " . " +
8389 _ (" This command requires JSON registers:" ) +
8490 _ (" prevtxs=JSON object" ) + " , " +
@@ -217,33 +223,142 @@ static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput)
217223
218224static void MutateTxAddOutAddr (CMutableTransaction& tx, const string& strInput)
219225{
220- // separate VALUE:ADDRESS in string
221- size_t pos = strInput.find (' :' );
222- if ((pos == string::npos) ||
223- (pos == 0 ) ||
224- (pos == (strInput.size () - 1 )))
225- throw runtime_error (" TX output missing separator" );
226+ // Seperate into VALUE:ADDRESS
227+ std::vector<std::string> vStrInputParts;
228+ boost::split (vStrInputParts, strInput, boost::is_any_of (" :" ));
226229
227- // extract and validate VALUE
228- string strValue = strInput. substr ( 0 , pos) ;
230+ // Extract and validate VALUE
231+ string strValue = vStrInputParts[ 0 ] ;
229232 CAmount value;
230233 if (!ParseMoney (strValue, value))
231234 throw runtime_error (" invalid TX output value" );
232235
233236 // extract and validate ADDRESS
234- string strAddr = strInput. substr (pos + 1 , string::npos) ;
237+ string strAddr = vStrInputParts[ 1 ] ;
235238 CBitcoinAddress addr (strAddr);
236239 if (!addr.IsValid ())
237240 throw runtime_error (" invalid TX output address" );
238-
239- // build standard output script via GetScriptForDestination()
240241 CScript scriptPubKey = GetScriptForDestination (addr.Get ());
241242
242243 // construct TxOut, append to transaction output list
243244 CTxOut txout (value, scriptPubKey);
244245 tx.vout .push_back (txout);
245246}
246247
248+ static void MutateTxAddOutPubKey (CMutableTransaction& tx, const string& strInput)
249+ {
250+ // Seperate into VALUE:PUBKEY[:FLAGS]
251+ std::vector<std::string> vStrInputParts;
252+ boost::split (vStrInputParts, strInput, boost::is_any_of (" :" ));
253+
254+ // Extract and validate VALUE
255+ string strValue = vStrInputParts[0 ];
256+ CAmount value;
257+ if (!ParseMoney (strValue, value))
258+ throw runtime_error (" invalid TX output value" );
259+
260+ // Extract and validate PUBKEY
261+ CPubKey pubkey (ParseHex (vStrInputParts[1 ]));
262+ if (!pubkey.IsFullyValid ())
263+ throw runtime_error (" invalid TX output pubkey" );
264+ CScript scriptPubKey = GetScriptForRawPubKey (pubkey);
265+ CBitcoinAddress addr (scriptPubKey);
266+
267+ // Extract and validate FLAGS
268+ bool bSegWit = false ;
269+ bool bScriptHash = false ;
270+ if (vStrInputParts.size () == 3 ) {
271+ std::string flags = vStrInputParts[2 ];
272+ bSegWit = (flags.find (" W" ) != std::string::npos);
273+ bScriptHash = (flags.find (" S" ) != std::string::npos);
274+ }
275+
276+ if (bSegWit) {
277+ // Call GetScriptForWitness() to build a P2WSH scriptPubKey
278+ scriptPubKey = GetScriptForWitness (scriptPubKey);
279+ }
280+ if (bScriptHash) {
281+ // Get the address for the redeem script, then call
282+ // GetScriptForDestination() to construct a P2SH scriptPubKey.
283+ CBitcoinAddress addr (scriptPubKey);
284+ scriptPubKey = GetScriptForDestination (addr.Get ());
285+ }
286+
287+ // construct TxOut, append to transaction output list
288+ CTxOut txout (value, scriptPubKey);
289+ tx.vout .push_back (txout);
290+ }
291+
292+ static void MutateTxAddOutMultiSig (CMutableTransaction& tx, const string& strInput)
293+ {
294+ // Seperate into VALUE:REQUIRED:NUMKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]
295+ std::vector<std::string> vStrInputParts;
296+ boost::split (vStrInputParts, strInput, boost::is_any_of (" :" ));
297+
298+ // Check that there are enough parameters
299+ if (vStrInputParts.size ()<3 )
300+ throw runtime_error (" Not enough multisig parameters" );
301+
302+ // Extract and validate VALUE
303+ string strValue = vStrInputParts[0 ];
304+ CAmount value;
305+ if (!ParseMoney (strValue, value))
306+ throw runtime_error (" invalid TX output value" );
307+
308+ // Extract REQUIRED
309+ uint required = std::stoul (vStrInputParts[1 ]);
310+
311+ // Extract NUMKEYS
312+ uint numkeys = std::stoul (vStrInputParts[2 ]);
313+
314+ // Validate there are the correct number of pubkeys
315+ if (vStrInputParts.size () < numkeys + 3 )
316+ throw runtime_error (" incorrect number of multisig pubkeys" );
317+
318+ if (required < 1 || required > 20 || numkeys < 1 || numkeys > 20 || numkeys < required)
319+ throw runtime_error (" multisig parameter mismatch. Required " \
320+ + to_string (required) + " of " + to_string (numkeys) + " signatures." );
321+
322+ // extract and validate PUBKEYs
323+ std::vector<CPubKey> pubkeys;
324+ for (uint pos = 1 ; pos <= numkeys; pos++) {
325+ CPubKey pubkey (ParseHex (vStrInputParts[pos + 2 ]));
326+ if (!pubkey.IsFullyValid ())
327+ throw runtime_error (" invalid TX output pubkey" );
328+ pubkeys.push_back (pubkey);
329+ }
330+
331+ // Extract FLAGS
332+ bool bSegWit = false ;
333+ bool bScriptHash = false ;
334+ if (vStrInputParts.size () == numkeys + 4 ) {
335+ std::string flags = vStrInputParts.back ();
336+ bSegWit = (flags.find (" W" ) != std::string::npos);
337+ bScriptHash = (flags.find (" S" ) != std::string::npos);
338+ }
339+ else if (vStrInputParts.size () > numkeys + 4 ) {
340+ // Validate that there were no more parameters passed
341+ throw runtime_error (" Too many parameters" );
342+ }
343+
344+ CScript scriptPubKey = GetScriptForMultisig (required, pubkeys);
345+
346+ if (bSegWit) {
347+ // Call GetScriptForWitness() to build a P2WSH scriptPubKey
348+ scriptPubKey = GetScriptForWitness (scriptPubKey);
349+ }
350+ if (bScriptHash) {
351+ // Get the address for the redeem script, then call
352+ // GetScriptForDestination() to construct a P2SH scriptPubKey.
353+ CBitcoinAddress addr (scriptPubKey);
354+ scriptPubKey = GetScriptForDestination (addr.Get ());
355+ }
356+
357+ // construct TxOut, append to transaction output list
358+ CTxOut txout (value, scriptPubKey);
359+ tx.vout .push_back (txout);
360+ }
361+
247362static void MutateTxAddOutData (CMutableTransaction& tx, const string& strInput)
248363{
249364 CAmount value = 0 ;
@@ -275,7 +390,7 @@ static void MutateTxAddOutData(CMutableTransaction& tx, const string& strInput)
275390
276391static void MutateTxAddOutScript (CMutableTransaction& tx, const string& strInput)
277392{
278- // separate VALUE:SCRIPT(:SEGWIT)(:P2SH)
393+ // separate VALUE:SCRIPT[:FLAGS]
279394 std::vector<std::string> vStrInput;
280395 boost::split (vStrInput, strInput, boost::is_any_of (" :" ));
281396 if (vStrInput.size () < 2 )
@@ -289,12 +404,21 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const string& strInput
289404
290405 // extract and validate script
291406 string strScript = vStrInput[1 ];
292- CScript scriptPubKey = ParseScript (strScript); // throws on err
407+ CScript scriptPubKey = ParseScript (strScript);
408+
409+ // Extract FLAGS
410+ bool bSegWit = false ;
411+ bool bScriptHash = false ;
412+ if (vStrInput.size () == 3 ) {
413+ std::string flags = vStrInput.back ();
414+ bSegWit = (flags.find (" W" ) != std::string::npos);
415+ bScriptHash = (flags.find (" S" ) != std::string::npos);
416+ }
293417
294- if (std::find (vStrInput. begin (), vStrInput. end (), " SEGWIT " ) != vStrInput. end () ) {
418+ if (bSegWit ) {
295419 scriptPubKey = GetScriptForWitness (scriptPubKey);
296420 }
297- if (std::find (vStrInput. begin (), vStrInput. end (), " P2SH " ) != vStrInput. end () ) {
421+ if (bScriptHash ) {
298422 CBitcoinAddress addr (scriptPubKey);
299423 scriptPubKey = GetScriptForDestination (addr.Get ());
300424 }
@@ -541,10 +665,14 @@ static void MutateTx(CMutableTransaction& tx, const string& command,
541665 MutateTxDelOutput (tx, commandVal);
542666 else if (command == " outaddr" )
543667 MutateTxAddOutAddr (tx, commandVal);
544- else if (command == " outdata" )
545- MutateTxAddOutData (tx, commandVal);
668+ else if (command == " outpubkey" )
669+ MutateTxAddOutPubKey (tx, commandVal);
670+ else if (command == " outmultisig" )
671+ MutateTxAddOutMultiSig (tx, commandVal);
546672 else if (command == " outscript" )
547673 MutateTxAddOutScript (tx, commandVal);
674+ else if (command == " outdata" )
675+ MutateTxAddOutData (tx, commandVal);
548676
549677 else if (command == " sign" ) {
550678 if (!ecc) { ecc.reset (new Secp256k1Init ()); }
0 commit comments