Merge pull request #1569
16b8b66a
specify restore height by YYYY-MM-DD format (kenshi84)
This commit is contained in:
commit
ab69d5b367
|
@ -190,6 +190,36 @@ namespace cryptonote
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
bool core_rpc_server::on_get_blocks_by_height(const COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::response& res)
|
||||||
|
{
|
||||||
|
CHECK_CORE_BUSY();
|
||||||
|
res.status = "Failed";
|
||||||
|
res.blocks.clear();
|
||||||
|
res.blocks.reserve(req.heights.size());
|
||||||
|
for (uint64_t height : req.heights)
|
||||||
|
{
|
||||||
|
block blk;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
blk = m_core.get_blockchain_storage().get_db().get_block_from_height(height);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
res.status = "Error retrieving block at height " + height;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
std::list<transaction> txs;
|
||||||
|
std::list<crypto::hash> missed_txs;
|
||||||
|
m_core.get_transactions(blk.tx_hashes, txs, missed_txs);
|
||||||
|
res.blocks.resize(res.blocks.size() + 1);
|
||||||
|
res.blocks.back().block = block_to_blob(blk);
|
||||||
|
for (auto& tx : txs)
|
||||||
|
res.blocks.back().txs.push_back(tx_to_blob(tx));
|
||||||
|
}
|
||||||
|
res.status = CORE_RPC_STATUS_OK;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
bool core_rpc_server::on_get_hashes(const COMMAND_RPC_GET_HASHES_FAST::request& req, COMMAND_RPC_GET_HASHES_FAST::response& res)
|
bool core_rpc_server::on_get_hashes(const COMMAND_RPC_GET_HASHES_FAST::request& req, COMMAND_RPC_GET_HASHES_FAST::response& res)
|
||||||
{
|
{
|
||||||
CHECK_CORE_BUSY();
|
CHECK_CORE_BUSY();
|
||||||
|
|
|
@ -76,6 +76,7 @@ namespace cryptonote
|
||||||
BEGIN_URI_MAP2()
|
BEGIN_URI_MAP2()
|
||||||
MAP_URI_AUTO_JON2("/getheight", on_get_height, COMMAND_RPC_GET_HEIGHT)
|
MAP_URI_AUTO_JON2("/getheight", on_get_height, COMMAND_RPC_GET_HEIGHT)
|
||||||
MAP_URI_AUTO_BIN2("/getblocks.bin", on_get_blocks, COMMAND_RPC_GET_BLOCKS_FAST)
|
MAP_URI_AUTO_BIN2("/getblocks.bin", on_get_blocks, COMMAND_RPC_GET_BLOCKS_FAST)
|
||||||
|
MAP_URI_AUTO_BIN2("/getblocks_by_height.bin", on_get_blocks_by_height, COMMAND_RPC_GET_BLOCKS_BY_HEIGHT)
|
||||||
MAP_URI_AUTO_BIN2("/gethashes.bin", on_get_hashes, COMMAND_RPC_GET_HASHES_FAST)
|
MAP_URI_AUTO_BIN2("/gethashes.bin", on_get_hashes, COMMAND_RPC_GET_HASHES_FAST)
|
||||||
MAP_URI_AUTO_BIN2("/get_o_indexes.bin", on_get_indexes, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES)
|
MAP_URI_AUTO_BIN2("/get_o_indexes.bin", on_get_indexes, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES)
|
||||||
MAP_URI_AUTO_BIN2("/getrandom_outs.bin", on_get_random_outs, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS)
|
MAP_URI_AUTO_BIN2("/getrandom_outs.bin", on_get_random_outs, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS)
|
||||||
|
@ -125,6 +126,7 @@ namespace cryptonote
|
||||||
|
|
||||||
bool on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res);
|
bool on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res);
|
||||||
bool on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res);
|
bool on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res);
|
||||||
|
bool on_get_blocks_by_height(const COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::response& res);
|
||||||
bool on_get_hashes(const COMMAND_RPC_GET_HASHES_FAST::request& req, COMMAND_RPC_GET_HASHES_FAST::response& res);
|
bool on_get_hashes(const COMMAND_RPC_GET_HASHES_FAST::request& req, COMMAND_RPC_GET_HASHES_FAST::response& res);
|
||||||
bool on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res);
|
bool on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res);
|
||||||
bool on_is_key_image_spent(const COMMAND_RPC_IS_KEY_IMAGE_SPENT::request& req, COMMAND_RPC_IS_KEY_IMAGE_SPENT::response& res);
|
bool on_is_key_image_spent(const COMMAND_RPC_IS_KEY_IMAGE_SPENT::request& req, COMMAND_RPC_IS_KEY_IMAGE_SPENT::response& res);
|
||||||
|
|
|
@ -49,7 +49,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 1
|
#define CORE_RPC_VERSION_MAJOR 1
|
||||||
#define CORE_RPC_VERSION_MINOR 5
|
#define CORE_RPC_VERSION_MINOR 6
|
||||||
#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)
|
||||||
|
|
||||||
|
@ -122,6 +122,28 @@ namespace cryptonote
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct COMMAND_RPC_GET_BLOCKS_BY_HEIGHT
|
||||||
|
{
|
||||||
|
struct request
|
||||||
|
{
|
||||||
|
std::vector<uint64_t> heights;
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE(heights)
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
struct response
|
||||||
|
{
|
||||||
|
std::vector<block_complete_entry> blocks;
|
||||||
|
std::string status;
|
||||||
|
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE(blocks)
|
||||||
|
KV_SERIALIZE(status)
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
struct COMMAND_RPC_GET_HASHES_FAST
|
struct COMMAND_RPC_GET_HASHES_FAST
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -939,22 +939,6 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!m_restore_height && m_restoring)
|
|
||||||
{
|
|
||||||
std::string heightstr = command_line::input_line("Restore from specific blockchain height (optional, default 0): ");
|
|
||||||
if (std::cin.eof())
|
|
||||||
return false;
|
|
||||||
if (heightstr.size())
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
m_restore_height = boost::lexical_cast<uint64_t>(heightstr);
|
|
||||||
}
|
|
||||||
catch (boost::bad_lexical_cast &) {
|
|
||||||
fail_msg_writer() << tr("bad m_restore_height parameter:") << " " << heightstr;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!m_generate_from_view_key.empty())
|
if (!m_generate_from_view_key.empty())
|
||||||
{
|
{
|
||||||
m_wallet_file = m_generate_from_view_key;
|
m_wallet_file = m_generate_from_view_key;
|
||||||
|
@ -1095,6 +1079,70 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
|
||||||
bool r = new_wallet(vm, m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic, old_language);
|
bool r = new_wallet(vm, m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic, old_language);
|
||||||
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
|
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
|
||||||
}
|
}
|
||||||
|
if (!m_restore_height && m_restoring)
|
||||||
|
{
|
||||||
|
uint32_t version;
|
||||||
|
bool connected = try_connect_to_daemon(false, &version);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
std::string heightstr;
|
||||||
|
if (!connected || version < MAKE_CORE_RPC_VERSION(1, 6))
|
||||||
|
heightstr = command_line::input_line("Restore from specific blockchain height (optional, default 0): ");
|
||||||
|
else
|
||||||
|
heightstr = command_line::input_line("Restore from specific blockchain height (optional, default 0),\nor alternatively from specific date (YYYY-MM-DD): ");
|
||||||
|
if (std::cin.eof())
|
||||||
|
return false;
|
||||||
|
if (heightstr.empty())
|
||||||
|
{
|
||||||
|
m_restore_height = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_restore_height = boost::lexical_cast<uint64_t>(heightstr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (const boost::bad_lexical_cast &)
|
||||||
|
{
|
||||||
|
if (!connected || version < MAKE_CORE_RPC_VERSION(1, 6))
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("bad m_restore_height parameter: ") << heightstr;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (heightstr.size() != 10 || heightstr[4] != '-' || heightstr[7] != '-')
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("date format must be YYYY-MM-DD");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
uint16_t year;
|
||||||
|
uint8_t month; // 1, 2, ..., 12
|
||||||
|
uint8_t day; // 1, 2, ..., 31
|
||||||
|
try
|
||||||
|
{
|
||||||
|
year = boost::lexical_cast<uint16_t>(heightstr.substr(0,4));
|
||||||
|
// lexical_cast<uint8_t> won't work becasue uint8_t is treated as character type
|
||||||
|
month = boost::lexical_cast<uint16_t>(heightstr.substr(5,2));
|
||||||
|
day = boost::lexical_cast<uint16_t>(heightstr.substr(8,2));
|
||||||
|
m_restore_height = m_wallet->get_blockchain_height_by_date(year, month, day);
|
||||||
|
success_msg_writer() << tr("Restore height is: ") << m_restore_height;
|
||||||
|
std::string confirm = command_line::input_line(tr("Is this okay? (Y/Yes/N/No): "));
|
||||||
|
if (std::cin.eof())
|
||||||
|
return false;
|
||||||
|
if(command_line::is_yes(confirm))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (const boost::bad_lexical_cast &)
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("bad m_restore_height parameter: ") << heightstr;
|
||||||
|
}
|
||||||
|
catch (const std::runtime_error& e)
|
||||||
|
{
|
||||||
|
fail_msg_writer() << e.what();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_wallet->set_refresh_from_block_height(m_restore_height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -5333,6 +5333,92 @@ bool wallet2::parse_uri(const std::string &uri, std::string &address, std::strin
|
||||||
return true;
|
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) {
|
void wallet2::generate_genesis(cryptonote::block& b) {
|
||||||
if (m_testnet)
|
if (m_testnet)
|
||||||
{
|
{
|
||||||
|
|
|
@ -558,6 +558,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);
|
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);
|
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:
|
private:
|
||||||
/*!
|
/*!
|
||||||
* \brief Stores wallet information to wallet file.
|
* \brief Stores wallet information to wallet file.
|
||||||
|
|
Loading…
Reference in New Issue