2018-07-27 00:36:45 +02:00
// Copyright (c) 2009-2018 The Bitcoin Core developers
2014-12-13 05:09:33 +01:00
// Distributed under the MIT software license, see the accompanying
2014-08-01 08:39:06 +02:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2014-06-24 05:10:24 +02:00
2017-11-10 01:57:53 +01:00
# include <core_io.h>
2014-09-14 12:43:56 +02:00
2017-11-10 01:57:53 +01:00
# include <consensus/consensus.h>
# include <consensus/validation.h>
2017-09-20 03:12:25 +02:00
# include <key_io.h>
2017-11-10 01:57:53 +01:00
# include <script/script.h>
# include <script/standard.h>
# include <serialize.h>
# include <streams.h>
2015-09-04 16:11:34 +02:00
# include <univalue.h>
2017-11-10 01:57:53 +01:00
# include <util.h>
# include <utilmoneystr.h>
# include <utilstrencodings.h>
2014-06-24 05:10:24 +02:00
2017-08-07 14:38:39 +02:00
UniValue ValueFromAmount ( const CAmount & amount )
{
bool sign = amount < 0 ;
int64_t n_abs = ( sign ? - amount : amount ) ;
int64_t quotient = n_abs / COIN ;
int64_t remainder = n_abs % COIN ;
return UniValue ( UniValue : : VNUM ,
strprintf ( " %s%d.%08d " , sign ? " - " : " " , quotient , remainder ) ) ;
}
2017-01-27 09:43:41 +01:00
std : : string FormatScript ( const CScript & script )
2014-09-20 03:13:04 +02:00
{
2017-01-27 09:43:41 +01:00
std : : string ret ;
2014-09-20 03:13:04 +02:00
CScript : : const_iterator it = script . begin ( ) ;
opcodetype op ;
while ( it ! = script . end ( ) ) {
CScript : : const_iterator it2 = it ;
2017-01-27 09:43:41 +01:00
std : : vector < unsigned char > vch ;
2018-04-04 18:14:13 +02:00
if ( script . GetOp ( it , op , vch ) ) {
2014-09-20 03:13:04 +02:00
if ( op = = OP_0 ) {
ret + = " 0 " ;
continue ;
} else if ( ( op > = OP_1 & & op < = OP_16 ) | | op = = OP_1NEGATE ) {
ret + = strprintf ( " %i " , op - OP_1NEGATE - 1 ) ;
continue ;
2016-04-05 14:26:01 +02:00
} else if ( op > = OP_NOP & & op < = OP_NOP10 ) {
2017-01-27 09:43:41 +01:00
std : : string str ( GetOpName ( op ) ) ;
if ( str . substr ( 0 , 3 ) = = std : : string ( " OP_ " ) ) {
ret + = str . substr ( 3 , std : : string : : npos ) + " " ;
2014-09-20 03:13:04 +02:00
continue ;
}
}
if ( vch . size ( ) > 0 ) {
ret + = strprintf ( " 0x%x 0x%x " , HexStr ( it2 , it - vch . size ( ) ) , HexStr ( it - vch . size ( ) , it ) ) ;
} else {
2016-04-05 14:26:01 +02:00
ret + = strprintf ( " 0x%x " , HexStr ( it2 , it ) ) ;
2014-09-20 03:13:04 +02:00
}
continue ;
}
ret + = strprintf ( " 0x%x " , HexStr ( it2 , script . end ( ) ) ) ;
break ;
}
return ret . substr ( 0 , ret . size ( ) - 1 ) ;
}
2017-06-06 21:15:28 +02:00
const std : : map < unsigned char , std : : string > mapSigHashTypes = {
{ static_cast < unsigned char > ( SIGHASH_ALL ) , std : : string ( " ALL " ) } ,
{ static_cast < unsigned char > ( SIGHASH_ALL | SIGHASH_ANYONECANPAY ) , std : : string ( " ALL|ANYONECANPAY " ) } ,
{ static_cast < unsigned char > ( SIGHASH_NONE ) , std : : string ( " NONE " ) } ,
{ static_cast < unsigned char > ( SIGHASH_NONE | SIGHASH_ANYONECANPAY ) , std : : string ( " NONE|ANYONECANPAY " ) } ,
{ static_cast < unsigned char > ( SIGHASH_SINGLE ) , std : : string ( " SINGLE " ) } ,
{ static_cast < unsigned char > ( SIGHASH_SINGLE | SIGHASH_ANYONECANPAY ) , std : : string ( " SINGLE|ANYONECANPAY " ) } ,
} ;
2015-07-31 01:56:00 +02:00
2018-06-29 04:04:40 +02:00
std : : string SighashToStr ( unsigned char sighash_type )
{
const auto & it = mapSigHashTypes . find ( sighash_type ) ;
if ( it = = mapSigHashTypes . end ( ) ) return " " ;
return it - > second ;
}
2015-07-31 01:56:00 +02:00
/**
* Create the assembly string representation of a CScript object .
* @ param [ in ] script CScript object to convert into the asm string representation .
* @ param [ in ] fAttemptSighashDecode Whether to attempt to decode sighash types on data within the script that matches the format
* of a signature . Only pass true for scripts you believe could contain signatures . For example ,
* pass false , or omit the this argument ( defaults to false ) , for scriptPubKeys .
*/
2017-01-27 09:43:41 +01:00
std : : string ScriptToAsmStr ( const CScript & script , const bool fAttemptSighashDecode )
2015-07-31 01:56:00 +02:00
{
2017-01-27 09:43:41 +01:00
std : : string str ;
2015-07-31 01:56:00 +02:00
opcodetype opcode ;
2017-01-27 09:43:41 +01:00
std : : vector < unsigned char > vch ;
2015-07-31 01:56:00 +02:00
CScript : : const_iterator pc = script . begin ( ) ;
while ( pc < script . end ( ) ) {
if ( ! str . empty ( ) ) {
str + = " " ;
}
if ( ! script . GetOp ( pc , opcode , vch ) ) {
str + = " [error] " ;
return str ;
}
if ( 0 < = opcode & & opcode < = OP_PUSHDATA4 ) {
2017-01-27 09:43:41 +01:00
if ( vch . size ( ) < = static_cast < std : : vector < unsigned char > : : size_type > ( 4 ) ) {
2015-07-31 01:56:00 +02:00
str + = strprintf ( " %d " , CScriptNum ( vch , false ) . getint ( ) ) ;
} else {
// the IsUnspendable check makes sure not to try to decode OP_RETURN data that may match the format of a signature
if ( fAttemptSighashDecode & & ! script . IsUnspendable ( ) ) {
2017-01-27 09:43:41 +01:00
std : : string strSigHashDecode ;
2015-07-31 01:56:00 +02:00
// goal: only attempt to decode a defined sighash type from data that looks like a signature within a scriptSig.
// this won't decode correctly formatted public keys in Pubkey or Multisig scripts due to
// the restrictions on the pubkey formats (see IsCompressedOrUncompressedPubKey) being incongruous with the
// checks in CheckSignatureEncoding.
2017-08-07 07:36:37 +02:00
if ( CheckSignatureEncoding ( vch , SCRIPT_VERIFY_STRICTENC , nullptr ) ) {
2015-07-31 01:56:00 +02:00
const unsigned char chSigHashType = vch . back ( ) ;
if ( mapSigHashTypes . count ( chSigHashType ) ) {
strSigHashDecode = " [ " + mapSigHashTypes . find ( chSigHashType ) - > second + " ] " ;
vch . pop_back ( ) ; // remove the sighash type byte. it will be replaced by the decode.
}
}
str + = HexStr ( vch ) + strSigHashDecode ;
} else {
str + = HexStr ( vch ) ;
}
}
} else {
str + = GetOpName ( opcode ) ;
}
}
return str ;
}
2017-03-18 21:32:14 +01:00
std : : string EncodeHexTx ( const CTransaction & tx , const int serializeFlags )
2014-06-24 05:10:24 +02:00
{
2017-03-18 21:32:14 +01:00
CDataStream ssTx ( SER_NETWORK , PROTOCOL_VERSION | serializeFlags ) ;
2014-06-24 05:10:24 +02:00
ssTx < < tx ;
return HexStr ( ssTx . begin ( ) , ssTx . end ( ) ) ;
}
2018-06-29 04:04:40 +02:00
void ScriptToUniv ( const CScript & script , UniValue & out , bool include_address )
{
out . pushKV ( " asm " , ScriptToAsmStr ( script ) ) ;
out . pushKV ( " hex " , HexStr ( script . begin ( ) , script . end ( ) ) ) ;
std : : vector < std : : vector < unsigned char > > solns ;
2018-06-11 07:19:07 +02:00
txnouttype type = Solver ( script , solns ) ;
2018-06-29 04:04:40 +02:00
out . pushKV ( " type " , GetTxnOutputType ( type ) ) ;
CTxDestination address ;
if ( include_address & & ExtractDestination ( script , address ) ) {
out . pushKV ( " address " , EncodeDestination ( address ) ) ;
}
}
2014-07-29 17:12:44 +02:00
void ScriptPubKeyToUniv ( const CScript & scriptPubKey ,
UniValue & out , bool fIncludeHex )
{
txnouttype type ;
2017-01-27 09:43:41 +01:00
std : : vector < CTxDestination > addresses ;
2014-07-29 17:12:44 +02:00
int nRequired ;
2015-07-31 01:56:00 +02:00
out . pushKV ( " asm " , ScriptToAsmStr ( scriptPubKey ) ) ;
2014-07-29 17:12:44 +02:00
if ( fIncludeHex )
out . pushKV ( " hex " , HexStr ( scriptPubKey . begin ( ) , scriptPubKey . end ( ) ) ) ;
if ( ! ExtractDestinations ( scriptPubKey , type , addresses , nRequired ) ) {
out . pushKV ( " type " , GetTxnOutputType ( type ) ) ;
return ;
}
out . pushKV ( " reqSigs " , nRequired ) ;
out . pushKV ( " type " , GetTxnOutputType ( type ) ) ;
UniValue a ( UniValue : : VARR ) ;
2017-08-23 03:02:33 +02:00
for ( const CTxDestination & addr : addresses ) {
a . push_back ( EncodeDestination ( addr ) ) ;
}
2014-07-29 17:12:44 +02:00
out . pushKV ( " addresses " , a ) ;
}
2017-08-11 21:21:14 +02:00
void TxToUniv ( const CTransaction & tx , const uint256 & hashBlock , UniValue & entry , bool include_hex , int serialize_flags )
2014-07-29 17:12:44 +02:00
{
entry . pushKV ( " txid " , tx . GetHash ( ) . GetHex ( ) ) ;
2016-09-21 16:52:53 +02:00
entry . pushKV ( " hash " , tx . GetWitnessHash ( ) . GetHex ( ) ) ;
2014-07-29 17:12:44 +02:00
entry . pushKV ( " version " , tx . nVersion ) ;
2016-09-22 02:51:00 +02:00
entry . pushKV ( " size " , ( int ) : : GetSerializeSize ( tx , SER_NETWORK , PROTOCOL_VERSION ) ) ;
entry . pushKV ( " vsize " , ( GetTransactionWeight ( tx ) + WITNESS_SCALE_FACTOR - 1 ) / WITNESS_SCALE_FACTOR ) ;
2018-03-26 17:20:56 +02:00
entry . pushKV ( " weight " , GetTransactionWeight ( tx ) ) ;
2014-07-29 17:12:44 +02:00
entry . pushKV ( " locktime " , ( int64_t ) tx . nLockTime ) ;
UniValue vin ( UniValue : : VARR ) ;
2016-09-21 16:52:53 +02:00
for ( unsigned int i = 0 ; i < tx . vin . size ( ) ; i + + ) {
const CTxIn & txin = tx . vin [ i ] ;
2014-07-29 17:12:44 +02:00
UniValue in ( UniValue : : VOBJ ) ;
if ( tx . IsCoinBase ( ) )
in . pushKV ( " coinbase " , HexStr ( txin . scriptSig . begin ( ) , txin . scriptSig . end ( ) ) ) ;
else {
in . pushKV ( " txid " , txin . prevout . hash . GetHex ( ) ) ;
in . pushKV ( " vout " , ( int64_t ) txin . prevout . n ) ;
UniValue o ( UniValue : : VOBJ ) ;
2015-07-31 01:56:00 +02:00
o . pushKV ( " asm " , ScriptToAsmStr ( txin . scriptSig , true ) ) ;
2014-07-29 17:12:44 +02:00
o . pushKV ( " hex " , HexStr ( txin . scriptSig . begin ( ) , txin . scriptSig . end ( ) ) ) ;
in . pushKV ( " scriptSig " , o ) ;
2016-08-04 02:49:16 +02:00
if ( ! tx . vin [ i ] . scriptWitness . IsNull ( ) ) {
2016-09-21 16:52:53 +02:00
UniValue txinwitness ( UniValue : : VARR ) ;
2016-08-04 02:49:16 +02:00
for ( const auto & item : tx . vin [ i ] . scriptWitness . stack ) {
2016-09-21 16:52:53 +02:00
txinwitness . push_back ( HexStr ( item . begin ( ) , item . end ( ) ) ) ;
}
in . pushKV ( " txinwitness " , txinwitness ) ;
}
2014-07-29 17:12:44 +02:00
}
in . pushKV ( " sequence " , ( int64_t ) txin . nSequence ) ;
vin . push_back ( in ) ;
}
entry . pushKV ( " vin " , vin ) ;
UniValue vout ( UniValue : : VARR ) ;
for ( unsigned int i = 0 ; i < tx . vout . size ( ) ; i + + ) {
const CTxOut & txout = tx . vout [ i ] ;
UniValue out ( UniValue : : VOBJ ) ;
2017-08-07 14:41:29 +02:00
out . pushKV ( " value " , ValueFromAmount ( txout . nValue ) ) ;
2014-07-29 17:12:44 +02:00
out . pushKV ( " n " , ( int64_t ) i ) ;
UniValue o ( UniValue : : VOBJ ) ;
ScriptPubKeyToUniv ( txout . scriptPubKey , o , true ) ;
out . pushKV ( " scriptPubKey " , o ) ;
vout . push_back ( out ) ;
}
entry . pushKV ( " vout " , vout ) ;
2014-12-15 09:11:16 +01:00
if ( ! hashBlock . IsNull ( ) )
2014-07-29 17:12:44 +02:00
entry . pushKV ( " blockhash " , hashBlock . GetHex ( ) ) ;
2014-11-04 19:01:41 +01:00
2017-08-11 21:21:14 +02:00
if ( include_hex ) {
2018-03-18 15:26:45 +01:00
entry . pushKV ( " hex " , EncodeHexTx ( tx , serialize_flags ) ) ; // The hex-encoded transaction. Used the name "hex" to be consistent with the verbose output of "getrawtransaction".
2017-08-11 21:21:14 +02:00
}
2014-07-29 17:12:44 +02:00
}