Compare commits

...

4 Commits

Author SHA1 Message Date
Some Random Crypto Guy 1667514896 bumped RC version 2025-09-03 16:01:50 +01:00
auruya 041cd03098 Add hardfork for stake carrot integration (#55)
* Add hardfork for stake carrot integration

* Add hardfork for stake carrot integration

* fixed assertion failure

* Add hardfork for stake carrot integration

* Add hardfork for stake carrot integration

---------

Co-authored-by: Some Random Crypto Guy <somerandomcryptoguy@protonmail.com>
2025-09-03 16:00:34 +01:00
somerandomcryptoguy 0c4998b091 added --generate-from-svb-key functionality (#53)
Co-authored-by: Some Random Crypto Guy <somerandomcryptoguy@protonmail.com>
2025-09-03 12:33:09 +01:00
auruya 7f25459169 add dest_asset_type check (#52) 2025-09-01 14:18:11 +01:00
14 changed files with 235 additions and 50 deletions
+30
View File
@@ -336,6 +336,34 @@ void carrot_and_legacy_account::set_keys(const cryptonote::account_keys& keys, b
m_keys.m_carrot_main_address = keys.m_carrot_main_address;
}
//----------------------------------------------------------------------------------------------------------------------
void carrot_and_legacy_account::create_from_svb_key(const cryptonote::account_public_address& address, const crypto::secret_key& svb_key)
{
// top level keys
m_keys.s_master = crypto::null_skey;
make_carrot_provespend_key(m_keys.s_master, m_keys.k_prove_spend);
m_keys.s_view_balance = svb_key;
// view balance keys
make_carrot_viewincoming_key(m_keys.s_view_balance, m_keys.k_view_incoming);
make_carrot_generateimage_key(m_keys.s_view_balance, m_keys.k_generate_image);
make_carrot_generateaddress_secret(m_keys.s_view_balance, m_keys.s_generate_address);
// carrot account address - use the provided address spend pubkey
m_keys.m_carrot_account_address = address;
k_view_incoming_dev.view_key_scalar_mult_ed25519(m_keys.m_carrot_account_address.m_spend_public_key,
m_keys.m_carrot_account_address.m_view_public_key
);
// carrot main wallet address
m_keys.m_carrot_main_address = address;
k_view_incoming_dev.view_key_scalar_mult_ed25519(crypto::get_G(),
m_keys.m_carrot_main_address.m_view_public_key
);
this->default_derive_type = AddressDeriveType::Carrot;
generate_subaddress_map();
}
//----------------------------------------------------------------------------------------------------------------------
void carrot_and_legacy_account::set_carrot_keys(const AddressDeriveType default_derive_type)
{
// top level keys
@@ -354,6 +382,7 @@ void carrot_and_legacy_account::set_carrot_keys(const AddressDeriveType default_
m_keys.m_carrot_account_address.m_spend_public_key,
m_keys.m_carrot_account_address.m_view_public_key
);
m_keys.m_carrot_account_address.m_is_carrot = true;
// carrot main wallet address
m_keys.m_carrot_main_address.m_spend_public_key = m_keys.m_carrot_account_address.m_spend_public_key;
@@ -361,6 +390,7 @@ void carrot_and_legacy_account::set_carrot_keys(const AddressDeriveType default_
crypto::get_G(),
m_keys.m_carrot_main_address.m_view_public_key
);
m_keys.m_carrot_main_address.m_is_carrot = true;
this->default_derive_type = default_derive_type;
generate_subaddress_map();
+1
View File
@@ -153,6 +153,7 @@ namespace carrot
const AddressDeriveType default_derive_type = AddressDeriveType::Carrot
);
void create_from_svb_key(const cryptonote::account_public_address& address, const crypto::secret_key& svb_key);
void set_carrot_keys(const AddressDeriveType default_derive_type = AddressDeriveType::Carrot);
void insert_subaddresses(const std::unordered_map<crypto::public_key, subaddress_index_extended>& subaddress_map);
void insert_return_output_info(
@@ -1381,17 +1381,31 @@ namespace cryptonote
for (const auto &o: tx.vout)
{
if (hf_version >= HF_VERSION_CARROT)
if (hf_version >= HF_VERSION_ENFORCE_CARROT)
{
// from v10, require outputs be carrot outputs
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_carrot_v1), false, "wrong variant type: "
<< o.target.type().name() << ", expected txout_to_carrot_v1 in transaction id=" << get_transaction_hash(tx));
} else {
} else if (hf_version >= HF_VERSION_CARROT) {
if (tx.type != cryptonote::transaction_type::PROTOCOL) {
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_carrot_v1), false, "wrong variant type: "
<< o.target.type().name() << ", expected txout_to_carrot_v1 in transaction id=" << get_transaction_hash(tx));
} else {
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key) ||
o.target.type() == typeid(txout_to_tagged_key) ||
o.target.type() == typeid(txout_to_carrot_v1), false, "wrong variant type: "
<< o.target.type().name() << ", expected txout_to_key or txout_to_tagged_key or txout_to_carrot_v1 in protocol transaction");
// require all outputs in a tx be of the same type
CHECK_AND_ASSERT_MES(o.target.type() == tx.vout[0].target.type(), false, "non-matching variant types: "
<< o.target.type().name() << " and " << tx.vout[0].target.type().name() << ", "
<< "expected matching variant types in protocol transaction");
}
}
else {
// require outputs be of type txout_to_key OR txout_to_tagged_key
// to allow grace period before requiring all to be txout_to_tagged_key
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key) || o.target.type() == typeid(txout_to_tagged_key), false, "wrong variant type: "
<< o.target.type().name() << ", expected txout_to_key or txout_to_tagged_key in transaction");
// require all outputs in a tx be of the same type
CHECK_AND_ASSERT_MES(o.target.type() == tx.vout[0].target.type(), false, "non-matching variant types: "
<< o.target.type().name() << " and " << tx.vout[0].target.type().name() << ", "
+1
View File
@@ -244,6 +244,7 @@
#define HF_VERSION_AUDIT2 8
#define HF_VERSION_AUDIT2_PAUSE 9
#define HF_VERSION_CARROT 10
#define HF_VERSION_ENFORCE_CARROT 11
#define HF_VERSION_REQUIRE_VIEW_TAGS 255
#define HF_VERSION_ENABLE_CONVERT 255
+56 -28
View File
@@ -1404,6 +1404,11 @@ bool Blockchain::prevalidate_protocol_transaction(const block& b, uint64_t heigh
CHECK_AND_ASSERT_MES(b.protocol_tx.version > 1, false, "Invalid coinbase protocol transaction version");
if (hf_version >= HF_VERSION_CARROT) {
CHECK_AND_ASSERT_MES(b.protocol_tx.version == TRANSACTION_VERSION_CARROT || 2, false, "protocol transaction has wrong version");
CHECK_AND_ASSERT_MES(b.protocol_tx.type == cryptonote::transaction_type::PROTOCOL, false, "protocol transaction has wrong type");
}
if (hf_version >= HF_VERSION_ENFORCE_CARROT) {
CHECK_AND_ASSERT_MES(b.protocol_tx.version == TRANSACTION_VERSION_CARROT, false, "protocol transaction has wrong version");
CHECK_AND_ASSERT_MES(b.protocol_tx.type == cryptonote::transaction_type::PROTOCOL, false, "protocol transaction has wrong type");
}
@@ -1516,6 +1521,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
case HF_VERSION_AUDIT2:
case HF_VERSION_AUDIT2_PAUSE:
case HF_VERSION_CARROT:
case HF_VERSION_ENFORCE_CARROT:
if (b.miner_tx.amount_burnt > 0) {
CHECK_AND_ASSERT_MES(money_in_use + b.miner_tx.amount_burnt > money_in_use, false, "miner transaction is overflowed by amount_burnt");
money_in_use += b.miner_tx.amount_burnt;
@@ -1583,7 +1589,7 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
LOG_PRINT_L1("Block at height: " << height << " - no yield payouts due - skipping");
} else {
// Iterate over the cached data for block yield, calculating the yield payouts due
if (hf_version >= HF_VERSION_CARROT) {
if (get_ideal_hard_fork_version(matured_height) >= HF_VERSION_CARROT) {
if (!calculate_yield_payouts(matured_height, carrot_yield_payouts)) {
LOG_ERROR("Block at height: " << height << " - Failed to obtain carrot yield payout information - aborting");
return false;
@@ -1981,11 +1987,14 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
cryptonote::yield_block_info ybi_matured;
bool ok = get_ybi_entry(start_height, ybi_matured);
if (ok && ybi_matured.locked_coins_this_block > 0) {
// Work out what the asset_type should be based on height of submission
uint8_t hf_submitted = m_hardfork->get_ideal_version(start_height);
// Iterate over the cached data for block yield, calculating the yield payouts due
std::vector<std::pair<yield_tx_info, uint64_t>> yield_payouts;
std::vector<std::pair<yield_tx_info_carrot, uint64_t>> carrot_yield_payouts;
if (b.major_version >= HF_VERSION_CARROT) {
std::vector<std::pair<yield_tx_info_carrot, uint64_t>> carrot_yield_payouts;
if (hf_submitted >= HF_VERSION_CARROT) {
if (!calculate_yield_payouts(start_height, carrot_yield_payouts)) {
LOG_ERROR("Failed to obtain yield payout information - aborting");
return false;
@@ -1997,11 +2006,8 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
}
}
// Work out what the asset_type should be based on height of submission
uint8_t hf_submitted = m_hardfork->get_ideal_version(start_height);
// Create the protocol_metadata entries here
if (b.major_version >= HF_VERSION_CARROT) {
if (!carrot_yield_payouts.empty()) {
for (const auto& yield_entry: carrot_yield_payouts) {
cryptonote::protocol_data_entry entry;
entry.amount_burnt = yield_entry.second;
@@ -2020,6 +2026,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
entry.origin_height = start_height;
entry.return_view_tag = yield_entry.first.return_view_tag;
entry.return_anchor_enc = yield_entry.first.return_anchor_enc;
entry.is_carrot = true;
protocol_entries.push_back(entry);
}
} else {
@@ -2040,6 +2047,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
entry.P_change = yield_entry.first.P_change;
entry.return_pubkey = yield_entry.first.return_pubkey;
entry.origin_height = start_height;
entry.is_carrot = false;
protocol_entries.push_back(entry);
}
}
@@ -3790,7 +3798,7 @@ bool Blockchain::check_tx_type_and_version(const transaction& tx, tx_verificatio
}
// Check for v1 TXs - genesis block protocol_tx exception required!
if (tx.version == 1 && epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(tx)) == "4f78ff511e860acd03138737a71505eb62eb78b620e180e58c8e13ed0e1e3e19") {
if (tx.version == 1) {
MERROR("v1 TXs are not permitted");
tvc.m_version_mismatch = true;
return false;
@@ -3823,6 +3831,32 @@ bool Blockchain::check_tx_type_and_version(const transaction& tx, tx_verificatio
}
}
if (tx.type == cryptonote::transaction_type::AUDIT) {
// Make sure we are supposed to accept AUDIT txs at this point
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS;
CHECK_AND_ASSERT_MES(audit_hard_forks.find(hf_version) != audit_hard_forks.end(), false, "trying to audit outside an audit fork");
std::string expected_asset_type = audit_hard_forks.at(hf_version).second.first;
CHECK_AND_ASSERT_MES(tx.source_asset_type == expected_asset_type, false, "trying to spend " << tx.source_asset_type << " coins in an AUDIT TX");
} else {
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
CHECK_AND_ASSERT_MES(tx.source_asset_type == "SAL1", false, "trying to spend " << tx.source_asset_type << " coins in a non-AUDIT TX");
} else {
CHECK_AND_ASSERT_MES(tx.source_asset_type == "SAL", false, "trying to spend " << tx.source_asset_type << " coins in a non-AUDIT TX");
}
}
if (tx.type == cryptonote::transaction_type::BURN) {
CHECK_AND_ASSERT_MES(tx.destination_asset_type == "BURN", false, "incorrect burn tx destination type:" << tx.destination_asset_type);
} else {
if (tx.source_asset_type != tx.destination_asset_type) {
MERROR_VER("Tx " << get_transaction_hash(tx) << " has mismatched asset types: " << tx.source_asset_type << " != " << tx.destination_asset_type);
tvc.m_verifivation_failed = true;
return false;
}
}
// Check for invalid TX types
if (tx.type == cryptonote::transaction_type::UNSET || tx.type > cryptonote::transaction_type::MAX) {
MERROR("TX type `" + std::to_string(tx.type) + "' is not supported");
@@ -4086,20 +4120,6 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
}
}
if (tx.type == cryptonote::transaction_type::AUDIT) {
// Make sure we are supposed to accept AUDIT txs at this point
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS;
CHECK_AND_ASSERT_MES(audit_hard_forks.find(hf_version) != audit_hard_forks.end(), false, "trying to audit outside an audit fork");
std::string expected_asset_type = audit_hard_forks.at(hf_version).second.first;
CHECK_AND_ASSERT_MES(tx.source_asset_type == expected_asset_type, false, "trying to spend " << tx.source_asset_type << " coins in an AUDIT TX");
} else {
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
CHECK_AND_ASSERT_MES(tx.source_asset_type == "SAL1", false, "trying to spend " << tx.source_asset_type << " coins in a non-AUDIT TX");
} else {
CHECK_AND_ASSERT_MES(tx.source_asset_type == "SAL", false, "trying to spend " << tx.source_asset_type << " coins in a non-AUDIT TX");
}
}
std::vector<std::vector<rct::ctkey>> pubkeys(tx.vin.size());
std::vector < uint64_t > results;
results.resize(tx.vin.size(), 0);
@@ -4703,7 +4723,7 @@ bool Blockchain::calculate_yield_payouts(const uint64_t start_height, std::vecto
if (!yield_entries.size()) {
// Report error and abort
LOG_ERROR("calculate_yield_payouts() called, but no yield TXs found at height " << start_height << " - aborting");
LOG_ERROR("calculate_yield_payouts() called for carrot, but no yield TXs found at height " << start_height << " - aborting");
return false;
}
@@ -4739,10 +4759,14 @@ bool Blockchain::calculate_yield_payouts(const uint64_t start_height, std::vecto
// Iterate over the yield_container, adding each proportion of the yield
for (auto& entry: yield_container) {
boost::multiprecision::int128_t locked_coins_128 = entry.first.locked_coins;
boost::multiprecision::int128_t yield_128 = (slippage_128 * locked_coins_128) / locked_total_128;
entry.second += yield_128.convert_to<uint64_t>();
uint64_t yield_u64 = boost::numeric_cast<uint64_t>(yield_128);
if (entry.second + yield_u64 < entry.second) {
throw std::overflow_error("uint64_t addition overflow");
}
entry.second += yield_u64;
}
}
@@ -4801,10 +4825,14 @@ bool Blockchain::calculate_yield_payouts(const uint64_t start_height, std::vecto
// Iterate over the yield_container, adding each proportion of the yield
for (auto& entry: yield_container) {
boost::multiprecision::int128_t locked_coins_128 = entry.first.locked_coins;
boost::multiprecision::int128_t yield_128 = (slippage_128 * locked_coins_128) / locked_total_128;
entry.second += yield_128.convert_to<uint64_t>();
uint64_t yield_u64 = boost::numeric_cast<uint64_t>(yield_128);
if (entry.second + yield_u64 < entry.second) {
throw std::overflow_error("uint64_t addition overflow");
}
entry.second += yield_u64;
}
}
+1 -1
View File
@@ -1022,7 +1022,7 @@ namespace cryptonote
}
if (!rvv.empty())
{
LOG_PRINT_L1("One transaction among this group has bad semantics, verifying one at a time");
LOG_PRINT_L1("Verifying transactions one at a time");
ret = false;
for (size_t n = 0; n < tx_info.size(); ++n)
{
+38 -8
View File
@@ -347,10 +347,12 @@ namespace cryptonote
// Clear the TX contents
tx.set_null();
tx.version = 2;
bool carrot_found = false;
bool noncarrot_found = false;
tx.type = cryptonote::transaction_type::PROTOCOL;
const bool do_carrot = hard_fork_version >= HF_VERSION_CARROT;
if (do_carrot)
const bool force_carrot = hard_fork_version >= HF_VERSION_ENFORCE_CARROT;
if (force_carrot)
{
try
{
@@ -371,7 +373,7 @@ namespace cryptonote
memcpy(e.enote_ephemeral_pubkey.data, entry.return_pubkey.data, sizeof(crypto::public_key));
enotes.push_back(e);
}
carrot_found = true;
tx = store_carrot_to_coinbase_transaction_v1(enotes, std::string{}, cryptonote::transaction_type::PROTOCOL, height);
tx.amount_burnt = 0;
tx.invalidate_hashes();
@@ -394,14 +396,31 @@ namespace cryptonote
std::vector<crypto::public_key> additional_tx_public_keys;
for (auto const& entry: protocol_data) {
if (entry.type == cryptonote::transaction_type::STAKE) {
// PAYOUT
LOG_PRINT_L2("Yield TX payout submitted " << entry.amount_burnt << entry.source_asset);
if (entry.is_carrot) {
tx_out out;
out.amount = entry.amount_burnt;
out.target = txout_to_carrot_v1 {
.key = entry.return_address,
.asset_type = entry.destination_asset,
.view_tag = entry.return_view_tag,
.encrypted_janus_anchor = entry.return_anchor_enc,
};
// Create the TX output for this refund
tx_out out;
cryptonote::set_tx_out(entry.amount_burnt, entry.destination_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
additional_tx_public_keys.push_back(entry.return_pubkey);
tx.vout.push_back(out);
additional_tx_public_keys.push_back(entry.return_pubkey);
tx.vout.push_back(out);
carrot_found = true;
} else {
// Create the TX output for this refund
tx_out out;
cryptonote::set_tx_out(entry.amount_burnt, entry.destination_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
additional_tx_public_keys.push_back(entry.return_pubkey);
tx.vout.push_back(out);
noncarrot_found = true;
}
} else if (entry.type == cryptonote::transaction_type::AUDIT) {
// PAYOUT
LOG_PRINT_L2("Audit TX payout submitted " << entry.amount_burnt << entry.source_asset);
@@ -411,9 +430,19 @@ namespace cryptonote
cryptonote::set_tx_out(entry.amount_burnt, entry.destination_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
additional_tx_public_keys.push_back(entry.return_pubkey);
tx.vout.push_back(out);
noncarrot_found = true;
}
}
if (carrot_found && noncarrot_found) {
LOG_ERROR("Cannot mix Carrot and non-Carrot outputs in the same protocol transaction");
return false;
}
if (carrot_found) {
// Ensure the TX version is correct
tx.version = TRANSACTION_VERSION_CARROT;
}
// Add in all of the additional TX pubkeys we need to process the payments
add_additional_tx_pub_keys_to_extra(tx.extra, additional_tx_public_keys);
@@ -565,6 +594,7 @@ namespace cryptonote
case HF_VERSION_AUDIT2:
case HF_VERSION_AUDIT2_PAUSE:
case HF_VERSION_CARROT:
case HF_VERSION_ENFORCE_CARROT:
// SRCG: subtract 20% that will be rewarded to staking users
CHECK_AND_ASSERT_MES(tx.amount_burnt == 0, false, "while creating outs: amount_burnt is nonzero");
tx.amount_burnt = amount / 5;
@@ -71,6 +71,7 @@ namespace cryptonote
carrot::view_tag_t return_view_tag;
carrot::encrypted_janus_anchor_t return_anchor_enc;
uint64_t origin_height;
bool is_carrot;
};
//---------------------------------------------------------------
+3
View File
@@ -92,6 +92,9 @@ const hardfork_t testnet_hard_forks[] = {
// version 10 Carrot - including treasury mint - starts from block 1100
{10, 1100, 0, 1739780005 },
// version 11 Carrot and CryptoNote starts from block 1200
{11, 1200, 0, 1756811153 },
};
const size_t num_testnet_hard_forks = sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]);
const uint64_t testnet_hard_fork_version_1_till = ((uint64_t)-1);
+73 -5
View File
@@ -192,6 +192,7 @@ namespace
const command_line::arg_descriptor<std::string> arg_generate_new_wallet = {"generate-new-wallet", sw::tr("Generate new wallet and save it to <arg>"), ""};
const command_line::arg_descriptor<std::string> arg_generate_from_device = {"generate-from-device", sw::tr("Generate new wallet from device and save it to <arg>"), ""};
const command_line::arg_descriptor<std::string> arg_generate_from_view_key = {"generate-from-view-key", sw::tr("Generate incoming-only wallet from view key"), ""};
const command_line::arg_descriptor<std::string> arg_generate_from_svb_key = {"generate-from-svb-key", sw::tr("Generate full view-only wallet from view key"), ""};
const command_line::arg_descriptor<std::string> arg_generate_from_spend_key = {"generate-from-spend-key", sw::tr("Generate deterministic wallet from spend key"), ""};
const command_line::arg_descriptor<std::string> arg_generate_from_keys = {"generate-from-keys", sw::tr("Generate wallet from private keys"), ""};
const command_line::arg_descriptor<std::string> arg_generate_from_multisig_keys = {"generate-from-multisig-keys", sw::tr("Generate a master wallet from multisig wallet keys"), ""};
@@ -4424,12 +4425,12 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
bool welcome = false;
if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_device.empty()) + (!m_generate_from_view_key.empty()) + (!m_generate_from_spend_key.empty()) + (!m_generate_from_keys.empty()) + (!m_generate_from_multisig_keys.empty()) + (!m_generate_from_json.empty()) > 1)
if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_device.empty()) + (!m_generate_from_view_key.empty()) + (!m_generate_from_svb_key.empty()) + (!m_generate_from_spend_key.empty()) + (!m_generate_from_keys.empty()) + (!m_generate_from_multisig_keys.empty()) + (!m_generate_from_json.empty()) > 1)
{
fail_msg_writer() << tr("can't specify more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\", --generate-from-view-key=\"wallet_name\", --generate-from-spend-key=\"wallet_name\", --generate-from-keys=\"wallet_name\", --generate-from-multisig-keys=\"wallet_name\", --generate-from-json=\"jsonfilename\" and --generate-from-device=\"wallet_name\"");
fail_msg_writer() << tr("can't specify more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\", --generate-from-view-key=\"wallet_name\", --generate-from-svb-key=\"wallet_name\", --generate-from-spend-key=\"wallet_name\", --generate-from-keys=\"wallet_name\", --generate-from-multisig-keys=\"wallet_name\", --generate-from-json=\"jsonfilename\" and --generate-from-device=\"wallet_name\"");
return false;
}
else if (m_generate_new.empty() && m_wallet_file.empty() && m_generate_from_device.empty() && m_generate_from_view_key.empty() && m_generate_from_spend_key.empty() && m_generate_from_keys.empty() && m_generate_from_multisig_keys.empty() && m_generate_from_json.empty())
else if (m_generate_new.empty() && m_wallet_file.empty() && m_generate_from_device.empty() && m_generate_from_view_key.empty() && m_generate_from_svb_key.empty() && m_generate_from_spend_key.empty() && m_generate_from_keys.empty() && m_generate_from_multisig_keys.empty() && m_generate_from_json.empty())
{
if(!ask_wallet_create_if_needed()) return false;
}
@@ -4584,6 +4585,69 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
password = *r;
welcome = true;
}
else if (!m_generate_from_svb_key.empty())
{
m_wallet_file = m_generate_from_svb_key;
// parse address
std::string address_string = input_line("Standard address");
if (std::cin.eof())
return false;
if (address_string.empty()) {
fail_msg_writer() << tr("No data supplied, cancelled");
return false;
}
cryptonote::address_parse_info info;
if(!get_account_address_from_str(info, nettype, address_string))
{
fail_msg_writer() << tr("failed to parse address");
return false;
}
if (info.is_subaddress)
{
fail_msg_writer() << tr("This address is a subaddress which cannot be used here.");
return false;
}
if (!info.is_carrot)
{
fail_msg_writer() << tr("This address is not a Carrot address, and cannot be used here.");
return false;
}
// parse view secret key
epee::wipeable_string viewkey_string = input_secure_line("Secret view key");
if (std::cin.eof())
return false;
if (viewkey_string.empty()) {
fail_msg_writer() << tr("No data supplied, cancelled");
return false;
}
crypto::secret_key viewkey;
if (!viewkey_string.hex_to_pod(unwrap(unwrap(viewkey))))
{
fail_msg_writer() << tr("failed to parse view key secret key");
return false;
}
// Create all of the necessary keys for Carrot view-only wallet
/*
// check the view key matches the given address
crypto::public_key pkey;
if (!crypto::secret_key_to_public_key(viewkey, pkey)) {
fail_msg_writer() << tr("failed to verify view key secret key");
return false;
}
if (info.address.m_view_public_key != pkey) {
fail_msg_writer() << tr("view key does not match standard address");
return false;
}
*/
auto r = new_wallet(vm, info.address, boost::none, viewkey);
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
password = *r;
welcome = true;
}
else if (!m_generate_from_spend_key.empty())
{
m_wallet_file = m_generate_from_spend_key;
@@ -5049,6 +5113,7 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
m_generate_new = command_line::get_arg(vm, arg_generate_new_wallet);
m_generate_from_device = command_line::get_arg(vm, arg_generate_from_device);
m_generate_from_view_key = command_line::get_arg(vm, arg_generate_from_view_key);
m_generate_from_svb_key = command_line::get_arg(vm, arg_generate_from_svb_key);
m_generate_from_spend_key = command_line::get_arg(vm, arg_generate_from_spend_key);
m_generate_from_keys = command_line::get_arg(vm, arg_generate_from_keys);
m_generate_from_multisig_keys = command_line::get_arg(vm, arg_generate_from_multisig_keys);
@@ -5064,6 +5129,7 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
m_subaddress_lookahead = command_line::get_arg(vm, arg_subaddress_lookahead);
m_use_english_language_names = command_line::get_arg(vm, arg_use_english_language_names);
m_restoring = !m_generate_from_view_key.empty() ||
!m_generate_from_svb_key.empty() ||
!m_generate_from_spend_key.empty() ||
!m_generate_from_keys.empty() ||
!m_generate_from_multisig_keys.empty() ||
@@ -5287,8 +5353,9 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr
}
//----------------------------------------------------------------------------------------------------
boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
const cryptonote::account_public_address& address, const boost::optional<crypto::secret_key>& spendkey,
const crypto::secret_key& viewkey)
const cryptonote::account_public_address& address,
const boost::optional<crypto::secret_key>& spendkey,
const crypto::secret_key& viewkey)
{
std::pair<std::unique_ptr<tools::wallet2>, tools::password_container> rc;
try { rc = tools::wallet2::make_new(vm, false, password_prompter); }
@@ -11829,6 +11896,7 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_params, arg_generate_new_wallet);
command_line::add_arg(desc_params, arg_generate_from_device);
command_line::add_arg(desc_params, arg_generate_from_view_key);
command_line::add_arg(desc_params, arg_generate_from_svb_key);
command_line::add_arg(desc_params, arg_generate_from_spend_key);
command_line::add_arg(desc_params, arg_generate_from_keys);
command_line::add_arg(desc_params, arg_generate_from_multisig_keys);
+6 -2
View File
@@ -101,8 +101,11 @@ namespace cryptonote
boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm, const crypto::secret_key& recovery_key,
bool recover, bool two_random, const std::string &old_language);
boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm, const cryptonote::account_public_address& address,
const boost::optional<crypto::secret_key>& spendkey, const crypto::secret_key& viewkey);
boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm,
const cryptonote::account_public_address& address,
const boost::optional<crypto::secret_key>& spendkey,
const crypto::secret_key& viewkey
);
boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm,
const epee::wipeable_string &multisig_keys, const epee::wipeable_string &seed_pass, const std::string &old_language);
boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm);
@@ -430,6 +433,7 @@ namespace cryptonote
std::string m_generate_new;
std::string m_generate_from_device;
std::string m_generate_from_view_key;
std::string m_generate_from_svb_key;
std::string m_generate_from_spend_key;
std::string m_generate_from_keys;
std::string m_generate_from_multisig_keys;
+1 -1
View File
@@ -1,5 +1,5 @@
#define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@"
#define DEF_SALVIUM_VERSION "1.0.0-rc2"
#define DEF_SALVIUM_VERSION "1.0.0-rc3"
#define DEF_MONERO_VERSION_TAG "release"
#define DEF_MONERO_VERSION "0.18.3.4"
#define DEF_MONERO_RELEASE_NAME "One"
+6 -2
View File
@@ -5845,7 +5845,7 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip
*/
void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& password,
const cryptonote::account_public_address &account_public_address,
const crypto::secret_key& viewkey, bool create_address_file)
const crypto::secret_key& viewkey, bool create_address_file)
{
clear();
prepare_file_names(wallet_);
@@ -5857,7 +5857,11 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file);
}
m_account.create_from_viewkey(account_public_address, viewkey);
if (account_public_address.m_is_carrot) {
m_account.create_from_svb_key(account_public_address, viewkey);
} else {
m_account.create_from_viewkey(account_public_address, viewkey);
}
init_type(hw::device::device_type::SOFTWARE);
m_watch_only = true;
m_account_public_address = account_public_address;
+1
View File
@@ -1019,6 +1019,7 @@ private:
* \param account_public_address The account's public address
* \param viewkey view secret key
* \param create_address_file Whether to create an address file
* \param is_carrot Whether viewkey is k_v (CN) or s_vb (Carrot)
*/
void generate(const std::string& wallet, const epee::wipeable_string& password,
const cryptonote::account_public_address &account_public_address,