diff --git a/README.md b/README.md index b84d4f911..4a5cefe56 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Salvium One v1.0.0 -Copyright (c) 2023-2024, Salvium +Copyright (c) 2023-2025, Salvium Portions Copyright (c) 2014-2023, The Monero Project Portions Copyright (c) 2012-2013 The Cryptonote developers. diff --git a/src/blocks/checkpoints.dat b/src/blocks/checkpoints.dat index 890c1dd3a..83134e50b 100644 Binary files a/src/blocks/checkpoints.dat and b/src/blocks/checkpoints.dat differ diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 0e7f205d7..9b8f61870 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -6514,7 +6514,7 @@ void Blockchain::cancel() } #if defined(PER_BLOCK_CHECKPOINT) -static const char expected_block_hashes_hash[] = "a2a5a9bc5d606392ac5c14be55b90a92b8577b8ffdac5c63cc6174f41764c753"; +static const char expected_block_hashes_hash[] = "1cf6e8892e0512c246cef62610ccf524f30f484e307ae01959a5a7dd166aa328"; void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints) { if (get_checkpoints == nullptr || !m_fast_sync) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index ce0f1948a..a23898a8b 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -6472,7 +6472,7 @@ bool simple_wallet::show_balance_unlocked(bool detailed) if (!detailed || balance_per_subaddress.empty()) continue; success_msg_writer() << tr("Balance per address:"); - success_msg_writer() << boost::format("%15s %21s %21s %7s %21s") % tr("Address") % tr("Balance") % tr("Unlocked balance") % tr("Outputs") % tr("Label"); + success_msg_writer() << boost::format("%16s %21s %21s %7s %21s") % tr("Address") % tr("Balance") % tr("Unlocked balance") % tr("Outputs") % tr("Label"); std::vector transfers; m_wallet->get_transfers(transfers); for (const auto& i : balance_per_subaddress) @@ -6480,9 +6480,9 @@ bool simple_wallet::show_balance_unlocked(bool detailed) carrot::subaddress_index_extended subaddr = {{m_current_subaddress_account, i.first}, is_carrot ? carrot::AddressDeriveType::Carrot : carrot::AddressDeriveType::PreCarrot}; cryptonote::subaddress_index subaddr_index = {m_current_subaddress_account, i.first}; - std::string address_str = m_wallet->get_subaddress_as_str(subaddr).substr(0, 6); + std::string address_str = m_wallet->get_subaddress_as_str(subaddr).substr(0, 8); uint64_t num_unspent_outputs = std::count_if(transfers.begin(), transfers.end(), [&subaddr_index](const tools::wallet2::transfer_details& td) { return !td.m_spent && td.m_subaddr_index == subaddr_index; }); - success_msg_writer() << boost::format(tr("%8u %6s %21s %21s %7u %21s")) % i.first % address_str % print_money(i.second) % print_money(unlocked_balance_per_subaddress[i.first].first) % num_unspent_outputs % m_wallet->get_subaddress_label(subaddr_index); + success_msg_writer() << boost::format(tr("%8u %8s %21s %21s %7u %21s")) % i.first % address_str % print_money(i.second) % print_money(unlocked_balance_per_subaddress[i.first].first) % num_unspent_outputs % m_wallet->get_subaddress_label(subaddr_index); } } return true; @@ -9902,7 +9902,7 @@ bool simple_wallet::get_transfers(std::vector& local_args, std::vec if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) payment_id = payment_id.substr(0,16); std::string note = m_wallet->get_tx_note(pd.m_tx_hash); - std::string destination = m_wallet->get_subaddress_as_str({m_current_subaddress_account, pd.m_subaddr_index.minor}); + std::string destination = m_wallet->get_subaddress_as_str({{m_current_subaddress_account, pd.m_subaddr_index.minor}, pd.m_is_carrot ? carrot::AddressDeriveType::Carrot : carrot::AddressDeriveType::PreCarrot}); const std::string type = pd.m_tx_type == cryptonote::transaction_type::STAKE ? "stake" : pd.m_coinbase ? tr("block") : tr("in"); @@ -10105,7 +10105,7 @@ bool simple_wallet::show_transfers(const std::vector &args_) { if (!destinations.empty()) destinations += ", "; - destinations += (transfer.direction == "in" ? output.first.substr(0, 6) : output.first) + ":" + print_money(output.second); + destinations += ((transfer.direction == "in" || transfer.direction == "block") ? output.first.substr(0, 8) : output.first) + ":" + print_money(output.second); } } @@ -10631,7 +10631,7 @@ std::string simple_wallet::get_prompt() const { if (m_locked) return std::string("[") + tr("locked due to inactivity") + "]"; - std::string addr_start = m_wallet->get_subaddress_as_str({m_current_subaddress_account, 0}).substr(0, 6); + std::string addr_start = m_wallet->get_subaddress_as_str({m_current_subaddress_account, 0}).substr(0, 8); std::string prompt = std::string("[") + tr("wallet") + " " + addr_start; if (!m_wallet->check_connection(NULL)) prompt += tr(" (no daemon)"); @@ -10854,7 +10854,7 @@ void simple_wallet::print_accounts(const std::string& tag) success_msg_writer() << tr("Accounts with tag: ") << tag; success_msg_writer() << tr("Tag's description: ") << account_tags.first.find(tag)->second; } - success_msg_writer() << boost::format(" %15s %21s %21s %21s %21s") % tr("Account") % tr("Balance") % tr("Unlocked balance") % tr("Asset") % tr("Label"); + success_msg_writer() << boost::format(" %18s %21s %21s %6s %21s") % tr("Account") % tr("Balance") % tr("Unlocked balance") % tr("Asset") % tr("Label"); std::map> total_balances; std::vector asset_types_in_wallet = m_wallet->list_asset_types(); for (const auto& asset: asset_types_in_wallet) { @@ -10868,10 +10868,10 @@ void simple_wallet::print_accounts(const std::string& tag) auto unlocked_balance = m_wallet->unlocked_balance(account_index, asset, false); if (balance == 0) continue; - success_msg_writer() << boost::format(tr(" %c%8u %6s %21s %21s %21s %21s")) + success_msg_writer() << boost::format(tr(" %c%8u %8s %21s %21s %6s %21s")) % (m_current_subaddress_account == account_index ? '*' : ' ') % account_index - % m_wallet->get_subaddress_as_str({account_index, 0}).substr(0, 6) + % m_wallet->get_subaddress_as_str({{account_index, 0}, carrot::AddressDeriveType::Auto}).substr(0, 8) % print_money(balance) % print_money(unlocked_balance) % asset @@ -10882,9 +10882,9 @@ void simple_wallet::print_accounts(const std::string& tag) if (total_balance > 0) total_balances[asset] = std::pair(total_balance, total_unlocked_balance); } - success_msg_writer() << tr("------------------------------------------------------------------------------------"); + success_msg_writer() << tr("------------------------------------------------------------------------------------------------------"); for (const auto& it: total_balances) - success_msg_writer() << boost::format(tr("%15s %21s %21s %15s")) % "Total" % print_money(it.second.first) % print_money(it.second.second) % it.first; + success_msg_writer() << boost::format(tr("%18s %21s %21s %6s")) % "Total" % print_money(it.second.first) % print_money(it.second.second) % it.first; } //---------------------------------------------------------------------------------------------------- bool simple_wallet::print_address(const std::vector &args/* = std::vector()*/) @@ -10900,16 +10900,35 @@ bool simple_wallet::print_address(const std::vector &args/* = std:: std::vector local_args = args; tools::wallet2::transfer_container transfers; m_wallet->get_transfers(transfers); - bool is_carrot = m_wallet->get_current_hard_fork() >= HF_VERSION_CARROT; - auto print_address_sub = [this, &transfers, is_carrot](uint32_t index) + auto print_address_sub = [this, &transfers](uint32_t index, bool cryptonote = true, bool carrot = true) { bool used = std::find_if( transfers.begin(), transfers.end(), [this, &index](const tools::wallet2::transfer_details& td) { return td.m_subaddr_index == cryptonote::subaddress_index{ m_current_subaddress_account, index }; }) != transfers.end(); - success_msg_writer() << index << " " << m_wallet->get_subaddress_as_str({{m_current_subaddress_account, index}, is_carrot ? carrot::AddressDeriveType::Carrot : carrot::AddressDeriveType::PreCarrot}) << " " << (index == 0 ? tr("Primary address") : m_wallet->get_subaddress_label({m_current_subaddress_account, index})) << " " << (used ? tr("(used)") : ""); + if (!cryptonote) { + success_msg_writer() << boost::format(tr("%8u %96s %21s %6s")) + % index + % m_wallet->get_subaddress_as_str({{m_current_subaddress_account, index}, carrot::AddressDeriveType::Carrot}) + % (index == 0 ? tr("Primary address") : m_wallet->get_subaddress_label({m_current_subaddress_account, index})) + % (used ? tr("(used)") : ""); + } else if (!carrot) { + success_msg_writer() << boost::format(tr("%8u %96s %21s %6s")) + % index + % m_wallet->get_subaddress_as_str({{m_current_subaddress_account, index}, carrot::AddressDeriveType::PreCarrot}) + % (index == 0 ? tr("Primary address") : m_wallet->get_subaddress_label({m_current_subaddress_account, index})) + % (used ? tr("(used)") : ""); + } else { + success_msg_writer() << boost::format(tr("%8u %96s %21s %6s\n %96s\n")) + % index + % m_wallet->get_subaddress_as_str({{m_current_subaddress_account, index}, carrot::AddressDeriveType::PreCarrot}) + % (index == 0 ? tr("Primary address") : m_wallet->get_subaddress_label({m_current_subaddress_account, index})) + % (used ? tr("(used)") : "") + % m_wallet->get_subaddress_as_str({{m_current_subaddress_account, index}, carrot::AddressDeriveType::Carrot}); + } + //success_msg_writer() << index << " " << m_wallet->get_subaddress_as_str({{m_current_subaddress_account, index}, is_carrot ? carrot::AddressDeriveType::Carrot : carrot::AddressDeriveType::PreCarrot}) << " " << (index == 0 ? tr("Primary address") : m_wallet->get_subaddress_label({m_current_subaddress_account, index})) << " " << (used ? tr("(used)") : ""); }; uint32_t index = 0; @@ -10917,11 +10936,18 @@ bool simple_wallet::print_address(const std::vector &args/* = std:: { print_address_sub(index); } - else if (local_args.size() == 1 && local_args[0] == "all") + else if (local_args[0] == "all") { local_args.erase(local_args.begin()); - for (; index < m_wallet->get_num_subaddresses(m_current_subaddress_account); ++index) - print_address_sub(index); + if (local_args.size() == 0) + for (; index < m_wallet->get_num_subaddresses(m_current_subaddress_account); ++index) + print_address_sub(index); + else if (local_args[0] == "cn") + for (; index < m_wallet->get_num_subaddresses(m_current_subaddress_account); ++index) + print_address_sub(index, true, false); + else + for (; index < m_wallet->get_num_subaddresses(m_current_subaddress_account); ++index) + print_address_sub(index, false, true); } else if (local_args[0] == "new") { @@ -11321,7 +11347,9 @@ bool simple_wallet::wallet_info(const std::vector &args) } message_writer() << tr("Filename: ") << m_wallet->get_wallet_file(); message_writer() << tr("Description: ") << description; - message_writer() << tr("Address: ") << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); + message_writer() << tr("CN Address: ") << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); + message_writer() << tr("Carrot Address: ") << m_wallet->get_account().get_carrot_public_address_str(m_wallet->nettype()); + std::string type; if (m_wallet->watch_only()) type = tr("Watch only"); diff --git a/src/version.cpp.in b/src/version.cpp.in index b707d723d..c625cc4f0 100644 --- a/src/version.cpp.in +++ b/src/version.cpp.in @@ -1,5 +1,5 @@ #define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@" -#define DEF_SALVIUM_VERSION "1.0.0-rc6" +#define DEF_SALVIUM_VERSION "1.0.0" #define DEF_MONERO_VERSION_TAG "release" #define DEF_MONERO_VERSION "0.18.3.4" #define DEF_MONERO_RELEASE_NAME "One" diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 544bde49b..3cd06a14c 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1584,11 +1584,24 @@ crypto::public_key wallet2::get_subaddress_spend_public_key(const cryptonote::su return hwdev.get_subaddress_spend_public_key(m_account.get_keys(), index); } //---------------------------------------------------------------------------------------------------- -std::string wallet2::get_subaddress_as_str(const carrot::subaddress_index_extended& subaddr) const +std::string wallet2::get_subaddress_as_str(const carrot::subaddress_index_extended& subaddr_const) const { - carrot::CarrotDestinationV1 address = m_account.subaddress(subaddr); + // Make a non-const copy of subaddr + carrot::subaddress_index_extended subaddr(subaddr_const); + + // Handle "auto" - the account class doesn't know the HF version, so this is the cleanest solution + if (subaddr.derive_type == carrot::AddressDeriveType::Auto) { + + // Get the HF version + uint32_t hf_version = estimate_current_hard_fork(); + THROW_WALLET_EXCEPTION_IF(hf_version == 0, error::wallet_internal_error, "unable to estimate the current hard fork - cannot generate subaddress as string"); + + // Change the non-const derivation type + subaddr.derive_type = (hf_version >= HF_VERSION_CARROT) ? carrot::AddressDeriveType::Carrot : carrot::AddressDeriveType::PreCarrot; + } // Build the cryptonote::account_public_address + carrot::CarrotDestinationV1 address = m_account.subaddress(subaddr); account_public_address addr{address.address_spend_pubkey, address.address_view_pubkey}; addr.m_is_carrot = subaddr.derive_type == carrot::AddressDeriveType::Carrot; @@ -2936,6 +2949,7 @@ void wallet2::process_new_scanned_transaction( payment.m_coinbase = miner_tx; payment.m_subaddr_index = i.first; payment.m_tx_type = tx.type; + payment.m_is_carrot = (tx.version >= TRANSACTION_VERSION_CARROT); if (pool) { if (emplace_or_replace(m_unconfirmed_payments, payment_id, pool_payment_details{payment, double_spend_seen})) all_same = false; @@ -12312,6 +12326,31 @@ void wallet2::device_show_address(uint32_t account_index, uint32_t address_index hwdev.display_address(subaddress_index{account_index, address_index}, payment_id); } //---------------------------------------------------------------------------------------------------- +uint8_t wallet2::estimate_current_hard_fork() const +{ + // Get the last-seen top height by the wallet + uint64_t guessed_height = m_blockchain.size(); + + // Get the correct hardfork table, based on current net type + const hardfork_t *hfs = + (m_nettype == cryptonote::MAINNET) ? mainnet_hard_forks : + (m_nettype == cryptonote::TESTNET) ? testnet_hard_forks : + stagenet_hard_forks; + size_t hfs_count = + (m_nettype == cryptonote::MAINNET) ? num_mainnet_hard_forks : + (m_nettype == cryptonote::TESTNET) ? num_testnet_hard_forks : + num_stagenet_hard_forks; + + // Iterate over the hard fork table, to see what the current fork is for the guessed height + for (size_t i = hfs_count-1; i>=0; --i) { + if (hfs[i].height <= guessed_height) + return hfs[i].version; + } + + // return "no value found" to the caller + return 0; +} +//---------------------------------------------------------------------------------------------------- uint8_t wallet2::get_current_hard_fork() { if (m_offline) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 0158ec7d2..1d3ef2405 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -496,9 +496,10 @@ private: bool m_coinbase; cryptonote::subaddress_index m_subaddr_index; cryptonote::transaction_type m_tx_type; + bool m_is_carrot; BEGIN_SERIALIZE_OBJECT() - VERSION_FIELD(0) + VERSION_FIELD(1) FIELD(m_tx_hash) VARINT_FIELD(m_amount) FIELD(m_asset_type) @@ -510,6 +511,11 @@ private: FIELD(m_coinbase) FIELD(m_subaddr_index) VARINT_FIELD(m_tx_type) + if (version < 1) { + m_is_carrot = false; + return true; + } + FIELD(m_is_carrot) END_SERIALIZE() }; @@ -1661,6 +1667,7 @@ private: size_t get_num_transfer_details() const { return m_transfers.size(); } const transfer_details &get_transfer_details(size_t idx) const; + uint8_t estimate_current_hard_fork() const; uint8_t get_current_hard_fork(); void get_hard_fork_info(uint8_t version, uint64_t &earliest_height); bool use_fork_rules(uint8_t version, int64_t early_blocks = 0); @@ -2293,7 +2300,7 @@ BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 12) BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1) BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0) BOOST_CLASS_VERSION(tools::wallet2::multisig_tx_set, 1) -BOOST_CLASS_VERSION(tools::wallet2::payment_details, 5) +BOOST_CLASS_VERSION(tools::wallet2::payment_details, 6) BOOST_CLASS_VERSION(tools::wallet2::pool_payment_details, 1) BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 8) BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 6) @@ -2622,6 +2629,12 @@ namespace boost a & x.m_amounts; a & x.m_asset_type; a & x.m_tx_type; + if (ver < 6) + { + x.m_is_carrot = false; + return; + } + a & x.m_is_carrot; } template diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index d734f23fc..0564822d2 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -67,6 +67,7 @@ namespace wallet_rpc bool all_accounts; bool all_assets; bool strict; + bool carrot_first; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(account_index) KV_SERIALIZE(address_indices) @@ -74,6 +75,7 @@ namespace wallet_rpc KV_SERIALIZE_OPT(all_accounts, false); KV_SERIALIZE_OPT(all_assets, false); KV_SERIALIZE_OPT(strict, false); + KV_SERIALIZE_OPT(carrot_first, false); END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init request; @@ -83,6 +85,7 @@ namespace wallet_rpc uint32_t account_index; uint32_t address_index; std::string address; + std::string address_alt; uint64_t balance; uint64_t unlocked_balance; std::string label; @@ -94,6 +97,7 @@ namespace wallet_rpc KV_SERIALIZE(account_index) KV_SERIALIZE(address_index) KV_SERIALIZE(address) + KV_SERIALIZE(address_alt) KV_SERIALIZE(balance) KV_SERIALIZE(unlocked_balance) KV_SERIALIZE(label) @@ -139,6 +143,7 @@ namespace wallet_rpc { uint32_t account_index; std::vector address_index; + bool carrot_first; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(account_index) KV_SERIALIZE(address_index) @@ -149,12 +154,14 @@ namespace wallet_rpc struct address_info { std::string address; + std::string address_alt; std::string label; uint32_t address_index; bool used; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(address) + KV_SERIALIZE(address_alt) KV_SERIALIZE(label) KV_SERIALIZE(address_index) KV_SERIALIZE(used) @@ -164,10 +171,12 @@ namespace wallet_rpc struct response_t { std::string address; // to remain compatible with older RPC format + std::string address_alt; std::vector addresses; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(address) + KV_SERIALIZE(address_alt) KV_SERIALIZE(addresses) END_KV_SERIALIZE_MAP() };