mirror of
				https://git.wownero.com/wownero/wownero.git
				synced 2024-08-15 01:03:23 +00:00 
			
		
		
		
	wallet2: check wallet compatibility with daemon's hard fork version
This commit is contained in:
		
							parent
							
								
									af4f97bf66
								
							
						
					
					
						commit
						864a78ee5f
					
				
					 15 changed files with 251 additions and 30 deletions
				
			
		| 
						 | 
					@ -231,6 +231,11 @@ namespace cryptonote
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    uint64_t get_window_size() const { return window_size; }
 | 
					    uint64_t get_window_size() const { return window_size; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief returns info for all known hard forks
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    const std::vector<hardfork_t>& get_hardforks() const { return heights; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private:
 | 
					  private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t get_block_version(uint64_t height) const;
 | 
					    uint8_t get_block_version(uint64_t height) const;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -899,6 +899,13 @@ namespace cryptonote
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    uint64_t get_earliest_ideal_height_for_version(uint8_t version) const { return m_hardfork->get_earliest_ideal_height_for_version(version); }
 | 
					    uint64_t get_earliest_ideal_height_for_version(uint8_t version) const { return m_hardfork->get_earliest_ideal_height_for_version(version); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief returns info for all known hard forks
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return the hardforks
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    const std::vector<hardfork_t>& get_hardforks() const { return m_hardfork->get_hardforks(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * @brief get information about hardfork voting for a version
 | 
					     * @brief get information about hardfork voting for a version
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2861,6 +2861,10 @@ namespace cryptonote
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    res.version = CORE_RPC_VERSION;
 | 
					    res.version = CORE_RPC_VERSION;
 | 
				
			||||||
    res.release = MONERO_VERSION_IS_RELEASE;
 | 
					    res.release = MONERO_VERSION_IS_RELEASE;
 | 
				
			||||||
 | 
					    res.current_height = m_core.get_current_blockchain_height();
 | 
				
			||||||
 | 
					    res.target_height = m_p2p.get_payload_object().is_synchronized() ? 0 : m_core.get_target_blockchain_height();
 | 
				
			||||||
 | 
					    for (const auto &hf : m_core.get_blockchain_storage().get_hardforks())
 | 
				
			||||||
 | 
					       res.hard_forks.push_back({hf.version, hf.height});
 | 
				
			||||||
    res.status = CORE_RPC_STATUS_OK;
 | 
					    res.status = CORE_RPC_STATUS_OK;
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -88,7 +88,7 @@ namespace cryptonote
 | 
				
			||||||
// advance which version they will stop working with
 | 
					// advance which version they will stop working with
 | 
				
			||||||
// Don't go over 32767 for any of these
 | 
					// Don't go over 32767 for any of these
 | 
				
			||||||
#define CORE_RPC_VERSION_MAJOR 3
 | 
					#define CORE_RPC_VERSION_MAJOR 3
 | 
				
			||||||
#define CORE_RPC_VERSION_MINOR 10
 | 
					#define CORE_RPC_VERSION_MINOR 11
 | 
				
			||||||
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
 | 
					#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
 | 
				
			||||||
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
 | 
					#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2123,15 +2123,34 @@ namespace cryptonote
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    typedef epee::misc_utils::struct_init<request_t> request;
 | 
					    typedef epee::misc_utils::struct_init<request_t> request;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct hf_entry
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      uint8_t hf_version;
 | 
				
			||||||
 | 
					      uint64_t height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      bool operator==(const hf_entry& hfe) const { return hf_version == hfe.hf_version && height == hfe.height; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      BEGIN_KV_SERIALIZE_MAP()
 | 
				
			||||||
 | 
					        KV_SERIALIZE(hf_version)
 | 
				
			||||||
 | 
					        KV_SERIALIZE(height)
 | 
				
			||||||
 | 
					      END_KV_SERIALIZE_MAP()
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct response_t: public rpc_response_base
 | 
					    struct response_t: public rpc_response_base
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      uint32_t version;
 | 
					      uint32_t version;
 | 
				
			||||||
      bool release;
 | 
					      bool release;
 | 
				
			||||||
 | 
					      uint64_t current_height;
 | 
				
			||||||
 | 
					      uint64_t target_height;
 | 
				
			||||||
 | 
					      std::vector<hf_entry> hard_forks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      BEGIN_KV_SERIALIZE_MAP()
 | 
					      BEGIN_KV_SERIALIZE_MAP()
 | 
				
			||||||
        KV_SERIALIZE_PARENT(rpc_response_base)
 | 
					        KV_SERIALIZE_PARENT(rpc_response_base)
 | 
				
			||||||
        KV_SERIALIZE(version)
 | 
					        KV_SERIALIZE(version)
 | 
				
			||||||
        KV_SERIALIZE(release)
 | 
					        KV_SERIALIZE(release)
 | 
				
			||||||
 | 
					        KV_SERIALIZE_OPT(current_height, (uint64_t)0)
 | 
				
			||||||
 | 
					        KV_SERIALIZE_OPT(target_height, (uint64_t)0)
 | 
				
			||||||
 | 
					        KV_SERIALIZE_OPT(hard_forks, std::vector<hf_entry>())
 | 
				
			||||||
      END_KV_SERIALIZE_MAP()
 | 
					      END_KV_SERIALIZE_MAP()
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    typedef epee::misc_utils::struct_init<response_t> response;
 | 
					    typedef epee::misc_utils::struct_init<response_t> response;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -181,7 +181,6 @@ namespace
 | 
				
			||||||
  const command_line::arg_descriptor<bool> arg_restore_from_seed = {"restore-from-seed", sw::tr("alias for --restore-deterministic-wallet"), false};
 | 
					  const command_line::arg_descriptor<bool> arg_restore_from_seed = {"restore-from-seed", sw::tr("alias for --restore-deterministic-wallet"), false};
 | 
				
			||||||
  const command_line::arg_descriptor<bool> arg_restore_multisig_wallet = {"restore-multisig-wallet", sw::tr("Recover multisig wallet using Electrum-style mnemonic seed"), false};
 | 
					  const command_line::arg_descriptor<bool> arg_restore_multisig_wallet = {"restore-multisig-wallet", sw::tr("Recover multisig wallet using Electrum-style mnemonic seed"), false};
 | 
				
			||||||
  const command_line::arg_descriptor<bool> arg_non_deterministic = {"non-deterministic", sw::tr("Generate non-deterministic view and spend keys"), false};
 | 
					  const command_line::arg_descriptor<bool> arg_non_deterministic = {"non-deterministic", sw::tr("Generate non-deterministic view and spend keys"), false};
 | 
				
			||||||
  const command_line::arg_descriptor<bool> arg_allow_mismatched_daemon_version = {"allow-mismatched-daemon-version", sw::tr("Allow communicating with a daemon that uses a different RPC version"), false};
 | 
					 | 
				
			||||||
  const command_line::arg_descriptor<uint64_t> arg_restore_height = {"restore-height", sw::tr("Restore from specific blockchain height"), 0};
 | 
					  const command_line::arg_descriptor<uint64_t> arg_restore_height = {"restore-height", sw::tr("Restore from specific blockchain height"), 0};
 | 
				
			||||||
  const command_line::arg_descriptor<std::string> arg_restore_date = {"restore-date", sw::tr("Restore from estimated blockchain height on specified date"), ""};
 | 
					  const command_line::arg_descriptor<std::string> arg_restore_date = {"restore-date", sw::tr("Restore from estimated blockchain height on specified date"), ""};
 | 
				
			||||||
  const command_line::arg_descriptor<bool> arg_do_not_relay = {"do-not-relay", sw::tr("The newly created transaction will not be relayed to the monero network"), false};
 | 
					  const command_line::arg_descriptor<bool> arg_do_not_relay = {"do-not-relay", sw::tr("The newly created transaction will not be relayed to the monero network"), false};
 | 
				
			||||||
| 
						 | 
					@ -3233,8 +3232,7 @@ bool simple_wallet::scan_tx(const std::vector<std::string> &args)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
simple_wallet::simple_wallet()
 | 
					simple_wallet::simple_wallet()
 | 
				
			||||||
  : m_allow_mismatched_daemon_version(false)
 | 
					  : m_refresh_progress_reporter(*this)
 | 
				
			||||||
  , m_refresh_progress_reporter(*this)
 | 
					 | 
				
			||||||
  , m_idle_run(true)
 | 
					  , m_idle_run(true)
 | 
				
			||||||
  , m_auto_refresh_enabled(false)
 | 
					  , m_auto_refresh_enabled(false)
 | 
				
			||||||
  , m_auto_refresh_refreshing(false)
 | 
					  , m_auto_refresh_refreshing(false)
 | 
				
			||||||
| 
						 | 
					@ -4755,7 +4753,6 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
 | 
				
			||||||
  m_restore_deterministic_wallet  = command_line::get_arg(vm, arg_restore_deterministic_wallet) || command_line::get_arg(vm, arg_restore_from_seed);
 | 
					  m_restore_deterministic_wallet  = command_line::get_arg(vm, arg_restore_deterministic_wallet) || command_line::get_arg(vm, arg_restore_from_seed);
 | 
				
			||||||
  m_restore_multisig_wallet       = command_line::get_arg(vm, arg_restore_multisig_wallet);
 | 
					  m_restore_multisig_wallet       = command_line::get_arg(vm, arg_restore_multisig_wallet);
 | 
				
			||||||
  m_non_deterministic             = command_line::get_arg(vm, arg_non_deterministic);
 | 
					  m_non_deterministic             = command_line::get_arg(vm, arg_non_deterministic);
 | 
				
			||||||
  m_allow_mismatched_daemon_version = command_line::get_arg(vm, arg_allow_mismatched_daemon_version);
 | 
					 | 
				
			||||||
  m_restore_height                = command_line::get_arg(vm, arg_restore_height);
 | 
					  m_restore_height                = command_line::get_arg(vm, arg_restore_height);
 | 
				
			||||||
  m_restore_date                  = command_line::get_arg(vm, arg_restore_date);
 | 
					  m_restore_date                  = command_line::get_arg(vm, arg_restore_date);
 | 
				
			||||||
  m_do_not_relay                  = command_line::get_arg(vm, arg_do_not_relay);
 | 
					  m_do_not_relay                  = command_line::get_arg(vm, arg_do_not_relay);
 | 
				
			||||||
| 
						 | 
					@ -4786,12 +4783,20 @@ bool simple_wallet::try_connect_to_daemon(bool silent, uint32_t* version)
 | 
				
			||||||
  uint32_t version_ = 0;
 | 
					  uint32_t version_ = 0;
 | 
				
			||||||
  if (!version)
 | 
					  if (!version)
 | 
				
			||||||
    version = &version_;
 | 
					    version = &version_;
 | 
				
			||||||
  if (!m_wallet->check_connection(version))
 | 
					  bool wallet_is_outdated, daemon_is_outdated = false;
 | 
				
			||||||
 | 
					  if (!m_wallet->check_connection(version, NULL, 200000, &wallet_is_outdated, &daemon_is_outdated))
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    if (!silent)
 | 
					    if (!silent)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      if (m_wallet->is_offline())
 | 
					      if (m_wallet->is_offline())
 | 
				
			||||||
        fail_msg_writer() << tr("wallet failed to connect to daemon, because it is set to offline mode");
 | 
					        fail_msg_writer() << tr("wallet failed to connect to daemon, because it is set to offline mode");
 | 
				
			||||||
 | 
					      else if (wallet_is_outdated)
 | 
				
			||||||
 | 
					        fail_msg_writer() << tr("wallet failed to connect to daemon, because it is not up to date. ") <<
 | 
				
			||||||
 | 
					          tr("Please make sure you are running the latest wallet.");
 | 
				
			||||||
 | 
					      else if (daemon_is_outdated)
 | 
				
			||||||
 | 
					        fail_msg_writer() << tr("wallet failed to connect to daemon: ") << m_wallet->get_daemon_address() << ". " <<
 | 
				
			||||||
 | 
					          tr("Daemon is not up to date. "
 | 
				
			||||||
 | 
					          "Please make sure the daemon is running the latest version or change the daemon address using the 'set_daemon' command.");
 | 
				
			||||||
      else
 | 
					      else
 | 
				
			||||||
        fail_msg_writer() << tr("wallet failed to connect to daemon: ") << m_wallet->get_daemon_address() << ". " <<
 | 
					        fail_msg_writer() << tr("wallet failed to connect to daemon: ") << m_wallet->get_daemon_address() << ". " <<
 | 
				
			||||||
          tr("Daemon either is not started or wrong port was passed. "
 | 
					          tr("Daemon either is not started or wrong port was passed. "
 | 
				
			||||||
| 
						 | 
					@ -4799,7 +4804,7 @@ bool simple_wallet::try_connect_to_daemon(bool silent, uint32_t* version)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (!m_allow_mismatched_daemon_version && ((*version >> 16) != CORE_RPC_VERSION_MAJOR))
 | 
					  if (!m_wallet->is_mismatched_daemon_version_allowed() && ((*version >> 16) != CORE_RPC_VERSION_MAJOR))
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    if (!silent)
 | 
					    if (!silent)
 | 
				
			||||||
      fail_msg_writer() << boost::format(tr("Daemon uses a different RPC major version (%u) than the wallet (%u): %s. Either update one of them, or use --allow-mismatched-daemon-version.")) % (*version>>16) % CORE_RPC_VERSION_MAJOR % m_wallet->get_daemon_address();
 | 
					      fail_msg_writer() << boost::format(tr("Daemon uses a different RPC major version (%u) than the wallet (%u): %s. Either update one of them, or use --allow-mismatched-daemon-version.")) % (*version>>16) % CORE_RPC_VERSION_MAJOR % m_wallet->get_daemon_address();
 | 
				
			||||||
| 
						 | 
					@ -10629,7 +10634,6 @@ int main(int argc, char* argv[])
 | 
				
			||||||
  command_line::add_arg(desc_params, arg_restore_multisig_wallet );
 | 
					  command_line::add_arg(desc_params, arg_restore_multisig_wallet );
 | 
				
			||||||
  command_line::add_arg(desc_params, arg_non_deterministic );
 | 
					  command_line::add_arg(desc_params, arg_non_deterministic );
 | 
				
			||||||
  command_line::add_arg(desc_params, arg_electrum_seed );
 | 
					  command_line::add_arg(desc_params, arg_electrum_seed );
 | 
				
			||||||
  command_line::add_arg(desc_params, arg_allow_mismatched_daemon_version);
 | 
					 | 
				
			||||||
  command_line::add_arg(desc_params, arg_restore_height);
 | 
					  command_line::add_arg(desc_params, arg_restore_height);
 | 
				
			||||||
  command_line::add_arg(desc_params, arg_restore_date);
 | 
					  command_line::add_arg(desc_params, arg_restore_date);
 | 
				
			||||||
  command_line::add_arg(desc_params, arg_do_not_relay);
 | 
					  command_line::add_arg(desc_params, arg_do_not_relay);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -429,7 +429,6 @@ namespace cryptonote
 | 
				
			||||||
    bool m_restore_deterministic_wallet;  // recover flag
 | 
					    bool m_restore_deterministic_wallet;  // recover flag
 | 
				
			||||||
    bool m_restore_multisig_wallet;  // recover flag
 | 
					    bool m_restore_multisig_wallet;  // recover flag
 | 
				
			||||||
    bool m_non_deterministic;  // old 2-random generation
 | 
					    bool m_non_deterministic;  // old 2-random generation
 | 
				
			||||||
    bool m_allow_mismatched_daemon_version;
 | 
					 | 
				
			||||||
    bool m_restoring;           // are we restoring, by whatever method?
 | 
					    bool m_restoring;           // are we restoring, by whatever method?
 | 
				
			||||||
    uint64_t m_restore_height;  // optional
 | 
					    uint64_t m_restore_height;  // optional
 | 
				
			||||||
    bool m_do_not_relay;
 | 
					    bool m_do_not_relay;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2173,9 +2173,15 @@ bool WalletImpl::connectToDaemon()
 | 
				
			||||||
Wallet::ConnectionStatus WalletImpl::connected() const
 | 
					Wallet::ConnectionStatus WalletImpl::connected() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uint32_t version = 0;
 | 
					    uint32_t version = 0;
 | 
				
			||||||
    m_is_connected = m_wallet->check_connection(&version, NULL, DEFAULT_CONNECTION_TIMEOUT_MILLIS);
 | 
					    bool wallet_is_outdated, daemon_is_outdated = false;
 | 
				
			||||||
 | 
					    m_is_connected = m_wallet->check_connection(&version, NULL, DEFAULT_CONNECTION_TIMEOUT_MILLIS, &wallet_is_outdated, &daemon_is_outdated);
 | 
				
			||||||
    if (!m_is_connected)
 | 
					    if (!m_is_connected)
 | 
				
			||||||
        return Wallet::ConnectionStatus_Disconnected;
 | 
					    {
 | 
				
			||||||
 | 
					        if (!m_wallet->light_wallet() && (wallet_is_outdated || daemon_is_outdated))
 | 
				
			||||||
 | 
					            return Wallet::ConnectionStatus_WrongVersion;
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            return Wallet::ConnectionStatus_Disconnected;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    // Version check is not implemented in light wallets nodes/wallets
 | 
					    // Version check is not implemented in light wallets nodes/wallets
 | 
				
			||||||
    if (!m_wallet->light_wallet() && (version >> 16) != CORE_RPC_VERSION_MAJOR)
 | 
					    if (!m_wallet->light_wallet() && (version >> 16) != CORE_RPC_VERSION_MAJOR)
 | 
				
			||||||
        return Wallet::ConnectionStatus_WrongVersion;
 | 
					        return Wallet::ConnectionStatus_WrongVersion;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -82,18 +82,21 @@ void NodeRPCProxy::invalidate()
 | 
				
			||||||
  m_rpc_payment_seed_hash = crypto::null_hash;
 | 
					  m_rpc_payment_seed_hash = crypto::null_hash;
 | 
				
			||||||
  m_rpc_payment_next_seed_hash = crypto::null_hash;
 | 
					  m_rpc_payment_next_seed_hash = crypto::null_hash;
 | 
				
			||||||
  m_height_time = 0;
 | 
					  m_height_time = 0;
 | 
				
			||||||
 | 
					  m_target_height_time = 0;
 | 
				
			||||||
  m_rpc_payment_diff = 0;
 | 
					  m_rpc_payment_diff = 0;
 | 
				
			||||||
  m_rpc_payment_credits_per_hash_found = 0;
 | 
					  m_rpc_payment_credits_per_hash_found = 0;
 | 
				
			||||||
  m_rpc_payment_height = 0;
 | 
					  m_rpc_payment_height = 0;
 | 
				
			||||||
  m_rpc_payment_cookie = 0;
 | 
					  m_rpc_payment_cookie = 0;
 | 
				
			||||||
 | 
					  m_daemon_hard_forks.clear();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version)
 | 
					boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version, std::vector<std::pair<uint8_t, uint64_t>> &daemon_hard_forks, uint64_t &height, uint64_t &target_height)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if (m_offline)
 | 
					  if (m_offline)
 | 
				
			||||||
    return boost::optional<std::string>("offline");
 | 
					    return boost::optional<std::string>("offline");
 | 
				
			||||||
  if (m_rpc_version == 0)
 | 
					  if (m_rpc_version == 0)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
 | 
					    const time_t now = time(NULL);
 | 
				
			||||||
    cryptonote::COMMAND_RPC_GET_VERSION::request req_t = AUTO_VAL_INIT(req_t);
 | 
					    cryptonote::COMMAND_RPC_GET_VERSION::request req_t = AUTO_VAL_INIT(req_t);
 | 
				
			||||||
    cryptonote::COMMAND_RPC_GET_VERSION::response resp_t = AUTO_VAL_INIT(resp_t);
 | 
					    cryptonote::COMMAND_RPC_GET_VERSION::response resp_t = AUTO_VAL_INIT(resp_t);
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
| 
						 | 
					@ -101,9 +104,28 @@ boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version
 | 
				
			||||||
      bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_version", req_t, resp_t, m_http_client, rpc_timeout);
 | 
					      bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_version", req_t, resp_t, m_http_client, rpc_timeout);
 | 
				
			||||||
      RETURN_ON_RPC_RESPONSE_ERROR(r, epee::json_rpc::error{}, resp_t, "get_version");
 | 
					      RETURN_ON_RPC_RESPONSE_ERROR(r, epee::json_rpc::error{}, resp_t, "get_version");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    m_rpc_version = resp_t.version;
 | 
					    m_rpc_version = resp_t.version;
 | 
				
			||||||
 | 
					    m_daemon_hard_forks.clear();
 | 
				
			||||||
 | 
					    for (const auto &hf : resp_t.hard_forks)
 | 
				
			||||||
 | 
					      m_daemon_hard_forks.push_back(std::make_pair(hf.hf_version, hf.height));
 | 
				
			||||||
 | 
					    if (resp_t.current_height > 0 || resp_t.target_height > 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      m_height = resp_t.current_height;
 | 
				
			||||||
 | 
					      m_target_height = resp_t.target_height;
 | 
				
			||||||
 | 
					      m_height_time = now;
 | 
				
			||||||
 | 
					      m_target_height_time = now;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  rpc_version = m_rpc_version;
 | 
					  rpc_version = m_rpc_version;
 | 
				
			||||||
 | 
					  daemon_hard_forks = m_daemon_hard_forks;
 | 
				
			||||||
 | 
					  boost::optional<std::string> result = get_height(height);
 | 
				
			||||||
 | 
					  if (result)
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					  result = get_target_height(target_height);
 | 
				
			||||||
 | 
					  if (result)
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
  return boost::optional<std::string>();
 | 
					  return boost::optional<std::string>();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -138,6 +160,7 @@ boost::optional<std::string> NodeRPCProxy::get_info()
 | 
				
			||||||
    m_adjusted_time = resp_t.adjusted_time;
 | 
					    m_adjusted_time = resp_t.adjusted_time;
 | 
				
			||||||
    m_get_info_time = now;
 | 
					    m_get_info_time = now;
 | 
				
			||||||
    m_height_time = now;
 | 
					    m_height_time = now;
 | 
				
			||||||
 | 
					    m_target_height_time = now;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return boost::optional<std::string>();
 | 
					  return boost::optional<std::string>();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -160,6 +183,13 @@ boost::optional<std::string> NodeRPCProxy::get_height(uint64_t &height)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
boost::optional<std::string> NodeRPCProxy::get_target_height(uint64_t &height)
 | 
					boost::optional<std::string> NodeRPCProxy::get_target_height(uint64_t &height)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					  const time_t now = time(NULL);
 | 
				
			||||||
 | 
					  if (now < m_target_height_time + 30) // re-cache every 30 seconds
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    height = m_target_height;
 | 
				
			||||||
 | 
					    return boost::optional<std::string>();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  auto res = get_info();
 | 
					  auto res = get_info();
 | 
				
			||||||
  if (res)
 | 
					  if (res)
 | 
				
			||||||
    return res;
 | 
					    return res;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,7 +48,7 @@ public:
 | 
				
			||||||
  void invalidate();
 | 
					  void invalidate();
 | 
				
			||||||
  void set_offline(bool offline) { m_offline = offline; }
 | 
					  void set_offline(bool offline) { m_offline = offline; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  boost::optional<std::string> get_rpc_version(uint32_t &version);
 | 
					  boost::optional<std::string> get_rpc_version(uint32_t &rpc_version, std::vector<std::pair<uint8_t, uint64_t>> &daemon_hard_forks, uint64_t &height, uint64_t &target_height);
 | 
				
			||||||
  boost::optional<std::string> get_height(uint64_t &height);
 | 
					  boost::optional<std::string> get_height(uint64_t &height);
 | 
				
			||||||
  void set_height(uint64_t h);
 | 
					  void set_height(uint64_t h);
 | 
				
			||||||
  boost::optional<std::string> get_target_height(uint64_t &height);
 | 
					  boost::optional<std::string> get_target_height(uint64_t &height);
 | 
				
			||||||
| 
						 | 
					@ -103,6 +103,8 @@ private:
 | 
				
			||||||
  crypto::hash m_rpc_payment_next_seed_hash;
 | 
					  crypto::hash m_rpc_payment_next_seed_hash;
 | 
				
			||||||
  uint32_t m_rpc_payment_cookie;
 | 
					  uint32_t m_rpc_payment_cookie;
 | 
				
			||||||
  time_t m_height_time;
 | 
					  time_t m_height_time;
 | 
				
			||||||
 | 
					  time_t m_target_height_time;
 | 
				
			||||||
 | 
					  std::vector<std::pair<uint8_t, uint64_t>> m_daemon_hard_forks;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,6 +47,7 @@
 | 
				
			||||||
using namespace epee;
 | 
					using namespace epee;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "cryptonote_config.h"
 | 
					#include "cryptonote_config.h"
 | 
				
			||||||
 | 
					#include "hardforks/hardforks.h"
 | 
				
			||||||
#include "cryptonote_core/tx_sanity_check.h"
 | 
					#include "cryptonote_core/tx_sanity_check.h"
 | 
				
			||||||
#include "wallet_rpc_helpers.h"
 | 
					#include "wallet_rpc_helpers.h"
 | 
				
			||||||
#include "wallet2.h"
 | 
					#include "wallet2.h"
 | 
				
			||||||
| 
						 | 
					@ -275,6 +276,7 @@ struct options {
 | 
				
			||||||
  const command_line::arg_descriptor<bool> no_dns = {"no-dns", tools::wallet2::tr("Do not use DNS"), false};
 | 
					  const command_line::arg_descriptor<bool> no_dns = {"no-dns", tools::wallet2::tr("Do not use DNS"), false};
 | 
				
			||||||
  const command_line::arg_descriptor<bool> offline = {"offline", tools::wallet2::tr("Do not connect to a daemon, nor use DNS"), false};
 | 
					  const command_line::arg_descriptor<bool> offline = {"offline", tools::wallet2::tr("Do not connect to a daemon, nor use DNS"), false};
 | 
				
			||||||
  const command_line::arg_descriptor<std::string> extra_entropy = {"extra-entropy", tools::wallet2::tr("File containing extra entropy to initialize the PRNG (any data, aim for 256 bits of entropy to be useful, which typically means more than 256 bits of data)")};
 | 
					  const command_line::arg_descriptor<std::string> extra_entropy = {"extra-entropy", tools::wallet2::tr("File containing extra entropy to initialize the PRNG (any data, aim for 256 bits of entropy to be useful, which typically means more than 256 bits of data)")};
 | 
				
			||||||
 | 
					  const command_line::arg_descriptor<bool> allow_mismatched_daemon_version = {"allow-mismatched-daemon-version", tools::wallet2::tr("Allow communicating with a daemon that uses a different version"), false};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file, std::string &mms_file)
 | 
					void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file, std::string &mms_file)
 | 
				
			||||||
| 
						 | 
					@ -484,6 +486,9 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
 | 
				
			||||||
    add_extra_entropy_thread_safe(data.data(), data.size());
 | 
					    add_extra_entropy_thread_safe(data.data(), data.size());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (command_line::has_arg(vm, opts.allow_mismatched_daemon_version))
 | 
				
			||||||
 | 
					    wallet->allow_mismatched_daemon_version(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  try
 | 
					  try
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    if (!command_line::is_arg_defaulted(vm, opts.tx_notify))
 | 
					    if (!command_line::is_arg_defaulted(vm, opts.tx_notify))
 | 
				
			||||||
| 
						 | 
					@ -1219,7 +1224,8 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended, std
 | 
				
			||||||
  m_load_deprecated_formats(false),
 | 
					  m_load_deprecated_formats(false),
 | 
				
			||||||
  m_credits_target(0),
 | 
					  m_credits_target(0),
 | 
				
			||||||
  m_enable_multisig(false),
 | 
					  m_enable_multisig(false),
 | 
				
			||||||
  m_has_ever_refreshed_from_node(false)
 | 
					  m_has_ever_refreshed_from_node(false),
 | 
				
			||||||
 | 
					  m_allow_mismatched_daemon_version(false)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  set_rpc_client_secret_key(rct::rct2sk(rct::skGen()));
 | 
					  set_rpc_client_secret_key(rct::rct2sk(rct::skGen()));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1279,6 +1285,7 @@ void wallet2::init_options(boost::program_options::options_description& desc_par
 | 
				
			||||||
  command_line::add_arg(desc_params, opts.no_dns);
 | 
					  command_line::add_arg(desc_params, opts.no_dns);
 | 
				
			||||||
  command_line::add_arg(desc_params, opts.offline);
 | 
					  command_line::add_arg(desc_params, opts.offline);
 | 
				
			||||||
  command_line::add_arg(desc_params, opts.extra_entropy);
 | 
					  command_line::add_arg(desc_params, opts.extra_entropy);
 | 
				
			||||||
 | 
					  command_line::add_arg(desc_params, opts.allow_mismatched_daemon_version);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::pair<std::unique_ptr<wallet2>, tools::password_container> wallet2::make_from_json(const boost::program_options::variables_map& vm, bool unattended, const std::string& json_file, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter)
 | 
					std::pair<std::unique_ptr<wallet2>, tools::password_container> wallet2::make_from_json(const boost::program_options::variables_map& vm, bool unattended, const std::string& json_file, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter)
 | 
				
			||||||
| 
						 | 
					@ -2915,6 +2922,26 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
 | 
				
			||||||
  refresh(trusted_daemon, start_height, blocks_fetched, received_money);
 | 
					  refresh(trusted_daemon, start_height, blocks_fetched, received_money);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
//----------------------------------------------------------------------------------------------------
 | 
					//----------------------------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					void check_block_hard_fork_version(cryptonote::network_type nettype, uint8_t hf_version, uint64_t height, bool &wallet_is_outdated, bool &daemon_is_outdated)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  const size_t wallet_num_hard_forks = nettype == TESTNET ? num_testnet_hard_forks
 | 
				
			||||||
 | 
					    : nettype == STAGENET ? num_stagenet_hard_forks : num_mainnet_hard_forks;
 | 
				
			||||||
 | 
					  const hardfork_t *wallet_hard_forks = nettype == TESTNET ? testnet_hard_forks
 | 
				
			||||||
 | 
					    : nettype == STAGENET ? stagenet_hard_forks : mainnet_hard_forks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  wallet_is_outdated = static_cast<size_t>(hf_version) > wallet_num_hard_forks;
 | 
				
			||||||
 | 
					  if (wallet_is_outdated)
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // check block's height falls within wallet's expected range for block's given version
 | 
				
			||||||
 | 
					  uint64_t start_height = hf_version == 1 ? 0 : wallet_hard_forks[hf_version - 1].height;
 | 
				
			||||||
 | 
					  uint64_t end_height = static_cast<size_t>(hf_version) + 1 > wallet_num_hard_forks
 | 
				
			||||||
 | 
					    ? std::numeric_limits<uint64_t>::max()
 | 
				
			||||||
 | 
					    : wallet_hard_forks[hf_version].height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  daemon_is_outdated = height < start_height || height >= end_height;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					//----------------------------------------------------------------------------------------------------
 | 
				
			||||||
void wallet2::pull_and_parse_next_blocks(uint64_t start_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, const std::vector<cryptonote::block_complete_entry> &prev_blocks, const std::vector<parsed_block> &prev_parsed_blocks, std::vector<cryptonote::block_complete_entry> &blocks, std::vector<parsed_block> &parsed_blocks, bool &last, bool &error, std::exception_ptr &exception)
 | 
					void wallet2::pull_and_parse_next_blocks(uint64_t start_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, const std::vector<cryptonote::block_complete_entry> &prev_blocks, const std::vector<parsed_block> &prev_parsed_blocks, std::vector<cryptonote::block_complete_entry> &blocks, std::vector<parsed_block> &parsed_blocks, bool &last, bool &error, std::exception_ptr &exception)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  error = false;
 | 
					  error = false;
 | 
				
			||||||
| 
						 | 
					@ -2956,6 +2983,23 @@ void wallet2::pull_and_parse_next_blocks(uint64_t start_height, uint64_t &blocks
 | 
				
			||||||
        error = true;
 | 
					        error = true;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!m_allow_mismatched_daemon_version)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        // make sure block's hard fork version is expected at the block's height
 | 
				
			||||||
 | 
					        uint8_t hf_version = parsed_blocks[i].block.major_version;
 | 
				
			||||||
 | 
					        uint64_t height = blocks_start_height + i;
 | 
				
			||||||
 | 
					        bool wallet_is_outdated = false;
 | 
				
			||||||
 | 
					        bool daemon_is_outdated = false;
 | 
				
			||||||
 | 
					        check_block_hard_fork_version(m_nettype, hf_version, height, wallet_is_outdated, daemon_is_outdated);
 | 
				
			||||||
 | 
					        THROW_WALLET_EXCEPTION_IF(wallet_is_outdated || daemon_is_outdated, error::incorrect_fork_version,
 | 
				
			||||||
 | 
					          "Unexpected hard fork version v" + std::to_string(hf_version) + " at height " + std::to_string(height) + ". " +
 | 
				
			||||||
 | 
					          (wallet_is_outdated
 | 
				
			||||||
 | 
					            ? "Make sure your wallet is up to date"
 | 
				
			||||||
 | 
					            : "Make sure the node you are connected to is running the latest version")
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      parsed_blocks[i].o_indices = std::move(o_indices[i]);
 | 
					      parsed_blocks[i].o_indices = std::move(o_indices[i]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3574,6 +3618,11 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
 | 
				
			||||||
      THROW_WALLET_EXCEPTION_IF(!waiter.wait(), error::wallet_internal_error, "Exception in thread pool");
 | 
					      THROW_WALLET_EXCEPTION_IF(!waiter.wait(), error::wallet_internal_error, "Exception in thread pool");
 | 
				
			||||||
      throw;
 | 
					      throw;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    catch (const error::incorrect_fork_version&)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      THROW_WALLET_EXCEPTION_IF(!waiter.wait(), error::wallet_internal_error, "Exception in thread pool");
 | 
				
			||||||
 | 
					      throw;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    catch (const std::exception&)
 | 
					    catch (const std::exception&)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      blocks_fetched += added_blocks;
 | 
					      blocks_fetched += added_blocks;
 | 
				
			||||||
| 
						 | 
					@ -4184,6 +4233,7 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st
 | 
				
			||||||
    m_auto_mine_for_rpc_payment_threshold = -1.0f;
 | 
					    m_auto_mine_for_rpc_payment_threshold = -1.0f;
 | 
				
			||||||
    m_credits_target = 0;
 | 
					    m_credits_target = 0;
 | 
				
			||||||
    m_enable_multisig = false;
 | 
					    m_enable_multisig = false;
 | 
				
			||||||
 | 
					    m_allow_mismatched_daemon_version = false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  else if(json.IsObject())
 | 
					  else if(json.IsObject())
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
| 
						 | 
					@ -5327,7 +5377,7 @@ bool wallet2::prepare_file_names(const std::string& file_path)
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
//----------------------------------------------------------------------------------------------------
 | 
					//----------------------------------------------------------------------------------------------------
 | 
				
			||||||
bool wallet2::check_connection(uint32_t *version, bool *ssl, uint32_t timeout)
 | 
					bool wallet2::check_connection(uint32_t *version, bool *ssl, uint32_t timeout, bool *wallet_is_outdated, bool *daemon_is_outdated)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  THROW_WALLET_EXCEPTION_IF(!m_is_initialized, error::wallet_not_initialized);
 | 
					  THROW_WALLET_EXCEPTION_IF(!m_is_initialized, error::wallet_not_initialized);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5364,24 +5414,103 @@ bool wallet2::check_connection(uint32_t *version, bool *ssl, uint32_t timeout)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!m_rpc_version)
 | 
					  if (!m_rpc_version && !check_version(version, wallet_is_outdated, daemon_is_outdated))
 | 
				
			||||||
  {
 | 
					    return false;
 | 
				
			||||||
    cryptonote::COMMAND_RPC_GET_VERSION::request req_t = AUTO_VAL_INIT(req_t);
 | 
					 | 
				
			||||||
    cryptonote::COMMAND_RPC_GET_VERSION::response resp_t = AUTO_VAL_INIT(resp_t);
 | 
					 | 
				
			||||||
    bool r = invoke_http_json_rpc("/json_rpc", "get_version", req_t, resp_t);
 | 
					 | 
				
			||||||
    if(!r || resp_t.status != CORE_RPC_STATUS_OK) {
 | 
					 | 
				
			||||||
      if(version)
 | 
					 | 
				
			||||||
        *version = 0;
 | 
					 | 
				
			||||||
      return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    m_rpc_version = resp_t.version;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (version)
 | 
					  if (version)
 | 
				
			||||||
    *version = m_rpc_version;
 | 
					    *version = m_rpc_version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
//----------------------------------------------------------------------------------------------------
 | 
					//----------------------------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					bool wallet2::check_version(uint32_t *version, bool *wallet_is_outdated, bool *daemon_is_outdated)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  uint32_t rpc_version;
 | 
				
			||||||
 | 
					  std::vector<std::pair<uint8_t, uint64_t>> daemon_hard_forks;
 | 
				
			||||||
 | 
					  uint64_t height;
 | 
				
			||||||
 | 
					  uint64_t target_height;
 | 
				
			||||||
 | 
					  if (m_node_rpc_proxy.get_rpc_version(rpc_version, daemon_hard_forks, height, target_height))
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    if(version)
 | 
				
			||||||
 | 
					      *version = 0;
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // check wallet compatibility with daemon's hard fork version
 | 
				
			||||||
 | 
					  if (!m_allow_mismatched_daemon_version)
 | 
				
			||||||
 | 
					    if (!check_hard_fork_version(m_nettype, daemon_hard_forks, height, target_height, wallet_is_outdated, daemon_is_outdated))
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  m_rpc_version = rpc_version;
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					//----------------------------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					bool wallet2::check_hard_fork_version(cryptonote::network_type nettype, const std::vector<std::pair<uint8_t, uint64_t>> &daemon_hard_forks, const uint64_t height, const uint64_t target_height, bool *wallet_is_outdated, bool *daemon_is_outdated)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  const size_t wallet_num_hard_forks = nettype == TESTNET ? num_testnet_hard_forks
 | 
				
			||||||
 | 
					    : nettype == STAGENET ? num_stagenet_hard_forks : num_mainnet_hard_forks;
 | 
				
			||||||
 | 
					  const hardfork_t *wallet_hard_forks = nettype == TESTNET ? testnet_hard_forks
 | 
				
			||||||
 | 
					    : nettype == STAGENET ? stagenet_hard_forks : mainnet_hard_forks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // First check if wallet or daemon is outdated (whether either are unaware of
 | 
				
			||||||
 | 
					  // a hard fork). Then check if fork has passed rendering versions incompatible
 | 
				
			||||||
 | 
					  if (daemon_hard_forks.size() > 0)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    bool daemon_outdated = daemon_hard_forks.size() < wallet_num_hard_forks;
 | 
				
			||||||
 | 
					    bool wallet_outdated = daemon_hard_forks.size() > wallet_num_hard_forks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (daemon_is_outdated)
 | 
				
			||||||
 | 
					      *daemon_is_outdated = daemon_outdated;
 | 
				
			||||||
 | 
					    if (wallet_is_outdated)
 | 
				
			||||||
 | 
					      *wallet_is_outdated = wallet_outdated;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (daemon_outdated)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      uint64_t daemon_missed_fork_height = wallet_hard_forks[daemon_hard_forks.size()].height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // If the daemon missed the fork, then technically it is no longer part of
 | 
				
			||||||
 | 
					      // the Monero network. Don't connect.
 | 
				
			||||||
 | 
					      bool daemon_missed_fork = height >= daemon_missed_fork_height || target_height >= daemon_missed_fork_height;
 | 
				
			||||||
 | 
					      if (daemon_missed_fork)
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (wallet_outdated)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      uint64_t wallet_missed_fork_height = daemon_hard_forks[wallet_num_hard_forks].second;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // If the wallet missed the fork, then technically it is no longer able
 | 
				
			||||||
 | 
					      // to communicate with the Monero network. Don't connect.
 | 
				
			||||||
 | 
					      bool wallet_missed_fork = height >= wallet_missed_fork_height || target_height >= wallet_missed_fork_height;
 | 
				
			||||||
 | 
					      if (wallet_missed_fork)
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    // Non-updated daemons won't return daemon_hard_forks in response to
 | 
				
			||||||
 | 
					    // get_version. Fall back to extra call to get_hard_fork_info by version.
 | 
				
			||||||
 | 
					    uint64_t daemon_fork_height;
 | 
				
			||||||
 | 
					    get_hard_fork_info(wallet_num_hard_forks-1/* wallet expects "double fork" pattern */, daemon_fork_height);
 | 
				
			||||||
 | 
					    bool daemon_outdated = daemon_fork_height == std::numeric_limits<uint64_t>::max();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (daemon_is_outdated)
 | 
				
			||||||
 | 
					      *daemon_is_outdated = daemon_outdated;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (daemon_outdated)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      uint64_t daemon_missed_fork_height = wallet_hard_forks[wallet_num_hard_forks-2].height;
 | 
				
			||||||
 | 
					      bool daemon_missed_fork = height >= daemon_missed_fork_height || target_height >= daemon_missed_fork_height;
 | 
				
			||||||
 | 
					      if (daemon_missed_fork)
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Don't need to check if wallet is outdated here because the daemons updated
 | 
				
			||||||
 | 
					    // for a future hard fork will serve daemon_hard_forks above. The check for
 | 
				
			||||||
 | 
					    // an outdated wallet is done above using daemon_hard_forks.
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					//----------------------------------------------------------------------------------------------------
 | 
				
			||||||
void wallet2::set_offline(bool offline)
 | 
					void wallet2::set_offline(bool offline)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  m_offline = offline;
 | 
					  m_offline = offline;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1091,7 +1091,9 @@ private:
 | 
				
			||||||
    bool sign_multisig_tx_to_file(multisig_tx_set &exported_txs, const std::string &filename, std::vector<crypto::hash> &txids);
 | 
					    bool sign_multisig_tx_to_file(multisig_tx_set &exported_txs, const std::string &filename, std::vector<crypto::hash> &txids);
 | 
				
			||||||
    std::vector<pending_tx> create_unmixable_sweep_transactions();
 | 
					    std::vector<pending_tx> create_unmixable_sweep_transactions();
 | 
				
			||||||
    void discard_unmixable_outputs();
 | 
					    void discard_unmixable_outputs();
 | 
				
			||||||
    bool check_connection(uint32_t *version = NULL, bool *ssl = NULL, uint32_t timeout = 200000);
 | 
					    bool check_connection(uint32_t *version = NULL, bool *ssl = NULL, uint32_t timeout = 200000, bool *wallet_is_outdated = NULL, bool *daemon_is_outdated = NULL);
 | 
				
			||||||
 | 
					    bool check_version(uint32_t *version, bool *wallet_is_outdated, bool *daemon_is_outdated);
 | 
				
			||||||
 | 
					    bool check_hard_fork_version(cryptonote::network_type nettype, const std::vector<std::pair<uint8_t, uint64_t>> &daemon_hard_forks, const uint64_t height, const uint64_t target_height, bool *wallet_is_outdated, bool *daemon_is_outdated);
 | 
				
			||||||
    void get_transfers(wallet2::transfer_container& incoming_transfers) const;
 | 
					    void get_transfers(wallet2::transfer_container& incoming_transfers) const;
 | 
				
			||||||
    void get_payments(const crypto::hash& payment_id, std::list<wallet2::payment_details>& payments, uint64_t min_height = 0, const boost::optional<uint32_t>& subaddr_account = boost::none, const std::set<uint32_t>& subaddr_indices = {}) const;
 | 
					    void get_payments(const crypto::hash& payment_id, std::list<wallet2::payment_details>& payments, uint64_t min_height = 0, const boost::optional<uint32_t>& subaddr_account = boost::none, const std::set<uint32_t>& subaddr_indices = {}) const;
 | 
				
			||||||
    void get_payments(std::list<std::pair<crypto::hash,wallet2::payment_details>>& payments, uint64_t min_height, uint64_t max_height = (uint64_t)-1, const boost::optional<uint32_t>& subaddr_account = boost::none, const std::set<uint32_t>& subaddr_indices = {}) const;
 | 
					    void get_payments(std::list<std::pair<crypto::hash,wallet2::payment_details>>& payments, uint64_t min_height, uint64_t max_height = (uint64_t)-1, const boost::optional<uint32_t>& subaddr_account = boost::none, const std::set<uint32_t>& subaddr_indices = {}) const;
 | 
				
			||||||
| 
						 | 
					@ -1358,6 +1360,8 @@ private:
 | 
				
			||||||
    void credits_target(uint64_t threshold) { m_credits_target = threshold; }
 | 
					    void credits_target(uint64_t threshold) { m_credits_target = threshold; }
 | 
				
			||||||
    bool is_multisig_enabled() const { return m_enable_multisig; }
 | 
					    bool is_multisig_enabled() const { return m_enable_multisig; }
 | 
				
			||||||
    void enable_multisig(bool enable) { m_enable_multisig = enable; }
 | 
					    void enable_multisig(bool enable) { m_enable_multisig = enable; }
 | 
				
			||||||
 | 
					    bool is_mismatched_daemon_version_allowed() const { return m_allow_mismatched_daemon_version; }
 | 
				
			||||||
 | 
					    void allow_mismatched_daemon_version(bool allow_mismatch) { m_allow_mismatched_daemon_version = allow_mismatch; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool get_tx_key_cached(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys) const;
 | 
					    bool get_tx_key_cached(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys) const;
 | 
				
			||||||
    void set_tx_key(const crypto::hash &txid, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, const boost::optional<cryptonote::account_public_address> &single_destination_subaddress = boost::none);
 | 
					    void set_tx_key(const crypto::hash &txid, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, const boost::optional<cryptonote::account_public_address> &single_destination_subaddress = boost::none);
 | 
				
			||||||
| 
						 | 
					@ -1875,6 +1879,7 @@ private:
 | 
				
			||||||
    rpc_payment_state_t m_rpc_payment_state;
 | 
					    rpc_payment_state_t m_rpc_payment_state;
 | 
				
			||||||
    uint64_t m_credits_target;
 | 
					    uint64_t m_credits_target;
 | 
				
			||||||
    bool m_enable_multisig;
 | 
					    bool m_enable_multisig;
 | 
				
			||||||
 | 
					    bool m_allow_mismatched_daemon_version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Aux transaction data from device
 | 
					    // Aux transaction data from device
 | 
				
			||||||
    serializable_unordered_map<crypto::hash, std::string> m_tx_device;
 | 
					    serializable_unordered_map<crypto::hash, std::string> m_tx_device;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -439,6 +439,16 @@ namespace tools
 | 
				
			||||||
      std::string to_string() const { return refresh_error::to_string(); }
 | 
					      std::string to_string() const { return refresh_error::to_string(); }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    //----------------------------------------------------------------------------------------------------
 | 
					    //----------------------------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					    struct incorrect_fork_version : public refresh_error
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      explicit incorrect_fork_version(std::string&& loc, const std::string& message)
 | 
				
			||||||
 | 
					        : refresh_error(std::move(loc), message)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      std::string to_string() const { return refresh_error::to_string(); }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    //----------------------------------------------------------------------------------------------------
 | 
				
			||||||
    struct signature_check_failed : public wallet_logic_error
 | 
					    struct signature_check_failed : public wallet_logic_error
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      explicit signature_check_failed(std::string&& loc, const std::string& message)
 | 
					      explicit signature_check_failed(std::string&& loc, const std::string& message)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,7 +55,7 @@ monerod_extra = [
 | 
				
			||||||
  ["--add-exclusive-node", "127.0.0.1:18283"],
 | 
					  ["--add-exclusive-node", "127.0.0.1:18283"],
 | 
				
			||||||
  ["--add-exclusive-node", "127.0.0.1:18282"],
 | 
					  ["--add-exclusive-node", "127.0.0.1:18282"],
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
wallet_base = [builddir + "/bin/monero-wallet-rpc", "--wallet-dir", WALLET_DIRECTORY, "--rpc-bind-port", "wallet_port", "--disable-rpc-login", "--rpc-ssl", "disabled", "--daemon-ssl", "disabled", "--log-level", "1"]
 | 
					wallet_base = [builddir + "/bin/monero-wallet-rpc", "--wallet-dir", WALLET_DIRECTORY, "--rpc-bind-port", "wallet_port", "--disable-rpc-login", "--rpc-ssl", "disabled", "--daemon-ssl", "disabled", "--log-level", "1", "--allow-mismatched-daemon-version"]
 | 
				
			||||||
wallet_extra = [
 | 
					wallet_extra = [
 | 
				
			||||||
  ["--daemon-port", "18180"],
 | 
					  ["--daemon-port", "18180"],
 | 
				
			||||||
  ["--daemon-port", "18180"],
 | 
					  ["--daemon-port", "18180"],
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,6 +30,7 @@ complete -c monero-wallet-cli -l tx-notify -r -d "Run a program for each new inc
 | 
				
			||||||
complete -c monero-wallet-cli -l no-dns -d "Do not use DNS"
 | 
					complete -c monero-wallet-cli -l no-dns -d "Do not use DNS"
 | 
				
			||||||
complete -c monero-wallet-cli -l offline -d "Do not connect to a daemon, nor use DNS"
 | 
					complete -c monero-wallet-cli -l offline -d "Do not connect to a daemon, nor use DNS"
 | 
				
			||||||
complete -c monero-wallet-cli -l extra-entropy -r -F -d "File containing extra entropy to initialize the PRNG (any data, aim for 256 bits of entropy to be useful, which typically means more than 256 bits of data)"
 | 
					complete -c monero-wallet-cli -l extra-entropy -r -F -d "File containing extra entropy to initialize the PRNG (any data, aim for 256 bits of entropy to be useful, which typically means more than 256 bits of data)"
 | 
				
			||||||
 | 
					complete -c monero-wallet-cli -l allow-mismatched-daemon-version -d "Allow communicating with a daemon that uses a different version"
 | 
				
			||||||
complete -c monero-wallet-cli -l wallet-file -r -F -d "Use wallet <arg>"
 | 
					complete -c monero-wallet-cli -l wallet-file -r -F -d "Use wallet <arg>"
 | 
				
			||||||
complete -c monero-wallet-cli -l generate-new-wallet -r -F -d "Generate new wallet and save it to <arg>"
 | 
					complete -c monero-wallet-cli -l generate-new-wallet -r -F -d "Generate new wallet and save it to <arg>"
 | 
				
			||||||
complete -c monero-wallet-cli -l generate-from-device -r -F -d "Generate new wallet from device and save it to <arg>"
 | 
					complete -c monero-wallet-cli -l generate-from-device -r -F -d "Generate new wallet from device and save it to <arg>"
 | 
				
			||||||
| 
						 | 
					@ -45,7 +46,6 @@ complete -c monero-wallet-cli -l restore-from-seed -d "alias for --restore-deter
 | 
				
			||||||
complete -c monero-wallet-cli -l restore-multisig-wallet -d "Recover multisig wallet using Electrum-style mnemonic seed"
 | 
					complete -c monero-wallet-cli -l restore-multisig-wallet -d "Recover multisig wallet using Electrum-style mnemonic seed"
 | 
				
			||||||
complete -c monero-wallet-cli -l non-deterministic -d "Generate non-deterministic view and spend keys"
 | 
					complete -c monero-wallet-cli -l non-deterministic -d "Generate non-deterministic view and spend keys"
 | 
				
			||||||
complete -c monero-wallet-cli -l electrum-seed -r -d "Specify Electrum seed for wallet recovery/creation"
 | 
					complete -c monero-wallet-cli -l electrum-seed -r -d "Specify Electrum seed for wallet recovery/creation"
 | 
				
			||||||
complete -c monero-wallet-cli -l allow-mismatched-daemon-version -d "Allow communicating with a daemon that uses a different RPC version"
 | 
					 | 
				
			||||||
complete -c monero-wallet-cli -l restore-height -r -d "Restore from specific blockchain height. Default: 0"
 | 
					complete -c monero-wallet-cli -l restore-height -r -d "Restore from specific blockchain height. Default: 0"
 | 
				
			||||||
complete -c monero-wallet-cli -l restore-date -r -d "Restore from estimated blockchain height on specified date"
 | 
					complete -c monero-wallet-cli -l restore-date -r -d "Restore from estimated blockchain height on specified date"
 | 
				
			||||||
complete -c monero-wallet-cli -l do-not-relay -d "The newly created transaction will not be relayed to the monero network"
 | 
					complete -c monero-wallet-cli -l do-not-relay -d "The newly created transaction will not be relayed to the monero network"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,6 +30,7 @@ complete -c monero-wallet-rpc -l tx-notify -r -d "Run a program for each new inc
 | 
				
			||||||
complete -c monero-wallet-rpc -l no-dns -d "Do not use DNS"
 | 
					complete -c monero-wallet-rpc -l no-dns -d "Do not use DNS"
 | 
				
			||||||
complete -c monero-wallet-rpc -l offline -d "Do not connect to a daemon, nor use DNS"
 | 
					complete -c monero-wallet-rpc -l offline -d "Do not connect to a daemon, nor use DNS"
 | 
				
			||||||
complete -c monero-wallet-rpc -l extra-entropy -r -F -d "File containing extra entropy to initialize the PRNG (any data, aim for 256 bits of entropy to be useful, which typically means more than 256 bits of data)"
 | 
					complete -c monero-wallet-rpc -l extra-entropy -r -F -d "File containing extra entropy to initialize the PRNG (any data, aim for 256 bits of entropy to be useful, which typically means more than 256 bits of data)"
 | 
				
			||||||
 | 
					complete -c monero-wallet-cli -l allow-mismatched-daemon-version -d "Allow communicating with a daemon that uses a different version"
 | 
				
			||||||
complete -c monero-wallet-rpc -l rpc-bind-port -r -d "Sets bind port for server"
 | 
					complete -c monero-wallet-rpc -l rpc-bind-port -r -d "Sets bind port for server"
 | 
				
			||||||
complete -c monero-wallet-rpc -l disable-rpc-login -d "Disable HTTP authentication for RPC connections served by this process"
 | 
					complete -c monero-wallet-rpc -l disable-rpc-login -d "Disable HTTP authentication for RPC connections served by this process"
 | 
				
			||||||
complete -c monero-wallet-rpc -l restricted-rpc -d "Restricts to view-only commands"
 | 
					complete -c monero-wallet-rpc -l restricted-rpc -d "Restricts to view-only commands"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue