2022-12-24 20:49:50 -03:00
// Copyright (c) 2009-2022 The Bitcoin Core developers
2014-12-13 01:09:33 -03:00
// Distributed under the MIT software license, see the accompanying
2014-08-01 02:39:06 -04:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2014-06-23 23:10:24 -04:00
2017-11-09 21:57:53 -03:00
# include <core_io.h>
2014-09-14 07:43:56 -03:00
2023-05-08 05:32:13 -04:00
# include <common/system.h>
2021-09-10 23:29:00 -03:00
# include <consensus/amount.h>
2017-11-09 21:57:53 -03:00
# include <consensus/consensus.h>
# include <consensus/validation.h>
2017-09-19 22:12:25 -03:00
# include <key_io.h>
2019-09-03 12:04:30 -04:00
# include <script/descriptor.h>
2017-11-09 21:57:53 -03:00
# include <script/script.h>
# include <script/standard.h>
# include <serialize.h>
# include <streams.h>
2020-10-09 12:50:44 -03:00
# include <undo.h>
2015-09-04 11:11:34 -03:00
# include <univalue.h>
2020-10-09 12:50:44 -03:00
# include <util/check.h>
2018-10-22 19:51:11 -03:00
# include <util/strencodings.h>
2014-06-23 23:10:24 -04:00
2022-03-30 16:11:15 -03:00
# include <map>
# include <string>
# include <vector>
2020-11-16 13:44:50 -03:00
UniValue ValueFromAmount ( const CAmount amount )
2017-08-07 08:38:39 -04:00
{
2020-11-16 13:44:50 -03:00
static_assert ( COIN > 1 ) ;
int64_t quotient = amount / COIN ;
int64_t remainder = amount % COIN ;
if ( amount < 0 ) {
quotient = - quotient ;
remainder = - remainder ;
}
2017-08-07 08:38:39 -04:00
return UniValue ( UniValue : : VNUM ,
2020-11-16 13:44:50 -03:00
strprintf ( " %s%d.%08d " , amount < 0 ? " - " : " " , quotient , remainder ) ) ;
2017-08-07 08:38:39 -04:00
}
2017-01-27 05:43:41 -03:00
std : : string FormatScript ( const CScript & script )
2014-09-19 22:13:04 -03:00
{
2017-01-27 05:43:41 -03:00
std : : string ret ;
2014-09-19 22:13:04 -03:00
CScript : : const_iterator it = script . begin ( ) ;
opcodetype op ;
while ( it ! = script . end ( ) ) {
CScript : : const_iterator it2 = it ;
2017-01-27 05:43:41 -03:00
std : : vector < unsigned char > vch ;
2018-04-04 13:14:13 -03:00
if ( script . GetOp ( it , op , vch ) ) {
2014-09-19 22:13:04 -03: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 09:26:01 -03:00
} else if ( op > = OP_NOP & & op < = OP_NOP10 ) {
2017-01-27 05:43:41 -03:00
std : : string str ( GetOpName ( op ) ) ;
if ( str . substr ( 0 , 3 ) = = std : : string ( " OP_ " ) ) {
ret + = str . substr ( 3 , std : : string : : npos ) + " " ;
2014-09-19 22:13:04 -03:00
continue ;
}
}
if ( vch . size ( ) > 0 ) {
2020-06-24 11:26:47 -04:00
ret + = strprintf ( " 0x%x 0x%x " , HexStr ( std : : vector < uint8_t > ( it2 , it - vch . size ( ) ) ) ,
HexStr ( std : : vector < uint8_t > ( it - vch . size ( ) , it ) ) ) ;
2014-09-19 22:13:04 -03:00
} else {
2020-06-24 11:26:47 -04:00
ret + = strprintf ( " 0x%x " , HexStr ( std : : vector < uint8_t > ( it2 , it ) ) ) ;
2014-09-19 22:13:04 -03:00
}
continue ;
}
2020-06-24 11:26:47 -04:00
ret + = strprintf ( " 0x%x " , HexStr ( std : : vector < uint8_t > ( it2 , script . end ( ) ) ) ) ;
2014-09-19 22:13:04 -03:00
break ;
}
2022-02-11 13:26:40 -03:00
return ret . substr ( 0 , ret . empty ( ) ? ret . npos : ret . size ( ) - 1 ) ;
2014-09-19 22:13:04 -03:00
}
2017-06-06 15:15:28 -04: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-30 20:56:00 -03:00
2018-06-28 22:04:40 -04: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-30 20:56:00 -03: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 05:43:41 -03:00
std : : string ScriptToAsmStr ( const CScript & script , const bool fAttemptSighashDecode )
2015-07-30 20:56:00 -03:00
{
2017-01-27 05:43:41 -03:00
std : : string str ;
2015-07-30 20:56:00 -03:00
opcodetype opcode ;
2017-01-27 05:43:41 -03:00
std : : vector < unsigned char > vch ;
2015-07-30 20:56:00 -03: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 05:43:41 -03:00
if ( vch . size ( ) < = static_cast < std : : vector < unsigned char > : : size_type > ( 4 ) ) {
2015-07-30 20:56:00 -03: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 05:43:41 -03:00
std : : string strSigHashDecode ;
2015-07-30 20:56:00 -03: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 01:36:37 -04:00
if ( CheckSignatureEncoding ( vch , SCRIPT_VERIFY_STRICTENC , nullptr ) ) {
2015-07-30 20:56:00 -03:00
const unsigned char chSigHashType = vch . back ( ) ;
2020-08-31 17:11:06 -04:00
const auto it = mapSigHashTypes . find ( chSigHashType ) ;
if ( it ! = mapSigHashTypes . end ( ) ) {
strSigHashDecode = " [ " + it - > second + " ] " ;
2015-07-30 20:56:00 -03:00
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 17:32:14 -03:00
std : : string EncodeHexTx ( const CTransaction & tx , const int serializeFlags )
2014-06-23 23:10:24 -04:00
{
2017-03-18 17:32:14 -03:00
CDataStream ssTx ( SER_NETWORK , PROTOCOL_VERSION | serializeFlags ) ;
2014-06-23 23:10:24 -04:00
ssTx < < tx ;
2020-06-24 09:48:26 -04:00
return HexStr ( ssTx ) ;
2014-06-23 23:10:24 -04:00
}
2023-02-03 13:44:22 -03:00
void ScriptToUniv ( const CScript & script , UniValue & out , bool include_hex , bool include_address , const SigningProvider * provider )
2014-07-29 11:12:44 -04:00
{
2021-02-01 12:52:07 -03:00
CTxDestination address ;
2014-07-29 11:12:44 -04:00
2021-09-28 20:11:49 -03:00
out . pushKV ( " asm " , ScriptToAsmStr ( script ) ) ;
2022-03-22 07:49:58 -03:00
if ( include_address ) {
2023-02-03 13:44:22 -03:00
out . pushKV ( " desc " , InferDescriptor ( script , provider ? * provider : DUMMY_SIGNING_PROVIDER ) - > ToString ( ) ) ;
2021-09-28 20:11:49 -03:00
}
if ( include_hex ) {
out . pushKV ( " hex " , HexStr ( script ) ) ;
2022-03-22 07:49:58 -03:00
}
2014-07-29 11:12:44 -04:00
2021-05-10 14:13:40 -04:00
std : : vector < std : : vector < unsigned char > > solns ;
2021-09-28 20:11:49 -03:00
const TxoutType type { Solver ( script , solns ) } ;
2014-07-29 11:12:44 -04:00
2021-09-28 20:11:49 -03:00
if ( include_address & & ExtractDestination ( script , address ) & & type ! = TxoutType : : PUBKEY ) {
2021-02-01 12:52:07 -03:00
out . pushKV ( " address " , EncodeDestination ( address ) ) ;
}
2014-07-29 11:12:44 -04:00
out . pushKV ( " type " , GetTxnOutputType ( type ) ) ;
}
2021-09-29 11:58:36 -03:00
void TxToUniv ( const CTransaction & tx , const uint256 & block_hash , UniValue & entry , bool include_hex , int serialize_flags , const CTxUndo * txundo , TxVerbosity verbosity )
2014-07-29 11:12:44 -04:00
{
2023-01-26 08:21:27 -03:00
CHECK_NONFATAL ( verbosity > = TxVerbosity : : SHOW_DETAILS ) ;
2014-07-29 11:12:44 -04:00
entry . pushKV ( " txid " , tx . GetHash ( ) . GetHex ( ) ) ;
2016-09-21 11:52:53 -03:00
entry . pushKV ( " hash " , tx . GetWitnessHash ( ) . GetHex ( ) ) ;
2019-08-01 17:54:48 -04:00
// Transaction version is actually unsigned in consensus checks, just signed in memory,
// so cast to unsigned before giving it to the user.
entry . pushKV ( " version " , static_cast < int64_t > ( static_cast < uint32_t > ( tx . nVersion ) ) ) ;
2018-06-22 14:27:18 -04:00
entry . pushKV ( " size " , ( int ) : : GetSerializeSize ( tx , PROTOCOL_VERSION ) ) ;
2016-09-21 21:51:00 -03:00
entry . pushKV ( " vsize " , ( GetTransactionWeight ( tx ) + WITNESS_SCALE_FACTOR - 1 ) / WITNESS_SCALE_FACTOR ) ;
2018-03-26 12:20:56 -03:00
entry . pushKV ( " weight " , GetTransactionWeight ( tx ) ) ;
2014-07-29 11:12:44 -04:00
entry . pushKV ( " locktime " , ( int64_t ) tx . nLockTime ) ;
2020-10-09 12:50:44 -03:00
UniValue vin { UniValue : : VARR } ;
// If available, use Undo data to calculate the fee. Note that txundo == nullptr
// for coinbase transactions and for transactions where undo data is unavailable.
2021-08-03 18:00:31 -04:00
const bool have_undo = txundo ! = nullptr ;
2020-10-09 12:50:44 -03:00
CAmount amt_total_in = 0 ;
CAmount amt_total_out = 0 ;
2016-09-21 11:52:53 -03:00
for ( unsigned int i = 0 ; i < tx . vin . size ( ) ; i + + ) {
const CTxIn & txin = tx . vin [ i ] ;
2014-07-29 11:12:44 -04:00
UniValue in ( UniValue : : VOBJ ) ;
2020-10-09 12:50:44 -03:00
if ( tx . IsCoinBase ( ) ) {
2020-06-24 09:48:26 -04:00
in . pushKV ( " coinbase " , HexStr ( txin . scriptSig ) ) ;
2020-10-09 12:50:44 -03:00
} else {
2014-07-29 11:12:44 -04:00
in . pushKV ( " txid " , txin . prevout . hash . GetHex ( ) ) ;
in . pushKV ( " vout " , ( int64_t ) txin . prevout . n ) ;
UniValue o ( UniValue : : VOBJ ) ;
2015-07-30 20:56:00 -03:00
o . pushKV ( " asm " , ScriptToAsmStr ( txin . scriptSig , true ) ) ;
2020-06-24 09:48:26 -04:00
o . pushKV ( " hex " , HexStr ( txin . scriptSig ) ) ;
2014-07-29 11:12:44 -04:00
in . pushKV ( " scriptSig " , o ) ;
2020-04-30 04:55:57 -04:00
}
if ( ! tx . vin [ i ] . scriptWitness . IsNull ( ) ) {
UniValue txinwitness ( UniValue : : VARR ) ;
for ( const auto & item : tx . vin [ i ] . scriptWitness . stack ) {
2020-06-24 09:48:26 -04:00
txinwitness . push_back ( HexStr ( item ) ) ;
2016-09-21 11:52:53 -03:00
}
2020-04-30 04:55:57 -04:00
in . pushKV ( " txinwitness " , txinwitness ) ;
2014-07-29 11:12:44 -04:00
}
2021-08-03 18:00:31 -04:00
if ( have_undo ) {
2021-02-27 14:39:09 -03:00
const Coin & prev_coin = txundo - > vprevout [ i ] ;
const CTxOut & prev_txout = prev_coin . out ;
2020-10-09 12:50:44 -03:00
amt_total_in + = prev_txout . nValue ;
2021-10-20 03:00:44 -03:00
if ( verbosity = = TxVerbosity : : SHOW_DETAILS_AND_PREVOUT ) {
UniValue o_script_pub_key ( UniValue : : VOBJ ) ;
2021-09-28 20:11:49 -03:00
ScriptToUniv ( prev_txout . scriptPubKey , /*out=*/ o_script_pub_key , /*include_hex=*/ true , /*include_address=*/ true ) ;
2021-10-20 03:00:44 -03:00
UniValue p ( UniValue : : VOBJ ) ;
p . pushKV ( " generated " , bool ( prev_coin . fCoinBase ) ) ;
p . pushKV ( " height " , uint64_t ( prev_coin . nHeight ) ) ;
p . pushKV ( " value " , ValueFromAmount ( prev_txout . nValue ) ) ;
p . pushKV ( " scriptPubKey " , o_script_pub_key ) ;
in . pushKV ( " prevout " , p ) ;
2021-02-27 14:39:09 -03:00
}
2020-10-09 12:50:44 -03:00
}
2014-07-29 11:12:44 -04: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 08:41:29 -04:00
out . pushKV ( " value " , ValueFromAmount ( txout . nValue ) ) ;
2014-07-29 11:12:44 -04:00
out . pushKV ( " n " , ( int64_t ) i ) ;
UniValue o ( UniValue : : VOBJ ) ;
2021-09-28 20:11:49 -03:00
ScriptToUniv ( txout . scriptPubKey , /*out=*/ o , /*include_hex=*/ true , /*include_address=*/ true ) ;
2014-07-29 11:12:44 -04:00
out . pushKV ( " scriptPubKey " , o ) ;
vout . push_back ( out ) ;
2020-10-09 12:50:44 -03:00
2021-08-03 18:00:31 -04:00
if ( have_undo ) {
2020-10-09 12:50:44 -03:00
amt_total_out + = txout . nValue ;
}
2014-07-29 11:12:44 -04:00
}
entry . pushKV ( " vout " , vout ) ;
2021-08-03 18:00:31 -04:00
if ( have_undo ) {
2020-10-09 12:50:44 -03:00
const CAmount fee = amt_total_in - amt_total_out ;
CHECK_NONFATAL ( MoneyRange ( fee ) ) ;
entry . pushKV ( " fee " , ValueFromAmount ( fee ) ) ;
}
2021-09-29 11:58:36 -03:00
if ( ! block_hash . IsNull ( ) ) {
entry . pushKV ( " blockhash " , block_hash . GetHex ( ) ) ;
}
2014-11-04 15:01:41 -03:00
2017-08-11 15:21:14 -04:00
if ( include_hex ) {
2018-03-18 11:26:45 -03: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 15:21:14 -04:00
}
2014-07-29 11:12:44 -04:00
}