Merge branch 'develop' into ui_develop

This commit is contained in:
cryptozoidberg 2020-12-01 18:01:13 +01:00
commit 60d6c44fb9
No known key found for this signature in database
GPG key ID: 22DEB97A54C6FDEC
28 changed files with 607 additions and 91 deletions

View file

@ -189,6 +189,13 @@ if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
set(Boost_LIBRARY_DIRS "/Users/roky/projects/Zano/mobile_repo/ofxiOSBoost/libs/boost/ios/")
set(Boost_LIBRARIES "libboost.a")
set(Boost_VERSION "ofxiOSBoost 1.60.0")
#workaround for new XCode 12 policy for builds(now it includes a slice for the "arm64" when builds for simulator)
set(__iphoneos_archs "armv7 armv7s arm64")
set(__iphonesimulator_archs "i386 x86_64")
set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "${__iphoneos_archs}")
set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "${__iphoneos_archs}")
set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "${__iphonesimulator_archs}")
set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "${__iphonesimulator_archs}")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Android")
set(Boost_INCLUDE_DIRS "/Users/roky/projects/Zano/mobile_repo/Boost-for-Android-Prebuilt/1.69.0/include")
set(Boost_LIBRARY_DIRS "/Users/roky/projects/Zano/mobile_repo/Boost-for-Android-Prebuilt/1.69.0/libs/llvm/${CMAKE_ANDROID_ARCH_ABI}/")

View file

@ -188,7 +188,7 @@ namespace tools
std::list<currency::block> blocks;
std::list<currency::transaction> txs;
bool r = source_core.get_blocks(i, 1, blocks, txs);
CHECK_AND_ASSERT_MES(r && blocks.size()==1, false, "Filed to get block " << i << " from core");
CHECK_AND_ASSERT_MES(r && blocks.size()==1, false, "Failed to get block " << i << " from core");
currency::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
crypto::hash tx_hash = AUTO_VAL_INIT(tx_hash);
for (auto& tx : txs)

View file

