Merge commit '8136bf37e2c0a76851c0bb6482b6e4c2b653f5d7' into MergeUpstream3

This commit is contained in:
Doyle 2020-05-27 15:40:27 +10:00
commit 7c07a3e8f3
15 changed files with 284 additions and 39 deletions

View file

@ -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;

View file

@ -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)

View file

@ -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;

View file

@ -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;

View file

@ -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";

View file

@ -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);

View file

@ -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;

View file

@ -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))

View file

@ -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;
}

View file

@ -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)));
}

View file

@ -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;
/*!

View file

@ -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;
}
//------------------------------------------------------------------------------------------------------------------------------

View file

@ -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()
};

View file

@ -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__':

View file

@ -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'