2015-01-02 16:52:46 +00:00
// Copyright (c) 2014-2015, The Monero Project
2014-07-23 13:03:52 +00:00
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
2014-03-03 22:07:58 +00:00
# include <boost/foreach.hpp>
# include "include_base_utils.h"
using namespace epee ;
# include "core_rpc_server.h"
# include "common/command_line.h"
# include "cryptonote_core/cryptonote_format_utils.h"
# include "cryptonote_core/account.h"
2014-04-09 12:14:35 +00:00
# include "cryptonote_core/cryptonote_basic_impl.h"
2014-03-03 22:07:58 +00:00
# include "misc_language.h"
# include "crypto/hash.h"
# include "core_rpc_server_error_codes.h"
2015-01-29 22:10:53 +00:00
# include "daemon/command_line_args.h"
2014-03-03 22:07:58 +00:00
namespace cryptonote
{
//-----------------------------------------------------------------------------------
void core_rpc_server : : init_options ( boost : : program_options : : options_description & desc )
{
command_line : : add_arg ( desc , arg_rpc_bind_ip ) ;
command_line : : add_arg ( desc , arg_rpc_bind_port ) ;
2014-09-08 17:07:15 +00:00
command_line : : add_arg ( desc , arg_testnet_rpc_bind_port ) ;
2014-03-03 22:07:58 +00:00
}
//------------------------------------------------------------------------------------------------------------------------------
2014-09-09 14:58:53 +00:00
core_rpc_server : : core_rpc_server (
core & cr
, nodetool : : node_server < cryptonote : : t_cryptonote_protocol_handler < cryptonote : : core > > & p2p
)
: m_core ( cr )
, m_p2p ( p2p )
2014-03-03 22:07:58 +00:00
{ }
//------------------------------------------------------------------------------------------------------------------------------
2014-09-08 17:07:15 +00:00
bool core_rpc_server : : handle_command_line (
const boost : : program_options : : variables_map & vm
)
2014-03-03 22:07:58 +00:00
{
2014-09-09 14:58:53 +00:00
auto p2p_bind_arg = m_testnet ? arg_testnet_rpc_bind_port : arg_rpc_bind_port ;
2014-09-08 17:07:15 +00:00
2014-03-03 22:07:58 +00:00
m_bind_ip = command_line : : get_arg ( vm , arg_rpc_bind_ip ) ;
2014-09-08 17:07:15 +00:00
m_port = command_line : : get_arg ( vm , p2p_bind_arg ) ;
2014-03-03 22:07:58 +00:00
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2014-09-08 17:07:15 +00:00
bool core_rpc_server : : init (
const boost : : program_options : : variables_map & vm
)
2014-03-03 22:07:58 +00:00
{
2015-01-29 22:10:53 +00:00
m_testnet = command_line : : get_arg ( vm , daemon_args : : arg_testnet_on ) ;
2014-03-03 22:07:58 +00:00
m_net_server . set_threads_prefix ( " RPC " ) ;
2014-09-09 14:58:53 +00:00
bool r = handle_command_line ( vm ) ;
2014-03-03 22:07:58 +00:00
CHECK_AND_ASSERT_MES ( r , false , " Failed to process command line in core_rpc_server " ) ;
2014-03-20 11:46:11 +00:00
return epee : : http_server_impl_base < core_rpc_server , connection_context > : : init ( m_port , m_bind_ip ) ;
2014-03-03 22:07:58 +00:00
}
//------------------------------------------------------------------------------------------------------------------------------
2014-06-01 21:53:44 +00:00
bool core_rpc_server : : check_core_busy ( )
2014-03-03 22:07:58 +00:00
{
2014-06-01 21:53:44 +00:00
if ( m_p2p . get_payload_object ( ) . get_core ( ) . get_blockchain_storage ( ) . is_storing_blockchain ( ) )
2014-03-20 11:46:11 +00:00
{
return false ;
}
2014-06-01 21:53:44 +00:00
return true ;
}
2014-10-06 13:18:16 +00:00
# define CHECK_CORE_BUSY() do { if(!check_core_busy()){res.status = CORE_RPC_STATUS_BUSY;return true;} } while(0)
2014-06-01 21:53:44 +00:00
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server : : check_core_ready ( )
{
if ( ! m_p2p . get_payload_object ( ) . is_synchronized ( ) )
2014-03-20 11:46:11 +00:00
{
return false ;
}
2014-06-01 21:53:44 +00:00
return check_core_busy ( ) ;
2014-03-20 11:46:11 +00:00
}
2014-10-06 13:18:16 +00:00
# define CHECK_CORE_READY() do { if(!check_core_ready()){res.status = CORE_RPC_STATUS_BUSY;return true;} } while(0)
2014-03-20 11:46:11 +00:00
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_get_height ( const COMMAND_RPC_GET_HEIGHT : : request & req , COMMAND_RPC_GET_HEIGHT : : response & res )
2014-03-20 11:46:11 +00:00
{
2014-06-01 21:53:44 +00:00
CHECK_CORE_BUSY ( ) ;
2014-03-03 22:07:58 +00:00
res . height = m_core . get_current_blockchain_height ( ) ;
2014-03-20 11:46:11 +00:00
res . status = CORE_RPC_STATUS_OK ;
2014-03-03 22:07:58 +00:00
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_get_info ( const COMMAND_RPC_GET_INFO : : request & req , COMMAND_RPC_GET_INFO : : response & res )
2014-03-03 22:07:58 +00:00
{
2014-06-01 21:53:44 +00:00
CHECK_CORE_BUSY ( ) ;
2014-03-03 22:07:58 +00:00
res . height = m_core . get_current_blockchain_height ( ) ;
2014-06-04 20:50:13 +00:00
res . target_height = m_core . get_target_blockchain_height ( ) ;
2014-03-03 22:07:58 +00:00
res . difficulty = m_core . get_blockchain_storage ( ) . get_difficulty_for_next_block ( ) ;
res . tx_count = m_core . get_blockchain_storage ( ) . get_total_transactions ( ) - res . height ; //without coinbase
res . tx_pool_size = m_core . get_pool_transactions_count ( ) ;
res . alt_blocks_count = m_core . get_blockchain_storage ( ) . get_alternative_blocks_count ( ) ;
uint64_t total_conn = m_p2p . get_connections_count ( ) ;
res . outgoing_connections_count = m_p2p . get_outgoing_connections_count ( ) ;
res . incoming_connections_count = total_conn - res . outgoing_connections_count ;
res . white_peerlist_size = m_p2p . get_peerlist_manager ( ) . get_white_peers_count ( ) ;
res . grey_peerlist_size = m_p2p . get_peerlist_manager ( ) . get_gray_peers_count ( ) ;
2014-03-20 11:46:11 +00:00
res . status = CORE_RPC_STATUS_OK ;
2014-03-03 22:07:58 +00:00
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_get_blocks ( const COMMAND_RPC_GET_BLOCKS_FAST : : request & req , COMMAND_RPC_GET_BLOCKS_FAST : : response & res )
2014-03-03 22:07:58 +00:00
{
2014-06-01 21:53:44 +00:00
CHECK_CORE_BUSY ( ) ;
2014-03-03 22:07:58 +00:00
std : : list < std : : pair < block , std : : list < transaction > > > bs ;
2014-08-01 08:17:50 +00:00
if ( ! m_core . find_blockchain_supplement ( req . start_height , req . block_ids , bs , res . current_height , res . start_height , COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT ) )
2014-03-03 22:07:58 +00:00
{
res . status = " Failed " ;
return false ;
}
BOOST_FOREACH ( auto & b , bs )
{
res . blocks . resize ( res . blocks . size ( ) + 1 ) ;
res . blocks . back ( ) . block = block_to_blob ( b . first ) ;
BOOST_FOREACH ( auto & t , b . second )
{
res . blocks . back ( ) . txs . push_back ( tx_to_blob ( t ) ) ;
}
}
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_get_random_outs ( const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS : : request & req , COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS : : response & res )
2014-03-03 22:07:58 +00:00
{
2014-06-01 21:53:44 +00:00
CHECK_CORE_BUSY ( ) ;
2014-03-03 22:07:58 +00:00
res . status = " Failed " ;
if ( ! m_core . get_random_outs_for_amounts ( req , res ) )
{
return true ;
}
res . status = CORE_RPC_STATUS_OK ;
std : : stringstream ss ;
typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS : : outs_for_amount outs_for_amount ;
typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS : : out_entry out_entry ;
std : : for_each ( res . outs . begin ( ) , res . outs . end ( ) , [ & ] ( outs_for_amount & ofa )
2014-03-20 11:46:11 +00:00
{
ss < < " [ " < < ofa . amount < < " ]: " ;
CHECK_AND_ASSERT_MES ( ofa . outs . size ( ) , ; , " internal error: ofa.outs.size() is empty for amount " < < ofa . amount ) ;
std : : for_each ( ofa . outs . begin ( ) , ofa . outs . end ( ) , [ & ] ( out_entry & oe )
{
ss < < oe . global_amount_index < < " " ;
} ) ;
ss < < ENDL ;
} ) ;
2014-03-03 22:07:58 +00:00
std : : string s = ss . str ( ) ;
LOG_PRINT_L2 ( " COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS: " < < ENDL < < s ) ;
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_get_indexes ( const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES : : request & req , COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES : : response & res )
2014-03-03 22:07:58 +00:00
{
2014-06-01 21:53:44 +00:00
CHECK_CORE_BUSY ( ) ;
2014-03-03 22:07:58 +00:00
bool r = m_core . get_tx_outputs_gindexs ( req . txid , res . o_indexes ) ;
if ( ! r )
{
res . status = " Failed " ;
return true ;
}
res . status = CORE_RPC_STATUS_OK ;
LOG_PRINT_L2 ( " COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES: [ " < < res . o_indexes . size ( ) < < " ] " ) ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_get_transactions ( const COMMAND_RPC_GET_TRANSACTIONS : : request & req , COMMAND_RPC_GET_TRANSACTIONS : : response & res )
2014-03-03 22:07:58 +00:00
{
2014-06-01 21:53:44 +00:00
CHECK_CORE_BUSY ( ) ;
2014-03-03 22:07:58 +00:00
std : : vector < crypto : : hash > vh ;
BOOST_FOREACH ( const auto & tx_hex_str , req . txs_hashes )
{
blobdata b ;
if ( ! string_tools : : parse_hexstr_to_binbuff ( tx_hex_str , b ) )
{
res . status = " Failed to parse hex representation of transaction hash " ;
return true ;
}
if ( b . size ( ) ! = sizeof ( crypto : : hash ) )
{
res . status = " Failed, size of data mismatch " ;
}
vh . push_back ( * reinterpret_cast < const crypto : : hash * > ( b . data ( ) ) ) ;
}
std : : list < crypto : : hash > missed_txs ;
std : : list < transaction > txs ;
bool r = m_core . get_transactions ( vh , txs , missed_txs ) ;
if ( ! r )
{
res . status = " Failed " ;
return true ;
}
BOOST_FOREACH ( auto & tx , txs )
{
blobdata blob = t_serializable_object_to_blob ( tx ) ;
res . txs_as_hex . push_back ( string_tools : : buff_to_hex_nodelimer ( blob ) ) ;
}
BOOST_FOREACH ( const auto & miss_tx , missed_txs )
{
res . missed_tx . push_back ( string_tools : : pod_to_hex ( miss_tx ) ) ;
}
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_send_raw_tx ( const COMMAND_RPC_SEND_RAW_TX : : request & req , COMMAND_RPC_SEND_RAW_TX : : response & res )
2014-03-03 22:07:58 +00:00
{
2014-04-02 16:00:17 +00:00
CHECK_CORE_READY ( ) ;
2014-03-03 22:07:58 +00:00
std : : string tx_blob ;
if ( ! string_tools : : parse_hexstr_to_binbuff ( req . tx_as_hex , tx_blob ) )
{
LOG_PRINT_L0 ( " [on_send_raw_tx]: Failed to parse tx from hexbuff: " < < req . tx_as_hex ) ;
res . status = " Failed " ;
return true ;
}
cryptonote_connection_context fake_context = AUTO_VAL_INIT ( fake_context ) ;
tx_verification_context tvc = AUTO_VAL_INIT ( tvc ) ;
if ( ! m_core . handle_incoming_tx ( tx_blob , tvc , false ) )
{
LOG_PRINT_L0 ( " [on_send_raw_tx]: Failed to process tx " ) ;
res . status = " Failed " ;
return true ;
}
if ( tvc . m_verifivation_failed )
{
LOG_PRINT_L0 ( " [on_send_raw_tx]: tx verification failed " ) ;
res . status = " Failed " ;
return true ;
}
if ( ! tvc . m_should_be_relayed )
{
LOG_PRINT_L0 ( " [on_send_raw_tx]: tx accepted, but not relayed " ) ;
res . status = " Not relayed " ;
return true ;
}
NOTIFY_NEW_TRANSACTIONS : : request r ;
r . txs . push_back ( tx_blob ) ;
m_core . get_protocol ( ) - > relay_transactions ( r , fake_context ) ;
//TODO: make sure that tx has reached other nodes here, probably wait to receive reflections from other nodes
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_start_mining ( const COMMAND_RPC_START_MINING : : request & req , COMMAND_RPC_START_MINING : : response & res )
2014-03-03 22:07:58 +00:00
{
2014-03-20 11:46:11 +00:00
CHECK_CORE_READY ( ) ;
2014-03-03 22:07:58 +00:00
account_public_address adr ;
2014-09-09 14:58:53 +00:00
if ( ! get_account_address_from_str ( adr , m_testnet , req . miner_address ) )
2014-03-03 22:07:58 +00:00
{
res . status = " Failed, wrong address " ;
2015-05-28 22:13:32 +00:00
LOG_PRINT_L0 ( res . status ) ;
2014-03-03 22:07:58 +00:00
return true ;
}
2014-04-30 20:50:06 +00:00
boost : : thread : : attributes attrs ;
attrs . set_stack_size ( THREAD_STACK_SIZE ) ;
if ( ! m_core . get_miner ( ) . start ( adr , static_cast < size_t > ( req . threads_count ) , attrs ) )
2014-03-03 22:07:58 +00:00
{
res . status = " Failed, mining not started " ;
2015-05-28 22:13:32 +00:00
LOG_PRINT_L0 ( res . status ) ;
2014-03-03 22:07:58 +00:00
return true ;
}
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_stop_mining ( const COMMAND_RPC_STOP_MINING : : request & req , COMMAND_RPC_STOP_MINING : : response & res )
2014-03-03 22:07:58 +00:00
{
if ( ! m_core . get_miner ( ) . stop ( ) )
{
res . status = " Failed, mining not stopped " ;
2015-05-28 22:13:32 +00:00
LOG_PRINT_L0 ( res . status ) ;
2014-03-03 22:07:58 +00:00
return true ;
}
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_mining_status ( const COMMAND_RPC_MINING_STATUS : : request & req , COMMAND_RPC_MINING_STATUS : : response & res )
2014-05-25 19:36:12 +00:00
{
CHECK_CORE_READY ( ) ;
const miner & lMiner = m_core . get_miner ( ) ;
res . active = lMiner . is_mining ( ) ;
if ( lMiner . is_mining ( ) ) {
res . speed = lMiner . get_speed ( ) ;
res . threads_count = lMiner . get_threads_count ( ) ;
const account_public_address & lMiningAdr = lMiner . get_mining_address ( ) ;
2014-09-09 14:58:53 +00:00
res . address = get_account_address_as_str ( m_testnet , lMiningAdr ) ;
2014-05-25 19:36:12 +00:00
}
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_save_bc ( const COMMAND_RPC_SAVE_BC : : request & req , COMMAND_RPC_SAVE_BC : : response & res )
2014-05-15 22:21:43 +00:00
{
2014-06-01 21:53:44 +00:00
CHECK_CORE_BUSY ( ) ;
2014-05-15 22:21:43 +00:00
if ( ! m_core . get_blockchain_storage ( ) . store_blockchain ( ) )
{
res . status = " Error while storing blockhain " ;
return true ;
}
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_get_peer_list ( const COMMAND_RPC_GET_PEER_LIST : : request & req , COMMAND_RPC_GET_PEER_LIST : : response & res )
2015-02-05 09:11:20 +00:00
{
std : : list < nodetool : : peerlist_entry > white_list ;
std : : list < nodetool : : peerlist_entry > gray_list ;
2015-05-28 13:07:31 +00:00
m_p2p . get_peerlist_manager ( ) . get_peerlist_full ( white_list , gray_list ) ;
2015-02-05 09:11:20 +00:00
for ( auto & entry : white_list )
{
res . white_list . emplace_back ( entry . id , entry . adr . ip , entry . adr . port , entry . last_seen ) ;
}
for ( auto & entry : gray_list )
{
res . gray_list . emplace_back ( entry . id , entry . adr . ip , entry . adr . port , entry . last_seen ) ;
}
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_set_log_hash_rate ( const COMMAND_RPC_SET_LOG_HASH_RATE : : request & req , COMMAND_RPC_SET_LOG_HASH_RATE : : response & res )
2015-02-05 09:11:20 +00:00
{
if ( m_core . get_miner ( ) . is_mining ( ) )
{
m_core . get_miner ( ) . do_print_hashrate ( req . visible ) ;
res . status = CORE_RPC_STATUS_OK ;
}
else
{
res . status = CORE_RPC_STATUS_NOT_MINING ;
}
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_set_log_level ( const COMMAND_RPC_SET_LOG_LEVEL : : request & req , COMMAND_RPC_SET_LOG_LEVEL : : response & res )
2015-02-05 09:11:20 +00:00
{
if ( req . level < LOG_LEVEL_MIN | | req . level > LOG_LEVEL_MAX )
{
res . status = " Error: log level not valid " ;
}
else
{
epee : : log_space : : log_singletone : : get_set_log_detalisation_level ( true , req . level ) ;
2015-04-10 14:13:57 +00:00
int otshell_utils_log_level = 100 - ( req . level * 20 ) ;
gCurrentLogger . setDebugLevel ( otshell_utils_log_level ) ;
2015-02-05 09:11:20 +00:00
res . status = CORE_RPC_STATUS_OK ;
}
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_get_transaction_pool ( const COMMAND_RPC_GET_TRANSACTION_POOL : : request & req , COMMAND_RPC_GET_TRANSACTION_POOL : : response & res )
2015-02-05 09:11:20 +00:00
{
CHECK_CORE_BUSY ( ) ;
2015-04-23 12:13:07 +00:00
m_core . get_pool_transactions_and_spent_keys_info ( res . transactions , res . spent_key_images ) ;
2015-02-05 09:11:20 +00:00
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_stop_daemon ( const COMMAND_RPC_STOP_DAEMON : : request & req , COMMAND_RPC_STOP_DAEMON : : response & res )
2015-02-05 09:11:20 +00:00
{
// FIXME: replace back to original m_p2p.send_stop_signal() after
// investigating why that isn't working quite right.
2015-02-05 10:38:49 +00:00
m_p2p . send_stop_signal ( ) ;
2015-02-05 09:11:20 +00:00
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_getblockcount ( const COMMAND_RPC_GETBLOCKCOUNT : : request & req , COMMAND_RPC_GETBLOCKCOUNT : : response & res )
2014-03-03 22:07:58 +00:00
{
2014-06-01 21:53:44 +00:00
CHECK_CORE_BUSY ( ) ;
2014-03-20 11:46:11 +00:00
res . count = m_core . get_current_blockchain_height ( ) ;
res . status = CORE_RPC_STATUS_OK ;
2014-03-03 22:07:58 +00:00
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_getblockhash ( const COMMAND_RPC_GETBLOCKHASH : : request & req , COMMAND_RPC_GETBLOCKHASH : : response & res , epee : : json_rpc : : error & error_resp )
2014-03-03 22:07:58 +00:00
{
2014-06-01 21:53:44 +00:00
if ( ! check_core_busy ( ) )
2014-03-20 11:46:11 +00:00
{
error_resp . code = CORE_RPC_ERROR_CODE_CORE_BUSY ;
error_resp . message = " Core is busy " ;
return false ;
}
2014-03-03 22:07:58 +00:00
if ( req . size ( ) ! = 1 )
{
error_resp . code = CORE_RPC_ERROR_CODE_WRONG_PARAM ;
error_resp . message = " Wrong parameters, expected height " ;
return false ;
}
uint64_t h = req [ 0 ] ;
if ( m_core . get_current_blockchain_height ( ) < = h )
{
error_resp . code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT ;
error_resp . message = std : : string ( " To big height: " ) + std : : to_string ( h ) + " , current blockchain height = " + std : : to_string ( m_core . get_current_blockchain_height ( ) ) ;
}
res = string_tools : : pod_to_hex ( m_core . get_block_id_by_height ( h ) ) ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2014-10-06 09:27:34 +00:00
// equivalent of strstr, but with arbitrary bytes (ie, NULs)
// This does not differentiate between "not found" and "found at offset 0"
uint64_t slow_memmem ( const void * start_buff , size_t buflen , const void * pat , size_t patlen )
2014-03-03 22:07:58 +00:00
{
2014-10-06 09:27:34 +00:00
const void * buf = start_buff ;
const void * end = ( const char * ) buf + buflen ;
if ( patlen > buflen | | patlen = = 0 ) return 0 ;
while ( buflen > 0 & & ( buf = memchr ( buf , ( ( const char * ) pat ) [ 0 ] , buflen - patlen + 1 ) ) )
2014-03-03 22:07:58 +00:00
{
if ( memcmp ( buf , pat , patlen ) = = 0 )
2014-10-06 09:27:34 +00:00
return ( const char * ) buf - ( const char * ) start_buff ;
buf = ( const char * ) buf + 1 ;
buflen = ( const char * ) end - ( const char * ) buf ;
2014-03-03 22:07:58 +00:00
}
return 0 ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_getblocktemplate ( const COMMAND_RPC_GETBLOCKTEMPLATE : : request & req , COMMAND_RPC_GETBLOCKTEMPLATE : : response & res , epee : : json_rpc : : error & error_resp )
2014-03-03 22:07:58 +00:00
{
2014-03-20 11:46:11 +00:00
if ( ! check_core_ready ( ) )
{
error_resp . code = CORE_RPC_ERROR_CODE_CORE_BUSY ;
error_resp . message = " Core is busy " ;
return false ;
}
2014-03-03 22:07:58 +00:00
if ( req . reserve_size > 255 )
{
error_resp . code = CORE_RPC_ERROR_CODE_TOO_BIG_RESERVE_SIZE ;
error_resp . message = " To big reserved size, maximum 255 " ;
return false ;
}
cryptonote : : account_public_address acc = AUTO_VAL_INIT ( acc ) ;
2014-09-09 14:58:53 +00:00
if ( ! req . wallet_address . size ( ) | | ! cryptonote : : get_account_address_from_str ( acc , m_testnet , req . wallet_address ) )
2014-03-03 22:07:58 +00:00
{
error_resp . code = CORE_RPC_ERROR_CODE_WRONG_WALLET_ADDRESS ;
error_resp . message = " Failed to parse wallet address " ;
return false ;
}
block b = AUTO_VAL_INIT ( b ) ;
cryptonote : : blobdata blob_reserve ;
blob_reserve . resize ( req . reserve_size , 0 ) ;
if ( ! m_core . get_block_template ( b , acc , res . difficulty , res . height , blob_reserve ) )
{
error_resp . code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR ;
error_resp . message = " Internal error: failed to create block template " ;
LOG_ERROR ( " Failed to create block template " ) ;
return false ;
}
blobdata block_blob = t_serializable_object_to_blob ( b ) ;
2014-05-03 16:19:43 +00:00
crypto : : public_key tx_pub_key = cryptonote : : get_tx_pub_key_from_extra ( b . miner_tx ) ;
2014-03-03 22:07:58 +00:00
if ( tx_pub_key = = null_pkey )
{
error_resp . code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR ;
error_resp . message = " Internal error: failed to create block template " ;
LOG_ERROR ( " Failed to tx pub key in coinbase extra " ) ;
return false ;
}
res . reserved_offset = slow_memmem ( ( void * ) block_blob . data ( ) , block_blob . size ( ) , & tx_pub_key , sizeof ( tx_pub_key ) ) ;
if ( ! res . reserved_offset )
{
error_resp . code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR ;
error_resp . message = " Internal error: failed to create block template " ;
LOG_ERROR ( " Failed to find tx pub key in blockblob " ) ;
return false ;
}
res . reserved_offset + = sizeof ( tx_pub_key ) + 3 ; //3 bytes: tag for TX_EXTRA_TAG_PUBKEY(1 byte), tag for TX_EXTRA_NONCE(1 byte), counter in TX_EXTRA_NONCE(1 byte)
if ( res . reserved_offset + req . reserve_size > block_blob . size ( ) )
{
error_resp . code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR ;
error_resp . message = " Internal error: failed to create block template " ;
LOG_ERROR ( " Failed to calculate offset for " ) ;
return false ;
}
2015-01-06 16:37:10 +00:00
res . prev_hash = string_tools : : pod_to_hex ( b . prev_id ) ;
2014-03-03 22:07:58 +00:00
res . blocktemplate_blob = string_tools : : buff_to_hex_nodelimer ( block_blob ) ;
2014-05-25 17:06:40 +00:00
res . status = CORE_RPC_STATUS_OK ;
2014-03-03 22:07:58 +00:00
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_submitblock ( const COMMAND_RPC_SUBMITBLOCK : : request & req , COMMAND_RPC_SUBMITBLOCK : : response & res , epee : : json_rpc : : error & error_resp )
2014-03-03 22:07:58 +00:00
{
2014-03-20 11:46:11 +00:00
CHECK_CORE_READY ( ) ;
2014-03-03 22:07:58 +00:00
if ( req . size ( ) ! = 1 )
{
error_resp . code = CORE_RPC_ERROR_CODE_WRONG_PARAM ;
error_resp . message = " Wrong param " ;
return false ;
}
blobdata blockblob ;
if ( ! string_tools : : parse_hexstr_to_binbuff ( req [ 0 ] , blockblob ) )
{
error_resp . code = CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB ;
error_resp . message = " Wrong block blob " ;
return false ;
}
2014-06-11 14:46:56 +00:00
// Fixing of high orphan issue for most pools
// Thanks Boolberry!
block b = AUTO_VAL_INIT ( b ) ;
if ( ! parse_and_validate_block_from_blob ( blockblob , b ) )
{
error_resp . code = CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB ;
error_resp . message = " Wrong block blob " ;
return false ;
}
2014-06-11 21:32:53 +00:00
// Fix from Boolberry neglects to check block
// size, do that with the function below
if ( ! m_core . check_incoming_block_size ( blockblob ) )
{
error_resp . code = CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB_SIZE ;
error_resp . message = " Block bloc size is too big, rejecting block " ;
return false ;
}
2014-06-11 14:46:56 +00:00
if ( ! m_core . handle_block_found ( b ) )
2014-03-03 22:07:58 +00:00
{
error_resp . code = CORE_RPC_ERROR_CODE_BLOCK_NOT_ACCEPTED ;
error_resp . message = " Block not accepted " ;
return false ;
}
2014-05-25 17:06:40 +00:00
res . status = CORE_RPC_STATUS_OK ;
2014-03-03 22:07:58 +00:00
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2014-04-09 12:14:35 +00:00
uint64_t core_rpc_server : : get_block_reward ( const block & blk )
{
uint64_t reward = 0 ;
BOOST_FOREACH ( const tx_out & out , blk . miner_tx . vout )
{
reward + = out . amount ;
}
return reward ;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server : : fill_block_header_responce ( const block & blk , bool orphan_status , uint64_t height , const crypto : : hash & hash , block_header_responce & responce )
{
responce . major_version = blk . major_version ;
responce . minor_version = blk . minor_version ;
responce . timestamp = blk . timestamp ;
responce . prev_hash = string_tools : : pod_to_hex ( blk . prev_id ) ;
responce . nonce = blk . nonce ;
responce . orphan_status = orphan_status ;
responce . height = height ;
responce . depth = m_core . get_current_blockchain_height ( ) - height - 1 ;
responce . hash = string_tools : : pod_to_hex ( hash ) ;
responce . difficulty = m_core . get_blockchain_storage ( ) . block_difficulty ( height ) ;
responce . reward = get_block_reward ( blk ) ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_get_last_block_header ( const COMMAND_RPC_GET_LAST_BLOCK_HEADER : : request & req , COMMAND_RPC_GET_LAST_BLOCK_HEADER : : response & res , epee : : json_rpc : : error & error_resp )
2014-04-09 12:14:35 +00:00
{
2014-06-01 21:53:44 +00:00
if ( ! check_core_busy ( ) )
2014-04-09 12:14:35 +00:00
{
error_resp . code = CORE_RPC_ERROR_CODE_CORE_BUSY ;
error_resp . message = " Core is busy. " ;
return false ;
}
uint64_t last_block_height ;
crypto : : hash last_block_hash ;
bool have_last_block_hash = m_core . get_blockchain_top ( last_block_height , last_block_hash ) ;
if ( ! have_last_block_hash )
{
error_resp . code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR ;
error_resp . message = " Internal error: can't get last block hash. " ;
return false ;
}
block last_block ;
bool have_last_block = m_core . get_block_by_hash ( last_block_hash , last_block ) ;
if ( ! have_last_block )
{
error_resp . code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR ;
error_resp . message = " Internal error: can't get last block. " ;
return false ;
}
bool responce_filled = fill_block_header_responce ( last_block , false , last_block_height , last_block_hash , res . block_header ) ;
if ( ! responce_filled )
{
error_resp . code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR ;
error_resp . message = " Internal error: can't produce valid response. " ;
return false ;
}
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_get_block_header_by_hash ( const COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH : : request & req , COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH : : response & res , epee : : json_rpc : : error & error_resp ) {
2014-06-01 21:53:44 +00:00
if ( ! check_core_busy ( ) )
2014-04-09 12:14:35 +00:00
{
error_resp . code = CORE_RPC_ERROR_CODE_CORE_BUSY ;
error_resp . message = " Core is busy. " ;
return false ;
}
crypto : : hash block_hash ;
bool hash_parsed = parse_hash256 ( req . hash , block_hash ) ;
if ( ! hash_parsed )
{
error_resp . code = CORE_RPC_ERROR_CODE_WRONG_PARAM ;
error_resp . message = " Failed to parse hex representation of block hash. Hex = " + req . hash + ' . ' ;
return false ;
}
block blk ;
bool have_block = m_core . get_block_by_hash ( block_hash , blk ) ;
if ( ! have_block )
{
error_resp . code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR ;
error_resp . message = " Internal error: can't get block by hash. Hash = " + req . hash + ' . ' ;
return false ;
}
if ( blk . miner_tx . vin . front ( ) . type ( ) ! = typeid ( txin_gen ) )
{
error_resp . code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR ;
error_resp . message = " Internal error: coinbase transaction in the block has the wrong type " ;
return false ;
}
uint64_t block_height = boost : : get < txin_gen > ( blk . miner_tx . vin . front ( ) ) . height ;
bool responce_filled = fill_block_header_responce ( blk , false , block_height , block_hash , res . block_header ) ;
if ( ! responce_filled )
{
error_resp . code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR ;
error_resp . message = " Internal error: can't produce valid response. " ;
return false ;
}
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_get_block_header_by_height ( const COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT : : request & req , COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT : : response & res , epee : : json_rpc : : error & error_resp ) {
2014-06-01 21:53:44 +00:00
if ( ! check_core_busy ( ) )
2014-04-09 12:14:35 +00:00
{
error_resp . code = CORE_RPC_ERROR_CODE_CORE_BUSY ;
error_resp . message = " Core is busy. " ;
return false ;
}
if ( m_core . get_current_blockchain_height ( ) < = req . height )
{
error_resp . code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT ;
error_resp . message = std : : string ( " To big height: " ) + std : : to_string ( req . height ) + " , current blockchain height = " + std : : to_string ( m_core . get_current_blockchain_height ( ) ) ;
return false ;
}
crypto : : hash block_hash = m_core . get_block_id_by_height ( req . height ) ;
block blk ;
bool have_block = m_core . get_block_by_hash ( block_hash , blk ) ;
if ( ! have_block )
{
error_resp . code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR ;
2014-04-30 17:52:21 +00:00
error_resp . message = " Internal error: can't get block by height. Height = " + std : : to_string ( req . height ) + ' . ' ;
2014-04-09 12:14:35 +00:00
return false ;
}
bool responce_filled = fill_block_header_responce ( blk , false , req . height , block_hash , res . block_header ) ;
if ( ! responce_filled )
{
error_resp . code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR ;
error_resp . message = " Internal error: can't produce valid response. " ;
return false ;
}
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_get_connections ( const COMMAND_RPC_GET_CONNECTIONS : : request & req , COMMAND_RPC_GET_CONNECTIONS : : response & res , epee : : json_rpc : : error & error_resp )
2014-07-18 23:33:03 +00:00
{
if ( ! check_core_busy ( ) )
{
error_resp . code = CORE_RPC_ERROR_CODE_CORE_BUSY ;
error_resp . message = " Core is busy. " ;
return false ;
}
res . connections = m_p2p . get_payload_object ( ) . get_connections ( ) ;
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-03-27 12:01:30 +00:00
bool core_rpc_server : : on_get_info_json ( const COMMAND_RPC_GET_INFO : : request & req , COMMAND_RPC_GET_INFO : : response & res , epee : : json_rpc : : error & error_resp )
2014-07-22 18:00:10 +00:00
{
if ( ! check_core_busy ( ) )
{
error_resp . code = CORE_RPC_ERROR_CODE_CORE_BUSY ;
error_resp . message = " Core is busy. " ;
return false ;
}
res . height = m_core . get_current_blockchain_height ( ) ;
res . target_height = m_core . get_target_blockchain_height ( ) ;
res . difficulty = m_core . get_blockchain_storage ( ) . get_difficulty_for_next_block ( ) ;
res . tx_count = m_core . get_blockchain_storage ( ) . get_total_transactions ( ) - res . height ; //without coinbase
res . tx_pool_size = m_core . get_pool_transactions_count ( ) ;
res . alt_blocks_count = m_core . get_blockchain_storage ( ) . get_alternative_blocks_count ( ) ;
uint64_t total_conn = m_p2p . get_connections_count ( ) ;
res . outgoing_connections_count = m_p2p . get_outgoing_connections_count ( ) ;
res . incoming_connections_count = total_conn - res . outgoing_connections_count ;
res . white_peerlist_size = m_p2p . get_peerlist_manager ( ) . get_white_peers_count ( ) ;
res . grey_peerlist_size = m_p2p . get_peerlist_manager ( ) . get_gray_peers_count ( ) ;
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-04-01 17:00:45 +00:00
bool core_rpc_server : : on_fast_exit ( const COMMAND_RPC_FAST_EXIT : : request & req , COMMAND_RPC_FAST_EXIT : : response & res )
{
cryptonote : : core : : set_fast_exit ( ) ;
m_p2p . deinit ( ) ;
m_core . deinit ( ) ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server : : on_out_peers ( const COMMAND_RPC_OUT_PEERS : : request & req , COMMAND_RPC_OUT_PEERS : : response & res )
{
// TODO
/*if (m_p2p.get_outgoing_connections_count() > req.out_peers)
{
m_p2p . m_config . m_net_config . connections_count = req . out_peers ;
if ( m_p2p . get_outgoing_connections_count ( ) > req . out_peers )
{
int count = m_p2p . get_outgoing_connections_count ( ) - req . out_peers ;
m_p2p . delete_connections ( count ) ;
}
}
else
m_p2p . m_config . m_net_config . connections_count = req . out_peers ;
*/
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server : : on_start_save_graph ( const COMMAND_RPC_START_SAVE_GRAPH : : request & req , COMMAND_RPC_START_SAVE_GRAPH : : response & res )
{
m_p2p . set_save_graph ( true ) ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server : : on_stop_save_graph ( const COMMAND_RPC_STOP_SAVE_GRAPH : : request & req , COMMAND_RPC_STOP_SAVE_GRAPH : : response & res )
{
m_p2p . set_save_graph ( false ) ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-01-29 22:10:53 +00:00
const command_line : : arg_descriptor < std : : string > core_rpc_server : : arg_rpc_bind_ip = {
" rpc-bind-ip "
, " IP for RPC server "
, " 127.0.0.1 "
} ;
const command_line : : arg_descriptor < std : : string > core_rpc_server : : arg_rpc_bind_port = {
" rpc-bind-port "
, " Port for RPC server "
, std : : to_string ( config : : RPC_DEFAULT_PORT )
} ;
const command_line : : arg_descriptor < std : : string > core_rpc_server : : arg_testnet_rpc_bind_port = {
" testnet-rpc-bind-port "
, " Port for testnet RPC server "
, std : : to_string ( config : : testnet : : RPC_DEFAULT_PORT )
} ;
} // namespace cryptonote