@ -60,18 +60,42 @@ namespace currency
return m_keys;
}
//-----------------------------------------------------------------
std::string account_base::get_seed_phrase() const
void crypt_with_pass(const void* scr_data, std::size_t src_length, void* dst_data, const std::string& password)
{
crypto::chacha8_key key = AUTO_VAL_INIT(key);
crypto::generate_chacha8_key(password, key);
crypto::hash pass_hash = crypto::cn_fast_hash(password.data(), password.size());
crypto::chacha8_iv iv = AUTO_VAL_INIT(iv);
CHECK_AND_ASSERT_THROW_MES(sizeof(pass_hash) >= sizeof(iv), "Invalid configuration: hash size is less than keys_file_data.iv");
iv = *((crypto::chacha8_iv*)&pass_hash);
crypto::chacha8(scr_data, src_length, key, iv, (char*)dst_data);
}
std::string account_base::get_seed_phrase(const std::string& password) const
{
if (m_keys_seed_binary.empty())
return "";
std::string keys_seed_text = tools::mnemonic_encoding::binary2text(m_keys_seed_binary);
std::string timestamp_word = currency::get_word_from_timstamp(m_creation_timestamp);
std::vector<unsigned char> processed_seed_binary = m_keys_seed_binary;
if (!password.empty())
{
//encrypt seed phrase binary data
crypt_with_pass(&m_keys_seed_binary[0], m_keys_seed_binary.size(), &processed_seed_binary[0], password);
}
std::string keys_seed_text = tools::mnemonic_encoding::binary2text(processed_seed_binary);
std::string timestamp_word = currency::get_word_from_timstamp(m_creation_timestamp, !password.empty());
// floor creation time to WALLET_BRAIN_DATE_QUANTUM to make checksum calculation stable
uint64_t creation_timestamp_rounded = get_timstamp_from_word(timestamp_word);
bool self_check_is_password_used = false;
uint64_t creation_timestamp_rounded = get_timstamp_from_word(timestamp_word, self_check_is_password_used);
CHECK_AND_ASSERT_THROW_MES(self_check_is_password_used == !password.empty(), "Account seed phrase internal error: password flag encoded wrong");
constexpr uint16_t checksum_max = tools::mnemonic_encoding::NUMWORDS >> 1; // maximum value of checksum
crypto::hash h = crypto::cn_fast_hash(m_keys_seed_binary.data(), m_keys_seed_binary.size());
std::string binary_for_check_sum((const char*)&m_keys_seed_binary[0], m_keys_seed_binary.size());
binary_for_check_sum.append(password);
crypto::hash h = crypto::cn_fast_hash(binary_for_check_sum.data(), binary_for_check_sum.size());
*reinterpret_cast<uint64_t*>(&h) = creation_timestamp_rounded;
h = crypto::cn_fast_hash(&h, sizeof h);
uint64_t h_64 = *reinterpret_cast<uint64_t*>(&h);
@ -104,7 +128,7 @@ namespace currency
return true;
}
//-----------------------------------------------------------------
bool account_base::restore_from_seed_phrase(const std::string& seed_phrase)
bool account_base::restore_from_seed_phrase(const std::string& seed_phrase, const std::string& seed_password)
{
//cut the last timestamp word from restore_dats
std::list<std::string> words;
@ -138,9 +162,20 @@ namespace currency
auditable_flag_and_checksum = tools::mnemonic_encoding::num_by_word(auditable_flag_and_checksum_word);
std::vector<unsigned char> keys_seed_binary = tools::mnemonic_encoding::text2binary(keys_seed_text);
CHECK_AND_ASSERT_MES(keys_seed_binary.size(), false, "text2binary failed to convert the given text"); // don't prints event incorrect seed into the log for security
std::vector<unsigned char> keys_seed_processed_binary = keys_seed_binary;
m_creation_timestamp = get_timstamp_from_word(timestamp_word);
bool has_password = false;
m_creation_timestamp = get_timstamp_from_word(timestamp_word, has_password);
//double check is password setting from timestamp word match with passed parameters
CHECK_AND_ASSERT_MES(has_password != seed_password.empty(), false, "Seed phrase password wrong interpretation");
if (has_password)
{
CHECK_AND_ASSERT_MES(!seed_password.empty(), false, "Seed phrase password wrong interpretation: internal error");
crypt_with_pass(&keys_seed_binary[0], keys_seed_binary.size(), &keys_seed_processed_binary[0], seed_password);
}
CHECK_AND_ASSERT_MES(keys_seed_processed_binary.size(), false, "text2binary failed to convert the given text"); // don't prints event incorrect seed into the log for security
bool auditable_flag = false;
@ -150,7 +185,9 @@ namespace currency
auditable_flag = (auditable_flag_and_checksum & 1) != 0; // auditable flag is the lower 1 bit
uint16_t checksum = static_cast<uint16_t>(auditable_flag_and_checksum >> 1); // checksum -- everything else
constexpr uint16_t checksum_max = tools::mnemonic_encoding::NUMWORDS >> 1; // maximum value of checksum
crypto::hash h = crypto::cn_fast_hash(keys_seed_binary.data(), keys_seed_binary.size());
std::string binary_for_check_sum((const char*)&keys_seed_processed_binary[0], keys_seed_processed_binary.size());
binary_for_check_sum.append(seed_password);
crypto::hash h = crypto::cn_fast_hash(binary_for_check_sum.data(), binary_for_check_sum.size());
*reinterpret_cast<uint64_t*>(&h) = m_creation_timestamp;
h = crypto::cn_fast_hash(&h, sizeof h);
uint64_t h_64 = *reinterpret_cast<uint64_t*>(&h);
@ -158,10 +195,10 @@ namespace currency
CHECK_AND_ASSERT_MES(checksum == checksum_calculated, false, "seed phase has invalid checksum: " << checksum_calculated << ", while " << checksum << " is expected, check your words");
}
bool r = restore_keys(keys_seed_binary);
bool r = restore_keys(keys_seed_processed_binary);
CHECK_AND_ASSERT_MES(r, false, "restore_keys failed");
m_keys_seed_binary = keys_seed_binary;
m_keys_seed_binary = keys_seed_processed_binary;
if (auditable_flag)
m_keys.account_address.flags |= ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE;
@ -169,6 +206,34 @@ namespace currency
return true;
}
//-----------------------------------------------------------------
bool account_base::is_seed_password_protected(const std::string& seed_phrase, bool& is_password_protected)
{
//cut the last timestamp word from restore_dats
std::list<std::string> words;
boost::split(words, seed_phrase, boost::is_space());
std::string timestamp_word;
if (words.size() == SEED_PHRASE_V1_WORDS_COUNT)
{
// 24 seed words + one timestamp word = 25 total
timestamp_word = words.back();
}
else if (words.size() == SEED_PHRASE_V2_WORDS_COUNT)
{
// 24 seed words + one timestamp word + one flags & checksum = 26 total
words.erase(--words.end());
timestamp_word = words.back();
}
else
{
return false;
}
get_timstamp_from_word(timestamp_word, is_password_protected);
return true;
}
//-----------------------------------------------------------------
bool account_base::restore_from_tracking_seed(const std::string& tracking_seed)
{
set_null();

View file

@ -53,9 +53,9 @@ namespace currency
const account_public_address& get_public_address() const { return m_keys.account_address; };
std::string get_public_address_str() const;
std::string get_seed_phrase() const;
std::string get_seed_phrase(const std::string& seed_password) const;
std::string get_tracking_seed() const;
bool restore_from_seed_phrase(const std::string& seed_phrase);
bool restore_from_seed_phrase(const std::string& seed_phrase, const std::string& seed_password);
bool restore_from_tracking_seed(const std::string& tracking_seed);
uint64_t get_createtime() const { return m_creation_timestamp; }
@ -65,6 +65,8 @@ namespace currency
bool store(const std::string& file_path);
void make_account_watch_only();
bool is_watch_only() const { return m_keys.spend_secret_key == currency::null_skey; }
bool is_auditable() const { return m_keys.account_address.is_auditable(); }
template <class t_archive>
inline void serialize(t_archive &a, const unsigned int /*ver*/)
@ -76,6 +78,7 @@ namespace currency
static std::string vector_of_chars_to_string(const std::vector<unsigned char>& v) { return std::string(v.begin(), v.end()); }
static std::vector<unsigned char> string_to_vector_of_chars(const std::string& v) { return std::vector<unsigned char>(v.begin(), v.end()); }
static bool is_seed_password_protected(const std::string& seed_phrase, bool& is_password_protected);
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(m_keys)

View file

@ -150,9 +150,10 @@
#define WALLET_FILE_MAX_KEYS_SIZE 10000 //
#define WALLET_BRAIN_DATE_OFFSET 1543622400
#define WALLET_BRAIN_DATE_QUANTUM 604800 //by last word we encode a number of week since launch of the project,
#define WALLET_BRAIN_DATE_QUANTUM 604800 //by last word we encode a number of week since launch of the project AND password flag,
//which let us to address tools::mnemonic_encoding::NUMWORDS weeks after project launch
//which is about 30 years
//which is about 15 years
#define WALLET_BRAIN_DATE_MAX_WEEKS_COUNT 800
#define OFFER_MAXIMUM_LIFE_TIME (60*60*24*30) // 30 days

View file

@ -1316,21 +1316,34 @@ namespace currency
return reward;
}
//---------------------------------------------------------------
std::string get_word_from_timstamp(uint64_t timestamp)
std::string get_word_from_timstamp(uint64_t timestamp, bool use_password)
{
uint64_t date_offset = timestamp > WALLET_BRAIN_DATE_OFFSET ? timestamp - WALLET_BRAIN_DATE_OFFSET : 0;
uint64_t weeks_count = date_offset / WALLET_BRAIN_DATE_QUANTUM;
CHECK_AND_ASSERT_THROW_MES(weeks_count < WALLET_BRAIN_DATE_MAX_WEEKS_COUNT, "SEED PHRASE need to be extended or refactored");
if (use_password)
weeks_count += WALLET_BRAIN_DATE_MAX_WEEKS_COUNT;
CHECK_AND_ASSERT_THROW_MES(weeks_count < std::numeric_limits<uint32_t>::max(), "internal error: unable to convert to uint32, val = " << weeks_count);
uint32_t weeks_count_32 = static_cast<uint32_t>(weeks_count);
return tools::mnemonic_encoding::word_by_num(weeks_count_32);
}
//---------------------------------------------------------------
uint64_t get_timstamp_from_word(std::string word)
uint64_t get_timstamp_from_word(std::string word, bool& password_used)
{
uint64_t count_of_weeks = tools::mnemonic_encoding::num_by_word(word);
if (count_of_weeks >= WALLET_BRAIN_DATE_MAX_WEEKS_COUNT)
{
count_of_weeks -= WALLET_BRAIN_DATE_MAX_WEEKS_COUNT;
password_used = true;
}
else {
password_used = false;
}
uint64_t timestamp = count_of_weeks * WALLET_BRAIN_DATE_QUANTUM + WALLET_BRAIN_DATE_OFFSET;
return timestamp;
}
//---------------------------------------------------------------

View file

@ -291,8 +291,8 @@ namespace currency
bool fill_tx_rpc_details(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce, const crypto::hash& h, uint64_t timestamp, bool is_short = false);
bool fill_block_rpc_details(block_rpc_extended_info& pei_rpc, const block_extended_info& bei_chain, const crypto::hash& h);
void append_per_block_increments_for_tx(const transaction& tx, std::unordered_map<uint64_t, uint32_t>& gindices);
std::string get_word_from_timstamp(uint64_t timestamp);
uint64_t get_timstamp_from_word(std::string word);
std::string get_word_from_timstamp(uint64_t timestamp, bool use_password);
uint64_t get_timstamp_from_word(std::string word, bool& password_used);
template<class t_txin_v>
typename std::conditional<std::is_const<t_txin_v>::value, const std::vector<txin_etc_details_v>, std::vector<txin_etc_details_v> >::type& get_txin_etc_options(t_txin_v& in)

View file

