@@ -78,8 +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" , _ (" Add raw script output to TX" ));
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." ));
8391 strUsage += HelpMessageOpt (" sign=SIGHASH-FLAGS" , _ (" Add zero or more signatures to transaction" ) + " . " +
8492 _ (" This command requires JSON registers:" ) +
8593 _ (" prevtxs=JSON object" ) + " , " +
@@ -168,6 +176,14 @@ static void RegisterLoad(const std::string& strInput)
168176 RegisterSetJson (key, valStr);
169177}
170178
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+
171187static void MutateTxVersion (CMutableTransaction& tx, const std::string& cmdVal)
172188{
173189 int64_t newVersion = atoi64 (cmdVal);
@@ -221,25 +237,18 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu
221237
222238static void MutateTxAddOutAddr (CMutableTransaction& tx, const std::string& strInput)
223239{
224- // separate VALUE:ADDRESS in string
225- size_t pos = strInput.find (' :' );
226- if ((pos == std::string::npos) ||
227- (pos == 0 ) ||
228- (pos == (strInput.size () - 1 )))
229- throw std::runtime_error (" TX output missing separator" );
240+ // Separate into VALUE:ADDRESS
241+ std::vector<std::string> vStrInputParts;
242+ boost::split (vStrInputParts, strInput, boost::is_any_of (" :" ));
230243
231- // extract and validate VALUE
232- std::string strValue = strInput.substr (0 , pos);
233- CAmount value;
234- if (!ParseMoney (strValue, value))
235- throw std::runtime_error (" invalid TX output value" );
244+ // Extract and validate VALUE
245+ CAmount value = ExtractAndValidateValue (vStrInputParts[0 ]);
236246
237247 // extract and validate ADDRESS
238- std::string strAddr = strInput. substr (pos + 1 , std::string::npos) ;
248+ std::string strAddr = vStrInputParts[ 1 ] ;
239249 CBitcoinAddress addr (strAddr);
240250 if (!addr.IsValid ())
241251 throw std::runtime_error (" invalid TX output address" );
242-
243252 // build standard output script via GetScriptForDestination()
244253 CScript scriptPubKey = GetScriptForDestination (addr.Get ());
245254
@@ -248,6 +257,114 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strIn
248257 tx.vout .push_back (txout);
249258}
250259
260+ static void MutateTxAddOutPubKey (CMutableTransaction& tx, const std::string& strInput)
261+ {
262+ // Separate into VALUE:PUBKEY[:FLAGS]
263+ std::vector<std::string> vStrInputParts;
264+ boost::split (vStrInputParts, strInput, boost::is_any_of (" :" ));
265+
266+ // Extract and validate VALUE
267+ CAmount value = ExtractAndValidateValue (vStrInputParts[0 ]);
268+
269+ // Extract and validate PUBKEY
270+ CPubKey pubkey (ParseHex (vStrInputParts[1 ]));
271+ if (!pubkey.IsFullyValid ())
272+ throw std::runtime_error (" invalid TX output pubkey" );
273+ CScript scriptPubKey = GetScriptForRawPubKey (pubkey);
274+ CBitcoinAddress addr (scriptPubKey);
275+
276+ // Extract and validate FLAGS
277+ bool bSegWit = false ;
278+ bool bScriptHash = false ;
279+ if (vStrInputParts.size () == 3 ) {
280+ std::string flags = vStrInputParts[2 ];
281+ bSegWit = (flags.find (" W" ) != std::string::npos);
282+ bScriptHash = (flags.find (" S" ) != std::string::npos);
283+ }
284+
285+ if (bSegWit) {
286+ // Call GetScriptForWitness() to build a P2WSH scriptPubKey
287+ scriptPubKey = GetScriptForWitness (scriptPubKey);
288+ }
289+ if (bScriptHash) {
290+ // Get the address for the redeem script, then call
291+ // GetScriptForDestination() to construct a P2SH scriptPubKey.
292+ CBitcoinAddress redeemScriptAddr (scriptPubKey);
293+ scriptPubKey = GetScriptForDestination (redeemScriptAddr.Get ());
294+ }
295+
296+ // construct TxOut, append to transaction output list
297+ CTxOut txout (value, scriptPubKey);
298+ tx.vout .push_back (txout);
299+ }
300+
301+ static void MutateTxAddOutMultiSig (CMutableTransaction& tx, const std::string& strInput)
302+ {
303+ // Separate into VALUE:REQUIRED:NUMKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]
304+ std::vector<std::string> vStrInputParts;
305+ boost::split (vStrInputParts, strInput, boost::is_any_of (" :" ));
306+
307+ // Check that there are enough parameters
308+ if (vStrInputParts.size ()<3 )
309+ throw std::runtime_error (" Not enough multisig parameters" );
310+
311+ // Extract and validate VALUE
312+ CAmount value = ExtractAndValidateValue (vStrInputParts[0 ]);
313+
314+ // Extract REQUIRED
315+ uint32_t required = stoul (vStrInputParts[1 ]);
316+
317+ // Extract NUMKEYS
318+ uint32_t numkeys = stoul (vStrInputParts[2 ]);
319+
320+ // Validate there are the correct number of pubkeys
321+ if (vStrInputParts.size () < numkeys + 3 )
322+ throw std::runtime_error (" incorrect number of multisig pubkeys" );
323+
324+ if (required < 1 || required > 20 || numkeys < 1 || numkeys > 20 || numkeys < required)
325+ throw std::runtime_error (" multisig parameter mismatch. Required " \
326+ + std::to_string (required) + " of " + std::to_string (numkeys) + " signatures." );
327+
328+ // extract and validate PUBKEYs
329+ std::vector<CPubKey> pubkeys;
330+ for (int pos = 1 ; pos <= int (numkeys); pos++) {
331+ CPubKey pubkey (ParseHex (vStrInputParts[pos + 2 ]));
332+ if (!pubkey.IsFullyValid ())
333+ throw std::runtime_error (" invalid TX output pubkey" );
334+ pubkeys.push_back (pubkey);
335+ }
336+
337+ // Extract FLAGS
338+ bool bSegWit = false ;
339+ bool bScriptHash = false ;
340+ if (vStrInputParts.size () == numkeys + 4 ) {
341+ std::string flags = vStrInputParts.back ();
342+ bSegWit = (flags.find (" W" ) != std::string::npos);
343+ bScriptHash = (flags.find (" S" ) != std::string::npos);
344+ }
345+ else if (vStrInputParts.size () > numkeys + 4 ) {
346+ // Validate that there were no more parameters passed
347+ throw std::runtime_error (" Too many parameters" );
348+ }
349+
350+ CScript scriptPubKey = GetScriptForMultisig (required, pubkeys);
351+
352+ if (bSegWit) {
353+ // Call GetScriptForWitness() to build a P2WSH scriptPubKey
354+ scriptPubKey = GetScriptForWitness (scriptPubKey);
355+ }
356+ if (bScriptHash) {
357+ // Get the address for the redeem script, then call
358+ // GetScriptForDestination() to construct a P2SH scriptPubKey.
359+ CBitcoinAddress addr (scriptPubKey);
360+ scriptPubKey = GetScriptForDestination (addr.Get ());
361+ }
362+
363+ // construct TxOut, append to transaction output list
364+ CTxOut txout (value, scriptPubKey);
365+ tx.vout .push_back (txout);
366+ }
367+
251368static void MutateTxAddOutData (CMutableTransaction& tx, const std::string& strInput)
252369{
253370 CAmount value = 0 ;
@@ -259,10 +376,8 @@ static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strIn
259376 throw std::runtime_error (" TX output value not specified" );
260377
261378 if (pos != std::string::npos) {
262- // extract and validate VALUE
263- std::string strValue = strInput.substr (0 , pos);
264- if (!ParseMoney (strValue, value))
265- throw std::runtime_error (" invalid TX output value" );
379+ // Extract and validate VALUE
380+ value = ExtractAndValidateValue (strInput.substr (0 , pos));
266381 }
267382
268383 // extract and validate DATA
@@ -279,21 +394,35 @@ static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strIn
279394
280395static void MutateTxAddOutScript (CMutableTransaction& tx, const std::string& strInput)
281396{
282- // separate VALUE:SCRIPT in string
283- size_t pos = strInput. find ( ' : ' ) ;
284- if ((pos == std::string::npos) ||
285- (pos == 0 ) )
397+ // separate VALUE:SCRIPT[:FLAGS]
398+ std::vector<std::string> vStrInputParts ;
399+ boost::split (vStrInputParts, strInput, boost::is_any_of ( " : " ));
400+ if (vStrInputParts. size () < 2 )
286401 throw std::runtime_error (" TX output missing separator" );
287402
288- // extract and validate VALUE
289- std::string strValue = strInput.substr (0 , pos);
290- CAmount value;
291- if (!ParseMoney (strValue, value))
292- throw std::runtime_error (" invalid TX output value" );
403+ // Extract and validate VALUE
404+ CAmount value = ExtractAndValidateValue (vStrInputParts[0 ]);
293405
294406 // extract and validate script
295- std::string strScript = strInput.substr (pos + 1 , std::string::npos);
296- CScript scriptPubKey = ParseScript (strScript); // throws on err
407+ std::string strScript = vStrInputParts[1 ];
408+ CScript scriptPubKey = ParseScript (strScript);
409+
410+ // Extract FLAGS
411+ bool bSegWit = false ;
412+ bool bScriptHash = false ;
413+ if (vStrInputParts.size () == 3 ) {
414+ std::string flags = vStrInputParts.back ();
415+ bSegWit = (flags.find (" W" ) != std::string::npos);
416+ bScriptHash = (flags.find (" S" ) != std::string::npos);
417+ }
418+
419+ if (bSegWit) {
420+ scriptPubKey = GetScriptForWitness (scriptPubKey);
421+ }
422+ if (bScriptHash) {
423+ CBitcoinAddress addr (scriptPubKey);
424+ scriptPubKey = GetScriptForDestination (addr.Get ());
425+ }
297426
298427 // construct TxOut, append to transaction output list
299428 CTxOut txout (value, scriptPubKey);
@@ -522,10 +651,14 @@ static void MutateTx(CMutableTransaction& tx, const std::string& command,
522651 MutateTxDelOutput (tx, commandVal);
523652 else if (command == " outaddr" )
524653 MutateTxAddOutAddr (tx, commandVal);
525- else if (command == " outdata" )
526- MutateTxAddOutData (tx, commandVal);
654+ else if (command == " outpubkey" )
655+ MutateTxAddOutPubKey (tx, commandVal);
656+ else if (command == " outmultisig" )
657+ MutateTxAddOutMultiSig (tx, commandVal);
527658 else if (command == " outscript" )
528659 MutateTxAddOutScript (tx, commandVal);
660+ else if (command == " outdata" )
661+ MutateTxAddOutData (tx, commandVal);
529662
530663 else if (command == " sign" ) {
531664 if (!ecc) { ecc.reset (new Secp256k1Init ()); }
0 commit comments