2015-12-31 06:39:56 +00:00
// Copyright (c) 2014-2016, 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"
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 ) ;
2015-11-27 18:24:29 +00:00
command_line : : add_arg ( desc , arg_restricted_rpc ) ;
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 ) ;
2015-11-27 18:24:29 +00:00
m_restricted = command_line : : get_arg ( vm , arg_restricted_rpc ) ;
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-12-08 23:06:29 +00:00
m_testnet = command_line : : get_arg ( vm , command_line : : arg_testnet_on ) ;
2015-01-29 22:10:53 +00:00
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 ( ) ;
2015-12-18 19:56:17 +00:00
crypto : : hash top_hash ;
if ( ! m_core . get_blockchain_top ( res . height , top_hash ) )
{
res . status = " Failed " ;
return false ;
}
+ + res . height ; // turn top block height into blockchain height
res . top_block_hash = string_tools : : pod_to_hex ( top_hash ) ;
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 ( ) ;
2016-01-29 15:09:17 +00:00
res . target = m_core . get_blockchain_storage ( ) . get_current_hard_fork_version ( ) < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2 ;
2014-03-03 22:07:58 +00:00
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 ( ) ;
2015-10-28 18:08:14 +00:00
res . testnet = m_testnet ;
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 ;
}
//------------------------------------------------------------------------------------------------------------------------------
2016-04-13 22:45:02 +00:00
bool core_rpc_server : : on_get_hashes ( const COMMAND_RPC_GET_HASHES_FAST : : request & req , COMMAND_RPC_GET_HASHES_FAST : : response & res )
{
CHECK_CORE_BUSY ( ) ;
NOTIFY_RESPONSE_CHAIN_ENTRY : : request resp ;
resp . start_height = req . start_height ;
if ( ! m_core . find_blockchain_supplement ( req . block_ids , resp ) )
{
res . status = " Failed " ;
return false ;
}
res . current_height = resp . total_height ;
res . start_height = resp . start_height ;
res . m_block_ids = std : : move ( resp . m_block_ids ) ;
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 " ;
2016-01-30 13:28:12 +00:00
return true ;
2014-03-03 22:07:58 +00:00
}
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 ;
}
2015-08-11 14:53:55 +00:00
LOG_PRINT_L2 ( " Found " < < txs . size ( ) < < " / " < < vh . size ( ) < < " transactions on the blockchain " ) ;
// try the pool for any missing txes
size_t found_in_pool = 0 ;
2016-04-03 11:51:28 +00:00
std : : unordered_set < crypto : : hash > pool_tx_hashes ;
2015-08-11 14:53:55 +00:00
if ( ! missed_txs . empty ( ) )
{
std : : list < transaction > pool_txs ;
bool r = m_core . get_pool_transactions ( pool_txs ) ;
if ( r )
{
for ( std : : list < transaction > : : const_iterator i = pool_txs . begin ( ) ; i ! = pool_txs . end ( ) ; + + i )
{
2016-04-03 11:51:28 +00:00
crypto : : hash tx_hash = get_transaction_hash ( * i ) ;
std : : list < crypto : : hash > : : iterator mi = std : : find ( missed_txs . begin ( ) , missed_txs . end ( ) , tx_hash ) ;
2015-08-11 14:53:55 +00:00
if ( mi ! = missed_txs . end ( ) )
{
2016-04-03 11:51:28 +00:00
pool_tx_hashes . insert ( tx_hash ) ;
2015-08-11 14:53:55 +00:00
missed_txs . erase ( mi ) ;
txs . push_back ( * i ) ;
+ + found_in_pool ;
}
}
}
LOG_PRINT_L2 ( " Found " < < found_in_pool < < " / " < < vh . size ( ) < < " transactions in the pool " ) ;
}
2014-03-03 22:07:58 +00:00
2016-04-03 11:51:28 +00:00
std : : list < std : : string > : : const_iterator txhi = req . txs_hashes . begin ( ) ;
std : : vector < crypto : : hash > : : const_iterator vhi = vh . begin ( ) ;
2014-03-03 22:07:58 +00:00
BOOST_FOREACH ( auto & tx , txs )
{
2016-04-03 11:51:28 +00:00
res . txs . push_back ( COMMAND_RPC_GET_TRANSACTIONS : : entry ( ) ) ;
COMMAND_RPC_GET_TRANSACTIONS : : entry & e = res . txs . back ( ) ;
crypto : : hash tx_hash = * vhi + + ;
e . tx_hash = * txhi + + ;
2014-03-03 22:07:58 +00:00
blobdata blob = t_serializable_object_to_blob ( tx ) ;
2016-04-03 11:51:28 +00:00
e . as_hex = string_tools : : buff_to_hex_nodelimer ( blob ) ;
if ( req . decode_as_json )
e . as_json = obj_to_json_str ( tx ) ;
e . in_pool = pool_tx_hashes . find ( tx_hash ) ! = pool_tx_hashes . end ( ) ;
if ( e . in_pool )
{
e . block_height = std : : numeric_limits < uint64_t > : : max ( ) ;
}
else
{
e . block_height = m_core . get_blockchain_storage ( ) . get_db ( ) . get_tx_block_height ( tx_hash ) ;
}
// fill up old style responses too, in case an old wallet asks
res . txs_as_hex . push_back ( e . as_hex ) ;
2015-10-13 21:11:52 +00:00
if ( req . decode_as_json )
2016-04-03 11:51:28 +00:00
res . txs_as_json . push_back ( e . as_json ) ;
2014-03-03 22:07:58 +00:00
}
BOOST_FOREACH ( const auto & miss_tx , missed_txs )
{
res . missed_tx . push_back ( string_tools : : pod_to_hex ( miss_tx ) ) ;
}
2016-04-03 11:51:28 +00:00
LOG_PRINT_L2 ( res . txs . size ( ) < < " transactions found, " < < res . missed_tx . size ( ) < < " not found " ) ;
2014-03-03 22:07:58 +00:00
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-08-11 09:49:15 +00:00
bool core_rpc_server : : on_is_key_image_spent ( const COMMAND_RPC_IS_KEY_IMAGE_SPENT : : request & req , COMMAND_RPC_IS_KEY_IMAGE_SPENT : : response & res )
{
CHECK_CORE_BUSY ( ) ;
std : : vector < crypto : : key_image > key_images ;
BOOST_FOREACH ( const auto & ki_hex_str , req . key_images )
{
blobdata b ;
if ( ! string_tools : : parse_hexstr_to_binbuff ( ki_hex_str , b ) )
{
res . status = " Failed to parse hex representation of key image " ;
return true ;
}
if ( b . size ( ) ! = sizeof ( crypto : : key_image ) )
{
res . status = " Failed, size of data mismatch " ;
}
key_images . push_back ( * reinterpret_cast < const crypto : : key_image * > ( b . data ( ) ) ) ;
}
2015-08-13 15:33:28 +00:00
std : : vector < bool > spent_status ;
bool r = m_core . are_key_images_spent ( key_images , spent_status ) ;
2015-08-11 09:49:15 +00:00
if ( ! r )
{
res . status = " Failed " ;
return true ;
}
2015-08-13 15:33:28 +00:00
res . spent_status . clear ( ) ;
for ( size_t n = 0 ; n < spent_status . size ( ) ; + + n )
2016-01-05 21:57:43 +00:00
res . spent_status . push_back ( spent_status [ n ] ? COMMAND_RPC_IS_KEY_IMAGE_SPENT : : SPENT_IN_BLOCKCHAIN : COMMAND_RPC_IS_KEY_IMAGE_SPENT : : UNSPENT ) ;
// check the pool too
std : : vector < cryptonote : : tx_info > txs ;
std : : vector < cryptonote : : spent_key_image_info > ki ;
r = m_core . get_pool_transactions_and_spent_keys_info ( txs , ki ) ;
if ( ! r )
{
res . status = " Failed " ;
return true ;
}
for ( std : : vector < cryptonote : : spent_key_image_info > : : const_iterator i = ki . begin ( ) ; i ! = ki . end ( ) ; + + i )
{
crypto : : hash hash ;
crypto : : key_image spent_key_image ;
if ( parse_hash256 ( i - > id_hash , hash ) )
{
memcpy ( & spent_key_image , & hash , sizeof ( hash ) ) ; // a bit dodgy, should be other parse functions somewhere
for ( size_t n = 0 ; n < res . spent_status . size ( ) ; + + n )
{
if ( res . spent_status [ n ] = = COMMAND_RPC_IS_KEY_IMAGE_SPENT : : UNSPENT )
{
if ( key_images [ n ] = = spent_key_image )
{
res . spent_status [ n ] = COMMAND_RPC_IS_KEY_IMAGE_SPENT : : SPENT_IN_POOL ;
break ;
}
}
}
}
}
2015-08-11 09:49:15 +00:00
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 ) ;
2016-03-27 11:35:36 +00:00
if ( ! m_core . handle_incoming_tx ( tx_blob , tvc , false , false ) | | tvc . m_verifivation_failed )
2014-03-03 22:07:58 +00:00
{
2016-03-27 11:35:36 +00:00
if ( tvc . m_verifivation_failed )
{
LOG_PRINT_L0 ( " [on_send_raw_tx]: tx verification failed " ) ;
}
else
{
LOG_PRINT_L0 ( " [on_send_raw_tx]: Failed to process tx " ) ;
}
2014-03-03 22:07:58 +00:00
res . status = " Failed " ;
2016-03-27 11:35:36 +00:00
if ( ( res . low_mixin = tvc . m_low_mixin ) )
res . reason = " mixin too low " ;
if ( ( res . double_spend = tvc . m_double_spend ) )
res . reason = " double spend " ;
if ( ( res . invalid_input = tvc . m_invalid_input ) )
res . reason = " invalid input " ;
if ( ( res . invalid_output = tvc . m_invalid_output ) )
res . reason = " invalid output " ;
if ( ( res . too_big = tvc . m_too_big ) )
res . reason = " too big " ;
if ( ( res . overspend = tvc . m_overspend ) )
res . reason = " overspend " ;
if ( ( res . fee_too_low = tvc . m_fee_too_low ) )
res . reason = " fee too low " ;
2014-03-03 22:07:58 +00:00
return true ;
}
2016-04-05 18:13:24 +00:00
if ( ! tvc . m_should_be_relayed | | req . do_not_relay )
2014-03-03 22:07:58 +00:00
{
LOG_PRINT_L0 ( " [on_send_raw_tx]: tx accepted, but not relayed " ) ;
2016-03-27 11:35:36 +00:00
res . reason = " Not relayed " ;
res . not_relayed = true ;
res . status = CORE_RPC_STATUS_OK ;
2014-03-03 22:07:58 +00:00
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 ;
2016-03-15 05:09:21 +00:00
error_resp . message = std : : string ( " Too big height: " ) + std : : to_string ( h ) + " , current blockchain height = " + std : : to_string ( m_core . get_current_blockchain_height ( ) ) ;
2014-03-03 22:07:58 +00:00
}
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 ;
}
2016-03-30 01:50:51 +00:00
blobdata hashing_blob = get_block_hashing_blob ( b ) ;
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 ) ;
2016-03-30 01:50:51 +00:00
res . blockhashing_blob = string_tools : : buff_to_hex_nodelimer ( hashing_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 ;
2016-03-15 05:09:21 +00:00
error_resp . message = std : : string ( " Too big height: " ) + std : : to_string ( req . height ) + " , current blockchain height = " + std : : to_string ( m_core . get_current_blockchain_height ( ) ) ;
2014-04-09 12:14:35 +00:00
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-10-13 20:37:35 +00:00
bool core_rpc_server : : on_get_block ( const COMMAND_RPC_GET_BLOCK : : request & req , COMMAND_RPC_GET_BLOCK : : response & res , epee : : json_rpc : : error & error_resp ) {
if ( ! check_core_busy ( ) )
{
error_resp . code = CORE_RPC_ERROR_CODE_CORE_BUSY ;
error_resp . message = " Core is busy. " ;
return false ;
}
crypto : : hash block_hash ;
if ( ! req . hash . empty ( ) )
{
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 ;
}
}
else
{
if ( m_core . get_current_blockchain_height ( ) < = req . height )
{
error_resp . code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT ;
2016-03-15 05:09:21 +00:00
error_resp . message = std : : string ( " Too big height: " ) + std : : to_string ( req . height ) + " , current blockchain height = " + std : : to_string ( m_core . get_current_blockchain_height ( ) ) ;
2015-10-13 20:37:35 +00:00
return false ;
}
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 ;
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 ;
}
for ( size_t n = 0 ; n < blk . tx_hashes . size ( ) ; + + n )
{
res . tx_hashes . push_back ( epee : : string_tools : : pod_to_hex ( blk . tx_hashes [ n ] ) ) ;
}
2016-06-09 20:48:29 +00:00
res . blob = string_tools : : buff_to_hex_nodelimer ( t_serializable_object_to_blob ( blk ) ) ;
2015-10-13 20:37:35 +00:00
res . json = obj_to_json_str ( blk ) ;
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 ( ) ;
2016-01-29 15:09:17 +00:00
res . target = m_core . get_blockchain_storage ( ) . get_current_hard_fork_version ( ) < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2 ;
2014-07-22 18:00:10 +00:00
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 ( ) ;
2016-01-11 22:52:01 +00:00
res . testnet = m_testnet ;
2014-07-22 18:00:10 +00:00
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-09-19 15:34:29 +00:00
bool core_rpc_server : : on_hard_fork_info ( const COMMAND_RPC_HARD_FORK_INFO : : request & req , COMMAND_RPC_HARD_FORK_INFO : : response & res , epee : : json_rpc : : error & error_resp )
{
if ( ! check_core_busy ( ) )
{
error_resp . code = CORE_RPC_ERROR_CODE_CORE_BUSY ;
error_resp . message = " Core is busy. " ;
return false ;
}
# if BLOCKCHAIN_DB == DB_LMDB
const Blockchain & blockchain = m_core . get_blockchain_storage ( ) ;
uint8_t version = req . version > 0 ? req . version : blockchain . get_ideal_hard_fork_version ( ) ;
res . version = blockchain . get_current_hard_fork_version ( ) ;
2015-12-19 14:52:30 +00:00
res . enabled = blockchain . get_hard_fork_voting_info ( version , res . window , res . votes , res . threshold , res . earliest_height , res . voting ) ;
2015-09-19 15:34:29 +00:00
res . state = blockchain . get_hard_fork_state ( ) ;
2015-10-26 10:17:48 +00:00
res . status = CORE_RPC_STATUS_OK ;
2015-09-19 15:34:29 +00:00
return true ;
# else
error_resp . code = CORE_RPC_ERROR_CODE_UNSUPPORTED_RPC ;
error_resp . message = " Hard fork inoperative in memory mode. " ;
return false ;
# endif
}
//------------------------------------------------------------------------------------------------------------------------------
2015-11-26 00:04:22 +00:00
bool core_rpc_server : : on_get_bans ( const COMMAND_RPC_GETBANS : : request & req , COMMAND_RPC_GETBANS : : response & res , epee : : json_rpc : : error & error_resp )
{
if ( ! check_core_busy ( ) )
{
error_resp . code = CORE_RPC_ERROR_CODE_CORE_BUSY ;
error_resp . message = " Core is busy. " ;
return false ;
}
2016-03-12 13:44:55 +00:00
auto now = time ( nullptr ) ;
2015-11-26 00:04:22 +00:00
std : : map < uint32_t , time_t > blocked_ips = m_p2p . get_blocked_ips ( ) ;
for ( std : : map < uint32_t , time_t > : : const_iterator i = blocked_ips . begin ( ) ; i ! = blocked_ips . end ( ) ; + + i )
{
2016-03-12 13:44:55 +00:00
if ( i - > second > now ) {
COMMAND_RPC_GETBANS : : ban b ;
b . ip = i - > first ;
b . seconds = i - > second - now ;
res . bans . push_back ( b ) ;
}
2015-11-26 00:04:22 +00:00
}
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server : : on_set_bans ( const COMMAND_RPC_SETBANS : : request & req , COMMAND_RPC_SETBANS : : response & res , epee : : json_rpc : : error & error_resp )
{
if ( ! check_core_busy ( ) )
{
error_resp . code = CORE_RPC_ERROR_CODE_CORE_BUSY ;
error_resp . message = " Core is busy. " ;
return false ;
}
for ( auto i = req . bans . begin ( ) ; i ! = req . bans . end ( ) ; + + i )
{
if ( i - > ban )
m_p2p . block_ip ( i - > ip , i - > seconds ) ;
else
m_p2p . unblock_ip ( i - > ip ) ;
}
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2016-01-30 13:28:26 +00:00
bool core_rpc_server : : on_flush_txpool ( const COMMAND_RPC_FLUSH_TRANSACTION_POOL : : request & req , COMMAND_RPC_FLUSH_TRANSACTION_POOL : : response & res , epee : : json_rpc : : error & error_resp )
{
if ( ! check_core_busy ( ) )
{
error_resp . code = CORE_RPC_ERROR_CODE_CORE_BUSY ;
error_resp . message = " Core is busy. " ;
return false ;
}
bool failed = false ;
std : : list < crypto : : hash > txids ;
if ( req . txids . empty ( ) )
{
std : : list < transaction > pool_txs ;
bool r = m_core . get_pool_transactions ( pool_txs ) ;
if ( ! r )
{
res . status = " Failed to get txpool contents " ;
return true ;
}
for ( const auto & tx : pool_txs )
{
txids . push_back ( cryptonote : : get_transaction_hash ( tx ) ) ;
}
}
else
{
for ( const auto & str : req . txids )
{
cryptonote : : blobdata txid_data ;
if ( ! epee : : string_tools : : parse_hexstr_to_binbuff ( str , txid_data ) )
{
failed = true ;
}
crypto : : hash txid = * reinterpret_cast < const crypto : : hash * > ( txid_data . data ( ) ) ;
txids . push_back ( txid ) ;
}
}
if ( ! m_core . get_blockchain_storage ( ) . flush_txes_from_pool ( txids ) )
{
res . status = " Failed to remove one more tx " ;
return false ;
}
if ( failed )
{
res . status = " Failed to parse txid " ;
return false ;
}
res . status = CORE_RPC_STATUS_OK ;
return true ;
}
//------------------------------------------------------------------------------------------------------------------------------
2016-03-26 14:30:23 +00:00
bool core_rpc_server : : on_get_output_histogram ( const COMMAND_RPC_GET_OUTPUT_HISTOGRAM : : request & req , COMMAND_RPC_GET_OUTPUT_HISTOGRAM : : response & res , epee : : json_rpc : : error & error_resp )
{
if ( ! check_core_busy ( ) )
{
error_resp . code = CORE_RPC_ERROR_CODE_CORE_BUSY ;
error_resp . message = " Core is busy. " ;
return false ;
}
std : : map < uint64_t , uint64_t > histogram ;
try
{
histogram = m_core . get_blockchain_storage ( ) . get_output_histogram ( req . amounts ) ;
}
catch ( const std : : exception & e )
{
res . status = " Failed to get output histogram " ;
return true ;
}
res . histogram . clear ( ) ;
res . histogram . reserve ( histogram . size ( ) ) ;
for ( const auto & i : histogram )
{
if ( i . second > = req . min_count & & ( i . second < = req . max_count | | req . max_count = = 0 ) )
res . histogram . push_back ( COMMAND_RPC_GET_OUTPUT_HISTOGRAM : : entry ( i . first , i . second ) ) ;
}
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 )
} ;
2015-11-27 18:24:29 +00:00
const command_line : : arg_descriptor < bool > core_rpc_server : : arg_restricted_rpc = {
" restricted-rpc "
, " Restrict RPC to view only commands "
, false
} ;
2015-01-29 22:10:53 +00:00
} // namespace cryptonote