@ -239,6 +239,28 @@ QString MainWindow::get_tx_pool_info()
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::request_dummy()
{
static int code_ = 0;
TRY_ENTRY();
LOG_API_TIMING();
PREPARE_RESPONSE(currency::COMMAND_RPC_GET_POOL_INFO::response, ar);
if (code_ == 2)
{
code_ = -1;
ar.error_code = API_RETURN_CODE_CORE_BUSY;
}
else
{
ar.error_code = API_RETURN_CODE_OK;
}
++code_;
return MAKE_RESPONSE(ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::get_default_fee()
{
TRY_ENTRY();
@ -1654,7 +1676,7 @@ QString MainWindow::restore_wallet(const QString& param)
//return que_call2<view::restore_wallet_request>("restore_wallet", param, [this](const view::restore_wallet_request& owd, view::api_response& ar){
PREPARE_ARG_FROM_JSON(view::restore_wallet_request, owd);
PREPARE_RESPONSE(view::open_wallet_response, ar);
ar.error_code = m_backend.restore_wallet(epee::string_encoding::utf8_to_wstring(owd.path), owd.pass, owd.restore_key, ar.response_data);
ar.error_code = m_backend.restore_wallet(epee::string_encoding::utf8_to_wstring(owd.path), owd.pass, owd.seed_phrase, owd.seed_pass, ar.response_data);
return MAKE_RESPONSE(ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
@ -1855,9 +1877,9 @@ QString MainWindow::get_smart_wallet_info(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
PREPARE_ARG_FROM_JSON(view::wallet_id_obj, wo);
PREPARE_ARG_FROM_JSON(view::request_get_smart_wallet_info, wo);
PREPARE_RESPONSE(view::get_restore_info_response, ar);
ar.error_code = m_backend.get_wallet_restore_info(wo.wallet_id, ar.response_data.restore_key);
ar.error_code = m_backend.get_wallet_restore_info(wo.wallet_id, ar.response_data.seed_phrase, wo.seed_password);
return MAKE_RESPONSE(ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
@ -1951,14 +1973,26 @@ QString MainWindow::open_url_in_browser(const QString& param)
CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR);
}
QString MainWindow::is_valid_restore_wallet_text(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
return m_backend.is_valid_brain_restore_data(param.toStdString()).c_str();
PREPARE_ARG_FROM_JSON(view::seed_info_param, rwtp);
return m_backend.is_valid_brain_restore_data(rwtp.seed_phrase, rwtp.seed_password).c_str();
CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR);
}
QString MainWindow::get_seed_phrase_info(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
PREPARE_ARG_FROM_JSON(view::seed_info_param, rwtp);
PREPARE_RESPONSE(view::seed_phrase_info, ar);
ar.error_code = m_backend.get_seed_phrase_info(rwtp.seed_phrase, rwtp.seed_password, ar.response_data).c_str();
return MAKE_RESPONSE(ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
void MainWindow::contextMenuEvent(QContextMenuEvent * event)
{
TRY_ENTRY();

View file

@ -137,6 +137,7 @@ public:
QString is_autostart_enabled();
QString toggle_autostart(const QString& param);
QString is_valid_restore_wallet_text(const QString& param);
QString get_seed_phrase_info(const QString& param);
QString print_text(const QString& param);
QString print_log(const QString& param);
QString set_clipboard(const QString& param);
@ -159,6 +160,9 @@ public:
QString is_remnotenode_mode_preconfigured();
QString start_backend(const QString& params);
//for test purposes onlys
QString request_dummy();
signals:
void quit_requested(const QString str);
void update_daemon_state(const QString str);

View file

@ -46,13 +46,14 @@ namespace
const command_line::arg_descriptor<std::string> arg_password = {"password", "Wallet password", "", true};
const command_line::arg_descriptor<bool> arg_dont_refresh = { "no-refresh", "Do not refresh after load", false, true };
const command_line::arg_descriptor<bool> arg_dont_set_date = { "no-set-creation-date", "Do not set wallet creation date", false, false };
const command_line::arg_descriptor<bool> arg_print_brain_wallet = { "print-brain-wallet", "Print to conosole brain wallet", false, false };
const command_line::arg_descriptor<int> arg_daemon_port = {"daemon-port", "Use daemon instance at port <arg> instead of default", 0};
const command_line::arg_descriptor<uint32_t> arg_log_level = {"set-log", "", 0, true};
const command_line::arg_descriptor<bool> arg_do_pos_mining = { "do-pos-mining", "Do PoS mining", false, false };
const command_line::arg_descriptor<std::string> arg_pos_mining_reward_address = { "pos-mining-reward-address", "Block reward will be sent to the giving address if specified", "" };
const command_line::arg_descriptor<std::string> arg_restore_wallet = { "restore-wallet", "Restore wallet from seed phrase or tracking seed and save it to <arg>", "" };
const command_line::arg_descriptor<bool> arg_offline_mode = { "offline-mode", "Don't connect to daemon, work offline (for cold-signing process)", false, true };
const command_line::arg_descriptor<std::string> arg_scan_for_wallet = { "scan-for-wallet", "", "", true };
const command_line::arg_descriptor<std::string> arg_addr_to_compare = { "addr-to-compare", "", "", true };
const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""};
@ -178,7 +179,6 @@ bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<st
simple_wallet::simple_wallet()
: m_daemon_port(0),
m_print_brain_wallet(false),
m_do_refresh_after_load(false),
m_do_not_set_date(false),
m_do_pos_mining(false),
@ -307,10 +307,6 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
m_do_refresh_after_load = false;
}
if (command_line::has_arg(vm, arg_print_brain_wallet))
{
m_print_brain_wallet = true;
}
if (!m_generate_new.empty())
{
@ -336,9 +332,26 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
fail_msg_writer() << "failed to read seed phrase";
return false;
}
bool looks_like_tracking_seed = restore_seed_container.password().find(':') != std::string::npos;
bool r = restore_wallet(m_restore_wallet, restore_seed_container.password(), pwd_container.password(), looks_like_tracking_seed);
tools::password_container seed_password_container;
if (!looks_like_tracking_seed)
{
bool is_password_protected = false;
bool sr = account_base::is_seed_password_protected(restore_seed_container.password(), is_password_protected);
if (!sr)
{
fail_msg_writer() << "failed to parse seed phrase";
return false;
}
if (is_password_protected && !seed_password_container.read_password("This seed is secured, to use it please enter the password:\n"))
{
fail_msg_writer() << "failed to read seed phrase";
return false;
}
}
bool r = restore_wallet(m_restore_wallet, restore_seed_container.password(), pwd_container.password(), looks_like_tracking_seed, seed_password_container.password());
CHECK_AND_ASSERT_MES(r, false, "wallet restoring failed");
}
else
@ -400,10 +413,6 @@ bool simple_wallet::new_wallet(const string &wallet_file, const std::string& pas
if (m_do_not_set_date)
m_wallet->reset_creation_time(0);
if (m_print_brain_wallet)
{
std::cout << "Seed phrase (keep it in secret): " << m_wallet->get_account().get_seed_phrase() << std::endl << std::flush;
}
}
catch (const std::exception& e)
@ -422,7 +431,7 @@ bool simple_wallet::new_wallet(const string &wallet_file, const std::string& pas
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::restore_wallet(const std::string& wallet_file, const std::string& seed_or_tracking_seed, const std::string& password, bool tracking_wallet)
bool simple_wallet::restore_wallet(const std::string& wallet_file, const std::string& seed_or_tracking_seed, const std::string& password, bool tracking_wallet, const std::string& seed_password)
{
m_wallet_file = wallet_file;
@ -434,13 +443,13 @@ bool simple_wallet::restore_wallet(const std::string& wallet_file, const std::st
if (tracking_wallet)
{
// auditable watch-only aka tracking wallet
m_wallet->restore(epee::string_encoding::utf8_to_wstring(wallet_file), password, seed_or_tracking_seed, true);
m_wallet->restore(epee::string_encoding::utf8_to_wstring(wallet_file), password, seed_or_tracking_seed, true, "");
message_writer(epee::log_space::console_color_white, true) << "Tracking wallet restored: " << m_wallet->get_account().get_public_address_str();
}
else
{
// normal or auditable wallet
m_wallet->restore(epee::string_encoding::utf8_to_wstring(wallet_file), password, seed_or_tracking_seed, false);
m_wallet->restore(epee::string_encoding::utf8_to_wstring(wallet_file), password, seed_or_tracking_seed, false, seed_password);
message_writer(epee::log_space::console_color_white, true) << (m_wallet->is_auditable() ? "Auditable wallet" : "Wallet") << " restored: " << m_wallet->get_account().get_public_address_str();
std::cout << "view key: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().view_secret_key) << std::endl << std::flush;
if (m_wallet->is_auditable())
@ -454,7 +463,11 @@ bool simple_wallet::restore_wallet(const std::string& wallet_file, const std::st
fail_msg_writer() << "failed to restore wallet, check your " << (tracking_wallet ? "tracking seed!" : "seed phrase!") << ENDL << e.what();
return false;
}
catch (...)
{
fail_msg_writer() << "failed to restore wallet, check your " << (tracking_wallet ? "tracking seed!" : "seed phrase!") << ENDL;
return false;
}
m_wallet->init(m_daemon_address);
success_msg_writer() <<
@ -482,9 +495,6 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa
m_wallet->load(epee::string_encoding::utf8_to_wstring(m_wallet_file), password);
message_writer(epee::log_space::console_color_white, true) << "Opened" << (m_wallet->is_auditable() ? " auditable" : "") << (m_wallet->is_watch_only() ? " watch-only" : "") << " wallet: " << m_wallet->get_account().get_public_address_str();
if (m_print_brain_wallet)
std::cout << "Seed phrase (keep it in secret): " << m_wallet->get_account().get_seed_phrase() << std::endl << std::flush;
break;
}
catch (const tools::error::wallet_load_notice_wallet_restored& /*e*/)
@ -1359,9 +1369,24 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
//----------------------------------------------------------------------------------------------------
bool simple_wallet::show_seed(const std::vector<std::string> &args)
{
success_msg_writer() << "Here's your wallet's seed phrase. Write it down and keep in a safe place.";
success_msg_writer(true) << "Anyone who knows the following 26 words can access your wallet:";
std::cout << m_wallet->get_account().get_seed_phrase() << std::endl << std::flush;
success_msg_writer() << "Please enter a password to secure this seed. Securing your seed is HIGHLY recommended. Leave password blank to stay unsecured.";
success_msg_writer(true) << "Remember, restoring a wallet from Secured Seed can only be done if you know its password.";
tools::password_container seed_password_container1;
if (!seed_password_container1.read_password("Enter seed password: "))
{
return false;
}
tools::password_container seed_password_container2;
if (!seed_password_container2.read_password("Confirm seed password: "))
{
return false;
}
if(seed_password_container1.password() != seed_password_container2.password())
{
std::cout << "Error: password mismatch. Please make sure you entered the correct password and confirmed it" << std::endl << std::flush;
}
std::cout << m_wallet->get_account().get_seed_phrase(seed_password_container2.password()) << std::endl << std::flush;
return true;
}
//----------------------------------------------------------------------------------------------------
@ -1712,6 +1737,109 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args)
return true;
}
//----------------------------------------------------------------------------------------------------
uint64_t
get_tick_count__()
{
using namespace std::chrono;
return duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
}
//----------------------------------------------------------------------------------------------------
bool check_if_file_looks_like_a_wallet(const std::wstring& wallet_)
{
std::string keys_buff;
boost::system::error_code e;
bool exists = boost::filesystem::exists(wallet_, e);
if (e || !exists)
return false;
boost::filesystem::ifstream data_file;
data_file.open(wallet_, std::ios_base::binary | std::ios_base::in);
if (data_file.fail())
return false;
tools::wallet_file_binary_header wbh = AUTO_VAL_INIT(wbh);
data_file.read((char*)&wbh, sizeof(wbh));
if (data_file.fail())
{
return false;
}
if (wbh.m_signature != WALLET_FILE_SIGNATURE_OLD && wbh.m_signature != WALLET_FILE_SIGNATURE_V2)
{
return false;
}
//std::cout << "\r \r";
LOG_PRINT_L0("Found wallet file: " << epee::string_encoding::convert_to_ansii(wallet_));
return false;
}
bool search_for_wallet_file(const std::wstring &search_here/*, const std::string &addr_to_compare*/)
{
if (search_here == L"/proc" || search_here == L"/bin" || search_here == L"/dev" || search_here == L"/etc"
|| search_here == L"/lib" || search_here == L"/lib64" || search_here == L"/proc" || search_here == L"/run"
|| search_here == L"/sbin" || search_here == L"/srv" || search_here == L"/sys" || search_here == L"/usr"
|| search_here == L"/var")
{
LOG_PRINT_L0("Skiping " << epee::string_encoding::convert_to_ansii(search_here));
return false;
}
//LOG_PRINT_L0("FOLDER: " << epee::string_encoding::convert_to_ansii(search_here));
static uint64_t last_tick = 0;
using namespace boost::filesystem;
//recursive_directory_iterator dir(search_here), end;
try
{
for (auto& dir : boost::make_iterator_range(directory_iterator(search_here), {}))
{
boost::system::error_code ec = AUTO_VAL_INIT(ec);
bool r = boost::filesystem::is_directory(dir.path(), ec);
if (r)
{
if (get_tick_count__() - last_tick > 300)
{
last_tick = get_tick_count__();
//std::cout << "\r \r ->" << dir.path();
}
bool r = search_for_wallet_file(dir.path().wstring());
if (r)
return true;
}
else
{
boost::system::error_code ec = AUTO_VAL_INIT(ec);
bool r = boost::filesystem::is_regular_file(dir.path(), ec);
if (!r)
{
//LOG_PRINT_L0("Skiping as not regular: " << epee::string_encoding::convert_to_ansii(dir.path().wstring()));
return false;
}
//LOG_PRINT_L0("FILE: " << dir.path().string());
std::wstring pa = dir.path().wstring();
r = check_if_file_looks_like_a_wallet(pa);
if (r)
return true;
}
}
}
catch (std::exception& /* ex*/)
{
//std::cout << "\r \r";
LOG_PRINT_CYAN("Skip: " << search_here, LOG_LEVEL_0);
return false;
}
return false;
}
//----------------------------------------------------------------------------------------------------
#ifdef WIN32
int wmain( int argc, wchar_t* argv_w[ ], wchar_t* envp[ ] )
@ -1763,14 +1891,14 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_params, arg_log_level);
command_line::add_arg(desc_params, arg_dont_refresh);
command_line::add_arg(desc_params, arg_dont_set_date);
command_line::add_arg(desc_params, arg_print_brain_wallet);
command_line::add_arg(desc_params, arg_do_pos_mining);
command_line::add_arg(desc_params, arg_pos_mining_reward_address);
command_line::add_arg(desc_params, arg_restore_wallet);
command_line::add_arg(desc_params, arg_offline_mode);
command_line::add_arg(desc_params, command_line::arg_log_file);
command_line::add_arg(desc_params, command_line::arg_log_level);
command_line::add_arg(desc_params, arg_scan_for_wallet);
command_line::add_arg(desc_params, arg_addr_to_compare);
tools::wallet_rpc_server::init_options(desc_params);
@ -1827,6 +1955,17 @@ int main(int argc, char* argv[])
log_space::get_set_log_detalisation_level(true, command_line::get_arg(vm, command_line::arg_log_level));
}
if (command_line::has_arg(vm, arg_scan_for_wallet))
{
log_space::log_singletone::add_logger(LOGGER_CONSOLE, nullptr, nullptr, LOG_LEVEL_4);
LOG_PRINT_L0("Searching from "
<< epee::string_encoding::convert_to_ansii(command_line::get_arg(vm, arg_scan_for_wallet)));
search_for_wallet_file(epee::string_encoding::convert_to_unicode(command_line::get_arg(vm, arg_scan_for_wallet)));
return EXIT_SUCCESS;
}
bool offline_mode = command_line::get_arg(vm, arg_offline_mode);
if (command_line::has_arg(vm, tools::wallet_rpc_server::arg_rpc_bind_port))

View file

@ -46,7 +46,7 @@ namespace currency
bool new_wallet(const std::string &wallet_file, const std::string& password, bool create_auditable_wallet);
bool open_wallet(const std::string &wallet_file, const std::string& password);
bool restore_wallet(const std::string& wallet_file, const std::string& seed_or_tracking_seed, const std::string& password, bool tracking_wallet);
bool restore_wallet(const std::string& wallet_file, const std::string& seed_or_tracking_seed, const std::string& password, bool tracking_wallet, const std::string& seed_password);
bool close_wallet();
bool help(const std::vector<std::string> &args = std::vector<std::string>());
@ -163,7 +163,6 @@ namespace currency
int m_daemon_port;
bool m_do_refresh_after_load;
bool m_do_not_set_date;
bool m_print_brain_wallet;
bool m_do_pos_mining;
bool m_offline_mode;
std::string m_restore_wallet;

View file

@ -8,6 +8,6 @@
#define PROJECT_REVISION "7"
#define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION
#define PROJECT_VERSION_BUILD_NO 105
#define PROJECT_VERSION_BUILD_NO 110
#define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO)
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]"

View file

@ -400,13 +400,13 @@ namespace plain_wallet
return epee::serialization::store_t_to_json(err_result);
}
std::string restore(const std::string& seed, const std::string& path, const std::string& password)
std::string restore(const std::string& seed, const std::string& path, const std::string& password, const std::string& seed_password)
{
GET_INSTANCE_PTR(inst_ptr);
std::string full_path = get_wallets_folder() + path;
epee::json_rpc::response<view::open_wallet_response, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response);
std::string rsp = inst_ptr->gwm.restore_wallet(epee::string_encoding::convert_to_unicode(full_path), password, seed, ok_response.result);
std::string rsp = inst_ptr->gwm.restore_wallet(epee::string_encoding::convert_to_unicode(full_path), password, seed, seed_password, ok_response.result);
if (rsp == API_RETURN_CODE_OK || rsp == API_RETURN_CODE_FILE_RESTORED)
{
if (rsp == API_RETURN_CODE_FILE_RESTORED)
@ -526,7 +526,7 @@ namespace plain_wallet
}
async_callback = [job_id, rwr]()
{
std::string res = restore(rwr.restore_key, rwr.path, rwr.pass);
std::string res = restore(rwr.seed_phrase, rwr.path, rwr.pass, rwr.seed_pass);
put_result(job_id, res);
};
}

