mirror of
				https://git.wownero.com/wownero/wownero.git
				synced 2024-08-15 01:03:23 +00:00 
			
		
		
		
	json rpc for wallet and bugfix
This commit is contained in:
		
							parent
							
								
									8efa1313f3
								
							
						
					
					
						commit
						29c2859a3e
					
				
					 43 changed files with 2299 additions and 845 deletions
				
			
		
							
								
								
									
										17
									
								
								ReleaseNotes.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								ReleaseNotes.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
Release notes 0.8.3
 | 
			
		||||
 | 
			
		||||
- JSON RPC for wallet
 | 
			
		||||
- fixed bug with blockchain storing
 | 
			
		||||
- fixed bug with correct display of transfer's change 
 | 
			
		||||
- bug fix in simple wallet
 | 
			
		||||
 | 
			
		||||
Release notes 0.8.2
 | 
			
		||||
 | 
			
		||||
- now wallet is still working when daemon stores blockchain and can't serve clients; 
 | 
			
		||||
- no-console option for a daemon; 
 | 
			
		||||
- fixed problem with network synchronization; 
 | 
			
		||||
- major bug fix in simple wallet. 
 | 
			
		||||
 | 
			
		||||
Release notes 0.8.1
 | 
			
		||||
 | 
			
		||||
Bytecoin project is moved to GitHub
 | 
			
		||||
