aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/crypto/crypto.cpp6
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.cpp16
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.h2
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp9
-rw-r--r--src/cryptonote_core/cryptonote_core.h2
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.cpp2
-rw-r--r--src/cryptonote_core/tx_pool.cpp6
-rw-r--r--src/device/device.hpp5
-rw-r--r--src/device/device_default.cpp4
-rw-r--r--src/device/device_default.hpp1
-rw-r--r--src/device/device_ledger.cpp78
-rw-r--r--src/device/device_ledger.hpp2
-rw-r--r--src/device_trezor/device_trezor.cpp63
-rw-r--r--src/device_trezor/device_trezor.hpp3
-rw-r--r--src/device_trezor/device_trezor_base.cpp110
-rw-r--r--src/device_trezor/device_trezor_base.hpp8
-rw-r--r--src/device_trezor/trezor/debug_link.cpp4
-rw-r--r--src/device_trezor/trezor/debug_link.hpp2
-rw-r--r--src/device_trezor/trezor/protocol.cpp232
-rw-r--r--src/device_trezor/trezor/protocol.hpp28
-rw-r--r--src/device_trezor/trezor/transport.cpp69
-rw-r--r--src/device_trezor/trezor/transport.hpp13
-rw-r--r--src/multisig/multisig.cpp7
-rw-r--r--src/net/zmq.cpp18
-rw-r--r--src/net/zmq.h24
-rw-r--r--src/p2p/net_node.h5
-rw-r--r--src/p2p/net_node.inl248
-rw-r--r--src/ringct/bulletproofs.cc20
-rw-r--r--src/ringct/rctOps.cpp12
-rw-r--r--src/ringct/rctOps.h1
-rw-r--r--src/ringct/rctSigs.cpp5
-rw-r--r--src/ringct/rctTypes.h3
-rw-r--r--src/rpc/bootstrap_node_selector.h2
-rw-r--r--src/rpc/core_rpc_server.cpp4
-rw-r--r--src/rpc/daemon_handler.cpp17
-rw-r--r--src/rpc/daemon_handler.h3
-rw-r--r--src/rpc/daemon_messages.cpp106
-rw-r--r--src/rpc/daemon_messages.h6
-rw-r--r--src/rpc/message.cpp24
-rw-r--r--src/rpc/message.h17
-rw-r--r--src/rpc/rpc_handler.h3
-rw-r--r--src/rpc/zmq_server.cpp9
-rw-r--r--src/serialization/json_object.cpp86
-rw-r--r--src/serialization/json_object.h104
-rw-r--r--src/simplewallet/simplewallet.cpp82
-rw-r--r--src/simplewallet/simplewallet.h5
-rw-r--r--src/wallet/api/wallet.cpp6
-rw-r--r--src/wallet/api/wallet2_api.h4
-rw-r--r--src/wallet/message_store.cpp2
-rw-r--r--src/wallet/wallet2.cpp84
-rw-r--r--src/wallet/wallet2.h14
-rw-r--r--src/wallet/wallet_rpc_server.cpp9
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h6
53 files changed, 1039 insertions, 562 deletions
diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp
index 0ec992de9..8a03f28bb 100644
--- a/src/crypto/crypto.cpp
+++ b/src/crypto/crypto.cpp
@@ -294,6 +294,7 @@ namespace crypto {
sc_mulsub(&sig.r, &sig.c, &unwrap(sec), &k);
if (!sc_isnonzero((const unsigned char*)sig.r.data))
goto try_again;
+ memwipe(&k, sizeof(k));
}
bool crypto_ops::check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig) {
@@ -390,6 +391,8 @@ namespace crypto {
// sig.r = k - sig.c*r
sc_mulsub(&sig.r, &sig.c, &unwrap(r), &k);
+
+ memwipe(&k, sizeof(k));
}
bool crypto_ops::check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const signature &sig) {
@@ -560,6 +563,7 @@ POP_WARNINGS
random_scalar(sig[i].c);
random_scalar(sig[i].r);
if (ge_frombytes_vartime(&tmp3, &*pubs[i]) != 0) {
+ memwipe(&k, sizeof(k));
local_abort("invalid pubkey");
}
ge_double_scalarmult_base_vartime(&tmp2, &sig[i].c, &tmp3, &sig[i].r);
@@ -573,6 +577,8 @@ POP_WARNINGS
hash_to_scalar(buf.get(), rs_comm_size(pubs_count), h);
sc_sub(&sig[sec_index].c, &h, &sum);
sc_mulsub(&sig[sec_index].r, &sig[sec_index].c, &unwrap(sec), &k);
+
+ memwipe(&k, sizeof(k));
}
bool crypto_ops::check_ring_signature(const hash &prefix_hash, const key_image &image,
diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp
index 80747dd89..cb6d1ec91 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.cpp
+++ b/src/cryptonote_basic/cryptonote_format_utils.cpp
@@ -126,6 +126,20 @@ namespace cryptonote
namespace cryptonote
{
//---------------------------------------------------------------
+ void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h, hw::device &hwdev)
+ {
+ hwdev.get_transaction_prefix_hash(tx,h);
+ }
+
+ //---------------------------------------------------------------
+ crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx, hw::device &hwdev)
+ {
+ crypto::hash h = null_hash;
+ get_transaction_prefix_hash(tx, h, hwdev);
+ return h;
+ }
+
+ //---------------------------------------------------------------
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h)
{
std::ostringstream s;
@@ -146,6 +160,8 @@ namespace cryptonote
if (tx.version >= 2 && !is_coinbase(tx))
{
rct::rctSig &rv = tx.rct_signatures;
+ if (rv.type == rct::RCTTypeNull)
+ return true;
if (rv.outPk.size() != tx.vout.size())
{
LOG_PRINT_L1("Failed to parse transaction from blob, bad outPk size in tx " << get_transaction_hash(tx));
diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h
index 8ed3b0b43..d1b24d950 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.h
+++ b/src/cryptonote_basic/cryptonote_format_utils.h
@@ -48,6 +48,8 @@ namespace epee
namespace cryptonote
{
//---------------------------------------------------------------
+ void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h, hw::device &hwdev);
+ crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx, hw::device &hwdev);
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h);
crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx);
bool parse_and_validate_tx_prefix_from_blob(const blobdata& tx_blob, transaction_prefix& tx);
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 3ff3c77e2..c1f9927a9 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -263,14 +263,14 @@ namespace cryptonote
m_blockchain_storage.set_enforce_dns_checkpoints(enforce_dns);
}
//-----------------------------------------------------------------------------------------------
- bool core::update_checkpoints()
+ bool core::update_checkpoints(const bool skip_dns /* = false */)
{
if (m_nettype != MAINNET || m_disable_dns_checkpoints) return true;
if (m_checkpoints_updating.test_and_set()) return true;
bool res = true;
- if (time(NULL) - m_last_dns_checkpoints_update >= 3600)
+ if (!skip_dns && time(NULL) - m_last_dns_checkpoints_update >= 3600)
{
res = m_blockchain_storage.update_checkpoints(m_checkpoints_path, true);
m_last_dns_checkpoints_update = time(NULL);
@@ -669,7 +669,8 @@ namespace cryptonote
// load json & DNS checkpoints, and verify them
// with respect to what blocks we already have
- CHECK_AND_ASSERT_MES(update_checkpoints(), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints.");
+ const bool skip_dns_checkpoints = !command_line::get_arg(vm, arg_dns_checkpoints);
+ CHECK_AND_ASSERT_MES(update_checkpoints(skip_dns_checkpoints), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints.");
// DNS versions checking
if (check_updates_string == "disabled")
@@ -1308,9 +1309,9 @@ namespace cryptonote
std::vector<crypto::hash> tx_hashes{};
tx_hashes.resize(tx_blobs.size());
- cryptonote::transaction tx{};
for (std::size_t i = 0; i < tx_blobs.size(); ++i)
{
+ cryptonote::transaction tx{};
if (!parse_and_validate_tx_from_blob(tx_blobs[i], tx, tx_hashes[i]))
{
LOG_ERROR("Failed to parse relayed transaction");
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index 255645efc..988f25ceb 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -699,7 +699,7 @@ namespace cryptonote
*
* @note see Blockchain::update_checkpoints()
*/
- bool update_checkpoints();
+ bool update_checkpoints(const bool skip_dns = false);
/**
* @brief tells the daemon to wind down operations and stop running
diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp
index b84a59698..3dd29dd1b 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.cpp
+++ b/src/cryptonote_core/cryptonote_tx_utils.cpp
@@ -590,7 +590,7 @@ namespace cryptonote
tx.vout[i].amount = 0;
crypto::hash tx_prefix_hash;
- get_transaction_prefix_hash(tx, tx_prefix_hash);
+ get_transaction_prefix_hash(tx, tx_prefix_hash, hwdev);
rct::ctkeyV outSk;
if (use_simple_rct)
tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, msout ? &kLRki : NULL, msout, index, outSk, rct_config, hwdev);
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index a7b2e4422..1fc2a637a 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -615,8 +615,8 @@ namespace cryptonote
CRITICAL_REGION_LOCAL1(m_blockchain);
m_blockchain.for_all_txpool_txes([this, &hashes, &txes](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata*) {
- const auto relay_method = meta.get_relay_method();
- if (relay_method != relay_method::block && relay_method != relay_method::fluff)
+ const auto tx_relay_method = meta.get_relay_method();
+ if (tx_relay_method != relay_method::block && tx_relay_method != relay_method::fluff)
return true;
const auto i = std::find(hashes.begin(), hashes.end(), txid);
if (i == hashes.end())
@@ -1121,7 +1121,7 @@ namespace cryptonote
// See `insert_key_images`.
if (1 < found->second.size() || *(found->second.cbegin()) != txid)
return true;
- return m_blockchain.txpool_tx_matches_category(txid, relay_category::broadcasted);
+ return m_blockchain.txpool_tx_matches_category(txid, relay_category::legacy);
}
return false;
}
diff --git a/src/device/device.hpp b/src/device/device.hpp
index 215e97eb6..ecc4849bf 100644
--- a/src/device/device.hpp
+++ b/src/device/device.hpp
@@ -56,6 +56,7 @@ namespace cryptonote
struct subaddress_index;
struct tx_destination_entry;
struct keypair;
+ class transaction_prefix;
}
namespace hw {
@@ -78,7 +79,7 @@ namespace hw {
virtual void on_button_request(uint64_t code=0) {}
virtual void on_button_pressed() {}
virtual boost::optional<epee::wipeable_string> on_pin_request() { return boost::none; }
- virtual boost::optional<epee::wipeable_string> on_passphrase_request(bool on_device) { return boost::none; }
+ virtual boost::optional<epee::wipeable_string> on_passphrase_request(bool & on_device) { on_device = true; return boost::none; }
virtual void on_progress(const device_progress& event) {}
virtual ~i_device_callback() = default;
};
@@ -203,6 +204,8 @@ namespace hw {
virtual bool open_tx(crypto::secret_key &tx_key) = 0;
+ virtual void get_transaction_prefix_hash(const cryptonote::transaction_prefix& tx, crypto::hash& h) = 0;
+
virtual bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) = 0;
bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key)
{
diff --git a/src/device/device_default.cpp b/src/device/device_default.cpp
index 57ac7c1b2..47156cbce 100644
--- a/src/device/device_default.cpp
+++ b/src/device/device_default.cpp
@@ -281,6 +281,10 @@ namespace hw {
return true;
}
+ void device_default::get_transaction_prefix_hash(const cryptonote::transaction_prefix& tx, crypto::hash& h) {
+ cryptonote::get_transaction_prefix_hash(tx, h);
+ }
+
bool device_default::generate_output_ephemeral_keys(const size_t tx_version,
const cryptonote::account_keys &sender_account_keys, const crypto::public_key &txkey_pub, const crypto::secret_key &tx_key,
const cryptonote::tx_destination_entry &dst_entr, const boost::optional<cryptonote::account_public_address> &change_addr, const size_t output_index,
diff --git a/src/device/device_default.hpp b/src/device/device_default.hpp
index 5252d4129..64cad78b0 100644
--- a/src/device/device_default.hpp
+++ b/src/device/device_default.hpp
@@ -112,6 +112,7 @@ namespace hw {
crypto::signature &sig) override;
bool open_tx(crypto::secret_key &tx_key) override;
+ void get_transaction_prefix_hash(const cryptonote::transaction_prefix& tx, crypto::hash& h) override;
bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) override;
diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp
index eaa9f910d..222a84d3f 100644
--- a/src/device/device_ledger.cpp
+++ b/src/device/device_ledger.cpp
@@ -259,7 +259,7 @@ namespace hw {
static int device_id = 0;
- #define PROTOCOL_VERSION 2
+ #define PROTOCOL_VERSION 3
#define INS_NONE 0x00
#define INS_RESET 0x02
@@ -296,6 +296,7 @@ namespace hw {
#define INS_BLIND 0x78
#define INS_UNBLIND 0x7A
#define INS_GEN_TXOUT_KEYS 0x7B
+ #define INS_PREFIX_HASH 0x7D
#define INS_VALIDATE 0x7C
#define INS_MLSAG 0x7E
#define INS_CLOSE_TX 0x80
@@ -1414,6 +1415,81 @@ namespace hw {
return true;
}
+ void device_ledger::get_transaction_prefix_hash(const cryptonote::transaction_prefix& tx, crypto::hash& h) {
+ AUTO_LOCK_CMD();
+
+ int pref_length = 0, pref_offset = 0, offset = 0;
+
+ #ifdef DEBUG_HWDEVICE
+ crypto::hash h_x;
+ this->controle_device->get_transaction_prefix_hash(tx,h_x);
+ MDEBUG("get_transaction_prefix_hash [[IN]] h_x/1 "<<h_x);
+ #endif
+
+ std::ostringstream s_x;
+ binary_archive<true> a_x(s_x);
+ CHECK_AND_ASSERT_THROW_MES(::serialization::serialize(a_x, const_cast<cryptonote::transaction_prefix&>(tx)),
+ "unable to serialize transaction prefix");
+ pref_length = s_x.str().size();
+ //auto pref = std::make_unique<unsigned char[]>(pref_length);
+ auto uprt_pref = std::unique_ptr<unsigned char[]>{ new unsigned char[pref_length] };
+ unsigned char* pref = uprt_pref.get();
+ memmove(pref, s_x.str().data(), pref_length);
+
+ offset = set_command_header_noopt(INS_PREFIX_HASH,1);
+ pref_offset = 0;
+ unsigned char v;
+
+ //version as varint
+ do {
+ v = pref[pref_offset];
+ this->buffer_send[offset] = v;
+ offset += 1;
+ pref_offset += 1;
+ } while (v&0x80);
+
+ //locktime as var int
+ do {
+ v = pref[pref_offset];
+ this->buffer_send[offset] = v;
+ offset += 1;
+ pref_offset += 1;
+ } while (v&0x80);
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange_wait_on_input();
+
+ //hash remains
+ int cnt = 0;
+ while (pref_offset < pref_length) {
+ int len;
+ cnt++;
+ offset = set_command_header(INS_PREFIX_HASH,2,cnt);
+ len = pref_length - pref_offset;
+ //options
+ if (len > (BUFFER_SEND_SIZE-7)) {
+ len = BUFFER_SEND_SIZE-7;
+ this->buffer_send[offset] = 0x80;
+ } else {
+ this->buffer_send[offset] = 0x00;
+ }
+ offset += 1;
+ //send chunk
+ memmove(&this->buffer_send[offset], pref+pref_offset, len);
+ offset += len;
+ pref_offset += len;
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+ }
+ memmove(h.data, &this->buffer_recv[0], 32);
+
+ #ifdef DEBUG_HWDEVICE
+ hw::ledger::check8("prefix_hash", "h", h_x.data, h.data);
+ #endif
+ }
+
bool device_ledger::encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) {
AUTO_LOCK_CMD();
diff --git a/src/device/device_ledger.hpp b/src/device/device_ledger.hpp
index e3e30fba8..070162cbc 100644
--- a/src/device/device_ledger.hpp
+++ b/src/device/device_ledger.hpp
@@ -275,6 +275,8 @@ namespace hw {
bool open_tx(crypto::secret_key &tx_key) override;
+ void get_transaction_prefix_hash(const cryptonote::transaction_prefix& tx, crypto::hash& h) override;
+
bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) override;
rct::key genCommitmentMask(const rct::key &amount_key) override;
diff --git a/src/device_trezor/device_trezor.cpp b/src/device_trezor/device_trezor.cpp
index a77f6697f..8bde1cb75 100644
--- a/src/device_trezor/device_trezor.cpp
+++ b/src/device_trezor/device_trezor.cpp
@@ -101,7 +101,7 @@ namespace trezor {
return device_trezor_base::disconnect();
}
- void device_trezor::device_state_reset_unsafe()
+ void device_trezor::device_state_initialize_unsafe()
{
require_connected();
if (m_live_refresh_in_progress)
@@ -117,7 +117,7 @@ namespace trezor {
}
m_live_refresh_in_progress = false;
- device_trezor_base::device_state_reset_unsafe();
+ device_trezor_base::device_state_initialize_unsafe();
}
void device_trezor::live_refresh_thread_main()
@@ -221,7 +221,7 @@ namespace trezor {
CHECK_AND_ASSERT_THROW_MES(!payment_id || !subaddress || subaddress->is_zero(), "Subaddress cannot be integrated");
TREZOR_AUTO_LOCK_CMD();
require_connected();
- device_state_reset_unsafe();
+ device_state_initialize_unsafe();
require_initialized();
auto req = std::make_shared<messages::monero::MoneroGetAddress>();
@@ -245,7 +245,7 @@ namespace trezor {
const boost::optional<cryptonote::network_type> & network_type){
TREZOR_AUTO_LOCK_CMD();
require_connected();
- device_state_reset_unsafe();
+ device_state_initialize_unsafe();
require_initialized();
auto req = std::make_shared<messages::monero::MoneroGetWatchKey>();
@@ -274,7 +274,7 @@ namespace trezor {
{
TREZOR_AUTO_LOCK_CMD();
require_connected();
- device_state_reset_unsafe();
+ device_state_initialize_unsafe();
require_initialized();
auto req = protocol::tx::get_tx_key(tx_aux_data);
@@ -294,15 +294,15 @@ namespace trezor {
TREZOR_AUTO_LOCK_CMD();
require_connected();
- device_state_reset_unsafe();
+ device_state_initialize_unsafe();
require_initialized();
std::shared_ptr<messages::monero::MoneroKeyImageExportInitRequest> req;
std::vector<protocol::ki::MoneroTransferDetails> mtds;
std::vector<protocol::ki::MoneroExportedKeyImage> kis;
- protocol::ki::key_image_data(wallet, transfers, mtds);
- protocol::ki::generate_commitment(mtds, transfers, req);
+ protocol::ki::key_image_data(wallet, transfers, mtds, client_version() <= 1);
+ protocol::ki::generate_commitment(mtds, transfers, req, client_version() <= 1);
EVENT_PROGRESS(0.);
this->set_msg_addr<messages::monero::MoneroKeyImageExportInitRequest>(req.get());
@@ -386,7 +386,7 @@ namespace trezor {
void device_trezor::live_refresh_start_unsafe()
{
- device_state_reset_unsafe();
+ device_state_initialize_unsafe();
require_initialized();
auto req = std::make_shared<messages::monero::MoneroLiveRefreshStartRequest>();
@@ -492,7 +492,7 @@ namespace trezor {
TREZOR_AUTO_LOCK_CMD();
require_connected();
- device_state_reset_unsafe();
+ device_state_initialize_unsafe();
require_initialized();
transaction_versions_check(unsigned_tx, aux_data);
@@ -514,7 +514,7 @@ namespace trezor {
auto & cpend = signed_tx.ptx.back();
cpend.tx = cdata.tx;
cpend.dust = 0;
- cpend.fee = 0;
+ cpend.fee = cpend.tx.rct_signatures.txnFee;
cpend.dust_added_to_fee = false;
cpend.change_dts = cdata.tx_data.change_dts;
cpend.selected_transfers = cdata.tx_data.selected_transfers;
@@ -524,6 +524,7 @@ namespace trezor {
// Transaction check
try {
+ MDEBUG("signed transaction: " << cryptonote::get_transaction_hash(cpend.tx) << ENDL << cryptonote::obj_to_json_str(cpend.tx) << ENDL);
transaction_check(cdata, aux_data);
} catch(const std::exception &e){
throw exc::ProtocolException(std::string("Transaction verification failed: ") + e.what());
@@ -582,7 +583,7 @@ namespace trezor {
require_connected();
if (idx > 0)
- device_state_reset_unsafe();
+ device_state_initialize_unsafe();
require_initialized();
EVENT_PROGRESS(0, 1, 1);
@@ -670,28 +671,42 @@ namespace trezor {
#undef EVENT_PROGRESS
}
- void device_trezor::transaction_versions_check(const ::tools::wallet2::unsigned_tx_set & unsigned_tx, hw::tx_aux_data & aux_data)
+ unsigned device_trezor::client_version()
{
auto trezor_version = get_version();
- unsigned client_version = 1; // default client version for tx
-
if (trezor_version <= pack_version(2, 0, 10)){
- client_version = 0;
+ throw exc::TrezorException("Trezor firmware 2.0.10 and lower are not supported. Please update.");
}
+ // default client version, higher versions check will be added
+ unsigned client_version = 1;
+
+#ifdef WITH_TREZOR_DEBUGGING
+ // Override client version for tests
+ const char *env_trezor_client_version = nullptr;
+ if ((env_trezor_client_version = getenv("TREZOR_CLIENT_VERSION")) != nullptr){
+ auto succ = epee::string_tools::get_xtype_from_string(client_version, env_trezor_client_version);
+ if (succ){
+ MINFO("Trezor client version overriden by TREZOR_CLIENT_VERSION to: " << client_version);
+ }
+ }
+#endif
+ return client_version;
+ }
+
+ void device_trezor::transaction_versions_check(const ::tools::wallet2::unsigned_tx_set & unsigned_tx, hw::tx_aux_data & aux_data)
+ {
+ unsigned cversion = client_version();
+
if (aux_data.client_version){
auto wanted_client_version = aux_data.client_version.get();
- if (wanted_client_version > client_version){
- throw exc::TrezorException("Trezor firmware 2.0.10 and lower does not support current transaction sign protocol. Please update.");
+ if (wanted_client_version > cversion){
+ throw exc::TrezorException("Trezor has too old firmware version. Please update.");
} else {
- client_version = wanted_client_version;
+ cversion = wanted_client_version;
}
}
- aux_data.client_version = client_version;
-
- if (client_version == 0 && aux_data.bp_version && aux_data.bp_version.get() != 1){
- throw exc::TrezorException("Trezor firmware 2.0.10 and lower does not support current transaction sign protocol (BPv2+). Please update.");
- }
+ aux_data.client_version = cversion;
}
void device_trezor::transaction_pre_check(std::shared_ptr<messages::monero::MoneroTransactionInitRequest> init_msg)
diff --git a/src/device_trezor/device_trezor.hpp b/src/device_trezor/device_trezor.hpp
index a26a42788..f558b7b19 100644
--- a/src/device_trezor/device_trezor.hpp
+++ b/src/device_trezor/device_trezor.hpp
@@ -67,10 +67,11 @@ namespace trezor {
bool m_live_refresh_enabled;
size_t m_num_transations_to_sign;
+ unsigned client_version();
void transaction_versions_check(const ::tools::wallet2::unsigned_tx_set & unsigned_tx, hw::tx_aux_data & aux_data);
void transaction_pre_check(std::shared_ptr<messages::monero::MoneroTransactionInitRequest> init_msg);
void transaction_check(const protocol::tx::TData & tdata, const hw::tx_aux_data & aux_data);
- void device_state_reset_unsafe() override;
+ void device_state_initialize_unsafe() override;
void live_refresh_start_unsafe();
void live_refresh_finish_unsafe();
void live_refresh_thread_main();
diff --git a/src/device_trezor/device_trezor_base.cpp b/src/device_trezor/device_trezor_base.cpp
index b7adf433d..354ae6691 100644
--- a/src/device_trezor/device_trezor_base.cpp
+++ b/src/device_trezor/device_trezor_base.cpp
@@ -28,6 +28,7 @@
//
#include "device_trezor_base.hpp"
+#include "memwipe.h"
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/regex.hpp>
@@ -151,7 +152,7 @@ namespace trezor {
bool device_trezor_base::disconnect() {
TREZOR_AUTO_LOCK_DEVICE();
- m_device_state.clear();
+ m_device_session_id.clear();
m_features.reset();
if (m_transport){
@@ -292,8 +293,8 @@ namespace trezor {
case messages::MessageType_PassphraseRequest:
on_passphrase_request(input, dynamic_cast<const messages::common::PassphraseRequest*>(input.m_msg.get()));
return true;
- case messages::MessageType_PassphraseStateRequest:
- on_passphrase_state_request(input, dynamic_cast<const messages::common::PassphraseStateRequest*>(input.m_msg.get()));
+ case messages::MessageType_Deprecated_PassphraseStateRequest:
+ on_passphrase_state_request(input, dynamic_cast<const messages::common::Deprecated_PassphraseStateRequest*>(input.m_msg.get()));
return true;
case messages::MessageType_PinMatrixRequest:
on_pin_request(input, dynamic_cast<const messages::common::PinMatrixRequest*>(input.m_msg.get()));
@@ -361,23 +362,34 @@ namespace trezor {
return false;
}
- void device_trezor_base::device_state_reset_unsafe()
+ void device_trezor_base::device_state_initialize_unsafe()
{
require_connected();
+ std::string tmp_session_id;
auto initMsg = std::make_shared<messages::management::Initialize>();
+ const auto data_cleaner = epee::misc_utils::create_scope_leave_handler([&]() {
+ memwipe(&tmp_session_id[0], tmp_session_id.size());
+ });
- if(!m_device_state.empty()) {
- initMsg->set_allocated_state(&m_device_state);
+ if(!m_device_session_id.empty()) {
+ tmp_session_id.assign(m_device_session_id.data(), m_device_session_id.size());
+ initMsg->set_allocated_session_id(&tmp_session_id);
}
m_features = this->client_exchange<messages::management::Features>(initMsg);
- initMsg->release_state();
+ if (m_features->has_session_id()){
+ m_device_session_id = m_features->session_id();
+ } else {
+ m_device_session_id.clear();
+ }
+
+ initMsg->release_session_id();
}
void device_trezor_base::device_state_reset()
{
TREZOR_AUTO_LOCK_CMD();
- device_state_reset_unsafe();
+ device_state_initialize_unsafe();
}
#ifdef WITH_TREZOR_DEBUGGING
@@ -441,48 +453,89 @@ namespace trezor {
pin = m_pin;
}
- // TODO: remove PIN from memory
+ std::string pin_field;
messages::common::PinMatrixAck m;
if (pin) {
- m.set_pin(pin.get().data(), pin.get().size());
+ pin_field.assign(pin->data(), pin->size());
+ m.set_allocated_pin(&pin_field);
}
+
+ const auto data_cleaner = epee::misc_utils::create_scope_leave_handler([&]() {
+ m.release_pin();
+ if (!pin_field.empty()){
+ memwipe(&pin_field[0], pin_field.size());
+ }
+ });
+
resp = call_raw(&m);
}
void device_trezor_base::on_passphrase_request(GenericMessage & resp, const messages::common::PassphraseRequest * msg)
{
CHECK_AND_ASSERT_THROW_MES(msg, "Empty message");
- MDEBUG("on_passhprase_request, on device: " << msg->on_device());
- boost::optional<epee::wipeable_string> passphrase;
- TREZOR_CALLBACK_GET(passphrase, on_passphrase_request, msg->on_device());
+ MDEBUG("on_passhprase_request");
- if (!passphrase && m_passphrase){
- passphrase = m_passphrase;
+ // Backward compatibility, migration clause.
+ if (msg->has__on_device() && msg->_on_device()){
+ messages::common::PassphraseAck m;
+ resp = call_raw(&m);
+ return;
}
- m_passphrase = boost::none;
+ bool on_device = true;
+ if (msg->has__on_device() && !msg->_on_device()){
+ on_device = false; // do not enter on device, old devices.
+ }
- messages::common::PassphraseAck m;
- if (!msg->on_device() && passphrase){
- // TODO: remove passphrase from memory
- m.set_passphrase(passphrase.get().data(), passphrase.get().size());
+ if (on_device && m_features && m_features->capabilities_size() > 0){
+ on_device = false;
+ for (auto it = m_features->capabilities().begin(); it != m_features->capabilities().end(); it++) {
+ if (*it == messages::management::Features::Capability_PassphraseEntry){
+ on_device = true;
+ }
+ }
}
- if (!m_device_state.empty()){
- m.set_allocated_state(&m_device_state);
+ boost::optional<epee::wipeable_string> passphrase;
+ TREZOR_CALLBACK_GET(passphrase, on_passphrase_request, on_device);
+
+ std::string passphrase_field;
+ messages::common::PassphraseAck m;
+ m.set_on_device(on_device);
+ if (!on_device) {
+ if (!passphrase && m_passphrase) {
+ passphrase = m_passphrase;
+ }
+
+ if (m_passphrase) {
+ m_passphrase = boost::none;
+ }
+
+ if (passphrase) {
+ passphrase_field.assign(passphrase->data(), passphrase->size());
+ m.set_allocated_passphrase(&passphrase_field);
+ }
}
+ const auto data_cleaner = epee::misc_utils::create_scope_leave_handler([&]() {
+ m.release_passphrase();
+ if (!passphrase_field.empty()){
+ memwipe(&passphrase_field[0], passphrase_field.size());
+ }
+ });
+
resp = call_raw(&m);
- m.release_state();
}
- void device_trezor_base::on_passphrase_state_request(GenericMessage & resp, const messages::common::PassphraseStateRequest * msg)
+ void device_trezor_base::on_passphrase_state_request(GenericMessage & resp, const messages::common::Deprecated_PassphraseStateRequest * msg)
{
MDEBUG("on_passhprase_state_request");
CHECK_AND_ASSERT_THROW_MES(msg, "Empty message");
- m_device_state = msg->state();
- messages::common::PassphraseStateAck m;
+ if (msg->has_state()) {
+ m_device_session_id = msg->state();
+ }
+ messages::common::Deprecated_PassphraseStateAck m;
resp = call_raw(&m);
}
@@ -510,7 +563,7 @@ namespace trezor {
}
auto msg = std::make_shared<messages::management::LoadDevice>();
- msg->set_mnemonic(mnemonic);
+ msg->add_mnemonics(mnemonic);
msg->set_pin(pin);
msg->set_passphrase_protection(passphrase_protection);
msg->set_label(label);
@@ -535,7 +588,8 @@ namespace trezor {
return boost::none;
}
- boost::optional<epee::wipeable_string> trezor_debug_callback::on_passphrase_request(bool on_device) {
+ boost::optional<epee::wipeable_string> trezor_debug_callback::on_passphrase_request(bool & on_device) {
+ on_device = true;
return boost::none;
}
diff --git a/src/device_trezor/device_trezor_base.hpp b/src/device_trezor/device_trezor_base.hpp
index c106d2099..62b2c2bf4 100644
--- a/src/device_trezor/device_trezor_base.hpp
+++ b/src/device_trezor/device_trezor_base.hpp
@@ -70,7 +70,7 @@ namespace trezor {
void on_button_request(uint64_t code=0) override;
boost::optional<epee::wipeable_string> on_pin_request() override;
- boost::optional<epee::wipeable_string> on_passphrase_request(bool on_device) override;
+ boost::optional<epee::wipeable_string> on_passphrase_request(bool & on_device) override;
void on_passphrase_state_request(const std::string &state);
void on_disconnect();
protected:
@@ -94,7 +94,7 @@ namespace trezor {
std::string m_full_name;
std::vector<unsigned int> m_wallet_deriv_path;
- std::string m_device_state; // returned after passphrase entry, session
+ epee::wipeable_string m_device_session_id; // returned after passphrase entry, session
std::shared_ptr<messages::management::Features> m_features; // features from the last device reset
boost::optional<epee::wipeable_string> m_pin;
boost::optional<epee::wipeable_string> m_passphrase;
@@ -117,7 +117,7 @@ namespace trezor {
void require_initialized() const;
void call_ping_unsafe();
void test_ping();
- virtual void device_state_reset_unsafe();
+ virtual void device_state_initialize_unsafe();
void ensure_derivation_path() noexcept;
// Communication methods
@@ -315,7 +315,7 @@ namespace trezor {
void on_button_pressed();
void on_pin_request(GenericMessage & resp, const messages::common::PinMatrixRequest * msg);
void on_passphrase_request(GenericMessage & resp, const messages::common::PassphraseRequest * msg);
- void on_passphrase_state_request(GenericMessage & resp, const messages::common::PassphraseStateRequest * msg);
+ void on_passphrase_state_request(GenericMessage & resp, const messages::common::Deprecated_PassphraseStateRequest * msg);
#ifdef WITH_TREZOR_DEBUGGING
void set_debug(bool debug){
diff --git a/src/device_trezor/trezor/debug_link.cpp b/src/device_trezor/trezor/debug_link.cpp
index c7ee59afe..102d1f966 100644
--- a/src/device_trezor/trezor/debug_link.cpp
+++ b/src/device_trezor/trezor/debug_link.cpp
@@ -71,9 +71,9 @@ namespace trezor{
call(decision, boost::none, true);
}
- void DebugLink::input_swipe(bool swipe){
+ void DebugLink::input_swipe(messages::debug::DebugLinkDecision_DebugSwipeDirection direction){
messages::debug::DebugLinkDecision decision;
- decision.set_up_down(swipe);
+ decision.set_swipe(direction);
call(decision, boost::none, true);
}
diff --git a/src/device_trezor/trezor/debug_link.hpp b/src/device_trezor/trezor/debug_link.hpp
index adf5f1d8f..a5f05ea94 100644
--- a/src/device_trezor/trezor/debug_link.hpp
+++ b/src/device_trezor/trezor/debug_link.hpp
@@ -49,7 +49,7 @@ namespace trezor {
std::shared_ptr<messages::debug::DebugLinkState> state();
void input_word(const std::string & word);
void input_button(bool button);
- void input_swipe(bool swipe);
+ void input_swipe(messages::debug::DebugLinkDecision_DebugSwipeDirection direction);
void press_yes() { input_button(true); }
void press_no() { input_button(false); }
void stop();
diff --git a/src/device_trezor/trezor/protocol.cpp b/src/device_trezor/trezor/protocol.cpp
index 61e51be14..2a7783497 100644
--- a/src/device_trezor/trezor/protocol.cpp
+++ b/src/device_trezor/trezor/protocol.cpp
@@ -145,7 +145,8 @@ namespace ki {
bool key_image_data(wallet_shim * wallet,
const std::vector<tools::wallet2::transfer_details> & transfers,
- std::vector<MoneroTransferDetails> & res)
+ std::vector<MoneroTransferDetails> & res,
+ bool need_all_additionals)
{
for(auto & td : transfers){
::crypto::public_key tx_pub_key = wallet->get_tx_pub_key_from_received_outs(td);
@@ -157,8 +158,14 @@ namespace ki {
cres.set_out_key(key_to_string(boost::get<cryptonote::txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key));
cres.set_tx_pub_key(key_to_string(tx_pub_key));
cres.set_internal_output_index(td.m_internal_output_index);
- for(auto & aux : additional_tx_pub_keys){
- cres.add_additional_tx_pub_keys(key_to_string(aux));
+ cres.set_sub_addr_major(td.m_subaddr_index.major);
+ cres.set_sub_addr_minor(td.m_subaddr_index.minor);
+ if (need_all_additionals) {
+ for (auto &aux : additional_tx_pub_keys) {
+ cres.add_additional_tx_pub_keys(key_to_string(aux));
+ }
+ } else if (!additional_tx_pub_keys.empty() && additional_tx_pub_keys.size() > td.m_internal_output_index) {
+ cres.add_additional_tx_pub_keys(key_to_string(additional_tx_pub_keys[td.m_internal_output_index]));
}
}
@@ -188,7 +195,8 @@ namespace ki {
void generate_commitment(std::vector<MoneroTransferDetails> & mtds,
const std::vector<tools::wallet2::transfer_details> & transfers,
- std::shared_ptr<messages::monero::MoneroKeyImageExportInitRequest> & req)
+ std::shared_ptr<messages::monero::MoneroKeyImageExportInitRequest> & req,
+ bool need_subaddr_indices)
{
req = std::make_shared<messages::monero::MoneroKeyImageExportInitRequest>();
@@ -213,11 +221,13 @@ namespace ki {
st.insert(cur.m_subaddr_index.minor);
}
- for (auto& x: sub_indices){
- auto subs = req->add_subs();
- subs->set_account(x.first);
- for(auto minor : x.second){
- subs->add_minor_indices(minor);
+ if (need_subaddr_indices) {
+ for (auto &x: sub_indices) {
+ auto subs = req->add_subs();
+ subs->set_account(x.first);
+ for (auto minor : x.second) {
+ subs->add_minor_indices(minor);
+ }
}
}
}
@@ -283,26 +293,6 @@ namespace tx {
translate_address(dst->mutable_addr(), &(src->addr));
}
- void translate_src_entry(MoneroTransactionSourceEntry * dst, const cryptonote::tx_source_entry * src){
- for(auto & cur : src->outputs){
- auto out = dst->add_outputs();
- out->set_idx(cur.first);
- translate_rct_key(out->mutable_key(), &(cur.second));
- }
-
- dst->set_real_output(src->real_output);
- dst->set_real_out_tx_key(key_to_string(src->real_out_tx_key));
- for(auto & cur : src->real_out_additional_tx_keys){
- dst->add_real_out_additional_tx_keys(key_to_string(cur));
- }
-
- dst->set_real_output_in_tx_index(src->real_output_in_tx_index);
- dst->set_amount(src->amount);
- dst->set_rct(src->rct);
- dst->set_mask(key_to_string(src->mask));
- translate_klrki(dst->mutable_multisig_klrki(), &(src->multisig_kLRki));
- }
-
void translate_klrki(MoneroMultisigKLRki * dst, const rct::multisig_kLRki * src){
dst->set_k(key_to_string(src->k));
dst->set_l(key_to_string(src->L));
@@ -369,6 +359,31 @@ namespace tx {
return res;
}
+ std::string compute_sealing_key(const std::string & master_key, size_t idx, bool is_iv)
+ {
+ // master-key-32B || domain-sep-12B || index-4B
+ uint8_t hash[32] = {0};
+ KECCAK_CTX ctx;
+ std::string sep = is_iv ? "sig-iv" : "sig-key";
+ std::string idx_data = tools::get_varint_data(idx);
+ if (idx_data.size() > 4){
+ throw std::invalid_argument("index is too big");
+ }
+
+ keccak_init(&ctx);
+ keccak_update(&ctx, (const uint8_t *) master_key.data(), master_key.size());
+ keccak_update(&ctx, (const uint8_t *) sep.data(), sep.size());
+ keccak_update(&ctx, hash, 12 - sep.size());
+ keccak_update(&ctx, (const uint8_t *) idx_data.data(), idx_data.size());
+ if (idx_data.size() < 4) {
+ keccak_update(&ctx, hash, 4 - idx_data.size());
+ }
+
+ keccak_finish(&ctx, hash);
+ keccak(hash, sizeof(hash), hash, sizeof(hash));
+ return std::string((const char*) hash, 32);
+ }
+
TData::TData() {
rsig_type = 0;
bp_version = 0;
@@ -383,7 +398,7 @@ namespace tx {
m_unsigned_tx = unsigned_tx;
m_aux_data = aux_data;
m_tx_idx = tx_idx;
- m_ct.tx_data = cur_tx();
+ m_ct.tx_data = cur_src_tx();
m_multisig = false;
m_client_version = 1;
}
@@ -451,6 +466,41 @@ namespace tx {
}
}
+ void Signer::set_tx_input(MoneroTransactionSourceEntry * dst, size_t idx, bool need_ring_keys, bool need_ring_indices){
+ const cryptonote::tx_source_entry & src = cur_tx().sources[idx];
+ const tools::wallet2::transfer_details & transfer = get_source_transfer(idx);
+
+ dst->set_real_output(src.real_output);
+ for(size_t i = 0; i < src.outputs.size(); ++i){
+ auto & cur = src.outputs[i];
+ auto out = dst->add_outputs();
+
+ if (i == src.real_output || need_ring_indices || client_version() <= 1) {
+ out->set_idx(cur.first);
+ }
+ if (i == src.real_output || need_ring_keys || client_version() <= 1) {
+ translate_rct_key(out->mutable_key(), &(cur.second));
+ }
+ }
+
+ dst->set_real_out_tx_key(key_to_string(src.real_out_tx_key));
+ dst->set_real_output_in_tx_index(src.real_output_in_tx_index);
+
+ if (client_version() <= 1) {
+ for (auto &cur : src.real_out_additional_tx_keys) {
+ dst->add_real_out_additional_tx_keys(key_to_string(cur));
+ }
+ } else if (!src.real_out_additional_tx_keys.empty()) {
+ dst->add_real_out_additional_tx_keys(key_to_string(src.real_out_additional_tx_keys.at(src.real_output_in_tx_index)));
+ }
+
+ dst->set_amount(src.amount);
+ dst->set_rct(src.rct);
+ dst->set_mask(key_to_string(src.mask));
+ translate_klrki(dst->mutable_multisig_klrki(), &(src.multisig_kLRki));
+ dst->set_subaddr_minor(transfer.m_subaddr_index.minor);
+ }
+
void Signer::compute_integrated_indices(TsxData * tsx_data){
if (m_aux_data == nullptr || m_aux_data->tx_recipients.empty()){
return;
@@ -492,6 +542,7 @@ namespace tx {
// extract payment ID from construction data
auto & tsx_data = m_ct.tsx_data;
auto & tx = cur_tx();
+ const size_t input_size = tx.sources.size();
m_ct.tx.version = 2;
m_ct.tx.unlock_time = tx.unlock_time;
@@ -500,12 +551,20 @@ namespace tx {
tsx_data.set_version(1);
tsx_data.set_client_version(client_version());
tsx_data.set_unlock_time(tx.unlock_time);
- tsx_data.set_num_inputs(static_cast<google::protobuf::uint32>(tx.sources.size()));
+ tsx_data.set_num_inputs(static_cast<google::protobuf::uint32>(input_size));
tsx_data.set_mixin(static_cast<google::protobuf::uint32>(tx.sources[0].outputs.size() - 1));
tsx_data.set_account(tx.subaddr_account);
tsx_data.set_monero_version(std::string(MONERO_VERSION) + "|" + MONERO_VERSION_TAG);
tsx_data.set_hard_fork(m_aux_data->hard_fork ? m_aux_data->hard_fork.get() : 0);
- assign_to_repeatable(tsx_data.mutable_minor_indices(), tx.subaddr_indices.begin(), tx.subaddr_indices.end());
+
+ if (client_version() <= 1){
+ assign_to_repeatable(tsx_data.mutable_minor_indices(), tx.subaddr_indices.begin(), tx.subaddr_indices.end());
+ }
+
+ // TODO: use HF_VERSION_CLSAG after CLSAG is merged
+ if (tsx_data.hard_fork() >= 13){
+ throw exc::ProtocolException("CLSAG is not yet implemented");
+ }
// Rsig decision
auto rsig_data = tsx_data.mutable_rsig_data();
@@ -525,6 +584,11 @@ namespace tx {
translate_dst_entry(dst, &cur);
}
+ m_ct.source_permutation.clear();
+ for (size_t n = 0; n < input_size; ++n){
+ m_ct.source_permutation.push_back(n);
+ }
+
compute_integrated_indices(&tsx_data);
int64_t fee = 0;
@@ -559,7 +623,7 @@ namespace tx {
CHECK_AND_ASSERT_THROW_MES(idx < cur_tx().sources.size(), "Invalid source index");
m_ct.cur_input_idx = idx;
auto res = std::make_shared<messages::monero::MoneroTransactionSetInputRequest>();
- translate_src_entry(res->mutable_src_entr(), &(cur_tx().sources[idx]));
+ set_tx_input(res->mutable_src_entr(), idx, false, true);
return res;
}
@@ -582,11 +646,6 @@ namespace tx {
void Signer::sort_ki(){
const size_t input_size = cur_tx().sources.size();
- m_ct.source_permutation.clear();
- for (size_t n = 0; n < input_size; ++n){
- m_ct.source_permutation.push_back(n);
- }
-
CHECK_AND_ASSERT_THROW_MES(m_ct.tx.vin.size() == input_size, "Invalid vector size");
std::sort(m_ct.source_permutation.begin(), m_ct.source_permutation.end(), [&](const size_t i0, const size_t i1) {
const cryptonote::txin_to_key &tk0 = boost::get<cryptonote::txin_to_key>(m_ct.tx.vin[i0]);
@@ -614,6 +673,9 @@ namespace tx {
std::shared_ptr<messages::monero::MoneroTransactionInputsPermutationRequest> Signer::step_permutation(){
sort_ki();
+ if (client_version() >= 2){
+ return nullptr;
+ }
auto res = std::make_shared<messages::monero::MoneroTransactionInputsPermutationRequest>();
assign_to_repeatable(res->mutable_perm(), m_ct.source_permutation.begin(), m_ct.source_permutation.end());
@@ -634,17 +696,10 @@ namespace tx {
auto tx = m_ct.tx_data;
auto res = std::make_shared<messages::monero::MoneroTransactionInputViniRequest>();
auto & vini = m_ct.tx.vin[idx];
- translate_src_entry(res->mutable_src_entr(), &(tx.sources[idx]));
+ set_tx_input(res->mutable_src_entr(), idx, false, false);
res->set_vini(cryptonote::t_serializable_object_to_blob(vini));
res->set_vini_hmac(m_ct.tx_in_hmacs[idx]);
-
- if (client_version() == 0) {
- CHECK_AND_ASSERT_THROW_MES(idx < m_ct.pseudo_outs.size(), "Invalid transaction index");
- CHECK_AND_ASSERT_THROW_MES(idx < m_ct.pseudo_outs_hmac.size(), "Invalid transaction index");
- res->set_pseudo_out(m_ct.pseudo_outs[idx]);
- res->set_pseudo_out_hmac(m_ct.pseudo_outs_hmac[idx]);
- }
-
+ res->set_orig_idx(m_ct.source_permutation[idx]);
return res;
}
@@ -657,31 +712,6 @@ namespace tx {
}
void Signer::step_all_inputs_set_ack(std::shared_ptr<const messages::monero::MoneroTransactionAllInputsSetAck> ack){
- if (client_version() > 0 || !is_offloading()){
- return;
- }
-
- // If offloading, expect rsig configuration.
- if (!ack->has_rsig_data()){
- throw exc::ProtocolException("Rsig offloading requires rsig param");
- }
-
- auto & rsig_data = ack->rsig_data();
- if (!rsig_data.has_mask()){
- throw exc::ProtocolException("Gamma masks not present in offloaded version");
- }
-
- auto & mask = rsig_data.mask();
- if (mask.size() != 32 * num_outputs()){
- throw exc::ProtocolException("Invalid number of gamma masks");
- }
-
- m_ct.rsig_gamma.reserve(num_outputs());
- for(size_t c=0; c < num_outputs(); ++c){
- rct::key cmask{};
- memcpy(cmask.bytes, mask.data() + c * 32, 32);
- m_ct.rsig_gamma.emplace_back(cmask);
- }
}
std::shared_ptr<messages::monero::MoneroTransactionSetOutputRequest> Signer::step_set_output(size_t idx){
@@ -696,15 +726,6 @@ namespace tx {
auto & cur_dst = m_ct.tx_data.splitted_dsts[idx];
translate_dst_entry(res->mutable_dst_entr(), &cur_dst);
res->set_dst_entr_hmac(m_ct.tx_out_entr_hmacs[idx]);
-
- // Range sig offloading to the host
- // ClientV0 sends offloaded BP with the last message in the batch.
- // ClientV1 needs additional message after the last message in the batch as BP uses deterministic masks.
- if (client_version() == 0 && is_offloading() && should_compute_bp_now()) {
- auto rsig_data = res->mutable_rsig_data();
- compute_bproof(*rsig_data);
- }
-
return res;
}
@@ -814,7 +835,7 @@ namespace tx {
}
std::shared_ptr<messages::monero::MoneroTransactionSetOutputRequest> Signer::step_rsig(size_t idx){
- if (client_version() == 0 || !is_offloading() || !should_compute_bp_now()){
+ if (!is_offloading() || !should_compute_bp_now()){
return nullptr;
}
@@ -917,11 +938,12 @@ namespace tx {
CHECK_AND_ASSERT_THROW_MES(idx < m_ct.spend_encs.size(), "Invalid transaction index");
auto res = std::make_shared<messages::monero::MoneroTransactionSignInputRequest>();
- translate_src_entry(res->mutable_src_entr(), &(m_ct.tx_data.sources[idx]));
+ set_tx_input(res->mutable_src_entr(), idx, true, true);
res->set_vini(cryptonote::t_serializable_object_to_blob(m_ct.tx.vin[idx]));
res->set_vini_hmac(m_ct.tx_in_hmacs[idx]);
res->set_pseudo_out_alpha(m_ct.alphas[idx]);
res->set_spend_key(m_ct.spend_encs[idx]);
+ res->set_orig_idx(m_ct.source_permutation[idx]);
CHECK_AND_ASSERT_THROW_MES(idx < m_ct.pseudo_outs.size(), "Invalid transaction index");
CHECK_AND_ASSERT_THROW_MES(idx < m_ct.pseudo_outs_hmac.size(), "Invalid transaction index");
@@ -931,10 +953,7 @@ namespace tx {
}
void Signer::step_sign_input_ack(std::shared_ptr<const messages::monero::MoneroTransactionSignInputAck> ack){
- rct::mgSig mg;
- if (!cn_deserialize(ack->signature(), mg)){
- throw exc::ProtocolException("Cannot deserialize mg[i]");
- }
+ m_ct.signatures.push_back(ack->signature());
// Sync updated pseudo_outputs, client_version>=1, HF10+
if (client_version() >= 1 && ack->has_pseudo_out()){
@@ -948,12 +967,9 @@ namespace tx {
string_to_key(m_ct.rv->pseudoOuts[m_ct.cur_input_idx], ack->pseudo_out());
}
}
-
- m_ct.rv->p.MGs.push_back(mg);
}
std::shared_ptr<messages::monero::MoneroTransactionFinalRequest> Signer::step_final(){
- m_ct.tx.rct_signatures = *(m_ct.rv);
return std::make_shared<messages::monero::MoneroTransactionFinalRequest>();
}
@@ -976,6 +992,42 @@ namespace tx {
m_ct.enc_salt1 = ack->salt();
m_ct.enc_salt2 = ack->rand_mult();
m_ct.enc_keys = ack->tx_enc_keys();
+
+ // Opening the sealed signatures
+ if (client_version() >= 3){
+ if(!ack->has_opening_key()){
+ throw exc::ProtocolException("Client version 3+ requires sealed signatures");
+ }
+
+ for(size_t i = 0; i < m_ct.signatures.size(); ++i){
+ CHECK_AND_ASSERT_THROW_MES(m_ct.signatures[i].size() > crypto::chacha::TAG_SIZE, "Invalid signature size");
+ std::string nonce = compute_sealing_key(ack->opening_key(), i, true);
+ std::string key = compute_sealing_key(ack->opening_key(), i, false);
+ size_t plen = m_ct.signatures[i].size() - crypto::chacha::TAG_SIZE;
+ std::unique_ptr<uint8_t[]> plaintext(new uint8_t[plen]);
+ uint8_t * buff = plaintext.get();
+
+ protocol::crypto::chacha::decrypt(
+ m_ct.signatures[i].data(),
+ m_ct.signatures[i].size(),
+ reinterpret_cast<const uint8_t *>(key.data()),
+ reinterpret_cast<const uint8_t *>(nonce.data()),
+ reinterpret_cast<char *>(buff), &plen);
+ m_ct.signatures[i].assign(reinterpret_cast<const char *>(buff), plen);
+ }
+ }
+
+ // CLSAG support comes here once it is merged to the Monero
+ m_ct.rv->p.MGs.reserve(m_ct.signatures.size());
+ for(size_t i = 0; i < m_ct.signatures.size(); ++i) {
+ rct::mgSig mg;
+ if (!cn_deserialize(m_ct.signatures[i], mg)) {
+ throw exc::ProtocolException("Cannot deserialize mg[i]");
+ }
+ m_ct.rv->p.MGs.push_back(mg);
+ }
+
+ m_ct.tx.rct_signatures = *(m_ct.rv);
}
std::string Signer::store_tx_aux_info(){
diff --git a/src/device_trezor/trezor/protocol.hpp b/src/device_trezor/trezor/protocol.hpp
index f58bf1039..8fc5eba97 100644
--- a/src/device_trezor/trezor/protocol.hpp
+++ b/src/device_trezor/trezor/protocol.hpp
@@ -118,7 +118,8 @@ namespace ki {
*/
bool key_image_data(wallet_shim * wallet,
const std::vector<tools::wallet2::transfer_details> & transfers,
- std::vector<MoneroTransferDetails> & res);
+ std::vector<MoneroTransferDetails> & res,
+ bool need_all_additionals=false);
/**
* Computes a hash over MoneroTransferDetails. Commitment used in the KI sync.
@@ -130,7 +131,8 @@ namespace ki {
*/
void generate_commitment(std::vector<MoneroTransferDetails> & mtds,
const std::vector<tools::wallet2::transfer_details> & transfers,
- std::shared_ptr<messages::monero::MoneroKeyImageExportInitRequest> & req);
+ std::shared_ptr<messages::monero::MoneroKeyImageExportInitRequest> & req,
+ bool need_subaddr_indices=false);
/**
* Processes Live refresh step response, parses KI, checks the signature
@@ -158,13 +160,13 @@ namespace tx {
void translate_address(MoneroAccountPublicAddress * dst, const cryptonote::account_public_address * src);
void translate_dst_entry(MoneroTransactionDestinationEntry * dst, const cryptonote::tx_destination_entry * src);
- void translate_src_entry(MoneroTransactionSourceEntry * dst, const cryptonote::tx_source_entry * src);
void translate_klrki(MoneroMultisigKLRki * dst, const rct::multisig_kLRki * src);
void translate_rct_key(MoneroRctKey * dst, const rct::ctkey * src);
std::string hash_addr(const MoneroAccountPublicAddress * addr, boost::optional<uint64_t> amount = boost::none, boost::optional<bool> is_subaddr = boost::none);
std::string hash_addr(const std::string & spend_key, const std::string & view_key, boost::optional<uint64_t> amount = boost::none, boost::optional<bool> is_subaddr = boost::none);
std::string hash_addr(const ::crypto::public_key * spend_key, const ::crypto::public_key * view_key, boost::optional<uint64_t> amount = boost::none, boost::optional<bool> is_subaddr = boost::none);
::crypto::secret_key compute_enc_key(const ::crypto::secret_key & private_view_key, const std::string & aux, const std::string & salt);
+ std::string compute_sealing_key(const std::string & master_key, size_t idx, bool is_iv=false);
typedef boost::variant<rct::rangeSig, rct::Bulletproof> rsig_v;
@@ -198,6 +200,7 @@ namespace tx {
std::vector<std::string> pseudo_outs_hmac;
std::vector<std::string> couts;
std::vector<std::string> couts_dec;
+ std::vector<std::string> signatures;
std::vector<rct::key> rsig_gamma;
std::string tx_prefix_hash;
std::string enc_salt1;
@@ -221,16 +224,33 @@ namespace tx {
unsigned m_client_version;
bool m_multisig;
- const tx_construction_data & cur_tx(){
+ const tx_construction_data & cur_src_tx() const {
CHECK_AND_ASSERT_THROW_MES(m_tx_idx < m_unsigned_tx->txes.size(), "Invalid transaction index");
return m_unsigned_tx->txes[m_tx_idx];
}
+ const tx_construction_data & cur_tx() const {
+ return m_ct.tx_data;
+ }
+
+ const tools::wallet2::transfer_details & get_transfer(size_t idx) const {
+ CHECK_AND_ASSERT_THROW_MES(idx < m_unsigned_tx->transfers.second.size() + m_unsigned_tx->transfers.first && idx >= m_unsigned_tx->transfers.first, "Invalid transfer index");
+ return m_unsigned_tx->transfers.second[idx - m_unsigned_tx->transfers.first];
+ }
+
+ const tools::wallet2::transfer_details & get_source_transfer(size_t idx) const {
+ const auto & sel_transfers = cur_tx().selected_transfers;
+ CHECK_AND_ASSERT_THROW_MES(idx < m_ct.source_permutation.size(), "Invalid source index - permutation");
+ CHECK_AND_ASSERT_THROW_MES(m_ct.source_permutation[idx] < sel_transfers.size(), "Invalid source index");
+ return get_transfer(sel_transfers.at(m_ct.source_permutation[idx]));
+ }
+
void extract_payment_id();
void compute_integrated_indices(TsxData * tsx_data);
bool should_compute_bp_now() const;
void compute_bproof(messages::monero::MoneroTransactionRsigData & rsig_data);
void process_bproof(rct::Bulletproof & bproof);
+ void set_tx_input(MoneroTransactionSourceEntry * dst, size_t idx, bool need_ring_keys=false, bool need_ring_indices=false);
public:
Signer(wallet_shim * wallet2, const unsigned_tx_set * unsigned_tx, size_t tx_idx = 0, hw::tx_aux_data * aux_data = nullptr);
diff --git a/src/device_trezor/trezor/transport.cpp b/src/device_trezor/trezor/transport.cpp
index 59b281f13..52bee6c6c 100644
--- a/src/device_trezor/trezor/transport.cpp
+++ b/src/device_trezor/trezor/transport.cpp
@@ -56,6 +56,11 @@ namespace trezor{
return true;
}
+ bool t_serialize(const epee::wipeable_string & in, std::string & out){
+ out.assign(in.data(), in.size());
+ return true;
+ }
+
bool t_serialize(const json_val & in, std::string & out){
rapidjson::StringBuffer sb;
rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
@@ -75,6 +80,11 @@ namespace trezor{
return true;
}
+ bool t_deserialize(std::string & in, epee::wipeable_string & out){
+ out = epee::wipeable_string(in);
+ return true;
+ }
+
bool t_deserialize(const std::string & in, json & out){
if (out.Parse(in.c_str()).HasParseError()) {
throw exc::CommunicationException("JSON parse error");
@@ -192,61 +202,69 @@ namespace trezor{
const auto msg_size = message_size(req);
const auto buff_size = serialize_message_buffer_size(msg_size) + 2;
- std::unique_ptr<uint8_t[]> req_buff(new uint8_t[buff_size]);
- uint8_t * req_buff_raw = req_buff.get();
+ epee::wipeable_string req_buff;
+ epee::wipeable_string chunk_buff;
+
+ req_buff.resize(buff_size);
+ chunk_buff.resize(REPLEN);
+
+ uint8_t * req_buff_raw = reinterpret_cast<uint8_t *>(req_buff.data());
+ uint8_t * chunk_buff_raw = reinterpret_cast<uint8_t *>(chunk_buff.data());
+
req_buff_raw[0] = '#';
req_buff_raw[1] = '#';
serialize_message(req, msg_size, req_buff_raw + 2, buff_size - 2);
size_t offset = 0;
- uint8_t chunk_buff[REPLEN];
// Chunk by chunk upload
while(offset < buff_size){
auto to_copy = std::min((size_t)(buff_size - offset), (size_t)(REPLEN - 1));
- chunk_buff[0] = '?';
- memcpy(chunk_buff + 1, req_buff_raw + offset, to_copy);
+ chunk_buff_raw[0] = '?';
+ memcpy(chunk_buff_raw + 1, req_buff_raw + offset, to_copy);
// Pad with zeros
if (to_copy < REPLEN - 1){
- memset(chunk_buff + 1 + to_copy, 0, REPLEN - 1 - to_copy);
+ memset(chunk_buff_raw + 1 + to_copy, 0, REPLEN - 1 - to_copy);
}
- transport.write_chunk(chunk_buff, REPLEN);
+ transport.write_chunk(chunk_buff_raw, REPLEN);
offset += REPLEN - 1;
}
}
void ProtocolV1::read(Transport & transport, std::shared_ptr<google::protobuf::Message> & msg, messages::MessageType * msg_type){
- char chunk[REPLEN];
+ epee::wipeable_string chunk_buff;
+ chunk_buff.resize(REPLEN);
+ char * chunk_buff_raw = chunk_buff.data();
// Initial chunk read
- size_t nread = transport.read_chunk(chunk, REPLEN);
+ size_t nread = transport.read_chunk(chunk_buff_raw, REPLEN);
if (nread != REPLEN){
throw exc::CommunicationException("Read chunk has invalid size");
}
- if (strncmp(chunk, "?##", 3) != 0){
+ if (memcmp(chunk_buff_raw, "?##", 3) != 0){
throw exc::CommunicationException("Malformed chunk");
}
uint16_t tag;
uint32_t len;
nread -= 3 + 6;
- deserialize_message_header(chunk + 3, tag, len);
+ deserialize_message_header(chunk_buff_raw + 3, tag, len);
- std::string data_acc(chunk + 3 + 6, nread);
+ epee::wipeable_string data_acc(chunk_buff_raw + 3 + 6, nread);
data_acc.reserve(len);
while(nread < len){
- const size_t cur = transport.read_chunk(chunk, REPLEN);
- if (chunk[0] != '?'){
+ const size_t cur = transport.read_chunk(chunk_buff_raw, REPLEN);
+ if (chunk_buff_raw[0] != '?'){
throw exc::CommunicationException("Chunk malformed");
}
- data_acc.append(chunk + 1, cur - 1);
+ data_acc.append(chunk_buff_raw + 1, cur - 1);
nread += cur - 1;
}
@@ -259,7 +277,7 @@ namespace trezor{
}
std::shared_ptr<google::protobuf::Message> msg_wrap(MessageMapper::get_message(tag));
- if (!msg_wrap->ParseFromArray(data_acc.c_str(), len)){
+ if (!msg_wrap->ParseFromArray(data_acc.data(), len)){
throw exc::CommunicationException("Message could not be parsed");
}
@@ -426,15 +444,16 @@ namespace trezor{
const auto msg_size = message_size(req);
const auto buff_size = serialize_message_buffer_size(msg_size);
+ epee::wipeable_string req_buff;
+ req_buff.resize(buff_size);
- std::unique_ptr<uint8_t[]> req_buff(new uint8_t[buff_size]);
- uint8_t * req_buff_raw = req_buff.get();
+ uint8_t * req_buff_raw = reinterpret_cast<uint8_t *>(req_buff.data());
serialize_message(req, msg_size, req_buff_raw, buff_size);
std::string uri = "/call/" + m_session.get();
- std::string req_hex = epee::to_hex::string(epee::span<const std::uint8_t>(req_buff_raw, buff_size));
- std::string res_hex;
+ epee::wipeable_string res_hex;
+ epee::wipeable_string req_hex = epee::to_hex::wipeable_string(epee::span<const std::uint8_t>(req_buff_raw, buff_size));
bool req_status = invoke_bridge_http(uri, req_hex, res_hex, m_http_client);
if (!req_status){
@@ -449,15 +468,15 @@ namespace trezor{
throw exc::CommunicationException("Could not read, no response stored");
}
- std::string bin_data;
- if (!epee::string_tools::parse_hexstr_to_binbuff(m_response.get(), bin_data)){
+ boost::optional<epee::wipeable_string> bin_data = m_response->parse_hexstr();
+ if (!bin_data){
throw exc::CommunicationException("Response is not well hexcoded");
}
uint16_t msg_tag;
uint32_t msg_len;
- deserialize_message_header(bin_data.c_str(), msg_tag, msg_len);
- if (bin_data.size() != msg_len + 6){
+ deserialize_message_header(bin_data->data(), msg_tag, msg_len);
+ if (bin_data->size() != msg_len + 6){
throw exc::CommunicationException("Response is not well hexcoded");
}
@@ -466,7 +485,7 @@ namespace trezor{
}
std::shared_ptr<google::protobuf::Message> msg_wrap(MessageMapper::get_message(msg_tag));
- if (!msg_wrap->ParseFromArray(bin_data.c_str() + 6, msg_len)){
+ if (!msg_wrap->ParseFromArray(bin_data->data() + 6, msg_len)){
throw exc::EncodingException("Response is not well hexcoded");
}
msg = msg_wrap;
diff --git a/src/device_trezor/trezor/transport.hpp b/src/device_trezor/trezor/transport.hpp
index affd91553..9a43b3637 100644
--- a/src/device_trezor/trezor/transport.hpp
+++ b/src/device_trezor/trezor/transport.hpp
@@ -66,10 +66,12 @@ namespace trezor {
// Base HTTP comm serialization.
bool t_serialize(const std::string & in, std::string & out);
+ bool t_serialize(const epee::wipeable_string & in, std::string & out);
bool t_serialize(const json_val & in, std::string & out);
std::string t_serialize(const json_val & in);
bool t_deserialize(const std::string & in, std::string & out);
+ bool t_deserialize(std::string & in, epee::wipeable_string & out);
bool t_deserialize(const std::string & in, json & out);
// Flexible json serialization. HTTP client tailored for bridge API
@@ -84,6 +86,13 @@ namespace trezor {
additional_params.push_back(std::make_pair("Content-Type","application/json; charset=utf-8"));
const http::http_response_info* pri = nullptr;
+ const auto data_cleaner = epee::misc_utils::create_scope_leave_handler([&]() {
+ if (!req_param.empty()) {
+ memwipe(&req_param[0], req_param.size());
+ }
+ transport.wipe_response();
+ });
+
if(!transport.invoke(uri, method, req_param, timeout, &pri, std::move(additional_params)))
{
MERROR("Failed to invoke http request to " << uri);
@@ -103,7 +112,7 @@ namespace trezor {
return false;
}
- return t_deserialize(pri->m_body, result_struct);
+ return t_deserialize(const_cast<http::http_response_info*>(pri)->m_body, result_struct);
}
// Forward decl
@@ -186,7 +195,7 @@ namespace trezor {
std::string m_bridge_host;
boost::optional<std::string> m_device_path;
boost::optional<std::string> m_session;
- boost::optional<std::string> m_response;
+ boost::optional<epee::wipeable_string> m_response;
boost::optional<json> m_device_info;
};
diff --git a/src/multisig/multisig.cpp b/src/multisig/multisig.cpp
index 999894db0..70a4c1c8e 100644
--- a/src/multisig/multisig.cpp
+++ b/src/multisig/multisig.cpp
@@ -82,6 +82,7 @@ namespace cryptonote
{
rct::key sk = rct::scalarmultKey(rct::pk2rct(k), rct::sk2rct(blinded_skey));
crypto::secret_key msk = get_multisig_blinded_secret_key(rct::rct2sk(sk));
+ memwipe(&sk, sizeof(sk));
multisig_keys.push_back(msk);
sc_add(spend_skey.bytes, spend_skey.bytes, (const unsigned char*)msk.data);
}
@@ -126,10 +127,10 @@ namespace cryptonote
//-----------------------------------------------------------------
crypto::secret_key generate_multisig_view_secret_key(const crypto::secret_key &skey, const std::vector<crypto::secret_key> &skeys)
{
- rct::key view_skey = rct::sk2rct(get_multisig_blinded_secret_key(skey));
+ crypto::secret_key view_skey = get_multisig_blinded_secret_key(skey);
for (const auto &k: skeys)
- sc_add(view_skey.bytes, view_skey.bytes, rct::sk2rct(k).bytes);
- return rct::rct2sk(view_skey);
+ sc_add((unsigned char*)&view_skey, rct::sk2rct(view_skey).bytes, rct::sk2rct(k).bytes);
+ return view_skey;
}
//-----------------------------------------------------------------
crypto::public_key generate_multisig_M_N_spend_public_key(const std::vector<crypto::public_key> &pkeys)
diff --git a/src/net/zmq.cpp b/src/net/zmq.cpp
index d02a22983..7ea80b907 100644
--- a/src/net/zmq.cpp
+++ b/src/net/zmq.cpp
@@ -33,6 +33,8 @@
#include <limits>
#include <utility>
+#include "byte_slice.h"
+
namespace net
{
namespace zmq
@@ -183,6 +185,22 @@ namespace zmq
{
return retry_op(zmq_send, socket, payload.data(), payload.size(), flags);
}
+
+ expect<void> send(epee::byte_slice&& payload, void* socket, int flags) noexcept
+ {
+ void* const data = const_cast<std::uint8_t*>(payload.data());
+ const std::size_t size = payload.size();
+ auto buffer = payload.take_buffer(); // clears `payload` from callee
+
+ zmq_msg_t msg{};
+ MONERO_ZMQ_CHECK(zmq_msg_init_data(std::addressof(msg), data, size, epee::release_byte_slice::call, buffer.get()));
+ buffer.release(); // zmq will now decrement byte_slice ref-count
+
+ expect<void> sent = retry_op(zmq_msg_send, std::addressof(msg), socket, flags);
+ if (!sent) // beware if removing `noexcept` from this function - possible leak here
+ zmq_msg_close(std::addressof(msg));
+ return sent;
+ }
} // zmq
} // net
diff --git a/src/net/zmq.h b/src/net/zmq.h
index c6a7fd743..65560b62e 100644
--- a/src/net/zmq.h
+++ b/src/net/zmq.h
@@ -53,6 +53,11 @@
#define MONERO_ZMQ_THROW(msg) \
MONERO_THROW( ::net::zmq::get_error_code(), msg )
+namespace epee
+{
+ class byte_slice;
+}
+
namespace net
{
namespace zmq
@@ -132,5 +137,24 @@ namespace zmq
\param flags See `zmq_send` for possible flags.
\return `success()` if sent, otherwise ZMQ error. */
expect<void> send(epee::span<const std::uint8_t> payload, void* socket, int flags = 0) noexcept;
+
+ /*! Sends `payload` on `socket`. Blocks until the entire message is queued
+ for sending, or until `zmq_term` is called on the `zmq_context`
+ associated with `socket`. If the context is terminated,
+ `make_error_code(ETERM)` is returned.
+
+ \note This will automatically retry on `EINTR`, so exiting on
+ interrupts requires context termination.
+ \note If non-blocking behavior is requested on `socket` or by `flags`,
+ then `net::zmq::make_error_code(EAGAIN)` will be returned if this
+ would block.
+
+ \param payload sent as one message on `socket`.
+ \param socket Handle created with `zmq_socket`.
+ \param flags See `zmq_msg_send` for possible flags.
+
+ \post `payload.emtpy()` - ownership is transferred to zmq.
+ \return `success()` if sent, otherwise ZMQ error. */
+ expect<void> send(epee::byte_slice&& payload, void* socket, int flags = 0) noexcept;
} // zmq
} // net
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 5337106dd..57b1335eb 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -384,6 +384,7 @@ namespace nodetool
bool is_addr_recently_failed(const epee::net_utils::network_address& addr);
bool is_priority_node(const epee::net_utils::network_address& na);
std::set<std::string> get_seed_nodes(cryptonote::network_type nettype) const;
+ std::set<std::string> get_seed_nodes();
bool connect_to_seed();
template <class Container>
@@ -467,7 +468,9 @@ namespace nodetool
std::list<epee::net_utils::network_address> m_priority_peers;
std::vector<epee::net_utils::network_address> m_exclusive_peers;
std::vector<epee::net_utils::network_address> m_seed_nodes;
- bool m_fallback_seed_nodes_added;
+ bool m_seed_nodes_initialized = false;
+ boost::shared_mutex m_seed_nodes_lock;
+ std::atomic_flag m_fallback_seed_nodes_added;
std::vector<nodetool::peerlist_entry> m_command_line_peers;
uint64_t m_peer_livetime;
//keep connections to initiate some interactions
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 9ff2627d0..f8c177e3a 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -435,6 +435,8 @@ namespace nodetool
if (command_line::has_arg(vm, arg_p2p_seed_node))
{
+ boost::unique_lock<boost::shared_mutex> lock(m_seed_nodes_lock);
+
if (!parse_peers_and_add_to_container(vm, arg_p2p_seed_node, m_seed_nodes))
return false;
}
@@ -630,7 +632,119 @@ namespace nodetool
full_addrs.insert("192.110.160.146:18080");
full_addrs.insert("88.198.163.90:18080");
full_addrs.insert("95.217.25.101:18080");
+ full_addrs.insert("209.250.243.248:18080");
+ full_addrs.insert("104.238.221.81:18080");
+ full_addrs.insert("66.85.74.134:18080");
+ }
+ return full_addrs;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes()
+ {
+ if (!m_exclusive_peers.empty() || m_offline)
+ {
+ return {};
+ }
+ if (m_nettype == cryptonote::TESTNET)
+ {
+ return get_seed_nodes(cryptonote::TESTNET);
+ }
+ if (m_nettype == cryptonote::STAGENET)
+ {
+ return get_seed_nodes(cryptonote::STAGENET);
+ }
+
+ std::set<std::string> full_addrs;
+
+ // for each hostname in the seed nodes list, attempt to DNS resolve and
+ // add the result addresses as seed nodes
+ // TODO: at some point add IPv6 support, but that won't be relevant
+ // for some time yet.
+
+ std::vector<std::vector<std::string>> dns_results;
+ dns_results.resize(m_seed_nodes_list.size());
+
+ // some libc implementation provide only a very small stack
+ // for threads, e.g. musl only gives +- 80kb, which is not
+ // enough to do a resolve with unbound. we request a stack
+ // of 1 mb, which should be plenty
+ boost::thread::attributes thread_attributes;
+ thread_attributes.set_stack_size(1024*1024);
+
+ std::list<boost::thread> dns_threads;
+ uint64_t result_index = 0;
+ for (const std::string& addr_str : m_seed_nodes_list)
+ {
+ boost::thread th = boost::thread(thread_attributes, [=, &dns_results, &addr_str]
+ {
+ MDEBUG("dns_threads[" << result_index << "] created for: " << addr_str);
+ // TODO: care about dnssec avail/valid
+ bool avail, valid;
+ std::vector<std::string> addr_list;
+
+ try
+ {
+ addr_list = tools::DNSResolver::instance().get_ipv4(addr_str, avail, valid);
+ MDEBUG("dns_threads[" << result_index << "] DNS resolve done");
+ boost::this_thread::interruption_point();
+ }
+ catch(const boost::thread_interrupted&)
+ {
+ // thread interruption request
+ // even if we now have results, finish thread without setting
+ // result variables, which are now out of scope in main thread
+ MWARNING("dns_threads[" << result_index << "] interrupted");
+ return;
+ }
+
+ MINFO("dns_threads[" << result_index << "] addr_str: " << addr_str << " number of results: " << addr_list.size());
+ dns_results[result_index] = addr_list;
+ });
+
+ dns_threads.push_back(std::move(th));
+ ++result_index;
+ }
+
+ MDEBUG("dns_threads created, now waiting for completion or timeout of " << CRYPTONOTE_DNS_TIMEOUT_MS << "ms");
+ boost::chrono::system_clock::time_point deadline = boost::chrono::system_clock::now() + boost::chrono::milliseconds(CRYPTONOTE_DNS_TIMEOUT_MS);
+ uint64_t i = 0;
+ for (boost::thread& th : dns_threads)
+ {
+ if (! th.try_join_until(deadline))
+ {
+ MWARNING("dns_threads[" << i << "] timed out, sending interrupt");
+ th.interrupt();
+ }
+ ++i;
+ }
+
+ i = 0;
+ for (const auto& result : dns_results)
+ {
+ MDEBUG("DNS lookup for " << m_seed_nodes_list[i] << ": " << result.size() << " results");
+ // if no results for node, thread's lookup likely timed out
+ if (result.size())
+ {
+ for (const auto& addr_string : result)
+ full_addrs.insert(addr_string + ":" + std::to_string(cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT));
+ }
+ ++i;
+ }
+
+ // append the fallback nodes if we have too few seed nodes to start with
+ if (full_addrs.size() < MIN_WANTED_SEED_NODES)
+ {
+ if (full_addrs.empty())
+ MINFO("DNS seed node lookup either timed out or failed, falling back to defaults");
+ else
+ MINFO("Not enough DNS seed nodes found, using fallback defaults too");
+
+ for (const auto &peer: get_seed_nodes(cryptonote::MAINNET))
+ full_addrs.insert(peer);
+ m_fallback_seed_nodes_added.test_and_set();
}
+
return full_addrs;
}
//-----------------------------------------------------------------------------------
@@ -648,123 +762,21 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::init(const boost::program_options::variables_map& vm)
{
- std::set<std::string> full_addrs;
-
bool res = handle_command_line(vm);
CHECK_AND_ASSERT_MES(res, false, "Failed to handle command line");
- m_fallback_seed_nodes_added = false;
if (m_nettype == cryptonote::TESTNET)
{
memcpy(&m_network_id, &::config::testnet::NETWORK_ID, 16);
- full_addrs = get_seed_nodes(cryptonote::TESTNET);
}
else if (m_nettype == cryptonote::STAGENET)
{
memcpy(&m_network_id, &::config::stagenet::NETWORK_ID, 16);
- full_addrs = get_seed_nodes(cryptonote::STAGENET);
}
else
{
memcpy(&m_network_id, &::config::NETWORK_ID, 16);
- if (m_exclusive_peers.empty() && !m_offline)
- {
- // for each hostname in the seed nodes list, attempt to DNS resolve and
- // add the result addresses as seed nodes
- // TODO: at some point add IPv6 support, but that won't be relevant
- // for some time yet.
-
- std::vector<std::vector<std::string>> dns_results;
- dns_results.resize(m_seed_nodes_list.size());
-
- // some libc implementation provide only a very small stack
- // for threads, e.g. musl only gives +- 80kb, which is not
- // enough to do a resolve with unbound. we request a stack
- // of 1 mb, which should be plenty
- boost::thread::attributes thread_attributes;
- thread_attributes.set_stack_size(1024*1024);
-
- std::list<boost::thread> dns_threads;
- uint64_t result_index = 0;
- for (const std::string& addr_str : m_seed_nodes_list)
- {
- boost::thread th = boost::thread(thread_attributes, [=, &dns_results, &addr_str]
- {
- MDEBUG("dns_threads[" << result_index << "] created for: " << addr_str);
- // TODO: care about dnssec avail/valid
- bool avail, valid;
- std::vector<std::string> addr_list;
-
- try
- {
- addr_list = tools::DNSResolver::instance().get_ipv4(addr_str, avail, valid);
- MDEBUG("dns_threads[" << result_index << "] DNS resolve done");
- boost::this_thread::interruption_point();
- }
- catch(const boost::thread_interrupted&)
- {
- // thread interruption request
- // even if we now have results, finish thread without setting
- // result variables, which are now out of scope in main thread
- MWARNING("dns_threads[" << result_index << "] interrupted");
- return;
- }
-
- MINFO("dns_threads[" << result_index << "] addr_str: " << addr_str << " number of results: " << addr_list.size());
- dns_results[result_index] = addr_list;
- });
-
- dns_threads.push_back(std::move(th));
- ++result_index;
- }
-
- MDEBUG("dns_threads created, now waiting for completion or timeout of " << CRYPTONOTE_DNS_TIMEOUT_MS << "ms");
- boost::chrono::system_clock::time_point deadline = boost::chrono::system_clock::now() + boost::chrono::milliseconds(CRYPTONOTE_DNS_TIMEOUT_MS);
- uint64_t i = 0;
- for (boost::thread& th : dns_threads)
- {
- if (! th.try_join_until(deadline))
- {
- MWARNING("dns_threads[" << i << "] timed out, sending interrupt");
- th.interrupt();
- }
- ++i;
- }
-
- i = 0;
- for (const auto& result : dns_results)
- {
- MDEBUG("DNS lookup for " << m_seed_nodes_list[i] << ": " << result.size() << " results");
- // if no results for node, thread's lookup likely timed out
- if (result.size())
- {
- for (const auto& addr_string : result)
- full_addrs.insert(addr_string + ":" + std::to_string(cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT));
- }
- ++i;
- }
-
- // append the fallback nodes if we have too few seed nodes to start with
- if (full_addrs.size() < MIN_WANTED_SEED_NODES)
- {
- if (full_addrs.empty())
- MINFO("DNS seed node lookup either timed out or failed, falling back to defaults");
- else
- MINFO("Not enough DNS seed nodes found, using fallback defaults too");
-
- for (const auto &peer: get_seed_nodes(cryptonote::MAINNET))
- full_addrs.insert(peer);
- m_fallback_seed_nodes_added = true;
- }
- }
- }
-
- for (const auto& full_addr : full_addrs)
- {
- MDEBUG("Seed node: " << full_addr);
- append_net_address(m_seed_nodes, full_addr, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT);
}
- MDEBUG("Number of seed nodes: " << m_seed_nodes.size());
m_config_folder = command_line::get_arg(vm, cryptonote::arg_data_dir);
network_zone& public_zone = m_network_zones.at(epee::net_utils::zone::public_);
@@ -1541,6 +1553,20 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::connect_to_seed()
{
+ boost::upgrade_lock<boost::shared_mutex> seed_nodes_upgrade_lock(m_seed_nodes_lock);
+
+ if (!m_seed_nodes_initialized)
+ {
+ boost::upgrade_to_unique_lock<boost::shared_mutex> seed_nodes_lock(seed_nodes_upgrade_lock);
+ m_seed_nodes_initialized = true;
+ for (const auto& full_addr : get_seed_nodes())
+ {
+ MDEBUG("Seed node: " << full_addr);
+ append_net_address(m_seed_nodes, full_addr, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT);
+ }
+ MDEBUG("Number of seed nodes: " << m_seed_nodes.size());
+ }
+
if (m_seed_nodes.empty() || m_offline || !m_exclusive_peers.empty())
return true;
@@ -1561,16 +1587,19 @@ namespace nodetool
break;
if(++try_count > m_seed_nodes.size())
{
- if (!m_fallback_seed_nodes_added)
+ if (!m_fallback_seed_nodes_added.test_and_set())
{
MWARNING("Failed to connect to any of seed peers, trying fallback seeds");
current_index = m_seed_nodes.size() - 1;
- for (const auto &peer: get_seed_nodes(m_nettype))
{
- MDEBUG("Fallback seed node: " << peer);
- append_net_address(m_seed_nodes, peer, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT);
+ boost::upgrade_to_unique_lock<boost::shared_mutex> seed_nodes_lock(seed_nodes_upgrade_lock);
+
+ for (const auto &peer: get_seed_nodes(m_nettype))
+ {
+ MDEBUG("Fallback seed node: " << peer);
+ append_net_address(m_seed_nodes, peer, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT);
+ }
}
- m_fallback_seed_nodes_added = true;
if (current_index == m_seed_nodes.size() - 1)
{
MWARNING("No fallback seeds, continuing without seeds");
@@ -1604,10 +1633,9 @@ namespace nodetool
// Only have seeds in the public zone right now.
size_t start_conn_count = get_public_outgoing_connections_count();
- if(!get_public_white_peers_count() && m_seed_nodes.size())
+ if(!get_public_white_peers_count() && !connect_to_seed())
{
- if (!connect_to_seed())
- return false;
+ return false;
}
if (!connect_to_peerlist(m_priority_peers)) return false;
diff --git a/src/ringct/bulletproofs.cc b/src/ringct/bulletproofs.cc
index 2ff88c6e7..6b88fd730 100644
--- a/src/ringct/bulletproofs.cc
+++ b/src/ringct/bulletproofs.cc
@@ -905,7 +905,7 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
rct::key m_y0 = rct::zero(), y1 = rct::zero();
int proof_data_index = 0;
rct::keyV w_cache;
- rct::keyV proof8_V, proof8_L, proof8_R;
+ std::vector<ge_p3> proof8_V, proof8_L, proof8_R;
for (const Bulletproof *p: proofs)
{
const Bulletproof &proof = *p;
@@ -918,13 +918,17 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
const rct::key weight_z = rct::skGen();
// pre-multiply some points by 8
- proof8_V.resize(proof.V.size()); for (size_t i = 0; i < proof.V.size(); ++i) proof8_V[i] = rct::scalarmult8(proof.V[i]);
- proof8_L.resize(proof.L.size()); for (size_t i = 0; i < proof.L.size(); ++i) proof8_L[i] = rct::scalarmult8(proof.L[i]);
- proof8_R.resize(proof.R.size()); for (size_t i = 0; i < proof.R.size(); ++i) proof8_R[i] = rct::scalarmult8(proof.R[i]);
- rct::key proof8_T1 = rct::scalarmult8(proof.T1);
- rct::key proof8_T2 = rct::scalarmult8(proof.T2);
- rct::key proof8_S = rct::scalarmult8(proof.S);
- rct::key proof8_A = rct::scalarmult8(proof.A);
+ proof8_V.resize(proof.V.size()); for (size_t i = 0; i < proof.V.size(); ++i) rct::scalarmult8(proof8_V[i], proof.V[i]);
+ proof8_L.resize(proof.L.size()); for (size_t i = 0; i < proof.L.size(); ++i) rct::scalarmult8(proof8_L[i], proof.L[i]);
+ proof8_R.resize(proof.R.size()); for (size_t i = 0; i < proof.R.size(); ++i) rct::scalarmult8(proof8_R[i], proof.R[i]);
+ ge_p3 proof8_T1;
+ ge_p3 proof8_T2;
+ ge_p3 proof8_S;
+ ge_p3 proof8_A;
+ rct::scalarmult8(proof8_T1, proof.T1);
+ rct::scalarmult8(proof8_T2, proof.T2);
+ rct::scalarmult8(proof8_S, proof.S);
+ rct::scalarmult8(proof8_A, proof.A);
PERF_TIMER_START_BP(VERIFY_line_61);
sc_mulsub(m_y0.bytes, proof.taux.bytes, weight_y.bytes, m_y0.bytes);
diff --git a/src/ringct/rctOps.cpp b/src/ringct/rctOps.cpp
index 6e4d063df..b2dd32ada 100644
--- a/src/ringct/rctOps.cpp
+++ b/src/ringct/rctOps.cpp
@@ -408,6 +408,18 @@ namespace rct {
return res;
}
+ //Computes 8P without byte conversion
+ void scalarmult8(ge_p3 &res, const key &P)
+ {
+ ge_p3 p3;
+ CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&p3, P.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
+ ge_p2 p2;
+ ge_p3_to_p2(&p2, &p3);
+ ge_p1p1 p1;
+ ge_mul8(&p1, &p2);
+ ge_p1p1_to_p3(&res, &p1);
+ }
+
//Computes lA where l is the curve order
bool isInMainSubgroup(const key & A) {
ge_p3 p3;
diff --git a/src/ringct/rctOps.h b/src/ringct/rctOps.h
index c24d48e9a..74e0ad833 100644
--- a/src/ringct/rctOps.h
+++ b/src/ringct/rctOps.h
@@ -124,6 +124,7 @@ namespace rct {
key scalarmultH(const key & a);
// multiplies a point by 8
key scalarmult8(const key & P);
+ void scalarmult8(ge_p3 &res, const key & P);
// checks a is in the main subgroup (ie, not a small one)
bool isInMainSubgroup(const key & a);
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index a7b265d63..2e3e7007e 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -29,6 +29,7 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "misc_log_ex.h"
+#include "misc_language.h"
#include "common/perf_timer.h"
#include "common/threadpool.h"
#include "common/util.h"
@@ -108,6 +109,7 @@ namespace rct {
//Borromean (c.f. gmax/andytoshi's paper)
boroSig genBorromean(const key64 x, const key64 P1, const key64 P2, const bits indices) {
key64 L[2], alpha;
+ auto wiper = epee::misc_utils::create_scope_leave_handler([&](){memwipe(alpha, sizeof(alpha));});
key c;
int naught = 0, prime = 0, ii = 0, jj=0;
boroSig bb;
@@ -190,6 +192,7 @@ namespace rct {
vector<geDsmp> Ip(dsRows);
rv.II = keyV(dsRows);
keyV alpha(rows);
+ auto wiper = epee::misc_utils::create_scope_leave_handler([&](){memwipe(alpha.data(), alpha.size() * sizeof(alpha[0]));});
keyV aG(rows);
rv.ss = keyM(cols, aG);
keyV aHP(dsRows);
@@ -548,7 +551,7 @@ namespace rct {
subKeys(M[i][1], pubs[i].mask, Cout);
}
mgSig result = MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows, hwdev);
- memwipe(&sk[0], sizeof(key));
+ memwipe(sk.data(), sk.size() * sizeof(key));
return result;
}
diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h
index bf4b7b4aa..9b7f26a02 100644
--- a/src/ringct/rctTypes.h
+++ b/src/ringct/rctTypes.h
@@ -48,6 +48,7 @@ extern "C" {
#include "hex.h"
#include "span.h"
+#include "memwipe.h"
#include "serialization/vector.h"
#include "serialization/debug_archive.h"
#include "serialization/binary_archive.h"
@@ -106,6 +107,8 @@ namespace rct {
key L;
key R;
key ki;
+
+ ~multisig_kLRki() { memwipe(&k, sizeof(k)); }
};
struct multisig_out {
diff --git a/src/rpc/bootstrap_node_selector.h b/src/rpc/bootstrap_node_selector.h
index fc993719b..47722a008 100644
--- a/src/rpc/bootstrap_node_selector.h
+++ b/src/rpc/bootstrap_node_selector.h
@@ -54,6 +54,8 @@ namespace bootstrap_node
struct selector
{
+ virtual ~selector() = default;
+
virtual void handle_result(const std::string &address, bool success) = 0;
virtual boost::optional<node_info> next_node() = 0;
};
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 9b0eeb1f1..82a7234d1 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -224,7 +224,7 @@ namespace cryptonote
}
else if (address == "auto")
{
- auto get_nodes = [this, credits_per_hash_threshold]() {
+ auto get_nodes = [this]() {
return get_public_nodes(credits_per_hash_threshold);
};
m_bootstrap_daemon.reset(new bootstrap_daemon(std::move(get_nodes), rpc_payment_enabled));
@@ -1990,7 +1990,7 @@ namespace cryptonote
r = false;
}
res.untrusted = true;
- return true;
+ return r;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request& req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
diff --git a/src/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp
index d05854e34..1aad82159 100644
--- a/src/rpc/daemon_handler.cpp
+++ b/src/rpc/daemon_handler.cpp
@@ -33,6 +33,7 @@
#include <stdexcept>
#include <boost/uuid/nil_generator.hpp>
+#include <boost/utility/string_ref.hpp>
// likely included by daemon_handler.h's includes,
// but including here for clarity
#include "cryptonote_core/cryptonote_core.h"
@@ -48,7 +49,7 @@ namespace rpc
{
namespace
{
- using handler_function = std::string(DaemonHandler& handler, const rapidjson::Value& id, const rapidjson::Value& msg);
+ using handler_function = epee::byte_slice(DaemonHandler& handler, const rapidjson::Value& id, const rapidjson::Value& msg);
struct handler_map
{
const char* method_name;
@@ -66,7 +67,7 @@ namespace rpc
}
template<typename Message>
- std::string handle_message(DaemonHandler& handler, const rapidjson::Value& id, const rapidjson::Value& parameters)
+ epee::byte_slice handle_message(DaemonHandler& handler, const rapidjson::Value& id, const rapidjson::Value& parameters)
{
typename Message::Request request{};
request.fromJson(parameters);
@@ -100,7 +101,8 @@ namespace rpc
{u8"key_images_spent", handle_message<KeyImagesSpent>},
{u8"mining_status", handle_message<MiningStatus>},
{u8"save_bc", handle_message<SaveBC>},
- {u8"send_raw_tx", handle_message<SendRawTxHex>},
+ {u8"send_raw_tx", handle_message<SendRawTx>},
+ {u8"send_raw_tx_hex", handle_message<SendRawTxHex>},
{u8"set_log_level", handle_message<SetLogLevel>},
{u8"start_mining", handle_message<StartMining>},
{u8"stop_mining", handle_message<StopMining>}
@@ -903,7 +905,7 @@ namespace rpc
return true;
}
- std::string DaemonHandler::handle(const std::string& request)
+ epee::byte_slice DaemonHandler::handle(const std::string& request)
{
MDEBUG("Handling RPC request: " << request);
@@ -916,8 +918,11 @@ namespace rpc
if (matched_handler == std::end(handlers) || matched_handler->method_name != request_type)
return BAD_REQUEST(request_type, req_full.getID());
- std::string response = matched_handler->call(*this, req_full.getID(), req_full.getMessage());
- MDEBUG("Returning RPC response: " << response);
+ epee::byte_slice response = matched_handler->call(*this, req_full.getID(), req_full.getMessage());
+
+ const boost::string_ref response_view{reinterpret_cast<const char*>(response.data()), response.size()};
+ MDEBUG("Returning RPC response: " << response_view);
+
return response;
}
catch (const std::exception& e)
diff --git a/src/rpc/daemon_handler.h b/src/rpc/daemon_handler.h
index 61eac17f0..b797b1155 100644
--- a/src/rpc/daemon_handler.h
+++ b/src/rpc/daemon_handler.h
@@ -28,6 +28,7 @@
#pragma once
+#include "byte_slice.h"
#include "daemon_messages.h"
#include "daemon_rpc_version.h"
#include "rpc_handler.h"
@@ -132,7 +133,7 @@ class DaemonHandler : public RpcHandler
void handle(const GetOutputDistribution::Request& req, GetOutputDistribution::Response& res);
- std::string handle(const std::string& request);
+ epee::byte_slice handle(const std::string& request) override final;
private:
diff --git a/src/rpc/daemon_messages.cpp b/src/rpc/daemon_messages.cpp
index 5c179408e..22f73472d 100644
--- a/src/rpc/daemon_messages.cpp
+++ b/src/rpc/daemon_messages.cpp
@@ -34,14 +34,14 @@ namespace cryptonote
namespace rpc
{
-void GetHeight::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetHeight::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void GetHeight::Request::fromJson(const rapidjson::Value& val)
{
}
-void GetHeight::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetHeight::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, height, height);
}
@@ -52,7 +52,7 @@ void GetHeight::Response::fromJson(const rapidjson::Value& val)
}
-void GetBlocksFast::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlocksFast::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, block_ids, block_ids);
INSERT_INTO_JSON_OBJECT(dest, start_height, start_height);
@@ -66,7 +66,7 @@ void GetBlocksFast::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, prune, prune);
}
-void GetBlocksFast::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlocksFast::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, blocks, blocks);
INSERT_INTO_JSON_OBJECT(dest, start_height, start_height);
@@ -83,7 +83,7 @@ void GetBlocksFast::Response::fromJson(const rapidjson::Value& val)
}
-void GetHashesFast::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetHashesFast::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, known_hashes, known_hashes);
INSERT_INTO_JSON_OBJECT(dest, start_height, start_height);
@@ -95,7 +95,7 @@ void GetHashesFast::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, start_height, start_height);
}
-void GetHashesFast::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetHashesFast::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, hashes, hashes);
INSERT_INTO_JSON_OBJECT(dest, start_height, start_height);
@@ -110,7 +110,7 @@ void GetHashesFast::Response::fromJson(const rapidjson::Value& val)
}
-void GetTransactions::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetTransactions::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, tx_hashes, tx_hashes);
}
@@ -120,7 +120,7 @@ void GetTransactions::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, tx_hashes, tx_hashes);
}
-void GetTransactions::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetTransactions::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, txs, txs);
INSERT_INTO_JSON_OBJECT(dest, missed_hashes, missed_hashes);
@@ -133,7 +133,7 @@ void GetTransactions::Response::fromJson(const rapidjson::Value& val)
}
-void KeyImagesSpent::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void KeyImagesSpent::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, key_images, key_images);
}
@@ -143,7 +143,7 @@ void KeyImagesSpent::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, key_images, key_images);
}
-void KeyImagesSpent::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void KeyImagesSpent::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, spent_status, spent_status);
}
@@ -154,7 +154,7 @@ void KeyImagesSpent::Response::fromJson(const rapidjson::Value& val)
}
-void GetTxGlobalOutputIndices::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetTxGlobalOutputIndices::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, tx_hash, tx_hash);
}
@@ -164,7 +164,7 @@ void GetTxGlobalOutputIndices::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, tx_hash, tx_hash);
}
-void GetTxGlobalOutputIndices::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetTxGlobalOutputIndices::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, output_indices, output_indices);
}
@@ -174,7 +174,7 @@ void GetTxGlobalOutputIndices::Response::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, output_indices, output_indices);
}
-void SendRawTx::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void SendRawTx::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, tx, tx);
INSERT_INTO_JSON_OBJECT(dest, relay, relay);
@@ -186,7 +186,7 @@ void SendRawTx::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, relay, relay);
}
-void SendRawTx::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void SendRawTx::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, relayed, relayed);
}
@@ -197,7 +197,7 @@ void SendRawTx::Response::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, relayed, relayed);
}
-void SendRawTxHex::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void SendRawTxHex::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, tx_as_hex, tx_as_hex);
INSERT_INTO_JSON_OBJECT(dest, relay, relay);
@@ -209,7 +209,7 @@ void SendRawTxHex::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, relay, relay);
}
-void StartMining::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void StartMining::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, miner_address, miner_address);
INSERT_INTO_JSON_OBJECT(dest, threads_count, threads_count);
@@ -225,7 +225,7 @@ void StartMining::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, ignore_battery, ignore_battery);
}
-void StartMining::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void StartMining::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void StartMining::Response::fromJson(const rapidjson::Value& val)
@@ -233,14 +233,14 @@ void StartMining::Response::fromJson(const rapidjson::Value& val)
}
-void StopMining::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void StopMining::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void StopMining::Request::fromJson(const rapidjson::Value& val)
{
}
-void StopMining::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void StopMining::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void StopMining::Response::fromJson(const rapidjson::Value& val)
@@ -248,14 +248,14 @@ void StopMining::Response::fromJson(const rapidjson::Value& val)
}
-void MiningStatus::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void MiningStatus::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void MiningStatus::Request::fromJson(const rapidjson::Value& val)
{
}
-void MiningStatus::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void MiningStatus::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, active, active);
INSERT_INTO_JSON_OBJECT(dest, speed, speed);
@@ -274,14 +274,14 @@ void MiningStatus::Response::fromJson(const rapidjson::Value& val)
}
-void GetInfo::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetInfo::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void GetInfo::Request::fromJson(const rapidjson::Value& val)
{
}
-void GetInfo::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetInfo::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, info, info);
}
@@ -292,14 +292,14 @@ void GetInfo::Response::fromJson(const rapidjson::Value& val)
}
-void SaveBC::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void SaveBC::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void SaveBC::Request::fromJson(const rapidjson::Value& val)
{
}
-void SaveBC::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void SaveBC::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void SaveBC::Response::fromJson(const rapidjson::Value& val)
@@ -307,7 +307,7 @@ void SaveBC::Response::fromJson(const rapidjson::Value& val)
}
-void GetBlockHash::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlockHash::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, height, height);
}
@@ -317,7 +317,7 @@ void GetBlockHash::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, height, height);
}
-void GetBlockHash::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlockHash::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, hash, hash);
}
@@ -328,14 +328,14 @@ void GetBlockHash::Response::fromJson(const rapidjson::Value& val)
}
-void GetLastBlockHeader::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetLastBlockHeader::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void GetLastBlockHeader::Request::fromJson(const rapidjson::Value& val)
{
}
-void GetLastBlockHeader::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetLastBlockHeader::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, header, header);
}
@@ -346,7 +346,7 @@ void GetLastBlockHeader::Response::fromJson(const rapidjson::Value& val)
}
-void GetBlockHeaderByHash::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlockHeaderByHash::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, hash, hash);
}
@@ -356,7 +356,7 @@ void GetBlockHeaderByHash::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, hash, hash);
}
-void GetBlockHeaderByHash::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlockHeaderByHash::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, header, header);
}
@@ -367,7 +367,7 @@ void GetBlockHeaderByHash::Response::fromJson(const rapidjson::Value& val)
}
-void GetBlockHeaderByHeight::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlockHeaderByHeight::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, height, height);
}
@@ -377,7 +377,7 @@ void GetBlockHeaderByHeight::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, height, height);
}
-void GetBlockHeaderByHeight::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlockHeaderByHeight::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, header, header);
}
@@ -388,7 +388,7 @@ void GetBlockHeaderByHeight::Response::fromJson(const rapidjson::Value& val)
}
-void GetBlockHeadersByHeight::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlockHeadersByHeight::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, heights, heights);
}
@@ -398,7 +398,7 @@ void GetBlockHeadersByHeight::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, heights, heights);
}
-void GetBlockHeadersByHeight::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlockHeadersByHeight::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, headers, headers);
}
@@ -409,14 +409,14 @@ void GetBlockHeadersByHeight::Response::fromJson(const rapidjson::Value& val)
}
-void GetPeerList::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetPeerList::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void GetPeerList::Request::fromJson(const rapidjson::Value& val)
{
}
-void GetPeerList::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetPeerList::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, white_list, white_list);
INSERT_INTO_JSON_OBJECT(dest, gray_list, gray_list);
@@ -429,7 +429,7 @@ void GetPeerList::Response::fromJson(const rapidjson::Value& val)
}
-void SetLogLevel::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void SetLogLevel::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, level, level);
}
@@ -439,7 +439,7 @@ void SetLogLevel::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, level, level);
}
-void SetLogLevel::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void SetLogLevel::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void SetLogLevel::Response::fromJson(const rapidjson::Value& val)
@@ -447,14 +447,14 @@ void SetLogLevel::Response::fromJson(const rapidjson::Value& val)
}
-void GetTransactionPool::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetTransactionPool::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void GetTransactionPool::Request::fromJson(const rapidjson::Value& val)
{
}
-void GetTransactionPool::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetTransactionPool::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, transactions, transactions);
INSERT_INTO_JSON_OBJECT(dest, key_images, key_images);
@@ -467,7 +467,7 @@ void GetTransactionPool::Response::fromJson(const rapidjson::Value& val)
}
-void HardForkInfo::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void HardForkInfo::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, version, version);
}
@@ -477,7 +477,7 @@ void HardForkInfo::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, version, version);
}
-void HardForkInfo::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void HardForkInfo::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, info, info);
}
@@ -488,7 +488,7 @@ void HardForkInfo::Response::fromJson(const rapidjson::Value& val)
}
-void GetOutputHistogram::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetOutputHistogram::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, amounts, amounts);
INSERT_INTO_JSON_OBJECT(dest, min_count, min_count);
@@ -506,7 +506,7 @@ void GetOutputHistogram::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, recent_cutoff, recent_cutoff);
}
-void GetOutputHistogram::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetOutputHistogram::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, histogram, histogram);
}
@@ -517,7 +517,7 @@ void GetOutputHistogram::Response::fromJson(const rapidjson::Value& val)
}
-void GetOutputKeys::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetOutputKeys::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, outputs, outputs);
}
@@ -527,7 +527,7 @@ void GetOutputKeys::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, outputs, outputs);
}
-void GetOutputKeys::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetOutputKeys::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, keys, keys);
}
@@ -538,14 +538,14 @@ void GetOutputKeys::Response::fromJson(const rapidjson::Value& val)
}
-void GetRPCVersion::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetRPCVersion::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void GetRPCVersion::Request::fromJson(const rapidjson::Value& val)
{
}
-void GetRPCVersion::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetRPCVersion::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, version, version);
}
@@ -555,7 +555,7 @@ void GetRPCVersion::Response::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, version, version);
}
-void GetFeeEstimate::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetFeeEstimate::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, num_grace_blocks, num_grace_blocks);
}
@@ -565,7 +565,7 @@ void GetFeeEstimate::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, num_grace_blocks, num_grace_blocks);
}
-void GetFeeEstimate::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetFeeEstimate::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, estimated_base_fee, estimated_base_fee);
INSERT_INTO_JSON_OBJECT(dest, fee_mask, fee_mask);
@@ -581,7 +581,7 @@ void GetFeeEstimate::Response::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, hard_fork_version, hard_fork_version);
}
-void GetOutputDistribution::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetOutputDistribution::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, amounts, amounts);
INSERT_INTO_JSON_OBJECT(dest, from_height, from_height);
@@ -597,7 +597,7 @@ void GetOutputDistribution::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, cumulative, cumulative);
}
-void GetOutputDistribution::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetOutputDistribution::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, status, status);
INSERT_INTO_JSON_OBJECT(dest, distributions, distributions);
diff --git a/src/rpc/daemon_messages.h b/src/rpc/daemon_messages.h
index bb5059cdc..64ea3e9d4 100644
--- a/src/rpc/daemon_messages.h
+++ b/src/rpc/daemon_messages.h
@@ -28,11 +28,11 @@
#pragma once
-#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <unordered_map>
#include <vector>
+#include "byte_stream.h"
#include "message.h"
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
#include "rpc/message_data_structs.h"
@@ -50,7 +50,7 @@ class classname \
public: \
Request() { } \
~Request() { } \
- void doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const override final; \
+ void doToJson(rapidjson::Writer<epee::byte_stream>& dest) const override final; \
void fromJson(const rapidjson::Value& val) override final;
#define BEGIN_RPC_MESSAGE_RESPONSE \
@@ -59,7 +59,7 @@ class classname \
public: \
Response() { } \
~Response() { } \
- void doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const override final; \
+ void doToJson(rapidjson::Writer<epee::byte_stream>& dest) const override final; \
void fromJson(const rapidjson::Value& val) override final;
#define END_RPC_MESSAGE_REQUEST };
diff --git a/src/rpc/message.cpp b/src/rpc/message.cpp
index 5b6a1c05b..fffb44921 100644
--- a/src/rpc/message.cpp
+++ b/src/rpc/message.cpp
@@ -62,7 +62,7 @@ const rapidjson::Value& get_method_field(const rapidjson::Value& src)
}
}
-void Message::toJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void Message::toJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
dest.StartObject();
INSERT_INTO_JSON_OBJECT(dest, status, status);
@@ -149,11 +149,11 @@ cryptonote::rpc::error FullMessage::getError()
return err;
}
-std::string FullMessage::getRequest(const std::string& request, const Message& message, const unsigned id)
+epee::byte_slice FullMessage::getRequest(const std::string& request, const Message& message, const unsigned id)
{
- rapidjson::StringBuffer buffer;
+ epee::byte_stream buffer;
{
- rapidjson::Writer<rapidjson::StringBuffer> dest{buffer};
+ rapidjson::Writer<epee::byte_stream> dest{buffer};
dest.StartObject();
INSERT_INTO_JSON_OBJECT(dest, jsonrpc, (boost::string_ref{"2.0", 3}));
@@ -172,15 +172,15 @@ std::string FullMessage::getRequest(const std::string& request, const Message& m
if (!dest.IsComplete())
throw std::logic_error{"Invalid JSON tree generated"};
}
- return std::string{buffer.GetString(), buffer.GetSize()};
+ return epee::byte_slice{std::move(buffer)};
}
-std::string FullMessage::getResponse(const Message& message, const rapidjson::Value& id)
+epee::byte_slice FullMessage::getResponse(const Message& message, const rapidjson::Value& id)
{
- rapidjson::StringBuffer buffer;
+ epee::byte_stream buffer;
{
- rapidjson::Writer<rapidjson::StringBuffer> dest{buffer};
+ rapidjson::Writer<epee::byte_stream> dest{buffer};
dest.StartObject();
INSERT_INTO_JSON_OBJECT(dest, jsonrpc, (boost::string_ref{"2.0", 3}));
@@ -207,17 +207,17 @@ std::string FullMessage::getResponse(const Message& message, const rapidjson::Va
if (!dest.IsComplete())
throw std::logic_error{"Invalid JSON tree generated"};
}
- return std::string{buffer.GetString(), buffer.GetSize()};
+ return epee::byte_slice{std::move(buffer)};
}
// convenience functions for bad input
-std::string BAD_REQUEST(const std::string& request)
+epee::byte_slice BAD_REQUEST(const std::string& request)
{
rapidjson::Value invalid;
return BAD_REQUEST(request, invalid);
}
-std::string BAD_REQUEST(const std::string& request, const rapidjson::Value& id)
+epee::byte_slice BAD_REQUEST(const std::string& request, const rapidjson::Value& id)
{
Message fail;
fail.status = Message::STATUS_BAD_REQUEST;
@@ -225,7 +225,7 @@ std::string BAD_REQUEST(const std::string& request, const rapidjson::Value& id)
return FullMessage::getResponse(fail, id);
}
-std::string BAD_JSON(const std::string& error_details)
+epee::byte_slice BAD_JSON(const std::string& error_details)
{
rapidjson::Value invalid;
Message fail;
diff --git a/src/rpc/message.h b/src/rpc/message.h
index 4cbc84fe4..5c369cdfc 100644
--- a/src/rpc/message.h
+++ b/src/rpc/message.h
@@ -29,10 +29,11 @@
#pragma once
#include <rapidjson/document.h>
-#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <string>
+#include "byte_slice.h"
+#include "byte_stream.h"
#include "rpc/message_data_structs.h"
namespace cryptonote
@@ -43,7 +44,7 @@ namespace rpc
class Message
{
- virtual void doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+ virtual void doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
public:
@@ -57,7 +58,7 @@ namespace rpc
virtual ~Message() { }
- void toJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const;
+ void toJson(rapidjson::Writer<epee::byte_stream>& dest) const;
virtual void fromJson(const rapidjson::Value& val);
@@ -85,8 +86,8 @@ namespace rpc
cryptonote::rpc::error getError();
- static std::string getRequest(const std::string& request, const Message& message, unsigned id);
- static std::string getResponse(const Message& message, const rapidjson::Value& id);
+ static epee::byte_slice getRequest(const std::string& request, const Message& message, unsigned id);
+ static epee::byte_slice getResponse(const Message& message, const rapidjson::Value& id);
private:
FullMessage() = default;
@@ -99,10 +100,10 @@ namespace rpc
// convenience functions for bad input
- std::string BAD_REQUEST(const std::string& request);
- std::string BAD_REQUEST(const std::string& request, const rapidjson::Value& id);
+ epee::byte_slice BAD_REQUEST(const std::string& request);
+ epee::byte_slice BAD_REQUEST(const std::string& request, const rapidjson::Value& id);
- std::string BAD_JSON(const std::string& error_details);
+ epee::byte_slice BAD_JSON(const std::string& error_details);
} // namespace rpc
diff --git a/src/rpc/rpc_handler.h b/src/rpc/rpc_handler.h
index b81983d28..9a1c3fc12 100644
--- a/src/rpc/rpc_handler.h
+++ b/src/rpc/rpc_handler.h
@@ -32,6 +32,7 @@
#include <cstdint>
#include <string>
#include <vector>
+#include "byte_slice.h"
#include "crypto/hash.h"
namespace cryptonote
@@ -54,7 +55,7 @@ class RpcHandler
RpcHandler() { }
virtual ~RpcHandler() { }
- virtual std::string handle(const std::string& request) = 0;
+ virtual epee::byte_slice handle(const std::string& request) = 0;
static boost::optional<output_distribution_data>
get_output_distribution(const std::function<bool(uint64_t, uint64_t, uint64_t, uint64_t&, std::vector<uint64_t>&, uint64_t&)> &f, uint64_t amount, uint64_t from_height, uint64_t to_height, const std::function<crypto::hash(uint64_t)> &get_hash, bool cumulative, uint64_t blockchain_height);
diff --git a/src/rpc/zmq_server.cpp b/src/rpc/zmq_server.cpp
index 1ee55673e..0d595539d 100644
--- a/src/rpc/zmq_server.cpp
+++ b/src/rpc/zmq_server.cpp
@@ -32,6 +32,8 @@
#include <cstdint>
#include <system_error>
+#include "byte_slice.h"
+
namespace cryptonote
{
@@ -73,10 +75,11 @@ void ZmqServer::serve()
{
const std::string message = MONERO_UNWRAP(net::zmq::receive(socket.get()));
MDEBUG("Received RPC request: \"" << message << "\"");
- const std::string& response = handler.handle(message);
+ epee::byte_slice response = handler.handle(message);
- MONERO_UNWRAP(net::zmq::send(epee::strspan<std::uint8_t>(response), socket.get()));
- MDEBUG("Sent RPC reply: \"" << response << "\"");
+ const boost::string_ref response_view{reinterpret_cast<const char*>(response.data()), response.size()};
+ MDEBUG("Sending RPC reply: \"" << response_view << "\"");
+ MONERO_UNWRAP(net::zmq::send(std::move(response), socket.get()));
}
}
catch (const std::system_error& e)
diff --git a/src/serialization/json_object.cpp b/src/serialization/json_object.cpp
index f20fd181a..6228b4bec 100644
--- a/src/serialization/json_object.cpp
+++ b/src/serialization/json_object.cpp
@@ -126,12 +126,12 @@ void read_hex(const rapidjson::Value& val, epee::span<std::uint8_t> dest)
}
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rapidjson::Value& src)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rapidjson::Value& src)
{
src.Accept(dest);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const boost::string_ref i)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const boost::string_ref i)
{
dest.String(i.data(), i.size());
}
@@ -146,7 +146,7 @@ void fromJsonValue(const rapidjson::Value& val, std::string& str)
str = val.GetString();
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, bool i)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, bool i)
{
dest.Bool(i);
}
@@ -185,7 +185,7 @@ void fromJsonValue(const rapidjson::Value& val, short& i)
to_int(val, i);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const unsigned int i)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const unsigned int i)
{
dest.Uint(i);
}
@@ -195,7 +195,7 @@ void fromJsonValue(const rapidjson::Value& val, unsigned int& i)
to_uint(val, i);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const int i)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const int i)
{
dest.Int(i);
}
@@ -205,7 +205,7 @@ void fromJsonValue(const rapidjson::Value& val, int& i)
to_int(val, i);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const unsigned long long i)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const unsigned long long i)
{
static_assert(!precision_loss<unsigned long long, std::uint64_t>(), "bad uint64 conversion");
dest.Uint64(i);
@@ -216,7 +216,7 @@ void fromJsonValue(const rapidjson::Value& val, unsigned long long& i)
to_uint64(val, i);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const long long i)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const long long i)
{
static_assert(!precision_loss<long long, std::int64_t>(), "bad int64 conversion");
dest.Int64(i);
@@ -237,7 +237,7 @@ void fromJsonValue(const rapidjson::Value& val, long& i)
to_int64(val, i);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::transaction& tx)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::transaction& tx)
{
dest.StartObject();
@@ -269,7 +269,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::transaction& tx)
GET_FROM_JSON_OBJECT(val, tx.rct_signatures, ringct);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::block& b)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::block& b)
{
dest.StartObject();
@@ -301,14 +301,14 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::block& b)
GET_FROM_JSON_OBJECT(val, b.tx_hashes, tx_hashes);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_v& txin)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_v& txin)
{
dest.StartObject();
struct add_input
{
using result_type = void;
- rapidjson::Writer<rapidjson::StringBuffer>& dest;
+ rapidjson::Writer<epee::byte_stream>& dest;
void operator()(cryptonote::txin_to_key const& input) const
{
@@ -373,7 +373,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_v& txin)
}
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_gen& txin)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_gen& txin)
{
dest.StartObject();
@@ -392,7 +392,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_gen& txin)
GET_FROM_JSON_OBJECT(val, txin.height, height);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_to_script& txin)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_to_script& txin)
{
dest.StartObject();
@@ -417,7 +417,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_script& txin
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_to_scripthash& txin)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_to_scripthash& txin)
{
dest.StartObject();
@@ -443,7 +443,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_scripthash&
GET_FROM_JSON_OBJECT(val, txin.sigset, sigset);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_to_key& txin)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_to_key& txin)
{
dest.StartObject();
@@ -467,7 +467,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_key& txin)
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txout_to_script& txout)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txout_to_script& txout)
{
dest.StartObject();
@@ -489,7 +489,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_script& txo
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txout_to_scripthash& txout)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txout_to_scripthash& txout)
{
dest.StartObject();
@@ -509,7 +509,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_scripthash&
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txout_to_key& txout)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txout_to_key& txout)
{
dest.StartObject();
@@ -528,7 +528,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_key& txout)
GET_FROM_JSON_OBJECT(val, txout.key, key);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::tx_out& txout)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::tx_out& txout)
{
dest.StartObject();
INSERT_INTO_JSON_OBJECT(dest, amount, txout.amount);
@@ -537,7 +537,7 @@ void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const crypton
{
using result_type = void;
- rapidjson::Writer<rapidjson::StringBuffer>& dest;
+ rapidjson::Writer<epee::byte_stream>& dest;
void operator()(cryptonote::txout_to_key const& output) const
{
@@ -596,7 +596,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::tx_out& txout)
}
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::connection_info& info)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::connection_info& info)
{
dest.StartObject();
@@ -668,7 +668,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::connection_info& inf
GET_FROM_JSON_OBJECT(val, info.current_upload, current_upload);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::tx_blob_entry& tx)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::tx_blob_entry& tx)
{
dest.StartObject();
@@ -689,7 +689,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::tx_blob_entry& tx)
GET_FROM_JSON_OBJECT(val, tx.prunable_hash, prunable_hash);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::block_complete_entry& blk)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::block_complete_entry& blk)
{
dest.StartObject();
@@ -711,7 +711,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::block_complete_entry
GET_FROM_JSON_OBJECT(val, blk.txs, transactions);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::block_with_transactions& blk)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::block_with_transactions& blk)
{
dest.StartObject();
@@ -733,7 +733,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::block_with_tran
GET_FROM_JSON_OBJECT(val, blk.transactions, transactions);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::transaction_info& tx_info)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::transaction_info& tx_info)
{
dest.StartObject();
@@ -757,7 +757,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::transaction_inf
GET_FROM_JSON_OBJECT(val, tx_info.transaction, transaction);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_key_and_amount_index& out)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_key_and_amount_index& out)
{
dest.StartObject();
@@ -779,7 +779,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_key_and_
GET_FROM_JSON_OBJECT(val, out.key, key);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::amount_with_random_outputs& out)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::amount_with_random_outputs& out)
{
dest.StartObject();
@@ -801,7 +801,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::amount_with_ran
GET_FROM_JSON_OBJECT(val, out.outputs, outputs);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::peer& peer)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::peer& peer)
{
dest.StartObject();
@@ -833,7 +833,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::peer& peer)
GET_FROM_JSON_OBJECT(val, peer.pruning_seed, pruning_seed);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::tx_in_pool& tx)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::tx_in_pool& tx)
{
dest.StartObject();
@@ -880,7 +880,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::tx_in_pool& tx)
GET_FROM_JSON_OBJECT(val, tx.double_spend_seen, double_spend_seen);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::hard_fork_info& info)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::hard_fork_info& info)
{
dest.StartObject();
@@ -914,7 +914,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::hard_fork_info&
GET_FROM_JSON_OBJECT(val, info.earliest_height, earliest_height);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_amount_count& out)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_amount_count& out)
{
dest.StartObject();
@@ -940,7 +940,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_amount_c
GET_FROM_JSON_OBJECT(val, out.recent_count, recent_count);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_amount_and_index& out)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_amount_and_index& out)
{
dest.StartObject();
@@ -962,7 +962,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_amount_a
GET_FROM_JSON_OBJECT(val, out.index, index);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_key_mask_unlocked& out)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_key_mask_unlocked& out)
{
dest.StartObject();
@@ -985,7 +985,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_key_mask
GET_FROM_JSON_OBJECT(val, out.unlocked, unlocked);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::error& err)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::error& err)
{
dest.StartObject();
@@ -1008,7 +1008,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::error& error)
GET_FROM_JSON_OBJECT(val, error.message, message);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::BlockHeaderResponse& response)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::BlockHeaderResponse& response)
{
dest.StartObject();
@@ -1045,7 +1045,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::BlockHeaderResp
GET_FROM_JSON_OBJECT(val, response.reward, reward);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::rctSig& sig)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rctSig& sig)
{
using boost::adaptors::transform;
@@ -1115,7 +1115,7 @@ void fromJsonValue(const rapidjson::Value& val, rct::rctSig& sig)
}
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::ecdhTuple& tuple)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::ecdhTuple& tuple)
{
dest.StartObject();
INSERT_INTO_JSON_OBJECT(dest, mask, tuple.mask);
@@ -1134,7 +1134,7 @@ void fromJsonValue(const rapidjson::Value& val, rct::ecdhTuple& tuple)
GET_FROM_JSON_OBJECT(val, tuple.amount, amount);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::rangeSig& sig)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rangeSig& sig)
{
dest.StartObject();
@@ -1171,7 +1171,7 @@ void fromJsonValue(const rapidjson::Value& val, rct::rangeSig& sig)
}
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::Bulletproof& p)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::Bulletproof& p)
{
dest.StartObject();
@@ -1212,7 +1212,7 @@ void fromJsonValue(const rapidjson::Value& val, rct::Bulletproof& p)
GET_FROM_JSON_OBJECT(val, p.t, t);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::boroSig& sig)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::boroSig& sig)
{
dest.StartObject();
@@ -1257,7 +1257,7 @@ void fromJsonValue(const rapidjson::Value& val, rct::boroSig& sig)
GET_FROM_JSON_OBJECT(val, sig.ee, ee);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::mgSig& sig)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::mgSig& sig)
{
dest.StartObject();
@@ -1278,7 +1278,7 @@ void fromJsonValue(const rapidjson::Value& val, rct::mgSig& sig)
GET_FROM_JSON_OBJECT(val, sig.cc, cc);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::DaemonInfo& info)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::DaemonInfo& info)
{
dest.StartObject();
@@ -1339,7 +1339,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& inf
GET_FROM_JSON_OBJECT(val, info.start_time, start_time);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_distribution& dist)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_distribution& dist)
{
dest.StartObject();
diff --git a/src/serialization/json_object.h b/src/serialization/json_object.h
index 664b539b5..2a9b63b08 100644
--- a/src/serialization/json_object.h
+++ b/src/serialization/json_object.h
@@ -31,9 +31,9 @@
#include <boost/utility/string_ref.hpp>
#include <cstring>
#include <rapidjson/document.h>
-#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
+#include "byte_stream.h"
#include "cryptonote_basic/cryptonote_basic.h"
#include "rpc/message_data_structs.h"
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
@@ -123,7 +123,7 @@ void read_hex(const rapidjson::Value& val, epee::span<std::uint8_t> dest);
// POD to json key
template <class Type>
-inline typename std::enable_if<is_to_hex<Type>()>::type toJsonKey(rapidjson::Writer<rapidjson::StringBuffer>& dest, const Type& pod)
+inline typename std::enable_if<is_to_hex<Type>()>::type toJsonKey(rapidjson::Writer<epee::byte_stream>& dest, const Type& pod)
{
const auto hex = epee::to_hex::array(pod);
dest.Key(hex.data(), hex.size());
@@ -131,7 +131,7 @@ inline typename std::enable_if<is_to_hex<Type>()>::type toJsonKey(rapidjson::Wri
// POD to json value
template <class Type>
-inline typename std::enable_if<is_to_hex<Type>()>::type toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const Type& pod)
+inline typename std::enable_if<is_to_hex<Type>()>::type toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const Type& pod)
{
const auto hex = epee::to_hex::array(pod);
dest.String(hex.data(), hex.size());
@@ -144,16 +144,16 @@ inline typename std::enable_if<is_to_hex<Type>()>::type fromJsonValue(const rapi
json::read_hex(val, epee::as_mut_byte_span(t));
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rapidjson::Value& src);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rapidjson::Value& src);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, boost::string_ref i);
-inline void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const std::string& i)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, boost::string_ref i);
+inline void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const std::string& i)
{
toJsonValue(dest, boost::string_ref{i});
}
void fromJsonValue(const rapidjson::Value& val, std::string& str);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, bool i);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, bool i);
void fromJsonValue(const rapidjson::Value& val, bool& b);
// integers overloads for toJsonValue are not needed for standard promotions
@@ -168,144 +168,144 @@ void fromJsonValue(const rapidjson::Value& val, unsigned short& i);
void fromJsonValue(const rapidjson::Value& val, short& i);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const unsigned i);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const unsigned i);
void fromJsonValue(const rapidjson::Value& val, unsigned& i);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const int);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const int);
void fromJsonValue(const rapidjson::Value& val, int& i);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const unsigned long long i);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const unsigned long long i);
void fromJsonValue(const rapidjson::Value& val, unsigned long long& i);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const long long i);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const long long i);
void fromJsonValue(const rapidjson::Value& val, long long& i);
-inline void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const unsigned long i) {
+inline void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const unsigned long i) {
toJsonValue(dest, static_cast<unsigned long long>(i));
}
void fromJsonValue(const rapidjson::Value& val, unsigned long& i);
-inline void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const long i) {
+inline void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const long i) {
toJsonValue(dest, static_cast<long long>(i));
}
void fromJsonValue(const rapidjson::Value& val, long& i);
// end integers
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::transaction& tx);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::transaction& tx);
void fromJsonValue(const rapidjson::Value& val, cryptonote::transaction& tx);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::block& b);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::block& b);
void fromJsonValue(const rapidjson::Value& val, cryptonote::block& b);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_v& txin);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_v& txin);
void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_v& txin);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_gen& txin);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_gen& txin);
void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_gen& txin);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_to_script& txin);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_to_script& txin);
void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_script& txin);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_to_scripthash& txin);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_to_scripthash& txin);
void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_scripthash& txin);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_to_key& txin);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_to_key& txin);
void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_key& txin);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txout_target_v& txout);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txout_target_v& txout);
void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_target_v& txout);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txout_to_script& txout);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txout_to_script& txout);
void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_script& txout);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txout_to_scripthash& txout);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txout_to_scripthash& txout);
void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_scripthash& txout);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txout_to_key& txout);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txout_to_key& txout);
void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_key& txout);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::tx_out& txout);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::tx_out& txout);
void fromJsonValue(const rapidjson::Value& val, cryptonote::tx_out& txout);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::connection_info& info);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::connection_info& info);
void fromJsonValue(const rapidjson::Value& val, cryptonote::connection_info& info);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::tx_blob_entry& tx);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::tx_blob_entry& tx);
void fromJsonValue(const rapidjson::Value& val, cryptonote::tx_blob_entry& tx);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::block_complete_entry& blk);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::block_complete_entry& blk);
void fromJsonValue(const rapidjson::Value& val, cryptonote::block_complete_entry& blk);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::block_with_transactions& blk);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::block_with_transactions& blk);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::block_with_transactions& blk);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::transaction_info& tx_info);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::transaction_info& tx_info);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::transaction_info& tx_info);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_key_and_amount_index& out);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_key_and_amount_index& out);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_key_and_amount_index& out);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::amount_with_random_outputs& out);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::amount_with_random_outputs& out);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::amount_with_random_outputs& out);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::peer& peer);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::peer& peer);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::peer& peer);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::tx_in_pool& tx);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::tx_in_pool& tx);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::tx_in_pool& tx);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::hard_fork_info& info);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::hard_fork_info& info);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::hard_fork_info& info);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_amount_count& out);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_amount_count& out);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_amount_count& out);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_amount_and_index& out);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_amount_and_index& out);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_amount_and_index& out);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_key_mask_unlocked& out);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_key_mask_unlocked& out);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_key_mask_unlocked& out);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::error& err);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::error& err);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::error& error);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::BlockHeaderResponse& response);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::BlockHeaderResponse& response);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::BlockHeaderResponse& response);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::rctSig& i);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rctSig& i);
void fromJsonValue(const rapidjson::Value& val, rct::rctSig& sig);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::ecdhTuple& tuple);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::ecdhTuple& tuple);
void fromJsonValue(const rapidjson::Value& val, rct::ecdhTuple& tuple);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::rangeSig& sig);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rangeSig& sig);
void fromJsonValue(const rapidjson::Value& val, rct::rangeSig& sig);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::Bulletproof& p);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::Bulletproof& p);
void fromJsonValue(const rapidjson::Value& val, rct::Bulletproof& p);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::boroSig& sig);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::boroSig& sig);
void fromJsonValue(const rapidjson::Value& val, rct::boroSig& sig);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::mgSig& sig);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::mgSig& sig);
void fromJsonValue(const rapidjson::Value& val, rct::mgSig& sig);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::DaemonInfo& info);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::DaemonInfo& info);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& info);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_distribution& dist);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_distribution& dist);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_distribution& dist);
template <typename Map>
-typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const Map& map);
+typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const Map& map);
template <typename Map>
typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type fromJsonValue(const rapidjson::Value& val, Map& map);
template <typename Vec>
-typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const Vec &vec);
+typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const Vec &vec);
template <typename Vec>
typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type fromJsonValue(const rapidjson::Value& val, Vec& vec);
@@ -315,7 +315,7 @@ typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type fromJson
// unfortunately because of how templates work they have to be here.
template <typename Map>
-inline typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const Map& map)
+inline typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const Map& map)
{
using key_type = typename Map::key_type;
static_assert(std::is_same<std::string, key_type>() || is_to_hex<key_type>(), "invalid map key type");
@@ -351,7 +351,7 @@ inline typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type from
}
template <typename Vec>
-inline typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const Vec &vec)
+inline typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const Vec &vec)
{
dest.StartArray();
for (const auto& t : vec)
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index d45ef3d7c..b1e69161f 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -143,6 +143,7 @@ enum TransferType {
};
static std::string get_human_readable_timespan(std::chrono::seconds seconds);
+static std::string get_human_readable_timespan(uint64_t seconds);
namespace
{
@@ -182,6 +183,7 @@ namespace
const char* USAGE_LOCKED_TRANSFER("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <addr> <amount>) <lockblocks> [<payment_id (obsolete)>]");
const char* USAGE_LOCKED_SWEEP_ALL("locked_sweep_all [index=<N1>[,<N2>,...] | index=all] [<priority>] [<ring_size>] <address> <lockblocks> [<payment_id (obsolete)>]");
const char* USAGE_SWEEP_ALL("sweep_all [index=<N1>[,<N2>,...] | index=all] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id (obsolete)>]");
+ const char* USAGE_SWEEP_ACCOUNT("sweep_account <account> [index=<N1>[,<N2>,...] | index=all] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id (obsolete)>]");
const char* USAGE_SWEEP_BELOW("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id (obsolete)>]");
const char* USAGE_SWEEP_SINGLE("sweep_single [<priority>] [<ring_size>] [outputs=<N>] <key_image> <address> [<payment_id (obsolete)>]");
const char* USAGE_DONATE("donate [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <amount> [<payment_id (obsolete)>]");
@@ -207,7 +209,7 @@ namespace
const char* USAGE_CHECK_SPEND_PROOF("check_spend_proof <txid> <signature_file> [<message>]");
const char* USAGE_GET_RESERVE_PROOF("get_reserve_proof (all|<amount>) [<message>]");
const char* USAGE_CHECK_RESERVE_PROOF("check_reserve_proof <address> <signature_file> [<message>]");
- const char* USAGE_SHOW_TRANSFERS("show_transfers [in|out|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]");
+ const char* USAGE_SHOW_TRANSFERS("show_transfers [in|out|all|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]");
const char* USAGE_UNSPENT_OUTPUTS("unspent_outputs [index=<N1>[,<N2>,...]] [<min_amount> [<max_amount>]]");
const char* USAGE_RESCAN_BC("rescan_bc [hard|soft|keep_ki] [start_height=0]");
const char* USAGE_SET_TX_NOTE("set_tx_note <txid> [free text note]");
@@ -3145,6 +3147,9 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("sweep_all", boost::bind(&simple_wallet::sweep_all, this, _1),
tr(USAGE_SWEEP_ALL),
tr("Send all unlocked balance to an address. If the parameter \"index=<N1>[,<N2>,...]\" or \"index=all\" is specified, the wallet sweeps outputs received by those or all address indices, respectively. If omitted, the wallet randomly chooses an address index to be used. If the parameter \"outputs=<N>\" is specified and N > 0, wallet splits the transaction into N even outputs."));
+ m_cmd_binder.set_handler("sweep_account", boost::bind(&simple_wallet::sweep_account, this, _1),
+ tr(USAGE_SWEEP_ACCOUNT),
+ tr("Send all unlocked balance from a given account to an address. If the parameter \"index=<N1>[,<N2>,...]\" or \"index=all\" is specified, the wallet sweeps outputs received by those or all address indices, respectively. If omitted, the wallet randomly chooses an address index to be used. If the parameter \"outputs=<N>\" is specified and N > 0, wallet splits the transaction into N even outputs."));
m_cmd_binder.set_handler("sweep_below",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::sweep_below, _1),
tr(USAGE_SWEEP_BELOW),
@@ -3338,7 +3343,7 @@ simple_wallet::simple_wallet()
"** Set of address indices used as inputs in this transfer."));
m_cmd_binder.set_handler("export_transfers",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::export_transfers, _1),
- tr("export_transfers [in|out|all|pending|failed|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]] [output=<filepath>]"),
+ tr("export_transfers [in|out|all|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]] [output=<filepath>]"),
tr("Export to CSV the incoming/outgoing transfers within an optional height range."));
m_cmd_binder.set_handler("unspent_outputs",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::unspent_outputs, _1),
@@ -5576,14 +5581,19 @@ boost::optional<epee::wipeable_string> simple_wallet::on_device_pin_request()
return pwd_container->password();
}
//----------------------------------------------------------------------------------------------------
-boost::optional<epee::wipeable_string> simple_wallet::on_device_passphrase_request(bool on_device)
+boost::optional<epee::wipeable_string> simple_wallet::on_device_passphrase_request(bool & on_device)
{
- if (on_device){
- message_writer(console_color_white, true) << tr("Please enter the device passphrase on the device");
- return boost::none;
+ if (on_device) {
+ std::string accepted = input_line(tr(
+ "Device asks for passphrase. Do you want to enter the passphrase on device (Y) (or on the host (N))?"));
+ if (std::cin.eof() || command_line::is_yes(accepted)) {
+ message_writer(console_color_white, true) << tr("Please enter the device passphrase on the device");
+ return boost::none;
+ }
}
PAUSE_READLINE();
+ on_device = false;
std::string msg = tr("Enter device passphrase");
auto pwd_container = tools::password_container::prompt(false, msg.c_str());
THROW_WALLET_EXCEPTION_IF(!pwd_container, tools::error::password_entry_failed, tr("Failed to read device passphrase"));
@@ -5748,15 +5758,19 @@ bool simple_wallet::show_balance_unlocked(bool detailed)
success_msg_writer() << tr("Currently selected account: [") << m_current_subaddress_account << tr("] ") << m_wallet->get_subaddress_label({m_current_subaddress_account, 0});
const std::string tag = m_wallet->get_account_tags().second[m_current_subaddress_account];
success_msg_writer() << tr("Tag: ") << (tag.empty() ? std::string{tr("(No tag assigned)")} : tag);
- uint64_t blocks_to_unlock;
- uint64_t unlocked_balance = m_wallet->unlocked_balance(m_current_subaddress_account, false, &blocks_to_unlock);
+ uint64_t blocks_to_unlock, time_to_unlock;
+ uint64_t unlocked_balance = m_wallet->unlocked_balance(m_current_subaddress_account, false, &blocks_to_unlock, &time_to_unlock);
std::string unlock_time_message;
- if (blocks_to_unlock > 0)
+ if (blocks_to_unlock > 0 && time_to_unlock > 0)
+ unlock_time_message = (boost::format(" (%lu block(s) and %s to unlock)") % blocks_to_unlock % get_human_readable_timespan(time_to_unlock)).str();
+ else if (blocks_to_unlock > 0)
unlock_time_message = (boost::format(" (%lu block(s) to unlock)") % blocks_to_unlock).str();
+ else if (time_to_unlock > 0)
+ unlock_time_message = (boost::format(" (%s to unlock)") % get_human_readable_timespan(time_to_unlock)).str();
success_msg_writer() << tr("Balance: ") << print_money(m_wallet->balance(m_current_subaddress_account, false)) << ", "
<< tr("unlocked balance: ") << print_money(unlocked_balance) << unlock_time_message << extra;
std::map<uint32_t, uint64_t> balance_per_subaddress = m_wallet->balance_per_subaddress(m_current_subaddress_account, false);
- std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account, false);
+ std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account, false);
if (!detailed || balance_per_subaddress.empty())
return true;
success_msg_writer() << tr("Balance per address:");
@@ -6221,6 +6235,7 @@ bool simple_wallet::prompt_if_old(const std::vector<tools::wallet2::pending_tx>
}
return true;
}
+//----------------------------------------------------------------------------------------------------
void simple_wallet::check_for_inactivity_lock(bool user)
{
if (m_locked)
@@ -6745,7 +6760,7 @@ bool simple_wallet::locked_transfer(const std::vector<std::string> &args_)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::locked_sweep_all(const std::vector<std::string> &args_)
{
- sweep_main(0, true, args_);
+ sweep_main(m_current_subaddress_account, 0, true, args_);
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -6856,18 +6871,22 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
return true;
}
//----------------------------------------------------------------------------------------------------
-bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<std::string> &args_)
+bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, const std::vector<std::string> &args_)
{
- auto print_usage = [below]()
+ auto print_usage = [this, account, below]()
{
if (below)
{
PRINT_USAGE(USAGE_SWEEP_BELOW);
}
- else
+ else if (account == m_current_subaddress_account)
{
PRINT_USAGE(USAGE_SWEEP_ALL);
}
+ else
+ {
+ PRINT_USAGE(USAGE_SWEEP_ACCOUNT);
+ }
};
if (args_.size() == 0)
{
@@ -7041,7 +7060,7 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
try
{
// figure out what tx will be necessary
- auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, outputs, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices);
+ auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, outputs, fake_outs_count, unlock_block /* unlock_time */, priority, extra, account, subaddr_indices);
if (ptx_vector.empty())
{
@@ -7381,7 +7400,27 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::sweep_all(const std::vector<std::string> &args_)
{
- sweep_main(0, false, args_);
+ sweep_main(m_current_subaddress_account, 0, false, args_);
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::sweep_account(const std::vector<std::string> &args_)
+{
+ auto local_args = args_;
+ if (local_args.empty())
+ {
+ PRINT_USAGE(USAGE_SWEEP_ACCOUNT);
+ return true;
+ }
+ uint32_t account = 0;
+ if (!epee::string_tools::get_xtype_from_string(account, local_args[0]))
+ {
+ fail_msg_writer() << tr("Invalid account");
+ return true;
+ }
+ local_args.erase(local_args.begin());
+
+ sweep_main(account, 0, false, local_args);
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -7398,7 +7437,7 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args_)
fail_msg_writer() << tr("invalid amount threshold");
return true;
}
- sweep_main(below, false, std::vector<std::string>(++args_.begin(), args_.end()));
+ sweep_main(m_current_subaddress_account, below, false, std::vector<std::string>(++args_.begin(), args_.end()));
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -8233,6 +8272,11 @@ static std::string get_human_readable_timespan(std::chrono::seconds seconds)
return sw::tr("a long time");
}
//----------------------------------------------------------------------------------------------------
+static std::string get_human_readable_timespan(uint64_t seconds)
+{
+ return get_human_readable_timespan(std::chrono::seconds(seconds));
+}
+//----------------------------------------------------------------------------------------------------
// mutates local_args as it parses and consumes arguments
bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vector<transfer_view>& transfers)
{
@@ -8495,7 +8539,7 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
std::vector<std::string> local_args = args_;
if(local_args.size() > 4) {
- fail_msg_writer() << tr("usage: show_transfers [in|out|all|pending|failed|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]");
+ fail_msg_writer() << tr("usage: show_transfers [in|out|all|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]");
return true;
}
@@ -8548,7 +8592,7 @@ bool simple_wallet::export_transfers(const std::vector<std::string>& args_)
std::vector<std::string> local_args = args_;
if(local_args.size() > 5) {
- fail_msg_writer() << tr("usage: export_transfers [in|out|all|pending|failed|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]] [output=<path>]");
+ fail_msg_writer() << tr("usage: export_transfers [in|out|all|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]] [output=<path>]");
return true;
}
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 4ba2793e0..59818b303 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -170,8 +170,9 @@ namespace cryptonote
bool transfer(const std::vector<std::string> &args);
bool locked_transfer(const std::vector<std::string> &args);
bool locked_sweep_all(const std::vector<std::string> &args);
- bool sweep_main(uint64_t below, bool locked, const std::vector<std::string> &args);
+ bool sweep_main(uint32_t account, uint64_t below, bool locked, const std::vector<std::string> &args);
bool sweep_all(const std::vector<std::string> &args);
+ bool sweep_account(const std::vector<std::string> &args);
bool sweep_below(const std::vector<std::string> &args);
bool sweep_single(const std::vector<std::string> &args);
bool sweep_unmixable(const std::vector<std::string> &args);
@@ -348,7 +349,7 @@ namespace cryptonote
virtual boost::optional<epee::wipeable_string> on_get_password(const char *reason);
virtual void on_device_button_request(uint64_t code);
virtual boost::optional<epee::wipeable_string> on_device_pin_request();
- virtual boost::optional<epee::wipeable_string> on_device_passphrase_request(bool on_device);
+ virtual boost::optional<epee::wipeable_string> on_device_passphrase_request(bool & on_device);
//----------------------------------------------------------
friend class refresh_progress_reporter_t;
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 4612b0397..d89261c64 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -267,13 +267,15 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
return boost::none;
}
- virtual boost::optional<epee::wipeable_string> on_device_passphrase_request(bool on_device)
+ virtual boost::optional<epee::wipeable_string> on_device_passphrase_request(bool & on_device)
{
if (m_listener) {
auto passphrase = m_listener->onDevicePassphraseRequest(on_device);
- if (!on_device && passphrase) {
+ if (passphrase) {
return boost::make_optional(epee::wipeable_string((*passphrase).data(), (*passphrase).size()));
}
+ } else {
+ on_device = true;
}
return boost::none;
}
diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h
index 6309724a4..9c3df8988 100644
--- a/src/wallet/api/wallet2_api.h
+++ b/src/wallet/api/wallet2_api.h
@@ -400,8 +400,8 @@ struct WalletListener
/**
* @brief called by device when passphrase entry is needed
*/
- virtual optional<std::string> onDevicePassphraseRequest(bool on_device) {
- if (!on_device) throw std::runtime_error("Not supported");
+ virtual optional<std::string> onDevicePassphraseRequest(bool & on_device) {
+ on_device = true;
return optional<std::string>();
}
diff --git a/src/wallet/message_store.cpp b/src/wallet/message_store.cpp
index 1bd462ef5..25a8bd4ef 100644
--- a/src/wallet/message_store.cpp
+++ b/src/wallet/message_store.cpp
@@ -724,7 +724,7 @@ void message_store::read_from_file(const multisig_wallet_state &state, const std
{
// Simply do nothing if the file is not there; allows e.g. easy recovery
// from problems with the MMS by deleting the file
- MERROR("No message store file found: " << filename);
+ MINFO("No message store file found: " << filename);
return;
}
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 4220f18be..02a067986 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1109,10 +1109,12 @@ boost::optional<epee::wipeable_string> wallet_device_callback::on_pin_request()
return boost::none;
}
-boost::optional<epee::wipeable_string> wallet_device_callback::on_passphrase_request(bool on_device)
+boost::optional<epee::wipeable_string> wallet_device_callback::on_passphrase_request(bool & on_device)
{
if (wallet)
return wallet->on_device_passphrase_request(on_device);
+ else
+ on_device = true;
return boost::none;
}
@@ -1521,6 +1523,18 @@ void wallet2::add_subaddress(uint32_t index_major, const std::string& label)
m_subaddress_labels[index_major][index_minor] = label;
}
//----------------------------------------------------------------------------------------------------
+bool wallet2::should_expand(const cryptonote::subaddress_index &index) const
+{
+ const uint32_t last_major = m_subaddress_labels.size() - 1 > (std::numeric_limits<uint32_t>::max() - m_subaddress_lookahead_major) ? std::numeric_limits<uint32_t>::max() : (m_subaddress_labels.size() + m_subaddress_lookahead_major - 1);
+ if (index.major > last_major)
+ return false;
+ const size_t nsub = index.major < m_subaddress_labels.size() ? m_subaddress_labels[index.major].size() : 0;
+ const uint32_t last_minor = nsub - 1 > (std::numeric_limits<uint32_t>::max() - m_subaddress_lookahead_minor) ? std::numeric_limits<uint32_t>::max() : (nsub + m_subaddress_lookahead_minor - 1);
+ if (index.minor > last_minor)
+ return false;
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index)
{
hw::device &hwdev = m_account.get_device();
@@ -2106,7 +2120,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_amount = amount;
td.m_pk_index = pk_index - 1;
td.m_subaddr_index = tx_scan_info[o].received->index;
- if (tx_scan_info[o].received->index.major < m_subaddress_labels.size() && tx_scan_info[o].received->index.minor < m_subaddress_labels[tx_scan_info[o].received->index.major].size())
+ if (should_expand(tx_scan_info[o].received->index))
expand_subaddresses(tx_scan_info[o].received->index);
if (tx.vout[o].amount == 0)
{
@@ -2185,7 +2199,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_amount = amount;
td.m_pk_index = pk_index - 1;
td.m_subaddr_index = tx_scan_info[o].received->index;
- if (tx_scan_info[o].received->index.major < m_subaddress_labels.size() && tx_scan_info[o].received->index.minor < m_subaddress_labels[tx_scan_info[o].received->index.major].size())
+ if (should_expand(tx_scan_info[o].received->index))
expand_subaddresses(tx_scan_info[o].received->index);
if (tx.vout[o].amount == 0)
{
@@ -4846,6 +4860,7 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password,
std::vector<crypto::secret_key> multisig_keys;
rct::key spend_pkey = rct::identity();
rct::key spend_skey;
+ auto wiper = epee::misc_utils::create_scope_leave_handler([&](){memwipe(&spend_skey, sizeof(spend_skey));});
std::vector<crypto::public_key> multisig_signers;
// decrypt keys
@@ -5491,13 +5506,12 @@ bool wallet2::check_connection(uint32_t *version, bool *ssl, uint32_t timeout)
cryptonote::COMMAND_RPC_GET_VERSION::request req_t = AUTO_VAL_INIT(req_t);
cryptonote::COMMAND_RPC_GET_VERSION::response resp_t = AUTO_VAL_INIT(resp_t);
bool r = invoke_http_json_rpc("/json_rpc", "get_version", req_t, resp_t);
- if(!r) {
+ if(!r || resp_t.status != CORE_RPC_STATUS_OK) {
if(version)
*version = 0;
return false;
}
- if (resp_t.status == CORE_RPC_STATUS_OK)
- m_rpc_version = resp_t.version;
+ m_rpc_version = resp_t.version;
}
if (version)
*version = m_rpc_version;
@@ -5910,18 +5924,22 @@ uint64_t wallet2::balance(uint32_t index_major, bool strict) const
return amount;
}
//----------------------------------------------------------------------------------------------------
-uint64_t wallet2::unlocked_balance(uint32_t index_major, bool strict, uint64_t *blocks_to_unlock) const
+uint64_t wallet2::unlocked_balance(uint32_t index_major, bool strict, uint64_t *blocks_to_unlock, uint64_t *time_to_unlock) const
{
uint64_t amount = 0;
if (blocks_to_unlock)
*blocks_to_unlock = 0;
+ if (time_to_unlock)
+ *time_to_unlock = 0;
if(m_light_wallet)
return m_light_wallet_balance;
for (const auto& i : unlocked_balance_per_subaddress(index_major, strict))
{
amount += i.second.first;
- if (blocks_to_unlock && i.second.second > *blocks_to_unlock)
- *blocks_to_unlock = i.second.second;
+ if (blocks_to_unlock && i.second.second.first > *blocks_to_unlock)
+ *blocks_to_unlock = i.second.second.first;
+ if (time_to_unlock && i.second.second.second > *time_to_unlock)
+ *time_to_unlock = i.second.second.second;
}
return amount;
}
@@ -5958,35 +5976,40 @@ std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_majo
return amount_per_subaddr;
}
//----------------------------------------------------------------------------------------------------
-std::map<uint32_t, std::pair<uint64_t, uint64_t>> wallet2::unlocked_balance_per_subaddress(uint32_t index_major, bool strict) const
+std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> wallet2::unlocked_balance_per_subaddress(uint32_t index_major, bool strict) const
{
- std::map<uint32_t, std::pair<uint64_t, uint64_t>> amount_per_subaddr;
+ std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> amount_per_subaddr;
const uint64_t blockchain_height = get_blockchain_current_height();
+ const uint64_t now = time(NULL);
for(const transfer_details& td: m_transfers)
{
if(td.m_subaddr_index.major == index_major && !is_spent(td, strict) && !td.m_frozen)
{
- uint64_t amount = 0, blocks_to_unlock = 0;
+ uint64_t amount = 0, blocks_to_unlock = 0, time_to_unlock = 0;
if (is_transfer_unlocked(td))
{
amount = td.amount();
blocks_to_unlock = 0;
+ time_to_unlock = 0;
}
else
{
uint64_t unlock_height = td.m_block_height + std::max<uint64_t>(CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE, CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS);
if (td.m_tx.unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER && td.m_tx.unlock_time > unlock_height)
unlock_height = td.m_tx.unlock_time;
+ uint64_t unlock_time = td.m_tx.unlock_time >= CRYPTONOTE_MAX_BLOCK_NUMBER ? td.m_tx.unlock_time : 0;
blocks_to_unlock = unlock_height > blockchain_height ? unlock_height - blockchain_height : 0;
+ time_to_unlock = unlock_time > now ? unlock_time - now : 0;
amount = 0;
}
auto found = amount_per_subaddr.find(td.m_subaddr_index.minor);
if (found == amount_per_subaddr.end())
- amount_per_subaddr[td.m_subaddr_index.minor] = std::make_pair(amount, blocks_to_unlock);
+ amount_per_subaddr[td.m_subaddr_index.minor] = std::make_pair(amount, std::make_pair(blocks_to_unlock, time_to_unlock));
else
{
found->second.first += amount;
- found->second.second = std::max(found->second.second, blocks_to_unlock);
+ found->second.second.first = std::max(found->second.second.first, blocks_to_unlock);
+ found->second.second.second = std::max(found->second.second.second, time_to_unlock);
}
}
}
@@ -6001,17 +6024,21 @@ uint64_t wallet2::balance_all(bool strict) const
return r;
}
//----------------------------------------------------------------------------------------------------
-uint64_t wallet2::unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock) const
+uint64_t wallet2::unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock, uint64_t *time_to_unlock) const
{
uint64_t r = 0;
if (blocks_to_unlock)
*blocks_to_unlock = 0;
+ if (time_to_unlock)
+ *time_to_unlock = 0;
for (uint32_t index_major = 0; index_major < get_num_subaddress_accounts(); ++index_major)
{
- uint64_t local_blocks_to_unlock;
- r += unlocked_balance(index_major, strict, blocks_to_unlock ? &local_blocks_to_unlock : NULL);
+ uint64_t local_blocks_to_unlock, local_time_to_unlock;
+ r += unlocked_balance(index_major, strict, blocks_to_unlock ? &local_blocks_to_unlock : NULL, time_to_unlock ? &local_time_to_unlock : NULL);
if (blocks_to_unlock)
*blocks_to_unlock = std::max(*blocks_to_unlock, local_blocks_to_unlock);
+ if (time_to_unlock)
+ *time_to_unlock = std::max(*time_to_unlock, local_time_to_unlock);
}
return r;
}
@@ -6490,7 +6517,7 @@ void wallet2::commit_tx(pending_tx& ptx)
// tx generated, get rid of used k values
for (size_t idx: ptx.selected_transfers)
- m_transfers[idx].m_multisig_k.clear();
+ memwipe(m_transfers[idx].m_multisig_k.data(), m_transfers[idx].m_multisig_k.size() * sizeof(m_transfers[idx].m_multisig_k[0]));
//fee includes dust if dust policy specified it.
LOG_PRINT_L1("Transaction successfully sent. <" << txid << ">" << ENDL
@@ -6932,13 +6959,13 @@ std::string wallet2::save_multisig_tx(multisig_tx_set txs)
// txes generated, get rid of used k values
for (size_t n = 0; n < txs.m_ptx.size(); ++n)
for (size_t idx: txs.m_ptx[n].construction_data.selected_transfers)
- m_transfers[idx].m_multisig_k.clear();
+ memwipe(m_transfers[idx].m_multisig_k.data(), m_transfers[idx].m_multisig_k.size() * sizeof(m_transfers[idx].m_multisig_k[0]));
// zero out some data we don't want to share
for (auto &ptx: txs.m_ptx)
{
for (auto &e: ptx.construction_data.sources)
- e.multisig_kLRki.k = rct::zero();
+ memwipe(&e.multisig_kLRki.k, sizeof(e.multisig_kLRki.k));
}
for (auto &ptx: txs.m_ptx)
@@ -7146,10 +7173,12 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto
ptx.tx.rct_signatures = sig.sigs;
rct::keyV k;
+ rct::key skey = rct::zero();
+ auto wiper = epee::misc_utils::create_scope_leave_handler([&](){ memwipe(k.data(), k.size() * sizeof(k[0])); memwipe(&skey, sizeof(skey)); });
+
for (size_t idx: sd.selected_transfers)
k.push_back(get_multisig_k(idx, sig.used_L));
- rct::key skey = rct::zero();
for (const auto &msk: get_account().get_multisig_keys())
{
crypto::public_key pmsk = get_multisig_signing_public_key(msk);
@@ -7197,7 +7226,7 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto
// txes generated, get rid of used k values
for (size_t n = 0; n < exported_txs.m_ptx.size(); ++n)
for (size_t idx: exported_txs.m_ptx[n].construction_data.selected_transfers)
- m_transfers[idx].m_multisig_k.clear();
+ memwipe(m_transfers[idx].m_multisig_k.data(), m_transfers[idx].m_multisig_k.size() * sizeof(m_transfers[idx].m_multisig_k[0]));
exported_txs.m_signers.insert(get_multisig_signer_public_key());
@@ -9650,7 +9679,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// throw if attempting a transaction with no money
THROW_WALLET_EXCEPTION_IF(needed_money == 0, error::zero_destination);
- std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account, false);
+ std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account, false);
std::map<uint32_t, uint64_t> balance_per_subaddr = balance_per_subaddress(subaddr_account, false);
if (subaddr_indices.empty()) // "index=<N1>[,<N2>,...]" wasn't specified -> use all the indices with non-zero unlocked balance
@@ -12755,7 +12784,7 @@ process:
const crypto::public_key& out_key = boost::get<cryptonote::txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key;
bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image, m_account.get_device());
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
- if (td.m_subaddr_index.major < m_subaddress_labels.size() && td.m_subaddr_index.minor < m_subaddress_labels[td.m_subaddr_index.major].size())
+ if (should_expand(td.m_subaddr_index))
expand_subaddresses(td.m_subaddr_index);
td.m_key_image_known = true;
td.m_key_image_request = true;
@@ -12948,7 +12977,7 @@ cryptonote::blobdata wallet2::export_multisig()
{
transfer_details &td = m_transfers[n];
crypto::key_image ki;
- td.m_multisig_k.clear();
+ memwipe(td.m_multisig_k.data(), td.m_multisig_k.size() * sizeof(td.m_multisig_k[0]));
info[n].m_LR.clear();
info[n].m_partial_key_images.clear();
@@ -13057,6 +13086,7 @@ size_t wallet2::import_multisig(std::vector<cryptonote::blobdata> blobs)
CHECK_AND_ASSERT_THROW_MES(info.size() + 1 <= m_multisig_signers.size() && info.size() + 1 >= m_multisig_threshold, "Wrong number of multisig sources");
std::vector<std::vector<rct::key>> k;
+ auto wiper = epee::misc_utils::create_scope_leave_handler([&](){memwipe(k.data(), k.size() * sizeof(k[0]));});
k.reserve(m_transfers.size());
for (const auto &td: m_transfers)
k.push_back(td.m_multisig_k);
@@ -13618,10 +13648,12 @@ boost::optional<epee::wipeable_string> wallet2::on_device_pin_request()
return boost::none;
}
//----------------------------------------------------------------------------------------------------
-boost::optional<epee::wipeable_string> wallet2::on_device_passphrase_request(bool on_device)
+boost::optional<epee::wipeable_string> wallet2::on_device_passphrase_request(bool & on_device)
{
if (nullptr != m_callback)
return m_callback->on_device_passphrase_request(on_device);
+ else
+ on_device = true;
return boost::none;
}
//----------------------------------------------------------------------------------------------------
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 1c3c00152..eb33713b5 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -145,7 +145,7 @@ private:
virtual void on_device_button_request(uint64_t code) {}
virtual void on_device_button_pressed() {}
virtual boost::optional<epee::wipeable_string> on_device_pin_request() { return boost::none; }
- virtual boost::optional<epee::wipeable_string> on_device_passphrase_request(bool on_device) { return boost::none; }
+ virtual boost::optional<epee::wipeable_string> on_device_passphrase_request(bool & on_device) { on_device = true; return boost::none; }
virtual void on_device_progress(const hw::device_progress& event) {};
// Common callbacks
virtual void on_pool_tx_removed(const crypto::hash &txid) {}
@@ -159,7 +159,7 @@ private:
void on_button_request(uint64_t code=0) override;
void on_button_pressed() override;
boost::optional<epee::wipeable_string> on_pin_request() override;
- boost::optional<epee::wipeable_string> on_passphrase_request(bool on_device) override;
+ boost::optional<epee::wipeable_string> on_passphrase_request(bool & on_device) override;
void on_progress(const hw::device_progress& event) override;
private:
wallet2 * wallet;
@@ -835,13 +835,13 @@ private:
// locked & unlocked balance of given or current subaddress account
uint64_t balance(uint32_t subaddr_index_major, bool strict) const;
- uint64_t unlocked_balance(uint32_t subaddr_index_major, bool strict, uint64_t *blocks_to_unlock = NULL) const;
+ uint64_t unlocked_balance(uint32_t subaddr_index_major, bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL) const;
// locked & unlocked balance per subaddress of given or current subaddress account
std::map<uint32_t, uint64_t> balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const;
- std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const;
+ std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const;
// all locked & unlocked balances of all subaddress accounts
uint64_t balance_all(bool strict) const;
- uint64_t unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock = NULL) const;
+ uint64_t unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL) const;
template<typename T>
void transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count,
std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs,
@@ -1507,7 +1507,7 @@ private:
void on_device_button_request(uint64_t code);
void on_device_button_pressed();
boost::optional<epee::wipeable_string> on_device_pin_request();
- boost::optional<epee::wipeable_string> on_device_passphrase_request(bool on_device);
+ boost::optional<epee::wipeable_string> on_device_passphrase_request(bool & on_device);
void on_device_progress(const hw::device_progress& event);
std::string get_rpc_status(const std::string &s) const;
@@ -1516,6 +1516,8 @@ private:
std::string get_client_signature() const;
void check_rpc_cost(const char *call, uint64_t post_call_credits, uint64_t pre_credits, double expected_cost);
+ bool should_expand(const cryptonote::subaddress_index &index) const;
+
cryptonote::account_base m_account;
boost::optional<epee::net_utils::http::login> m_daemon_login;
std::string m_daemon_address;
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index db2e2344b..30eed07e7 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -428,10 +428,10 @@ namespace tools
try
{
res.balance = req.all_accounts ? m_wallet->balance_all(req.strict) : m_wallet->balance(req.account_index, req.strict);
- res.unlocked_balance = req.all_accounts ? m_wallet->unlocked_balance_all(req.strict, &res.blocks_to_unlock) : m_wallet->unlocked_balance(req.account_index, req.strict, &res.blocks_to_unlock);
+ res.unlocked_balance = req.all_accounts ? m_wallet->unlocked_balance_all(req.strict, &res.blocks_to_unlock, &res.time_to_unlock) : m_wallet->unlocked_balance(req.account_index, req.strict, &res.blocks_to_unlock, &res.time_to_unlock);
res.multisig_import_needed = m_wallet->multisig() && m_wallet->has_multisig_partial_key_images();
std::map<uint32_t, std::map<uint32_t, uint64_t>> balance_per_subaddress_per_account;
- std::map<uint32_t, std::map<uint32_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress_per_account;
+ std::map<uint32_t, std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>>> unlocked_balance_per_subaddress_per_account;
if (req.all_accounts)
{
for (uint32_t account_index = 0; account_index < m_wallet->get_num_subaddress_accounts(); ++account_index)
@@ -451,7 +451,7 @@ namespace tools
{
uint32_t account_index = p.first;
std::map<uint32_t, uint64_t> balance_per_subaddress = p.second;
- std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress = unlocked_balance_per_subaddress_per_account[account_index];
+ std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress = unlocked_balance_per_subaddress_per_account[account_index];
std::set<uint32_t> address_indices;
if (!req.all_accounts && !req.address_indices.empty())
{
@@ -471,7 +471,8 @@ namespace tools
info.address = m_wallet->get_subaddress_as_str(index);
info.balance = balance_per_subaddress[i];
info.unlocked_balance = unlocked_balance_per_subaddress[i].first;
- info.blocks_to_unlock = unlocked_balance_per_subaddress[i].second;
+ info.blocks_to_unlock = unlocked_balance_per_subaddress[i].second.first;
+ info.time_to_unlock = unlocked_balance_per_subaddress[i].second.second;
info.label = m_wallet->get_subaddress_label(index);
info.num_unspent_outputs = std::count_if(transfers.begin(), transfers.end(), [&](const tools::wallet2::transfer_details& td) { return !td.m_spent && td.m_subaddr_index == index; });
res.per_subaddress.emplace_back(std::move(info));
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index a212b79e6..507ff4f6c 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -47,7 +47,7 @@
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define WALLET_RPC_VERSION_MAJOR 1
-#define WALLET_RPC_VERSION_MINOR 17
+#define WALLET_RPC_VERSION_MINOR 18
#define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR)
namespace tools
@@ -84,6 +84,7 @@ namespace wallet_rpc
std::string label;
uint64_t num_unspent_outputs;
uint64_t blocks_to_unlock;
+ uint64_t time_to_unlock;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(account_index)
@@ -94,6 +95,7 @@ namespace wallet_rpc
KV_SERIALIZE(label)
KV_SERIALIZE(num_unspent_outputs)
KV_SERIALIZE(blocks_to_unlock)
+ KV_SERIALIZE(time_to_unlock)
END_KV_SERIALIZE_MAP()
};
@@ -104,6 +106,7 @@ namespace wallet_rpc
bool multisig_import_needed;
std::vector<per_subaddress_info> per_subaddress;
uint64_t blocks_to_unlock;
+ uint64_t time_to_unlock;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(balance)
@@ -111,6 +114,7 @@ namespace wallet_rpc
KV_SERIALIZE(multisig_import_needed)
KV_SERIALIZE(per_subaddress)
KV_SERIALIZE(blocks_to_unlock)
+ KV_SERIALIZE(time_to_unlock)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;