View file

@ -27,7 +27,7 @@ namespace plain_wallet
std::string get_connectivity_status();
std::string open(const std::string& path, const std::string& password);
std::string restore(const std::string& seed, const std::string& path, const std::string& password);
std::string restore(const std::string& seed, const std::string& path, const std::string& password, const std::string& seed_password);
std::string generate(const std::string& path, const std::string& password);
std::string get_opened_wallets();

View file

@ -272,6 +272,19 @@ public:
END_KV_SERIALIZE_MAP()
};
struct request_get_smart_wallet_info
{
uint64_t wallet_id;
std::string seed_password;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(wallet_id)
KV_SERIALIZE(seed_password)
END_KV_SERIALIZE_MAP()
};
struct response_mining_estimate
{
uint64_t final_amount;
@ -429,16 +442,19 @@ public:
END_KV_SERIALIZE_MAP()
};
struct restore_wallet_request
{
std::string pass;
std::string seed_pass;
std::string path;
std::string restore_key;
std::string seed_phrase;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(pass)
KV_SERIALIZE(path)
KV_SERIALIZE(restore_key)
KV_SERIALIZE(seed_pass)
KV_SERIALIZE(seed_phrase)
END_KV_SERIALIZE_MAP()
};
@ -548,6 +564,8 @@ public:
END_KV_SERIALIZE_MAP()
};
typedef tools::wallet_public::seed_info_param seed_info_param;
typedef tools::wallet_public::seed_phrase_info seed_phrase_info;
struct start_backend_params
{
@ -587,12 +605,10 @@ public:
struct get_restore_info_response
{
std::string restore_key;
std::string error_code;
std::string seed_phrase;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(restore_key)
KV_SERIALIZE(error_code)
KV_SERIALIZE(seed_phrase)
END_KV_SERIALIZE_MAP()
};

View file

@ -2324,6 +2324,8 @@ void wallet2::assign_account(const currency::account_base& acc)
clear();
m_account = acc;
init_log_prefix();
if (m_account.is_watch_only())
m_watch_only = true;
}
//----------------------------------------------------------------------------------------------------
void wallet2::generate(const std::wstring& path, const std::string& pass, bool auditable_wallet)
@ -2345,7 +2347,7 @@ void wallet2::generate(const std::wstring& path, const std::string& pass, bool a
store();
}
//----------------------------------------------------------------------------------------------------
void wallet2::restore(const std::wstring& path, const std::string& pass, const std::string& seed_or_tracking_seed, bool tracking_wallet)
void wallet2::restore(const std::wstring& path, const std::string& pass, const std::string& seed_or_tracking_seed, bool tracking_wallet, const std::string& seed_password)
{
bool r = false;
clear();
@ -2361,7 +2363,7 @@ void wallet2::restore(const std::wstring& path, const std::string& pass, const s
}
else
{
r = m_account.restore_from_seed_phrase(seed_or_tracking_seed);
r = m_account.restore_from_seed_phrase(seed_or_tracking_seed, seed_password);
init_log_prefix();
THROW_IF_FALSE_WALLET_EX(r, error::wallet_wrong_seed_error, epee::string_encoding::convert_to_ansii(m_wallet_file));
}

View file

@ -470,7 +470,7 @@ namespace tools
void assign_account(const currency::account_base& acc);
void generate(const std::wstring& path, const std::string& password, bool auditable_wallet);
void restore(const std::wstring& path, const std::string& pass, const std::string& seed_or_tracking_seed, bool tracking_wallet);
void restore(const std::wstring& path, const std::string& pass, const std::string& seed_or_tracking_seed, bool tracking_wallet, const std::string& seed_password);
void load(const std::wstring& path, const std::string& password);
void store();
void store(const std::wstring& path);

View file

@ -23,4 +23,16 @@ namespace tools
wi.is_watch_only = w.is_watch_only();
return true;
}
inline std::string get_seed_phrase_info(const std::string& seed_phrase, const std::string& seed_password, view::seed_phrase_info& result)
{
//cut the last timestamp word from restore_dats
result.syntax_correct = currency::account_base::is_seed_password_protected(seed_phrase, result.require_password);
if (result.syntax_correct)
{
currency::account_base acc;
result.hash_sum_matched = acc.restore_from_seed_phrase(seed_phrase, seed_password);
}
return API_RETURN_CODE_OK;
}
}