| 
						 | 
				
			
			@ -42,10 +42,10 @@ bool communicate(const std::string url, t_request& req, t_response& rsp, const s
 | 
			
		|||
    if(use_jrpc)
 | 
			
		||||
    {
 | 
			
		||||
      epee::json_rpc::request<t_request> req_t = AUTO_VAL_INIT(req_t);
 | 
			
		||||
      req_t.params = req;
 | 
			
		||||
      req_t.jsonrpc = "2.0";
 | 
			
		||||
      req_t.id = "10";
 | 
			
		||||
      req_t.method = "command_example_1";
 | 
			
		||||
      req_t.version = "1.1";
 | 
			
		||||
      req_t.params = req;
 | 
			
		||||
      epee::json_rpc::response<t_response, std::string> resp_t = AUTO_VAL_INIT(resp_t);
 | 
			
		||||
      if(!epee::net_utils::invoke_http_json_remote_command2("/request_json_rpc", req_t, resp_t, http_client))
 | 
			
		||||
      {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -261,6 +261,7 @@ namespace epee
 | 
			
		|||
          continue_handle = false;
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        string_tools::trim(command);
 | 
			
		||||
 | 
			
		||||
        LOG_PRINT_L2("Read command: " << command);
 | 
			
		||||
        if(0 == command.compare("exit") || 0 == command.compare("q"))
 | 
			
		||||
| 
						 | 
				
			
			@ -281,7 +282,8 @@ namespace epee
 | 
			
		|||
            continue;
 | 
			
		||||
          }
 | 
			
		||||
          log_space::get_set_log_detalisation_level(true, n);
 | 
			
		||||
          LOG_PRINT_L0("New log level set " << n);
 | 
			
		||||
          std::cout << "New log level set " << n;
 | 
			
		||||
          LOG_PRINT_L2("New log level set " << n);
 | 
			
		||||
        }else if (command.empty())
 | 
			
		||||
        {
 | 
			
		||||
          continue;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1380,6 +1380,9 @@ POP_WARNINGS
 | 
			
		|||
#define LOG_PRINT_RED(mess, level)        LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, epee::log_space::console_color_red)
 | 
			
		||||
#define LOG_PRINT_GREEN(mess, level)        LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, epee::log_space::console_color_green)
 | 
			
		||||
#define LOG_PRINT_BLUE(mess, level)       LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, epee::log_space::console_color_blue)
 | 
			
		||||
#define LOG_PRINT_YELLOW(mess, level)       LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, epee::log_space::console_color_yellow)
 | 
			
		||||
#define LOG_PRINT_CYAN(mess, level)       LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, epee::log_space::console_color_cyan)
 | 
			
		||||
#define LOG_PRINT_MAGENTA(mess, level)       LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, epee::log_space::console_color_magenta)
 | 
			
		||||
 | 
			
		||||
#define LOG_PRINT_RED_L0(mess)    LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, LOG_LEVEL_0, epee::log_space::console_color_red)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -801,7 +801,7 @@ using namespace std;
 | 
			
		|||
				}else
 | 
			
		||||
				{   //Apparently there are no signs of the form of transfer, will receive data until the connection is closed
 | 
			
		||||
					m_state = reciev_machine_state_error;
 | 
			
		||||
					LOG_PRINT("Undefinded transfer type, consider http_body_transfer_connection_close method.", LOG_LEVEL_2);
 | 
			
		||||
					LOG_PRINT("Undefinded transfer type, consider http_body_transfer_connection_close method. header: " << m_header_cache, LOG_LEVEL_2);
 | 
			
		||||
					return false;
 | 
			
		||||
				} 
 | 
			
		||||
				return false;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -118,15 +118,15 @@ namespace epee
 | 
			
		|||
    template<typename t_param>
 | 
			
		||||
    struct request
 | 
			
		||||
    {
 | 
			
		||||
      std::string version;
 | 
			
		||||
      std::string jsonrpc;
 | 
			
		||||
      std::string method;
 | 
			
		||||
      std::string id;
 | 
			
		||||
      t_param     params;
 | 
			
		||||
 | 
			
		||||
      BEGIN_KV_SERIALIZE_MAP()
 | 
			
		||||
        KV_SERIALIZE(version)
 | 
			
		||||
        KV_SERIALIZE(method)
 | 
			
		||||
        KV_SERIALIZE(jsonrpc)
 | 
			
		||||
        KV_SERIALIZE(id)
 | 
			
		||||
        KV_SERIALIZE(method)
 | 
			
		||||
        KV_SERIALIZE(params)
 | 
			
		||||
      END_KV_SERIALIZE_MAP()
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			@ -147,21 +147,54 @@ namespace epee
 | 
			
		|||
      END_KV_SERIALIZE_MAP()
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    template<typename t_param, typename t_error>
 | 
			
		||||
    struct response
 | 
			
		||||
    struct dummy_result
 | 
			
		||||
    {
 | 
			
		||||
      t_param     result;
 | 
			
		||||
      t_error     error;
 | 
			
		||||
      std::string id;
 | 
			
		||||
 | 
			
		||||
      BEGIN_KV_SERIALIZE_MAP()
 | 
			
		||||
        KV_SERIALIZE(result)
 | 
			
		||||
        KV_SERIALIZE(error)
 | 
			
		||||
        KV_SERIALIZE(id)
 | 
			
		||||
      END_KV_SERIALIZE_MAP()
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    typedef response<std::string, error> error_response;
 | 
			
		||||
    template<typename t_param, typename t_error>
 | 
			
		||||
    struct response
 | 
			
		||||
    {
 | 
			
		||||
      std::string jsonrpc;
 | 
			
		||||
      t_param     result;
 | 
			
		||||
      std::string id;
 | 
			
		||||
      t_error     error;
 | 
			
		||||
      BEGIN_KV_SERIALIZE_MAP()
 | 
			
		||||
        KV_SERIALIZE(jsonrpc)
 | 
			
		||||
        KV_SERIALIZE(id)
 | 
			
		||||
        KV_SERIALIZE(result)
 | 
			
		||||
        KV_SERIALIZE(error)
 | 
			
		||||
      END_KV_SERIALIZE_MAP()
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    template<typename t_param>
 | 
			
		||||
    struct response<t_param, dummy_error>
 | 
			
		||||
    {
 | 
			
		||||
      std::string jsonrpc;
 | 
			
		||||
      t_param     result;
 | 
			
		||||
      std::string id;
 | 
			
		||||
      BEGIN_KV_SERIALIZE_MAP()
 | 
			
		||||
        KV_SERIALIZE(jsonrpc)
 | 
			
		||||
        KV_SERIALIZE(id)
 | 
			
		||||
        KV_SERIALIZE(result)
 | 
			
		||||
      END_KV_SERIALIZE_MAP()
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    template<typename t_error>
 | 
			
		||||
    struct response<dummy_result, t_error>
 | 
			
		||||
    {
 | 
			
		||||
      std::string jsonrpc;
 | 
			
		||||
      t_error     error;
 | 
			
		||||
      std::string id;
 | 
			
		||||
      BEGIN_KV_SERIALIZE_MAP()
 | 
			
		||||
        KV_SERIALIZE(jsonrpc)
 | 
			
		||||
        KV_SERIALIZE(id)
 | 
			
		||||
        KV_SERIALIZE(error)
 | 
			
		||||
      END_KV_SERIALIZE_MAP()
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    typedef response<dummy_result, error> error_response;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -184,6 +217,7 @@ namespace epee
 | 
			
		|||
    if(!ps.get_value("method", callback_name, nullptr)) \
 | 
			
		||||
    { \
 | 
			
		||||
      epee::json_rpc::error_response rsp; \
 | 
			
		||||
      rsp.jsonrpc = "2.0"; \
 | 
			
		||||
      rsp.error.code = -32600; \
 | 
			
		||||
      rsp.error.message = "Invalid Request"; \
 | 
			
		||||
      epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(rsp), response_info.m_body); \
 | 
			
		||||
| 
						 | 
				
			
			@ -201,14 +235,45 @@ namespace epee
 | 
			
		|||
  uint64_t ticks1 = epee::misc_utils::get_tick_count(); \
 | 
			
		||||
  boost::value_initialized<epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error> > resp_; \
 | 
			
		||||
  epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error>& resp =  static_cast<epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error> &>(resp_); \
 | 
			
		||||
  resp.jsonrpc = "2.0"; \
 | 
			
		||||
  resp.id = req.id; \
 | 
			
		||||
  epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \
 | 
			
		||||
  fail_resp.jsonrpc = "2.0"; \
 | 
			
		||||
  fail_resp.id = req.id; \
 | 
			
		||||
  if(!callback_f(req.params, resp.result, fail_resp.error, m_conn_context)) \
 | 
			
		||||
  { \
 | 
			
		||||
    epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(fail_resp), response_info.m_body); \
 | 
			
		||||
    return true; \
 | 
			
		||||
  } \
 | 
			
		||||
  uint64_t ticks2 = epee::misc_utils::get_tick_count(); \
 | 
			
		||||
  epee::serialization::store_t_to_json(resp, response_info.m_body); \
 | 
			
		||||
  uint64_t ticks3 = epee::misc_utils::get_tick_count(); \
 | 
			
		||||
  response_info.m_mime_tipe = "application/json"; \
 | 
			
		||||
  response_info.m_header_info.m_content_type = " application/json"; \
 | 
			
		||||
  LOG_PRINT( query_info.m_URI << "[" << method_name << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \
 | 
			
		||||
  return true;\
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define MAP_JON_RPC_WERI(method_name, callback_f, command_type) \
 | 
			
		||||
    else if(callback_name == method_name) \
 | 
			
		||||
{ \
 | 
			
		||||
  epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(fail_resp), response_info.m_body); \
 | 
			
		||||
  return true; \
 | 
			
		||||
} \
 | 
			
		||||
  handled = true; \
 | 
			
		||||
  boost::value_initialized<epee::json_rpc::request<command_type::request> > req_; \
 | 
			
		||||
  epee::json_rpc::request<command_type::request>& req = static_cast<epee::json_rpc::request<command_type::request>&>(req_);\
 | 
			
		||||
  req.load(ps); \
 | 
			
		||||
  uint64_t ticks1 = epee::misc_utils::get_tick_count(); \
 | 
			
		||||
  boost::value_initialized<epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error> > resp_; \
 | 
			
		||||
  epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error>& resp =  static_cast<epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error> &>(resp_); \
 | 
			
		||||
  resp.jsonrpc = "2.0"; \
 | 
			
		||||
  resp.id = req.id; \
 | 
			
		||||
  epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \
 | 
			
		||||
  fail_resp.jsonrpc = "2.0"; \
 | 
			
		||||
  fail_resp.id = req.id; \
 | 
			
		||||
  if(!callback_f(req.params, resp.result, fail_resp.error, m_conn_context, response_info)) \
 | 
			
		||||
  { \
 | 
			
		||||
    epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(fail_resp), response_info.m_body); \
 | 
			
		||||
    return true; \
 | 
			
		||||
  } \
 | 
			
		||||
  uint64_t ticks2 = epee::misc_utils::get_tick_count(); \
 | 
			
		||||
  epee::serialization::store_t_to_json(resp, response_info.m_body); \
 | 
			
		||||
  uint64_t ticks3 = epee::misc_utils::get_tick_count(); \
 | 
			
		||||
| 
						 | 
				
			
			@ -229,16 +294,18 @@ namespace epee
 | 
			
		|||
  uint64_t ticks1 = epee::misc_utils::get_tick_count(); \
 | 
			
		||||
  boost::value_initialized<epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error> > resp_; \
 | 
			
		||||
  epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error>& resp =  static_cast<epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error> &>(resp_); \
 | 
			
		||||
  resp.jsonrpc = "2.0"; \
 | 
			
		||||
  resp.id = req.id; \
 | 
			
		||||
  if(!callback_f(req.params, resp.result, m_conn_context)) \
 | 
			
		||||
{ \
 | 
			
		||||
  epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \
 | 
			
		||||
  fail_resp.id = req.id; \
 | 
			
		||||
  fail_resp.error.code = -32603; \
 | 
			
		||||
  fail_resp.error.message = "Internal error"; \
 | 
			
		||||
  epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(fail_resp), response_info.m_body); \
 | 
			
		||||
  return true; \
 | 
			
		||||
} \
 | 
			
		||||
  { \
 | 
			
		||||
    epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \
 | 
			
		||||
    fail_resp.jsonrpc = "2.0"; \
 | 
			
		||||
    fail_resp.id = req.id; \
 | 
			
		||||
    fail_resp.error.code = -32603; \
 | 
			
		||||
    fail_resp.error.message = "Internal error"; \
 | 
			
		||||
    epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(fail_resp), response_info.m_body); \
 | 
			
		||||
    return true; \
 | 
			
		||||
  } \
 | 
			
		||||
  uint64_t ticks2 = epee::misc_utils::get_tick_count(); \
 | 
			
		||||
  epee::serialization::store_t_to_json(resp, response_info.m_body); \
 | 
			
		||||
  uint64_t ticks3 = epee::misc_utils::get_tick_count(); \
 | 
			
		||||
| 
						 | 
				
			
			@ -251,6 +318,7 @@ namespace epee
 | 
			
		|||
 | 
			
		||||
#define END_JSON_RPC_MAP() \
 | 
			
		||||
  epee::json_rpc::error_response rsp; \
 | 
			
		||||
  rsp.jsonrpc = "2.0"; \
 | 
			
		||||
  rsp.error.code = -32601; \
 | 
			
		||||
  rsp.error.message = "Method not found"; \
 | 
			
		||||
  epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(rsp), response_info.m_body); \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -137,6 +137,9 @@ namespace net_utils
 | 
			
		|||
#define LOG_PRINT_CC_GREEN(ct, message, log_level) LOG_PRINT_GREEN("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, log_level)
 | 
			
		||||
#define LOG_PRINT_CC_RED(ct, message, log_level) LOG_PRINT_RED("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, log_level)
 | 
			
		||||
#define LOG_PRINT_CC_BLUE(ct, message, log_level) LOG_PRINT_BLUE("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, log_level)
 | 
			
		||||
#define LOG_PRINT_CC_YELLOW(ct, message, log_level) LOG_PRINT_YELLOW("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, log_level)
 | 
			
		||||
#define LOG_PRINT_CC_CYAN(ct, message, log_level) LOG_PRINT_CYAN("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, log_level)
 | 
			
		||||
#define LOG_PRINT_CC_MAGENTA(ct, message, log_level) LOG_PRINT_MAGENTA("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, log_level)
 | 
			
		||||
#define LOG_ERROR_CC(ct, message) LOG_ERROR("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message)
 | 
			
		||||
 | 
			
		||||
#define LOG_PRINT_CC_L0(ct, message) LOG_PRINT_L0("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message)
 | 
			
		||||
| 
						 | 
				
			
			@ -154,6 +157,9 @@ namespace net_utils
 | 
			
		|||
#define LOG_PRINT_CCONTEXT_GREEN(message, log_level) LOG_PRINT_CC_GREEN(context, message, log_level)
 | 
			
		||||
#define LOG_PRINT_CCONTEXT_RED(message, log_level) LOG_PRINT_CC_RED(context, message, log_level)
 | 
			
		||||
#define LOG_PRINT_CCONTEXT_BLUE(message, log_level) LOG_PRINT_CC_BLUE(context, message, log_level) 
 | 
			
		||||
#define LOG_PRINT_CCONTEXT_YELLOW(message, log_level) LOG_PRINT_CC_YELLOW(context, message, log_level) 
 | 
			
		||||
#define LOG_PRINT_CCONTEXT_CYAN(message, log_level) LOG_PRINT_CC_CYAN(context, message, log_level) 
 | 
			
		||||
#define LOG_PRINT_CCONTEXT_MAGENTA(message, log_level) LOG_PRINT_CC_MAGENTA(context, message, log_level) 
 | 
			
		||||
 | 
			
		||||
#define CHECK_AND_ASSERT_MES_CC(condition, return_val, err_message) CHECK_AND_ASSERT_MES(condition, return_val, "[" << epee::net_utils::print_connection_context_short(context) << "]" << err_message)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -98,10 +98,10 @@ namespace epee
 | 
			
		|||
    bool invoke_http_json_rpc(const std::string& url, const std::string& method_name, t_request& out_struct, t_response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& http_method = "GET", const std::string& req_id = "0")
 | 
			
		||||
    {
 | 
			
		||||
      epee::json_rpc::request<t_request> req_t = AUTO_VAL_INIT(req_t);
 | 
			
		||||
      req_t.params = out_struct;
 | 
			
		||||
      req_t.jsonrpc = "2.0";
 | 
			
		||||
      req_t.id = req_id;
 | 
			
		||||
      req_t.method = method_name;
 | 
			
		||||
      req_t.version = "2.0";
 | 
			
		||||
      req_t.params = out_struct;
 | 
			
		||||
      epee::json_rpc::response<t_response, epee::json_rpc::error> resp_t = AUTO_VAL_INIT(resp_t);
 | 
			
		||||
      if(!epee::net_utils::invoke_http_json_remote_command2(url, req_t, resp_t, transport, timeout, http_method))
 | 
			
		||||
      {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,6 +27,7 @@ namespace boost
 | 
			
		|||
    template <class Archive, class h_key, class hval>
 | 
			
		||||
    inline void load(Archive &a, std::unordered_map<h_key, hval> &x, const boost::serialization::version_type ver)
 | 
			
		||||
    {
 | 
			
		||||
      x.clear();
 | 
			
		||||
      size_t s = 0;
 | 
			
		||||
      a >> s;
 | 
			
		||||
      for(size_t i = 0; i != s; i++)
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +55,7 @@ namespace boost
 | 
			
		|||
    template <class Archive, class hval>
 | 
			
		||||
    inline void load(Archive &a, std::unordered_set<hval> &x, const boost::serialization::version_type ver)
 | 
			
		||||
    {
 | 
			
		||||
      x.clear();
 | 
			
		||||
      size_t s = 0;
 | 
			
		||||
      a >> s;
 | 
			
		||||
      for(size_t i = 0; i != s; i++)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,29 +4,29 @@
 | 
			
		|||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#define CRYPTONOTE_MAX_BLOCK_NUMBER                       500000000
 | 
			
		||||
#define CRYPTONOTE_MAX_BLOCK_SIZE                         500000000  // block header blob limit, never used!
 | 
			
		||||
#define CRYPTONOTE_MAX_TX_SIZE                            1000000000
 | 
			
		||||
#define CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER            0
 | 
			
		||||
#define CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX           6 // addresses start with "2"
 | 
			
		||||
#define CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW              10
 | 
			
		||||
#define CRYPTONOTE_MAX_BLOCK_NUMBER                     500000000
 | 
			
		||||
#define CRYPTONOTE_MAX_BLOCK_SIZE                       500000000  // block header blob limit, never used!
 | 
			
		||||
#define CRYPTONOTE_MAX_TX_SIZE                          1000000000
 | 
			
		||||
#define CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER          0
 | 
			
		||||
#define CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX         6 // addresses start with "2"
 | 
			
		||||
#define CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW            10
 | 
			
		||||
#define CURRENT_TRANSACTION_VERSION                     1
 | 
			
		||||
#define CURRENT_BLOCK_MAJOR_VERSION                     1
 | 
			
		||||
#define CURRENT_BLOCK_MINOR_VERSION                     0
 | 
			
		||||
#define CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT                60*60*2
 | 
			
		||||
#define CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT              60*60*2
 | 
			
		||||
 | 
			
		||||
#define BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW               60
 | 
			
		||||
 | 
			
		||||
// MONEY_SUPPLY - total number coins to be generated
 | 
			
		||||
#define MONEY_SUPPLY                                    ((uint64_t)(-1))
 | 
			
		||||
// COIN - number of smallest units in one coin
 | 
			
		||||
#define COIN                                            ((uint64_t)1000000000000) // pow(10, 12)
 | 
			
		||||
#define DEFAULT_FEE                                     ((uint64_t)1000000) // pow(10, 6)
 | 
			
		||||
 | 
			
		||||
#define CRYPTONOTE_REWARD_BLOCKS_WINDOW                   100
 | 
			
		||||
#define CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE            10000 //size of block (bytes) after which reward for block calculated using block size
 | 
			
		||||
#define CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE            600
 | 
			
		||||
#define CRYPTONOTE_DISPLAY_DECIMAL_POINT                  8
 | 
			
		||||
#define CRYPTONOTE_REWARD_BLOCKS_WINDOW                 100
 | 
			
		||||
#define CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE       10000 //size of block (bytes) after which reward for block calculated using block size
 | 
			
		||||
#define CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE          600
 | 
			
		||||
#define CRYPTONOTE_DISPLAY_DECIMAL_POINT                8
 | 
			
		||||
// COIN - number of smallest units in one coin
 | 
			
		||||
#define COIN                                            ((uint64_t)100000000) // pow(10, 8)
 | 
			
		||||
#define DEFAULT_FEE                                     ((uint64_t)1000000) // pow(10, 6)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define ORPHANED_BLOCKS_MAX_COUNT                       100
 | 
			
		||||
| 
						 | 
				
			
			@ -39,8 +39,8 @@
 | 
			
		|||
#define DIFFICULTY_BLOCKS_COUNT                         DIFFICULTY_WINDOW + DIFFICULTY_LAG
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS        DIFFICULTY_TARGET * CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS
 | 
			
		||||
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS         1
 | 
			
		||||
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS      DIFFICULTY_TARGET * CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS
 | 
			
		||||
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS       1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN             DIFFICULTY_TARGET //just alias
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +48,7 @@
 | 
			
		|||
 | 
			
		||||
#define BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT          10000  //by default, blocks ids count in synchronizing
 | 
			
		||||
#define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT              200    //by default, blocks count in blocks downloading
 | 
			
		||||
#define CRYPTONOTE_PROTOCOL_HOP_RELAX_COUNT               3      //value of hop, after which we use only announce of new block
 | 
			
		||||
#define CRYPTONOTE_PROTOCOL_HOP_RELAX_COUNT             3      //value of hop, after which we use only announce of new block
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define P2P_DEFAULT_PORT                                8080
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,6 +44,7 @@ bool blockchain_storage::have_tx_keyimg_as_spent(const crypto::key_image &key_im
 | 
			
		|||
//------------------------------------------------------------------
 | 
			
		||||
transaction *blockchain_storage::get_tx(const crypto::hash &id)
 | 
			
		||||
{
 | 
			
		||||
  CRITICAL_REGION_LOCAL(m_blockchain_lock);
 | 
			
		||||
  auto it = m_transactions.find(id);
 | 
			
		||||
  if (it == m_transactions.end())
 | 
			
		||||
    return NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -65,26 +66,12 @@ bool blockchain_storage::init(const std::string& config_folder)
 | 
			
		|||
  const std::string filename = m_config_folder + "/" CRYPTONOTE_BLOCKCHAINDATA_FILENAME;
 | 
			
		||||
  if(!tools::unserialize_obj_from_file(*this, filename))
 | 
			
		||||
  {
 | 
			
		||||
    const std::string temp_filename = m_config_folder + "/" CRYPTONOTE_BLOCKCHAINDATA_TEMP_FILENAME;
 | 
			
		||||
    if(tools::unserialize_obj_from_file(*this, temp_filename))
 | 
			
		||||
    {
 | 
			
		||||
      LOG_PRINT_L0("Blockchain storage loaded from temporary file");
 | 
			
		||||
      std::error_code ec = tools::replace_file(temp_filename, filename);
 | 
			
		||||
      if (ec)
 | 
			
		||||
      {
 | 
			
		||||
        LOG_ERROR("Failed to rename blockchain data file " << temp_filename << " to " << filename << ": " << ec.message() << ':' << ec.value());
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      LOG_PRINT_L0("Blockchain storage file not found, generating genesis block.");
 | 
			
		||||
      LOG_PRINT_L0("Can't load blockchain storage from file, generating genesis block.");
 | 
			
		||||
      block bl = boost::value_initialized<block>();
 | 
			
		||||
      block_verification_context bvc = boost::value_initialized<block_verification_context>();
 | 
			
		||||
      generate_genesis_block(bl);
 | 
			
		||||
      add_new_block(bl, bvc);
 | 
			
		||||
      CHECK_AND_ASSERT_MES(!bvc.m_verifivation_failed && bvc.m_added_to_main_chain, false, "Failed to add genesis block to blockchain");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if(!m_blocks.size())
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -177,6 +164,7 @@ bool blockchain_storage::reset_and_set_genesis_block(const block& b)
 | 
			
		|||
//------------------------------------------------------------------
 | 
			
		||||
bool blockchain_storage::purge_transaction_keyimages_from_blockchain(const transaction& tx, bool strict_check)
 | 
			
		||||
{
 | 
			
		||||
  CRITICAL_REGION_LOCAL(m_blockchain_lock);
 | 
			
		||||
    struct purge_transaction_visitor: public boost::static_visitor<bool>
 | 
			
		||||
  {
 | 
			
		||||
    key_images_container& m_spent_keys;
 | 
			
		||||
| 
						 | 
				
			
			@ -221,6 +209,7 @@ bool blockchain_storage::purge_transaction_keyimages_from_blockchain(const trans
 | 
			
		|||
//------------------------------------------------------------------
 | 
			
		||||
bool blockchain_storage::purge_transaction_from_blockchain(const crypto::hash& tx_id)
 | 
			
		||||
{
 | 
			
		||||
  CRITICAL_REGION_LOCAL(m_blockchain_lock);
 | 
			
		||||
  auto tx_index_it = m_transactions.find(tx_id);
 | 
			
		||||
  CHECK_AND_ASSERT_MES(tx_index_it != m_transactions.end(), false, "purge_block_data_from_blockchain: transaction not found in blockchain index!!");
 | 
			
		||||
  transaction& tx = tx_index_it->second.tx;
 | 
			
		||||
| 
						 | 
				
			
			@ -525,9 +514,7 @@ bool blockchain_storage::validate_miner_transaction(const block& b, size_t cumul
 | 
			
		|||
 | 
			
		||||
  std::vector<size_t> last_blocks_sizes;
 | 
			
		||||
  get_last_n_blocks_sizes(last_blocks_sizes, CRYPTONOTE_REWARD_BLOCKS_WINDOW);
 | 
			
		||||
  bool block_too_big = false;
 | 
			
		||||
  base_reward = get_block_reward(last_blocks_sizes, cumulative_block_size, block_too_big, already_generated_coins);
 | 
			
		||||
  if(block_too_big)
 | 
			
		||||
  if(!get_block_reward(misc_utils::median(last_blocks_sizes), cumulative_block_size, already_generated_coins, base_reward))
 | 
			
		||||
  {
 | 
			
		||||
    LOG_PRINT_L0("block size " << cumulative_block_size << " is bigger than allowed for this blockchain");
 | 
			
		||||
    return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -568,18 +555,15 @@ bool blockchain_storage::get_last_n_blocks_sizes(std::vector<size_t>& sz, size_t
 | 
			
		|||
//------------------------------------------------------------------
 | 
			
		||||
uint64_t blockchain_storage::get_current_comulative_blocksize_limit()
 | 
			
		||||
{
 | 
			
		||||
  return m_current_block_comul_sz_limit;
 | 
			
		||||
  return m_current_block_cumul_sz_limit;
 | 
			
		||||
}
 | 
			
		||||
//------------------------------------------------------------------
 | 
			
		||||
bool blockchain_storage::create_block_template(block& b, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce)
 | 
			
		||||
{
 | 
			
		||||
  size_t txs_cumulative_size = 0;
 | 
			
		||||
  uint64_t fee = 0;
 | 
			
		||||
  size_t comul_sz_limit = 0;
 | 
			
		||||
  std::vector<size_t> sz;
 | 
			
		||||
  size_t median_size;
 | 
			
		||||
  uint64_t already_generated_coins;
 | 
			
		||||
 | 
			
		||||
  CRITICAL_REGION_BEGIN(m_blockchain_lock);
 | 
			
		||||
  get_last_n_blocks_sizes(sz, CRYPTONOTE_REWARD_BLOCKS_WINDOW);
 | 
			
		||||
  b.major_version = CURRENT_BLOCK_MAJOR_VERSION;
 | 
			
		||||
  b.minor_version = CURRENT_BLOCK_MINOR_VERSION;
 | 
			
		||||
  b.prev_id = get_tail_id();
 | 
			
		||||
| 
						 | 
				
			
			@ -588,72 +572,73 @@ bool blockchain_storage::create_block_template(block& b, const account_public_ad
 | 
			
		|||
  diffic = get_difficulty_for_next_block();
 | 
			
		||||
  CHECK_AND_ASSERT_MES(diffic, false, "difficulty owverhead.");
 | 
			
		||||
 | 
			
		||||
  comul_sz_limit = m_current_block_comul_sz_limit - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
 | 
			
		||||
  median_size = m_current_block_cumul_sz_limit;
 | 
			
		||||
  already_generated_coins = m_blocks.back().already_generated_coins;
 | 
			
		||||
 | 
			
		||||
  CRITICAL_REGION_END();
 | 
			
		||||
 | 
			
		||||
  m_tx_pool.fill_block_template(b, txs_cumulative_size, comul_sz_limit, fee);
 | 
			
		||||
  size_t txs_size;
 | 
			
		||||
  uint64_t fee;
 | 
			
		||||
  if (!m_tx_pool.fill_block_template(b, median_size, already_generated_coins, txs_size, fee)) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
     two-phase miner transaction generation: we don't know exact block size until we prepare block, but we don't know reward until we know
 | 
			
		||||
     block size, so first miner transaction generated with fake amount of money, and with phase we know think we know expected block size
 | 
			
		||||
  */
 | 
			
		||||
  //make blocks coin-base tx looks close to real coinbase tx to get truthful blob size
 | 
			
		||||
  bool r = construct_miner_tx(height, m_blocks.back().already_generated_coins, miner_address, b.miner_tx, fee, sz, txs_cumulative_size, ex_nonce, 11);
 | 
			
		||||
  bool r = construct_miner_tx(height, median_size, already_generated_coins, txs_size, fee, miner_address, b.miner_tx, ex_nonce, 11);
 | 
			
		||||
  CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, first chance");
 | 
			
		||||
#ifdef _DEBUG
 | 
			
		||||
  std::list<size_t> try_val;
 | 
			
		||||
  try_val.push_back(get_object_blobsize(b.miner_tx));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  size_t cumulative_size = txs_cumulative_size + get_object_blobsize(b.miner_tx);
 | 
			
		||||
  size_t try_count = 0;
 | 
			
		||||
  for(; try_count != 10; ++try_count)
 | 
			
		||||
  {
 | 
			
		||||
    r = construct_miner_tx(height, m_blocks.back().already_generated_coins, miner_address, b.miner_tx, fee, sz, cumulative_size, ex_nonce, 11);
 | 
			
		||||
  size_t cumulative_size = txs_size + get_object_blobsize(b.miner_tx);
 | 
			
		||||
  for (size_t try_count = 0; try_count != 10; ++try_count) {
 | 
			
		||||
    r = construct_miner_tx(height, median_size, already_generated_coins, cumulative_size, fee, miner_address, b.miner_tx, ex_nonce, 11);
 | 
			
		||||
#ifdef _DEBUG
 | 
			
		||||
    try_val.push_back(get_object_blobsize(b.miner_tx));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, second chance");
 | 
			
		||||
    size_t coinbase_blob_size = get_object_blobsize(b.miner_tx);
 | 
			
		||||
    if(coinbase_blob_size > cumulative_size - txs_cumulative_size )
 | 
			
		||||
    {
 | 
			
		||||
      cumulative_size = txs_cumulative_size + coinbase_blob_size;
 | 
			
		||||
    if (coinbase_blob_size > cumulative_size - txs_size) {
 | 
			
		||||
      cumulative_size = txs_size + coinbase_blob_size;
 | 
			
		||||
      continue;
 | 
			
		||||
    }else
 | 
			
		||||
    {
 | 
			
		||||
      if(coinbase_blob_size < cumulative_size - txs_cumulative_size )
 | 
			
		||||
      {
 | 
			
		||||
        size_t delta = cumulative_size - txs_cumulative_size - coinbase_blob_size;
 | 
			
		||||
        b.miner_tx.extra.insert(b.miner_tx.extra.end(), delta, 0);
 | 
			
		||||
        //here  could be 1 byte difference, because of extra field counter is varint, and it can become from 1-byte len to 2-bytes len.
 | 
			
		||||
        if(cumulative_size != txs_cumulative_size + get_object_blobsize(b.miner_tx))
 | 
			
		||||
        {
 | 
			
		||||
          CHECK_AND_ASSERT_MES(cumulative_size + 1== txs_cumulative_size + get_object_blobsize(b.miner_tx), false, "unexpected case: cumulative_size=" << cumulative_size << " + 1 is not equal txs_cumulative_size=" << txs_cumulative_size << " + get_object_blobsize(b.miner_tx)=" << get_object_blobsize(b.miner_tx) );
 | 
			
		||||
          b.miner_tx.extra.resize(b.miner_tx.extra.size() - 1 );
 | 
			
		||||
          if(cumulative_size != txs_cumulative_size + get_object_blobsize(b.miner_tx))
 | 
			
		||||
          {//fuck, not lucky, -1 makes varint-counter size smaller, in that case we continue to grow with cumulative_size
 | 
			
		||||
            LOG_PRINT_RED("Miner tx creation have no luck with delta_extra size = " << delta << " and " << delta - 1 , LOG_LEVEL_2);
 | 
			
		||||
            cumulative_size += delta + 1;
 | 
			
		||||
            continue;
 | 
			
		||||
          }
 | 
			
		||||
          LOG_PRINT_GREEN("Setting extra for block: " << b.miner_tx.extra.size() << ", try_count=" << try_count, LOG_LEVEL_1);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      CHECK_AND_ASSERT_MES(cumulative_size == txs_cumulative_size + get_object_blobsize(b.miner_tx), false, "unexpected case: cumulative_size=" << cumulative_size << " is not equal txs_cumulative_size=" << txs_cumulative_size << " + get_object_blobsize(b.miner_tx)=" << get_object_blobsize(b.miner_tx) );
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (coinbase_blob_size < cumulative_size - txs_size) {
 | 
			
		||||
      size_t delta = cumulative_size - txs_size - coinbase_blob_size;
 | 
			
		||||
      b.miner_tx.extra.insert(b.miner_tx.extra.end(), delta, 0);
 | 
			
		||||
      //here  could be 1 byte difference, because of extra field counter is varint, and it can become from 1-byte len to 2-bytes len.
 | 
			
		||||
      if (cumulative_size != txs_size + get_object_blobsize(b.miner_tx)) {
 | 
			
		||||
        CHECK_AND_ASSERT_MES(cumulative_size + 1 == txs_size + get_object_blobsize(b.miner_tx), false, "unexpected case: cumulative_size=" << cumulative_size << " + 1 is not equal txs_cumulative_size=" << txs_size << " + get_object_blobsize(b.miner_tx)=" << get_object_blobsize(b.miner_tx));
 | 
			
		||||
        b.miner_tx.extra.resize(b.miner_tx.extra.size() - 1);
 | 
			
		||||
        if (cumulative_size != txs_size + get_object_blobsize(b.miner_tx)) {
 | 
			
		||||
          //fuck, not lucky, -1 makes varint-counter size smaller, in that case we continue to grow with cumulative_size
 | 
			
		||||
          LOG_PRINT_RED("Miner tx creation have no luck with delta_extra size = " << delta << " and " << delta - 1 , LOG_LEVEL_2);
 | 
			
		||||
          cumulative_size += delta - 1;
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
        LOG_PRINT_GREEN("Setting extra for block: " << b.miner_tx.extra.size() << ", try_count=" << try_count, LOG_LEVEL_1);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    CHECK_AND_ASSERT_MES(cumulative_size == txs_size + get_object_blobsize(b.miner_tx), false, "unexpected case: cumulative_size=" << cumulative_size << " is not equal txs_cumulative_size=" << txs_size << " + get_object_blobsize(b.miner_tx)=" << get_object_blobsize(b.miner_tx));
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  LOG_ERROR("Failed to create_block_template with " << try_count << " tries");
 | 
			
		||||
  LOG_ERROR("Failed to create_block_template with " << 10 << " tries");
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
//------------------------------------------------------------------
 | 
			
		||||
bool blockchain_storage::complete_timestamps_vector(uint64_t start_top_height, std::vector<uint64_t>& timestamps)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
  if(timestamps.size() >= BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW)
 | 
			
		||||
    return true;
 | 
			
		||||
 | 
			
		||||
  CRITICAL_REGION_LOCAL(m_blockchain_lock);
 | 
			
		||||
  size_t need_elements = BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW - timestamps.size();
 | 
			
		||||
  CHECK_AND_ASSERT_MES(start_top_height < m_blocks.size(), false, "internal error: passed start_height = " << start_top_height << " not less then m_blocks.size()=" << m_blocks.size());
 | 
			
		||||
  size_t stop_offset = start_top_height > need_elements ? start_top_height - need_elements:0;
 | 
			
		||||
| 
						 | 
				
			
			@ -947,22 +932,6 @@ bool blockchain_storage::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDO
 | 
			
		|||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//------------------------------------------------------------------
 | 
			
		||||
//bool blockchain_storage::get_outs_for_amounts(uint64_t amount, std::vector<std::pair<crypto::hash, size_t> >& keys, std::map<crypto::hash, transaction>& txs)
 | 
			
		||||
//{
 | 
			
		||||
//  auto it = m_outputs.find(amount);
 | 
			
		||||
//  if(it == m_outputs.end())
 | 
			
		||||
//    return false;
 | 
			
		||||
//  keys = it->second;
 | 
			
		||||
//  typedef std::pair<crypto::hash, size_t> pair;
 | 
			
		||||
//  BOOST_FOREACH(pair& pr, keys)
 | 
			
		||||
//  {
 | 
			
		||||
//    auto it = m_transactions.find(pr.first);
 | 
			
		||||
//    CHECK_AND_ASSERT_MES(it != m_transactions.end(), false, "internal error: transaction with id " << pr.first << " not found in internal index, but have refference for amount " << amount);
 | 
			
		||||
//    txs[pr.first] = it->second.tx;
 | 
			
		||||
//  }
 | 
			
		||||
//  return true;
 | 
			
		||||
//}
 | 
			
		||||
//------------------------------------------------------------------
 | 
			
		||||
bool blockchain_storage::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, uint64_t& starter_offset)
 | 
			
		||||
{
 | 
			
		||||
  CRITICAL_REGION_LOCAL(m_blockchain_lock);
 | 
			
		||||
| 
						 | 
				
			
			@ -1036,7 +1005,8 @@ void blockchain_storage::print_blockchain(uint64_t start_index, uint64_t end_ind
 | 
			
		|||
      << "\nid\t\t" <<  get_block_hash(m_blocks[i].bl)
 | 
			
		||||
      << "\ndifficulty\t\t" << block_difficulty(i) << ", nonce " << m_blocks[i].bl.nonce << ", tx_count " << m_blocks[i].bl.tx_hashes.size() << ENDL;
 | 
			
		||||
  }
 | 
			
		||||
  LOG_PRINT_L0("Current blockchain:" << ENDL << ss.str());
 | 
			
		||||
  LOG_PRINT_L1("Current blockchain:" << ENDL << ss.str());
 | 
			
		||||
  LOG_PRINT_L0("Blockchain printed with log level 1");
 | 
			
		||||
}
 | 
			
		||||
//------------------------------------------------------------------
 | 
			
		||||
void blockchain_storage::print_blockchain_index()
 | 
			
		||||
| 
						 | 
				
			
			@ -1605,7 +1575,7 @@ bool blockchain_storage::update_next_comulative_size_limit()
 | 
			
		|||
  if(median <= CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE)
 | 
			
		||||
    median = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE;
 | 
			
		||||
 | 
			
		||||
  m_current_block_comul_sz_limit = median*2;
 | 
			
		||||
  m_current_block_cumul_sz_limit = median*2;
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,7 +50,7 @@ namespace cryptonote
 | 
			
		|||
      uint64_t already_generated_coins;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    blockchain_storage(tx_memory_pool& tx_pool):m_tx_pool(tx_pool), m_current_block_comul_sz_limit(0), m_is_in_checkpoint_zone(false)
 | 
			
		||||
    blockchain_storage(tx_memory_pool& tx_pool):m_tx_pool(tx_pool), m_current_block_cumul_sz_limit(0), m_is_in_checkpoint_zone(false)
 | 
			
		||||
    {};
 | 
			
		||||
 | 
			
		||||
    bool init() { return init(tools::get_default_data_dir()); }
 | 
			
		||||
| 
						 | 
				
			
			@ -175,7 +175,7 @@ namespace cryptonote
 | 
			
		|||
    blocks_by_id_index m_blocks_index;       // crypto::hash -> height
 | 
			
		||||
    transactions_container m_transactions;
 | 
			
		||||
    key_images_container m_spent_keys;
 | 
			
		||||
    size_t m_current_block_comul_sz_limit;
 | 
			
		||||
    size_t m_current_block_cumul_sz_limit;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // all alternative chains
 | 
			
		||||
| 
						 | 
				
			
			@ -235,12 +235,12 @@ namespace cryptonote
 | 
			
		|||
  /*                                                                      */
 | 
			
		||||
  /************************************************************************/
 | 
			
		||||
 | 
			
		||||
  #define CURRENT_BLOCKCHAIN_STORAGE_ARCHIVE_VER    11
 | 
			
		||||
  #define CURRENT_BLOCKCHAIN_STORAGE_ARCHIVE_VER    12
 | 
			
		||||
 | 
			
		||||
  template<class archive_t>
 | 
			
		||||
  void blockchain_storage::serialize(archive_t & ar, const unsigned int version)
 | 
			
		||||
  {
 | 
			
		||||
    if(version < CURRENT_BLOCKCHAIN_STORAGE_ARCHIVE_VER)
 | 
			
		||||
    if(version < 11)
 | 
			
		||||
      return;
 | 
			
		||||
    CRITICAL_REGION_LOCAL(m_blockchain_lock);
 | 
			
		||||
    ar & m_blocks;
 | 
			
		||||
| 
						 | 
				
			
			@ -250,14 +250,54 @@ namespace cryptonote
 | 
			
		|||
    ar & m_alternative_chains;
 | 
			
		||||
    ar & m_outputs;
 | 
			
		||||
    ar & m_invalid_blocks;
 | 
			
		||||
    ar & m_current_block_comul_sz_limit;
 | 
			
		||||
    ar & m_current_block_cumul_sz_limit;
 | 
			
		||||
    /*serialization bug workaround*/
 | 
			
		||||
    if(version > 11)
 | 
			
		||||
    {
 | 
			
		||||
      uint64_t total_check_count = m_blocks.size() + m_blocks_index.size() + m_transactions.size() + m_spent_keys.size() + m_alternative_chains.size() + m_outputs.size() + m_invalid_blocks.size() + m_current_block_cumul_sz_limit;
 | 
			
		||||
      if(archive_t::is_saving::value)
 | 
			
		||||
      {        
 | 
			
		||||
        ar & total_check_count;
 | 
			
		||||
      }else
 | 
			
		||||
      {
 | 
			
		||||
        uint64_t total_check_count_loaded = 0;
 | 
			
		||||
        ar & total_check_count_loaded;
 | 
			
		||||
        if(total_check_count != total_check_count_loaded)
 | 
			
		||||
        {
 | 
			
		||||
          LOG_ERROR("Blockchain storage data corruption detected. total_count loaded from file = " << total_check_count_loaded << ", expected = " << total_check_count);
 | 
			
		||||
 | 
			
		||||
          LOG_PRINT_L0("Blockchain storage:" << ENDL << 
 | 
			
		||||
            "m_blocks: " << m_blocks.size() << ENDL  << 
 | 
			
		||||
            "m_blocks_index: " << m_blocks_index.size() << ENDL  << 
 | 
			
		||||
            "m_transactions: " << m_transactions.size() << ENDL  << 
 | 
			
		||||
            "m_spent_keys: " << m_spent_keys.size() << ENDL  << 
 | 
			
		||||
            "m_alternative_chains: " << m_alternative_chains.size() << ENDL  << 
 | 
			
		||||
            "m_outputs: " << m_outputs.size() << ENDL  << 
 | 
			
		||||
            "m_invalid_blocks: " << m_invalid_blocks.size() << ENDL  << 
 | 
			
		||||
            "m_current_block_cumul_sz_limit: " << m_current_block_cumul_sz_limit);
 | 
			
		||||
 | 
			
		||||
          throw std::runtime_error("Blockchain data corruption");
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    LOG_PRINT_L2("Blockchain storage:" << ENDL << 
 | 
			
		||||
        "m_blocks: " << m_blocks.size() << ENDL  << 
 | 
			
		||||
        "m_blocks_index: " << m_blocks_index.size() << ENDL  << 
 | 
			
		||||
        "m_transactions: " << m_transactions.size() << ENDL  << 
 | 
			
		||||
        "m_spent_keys: " << m_spent_keys.size() << ENDL  << 
 | 
			
		||||
        "m_alternative_chains: " << m_alternative_chains.size() << ENDL  << 
 | 
			
		||||
        "m_outputs: " << m_outputs.size() << ENDL  << 
 | 
			
		||||
        "m_invalid_blocks: " << m_invalid_blocks.size() << ENDL  << 
 | 
			
		||||
        "m_current_block_cumul_sz_limit: " << m_current_block_cumul_sz_limit);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //------------------------------------------------------------------
 | 
			
		||||
  template<class visitor_t>
 | 
			
		||||
  bool blockchain_storage::scan_outputkeys_for_indexes(const txin_to_key& tx_in_to_key, visitor_t& vis, uint64_t* pmax_related_block_height)
 | 
			
		||||
  {
 | 
			
		||||
 | 
			
		||||
    CRITICAL_REGION_LOCAL(m_blockchain_lock);
 | 
			
		||||
    auto it = m_outputs.find(tx_in_to_key.amount);
 | 
			
		||||
    if(it == m_outputs.end() || !tx_in_to_key.key_offsets.size())
 | 
			
		||||
      return false;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,7 +25,7 @@ namespace cryptonote {
 | 
			
		|||
  //-----------------------------------------------------------------------------------------------
 | 
			
		||||
  size_t get_max_block_size()
 | 
			
		||||
  {
 | 
			
		||||
    return CRYPTONOTE_MAX_BLOCK_SIZE; 
 | 
			
		||||
    return CRYPTONOTE_MAX_BLOCK_SIZE;
 | 
			
		||||
  }
 | 
			
		||||
  //-----------------------------------------------------------------------------------------------
 | 
			
		||||
  size_t get_max_tx_size()
 | 
			
		||||
| 
						 | 
				
			
			@ -33,46 +33,39 @@ namespace cryptonote {
 | 
			
		|||
    return CRYPTONOTE_MAX_TX_SIZE;
 | 
			
		||||
  }
 | 
			
		||||
  //-----------------------------------------------------------------------------------------------
 | 
			
		||||
  uint64_t get_block_reward(std::vector<size_t>& last_blocks_sizes, size_t current_block_size, bool& block_too_big, uint64_t already_generated_coins)
 | 
			
		||||
  {
 | 
			
		||||
    block_too_big = false;
 | 
			
		||||
 | 
			
		||||
  bool get_block_reward(size_t median_size, size_t current_block_size, uint64_t already_generated_coins, uint64_t &reward) {
 | 
			
		||||
    uint64_t base_reward = (MONEY_SUPPLY - already_generated_coins) >> 18;
 | 
			
		||||
 | 
			
		||||
    if(current_block_size < CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE)
 | 
			
		||||
      return base_reward;
 | 
			
		||||
 | 
			
		||||
    size_t med_sz = misc_utils::median(last_blocks_sizes);
 | 
			
		||||
 | 
			
		||||
    //make it soft
 | 
			
		||||
    if(med_sz < CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE)
 | 
			
		||||
      med_sz = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE;
 | 
			
		||||
    if (median_size < CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE) {
 | 
			
		||||
      median_size = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(current_block_size > med_sz)
 | 
			
		||||
    {
 | 
			
		||||
      if(current_block_size > med_sz*2)
 | 
			
		||||
      {
 | 
			
		||||
        LOG_PRINT_L0("Block cumulative size is too big: " << current_block_size << ", expected less than " << med_sz*2);
 | 
			
		||||
         block_too_big = true;
 | 
			
		||||
         return 0;
 | 
			
		||||
      }
 | 
			
		||||
    if (current_block_size <= median_size) {
 | 
			
		||||
      reward = base_reward;
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
      assert(med_sz < std::numeric_limits<uint32_t>::max());
 | 
			
		||||
      assert(current_block_size < std::numeric_limits<uint32_t>::max());
 | 
			
		||||
    if(current_block_size > 2 * median_size) {
 | 
			
		||||
      LOG_PRINT_L4("Block cumulative size is too big: " << current_block_size << ", expected less than " << 2 * median_size);
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
      uint64_t product_hi;
 | 
			
		||||
      uint64_t product_lo = mul128(base_reward, current_block_size * (2 * med_sz - current_block_size), &product_hi);
 | 
			
		||||
    assert(median_size < std::numeric_limits<uint32_t>::max());
 | 
			
		||||
    assert(current_block_size < std::numeric_limits<uint32_t>::max());
 | 
			
		||||
 | 
			
		||||
      uint64_t reward_hi;
 | 
			
		||||
      uint64_t reward_lo;
 | 
			
		||||
      div128_32(product_hi, product_lo, static_cast<uint32_t>(med_sz), &reward_hi, &reward_lo);
 | 
			
		||||
      div128_32(reward_hi, reward_lo, static_cast<uint32_t>(med_sz), &reward_hi, &reward_lo);
 | 
			
		||||
      assert(0 == reward_hi);
 | 
			
		||||
      assert(reward_lo < base_reward);
 | 
			
		||||
    uint64_t product_hi;
 | 
			
		||||
    uint64_t product_lo = mul128(base_reward, current_block_size * (2 * median_size - current_block_size), &product_hi);
 | 
			
		||||
 | 
			
		||||
      return reward_lo;
 | 
			
		||||
    }else
 | 
			
		||||
      return base_reward;
 | 
			
		||||
    uint64_t reward_hi;
 | 
			
		||||
    uint64_t reward_lo;
 | 
			
		||||
    div128_32(product_hi, product_lo, static_cast<uint32_t>(median_size), &reward_hi, &reward_lo);
 | 
			
		||||
    div128_32(reward_hi, reward_lo, static_cast<uint32_t>(median_size), &reward_hi, &reward_lo);
 | 
			
		||||
    assert(0 == reward_hi);
 | 
			
		||||
    assert(reward_lo < base_reward);
 | 
			
		||||
 | 
			
		||||
    reward = reward_lo;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  //------------------------------------------------------------------------------------
 | 
			
		||||
  uint8_t get_account_address_checksum(const public_address_outer_blob& bl)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ namespace cryptonote {
 | 
			
		|||
  /************************************************************************/
 | 
			
		||||
  size_t get_max_block_size();
 | 
			
		||||
  size_t get_max_tx_size();
 | 
			
		||||
  uint64_t get_block_reward(std::vector<size_t>& last_blocks_sizes, size_t current_block_size, bool& block_too_big, uint64_t already_generated_coins);
 | 
			
		||||
  bool get_block_reward(size_t median_size, size_t current_block_size, uint64_t already_generated_coins, uint64_t &reward);
 | 
			
		||||
  uint8_t get_account_address_checksum(const public_address_outer_blob& bl);
 | 
			
		||||
  std::string get_account_address_as_str(const account_public_address& adr);
 | 
			
		||||
  bool get_account_address_from_str(account_public_address& adr, const std::string& str);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,13 +54,7 @@ namespace cryptonote
 | 
			
		|||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  //---------------------------------------------------------------
 | 
			
		||||
  bool construct_miner_tx(uint64_t height, uint64_t already_generated_coins, const account_public_address& miner_address, transaction& tx, uint64_t fee, std::vector<size_t>& blocks_sizes, size_t current_block_size, size_t max_outs)
 | 
			
		||||
  {
 | 
			
		||||
    return construct_miner_tx(height, already_generated_coins, miner_address, tx, fee, blocks_sizes, current_block_size, blobdata(), max_outs);
 | 
			
		||||
  }
 | 
			
		||||
  //---------------------------------------------------------------
 | 
			
		||||
  bool construct_miner_tx(uint64_t height, uint64_t already_generated_coins, const account_public_address& miner_address, transaction& tx, uint64_t fee, std::vector<size_t>& blocks_sizes, size_t current_block_size, const blobdata& extra_nonce, size_t max_outs)
 | 
			
		||||
  {
 | 
			
		||||
  bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, size_t current_block_size, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs) {
 | 
			
		||||
    tx.vin.clear();
 | 
			
		||||
    tx.vout.clear();
 | 
			
		||||
    tx.extra.clear();
 | 
			
		||||
| 
						 | 
				
			
			@ -74,13 +68,13 @@ namespace cryptonote
 | 
			
		|||
    txin_gen in;
 | 
			
		||||
    in.height = height;
 | 
			
		||||
 | 
			
		||||
    bool block_too_big = false;
 | 
			
		||||
    uint64_t block_reward = get_block_reward(blocks_sizes, current_block_size, block_too_big, already_generated_coins) + fee;
 | 
			
		||||
    if(block_too_big)
 | 
			
		||||
    uint64_t block_reward;
 | 
			
		||||
    if(!get_block_reward(median_size, current_block_size, already_generated_coins, block_reward))
 | 
			
		||||
    {
 | 
			
		||||
      LOG_PRINT_L0("Block is too big");
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    block_reward += fee;
 | 
			
		||||
 | 
			
		||||
    std::vector<size_t> out_amounts;
 | 
			
		||||
    decompose_amount_into_digits(block_reward, DEFAULT_FEE,
 | 
			
		||||
| 
						 | 
				
			
			@ -120,7 +114,7 @@ namespace cryptonote
 | 
			
		|||
    //lock
 | 
			
		||||
    tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW;
 | 
			
		||||
    tx.vin.push_back(in);
 | 
			
		||||
    //LOG_PRINT("MINER_TX generated ok, block_reward=" << print_money(block_reward) << "("  << print_money(block_reward - fee) << "+" << print_money(fee) 
 | 
			
		||||
    //LOG_PRINT("MINER_TX generated ok, block_reward=" << print_money(block_reward) << "("  << print_money(block_reward - fee) << "+" << print_money(fee)
 | 
			
		||||
    //  << "), current_block_size=" << current_block_size << ", already_generated_coins=" << already_generated_coins << ", tx_id=" << get_transaction_hash(tx), LOG_LEVEL_2);
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -152,33 +146,37 @@ namespace cryptonote
 | 
			
		|||
  //---------------------------------------------------------------
 | 
			
		||||
  bool parse_amount(uint64_t& amount, const std::string& str_amount_)
 | 
			
		||||
  {
 | 
			
		||||
    std::vector<std::string> pars;
 | 
			
		||||
    std::string str_amount = str_amount_;
 | 
			
		||||
    boost::algorithm::trim(str_amount);
 | 
			
		||||
    if(!str_amount.size())
 | 
			
		||||
      return false;
 | 
			
		||||
    if(str_amount[0] == '-')
 | 
			
		||||
 | 
			
		||||
    size_t point_index = str_amount.find_first_of('.');
 | 
			
		||||
    size_t fraction_size;
 | 
			
		||||
    if (std::string::npos != point_index)
 | 
			
		||||
    {
 | 
			
		||||
      fraction_size = str_amount.size() - point_index - 1;
 | 
			
		||||
      while (CRYPTONOTE_DISPLAY_DECIMAL_POINT < fraction_size && '0' == str_amount.back())
 | 
			
		||||
      {
 | 
			
		||||
        str_amount.erase(str_amount.size() - 1, 1);
 | 
			
		||||
        --fraction_size;
 | 
			
		||||
      }
 | 
			
		||||
      if (CRYPTONOTE_DISPLAY_DECIMAL_POINT < fraction_size)
 | 
			
		||||
        return false;
 | 
			
		||||
      str_amount.erase(point_index, 1);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      fraction_size = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (str_amount.empty())
 | 
			
		||||
      return false;
 | 
			
		||||
 | 
			
		||||
    boost::split(pars, str_amount, boost::is_any_of("."), boost::token_compress_on );
 | 
			
		||||
    if(pars.size() > 2 || pars.size() < 1)
 | 
			
		||||
      return false;
 | 
			
		||||
    uint64_t left = 0;
 | 
			
		||||
    if(!string_tools::get_xtype_from_string(left, pars[0]))
 | 
			
		||||
      return false;
 | 
			
		||||
    amount = left * power_integral(10, CRYPTONOTE_DISPLAY_DECIMAL_POINT);
 | 
			
		||||
    if(pars.size() == 2)
 | 
			
		||||
    if (fraction_size < CRYPTONOTE_DISPLAY_DECIMAL_POINT)
 | 
			
		||||
    {
 | 
			
		||||
      uint64_t right = 0;
 | 
			
		||||
      if(pars[1].size() > 8 )
 | 
			
		||||
        return false;
 | 
			
		||||
      if(pars[1].size() < 8 )
 | 
			
		||||
        pars[1].append(8 - pars[1].size(), '0');
 | 
			
		||||
      if(!string_tools::get_xtype_from_string(right, pars[1]))
 | 
			
		||||
        return false;   
 | 
			
		||||
      amount += right;
 | 
			
		||||
      str_amount.append(CRYPTONOTE_DISPLAY_DECIMAL_POINT - fraction_size, '0');
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
 | 
			
		||||
    return string_tools::get_xtype_from_string(amount, str_amount);
 | 
			
		||||
  }
 | 
			
		||||
  //---------------------------------------------------------------
 | 
			
		||||
  bool get_tx_fee(const transaction& tx, uint64_t & fee)
 | 
			
		||||
| 
						 | 
				
			
			@ -218,7 +216,7 @@ namespace cryptonote
 | 
			
		|||
    tx_pub_key = null_pkey;
 | 
			
		||||
    bool padding_started = false; //let the padding goes only at the end
 | 
			
		||||
    bool tx_extra_tag_pubkey_found = false;
 | 
			
		||||
    bool tx_extra_extra_nonce_found = false;    
 | 
			
		||||
    bool tx_extra_extra_nonce_found = false;
 | 
			
		||||
    for(size_t i = 0; i != tx.extra.size();)
 | 
			
		||||
    {
 | 
			
		||||
      if(padding_started)
 | 
			
		||||
| 
						 | 
				
			
			@ -573,7 +571,7 @@ namespace cryptonote
 | 
			
		|||
  blobdata get_block_hashing_blob(const block& b)
 | 
			
		||||
  {
 | 
			
		||||
    blobdata blob = t_serializable_object_to_blob(static_cast<block_header>(b));
 | 
			
		||||
    crypto::hash tree_root_hash = get_tx_tree_hash(b);     
 | 
			
		||||
    crypto::hash tree_root_hash = get_tx_tree_hash(b);
 | 
			
		||||
    blob.append((const char*)&tree_root_hash, sizeof(tree_root_hash ));
 | 
			
		||||
    blob.append(tools::get_varint_data(b.tx_hashes.size()+1));
 | 
			
		||||
    return blob;
 | 
			
		||||
| 
						 | 
				
			
			@ -599,7 +597,7 @@ namespace cryptonote
 | 
			
		|||
 | 
			
		||||
    account_public_address ac = boost::value_initialized<account_public_address>();
 | 
			
		||||
    std::vector<size_t> sz;
 | 
			
		||||
    construct_miner_tx(0, 0, ac, bl.miner_tx, 0, sz, 0, 1); // zero fee in genesis
 | 
			
		||||
    construct_miner_tx(0, 0, 0, 0, 0, ac, bl.miner_tx); // zero fee in genesis
 | 
			
		||||
    blobdata txb = tx_to_blob(bl.miner_tx);
 | 
			
		||||
    std::string hex_tx_represent = string_tools::buff_to_hex_nodelimer(txb);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,9 +17,8 @@ namespace cryptonote
 | 
			
		|||
  void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h);
 | 
			
		||||
  crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx);
 | 
			
		||||
  bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash);
 | 
			
		||||
  bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx);  
 | 
			
		||||
  bool construct_miner_tx(uint64_t height, uint64_t already_generated_coins, const account_public_address& miner_address, transaction& tx, uint64_t fee, std::vector<size_t>& blocks_sizes, size_t current_block_size, const blobdata& extra_nonce, size_t max_outs = 1);
 | 
			
		||||
  bool construct_miner_tx(uint64_t height, uint64_t already_generated_coins, const account_public_address& miner_address, transaction& tx, uint64_t fee, std::vector<size_t>& blocks_sizes, size_t current_block_size, size_t max_outs = 1);
 | 
			
		||||
  bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx);
 | 
			
		||||
  bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, size_t current_block_size, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 1);
 | 
			
		||||
 | 
			
		||||
  struct tx_source_entry
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,8 +2,10 @@
 | 
			
		|||
// Distributed under the MIT/X11 software license, see the accompanying
 | 
			
		||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <boost/filesystem.hpp>
 | 
			
		||||
#include <unordered_set>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "tx_pool.h"
 | 
			
		||||
#include "cryptonote_format_utils.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -11,6 +13,7 @@
 | 
			
		|||
#include "cryptonote_config.h"
 | 
			
		||||
#include "blockchain_storage.h"
 | 
			
		||||
#include "common/boost_serialization_helper.h"
 | 
			
		||||
#include "common/int-util.h"
 | 
			
		||||
#include "misc_language.h"
 | 
			
		||||
#include "warnings.h"
 | 
			
		||||
#include "crypto/hash.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -345,31 +348,60 @@ namespace cryptonote
 | 
			
		|||
    return ss.str();
 | 
			
		||||
  }
 | 
			
		||||
  //---------------------------------------------------------------------------------
 | 
			
		||||
  bool tx_memory_pool::fill_block_template(block& bl, size_t& cumulative_sizes, size_t max_comulative_sz, uint64_t& fee)
 | 
			
		||||
  {
 | 
			
		||||
  bool tx_memory_pool::fill_block_template(block &bl, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee) {
 | 
			
		||||
    typedef transactions_container::value_type txv;
 | 
			
		||||
    CRITICAL_REGION_LOCAL(m_transactions_lock);
 | 
			
		||||
 | 
			
		||||
    std::vector<txv *> txs(m_transactions.size());
 | 
			
		||||
    std::transform(m_transactions.begin(), m_transactions.end(), txs.begin(), [](txv &a) -> txv * { return &a; });
 | 
			
		||||
    std::sort(txs.begin(), txs.end(), [](txv *a, txv *b) -> bool {
 | 
			
		||||
      uint64_t a_hi, a_lo = mul128(a->second.fee, b->second.blob_size, &a_hi);
 | 
			
		||||
      uint64_t b_hi, b_lo = mul128(b->second.fee, a->second.blob_size, &b_hi);
 | 
			
		||||
      return a_hi > b_hi || (a_hi == b_hi && a_lo > b_lo);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    size_t current_size = 0;
 | 
			
		||||
    uint64_t current_fee = 0;
 | 
			
		||||
    uint64_t best_money;
 | 
			
		||||
    if (!get_block_reward(median_size, CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE, already_generated_coins, best_money)) {
 | 
			
		||||
      LOG_ERROR("Block with just a miner transaction is already too large!");
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    size_t best_position = 0;
 | 
			
		||||
    total_size = 0;
 | 
			
		||||
    fee = 0;
 | 
			
		||||
 | 
			
		||||
    std::unordered_set<crypto::key_image> k_images;
 | 
			
		||||
 | 
			
		||||
    BOOST_FOREACH(transactions_container::value_type& tx,  m_transactions)
 | 
			
		||||
    {
 | 
			
		||||
      if(cumulative_sizes + tx.second.blob_size > max_comulative_sz)
 | 
			
		||||
        continue;
 | 
			
		||||
    for (size_t i = 0; i < txs.size(); i++) {
 | 
			
		||||
      txv &tx(*txs[i]);
 | 
			
		||||
 | 
			
		||||
      if(!is_transaction_ready_to_go(tx.second))
 | 
			
		||||
      if(!is_transaction_ready_to_go(tx.second) || have_key_images(k_images, tx.second.tx)) {
 | 
			
		||||
        txs[i] = NULL;
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      if(have_key_images(k_images, tx.second.tx))
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      bl.tx_hashes.push_back(tx.first);
 | 
			
		||||
      cumulative_sizes += tx.second.blob_size;
 | 
			
		||||
      fee += tx.second.fee;
 | 
			
		||||
      }
 | 
			
		||||
      append_key_images(k_images, tx.second.tx);
 | 
			
		||||
 | 
			
		||||
      if(cumulative_sizes >= max_comulative_sz)
 | 
			
		||||
      current_size += tx.second.blob_size;
 | 
			
		||||
      current_fee += tx.second.fee;
 | 
			
		||||
 | 
			
		||||
      uint64_t current_reward;
 | 
			
		||||
      if (!get_block_reward(median_size, current_size + CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE, already_generated_coins, current_reward)) {
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (best_money < current_reward + current_fee) {
 | 
			
		||||
        best_money = current_reward + current_fee;
 | 
			
		||||
        best_position = i + 1;
 | 
			
		||||
        total_size = current_size;
 | 
			
		||||
        fee = current_fee;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < best_position; i++) {
 | 
			
		||||
      if (txs[i]) {
 | 
			
		||||
        bl.tx_hashes.push_back(txs[i]->first);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,7 +49,7 @@ namespace cryptonote
 | 
			
		|||
    // load/store operations
 | 
			
		||||
    bool init(const std::string& config_folder);
 | 
			
		||||
    bool deinit();
 | 
			
		||||
    bool fill_block_template(block& bl, size_t& cumulative_sizes, size_t max_comulative_sz, uint64_t& fee);
 | 
			
		||||
    bool fill_block_template(block &bl, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee);
 | 
			
		||||
    bool get_transactions(std::list<transaction>& txs);
 | 
			
		||||
    bool get_transaction(const crypto::hash& h, transaction& tx);
 | 
			
		||||
    size_t get_transactions_count();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -108,7 +108,9 @@ namespace cryptonote
 | 
			
		|||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LOG_PRINT_CCONTEXT_BLUE("Sync data returned unknown top block " << "["<< m_core.get_current_blockchain_height() << "->" << hshd.current_height << "] " << hshd.top_id << ", set SYNCHRONIZATION mode", (is_inital ? LOG_LEVEL_0:LOG_LEVEL_1));
 | 
			
		||||
    LOG_PRINT_CCONTEXT_YELLOW("Sync data returned unknown top block: " << m_core.get_current_blockchain_height() << "->" << hshd.current_height 
 | 
			
		||||
      << "[" << static_cast<int64_t>(hshd.current_height - m_core.get_current_blockchain_height()) << " blocks(" << (hshd.current_height - m_core.get_current_blockchain_height()) /720 << " days) behind] " << ENDL 
 | 
			
		||||
      << "remote top: "  << hshd.top_id << "[" << hshd.current_height << "]" << ", set SYNCHRONIZATION mode", (is_inital ? LOG_LEVEL_0:LOG_LEVEL_1));
 | 
			
		||||
    context.m_state = cryptonote_connection_context::state_synchronizing;
 | 
			
		||||
    context.m_remote_blockchain_height = hshd.current_height;
 | 
			
		||||
    //let the socket to send response to handshake, but request callback, to let send request data after response
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,9 +29,6 @@ using namespace epee;
 | 
			
		|||
 | 
			
		||||
namespace po = boost::program_options;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BOOST_CLASS_VERSION(nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >, 1);
 | 
			
		||||
 | 
			
		||||
namespace
 | 
			
		||||
{
 | 
			
		||||
  const command_line::arg_descriptor<std::string> arg_config_file = {"config-file", "Specify configuration file", std::string(CRYPTONOTE_NAME ".conf")};
 | 
			
		||||
| 
						 | 
				
			
			@ -51,7 +48,7 @@ int main(int argc, char* argv[])
 | 
			
		|||
  _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
 | 
			
		||||
#endif
 | 
			
		||||
  log_space::get_set_log_detalisation_level(true, LOG_LEVEL_0);
 | 
			
		||||
  log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
 | 
			
		||||
  log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, 0);
 | 
			
		||||
  LOG_PRINT_L0("Starting...");
 | 
			
		||||
 | 
			
		||||
  TRY_ENTRY();  
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -199,6 +199,8 @@ namespace cryptonote
 | 
			
		|||
  //------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
  bool core_rpc_server::on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res, connection_context& cntx)
 | 
			
		||||
  {
 | 
			
		||||
    CHECK_CORE_READY();
 | 
			
		||||
 | 
			
		||||
    std::string tx_blob;
 | 
			
		||||
    if(!string_tools::parse_hexstr_to_binbuff(req.tx_as_hex, tx_blob))
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,7 @@
 | 
			
		|||
#include "cryptonote_core/cryptonote_format_utils.h"
 | 
			
		||||
#include "storages/http_abstract_invoke.h"
 | 
			
		||||
#include "rpc/core_rpc_server_commands_defs.h"
 | 
			
		||||
#include "wallet/wallet_rpc_server.h"
 | 
			
		||||
#include "version.h"
 | 
			
		||||
 | 
			
		||||
#if defined(WIN32)
 | 
			
		||||
| 
						 | 
				
			
			@ -37,27 +38,109 @@ namespace
 | 
			
		|||
  const command_line::arg_descriptor<std::string> arg_daemon_address = {"daemon-address", "Use daemon instance at <host>:<port>", ""};
 | 
			
		||||
  const command_line::arg_descriptor<std::string> arg_daemon_host = {"daemon-host", "Use daemon instance at host <arg> instead of localhost", ""};
 | 
			
		||||
  const command_line::arg_descriptor<std::string> arg_password = {"password", "Wallet password", "", true};
 | 
			
		||||
  const command_line::arg_descriptor<int> arg_daemon_port = {"daemon-port", "Use daemon instance at port <arg> instead of 8080", 0};
 | 
			
		||||
  const command_line::arg_descriptor<int> arg_daemon_port = {"daemon-port", "Use daemon instance at port <arg> instead of 8081", 0};
 | 
			
		||||
  const command_line::arg_descriptor<uint32_t> arg_log_level = {"set_log", "", 0, true};
 | 
			
		||||
 | 
			
		||||
  const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""};
 | 
			
		||||
 | 
			
		||||
  void print_success_msg(const std::string& msg, bool color = false)
 | 
			
		||||
  inline std::string interpret_rpc_response(bool ok, const std::string& status)
 | 
			
		||||
  {
 | 
			
		||||
    LOG_PRINT_L4(msg);
 | 
			
		||||
    if (color) epee::log_space::set_console_color(epee::log_space::console_color_green, false);
 | 
			
		||||
    std::cout << msg;
 | 
			
		||||
    if (color) epee::log_space::reset_console_color();
 | 
			
		||||
    std::cout << std::endl;
 | 
			
		||||
    std::string err;
 | 
			
		||||
    if (ok)
 | 
			
		||||
    {
 | 
			
		||||
      if (status == CORE_RPC_STATUS_BUSY)
 | 
			
		||||
      {
 | 
			
		||||
        err = "daemon is busy. Please try later";
 | 
			
		||||
      }
 | 
			
		||||
      else if (status != CORE_RPC_STATUS_OK)
 | 
			
		||||
      {
 | 
			
		||||
        err = status;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      err = "possible lost connection to daemon";
 | 
			
		||||
    }
 | 
			
		||||
    return err;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void print_fail_msg(const std::string& msg)
 | 
			
		||||
  class message_writer
 | 
			
		||||
  {
 | 
			
		||||
    LOG_PRINT_L1("Error:" << msg);
 | 
			
		||||
    epee::log_space::set_console_color(epee::log_space::console_color_red, true);
 | 
			
		||||
    std::cout << "Error: " << msg;
 | 
			
		||||
    epee::log_space::reset_console_color();
 | 
			
		||||
    std::cout << std::endl;
 | 
			
		||||
  public:
 | 
			
		||||
    message_writer(epee::log_space::console_colors color = epee::log_space::console_color_default, bool bright = false,
 | 
			
		||||
      std::string&& prefix = std::string(), int log_level = LOG_LEVEL_2)
 | 
			
		||||
      : m_flush(true)
 | 
			
		||||
      , m_color(color)
 | 
			
		||||
      , m_bright(bright)
 | 
			
		||||
      , m_log_level(log_level)
 | 
			
		||||
    {
 | 
			
		||||
      m_oss << prefix;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    message_writer(message_writer&& rhs)
 | 
			
		||||
      : m_flush(std::move(rhs.m_flush))
 | 
			
		||||
#if defined(_MSC_VER)
 | 
			
		||||
      , m_oss(std::move(rhs.m_oss))
 | 
			
		||||
#else
 | 
			
		||||
      // GCC bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316
 | 
			
		||||
      , m_oss(rhs.m_oss.str(), ios_base::out | ios_base::ate) 
 | 
			
		||||
#endif
 | 
			
		||||
      , m_color(std::move(rhs.m_color))
 | 
			
		||||
      , m_log_level(std::move(rhs.m_log_level))
 | 
			
		||||
    {
 | 
			
		||||
      rhs.m_flush = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    message_writer& operator<<(const T& val)
 | 
			
		||||
    {
 | 
			
		||||
      m_oss << val;
 | 
			
		||||
      return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~message_writer()
 | 
			
		||||
    {
 | 
			
		||||
      if (m_flush)
 | 
			
		||||
      {
 | 
			
		||||
        m_flush = false;
 | 
			
		||||
 | 
			
		||||
        LOG_PRINT(m_oss.str(), m_log_level)
 | 
			
		||||
 | 
			
		||||
        if (epee::log_space::console_color_default == m_color)
 | 
			
		||||
        {
 | 
			
		||||
          std::cout << m_oss.str();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
          epee::log_space::set_console_color(m_color, m_bright);
 | 
			
		||||
          std::cout << m_oss.str();
 | 
			
		||||
          epee::log_space::reset_console_color();
 | 
			
		||||
        }
 | 
			
		||||
        std::cout << std::endl;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    message_writer(message_writer& rhs);
 | 
			
		||||
    message_writer& operator=(message_writer& rhs);
 | 
			
		||||
    message_writer& operator=(message_writer&& rhs);
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    bool m_flush;
 | 
			
		||||
    std::stringstream m_oss;
 | 
			
		||||
    epee::log_space::console_colors m_color;
 | 
			
		||||
    bool m_bright;
 | 
			
		||||
    int m_log_level;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  message_writer success_msg_writer(bool color = false)
 | 
			
		||||
  {
 | 
			
		||||
    return message_writer(color ? epee::log_space::console_color_green : epee::log_space::console_color_default, false, std::string(), LOG_LEVEL_2);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  message_writer fail_msg_writer()
 | 
			
		||||
  {
 | 
			
		||||
    return message_writer(epee::log_space::console_color_red, true, "Error: ", LOG_LEVEL_0);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -75,21 +158,22 @@ std::string simple_wallet::get_commands_str()
 | 
			
		|||
 | 
			
		||||
bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
 | 
			
		||||
{
 | 
			
		||||
  std::cout << get_commands_str();
 | 
			
		||||
  success_msg_writer() << get_commands_str();
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
simple_wallet::simple_wallet()
 | 
			
		||||
  : m_daemon_port(0)
 | 
			
		||||
  , m_refresh_progress_reporter(*this)
 | 
			
		||||
{
 | 
			
		||||
  m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), "Start mining in daemon, start_mining <threads_count>");
 | 
			
		||||
  m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), "start_mining <threads_count> - Start mining in daemon");
 | 
			
		||||
  m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, _1), "Stop mining in daemon");
 | 
			
		||||
  m_cmd_binder.set_handler("refresh", boost::bind(&simple_wallet::refresh, this, _1), "Resynchronize transactions and balance");
 | 
			
		||||
  m_cmd_binder.set_handler("show_balance", boost::bind(&simple_wallet::show_balance, this, _1), "Show current wallet balance");
 | 
			
		||||
  m_cmd_binder.set_handler("show_incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, _1), "Show incoming transfers");
 | 
			
		||||
  m_cmd_binder.set_handler("show_bc_height", boost::bind(&simple_wallet::show_blockchain_height, this, _1), "Show blockchain height");
 | 
			
		||||
  m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this, _1), "transfer <mixin_count> {<addr> <amount>} Transfer <amount> to <address>. <mixin_count> is the number of transactions yours is indistinguishable from (from 0 to maximum available)");
 | 
			
		||||
  m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), "Change current log detalization level, <level> is a number 0-4");
 | 
			
		||||
  m_cmd_binder.set_handler("balance", boost::bind(&simple_wallet::show_balance, this, _1), "Show current wallet balance");
 | 
			
		||||
  m_cmd_binder.set_handler("incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, _1), "incoming_transfers [available|unavailable] - Show incoming transfers - all of them or filter them by availability");
 | 
			
		||||
  m_cmd_binder.set_handler("bc_height", boost::bind(&simple_wallet::show_blockchain_height, this, _1), "Show blockchain height");
 | 
			
		||||
  m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this, _1), "transfer <mixin_count> <addr_1> <amount_1> [<addr_2> <amount_2> ... <addr_N> <amount_N>] - Transfer <amount_1>,... <amount_N> to <address_1>,... <address_N>, respectively. <mixin_count> is the number of transactions yours is indistinguishable from (from 0 to maximum available)");
 | 
			
		||||
  m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), "set_log <level> - Change current log detalization level, <level> is a number 0-4");
 | 
			
		||||
  m_cmd_binder.set_handler("address", boost::bind(&simple_wallet::print_address, this, _1), "Show current wallet public address");
 | 
			
		||||
  m_cmd_binder.set_handler("save", boost::bind(&simple_wallet::save, this, _1), "Save wallet synchronized data");
 | 
			
		||||
  m_cmd_binder.set_handler("help", boost::bind(&simple_wallet::help, this, _1), "Show this help");
 | 
			
		||||
| 
						 | 
				
			
			@ -99,18 +183,18 @@ bool simple_wallet::set_log(const std::vector<std::string> &args)
 | 
			
		|||
{
 | 
			
		||||
  if(args.size() != 1) 
 | 
			
		||||
  {
 | 
			
		||||
    std::cout << "use: set_log <log_level_number_0-4>" << ENDL;
 | 
			
		||||
    fail_msg_writer() << "use: set_log <log_level_number_0-4>";
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  uint16_t l = 0;
 | 
			
		||||
  if(!string_tools::get_xtype_from_string(l, args[0]))
 | 
			
		||||
  {
 | 
			
		||||
    std::cout << "wrong number format, use: set_log <log_level_number_0-4>" << ENDL;
 | 
			
		||||
    fail_msg_writer() << "wrong number format, use: set_log <log_level_number_0-4>";
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  if(LOG_LEVEL_4 < l)
 | 
			
		||||
  {
 | 
			
		||||
    std::cout << "wrong number range, use: set_log <log_level_number_0-4>" << ENDL;
 | 
			
		||||
    fail_msg_writer() << "wrong number range, use: set_log <log_level_number_0-4>";
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -122,19 +206,27 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
 | 
			
		|||
{
 | 
			
		||||
  handle_command_line(vm);
 | 
			
		||||
 | 
			
		||||
  CHECK_AND_ASSERT_MES(m_daemon_address.empty() || (m_daemon_host.empty() && !m_daemon_port), false, "you can't specify daemon host or port several times");
 | 
			
		||||
  if (!m_daemon_address.empty() && !m_daemon_host.empty() && 0 != m_daemon_port)
 | 
			
		||||
  {
 | 
			
		||||
    fail_msg_writer() << "you can't specify daemon host or port several times";
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t c = 0; 
 | 
			
		||||
  if(!m_generate_new.empty()) ++c;
 | 
			
		||||
  if(!m_wallet_file.empty()) ++c;
 | 
			
		||||
  CHECK_AND_ASSERT_MES(c == 1, false, "you must specify --wallet-file or --generate-new-wallet params");
 | 
			
		||||
  if (1 != c)
 | 
			
		||||
  {
 | 
			
		||||
    fail_msg_writer() << "you must specify --wallet-file or --generate-new-wallet params";
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (m_daemon_host.empty())
 | 
			
		||||
    m_daemon_host = "localhost";
 | 
			
		||||
  if (!m_daemon_port)
 | 
			
		||||
    m_daemon_port = RPC_DEFAULT_PORT;
 | 
			
		||||
  if (m_daemon_address.empty())
 | 
			
		||||
    m_daemon_address = string("http://") + m_daemon_host + ":" + lexical_cast<string>(m_daemon_port);
 | 
			
		||||
    m_daemon_address = std::string("http://") + m_daemon_host + ":" + std::to_string(m_daemon_port);
 | 
			
		||||
 | 
			
		||||
  tools::password_container pwd_container;
 | 
			
		||||
  if (command_line::has_arg(vm, arg_password))
 | 
			
		||||
| 
						 | 
				
			
			@ -144,7 +236,11 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
 | 
			
		|||
  else
 | 
			
		||||
  {
 | 
			
		||||
    bool r = pwd_container.read_password();
 | 
			
		||||
    CHECK_AND_ASSERT_MES(r, false, "failed to read wallet password");
 | 
			
		||||
    if (!r)
 | 
			
		||||
    {
 | 
			
		||||
      fail_msg_writer() << "failed to read wallet password";
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!m_generate_new.empty())
 | 
			
		||||
| 
						 | 
				
			
			@ -169,25 +265,22 @@ bool simple_wallet::deinit()
 | 
			
		|||
  return close_wallet();
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool simple_wallet::handle_command_line(const boost::program_options::variables_map& vm)
 | 
			
		||||
void simple_wallet::handle_command_line(const boost::program_options::variables_map& vm)
 | 
			
		||||
{
 | 
			
		||||
  m_wallet_file    = command_line::get_arg(vm, arg_wallet_file);
 | 
			
		||||
  m_generate_new   = command_line::get_arg(vm, arg_generate_new_wallet);
 | 
			
		||||
  m_daemon_address = command_line::get_arg(vm, arg_daemon_address);
 | 
			
		||||
  m_daemon_host    = command_line::get_arg(vm, arg_daemon_host);
 | 
			
		||||
  m_daemon_port    = command_line::get_arg(vm, arg_daemon_port);
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool simple_wallet::try_connect_to_daemon()
 | 
			
		||||
{
 | 
			
		||||
  if (!m_wallet->check_connection())
 | 
			
		||||
  {
 | 
			
		||||
    std::string msg = "wallet failed to connect to daemon (" + m_daemon_address + "). " +
 | 
			
		||||
      "Daemon either is not started or passed wrong port. " +
 | 
			
		||||
    fail_msg_writer() << "wallet failed to connect to daemon (" << m_daemon_address << "). " <<
 | 
			
		||||
      "Daemon either is not started or passed wrong port. " <<
 | 
			
		||||
      "Please, make sure that daemon is running or restart the wallet with correct daemon address.";
 | 
			
		||||
    print_fail_msg(msg);
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -196,29 +289,31 @@ bool simple_wallet::try_connect_to_daemon()
 | 
			
		|||
bool simple_wallet::new_wallet(const string &wallet_file, const std::string& password)
 | 
			
		||||
{
 | 
			
		||||
  m_wallet_file = wallet_file;
 | 
			
		||||
  if(boost::filesystem::exists(wallet_file))
 | 
			
		||||
 | 
			
		||||
  m_wallet.reset(new tools::wallet2());
 | 
			
		||||
  m_wallet->callback(this);
 | 
			
		||||
  try
 | 
			
		||||
  {
 | 
			
		||||
    std::cout << "wallet creation failed, file " << wallet_file << " already exists" << std::endl;
 | 
			
		||||
    m_wallet->generate(wallet_file, password);
 | 
			
		||||
    message_writer(epee::log_space::console_color_white, true) << "Generated new wallet: " << m_wallet->get_account().get_public_address_str();
 | 
			
		||||
  }
 | 
			
		||||
  catch (const std::exception& e)
 | 
			
		||||
  {
 | 
			
		||||
    fail_msg_writer() << "failed to generate new wallet: " << e.what();
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  m_wallet.reset(new tools::wallet2());
 | 
			
		||||
  bool r = m_wallet->generate(wallet_file, password);
 | 
			
		||||
  if(!r)
 | 
			
		||||
    return false;
 | 
			
		||||
  m_wallet->init(m_daemon_address);
 | 
			
		||||
 | 
			
		||||
  cout << "Generated new wallet" << ENDL;
 | 
			
		||||
  print_address(std::vector<std::string>());
 | 
			
		||||
  r = m_wallet->init(m_daemon_address);
 | 
			
		||||
  CHECK_AND_ASSERT_MES(r, false, "failed to init wallet");
 | 
			
		||||
  std::cout << "**********************************************************************" << ENDL 
 | 
			
		||||
    << "Your wallet has been generated. " << ENDL 
 | 
			
		||||
    << "To start synchronizing with the daemon use \"refresh\" command." << ENDL
 | 
			
		||||
    << "Use \"help\" command to see the list of available commands." << ENDL
 | 
			
		||||
    << "Always use \"exit\" command when closing simplewallet to save "
 | 
			
		||||
    << "current session's state. Otherwise, you will possibly need to synchronize " << ENDL 
 | 
			
		||||
    << "your wallet again. Your wallet key is NOT under risk anyway." << ENDL 
 | 
			
		||||
    << "**********************************************************************" << ENDL;
 | 
			
		||||
  success_msg_writer() <<
 | 
			
		||||
    "**********************************************************************\n" <<
 | 
			
		||||
    "Your wallet has been generated.\n" <<
 | 
			
		||||
    "To start synchronizing with the daemon use \"refresh\" command.\n" <<
 | 
			
		||||
    "Use \"help\" command to see the list of available commands.\n" <<
 | 
			
		||||
    "Always use \"exit\" command when closing simplewallet to save\n" <<
 | 
			
		||||
    "current session's state. Otherwise, you will possibly need to synchronize \n" <<
 | 
			
		||||
    "your wallet again. Your wallet key is NOT under risk anyway.\n" <<
 | 
			
		||||
    "**********************************************************************";
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			@ -226,35 +321,63 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa
 | 
			
		|||
{
 | 
			
		||||
  m_wallet_file = wallet_file;
 | 
			
		||||
  m_wallet.reset(new tools::wallet2());
 | 
			
		||||
  m_wallet->callback(this);
 | 
			
		||||
 | 
			
		||||
  bool r = m_wallet->load(m_wallet_file, password);
 | 
			
		||||
  CHECK_AND_ASSERT_MES(r, false, "failed to load wallet " + m_wallet_file);
 | 
			
		||||
  r = m_wallet->init(m_daemon_address);
 | 
			
		||||
  CHECK_AND_ASSERT_MES(r, false, "failed to init wallet");
 | 
			
		||||
  try
 | 
			
		||||
  {
 | 
			
		||||
    m_wallet->load(m_wallet_file, password);
 | 
			
		||||
    message_writer(epee::log_space::console_color_white, true) << "Opened wallet: " << m_wallet->get_account().get_public_address_str();
 | 
			
		||||
  }
 | 
			
		||||
  catch (const std::exception& e)
 | 
			
		||||
  {
 | 
			
		||||
    fail_msg_writer() << "failed to load wallet: " << e.what();
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  m_wallet->init(m_daemon_address);
 | 
			
		||||
 | 
			
		||||
  refresh(std::vector<std::string>());
 | 
			
		||||
  std::cout << "**********************************************************************" << ENDL 
 | 
			
		||||
    << "Use \"help\" command to see the list of available commands." << ENDL 
 | 
			
		||||
    << "**********************************************************************" << ENDL ;
 | 
			
		||||
  success_msg_writer() <<
 | 
			
		||||
    "**********************************************************************\n" <<
 | 
			
		||||
    "Use \"help\" command to see the list of available commands.\n" <<
 | 
			
		||||
    "**********************************************************************";
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool simple_wallet::close_wallet()
 | 
			
		||||
{
 | 
			
		||||
  bool r = m_wallet->deinit();
 | 
			
		||||
  CHECK_AND_ASSERT_MES(r, false, "failed to deinit wallet");
 | 
			
		||||
  r = m_wallet->store();
 | 
			
		||||
  CHECK_AND_ASSERT_MES(r, false, "failed to store wallet " + m_wallet_file);
 | 
			
		||||
  if (!r)
 | 
			
		||||
  {
 | 
			
		||||
    fail_msg_writer() << "failed to deinit wallet";
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  try
 | 
			
		||||
  {
 | 
			
		||||
    m_wallet->store();
 | 
			
		||||
  }
 | 
			
		||||
  catch (const std::exception& e)
 | 
			
		||||
  {
 | 
			
		||||
    fail_msg_writer() << e.what();
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool simple_wallet::save(const std::vector<std::string> &args)
 | 
			
		||||
{
 | 
			
		||||
  bool r = m_wallet->store();
 | 
			
		||||
  if (r)
 | 
			
		||||
    print_success_msg("Wallet data saved");
 | 
			
		||||
  else
 | 
			
		||||
    print_fail_msg("failed to store wallet " + m_wallet_file);
 | 
			
		||||
  try
 | 
			
		||||
  {
 | 
			
		||||
    m_wallet->store();
 | 
			
		||||
    success_msg_writer() << "Wallet data saved";
 | 
			
		||||
  }
 | 
			
		||||
  catch (const std::exception& e)
 | 
			
		||||
  {
 | 
			
		||||
    fail_msg_writer() << e.what();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			@ -276,24 +399,24 @@ bool simple_wallet::start_mining(const std::vector<std::string>& args)
 | 
			
		|||
    bool ok = string_tools::get_xtype_from_string(num, args[0]);
 | 
			
		||||
    if(!ok || 0 == num)
 | 
			
		||||
    {
 | 
			
		||||
      print_fail_msg("wrong number of mining threads: \"" + args[0] + "\"");
 | 
			
		||||
      fail_msg_writer() << "wrong number of mining threads: \"" << args[0] << "\"";
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    req.threads_count = num;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    print_fail_msg("wrong number of arguments, expected the number of mining threads");
 | 
			
		||||
    fail_msg_writer() << "wrong number of arguments, expected the number of mining threads";
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  COMMAND_RPC_START_MINING::response res;
 | 
			
		||||
  bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/start_mining", req, res, m_http_client);
 | 
			
		||||
  std::string err = tools::interpret_rpc_response(r, res.status);
 | 
			
		||||
  std::string err = interpret_rpc_response(r, res.status);
 | 
			
		||||
  if (err.empty())
 | 
			
		||||
    print_success_msg("Mining started in daemon");
 | 
			
		||||
    success_msg_writer() << "Mining started in daemon";
 | 
			
		||||
  else
 | 
			
		||||
    print_fail_msg("mining has NOT been started: " + err);
 | 
			
		||||
    fail_msg_writer() << "mining has NOT been started: " << err;
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			@ -305,82 +428,158 @@ bool simple_wallet::stop_mining(const std::vector<std::string>& args)
 | 
			
		|||
  COMMAND_RPC_STOP_MINING::request req;
 | 
			
		||||
  COMMAND_RPC_STOP_MINING::response res;
 | 
			
		||||
  bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/stop_mining", req, res, m_http_client);
 | 
			
		||||
  std::string err = tools::interpret_rpc_response(r, res.status);
 | 
			
		||||
  std::string err = interpret_rpc_response(r, res.status);
 | 
			
		||||
  if (err.empty())
 | 
			
		||||
    print_success_msg("Mining stopped in daemon");
 | 
			
		||||
    success_msg_writer() << "Mining stopped in daemon";
 | 
			
		||||
  else
 | 
			
		||||
    print_fail_msg("mining has NOT been stopped: " + err);
 | 
			
		||||
    fail_msg_writer() << "mining has NOT been stopped: " << err;
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
void simple_wallet::on_new_block(uint64_t height, const cryptonote::block& block)
 | 
			
		||||
{
 | 
			
		||||
  m_refresh_progress_reporter.update(height, false);
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
void simple_wallet::on_money_received(uint64_t height, const cryptonote::transaction& tx, size_t out_index)
 | 
			
		||||
{
 | 
			
		||||
  message_writer(epee::log_space::console_color_green, false) <<
 | 
			
		||||
    "Height " << height <<
 | 
			
		||||
    ", transaction " << get_transaction_hash(tx) <<
 | 
			
		||||
    ", received " << print_money(tx.vout[out_index].amount);
 | 
			
		||||
  m_refresh_progress_reporter.update(height, true);
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
void simple_wallet::on_money_spent(uint64_t height, const cryptonote::transaction& in_tx, size_t out_index, const cryptonote::transaction& spend_tx)
 | 
			
		||||
{
 | 
			
		||||
  message_writer(epee::log_space::console_color_magenta, false) <<
 | 
			
		||||
    "Height " << height <<
 | 
			
		||||
    ", transaction " << get_transaction_hash(spend_tx) <<
 | 
			
		||||
    ", spent " << print_money(in_tx.vout[out_index].amount);
 | 
			
		||||
  m_refresh_progress_reporter.update(height, true);
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool simple_wallet::refresh(const std::vector<std::string>& args)
 | 
			
		||||
{
 | 
			
		||||
  if (!try_connect_to_daemon())
 | 
			
		||||
    return true;
 | 
			
		||||
 | 
			
		||||
  std::cout << "Starting refresh..." << endl;
 | 
			
		||||
  std::atomic<bool> refresh_is_done(false);
 | 
			
		||||
  std::thread th([&]()
 | 
			
		||||
  {
 | 
			
		||||
    epee::misc_utils::sleep_no_w(1000);
 | 
			
		||||
    while(!refresh_is_done)
 | 
			
		||||
    {
 | 
			
		||||
      std::string err;
 | 
			
		||||
      uint64_t bc_height = get_daemon_blockchain_height(err);
 | 
			
		||||
      if (err.empty())
 | 
			
		||||
        cout << "Height " << m_wallet->get_blockchain_current_height() << " of " << bc_height << endl;
 | 
			
		||||
      epee::misc_utils::sleep_no_w(1000);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  uint64_t initial_height = m_wallet->get_blockchain_current_height();
 | 
			
		||||
  message_writer() << "Starting refresh...";
 | 
			
		||||
  uint64_t fetched_blocks = 0;
 | 
			
		||||
  bool money_received = false;
 | 
			
		||||
  tools::wallet2::fail_details fd;
 | 
			
		||||
  bool ok = m_wallet->refresh(fetched_blocks, money_received, fd);
 | 
			
		||||
  refresh_is_done = true;
 | 
			
		||||
  th.join();
 | 
			
		||||
  if (ok)
 | 
			
		||||
  bool ok = false;
 | 
			
		||||
  std::ostringstream ss;
 | 
			
		||||
  try
 | 
			
		||||
  {
 | 
			
		||||
    std::stringstream ss;
 | 
			
		||||
    ss << "Refresh done, blocks received: " << fetched_blocks;
 | 
			
		||||
    print_success_msg(ss.str(), true);
 | 
			
		||||
 | 
			
		||||
    m_wallet->refresh(fetched_blocks);
 | 
			
		||||
    ok = true;
 | 
			
		||||
    // Clear line "Height xxx of xxx"
 | 
			
		||||
    std::cout << "\r                                                                \r";
 | 
			
		||||
    success_msg_writer(true) << "Refresh done, blocks received: " << fetched_blocks;
 | 
			
		||||
    show_balance();
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  catch (const tools::error::daemon_busy&)
 | 
			
		||||
  {
 | 
			
		||||
    fetched_blocks = m_wallet->get_blockchain_current_height() - initial_height;
 | 
			
		||||
    std::stringstream ss;
 | 
			
		||||
    ss << "refresh failed: " << fd.what() << ". Blocks received: " << fetched_blocks;
 | 
			
		||||
    print_fail_msg(ss.str());
 | 
			
		||||
    ss << "daemon is busy. Please try later";
 | 
			
		||||
  }
 | 
			
		||||
  catch (const tools::error::no_connection_to_daemon&)
 | 
			
		||||
  {
 | 
			
		||||
    ss << "no connection to daemon. Please, make sure daemon is running";
 | 
			
		||||
  }
 | 
			
		||||
  catch (const tools::error::wallet_rpc_error& e)
 | 
			
		||||
  {
 | 
			
		||||
    LOG_ERROR("Unknown RPC error: " << e.to_string());
 | 
			
		||||
    ss << "RPC error \"" << e.what() << '"';
 | 
			
		||||
  }
 | 
			
		||||
  catch (const tools::error::refresh_error& e)
 | 
			
		||||
  {
 | 
			
		||||
    LOG_ERROR("refresh error: " << e.to_string());
 | 
			
		||||
    ss << e.what();
 | 
			
		||||
  }
 | 
			
		||||
  catch (const tools::error::wallet_internal_error& e)
 | 
			
		||||
  {
 | 
			
		||||
    LOG_ERROR("internal error: " << e.to_string());
 | 
			
		||||
    ss << "internal error: " << e.what();
 | 
			
		||||
  }
 | 
			
		||||
  catch (const std::exception& e)
 | 
			
		||||
  {
 | 
			
		||||
    LOG_ERROR("unexpected error: " << e.what());
 | 
			
		||||
    ss << "unexpected error: " << e.what();
 | 
			
		||||
  }
 | 
			
		||||
  catch (...)
 | 
			
		||||
  {
 | 
			
		||||
    LOG_ERROR("Unknown error");
 | 
			
		||||
    ss << "unknown error";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!ok)
 | 
			
		||||
  {
 | 
			
		||||
    fail_msg_writer() << "refresh failed: " << ss.str() << ". Blocks received: " << fetched_blocks;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool simple_wallet::show_balance(const std::vector<std::string>& args/* = std::vector<std::string>()*/)
 | 
			
		||||
{
 | 
			
		||||
  std::stringstream ss;
 | 
			
		||||
  ss << "balance: " << print_money(m_wallet->balance()) << ", unlocked balance: " << print_money(m_wallet->unlocked_balance());
 | 
			
		||||
  print_success_msg(ss.str());
 | 
			
		||||
  success_msg_writer() << "balance: " << print_money(m_wallet->balance()) << ", unlocked balance: " << print_money(m_wallet->unlocked_balance());
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args)
 | 
			
		||||
{
 | 
			
		||||
  std::cout << "        amount       \tspent\tglobal index\t                              tx id" << std::endl;
 | 
			
		||||
  bool ok = m_wallet->enum_incoming_transfers([](const cryptonote::transaction& tx, uint64_t global_out_index, uint64_t amount, bool spent) {
 | 
			
		||||
    epee::log_space::set_console_color(spent ? epee::log_space::console_color_magenta : epee::log_space::console_color_green, true);
 | 
			
		||||
    std::cout << std::setw(21) << print_money(amount) << '\t'
 | 
			
		||||
      << std::setw(3) << (spent ? 'T' : 'F') << "  \t"
 | 
			
		||||
      << std::setw(12) << global_out_index << '\t'
 | 
			
		||||
      << get_transaction_hash(tx)
 | 
			
		||||
      << '\n';
 | 
			
		||||
  });
 | 
			
		||||
  epee::log_space::reset_console_color();
 | 
			
		||||
  if (ok)
 | 
			
		||||
    std::cout.flush();
 | 
			
		||||
  else
 | 
			
		||||
    print_fail_msg("No incoming transfers");
 | 
			
		||||
  bool filter = false;
 | 
			
		||||
  bool available = false;
 | 
			
		||||
  if (!args.empty())
 | 
			
		||||
  {
 | 
			
		||||
    if (args[0] == "available")
 | 
			
		||||
    {
 | 
			
		||||
      filter = true;
 | 
			
		||||
      available = true;
 | 
			
		||||
    }
 | 
			
		||||
    else if (args[0] == "unavailable")
 | 
			
		||||
    {
 | 
			
		||||
      filter = true;
 | 
			
		||||
      available = false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  tools::wallet2::transfer_container transfers;
 | 
			
		||||
  m_wallet->get_transfers(transfers);
 | 
			
		||||
 | 
			
		||||
  bool transfers_found = false;
 | 
			
		||||
  for (const auto& td : transfers)
 | 
			
		||||
  {
 | 
			
		||||
    if (!filter || available != td.m_spent)
 | 
			
		||||
    {
 | 
			
		||||
      if (!transfers_found)
 | 
			
		||||
      {
 | 
			
		||||
        message_writer() << "        amount       \tspent\tglobal index\t                              tx id";
 | 
			
		||||
        transfers_found = true;
 | 
			
		||||
      }
 | 
			
		||||
      message_writer(td.m_spent ? epee::log_space::console_color_magenta : epee::log_space::console_color_green, false) <<
 | 
			
		||||
        std::setw(21) << print_money(td.amount()) << '\t' <<
 | 
			
		||||
        std::setw(3) << (td.m_spent ? 'T' : 'F') << "  \t" <<
 | 
			
		||||
        std::setw(12) << td.m_global_output_index << '\t' <<
 | 
			
		||||
        get_transaction_hash(td.m_tx);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!transfers_found)
 | 
			
		||||
  {
 | 
			
		||||
    if (!filter)
 | 
			
		||||
    {
 | 
			
		||||
      success_msg_writer() << "No incoming transfers";
 | 
			
		||||
    }
 | 
			
		||||
    else if (available)
 | 
			
		||||
    {
 | 
			
		||||
      success_msg_writer() << "No incoming available transfers";
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      success_msg_writer() << "No incoming unavailable transfers";
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			@ -389,7 +588,7 @@ uint64_t simple_wallet::get_daemon_blockchain_height(std::string& err)
 | 
			
		|||
  COMMAND_RPC_GET_HEIGHT::request req;
 | 
			
		||||
  COMMAND_RPC_GET_HEIGHT::response res = boost::value_initialized<COMMAND_RPC_GET_HEIGHT::response>();
 | 
			
		||||
  bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/getheight", req, res, m_http_client);
 | 
			
		||||
  err = tools::interpret_rpc_response(r, res.status);
 | 
			
		||||
  err = interpret_rpc_response(r, res.status);
 | 
			
		||||
  return res.height;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			@ -401,9 +600,9 @@ bool simple_wallet::show_blockchain_height(const std::vector<std::string>& args)
 | 
			
		|||
  std::string err;
 | 
			
		||||
  uint64_t bc_height = get_daemon_blockchain_height(err);
 | 
			
		||||
  if (err.empty())
 | 
			
		||||
    print_success_msg(boost::lexical_cast<std::string>(bc_height));
 | 
			
		||||
    success_msg_writer() << bc_height;
 | 
			
		||||
  else
 | 
			
		||||
    print_fail_msg("failed to get blockchain height: " + err);
 | 
			
		||||
    fail_msg_writer() << "failed to get blockchain height: " << err;
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			@ -415,65 +614,132 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
 | 
			
		|||
  std::vector<std::string> local_args = args_;
 | 
			
		||||
  if(local_args.size() < 3)
 | 
			
		||||
  {
 | 
			
		||||
    print_fail_msg("wrong number of arguments, expected at least 3, got " + boost::lexical_cast<std::string>(local_args.size()));
 | 
			
		||||
    fail_msg_writer() << "wrong number of arguments, expected at least 3, got " << local_args.size();
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t fake_outs_count;
 | 
			
		||||
  if(!string_tools::get_xtype_from_string(fake_outs_count, local_args[0]))
 | 
			
		||||
  {
 | 
			
		||||
    print_fail_msg("mixin_count should be non-negative integer, got " + local_args[0]);
 | 
			
		||||
    fail_msg_writer() << "mixin_count should be non-negative integer, got " << local_args[0];
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  local_args.erase(local_args.begin());
 | 
			
		||||
 | 
			
		||||
  vector<cryptonote::tx_destination_entry> dsts;
 | 
			
		||||
  uint64_t summary_amount = 0;
 | 
			
		||||
  for (size_t i = 0; i < local_args.size(); i += 2) 
 | 
			
		||||
  for (size_t i = 1; i < local_args.size(); i += 2) 
 | 
			
		||||
  {
 | 
			
		||||
    cryptonote::tx_destination_entry de;
 | 
			
		||||
    if(!get_account_address_from_str(de.addr, local_args[i]))
 | 
			
		||||
    {
 | 
			
		||||
      print_fail_msg("wrong address: " + local_args[i]);
 | 
			
		||||
      fail_msg_writer() << "wrong address: " << local_args[i];
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (local_args.size() <= i + 1)
 | 
			
		||||
    {
 | 
			
		||||
      print_fail_msg("amount for the last address " + local_args[i] + " is not specified");
 | 
			
		||||
      fail_msg_writer() << "amount for the last address " << local_args[i] << " is not specified";
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool ok = cryptonote::parse_amount(de.amount, local_args[i + 1]);
 | 
			
		||||
    if(!ok || 0 == de.amount)
 | 
			
		||||
    {
 | 
			
		||||
      print_fail_msg("amount is wrong: " + local_args[i] + " " + local_args[i + 1]);
 | 
			
		||||
      fail_msg_writer() << "amount is wrong: " << local_args[i] << ' ' << local_args[i + 1] <<
 | 
			
		||||
        ", expected number from 0 to " << print_money(std::numeric_limits<uint64_t>::max());
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    summary_amount += de.amount;
 | 
			
		||||
    dsts.push_back(de);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if(summary_amount > m_wallet->unlocked_balance())
 | 
			
		||||
  try
 | 
			
		||||
  {
 | 
			
		||||
    print_fail_msg("not enough money to transfer " + print_money(summary_amount) + ", available (unlocked) only " + print_money(m_wallet->unlocked_balance()));
 | 
			
		||||
    return true;
 | 
			
		||||
    cryptonote::transaction tx;
 | 
			
		||||
    m_wallet->transfer(dsts, fake_outs_count, 0, DEFAULT_FEE, tx);
 | 
			
		||||
    success_msg_writer(true) << "Money successfully sent, transaction " << get_transaction_hash(tx);
 | 
			
		||||
  }
 | 
			
		||||
  catch (const tools::error::daemon_busy&)
 | 
			
		||||
  {
 | 
			
		||||
    fail_msg_writer() << "daemon is busy. Please try later";
 | 
			
		||||
  }
 | 
			
		||||
  catch (const tools::error::no_connection_to_daemon&)
 | 
			
		||||
  {
 | 
			
		||||
    fail_msg_writer() << "no connection to daemon. Please, make sure daemon is running.";
 | 
			
		||||
  }
 | 
			
		||||
  catch (const tools::error::wallet_rpc_error& e)
 | 
			
		||||
  {
 | 
			
		||||
    LOG_ERROR("Unknown RPC error: " << e.to_string());
 | 
			
		||||
    fail_msg_writer() << "RPC error \"" << e.what() << '"';
 | 
			
		||||
  }
 | 
			
		||||
  catch (const tools::error::get_random_outs_error&)
 | 
			
		||||
  {
 | 
			
		||||
    fail_msg_writer() << "failed to get random outputs to mix";
 | 
			
		||||
  }
 | 
			
		||||
  catch (const tools::error::not_enough_money& e)
 | 
			
		||||
  {
 | 
			
		||||
    fail_msg_writer() << "not enough money to transfer, available only " << print_money(e.available()) <<
 | 
			
		||||
      ", transaction amount " << print_money(e.tx_amount() + e.fee()) << " = " << print_money(e.tx_amount()) <<
 | 
			
		||||
      " + " << print_money(e.fee()) << " (fee)";
 | 
			
		||||
  }
 | 
			
		||||
  catch (const tools::error::not_enough_outs_to_mix& e)
 | 
			
		||||
  {
 | 
			
		||||
    auto writer = fail_msg_writer();
 | 
			
		||||
    writer << "not enough outputs for specified mixin_count = " << e.mixin_count() << ":";
 | 
			
		||||
    for (const cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& outs_for_amount : e.scanty_outs())
 | 
			
		||||
    {
 | 
			
		||||
      writer << "\noutput amount = " << print_money(outs_for_amount.amount) << ", fount outputs to mix = " << outs_for_amount.outs.size();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  catch (const tools::error::tx_not_constructed&)
 | 
			
		||||
  {
 | 
			
		||||
    fail_msg_writer() << "transaction was not constructed";
 | 
			
		||||
  }
 | 
			
		||||
  catch (const tools::error::tx_rejected& e)
 | 
			
		||||
  {
 | 
			
		||||
    fail_msg_writer() << "transaction " << get_transaction_hash(e.tx()) << " was rejected by daemon with status \"" << e.status() << '"';
 | 
			
		||||
  }
 | 
			
		||||
  catch (const tools::error::tx_sum_overflow& e)
 | 
			
		||||
  {
 | 
			
		||||
    fail_msg_writer() << e.what();
 | 
			
		||||
  }
 | 
			
		||||
  catch (const tools::error::tx_too_big& e)
 | 
			
		||||
  {
 | 
			
		||||
    cryptonote::transaction tx = e.tx();
 | 
			
		||||
    fail_msg_writer() << "transaction " << get_transaction_hash(e.tx()) << " is too big. Transaction size: " <<
 | 
			
		||||
      get_object_blobsize(e.tx()) << " bytes, transaction size limit: " << e.tx_size_limit() << " bytes";
 | 
			
		||||
  }
 | 
			
		||||
  catch (const tools::error::zero_destination&)
 | 
			
		||||
  {
 | 
			
		||||
    fail_msg_writer() << "one of destinations is zero";
 | 
			
		||||
  }
 | 
			
		||||
  catch (const tools::error::transfer_error& e)
 | 
			
		||||
  {
 | 
			
		||||
    LOG_ERROR("unknown transfer error: " << e.to_string());
 | 
			
		||||
    fail_msg_writer() << "unknown transfer error: " << e.what();
 | 
			
		||||
  }
 | 
			
		||||
  catch (const tools::error::wallet_internal_error& e)
 | 
			
		||||
  {
 | 
			
		||||
    LOG_ERROR("internal error: " << e.to_string());
 | 
			
		||||
    fail_msg_writer() << "internal error: " << e.what();
 | 
			
		||||
  }
 | 
			
		||||
  catch (const std::exception& e)
 | 
			
		||||
  {
 | 
			
		||||
    LOG_ERROR("unexpected error: " << e.what());
 | 
			
		||||
    fail_msg_writer() << "unexpected error: " << e.what();
 | 
			
		||||
  }
 | 
			
		||||
  catch (...)
 | 
			
		||||
  {
 | 
			
		||||
    LOG_ERROR("Unknown error");
 | 
			
		||||
    fail_msg_writer() << "unknown error";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  cryptonote::transaction tx;
 | 
			
		||||
  tools::wallet2::fail_details tfd;
 | 
			
		||||
  bool ok = m_wallet->transfer(dsts, fake_outs_count, 0, DEFAULT_FEE, tx, tfd);
 | 
			
		||||
  if (ok)
 | 
			
		||||
    print_success_msg("Money successfully sent", true);
 | 
			
		||||
  else
 | 
			
		||||
    print_fail_msg("failed to transfer money: " + tfd.what());
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool simple_wallet::run()
 | 
			
		||||
{
 | 
			
		||||
  return m_cmd_binder.run_handling("[wallet]# ", "");
 | 
			
		||||
  std::string addr_start = m_wallet->get_account().get_public_address_str().substr(0, 6);
 | 
			
		||||
  return m_cmd_binder.run_handling("[wallet " + addr_start + "]: ", "");
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
void simple_wallet::stop()
 | 
			
		||||
| 
						 | 
				
			
			@ -482,9 +748,9 @@ void simple_wallet::stop()
 | 
			
		|||
  m_wallet->stop();
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool simple_wallet::print_address(const std::vector<std::string> &args)
 | 
			
		||||
bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
 | 
			
		||||
{
 | 
			
		||||
  print_success_msg(m_wallet->get_account().get_public_address_str());
 | 
			
		||||
  success_msg_writer() << m_wallet->get_account().get_public_address_str();
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			@ -495,7 +761,6 @@ bool simple_wallet::process_command(const std::vector<std::string> &args)
 | 
			
		|||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
int main(int argc, char* argv[])
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
  _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -517,6 +782,7 @@ int main(int argc, char* argv[])
 | 
			
		|||
  command_line::add_arg(desc_params, arg_daemon_port);
 | 
			
		||||
  command_line::add_arg(desc_params, arg_command);
 | 
			
		||||
  command_line::add_arg(desc_params, arg_log_level);
 | 
			
		||||
  tools::wallet_rpc_server::init_options(desc_params);
 | 
			
		||||
 | 
			
		||||
  po::positional_options_description positional_options;
 | 
			
		||||
  positional_options.add(arg_command.name, -1);
 | 
			
		||||
| 
						 | 
				
			
			@ -531,13 +797,13 @@ int main(int argc, char* argv[])
 | 
			
		|||
 | 
			
		||||
    if (command_line::get_arg(vm, command_line::arg_help))
 | 
			
		||||
    {
 | 
			
		||||
      std::cout << "Usage: simplewallet [--wallet-file=<file>|--generate-new-wallet=<file>] [--daemon-address=<host>:<port>] [<COMMAND>]\n";
 | 
			
		||||
      std::cout << desc_all << '\n' << w.get_commands_str() << std::endl;
 | 
			
		||||
      success_msg_writer() << "Usage: simplewallet [--wallet-file=<file>|--generate-new-wallet=<file>] [--daemon-address=<host>:<port>] [<COMMAND>]";
 | 
			
		||||
      success_msg_writer() << desc_all << '\n' << w.get_commands_str();
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    else if (command_line::get_arg(vm, command_line::arg_version))
 | 
			
		||||
    {
 | 
			
		||||
      std::cout << CRYPTONOTE_NAME << " wallet v" << PROJECT_VERSION_LONG << ENDL;
 | 
			
		||||
      success_msg_writer() << CRYPTONOTE_NAME << " wallet v" << PROJECT_VERSION_LONG;
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -551,33 +817,104 @@ int main(int argc, char* argv[])
 | 
			
		|||
 | 
			
		||||
  //set up logging options
 | 
			
		||||
  log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2);
 | 
			
		||||
  log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_0);
 | 
			
		||||
  //log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_0);
 | 
			
		||||
  log_space::log_singletone::add_logger(LOGGER_FILE,
 | 
			
		||||
    log_space::log_singletone::get_default_log_file().c_str(),
 | 
			
		||||
    log_space::log_singletone::get_default_log_folder().c_str(), LOG_LEVEL_4);
 | 
			
		||||
 | 
			
		||||
  LOG_PRINT_L0(CRYPTONOTE_NAME << " wallet v" << PROJECT_VERSION_LONG);
 | 
			
		||||
  message_writer(epee::log_space::console_color_white, true) << CRYPTONOTE_NAME << " wallet v" << PROJECT_VERSION_LONG;
 | 
			
		||||
 | 
			
		||||
  if(command_line::has_arg(vm, arg_log_level))
 | 
			
		||||
  {
 | 
			
		||||
    LOG_PRINT_L0("Setting log level = " << command_line::get_arg(vm, arg_log_level));
 | 
			
		||||
    log_space::get_set_log_detalisation_level(true, command_line::get_arg(vm, arg_log_level));
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  if(command_line::has_arg(vm, tools::wallet_rpc_server::arg_rpc_bind_port))
 | 
			
		||||
  {
 | 
			
		||||
    log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_2);
 | 
			
		||||
    //runs wallet with rpc interface 
 | 
			
		||||
    if(!command_line::has_arg(vm, arg_wallet_file) )
 | 
			
		||||
    {
 | 
			
		||||
      LOG_ERROR("Wallet file not set.");
 | 
			
		||||
      return 1;
 | 
			
		||||
    }
 | 
			
		||||
    if(!command_line::has_arg(vm, arg_daemon_address) )
 | 
			
		||||
    {
 | 
			
		||||
      LOG_ERROR("Daemon address not set.");
 | 
			
		||||
      return 1;
 | 
			
		||||
    }
 | 
			
		||||
    if(!command_line::has_arg(vm, arg_password) )
 | 
			
		||||
    {
 | 
			
		||||
      LOG_ERROR("Wallet password not set.");
 | 
			
		||||
      return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  r = w.init(vm);
 | 
			
		||||
  CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize wallet");
 | 
			
		||||
    std::string wallet_file     = command_line::get_arg(vm, arg_wallet_file);    
 | 
			
		||||
    std::string wallet_password = command_line::get_arg(vm, arg_password);
 | 
			
		||||
    std::string daemon_address  = command_line::get_arg(vm, arg_daemon_address);
 | 
			
		||||
    std::string daemon_host = command_line::get_arg(vm, arg_daemon_host);
 | 
			
		||||
    int daemon_port = command_line::get_arg(vm, arg_daemon_port);
 | 
			
		||||
    if (daemon_host.empty())
 | 
			
		||||
      daemon_host = "localhost";
 | 
			
		||||
    if (!daemon_port)
 | 
			
		||||
      daemon_port = RPC_DEFAULT_PORT;
 | 
			
		||||
    if (daemon_address.empty())
 | 
			
		||||
      daemon_address = std::string("http://") + daemon_host + ":" + std::to_string(daemon_port);
 | 
			
		||||
 | 
			
		||||
  std::vector<std::string> command = command_line::get_arg(vm, arg_command);
 | 
			
		||||
  if (!command.empty())
 | 
			
		||||
    w.process_command(command);
 | 
			
		||||
    tools::wallet2 wal;
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
      LOG_PRINT_L0("Loading wallet...");
 | 
			
		||||
      wal.load(wallet_file, wallet_password);
 | 
			
		||||
      wal.init(daemon_address);
 | 
			
		||||
      wal.refresh();
 | 
			
		||||
      LOG_PRINT_GREEN("Loaded ok", LOG_LEVEL_0);
 | 
			
		||||
    }
 | 
			
		||||
    catch (const std::exception& e)
 | 
			
		||||
    {
 | 
			
		||||
      LOG_ERROR("Wallet initialize failed: " << e.what());
 | 
			
		||||
      return 1;
 | 
			
		||||
    }
 | 
			
		||||
    tools::wallet_rpc_server wrpc(wal);
 | 
			
		||||
    bool r = wrpc.init(vm);
 | 
			
		||||
    CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize wallet rpc server");
 | 
			
		||||
 | 
			
		||||
  tools::signal_handler::install([&w] {
 | 
			
		||||
    w.stop();
 | 
			
		||||
  });
 | 
			
		||||
  w.run();
 | 
			
		||||
    tools::signal_handler::install([&wrpc, &wal] {
 | 
			
		||||
      wrpc.send_stop_signal();
 | 
			
		||||
      wal.store();
 | 
			
		||||
    });
 | 
			
		||||
    LOG_PRINT_L0("Starting wallet rpc server");
 | 
			
		||||
    wrpc.run();
 | 
			
		||||
    LOG_PRINT_L0("Stopped wallet rpc server");
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
      LOG_PRINT_L0("Storing wallet...");
 | 
			
		||||
      wal.store();
 | 
			
		||||
      LOG_PRINT_GREEN("Stored ok", LOG_LEVEL_0);
 | 
			
		||||
    }
 | 
			
		||||
    catch (const std::exception& e)
 | 
			
		||||
    {
 | 
			
		||||
      LOG_ERROR("Failed to store wallet: " << e.what());
 | 
			
		||||
      return 1;
 | 
			
		||||
    }
 | 
			
		||||
  }else
 | 
			
		||||
  {
 | 
			
		||||
    //runs wallet with console interface 
 | 
			
		||||
    r = w.init(vm);
 | 
			
		||||
    CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize wallet");
 | 
			
		||||
 | 
			
		||||
  w.deinit();
 | 
			
		||||
    std::vector<std::string> command = command_line::get_arg(vm, arg_command);
 | 
			
		||||
    if (!command.empty())
 | 
			
		||||
      w.process_command(command);
 | 
			
		||||
 | 
			
		||||
    tools::signal_handler::install([&w] {
 | 
			
		||||
      w.stop();
 | 
			
		||||
    });
 | 
			
		||||
    w.run();
 | 
			
		||||
 | 
			
		||||
    w.deinit();
 | 
			
		||||
  }
 | 
			
		||||
  return 1;
 | 
			
		||||
  //CATCH_ENTRY_L0("main", 1);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ namespace cryptonote
 | 
			
		|||
  /************************************************************************/
 | 
			
		||||
  /*                                                                      */
 | 
			
		||||
  /************************************************************************/
 | 
			
		||||
  class simple_wallet
 | 
			
		||||
  class simple_wallet : public tools::i_wallet2_callback
 | 
			
		||||
  {
 | 
			
		||||
  public:
 | 
			
		||||
    typedef std::vector<std::string> command_type;
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +35,7 @@ namespace cryptonote
 | 
			
		|||
    bool process_command(const std::vector<std::string> &args);
 | 
			
		||||
    std::string get_commands_str();
 | 
			
		||||
  private:
 | 
			
		||||
    bool handle_command_line(const boost::program_options::variables_map& vm);
 | 
			
		||||
    void handle_command_line(const boost::program_options::variables_map& vm);
 | 
			
		||||
 | 
			
		||||
    bool run_console_handler();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -51,13 +51,72 @@ namespace cryptonote
 | 
			
		|||
    bool show_incoming_transfers(const std::vector<std::string> &args);
 | 
			
		||||
    bool show_blockchain_height(const std::vector<std::string> &args);
 | 
			
		||||
    bool transfer(const std::vector<std::string> &args);
 | 
			
		||||
    bool print_address(const std::vector<std::string> &args);
 | 
			
		||||
    bool print_address(const std::vector<std::string> &args = std::vector<std::string>());
 | 
			
		||||
    bool save(const std::vector<std::string> &args);
 | 
			
		||||
    bool set_log(const std::vector<std::string> &args);
 | 
			
		||||
 | 
			
		||||
    uint64_t get_daemon_blockchain_height(std::string& err);
 | 
			
		||||
    bool try_connect_to_daemon();
 | 
			
		||||
 | 
			
		||||
    //----------------- i_wallet2_callback ---------------------
 | 
			
		||||
    virtual void on_new_block(uint64_t height, const cryptonote::block& block);
 | 
			
		||||
    virtual void on_money_received(uint64_t height, const cryptonote::transaction& tx, size_t out_index);
 | 
			
		||||
    virtual void on_money_spent(uint64_t height, const cryptonote::transaction& in_tx, size_t out_index, const cryptonote::transaction& spend_tx);
 | 
			
		||||
    //----------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
    friend class refresh_progress_reporter_t;
 | 
			
		||||
 | 
			
		||||
    class refresh_progress_reporter_t
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
      refresh_progress_reporter_t(cryptonote::simple_wallet& simple_wallet)
 | 
			
		||||
        : m_simple_wallet(simple_wallet)
 | 
			
		||||
        , m_blockchain_height(0)
 | 
			
		||||
        , m_blockchain_height_update_time()
 | 
			
		||||
        , m_print_time()
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      void update(uint64_t height, bool force = false)
 | 
			
		||||
      {
 | 
			
		||||
        auto current_time = std::chrono::system_clock::now();
 | 
			
		||||
        if (std::chrono::seconds(DIFFICULTY_TARGET / 2) < current_time - m_blockchain_height_update_time || m_blockchain_height <= height)
 | 
			
		||||
        {
 | 
			
		||||
          update_blockchain_height();
 | 
			
		||||
          m_blockchain_height = (std::max)(m_blockchain_height, height);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (std::chrono::milliseconds(1) < current_time - m_print_time || force)
 | 
			
		||||
        {
 | 
			
		||||
          std::cout << "Height " << height << " of " << m_blockchain_height << '\r';
 | 
			
		||||
          m_print_time = current_time;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
      void update_blockchain_height()
 | 
			
		||||
      {
 | 
			
		||||
        std::string err;
 | 
			
		||||
        uint64_t blockchain_height = m_simple_wallet.get_daemon_blockchain_height(err);
 | 
			
		||||
        if (err.empty())
 | 
			
		||||
        {
 | 
			
		||||
          m_blockchain_height = blockchain_height;
 | 
			
		||||
          m_blockchain_height_update_time = std::chrono::system_clock::now();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
          LOG_ERROR("Failed to get current blockchain height: " << err);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
      cryptonote::simple_wallet& m_simple_wallet;
 | 
			
		||||
      uint64_t m_blockchain_height;
 | 
			
		||||
      std::chrono::system_clock::time_point m_blockchain_height_update_time;
 | 
			
		||||
      std::chrono::system_clock::time_point m_print_time;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    std::string m_wallet_file;
 | 
			
		||||
    std::string m_generate_new;
 | 
			
		||||
    std::string m_import_path;
 | 
			
		||||
| 
						 | 
				
			
			@ -70,5 +129,6 @@ namespace cryptonote
 | 
			
		|||
 | 
			
		||||
    std::unique_ptr<tools::wallet2> m_wallet;
 | 
			
		||||
    net_utils::http::http_simple_client m_http_client;
 | 
			
		||||
    refresh_progress_reporter_t m_refresh_progress_reporter;
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
#define BUILD_COMMIT_ID "@VERSION@"
 | 
			
		||||
#define PROJECT_VERSION "0.8.2"
 | 
			
		||||
#define PROJECT_VERSION_BUILD_NO "284"
 | 
			
		||||
#define PROJECT_VERSION "0.8.3"
 | 
			
		||||
#define PROJECT_VERSION_BUILD_NO "288"
 | 
			
		||||
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,25 +25,25 @@ using namespace cryptonote;
 | 
			
		|||
namespace tools
 | 
			
		||||
{
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::init(const std::string& daemon_address, uint64_t upper_transaction_size_limit)
 | 
			
		||||
void wallet2::init(const std::string& daemon_address, uint64_t upper_transaction_size_limit)
 | 
			
		||||
{
 | 
			
		||||
  m_upper_transaction_size_limit = upper_transaction_size_limit;
 | 
			
		||||
  m_daemon_address = daemon_address;
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::process_new_transaction(cryptonote::transaction& tx, uint64_t height, fail_details& fd)
 | 
			
		||||
void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_t height)
 | 
			
		||||
{
 | 
			
		||||
  process_unconfirmed(tx);
 | 
			
		||||
  std::vector<size_t> outs;
 | 
			
		||||
  uint64_t tx_money_got_in_outs = 0;
 | 
			
		||||
  crypto::public_key tx_pub_key = null_pkey;
 | 
			
		||||
  bool r = parse_and_validate_tx_extra(tx, tx_pub_key);
 | 
			
		||||
  fd.reason = fail_details::error_to_parse_tx_extra;
 | 
			
		||||
  CHECK_AND_ASSERT_MES(r && tx_pub_key != null_pkey, false, "process_new_transaction failed.");
 | 
			
		||||
  CHECK_AND_THROW_WALLET_EX(!r, error::tx_extra_parse_error, tx);
 | 
			
		||||
 | 
			
		||||
  r = lookup_acc_outs(m_account.get_keys(), tx, tx_pub_key, outs, tx_money_got_in_outs);
 | 
			
		||||
  fd.reason = fail_details::error_invalid_tx;
 | 
			
		||||
  CHECK_AND_ASSERT_MES(r, false, "call lookup_acc_outs failed");
 | 
			
		||||
  if(outs.size() && tx_money_got_in_outs)
 | 
			
		||||
  CHECK_AND_THROW_WALLET_EX(!r, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys());
 | 
			
		||||
 | 
			
		||||
  if(!outs.empty() && tx_money_got_in_outs)
 | 
			
		||||
  {
 | 
			
		||||
    //good news - got money! take care about it
 | 
			
		||||
    //usually we have only one transfer for user in transaction
 | 
			
		||||
| 
						 | 
				
			
			@ -51,25 +51,18 @@ bool wallet2::process_new_transaction(cryptonote::transaction& tx, uint64_t heig
 | 
			
		|||
    cryptonote::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response res = AUTO_VAL_INIT(res);
 | 
			
		||||
    req.txid = get_transaction_hash(tx);
 | 
			
		||||
    bool r = net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/get_o_indexes.bin", req, res, m_http_client, WALLET_RCP_CONNECTION_TIMEOUT);
 | 
			
		||||
    if (!r)                                      fd.reason = fail_details::error_not_connected;
 | 
			
		||||
    else if (CORE_RPC_STATUS_BUSY == res.status) fd.reason = fail_details::error_daemon_is_busy;
 | 
			
		||||
    else if (CORE_RPC_STATUS_OK != res.status)   fd.reason = fail_details::error_internal_error;
 | 
			
		||||
    else                                         fd.reason = fail_details::error_ok;
 | 
			
		||||
    if (fail_details::error_ok != fd.reason)
 | 
			
		||||
    {
 | 
			
		||||
      // in case of split while lookup_acc_outs, transaction could be lost (especially if it is coinbase tx)
 | 
			
		||||
      LOG_PRINT_L0("failed to invoke get_o_indexes.bin: " << interpret_rpc_response(r, res.status));
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fd.reason = fail_details::error_internal_error;
 | 
			
		||||
    CHECK_AND_ASSERT_MES(res.o_indexes.size() == tx.vout.size(), false, "internal error: transactions outputs size=" << tx.vout.size()
 | 
			
		||||
      << " not match with COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES response size=" << res.o_indexes.size());
 | 
			
		||||
    CHECK_AND_THROW_WALLET_EX(!r, error::no_connection_to_daemon, "get_o_indexes.bin");
 | 
			
		||||
    CHECK_AND_THROW_WALLET_EX(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_o_indexes.bin");
 | 
			
		||||
    CHECK_AND_THROW_WALLET_EX(res.status != CORE_RPC_STATUS_OK, error::get_out_indices_error, res.status);
 | 
			
		||||
    CHECK_AND_THROW_WALLET_EX(res.o_indexes.size() != tx.vout.size(), error::wallet_internal_error,
 | 
			
		||||
      "transactions outputs size=" + std::to_string(tx.vout.size()) +
 | 
			
		||||
      " not match with COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES response size=" + std::to_string(res.o_indexes.size()));
 | 
			
		||||
 | 
			
		||||
    BOOST_FOREACH(size_t o, outs)
 | 
			
		||||
    {
 | 
			
		||||
      fd.reason = fail_details::error_invalid_tx;
 | 
			
		||||
      CHECK_AND_ASSERT_MES(o < tx.vout.size(), false, "wrong out in transaction: internal index=" << o << ", total_outs" << tx.vout.size());
 | 
			
		||||
      CHECK_AND_THROW_WALLET_EX(tx.vout.size() <= o, error::wallet_internal_error, "wrong out in transaction: internal index=" +
 | 
			
		||||
        std::to_string(o) + ", total_outs=" + std::to_string(tx.vout.size()));
 | 
			
		||||
 | 
			
		||||
      m_transfers.push_back(boost::value_initialized<transfer_details>());
 | 
			
		||||
      transfer_details& td = m_transfers.back();
 | 
			
		||||
      td.m_block_height = height;
 | 
			
		||||
| 
						 | 
				
			
			@ -79,12 +72,13 @@ bool wallet2::process_new_transaction(cryptonote::transaction& tx, uint64_t heig
 | 
			
		|||
      td.m_spent = false;
 | 
			
		||||
      cryptonote::keypair in_ephemeral;
 | 
			
		||||
      cryptonote::generate_key_image_helper(m_account.get_keys(), tx_pub_key, o, in_ephemeral, td.m_key_image);
 | 
			
		||||
      fd.reason = fail_details::error_internal_error;
 | 
			
		||||
      CHECK_AND_ASSERT_MES(in_ephemeral.pub == boost::get<cryptonote::txout_to_key>(tx.vout[o].target).key,
 | 
			
		||||
        false, "internal error: at key_image generating ephemeral public key not matched with output_key");
 | 
			
		||||
      CHECK_AND_THROW_WALLET_EX(in_ephemeral.pub != boost::get<cryptonote::txout_to_key>(tx.vout[o].target).key,
 | 
			
		||||
        error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
 | 
			
		||||
 | 
			
		||||
      m_key_images[td.m_key_image] = m_transfers.size()-1;
 | 
			
		||||
      LOG_PRINT_COLOR("Received money: " << print_money(td.amount()) << ", with tx: " << get_transaction_hash(tx),
 | 
			
		||||
        LOG_LEVEL_0, epee::log_space::console_color_green);
 | 
			
		||||
      LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << get_transaction_hash(tx));
 | 
			
		||||
      if (0 != m_callback)
 | 
			
		||||
        m_callback->on_money_received(height, td.m_tx, td.m_internal_output_index);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // check all outputs for spending (compare key images)
 | 
			
		||||
| 
						 | 
				
			
			@ -95,36 +89,42 @@ bool wallet2::process_new_transaction(cryptonote::transaction& tx, uint64_t heig
 | 
			
		|||
    auto it = m_key_images.find(boost::get<cryptonote::txin_to_key>(in).k_image);
 | 
			
		||||
    if(it != m_key_images.end())
 | 
			
		||||
    {
 | 
			
		||||
      LOG_PRINT_COLOR("Spent money: " << print_money(boost::get<cryptonote::txin_to_key>(in).amount) << ", with tx: " << get_transaction_hash(tx),
 | 
			
		||||
        LOG_LEVEL_0, epee::log_space::console_color_magenta);
 | 
			
		||||
      m_transfers[it->second].m_spent = true;
 | 
			
		||||
      LOG_PRINT_L0("Spent money: " << print_money(boost::get<cryptonote::txin_to_key>(in).amount) << ", with tx: " << get_transaction_hash(tx));
 | 
			
		||||
      transfer_details& td = m_transfers[it->second];
 | 
			
		||||
      td.m_spent = true;
 | 
			
		||||
      if (0 != m_callback)
 | 
			
		||||
        m_callback->on_money_spent(height, td.m_tx, td.m_internal_output_index, tx);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::process_new_blockchain_entry(cryptonote::block& b, cryptonote::block_complete_entry& bche, crypto::hash& bl_id, uint64_t height, fail_details& fd)
 | 
			
		||||
void wallet2::process_unconfirmed(const cryptonote::transaction& tx)
 | 
			
		||||
{
 | 
			
		||||
  auto unconf_it = m_unconfirmed_txs.find(get_transaction_hash(tx));
 | 
			
		||||
  if(unconf_it != m_unconfirmed_txs.end())
 | 
			
		||||
    m_unconfirmed_txs.erase(unconf_it);
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
void wallet2::process_new_blockchain_entry(const cryptonote::block& b, cryptonote::block_complete_entry& bche, crypto::hash& bl_id, uint64_t height)
 | 
			
		||||
{
 | 
			
		||||
  //handle transactions from new block
 | 
			
		||||
  fd.reason = fail_details::error_internal_error;
 | 
			
		||||
  CHECK_AND_ASSERT_MES(height == m_blockchain.size(), false, "internal error: current_index=" << height << ", m_blockchain.size()=" << m_blockchain.size());
 | 
			
		||||
  CHECK_AND_THROW_WALLET_EX(height != m_blockchain.size(), error::wallet_internal_error,
 | 
			
		||||
    "current_index=" + std::to_string(height) + ", m_blockchain.size()=" + std::to_string(m_blockchain.size()));
 | 
			
		||||
 | 
			
		||||
  //optimization: seeking only for blocks that are not older then the wallet creation time plus 1 day. 1 day is for possible user incorrect time setup
 | 
			
		||||
  if(b.timestamp + 60*60*24 > m_account.get_createtime())
 | 
			
		||||
  {
 | 
			
		||||
    TIME_MEASURE_START(miner_tx_handle_time);
 | 
			
		||||
    bool r = process_new_transaction(b.miner_tx, height, fd);
 | 
			
		||||
    process_new_transaction(b.miner_tx, height);
 | 
			
		||||
    TIME_MEASURE_FINISH(miner_tx_handle_time);
 | 
			
		||||
    CHECK_AND_NO_ASSERT_MES(r, false, "failed to process transaction");
 | 
			
		||||
 | 
			
		||||
    TIME_MEASURE_START(txs_handle_time);
 | 
			
		||||
    BOOST_FOREACH(auto& txblob, bche.txs)
 | 
			
		||||
    {
 | 
			
		||||
      cryptonote::transaction tx;
 | 
			
		||||
      r = parse_and_validate_tx_from_blob(txblob, tx);
 | 
			
		||||
      fd.reason = fail_details::error_to_parse_tx;
 | 
			
		||||
      CHECK_AND_ASSERT_MES(r, false, "failed to parse and validate transaction from blob");
 | 
			
		||||
      r = process_new_transaction(tx, height, fd);
 | 
			
		||||
      CHECK_AND_ASSERT_MES(r, false, "failed to process transaction");
 | 
			
		||||
      bool r = parse_and_validate_tx_from_blob(txblob, tx);
 | 
			
		||||
      CHECK_AND_THROW_WALLET_EX(!r, error::tx_parse_error, txblob);
 | 
			
		||||
      process_new_transaction(tx, height);
 | 
			
		||||
    }
 | 
			
		||||
    TIME_MEASURE_FINISH(txs_handle_time);
 | 
			
		||||
    LOG_PRINT_L2("Processed block: " << bl_id << ", height " << height << ", " <<  miner_tx_handle_time + txs_handle_time << "(" << miner_tx_handle_time << "/" << txs_handle_time <<")ms");
 | 
			
		||||
| 
						 | 
				
			
			@ -134,16 +134,18 @@ bool wallet2::process_new_blockchain_entry(cryptonote::block& b, cryptonote::blo
 | 
			
		|||
  }
 | 
			
		||||
  m_blockchain.push_back(bl_id);
 | 
			
		||||
  ++m_local_bc_height;
 | 
			
		||||
  return true;
 | 
			
		||||
 | 
			
		||||
  if (0 != m_callback)
 | 
			
		||||
    m_callback->on_new_block(height, b);
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::get_short_chain_history(std::list<crypto::hash>& ids)
 | 
			
		||||
void wallet2::get_short_chain_history(std::list<crypto::hash>& ids)
 | 
			
		||||
{
 | 
			
		||||
  size_t i = 0;
 | 
			
		||||
  size_t current_multiplier = 1;
 | 
			
		||||
  size_t sz = m_blockchain.size();
 | 
			
		||||
  if(!sz)
 | 
			
		||||
    return true;
 | 
			
		||||
    return;
 | 
			
		||||
  size_t current_back_offset = 1;
 | 
			
		||||
  bool genesis_included = false;
 | 
			
		||||
  while(current_back_offset < sz)
 | 
			
		||||
| 
						 | 
				
			
			@ -162,77 +164,68 @@ bool wallet2::get_short_chain_history(std::list<crypto::hash>& ids)
 | 
			
		|||
  }
 | 
			
		||||
  if(!genesis_included)
 | 
			
		||||
    ids.push_back(m_blockchain[0]);
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::pull_blocks(size_t& blocks_added, fail_details& fd)
 | 
			
		||||
void wallet2::pull_blocks(size_t& blocks_added)
 | 
			
		||||
{
 | 
			
		||||
  blocks_added = 0;
 | 
			
		||||
  cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::request req = AUTO_VAL_INIT(req);
 | 
			
		||||
  cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::response res = AUTO_VAL_INIT(res);
 | 
			
		||||
  get_short_chain_history(req.block_ids);
 | 
			
		||||
  bool r = net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/getblocks.bin", req, res, m_http_client, WALLET_RCP_CONNECTION_TIMEOUT);
 | 
			
		||||
  if (!r)                                      fd.reason = fail_details::error_not_connected;
 | 
			
		||||
  else if (CORE_RPC_STATUS_BUSY == res.status) fd.reason = fail_details::error_daemon_is_busy;
 | 
			
		||||
  else if (CORE_RPC_STATUS_OK != res.status)   fd.reason = fail_details::error_internal_error;
 | 
			
		||||
  else                                         fd.reason = fail_details::error_ok;
 | 
			
		||||
  if (fail_details::error_ok != fd.reason)
 | 
			
		||||
  {
 | 
			
		||||
    LOG_PRINT_L0("failed to get blocks: " << interpret_rpc_response(r, res.status));
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //find split position, if split happened
 | 
			
		||||
 | 
			
		||||
  fd.reason = fail_details::error_internal_error;
 | 
			
		||||
  CHECK_AND_ASSERT_MES(res.start_height < m_blockchain.size(), false, "wrong daemon response: m_start_height="
 | 
			
		||||
    << res.start_height << " not less than local blockchain size=" << m_blockchain.size());
 | 
			
		||||
  CHECK_AND_THROW_WALLET_EX(!r, error::no_connection_to_daemon, "getblocks.bin");
 | 
			
		||||
  CHECK_AND_THROW_WALLET_EX(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getblocks.bin");
 | 
			
		||||
  CHECK_AND_THROW_WALLET_EX(res.status != CORE_RPC_STATUS_OK, error::get_blocks_error, res.status);
 | 
			
		||||
  CHECK_AND_THROW_WALLET_EX(m_blockchain.size() <= res.start_height, error::wallet_internal_error,
 | 
			
		||||
    "wrong daemon response: m_start_height=" + std::to_string(res.start_height) +
 | 
			
		||||
    " not less than local blockchain size=" + std::to_string(m_blockchain.size()));
 | 
			
		||||
 | 
			
		||||
  size_t current_index = res.start_height;
 | 
			
		||||
  BOOST_FOREACH(auto& bl_entry, res.blocks)
 | 
			
		||||
  {
 | 
			
		||||
    cryptonote::block bl;
 | 
			
		||||
    r = cryptonote::parse_and_validate_block_from_blob(bl_entry.block, bl);
 | 
			
		||||
    fd.reason = fail_details::error_to_parse_block;
 | 
			
		||||
    CHECK_AND_ASSERT_MES(r, false, "failed to parse/validate block");
 | 
			
		||||
    CHECK_AND_THROW_WALLET_EX(!r, error::block_parse_error, bl_entry.block);
 | 
			
		||||
 | 
			
		||||
    crypto::hash bl_id = get_block_hash(bl);
 | 
			
		||||
    if(current_index >= m_blockchain.size())
 | 
			
		||||
    {
 | 
			
		||||
      r = process_new_blockchain_entry(bl, bl_entry, bl_id, current_index, fd);
 | 
			
		||||
      if(!r) return false;
 | 
			
		||||
      process_new_blockchain_entry(bl, bl_entry, bl_id, current_index);
 | 
			
		||||
      ++blocks_added;
 | 
			
		||||
    }else
 | 
			
		||||
    {
 | 
			
		||||
      if(bl_id != m_blockchain[current_index])
 | 
			
		||||
      {
 | 
			
		||||
        //split detected here !!!
 | 
			
		||||
        fd.reason = fail_details::error_internal_error;
 | 
			
		||||
        CHECK_AND_ASSERT_MES(current_index != res.start_height, false, "wrong daemon response: first block in response " << string_tools::pod_to_hex(bl_id)
 | 
			
		||||
          << "\nnot match with local block id " << string_tools::pod_to_hex(m_blockchain[current_index]));
 | 
			
		||||
        detach_blockchain(current_index);
 | 
			
		||||
        r = process_new_blockchain_entry(bl, bl_entry, bl_id, current_index, fd);
 | 
			
		||||
        if(!r) return false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    else if(bl_id != m_blockchain[current_index])
 | 
			
		||||
    {
 | 
			
		||||
      //split detected here !!!
 | 
			
		||||
      CHECK_AND_THROW_WALLET_EX(current_index == res.start_height, error::wallet_internal_error,
 | 
			
		||||
        "wrong daemon response: split starts from the first block in response " + string_tools::pod_to_hex(bl_id) + 
 | 
			
		||||
        " (height " + std::to_string(res.start_height) + "), local block id at this height: " +
 | 
			
		||||
        string_tools::pod_to_hex(m_blockchain[current_index]));
 | 
			
		||||
 | 
			
		||||
      detach_blockchain(current_index);
 | 
			
		||||
      process_new_blockchain_entry(bl, bl_entry, bl_id, current_index);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      LOG_PRINT_L2("Block is already in blockchain: " << string_tools::pod_to_hex(bl_id));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ++current_index;
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::refresh(fail_details& fd)
 | 
			
		||||
void wallet2::refresh()
 | 
			
		||||
{
 | 
			
		||||
  size_t blocks_fetched = 0;
 | 
			
		||||
  return refresh(blocks_fetched, fd);
 | 
			
		||||
  refresh(blocks_fetched);
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::refresh(size_t & blocks_fetched, fail_details& fd)
 | 
			
		||||
void wallet2::refresh(size_t & blocks_fetched)
 | 
			
		||||
{
 | 
			
		||||
  bool received_money = false;
 | 
			
		||||
  return refresh(blocks_fetched, received_money, fd);
 | 
			
		||||
  refresh(blocks_fetched, received_money);
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::refresh(size_t & blocks_fetched, bool& received_money, fail_details& fd)
 | 
			
		||||
void wallet2::refresh(size_t & blocks_fetched, bool& received_money)
 | 
			
		||||
{
 | 
			
		||||
  received_money = false;
 | 
			
		||||
  blocks_fetched = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -242,33 +235,49 @@ bool wallet2::refresh(size_t & blocks_fetched, bool& received_money, fail_detail
 | 
			
		|||
 | 
			
		||||
  while(m_run.load(std::memory_order_relaxed))
 | 
			
		||||
  {
 | 
			
		||||
    bool res = pull_blocks(added_blocks, fd);
 | 
			
		||||
    if(!res)
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
      pull_blocks(added_blocks);
 | 
			
		||||
      blocks_fetched += added_blocks;
 | 
			
		||||
      if(!added_blocks)
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    catch (const std::exception&)
 | 
			
		||||
    {
 | 
			
		||||
      blocks_fetched += added_blocks;
 | 
			
		||||
      if(try_count < 3)
 | 
			
		||||
      {
 | 
			
		||||
        LOG_PRINT_L1("Another try pull_blocks (try_count=" << try_count << ")...");
 | 
			
		||||
        ++try_count;
 | 
			
		||||
        continue;
 | 
			
		||||
      }else
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        LOG_PRINT_L1("pull_blocks failed, try_count=" << try_count);
 | 
			
		||||
        return false;
 | 
			
		||||
        LOG_ERROR("pull_blocks failed, try_count=" << try_count);
 | 
			
		||||
        throw;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    blocks_fetched+=added_blocks;
 | 
			
		||||
 | 
			
		||||
    if(!added_blocks)
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
  if(last_tx_hash_id != (m_transfers.size() ? get_transaction_hash(m_transfers.back().m_tx) : null_hash))
 | 
			
		||||
    received_money = true;
 | 
			
		||||
 | 
			
		||||
  LOG_PRINT_L1("Refresh done, blocks received: " << blocks_fetched << ", balance: " << print_money(balance()) << ", unlocked: " << print_money(unlocked_balance()));
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::detach_blockchain(uint64_t height)
 | 
			
		||||
bool wallet2::refresh(size_t & blocks_fetched, bool& received_money, bool& ok)
 | 
			
		||||
{
 | 
			
		||||
  try
 | 
			
		||||
  {
 | 
			
		||||
    refresh(blocks_fetched, received_money);
 | 
			
		||||
    ok = true;
 | 
			
		||||
  }
 | 
			
		||||
  catch (...)
 | 
			
		||||
  {
 | 
			
		||||
    ok = false;
 | 
			
		||||
  }
 | 
			
		||||
  return ok;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
void wallet2::detach_blockchain(uint64_t height)
 | 
			
		||||
{
 | 
			
		||||
  LOG_PRINT_L0("Detaching blockchain on height " << height);
 | 
			
		||||
  size_t transfers_detached = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -279,7 +288,7 @@ bool wallet2::detach_blockchain(uint64_t height)
 | 
			
		|||
  for(size_t i = i_start; i!= m_transfers.size();i++)
 | 
			
		||||
  {
 | 
			
		||||
    auto it_ki = m_key_images.find(m_transfers[i].m_key_image);
 | 
			
		||||
    CHECK_AND_ASSERT_MES(it_ki != m_key_images.end(), false, "key image not found");
 | 
			
		||||
    CHECK_AND_THROW_WALLET_EX(it_ki == m_key_images.end(), error::wallet_internal_error, "key image not found");
 | 
			
		||||
    m_key_images.erase(it_ki);
 | 
			
		||||
    ++transfers_detached;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -290,8 +299,6 @@ bool wallet2::detach_blockchain(uint64_t height)
 | 
			
		|||
  m_local_bc_height -= blocks_detached;
 | 
			
		||||
 | 
			
		||||
  LOG_PRINT_L0("Detached blockchain on height " << height << ", transfers detached " << transfers_detached << ", blocks detached " << blocks_detached);
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::deinit()
 | 
			
		||||
| 
						 | 
				
			
			@ -343,13 +350,14 @@ namespace
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::load_keys(const std::string& keys_file_name, const std::string& password)
 | 
			
		||||
void wallet2::load_keys(const std::string& keys_file_name, const std::string& password)
 | 
			
		||||
{
 | 
			
		||||
  wallet2::keys_file_data keys_file_data;
 | 
			
		||||
  std::string buf;
 | 
			
		||||
  bool r = epee::file_io_utils::load_file_to_string(keys_file_name, buf);
 | 
			
		||||
  r &= ::serialization::parse_binary(buf, keys_file_data);
 | 
			
		||||
  CHECK_AND_ASSERT_MES(r, false, "failed to load wallet keys file: " << keys_file_name);
 | 
			
		||||
  CHECK_AND_THROW_WALLET_EX(!r, error::file_read_error, keys_file_name);
 | 
			
		||||
  r = ::serialization::parse_binary(buf, keys_file_data);
 | 
			
		||||
  CHECK_AND_THROW_WALLET_EX(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"');
 | 
			
		||||
 | 
			
		||||
  crypto::chacha8_key key;
 | 
			
		||||
  crypto::generate_chacha8_key(password, key);
 | 
			
		||||
| 
						 | 
				
			
			@ -361,34 +369,28 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa
 | 
			
		|||
  r = epee::serialization::load_t_from_binary(m_account, account_data);
 | 
			
		||||
  r = r && verify_keys(keys.m_view_secret_key,  keys.m_account_address.m_view_public_key);
 | 
			
		||||
  r = r && verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key);
 | 
			
		||||
  if (!r)
 | 
			
		||||
  {
 | 
			
		||||
    LOG_ERROR("invalid password");
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
  CHECK_AND_THROW_WALLET_EX(!r, error::invalid_password);
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::generate(const std::string& wallet_, const std::string& password)
 | 
			
		||||
void wallet2::generate(const std::string& wallet_, const std::string& password)
 | 
			
		||||
{
 | 
			
		||||
  clear();
 | 
			
		||||
  prepare_file_names(wallet_);
 | 
			
		||||
  boost::system::error_code e;
 | 
			
		||||
  if(boost::filesystem::exists(m_wallet_file, e) || boost::filesystem::exists(m_keys_file, e))
 | 
			
		||||
  {
 | 
			
		||||
    LOG_PRINT_RED_L0("failed to generate wallet, file already exist or wrong path: " << wallet_);
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  boost::system::error_code ignored_ec;
 | 
			
		||||
  CHECK_AND_THROW_WALLET_EX(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, m_wallet_file);
 | 
			
		||||
  CHECK_AND_THROW_WALLET_EX(boost::filesystem::exists(m_keys_file,   ignored_ec), error::file_exists, m_keys_file);
 | 
			
		||||
 | 
			
		||||
  m_account.generate();
 | 
			
		||||
  m_account_public_address = m_account.get_keys().m_account_address;
 | 
			
		||||
 | 
			
		||||
  bool r = store_keys(m_keys_file, password);
 | 
			
		||||
  CHECK_AND_ASSERT_MES(r, false, "Failed to store wallet key files!");
 | 
			
		||||
  CHECK_AND_THROW_WALLET_EX(!r, error::file_save_error, m_keys_file);
 | 
			
		||||
 | 
			
		||||
  r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str());
 | 
			
		||||
  if(!r) LOG_PRINT_RED_L0("String with address text not saved");
 | 
			
		||||
  return store();
 | 
			
		||||
 | 
			
		||||
  store();
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::prepare_file_names(const std::string& file_path)
 | 
			
		||||
| 
						 | 
				
			
			@ -418,51 +420,46 @@ bool wallet2::check_connection()
 | 
			
		|||
  return m_http_client.connect(u.host, std::to_string(u.port), WALLET_RCP_CONNECTION_TIMEOUT);
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::load(const std::string& wallet_, const std::string& password)
 | 
			
		||||
void wallet2::load(const std::string& wallet_, const std::string& password)
 | 
			
		||||
{
 | 
			
		||||
  clear();
 | 
			
		||||
  prepare_file_names(wallet_);
 | 
			
		||||
 | 
			
		||||
  boost::system::error_code e;
 | 
			
		||||
  if(!boost::filesystem::exists(m_keys_file, e) || e)
 | 
			
		||||
  {
 | 
			
		||||
    LOG_PRINT_L0("file not found: " << m_keys_file);
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool r = load_keys(m_keys_file, password);
 | 
			
		||||
  if (!r)
 | 
			
		||||
    return false;
 | 
			
		||||
  bool exists = boost::filesystem::exists(m_keys_file, e);
 | 
			
		||||
  CHECK_AND_THROW_WALLET_EX(e || !exists, error::file_not_found, m_keys_file);
 | 
			
		||||
 | 
			
		||||
  load_keys(m_keys_file, password);
 | 
			
		||||
  LOG_PRINT_L0("Loaded wallet keys file, with public address: " << m_account.get_public_address_str());
 | 
			
		||||
 | 
			
		||||
  //keys loaded ok!
 | 
			
		||||
  //try to load wallet file. but even if we failed, it is not big problem
 | 
			
		||||
  if(!boost::filesystem::exists(m_wallet_file, e) || e)
 | 
			
		||||
  {
 | 
			
		||||
    LOG_PRINT_L0("file not found: " << m_wallet_file << ", starting with empty blockchain");
 | 
			
		||||
    m_account_public_address = m_account.get_keys().m_account_address;
 | 
			
		||||
    return true;
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  r = tools::unserialize_obj_from_file(*this, m_wallet_file);
 | 
			
		||||
  CHECK_AND_ASSERT_MES(r, false, "failed to load wallet from file " << m_wallet_file);
 | 
			
		||||
  CHECK_AND_ASSERT_MES(m_account_public_address.m_spend_public_key == m_account.get_keys().m_account_address.m_spend_public_key &&
 | 
			
		||||
                       m_account_public_address.m_view_public_key == m_account.get_keys().m_account_address.m_view_public_key,
 | 
			
		||||
                       false, "addresses of wallet keys file and wallet data file are mismatched");
 | 
			
		||||
  if(!m_blockchain.size())
 | 
			
		||||
  bool r = tools::unserialize_obj_from_file(*this, m_wallet_file);
 | 
			
		||||
  CHECK_AND_THROW_WALLET_EX(!r, error::file_read_error, m_wallet_file);
 | 
			
		||||
  CHECK_AND_THROW_WALLET_EX(
 | 
			
		||||
    m_account_public_address.m_spend_public_key != m_account.get_keys().m_account_address.m_spend_public_key ||
 | 
			
		||||
    m_account_public_address.m_view_public_key  != m_account.get_keys().m_account_address.m_view_public_key,
 | 
			
		||||
    error::wallet_files_doesnt_correspond, m_keys_file, m_wallet_file);
 | 
			
		||||
 | 
			
		||||
  if(m_blockchain.empty())
 | 
			
		||||
  {
 | 
			
		||||
    cryptonote::block b;
 | 
			
		||||
    cryptonote::generate_genesis_block(b);
 | 
			
		||||
    m_blockchain.push_back(get_block_hash(b));
 | 
			
		||||
  }
 | 
			
		||||
  m_local_bc_height = m_blockchain.size();
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::store()
 | 
			
		||||
void wallet2::store()
 | 
			
		||||
{
 | 
			
		||||
  bool r = tools::serialize_obj_to_file(*this, m_wallet_file);
 | 
			
		||||
  CHECK_AND_ASSERT_MES(r, false, "failed to save wallet to file " << m_wallet_file);
 | 
			
		||||
  return r;
 | 
			
		||||
  CHECK_AND_THROW_WALLET_EX(!r, error::file_save_error, m_wallet_file);
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
uint64_t wallet2::unlocked_balance()
 | 
			
		||||
| 
						 | 
				
			
			@ -482,13 +479,16 @@ uint64_t wallet2::balance()
 | 
			
		|||
    if(!td.m_spent)
 | 
			
		||||
      amount += td.amount();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  BOOST_FOREACH(auto& utx, m_unconfirmed_txs)
 | 
			
		||||
    amount+= utx.second.m_change;
 | 
			
		||||
 | 
			
		||||
  return amount;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::get_transfers(wallet2::transfer_container& incoming_transfers)
 | 
			
		||||
void wallet2::get_transfers(wallet2::transfer_container& incoming_transfers) const
 | 
			
		||||
{
 | 
			
		||||
  incoming_transfers = m_transfers;
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::is_transfer_unlocked(const transfer_details& td) const
 | 
			
		||||
| 
						 | 
				
			
			@ -581,22 +581,25 @@ uint64_t wallet2::select_transfers(uint64_t needed_money, bool add_dust, uint64_
 | 
			
		|||
  return found_money;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
 | 
			
		||||
  uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx)
 | 
			
		||||
void wallet2::add_unconfirmed_tx(const cryptonote::transaction& tx, uint64_t change_amount)
 | 
			
		||||
{
 | 
			
		||||
  return transfer(dsts, fake_outputs_count, unlock_time, fee, detail::digit_split_strategy, tx_dust_policy(fee), tx);
 | 
			
		||||
  unconfirmed_transfer_details& utd = m_unconfirmed_txs[cryptonote::get_transaction_hash(tx)];
 | 
			
		||||
  utd.m_change = change_amount;
 | 
			
		||||
  utd.m_sent_time = time(NULL);
 | 
			
		||||
  utd.m_tx = tx;
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx, fail_details& tfd)
 | 
			
		||||
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
 | 
			
		||||
                       uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx)
 | 
			
		||||
{
 | 
			
		||||
  return transfer(dsts, fake_outputs_count, unlock_time, fee, detail::digit_split_strategy, tx_dust_policy(fee), tx, tfd);
 | 
			
		||||
  transfer(dsts, fake_outputs_count, unlock_time, fee, detail::digit_split_strategy, tx_dust_policy(fee), tx);
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
bool wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
 | 
			
		||||
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
 | 
			
		||||
                       uint64_t unlock_time, uint64_t fee)
 | 
			
		||||
{
 | 
			
		||||
  cryptonote::transaction tx;
 | 
			
		||||
  return transfer(dsts, fake_outputs_count, unlock_time, fee, tx);
 | 
			
		||||
  transfer(dsts, fake_outputs_count, unlock_time, fee, tx);
 | 
			
		||||
}
 | 
			
		||||
//----------------------------------------------------------------------------------------------------
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,7 @@
 | 
			
		|||
#include <boost/serialization/list.hpp>
 | 
			
		||||
#include <boost/serialization/vector.hpp>
 | 
			
		||||
#include <atomic>
 | 
			
		||||
 | 
			
		||||
#include "include_base_utils.h"
 | 
			
		||||
#include "cryptonote_core/account.h"
 | 
			
		||||
#include "cryptonote_core/account_boost_serialization.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -20,38 +21,40 @@
 | 
			
		|||
#include "crypto/chacha8.h"
 | 
			
		||||
#include "crypto/hash.h"
 | 
			
		||||
 | 
			
		||||
#include "wallet_errors.h"
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_TX_SPENDABLE_AGE                               10
 | 
			
		||||
#define WALLET_RCP_CONNECTION_TIMEOUT                          200000
 | 
			
		||||
 | 
			
		||||
namespace tools
 | 
			
		||||
{
 | 
			
		||||
  inline std::string interpret_rpc_response(bool ok, const std::string& status)
 | 
			
		||||
  class i_wallet2_callback
 | 
			
		||||
  {
 | 
			
		||||
    std::string err;
 | 
			
		||||
    if (ok)
 | 
			
		||||
    {
 | 
			
		||||
      if (status == CORE_RPC_STATUS_BUSY)
 | 
			
		||||
      {
 | 
			
		||||
        err = "daemon is busy. Please try later";
 | 
			
		||||
      }
 | 
			
		||||
      else if (status != CORE_RPC_STATUS_OK)
 | 
			
		||||
      {
 | 
			
		||||
        err = status;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      err = "possible lost connection to daemon";
 | 
			
		||||
    }
 | 
			
		||||
    return err;
 | 
			
		||||
  }
 | 
			
		||||
  public:
 | 
			
		||||
    virtual void on_new_block(uint64_t height, const cryptonote::block& block) {}
 | 
			
		||||
    virtual void on_money_received(uint64_t height, const cryptonote::transaction& tx, size_t out_index) {}
 | 
			
		||||
    virtual void on_money_spent(uint64_t height, const cryptonote::transaction& in_tx, size_t out_index, const cryptonote::transaction& spend_tx) {}
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  struct tx_dust_policy
 | 
			
		||||
  {
 | 
			
		||||
    uint64_t dust_threshold;
 | 
			
		||||
    bool add_to_fee;
 | 
			
		||||
    cryptonote::account_public_address addr_for_dust;
 | 
			
		||||
 | 
			
		||||
    tx_dust_policy(uint64_t a_dust_threshold = 0, bool an_add_to_fee = true, cryptonote::account_public_address an_addr_for_dust = cryptonote::account_public_address())
 | 
			
		||||
      : dust_threshold(a_dust_threshold)
 | 
			
		||||
      , add_to_fee(an_add_to_fee)
 | 
			
		||||
      , addr_for_dust(an_addr_for_dust)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  class wallet2
 | 
			
		||||
  {
 | 
			
		||||
    wallet2(const wallet2&) : m_run(true) {};
 | 
			
		||||
    wallet2(const wallet2&) : m_run(true), m_callback(0) {};
 | 
			
		||||
  public:
 | 
			
		||||
    wallet2() : m_run(true) {};
 | 
			
		||||
    wallet2() : m_run(true), m_callback(0) {};
 | 
			
		||||
    struct transfer_details
 | 
			
		||||
    {
 | 
			
		||||
      uint64_t m_block_height;
 | 
			
		||||
| 
						 | 
				
			
			@ -63,22 +66,16 @@ namespace tools
 | 
			
		|||
 | 
			
		||||
      uint64_t amount() const { return m_tx.vout[m_internal_output_index].amount; }
 | 
			
		||||
    };
 | 
			
		||||
    typedef std::vector<transfer_details> transfer_container;
 | 
			
		||||
 | 
			
		||||
    struct tx_dust_policy
 | 
			
		||||
    struct unconfirmed_transfer_details
 | 
			
		||||
    {
 | 
			
		||||
      uint64_t dust_threshold;
 | 
			
		||||
      bool add_to_fee;
 | 
			
		||||
      cryptonote::account_public_address addr_for_dust;
 | 
			
		||||
 | 
			
		||||
      tx_dust_policy(uint64_t a_dust_threshold = 0, bool an_add_to_fee = true, cryptonote::account_public_address an_addr_for_dust = cryptonote::account_public_address())
 | 
			
		||||
        : dust_threshold(a_dust_threshold)
 | 
			
		||||
        , add_to_fee(an_add_to_fee)
 | 
			
		||||
        , addr_for_dust(an_addr_for_dust)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
      cryptonote::transaction m_tx;
 | 
			
		||||
      uint64_t m_change;
 | 
			
		||||
      time_t m_sent_time; 
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    typedef std::vector<transfer_details> transfer_container;
 | 
			
		||||
 | 
			
		||||
    struct keys_file_data
 | 
			
		||||
    {
 | 
			
		||||
      crypto::chacha8_iv iv;
 | 
			
		||||
| 
						 | 
				
			
			@ -90,77 +87,34 @@ namespace tools
 | 
			
		|||
      END_SERIALIZE()
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct fail_details
 | 
			
		||||
    {
 | 
			
		||||
      enum fail_reason
 | 
			
		||||
      {
 | 
			
		||||
        error_ok = 0,
 | 
			
		||||
        error_not_connected,
 | 
			
		||||
        error_daemon_is_busy,
 | 
			
		||||
        error_rejected_by_daemon,
 | 
			
		||||
        error_too_big_transaction,
 | 
			
		||||
        error_not_enough_money,
 | 
			
		||||
        error_too_big_mixin,
 | 
			
		||||
        error_to_parse_block,
 | 
			
		||||
        error_to_parse_tx,
 | 
			
		||||
        error_to_parse_tx_extra,
 | 
			
		||||
        error_invalid_tx,
 | 
			
		||||
        error_internal_error
 | 
			
		||||
      };
 | 
			
		||||
      fail_reason reason;
 | 
			
		||||
      uint64_t tx_blob_size;
 | 
			
		||||
      uint64_t max_expected_tx_blob_size;
 | 
			
		||||
 | 
			
		||||
      std::string what() const
 | 
			
		||||
      {
 | 
			
		||||
        switch (reason)
 | 
			
		||||
        {
 | 
			
		||||
        case error_ok:                  return "OK";
 | 
			
		||||
        case error_not_connected:       return "not connected";
 | 
			
		||||
        case error_daemon_is_busy:      return "daemon is busy. Please try later";
 | 
			
		||||
        case error_rejected_by_daemon:  return "rejected by daemon";
 | 
			
		||||
        case error_too_big_transaction: return "transaction size is too big";
 | 
			
		||||
        case error_not_enough_money:    return "not enough money";
 | 
			
		||||
        case error_too_big_mixin:       return "not enough outputs for specified mixin_count";
 | 
			
		||||
        case error_to_parse_block:      return "failed to parse/validate block";
 | 
			
		||||
        case error_to_parse_tx:         return "failed to parse/validate tx";
 | 
			
		||||
        case error_to_parse_tx_extra:   return "failed to parse/validate tx extra";
 | 
			
		||||
        case error_invalid_tx:          return "wrong tx";
 | 
			
		||||
        case error_internal_error:      return "internal error";
 | 
			
		||||
        default:                        return "unknown error";
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    bool generate(const std::string& wallet, const std::string& password);
 | 
			
		||||
    bool load(const std::string& wallet, const std::string& password);
 | 
			
		||||
    bool store();
 | 
			
		||||
    void generate(const std::string& wallet, const std::string& password);
 | 
			
		||||
    void load(const std::string& wallet, const std::string& password);
 | 
			
		||||
    void store();
 | 
			
		||||
    cryptonote::account_base& get_account(){return m_account;}
 | 
			
		||||
 | 
			
		||||
    bool init(const std::string& daemon_address = "http://localhost:8080", uint64_t upper_transaction_size_limit = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE*2 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE);
 | 
			
		||||
 | 
			
		||||
    bool refresh(fail_details& fd);
 | 
			
		||||
    bool refresh(size_t & blocks_fetched, fail_details& fd);
 | 
			
		||||
    bool refresh(size_t & blocks_fetched, bool& received_money, fail_details& fd);
 | 
			
		||||
    void init(const std::string& daemon_address = "http://localhost:8080", uint64_t upper_transaction_size_limit = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE*2 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE);
 | 
			
		||||
    bool deinit();
 | 
			
		||||
 | 
			
		||||
    void stop() { m_run.store(false, std::memory_order_relaxed); }
 | 
			
		||||
 | 
			
		||||
    i_wallet2_callback* callback() const { return m_callback; }
 | 
			
		||||
    void callback(i_wallet2_callback* callback) { m_callback = callback; }
 | 
			
		||||
 | 
			
		||||
    void refresh();
 | 
			
		||||
    void refresh(size_t & blocks_fetched);
 | 
			
		||||
    void refresh(size_t & blocks_fetched, bool& received_money);
 | 
			
		||||
    bool refresh(size_t & blocks_fetched, bool& received_money, bool& ok);
 | 
			
		||||
 | 
			
		||||
    uint64_t balance();
 | 
			
		||||
    uint64_t unlocked_balance();
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    bool enum_incoming_transfers(const T& handler) const;
 | 
			
		||||
    void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy);
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    bool transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy);
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    bool transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx, fail_details& tfd);
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    bool transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx);
 | 
			
		||||
    bool transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee);
 | 
			
		||||
    bool transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx);
 | 
			
		||||
    bool transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx, fail_details& tfd);
 | 
			
		||||
    void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx);
 | 
			
		||||
    void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee);
 | 
			
		||||
    void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx);
 | 
			
		||||
    bool check_connection();
 | 
			
		||||
    bool get_transfers(wallet2::transfer_container& incoming_transfers);
 | 
			
		||||
    void get_transfers(wallet2::transfer_container& incoming_transfers) const;
 | 
			
		||||
    uint64_t get_blockchain_current_height() const { return m_local_bc_height; }
 | 
			
		||||
    template <class t_archive>
 | 
			
		||||
    inline void serialize(t_archive &a, const unsigned int ver)
 | 
			
		||||
| 
						 | 
				
			
			@ -171,21 +125,26 @@ namespace tools
 | 
			
		|||
      a & m_transfers;
 | 
			
		||||
      a & m_account_public_address;
 | 
			
		||||
      a & m_key_images;
 | 
			
		||||
      if(ver < 6)
 | 
			
		||||
        return;
 | 
			
		||||
      a & m_unconfirmed_txs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    bool store_keys(const std::string& keys_file_name, const std::string& password);
 | 
			
		||||
    bool load_keys(const std::string& keys_file_name, const std::string& password);
 | 
			
		||||
    bool process_new_transaction(cryptonote::transaction& tx, uint64_t height, fail_details& fd);
 | 
			
		||||
    bool process_new_blockchain_entry(cryptonote::block& b, cryptonote::block_complete_entry& bche, crypto::hash& bl_id, uint64_t height, fail_details& fd);
 | 
			
		||||
    bool detach_blockchain(uint64_t height);
 | 
			
		||||
    bool get_short_chain_history(std::list<crypto::hash>& ids);
 | 
			
		||||
    void load_keys(const std::string& keys_file_name, const std::string& password);
 | 
			
		||||
    void process_new_transaction(const cryptonote::transaction& tx, uint64_t height);
 | 
			
		||||
    void process_new_blockchain_entry(const cryptonote::block& b, cryptonote::block_complete_entry& bche, crypto::hash& bl_id, uint64_t height);
 | 
			
		||||
    void detach_blockchain(uint64_t height);
 | 
			
		||||
    void get_short_chain_history(std::list<crypto::hash>& ids);
 | 
			
		||||
    bool is_tx_spendtime_unlocked(uint64_t unlock_time) const;
 | 
			
		||||
    bool is_transfer_unlocked(const transfer_details& td) const;
 | 
			
		||||
    bool clear();
 | 
			
		||||
    bool pull_blocks(size_t& blocks_added, fail_details& fd);
 | 
			
		||||
    void pull_blocks(size_t& blocks_added);
 | 
			
		||||
    uint64_t select_transfers(uint64_t needed_money, bool add_dust, uint64_t dust, std::list<transfer_container::iterator>& selected_transfers);
 | 
			
		||||
    bool prepare_file_names(const std::string& file_path);
 | 
			
		||||
    void process_unconfirmed(const cryptonote::transaction& tx);
 | 
			
		||||
    void add_unconfirmed_tx(const cryptonote::transaction& tx, uint64_t change_amount);
 | 
			
		||||
 | 
			
		||||
    cryptonote::account_base m_account;
 | 
			
		||||
    std::string m_daemon_address;
 | 
			
		||||
| 
						 | 
				
			
			@ -194,6 +153,7 @@ namespace tools
 | 
			
		|||
    epee::net_utils::http::http_simple_client m_http_client;
 | 
			
		||||
    std::vector<crypto::hash> m_blockchain;
 | 
			
		||||
    std::atomic<uint64_t> m_local_bc_height; //temporary workaround 
 | 
			
		||||
    std::unordered_map<crypto::hash, unconfirmed_transfer_details> m_unconfirmed_txs;
 | 
			
		||||
 | 
			
		||||
    transfer_container m_transfers;
 | 
			
		||||
    std::unordered_map<crypto::key_image, size_t> m_key_images;
 | 
			
		||||
| 
						 | 
				
			
			@ -201,9 +161,11 @@ namespace tools
 | 
			
		|||
    uint64_t m_upper_transaction_size_limit; //TODO: auto-calc this value or request from daemon, now use some fixed value
 | 
			
		||||
 | 
			
		||||
    std::atomic<bool> m_run;
 | 
			
		||||
 | 
			
		||||
    i_wallet2_callback* m_callback;
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
BOOST_CLASS_VERSION(tools::wallet2, 5)
 | 
			
		||||
BOOST_CLASS_VERSION(tools::wallet2, 6)
 | 
			
		||||
 | 
			
		||||
namespace boost
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -219,6 +181,16 @@ namespace boost
 | 
			
		|||
      a & x.m_spent;
 | 
			
		||||
      a & x.m_key_image;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <class Archive>
 | 
			
		||||
    inline void serialize(Archive &a, tools::wallet2::unconfirmed_transfer_details &x, const boost::serialization::version_type ver)
 | 
			
		||||
    {
 | 
			
		||||
      a & x.m_change;
 | 
			
		||||
      a & x.m_sent_time;
 | 
			
		||||
      a & x.m_tx;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -288,62 +260,31 @@ namespace tools
 | 
			
		|||
  }
 | 
			
		||||
  //----------------------------------------------------------------------------------------------------
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  bool wallet2::enum_incoming_transfers(const T& handler) const
 | 
			
		||||
  {
 | 
			
		||||
    if(!m_transfers.empty())
 | 
			
		||||
    {
 | 
			
		||||
      BOOST_FOREACH(const transfer_details& td, m_transfers)
 | 
			
		||||
      {
 | 
			
		||||
        handler(td.m_tx, td.m_global_output_index, td.amount(), td.m_spent);
 | 
			
		||||
      }
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  //----------------------------------------------------------------------------------------------------
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  bool wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
 | 
			
		||||
  void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
 | 
			
		||||
    uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy)
 | 
			
		||||
  {
 | 
			
		||||
    cryptonote::transaction tx;
 | 
			
		||||
    return transfer(dsts, fake_outputs_count, unlock_time, fee, destination_split_strategy, dust_policy, tx);
 | 
			
		||||
    transfer(dsts, fake_outputs_count, unlock_time, fee, destination_split_strategy, dust_policy, tx);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  bool wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
 | 
			
		||||
  void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
 | 
			
		||||
    uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx)
 | 
			
		||||
  {
 | 
			
		||||
    fail_details stub = AUTO_VAL_INIT(stub);
 | 
			
		||||
    return transfer(dsts, fake_outputs_count, unlock_time, fee, destination_split_strategy, dust_policy, tx, stub);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  bool wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
 | 
			
		||||
    uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx, fail_details& tfd)
 | 
			
		||||
  {
 | 
			
		||||
    using namespace cryptonote;
 | 
			
		||||
 | 
			
		||||
    uint64_t needed_money = fee;
 | 
			
		||||
    BOOST_FOREACH(auto& dt, dsts)
 | 
			
		||||
    {
 | 
			
		||||
      CHECK_AND_ASSERT_MES(dt.amount > 0, false, "Wrong destination amount value: " << dt.amount);
 | 
			
		||||
      CHECK_AND_THROW_WALLET_EX(0 == dt.amount, error::zero_destination);
 | 
			
		||||
      needed_money += dt.amount;
 | 
			
		||||
      CHECK_AND_THROW_WALLET_EX(needed_money < dt.amount, error::tx_sum_overflow, dsts, fee);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::list<transfer_container::iterator> selected_transfers;
 | 
			
		||||
    uint64_t found_money = select_transfers(needed_money, 0 == fake_outputs_count, dust_policy.dust_threshold, selected_transfers);
 | 
			
		||||
    CHECK_AND_THROW_WALLET_EX(found_money < needed_money, error::not_enough_money, found_money, needed_money - fee, fee);
 | 
			
		||||
 | 
			
		||||
    if(found_money < needed_money)
 | 
			
		||||
    {
 | 
			
		||||
      LOG_ERROR("not enough money, available only " << print_money(found_money) << ", transaction amount " <<
 | 
			
		||||
        print_money(needed_money) << " = " << print_money(needed_money - fee) << " + " << print_money(fee) << " (fee)");
 | 
			
		||||
      tfd.reason = fail_details::error_not_enough_money;
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    //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;
 | 
			
		||||
    typedef cryptonote::tx_source_entry::output_entry tx_output_entry;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -354,41 +295,30 @@ namespace tools
 | 
			
		|||
      req.outs_count = fake_outputs_count + 1;// add one to make possible (if need) to skip real output key
 | 
			
		||||
      BOOST_FOREACH(transfer_container::iterator it, selected_transfers)
 | 
			
		||||
      {
 | 
			
		||||
        CHECK_AND_ASSERT_MES(it->m_tx.vout.size() > it->m_internal_output_index, false, "internal error: m_internal_output_index = "
 | 
			
		||||
          << it->m_internal_output_index << " more than " << it->m_tx.vout.size());
 | 
			
		||||
        CHECK_AND_THROW_WALLET_EX(it->m_tx.vout.size() <= it->m_internal_output_index, error::wallet_internal_error,
 | 
			
		||||
          "m_internal_output_index = " + std::to_string(it->m_internal_output_index) +
 | 
			
		||||
          " is greater or equal to outputs count = " + std::to_string(it->m_tx.vout.size()));
 | 
			
		||||
        req.amounts.push_back(it->amount());
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      bool r = net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/getrandom_outs.bin", req, daemon_resp, m_http_client, 200000);
 | 
			
		||||
      if (!r)                                              tfd.reason = fail_details::error_not_connected;
 | 
			
		||||
      else if (CORE_RPC_STATUS_BUSY == daemon_resp.status) tfd.reason = fail_details::error_daemon_is_busy;
 | 
			
		||||
      else if (CORE_RPC_STATUS_OK != daemon_resp.status)   tfd.reason = fail_details::error_internal_error;
 | 
			
		||||
      else                                                 tfd.reason = fail_details::error_ok;
 | 
			
		||||
      if (fail_details::error_ok != tfd.reason)
 | 
			
		||||
      {
 | 
			
		||||
        LOG_PRINT_L0("failed to invoke getrandom_outs.bin: " << interpret_rpc_response(r, daemon_resp.status));
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
      CHECK_AND_THROW_WALLET_EX(!r, error::no_connection_to_daemon, "getrandom_outs.bin");
 | 
			
		||||
      CHECK_AND_THROW_WALLET_EX(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getrandom_outs.bin");
 | 
			
		||||
      CHECK_AND_THROW_WALLET_EX(daemon_resp.status != CORE_RPC_STATUS_OK, error::get_random_outs_error, daemon_resp.status);
 | 
			
		||||
      CHECK_AND_THROW_WALLET_EX(daemon_resp.outs.size() != selected_transfers.size(), error::wallet_internal_error,
 | 
			
		||||
        "daemon returned wrong response for getrandom_outs.bin, wrong amounts count = " +
 | 
			
		||||
        std::to_string(daemon_resp.outs.size()) + ", expected " +  std::to_string(selected_transfers.size()));
 | 
			
		||||
 | 
			
		||||
      tfd.reason = fail_details::error_internal_error;
 | 
			
		||||
      CHECK_AND_ASSERT_MES(daemon_resp.outs.size() == selected_transfers.size(), false,
 | 
			
		||||
        "internal error: daemon returned wrong response for getrandom_outs.bin, wrong amounts count = "
 | 
			
		||||
        << daemon_resp.outs.size() << ", expected " << selected_transfers.size());
 | 
			
		||||
 | 
			
		||||
      tfd.reason = fail_details::error_ok;
 | 
			
		||||
      std::vector<COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount> scanty_outs;
 | 
			
		||||
      BOOST_FOREACH(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_outs, daemon_resp.outs)
 | 
			
		||||
      {
 | 
			
		||||
        if (amount_outs.outs.size() != fake_outputs_count)
 | 
			
		||||
        if (amount_outs.outs.size() < fake_outputs_count)
 | 
			
		||||
        {
 | 
			
		||||
          tfd.reason = fail_details::error_too_big_mixin;
 | 
			
		||||
          LOG_PRINT_L0("not enough outputs to mix output " << print_money(amount_outs.amount) << ", requested " <<
 | 
			
		||||
            fake_outputs_count << ", found " << amount_outs.outs.size());
 | 
			
		||||
          scanty_outs.push_back(amount_outs);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (fail_details::error_ok != tfd.reason)
 | 
			
		||||
        return false;
 | 
			
		||||
      CHECK_AND_THROW_WALLET_EX(!scanty_outs.empty(), error::not_enough_outs_to_mix, scanty_outs, fake_outputs_count);
 | 
			
		||||
    }
 | 
			
		||||
    tfd.reason = fail_details::error_ok;
 | 
			
		||||
 
 | 
			
		||||
    //prepare inputs
 | 
			
		||||
    size_t i = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -443,60 +373,36 @@ namespace tools
 | 
			
		|||
    uint64_t dust = 0;
 | 
			
		||||
    std::vector<cryptonote::tx_destination_entry> splitted_dsts;
 | 
			
		||||
    destination_split_strategy(dsts, change_dts, dust_policy.dust_threshold, splitted_dsts, dust);
 | 
			
		||||
    CHECK_AND_ASSERT_MES(dust <= dust_policy.dust_threshold, false, "internal error: invalid dust value");
 | 
			
		||||
    CHECK_AND_THROW_WALLET_EX(dust_policy.dust_threshold < dust, error::wallet_internal_error, "invalid dust value: dust = " +
 | 
			
		||||
      std::to_string(dust) + ", dust_threshold = " + std::to_string(dust_policy.dust_threshold));
 | 
			
		||||
    if (0 != dust && !dust_policy.add_to_fee)
 | 
			
		||||
    {
 | 
			
		||||
      splitted_dsts.push_back(cryptonote::tx_destination_entry(dust, dust_policy.addr_for_dust));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tfd.reason = fail_details::error_internal_error;
 | 
			
		||||
    bool r = cryptonote::construct_tx(m_account.get_keys(), sources, splitted_dsts, tx, unlock_time);
 | 
			
		||||
    CHECK_AND_ASSERT_MES(r, false, "Transaction construction failed");
 | 
			
		||||
 | 
			
		||||
    //check transaction size
 | 
			
		||||
    if(get_object_blobsize(tx) >= m_upper_transaction_size_limit)
 | 
			
		||||
    {
 | 
			
		||||
      LOG_PRINT_L0("Transaction size is too big: " << get_object_blobsize(tx)  << ", expected size < " << m_upper_transaction_size_limit);
 | 
			
		||||
      tfd.reason = fail_details::error_too_big_transaction;
 | 
			
		||||
      tfd.tx_blob_size = get_object_blobsize(tx);
 | 
			
		||||
      tfd.max_expected_tx_blob_size = m_upper_transaction_size_limit;
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    COMMAND_RPC_SEND_RAW_TX::request req;
 | 
			
		||||
    req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(tx));
 | 
			
		||||
    COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp;
 | 
			
		||||
    r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/sendrawtransaction", req, daemon_send_resp, m_http_client, 200000);
 | 
			
		||||
    if (!r)
 | 
			
		||||
    {
 | 
			
		||||
      tfd.reason = fail_details::error_not_connected;
 | 
			
		||||
      LOG_PRINT_L0("failed to send transaction: " << interpret_rpc_response(r, daemon_send_resp.status));
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    else if (CORE_RPC_STATUS_BUSY == daemon_send_resp.status)
 | 
			
		||||
    {
 | 
			
		||||
      tfd.reason = fail_details::error_daemon_is_busy;
 | 
			
		||||
      LOG_PRINT_L0("failed to send transaction: " << interpret_rpc_response(r, daemon_send_resp.status));
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    else if (CORE_RPC_STATUS_OK != daemon_send_resp.status)
 | 
			
		||||
    {
 | 
			
		||||
      tfd.reason = fail_details::error_rejected_by_daemon;
 | 
			
		||||
      LOG_ERROR("daemon failed to accept generated transaction, id: " << get_transaction_hash(tx));
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      tfd.reason = fail_details::error_ok;
 | 
			
		||||
    }
 | 
			
		||||
    CHECK_AND_THROW_WALLET_EX(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time);
 | 
			
		||||
    CHECK_AND_THROW_WALLET_EX(m_upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, m_upper_transaction_size_limit);
 | 
			
		||||
 | 
			
		||||
    std::string key_images;
 | 
			
		||||
    std::for_each(tx.vin.begin(), tx.vin.end(), [&](const txin_v& s_e) -> bool
 | 
			
		||||
    bool all_are_txin_to_key = std::all_of(tx.vin.begin(), tx.vin.end(), [&](const txin_v& s_e) -> bool
 | 
			
		||||
    {
 | 
			
		||||
      CHECKED_GET_SPECIFIC_VARIANT(s_e, const txin_to_key, in, false);
 | 
			
		||||
      key_images += boost::to_string(in.k_image) + " ";
 | 
			
		||||
      return true;
 | 
			
		||||
    });
 | 
			
		||||
    CHECK_AND_THROW_WALLET_EX(!all_are_txin_to_key, error::unexpected_txin_type, tx);
 | 
			
		||||
 | 
			
		||||
    COMMAND_RPC_SEND_RAW_TX::request req;
 | 
			
		||||
    req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(tx));
 | 
			
		||||
    COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp;
 | 
			
		||||
    r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/sendrawtransaction", req, daemon_send_resp, m_http_client, 200000);
 | 
			
		||||
    CHECK_AND_THROW_WALLET_EX(!r, error::no_connection_to_daemon, "sendrawtransaction");
 | 
			
		||||
    CHECK_AND_THROW_WALLET_EX(daemon_send_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "sendrawtransaction");
 | 
			
		||||
    CHECK_AND_THROW_WALLET_EX(daemon_send_resp.status != CORE_RPC_STATUS_OK, error::tx_rejected, tx, daemon_send_resp.status);
 | 
			
		||||
 | 
			
		||||
    add_unconfirmed_tx(tx, change_dts.amount);
 | 
			
		||||
 | 
			
		||||
    LOG_PRINT_L2("transaction " << get_transaction_hash(tx) << " generated ok and sent to daemon, key_images: [" << key_images << "]");
 | 
			
		||||
 | 
			
		||||
    BOOST_FOREACH(transfer_container::iterator it, selected_transfers)
 | 
			
		||||
| 
						 | 
				
			
			@ -507,8 +413,5 @@ namespace tools
 | 
			
		|||
                  << "Balance: " << print_money(balance()) << ENDL
 | 
			
		||||
                  << "Unlocked: " << print_money(unlocked_balance()) << ENDL
 | 
			
		||||
                  << "Please, wait for confirmation for your balance to be unlocked.");
 | 
			
		||||
 | 
			
		||||
    tfd.reason = fail_details::error_ok;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										611
									
								
								src/wallet/wallet_errors.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										611
									
								
								src/wallet/wallet_errors.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,611 @@
 | 
			
		|||
// Copyright (c) 2012-2013 The Cryptonote developers
 | 
			
		||||
// Distributed under the MIT/X11 software license, see the accompanying
 | 
			
		||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "cryptonote_core/cryptonote_format_utils.h"
 | 
			
		||||
#include "rpc/core_rpc_server_commands_defs.h"
 | 
			
		||||
#include "include_base_utils.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace tools
 | 
			
		||||
{
 | 
			
		||||
  namespace error
 | 
			
		||||
  {
 | 
			
		||||
    // std::exception
 | 
			
		||||
    //   std::runtime_error
 | 
			
		||||
    //     wallet_runtime_error *
 | 
			
		||||
    //       wallet_internal_error
 | 
			
		||||
    //         unexpected_txin_type
 | 
			
		||||
    //   std::logic_error
 | 
			
		||||
    //     wallet_logic_error *
 | 
			
		||||
    //       file_exists
 | 
			
		||||
    //       file_not_found
 | 
			
		||||
    //       file_read_error
 | 
			
		||||
    //       file_save_error
 | 
			
		||||
    //       invalid_password
 | 
			
		||||
    //       refresh_error *
 | 
			
		||||
    //         acc_outs_lookup_error
 | 
			
		||||
    //         block_parse_error
 | 
			
		||||
    //         get_blocks_error
 | 
			
		||||
    //         get_out_indexes_error
 | 
			
		||||
    //         tx_extra_parse_error
 | 
			
		||||
    //         tx_parse_error
 | 
			
		||||
    //       transfer_error *
 | 
			
		||||
    //         get_random_outs_general_error
 | 
			
		||||
    //         not_enough_money
 | 
			
		||||
    //         not_enough_outs_to_mix
 | 
			
		||||
    //         tx_not_constructed
 | 
			
		||||
    //         tx_rejected
 | 
			
		||||
    //         tx_sum_overflow
 | 
			
		||||
    //         tx_too_big
 | 
			
		||||
    //         zero_destination
 | 
			
		||||
    //       wallet_rpc_error *
 | 
			
		||||
    //         daemon_busy
 | 
			
		||||
    //         no_connection_to_daemon
 | 
			
		||||
    //       wallet_files_doesnt_correspond
 | 
			
		||||
    //
 | 
			
		||||
    // * - class with protected ctor
 | 
			
		||||
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    template<typename Base>
 | 
			
		||||
    struct wallet_error_base : public Base
 | 
			
		||||
    {
 | 
			
		||||
      const std::string& location() const { return m_loc; }
 | 
			
		||||
 | 
			
		||||
      std::string to_string() const
 | 
			
		||||
      {
 | 
			
		||||
        std::ostringstream ss;
 | 
			
		||||
        ss << m_loc << ':' << typeid(*this).name() << ": " << Base::what();
 | 
			
		||||
        return ss.str();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    protected:
 | 
			
		||||
      wallet_error_base(std::string&& loc, const std::string& message)
 | 
			
		||||
        : Base(message)
 | 
			
		||||
        , m_loc(loc)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
      std::string m_loc;
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    const char* const failed_rpc_request_messages[] = {
 | 
			
		||||
      "failed to get blocks",
 | 
			
		||||
      "failed to get out indices",
 | 
			
		||||
      "failed to get random outs"
 | 
			
		||||
    };
 | 
			
		||||
    enum failed_rpc_request_message_indices
 | 
			
		||||
    {
 | 
			
		||||
      get_blocks_error_message_index,
 | 
			
		||||
      get_out_indices_error_message_index,
 | 
			
		||||
      get_random_outs_error_message_index
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    template<typename Base, int msg_index>
 | 
			
		||||
    struct failed_rpc_request : public Base
 | 
			
		||||
    {
 | 
			
		||||
      explicit failed_rpc_request(std::string&& loc, const std::string& status)
 | 
			
		||||
        : Base(std::move(loc), failed_rpc_request_messages[msg_index])
 | 
			
		||||
        , m_status(status)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const std::string& status() const { return m_status; }
 | 
			
		||||
 | 
			
		||||
      std::string to_string() const
 | 
			
		||||
      {
 | 
			
		||||
        std::ostringstream ss;
 | 
			
		||||
        ss << Base::to_string() << ", status = " << status();
 | 
			
		||||
        return ss.str();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
      std::string m_status;
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    typedef wallet_error_base<std::logic_error> wallet_logic_error;
 | 
			
		||||
    typedef wallet_error_base<std::runtime_error> wallet_runtime_error;
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct wallet_internal_error : public wallet_runtime_error
 | 
			
		||||
    {
 | 
			
		||||
      explicit wallet_internal_error(std::string&& loc, const std::string& message)
 | 
			
		||||
        : wallet_runtime_error(std::move(loc), message)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct unexpected_txin_type : public wallet_internal_error
 | 
			
		||||
    {
 | 
			
		||||
      explicit unexpected_txin_type(std::string&& loc, const cryptonote::transaction& tx)
 | 
			
		||||
        : wallet_internal_error(std::move(loc), "one of tx inputs has unexpected type")
 | 
			
		||||
        , m_tx(tx)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const cryptonote::transaction& tx() const { return m_tx; }
 | 
			
		||||
 | 
			
		||||
      std::string to_string() const
 | 
			
		||||
      {
 | 
			
		||||
        std::ostringstream ss;
 | 
			
		||||
        cryptonote::transaction tx = m_tx;
 | 
			
		||||
        ss << wallet_internal_error::to_string() << ", tx:\n" << cryptonote::obj_to_json_str(tx);
 | 
			
		||||
        return ss.str();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
      cryptonote::transaction m_tx;
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    const char* const file_error_messages[] = {
 | 
			
		||||
      "file already exists",
 | 
			
		||||
      "file not found",
 | 
			
		||||
      "failed to read file",
 | 
			
		||||
      "failed to save file"
 | 
			
		||||
    };
 | 
			
		||||
    enum file_error_message_indices
 | 
			
		||||
    {
 | 
			
		||||
      file_exists_message_index,
 | 
			
		||||
      file_not_found_message_index,
 | 
			
		||||
      file_read_error_message_index,
 | 
			
		||||
      file_save_error_message_index
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    template<int msg_index>
 | 
			
		||||
    struct file_error_base : public wallet_logic_error
 | 
			
		||||
    {
 | 
			
		||||
      explicit file_error_base(std::string&& loc, const std::string& file)
 | 
			
		||||
        : wallet_logic_error(std::move(loc), std::string(file_error_messages[msg_index]) +  " \"" + file + '\"')
 | 
			
		||||
        , m_file(file)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const std::string& file() const { return m_file; }
 | 
			
		||||
 | 
			
		||||
      std::string to_string() const { return wallet_logic_error::to_string(); }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
      std::string m_file;
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    typedef file_error_base<file_exists_message_index> file_exists;
 | 
			
		||||
    typedef file_error_base<file_not_found_message_index>  file_not_found;
 | 
			
		||||
    typedef file_error_base<file_not_found_message_index>  file_not_found;
 | 
			
		||||
    typedef file_error_base<file_read_error_message_index> file_read_error;
 | 
			
		||||
    typedef file_error_base<file_save_error_message_index> file_save_error;
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct invalid_password : public wallet_logic_error
 | 
			
		||||
    {
 | 
			
		||||
      explicit invalid_password(std::string&& loc)
 | 
			
		||||
        : wallet_logic_error(std::move(loc), "invalid password")
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      std::string to_string() const { return wallet_logic_error::to_string(); }
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct refresh_error : public wallet_logic_error
 | 
			
		||||
    {
 | 
			
		||||
    protected:
 | 
			
		||||
      refresh_error(std::string&& loc, const std::string& message)
 | 
			
		||||
        : wallet_logic_error(std::move(loc), message)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct acc_outs_lookup_error : public refresh_error
 | 
			
		||||
    {
 | 
			
		||||
      explicit acc_outs_lookup_error(std::string&& loc, const cryptonote::transaction& tx,
 | 
			
		||||
        const crypto::public_key& tx_pub_key, const cryptonote::account_keys& acc_keys)
 | 
			
		||||
        : refresh_error(std::move(loc), "account outs lookup error")
 | 
			
		||||
        , m_tx(tx)
 | 
			
		||||
        , m_tx_pub_key(tx_pub_key)
 | 
			
		||||
        , m_acc_keys(acc_keys)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const cryptonote::transaction& tx() const { return m_tx; }
 | 
			
		||||
      const crypto::public_key& tx_pub_key() const { return m_tx_pub_key; }
 | 
			
		||||
      const cryptonote::account_keys& acc_keys() const { return m_acc_keys; }
 | 
			
		||||
 | 
			
		||||
      std::string to_string() const
 | 
			
		||||
      {
 | 
			
		||||
        std::ostringstream ss;
 | 
			
		||||
        cryptonote::transaction tx = m_tx;
 | 
			
		||||
        ss << refresh_error::to_string() << ", tx: " << cryptonote::obj_to_json_str(tx);
 | 
			
		||||
        return ss.str();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
      const cryptonote::transaction m_tx;
 | 
			
		||||
      const crypto::public_key m_tx_pub_key;
 | 
			
		||||
      const cryptonote::account_keys m_acc_keys;
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct block_parse_error : public refresh_error
 | 
			
		||||
    {
 | 
			
		||||
      explicit block_parse_error(std::string&& loc, const cryptonote::blobdata& block_data)
 | 
			
		||||
        : refresh_error(std::move(loc), "block parse error")
 | 
			
		||||
        , m_block_blob(block_data)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const cryptonote::blobdata& block_blob() const { return m_block_blob; }
 | 
			
		||||
 | 
			
		||||
      std::string to_string() const { return refresh_error::to_string(); }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
      cryptonote::blobdata m_block_blob;
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    typedef failed_rpc_request<refresh_error, get_blocks_error_message_index> get_blocks_error;
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    typedef failed_rpc_request<refresh_error, get_out_indices_error_message_index> get_out_indices_error;
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct tx_extra_parse_error : public refresh_error
 | 
			
		||||
    {
 | 
			
		||||
      explicit tx_extra_parse_error(std::string&& loc, const cryptonote::transaction& tx)
 | 
			
		||||
        : refresh_error(std::move(loc), "transaction extra parse error")
 | 
			
		||||
        , m_tx(tx)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const cryptonote::transaction& tx() const { return m_tx; }
 | 
			
		||||
 | 
			
		||||
      std::string to_string() const
 | 
			
		||||
      {
 | 
			
		||||
        std::ostringstream ss;
 | 
			
		||||
        cryptonote::transaction tx = m_tx;
 | 
			
		||||
        ss << refresh_error::to_string() << ", tx: " << cryptonote::obj_to_json_str(tx);
 | 
			
		||||
        return ss.str();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
      const cryptonote::transaction m_tx;
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct tx_parse_error : public refresh_error
 | 
			
		||||
    {
 | 
			
		||||
      explicit tx_parse_error(std::string&& loc, const cryptonote::blobdata& tx_blob)
 | 
			
		||||
        : refresh_error(std::move(loc), "transaction parse error")
 | 
			
		||||
        , m_tx_blob(tx_blob)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const cryptonote::blobdata& tx_blob() const { return m_tx_blob; }
 | 
			
		||||
 | 
			
		||||
      std::string to_string() const { return refresh_error::to_string(); }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
      cryptonote::blobdata m_tx_blob;
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct transfer_error : public wallet_logic_error
 | 
			
		||||
    {
 | 
			
		||||
    protected:
 | 
			
		||||
      transfer_error(std::string&& loc, const std::string& message)
 | 
			
		||||
        : wallet_logic_error(std::move(loc), message)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    typedef failed_rpc_request<transfer_error, get_random_outs_error_message_index> get_random_outs_error;
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct not_enough_money : public transfer_error
 | 
			
		||||
    {
 | 
			
		||||
      not_enough_money(std::string&& loc, uint64_t availbable, uint64_t tx_amount, uint64_t fee)
 | 
			
		||||
        : transfer_error(std::move(loc), "not enough money")
 | 
			
		||||
        , m_available(availbable)
 | 
			
		||||
        , m_tx_amount(tx_amount)
 | 
			
		||||
        , m_fee(fee)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      uint64_t available() const { return m_available; }
 | 
			
		||||
      uint64_t tx_amount() const { return m_tx_amount; }
 | 
			
		||||
      uint64_t fee() const { return m_fee; }
 | 
			
		||||
 | 
			
		||||
      std::string to_string() const
 | 
			
		||||
      {
 | 
			
		||||
        std::ostringstream ss;
 | 
			
		||||
        ss << transfer_error::to_string() <<
 | 
			
		||||
          ", available = " << cryptonote::print_money(m_available) <<
 | 
			
		||||
          ", tx_amount = " << cryptonote::print_money(m_tx_amount) <<
 | 
			
		||||
          ", fee = " << cryptonote::print_money(m_fee);
 | 
			
		||||
        return ss.str();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
      uint64_t m_available;
 | 
			
		||||
      uint64_t m_tx_amount;
 | 
			
		||||
      uint64_t m_fee;
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct not_enough_outs_to_mix : public transfer_error
 | 
			
		||||
    {
 | 
			
		||||
      typedef std::vector<cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount> scanty_outs_t;
 | 
			
		||||
 | 
			
		||||
      explicit not_enough_outs_to_mix(std::string&& loc, const scanty_outs_t& scanty_outs, size_t mixin_count)
 | 
			
		||||
        : transfer_error(std::move(loc), "not enough outputs to mix")
 | 
			
		||||
        , m_scanty_outs(scanty_outs)
 | 
			
		||||
        , m_mixin_count(mixin_count)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const scanty_outs_t& scanty_outs() const { return m_scanty_outs; }
 | 
			
		||||
      size_t mixin_count() const { return m_mixin_count; }
 | 
			
		||||
 | 
			
		||||
      std::string to_string() const
 | 
			
		||||
      {
 | 
			
		||||
        std::ostringstream ss;
 | 
			
		||||
        ss << transfer_error::to_string() << ", mixin_count = " << m_mixin_count << ", scanty_outs:";
 | 
			
		||||
        for (const auto& outs_for_amount : m_scanty_outs)
 | 
			
		||||
        {
 | 
			
		||||
          ss << '\n' << cryptonote::print_money(outs_for_amount.amount) << " - " << outs_for_amount.outs.size();
 | 
			
		||||
        }
 | 
			
		||||
        return ss.str();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
      scanty_outs_t m_scanty_outs;
 | 
			
		||||
      size_t m_mixin_count;
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct tx_not_constructed : public transfer_error
 | 
			
		||||
    {
 | 
			
		||||
      typedef std::vector<cryptonote::tx_source_entry> sources_t;
 | 
			
		||||
      typedef std::vector<cryptonote::tx_destination_entry> destinations_t;
 | 
			
		||||
 | 
			
		||||
      explicit tx_not_constructed(std::string&& loc, const sources_t& sources, const destinations_t& destinations, uint64_t unlock_time)
 | 
			
		||||
        : transfer_error(std::move(loc), "transaction was not constructed")
 | 
			
		||||
        , m_sources(sources)
 | 
			
		||||
        , m_destinations(destinations)
 | 
			
		||||
        , m_unlock_time(unlock_time)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const sources_t& sources() const { return m_sources; }
 | 
			
		||||
      const destinations_t& destinations() const { return m_destinations; }
 | 
			
		||||
      uint64_t unlock_time() const { return m_unlock_time; }
 | 
			
		||||
 | 
			
		||||
      std::string to_string() const
 | 
			
		||||
      {
 | 
			
		||||
        std::ostringstream ss;
 | 
			
		||||
        ss << transfer_error::to_string();
 | 
			
		||||
        ss << "\nSources:";
 | 
			
		||||
        for (size_t i = 0; i < m_sources.size(); ++i)
 | 
			
		||||
        {
 | 
			
		||||
          const cryptonote::tx_source_entry& src = m_sources[i];
 | 
			
		||||
          ss << "\n  source " << i << ":";
 | 
			
		||||
          ss << "\n    amount: " << cryptonote::print_money(src.amount);
 | 
			
		||||
          // It's not good, if logs will contain such much data
 | 
			
		||||
          //ss << "\n    real_output: " << src.real_output;
 | 
			
		||||
          //ss << "\n    real_output_in_tx_index: " << src.real_output_in_tx_index;
 | 
			
		||||
          //ss << "\n    real_out_tx_key: " << epee::string_tools::pod_to_hex(src.real_out_tx_key);
 | 
			
		||||
          //ss << "\n    outputs:";
 | 
			
		||||
          //for (size_t j = 0; j < src.outputs.size(); ++j)
 | 
			
		||||
          //{
 | 
			
		||||
          //  const cryptonote::tx_source_entry::output_entry& out = src.outputs[j];
 | 
			
		||||
          //  ss << "\n      " << j << ": " << out.first << ", " << epee::string_tools::pod_to_hex(out.second);
 | 
			
		||||
          //}
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ss << "\nDestinations:";
 | 
			
		||||
        for (size_t i = 0; i < m_destinations.size(); ++i)
 | 
			
		||||
        {
 | 
			
		||||
          const cryptonote::tx_destination_entry& dst = m_destinations[i];
 | 
			
		||||
          ss << "\n  " << i << ": " << cryptonote::get_account_address_as_str(dst.addr) << " " <<
 | 
			
		||||
            cryptonote::print_money(dst.amount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ss << "\nunlock_time: " << m_unlock_time;
 | 
			
		||||
 | 
			
		||||
        return ss.str();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
      sources_t m_sources;
 | 
			
		||||
      destinations_t m_destinations;
 | 
			
		||||
      uint64_t m_unlock_time;
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct tx_rejected : public transfer_error
 | 
			
		||||
    {
 | 
			
		||||
      explicit tx_rejected(std::string&& loc, const cryptonote::transaction& tx, const std::string& status)
 | 
			
		||||
        : transfer_error(std::move(loc), "transaction was rejected by daemon")
 | 
			
		||||
        , m_tx(tx)
 | 
			
		||||
        , m_status(status)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const cryptonote::transaction& tx() const { return m_tx; }
 | 
			
		||||
      const std::string& status() const { return m_status; }
 | 
			
		||||
 | 
			
		||||
      std::string to_string() const
 | 
			
		||||
      {
 | 
			
		||||
        std::ostringstream ss;
 | 
			
		||||
        ss << transfer_error::to_string() << ", status = " << m_status << ", tx:\n";
 | 
			
		||||
        cryptonote::transaction tx = m_tx;
 | 
			
		||||
        ss << cryptonote::obj_to_json_str(tx);
 | 
			
		||||
        return ss.str();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
      cryptonote::transaction m_tx;
 | 
			
		||||
      std::string m_status;
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct tx_sum_overflow : public transfer_error
 | 
			
		||||
    {
 | 
			
		||||
      tx_sum_overflow(std::string&& loc, const std::vector<cryptonote::tx_destination_entry>& destinations, uint64_t fee)
 | 
			
		||||
        : transfer_error(std::move(loc), "transaction sum + fee exceeds " + cryptonote::print_money(std::numeric_limits<uint64_t>::max()))
 | 
			
		||||
        , m_destinations(destinations)
 | 
			
		||||
        , m_fee(fee)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const std::vector<cryptonote::tx_destination_entry>& destinations() const { return m_destinations; }
 | 
			
		||||
      uint64_t fee() const { return m_fee; }
 | 
			
		||||
 | 
			
		||||
      std::string to_string() const
 | 
			
		||||
      {
 | 
			
		||||
        std::ostringstream ss;
 | 
			
		||||
        ss << transfer_error::to_string() <<
 | 
			
		||||
          ", fee = " << cryptonote::print_money(m_fee) <<
 | 
			
		||||
          ", destinations:";
 | 
			
		||||
        for (const auto& dst : m_destinations)
 | 
			
		||||
        {
 | 
			
		||||
          ss << '\n' << cryptonote::print_money(dst.amount) << " -> " << cryptonote::get_account_address_as_str(dst.addr);
 | 
			
		||||
        }
 | 
			
		||||
        return ss.str();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
      std::vector<cryptonote::tx_destination_entry> m_destinations;
 | 
			
		||||
      uint64_t m_fee;
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct tx_too_big : public transfer_error
 | 
			
		||||
    {
 | 
			
		||||
      explicit tx_too_big(std::string&& loc, const cryptonote::transaction& tx, uint64_t tx_size_limit)
 | 
			
		||||
        : transfer_error(std::move(loc), "transaction is too big")
 | 
			
		||||
        , m_tx(tx)
 | 
			
		||||
        , m_tx_size_limit(tx_size_limit)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const cryptonote::transaction& tx() const { return m_tx; }
 | 
			
		||||
      uint64_t tx_size_limit() const { return m_tx_size_limit; }
 | 
			
		||||
 | 
			
		||||
      std::string to_string() const
 | 
			
		||||
      {
 | 
			
		||||
        std::ostringstream ss;
 | 
			
		||||
        cryptonote::transaction tx = m_tx;
 | 
			
		||||
        ss << transfer_error::to_string() <<
 | 
			
		||||
          ", tx_size_limit = " << m_tx_size_limit <<
 | 
			
		||||
          ", tx size = " << get_object_blobsize(m_tx) <<
 | 
			
		||||
          ", tx:\n" << cryptonote::obj_to_json_str(tx);
 | 
			
		||||
        return ss.str();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
      cryptonote::transaction m_tx;
 | 
			
		||||
      uint64_t m_tx_size_limit;
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct zero_destination : public transfer_error
 | 
			
		||||
    {
 | 
			
		||||
      explicit zero_destination(std::string&& loc)
 | 
			
		||||
        : transfer_error(std::move(loc), "destination amount is zero")
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct wallet_rpc_error : public wallet_logic_error
 | 
			
		||||
    {
 | 
			
		||||
      const std::string& request() const { return m_request; }
 | 
			
		||||
 | 
			
		||||
      std::string to_string() const
 | 
			
		||||
      {
 | 
			
		||||
        std::ostringstream ss;
 | 
			
		||||
        ss << wallet_logic_error::to_string() << ", request = " << m_request;
 | 
			
		||||
        return ss.str();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    protected:
 | 
			
		||||
      wallet_rpc_error(std::string&& loc, const std::string& message, const std::string& request)
 | 
			
		||||
        : wallet_logic_error(std::move(loc), message)
 | 
			
		||||
        , m_request(request)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
      std::string m_request;
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct daemon_busy : public wallet_rpc_error
 | 
			
		||||
    {
 | 
			
		||||
      explicit daemon_busy(std::string&& loc, const std::string& request)
 | 
			
		||||
        : wallet_rpc_error(std::move(loc), "daemon is busy", request)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct no_connection_to_daemon : public wallet_rpc_error
 | 
			
		||||
    {
 | 
			
		||||
      explicit no_connection_to_daemon(std::string&& loc, const std::string& request)
 | 
			
		||||
        : wallet_rpc_error(std::move(loc), "no connection to daemon", request)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
    struct wallet_files_doesnt_correspond : public wallet_logic_error
 | 
			
		||||
    {
 | 
			
		||||
      explicit wallet_files_doesnt_correspond(std::string&& loc, const std::string& keys_file, const std::string& wallet_file)
 | 
			
		||||
        : wallet_logic_error(std::move(loc), "file " + wallet_file + " does not correspond to " + keys_file)
 | 
			
		||||
      {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const std::string& keys_file() const { return m_keys_file; }
 | 
			
		||||
      const std::string& wallet_file() const { return m_wallet_file; }
 | 
			
		||||
 | 
			
		||||
      std::string to_string() const { return wallet_logic_error::to_string(); }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
      std::string m_keys_file;
 | 
			
		||||
      std::string m_wallet_file;
 | 
			
		||||
    };
 | 
			
		||||
    //----------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#if !defined(_MSC_VER)
 | 
			
		||||
 | 
			
		||||
    template<typename TException, typename... TArgs>
 | 
			
		||||
    void throw_wallet_ex(std::string&& loc, const TArgs&... args)
 | 
			
		||||
    {
 | 
			
		||||
      TException e(std::move(loc), args...);
 | 
			
		||||
      LOG_PRINT_L0(e.to_string());
 | 
			
		||||
      throw e;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
    #include <boost/preprocessor/repetition/enum_binary_params.hpp>
 | 
			
		||||
    #include <boost/preprocessor/repetition/enum_params.hpp>
 | 
			
		||||
    #include <boost/preprocessor/repetition/repeat_from_to.hpp>
 | 
			
		||||
 | 
			
		||||
    template<typename TException>
 | 
			
		||||
    void throw_wallet_ex(std::string&& loc)
 | 
			
		||||
    {
 | 
			
		||||
      TException e(std::move(loc));
 | 
			
		||||
      LOG_PRINT_L0(e.to_string());
 | 
			
		||||
      throw e;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#define GEN_throw_wallet_ex(z, n, data)                                                       \
 | 
			
		||||
    template<typename TException, BOOST_PP_ENUM_PARAMS(n, typename TArg)>                     \
 | 
			
		||||
    void throw_wallet_ex(std::string&& loc, BOOST_PP_ENUM_BINARY_PARAMS(n, const TArg, &arg)) \
 | 
			
		||||
    {                                                                                         \
 | 
			
		||||
      TException e(std::move(loc), BOOST_PP_ENUM_PARAMS(n, arg));                             \
 | 
			
		||||
      LOG_PRINT_L0(e.to_string());                                                            \
 | 
			
		||||
      throw e;                                                                                \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    BOOST_PP_REPEAT_FROM_TO(1, 6, GEN_throw_wallet_ex, ~)
 | 
			
		||||
#endif
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define STRINGIZE_DETAIL(x) #x
 | 
			
		||||
#define STRINGIZE(x) STRINGIZE_DETAIL(x)
 | 
			
		||||
 | 
			
		||||
#define CHECK_AND_THROW_WALLET_EX(cond, err_type, ...)                                                      \
 | 
			
		||||
  if (cond)                                                                                                 \
 | 
			
		||||
  {                                                                                                         \
 | 
			
		||||
    LOG_ERROR(#cond << ". THROW EXCEPTION: " << #err_type);                                                 \
 | 
			
		||||
    tools::error::throw_wallet_ex<err_type>(std::string(__FILE__ ":" STRINGIZE(__LINE__)), ## __VA_ARGS__); \
 | 
			
		||||
  }
 | 
			
		||||
							
								
								
									
										132
									
								
								src/wallet/wallet_rpc_server.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								src/wallet/wallet_rpc_server.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,132 @@
 | 
			
		|||
// Copyright (c) 2012-2013 The Cryptonote developers
 | 
			
		||||
// Distributed under the MIT/X11 software license, see the accompanying
 | 
			
		||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "include_base_utils.h"
 | 
			
		||||
using namespace epee;
 | 
			
		||||
 | 
			
		||||
#include "wallet_rpc_server.h"
 | 
			
		||||
#include "common/command_line.h"
 | 
			
		||||
#include "cryptonote_core/cryptonote_format_utils.h"
 | 
			
		||||
#include "cryptonote_core/account.h"
 | 
			
		||||
#include "misc_language.h"
 | 
			
		||||
#include "crypto/hash.h"
 | 
			
		||||
 | 
			
		||||
namespace tools
 | 
			
		||||
{
 | 
			
		||||
  //-----------------------------------------------------------------------------------
 | 
			
		||||
  const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_rpc_bind_port = {"rpc-bind-port", "Starts wallet as rpc server for wallet operations, sets bind port for server", "", true};
 | 
			
		||||
  const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_rpc_bind_ip = {"rpc-bind-ip", "Specify ip to bind rpc server", "127.0.0.1"};
 | 
			
		||||
 | 
			
		||||
  void wallet_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);
 | 
			
		||||
  }
 | 
			
		||||
  //------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
  wallet_rpc_server::wallet_rpc_server(wallet2& w):m_wallet(w)
 | 
			
		||||
  {}
 | 
			
		||||
  //------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
  bool wallet_rpc_server::run()
 | 
			
		||||
  {
 | 
			
		||||
    m_net_server.add_idle_handler([this](){
 | 
			
		||||
      m_wallet.refresh();
 | 
			
		||||
      return true;
 | 
			
		||||
    }, 20000);
 | 
			
		||||
 | 
			
		||||
    //DO NOT START THIS SERVER IN MORE THEN 1 THREADS WITHOUT REFACTORING
 | 
			
		||||
    return epee::http_server_impl_base<wallet_rpc_server, connection_context>::run(1, true);
 | 
			
		||||
  }
 | 
			
		||||
  //------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
  bool wallet_rpc_server::handle_command_line(const boost::program_options::variables_map& vm)
 | 
			
		||||
  {
 | 
			
		||||
    m_bind_ip = command_line::get_arg(vm, arg_rpc_bind_ip);
 | 
			
		||||
    m_port = command_line::get_arg(vm, arg_rpc_bind_port);
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  //------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
  bool wallet_rpc_server::init(const boost::program_options::variables_map& vm)
 | 
			
		||||
  {
 | 
			
		||||
    m_net_server.set_threads_prefix("RPC");
 | 
			
		||||
    bool r = handle_command_line(vm);
 | 
			
		||||
    CHECK_AND_ASSERT_MES(r, false, "Failed to process command line in core_rpc_server");
 | 
			
		||||
    return epee::http_server_impl_base<wallet_rpc_server, connection_context>::init(m_port, m_bind_ip);
 | 
			
		||||
  }
 | 
			
		||||
  //------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
  bool wallet_rpc_server::on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE::request& req, wallet_rpc::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er, connection_context& cntx)
 | 
			
		||||
  {
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
      res.balance = m_wallet.balance();
 | 
			
		||||
      res.unlocked_balance = m_wallet.unlocked_balance();
 | 
			
		||||
    }
 | 
			
		||||
    catch (std::exception& e)
 | 
			
		||||
    {
 | 
			
		||||
      er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
 | 
			
		||||
      er.message = e.what();
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  //------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
  bool wallet_rpc_server::on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx)
 | 
			
		||||
  {
 | 
			
		||||
 | 
			
		||||
    std::vector<cryptonote::tx_destination_entry> dsts;
 | 
			
		||||
    for (auto it = req.destinations.begin(); it != req.destinations.end(); it++) 
 | 
			
		||||
    {
 | 
			
		||||
      cryptonote::tx_destination_entry de;
 | 
			
		||||
      if(!get_account_address_from_str(de.addr, it->address))
 | 
			
		||||
      {
 | 
			
		||||
        er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
 | 
			
		||||
        er.message = std::string("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + it->address;
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
      de.amount = it->amount;
 | 
			
		||||
      dsts.push_back(de);
 | 
			
		||||
    }
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
      cryptonote::transaction tx;
 | 
			
		||||
      m_wallet.transfer(dsts, req.mixin, req.unlock_time, req.fee, tx);
 | 
			
		||||
      res.tx_hash = boost::lexical_cast<std::string>(cryptonote::get_transaction_hash(tx));
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    catch (const tools::error::daemon_busy& e)
 | 
			
		||||
    {
 | 
			
		||||
      er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY;
 | 
			
		||||
      er.message = e.what();
 | 
			
		||||
      return false; 
 | 
			
		||||
    }
 | 
			
		||||
    catch (const std::exception& e)
 | 
			
		||||
    {
 | 
			
		||||
      er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR;
 | 
			
		||||
      er.message = e.what();
 | 
			
		||||
      return false; 
 | 
			
		||||
    }
 | 
			
		||||
    catch (...)
 | 
			
		||||
    {
 | 
			
		||||
      er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
 | 
			
		||||
      er.message = "WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR";
 | 
			
		||||
      return false; 
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  //------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
  bool wallet_rpc_server::on_store(const wallet_rpc::COMMAND_RPC_STORE::request& req, wallet_rpc::COMMAND_RPC_STORE::response& res, epee::json_rpc::error& er, connection_context& cntx)
 | 
			
		||||
  {
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
      m_wallet.store();
 | 
			
		||||
    }
 | 
			
		||||
    catch (std::exception& e)
 | 
			
		||||
    {
 | 
			
		||||
      er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
 | 
			
		||||
      er.message = e.what();
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  //------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										55
									
								
								src/wallet/wallet_rpc_server.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/wallet/wallet_rpc_server.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,55 @@
 | 
			
		|||
// Copyright (c) 2012-2013 The Cryptonote developers
 | 
			
		||||
// Distributed under the MIT/X11 software license, see the accompanying
 | 
			
		||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
 | 
			
		||||
 | 
			
		||||
#pragma  once 
 | 
			
		||||
 | 
			
		||||
#include <boost/program_options/options_description.hpp>
 | 
			
		||||
#include <boost/program_options/variables_map.hpp>
 | 
			
		||||
#include "net/http_server_impl_base.h"
 | 
			
		||||
#include "wallet_rpc_server_commans_defs.h"
 | 
			
		||||
#include "wallet2.h"
 | 
			
		||||
#include "common/command_line.h"
 | 
			
		||||
namespace tools
 | 
			
		||||
{
 | 
			
		||||
  /************************************************************************/
 | 
			
		||||
  /*                                                                      */
 | 
			
		||||
  /************************************************************************/
 | 
			
		||||
  class wallet_rpc_server: public epee::http_server_impl_base<wallet_rpc_server>
 | 
			
		||||
  {
 | 
			
		||||
  public:
 | 
			
		||||
    typedef epee::net_utils::connection_context_base connection_context;
 | 
			
		||||
 | 
			
		||||
    wallet_rpc_server(wallet2& cr);
 | 
			
		||||
 | 
			
		||||
    const static command_line::arg_descriptor<std::string> arg_rpc_bind_port;
 | 
			
		||||
    const static command_line::arg_descriptor<std::string> arg_rpc_bind_ip;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    static void init_options(boost::program_options::options_description& desc);
 | 
			
		||||
    bool init(const boost::program_options::variables_map& vm);
 | 
			
		||||
    bool run();
 | 
			
		||||
  private:
 | 
			
		||||
 | 
			
		||||
    CHAIN_HTTP_TO_MAP2(connection_context); //forward http requests to uri map
 | 
			
		||||
 | 
			
		||||
    BEGIN_URI_MAP2()
 | 
			
		||||
      BEGIN_JSON_RPC_MAP("/json_rpc")
 | 
			
		||||
        MAP_JON_RPC_WE("getbalance",  on_getbalance, wallet_rpc::COMMAND_RPC_GET_BALANCE)
 | 
			
		||||
        MAP_JON_RPC_WE("transfer",    on_transfer,   wallet_rpc::COMMAND_RPC_TRANSFER)
 | 
			
		||||
        MAP_JON_RPC_WE("store",       on_store,      wallet_rpc::COMMAND_RPC_STORE)
 | 
			
		||||
      END_JSON_RPC_MAP()
 | 
			
		||||
    END_URI_MAP2()
 | 
			
		||||
 | 
			
		||||
      //json_rpc
 | 
			
		||||
      bool on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE::request& req, wallet_rpc::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er, connection_context& cntx);
 | 
			
		||||
      bool on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx);
 | 
			
		||||
      bool on_store(const wallet_rpc::COMMAND_RPC_STORE::request& req, wallet_rpc::COMMAND_RPC_STORE::response& res, epee::json_rpc::error& er, connection_context& cntx);
 | 
			
		||||
 | 
			
		||||
      bool handle_command_line(const boost::program_options::variables_map& vm);
 | 
			
		||||
 | 
			
		||||
      wallet2& m_wallet;
 | 
			
		||||
      std::string m_port;
 | 
			
		||||
      std::string m_bind_ip;
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										91
									
								
								src/wallet/wallet_rpc_server_commans_defs.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								src/wallet/wallet_rpc_server_commans_defs.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,91 @@
 | 
			
		|||
// Copyright (c) 2012-2013 The Cryptonote developers
 | 
			
		||||
// Distributed under the MIT/X11 software license, see the accompanying
 | 
			
		||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
 | 
			
		||||
#include "cryptonote_core/cryptonote_basic.h"
 | 
			
		||||
#include "crypto/hash.h"
 | 
			
		||||
#include "wallet_rpc_server_error_codes.h"
 | 
			
		||||
namespace tools
 | 
			
		||||
{
 | 
			
		||||
namespace wallet_rpc
 | 
			
		||||
{
 | 
			
		||||
#define WALLET_RPC_STATUS_OK      "OK"
 | 
			
		||||
#define WALLET_RPC_STATUS_BUSY    "BUSY"
 | 
			
		||||
 | 
			
		||||
  struct COMMAND_RPC_GET_BALANCE
 | 
			
		||||
  {
 | 
			
		||||
    struct request
 | 
			
		||||
    {
 | 
			
		||||
      BEGIN_KV_SERIALIZE_MAP()
 | 
			
		||||
      END_KV_SERIALIZE_MAP()
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct response
 | 
			
		||||
    {
 | 
			
		||||
      uint64_t 	 balance;
 | 
			
		||||
      uint64_t 	 unlocked_balance;
 | 
			
		||||
 | 
			
		||||
      BEGIN_KV_SERIALIZE_MAP()
 | 
			
		||||
        KV_SERIALIZE(balance)
 | 
			
		||||
        KV_SERIALIZE(unlocked_balance)
 | 
			
		||||
      END_KV_SERIALIZE_MAP()
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  struct trnsfer_destination
 | 
			
		||||
  {
 | 
			
		||||
    uint64_t amount;
 | 
			
		||||
    std::string address;
 | 
			
		||||
    BEGIN_KV_SERIALIZE_MAP()
 | 
			
		||||
      KV_SERIALIZE(amount)
 | 
			
		||||
      KV_SERIALIZE(address)
 | 
			
		||||
    END_KV_SERIALIZE_MAP()
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  struct COMMAND_RPC_TRANSFER
 | 
			
		||||
  {
 | 
			
		||||
    struct request
 | 
			
		||||
    {
 | 
			
		||||
      std::list<trnsfer_destination> destinations;
 | 
			
		||||
      uint64_t fee;
 | 
			
		||||
      uint64_t mixin;
 | 
			
		||||
      uint64_t unlock_time;
 | 
			
		||||
 | 
			
		||||
      BEGIN_KV_SERIALIZE_MAP()
 | 
			
		||||
        KV_SERIALIZE(destinations)
 | 
			
		||||
        KV_SERIALIZE(fee)
 | 
			
		||||
        KV_SERIALIZE(mixin)
 | 
			
		||||
        KV_SERIALIZE(unlock_time)
 | 
			
		||||
      END_KV_SERIALIZE_MAP()
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct response
 | 
			
		||||
    {
 | 
			
		||||
      std::string tx_hash;
 | 
			
		||||
 | 
			
		||||
      BEGIN_KV_SERIALIZE_MAP()
 | 
			
		||||
        KV_SERIALIZE(tx_hash)
 | 
			
		||||
      END_KV_SERIALIZE_MAP()
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  struct COMMAND_RPC_STORE
 | 
			
		||||
  {
 | 
			
		||||
    struct request
 | 
			
		||||
    {
 | 
			
		||||
      BEGIN_KV_SERIALIZE_MAP()
 | 
			
		||||
      END_KV_SERIALIZE_MAP()
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct response
 | 
			
		||||
    {
 | 
			
		||||
      BEGIN_KV_SERIALIZE_MAP()
 | 
			
		||||
      END_KV_SERIALIZE_MAP()
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								src/wallet/wallet_rpc_server_error_codes.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/wallet/wallet_rpc_server_error_codes.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
// Copyright (c) 2012-2013 The Cryptonote developers
 | 
			
		||||
// Distributed under the MIT/X11 software license, see the accompanying
 | 
			
		||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
 | 
			
		||||
 | 
			
		||||
#pragma  once 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR           -1
 | 
			
		||||
#define WALLET_RPC_ERROR_CODE_WRONG_ADDRESS           -2
 | 
			
		||||
#define WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY          -3
 | 
			
		||||
#define WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR  -4
 | 
			
		||||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ namespace
 | 
			
		|||
    const account_public_address& miner_address, std::vector<size_t>& block_sizes, size_t target_tx_size,
 | 
			
		||||
    size_t target_block_size, uint64_t fee = 0)
 | 
			
		||||
  {
 | 
			
		||||
    if (!construct_miner_tx(height, already_generated_coins, miner_address, miner_tx, fee, block_sizes, target_block_size))
 | 
			
		||||
    if (!construct_miner_tx(height, misc_utils::median(block_sizes), already_generated_coins, target_block_size, fee, miner_address, miner_tx))
 | 
			
		||||
      return false;
 | 
			
		||||
 | 
			
		||||
    size_t current_size = get_object_blobsize(miner_tx);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -71,8 +71,8 @@ uint64_t test_generator::get_already_generated_coins(const cryptonote::block& bl
 | 
			
		|||
void test_generator::add_block(const cryptonote::block& blk, size_t tsx_size, std::vector<size_t>& block_sizes, uint64_t already_generated_coins)
 | 
			
		||||
{
 | 
			
		||||
  const size_t block_size = tsx_size + get_object_blobsize(blk.miner_tx);
 | 
			
		||||
  bool block_too_big;
 | 
			
		||||
  uint64_t block_reward = get_block_reward(block_sizes, block_size, block_too_big, already_generated_coins);
 | 
			
		||||
  uint64_t block_reward;
 | 
			
		||||
  get_block_reward(misc_utils::median(block_sizes), block_size, already_generated_coins, block_reward);
 | 
			
		||||
  m_blocks_info[get_block_hash(blk)] = block_info(blk.prev_id, already_generated_coins + block_reward, block_size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -108,7 +108,7 @@ bool test_generator::construct_block(cryptonote::block& blk, uint64_t height, co
 | 
			
		|||
  size_t target_block_size = txs_size + get_object_blobsize(blk.miner_tx);
 | 
			
		||||
  while (true)
 | 
			
		||||
  {
 | 
			
		||||
    if (!construct_miner_tx(height, already_generated_coins, miner_acc.get_keys().m_account_address, blk.miner_tx, total_fee, block_sizes, target_block_size, 10))
 | 
			
		||||
    if (!construct_miner_tx(height, misc_utils::median(block_sizes), already_generated_coins, target_block_size, total_fee, miner_acc.get_keys().m_account_address, blk.miner_tx, blobdata(), 10))
 | 
			
		||||
      return false;
 | 
			
		||||
 | 
			
		||||
    size_t actual_block_size = txs_size + get_object_blobsize(blk.miner_tx);
 | 
			
		||||
| 
						 | 
				
			
			@ -209,7 +209,7 @@ bool test_generator::construct_block_manually(block& blk, const block& prev_bloc
 | 
			
		|||
  {
 | 
			
		||||
    size_t current_block_size = txs_sizes + get_object_blobsize(blk.miner_tx);
 | 
			
		||||
    // TODO: This will work, until size of constructed block is less then CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE
 | 
			
		||||
    if (!construct_miner_tx(height, already_generated_coins, miner_acc.get_keys().m_account_address, blk.miner_tx, 0, block_sizes, current_block_size, 1))
 | 
			
		||||
    if (!construct_miner_tx(height, misc_utils::median(block_sizes), already_generated_coins, current_block_size, 0, miner_acc.get_keys().m_account_address, blk.miner_tx, blobdata(), 1))
 | 
			
		||||
      return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -496,14 +496,13 @@ bool construct_miner_tx_manually(size_t height, uint64_t already_generated_coins
 | 
			
		|||
  tx.vin.push_back(in);
 | 
			
		||||
 | 
			
		||||
  // This will work, until size of constructed block is less then CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE
 | 
			
		||||
  std::vector<size_t> block_sizes;
 | 
			
		||||
  bool block_too_big = false;
 | 
			
		||||
  uint64_t block_reward = get_block_reward(block_sizes, 0, block_too_big, already_generated_coins) + fee;
 | 
			
		||||
  if (block_too_big)
 | 
			
		||||
  uint64_t block_reward;
 | 
			
		||||
  if (!get_block_reward(0, 0, already_generated_coins, block_reward))
 | 
			
		||||
  {
 | 
			
		||||
    LOG_PRINT_L0("Block is too big");
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  block_reward += fee;
 | 
			
		||||
 | 
			
		||||
  crypto::key_derivation derivation;
 | 
			
		||||
  crypto::public_key out_eph_public_key;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@
 | 
			
		|||
#include "cryptonote_core/cryptonote_basic_impl.h"
 | 
			
		||||
#include "cryptonote_core/account.h"
 | 
			
		||||
#include "cryptonote_core/cryptonote_format_utils.h"
 | 
			
		||||
#include "misc_language.h"
 | 
			
		||||
 | 
			
		||||
using namespace cryptonote;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -35,19 +36,18 @@ bool test_transaction_generation_and_ring_signature()
 | 
			
		|||
  rv_acc.generate();
 | 
			
		||||
  account_base rv_acc2;
 | 
			
		||||
  rv_acc2.generate();
 | 
			
		||||
  std::vector<size_t> b;
 | 
			
		||||
  transaction tx_mine_1;
 | 
			
		||||
  construct_miner_tx(0, 0, miner_acc1.get_keys().m_account_address, tx_mine_1, 0, b, 10);
 | 
			
		||||
  construct_miner_tx(0, 0, 0, 10, 0, miner_acc1.get_keys().m_account_address, tx_mine_1);
 | 
			
		||||
  transaction tx_mine_2;
 | 
			
		||||
  construct_miner_tx(0, 0, miner_acc2.get_keys().m_account_address, tx_mine_2, 0, b, 0);
 | 
			
		||||
  construct_miner_tx(0, 0, 0, 0, 0, miner_acc2.get_keys().m_account_address, tx_mine_2);
 | 
			
		||||
  transaction tx_mine_3;
 | 
			
		||||
  construct_miner_tx(0, 0, miner_acc3.get_keys().m_account_address, tx_mine_3, 0, b, 0);
 | 
			
		||||
  construct_miner_tx(0, 0, 0, 0, 0, miner_acc3.get_keys().m_account_address, tx_mine_3);
 | 
			
		||||
  transaction tx_mine_4;
 | 
			
		||||
  construct_miner_tx(0, 0, miner_acc4.get_keys().m_account_address, tx_mine_4, 0, b, 0);
 | 
			
		||||
  construct_miner_tx(0, 0, 0, 0, 0, miner_acc4.get_keys().m_account_address, tx_mine_4);
 | 
			
		||||
  transaction tx_mine_5;
 | 
			
		||||
  construct_miner_tx(0, 0, miner_acc5.get_keys().m_account_address, tx_mine_5, 0, b, 0);
 | 
			
		||||
  construct_miner_tx(0, 0, 0, 0, 0, miner_acc5.get_keys().m_account_address, tx_mine_5);
 | 
			
		||||
  transaction tx_mine_6;
 | 
			
		||||
  construct_miner_tx(0, 0, miner_acc6.get_keys().m_account_address, tx_mine_6, 0, b, 0);
 | 
			
		||||
  construct_miner_tx(0, 0, 0, 0, 0, miner_acc6.get_keys().m_account_address, tx_mine_6);
 | 
			
		||||
 | 
			
		||||
  //fill inputs entry
 | 
			
		||||
  typedef tx_source_entry::output_entry tx_output_entry;
 | 
			
		||||
| 
						 | 
				
			
			@ -111,7 +111,7 @@ bool test_transaction_generation_and_ring_signature()
 | 
			
		|||
 | 
			
		||||
  std::vector<size_t> outs;
 | 
			
		||||
  uint64_t money = 0;
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  r = lookup_acc_outs(rv_acc.get_keys(), tx_rc1, get_tx_pub_key_from_extra(tx_rc1), outs,  money);
 | 
			
		||||
  CHECK_AND_ASSERT_MES(r, false, "failed to lookup_acc_outs");
 | 
			
		||||
  CHECK_AND_ASSERT_MES(td.amount == money, false, "wrong money amount in new transaction");
 | 
			
		||||
| 
						 | 
				
			
			@ -130,7 +130,7 @@ bool test_block_creation()
 | 
			
		|||
  bool r = get_account_address_from_str(adr, "0099be99c70ef10fd534c43c88e9d13d1c8853213df7e362afbec0e4ee6fec4948d0c190b58f4b356cd7feaf8d9d0a76e7c7e5a9a0a497a6b1faf7a765882dd08ac2");
 | 
			
		||||
  CHECK_AND_ASSERT_MES(r, false, "failed to import");
 | 
			
		||||
  block b;
 | 
			
		||||
  r = construct_miner_tx(90, 3553616528562147, adr, b.miner_tx, 10000000, szs, 33094, 11);
 | 
			
		||||
  r = construct_miner_tx(90, epee::misc_utils::median(szs), 3553616528562147, 33094, 10000000, adr, b.miner_tx, blobdata(), 11);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@
 | 
			
		|||
#include <fstream>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
 | 
			
		||||
#include "cryptonote_config.h"
 | 
			
		||||
#include "cryptonote_core/difficulty.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,7 +50,15 @@ bool do_send_money(tools::wallet2& w1, tools::wallet2& w2, size_t mix_in_factor,
 | 
			
		|||
    dsts.push_back(de);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return w1.transfer(dsts, mix_in_factor, 0, DEFAULT_FEE, tools::detail::null_split_strategy, tools::wallet2::tx_dust_policy(DEFAULT_FEE), tx);
 | 
			
		||||
  try
 | 
			
		||||
  {
 | 
			
		||||
    w1.transfer(dsts, mix_in_factor, 0, DEFAULT_FEE, tools::detail::null_split_strategy, tools::tx_dust_policy(DEFAULT_FEE), tx);
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  catch (const std::exception&)
 | 
			
		||||
  {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint64_t get_money_in_first_transfers(const tools::wallet2::transfer_container& incoming_transfers, size_t n_transfers)
 | 
			
		||||
| 
						 | 
				
			
			@ -84,36 +92,30 @@ bool transactions_flow_test(std::string& working_folder,
 | 
			
		|||
    path_terget_wallet = generate_random_wallet_name();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  if(!w1.generate(working_folder + "/" + path_source_wallet, ""))
 | 
			
		||||
  try
 | 
			
		||||
  {
 | 
			
		||||
    LOG_ERROR("failed to load source wallet from " << path_source_wallet);
 | 
			
		||||
    w1.generate(working_folder + "/" + path_source_wallet, "");
 | 
			
		||||
    w2.generate(working_folder + "/" + path_terget_wallet, "");
 | 
			
		||||
  }
 | 
			
		||||
  catch (const std::exception& e)
 | 
			
		||||
  {
 | 
			
		||||
    LOG_ERROR("failed to generate wallet: " << e.what());
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if(!w2.generate(working_folder + "/" + path_terget_wallet, ""))
 | 
			
		||||
  {
 | 
			
		||||
    LOG_ERROR( "failed to generate target load wallet from " << path_source_wallet );
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  w1.init(daemon_addr_a);
 | 
			
		||||
 | 
			
		||||
  if(!w1.init(daemon_addr_a))
 | 
			
		||||
  {
 | 
			
		||||
    LOG_ERROR("failed to init source wallet from " << daemon_addr_a );
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  size_t blocks_fetched = 0;
 | 
			
		||||
  tools::wallet2::fail_details fd;
 | 
			
		||||
  if(!w1.refresh(blocks_fetched, fd))
 | 
			
		||||
  bool received_money;
 | 
			
		||||
  bool ok;
 | 
			
		||||
  if(!w1.refresh(blocks_fetched, received_money, ok))
 | 
			
		||||
  {
 | 
			
		||||
    LOG_ERROR( "failed to refresh source wallet from " << daemon_addr_a );
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if(!w2.init(daemon_addr_b))
 | 
			
		||||
  {
 | 
			
		||||
    LOG_ERROR( "failed to init target wallet from " << daemon_addr_b );
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  w2.init(daemon_addr_b);
 | 
			
		||||
 | 
			
		||||
  LOG_PRINT_GREEN("Using wallets: " << ENDL
 | 
			
		||||
    << "Source:  " << w1.get_account().get_public_address_str() << ENDL << "Path: " << working_folder + "/" + path_source_wallet << ENDL
 | 
			
		||||
    << "Target:  " << w2.get_account().get_public_address_str() << ENDL << "Path: " << working_folder + "/" + path_terget_wallet, LOG_LEVEL_1);
 | 
			
		||||
| 
						 | 
				
			
			@ -125,7 +127,6 @@ bool transactions_flow_test(std::string& working_folder,
 | 
			
		|||
  bool r = net_utils::invoke_http_json_remote_command2(daemon_addr_a + "/stop_mine", daemon1_req, daemon1_rsp, http_client, 10000);
 | 
			
		||||
  CHECK_AND_ASSERT_MES(r, false, "failed to stop mining");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  COMMAND_RPC_START_MINING::request daemon_req = AUTO_VAL_INIT(daemon_req);
 | 
			
		||||
  COMMAND_RPC_START_MINING::response daemon_rsp = AUTO_VAL_INIT(daemon_rsp);
 | 
			
		||||
  daemon_req.miner_address = w1.get_account().get_public_address_str();
 | 
			
		||||
| 
						 | 
				
			
			@ -135,11 +136,11 @@ bool transactions_flow_test(std::string& working_folder,
 | 
			
		|||
  CHECK_AND_ASSERT_MES(daemon_rsp.status == CORE_RPC_STATUS_OK, false, "failed to getrandom_outs.bin");
 | 
			
		||||
 | 
			
		||||
  //wait for money, until balance will have enough money
 | 
			
		||||
  w1.refresh(blocks_fetched, fd);
 | 
			
		||||
  w1.refresh(blocks_fetched, received_money, ok);
 | 
			
		||||
  while(w1.unlocked_balance() < amount_to_transfer)
 | 
			
		||||
  {
 | 
			
		||||
    misc_utils::sleep_no_w(1000);
 | 
			
		||||
    w1.refresh(blocks_fetched, fd);
 | 
			
		||||
    w1.refresh(blocks_fetched, received_money, ok);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //lets make a lot of small outs to ourselves
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +167,7 @@ bool transactions_flow_test(std::string& working_folder,
 | 
			
		|||
    }else
 | 
			
		||||
    {
 | 
			
		||||
      misc_utils::sleep_no_w(1000);
 | 
			
		||||
      w1.refresh(fd);
 | 
			
		||||
      w1.refresh(blocks_fetched, received_money, ok);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  //do actual transfer
 | 
			
		||||
| 
						 | 
				
			
			@ -188,7 +189,7 @@ bool transactions_flow_test(std::string& working_folder,
 | 
			
		|||
    {
 | 
			
		||||
      misc_utils::sleep_no_w(1000);
 | 
			
		||||
      LOG_PRINT_L0("not enough money, waiting for cashback or mining");
 | 
			
		||||
      w1.refresh(blocks_fetched, fd);
 | 
			
		||||
      w1.refresh(blocks_fetched, received_money, ok);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    transaction tx;
 | 
			
		||||
| 
						 | 
				
			
			@ -203,7 +204,7 @@ bool transactions_flow_test(std::string& working_folder,
 | 
			
		|||
    if(!do_send_money(w1, w2, mix_in_factor, amount_to_tx, tx))
 | 
			
		||||
    {
 | 
			
		||||
      LOG_PRINT_L0("failed to transfer money, tx: " << get_transaction_hash(tx) << ", refresh and try again" );
 | 
			
		||||
      w1.refresh(blocks_fetched, fd);
 | 
			
		||||
      w1.refresh(blocks_fetched, received_money, ok);
 | 
			
		||||
      if(!do_send_money(w1, w2, mix_in_factor, amount_to_tx, tx))
 | 
			
		||||
      {
 | 
			
		||||
        LOG_PRINT_L0( "failed to transfer money, second chance. tx: " << get_transaction_hash(tx) << ", exit" );
 | 
			
		||||
| 
						 | 
				
			
			@ -228,7 +229,7 @@ bool transactions_flow_test(std::string& working_folder,
 | 
			
		|||
  misc_utils::sleep_no_w(DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN*20*1000);//wait two blocks before sync on another wallet on another daemon
 | 
			
		||||
  LOG_PRINT_L0( "refreshing...");
 | 
			
		||||
  bool recvd_money = false;
 | 
			
		||||
  while(w2.refresh(blocks_fetched, recvd_money, fd) && ( (blocks_fetched && recvd_money) || !blocks_fetched  ) )
 | 
			
		||||
  while(w2.refresh(blocks_fetched, recvd_money, ok) && ( (blocks_fetched && recvd_money) || !blocks_fetched  ) )
 | 
			
		||||
  {
 | 
			
		||||
    misc_utils::sleep_no_w(DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN*1000);//wait two blocks before sync on another wallet on another daemon
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,7 +35,7 @@ namespace
 | 
			
		|||
      if (predicate())
 | 
			
		||||
        return true;
 | 
			
		||||
      //std::this_thread::sleep_for(std::chrono::milliseconds(sleep_ms));
 | 
			
		||||
      epee::misc_utils::sleep_no_w(sleep_ms);
 | 
			
		||||
      epee::misc_utils::sleep_no_w(static_cast<long>(sleep_ms));
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,8 +29,7 @@ public:
 | 
			
		|||
    {
 | 
			
		||||
      m_miners[i].generate();
 | 
			
		||||
 | 
			
		||||
      std::vector<size_t> block_sizes;
 | 
			
		||||
      if (!construct_miner_tx(0, 0, m_miners[i].get_keys().m_account_address, m_miner_txs[i], 0, block_sizes, 2))
 | 
			
		||||
      if (!construct_miner_tx(0, 0, 0, 2, 0, m_miners[i].get_keys().m_account_address, m_miner_txs[i]))
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
      txout_to_key tx_out = boost::get<txout_to_key>(m_miner_txs[i].vout[0].target);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,8 +17,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    m_bob.generate();
 | 
			
		||||
 | 
			
		||||
    std::vector<size_t> block_sizes;
 | 
			
		||||
    if (!construct_miner_tx(0, 0, m_bob.get_keys().m_account_address, m_tx, 0, block_sizes, 2))
 | 
			
		||||
    if (!construct_miner_tx(0, 0, 0, 2, 0, m_bob.get_keys().m_account_address, m_tx))
 | 
			
		||||
      return false;
 | 
			
		||||
 | 
			
		||||
    m_tx_pub_key = get_tx_pub_key_from_extra(m_tx);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,14 +16,13 @@ namespace
 | 
			
		|||
  protected:
 | 
			
		||||
    static const size_t current_block_size = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE / 2;
 | 
			
		||||
 | 
			
		||||
    std::vector<size_t> m_last_block_sizes;
 | 
			
		||||
    bool m_block_too_big;
 | 
			
		||||
    bool m_block_not_too_big;
 | 
			
		||||
    uint64_t m_block_reward;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  #define TEST_ALREADY_GENERATED_COINS(already_generated_coins, expected_reward)                                         \
 | 
			
		||||
    m_block_reward = get_block_reward(m_last_block_sizes, current_block_size, m_block_too_big, already_generated_coins); \
 | 
			
		||||
    ASSERT_FALSE(m_block_too_big);                                                                                       \
 | 
			
		||||
  #define TEST_ALREADY_GENERATED_COINS(already_generated_coins, expected_reward)                            \
 | 
			
		||||
    m_block_not_too_big = get_block_reward(0, current_block_size, already_generated_coins, m_block_reward); \
 | 
			
		||||
    ASSERT_TRUE(m_block_not_too_big);                                                                       \
 | 
			
		||||
    ASSERT_EQ(m_block_reward, UINT64_C(expected_reward));
 | 
			
		||||
 | 
			
		||||
  TEST_F(block_reward_and_already_generated_coins, handles_first_values)
 | 
			
		||||
| 
						 | 
				
			
			@ -53,72 +52,70 @@ namespace
 | 
			
		|||
  protected:
 | 
			
		||||
    virtual void SetUp()
 | 
			
		||||
    {
 | 
			
		||||
      m_standard_block_reward = get_block_reward(m_last_block_sizes, 0, m_block_too_big, already_generated_coins);
 | 
			
		||||
      ASSERT_FALSE(m_block_too_big);
 | 
			
		||||
      m_block_not_too_big = get_block_reward(0, 0, already_generated_coins, m_standard_block_reward);
 | 
			
		||||
      ASSERT_TRUE(m_block_not_too_big);
 | 
			
		||||
      ASSERT_LT(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE, m_standard_block_reward);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void do_test(size_t current_block_size)
 | 
			
		||||
    void do_test(size_t median_block_size, size_t current_block_size)
 | 
			
		||||
    {
 | 
			
		||||
      m_block_reward = get_block_reward(m_last_block_sizes, current_block_size, m_block_too_big, already_generated_coins);
 | 
			
		||||
      m_block_not_too_big = get_block_reward(median_block_size, current_block_size, already_generated_coins, m_block_reward);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static const uint64_t already_generated_coins = 0;
 | 
			
		||||
 | 
			
		||||
    std::vector<size_t> m_last_block_sizes;
 | 
			
		||||
    bool m_block_too_big;
 | 
			
		||||
    bool m_block_not_too_big;
 | 
			
		||||
    uint64_t m_block_reward;
 | 
			
		||||
    uint64_t m_standard_block_reward;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  TEST_F(block_reward_and_current_block_size, handles_block_size_less_relevance_level)
 | 
			
		||||
  {
 | 
			
		||||
    do_test(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE - 1);
 | 
			
		||||
    ASSERT_FALSE(m_block_too_big);
 | 
			
		||||
    do_test(0, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE - 1);
 | 
			
		||||
    ASSERT_TRUE(m_block_not_too_big);
 | 
			
		||||
    ASSERT_EQ(m_block_reward, m_standard_block_reward);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  TEST_F(block_reward_and_current_block_size, handles_block_size_eq_relevance_level)
 | 
			
		||||
  {
 | 
			
		||||
    do_test(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE);
 | 
			
		||||
    ASSERT_FALSE(m_block_too_big);
 | 
			
		||||
    do_test(0, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE);
 | 
			
		||||
    ASSERT_TRUE(m_block_not_too_big);
 | 
			
		||||
    ASSERT_EQ(m_block_reward, m_standard_block_reward);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  TEST_F(block_reward_and_current_block_size, handles_block_size_gt_relevance_level)
 | 
			
		||||
  {
 | 
			
		||||
    do_test(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE + 1);
 | 
			
		||||
    ASSERT_FALSE(m_block_too_big);
 | 
			
		||||
    do_test(0, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE + 1);
 | 
			
		||||
    ASSERT_TRUE(m_block_not_too_big);
 | 
			
		||||
    ASSERT_LT(m_block_reward, m_standard_block_reward);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  TEST_F(block_reward_and_current_block_size, handles_block_size_less_2_relevance_level)
 | 
			
		||||
  {
 | 
			
		||||
    do_test(2 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE - 1);
 | 
			
		||||
    ASSERT_FALSE(m_block_too_big);
 | 
			
		||||
    do_test(0, 2 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE - 1);
 | 
			
		||||
    ASSERT_TRUE(m_block_not_too_big);
 | 
			
		||||
    ASSERT_LT(m_block_reward, m_standard_block_reward);
 | 
			
		||||
    ASSERT_LT(0, m_block_reward);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  TEST_F(block_reward_and_current_block_size, handles_block_size_eq_2_relevance_level)
 | 
			
		||||
  {
 | 
			
		||||
    do_test(2 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE);
 | 
			
		||||
    ASSERT_FALSE(m_block_too_big);
 | 
			
		||||
    do_test(0, 2 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE);
 | 
			
		||||
    ASSERT_TRUE(m_block_not_too_big);
 | 
			
		||||
    ASSERT_EQ(0, m_block_reward);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  TEST_F(block_reward_and_current_block_size, handles_block_size_gt_2_relevance_level)
 | 
			
		||||
  {
 | 
			
		||||
    do_test(2 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE + 1);
 | 
			
		||||
    ASSERT_TRUE(m_block_too_big);
 | 
			
		||||
    do_test(0, 2 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE + 1);
 | 
			
		||||
    ASSERT_FALSE(m_block_not_too_big);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  TEST_F(block_reward_and_current_block_size, fails_on_huge_median_size)
 | 
			
		||||
  {
 | 
			
		||||
#if !defined(NDEBUG)
 | 
			
		||||
    size_t huge_size = std::numeric_limits<uint32_t>::max() + UINT64_C(2);
 | 
			
		||||
    m_last_block_sizes.push_back(huge_size);
 | 
			
		||||
    ASSERT_DEATH(do_test(huge_size + 1), "");
 | 
			
		||||
    ASSERT_DEATH(do_test(huge_size, huge_size + 1), "");
 | 
			
		||||
#endif
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -126,8 +123,7 @@ namespace
 | 
			
		|||
  {
 | 
			
		||||
#if !defined(NDEBUG)
 | 
			
		||||
    size_t huge_size = std::numeric_limits<uint32_t>::max() + UINT64_C(2);
 | 
			
		||||
    m_last_block_sizes.push_back(huge_size - 2);
 | 
			
		||||
    ASSERT_DEATH(do_test(huge_size), "");
 | 
			
		||||
    ASSERT_DEATH(do_test(huge_size - 2, huge_size), "");
 | 
			
		||||
#endif
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -145,21 +141,21 @@ namespace
 | 
			
		|||
 | 
			
		||||
      m_last_block_sizes_median = 7 * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE;
 | 
			
		||||
 | 
			
		||||
      m_standard_block_reward = get_block_reward(m_last_block_sizes, 0, m_block_too_big, already_generated_coins);
 | 
			
		||||
      ASSERT_FALSE(m_block_too_big);
 | 
			
		||||
      m_block_not_too_big = get_block_reward(epee::misc_utils::median(m_last_block_sizes), 0, already_generated_coins, m_standard_block_reward);
 | 
			
		||||
      ASSERT_TRUE(m_block_not_too_big);
 | 
			
		||||
      ASSERT_LT(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE, m_standard_block_reward);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void do_test(size_t current_block_size)
 | 
			
		||||
    {
 | 
			
		||||
      m_block_reward = get_block_reward(m_last_block_sizes, current_block_size, m_block_too_big, already_generated_coins);
 | 
			
		||||
      m_block_not_too_big = get_block_reward(epee::misc_utils::median(m_last_block_sizes), current_block_size, already_generated_coins, m_block_reward);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static const uint64_t already_generated_coins = 0;
 | 
			
		||||
 | 
			
		||||
    std::vector<size_t> m_last_block_sizes;
 | 
			
		||||
    uint64_t m_last_block_sizes_median;
 | 
			
		||||
    bool m_block_too_big;
 | 
			
		||||
    bool m_block_not_too_big;
 | 
			
		||||
    uint64_t m_block_reward;
 | 
			
		||||
    uint64_t m_standard_block_reward;
 | 
			
		||||
  };
 | 
			
		||||
| 
						 | 
				
			
			@ -167,28 +163,28 @@ namespace
 | 
			
		|||
  TEST_F(block_reward_and_last_block_sizes, handles_block_size_less_median)
 | 
			
		||||
  {
 | 
			
		||||
    do_test(m_last_block_sizes_median - 1);
 | 
			
		||||
    ASSERT_FALSE(m_block_too_big);
 | 
			
		||||
    ASSERT_TRUE(m_block_not_too_big);
 | 
			
		||||
    ASSERT_EQ(m_block_reward, m_standard_block_reward);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  TEST_F(block_reward_and_last_block_sizes, handles_block_size_eq_median)
 | 
			
		||||
  {
 | 
			
		||||
    do_test(m_last_block_sizes_median);
 | 
			
		||||
    ASSERT_FALSE(m_block_too_big);
 | 
			
		||||
    ASSERT_TRUE(m_block_not_too_big);
 | 
			
		||||
    ASSERT_EQ(m_block_reward, m_standard_block_reward);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  TEST_F(block_reward_and_last_block_sizes, handles_block_size_gt_median)
 | 
			
		||||
  {
 | 
			
		||||
    do_test(m_last_block_sizes_median + 1);
 | 
			
		||||
    ASSERT_FALSE(m_block_too_big);
 | 
			
		||||
    ASSERT_TRUE(m_block_not_too_big);
 | 
			
		||||
    ASSERT_LT(m_block_reward, m_standard_block_reward);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  TEST_F(block_reward_and_last_block_sizes, handles_block_size_less_2_medians)
 | 
			
		||||
  {
 | 
			
		||||
    do_test(2 * m_last_block_sizes_median - 1);
 | 
			
		||||
    ASSERT_FALSE(m_block_too_big);
 | 
			
		||||
    ASSERT_TRUE(m_block_not_too_big);
 | 
			
		||||
    ASSERT_LT(m_block_reward, m_standard_block_reward);
 | 
			
		||||
    ASSERT_LT(0, m_block_reward);
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -196,14 +192,14 @@ namespace
 | 
			
		|||
  TEST_F(block_reward_and_last_block_sizes, handles_block_size_eq_2_medians)
 | 
			
		||||
  {
 | 
			
		||||
    do_test(2 * m_last_block_sizes_median);
 | 
			
		||||
    ASSERT_FALSE(m_block_too_big);
 | 
			
		||||
    ASSERT_TRUE(m_block_not_too_big);
 | 
			
		||||
    ASSERT_EQ(0, m_block_reward);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  TEST_F(block_reward_and_last_block_sizes, handles_block_size_gt_2_medians)
 | 
			
		||||
  {
 | 
			
		||||
    do_test(2 * m_last_block_sizes_median + 1);
 | 
			
		||||
    ASSERT_TRUE(m_block_too_big);
 | 
			
		||||
    ASSERT_FALSE(m_block_not_too_big);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  TEST_F(block_reward_and_last_block_sizes, calculates_correctly)
 | 
			
		||||
| 
						 | 
				
			
			@ -211,16 +207,16 @@ namespace
 | 
			
		|||
    ASSERT_EQ(0, m_last_block_sizes_median % 8);
 | 
			
		||||
 | 
			
		||||
    do_test(m_last_block_sizes_median * 9 / 8);
 | 
			
		||||
    ASSERT_FALSE(m_block_too_big);
 | 
			
		||||
    ASSERT_TRUE(m_block_not_too_big);
 | 
			
		||||
    ASSERT_EQ(m_block_reward, m_standard_block_reward * 63 / 64);
 | 
			
		||||
 | 
			
		||||
    // 3/2 = 12/8
 | 
			
		||||
    do_test(m_last_block_sizes_median * 3 / 2);
 | 
			
		||||
    ASSERT_FALSE(m_block_too_big);
 | 
			
		||||
    ASSERT_TRUE(m_block_not_too_big);
 | 
			
		||||
    ASSERT_EQ(m_block_reward, m_standard_block_reward * 3 / 4);
 | 
			
		||||
 | 
			
		||||
    do_test(m_last_block_sizes_median * 15 / 8);
 | 
			
		||||
    ASSERT_FALSE(m_block_too_big);
 | 
			
		||||
    ASSERT_TRUE(m_block_not_too_big);
 | 
			
		||||
    ASSERT_EQ(m_block_reward, m_standard_block_reward * 15 / 64);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,6 +45,7 @@ TEST_pos(uint16_t,     0,     "0");
 | 
			
		|||
TEST_pos(uint16_t,     1,     "1");
 | 
			
		||||
TEST_pos(uint16_t, 65535, "65535");
 | 
			
		||||
 | 
			
		||||
TEST_neg(uint16_t, "");
 | 
			
		||||
TEST_neg(uint16_t, "+0");
 | 
			
		||||
TEST_neg(uint16_t, "+1");
 | 
			
		||||
TEST_neg(uint16_t, "+65535");
 | 
			
		||||
| 
						 | 
				
			
			@ -77,6 +78,7 @@ TEST_pos(uint32_t,          0,          "0");
 | 
			
		|||
TEST_pos(uint32_t,          1,          "1");
 | 
			
		||||
TEST_pos(uint32_t, 4294967295, "4294967295");
 | 
			
		||||
 | 
			
		||||
TEST_neg(uint32_t, "");
 | 
			
		||||
TEST_neg(uint32_t, "+0");
 | 
			
		||||
TEST_neg(uint32_t, "+1");
 | 
			
		||||
TEST_neg(uint32_t, "+4294967295");
 | 
			
		||||
| 
						 | 
				
			
			@ -107,6 +109,7 @@ TEST_pos(uint64_t, 0, "0");
 | 
			
		|||
TEST_pos(uint64_t, 1, "1");
 | 
			
		||||
TEST_pos(uint64_t, 18446744073709551615ULL, "18446744073709551615");
 | 
			
		||||
 | 
			
		||||
TEST_neg(uint64_t, "");
 | 
			
		||||
TEST_neg(uint64_t, "+0");
 | 
			
		||||
TEST_neg(uint64_t, "+1");
 | 
			
		||||
TEST_neg(uint64_t, "+18446744073709551615");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										124
									
								
								tests/unit_tests/parse_amount.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								tests/unit_tests/parse_amount.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,124 @@
 | 
			
		|||
// Copyright (c) 2012-2013 The Cryptonote developers
 | 
			
		||||
// Distributed under the MIT/X11 software license, see the accompanying
 | 
			
		||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
 | 
			
		||||
 | 
			
		||||
#include "gtest/gtest.h"
 | 
			
		||||
 | 
			
		||||
#include "cryptonote_core/cryptonote_format_utils.h"
 | 
			
		||||
 | 
			
		||||
using namespace cryptonote;
 | 
			
		||||
 | 
			
		||||
namespace
 | 
			
		||||
{
 | 
			
		||||
  void do_pos_test(uint64_t expected, const std::string& str)
 | 
			
		||||
  {
 | 
			
		||||
    uint64_t val;
 | 
			
		||||
    std::string number_str = str;
 | 
			
		||||
    std::replace(number_str.begin(), number_str.end(), '_', '.');
 | 
			
		||||
    number_str.erase(std::remove(number_str.begin(), number_str.end(), '~'), number_str.end());
 | 
			
		||||
    ASSERT_TRUE(parse_amount(val, number_str));
 | 
			
		||||
    ASSERT_EQ(expected, val);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void do_neg_test(const std::string& str)
 | 
			
		||||
  {
 | 
			
		||||
    uint64_t val;
 | 
			
		||||
    std::string number_str = str;
 | 
			
		||||
    std::replace(number_str.begin(), number_str.end(), '_', '.');
 | 
			
		||||
    number_str.erase(std::remove(number_str.begin(), number_str.end(), '~'), number_str.end());
 | 
			
		||||
    ASSERT_FALSE(parse_amount(val, number_str));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define TEST_pos(expected, str)            \
 | 
			
		||||
  TEST(parse_amount, handles_pos_ ## str)  \
 | 
			
		||||
  {                                        \
 | 
			
		||||
    do_pos_test(UINT64_C(expected), #str); \
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#define TEST_neg(str)                      \
 | 
			
		||||
  TEST(parse_amount, handles_neg_ ## str)  \
 | 
			
		||||
  {                                        \
 | 
			
		||||
    do_neg_test(#str);                     \
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#define TEST_neg_n(str, name)              \
 | 
			
		||||
  TEST(parse_amount, handles_neg_ ## name) \
 | 
			
		||||
  {                                        \
 | 
			
		||||
    do_neg_test(#str);                     \
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
TEST_pos(0, 0);
 | 
			
		||||
TEST_pos(0, 00);
 | 
			
		||||
TEST_pos(0, 00000000);
 | 
			
		||||
TEST_pos(0, 000000000);
 | 
			
		||||
TEST_pos(0, 00000000000000000000000000000000);
 | 
			
		||||
 | 
			
		||||
TEST_pos(0, _0);
 | 
			
		||||
TEST_pos(0, _00);
 | 
			
		||||
TEST_pos(0, _00000000);
 | 
			
		||||
TEST_pos(0, _000000000);
 | 
			
		||||
TEST_pos(0, _00000000000000000000000000000000);
 | 
			
		||||
 | 
			
		||||
TEST_pos(0, 00000000_);
 | 
			
		||||
TEST_pos(0, 000000000_);
 | 
			
		||||
TEST_pos(0, 00000000000000000000000000000000_);
 | 
			
		||||
 | 
			
		||||
TEST_pos(0, 0_);
 | 
			
		||||
TEST_pos(0, 0_0);
 | 
			
		||||
TEST_pos(0, 0_00);
 | 
			
		||||
TEST_pos(0, 0_00000000);
 | 
			
		||||
TEST_pos(0, 0_000000000);
 | 
			
		||||
TEST_pos(0, 0_00000000000000000000000000000000);
 | 
			
		||||
 | 
			
		||||
TEST_pos(0, 00_);
 | 
			
		||||
TEST_pos(0, 00_0);
 | 
			
		||||
TEST_pos(0, 00_00);
 | 
			
		||||
TEST_pos(0, 00_00000000);
 | 
			
		||||
TEST_pos(0, 00_000000000);
 | 
			
		||||
TEST_pos(0, 00_00000000000000000000000000000000);
 | 
			
		||||
 | 
			
		||||
TEST_pos(1, 0_00000001);
 | 
			
		||||
TEST_pos(1, 0_000000010);
 | 
			
		||||
TEST_pos(1, 0_000000010000000000000000000000000);
 | 
			
		||||
TEST_pos(9, 0_00000009);
 | 
			
		||||
TEST_pos(9, 0_000000090);
 | 
			
		||||
TEST_pos(9, 0_000000090000000000000000000000000);
 | 
			
		||||
 | 
			
		||||
TEST_pos(           100000000,            1);
 | 
			
		||||
TEST_pos(       6553500000000,        65535);
 | 
			
		||||
TEST_pos(  429496729500000000,   4294967295);
 | 
			
		||||
TEST_pos(18446744073700000000, 184467440737_);
 | 
			
		||||
TEST_pos(18446744073700000000, 184467440737_0);
 | 
			
		||||
TEST_pos(18446744073700000000, 184467440737_00000000);
 | 
			
		||||
TEST_pos(18446744073700000000, 184467440737_000000000);
 | 
			
		||||
TEST_pos(18446744073700000000, 184467440737_0000000000000000000);
 | 
			
		||||
TEST_pos(18446744073709551615, 184467440737_09551615);
 | 
			
		||||
 | 
			
		||||
// Invalid numbers
 | 
			
		||||
TEST_neg_n(~, empty_string);
 | 
			
		||||
TEST_neg_n(-0, minus_0);
 | 
			
		||||
TEST_neg_n(+0, plus_0);
 | 
			
		||||
TEST_neg_n(-1, minus_1);
 | 
			
		||||
TEST_neg_n(+1, plus_1);
 | 
			
		||||
TEST_neg_n(_, only_point);
 | 
			
		||||
 | 
			
		||||
// A lot of fraction digits
 | 
			
		||||
TEST_neg(0_000000001);
 | 
			
		||||
TEST_neg(0_000000009);
 | 
			
		||||
TEST_neg(184467440737_000000001);
 | 
			
		||||
 | 
			
		||||
// Overflow
 | 
			
		||||
TEST_neg(184467440737_09551616);
 | 
			
		||||
TEST_neg(184467440738);
 | 
			
		||||
TEST_neg(18446744073709551616);
 | 
			
		||||
 | 
			
		||||
// Two or more points
 | 
			
		||||
TEST_neg(__);
 | 
			
		||||
TEST_neg(0__);
 | 
			
		||||
TEST_neg(__0);
 | 
			
		||||
TEST_neg(0__0);
 | 
			
		||||
TEST_neg(0_0_);
 | 
			
		||||
TEST_neg(_0_0);
 | 
			
		||||
TEST_neg(0_0_0);
 | 
			
		||||
| 
						 | 
				
			
			@ -7,30 +7,28 @@
 | 
			
		|||
#include "common/util.h"
 | 
			
		||||
#include "cryptonote_core/cryptonote_format_utils.h"
 | 
			
		||||
 | 
			
		||||
TEST(parse_and_validate_tx_extra, is_correct_parse_and_validate_tx_extra) 
 | 
			
		||||
TEST(parse_and_validate_tx_extra, is_correct_parse_and_validate_tx_extra)
 | 
			
		||||
{
 | 
			
		||||
  cryptonote::transaction tx = AUTO_VAL_INIT(tx);
 | 
			
		||||
  cryptonote::account_base acc;
 | 
			
		||||
  acc.generate();
 | 
			
		||||
  std::vector<size_t> bss;
 | 
			
		||||
  cryptonote::blobdata b = "dsdsdfsdfsf";
 | 
			
		||||
  bool r = cryptonote::construct_miner_tx(0, 10000000000000, acc.get_keys().m_account_address, tx, DEFAULT_FEE, bss, 1000, b, 1);
 | 
			
		||||
  bool r = cryptonote::construct_miner_tx(0, 0, 10000000000000, 1000, DEFAULT_FEE, acc.get_keys().m_account_address, tx, b, 1);
 | 
			
		||||
  ASSERT_TRUE(r);
 | 
			
		||||
  crypto::public_key tx_pub_key;
 | 
			
		||||
  r = cryptonote::parse_and_validate_tx_extra(tx, tx_pub_key);
 | 
			
		||||
  ASSERT_TRUE(r);
 | 
			
		||||
}
 | 
			
		||||
TEST(parse_and_validate_tx_extra, is_correct_extranonce_too_big) 
 | 
			
		||||
TEST(parse_and_validate_tx_extra, is_correct_extranonce_too_big)
 | 
			
		||||
{
 | 
			
		||||
  cryptonote::transaction tx = AUTO_VAL_INIT(tx);
 | 
			
		||||
  cryptonote::account_base acc;
 | 
			
		||||
  acc.generate();
 | 
			
		||||
  std::vector<size_t> bss;
 | 
			
		||||
  cryptonote::blobdata b(260, 0);
 | 
			
		||||
  bool r = cryptonote::construct_miner_tx(0, 10000000000000, acc.get_keys().m_account_address, tx, DEFAULT_FEE, bss, 1000, b, 1);
 | 
			
		||||
  bool r = cryptonote::construct_miner_tx(0, 0, 10000000000000, 1000, DEFAULT_FEE, acc.get_keys().m_account_address, tx, b, 1);
 | 
			
		||||
  ASSERT_FALSE(r);
 | 
			
		||||
}
 | 
			
		||||
TEST(parse_and_validate_tx_extra, is_correct_wrong_extra_couner_too_big) 
 | 
			
		||||
TEST(parse_and_validate_tx_extra, is_correct_wrong_extra_couner_too_big)
 | 
			
		||||
{
 | 
			
		||||
  cryptonote::transaction tx = AUTO_VAL_INIT(tx);
 | 
			
		||||
  tx.extra.resize(20, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +73,7 @@ TEST(validate_parse_amount_case, validate_parse_amount)
 | 
			
		|||
  r = cryptonote::parse_amount(res, "   100.0001    ");
 | 
			
		||||
  ASSERT_TRUE(r);
 | 
			
		||||
  ASSERT_EQ(res, 10000010000);
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  r = cryptonote::parse_amount(res, "   100.0000    ");
 | 
			
		||||
  ASSERT_TRUE(r);
 | 
			
		||||
  ASSERT_EQ(res, 10000000000);
 | 
			
		||||
| 
						 | 
				
			
			@ -88,10 +86,10 @@ TEST(validate_parse_amount_case, validate_parse_amount)
 | 
			
		|||
 | 
			
		||||
  r = cryptonote::parse_amount(res, "100 . 0000");
 | 
			
		||||
  ASSERT_FALSE(r);
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  r = cryptonote::parse_amount(res, "100.00 00");
 | 
			
		||||
  ASSERT_FALSE(r);
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  r = cryptonote::parse_amount(res, "1 00.00 00");
 | 
			
		||||
  ASSERT_FALSE(r);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue