@@ -78,10 +78,16 @@ static int AppInitRawTx(int argc, char* argv[])
7878 strUsage += HelpMessageOpt (" locktime=N" , _ (" Set TX lock time to N" ));
7979 strUsage += HelpMessageOpt (" nversion=N" , _ (" Set TX version to N" ));
8080 strUsage += HelpMessageOpt (" outaddr=VALUE:ADDRESS" , _ (" Add address-based output to TX" ));
81+ strUsage += HelpMessageOpt (" outpubkey=VALUE:PUBKEY[:FLAGS]" , _ (" Add pay-to-pubkey output to TX" ) + " . " +
82+ _ (" Optionally add the \" W\" flag to produce a pay-to-witness-pubkey-hash output" ) + " . " +
83+ _ (" Optionally add the \" S\" flag to wrap the output in a pay-to-script-hash." ));
8184 strUsage += HelpMessageOpt (" outdata=[VALUE:]DATA" , _ (" Add data-based output to TX" ));
82- strUsage += HelpMessageOpt (" outscript=VALUE:SCRIPT(:\" SEGWIT\" )(:\" P2SH\" )" , _ (" Add raw script output to TX" ) + " . " +
83- _ (" Optionally add the \" SEGWIT\" flag to produce a segwit output" ) + " . " +
84- _ (" Optionally add the \" P2SH\" flag to wrap the script in a P2SH output." ));
85+ strUsage += HelpMessageOpt (" outscript=VALUE:SCRIPT[:FLAGS]" , _ (" Add raw script output to TX" ) + " . " +
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." ));
88+ strUsage += HelpMessageOpt (" outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]" , _ (" Add Pay To n-of-m Multi-sig output to TX. n = REQUIRED, m = PUBKEYS" ) + " . " +
89+ _ (" Optionally add the \" W\" flag to produce a pay-to-witness-script-hash output" ) + " . " +
90+ _ (" Optionally add the \" S\" flag to wrap the output in a pay-to-script-hash." ));
8591 strUsage += HelpMessageOpt (" sign=SIGHASH-FLAGS" , _ (" Add zero or more signatures to transaction" ) + " . " +
8692 _ (" This command requires JSON registers:" ) +
8793 _ (" prevtxs=JSON object" ) + " , " +
@@ -170,6 +176,14 @@ static void RegisterLoad(const std::string& strInput)
170176 RegisterSetJson (key, valStr);
171177}
172178
179+ static CAmount ExtractAndValidateValue (const std::string& strValue)
180+ {
181+ CAmount value;
182+ if (!ParseMoney (strValue, value))
183+ throw std::runtime_error (" invalid TX output value" );
184+ return value;
185+ }
186+
173187static void MutateTxVersion (CMutableTransaction& tx, const std::string& cmdVal)
174188{
175189 int64_t newVersion = atoi64 (cmdVal);
@@ -224,25 +238,18 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu
224238
225239static void MutateTxAddOutAddr (CMutableTransaction& tx, const std::string& strInput)
226240{
227- // separate VALUE:ADDRESS in string
228- size_t pos = strInput.find (' :' );
229- if ((pos == std::string::npos) ||
230- (pos == 0 ) ||
231- (pos == (strInput.size () - 1 )))
232- throw std::runtime_error (" TX output missing separator" );
241+ // Separate into VALUE:ADDRESS
242+ std::vector<std::string> vStrInputParts;
243+ boost::split (vStrInputParts, strInput, boost::is_any_of (" :" ));
233244
234- // extract and validate VALUE
235- std::string strValue = strInput.substr (0 , pos);
236- CAmount value;
237- if (!ParseMoney (strValue, value))
238- throw std::runtime_error (" invalid TX output value" );
245+ // Extract and validate VALUE
246+ CAmount value = ExtractAndValidateValue (vStrInputParts[0 ]);
239247
240248 // extract and validate ADDRESS
241- std::string strAddr = strInput. substr (pos + 1 , std::string::npos) ;
249+ std::string strAddr = vStrInputParts[ 1 ] ;
242250 CBitcoinAddress addr (strAddr);
243251 if (!addr.IsValid ())
244252 throw std::runtime_error (" invalid TX output address" );
245-
246253 // build standard output script via GetScriptForDestination()
247254 CScript scriptPubKey = GetScriptForDestination (addr.Get ());
248255
@@ -251,6 +258,114 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strIn
251258 tx.vout .push_back (txout);
252259}
253260
261+ static void MutateTxAddOutPubKey (CMutableTransaction& tx, const std::string& strInput)
262+ {
263+ // Separate into VALUE:PUBKEY[:FLAGS]
264+ std::vector<std::string> vStrInputParts;
265+ boost::split (vStrInputParts, strInput, boost::is_any_of (" :" ));
266+
267+ // Extract and validate VALUE
268+ CAmount value = ExtractAndValidateValue (vStrInputParts[0 ]);
269+
270+ // Extract and validate PUBKEY
271+ CPubKey pubkey (ParseHex (vStrInputParts[1 ]));
272+ if (!pubkey.IsFullyValid ())
273+ throw std::runtime_error (" invalid TX output pubkey" );
274+ CScript scriptPubKey = GetScriptForRawPubKey (pubkey);
275+ CBitcoinAddress addr (scriptPubKey);
276+
277+ // Extract and validate FLAGS
278+ bool bSegWit = false ;
279+ bool bScriptHash = false ;
280+ if (vStrInputParts.size () == 3 ) {
281+ std::string flags = vStrInputParts[2 ];
282+ bSegWit = (flags.find (" W" ) != std::string::npos);
283+ bScriptHash = (flags.find (" S" ) != std::string::npos);
284+ }
285+
286+ if (bSegWit) {
287+ // Call GetScriptForWitness() to build a P2WSH scriptPubKey
288+ scriptPubKey = GetScriptForWitness (scriptPubKey);
289+ }
290+ if (bScriptHash) {
291+ // Get the address for the redeem script, then call
292+ // GetScriptForDestination() to construct a P2SH scriptPubKey.
293+ CBitcoinAddress redeemScriptAddr (scriptPubKey);
294+ scriptPubKey = GetScriptForDestination (redeemScriptAddr.Get ());
295+ }
296+
297+ // construct TxOut, append to transaction output list
298+ CTxOut txout (value, scriptPubKey);
299+ tx.vout .push_back (txout);
300+ }
301+
302+ static void MutateTxAddOutMultiSig (CMutableTransaction& tx, const std::string& strInput)
303+ {
304+ // Separate into VALUE:REQUIRED:NUMKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]
305+ std::vector<std::string> vStrInputParts;
306+ boost::split (vStrInputParts, strInput, boost::is_any_of (" :" ));
307+
308+ // Check that there are enough parameters
309+ if (vStrInputParts.size ()<3 )
310+ throw std::runtime_error (" Not enough multisig parameters" );
311+
312+ // Extract and validate VALUE
313+ CAmount value = ExtractAndValidateValue (vStrInputParts[0 ]);
314+
315+ // Extract REQUIRED
316+ uint32_t required = stoul (vStrInputParts[1 ]);
317+
318+ // Extract NUMKEYS
319+ uint32_t numkeys = stoul (vStrInputParts[2 ]);
320+
321+ // Validate there are the correct number of pubkeys
322+ if (vStrInputParts.size () < numkeys + 3 )
323+ throw std::runtime_error (" incorrect number of multisig pubkeys" );
324+
325+ if (required < 1 || required > 20 || numkeys < 1 || numkeys > 20 || numkeys < required)
326+ throw std::runtime_error (" multisig parameter mismatch. Required " \
327+ + std::to_string (required) + " of " + std::to_string (numkeys) + " signatures." );
328+
329+ // extract and validate PUBKEYs
330+ std::vector<CPubKey> pubkeys;
331+ for (int pos = 1 ; pos <= int (numkeys); pos++) {
332+ CPubKey pubkey (ParseHex (vStrInputParts[pos + 2 ]));
333+ if (!pubkey.IsFullyValid ())
334+ throw std::runtime_error (" invalid TX output pubkey" );
335+ pubkeys.push_back (pubkey);
336+ }
337+
338+ // Extract FLAGS
339+ bool bSegWit = false ;
340+ bool bScriptHash = false ;
341+ if (vStrInputParts.size () == numkeys + 4 ) {
342+ std::string flags = vStrInputParts.back ();
343+ bSegWit = (flags.find (" W" ) != std::string::npos);
344+ bScriptHash = (flags.find (" S" ) != std::string::npos);
345+ }
346+ else if (vStrInputParts.size () > numkeys + 4 ) {
347+ // Validate that there were no more parameters passed
348+ throw std::runtime_error (" Too many parameters" );
349+ }
350+
351+ CScript scriptPubKey = GetScriptForMultisig (required, pubkeys);
352+
353+ if (bSegWit) {
354+ // Call GetScriptForWitness() to build a P2WSH scriptPubKey
355+ scriptPubKey = GetScriptForWitness (scriptPubKey);
356+ }
357+ if (bScriptHash) {
358+ // Get the address for the redeem script, then call
359+ // GetScriptForDestination() to construct a P2SH scriptPubKey.
360+ CBitcoinAddress addr (scriptPubKey);
361+ scriptPubKey = GetScriptForDestination (addr.Get ());
362+ }
363+
364+ // construct TxOut, append to transaction output list
365+ CTxOut txout (value, scriptPubKey);
366+ tx.vout .push_back (txout);
367+ }
368+
254369static void MutateTxAddOutData (CMutableTransaction& tx, const std::string& strInput)
255370{
256371 CAmount value = 0 ;
@@ -262,10 +377,8 @@ static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strIn
262377 throw std::runtime_error (" TX output value not specified" );
263378
264379 if (pos != std::string::npos) {
265- // extract and validate VALUE
266- std::string strValue = strInput.substr (0 , pos);
267- if (!ParseMoney (strValue, value))
268- throw std::runtime_error (" invalid TX output value" );
380+ // Extract and validate VALUE
381+ value = ExtractAndValidateValue (strInput.substr (0 , pos));
269382 }
270383
271384 // extract and validate DATA
@@ -282,26 +395,32 @@ static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strIn
282395
283396static void MutateTxAddOutScript (CMutableTransaction& tx, const std::string& strInput)
284397{
285- // separate VALUE:SCRIPT(:SEGWIT)(:P2SH)
286- std::vector<std::string> vStrInput;
287- boost::split (vStrInput, strInput, boost::is_any_of (" :" ));
288- if (vStrInput.size () < 2 )
289- throw srd::runtime_error (" TX output missing separator" );
290-
291- // extract and validate VALUE
292- std::string strValue = vStrInput[0 ];
293- CAmount value;
294- if (!ParseMoney (strValue, value))
295- throw std::runtime_error (" invalid TX output value" );
398+ // separate VALUE:SCRIPT[:FLAGS]
399+ std::vector<std::string> vStrInputParts;
400+ boost::split (vStrInputParts, strInput, boost::is_any_of (" :" ));
401+ if (vStrInputParts.size () < 2 )
402+ throw std::runtime_error (" TX output missing separator" );
403+
404+ // Extract and validate VALUE
405+ CAmount value = ExtractAndValidateValue (vStrInputParts[0 ]);
296406
297407 // extract and validate script
298- std::string strScript = vStrInput[1 ];
299- CScript scriptPubKey = ParseScript (strScript); // throws on err
408+ std::string strScript = vStrInputParts[1 ];
409+ CScript scriptPubKey = ParseScript (strScript);
410+
411+ // Extract FLAGS
412+ bool bSegWit = false ;
413+ bool bScriptHash = false ;
414+ if (vStrInputParts.size () == 3 ) {
415+ std::string flags = vStrInputParts.back ();
416+ bSegWit = (flags.find (" W" ) != std::string::npos);
417+ bScriptHash = (flags.find (" S" ) != std::string::npos);
418+ }
300419
301- if (std::find (vStrInput. begin (), vStrInput. end (), " SEGWIT " ) != vStrInput. end () ) {
420+ if (bSegWit ) {
302421 scriptPubKey = GetScriptForWitness (scriptPubKey);
303422 }
304- if (std::find (vStrInput. begin (), vStrInput. end (), " P2SH " ) != vStrInput. end () ) {
423+ if (bScriptHash ) {
305424 CBitcoinAddress addr (scriptPubKey);
306425 scriptPubKey = GetScriptForDestination (addr.Get ());
307426 }
@@ -548,10 +667,14 @@ static void MutateTx(CMutableTransaction& tx, const std::string& command,
548667 MutateTxDelOutput (tx, commandVal);
549668 else if (command == " outaddr" )
550669 MutateTxAddOutAddr (tx, commandVal);
551- else if (command == " outdata" )
552- MutateTxAddOutData (tx, commandVal);
670+ else if (command == " outpubkey" )
671+ MutateTxAddOutPubKey (tx, commandVal);
672+ else if (command == " outmultisig" )
673+ MutateTxAddOutMultiSig (tx, commandVal);
553674 else if (command == " outscript" )
554675 MutateTxAddOutScript (tx, commandVal);
676+ else if (command == " outdata" )
677+ MutateTxAddOutData (tx, commandVal);
555678
556679 else if (command == " sign" ) {
557680 if (!ecc) { ecc.reset (new Secp256k1Init ()); }
0 commit comments