2022-12-24 23:49:50 +00:00
// Copyright (c) 2009-2022 The Bitcoin Core developers
2020-09-10 08:09:07 +10:00
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2024-10-10 12:20:34 +02:00
# include <bitcoin-build-config.h> // IWYU pragma: keep
2020-09-10 08:09:07 +10:00
# include <arith_uint256.h>
2021-06-17 14:09:53 +02:00
# include <chain.h>
# include <chainparams.h>
# include <chainparamsbase.h>
2020-09-10 08:09:07 +10:00
# include <clientversion.h>
2023-03-23 12:23:29 +01:00
# include <common/args.h>
2023-05-08 11:32:13 +02:00
# include <common/system.h>
2022-06-28 13:27:57 +01:00
# include <compat/compat.h>
2020-09-10 08:09:07 +10:00
# include <core_io.h>
2021-06-17 14:09:53 +02:00
# include <streams.h>
2023-03-06 17:22:33 +01:00
# include <util/exception.h>
2023-09-06 16:59:32 +02:00
# include <util/strencodings.h>
2020-09-10 08:09:07 +10:00
# include <util/translation.h>
2021-01-15 10:40:29 +08:00
# include <atomic>
2021-06-17 14:09:53 +02:00
# include <cstdio>
2020-09-10 08:09:07 +10:00
# include <functional>
# include <memory>
# include <thread>
static const int CONTINUE_EXECUTION = - 1 ;
const std : : function < std : : string ( const char * ) > G_TRANSLATION_FUN = nullptr ;
static void SetupBitcoinUtilArgs ( ArgsManager & argsman )
{
SetupHelpOptions ( argsman ) ;
2021-01-12 14:01:09 +01:00
argsman . AddArg ( " -version " , " Print version and exit " , ArgsManager : : ALLOW_ANY , OptionsCategory : : OPTIONS ) ;
2021-06-17 14:01:57 +02:00
argsman . AddCommand ( " grind " , " Perform proof of work on hex header string " ) ;
2021-01-15 16:09:12 +10:00
2020-09-10 08:09:07 +10:00
SetupChainParamsBaseOptions ( argsman ) ;
}
// This function returns either one of EXIT_ codes when it's expected to stop the process or
// CONTINUE_EXECUTION when it's expected to continue further.
2021-06-17 15:17:28 +02:00
static int AppInitUtil ( ArgsManager & args , int argc , char * argv [ ] )
2020-09-10 08:09:07 +10:00
{
2021-06-17 15:17:28 +02:00
SetupBitcoinUtilArgs ( args ) ;
2020-09-10 08:09:07 +10:00
std : : string error ;
2021-06-17 15:17:28 +02:00
if ( ! args . ParseParameters ( argc , argv , error ) ) {
2020-09-10 08:09:07 +10:00
tfm : : format ( std : : cerr , " Error parsing command line arguments: %s \n " , error ) ;
return EXIT_FAILURE ;
}
2024-11-20 22:55:23 +01:00
if ( HelpRequested ( args ) | | args . GetBoolArg ( " -version " , false ) ) {
2020-09-10 08:09:07 +10:00
// First part of help message is specific to this utility
2024-10-26 13:27:25 +01:00
std : : string strUsage = CLIENT_NAME " bitcoin-util utility version " + FormatFullVersion ( ) + " \n " ;
2022-02-21 19:32:59 +00:00
2024-11-20 22:55:23 +01:00
if ( args . GetBoolArg ( " -version " , false ) ) {
2022-02-21 19:32:59 +00:00
strUsage + = FormatParagraph ( LicenseInfo ( ) ) ;
} else {
2021-01-12 14:01:09 +01:00
strUsage + = " \n "
2024-03-20 23:12:02 +00:00
" The bitcoin-util tool provides bitcoin related functionality that does not rely on the ability to access a running node. Available [commands] are listed below. \n "
" \n "
" Usage: bitcoin-util [options] [command] \n "
" or: bitcoin-util [options] grind <hex-block-header> \n " ;
2021-06-17 15:17:28 +02:00
strUsage + = " \n " + args . GetHelpMessage ( ) ;
2021-01-12 14:01:09 +01:00
}
2020-09-10 08:09:07 +10:00
tfm : : format ( std : : cout , " %s " , strUsage ) ;
if ( argc < 2 ) {
tfm : : format ( std : : cerr , " Error: too few parameters \n " ) ;
return EXIT_FAILURE ;
}
return EXIT_SUCCESS ;
}
2021-01-15 16:09:12 +10:00
// Check for chain settings (Params() calls are only valid after this clause)
try {
2023-04-17 22:20:59 +02:00
SelectParams ( args . GetChainType ( ) ) ;
2021-01-15 16:09:12 +10:00
} catch ( const std : : exception & e ) {
tfm : : format ( std : : cerr , " Error: %s \n " , e . what ( ) ) ;
return EXIT_FAILURE ;
}
2020-09-10 08:09:07 +10:00
return CONTINUE_EXECUTION ;
}
2022-09-19 17:14:49 +02:00
static void grind_task ( uint32_t nBits , CBlockHeader header , uint32_t offset , uint32_t step , std : : atomic < bool > & found , uint32_t & proposed_nonce )
2020-09-10 08:09:07 +10:00
{
arith_uint256 target ;
bool neg , over ;
target . SetCompact ( nBits , & neg , & over ) ;
if ( target = = 0 | | neg | | over ) return ;
header . nNonce = offset ;
uint32_t finish = std : : numeric_limits < uint32_t > : : max ( ) - step ;
finish = finish - ( finish % step ) + offset ;
while ( ! found & & header . nNonce < finish ) {
const uint32_t next = ( finish - header . nNonce < 5000 * step ) ? finish : header . nNonce + 5000 * step ;
do {
if ( UintToArith256 ( header . GetHash ( ) ) < = target ) {
if ( ! found . exchange ( true ) ) {
2022-09-19 17:14:49 +02:00
proposed_nonce = header . nNonce ;
2020-09-10 08:09:07 +10:00
}
return ;
}
header . nNonce + = step ;
} while ( header . nNonce ! = next ) ;
}
}
2021-06-17 14:50:54 +02:00
static int Grind ( const std : : vector < std : : string > & args , std : : string & strPrint )
2020-09-10 08:09:07 +10:00
{
2021-01-15 16:09:12 +10:00
if ( args . size ( ) ! = 1 ) {
2020-09-10 08:09:07 +10:00
strPrint = " Must specify block header to grind " ;
2021-01-15 16:09:12 +10:00
return EXIT_FAILURE ;
2020-09-10 08:09:07 +10:00
}
CBlockHeader header ;
2021-01-15 16:09:12 +10:00
if ( ! DecodeHexBlockHeader ( header , args [ 0 ] ) ) {
2020-09-10 08:09:07 +10:00
strPrint = " Could not decode block header " ;
2021-01-15 16:09:12 +10:00
return EXIT_FAILURE ;
2020-09-10 08:09:07 +10:00
}
uint32_t nBits = header . nBits ;
std : : atomic < bool > found { false } ;
2022-09-19 17:14:49 +02:00
uint32_t proposed_nonce { } ;
2020-09-10 08:09:07 +10:00
std : : vector < std : : thread > threads ;
int n_tasks = std : : max ( 1u , std : : thread : : hardware_concurrency ( ) ) ;
2023-03-26 20:17:55 +01:00
threads . reserve ( n_tasks ) ;
2020-09-10 08:09:07 +10:00
for ( int i = 0 ; i < n_tasks ; + + i ) {
2022-09-19 17:14:49 +02:00
threads . emplace_back ( grind_task , nBits , header , i , n_tasks , std : : ref ( found ) , std : : ref ( proposed_nonce ) ) ;
2020-09-10 08:09:07 +10:00
}
for ( auto & t : threads ) {
t . join ( ) ;
}
2022-09-19 17:14:49 +02:00
if ( found ) {
header . nNonce = proposed_nonce ;
} else {
2020-09-10 08:09:07 +10:00
strPrint = " Could not satisfy difficulty target " ;
2021-01-15 16:09:12 +10:00
return EXIT_FAILURE ;
2020-09-10 08:09:07 +10:00
}
2023-01-03 13:21:44 +01:00
DataStream ss { } ;
2020-09-10 08:09:07 +10:00
ss < < header ;
strPrint = HexStr ( ss ) ;
2021-01-15 16:09:12 +10:00
return EXIT_SUCCESS ;
2020-09-10 08:09:07 +10:00
}
2022-05-30 15:59:43 +01:00
MAIN_FUNCTION
2020-09-10 08:09:07 +10:00
{
2021-06-17 15:17:28 +02:00
ArgsManager & args = gArgs ;
2020-09-10 08:09:07 +10:00
SetupEnvironment ( ) ;
try {
2021-06-17 15:17:28 +02:00
int ret = AppInitUtil ( args , argc , argv ) ;
if ( ret ! = CONTINUE_EXECUTION ) {
2020-09-10 08:09:07 +10:00
return ret ;
2021-06-17 15:17:28 +02:00
}
2021-01-15 16:09:12 +10:00
} catch ( const std : : exception & e ) {
2020-09-10 08:09:07 +10:00
PrintExceptionContinue ( & e , " AppInitUtil() " ) ;
return EXIT_FAILURE ;
} catch ( . . . ) {
PrintExceptionContinue ( nullptr , " AppInitUtil() " ) ;
return EXIT_FAILURE ;
}
2021-06-17 15:17:28 +02:00
const auto cmd = args . GetCommand ( ) ;
2021-01-15 16:09:12 +10:00
if ( ! cmd ) {
tfm : : format ( std : : cerr , " Error: must specify a command \n " ) ;
return EXIT_FAILURE ;
}
2020-09-10 08:09:07 +10:00
int ret = EXIT_FAILURE ;
2021-01-15 16:09:12 +10:00
std : : string strPrint ;
2020-09-10 08:09:07 +10:00
try {
2021-01-15 16:09:12 +10:00
if ( cmd - > command = = " grind " ) {
ret = Grind ( cmd - > args , strPrint ) ;
} else {
assert ( false ) ; // unknown command should be caught earlier
}
} catch ( const std : : exception & e ) {
strPrint = std : : string ( " error: " ) + e . what ( ) ;
2020-09-10 08:09:07 +10:00
} catch ( . . . ) {
2021-01-15 16:09:12 +10:00
strPrint = " unknown error " ;
}
if ( strPrint ! = " " ) {
tfm : : format ( ret = = 0 ? std : : cout : std : : cerr , " %s \n " , strPrint ) ;
2020-09-10 08:09:07 +10:00
}
2021-01-15 16:09:12 +10:00
2020-09-10 08:09:07 +10:00
return ret ;
}