@@ -78,10 +78,16 @@ static int AppInitRawTx(int argc, char* argv[])
78
78
strUsage += HelpMessageOpt (" locktime=N" , _ (" Set TX lock time to N" ));
79
79
strUsage += HelpMessageOpt (" nversion=N" , _ (" Set TX version to N" ));
80
80
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." ));
81
84
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." ));
85
91
strUsage += HelpMessageOpt (" sign=SIGHASH-FLAGS" , _ (" Add zero or more signatures to transaction" ) + " . " +
86
92
_ (" This command requires JSON registers:" ) +
87
93
_ (" prevtxs=JSON object" ) + " , " +
@@ -170,6 +176,14 @@ static void RegisterLoad(const std::string& strInput)
170
176
RegisterSetJson (key, valStr);
171
177
}
172
178
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
+
173
187
static void MutateTxVersion (CMutableTransaction& tx, const std::string& cmdVal)
174
188
{
175
189
int64_t newVersion = atoi64 (cmdVal);
@@ -224,25 +238,18 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu
224
238
225
239
static void MutateTxAddOutAddr (CMutableTransaction& tx, const std::string& strInput)
226
240
{
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 (" :" ));
233
244
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 ]);
239
247
240
248
// extract and validate ADDRESS
241
- std::string strAddr = strInput. substr (pos + 1 , std::string::npos) ;
249
+ std::string strAddr = vStrInputParts[ 1 ] ;
242
250
CBitcoinAddress addr (strAddr);
243
251
if (!addr.IsValid ())
244
252
throw std::runtime_error (" invalid TX output address" );
245
-
246
253
// build standard output script via GetScriptForDestination()
247
254
CScript scriptPubKey = GetScriptForDestination (addr.Get ());
248
255
@@ -251,6 +258,114 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strIn
251
258
tx.vout .push_back (txout);
252
259
}
253
260
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
+
254
369
static void MutateTxAddOutData (CMutableTransaction& tx, const std::string& strInput)
255
370
{
256
371
CAmount value = 0 ;
@@ -262,10 +377,8 @@ static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strIn
262
377
throw std::runtime_error (" TX output value not specified" );
263
378
264
379
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));
269
382
}
270
383
271
384
// extract and validate DATA
@@ -282,26 +395,32 @@ static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strIn
282
395
283
396
static void MutateTxAddOutScript (CMutableTransaction& tx, const std::string& strInput)
284
397
{
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 ]);
296
406
297
407
// 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
+ }
300
419
301
- if (std::find (vStrInput. begin (), vStrInput. end (), " SEGWIT " ) != vStrInput. end () ) {
420
+ if (bSegWit ) {
302
421
scriptPubKey = GetScriptForWitness (scriptPubKey);
303
422
}
304
- if (std::find (vStrInput. begin (), vStrInput. end (), " P2SH " ) != vStrInput. end () ) {
423
+ if (bScriptHash ) {
305
424
CBitcoinAddress addr (scriptPubKey);
306
425
scriptPubKey = GetScriptForDestination (addr.Get ());
307
426
}
@@ -548,10 +667,14 @@ static void MutateTx(CMutableTransaction& tx, const std::string& command,
548
667
MutateTxDelOutput (tx, commandVal);
549
668
else if (command == " outaddr" )
550
669
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);
553
674
else if (command == " outscript" )
554
675
MutateTxAddOutScript (tx, commandVal);
676
+ else if (command == " outdata" )
677
+ MutateTxAddOutData (tx, commandVal);
555
678
556
679
else if (command == " sign" ) {
557
680
if (!ecc) { ecc.reset (new Secp256k1Init ()); }
0 commit comments