View file

@ -168,6 +168,29 @@ namespace wallet_public
};
struct seed_info_param
{
std::string seed_phrase;
std::string seed_password;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(seed_phrase)
KV_SERIALIZE(seed_password)
END_KV_SERIALIZE_MAP()
};
struct seed_phrase_info
{
bool syntax_correct;
bool require_password;
bool hash_sum_matched;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(syntax_correct)
KV_SERIALIZE(require_password)
KV_SERIALIZE(hash_sum_matched)
END_KV_SERIALIZE_MAP()
};
struct COMMAND_RPC_GET_BALANCE
{
@ -221,7 +244,6 @@ namespace wallet_public
{
std::string address;
std::string path;
std::string seed;
uint64_t transfers_count;
uint64_t transfer_entries_count;
bool is_whatch_only;
@ -230,7 +252,6 @@ namespace wallet_public
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(address)
KV_SERIALIZE(path)
KV_SERIALIZE(seed)
KV_SERIALIZE(transfers_count)
KV_SERIALIZE(transfer_entries_count)
KV_SERIALIZE(is_whatch_only)
@ -239,6 +260,32 @@ namespace wallet_public
};
};
struct COMMAND_RPC_GET_WALLET_RESTORE_INFO
{
struct request
{
std::string seed_password;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(seed_password)
END_KV_SERIALIZE_MAP()
};
struct response
{
std::string seed_phrase;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(seed_phrase)
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_RPC_GET_SEED_PHRASE_INFO
{
typedef seed_info_param request;
typedef seed_phrase_info response;
};
struct wallet_provision_info
{

View file

@ -15,6 +15,7 @@ using namespace epee;
#include "misc_language.h"
#include "crypto/hash.h"
#include "wallet_rpc_server_error_codes.h"
#include "wallet_helpers.h"
#define WALLET_RPC_BEGIN_TRY_ENTRY() try {
#define WALLET_RPC_CATCH_TRY_ENTRY() } \
@ -196,7 +197,6 @@ namespace tools
res.path = epee::string_encoding::convert_to_ansii(m_wallet.get_wallet_path());
res.transfers_count = m_wallet.get_recent_transfers_total_count();
res.transfer_entries_count = m_wallet.get_transfer_entries_count();
res.seed = m_wallet.get_account().get_seed_phrase();
std::map<uint64_t, uint64_t> distribution;
m_wallet.get_utxo_distribution(distribution);
for (const auto& ent : distribution)
@ -211,6 +211,25 @@ namespace tools
return false;
}
}
bool wallet_rpc_server::on_getwallet_restore_info(const wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO::request& req, wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
try
{
res.seed_phrase = m_wallet.get_account().get_seed_phrase(res.seed_phrase);
return true;
}
catch (std::exception& e)
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = e.what();
return false;
}
}
bool wallet_rpc_server::on_get_seed_phrase_info(const wallet_public::COMMAND_RPC_GET_SEED_PHRASE_INFO::request& req, wallet_public::COMMAND_RPC_GET_SEED_PHRASE_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
tools::get_seed_phrase_info(req.seed_phrase, req.seed_password, res);
return true;
}
bool wallet_rpc_server::on_get_recent_txs_and_info(const wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::request& req, wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
try

View file

@ -51,6 +51,8 @@ namespace tools
MAP_JON_RPC_WE("sign_transfer", on_sign_transfer, wallet_public::COMMAND_SIGN_TRANSFER)
MAP_JON_RPC_WE("submit_transfer", on_submit_transfer, wallet_public::COMMAND_SUBMIT_TRANSFER)
MAP_JON_RPC_WE("search_for_transactions", on_search_for_transactions, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS)
MAP_JON_RPC_WE("get_restore_info", on_getwallet_restore_info, wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO)
MAP_JON_RPC_WE("get_seed_phrase_info", on_get_seed_phrase_info, wallet_public::COMMAND_RPC_GET_SEED_PHRASE_INFO)
//contracts API
MAP_JON_RPC_WE("contracts_send_proposal", on_contracts_send_proposal, wallet_public::COMMAND_CONTRACTS_SEND_PROPOSAL)
MAP_JON_RPC_WE("contracts_accept_proposal", on_contracts_accept_proposal, wallet_public::COMMAND_CONTRACTS_ACCEPT_PROPOSAL)
@ -70,6 +72,8 @@ namespace tools
bool on_getbalance(const wallet_public::COMMAND_RPC_GET_BALANCE::request& req, wallet_public::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_getaddress(const wallet_public::COMMAND_RPC_GET_ADDRESS::request& req, wallet_public::COMMAND_RPC_GET_ADDRESS::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_getwallet_info(const wallet_public::COMMAND_RPC_GET_WALLET_INFO::request& req, wallet_public::COMMAND_RPC_GET_WALLET_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_getwallet_restore_info(const wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO::request& req, wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_get_seed_phrase_info(const wallet_public::COMMAND_RPC_GET_SEED_PHRASE_INFO::request& req, wallet_public::COMMAND_RPC_GET_SEED_PHRASE_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_get_recent_txs_and_info(const wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::request& req, wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_transfer(const wallet_public::COMMAND_RPC_TRANSFER::request& req, wallet_public::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_store(const wallet_public::COMMAND_RPC_STORE::request& req, wallet_public::COMMAND_RPC_STORE::response& res, epee::json_rpc::error& er, connection_context& cntx);

View file

@ -911,7 +911,7 @@ std::string wallets_manager::open_wallet(const std::wstring& path, const std::st
w->get_unconfirmed_transfers(owr.recent_history.history, exclude_mining_txs);
owr.wallet_local_bc_size = w->get_blockchain_current_size();
//workaround for missed fee
owr.seed = w->get_account().get_seed_phrase();
//owr.seed = w->get_account().get_seed_phrase();
break;
}
catch (const tools::error::file_not_found& /**/)
@ -1015,7 +1015,7 @@ std::string wallets_manager::generate_wallet(const std::wstring& path, const std
{
w->generate(path, password, false);
w->set_minimum_height(m_last_daemon_height);
owr.seed = w->get_account().get_seed_phrase();
//owr.seed = w->get_account().get_seed_phrase();
}
catch (const tools::error::file_exists&)
{
@ -1058,10 +1058,10 @@ std::string wallets_manager::is_pos_allowed()
else
return API_RETURN_CODE_FALSE;
}
std::string wallets_manager::is_valid_brain_restore_data(const std::string& seed_phrase)
std::string wallets_manager::is_valid_brain_restore_data(const std::string& seed_phrase, const std::string& seed_password)
{
currency::account_base acc;
if (acc.restore_from_seed_phrase(seed_phrase))
if (acc.restore_from_seed_phrase(seed_phrase, seed_password))
return API_RETURN_CODE_TRUE;
currency::account_public_address addr;
@ -1081,11 +1081,18 @@ void wallets_manager::subscribe_to_core_events(currency::i_core_event_handler* p
}
#endif
std::string wallets_manager::get_seed_phrase_info(const std::string& seed_phrase, const std::string& seed_password, view::seed_phrase_info& result)
{
return tools::get_seed_phrase_info(seed_phrase, seed_password, result);
}
void wallets_manager::get_gui_options(view::gui_options& opt)
{
opt = m_ui_opt;
}
std::string wallets_manager::restore_wallet(const std::wstring& path, const std::string& password, const std::string& restore_key, view::open_wallet_response& owr)
std::string wallets_manager::restore_wallet(const std::wstring& path, const std::string& password, const std::string& seed_phrase, const std::string& seed_password, view::open_wallet_response& owr)
{
std::shared_ptr<tools::wallet2> w(new tools::wallet2());
w->set_use_deffered_global_outputs(m_use_deffered_global_outputs);
@ -1108,9 +1115,9 @@ std::string wallets_manager::restore_wallet(const std::wstring& path, const std:
currency::account_base acc;
try
{
bool auditable_watch_only = restore_key.find(':') != std::string::npos;
w->restore(path, password, restore_key, auditable_watch_only);
owr.seed = w->get_account().get_seed_phrase();
bool auditable_watch_only = seed_phrase.find(':') != std::string::npos;
w->restore(path, password, seed_phrase, auditable_watch_only, seed_password);
//owr.seed = w->get_account().get_seed_phrase();
}
catch (const tools::error::file_exists&)
{
@ -1625,14 +1632,14 @@ std::string wallets_manager::get_mining_history(uint64_t wallet_id, tools::walle
wo.w->get()->get_mining_history(mh);
return API_RETURN_CODE_OK;
}
std::string wallets_manager::get_wallet_restore_info(uint64_t wallet_id, std::string& restore_key)
std::string wallets_manager::get_wallet_restore_info(uint64_t wallet_id, std::string& seed_phrase, const std::string& seed_password)
{
GET_WALLET_OPT_BY_ID(wallet_id, wo);
if (wo.wallet_state != view::wallet_status_info::wallet_state_ready || wo.long_refresh_in_progress)
return API_RETURN_CODE_CORE_BUSY;
restore_key = wo.w->get()->get_account().get_seed_phrase();
seed_phrase = wo.w->get()->get_account().get_seed_phrase(seed_password);
return API_RETURN_CODE_OK;
}

View file

@ -99,7 +99,7 @@ public:
bool get_opened_wallets(std::list<view::open_wallet_response>& result);
std::string open_wallet(const std::wstring& path, const std::string& password, uint64_t txs_to_return, view::open_wallet_response& owr, bool exclude_mining_txs = false);
std::string generate_wallet(const std::wstring& path, const std::string& password, view::open_wallet_response& owr);
std::string restore_wallet(const std::wstring& path, const std::string& password, const std::string& restore_key, view::open_wallet_response& owr);
std::string restore_wallet(const std::wstring& path, const std::string& password, const std::string& seed_phrase, const std::string& seed_password, view::open_wallet_response& owr);
std::string invoke(uint64_t wallet_id, std::string params);
std::string get_wallet_status(uint64_t wallet_id);
std::string run_wallet(uint64_t wallet_id);
@ -132,7 +132,7 @@ public:
std::string stop_pos_mining(uint64_t wallet_id);
std::string check_available_sources(uint64_t wallet_id, std::list<uint64_t>& amounts);
std::string get_mining_history(uint64_t wallet_id, tools::wallet_public::mining_history& wrpc);
std::string get_wallet_restore_info(uint64_t wallet_id, std::string& restore_key);
std::string get_wallet_restore_info(uint64_t wallet_id, std::string& seed_phrase, const std::string& seed_password);
std::string backup_wallet(uint64_t wallet_id, const std::wstring& path);
std::string reset_wallet_password(uint64_t wallet_id, const std::string& pass);
std::string is_wallet_password_valid(uint64_t wallet_id, const std::string& pass);
@ -149,7 +149,8 @@ public:
void toggle_pos_mining();
std::string transfer(size_t wallet_id, const view::transfer_params& tp, currency::transaction& res_tx);
std::string get_config_folder();
std::string is_valid_brain_restore_data(const std::string& seed_phrase);
std::string is_valid_brain_restore_data(const std::string& seed_phrase, const std::string& seed_password);
std::string get_seed_phrase_info(const std::string& seed_phrase, const std::string& seed_password, view::seed_phrase_info& result);
#ifndef MOBILE_WALLET_BUILD
void subscribe_to_core_events(currency::i_core_event_handler* pevents_handler);
//void unsubscribe_to_core_events();

View file

@ -863,6 +863,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(wallet_unconfirmed_tx_expiration);
GENERATE_AND_PLAY(wallet_unconfimed_tx_balance);
GENERATE_AND_PLAY(packing_outputs_on_pos_minting_wallet);
GENERATE_AND_PLAY(wallet_watch_only_and_chain_switch);
GENERATE_AND_PLAY(wallet_rpc_integrated_address);
GENERATE_AND_PLAY(wallet_rpc_integrated_address_transfer);

View file

@ -3441,5 +3441,103 @@ bool wallet_sending_to_integrated_address::c1(currency::core& c, size_t ev_index
miner_wlt_2->refresh();
CHECK_AND_ASSERT_MES(callback_succeded, false, "callback was not succeded (2)");
return true;
}
//------------------------------------------------------------------------------
wallet_watch_only_and_chain_switch::wallet_watch_only_and_chain_switch()
: m_split_point_block_height(0)
{
REGISTER_CALLBACK_METHOD(wallet_watch_only_and_chain_switch, c1);
}
bool wallet_watch_only_and_chain_switch::generate(std::vector<test_event_entry>& events) const
{
bool r = false;
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate();
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.make_account_watch_only();
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(true); bob_acc.make_account_watch_only(); // Bob gonna have a tracking wallet
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
// 0 10 11 12 13 23 15 <- blockchain height
// (0 )- (0r)- (1 )- (2 )- (3 )- (3r)- <- main chain
// | tx_0
// \ tx_1
// \
// \- (2a)- (3a)- (3ar)-
MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner_acc);
MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner_acc);
MAKE_TX_FEE(events, tx_0, miner_acc, alice_acc, MK_TEST_COINS(9), TESTS_DEFAULT_FEE, blk_2);
MAKE_TX_FEE(events, tx_1, miner_acc, bob_acc, MK_TEST_COINS(7), TESTS_DEFAULT_FEE, blk_2);
MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_2, miner_acc, std::list<transaction>({ tx_0, tx_1 }));
REWIND_BLOCKS_N(events, blk_3r, blk_3, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE);
m_split_point_block_id = get_block_hash(blk_1);
m_split_point_block_height = get_block_height(blk_1);
DO_CALLBACK(events, "c1");
return true;
}
bool wallet_watch_only_and_chain_switch::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bool r = false;
std::shared_ptr<tools::wallet2> miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX);
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX);
// make sure Alice's wallet is watch-only but not a tracking wallet (not auditable)
CHECK_AND_ASSERT_MES(alice_wlt->is_watch_only() && !alice_wlt->is_auditable(), false, "incorrect type of Alice's wallet");
// make sure Bob's wallet is a tracking wallet
CHECK_AND_ASSERT_MES(bob_wlt->is_watch_only() && bob_wlt->is_auditable(), false, "incorrect type of Bob's wallet");
miner_wlt->refresh();
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
// check the balances
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(9), false, UINT64_MAX, MK_TEST_COINS(9), 0, 0, 0), false, "");
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(7), false, UINT64_MAX, MK_TEST_COINS(7), 0, 0, 0), false, "");
// make a split
block out_block;
crypto::hash prev_id = m_split_point_block_id;
uint64_t current_height = m_split_point_block_height + 1;
for (size_t i = 0; i < CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3; ++i)
{
r = mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector<transaction>(), prev_id, current_height, &out_block);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime_with_given_txs failed");
current_height++;
prev_id = get_block_hash(out_block);
}
// make sure the split has happened
uint64_t top_height = 0;
crypto::hash top_id;
c.get_blockchain_top(top_height, top_id);
CHECK_AND_ASSERT_MES(top_height == current_height - 1, false, "incorrect top_hegiht = " << top_height);
CHECK_AND_ASSERT_MES(top_id == prev_id, false, "incorrect top id = " << top_id);
// tx_0 and tx_1 should be moved back to the pool
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 2, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
// check the balances, should be zero in actual and few coins in awaiting
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(9), false, UINT64_MAX, 0, 0, MK_TEST_COINS(9), 0), false, "");
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(7), false, UINT64_MAX, 0, 0, MK_TEST_COINS(7), 0), false, "");
return true;
}

