aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
authorkenshi84 <kenshi84@protonmail.ch>2016-12-25 17:18:15 +0900
committerkenshi84 <kenshi84@protonmail.ch>2017-01-16 10:00:28 +0900
commit16b8b66adcad57983b099fdf3ac1b52519390bc6 (patch)
tree5da228ea1d398d68e9ba0fc3172b748356ed07ec /src/wallet
parentMerge pull request #1578 (diff)
downloadmonero-16b8b66adcad57983b099fdf3ac1b52519390bc6.tar.xz
specify restore height by YYYY-MM-DD format
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/wallet2.cpp86
-rw-r--r--src/wallet/wallet2.h2
2 files changed, 88 insertions, 0 deletions
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 8a03b94af..7a83b883a 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -5330,6 +5330,92 @@ bool wallet2::parse_uri(const std::string &uri, std::string &address, std::strin
return true;
}
//----------------------------------------------------------------------------------------------------
+uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day)
+{
+ uint32_t version;
+ if (!check_connection(&version))
+ {
+ throw std::runtime_error("failed to connect to daemon: " + get_daemon_address());
+ }
+ if (version < MAKE_CORE_RPC_VERSION(1, 6))
+ {
+ throw std::runtime_error("this function requires RPC version 1.6 or higher");
+ }
+ std::tm date = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ date.tm_year = year - 1900;
+ date.tm_mon = month - 1;
+ date.tm_mday = day;
+ if (date.tm_mon < 0 || 11 < date.tm_mon || date.tm_mday < 1 || 31 < date.tm_mday)
+ {
+ throw std::runtime_error("month or day out of range");
+ }
+ uint64_t timestamp_target = std::mktime(&date);
+ std::string err;
+ uint64_t height_min = 0;
+ uint64_t height_max = get_daemon_blockchain_height(err) - 1;
+ if (!err.empty())
+ {
+ throw std::runtime_error("failed to get blockchain height");
+ }
+ while (true)
+ {
+ COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::request req;
+ COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::response res;
+ uint64_t height_mid = (height_min + height_max) / 2;
+ req.heights =
+ {
+ height_min,
+ height_mid,
+ height_max
+ };
+ bool r = net_utils::invoke_http_bin_remote_command2(get_daemon_address() + "/getblocks_by_height.bin", req, res, m_http_client);
+ if (!r || res.status != CORE_RPC_STATUS_OK)
+ {
+ std::ostringstream oss;
+ oss << "failed to get blocks by heights: ";
+ for (auto height : req.heights)
+ oss << height << ' ';
+ oss << endl << "reason: ";
+ if (!r)
+ oss << "possibly lost connection to daemon";
+ else if (res.status == CORE_RPC_STATUS_BUSY)
+ oss << "daemon is busy";
+ else
+ oss << res.status;
+ throw std::runtime_error(oss.str());
+ }
+ cryptonote::block blk_min, blk_mid, blk_max;
+ if (!parse_and_validate_block_from_blob(res.blocks[0].block, blk_min)) throw std::runtime_error("failed to parse blob at height " + height_min);
+ if (!parse_and_validate_block_from_blob(res.blocks[1].block, blk_mid)) throw std::runtime_error("failed to parse blob at height " + height_mid);
+ if (!parse_and_validate_block_from_blob(res.blocks[2].block, blk_max)) throw std::runtime_error("failed to parse blob at height " + height_max);
+ uint64_t timestamp_min = blk_min.timestamp;
+ uint64_t timestamp_mid = blk_mid.timestamp;
+ uint64_t timestamp_max = blk_max.timestamp;
+ if (!(timestamp_min <= timestamp_mid && timestamp_mid <= timestamp_max))
+ {
+ // the timestamps are not in the chronological order.
+ // assuming they're sufficiently close to each other, simply return the smallest height
+ return std::min({height_min, height_mid, height_max});
+ }
+ if (timestamp_target > timestamp_max)
+ {
+ throw std::runtime_error("specified date is in the future");
+ }
+ if (timestamp_target <= timestamp_min + 2 * 24 * 60 * 60) // two days of "buffer" period
+ {
+ return height_min;
+ }
+ if (timestamp_target <= timestamp_mid)
+ height_max = height_mid;
+ else
+ height_min = height_mid;
+ if (height_max - height_min <= 2 * 24 * 30) // don't divide the height range finer than two days
+ {
+ return height_min;
+ }
+ }
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::generate_genesis(cryptonote::block& b) {
if (m_testnet)
{
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 5a569950f..21692d7b4 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -554,6 +554,8 @@ namespace tools
std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error);
bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector<std::string> &unknown_parameters, std::string &error);
+ uint64_t get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day); // 1<=month<=12, 1<=day<=31
+
private:
/*!
* \brief Stores wallet information to wallet file.