2015-12-13 14:51:43 +01:00
// Copyright (c) 2009-2015 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
2020-03-19 23:46:56 +01:00
# include <core_io.h>
2014-09-14 12:43:56 +02:00
Merge #11372: Address encoding cleanup
92f1f8b31 Split off key_io_tests from base58_tests (Pieter Wuille)
119b0f85e Split key_io (address/key encodings) off from base58 (Pieter Wuille)
ebfe217b1 Stop using CBase58Data for ext keys (Pieter Wuille)
32e69fa0d Replace CBitcoinSecret with {Encode,Decode}Secret (Pieter Wuille)
Pull request description:
This PR contains some of the changes left as TODO in #11167 (and built on top of that PR). They are not intended for backporting.
This removes the `CBase58`, `CBitcoinSecret`, `CBitcoinExtKey`, and `CBitcoinExtPubKey` classes, in favor of simple `Encode`/`Decode` functions. Furthermore, all Bitcoin-specific logic (addresses, WIF, BIP32) is moved to `key_io.{h,cpp}`, leaving `base58.{h,cpp}` as a pure utility that implements the base58 encoding/decoding logic.
Tree-SHA512: a5962c0ed27ad53cbe00f22af432cf11aa530e3efc9798e25c004bc9ed1b5673db5df3956e398ee2c085e3a136ac8da69fe7a7d97a05fb2eb3be0b60d0479655
Make linter happy
Dashify
2018-03-07 00:04:56 +01:00
# include <consensus/consensus.h>
# include <consensus/validation.h>
# include <key_io.h>
2020-03-19 23:46:56 +01:00
# include <primitives/transaction.h>
# include <script/script.h>
# include <script/standard.h>
# include <serialize.h>
# include <streams.h>
# include <univalue.h>
2021-06-27 08:33:13 +02:00
# include <util/system.h>
# include <util/moneystr.h>
# include <util/strencodings.h>
2014-06-24 05:10:24 +02:00
2020-03-19 23:46:56 +01:00
# include <spentindex.h>
2019-06-11 13:42:17 +02:00
2020-03-19 23:46:56 +01:00
# include <evo/cbtx.h>
# include <evo/providertx.h>
# include <evo/specialtx.h>
# include <llmq/quorums_commitment.h>
2019-06-11 13:42:17 +02:00
2017-08-08 11:27:15 +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 ) ) ;
}
2014-08-23 05:09:47 +02:00
2017-01-30 13:13:07 +01:00
std : : string FormatScript ( const CScript & script )
2014-09-20 03:13:04 +02:00
{
2017-01-30 13:13:07 +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-30 13:13:07 +01:00
std : : vector < unsigned char > vch ;
2018-04-23 21:08:42 +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:54:18 +02:00
} else if ( op > = OP_NOP & & op < = OP_NOP10 ) {
2017-01-30 13:13:07 +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 ) {
2020-06-24 17:26:47 +02: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-20 03:13:04 +02:00
} else {
2020-06-24 17:26:47 +02:00
ret + = strprintf ( " 0x%x " , HexStr ( std : : vector < uint8_t > ( it2 , it ) ) ) ;
2014-09-20 03:13:04 +02:00
}
continue ;
}
2020-06-24 17:26:47 +02:00
ret + = strprintf ( " 0x%x " , HexStr ( std : : vector < uint8_t > ( it2 , script . end ( ) ) ) ) ;
2014-09-20 03:13:04 +02:00
break ;
}
return ret . substr ( 0 , ret . size ( ) - 1 ) ;
}
2017-06-08 19:35: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
/**
* 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-30 13:13:07 +01:00
std : : string ScriptToAsmStr ( const CScript & script , const bool fAttemptSighashDecode )
2015-07-31 01:56:00 +02:00
{
2017-01-30 13:13:07 +01:00
std : : string str ;
2015-07-31 01:56:00 +02:00
opcodetype opcode ;
2017-01-30 13:13:07 +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-30 13:13:07 +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-30 13:13:07 +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.
2019-08-06 05:08:33 +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-01-30 13:13:07 +01:00
std : : string EncodeHexTx ( const CTransaction & tx )
2014-06-24 05:10:24 +02:00
{
CDataStream ssTx ( SER_NETWORK , PROTOCOL_VERSION ) ;
ssTx < < tx ;
2021-05-18 19:17:10 +02:00
return HexStr ( ssTx ) ;
2014-06-24 05:10:24 +02:00
}
2014-07-29 17:12:44 +02:00
void ScriptPubKeyToUniv ( const CScript & scriptPubKey ,
UniValue & out , bool fIncludeHex )
{
txnouttype type ;
2017-01-30 13:13:07 +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 )
2021-05-18 19:17:10 +02:00
out . pushKV ( " hex " , HexStr ( scriptPubKey ) ) ;
2014-07-29 17:12:44 +02:00
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 ) ;
Merge #11117: Prepare for non-Base58 addresses (#3294)
* Merge #11117: Prepare for non-Base58 addresses
864cd2787 Move CBitcoinAddress to base58.cpp (Pieter Wuille)
5c8ff0d44 Introduce wrappers around CBitcoinAddress (Pieter Wuille)
Pull request description:
This patch removes the need for the intermediary Base58 type `CBitcoinAddress`, by providing {`Encode`,`Decode`,`IsValid`}`Destination` functions that directly operate on the conversion between `std::string`s and `CTxDestination`.
As a side, it also fixes a number of indentation issues, and removes probably several unnecessary implicit `CTxDestination`<->`CBitcoinAddress` conversions.
This change is far from complete. In follow-ups I'd like to:
* Split off the specific address and key encoding logic from base58.h, and move it to a address.h or so.
* Replace `CTxDestination` with a non-`boost::variant` version (which can be more efficient as `boost::variant` allocates everything on the heap, and remove the need for `boost::get<...>` and `IsValidDestination` calls everywhere).
* Do the same for `CBitcoinSecret`, `CBitcoinExtKey`, and `CBitcoinExtPubKey`.
However, I've tried to keep this patch to be minimally invasive, but still enough to support non-Base58 addresses. Perhaps a smaller patch is possible to hack Bech32 support into `CBitcoinAddress`, but I would consider that a move in the wrong direction.
Tree-SHA512: c2c77ffb57caeadf2429b1c2562ce60e8c7be8aa9f8e51b591f354b6b441162625b2efe14c023a1ae485cf2ed417263afa35c892891dfaa7844e7fbabccab85e
* CBitcoinAddress -> EncodeDestination in providertx.h
Signed-off-by: Pasta <pasta@dashboost.org>
* more CBitcoinAddress -> EncodeDestination in providertx.h
Signed-off-by: Pasta <pasta@dashboost.org>
* more CBitcoinAddress -> EncodeDestination in providertx.h
Signed-off-by: Pasta <pasta@dashboost.org>
* more CBitcoinAddress -> EncodeDestination in providertx.h
Signed-off-by: Pasta <pasta@dashboost.org>
* fix CBitcoinAddress GetKeyID check
Signed-off-by: Pasta <pasta@dashboost.org>
* fix providertx.cpp
Signed-off-by: Pasta <pasta@dashboost.org>
* hopefully fix governance-classes.cpp
Signed-off-by: Pasta <pasta@dashboost.org>
* partially fix governance-validators.cpp, unable to resolve "address.IsScript()"
Signed-off-by: Pasta <pasta@dashboost.org>
* partially fix governance-classes.cpp, unable to resolve "address.IsScript()"
Signed-off-by: Pasta <pasta@dashboost.org>
* fix governance-classes.h
Signed-off-by: Pasta <pasta@dashboost.org>
* DecodeTransaction -> DecodeDestination, fix governance-validators.cpp
Signed-off-by: Pasta <pasta@dashboost.org>
* More fixes for 3294
* Move GetIndexKey into rpc/misc.cpp near getAddressesFromParams
No need to have it in base58.cpp anymore as this is only used in getAddressesFromParams
Co-authored-by: Wladimir J. van der Laan <laanwj@gmail.com>
Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
Co-authored-by: Alexander Block <ablock84@gmail.com>
2020-01-22 11:35:04 +01:00
for ( const CTxDestination & addr : addresses ) {
a . push_back ( EncodeDestination ( addr ) ) ;
}
2014-07-29 17:12:44 +02:00
out . pushKV ( " addresses " , a ) ;
}
2020-01-22 11:36:22 +01:00
void TxToUniv ( const CTransaction & tx , const uint256 & hashBlock , UniValue & entry , bool include_hex , const CSpentIndexTxInfo * ptxSpentInfo )
2014-07-29 17:12:44 +02:00
{
2019-06-11 13:42:17 +02:00
uint256 txid = tx . GetHash ( ) ;
entry . pushKV ( " txid " , txid . GetHex ( ) ) ;
2014-07-29 17:12:44 +02:00
entry . pushKV ( " version " , tx . nVersion ) ;
2019-08-28 09:54:44 +02:00
entry . pushKV ( " type " , tx . nType ) ;
2019-06-11 13:42:17 +02:00
entry . pushKV ( " size " , ( int ) : : GetSerializeSize ( tx , SER_NETWORK , PROTOCOL_VERSION ) ) ;
2014-07-29 17:12:44 +02:00
entry . pushKV ( " locktime " , ( int64_t ) tx . nLockTime ) ;
UniValue vin ( UniValue : : VARR ) ;
2019-07-05 09:06:28 +02:00
for ( const CTxIn & txin : tx . vin ) {
2014-07-29 17:12:44 +02:00
UniValue in ( UniValue : : VOBJ ) ;
if ( tx . IsCoinBase ( ) )
2021-05-18 19:17:10 +02:00
in . pushKV ( " coinbase " , HexStr ( txin . scriptSig ) ) ;
2014-07-29 17:12:44 +02:00
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 ) ) ;
2021-05-18 19:17:10 +02:00
o . pushKV ( " hex " , HexStr ( txin . scriptSig ) ) ;
2014-07-29 17:12:44 +02:00
in . pushKV ( " scriptSig " , o ) ;
2019-06-11 13:42:17 +02:00
// Add address and value info if spentindex enabled
if ( ptxSpentInfo ! = nullptr ) {
CSpentIndexKey spentKey ( txin . prevout . hash , txin . prevout . n ) ;
auto it = ptxSpentInfo - > mSpentInfo . find ( spentKey ) ;
if ( it ! = ptxSpentInfo - > mSpentInfo . end ( ) ) {
auto spentInfo = it - > second ;
2020-06-18 11:17:23 +02:00
in . pushKV ( " value " , ValueFromAmount ( spentInfo . satoshis ) ) ;
in . pushKV ( " valueSat " , spentInfo . satoshis ) ;
2019-06-11 13:42:17 +02:00
if ( spentInfo . addressType = = 1 ) {
2020-06-18 11:17:23 +02:00
in . pushKV ( " address " , EncodeDestination ( CKeyID ( spentInfo . addressHash ) ) ) ;
2019-06-11 13:42:17 +02:00
} else if ( spentInfo . addressType = = 2 ) {
2020-06-18 11:17:23 +02:00
in . pushKV ( " address " , EncodeDestination ( CScriptID ( spentInfo . addressHash ) ) ) ;
2019-06-11 13:42:17 +02:00
}
}
}
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-08 11:27:15 +02:00
out . pushKV ( " value " , ValueFromAmount ( txout . nValue ) ) ;
2019-06-11 13:42:17 +02:00
out . pushKV ( " valueSat " , 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 ) ;
2019-06-11 13:42:17 +02:00
// Add spent information if spentindex is enabled
if ( ptxSpentInfo ! = nullptr ) {
CSpentIndexKey spentKey ( txid , i ) ;
auto it = ptxSpentInfo - > mSpentInfo . find ( spentKey ) ;
if ( it ! = ptxSpentInfo - > mSpentInfo . end ( ) ) {
auto spentInfo = it - > second ;
2020-06-18 11:17:23 +02:00
out . pushKV ( " spentTxId " , spentInfo . txid . GetHex ( ) ) ;
out . pushKV ( " spentIndex " , ( int ) spentInfo . inputIndex ) ;
out . pushKV ( " spentHeight " , spentInfo . blockHeight ) ;
2019-06-11 13:42:17 +02:00
}
}
2014-07-29 17:12:44 +02:00
vout . push_back ( out ) ;
}
entry . pushKV ( " vout " , vout ) ;
2019-06-11 13:42:17 +02:00
if ( ! tx . vExtraPayload . empty ( ) ) {
2020-06-18 11:17:23 +02:00
entry . pushKV ( " extraPayloadSize " , ( int ) tx . vExtraPayload . size ( ) ) ;
entry . pushKV ( " extraPayload " , HexStr ( tx . vExtraPayload ) ) ;
2019-06-11 13:42:17 +02:00
}
if ( tx . nType = = TRANSACTION_PROVIDER_REGISTER ) {
CProRegTx proTx ;
if ( GetTxPayload ( tx , proTx ) ) {
UniValue obj ;
proTx . ToJson ( obj ) ;
2020-06-18 11:17:23 +02:00
entry . pushKV ( " proRegTx " , obj ) ;
2019-06-11 13:42:17 +02:00
}
} else if ( tx . nType = = TRANSACTION_PROVIDER_UPDATE_SERVICE ) {
CProUpServTx proTx ;
if ( GetTxPayload ( tx , proTx ) ) {
UniValue obj ;
proTx . ToJson ( obj ) ;
2020-06-18 11:17:23 +02:00
entry . pushKV ( " proUpServTx " , obj ) ;
2019-06-11 13:42:17 +02:00
}
} else if ( tx . nType = = TRANSACTION_PROVIDER_UPDATE_REGISTRAR ) {
CProUpRegTx proTx ;
if ( GetTxPayload ( tx , proTx ) ) {
UniValue obj ;
proTx . ToJson ( obj ) ;
2020-06-18 11:17:23 +02:00
entry . pushKV ( " proUpRegTx " , obj ) ;
2019-06-11 13:42:17 +02:00
}
} else if ( tx . nType = = TRANSACTION_PROVIDER_UPDATE_REVOKE ) {
CProUpRevTx proTx ;
if ( GetTxPayload ( tx , proTx ) ) {
UniValue obj ;
proTx . ToJson ( obj ) ;
2020-06-18 11:17:23 +02:00
entry . pushKV ( " proUpRevTx " , obj ) ;
2019-06-11 13:42:17 +02:00
}
} else if ( tx . nType = = TRANSACTION_COINBASE ) {
CCbTx cbTx ;
if ( GetTxPayload ( tx , cbTx ) ) {
UniValue obj ;
cbTx . ToJson ( obj ) ;
2020-06-18 11:17:23 +02:00
entry . pushKV ( " cbTx " , obj ) ;
2019-06-11 13:42:17 +02:00
}
} else if ( tx . nType = = TRANSACTION_QUORUM_COMMITMENT ) {
llmq : : CFinalCommitmentTxPayload qcTx ;
if ( GetTxPayload ( tx , qcTx ) ) {
UniValue obj ;
qcTx . ToJson ( obj ) ;
2020-06-18 11:17:23 +02:00
entry . pushKV ( " qcTx " , obj ) ;
2019-06-11 13:42:17 +02:00
}
}
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
2020-01-22 11:36:22 +01:00
if ( include_hex ) {
2018-03-21 16:16:28 +01:00
entry . pushKV ( " hex " , EncodeHexTx ( tx ) ) ; // The hex-encoded transaction. Used the name "hex" to be consistent with the verbose output of "getrawtransaction".
2020-01-22 11:36:22 +01:00
}
2014-07-29 17:12:44 +02:00
}