View file

@ -265,4 +265,14 @@ struct wallet_sending_to_integrated_address : public wallet_test
wallet_sending_to_integrated_address();
bool generate(std::vector<test_event_entry>& events) const;
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
};
};
struct wallet_watch_only_and_chain_switch : public wallet_test
{
wallet_watch_only_and_chain_switch();
bool generate(std::vector<test_event_entry>& events) const;
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
mutable crypto::hash m_split_point_block_id;
mutable uint64_t m_split_point_block_height;
};

View file

@ -842,7 +842,7 @@ namespace db_test
ptr = db_array[4];
ASSERT_EQ(ptr->v, "X");
ASSERT_TRUE(db_array.clear());
ASSERT_TRUE((db_array.clear()? true: false));
db_array.commit_transaction();

View file

@ -13,10 +13,10 @@ TEST(wallet_seed, store_restore_test)
{
currency::account_base acc;
acc.generate();
auto seed_phrase = acc.get_seed_phrase();
auto seed_phrase = acc.get_seed_phrase("");
currency::account_base acc2;
bool r = acc2.restore_from_seed_phrase(seed_phrase);
bool r = acc2.restore_from_seed_phrase(seed_phrase, "");
ASSERT_TRUE(r);
if (memcmp(&acc2.get_keys(), &acc.get_keys(), sizeof(currency::account_keys)))
@ -29,10 +29,10 @@ TEST(wallet_seed, store_restore_test)
{
currency::account_base acc;
acc.generate();
auto seed_phrase = acc.get_seed_phrase();
auto seed_phrase = acc.get_seed_phrase("");
currency::account_base acc2;
bool r = acc2.restore_from_seed_phrase(seed_phrase);
bool r = acc2.restore_from_seed_phrase(seed_phrase, "");
ASSERT_TRUE(r);
if (memcmp(&acc2.get_keys(), &acc.get_keys(), sizeof(currency::account_keys)))
@ -57,7 +57,7 @@ wallet_seed_entry wallet_seed_entries[] =
{
{
// legacy 24-word seed phrase -- invalid
"dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew",
"dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew god",
"",
"",
0,
@ -66,7 +66,7 @@ wallet_seed_entry wallet_seed_entries[] =
},
{
// old-style 25-word seed phrase -- valid
"dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew",
"dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew god",
"5e051454d7226b5734ebd64f754b57db4c655ecda00bd324f1b241d0b6381c0f",
"7dde5590fdf430568c00556ac2accf09da6cde9a29a4bc7d1cb6fd267130f006",
0,
@ -148,7 +148,41 @@ TEST(wallet_seed, basic_test)
bool r = false;
try
{
r = acc.restore_from_seed_phrase(wse.seed_phrase);
r = acc.restore_from_seed_phrase(wse.seed_phrase, "");
if (r)
{
for (size_t j = 0; j != 100; j++)
{
//generate random password
std::string pass = epee::string_tools::pod_to_hex(crypto::cn_fast_hash(&j, sizeof(j)));
if (j!= 0 && j < 64)
{
pass.resize(j);
}
//get secured seed
std::string secured_seed = acc.get_seed_phrase(pass);
//try to restore it without password(should fail)
currency::account_base acc2;
bool r_fail = acc2.restore_from_seed_phrase(secured_seed, "");
ASSERT_EQ(r_fail, false);
//try to restore it with wrong password
bool r_fake_pass = acc2.restore_from_seed_phrase(secured_seed, "fake_password");
if (r_fake_pass)
{
//accidentally checksumm matched(quite possible)
ASSERT_EQ(false, acc2.get_keys() == acc.get_keys());
}
//try to restore it from right password
currency::account_base acc3;
bool r_true_res = acc3.restore_from_seed_phrase(secured_seed, pass);
ASSERT_EQ(true, r_true_res);
ASSERT_EQ(true, acc3.get_keys() == acc.get_keys());
}
}
}
catch (...)
{