mirror of
https://github.com/oxen-io/oxen-core.git
synced 2023-12-14 02:22:56 +01:00
Merge commit '8136bf37e2c0a76851c0bb6482b6e4c2b653f5d7' into MergeUpstream3
This commit is contained in:
commit
7c07a3e8f3
15 changed files with 284 additions and 39 deletions
|
@ -264,12 +264,12 @@ skip:
|
|||
{
|
||||
throw std::runtime_error("Aborting: tx == null_hash");
|
||||
}
|
||||
if (!db->get_tx_blob(tx_id, bd))
|
||||
if (!db->get_pruned_tx_blob(tx_id, bd))
|
||||
{
|
||||
throw std::runtime_error("Aborting: tx not found");
|
||||
}
|
||||
transaction tx;
|
||||
if (!parse_and_validate_tx_from_blob(bd, tx))
|
||||
if (!parse_and_validate_tx_base_from_blob(bd, tx))
|
||||
{
|
||||
LOG_PRINT_L0("Bad txn from db");
|
||||
return 1;
|
||||
|
|
|
@ -102,6 +102,11 @@ namespace cryptonote
|
|||
, "Run in a regression testing mode."
|
||||
, false
|
||||
};
|
||||
const command_line::arg_descriptor<bool> arg_keep_fakechain = {
|
||||
"keep-fakechain"
|
||||
, "Don't delete any existing database when in fakechain mode."
|
||||
, false
|
||||
};
|
||||
const command_line::arg_descriptor<difficulty_type> arg_fixed_difficulty = {
|
||||
"fixed-difficulty"
|
||||
, "Fixed difficulty used for testing."
|
||||
|
@ -366,6 +371,7 @@ namespace cryptonote
|
|||
command_line::add_arg(desc, arg_testnet_on);
|
||||
command_line::add_arg(desc, arg_stagenet_on);
|
||||
command_line::add_arg(desc, arg_regtest_on);
|
||||
command_line::add_arg(desc, arg_keep_fakechain);
|
||||
command_line::add_arg(desc, arg_fixed_difficulty);
|
||||
command_line::add_arg(desc, arg_dev_allow_local);
|
||||
command_line::add_arg(desc, arg_prep_blocks_threads);
|
||||
|
@ -648,6 +654,7 @@ namespace cryptonote
|
|||
size_t max_txpool_weight = command_line::get_arg(vm, arg_max_txpool_weight);
|
||||
bool const prune_blockchain = false; /* command_line::get_arg(vm, arg_prune_blockchain); */
|
||||
bool keep_alt_blocks = command_line::get_arg(vm, arg_keep_alt_blocks);
|
||||
bool keep_fakechain = command_line::get_arg(vm, arg_keep_fakechain);
|
||||
|
||||
r = init_service_keys();
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to create or load service keys");
|
||||
|
@ -681,9 +688,13 @@ namespace cryptonote
|
|||
bool sync_on_blocks = true;
|
||||
uint64_t sync_threshold = 1;
|
||||
|
||||
<<<<<<< HEAD
|
||||
std::string const lns_db_file_path = m_config_folder + "/lns.db";
|
||||
#if !defined(LOKI_ENABLE_INTEGRATION_TEST_HOOKS) // In integration mode, don't delete the DB. This should be explicitly done in the tests. Otherwise the more likely behaviour is persisting the DB across multiple daemons in the same test.
|
||||
if (m_nettype == FAKECHAIN)
|
||||
=======
|
||||
if (m_nettype == FAKECHAIN && !keep_fakechain)
|
||||
>>>>>>> 8136bf37e2c0a76851c0bb6482b6e4c2b653f5d7
|
||||
{
|
||||
// reset the db by removing the database file before opening it
|
||||
if (!db->remove_data_file(filename))
|
||||
|
@ -2484,9 +2495,10 @@ namespace cryptonote
|
|||
#endif
|
||||
|
||||
static constexpr double threshold = 1. / (864000 / DIFFICULTY_TARGET_V2); // one false positive every 10 days
|
||||
static constexpr unsigned int max_blocks_checked = 150;
|
||||
|
||||
const time_t now = time(NULL);
|
||||
const std::vector<time_t> timestamps = m_blockchain_storage.get_last_block_timestamps(60);
|
||||
const std::vector<time_t> timestamps = m_blockchain_storage.get_last_block_timestamps(max_blocks_checked);
|
||||
|
||||
static const unsigned int seconds[] = { 5400, 3600, 1800, 1200, 600 };
|
||||
for (size_t n = 0; n < sizeof(seconds)/sizeof(seconds[0]); ++n)
|
||||
|
@ -2498,7 +2510,11 @@ namespace cryptonote
|
|||
MDEBUG("blocks in the last " << seconds[n] / 60 << " minutes: " << b << " (probability " << p << ")");
|
||||
if (p < threshold)
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
MWARNING("There were " << b << " blocks in the last " << seconds[n] / 60 << " minutes, there might be large hash rate changes, or we might be partitioned, cut off from the Loki network or under attack. Or it could be just sheer bad luck.");
|
||||
=======
|
||||
MWARNING("There were " << b << (b == max_blocks_checked ? " or more" : "") << " blocks in the last " << seconds[n] / 60 << " minutes, there might be large hash rate changes, or we might be partitioned, cut off from the Monero network or under attack. Or it could be just sheer bad luck.");
|
||||
>>>>>>> 8136bf37e2c0a76851c0bb6482b6e4c2b653f5d7
|
||||
|
||||
std::shared_ptr<tools::Notify> block_rate_notify = m_block_rate_notify;
|
||||
if (block_rate_notify)
|
||||
|
|
|
@ -231,7 +231,7 @@ namespace cryptonote
|
|||
auto connection_time = time(NULL) - cntxt.m_started;
|
||||
ss << std::setw(30) << std::left << std::string(cntxt.m_is_income ? " [INC]":"[OUT]") +
|
||||
cntxt.m_remote_address.str()
|
||||
<< std::setw(20) << std::hex << peer_id
|
||||
<< std::setw(20) << nodetool::peerid_to_string(peer_id)
|
||||
<< std::setw(20) << std::hex << support_flags
|
||||
<< std::setw(30) << std::to_string(cntxt.m_recv_cnt)+ "(" + std::to_string(time(NULL) - cntxt.m_last_recv) + ")" + "/" + std::to_string(cntxt.m_send_cnt) + "(" + std::to_string(time(NULL) - cntxt.m_last_send) + ")"
|
||||
<< std::setw(25) << get_protocol_state_string(cntxt.m_state)
|
||||
|
@ -290,9 +290,7 @@ namespace cryptonote
|
|||
}
|
||||
cnx.rpc_port = cntxt.m_rpc_port;
|
||||
|
||||
std::stringstream peer_id_str;
|
||||
peer_id_str << std::hex << std::setw(16) << peer_id;
|
||||
peer_id_str >> cnx.peer_id;
|
||||
cnx.peer_id = nodetool::peerid_to_string(peer_id);
|
||||
|
||||
cnx.support_flags = support_flags;
|
||||
|
||||
|
|
|
@ -237,6 +237,16 @@ bool command_parser_executor::print_blockchain_info(const std::vector<std::strin
|
|||
}
|
||||
uint64_t start_index = 0;
|
||||
uint64_t end_index = 0;
|
||||
if (args[0][0] == '-')
|
||||
{
|
||||
int64_t nblocks;
|
||||
if(!epee::string_tools::get_xtype_from_string(nblocks, args[0]))
|
||||
{
|
||||
std::cout << "wrong number of blocks" << std::endl;
|
||||
return false;
|
||||
}
|
||||
return m_executor.print_blockchain_info(nblocks, (uint64_t)-nblocks);
|
||||
}
|
||||
if(!epee::string_tools::get_xtype_from_string(start_index, args[0]))
|
||||
{
|
||||
std::cout << "wrong starter block index parameter" << std::endl;
|
||||
|
@ -393,12 +403,15 @@ bool command_parser_executor::print_block(const std::vector<std::string>& args)
|
|||
|
||||
bool command_parser_executor::print_transaction(const std::vector<std::string>& args)
|
||||
{
|
||||
bool include_metadata = false;
|
||||
bool include_hex = false;
|
||||
bool include_json = false;
|
||||
|
||||
// Assumes that optional flags come after mandatory argument <transaction_hash>
|
||||
for (unsigned int i = 1; i < args.size(); ++i) {
|
||||
if (args[i] == "+hex")
|
||||
if (args[i] == "+meta")
|
||||
include_metadata = true;
|
||||
else if (args[i] == "+hex")
|
||||
include_hex = true;
|
||||
else if (args[i] == "+json")
|
||||
include_json = true;
|
||||
|
@ -410,7 +423,7 @@ bool command_parser_executor::print_transaction(const std::vector<std::string>&
|
|||
}
|
||||
if (args.empty())
|
||||
{
|
||||
std::cout << "expected: print_tx <transaction_hash> [+hex] [+json]" << std::endl;
|
||||
std::cout << "expected: print_tx <transaction_hash> [+meta] [+hex] [+json]" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -418,7 +431,7 @@ bool command_parser_executor::print_transaction(const std::vector<std::string>&
|
|||
crypto::hash tx_hash;
|
||||
if (parse_hash256(str_hash, tx_hash))
|
||||
{
|
||||
m_executor.print_transaction(tx_hash, include_hex, include_json);
|
||||
m_executor.print_transaction(tx_hash, include_metadata, include_hex, include_json);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -644,7 +644,7 @@ bool rpc_command_executor::print_connections() {
|
|||
<< std::setw(30) << std::left << address
|
||||
<< std::setw(8) << (get_address_type_name((epee::net_utils::address_type)info.address_type))
|
||||
<< std::setw(6) << (info.ssl ? "yes" : "no")
|
||||
<< std::setw(20) << epee::string_tools::pad_string(info.peer_id, 16, '0', true)
|
||||
<< std::setw(20) << info.peer_id
|
||||
<< std::setw(20) << info.support_flags
|
||||
<< std::setw(30) << std::to_string(info.recv_count) + "(" + std::to_string(info.recv_idle_time) + ")/" + std::to_string(info.send_count) + "(" + std::to_string(info.send_idle_time) + ")"
|
||||
<< std::setw(25) << info.state
|
||||
|
@ -698,16 +698,72 @@ bool rpc_command_executor::print_net_stats()
|
|||
return true;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
bool rpc_command_executor::print_blockchain_info(uint64_t start_block_index, uint64_t end_block_index) {
|
||||
GET_BLOCK_HEADERS_RANGE::request req{};
|
||||
GET_BLOCK_HEADERS_RANGE::response res{};
|
||||
=======
|
||||
bool t_rpc_command_executor::print_blockchain_info(int64_t start_block_index, uint64_t end_block_index) {
|
||||
cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::request req;
|
||||
cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::response res;
|
||||
epee::json_rpc::error error_resp;
|
||||
std::string fail_message = "Problem fetching info";
|
||||
|
||||
// negative: relative to the end
|
||||
if (start_block_index < 0)
|
||||
{
|
||||
cryptonote::COMMAND_RPC_GET_INFO::request ireq;
|
||||
cryptonote::COMMAND_RPC_GET_INFO::response ires;
|
||||
if (m_is_rpc)
|
||||
{
|
||||
if (!m_rpc_client->rpc_request(ireq, ires, "/getinfo", fail_message.c_str()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_rpc_server->on_get_info(ireq, ires) || ires.status != CORE_RPC_STATUS_OK)
|
||||
{
|
||||
tools::fail_msg_writer() << make_error(fail_message, ires.status);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (start_block_index < 0 && (uint64_t)-start_block_index >= ires.height)
|
||||
{
|
||||
tools::fail_msg_writer() << "start offset is larger than blockchain height";
|
||||
return true;
|
||||
}
|
||||
start_block_index = ires.height + start_block_index;
|
||||
end_block_index = start_block_index + end_block_index - 1;
|
||||
}
|
||||
>>>>>>> 8136bf37e2c0a76851c0bb6482b6e4c2b653f5d7
|
||||
|
||||
req.start_height = start_block_index;
|
||||
req.end_height = end_block_index;
|
||||
req.fill_pow_hash = false;
|
||||
|
||||
<<<<<<< HEAD
|
||||
if (!invoke<GET_BLOCK_HEADERS_RANGE>(std::move(req), res, "Failed to retrieve block headers"))
|
||||
return false;
|
||||
=======
|
||||
fail_message = "Failed calling getblockheadersrange";
|
||||
if (m_is_rpc)
|
||||
{
|
||||
if (!m_rpc_client->json_rpc_request(req, res, "getblockheadersrange", fail_message.c_str()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_rpc_server->on_get_block_headers_range(req, res, error_resp) || res.status != CORE_RPC_STATUS_OK)
|
||||
{
|
||||
tools::fail_msg_writer() << make_error(fail_message, res.status);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
>>>>>>> 8136bf37e2c0a76851c0bb6482b6e4c2b653f5d7
|
||||
|
||||
bool first = true;
|
||||
for (auto & header : res.headers)
|
||||
|
@ -813,7 +869,12 @@ bool rpc_command_executor::print_block_by_height(uint64_t height, bool include_h
|
|||
return print_block(std::move(req), include_hex);
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
bool rpc_command_executor::print_transaction(const crypto::hash& transaction_hash,
|
||||
=======
|
||||
bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash,
|
||||
bool include_metadata,
|
||||
>>>>>>> 8136bf37e2c0a76851c0bb6482b6e4c2b653f5d7
|
||||
bool include_hex,
|
||||
bool include_json) {
|
||||
GET_TRANSACTIONS::request req{};
|
||||
|
@ -841,6 +902,29 @@ bool rpc_command_executor::print_transaction(const crypto::hash& transaction_has
|
|||
const std::string &as_hex = (1 == res.txs.size()) ? res.txs.front().as_hex : res.txs_as_hex.front();
|
||||
const std::string &pruned_as_hex = (1 == res.txs.size()) ? res.txs.front().pruned_as_hex : "";
|
||||
const std::string &prunable_as_hex = (1 == res.txs.size()) ? res.txs.front().prunable_as_hex : "";
|
||||
// Print metadata if requested
|
||||
if (include_metadata)
|
||||
{
|
||||
if (!res.txs.front().in_pool)
|
||||
{
|
||||
tools::msg_writer() << "Block timestamp: " << res.txs.front().block_timestamp << " (" << tools::get_human_readable_timestamp(res.txs.front().block_timestamp) << ")";
|
||||
}
|
||||
cryptonote::blobdata blob;
|
||||
if (epee::string_tools::parse_hexstr_to_binbuff(pruned_as_hex + prunable_as_hex, blob))
|
||||
{
|
||||
cryptonote::transaction tx;
|
||||
if (cryptonote::parse_and_validate_tx_from_blob(blob, tx))
|
||||
{
|
||||
tools::msg_writer() << "Size: " << blob.size();
|
||||
tools::msg_writer() << "Weight: " << cryptonote::get_transaction_weight(tx);
|
||||
}
|
||||
else
|
||||
tools::fail_msg_writer() << "Error parsing transaction blob";
|
||||
}
|
||||
else
|
||||
tools::fail_msg_writer() << "Error parsing transaction from hex";
|
||||
}
|
||||
|
||||
// Print raw hex if requested
|
||||
if (include_hex)
|
||||
{
|
||||
|
@ -1509,7 +1593,7 @@ bool rpc_command_executor::sync_info()
|
|||
for (const auto &s: res.spans)
|
||||
if (s.connection_id == p.info.connection_id)
|
||||
nblocks += s.nblocks, size += s.size;
|
||||
tools::success_msg_writer() << address << " " << epee::string_tools::pad_string(p.info.peer_id, 16, '0', true) << " " <<
|
||||
tools::success_msg_writer() << address << " " << p.info.peer_id << " " <<
|
||||
epee::string_tools::pad_string(p.info.state, 16) << " " <<
|
||||
epee::string_tools::pad_string(epee::string_tools::to_string_hex(p.info.pruning_seed), 8) << " " << p.info.height << " " <<
|
||||
p.info.current_download << " kB/s, " << nblocks << " blocks / " << size/1e6 << " MB queued";
|
||||
|
|
|
@ -112,7 +112,7 @@ public:
|
|||
|
||||
bool print_connections();
|
||||
|
||||
bool print_blockchain_info(uint64_t start_block_index, uint64_t end_block_index);
|
||||
bool print_blockchain_info(int64_t start_block_index, uint64_t end_block_index);
|
||||
|
||||
bool print_quorum_state(uint64_t start_height, uint64_t end_height);
|
||||
|
||||
|
@ -130,7 +130,11 @@ public:
|
|||
|
||||
bool print_block_by_height(uint64_t height, bool include_hex);
|
||||
|
||||
<<<<<<< HEAD
|
||||
bool print_transaction(const crypto::hash& transaction_hash, bool include_hex, bool include_json);
|
||||
=======
|
||||
bool print_transaction(crypto::hash transaction_hash, bool include_metadata, bool include_hex, bool include_json);
|
||||
>>>>>>> 8136bf37e2c0a76851c0bb6482b6e4c2b653f5d7
|
||||
|
||||
bool is_key_image_spent(const crypto::key_image &ki);
|
||||
|
||||
|
|
|
@ -1364,7 +1364,7 @@ namespace nodetool
|
|||
bool node_server<t_payload_net_handler>::make_new_connection_from_anchor_peerlist(const std::vector<anchor_peerlist_entry>& anchor_peerlist)
|
||||
{
|
||||
for (const auto& pe: anchor_peerlist) {
|
||||
_note("Considering connecting (out) to anchor peer: " << peerid_type(pe.id) << " " << pe.adr.str());
|
||||
_note("Considering connecting (out) to anchor peer: " << peerid_to_string(pe.id) << " " << pe.adr.str());
|
||||
|
||||
if(is_peer_used(pe)) {
|
||||
_note("Peer is used");
|
||||
|
@ -1949,7 +1949,7 @@ namespace nodetool
|
|||
const network_zone& zone = m_network_zones.at(zone_type);
|
||||
if(zone.m_config.m_peer_id != tr.peer_id)
|
||||
{
|
||||
MWARNING("check_trust failed: peer_id mismatch (passed " << tr.peer_id << ", expected " << zone.m_config.m_peer_id<< ")");
|
||||
MWARNING("check_trust failed: peer_id mismatch (passed " << tr.peer_id << ", expected " << peerid_to_string(zone.m_config.m_peer_id) << ")");
|
||||
return false;
|
||||
}
|
||||
crypto::public_key pk{};
|
||||
|
@ -2218,7 +2218,7 @@ namespace nodetool
|
|||
network_zone& zone = m_network_zones.at(address.get_zone());
|
||||
if(rsp.status != PING_OK_RESPONSE_STATUS_TEXT || pr != rsp.peer_id)
|
||||
{
|
||||
LOG_WARNING_CC(ping_context, "back ping invoke wrong response \"" << rsp.status << "\" from" << address.str() << ", hsh_peer_id=" << pr_ << ", rsp.peer_id=" << rsp.peer_id);
|
||||
LOG_WARNING_CC(ping_context, "back ping invoke wrong response \"" << rsp.status << "\" from" << address.str() << ", hsh_peer_id=" << pr_ << ", rsp.peer_id=" << peerid_to_string(rsp.peer_id));
|
||||
zone.m_net_server.get_config_object().close(ping_context.m_connection_id);
|
||||
return;
|
||||
}
|
||||
|
@ -2451,7 +2451,7 @@ namespace nodetool
|
|||
zone.second.m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
|
||||
{
|
||||
ss << cntxt.m_remote_address.str()
|
||||
<< " \t\tpeer_id " << cntxt.peer_id
|
||||
<< " \t\tpeer_id " << peerid_to_string(cntxt.peer_id)
|
||||
<< " \t\tconn_id " << cntxt.m_connection_id << (cntxt.m_is_income ? " INC":" OUT")
|
||||
<< std::endl;
|
||||
return true;
|
||||
|
@ -2709,12 +2709,17 @@ namespace nodetool
|
|||
if (!check_connection_and_handshake_with_peer(pe.adr, pe.last_seen))
|
||||
{
|
||||
zone.second.m_peerlist.remove_from_peer_gray(pe);
|
||||
LOG_PRINT_L2("PEER EVICTED FROM GRAY PEER LIST IP address: " << pe.adr.host_str() << " Peer ID: " << peerid_type(pe.id));
|
||||
LOG_PRINT_L2("PEER EVICTED FROM GRAY PEER LIST: address: " << pe.adr.host_str() << " Peer ID: " << peerid_to_string(pe.id));
|
||||
}
|
||||
else
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
zone.second.m_peerlist.set_peer_just_seen(pe.id, pe.adr, pe.pruning_seed, pe.rpc_port);
|
||||
LOG_PRINT_L2("PEER PROMOTED TO WHITE PEER LIST IP address: " << pe.adr.host_str() << " Peer ID: " << peerid_type(pe.id));
|
||||
=======
|
||||
zone.second.m_peerlist.set_peer_just_seen(pe.id, pe.adr, pe.pruning_seed, pe.rpc_port, pe.rpc_credits_per_hash);
|
||||
LOG_PRINT_L2("PEER PROMOTED TO WHITE PEER LIST IP address: " << pe.adr.host_str() << " Peer ID: " << peerid_to_string(pe.id));
|
||||
>>>>>>> 8136bf37e2c0a76851c0bb6482b6e4c2b653f5d7
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -128,7 +128,7 @@ namespace nodetool
|
|||
ss << std::setfill ('0') << std::setw (8) << std::hex << std::noshowbase;
|
||||
for(const peerlist_entry& pe: pl)
|
||||
{
|
||||
ss << pe.id << "\t" << pe.adr.str()
|
||||
ss << peerid_to_string(pe.id) << "\t" << pe.adr.str()
|
||||
<< " \trpc port " << (pe.rpc_port > 0 ? std::to_string(pe.rpc_port) : "-")
|
||||
<< " \tpruning seed " << pe.pruning_seed
|
||||
<< " \tlast_seen: " << (pe.last_seen == 0 ? std::string("never") : epee::misc_utils::get_time_interval_string(now_time - pe.last_seen))
|
||||
|
|
|
@ -202,7 +202,7 @@ namespace
|
|||
const char* USAGE_GET_TX_NOTE("get_tx_note <txid>");
|
||||
const char* USAGE_GET_DESCRIPTION("get_description");
|
||||
const char* USAGE_SET_DESCRIPTION("set_description [free text note]");
|
||||
const char* USAGE_SIGN("sign <filename>");
|
||||
const char* USAGE_SIGN("sign [<account_index>,<address_index>] <filename>");
|
||||
const char* USAGE_VERIFY("verify <filename> <address> <signature>");
|
||||
const char* USAGE_EXPORT_KEY_IMAGES("export_key_images <filename> [requested-only]");
|
||||
const char* USAGE_IMPORT_KEY_IMAGES("import_key_images <filename>");
|
||||
|
@ -2756,6 +2756,7 @@ simple_wallet::simple_wallet()
|
|||
m_cmd_binder.set_handler("set",
|
||||
boost::bind(&simple_wallet::on_command, this, &simple_wallet::set_variable, _1),
|
||||
tr(USAGE_SET_VARIABLE),
|
||||
<<<<<<< HEAD
|
||||
tr(R"(Available options:
|
||||
seed language
|
||||
Set the wallet's seed language.
|
||||
|
@ -2809,6 +2810,77 @@ ignore-outputs-below <amount>
|
|||
Device name for hardware wallet.
|
||||
export-format <\"binary\"|\"ascii\">
|
||||
Save all exported files as binary (cannot be copied and pasted) or ascii (can be).)"));
|
||||
=======
|
||||
tr("Available options:\n "
|
||||
"seed language\n "
|
||||
" Set the wallet's seed language.\n "
|
||||
"always-confirm-transfers <1|0>\n "
|
||||
" Whether to confirm unsplit txes.\n "
|
||||
"print-ring-members <1|0>\n "
|
||||
" Whether to print detailed information about ring members during confirmation.\n "
|
||||
"store-tx-info <1|0>\n "
|
||||
" Whether to store outgoing tx info (destination address, payment ID, tx secret key) for future reference.\n "
|
||||
"default-ring-size <n>\n "
|
||||
" Set the default ring size (obsolete).\n "
|
||||
"auto-refresh <1|0>\n "
|
||||
" Whether to automatically synchronize new blocks from the daemon.\n "
|
||||
"refresh-type <full|optimize-coinbase|no-coinbase|default>\n "
|
||||
" Set the wallet's refresh behaviour.\n "
|
||||
"priority [0|1|2|3|4]\n "
|
||||
" Set the fee to default/unimportant/normal/elevated/priority.\n "
|
||||
"confirm-missing-payment-id <1|0> (obsolete)\n "
|
||||
"ask-password <0|1|2 (or never|action|decrypt)>\n "
|
||||
" action: ask the password before many actions such as transfer, etc\n "
|
||||
" decrypt: same as action, but keeps the spend key encrypted in memory when not needed\n "
|
||||
"unit <monero|millinero|micronero|nanonero|piconero>\n "
|
||||
" Set the default monero (sub-)unit.\n "
|
||||
"min-outputs-count [n]\n "
|
||||
" Try to keep at least that many outputs of value at least min-outputs-value.\n "
|
||||
"min-outputs-value [n]\n "
|
||||
" Try to keep at least min-outputs-count outputs of at least that value.\n "
|
||||
"merge-destinations <1|0>\n "
|
||||
" Whether to merge multiple payments to the same destination address.\n "
|
||||
"confirm-backlog <1|0>\n "
|
||||
" Whether to warn if there is transaction backlog.\n "
|
||||
"confirm-backlog-threshold [n]\n "
|
||||
" Set a threshold for confirm-backlog to only warn if the transaction backlog is greater than n blocks.\n "
|
||||
"confirm-export-overwrite <1|0>\n "
|
||||
" Whether to warn if the file to be exported already exists.\n "
|
||||
"refresh-from-block-height [n]\n "
|
||||
" Set the height before which to ignore blocks.\n "
|
||||
"auto-low-priority <1|0>\n "
|
||||
" Whether to automatically use the low priority fee level when it's safe to do so.\n "
|
||||
"segregate-pre-fork-outputs <1|0>\n "
|
||||
" Set this if you intend to spend outputs on both Monero AND a key reusing fork.\n "
|
||||
"key-reuse-mitigation2 <1|0>\n "
|
||||
" Set this if you are not sure whether you will spend on a key reusing Monero fork later.\n "
|
||||
"subaddress-lookahead <major>:<minor>\n "
|
||||
" Set the lookahead sizes for the subaddress hash table.\n "
|
||||
"segregation-height <n>\n "
|
||||
" Set to the height of a key reusing fork you want to use, 0 to use default.\n "
|
||||
"ignore-fractional-outputs <1|0>\n "
|
||||
" Whether to ignore fractional outputs that result in net loss when spending due to fee.\n "
|
||||
"ignore-outputs-above <amount>\n "
|
||||
" Ignore outputs of amount above this threshold when spending. Value 0 is translated to the maximum value (18 million) which disables this filter.\n "
|
||||
"ignore-outputs-below <amount>\n "
|
||||
" Ignore outputs of amount below this threshold when spending.\n "
|
||||
"track-uses <1|0>\n "
|
||||
" Whether to keep track of owned outputs uses.\n "
|
||||
"setup-background-mining <1|0>\n "
|
||||
" Whether to enable background mining. Set this to support the network and to get a chance to receive new monero.\n "
|
||||
"device-name <device_name[:device_spec]>\n "
|
||||
" Device name for hardware wallet.\n "
|
||||
"export-format <\"binary\"|\"ascii\">\n "
|
||||
" Save all exported files as binary (cannot be copied and pasted) or ascii (can be).\n "
|
||||
"persistent-client-id <1|0>\n "
|
||||
" Whether to keep using the same client id for RPC payment over wallet restarts.\n"
|
||||
"auto-mine-for-rpc-payment-threshold <float>\n "
|
||||
" Whether to automatically start mining for RPC payment if the daemon requires it.\n"
|
||||
"credits-target <unsigned int>\n"
|
||||
" The RPC payment credits balance to target (0 for default).\n "
|
||||
"inactivity-lock-timeout <unsigned int>\n "
|
||||
" How many seconds to wait before locking the wallet (0 to disable)."));
|
||||
>>>>>>> 8136bf37e2c0a76851c0bb6482b6e4c2b653f5d7
|
||||
m_cmd_binder.set_handler("encrypted_seed",
|
||||
boost::bind(&simple_wallet::on_command, this, &simple_wallet::encrypted_seed, _1),
|
||||
tr("Display the encrypted Electrum-style mnemonic seed."));
|
||||
|
@ -2904,7 +2976,7 @@ Pending or Failed: "failed"|"pending", "out", Lock, Checkpointed, Time, Amount*
|
|||
m_cmd_binder.set_handler("sign",
|
||||
boost::bind(&simple_wallet::on_command, this, &simple_wallet::sign, _1),
|
||||
tr(USAGE_SIGN),
|
||||
tr("Sign the contents of a file."));
|
||||
tr("Sign the contents of a file with the given subaddress (or the main address if not specified)"));
|
||||
m_cmd_binder.set_handler("verify",
|
||||
boost::bind(&simple_wallet::on_command, this, &simple_wallet::verify, _1),
|
||||
tr(USAGE_VERIFY),
|
||||
|
@ -5563,7 +5635,8 @@ void simple_wallet::check_for_inactivity_lock(bool user)
|
|||
|
||||
while (1)
|
||||
{
|
||||
tools::msg_writer() << tr("Locked due to inactivity. The wallet password is required to unlock the console.");
|
||||
const char *inactivity_msg = user ? "" : tr("Locked due to inactivity.");
|
||||
tools::msg_writer() << inactivity_msg << (inactivity_msg[0] ? " " : "") << tr("The wallet password is required to unlock the console.");
|
||||
try
|
||||
{
|
||||
if (get_and_verify_password())
|
||||
|
@ -9265,7 +9338,7 @@ bool simple_wallet::sign(const std::vector<std::string> &args)
|
|||
fail_msg_writer() << tr("command not supported by HW wallet");
|
||||
return true;
|
||||
}
|
||||
if (args.size() != 1)
|
||||
if (args.size() != 1 && args.size() != 2)
|
||||
{
|
||||
PRINT_USAGE(USAGE_SIGN);
|
||||
return true;
|
||||
|
@ -9281,7 +9354,20 @@ bool simple_wallet::sign(const std::vector<std::string> &args)
|
|||
return true;
|
||||
}
|
||||
|
||||
std::string filename = args[0];
|
||||
subaddress_index index{0, 0};
|
||||
if (args.size() == 2)
|
||||
{
|
||||
unsigned int a, b;
|
||||
if (sscanf(args[0].c_str(), "%u,%u", &a, &b) != 2)
|
||||
{
|
||||
fail_msg_writer() << tr("Invalid subaddress index format");
|
||||
return true;
|
||||
}
|
||||
index.major = a;
|
||||
index.minor = b;
|
||||
}
|
||||
|
||||
const std::string &filename = args.back();
|
||||
std::string data;
|
||||
bool r = m_wallet->load_from_file(filename, data);
|
||||
if (!r)
|
||||
|
@ -9292,7 +9378,7 @@ bool simple_wallet::sign(const std::vector<std::string> &args)
|
|||
|
||||
SCOPED_WALLET_UNLOCK();
|
||||
|
||||
std::string signature = m_wallet->sign(data);
|
||||
std::string signature = m_wallet->sign(data, index);
|
||||
success_msg_writer() << signature;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -13111,13 +13111,27 @@ void wallet2::set_account_tag_description(const std::string& tag, const std::str
|
|||
m_account_tags.first[tag] = description;
|
||||
}
|
||||
|
||||
std::string wallet2::sign(const std::string &data) const
|
||||
std::string wallet2::sign(const std::string &data, cryptonote::subaddress_index index) const
|
||||
{
|
||||
crypto::hash hash;
|
||||
crypto::cn_fast_hash(data.data(), data.size(), hash);
|
||||
const cryptonote::account_keys &keys = m_account.get_keys();
|
||||
crypto::signature signature;
|
||||
crypto::generate_signature(hash, keys.m_account_address.m_spend_public_key, keys.m_spend_secret_key, signature);
|
||||
crypto::secret_key skey;
|
||||
crypto::public_key pkey;
|
||||
if (index.is_zero())
|
||||
{
|
||||
skey = keys.m_spend_secret_key;
|
||||
pkey = keys.m_account_address.m_spend_public_key;
|
||||
}
|
||||
else
|
||||
{
|
||||
skey = keys.m_spend_secret_key;
|
||||
crypto::secret_key m = m_account.get_device().get_subaddress_secret_key(keys.m_view_secret_key, index);
|
||||
sc_add((unsigned char*)&skey, (unsigned char*)&m, (unsigned char*)&skey);
|
||||
secret_key_to_public_key(skey, pkey);
|
||||
}
|
||||
crypto::generate_signature(hash, pkey, skey, signature);
|
||||
return std::string("SigV1") + tools::base58::encode(std::string((const char *)&signature, sizeof(signature)));
|
||||
}
|
||||
|
||||
|
|
|
@ -1337,7 +1337,7 @@ private:
|
|||
*/
|
||||
void set_account_tag_description(const std::string& tag, const std::string& description);
|
||||
|
||||
std::string sign(const std::string &data) const;
|
||||
std::string sign(const std::string &data, cryptonote::subaddress_index index = {0, 0}) const;
|
||||
bool verify(const std::string &data, const cryptonote::account_public_address &address, const std::string &signature) const;
|
||||
|
||||
/*!
|
||||
|
|
|
@ -1846,7 +1846,7 @@ namespace tools
|
|||
return false;
|
||||
}
|
||||
|
||||
res.signature = m_wallet->sign(req.data);
|
||||
res.signature = m_wallet->sign(req.data, {req.account_index, req.address_index});
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -1590,10 +1590,18 @@ namespace wallet_rpc
|
|||
{
|
||||
struct request
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
std::string data; // Anything you need to sign.
|
||||
=======
|
||||
std::string data;
|
||||
uint32_t account_index;
|
||||
uint32_t address_index;
|
||||
>>>>>>> 8136bf37e2c0a76851c0bb6482b6e4c2b653f5d7
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(data);
|
||||
KV_SERIALIZE(data)
|
||||
KV_SERIALIZE_OPT(account_index, 0u)
|
||||
KV_SERIALIZE_OPT(address_index, 0u)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
|
|
@ -43,7 +43,8 @@ from framework.wallet import Wallet
|
|||
class MessageSigningTest():
|
||||
def run_test(self):
|
||||
self.create()
|
||||
self.check_signing()
|
||||
self.check_signing(False)
|
||||
self.check_signing(True)
|
||||
|
||||
def create(self):
|
||||
print('Creating wallets')
|
||||
|
@ -65,20 +66,34 @@ class MessageSigningTest():
|
|||
assert res.address == self.address[i]
|
||||
assert res.seed == seeds[i]
|
||||
|
||||
def check_signing(self):
|
||||
print('Signing/verifing messages')
|
||||
def check_signing(self, subaddress):
|
||||
print('Signing/verifing messages with ' + ('subaddress' if subaddress else 'standard address'))
|
||||
messages = ['foo', '']
|
||||
if subaddress:
|
||||
address = []
|
||||
for i in range(2):
|
||||
res = self.wallet[i].create_account()
|
||||
if i == 0:
|
||||
account_index = res.account_index
|
||||
res = self.wallet[i].create_address(account_index = account_index)
|
||||
if i == 0:
|
||||
address_index = res.address_index
|
||||
address.append(res.address)
|
||||
else:
|
||||
address = [self.address[0], self.address[1]]
|
||||
account_index = 0
|
||||
address_index = 0
|
||||
for message in messages:
|
||||
res = self.wallet[0].sign(message)
|
||||
res = self.wallet[0].sign(message, account_index = account_index, address_index = address_index)
|
||||
signature = res.signature
|
||||
for i in range(2):
|
||||
res = self.wallet[i].verify(message, self.address[0], signature)
|
||||
res = self.wallet[i].verify(message, address[0], signature)
|
||||
assert res.good
|
||||
res = self.wallet[i].verify('different', self.address[0], signature)
|
||||
res = self.wallet[i].verify('different', address[0], signature)
|
||||
assert not res.good
|
||||
res = self.wallet[i].verify(message, self.address[1], signature)
|
||||
res = self.wallet[i].verify(message, address[1], signature)
|
||||
assert not res.good
|
||||
res = self.wallet[i].verify(message, self.address[0], signature + 'x')
|
||||
res = self.wallet[i].verify(message, address[0], signature + 'x')
|
||||
assert not res.good
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -706,11 +706,13 @@ class Wallet(object):
|
|||
}
|
||||
return self.rpc.send_json_rpc_request(check_reserve_proof)
|
||||
|
||||
def sign(self, data):
|
||||
def sign(self, data, account_index = 0, address_index = 0):
|
||||
sign = {
|
||||
'method': 'sign',
|
||||
'params' : {
|
||||
'data': data,
|
||||
'account_index': account_index,
|
||||
'address_index': address_index,
|
||||
},
|
||||
'jsonrpc': '2.0',
|
||||
'id': '0'
|
||||
|
|
Loading…
Reference in a new issue