@ -78,10 +78,16 @@ static int AppInitRawTx(int argc, char* argv[])
strUsage + = HelpMessageOpt ( " locktime=N " , _ ( " Set TX lock time to N " ) ) ;
strUsage + = HelpMessageOpt ( " locktime=N " , _ ( " Set TX lock time to N " ) ) ;
strUsage + = HelpMessageOpt ( " nversion=N " , _ ( " Set TX version to N " ) ) ;
strUsage + = HelpMessageOpt ( " nversion=N " , _ ( " Set TX version to N " ) ) ;
strUsage + = HelpMessageOpt ( " outaddr=VALUE:ADDRESS " , _ ( " Add address-based output to TX " ) ) ;
strUsage + = HelpMessageOpt ( " outaddr=VALUE:ADDRESS " , _ ( " Add address-based output to TX " ) ) ;
strUsage + = HelpMessageOpt ( " outpubkey=VALUE:PUBKEY[:FLAGS] " , _ ( " Add pay-to-pubkey output to TX " ) + " . " +
_ ( " Optionally add the \" W \" flag to produce a pay-to-witness-pubkey-hash output " ) + " . " +
_ ( " Optionally add the \" S \" flag to wrap the output in a pay-to-script-hash. " ) ) ;
strUsage + = HelpMessageOpt ( " outdata=[VALUE:]DATA " , _ ( " Add data-based output to TX " ) ) ;
strUsage + = HelpMessageOpt ( " outdata=[VALUE:]DATA " , _ ( " Add data-based output to TX " ) ) ;
strUsage + = HelpMessageOpt ( " outscript=VALUE:SCRIPT(: \" SEGWIT \" )(: \" P2SH \" ) " , _ ( " Add raw script output to TX " ) + " . " +
strUsage + = HelpMessageOpt ( " outscript=VALUE:SCRIPT[:FLAGS] " , _ ( " Add raw script output to TX " ) + " . " +
_ ( " Optionally add the \" SEGWIT \" flag to produce a segwit output " ) + " . " +
_ ( " Optionally add the \" W \" flag to produce a pay-to-witness-script-hash output " ) + " . " +
_ ( " Optionally add the \" P2SH \" flag to wrap the script in a P2SH output. " ) ) ;
_ ( " Optionally add the \" S \" flag to wrap the output in a pay-to-script-hash. " ) ) ;
strUsage + = HelpMessageOpt ( " outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS] " , _ ( " Add Pay To n-of-m Multi-sig output to TX. n = REQUIRED, m = PUBKEYS " ) + " . " +
_ ( " Optionally add the \" W \" flag to produce a pay-to-witness-script-hash output " ) + " . " +
_ ( " Optionally add the \" S \" flag to wrap the output in a pay-to-script-hash. " ) ) ;
strUsage + = HelpMessageOpt ( " sign=SIGHASH-FLAGS " , _ ( " Add zero or more signatures to transaction " ) + " . " +
strUsage + = HelpMessageOpt ( " sign=SIGHASH-FLAGS " , _ ( " Add zero or more signatures to transaction " ) + " . " +
_ ( " This command requires JSON registers: " ) +
_ ( " This command requires JSON registers: " ) +
_ ( " prevtxs=JSON object " ) + " , " +
_ ( " prevtxs=JSON object " ) + " , " +
@ -170,6 +176,14 @@ static void RegisterLoad(const std::string& strInput)
RegisterSetJson ( key , valStr ) ;
RegisterSetJson ( key , valStr ) ;
}
}
static CAmount ExtractAndValidateValue ( const std : : string & strValue )
{
CAmount value ;
if ( ! ParseMoney ( strValue , value ) )
throw std : : runtime_error ( " invalid TX output value " ) ;
return value ;
}
static void MutateTxVersion ( CMutableTransaction & tx , const std : : string & cmdVal )
static void MutateTxVersion ( CMutableTransaction & tx , const std : : string & cmdVal )
{
{
int64_t newVersion = atoi64 ( cmdVal ) ;
int64_t newVersion = atoi64 ( cmdVal ) ;
@ -224,25 +238,18 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu
static void MutateTxAddOutAddr ( CMutableTransaction & tx , const std : : string & strInput )
static void MutateTxAddOutAddr ( CMutableTransaction & tx , const std : : string & strInput )
{
{
// separate VALUE:ADDRESS in string
// Separate into VALUE:ADDRESS
size_t pos = strInput . find ( ' : ' ) ;
std : : vector < std : : string > vStrInputParts ;
if ( ( pos = = std : : string : : npos ) | |
boost : : split ( vStrInputParts , strInput , boost : : is_any_of ( " : " ) ) ;
( pos = = 0 ) | |
( pos = = ( strInput . size ( ) - 1 ) ) )
throw std : : runtime_error ( " TX output missing separator " ) ;
// extract and validate VALUE
// Extract and validate VALUE
std : : string strValue = strInput . substr ( 0 , pos ) ;
CAmount value = ExtractAndValidateValue ( vStrInputParts [ 0 ] ) ;
CAmount value ;
if ( ! ParseMoney ( strValue , value ) )
throw std : : runtime_error ( " invalid TX output value " ) ;
// extract and validate ADDRESS
// extract and validate ADDRESS
std : : string strAddr = strInput . substr ( pos + 1 , std : : string : : npos ) ;
std : : string strAddr = vStrInputParts [ 1 ] ;
CBitcoinAddress addr ( strAddr ) ;
CBitcoinAddress addr ( strAddr ) ;
if ( ! addr . IsValid ( ) )
if ( ! addr . IsValid ( ) )
throw std : : runtime_error ( " invalid TX output address " ) ;
throw std : : runtime_error ( " invalid TX output address " ) ;
// build standard output script via GetScriptForDestination()
// build standard output script via GetScriptForDestination()
CScript scriptPubKey = GetScriptForDestination ( addr . Get ( ) ) ;
CScript scriptPubKey = GetScriptForDestination ( addr . Get ( ) ) ;
@ -251,6 +258,114 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strIn
tx . vout . push_back ( txout ) ;
tx . vout . push_back ( txout ) ;
}
}
static void MutateTxAddOutPubKey ( CMutableTransaction & tx , const std : : string & strInput )
{
// Separate into VALUE:PUBKEY[:FLAGS]
std : : vector < std : : string > vStrInputParts ;
boost : : split ( vStrInputParts , strInput , boost : : is_any_of ( " : " ) ) ;
// Extract and validate VALUE
CAmount value = ExtractAndValidateValue ( vStrInputParts [ 0 ] ) ;
// Extract and validate PUBKEY
CPubKey pubkey ( ParseHex ( vStrInputParts [ 1 ] ) ) ;
if ( ! pubkey . IsFullyValid ( ) )
throw std : : runtime_error ( " invalid TX output pubkey " ) ;
CScript scriptPubKey = GetScriptForRawPubKey ( pubkey ) ;
CBitcoinAddress addr ( scriptPubKey ) ;
// Extract and validate FLAGS
bool bSegWit = false ;
bool bScriptHash = false ;
if ( vStrInputParts . size ( ) = = 3 ) {
std : : string flags = vStrInputParts [ 2 ] ;
bSegWit = ( flags . find ( " W " ) ! = std : : string : : npos ) ;
bScriptHash = ( flags . find ( " S " ) ! = std : : string : : npos ) ;
}
if ( bSegWit ) {
// Call GetScriptForWitness() to build a P2WSH scriptPubKey
scriptPubKey = GetScriptForWitness ( scriptPubKey ) ;
}
if ( bScriptHash ) {
// Get the address for the redeem script, then call
// GetScriptForDestination() to construct a P2SH scriptPubKey.
CBitcoinAddress redeemScriptAddr ( scriptPubKey ) ;
scriptPubKey = GetScriptForDestination ( redeemScriptAddr . Get ( ) ) ;
}
// construct TxOut, append to transaction output list
CTxOut txout ( value , scriptPubKey ) ;
tx . vout . push_back ( txout ) ;
}
static void MutateTxAddOutMultiSig ( CMutableTransaction & tx , const std : : string & strInput )
{
// Separate into VALUE:REQUIRED:NUMKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]
std : : vector < std : : string > vStrInputParts ;
boost : : split ( vStrInputParts , strInput , boost : : is_any_of ( " : " ) ) ;
// Check that there are enough parameters
if ( vStrInputParts . size ( ) < 3 )
throw std : : runtime_error ( " Not enough multisig parameters " ) ;
// Extract and validate VALUE
CAmount value = ExtractAndValidateValue ( vStrInputParts [ 0 ] ) ;
// Extract REQUIRED
uint32_t required = stoul ( vStrInputParts [ 1 ] ) ;
// Extract NUMKEYS
uint32_t numkeys = stoul ( vStrInputParts [ 2 ] ) ;
// Validate there are the correct number of pubkeys
if ( vStrInputParts . size ( ) < numkeys + 3 )
throw std : : runtime_error ( " incorrect number of multisig pubkeys " ) ;
if ( required < 1 | | required > 20 | | numkeys < 1 | | numkeys > 20 | | numkeys < required )
throw std : : runtime_error ( " multisig parameter mismatch. Required " \
+ std : : to_string ( required ) + " of " + std : : to_string ( numkeys ) + " signatures. " ) ;
// extract and validate PUBKEYs
std : : vector < CPubKey > pubkeys ;
for ( int pos = 1 ; pos < = int ( numkeys ) ; pos + + ) {
CPubKey pubkey ( ParseHex ( vStrInputParts [ pos + 2 ] ) ) ;
if ( ! pubkey . IsFullyValid ( ) )
throw std : : runtime_error ( " invalid TX output pubkey " ) ;
pubkeys . push_back ( pubkey ) ;
}
// Extract FLAGS
bool bSegWit = false ;
bool bScriptHash = false ;
if ( vStrInputParts . size ( ) = = numkeys + 4 ) {
std : : string flags = vStrInputParts . back ( ) ;
bSegWit = ( flags . find ( " W " ) ! = std : : string : : npos ) ;
bScriptHash = ( flags . find ( " S " ) ! = std : : string : : npos ) ;
}
else if ( vStrInputParts . size ( ) > numkeys + 4 ) {
// Validate that there were no more parameters passed
throw std : : runtime_error ( " Too many parameters " ) ;
}
CScript scriptPubKey = GetScriptForMultisig ( required , pubkeys ) ;
if ( bSegWit ) {
// Call GetScriptForWitness() to build a P2WSH scriptPubKey
scriptPubKey = GetScriptForWitness ( scriptPubKey ) ;
}
if ( bScriptHash ) {
// Get the address for the redeem script, then call
// GetScriptForDestination() to construct a P2SH scriptPubKey.
CBitcoinAddress addr ( scriptPubKey ) ;
scriptPubKey = GetScriptForDestination ( addr . Get ( ) ) ;
}
// construct TxOut, append to transaction output list
CTxOut txout ( value , scriptPubKey ) ;
tx . vout . push_back ( txout ) ;
}
static void MutateTxAddOutData ( CMutableTransaction & tx , const std : : string & strInput )
static void MutateTxAddOutData ( CMutableTransaction & tx , const std : : string & strInput )
{
{
CAmount value = 0 ;
CAmount value = 0 ;
@ -262,10 +377,8 @@ static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strIn
throw std : : runtime_error ( " TX output value not specified " ) ;
throw std : : runtime_error ( " TX output value not specified " ) ;
if ( pos ! = std : : string : : npos ) {
if ( pos ! = std : : string : : npos ) {
// extract and validate VALUE
// Extract and validate VALUE
std : : string strValue = strInput . substr ( 0 , pos ) ;
value = ExtractAndValidateValue ( strInput . substr ( 0 , pos ) ) ;
if ( ! ParseMoney ( strValue , value ) )
throw std : : runtime_error ( " invalid TX output value " ) ;
}
}
// extract and validate DATA
// extract and validate DATA
@ -282,26 +395,32 @@ static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strIn
static void MutateTxAddOutScript ( CMutableTransaction & tx , const std : : string & strInput )
static void MutateTxAddOutScript ( CMutableTransaction & tx , const std : : string & strInput )
{
{
// separate VALUE:SCRIPT(:SEGWIT)(:P2SH)
// separate VALUE:SCRIPT[:FLAGS]
std : : vector < std : : string > vStrInput ;
std : : vector < std : : string > vStrInputParts ;
boost : : split ( vStrInput , strInput , boost : : is_any_of ( " : " ) ) ;
boost : : split ( vStrInputParts , strInput , boost : : is_any_of ( " : " ) ) ;
if ( vStrInput . size ( ) < 2 )
if ( vStrInputParts . size ( ) < 2 )
throw sr d : : runtime_error ( " TX output missing separator " ) ;
throw st d : : runtime_error ( " TX output missing separator " ) ;
// extract and validate VALUE
// Extract and validate VALUE
std : : string strValue = vStrInput [ 0 ] ;
CAmount value = ExtractAndValidateValue ( vStrInputParts [ 0 ] ) ;
CAmount value ;
if ( ! ParseMoney ( strValue , value ) )
throw std : : runtime_error ( " invalid TX output value " ) ;
// extract and validate script
// extract and validate script
std : : string strScript = vStrInput [ 1 ] ;
std : : string strScript = vStrInputParts [ 1 ] ;
CScript scriptPubKey = ParseScript ( strScript ) ; // throws on err
CScript scriptPubKey = ParseScript ( strScript ) ;
// Extract FLAGS
bool bSegWit = false ;
bool bScriptHash = false ;
if ( vStrInputParts . size ( ) = = 3 ) {
std : : string flags = vStrInputParts . back ( ) ;
bSegWit = ( flags . find ( " W " ) ! = std : : string : : npos ) ;
bScriptHash = ( flags . find ( " S " ) ! = std : : string : : npos ) ;
}
if ( std : : find ( vStrInput . begin ( ) , vStrInput . end ( ) , " SEGWIT " ) ! = vStrInput . end ( ) ) {
if ( bSegWit ) {
scriptPubKey = GetScriptForWitness ( scriptPubKey ) ;
scriptPubKey = GetScriptForWitness ( scriptPubKey ) ;
}
}
if ( std : : find ( vStrInput . begin ( ) , vStrInput . end ( ) , " P2SH " ) ! = vStrInput . end ( ) ) {
if ( bScriptHash ) {
CBitcoinAddress addr ( scriptPubKey ) ;
CBitcoinAddress addr ( scriptPubKey ) ;
scriptPubKey = GetScriptForDestination ( addr . Get ( ) ) ;
scriptPubKey = GetScriptForDestination ( addr . Get ( ) ) ;
}
}
@ -548,10 +667,14 @@ static void MutateTx(CMutableTransaction& tx, const std::string& command,
MutateTxDelOutput ( tx , commandVal ) ;
MutateTxDelOutput ( tx , commandVal ) ;
else if ( command = = " outaddr " )
else if ( command = = " outaddr " )
MutateTxAddOutAddr ( tx , commandVal ) ;
MutateTxAddOutAddr ( tx , commandVal ) ;
else if ( command = = " outdata " )
else if ( command = = " outpubkey " )
MutateTxAddOutData ( tx , commandVal ) ;
MutateTxAddOutPubKey ( tx , commandVal ) ;
else if ( command = = " outmultisig " )
MutateTxAddOutMultiSig ( tx , commandVal ) ;
else if ( command = = " outscript " )
else if ( command = = " outscript " )
MutateTxAddOutScript ( tx , commandVal ) ;
MutateTxAddOutScript ( tx , commandVal ) ;
else if ( command = = " outdata " )
MutateTxAddOutData ( tx , commandVal ) ;
else if ( command = = " sign " ) {
else if ( command = = " sign " ) {
if ( ! ecc ) { ecc . reset ( new Secp256k1Init ( ) ) ; }
if ( ! ecc ) { ecc . reset ( new Secp256k1Init ( ) ) ; }